mirror of
https://github.com/immich-app/immich.git
synced 2025-01-28 00:59:18 -05:00
feat(server): server-side checking of duplicate import paths and exclusion patterns (#6993)
validate path and pattern
This commit is contained in:
parent
2ee9044b6a
commit
954c1c2ef4
2 changed files with 57 additions and 3 deletions
|
@ -98,6 +98,36 @@ describe(`${LibraryController.name} (e2e)`, () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not create an external library with duplicate import paths', async () => {
|
||||||
|
const { status, body } = await request(server)
|
||||||
|
.post('/library')
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||||
|
.send({
|
||||||
|
type: LibraryType.EXTERNAL,
|
||||||
|
name: 'My Awesome Library',
|
||||||
|
importPaths: ['/path', '/path'],
|
||||||
|
exclusionPatterns: ['**/Raw/**'],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body).toEqual(errorStub.badRequest(["All importPaths's elements must be unique"]));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not create an external library with duplicate exclusion patterns', async () => {
|
||||||
|
const { status, body } = await request(server)
|
||||||
|
.post('/library')
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||||
|
.send({
|
||||||
|
type: LibraryType.EXTERNAL,
|
||||||
|
name: 'My Awesome Library',
|
||||||
|
importPaths: ['/path/to/import'],
|
||||||
|
exclusionPatterns: ['**/Raw/**', '**/Raw/**'],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body).toEqual(errorStub.badRequest(["All exclusionPatterns's elements must be unique"]));
|
||||||
|
});
|
||||||
|
|
||||||
it('should create an upload library with defaults', async () => {
|
it('should create an upload library with defaults', async () => {
|
||||||
const { status, body } = await request(server)
|
const { status, body } = await request(server)
|
||||||
.post('/library')
|
.post('/library')
|
||||||
|
@ -229,7 +259,7 @@ describe(`${LibraryController.name} (e2e)`, () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not allow an empty import path', async () => {
|
it('should reject an empty import path', async () => {
|
||||||
const { status, body } = await request(server)
|
const { status, body } = await request(server)
|
||||||
.put(`/library/${library.id}`)
|
.put(`/library/${library.id}`)
|
||||||
.set('Authorization', `Bearer ${admin.accessToken}`)
|
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||||
|
@ -239,6 +269,16 @@ describe(`${LibraryController.name} (e2e)`, () => {
|
||||||
expect(body).toEqual(errorStub.badRequest(['each value in importPaths should not be empty']));
|
expect(body).toEqual(errorStub.badRequest(['each value in importPaths should not be empty']));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should reject duplicate import paths', async () => {
|
||||||
|
const { status, body } = await request(server)
|
||||||
|
.put(`/library/${library.id}`)
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||||
|
.send({ importPaths: ['/path', '/path'] });
|
||||||
|
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body).toEqual(errorStub.badRequest(["All importPaths's elements must be unique"]));
|
||||||
|
});
|
||||||
|
|
||||||
it('should change the exclusion pattern', async () => {
|
it('should change the exclusion pattern', async () => {
|
||||||
const { status, body } = await request(server)
|
const { status, body } = await request(server)
|
||||||
.put(`/library/${library.id}`)
|
.put(`/library/${library.id}`)
|
||||||
|
@ -253,7 +293,17 @@ describe(`${LibraryController.name} (e2e)`, () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not allow an empty exclusion pattern', async () => {
|
it('should reject duplicate exclusion patterns', async () => {
|
||||||
|
const { status, body } = await request(server)
|
||||||
|
.put(`/library/${library.id}`)
|
||||||
|
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||||
|
.send({ exclusionPatterns: ['**/*.jpg', '**/*.jpg'] });
|
||||||
|
|
||||||
|
expect(status).toBe(400);
|
||||||
|
expect(body).toEqual(errorStub.badRequest(["All exclusionPatterns's elements must be unique"]));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reject an empty exclusion pattern', async () => {
|
||||||
const { status, body } = await request(server)
|
const { status, body } = await request(server)
|
||||||
.put(`/library/${library.id}`)
|
.put(`/library/${library.id}`)
|
||||||
.set('Authorization', `Bearer ${admin.accessToken}`)
|
.set('Authorization', `Bearer ${admin.accessToken}`)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { LibraryEntity, LibraryType } from '@app/infra/entities';
|
import { LibraryEntity, LibraryType } from '@app/infra/entities';
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
import { IsBoolean, IsEnum, IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
import { ArrayUnique, IsBoolean, IsEnum, IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
||||||
import { ValidateUUID } from '../domain.util';
|
import { ValidateUUID } from '../domain.util';
|
||||||
|
|
||||||
export class CreateLibraryDto {
|
export class CreateLibraryDto {
|
||||||
|
@ -20,11 +20,13 @@ export class CreateLibraryDto {
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString({ each: true })
|
@IsString({ each: true })
|
||||||
@IsNotEmpty({ each: true })
|
@IsNotEmpty({ each: true })
|
||||||
|
@ArrayUnique()
|
||||||
importPaths?: string[];
|
importPaths?: string[];
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString({ each: true })
|
@IsString({ each: true })
|
||||||
@IsNotEmpty({ each: true })
|
@IsNotEmpty({ each: true })
|
||||||
|
@ArrayUnique()
|
||||||
exclusionPatterns?: string[];
|
exclusionPatterns?: string[];
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
@ -45,11 +47,13 @@ export class UpdateLibraryDto {
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString({ each: true })
|
@IsString({ each: true })
|
||||||
@IsNotEmpty({ each: true })
|
@IsNotEmpty({ each: true })
|
||||||
|
@ArrayUnique()
|
||||||
importPaths?: string[];
|
importPaths?: string[];
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsNotEmpty({ each: true })
|
@IsNotEmpty({ each: true })
|
||||||
@IsString({ each: true })
|
@IsString({ each: true })
|
||||||
|
@ArrayUnique()
|
||||||
exclusionPatterns?: string[];
|
exclusionPatterns?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue