mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-03 19:17:11 -05:00 
			
		
		
		
	refactor: api validators (boolean and date) (#7709)
* refactor: api validators (boolean and date) * chore: open api * revert: time bucket change
This commit is contained in:
		
							parent
							
								
									753842745d
								
							
						
					
					
						commit
						a50f125dd1
					
				@ -66,8 +66,8 @@ class Asset {
 | 
			
		||||
      assetData: new File([await fs.openAsBlob(this.path)], basename(this.path)),
 | 
			
		||||
      deviceAssetId: this.deviceAssetId,
 | 
			
		||||
      deviceId: 'CLI',
 | 
			
		||||
      fileCreatedAt: this.fileCreatedAt,
 | 
			
		||||
      fileModifiedAt: this.fileModifiedAt,
 | 
			
		||||
      fileCreatedAt: this.fileCreatedAt.toISOString(),
 | 
			
		||||
      fileModifiedAt: this.fileModifiedAt.toISOString(),
 | 
			
		||||
      isFavorite: String(false),
 | 
			
		||||
    };
 | 
			
		||||
    const formData = new FormData();
 | 
			
		||||
 | 
			
		||||
@ -6,10 +6,9 @@ import request from 'supertest';
 | 
			
		||||
import { beforeAll, beforeEach, describe, expect, it } from 'vitest';
 | 
			
		||||
 | 
			
		||||
const invalidBirthday = [
 | 
			
		||||
  // TODO: enable after replacing `@Type(() => Date)`
 | 
			
		||||
  // { birthDate: 'false', response: 'Invalid date' },
 | 
			
		||||
  // { birthDate: '123567', response: 'Invalid date },
 | 
			
		||||
  // { birthDate: 123_567, response: ['Birth date cannot be in the future'] },
 | 
			
		||||
  { birthDate: 'false', response: 'birthDate must be a date string' },
 | 
			
		||||
  { birthDate: '123567', response: 'birthDate must be a date string' },
 | 
			
		||||
  { birthDate: 123_567, response: 'birthDate must be a date string' },
 | 
			
		||||
  { birthDate: new Date(9999, 0, 0).toISOString(), response: ['Birth date cannot be in the future'] },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@ -152,16 +151,16 @@ describe('/person', () => {
 | 
			
		||||
      expect(body).toEqual(errorDto.unauthorized);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    it('should not accept invalid birth dates', async () => {
 | 
			
		||||
    for (const { birthDate, response } of invalidBirthday) {
 | 
			
		||||
      it(`should not accept an invalid birth date [${birthDate}]`, async () => {
 | 
			
		||||
        const { status, body } = await request(app)
 | 
			
		||||
          .post(`/person`)
 | 
			
		||||
          .set('Authorization', `Bearer ${admin.accessToken}`)
 | 
			
		||||
          .send({ birthDate });
 | 
			
		||||
        expect(status).toBe(400);
 | 
			
		||||
        expect(body).toEqual(errorDto.badRequest(response));
 | 
			
		||||
      }
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    it('should create a person', async () => {
 | 
			
		||||
      const { status, body } = await request(app)
 | 
			
		||||
@ -202,16 +201,16 @@ describe('/person', () => {
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    it('should not accept invalid birth dates', async () => {
 | 
			
		||||
    for (const { birthDate, response } of invalidBirthday) {
 | 
			
		||||
      it(`should not accept an invalid birth date [${birthDate}]`, async () => {
 | 
			
		||||
        const { status, body } = await request(app)
 | 
			
		||||
          .put(`/person/${visiblePerson.id}`)
 | 
			
		||||
          .set('Authorization', `Bearer ${admin.accessToken}`)
 | 
			
		||||
          .send({ birthDate });
 | 
			
		||||
        expect(status).toBe(400);
 | 
			
		||||
        expect(body).toEqual(errorDto.badRequest(response));
 | 
			
		||||
      }
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    it('should update a date of birth', async () => {
 | 
			
		||||
      const { status, body } = await request(app)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								mobile/openapi/doc/PersonApi.md
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								mobile/openapi/doc/PersonApi.md
									
									
									
										generated
									
									
									
								
							@ -114,7 +114,7 @@ try {
 | 
			
		||||
 | 
			
		||||
Name | Type | Description  | Notes
 | 
			
		||||
------------- | ------------- | ------------- | -------------
 | 
			
		||||
 **withHidden** | **bool**|  | [optional] [default to false]
 | 
			
		||||
 **withHidden** | **bool**|  | [optional] 
 | 
			
		||||
 | 
			
		||||
### Return type
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								mobile/openapi/doc/ScanLibraryDto.md
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								mobile/openapi/doc/ScanLibraryDto.md
									
									
									
										generated
									
									
									
								
							@ -8,7 +8,7 @@ import 'package:openapi/api.dart';
 | 
			
		||||
## Properties
 | 
			
		||||
Name | Type | Description | Notes
 | 
			
		||||
------------ | ------------- | ------------- | -------------
 | 
			
		||||
**refreshAllFiles** | **bool** |  | [optional] [default to false]
 | 
			
		||||
**refreshAllFiles** | **bool** |  | [optional] 
 | 
			
		||||
**refreshModifiedFiles** | **bool** |  | [optional] 
 | 
			
		||||
 | 
			
		||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								mobile/openapi/doc/SharedLinkCreateDto.md
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								mobile/openapi/doc/SharedLinkCreateDto.md
									
									
									
										generated
									
									
									
								
							@ -10,7 +10,7 @@ Name | Type | Description | Notes
 | 
			
		||||
------------ | ------------- | ------------- | -------------
 | 
			
		||||
**albumId** | **String** |  | [optional] 
 | 
			
		||||
**allowDownload** | **bool** |  | [optional] [default to true]
 | 
			
		||||
**allowUpload** | **bool** |  | [optional] [default to false]
 | 
			
		||||
**allowUpload** | **bool** |  | [optional] 
 | 
			
		||||
**assetIds** | **List<String>** |  | [optional] [default to const []]
 | 
			
		||||
**description** | **String** |  | [optional] 
 | 
			
		||||
**expiresAt** | [**DateTime**](DateTime.md) |  | [optional] 
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										18
									
								
								mobile/openapi/lib/model/scan_library_dto.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										18
									
								
								mobile/openapi/lib/model/scan_library_dto.dart
									
									
									
										generated
									
									
									
								
							@ -13,11 +13,17 @@ part of openapi.api;
 | 
			
		||||
class ScanLibraryDto {
 | 
			
		||||
  /// Returns a new [ScanLibraryDto] instance.
 | 
			
		||||
  ScanLibraryDto({
 | 
			
		||||
    this.refreshAllFiles = false,
 | 
			
		||||
    this.refreshAllFiles,
 | 
			
		||||
    this.refreshModifiedFiles,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  bool refreshAllFiles;
 | 
			
		||||
  ///
 | 
			
		||||
  /// Please note: This property should have been non-nullable! Since the specification file
 | 
			
		||||
  /// does not include a default value (using the "default:" property), however, the generated
 | 
			
		||||
  /// source code must fall back to having a nullable type.
 | 
			
		||||
  /// Consider adding a "default:" property in the specification file to hide this note.
 | 
			
		||||
  ///
 | 
			
		||||
  bool? refreshAllFiles;
 | 
			
		||||
 | 
			
		||||
  ///
 | 
			
		||||
  /// Please note: This property should have been non-nullable! Since the specification file
 | 
			
		||||
@ -35,7 +41,7 @@ class ScanLibraryDto {
 | 
			
		||||
  @override
 | 
			
		||||
  int get hashCode =>
 | 
			
		||||
    // ignore: unnecessary_parenthesis
 | 
			
		||||
    (refreshAllFiles.hashCode) +
 | 
			
		||||
    (refreshAllFiles == null ? 0 : refreshAllFiles!.hashCode) +
 | 
			
		||||
    (refreshModifiedFiles == null ? 0 : refreshModifiedFiles!.hashCode);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
@ -43,7 +49,11 @@ class ScanLibraryDto {
 | 
			
		||||
 | 
			
		||||
  Map<String, dynamic> toJson() {
 | 
			
		||||
    final json = <String, dynamic>{};
 | 
			
		||||
    if (this.refreshAllFiles != null) {
 | 
			
		||||
      json[r'refreshAllFiles'] = this.refreshAllFiles;
 | 
			
		||||
    } else {
 | 
			
		||||
    //  json[r'refreshAllFiles'] = null;
 | 
			
		||||
    }
 | 
			
		||||
    if (this.refreshModifiedFiles != null) {
 | 
			
		||||
      json[r'refreshModifiedFiles'] = this.refreshModifiedFiles;
 | 
			
		||||
    } else {
 | 
			
		||||
@ -60,7 +70,7 @@ class ScanLibraryDto {
 | 
			
		||||
      final json = value.cast<String, dynamic>();
 | 
			
		||||
 | 
			
		||||
      return ScanLibraryDto(
 | 
			
		||||
        refreshAllFiles: mapValueOfType<bool>(json, r'refreshAllFiles') ?? false,
 | 
			
		||||
        refreshAllFiles: mapValueOfType<bool>(json, r'refreshAllFiles'),
 | 
			
		||||
        refreshModifiedFiles: mapValueOfType<bool>(json, r'refreshModifiedFiles'),
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										18
									
								
								mobile/openapi/lib/model/shared_link_create_dto.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										18
									
								
								mobile/openapi/lib/model/shared_link_create_dto.dart
									
									
									
										generated
									
									
									
								
							@ -15,7 +15,7 @@ class SharedLinkCreateDto {
 | 
			
		||||
  SharedLinkCreateDto({
 | 
			
		||||
    this.albumId,
 | 
			
		||||
    this.allowDownload = true,
 | 
			
		||||
    this.allowUpload = false,
 | 
			
		||||
    this.allowUpload,
 | 
			
		||||
    this.assetIds = const [],
 | 
			
		||||
    this.description,
 | 
			
		||||
    this.expiresAt,
 | 
			
		||||
@ -34,7 +34,13 @@ class SharedLinkCreateDto {
 | 
			
		||||
 | 
			
		||||
  bool allowDownload;
 | 
			
		||||
 | 
			
		||||
  bool allowUpload;
 | 
			
		||||
  ///
 | 
			
		||||
  /// Please note: This property should have been non-nullable! Since the specification file
 | 
			
		||||
  /// does not include a default value (using the "default:" property), however, the generated
 | 
			
		||||
  /// source code must fall back to having a nullable type.
 | 
			
		||||
  /// Consider adding a "default:" property in the specification file to hide this note.
 | 
			
		||||
  ///
 | 
			
		||||
  bool? allowUpload;
 | 
			
		||||
 | 
			
		||||
  List<String> assetIds;
 | 
			
		||||
 | 
			
		||||
@ -77,7 +83,7 @@ class SharedLinkCreateDto {
 | 
			
		||||
    // ignore: unnecessary_parenthesis
 | 
			
		||||
    (albumId == null ? 0 : albumId!.hashCode) +
 | 
			
		||||
    (allowDownload.hashCode) +
 | 
			
		||||
    (allowUpload.hashCode) +
 | 
			
		||||
    (allowUpload == null ? 0 : allowUpload!.hashCode) +
 | 
			
		||||
    (assetIds.hashCode) +
 | 
			
		||||
    (description == null ? 0 : description!.hashCode) +
 | 
			
		||||
    (expiresAt == null ? 0 : expiresAt!.hashCode) +
 | 
			
		||||
@ -96,7 +102,11 @@ class SharedLinkCreateDto {
 | 
			
		||||
    //  json[r'albumId'] = null;
 | 
			
		||||
    }
 | 
			
		||||
      json[r'allowDownload'] = this.allowDownload;
 | 
			
		||||
    if (this.allowUpload != null) {
 | 
			
		||||
      json[r'allowUpload'] = this.allowUpload;
 | 
			
		||||
    } else {
 | 
			
		||||
    //  json[r'allowUpload'] = null;
 | 
			
		||||
    }
 | 
			
		||||
      json[r'assetIds'] = this.assetIds;
 | 
			
		||||
    if (this.description != null) {
 | 
			
		||||
      json[r'description'] = this.description;
 | 
			
		||||
@ -128,7 +138,7 @@ class SharedLinkCreateDto {
 | 
			
		||||
      return SharedLinkCreateDto(
 | 
			
		||||
        albumId: mapValueOfType<String>(json, r'albumId'),
 | 
			
		||||
        allowDownload: mapValueOfType<bool>(json, r'allowDownload') ?? true,
 | 
			
		||||
        allowUpload: mapValueOfType<bool>(json, r'allowUpload') ?? false,
 | 
			
		||||
        allowUpload: mapValueOfType<bool>(json, r'allowUpload'),
 | 
			
		||||
        assetIds: json[r'assetIds'] is Iterable
 | 
			
		||||
            ? (json[r'assetIds'] as Iterable).cast<String>().toList(growable: false)
 | 
			
		||||
            : const [],
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								mobile/openapi/test/scan_library_dto_test.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								mobile/openapi/test/scan_library_dto_test.dart
									
									
									
										generated
									
									
									
								
							@ -16,7 +16,7 @@ void main() {
 | 
			
		||||
  // final instance = ScanLibraryDto();
 | 
			
		||||
 | 
			
		||||
  group('test ScanLibraryDto', () {
 | 
			
		||||
    // bool refreshAllFiles (default value: false)
 | 
			
		||||
    // bool refreshAllFiles
 | 
			
		||||
    test('to test the property `refreshAllFiles`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
@ -26,7 +26,7 @@ void main() {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // bool allowUpload (default value: false)
 | 
			
		||||
    // bool allowUpload
 | 
			
		||||
    test('to test the property `allowUpload`', () async {
 | 
			
		||||
      // TODO
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
@ -4012,7 +4012,6 @@
 | 
			
		||||
            "required": false,
 | 
			
		||||
            "in": "query",
 | 
			
		||||
            "schema": {
 | 
			
		||||
              "default": false,
 | 
			
		||||
              "type": "boolean"
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
@ -8937,7 +8936,6 @@
 | 
			
		||||
      "ScanLibraryDto": {
 | 
			
		||||
        "properties": {
 | 
			
		||||
          "refreshAllFiles": {
 | 
			
		||||
            "default": false,
 | 
			
		||||
            "type": "boolean"
 | 
			
		||||
          },
 | 
			
		||||
          "refreshModifiedFiles": {
 | 
			
		||||
@ -9346,7 +9344,6 @@
 | 
			
		||||
            "type": "boolean"
 | 
			
		||||
          },
 | 
			
		||||
          "allowUpload": {
 | 
			
		||||
            "default": false,
 | 
			
		||||
            "type": "boolean"
 | 
			
		||||
          },
 | 
			
		||||
          "assetIds": {
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import { IsBoolean, IsString } from 'class-validator';
 | 
			
		||||
import { Optional, ValidateUUID } from '../../domain.util';
 | 
			
		||||
import { IsString } from 'class-validator';
 | 
			
		||||
import { Optional, ValidateBoolean, ValidateUUID } from '../../domain.util';
 | 
			
		||||
 | 
			
		||||
export class UpdateAlbumDto {
 | 
			
		||||
  @Optional()
 | 
			
		||||
@ -13,7 +13,6 @@ export class UpdateAlbumDto {
 | 
			
		||||
  @ValidateUUID({ optional: true })
 | 
			
		||||
  albumThumbnailAssetId?: string;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isActivityEnabled?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,6 @@
 | 
			
		||||
import { Transform } from 'class-transformer';
 | 
			
		||||
import { IsBoolean } from 'class-validator';
 | 
			
		||||
import { Optional, toBoolean } from '../../domain.util';
 | 
			
		||||
import { ValidateBoolean } from '../../domain.util';
 | 
			
		||||
 | 
			
		||||
export class AlbumInfoDto {
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  withoutAssets?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,13 +1,7 @@
 | 
			
		||||
import { ApiProperty } from '@nestjs/swagger';
 | 
			
		||||
import { Transform } from 'class-transformer';
 | 
			
		||||
import { IsBoolean } from 'class-validator';
 | 
			
		||||
import { Optional, toBoolean, ValidateUUID } from '../../domain.util';
 | 
			
		||||
import { ValidateBoolean, ValidateUUID } from '../../domain.util';
 | 
			
		||||
 | 
			
		||||
export class GetAlbumsDto {
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @ApiProperty()
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  /**
 | 
			
		||||
   * true: only shared albums
 | 
			
		||||
   * false: only non-shared own albums
 | 
			
		||||
 | 
			
		||||
@ -1,24 +1,16 @@
 | 
			
		||||
import { AssetType } from '@app/infra/entities';
 | 
			
		||||
import { ApiProperty } from '@nestjs/swagger';
 | 
			
		||||
import { Transform } from 'class-transformer';
 | 
			
		||||
import { IsBoolean } from 'class-validator';
 | 
			
		||||
import { Optional, toBoolean } from '../../domain.util';
 | 
			
		||||
import { ValidateBoolean } from '../../domain.util';
 | 
			
		||||
import { AssetStats } from '../../repositories';
 | 
			
		||||
 | 
			
		||||
export class AssetStatsDto {
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isArchived?: boolean;
 | 
			
		||||
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isFavorite?: boolean;
 | 
			
		||||
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isTrashed?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
import { Type } from 'class-transformer';
 | 
			
		||||
import {
 | 
			
		||||
  IsBoolean,
 | 
			
		||||
  IsDateString,
 | 
			
		||||
  IsInt,
 | 
			
		||||
  IsLatitude,
 | 
			
		||||
@ -10,7 +9,7 @@ import {
 | 
			
		||||
  IsString,
 | 
			
		||||
  ValidateIf,
 | 
			
		||||
} from 'class-validator';
 | 
			
		||||
import { Optional, ValidateUUID } from '../../domain.util';
 | 
			
		||||
import { Optional, ValidateBoolean, ValidateUUID } from '../../domain.util';
 | 
			
		||||
import { BulkIdsDto } from '../response-dto';
 | 
			
		||||
 | 
			
		||||
export class DeviceIdDto {
 | 
			
		||||
@ -28,23 +27,13 @@ const hasGPS = (o: { latitude: undefined; longitude: undefined }) =>
 | 
			
		||||
  o.latitude !== undefined || o.longitude !== undefined;
 | 
			
		||||
const ValidateGPS = () => ValidateIf(hasGPS);
 | 
			
		||||
 | 
			
		||||
export class AssetBulkUpdateDto extends BulkIdsDto {
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
export class UpdateAssetBase {
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isFavorite?: boolean;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isArchived?: boolean;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @ValidateUUID()
 | 
			
		||||
  stackParentId?: string;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  removeParent?: boolean;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsDateString()
 | 
			
		||||
  dateTimeOriginal?: string;
 | 
			
		||||
@ -60,32 +49,21 @@ export class AssetBulkUpdateDto extends BulkIdsDto {
 | 
			
		||||
  longitude?: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class UpdateAssetDto {
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  isFavorite?: boolean;
 | 
			
		||||
export class AssetBulkUpdateDto extends UpdateAssetBase {
 | 
			
		||||
  @ValidateUUID({ each: true })
 | 
			
		||||
  ids!: string[];
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  isArchived?: boolean;
 | 
			
		||||
  @ValidateUUID({ optional: true })
 | 
			
		||||
  stackParentId?: string;
 | 
			
		||||
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  removeParent?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class UpdateAssetDto extends UpdateAssetBase {
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsString()
 | 
			
		||||
  description?: string;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsDateString()
 | 
			
		||||
  dateTimeOriginal?: string;
 | 
			
		||||
 | 
			
		||||
  @ValidateGPS()
 | 
			
		||||
  @IsLatitude()
 | 
			
		||||
  @IsNotEmpty()
 | 
			
		||||
  latitude?: number;
 | 
			
		||||
 | 
			
		||||
  @ValidateGPS()
 | 
			
		||||
  @IsLongitude()
 | 
			
		||||
  @IsNotEmpty()
 | 
			
		||||
  longitude?: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class RandomAssetsDto {
 | 
			
		||||
@ -97,7 +75,6 @@ export class RandomAssetsDto {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class AssetBulkDeleteDto extends BulkIdsDto {
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  force?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,34 +1,18 @@
 | 
			
		||||
import { ApiProperty } from '@nestjs/swagger';
 | 
			
		||||
import { Transform, Type } from 'class-transformer';
 | 
			
		||||
import { IsBoolean, IsDate } from 'class-validator';
 | 
			
		||||
import { Optional, toBoolean } from '../../domain.util';
 | 
			
		||||
import { ValidateBoolean, ValidateDate } from '../../domain.util';
 | 
			
		||||
 | 
			
		||||
export class MapMarkerDto {
 | 
			
		||||
  @ApiProperty()
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isArchived?: boolean;
 | 
			
		||||
 | 
			
		||||
  @ApiProperty()
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isFavorite?: boolean;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsDate()
 | 
			
		||||
  @Type(() => Date)
 | 
			
		||||
  @ValidateDate({ optional: true })
 | 
			
		||||
  fileCreatedAfter?: Date;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsDate()
 | 
			
		||||
  @Type(() => Date)
 | 
			
		||||
  @ValidateDate({ optional: true })
 | 
			
		||||
  fileCreatedBefore?: Date;
 | 
			
		||||
 | 
			
		||||
  @ApiProperty()
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  withPartners?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,6 @@
 | 
			
		||||
import { ApiProperty } from '@nestjs/swagger';
 | 
			
		||||
import { Transform } from 'class-transformer';
 | 
			
		||||
import { IsBoolean, IsEnum, IsNotEmpty, IsString } from 'class-validator';
 | 
			
		||||
import { Optional, ValidateUUID, toBoolean } from '../../domain.util';
 | 
			
		||||
import { IsEnum, IsNotEmpty, IsString } from 'class-validator';
 | 
			
		||||
import { ValidateBoolean, ValidateUUID } from '../../domain.util';
 | 
			
		||||
import { TimeBucketSize } from '../../repositories';
 | 
			
		||||
 | 
			
		||||
export class TimeBucketDto {
 | 
			
		||||
@ -19,34 +18,23 @@ export class TimeBucketDto {
 | 
			
		||||
  @ValidateUUID({ optional: true })
 | 
			
		||||
  personId?: string;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isArchived?: boolean;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isFavorite?: boolean;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isTrashed?: boolean;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  withStacked?: boolean;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  withPartners?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class TimeBucketAssetDto extends TimeBucketDto {
 | 
			
		||||
  @IsString()
 | 
			
		||||
  @IsNotEmpty()
 | 
			
		||||
  timeBucket!: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,14 +1,13 @@
 | 
			
		||||
import { AssetPathType, EntityType, PathType, PersonPathType, UserPathType } from '@app/infra/entities';
 | 
			
		||||
import { ApiProperty } from '@nestjs/swagger';
 | 
			
		||||
import { Type } from 'class-transformer';
 | 
			
		||||
import { IsArray, IsDate, IsEnum, IsString, IsUUID, ValidateNested } from 'class-validator';
 | 
			
		||||
import { Optional, ValidateUUID } from '../domain.util';
 | 
			
		||||
import { IsArray, IsEnum, IsString, IsUUID, ValidateNested } from 'class-validator';
 | 
			
		||||
import { Optional, ValidateDate, ValidateUUID } from '../domain.util';
 | 
			
		||||
 | 
			
		||||
const PathEnum = Object.values({ ...AssetPathType, ...PersonPathType, ...UserPathType });
 | 
			
		||||
 | 
			
		||||
export class AuditDeletesDto {
 | 
			
		||||
  @IsDate()
 | 
			
		||||
  @Type(() => Date)
 | 
			
		||||
  @ValidateDate()
 | 
			
		||||
  after!: Date;
 | 
			
		||||
 | 
			
		||||
  @ApiProperty({ enum: EntityType, enumName: 'EntityType' })
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import { ImmichLogger } from '@app/infra/logger';
 | 
			
		||||
import { applyDecorators } from '@nestjs/common';
 | 
			
		||||
import { BadRequestException, applyDecorators } from '@nestjs/common';
 | 
			
		||||
import { ApiProperty } from '@nestjs/swagger';
 | 
			
		||||
import { Transform, Type } from 'class-transformer';
 | 
			
		||||
import { Transform } from 'class-transformer';
 | 
			
		||||
import {
 | 
			
		||||
  IsArray,
 | 
			
		||||
  IsBoolean,
 | 
			
		||||
@ -12,6 +12,7 @@ import {
 | 
			
		||||
  IsUUID,
 | 
			
		||||
  ValidateIf,
 | 
			
		||||
  ValidationOptions,
 | 
			
		||||
  isDateString,
 | 
			
		||||
} from 'class-validator';
 | 
			
		||||
import { CronJob } from 'cron';
 | 
			
		||||
import _ from 'lodash';
 | 
			
		||||
@ -40,14 +41,10 @@ export interface OpenGraphTags {
 | 
			
		||||
  imageUrl?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type Options = {
 | 
			
		||||
  optional?: boolean;
 | 
			
		||||
  each?: boolean;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const isConnectionAborted = (error: Error | any) => error.code === 'ECONNABORTED';
 | 
			
		||||
 | 
			
		||||
export function ValidateUUID(options?: Options) {
 | 
			
		||||
type UUIDOptions = { optional?: boolean; each?: boolean };
 | 
			
		||||
export const ValidateUUID = (options?: UUIDOptions) => {
 | 
			
		||||
  const { optional, each } = { optional: false, each: false, ...options };
 | 
			
		||||
  return applyDecorators(
 | 
			
		||||
    IsUUID('4', { each }),
 | 
			
		||||
@ -55,8 +52,59 @@ export function ValidateUUID(options?: Options) {
 | 
			
		||||
    optional ? Optional() : IsNotEmpty(),
 | 
			
		||||
    each ? IsArray() : IsString(),
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
type DateOptions = { optional?: boolean; nullable?: boolean; format?: 'date' | 'date-time' };
 | 
			
		||||
export const ValidateDate = (options?: DateOptions) => {
 | 
			
		||||
  const { optional, nullable, format } = { optional: false, nullable: false, format: 'date-time', ...options };
 | 
			
		||||
 | 
			
		||||
  const decorators = [
 | 
			
		||||
    ApiProperty({ format }),
 | 
			
		||||
    IsDate(),
 | 
			
		||||
    optional ? Optional({ nullable: true }) : IsNotEmpty(),
 | 
			
		||||
    Transform(({ key, value }) => {
 | 
			
		||||
      if (value === null || value === undefined) {
 | 
			
		||||
        return value;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (!isDateString(value)) {
 | 
			
		||||
        throw new BadRequestException(`${key} must be a date string`);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return new Date(value as string);
 | 
			
		||||
    }),
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  if (optional) {
 | 
			
		||||
    decorators.push(Optional({ nullable }));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return applyDecorators(...decorators);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
type BooleanOptions = { optional?: boolean };
 | 
			
		||||
export const ValidateBoolean = (options?: BooleanOptions) => {
 | 
			
		||||
  const { optional } = { optional: false, ...options };
 | 
			
		||||
  const decorators = [
 | 
			
		||||
    // ApiProperty(),
 | 
			
		||||
    IsBoolean(),
 | 
			
		||||
    Transform(({ value }) => {
 | 
			
		||||
      if (value == 'true') {
 | 
			
		||||
        return true;
 | 
			
		||||
      } else if (value == 'false') {
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
      return value;
 | 
			
		||||
    }),
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  if (optional) {
 | 
			
		||||
    decorators.push(Optional());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return applyDecorators(...decorators);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function validateCronExpression(expression: string) {
 | 
			
		||||
  try {
 | 
			
		||||
    new CronJob(expression, () => {});
 | 
			
		||||
@ -67,34 +115,7 @@ export function validateCronExpression(expression: string) {
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IValue {
 | 
			
		||||
  value?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const QueryBoolean = ({ optional }: { optional?: boolean }) => {
 | 
			
		||||
  const decorators = [IsBoolean(), Transform(toBoolean)];
 | 
			
		||||
  if (optional) {
 | 
			
		||||
    decorators.push(Optional());
 | 
			
		||||
  }
 | 
			
		||||
  return applyDecorators(...decorators);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const QueryDate = ({ optional }: { optional?: boolean }) => {
 | 
			
		||||
  const decorators = [IsDate(), Type(() => Date)];
 | 
			
		||||
  if (optional) {
 | 
			
		||||
    decorators.push(Optional());
 | 
			
		||||
  }
 | 
			
		||||
  return applyDecorators(...decorators);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const toBoolean = ({ value }: IValue) => {
 | 
			
		||||
  if (value == 'true') {
 | 
			
		||||
    return true;
 | 
			
		||||
  } else if (value == 'false') {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  return value;
 | 
			
		||||
};
 | 
			
		||||
type IValue = { value: string };
 | 
			
		||||
 | 
			
		||||
export const toEmail = ({ value }: IValue) => value?.toLowerCase();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import { ApiProperty } from '@nestjs/swagger';
 | 
			
		||||
import { IsBoolean, IsEnum, IsNotEmpty } from 'class-validator';
 | 
			
		||||
import { Optional } from '../domain.util';
 | 
			
		||||
import { IsEnum, IsNotEmpty } from 'class-validator';
 | 
			
		||||
import { ValidateBoolean } from '../domain.util';
 | 
			
		||||
import { JobCommand, QueueName } from './job.constants';
 | 
			
		||||
 | 
			
		||||
export class JobIdParamDto {
 | 
			
		||||
@ -16,8 +16,7 @@ export class JobCommandDto {
 | 
			
		||||
  @ApiProperty({ type: 'string', enum: JobCommand, enumName: 'JobCommand' })
 | 
			
		||||
  command!: JobCommand;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  force!: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import { LibraryEntity, LibraryType } from '@app/infra/entities';
 | 
			
		||||
import { ApiProperty } from '@nestjs/swagger';
 | 
			
		||||
import { ArrayMaxSize, ArrayUnique, IsBoolean, IsEnum, IsNotEmpty, IsString } from 'class-validator';
 | 
			
		||||
import { Optional, ValidateUUID } from '../domain.util';
 | 
			
		||||
import { ArrayMaxSize, ArrayUnique, IsEnum, IsNotEmpty, IsString } from 'class-validator';
 | 
			
		||||
import { Optional, ValidateBoolean, ValidateUUID } from '../domain.util';
 | 
			
		||||
 | 
			
		||||
export class CreateLibraryDto {
 | 
			
		||||
  @IsEnum(LibraryType)
 | 
			
		||||
@ -16,8 +16,7 @@ export class CreateLibraryDto {
 | 
			
		||||
  @IsNotEmpty()
 | 
			
		||||
  name?: string;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isVisible?: boolean;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
@ -34,8 +33,7 @@ export class CreateLibraryDto {
 | 
			
		||||
  @ArrayMaxSize(128)
 | 
			
		||||
  exclusionPatterns?: string[];
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isWatched?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -45,8 +43,7 @@ export class UpdateLibraryDto {
 | 
			
		||||
  @IsNotEmpty()
 | 
			
		||||
  name?: string;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isVisible?: boolean;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
@ -102,13 +99,11 @@ export class LibrarySearchDto {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class ScanLibraryDto {
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  refreshModifiedFiles?: boolean;
 | 
			
		||||
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Optional()
 | 
			
		||||
  refreshAllFiles?: boolean = false;
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  refreshAllFiles?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class SearchLibraryDto {
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,9 @@
 | 
			
		||||
import { AssetFaceEntity, PersonEntity } from '@app/infra/entities';
 | 
			
		||||
import { ApiProperty } from '@nestjs/swagger';
 | 
			
		||||
import { Transform, Type } from 'class-transformer';
 | 
			
		||||
import { IsArray, IsBoolean, IsDate, IsNotEmpty, IsString, MaxDate, ValidateNested } from 'class-validator';
 | 
			
		||||
import { Type } from 'class-transformer';
 | 
			
		||||
import { IsArray, IsNotEmpty, IsString, MaxDate, ValidateNested } from 'class-validator';
 | 
			
		||||
import { AuthDto } from '../auth';
 | 
			
		||||
import { Optional, ValidateUUID, toBoolean } from '../domain.util';
 | 
			
		||||
import { Optional, ValidateBoolean, ValidateDate, ValidateUUID } from '../domain.util';
 | 
			
		||||
 | 
			
		||||
export class PersonCreateDto {
 | 
			
		||||
  /**
 | 
			
		||||
@ -17,18 +17,14 @@ export class PersonCreateDto {
 | 
			
		||||
   * Person date of birth.
 | 
			
		||||
   * Note: the mobile app cannot currently set the birth date to null.
 | 
			
		||||
   */
 | 
			
		||||
  @Optional({ nullable: true })
 | 
			
		||||
  @IsDate()
 | 
			
		||||
  @Type(() => Date)
 | 
			
		||||
  @MaxDate(() => new Date(), { message: 'Birth date cannot be in the future' })
 | 
			
		||||
  @ApiProperty({ format: 'date' })
 | 
			
		||||
  @ValidateDate({ optional: true, nullable: true, format: 'date' })
 | 
			
		||||
  birthDate?: Date | null;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Person visibility
 | 
			
		||||
   */
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isHidden?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -63,9 +59,8 @@ export class MergePersonDto {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class PersonSearchDto {
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  withHidden?: boolean = false;
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  withHidden?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class PersonResponseDto {
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,9 @@
 | 
			
		||||
import { AssetOrder } from '@app/domain/asset/dto/asset.dto';
 | 
			
		||||
import { AssetType, GeodataPlacesEntity } from '@app/infra/entities';
 | 
			
		||||
import { ApiProperty } from '@nestjs/swagger';
 | 
			
		||||
import { Transform, Type } from 'class-transformer';
 | 
			
		||||
import { IsBoolean, IsEnum, IsInt, IsNotEmpty, IsString, Max, Min } from 'class-validator';
 | 
			
		||||
import { Optional, QueryBoolean, QueryDate, ValidateUUID, toBoolean } from '../../domain.util';
 | 
			
		||||
import { Type } from 'class-transformer';
 | 
			
		||||
import { IsEnum, IsInt, IsNotEmpty, IsString, Max, Min } from 'class-validator';
 | 
			
		||||
import { Optional, ValidateBoolean, ValidateDate, ValidateUUID } from '../../domain.util';
 | 
			
		||||
 | 
			
		||||
class BaseSearchDto {
 | 
			
		||||
  @ValidateUUID({ optional: true })
 | 
			
		||||
@ -19,62 +19,62 @@ class BaseSearchDto {
 | 
			
		||||
  @ApiProperty({ enumName: 'AssetTypeEnum', enum: AssetType })
 | 
			
		||||
  type?: AssetType;
 | 
			
		||||
 | 
			
		||||
  @QueryBoolean({ optional: true })
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isArchived?: boolean;
 | 
			
		||||
 | 
			
		||||
  @QueryBoolean({ optional: true })
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  @ApiProperty({ default: false })
 | 
			
		||||
  withArchived?: boolean;
 | 
			
		||||
 | 
			
		||||
  @QueryBoolean({ optional: true })
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isEncoded?: boolean;
 | 
			
		||||
 | 
			
		||||
  @QueryBoolean({ optional: true })
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isExternal?: boolean;
 | 
			
		||||
 | 
			
		||||
  @QueryBoolean({ optional: true })
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isFavorite?: boolean;
 | 
			
		||||
 | 
			
		||||
  @QueryBoolean({ optional: true })
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isMotion?: boolean;
 | 
			
		||||
 | 
			
		||||
  @QueryBoolean({ optional: true })
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isOffline?: boolean;
 | 
			
		||||
 | 
			
		||||
  @QueryBoolean({ optional: true })
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isReadOnly?: boolean;
 | 
			
		||||
 | 
			
		||||
  @QueryBoolean({ optional: true })
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isVisible?: boolean;
 | 
			
		||||
 | 
			
		||||
  @QueryBoolean({ optional: true })
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  withDeleted?: boolean;
 | 
			
		||||
 | 
			
		||||
  @QueryBoolean({ optional: true })
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  withExif?: boolean;
 | 
			
		||||
 | 
			
		||||
  @QueryDate({ optional: true })
 | 
			
		||||
  @ValidateDate({ optional: true })
 | 
			
		||||
  createdBefore?: Date;
 | 
			
		||||
 | 
			
		||||
  @QueryDate({ optional: true })
 | 
			
		||||
  @ValidateDate({ optional: true })
 | 
			
		||||
  createdAfter?: Date;
 | 
			
		||||
 | 
			
		||||
  @QueryDate({ optional: true })
 | 
			
		||||
  @ValidateDate({ optional: true })
 | 
			
		||||
  updatedBefore?: Date;
 | 
			
		||||
 | 
			
		||||
  @QueryDate({ optional: true })
 | 
			
		||||
  @ValidateDate({ optional: true })
 | 
			
		||||
  updatedAfter?: Date;
 | 
			
		||||
 | 
			
		||||
  @QueryDate({ optional: true })
 | 
			
		||||
  @ValidateDate({ optional: true })
 | 
			
		||||
  trashedBefore?: Date;
 | 
			
		||||
 | 
			
		||||
  @QueryDate({ optional: true })
 | 
			
		||||
  @ValidateDate({ optional: true })
 | 
			
		||||
  trashedAfter?: Date;
 | 
			
		||||
 | 
			
		||||
  @QueryDate({ optional: true })
 | 
			
		||||
  @ValidateDate({ optional: true })
 | 
			
		||||
  takenBefore?: Date;
 | 
			
		||||
 | 
			
		||||
  @QueryDate({ optional: true })
 | 
			
		||||
  @ValidateDate({ optional: true })
 | 
			
		||||
  takenAfter?: Date;
 | 
			
		||||
 | 
			
		||||
  @IsString()
 | 
			
		||||
@ -120,7 +120,7 @@ class BaseSearchDto {
 | 
			
		||||
  @Optional()
 | 
			
		||||
  size?: number;
 | 
			
		||||
 | 
			
		||||
  @QueryBoolean({ optional: true })
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isNotInAlbum?: boolean;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
@ -141,10 +141,10 @@ export class MetadataSearchDto extends BaseSearchDto {
 | 
			
		||||
  @Optional()
 | 
			
		||||
  checksum?: string;
 | 
			
		||||
 | 
			
		||||
  @QueryBoolean({ optional: true })
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  withStacked?: boolean;
 | 
			
		||||
 | 
			
		||||
  @QueryBoolean({ optional: true })
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  withPeople?: boolean;
 | 
			
		||||
 | 
			
		||||
  @IsString()
 | 
			
		||||
@ -197,34 +197,24 @@ export class SearchDto {
 | 
			
		||||
  @Optional()
 | 
			
		||||
  query?: string;
 | 
			
		||||
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  smart?: boolean;
 | 
			
		||||
 | 
			
		||||
  /** @deprecated */
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  clip?: boolean;
 | 
			
		||||
 | 
			
		||||
  @IsEnum(AssetType)
 | 
			
		||||
  @Optional()
 | 
			
		||||
  type?: AssetType;
 | 
			
		||||
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  recent?: boolean;
 | 
			
		||||
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  motion?: boolean;
 | 
			
		||||
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  withArchived?: boolean;
 | 
			
		||||
 | 
			
		||||
  @IsInt()
 | 
			
		||||
@ -252,9 +242,7 @@ export class SearchPeopleDto {
 | 
			
		||||
  @IsNotEmpty()
 | 
			
		||||
  name!: string;
 | 
			
		||||
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  withHidden?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,7 @@
 | 
			
		||||
import { SharedLinkType } from '@app/infra/entities';
 | 
			
		||||
import { ApiProperty } from '@nestjs/swagger';
 | 
			
		||||
import { Type } from 'class-transformer';
 | 
			
		||||
import { IsBoolean, IsDate, IsEnum, IsString } from 'class-validator';
 | 
			
		||||
import { Optional, ValidateUUID } from '../domain.util';
 | 
			
		||||
import { IsEnum, IsString } from 'class-validator';
 | 
			
		||||
import { Optional, ValidateBoolean, ValidateDate, ValidateUUID } from '../domain.util';
 | 
			
		||||
 | 
			
		||||
export class SharedLinkCreateDto {
 | 
			
		||||
  @IsEnum(SharedLinkType)
 | 
			
		||||
@ -23,21 +22,16 @@ export class SharedLinkCreateDto {
 | 
			
		||||
  @Optional()
 | 
			
		||||
  password?: string;
 | 
			
		||||
 | 
			
		||||
  @IsDate()
 | 
			
		||||
  @Type(() => Date)
 | 
			
		||||
  @Optional({ nullable: true })
 | 
			
		||||
  @ValidateDate({ optional: true, nullable: true })
 | 
			
		||||
  expiresAt?: Date | null = null;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  allowUpload?: boolean = false;
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  allowUpload?: boolean;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  allowDownload?: boolean = true;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  showMetadata?: boolean = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -54,10 +48,10 @@ export class SharedLinkEditDto {
 | 
			
		||||
  @Optional()
 | 
			
		||||
  allowUpload?: boolean;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  allowDownload?: boolean;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  showMetadata?: boolean;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
@ -65,8 +59,7 @@ export class SharedLinkEditDto {
 | 
			
		||||
   * Setting this flag and not sending expiryAt is considered as null instead.
 | 
			
		||||
   * Clients that can send null values can ignore this.
 | 
			
		||||
   */
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  changeExpiryTime?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,11 @@
 | 
			
		||||
import { ApiProperty } from '@nestjs/swagger';
 | 
			
		||||
import { Type } from 'class-transformer';
 | 
			
		||||
import { IsBoolean, IsEnum, IsNotEmpty, IsNumber, IsString, Max, Min } from 'class-validator';
 | 
			
		||||
import { Optional } from '../../domain.util';
 | 
			
		||||
import { IsEnum, IsNotEmpty, IsNumber, IsString, Max, Min } from 'class-validator';
 | 
			
		||||
import { Optional, ValidateBoolean } from '../../domain.util';
 | 
			
		||||
import { CLIPMode, ModelType } from '../../repositories';
 | 
			
		||||
 | 
			
		||||
export class ModelConfig {
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean()
 | 
			
		||||
  enabled!: boolean;
 | 
			
		||||
 | 
			
		||||
  @IsString()
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,8 @@
 | 
			
		||||
import { AudioCodec, CQMode, ToneMapping, TranscodeHWAccel, TranscodePolicy, VideoCodec } from '@app/infra/entities';
 | 
			
		||||
import { ApiProperty } from '@nestjs/swagger';
 | 
			
		||||
import { Type } from 'class-transformer';
 | 
			
		||||
import { IsBoolean, IsEnum, IsInt, IsString, Max, Min } from 'class-validator';
 | 
			
		||||
import { IsEnum, IsInt, IsString, Max, Min } from 'class-validator';
 | 
			
		||||
import { ValidateBoolean } from '../../domain.util';
 | 
			
		||||
 | 
			
		||||
export class SystemConfigFFmpegDto {
 | 
			
		||||
  @IsInt()
 | 
			
		||||
@ -68,14 +69,14 @@ export class SystemConfigFFmpegDto {
 | 
			
		||||
  @ApiProperty({ type: 'integer' })
 | 
			
		||||
  npl!: number;
 | 
			
		||||
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean()
 | 
			
		||||
  temporalAQ!: boolean;
 | 
			
		||||
 | 
			
		||||
  @IsEnum(CQMode)
 | 
			
		||||
  @ApiProperty({ enumName: 'CQMode', enum: CQMode })
 | 
			
		||||
  cqMode!: CQMode;
 | 
			
		||||
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean()
 | 
			
		||||
  twoPass!: boolean;
 | 
			
		||||
 | 
			
		||||
  @IsString()
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,5 @@
 | 
			
		||||
import { validateCronExpression } from '@app/domain';
 | 
			
		||||
import { Type } from 'class-transformer';
 | 
			
		||||
import {
 | 
			
		||||
  IsBoolean,
 | 
			
		||||
  IsNotEmpty,
 | 
			
		||||
  IsObject,
 | 
			
		||||
  IsString,
 | 
			
		||||
@ -11,6 +9,7 @@ import {
 | 
			
		||||
  ValidatorConstraint,
 | 
			
		||||
  ValidatorConstraintInterface,
 | 
			
		||||
} from 'class-validator';
 | 
			
		||||
import { ValidateBoolean, validateCronExpression } from '../../domain.util';
 | 
			
		||||
 | 
			
		||||
const isEnabled = (config: SystemConfigLibraryScanDto) => config.enabled;
 | 
			
		||||
 | 
			
		||||
@ -22,7 +21,7 @@ class CronValidator implements ValidatorConstraintInterface {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class SystemConfigLibraryScanDto {
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean()
 | 
			
		||||
  enabled!: boolean;
 | 
			
		||||
 | 
			
		||||
  @ValidateIf(isEnabled)
 | 
			
		||||
@ -33,7 +32,7 @@ export class SystemConfigLibraryScanDto {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class SystemConfigLibraryWatchDto {
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean()
 | 
			
		||||
  enabled!: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,10 @@
 | 
			
		||||
import { LogLevel } from '@app/infra/entities';
 | 
			
		||||
import { ApiProperty } from '@nestjs/swagger';
 | 
			
		||||
import { IsBoolean, IsEnum } from 'class-validator';
 | 
			
		||||
import { IsEnum } from 'class-validator';
 | 
			
		||||
import { ValidateBoolean } from '../../domain.util';
 | 
			
		||||
 | 
			
		||||
export class SystemConfigLoggingDto {
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean()
 | 
			
		||||
  enabled!: boolean;
 | 
			
		||||
 | 
			
		||||
  @ApiProperty({ enum: LogLevel, enumName: 'LogLevel' })
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,10 @@
 | 
			
		||||
import { CLIPConfig, RecognitionConfig } from '@app/domain';
 | 
			
		||||
import { Type } from 'class-transformer';
 | 
			
		||||
import { IsBoolean, IsObject, IsUrl, ValidateIf, ValidateNested } from 'class-validator';
 | 
			
		||||
import { IsObject, IsUrl, ValidateIf, ValidateNested } from 'class-validator';
 | 
			
		||||
import { ValidateBoolean } from '../../domain.util';
 | 
			
		||||
import { CLIPConfig, RecognitionConfig } from '../../smart-info/dto/model-config.dto';
 | 
			
		||||
 | 
			
		||||
export class SystemConfigMachineLearningDto {
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean()
 | 
			
		||||
  enabled!: boolean;
 | 
			
		||||
 | 
			
		||||
  @IsUrl({ require_tld: false, allow_underscores: true })
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,8 @@
 | 
			
		||||
import { IsBoolean, IsString } from 'class-validator';
 | 
			
		||||
import { IsString } from 'class-validator';
 | 
			
		||||
import { ValidateBoolean } from '../../domain.util';
 | 
			
		||||
 | 
			
		||||
export class SystemConfigMapDto {
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean()
 | 
			
		||||
  enabled!: boolean;
 | 
			
		||||
 | 
			
		||||
  @IsString()
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import { IsBoolean } from 'class-validator';
 | 
			
		||||
import { ValidateBoolean } from '../../domain.util';
 | 
			
		||||
 | 
			
		||||
export class SystemConfigNewVersionCheckDto {
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean()
 | 
			
		||||
  enabled!: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,13 +1,14 @@
 | 
			
		||||
import { IsBoolean, IsNotEmpty, IsNumber, IsString, IsUrl, Min, ValidateIf } from 'class-validator';
 | 
			
		||||
import { IsNotEmpty, IsNumber, IsString, IsUrl, Min, ValidateIf } from 'class-validator';
 | 
			
		||||
import { ValidateBoolean } from '../../domain.util';
 | 
			
		||||
 | 
			
		||||
const isEnabled = (config: SystemConfigOAuthDto) => config.enabled;
 | 
			
		||||
const isOverrideEnabled = (config: SystemConfigOAuthDto) => config.mobileOverrideEnabled;
 | 
			
		||||
 | 
			
		||||
export class SystemConfigOAuthDto {
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean()
 | 
			
		||||
  autoLaunch!: boolean;
 | 
			
		||||
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean()
 | 
			
		||||
  autoRegister!: boolean;
 | 
			
		||||
 | 
			
		||||
  @IsString()
 | 
			
		||||
@ -27,7 +28,7 @@ export class SystemConfigOAuthDto {
 | 
			
		||||
  @Min(0)
 | 
			
		||||
  defaultStorageQuota!: number;
 | 
			
		||||
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean()
 | 
			
		||||
  enabled!: boolean;
 | 
			
		||||
 | 
			
		||||
  @ValidateIf(isEnabled)
 | 
			
		||||
@ -35,7 +36,7 @@ export class SystemConfigOAuthDto {
 | 
			
		||||
  @IsString()
 | 
			
		||||
  issuerUrl!: string;
 | 
			
		||||
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean()
 | 
			
		||||
  mobileOverrideEnabled!: boolean;
 | 
			
		||||
 | 
			
		||||
  @ValidateIf(isOverrideEnabled)
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import { IsBoolean } from 'class-validator';
 | 
			
		||||
import { ValidateBoolean } from '../../domain.util';
 | 
			
		||||
 | 
			
		||||
export class SystemConfigPasswordLoginDto {
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean()
 | 
			
		||||
  enabled!: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import { IsBoolean } from 'class-validator';
 | 
			
		||||
import { ValidateBoolean } from '../../domain.util';
 | 
			
		||||
 | 
			
		||||
export class SystemConfigReverseGeocodingDto {
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean()
 | 
			
		||||
  enabled!: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,13 @@
 | 
			
		||||
import { IsBoolean, IsNotEmpty, IsString } from 'class-validator';
 | 
			
		||||
import { IsNotEmpty, IsString } from 'class-validator';
 | 
			
		||||
import { ValidateBoolean } from '../../domain.util';
 | 
			
		||||
 | 
			
		||||
export class SystemConfigStorageTemplateDto {
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean()
 | 
			
		||||
  enabled!: boolean;
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
 | 
			
		||||
  @ValidateBoolean()
 | 
			
		||||
  hashVerificationEnabled!: boolean;
 | 
			
		||||
 | 
			
		||||
  @IsNotEmpty()
 | 
			
		||||
  @IsString()
 | 
			
		||||
  template!: string;
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,10 @@
 | 
			
		||||
import { ApiProperty } from '@nestjs/swagger';
 | 
			
		||||
import { Type } from 'class-transformer';
 | 
			
		||||
import { IsBoolean, IsInt, Min } from 'class-validator';
 | 
			
		||||
import { IsInt, Min } from 'class-validator';
 | 
			
		||||
import { ValidateBoolean } from '../../domain.util';
 | 
			
		||||
 | 
			
		||||
export class SystemConfigTrashDto {
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean()
 | 
			
		||||
  enabled!: boolean;
 | 
			
		||||
 | 
			
		||||
  @IsInt()
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import { ApiProperty } from '@nestjs/swagger';
 | 
			
		||||
import { Transform } from 'class-transformer';
 | 
			
		||||
import { IsBoolean, IsEmail, IsNotEmpty, IsNumber, IsPositive, IsString } from 'class-validator';
 | 
			
		||||
import { Optional, toEmail, toSanitized } from '../../domain.util';
 | 
			
		||||
import { IsEmail, IsNotEmpty, IsNumber, IsPositive, IsString } from 'class-validator';
 | 
			
		||||
import { Optional, ValidateBoolean, toEmail, toSanitized } from '../../domain.util';
 | 
			
		||||
 | 
			
		||||
export class CreateUserDto {
 | 
			
		||||
  @IsEmail({ require_tld: false })
 | 
			
		||||
@ -21,8 +21,7 @@ export class CreateUserDto {
 | 
			
		||||
  @Transform(toSanitized)
 | 
			
		||||
  storageLabel?: string | null;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  memoriesEnabled?: boolean;
 | 
			
		||||
 | 
			
		||||
  @Optional({ nullable: true })
 | 
			
		||||
@ -31,8 +30,7 @@ export class CreateUserDto {
 | 
			
		||||
  @ApiProperty({ type: 'integer', format: 'int64' })
 | 
			
		||||
  quotaSizeInBytes?: number | null;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  shouldChangePassword?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
import { UserAvatarColor } from '@app/infra/entities';
 | 
			
		||||
import { ApiProperty } from '@nestjs/swagger';
 | 
			
		||||
import { Transform } from 'class-transformer';
 | 
			
		||||
import { IsBoolean, IsEmail, IsEnum, IsNotEmpty, IsNumber, IsPositive, IsString, IsUUID } from 'class-validator';
 | 
			
		||||
import { Optional, toEmail, toSanitized } from '../../domain.util';
 | 
			
		||||
import { IsEmail, IsEnum, IsNotEmpty, IsNumber, IsPositive, IsString, IsUUID } from 'class-validator';
 | 
			
		||||
import { Optional, ValidateBoolean, toEmail, toSanitized } from '../../domain.util';
 | 
			
		||||
 | 
			
		||||
export class UpdateUserDto {
 | 
			
		||||
  @Optional()
 | 
			
		||||
@ -30,16 +30,13 @@ export class UpdateUserDto {
 | 
			
		||||
  @ApiProperty({ format: 'uuid' })
 | 
			
		||||
  id!: string;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isAdmin?: boolean;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  shouldChangePassword?: boolean;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  memoriesEnabled?: boolean;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
 | 
			
		||||
@ -1,19 +1,13 @@
 | 
			
		||||
import { Optional, toBoolean } from '@app/domain';
 | 
			
		||||
import { Optional, ValidateBoolean, ValidateDate } from '@app/domain';
 | 
			
		||||
import { ApiProperty } from '@nestjs/swagger';
 | 
			
		||||
import { Transform, Type } from 'class-transformer';
 | 
			
		||||
import { IsBoolean, IsDate, IsInt, IsNotEmpty, IsUUID } from 'class-validator';
 | 
			
		||||
import { Type } from 'class-transformer';
 | 
			
		||||
import { IsInt, IsUUID } from 'class-validator';
 | 
			
		||||
 | 
			
		||||
export class AssetSearchDto {
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsNotEmpty()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isFavorite?: boolean;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsNotEmpty()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isArchived?: boolean;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
@ -33,13 +27,9 @@ export class AssetSearchDto {
 | 
			
		||||
  @ApiProperty({ format: 'uuid' })
 | 
			
		||||
  userId?: string;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsDate()
 | 
			
		||||
  @Type(() => Date)
 | 
			
		||||
  @ValidateDate({ optional: true })
 | 
			
		||||
  updatedAfter?: Date;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsDate()
 | 
			
		||||
  @Type(() => Date)
 | 
			
		||||
  @ValidateDate({ optional: true })
 | 
			
		||||
  updatedBefore?: Date;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,6 @@
 | 
			
		||||
import { Optional, toBoolean, UploadFieldName, ValidateUUID } from '@app/domain';
 | 
			
		||||
import { Optional, UploadFieldName, ValidateBoolean, ValidateDate, ValidateUUID } from '@app/domain';
 | 
			
		||||
import { ApiProperty } from '@nestjs/swagger';
 | 
			
		||||
import { Transform, Type } from 'class-transformer';
 | 
			
		||||
import { IsBoolean, IsDate, IsNotEmpty, IsString } from 'class-validator';
 | 
			
		||||
import { IsNotEmpty, IsString } from 'class-validator';
 | 
			
		||||
 | 
			
		||||
export class CreateAssetDto {
 | 
			
		||||
  @ValidateUUID({ optional: true })
 | 
			
		||||
@ -15,43 +14,29 @@ export class CreateAssetDto {
 | 
			
		||||
  @IsString()
 | 
			
		||||
  deviceId!: string;
 | 
			
		||||
 | 
			
		||||
  @IsNotEmpty()
 | 
			
		||||
  @IsDate()
 | 
			
		||||
  @Type(() => Date)
 | 
			
		||||
  @ValidateDate()
 | 
			
		||||
  fileCreatedAt!: Date;
 | 
			
		||||
 | 
			
		||||
  @IsNotEmpty()
 | 
			
		||||
  @IsDate()
 | 
			
		||||
  @Type(() => Date)
 | 
			
		||||
  @ValidateDate()
 | 
			
		||||
  fileModifiedAt!: Date;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsString()
 | 
			
		||||
  duration?: string;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isFavorite?: boolean;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isArchived?: boolean;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isVisible?: boolean;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isOffline?: boolean;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  isReadOnly?: boolean;
 | 
			
		||||
 | 
			
		||||
  // The properties below are added to correctly generate the API docs
 | 
			
		||||
 | 
			
		||||
@ -1,18 +1,12 @@
 | 
			
		||||
import { Optional, toBoolean } from '@app/domain';
 | 
			
		||||
import { ValidateBoolean } from '@app/domain';
 | 
			
		||||
import { ApiProperty } from '@nestjs/swagger';
 | 
			
		||||
import { Transform } from 'class-transformer';
 | 
			
		||||
import { IsBoolean } from 'class-validator';
 | 
			
		||||
 | 
			
		||||
export class ServeFileDto {
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @ApiProperty({ type: Boolean, title: 'Is serve thumbnail (resize) file' })
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  @ApiProperty({ title: 'Is serve thumbnail (resize) file' })
 | 
			
		||||
  isThumb?: boolean;
 | 
			
		||||
 | 
			
		||||
  @Optional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  @Transform(toBoolean)
 | 
			
		||||
  @ApiProperty({ type: Boolean, title: 'Is request made from web' })
 | 
			
		||||
  @ValidateBoolean({ optional: true })
 | 
			
		||||
  @ApiProperty({ title: 'Is request made from web' })
 | 
			
		||||
  isWeb?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user