mirror of
https://github.com/samsonjs/immich.git
synced 2026-04-27 15:07:45 +00:00
fix(server): enforce crop is the first action (#25547)
* fix(server): enforce crop is the first action * chore: test
This commit is contained in:
parent
6b2737bae3
commit
e04d316203
2 changed files with 35 additions and 8 deletions
|
|
@ -2,6 +2,7 @@ import { BadRequestException } from '@nestjs/common';
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { MapAsset } from 'src/dtos/asset-response.dto';
|
import { MapAsset } from 'src/dtos/asset-response.dto';
|
||||||
import { AssetJobName, AssetStatsResponseDto } from 'src/dtos/asset.dto';
|
import { AssetJobName, AssetStatsResponseDto } from 'src/dtos/asset.dto';
|
||||||
|
import { AssetEditAction } from 'src/dtos/editing.dto';
|
||||||
import { AssetMetadataKey, AssetStatus, AssetType, AssetVisibility, JobName, JobStatus } from 'src/enum';
|
import { AssetMetadataKey, AssetStatus, AssetType, AssetVisibility, JobName, JobStatus } from 'src/enum';
|
||||||
import { AssetStats } from 'src/repositories/asset.repository';
|
import { AssetStats } from 'src/repositories/asset.repository';
|
||||||
import { AssetService } from 'src/services/asset.service';
|
import { AssetService } from 'src/services/asset.service';
|
||||||
|
|
@ -813,4 +814,25 @@ describe(AssetService.name, () => {
|
||||||
expect(mocks.asset.upsertBulkMetadata).not.toHaveBeenCalled();
|
expect(mocks.asset.upsertBulkMetadata).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('editAsset', () => {
|
||||||
|
it('should enforce crop first', async () => {
|
||||||
|
await expect(
|
||||||
|
sut.editAsset(authStub.admin, 'asset-1', {
|
||||||
|
edits: [
|
||||||
|
{
|
||||||
|
action: AssetEditAction.Rotate,
|
||||||
|
parameters: { angle: 90 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: AssetEditAction.Crop,
|
||||||
|
parameters: { x: 0, y: 0, width: 100, height: 100 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
).rejects.toBeInstanceOf(BadRequestException);
|
||||||
|
|
||||||
|
expect(mocks.assetEdit.replaceAll).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import {
|
||||||
mapStats,
|
mapStats,
|
||||||
} from 'src/dtos/asset.dto';
|
} from 'src/dtos/asset.dto';
|
||||||
import { AuthDto } from 'src/dtos/auth.dto';
|
import { AuthDto } from 'src/dtos/auth.dto';
|
||||||
import { AssetEditAction, AssetEditActionListDto, AssetEditsDto } from 'src/dtos/editing.dto';
|
import { AssetEditAction, AssetEditActionCrop, AssetEditActionListDto, AssetEditsDto } from 'src/dtos/editing.dto';
|
||||||
import { AssetOcrResponseDto } from 'src/dtos/ocr.dto';
|
import { AssetOcrResponseDto } from 'src/dtos/ocr.dto';
|
||||||
import {
|
import {
|
||||||
AssetFileType,
|
AssetFileType,
|
||||||
|
|
@ -574,16 +574,21 @@ export class AssetService extends BaseService {
|
||||||
throw new BadRequestException('Editing SVG images is not supported');
|
throw new BadRequestException('Editing SVG images is not supported');
|
||||||
}
|
}
|
||||||
|
|
||||||
// check that crop parameters will not go out of bounds
|
const cropIndex = dto.edits.findIndex((e) => e.action === AssetEditAction.Crop);
|
||||||
const { width: assetWidth, height: assetHeight } = getDimensions(asset.exifInfo!);
|
if (cropIndex > 0) {
|
||||||
|
throw new BadRequestException('Crop action must be the first edit action');
|
||||||
if (!assetWidth || !assetHeight) {
|
|
||||||
throw new BadRequestException('Asset dimensions are not available for editing');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const crop = dto.edits.find((e) => e.action === AssetEditAction.Crop)?.parameters;
|
const crop = cropIndex === -1 ? null : (dto.edits[cropIndex] as AssetEditActionCrop);
|
||||||
if (crop) {
|
if (crop) {
|
||||||
const { x, y, width, height } = crop;
|
// check that crop parameters will not go out of bounds
|
||||||
|
const { width: assetWidth, height: assetHeight } = getDimensions(asset.exifInfo!);
|
||||||
|
|
||||||
|
if (!assetWidth || !assetHeight) {
|
||||||
|
throw new BadRequestException('Asset dimensions are not available for editing');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { x, y, width, height } = crop.parameters;
|
||||||
if (x + width > assetWidth || y + height > assetHeight) {
|
if (x + width > assetWidth || y + height > assetHeight) {
|
||||||
throw new BadRequestException('Crop parameters are out of bounds');
|
throw new BadRequestException('Crop parameters are out of bounds');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue