From fe1e09e51f565b0e521862b5f3e18a8b5b1f588a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=BCndig?= Date: Tue, 28 Jan 2025 04:54:29 +0100 Subject: [PATCH] fix(server): Allow negative rating (for rejected images) (#15699) Allow negative rating (for rejected images) --- e2e/src/api/specs/asset.e2e-spec.ts | 14 ++++++++++++++ .../lib/model/asset_bulk_update_dto.dart | Bin 7571 -> 7572 bytes .../openapi/lib/model/update_asset_dto.dart | Bin 7983 -> 7984 bytes open-api/immich-openapi-specs.json | 4 ++-- server/src/dtos/asset.dto.ts | 2 +- server/src/services/metadata.service.spec.ts | 11 +++++++++++ server/src/services/metadata.service.ts | 2 +- 7 files changed, 29 insertions(+), 4 deletions(-) diff --git a/e2e/src/api/specs/asset.e2e-spec.ts b/e2e/src/api/specs/asset.e2e-spec.ts index 32cbdd6df..1b644454a 100644 --- a/e2e/src/api/specs/asset.e2e-spec.ts +++ b/e2e/src/api/specs/asset.e2e-spec.ts @@ -701,6 +701,20 @@ describe('/asset', () => { expect(status).toEqual(200); }); + it('should set the negative rating', async () => { + const { status, body } = await request(app) + .put(`/assets/${user1Assets[0].id}`) + .set('Authorization', `Bearer ${user1.accessToken}`) + .send({ rating: -1 }); + expect(body).toMatchObject({ + id: user1Assets[0].id, + exifInfo: expect.objectContaining({ + rating: -1, + }), + }); + expect(status).toEqual(200); + }); + it('should reject invalid rating', async () => { for (const test of [{ rating: 7 }, { rating: 3.5 }, { rating: null }]) { const { status, body } = await request(app) diff --git a/mobile/openapi/lib/model/asset_bulk_update_dto.dart b/mobile/openapi/lib/model/asset_bulk_update_dto.dart index da23d2f09d2e057484e7a823db94eed4241862b7..0b5a2c30d913bdf7bc161496704d916485633328 100644 GIT binary patch delta 15 XcmbPiJ;i#%4o)Ur!_7N6ZwUhcFZBh{ delta 14 WcmbPYJ=uE04o*gc&AT{n2?GEtq6MP> diff --git a/mobile/openapi/lib/model/update_asset_dto.dart b/mobile/openapi/lib/model/update_asset_dto.dart index 9ebce5fd9232b4688afc579acc67610423a259a4..c6ae6d8e07d3ddbdd7a59ba3d3a5416d838c3109 100644 GIT binary patch delta 15 WcmZ2)x4~|MFgKH~;bswTX%PS@=mZM@ delta 14 VcmdmBx881pFgK&YW>Icw5db9m1Kj`s diff --git a/open-api/immich-openapi-specs.json b/open-api/immich-openapi-specs.json index fc62b5829..3067b2544 100644 --- a/open-api/immich-openapi-specs.json +++ b/open-api/immich-openapi-specs.json @@ -7951,7 +7951,7 @@ }, "rating": { "maximum": 5, - "minimum": 0, + "minimum": -1, "type": "number" } }, @@ -12780,7 +12780,7 @@ }, "rating": { "maximum": 5, - "minimum": 0, + "minimum": -1, "type": "number" } }, diff --git a/server/src/dtos/asset.dto.ts b/server/src/dtos/asset.dto.ts index 42d6d7d74..8aa63f2f6 100644 --- a/server/src/dtos/asset.dto.ts +++ b/server/src/dtos/asset.dto.ts @@ -52,7 +52,7 @@ export class UpdateAssetBase { @Optional() @IsInt() @Max(5) - @Min(0) + @Min(-1) rating?: number; } diff --git a/server/src/services/metadata.service.spec.ts b/server/src/services/metadata.service.spec.ts index 8cc6e014d..99ca1e7ed 100644 --- a/server/src/services/metadata.service.spec.ts +++ b/server/src/services/metadata.service.spec.ts @@ -1162,6 +1162,17 @@ describe(MetadataService.name, () => { }), ); }); + it('should handle valid negative rating value', async () => { + assetMock.getByIds.mockResolvedValue([assetStub.image]); + mockReadTags({ Rating: -1 }); + + await sut.handleMetadataExtraction({ id: assetStub.image.id }); + expect(assetMock.upsertExif).toHaveBeenCalledWith( + expect.objectContaining({ + rating: -1, + }), + ); + }); }); describe('handleQueueSidecar', () => { diff --git a/server/src/services/metadata.service.ts b/server/src/services/metadata.service.ts index d5b7e6e4e..db3af9fca 100644 --- a/server/src/services/metadata.service.ts +++ b/server/src/services/metadata.service.ts @@ -204,7 +204,7 @@ export class MetadataService extends BaseService { // comments description: String(exifTags.ImageDescription || exifTags.Description || '').trim(), profileDescription: exifTags.ProfileDescription || null, - rating: validateRange(exifTags.Rating, 0, 5), + rating: validateRange(exifTags.Rating, -1, 5), // grouping livePhotoCID: (exifTags.ContentIdentifier || exifTags.MediaGroupUUID) ?? null,