mirror of
https://github.com/immich-app/immich.git
synced 2025-12-27 09:14:55 +03:00
feat(web): add Exif-Rating (#11580)
* Add Exif-Rating * Integrate star rating as own component * Add e2e tests for rating and validation * Rename component and async handleChangeRating * Display rating can be enabled in app settings * Correct i18n reference Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com> * Star rating: change from slider to buttons * Star rating for clarity * Design updates. * Renaming and code optimization * chore: clean up * chore: e2e formatting * light mode border and default value --------- Co-authored-by: Christoph Suter <christoph@suter-burri.ch> Co-authored-by: Michel Heusschen <59014050+michelheusschen@users.noreply.github.com> Co-authored-by: Mert <101130780+mertalev@users.noreply.github.com> Co-authored-by: Jason Rasmussen <jrasm91@gmail.com> Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
@@ -228,6 +228,13 @@ describe(AssetService.name, () => {
|
||||
await sut.update(authStub.admin, 'asset-1', { description: 'Test description' });
|
||||
expect(assetMock.upsertExif).toHaveBeenCalledWith({ assetId: 'asset-1', description: 'Test description' });
|
||||
});
|
||||
|
||||
it('should update the exif rating', async () => {
|
||||
accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset-1']));
|
||||
assetMock.getById.mockResolvedValue(assetStub.image);
|
||||
await sut.update(authStub.admin, 'asset-1', { rating: 3 });
|
||||
expect(assetMock.upsertExif).toHaveBeenCalledWith({ assetId: 'asset-1', rating: 3 });
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateAll', () => {
|
||||
|
||||
@@ -158,8 +158,8 @@ export class AssetService {
|
||||
async update(auth: AuthDto, id: string, dto: UpdateAssetDto): Promise<AssetResponseDto> {
|
||||
await this.access.requirePermission(auth, Permission.ASSET_UPDATE, id);
|
||||
|
||||
const { description, dateTimeOriginal, latitude, longitude, ...rest } = dto;
|
||||
await this.updateMetadata({ id, description, dateTimeOriginal, latitude, longitude });
|
||||
const { description, dateTimeOriginal, latitude, longitude, rating, ...rest } = dto;
|
||||
await this.updateMetadata({ id, description, dateTimeOriginal, latitude, longitude, rating });
|
||||
|
||||
await this.assetRepository.update({ id, ...rest });
|
||||
const asset = await this.assetRepository.getById(id, {
|
||||
@@ -405,8 +405,8 @@ export class AssetService {
|
||||
}
|
||||
|
||||
private async updateMetadata(dto: ISidecarWriteJob) {
|
||||
const { id, description, dateTimeOriginal, latitude, longitude } = dto;
|
||||
const writes = _.omitBy({ description, dateTimeOriginal, latitude, longitude }, _.isUndefined);
|
||||
const { id, description, dateTimeOriginal, latitude, longitude, rating } = dto;
|
||||
const writes = _.omitBy({ description, dateTimeOriginal, latitude, longitude, rating }, _.isUndefined);
|
||||
if (Object.keys(writes).length > 0) {
|
||||
await this.assetRepository.upsertExif({ assetId: id, ...writes });
|
||||
await this.jobRepository.queue({ name: JobName.SIDECAR_WRITE, data: { id, ...writes } });
|
||||
|
||||
@@ -606,6 +606,7 @@ describe(MetadataService.name, () => {
|
||||
ProfileDescription: 'extensive description',
|
||||
ProjectionType: 'equirectangular',
|
||||
tz: '+02:00',
|
||||
Rating: 3,
|
||||
};
|
||||
assetMock.getByIds.mockResolvedValue([assetStub.image]);
|
||||
metadataMock.readTags.mockResolvedValue(tags);
|
||||
@@ -638,6 +639,7 @@ describe(MetadataService.name, () => {
|
||||
profileDescription: tags.ProfileDescription,
|
||||
projectionType: 'EQUIRECTANGULAR',
|
||||
timeZone: tags.tz,
|
||||
rating: tags.Rating,
|
||||
});
|
||||
expect(assetMock.update).toHaveBeenCalledWith({
|
||||
id: assetStub.image.id,
|
||||
|
||||
@@ -273,7 +273,7 @@ export class MetadataService implements OnEvents {
|
||||
}
|
||||
|
||||
async handleSidecarWrite(job: ISidecarWriteJob): Promise<JobStatus> {
|
||||
const { id, description, dateTimeOriginal, latitude, longitude } = job;
|
||||
const { id, description, dateTimeOriginal, latitude, longitude, rating } = job;
|
||||
const [asset] = await this.assetRepository.getByIds([id]);
|
||||
if (!asset) {
|
||||
return JobStatus.FAILED;
|
||||
@@ -287,6 +287,7 @@ export class MetadataService implements OnEvents {
|
||||
DateTimeOriginal: dateTimeOriginal,
|
||||
GPSLatitude: latitude,
|
||||
GPSLongitude: longitude,
|
||||
Rating: rating,
|
||||
},
|
||||
_.isUndefined,
|
||||
);
|
||||
@@ -503,6 +504,7 @@ export class MetadataService implements OnEvents {
|
||||
profileDescription: tags.ProfileDescription || null,
|
||||
projectionType: tags.ProjectionType ? String(tags.ProjectionType).toUpperCase() : null,
|
||||
timeZone: tags.tz ?? null,
|
||||
rating: tags.Rating ?? null,
|
||||
};
|
||||
|
||||
if (exifData.latitude === 0 && exifData.longitude === 0) {
|
||||
|
||||
Reference in New Issue
Block a user