2022-02-03 10:06:44 -06:00
|
|
|
import {
|
|
|
|
|
Controller,
|
|
|
|
|
Post,
|
|
|
|
|
UseInterceptors,
|
|
|
|
|
Body,
|
|
|
|
|
UseGuards,
|
|
|
|
|
Get,
|
|
|
|
|
Param,
|
|
|
|
|
ValidationPipe,
|
|
|
|
|
Query,
|
2022-02-06 00:07:56 -06:00
|
|
|
Response,
|
|
|
|
|
Headers,
|
2022-02-13 15:10:42 -06:00
|
|
|
Delete,
|
2022-03-27 15:47:49 -05:00
|
|
|
Logger,
|
2022-06-19 08:16:35 -05:00
|
|
|
HttpCode,
|
2022-07-06 16:12:55 -05:00
|
|
|
BadRequestException,
|
2022-07-10 21:41:45 -05:00
|
|
|
UploadedFile,
|
2022-02-03 10:06:44 -06:00
|
|
|
} from '@nestjs/common';
|
|
|
|
|
import { JwtAuthGuard } from '../../modules/immich-jwt/guards/jwt-auth.guard';
|
|
|
|
|
import { AssetService } from './asset.service';
|
2022-07-13 07:23:48 -05:00
|
|
|
import { FileInterceptor } from '@nestjs/platform-express';
|
2022-05-27 22:15:35 -05:00
|
|
|
import { assetUploadOption } from '../../config/asset-upload.config';
|
2022-02-03 10:06:44 -06:00
|
|
|
import { AuthUserDto, GetAuthUser } from '../../decorators/auth-user.decorator';
|
|
|
|
|
import { ServeFileDto } from './dto/serve-file.dto';
|
2022-02-06 00:07:56 -06:00
|
|
|
import { Response as Res } from 'express';
|
2022-02-10 20:40:11 -06:00
|
|
|
import { BackgroundTaskService } from '../../modules/background-task/background-task.service';
|
2022-02-13 15:10:42 -06:00
|
|
|
import { DeleteAssetDto } from './dto/delete-asset.dto';
|
2022-03-02 16:44:24 -06:00
|
|
|
import { SearchAssetDto } from './dto/search-asset.dto';
|
2022-03-22 01:22:04 -05:00
|
|
|
import { CommunicationGateway } from '../communication/communication.gateway';
|
2022-06-11 16:12:06 -05:00
|
|
|
import { InjectQueue } from '@nestjs/bull';
|
|
|
|
|
import { Queue } from 'bull';
|
2022-07-02 21:06:36 -05:00
|
|
|
import { IAssetUploadedJob } from '@app/job/index';
|
|
|
|
|
import { assetUploadedQueueName } from '@app/job/constants/queue-name.constant';
|
|
|
|
|
import { assetUploadedProcessorName } from '@app/job/constants/job-name.constant';
|
2022-07-06 16:12:55 -05:00
|
|
|
import { CheckDuplicateAssetDto } from './dto/check-duplicate-asset.dto';
|
2022-07-10 21:41:45 -05:00
|
|
|
import { ApiBearerAuth, ApiBody, ApiConsumes, ApiResponse, ApiTags } from '@nestjs/swagger';
|
2022-07-08 21:26:50 -05:00
|
|
|
import { CuratedObjectsResponseDto } from './response-dto/curated-objects-response.dto';
|
|
|
|
|
import { CuratedLocationsResponseDto } from './response-dto/curated-locations-response.dto';
|
|
|
|
|
import { AssetResponseDto } from './response-dto/asset-response.dto';
|
2022-07-10 21:41:45 -05:00
|
|
|
import { CheckDuplicateAssetResponseDto } from './response-dto/check-duplicate-asset-response.dto';
|
|
|
|
|
import { AssetFileUploadDto } from './dto/asset-file-upload.dto';
|
|
|
|
|
import { CreateAssetDto } from './dto/create-asset.dto';
|
|
|
|
|
import { AssetFileUploadResponseDto } from './response-dto/asset-file-upload-response.dto';
|
2022-07-13 07:23:48 -05:00
|
|
|
import { DeleteAssetResponseDto, DeleteAssetStatusEnum } from './response-dto/delete-asset-response.dto';
|
2022-07-15 23:18:17 -05:00
|
|
|
import { GetAssetThumbnailDto } from './dto/get-asset-thumbnail.dto';
|
2022-08-26 22:53:37 -07:00
|
|
|
import { AssetCountByTimeGroupResponseDto } from './response-dto/asset-count-by-time-group-response.dto';
|
|
|
|
|
import { GetAssetCountByTimeGroupDto } from './dto/get-asset-count-by-time-group.dto';
|
2022-02-03 10:06:44 -06:00
|
|
|
|
|
|
|
|
@UseGuards(JwtAuthGuard)
|
2022-07-08 21:26:50 -05:00
|
|
|
@ApiBearerAuth()
|
|
|
|
|
@ApiTags('Asset')
|
2022-02-03 10:06:44 -06:00
|
|
|
@Controller('asset')
|
|
|
|
|
export class AssetController {
|
|
|
|
|
constructor(
|
2022-03-22 01:22:04 -05:00
|
|
|
private wsCommunicateionGateway: CommunicationGateway,
|
2022-02-10 20:40:11 -06:00
|
|
|
private assetService: AssetService,
|
|
|
|
|
private backgroundTaskService: BackgroundTaskService,
|
2022-06-11 16:12:06 -05:00
|
|
|
|
2022-07-02 21:06:36 -05:00
|
|
|
@InjectQueue(assetUploadedQueueName)
|
|
|
|
|
private assetUploadedQueue: Queue<IAssetUploadedJob>,
|
2022-06-11 16:12:06 -05:00
|
|
|
) {}
|
2022-02-03 10:06:44 -06:00
|
|
|
|
|
|
|
|
@Post('upload')
|
2022-07-10 21:41:45 -05:00
|
|
|
@UseInterceptors(FileInterceptor('assetData', assetUploadOption))
|
|
|
|
|
@ApiConsumes('multipart/form-data')
|
|
|
|
|
@ApiBody({
|
|
|
|
|
description: 'Asset Upload Information',
|
|
|
|
|
type: AssetFileUploadDto,
|
|
|
|
|
})
|
2022-02-03 10:06:44 -06:00
|
|
|
async uploadFile(
|
2022-06-25 19:53:06 +02:00
|
|
|
@GetAuthUser() authUser: AuthUserDto,
|
2022-07-10 21:41:45 -05:00
|
|
|
@UploadedFile() file: Express.Multer.File,
|
2022-02-03 10:06:44 -06:00
|
|
|
@Body(ValidationPipe) assetInfo: CreateAssetDto,
|
2022-07-10 21:41:45 -05:00
|
|
|
): Promise<AssetFileUploadResponseDto> {
|
|
|
|
|
try {
|
|
|
|
|
const savedAsset = await this.assetService.createUserAsset(authUser, assetInfo, file.path, file.mimetype);
|
|
|
|
|
if (!savedAsset) {
|
|
|
|
|
throw new BadRequestException('Asset not created');
|
2022-03-27 15:47:49 -05:00
|
|
|
}
|
2022-02-03 10:06:44 -06:00
|
|
|
|
2022-07-10 21:41:45 -05:00
|
|
|
await this.assetUploadedQueue.add(
|
|
|
|
|
assetUploadedProcessorName,
|
|
|
|
|
{ asset: savedAsset, fileName: file.originalname, fileSize: file.size },
|
|
|
|
|
{ jobId: savedAsset.id },
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return new AssetFileUploadResponseDto(savedAsset.id);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
Logger.error(`Error uploading file ${e}`);
|
|
|
|
|
throw new BadRequestException(`Error uploading file`, `${e}`);
|
|
|
|
|
}
|
2022-02-03 10:06:44 -06:00
|
|
|
}
|
|
|
|
|
|
2022-04-02 12:31:53 -05:00
|
|
|
@Get('/download')
|
|
|
|
|
async downloadFile(
|
|
|
|
|
@GetAuthUser() authUser: AuthUserDto,
|
|
|
|
|
@Response({ passthrough: true }) res: Res,
|
2022-07-10 21:41:45 -05:00
|
|
|
@Query(new ValidationPipe({ transform: true })) query: ServeFileDto,
|
|
|
|
|
): Promise<any> {
|
2022-04-23 21:08:45 -05:00
|
|
|
return this.assetService.downloadFile(query, res);
|
2022-04-02 12:31:53 -05:00
|
|
|
}
|
|
|
|
|
|
2022-02-03 10:06:44 -06:00
|
|
|
@Get('/file')
|
|
|
|
|
async serveFile(
|
2022-06-25 19:53:06 +02:00
|
|
|
@Headers() headers: Record<string, string>,
|
2022-02-03 10:06:44 -06:00
|
|
|
@GetAuthUser() authUser: AuthUserDto,
|
2022-02-06 00:07:56 -06:00
|
|
|
@Response({ passthrough: true }) res: Res,
|
2022-07-10 21:41:45 -05:00
|
|
|
@Query(new ValidationPipe({ transform: true })) query: ServeFileDto,
|
|
|
|
|
): Promise<any> {
|
2022-02-13 15:10:42 -06:00
|
|
|
return this.assetService.serveFile(authUser, query, res, headers);
|
2022-02-03 10:06:44 -06:00
|
|
|
}
|
|
|
|
|
|
2022-04-23 21:08:45 -05:00
|
|
|
@Get('/thumbnail/:assetId')
|
2022-07-15 23:18:17 -05:00
|
|
|
async getAssetThumbnail(
|
|
|
|
|
@Param('assetId') assetId: string,
|
|
|
|
|
@Query(new ValidationPipe({ transform: true })) query: GetAssetThumbnailDto,
|
|
|
|
|
): Promise<any> {
|
|
|
|
|
return this.assetService.getAssetThumbnail(assetId, query);
|
2022-04-23 21:08:45 -05:00
|
|
|
}
|
|
|
|
|
|
2022-08-26 22:53:37 -07:00
|
|
|
@Get('/curated-objects')
|
2022-07-08 21:26:50 -05:00
|
|
|
async getCuratedObjects(@GetAuthUser() authUser: AuthUserDto): Promise<CuratedObjectsResponseDto[]> {
|
2022-03-27 14:58:54 -05:00
|
|
|
return this.assetService.getCuratedObject(authUser);
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-26 22:53:37 -07:00
|
|
|
@Get('/curated-locations')
|
2022-07-08 21:26:50 -05:00
|
|
|
async getCuratedLocations(@GetAuthUser() authUser: AuthUserDto): Promise<CuratedLocationsResponseDto[]> {
|
2022-03-16 10:19:31 -05:00
|
|
|
return this.assetService.getCuratedLocation(authUser);
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-26 22:53:37 -07:00
|
|
|
@Get('/search-terms')
|
2022-07-13 07:23:48 -05:00
|
|
|
async getAssetSearchTerms(@GetAuthUser() authUser: AuthUserDto): Promise<string[]> {
|
2022-02-27 12:43:29 -06:00
|
|
|
return this.assetService.getAssetSearchTerm(authUser);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-02 16:44:24 -06:00
|
|
|
@Post('/search')
|
2022-07-08 21:26:50 -05:00
|
|
|
async searchAsset(
|
|
|
|
|
@GetAuthUser() authUser: AuthUserDto,
|
|
|
|
|
@Body(ValidationPipe) searchAssetDto: SearchAssetDto,
|
|
|
|
|
): Promise<AssetResponseDto[]> {
|
2022-03-02 16:44:24 -06:00
|
|
|
return this.assetService.searchAsset(authUser, searchAssetDto);
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-26 22:53:37 -07:00
|
|
|
@Get('/count-by-date')
|
|
|
|
|
async getAssetCountByTimeGroup(
|
|
|
|
|
@GetAuthUser() authUser: AuthUserDto,
|
|
|
|
|
@Body(ValidationPipe) getAssetCountByTimeGroupDto: GetAssetCountByTimeGroupDto,
|
|
|
|
|
): Promise<AssetCountByTimeGroupResponseDto> {
|
|
|
|
|
return this.assetService.getAssetCountByTimeGroup(authUser, getAssetCountByTimeGroupDto);
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-08 21:26:50 -05:00
|
|
|
/**
|
|
|
|
|
* Get all AssetEntity belong to the user
|
|
|
|
|
*/
|
2022-02-13 15:10:42 -06:00
|
|
|
@Get('/')
|
2022-07-08 21:26:50 -05:00
|
|
|
async getAllAssets(@GetAuthUser() authUser: AuthUserDto): Promise<AssetResponseDto[]> {
|
2022-06-03 11:04:30 -05:00
|
|
|
return await this.assetService.getAllAssets(authUser);
|
2022-02-13 15:10:42 -06:00
|
|
|
}
|
|
|
|
|
|
2022-07-08 21:26:50 -05:00
|
|
|
/**
|
|
|
|
|
* Get all asset of a device that are in the database, ID only.
|
|
|
|
|
*/
|
2022-02-03 10:06:44 -06:00
|
|
|
@Get('/:deviceId')
|
|
|
|
|
async getUserAssetsByDeviceId(@GetAuthUser() authUser: AuthUserDto, @Param('deviceId') deviceId: string) {
|
|
|
|
|
return await this.assetService.getUserAssetsByDeviceId(authUser, deviceId);
|
|
|
|
|
}
|
2022-02-10 20:40:11 -06:00
|
|
|
|
2022-07-08 21:26:50 -05:00
|
|
|
/**
|
|
|
|
|
* Get a single asset's information
|
|
|
|
|
*/
|
2022-02-10 20:40:11 -06:00
|
|
|
@Get('/assetById/:assetId')
|
2022-07-08 21:26:50 -05:00
|
|
|
async getAssetById(
|
|
|
|
|
@GetAuthUser() authUser: AuthUserDto,
|
|
|
|
|
@Param('assetId') assetId: string,
|
|
|
|
|
): Promise<AssetResponseDto> {
|
2022-04-03 12:31:45 -05:00
|
|
|
return await this.assetService.getAssetById(authUser, assetId);
|
2022-02-10 20:40:11 -06:00
|
|
|
}
|
2022-02-13 15:10:42 -06:00
|
|
|
|
|
|
|
|
@Delete('/')
|
2022-07-13 07:23:48 -05:00
|
|
|
async deleteAsset(
|
|
|
|
|
@GetAuthUser() authUser: AuthUserDto,
|
|
|
|
|
@Body(ValidationPipe) assetIds: DeleteAssetDto,
|
|
|
|
|
): Promise<DeleteAssetResponseDto[]> {
|
2022-07-08 21:26:50 -05:00
|
|
|
const deleteAssetList: AssetResponseDto[] = [];
|
2022-02-13 15:10:42 -06:00
|
|
|
|
2022-03-23 14:53:45 -05:00
|
|
|
for (const id of assetIds.ids) {
|
2022-02-13 15:10:42 -06:00
|
|
|
const assets = await this.assetService.getAssetById(authUser, id);
|
2022-06-25 19:53:06 +02:00
|
|
|
if (!assets) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2022-02-13 15:10:42 -06:00
|
|
|
deleteAssetList.push(assets);
|
2022-03-23 14:53:45 -05:00
|
|
|
}
|
2022-02-13 15:10:42 -06:00
|
|
|
|
|
|
|
|
const result = await this.assetService.deleteAssetById(authUser, assetIds);
|
|
|
|
|
|
|
|
|
|
result.forEach((res) => {
|
2022-07-13 07:23:48 -05:00
|
|
|
deleteAssetList.filter((a) => a.id == res.id && res.status == DeleteAssetStatusEnum.SUCCESS);
|
2022-02-13 15:10:42 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await this.backgroundTaskService.deleteFileOnDisk(deleteAssetList);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2022-06-19 08:16:35 -05:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check duplicated asset before uploading - for Web upload used
|
|
|
|
|
*/
|
|
|
|
|
@Post('/check')
|
|
|
|
|
@HttpCode(200)
|
|
|
|
|
async checkDuplicateAsset(
|
|
|
|
|
@GetAuthUser() authUser: AuthUserDto,
|
2022-07-06 16:12:55 -05:00
|
|
|
@Body(ValidationPipe) checkDuplicateAssetDto: CheckDuplicateAssetDto,
|
2022-07-10 21:41:45 -05:00
|
|
|
): Promise<CheckDuplicateAssetResponseDto> {
|
2022-07-26 20:53:25 -05:00
|
|
|
return await this.assetService.checkDuplicatedAsset(authUser, checkDuplicateAssetDto);
|
2022-06-19 08:16:35 -05:00
|
|
|
}
|
2022-02-03 10:06:44 -06:00
|
|
|
}
|