Merge branch 'main' of https://github.com/immich-app/immich into feat/sidecar-asset-files

This commit is contained in:
Jonathan Jogenfors
2025-10-31 01:11:07 +01:00
3 changed files with 29 additions and 14 deletions

View File

@@ -57,6 +57,28 @@ describe(AssetController.name, () => {
}); });
}); });
describe('PUT /assets/copy', () => {
it('should be an authenticated route', async () => {
await request(ctx.getHttpServer()).get(`/assets/copy`);
expect(ctx.authenticate).toHaveBeenCalled();
});
it('should require target and source id', async () => {
const { status, body } = await request(ctx.getHttpServer()).put('/assets/copy').send({});
expect(status).toBe(400);
expect(body).toEqual(
factory.responses.badRequest(expect.arrayContaining(['sourceId must be a UUID', 'targetId must be a UUID'])),
);
});
it('should work', async () => {
const { status } = await request(ctx.getHttpServer())
.put('/assets/copy')
.send({ sourceId: factory.uuid(), targetId: factory.uuid() });
expect(status).toBe(204);
});
});
describe('PUT /assets/:id', () => { describe('PUT /assets/:id', () => {
it('should be an authenticated route', async () => { it('should be an authenticated route', async () => {
await request(ctx.getHttpServer()).get(`/assets/123`); await request(ctx.getHttpServer()).get(`/assets/123`);

View File

@@ -81,6 +81,13 @@ export class AssetController {
return this.service.get(auth, id) as Promise<AssetResponseDto>; return this.service.get(auth, id) as Promise<AssetResponseDto>;
} }
@Put('copy')
@Authenticated({ permission: Permission.AssetCopy })
@HttpCode(HttpStatus.NO_CONTENT)
copyAsset(@Auth() auth: AuthDto, @Body() dto: AssetCopyDto): Promise<void> {
return this.service.copy(auth, dto);
}
@Put(':id') @Put(':id')
@Authenticated({ permission: Permission.AssetUpdate }) @Authenticated({ permission: Permission.AssetUpdate })
updateAsset( updateAsset(
@@ -91,13 +98,6 @@ export class AssetController {
return this.service.update(auth, id, dto); return this.service.update(auth, id, dto);
} }
@Put('copy')
@Authenticated({ permission: Permission.AssetCopy })
@HttpCode(HttpStatus.NO_CONTENT)
copyAsset(@Auth() auth: AuthDto, @Body() dto: AssetCopyDto): Promise<void> {
return this.service.copy(auth, dto);
}
@Get(':id/metadata') @Get(':id/metadata')
@Authenticated({ permission: Permission.AssetRead }) @Authenticated({ permission: Permission.AssetRead })
getAssetMetadata(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise<AssetMetadataResponseDto[]> { getAssetMetadata(@Auth() auth: AuthDto, @Param() { id }: UUIDParamDto): Promise<AssetMetadataResponseDto[]> {

View File

@@ -179,7 +179,6 @@ describe(AssetService.name, () => {
const { sut, ctx } = setup(); const { sut, ctx } = setup();
const storageRepo = ctx.getMock(StorageRepository); const storageRepo = ctx.getMock(StorageRepository);
const jobRepo = ctx.getMock(JobRepository); const jobRepo = ctx.getMock(JobRepository);
const assetRepo = ctx.getMock(AssetRepository);
storageRepo.copyFile.mockResolvedValue(); storageRepo.copyFile.mockResolvedValue();
jobRepo.queue.mockResolvedValue(); jobRepo.queue.mockResolvedValue();
@@ -207,12 +206,6 @@ describe(AssetService.name, () => {
expect(storageRepo.copyFile).toHaveBeenCalledWith('/path/to/my/sidecar.xmp', `${newAsset.originalPath}.xmp`); expect(storageRepo.copyFile).toHaveBeenCalledWith('/path/to/my/sidecar.xmp', `${newAsset.originalPath}.xmp`);
expect(assetRepo.upsertFile).toHaveBeenCalledWith({
assetId: newAsset.id,
path: `${newAsset.originalPath}.xmp`,
type: AssetFileType.Sidecar,
});
expect(jobRepo.queue).toHaveBeenCalledWith({ expect(jobRepo.queue).toHaveBeenCalledWith({
name: JobName.AssetExtractMetadata, name: JobName.AssetExtractMetadata,
data: { id: newAsset.id }, data: { id: newAsset.id },