diff --git a/server/src/app.module.ts b/server/src/app.module.ts index 2d6d7878dcd8a..a4518598a3678 100644 --- a/server/src/app.module.ts +++ b/server/src/app.module.ts @@ -13,15 +13,15 @@ import { IWorker } from 'src/constants'; import { controllers } from 'src/controllers'; import { entities } from 'src/entities'; import { ImmichWorker } from 'src/enum'; -import { IJobRepository } from 'src/interfaces/job.interface'; import { AuthGuard } from 'src/middleware/auth.guard'; import { ErrorInterceptor } from 'src/middleware/error.interceptor'; import { FileUploadInterceptor } from 'src/middleware/file-upload.interceptor'; import { GlobalExceptionFilter } from 'src/middleware/global-exception.filter'; import { LoggingInterceptor } from 'src/middleware/logging.interceptor'; -import { providers, repositories } from 'src/repositories'; +import { repositories } from 'src/repositories'; import { ConfigRepository } from 'src/repositories/config.repository'; import { EventRepository } from 'src/repositories/event.repository'; +import { JobRepository } from 'src/repositories/job.repository'; import { LoggingRepository } from 'src/repositories/logging.repository'; import { teardownTelemetry, TelemetryRepository } from 'src/repositories/telemetry.repository'; import { services } from 'src/services'; @@ -29,7 +29,7 @@ import { AuthService } from 'src/services/auth.service'; import { CliService } from 'src/services/cli.service'; import { DatabaseService } from 'src/services/database.service'; -const common = [...services, ...providers, ...repositories]; +const common = [...repositories, ...services]; const middleware = [ FileUploadInterceptor, @@ -80,7 +80,7 @@ class BaseModule implements OnModuleInit, OnModuleDestroy { @Inject(IWorker) private worker: ImmichWorker, logger: LoggingRepository, private eventRepository: EventRepository, - @Inject(IJobRepository) private jobRepository: IJobRepository, + private jobRepository: JobRepository, private telemetryRepository: TelemetryRepository, private authService: AuthService, ) { @@ -88,7 +88,7 @@ class BaseModule implements OnModuleInit, OnModuleDestroy { } async onModuleInit() { - this.telemetryRepository.setup({ repositories: [...providers.map(({ useClass }) => useClass), ...repositories] }); + this.telemetryRepository.setup({ repositories }); this.jobRepository.setup({ services }); if (this.worker === ImmichWorker.MICROSERVICES) { diff --git a/server/src/bin/sync-sql.ts b/server/src/bin/sync-sql.ts index e0d578d58f923..4765993643427 100644 --- a/server/src/bin/sync-sql.ts +++ b/server/src/bin/sync-sql.ts @@ -4,6 +4,7 @@ import { Reflector } from '@nestjs/core'; import { SchedulerRegistry } from '@nestjs/schedule'; import { Test } from '@nestjs/testing'; import { TypeOrmModule } from '@nestjs/typeorm'; +import { ClassConstructor } from 'class-transformer'; import { PostgresJSDialect } from 'kysely-postgres-js'; import { KyselyModule } from 'nestjs-kysely'; import { OpenTelemetryModule } from 'nestjs-otel'; @@ -13,7 +14,7 @@ import postgres from 'postgres'; import { format } from 'sql-formatter'; import { GENERATE_SQL_KEY, GenerateSqlQueries } from 'src/decorators'; import { entities } from 'src/entities'; -import { providers, repositories } from 'src/repositories'; +import { repositories } from 'src/repositories'; import { AccessRepository } from 'src/repositories/access.repository'; import { ConfigRepository } from 'src/repositories/config.repository'; import { LoggingRepository } from 'src/repositories/logging.repository'; @@ -45,8 +46,7 @@ export class SqlLogger implements Logger { const reflector = new Reflector(); -type Repository = (typeof providers)[0]['useClass']; -type Provider = { provide: any; useClass: Repository }; +type Repository = ClassConstructor; type SqlGeneratorOptions = { targetDir: string }; class SqlGenerator { @@ -59,15 +59,11 @@ class SqlGenerator { async run() { try { await this.setup(); - const targets = [ - ...providers, - ...repositories.map((repository) => ({ provide: repository, useClass: repository as any })), - ]; - for (const repository of targets) { - if (repository.provide === LoggingRepository) { + for (const Repository of repositories) { + if (Repository === LoggingRepository) { continue; } - await this.process(repository); + await this.process(Repository); } await this.write(); this.stats(); @@ -105,19 +101,19 @@ class SqlGenerator { TypeOrmModule.forFeature(entities), OpenTelemetryModule.forRoot(otel), ], - providers: [...providers, ...repositories, AuthService, SchedulerRegistry], + providers: [...repositories, AuthService, SchedulerRegistry], }).compile(); this.app = await moduleFixture.createNestApplication().init(); } - async process({ provide: token, useClass: Repository }: Provider) { + async process(Repository: Repository) { if (!this.app) { throw new Error('Not initialized'); } const data: string[] = [`-- NOTE: This file is auto generated by ./sql-generator`]; - const instance = this.app.get(token); + const instance = this.app.get(Repository); // normal repositories data.push(...(await this.runTargets(instance, `${Repository.name}`))); diff --git a/server/src/config.ts b/server/src/config.ts index 7dd015c0fa0ba..e7f3d4b8b6153 100644 --- a/server/src/config.ts +++ b/server/src/config.ts @@ -5,14 +5,14 @@ import { CQMode, ImageFormat, LogLevel, + QueueName, ToneMapping, TranscodeHWAccel, TranscodePolicy, VideoCodec, VideoContainer, } from 'src/enum'; -import { ConcurrentQueueName, QueueName } from 'src/interfaces/job.interface'; -import { ImageOptions } from 'src/types'; +import { ConcurrentQueueName, ImageOptions } from 'src/types'; export interface SystemConfig { backup: { diff --git a/server/src/constants.ts b/server/src/constants.ts index 050a7d06fab45..889ce81620b86 100644 --- a/server/src/constants.ts +++ b/server/src/constants.ts @@ -1,7 +1,7 @@ import { Duration } from 'luxon'; import { readFileSync } from 'node:fs'; import { SemVer } from 'semver'; -import { ExifOrientation } from 'src/enum'; +import { DatabaseExtension, ExifOrientation } from 'src/enum'; export const POSTGRES_VERSION_RANGE = '>=14.0.0'; export const VECTORS_VERSION_RANGE = '>=0.2 <0.4'; @@ -16,6 +16,16 @@ export const LIFECYCLE_EXTENSION = 'x-immich-lifecycle'; export const DEPRECATED_IN_PREFIX = 'This property was deprecated in '; export const ADDED_IN_PREFIX = 'This property was added in '; +export const JOBS_ASSET_PAGINATION_SIZE = 1000; +export const JOBS_LIBRARY_PAGINATION_SIZE = 10_000; + +export const EXTENSION_NAMES: Record = { + cube: 'cube', + earthdistance: 'earthdistance', + vector: 'pgvector', + vectors: 'pgvecto.rs', +} as const; + export const SALT_ROUNDS = 10; export const IWorker = 'IWorker'; diff --git a/server/src/controllers/asset-media.controller.ts b/server/src/controllers/asset-media.controller.ts index fd405b8928c7a..3d2845690d3f8 100644 --- a/server/src/controllers/asset-media.controller.ts +++ b/server/src/controllers/asset-media.controller.ts @@ -35,9 +35,10 @@ import { AuthDto } from 'src/dtos/auth.dto'; import { ImmichHeader, RouteKey } from 'src/enum'; import { AssetUploadInterceptor } from 'src/middleware/asset-upload.interceptor'; import { Auth, Authenticated, FileResponse } from 'src/middleware/auth.guard'; -import { FileUploadInterceptor, UploadFiles, getFiles } from 'src/middleware/file-upload.interceptor'; +import { FileUploadInterceptor, getFiles } from 'src/middleware/file-upload.interceptor'; import { LoggingRepository } from 'src/repositories/logging.repository'; import { AssetMediaService } from 'src/services/asset-media.service'; +import { UploadFiles } from 'src/types'; import { sendFile } from 'src/utils/file'; import { FileNotEmptyValidator, UUIDParamDto } from 'src/validation'; diff --git a/server/src/decorators.ts b/server/src/decorators.ts index 7aab2e248aca1..56efdd1c08db0 100644 --- a/server/src/decorators.ts +++ b/server/src/decorators.ts @@ -2,8 +2,7 @@ import { SetMetadata, applyDecorators } from '@nestjs/common'; import { ApiExtension, ApiOperation, ApiProperty, ApiTags } from '@nestjs/swagger'; import _ from 'lodash'; import { ADDED_IN_PREFIX, DEPRECATED_IN_PREFIX, LIFECYCLE_EXTENSION } from 'src/constants'; -import { ImmichWorker, MetadataKey } from 'src/enum'; -import { JobName, QueueName } from 'src/interfaces/job.interface'; +import { ImmichWorker, JobName, MetadataKey, QueueName } from 'src/enum'; import { EmitEvent } from 'src/repositories/event.repository'; import { setUnion } from 'src/utils/set'; diff --git a/server/src/dtos/job.dto.ts b/server/src/dtos/job.dto.ts index 31612bd8a4fb7..ce6aad4c066e7 100644 --- a/server/src/dtos/job.dto.ts +++ b/server/src/dtos/job.dto.ts @@ -1,7 +1,6 @@ import { ApiProperty } from '@nestjs/swagger'; import { IsEnum, IsNotEmpty } from 'class-validator'; -import { ManualJobName } from 'src/enum'; -import { JobCommand, QueueName } from 'src/interfaces/job.interface'; +import { JobCommand, ManualJobName, QueueName } from 'src/enum'; import { ValidateBoolean } from 'src/validation'; export class JobIdParamDto { diff --git a/server/src/dtos/system-config.dto.ts b/server/src/dtos/system-config.dto.ts index 350918254542a..6b51c015b7201 100644 --- a/server/src/dtos/system-config.dto.ts +++ b/server/src/dtos/system-config.dto.ts @@ -25,13 +25,14 @@ import { Colorspace, ImageFormat, LogLevel, + QueueName, ToneMapping, TranscodeHWAccel, TranscodePolicy, VideoCodec, VideoContainer, } from 'src/enum'; -import { ConcurrentQueueName, QueueName } from 'src/interfaces/job.interface'; +import { ConcurrentQueueName } from 'src/types'; import { IsCronExpression, ValidateBoolean } from 'src/validation'; const isLibraryScanEnabled = (config: SystemConfigLibraryScanDto) => config.enabled; diff --git a/server/src/enum.ts b/server/src/enum.ts index b887fbace3bb3..0c1fb01a12310 100644 --- a/server/src/enum.ts +++ b/server/src/enum.ts @@ -398,3 +398,142 @@ export enum BootstrapEventPriority { // Initialise config after other bootstrap services, stop other services from using config on bootstrap SystemConfig = 100, } + +export enum QueueName { + THUMBNAIL_GENERATION = 'thumbnailGeneration', + METADATA_EXTRACTION = 'metadataExtraction', + VIDEO_CONVERSION = 'videoConversion', + FACE_DETECTION = 'faceDetection', + FACIAL_RECOGNITION = 'facialRecognition', + SMART_SEARCH = 'smartSearch', + DUPLICATE_DETECTION = 'duplicateDetection', + BACKGROUND_TASK = 'backgroundTask', + STORAGE_TEMPLATE_MIGRATION = 'storageTemplateMigration', + MIGRATION = 'migration', + SEARCH = 'search', + SIDECAR = 'sidecar', + LIBRARY = 'library', + NOTIFICATION = 'notifications', + BACKUP_DATABASE = 'backupDatabase', +} + +export enum JobName { + //backups + BACKUP_DATABASE = 'database-backup', + + // conversion + QUEUE_VIDEO_CONVERSION = 'queue-video-conversion', + VIDEO_CONVERSION = 'video-conversion', + + // thumbnails + QUEUE_GENERATE_THUMBNAILS = 'queue-generate-thumbnails', + GENERATE_THUMBNAILS = 'generate-thumbnails', + GENERATE_PERSON_THUMBNAIL = 'generate-person-thumbnail', + + // metadata + QUEUE_METADATA_EXTRACTION = 'queue-metadata-extraction', + METADATA_EXTRACTION = 'metadata-extraction', + LINK_LIVE_PHOTOS = 'link-live-photos', + + // user + USER_DELETION = 'user-deletion', + USER_DELETE_CHECK = 'user-delete-check', + USER_SYNC_USAGE = 'user-sync-usage', + + // asset + ASSET_DELETION = 'asset-deletion', + ASSET_DELETION_CHECK = 'asset-deletion-check', + + // storage template + STORAGE_TEMPLATE_MIGRATION = 'storage-template-migration', + STORAGE_TEMPLATE_MIGRATION_SINGLE = 'storage-template-migration-single', + + // tags + TAG_CLEANUP = 'tag-cleanup', + + // migration + QUEUE_MIGRATION = 'queue-migration', + MIGRATE_ASSET = 'migrate-asset', + MIGRATE_PERSON = 'migrate-person', + + // facial recognition + PERSON_CLEANUP = 'person-cleanup', + QUEUE_FACE_DETECTION = 'queue-face-detection', + FACE_DETECTION = 'face-detection', + QUEUE_FACIAL_RECOGNITION = 'queue-facial-recognition', + FACIAL_RECOGNITION = 'facial-recognition', + + // library management + LIBRARY_QUEUE_SYNC_FILES = 'library-queue-sync-files', + LIBRARY_QUEUE_SYNC_ASSETS = 'library-queue-sync-assets', + LIBRARY_SYNC_FILE = 'library-sync-file', + LIBRARY_SYNC_ASSET = 'library-sync-asset', + LIBRARY_DELETE = 'library-delete', + LIBRARY_QUEUE_SYNC_ALL = 'library-queue-sync-all', + LIBRARY_QUEUE_CLEANUP = 'library-queue-cleanup', + + // cleanup + DELETE_FILES = 'delete-files', + CLEAN_OLD_AUDIT_LOGS = 'clean-old-audit-logs', + CLEAN_OLD_SESSION_TOKENS = 'clean-old-session-tokens', + + // smart search + QUEUE_SMART_SEARCH = 'queue-smart-search', + SMART_SEARCH = 'smart-search', + + QUEUE_TRASH_EMPTY = 'queue-trash-empty', + + // duplicate detection + QUEUE_DUPLICATE_DETECTION = 'queue-duplicate-detection', + DUPLICATE_DETECTION = 'duplicate-detection', + + // XMP sidecars + QUEUE_SIDECAR = 'queue-sidecar', + SIDECAR_DISCOVERY = 'sidecar-discovery', + SIDECAR_SYNC = 'sidecar-sync', + SIDECAR_WRITE = 'sidecar-write', + + // Notification + NOTIFY_SIGNUP = 'notify-signup', + NOTIFY_ALBUM_INVITE = 'notify-album-invite', + NOTIFY_ALBUM_UPDATE = 'notify-album-update', + SEND_EMAIL = 'notification-send-email', + + // Version check + VERSION_CHECK = 'version-check', +} + +export enum JobCommand { + START = 'start', + PAUSE = 'pause', + RESUME = 'resume', + EMPTY = 'empty', + CLEAR_FAILED = 'clear-failed', +} + +export enum JobStatus { + SUCCESS = 'success', + FAILED = 'failed', + SKIPPED = 'skipped', +} + +export enum QueueCleanType { + FAILED = 'failed', +} + +export enum VectorIndex { + CLIP = 'clip_index', + FACE = 'face_index', +} + +export enum DatabaseLock { + GeodataImport = 100, + Migrations = 200, + SystemFileMounts = 300, + StorageTemplateMigration = 420, + VersionHistory = 500, + CLIPDimSize = 512, + Library = 1337, + GetSystemConfig = 69, + BackupDatabase = 42, +} diff --git a/server/src/interfaces/job.interface.ts b/server/src/interfaces/job.interface.ts deleted file mode 100644 index 1f2b92074ac19..0000000000000 --- a/server/src/interfaces/job.interface.ts +++ /dev/null @@ -1,329 +0,0 @@ -import { ClassConstructor } from 'class-transformer'; -import { EmailImageAttachment } from 'src/repositories/notification.repository'; - -export enum QueueName { - THUMBNAIL_GENERATION = 'thumbnailGeneration', - METADATA_EXTRACTION = 'metadataExtraction', - VIDEO_CONVERSION = 'videoConversion', - FACE_DETECTION = 'faceDetection', - FACIAL_RECOGNITION = 'facialRecognition', - SMART_SEARCH = 'smartSearch', - DUPLICATE_DETECTION = 'duplicateDetection', - BACKGROUND_TASK = 'backgroundTask', - STORAGE_TEMPLATE_MIGRATION = 'storageTemplateMigration', - MIGRATION = 'migration', - SEARCH = 'search', - SIDECAR = 'sidecar', - LIBRARY = 'library', - NOTIFICATION = 'notifications', - BACKUP_DATABASE = 'backupDatabase', -} - -export type ConcurrentQueueName = Exclude< - QueueName, - | QueueName.STORAGE_TEMPLATE_MIGRATION - | QueueName.FACIAL_RECOGNITION - | QueueName.DUPLICATE_DETECTION - | QueueName.BACKUP_DATABASE ->; - -export enum JobCommand { - START = 'start', - PAUSE = 'pause', - RESUME = 'resume', - EMPTY = 'empty', - CLEAR_FAILED = 'clear-failed', -} - -export enum JobName { - //backups - BACKUP_DATABASE = 'database-backup', - - // conversion - QUEUE_VIDEO_CONVERSION = 'queue-video-conversion', - VIDEO_CONVERSION = 'video-conversion', - - // thumbnails - QUEUE_GENERATE_THUMBNAILS = 'queue-generate-thumbnails', - GENERATE_THUMBNAILS = 'generate-thumbnails', - GENERATE_PERSON_THUMBNAIL = 'generate-person-thumbnail', - - // metadata - QUEUE_METADATA_EXTRACTION = 'queue-metadata-extraction', - METADATA_EXTRACTION = 'metadata-extraction', - LINK_LIVE_PHOTOS = 'link-live-photos', - - // user - USER_DELETION = 'user-deletion', - USER_DELETE_CHECK = 'user-delete-check', - USER_SYNC_USAGE = 'user-sync-usage', - - // asset - ASSET_DELETION = 'asset-deletion', - ASSET_DELETION_CHECK = 'asset-deletion-check', - - // storage template - STORAGE_TEMPLATE_MIGRATION = 'storage-template-migration', - STORAGE_TEMPLATE_MIGRATION_SINGLE = 'storage-template-migration-single', - - // tags - TAG_CLEANUP = 'tag-cleanup', - - // migration - QUEUE_MIGRATION = 'queue-migration', - MIGRATE_ASSET = 'migrate-asset', - MIGRATE_PERSON = 'migrate-person', - - // facial recognition - PERSON_CLEANUP = 'person-cleanup', - QUEUE_FACE_DETECTION = 'queue-face-detection', - FACE_DETECTION = 'face-detection', - QUEUE_FACIAL_RECOGNITION = 'queue-facial-recognition', - FACIAL_RECOGNITION = 'facial-recognition', - - // library management - LIBRARY_QUEUE_SYNC_FILES = 'library-queue-sync-files', - LIBRARY_QUEUE_SYNC_ASSETS = 'library-queue-sync-assets', - LIBRARY_SYNC_FILE = 'library-sync-file', - LIBRARY_SYNC_ASSET = 'library-sync-asset', - LIBRARY_DELETE = 'library-delete', - LIBRARY_QUEUE_SYNC_ALL = 'library-queue-sync-all', - LIBRARY_QUEUE_CLEANUP = 'library-queue-cleanup', - - // cleanup - DELETE_FILES = 'delete-files', - CLEAN_OLD_AUDIT_LOGS = 'clean-old-audit-logs', - CLEAN_OLD_SESSION_TOKENS = 'clean-old-session-tokens', - - // smart search - QUEUE_SMART_SEARCH = 'queue-smart-search', - SMART_SEARCH = 'smart-search', - - QUEUE_TRASH_EMPTY = 'queue-trash-empty', - - // duplicate detection - QUEUE_DUPLICATE_DETECTION = 'queue-duplicate-detection', - DUPLICATE_DETECTION = 'duplicate-detection', - - // XMP sidecars - QUEUE_SIDECAR = 'queue-sidecar', - SIDECAR_DISCOVERY = 'sidecar-discovery', - SIDECAR_SYNC = 'sidecar-sync', - SIDECAR_WRITE = 'sidecar-write', - - // Notification - NOTIFY_SIGNUP = 'notify-signup', - NOTIFY_ALBUM_INVITE = 'notify-album-invite', - NOTIFY_ALBUM_UPDATE = 'notify-album-update', - SEND_EMAIL = 'notification-send-email', - - // Version check - VERSION_CHECK = 'version-check', -} - -export const JOBS_ASSET_PAGINATION_SIZE = 1000; -export const JOBS_LIBRARY_PAGINATION_SIZE = 10_000; - -export interface IBaseJob { - force?: boolean; -} - -export interface IDelayedJob extends IBaseJob { - /** The minimum time to wait to execute this job, in milliseconds. */ - delay?: number; -} - -export interface IEntityJob extends IBaseJob { - id: string; - source?: 'upload' | 'sidecar-write' | 'copy'; - notify?: boolean; -} - -export interface IAssetDeleteJob extends IEntityJob { - deleteOnDisk: boolean; -} - -export interface ILibraryFileJob extends IEntityJob { - ownerId: string; - assetPath: string; -} - -export interface ILibraryAssetJob extends IEntityJob { - importPaths: string[]; - exclusionPatterns: string[]; -} - -export interface IBulkEntityJob extends IBaseJob { - ids: string[]; -} - -export interface IDeleteFilesJob extends IBaseJob { - files: Array; -} - -export interface ISidecarWriteJob extends IEntityJob { - description?: string; - dateTimeOriginal?: string; - latitude?: number; - longitude?: number; - rating?: number; - tags?: true; -} - -export interface IDeferrableJob extends IEntityJob { - deferred?: boolean; -} - -export interface INightlyJob extends IBaseJob { - nightly?: boolean; -} - -export interface IEmailJob { - to: string; - subject: string; - html: string; - text: string; - imageAttachments?: EmailImageAttachment[]; -} - -export interface INotifySignupJob extends IEntityJob { - tempPassword?: string; -} - -export interface INotifyAlbumInviteJob extends IEntityJob { - recipientId: string; -} - -export interface INotifyAlbumUpdateJob extends IEntityJob, IDelayedJob { - recipientIds: string[]; -} - -export interface JobCounts { - active: number; - completed: number; - failed: number; - delayed: number; - waiting: number; - paused: number; -} - -export interface QueueStatus { - isActive: boolean; - isPaused: boolean; -} - -export enum QueueCleanType { - FAILED = 'failed', -} - -export type JobItem = - // Backups - | { name: JobName.BACKUP_DATABASE; data?: IBaseJob } - - // Transcoding - | { name: JobName.QUEUE_VIDEO_CONVERSION; data: IBaseJob } - | { name: JobName.VIDEO_CONVERSION; data: IEntityJob } - - // Thumbnails - | { name: JobName.QUEUE_GENERATE_THUMBNAILS; data: IBaseJob } - | { name: JobName.GENERATE_THUMBNAILS; data: IEntityJob } - - // User - | { name: JobName.USER_DELETE_CHECK; data?: IBaseJob } - | { name: JobName.USER_DELETION; data: IEntityJob } - | { name: JobName.USER_SYNC_USAGE; data?: IBaseJob } - - // Storage Template - | { name: JobName.STORAGE_TEMPLATE_MIGRATION; data?: IBaseJob } - | { name: JobName.STORAGE_TEMPLATE_MIGRATION_SINGLE; data: IEntityJob } - - // Migration - | { name: JobName.QUEUE_MIGRATION; data?: IBaseJob } - | { name: JobName.MIGRATE_ASSET; data: IEntityJob } - | { name: JobName.MIGRATE_PERSON; data: IEntityJob } - - // Metadata Extraction - | { name: JobName.QUEUE_METADATA_EXTRACTION; data: IBaseJob } - | { name: JobName.METADATA_EXTRACTION; data: IEntityJob } - | { name: JobName.LINK_LIVE_PHOTOS; data: IEntityJob } - // Sidecar Scanning - | { name: JobName.QUEUE_SIDECAR; data: IBaseJob } - | { name: JobName.SIDECAR_DISCOVERY; data: IEntityJob } - | { name: JobName.SIDECAR_SYNC; data: IEntityJob } - | { name: JobName.SIDECAR_WRITE; data: ISidecarWriteJob } - - // Facial Recognition - | { name: JobName.QUEUE_FACE_DETECTION; data: IBaseJob } - | { name: JobName.FACE_DETECTION; data: IEntityJob } - | { name: JobName.QUEUE_FACIAL_RECOGNITION; data: INightlyJob } - | { name: JobName.FACIAL_RECOGNITION; data: IDeferrableJob } - | { name: JobName.GENERATE_PERSON_THUMBNAIL; data: IEntityJob } - - // Smart Search - | { name: JobName.QUEUE_SMART_SEARCH; data: IBaseJob } - | { name: JobName.SMART_SEARCH; data: IEntityJob } - | { name: JobName.QUEUE_TRASH_EMPTY; data?: IBaseJob } - - // Duplicate Detection - | { name: JobName.QUEUE_DUPLICATE_DETECTION; data: IBaseJob } - | { name: JobName.DUPLICATE_DETECTION; data: IEntityJob } - - // Filesystem - | { name: JobName.DELETE_FILES; data: IDeleteFilesJob } - - // Cleanup - | { name: JobName.CLEAN_OLD_AUDIT_LOGS; data?: IBaseJob } - | { name: JobName.CLEAN_OLD_SESSION_TOKENS; data?: IBaseJob } - - // Tags - | { name: JobName.TAG_CLEANUP; data?: IBaseJob } - - // Asset Deletion - | { name: JobName.PERSON_CLEANUP; data?: IBaseJob } - | { name: JobName.ASSET_DELETION; data: IAssetDeleteJob } - | { name: JobName.ASSET_DELETION_CHECK; data?: IBaseJob } - - // Library Management - | { name: JobName.LIBRARY_SYNC_FILE; data: ILibraryFileJob } - | { name: JobName.LIBRARY_QUEUE_SYNC_FILES; data: IEntityJob } - | { name: JobName.LIBRARY_QUEUE_SYNC_ASSETS; data: IEntityJob } - | { name: JobName.LIBRARY_SYNC_ASSET; data: ILibraryAssetJob } - | { name: JobName.LIBRARY_DELETE; data: IEntityJob } - | { name: JobName.LIBRARY_QUEUE_SYNC_ALL; data?: IBaseJob } - | { name: JobName.LIBRARY_QUEUE_CLEANUP; data: IBaseJob } - - // Notification - | { name: JobName.SEND_EMAIL; data: IEmailJob } - | { name: JobName.NOTIFY_ALBUM_INVITE; data: INotifyAlbumInviteJob } - | { name: JobName.NOTIFY_ALBUM_UPDATE; data: INotifyAlbumUpdateJob } - | { name: JobName.NOTIFY_SIGNUP; data: INotifySignupJob } - - // Version check - | { name: JobName.VERSION_CHECK; data: IBaseJob }; - -export enum JobStatus { - SUCCESS = 'success', - FAILED = 'failed', - SKIPPED = 'skipped', -} -export type Jobs = { [K in JobItem['name']]: (JobItem & { name: K })['data'] }; -export type JobOf = Jobs[T]; - -export const IJobRepository = 'IJobRepository'; - -export interface IJobRepository { - setup(options: { services: ClassConstructor[] }): void; - startWorkers(): void; - run(job: JobItem): Promise; - setConcurrency(queueName: QueueName, concurrency: number): void; - queue(item: JobItem): Promise; - queueAll(items: JobItem[]): Promise; - pause(name: QueueName): Promise; - resume(name: QueueName): Promise; - empty(name: QueueName): Promise; - clear(name: QueueName, type: QueueCleanType): Promise; - getQueueStatus(name: QueueName): Promise; - getJobCounts(name: QueueName): Promise; - waitForQueueCompletion(...queues: QueueName[]): Promise; - removeJob(jobId: string, name: JobName): Promise; -} diff --git a/server/src/middleware/file-upload.interceptor.ts b/server/src/middleware/file-upload.interceptor.ts index 743764ff7529e..6f6d9aaf43468 100644 --- a/server/src/middleware/file-upload.interceptor.ts +++ b/server/src/middleware/file-upload.interceptor.ts @@ -10,14 +10,10 @@ import { UploadFieldName } from 'src/dtos/asset-media.dto'; import { RouteKey } from 'src/enum'; import { AuthRequest } from 'src/middleware/auth.guard'; import { LoggingRepository } from 'src/repositories/logging.repository'; -import { AssetMediaService, UploadFile } from 'src/services/asset-media.service'; +import { AssetMediaService } from 'src/services/asset-media.service'; +import { ImmichFile, UploadFile, UploadFiles } from 'src/types'; import { asRequest, mapToUploadFile } from 'src/utils/asset.util'; -export interface UploadFiles { - assetData: ImmichFile[]; - sidecarData: ImmichFile[]; -} - export function getFile(files: UploadFiles, property: 'assetData' | 'sidecarData') { const file = files[property]?.[0]; return file ? mapToUploadFile(file) : file; @@ -30,12 +26,6 @@ export function getFiles(files: UploadFiles) { }; } -export interface ImmichFile extends Express.Multer.File { - /** sha1 hash of file */ - uuid: string; - checksum: Buffer; -} - type DiskStorageCallback = (error: Error | null, result: string) => void; type ImmichMulterFile = Express.Multer.File & { uuid: string }; diff --git a/server/src/repositories/config.repository.ts b/server/src/repositories/config.repository.ts index 27c10bcdcc0f6..2d5f2bc2e2b28 100644 --- a/server/src/repositories/config.repository.ts +++ b/server/src/repositories/config.repository.ts @@ -13,9 +13,16 @@ import { Notice } from 'postgres'; import { citiesFile, excludePaths, IWorker } from 'src/constants'; import { Telemetry } from 'src/decorators'; import { EnvDto } from 'src/dtos/env.dto'; -import { DatabaseExtension, ImmichEnvironment, ImmichHeader, ImmichTelemetry, ImmichWorker, LogLevel } from 'src/enum'; -import { QueueName } from 'src/interfaces/job.interface'; -import { DatabaseConnectionParams, VectorExtension } from 'src/repositories/database.repository'; +import { + DatabaseExtension, + ImmichEnvironment, + ImmichHeader, + ImmichTelemetry, + ImmichWorker, + LogLevel, + QueueName, +} from 'src/enum'; +import { DatabaseConnectionParams, VectorExtension } from 'src/types'; import { setDifference } from 'src/utils/set'; import { PostgresConnectionOptions } from 'typeorm/driver/postgres/PostgresConnectionOptions.js'; diff --git a/server/src/repositories/database.repository.ts b/server/src/repositories/database.repository.ts index 6edcedd13c92b..ef97147c61cfc 100644 --- a/server/src/repositories/database.repository.ts +++ b/server/src/repositories/database.repository.ts @@ -4,66 +4,16 @@ import AsyncLock from 'async-lock'; import { Kysely, sql } from 'kysely'; import { InjectKysely } from 'nestjs-kysely'; import semver from 'semver'; -import { POSTGRES_VERSION_RANGE, VECTOR_VERSION_RANGE, VECTORS_VERSION_RANGE } from 'src/constants'; +import { EXTENSION_NAMES, POSTGRES_VERSION_RANGE, VECTOR_VERSION_RANGE, VECTORS_VERSION_RANGE } from 'src/constants'; import { DB } from 'src/db'; -import { DatabaseExtension } from 'src/enum'; +import { DatabaseExtension, DatabaseLock, VectorIndex } from 'src/enum'; import { ConfigRepository } from 'src/repositories/config.repository'; import { LoggingRepository } from 'src/repositories/logging.repository'; +import { ExtensionVersion, VectorExtension, VectorUpdateResult } from 'src/types'; import { UPSERT_COLUMNS } from 'src/utils/database'; import { isValidInteger } from 'src/validation'; import { DataSource, EntityManager, EntityMetadata, QueryRunner } from 'typeorm'; -export type VectorExtension = DatabaseExtension.VECTOR | DatabaseExtension.VECTORS; - -export type DatabaseConnectionURL = { - connectionType: 'url'; - url: string; -}; - -export type DatabaseConnectionParts = { - connectionType: 'parts'; - host: string; - port: number; - username: string; - password: string; - database: string; -}; - -export type DatabaseConnectionParams = DatabaseConnectionURL | DatabaseConnectionParts; - -export enum VectorIndex { - CLIP = 'clip_index', - FACE = 'face_index', -} - -export enum DatabaseLock { - GeodataImport = 100, - Migrations = 200, - SystemFileMounts = 300, - StorageTemplateMigration = 420, - VersionHistory = 500, - CLIPDimSize = 512, - Library = 1337, - GetSystemConfig = 69, - BackupDatabase = 42, -} - -export const EXTENSION_NAMES: Record = { - cube: 'cube', - earthdistance: 'earthdistance', - vector: 'pgvector', - vectors: 'pgvecto.rs', -} as const; - -export interface ExtensionVersion { - availableVersion: string | null; - installedVersion: string | null; -} - -export interface VectorUpdateResult { - restartRequired: boolean; -} - @Injectable() export class DatabaseRepository { private vectorExtension: VectorExtension; diff --git a/server/src/repositories/event.repository.ts b/server/src/repositories/event.repository.ts index 671b86f99c680..3156804d09009 100644 --- a/server/src/repositories/event.repository.ts +++ b/server/src/repositories/event.repository.ts @@ -15,10 +15,10 @@ import { EventConfig } from 'src/decorators'; import { AssetResponseDto } from 'src/dtos/asset-response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { ReleaseNotification, ServerVersionResponseDto } from 'src/dtos/server.dto'; -import { ImmichWorker, MetadataKey } from 'src/enum'; -import { JobItem, QueueName } from 'src/interfaces/job.interface'; +import { ImmichWorker, MetadataKey, QueueName } from 'src/enum'; import { ConfigRepository } from 'src/repositories/config.repository'; import { LoggingRepository } from 'src/repositories/logging.repository'; +import { JobItem } from 'src/types'; import { handlePromiseError } from 'src/utils/misc'; type EmitHandlers = Partial<{ [T in EmitEvent]: Array> }>; diff --git a/server/src/repositories/index.ts b/server/src/repositories/index.ts index 3c96f4c89127e..d3a8aeeb69ace 100644 --- a/server/src/repositories/index.ts +++ b/server/src/repositories/index.ts @@ -1,4 +1,3 @@ -import { IJobRepository } from 'src/interfaces/job.interface'; import { AccessRepository } from 'src/repositories/access.repository'; import { ActivityRepository } from 'src/repositories/activity.repository'; import { AlbumUserRepository } from 'src/repositories/album-user.repository'; @@ -52,6 +51,7 @@ export const repositories = [ CryptoRepository, DatabaseRepository, EventRepository, + JobRepository, LibraryRepository, LoggingRepository, MachineLearningRepository, @@ -79,5 +79,3 @@ export const repositories = [ ViewRepository, VersionHistoryRepository, ]; - -export const providers = [{ provide: IJobRepository, useClass: JobRepository }]; diff --git a/server/src/repositories/job.repository.ts b/server/src/repositories/job.repository.ts index d6693f67f3256..fd9f4c5363fb0 100644 --- a/server/src/repositories/job.repository.ts +++ b/server/src/repositories/job.repository.ts @@ -5,22 +5,11 @@ import { JobsOptions, Queue, Worker } from 'bullmq'; import { ClassConstructor } from 'class-transformer'; import { setTimeout } from 'node:timers/promises'; import { JobConfig } from 'src/decorators'; -import { MetadataKey } from 'src/enum'; -import { - IEntityJob, - IJobRepository, - JobCounts, - JobItem, - JobName, - JobOf, - JobStatus, - QueueCleanType, - QueueName, - QueueStatus, -} from 'src/interfaces/job.interface'; +import { JobName, JobStatus, MetadataKey, QueueCleanType, QueueName } from 'src/enum'; import { ConfigRepository } from 'src/repositories/config.repository'; import { EventRepository } from 'src/repositories/event.repository'; import { LoggingRepository } from 'src/repositories/logging.repository'; +import { IEntityJob, JobCounts, JobItem, JobOf, QueueStatus } from 'src/types'; import { getKeyByValue, getMethodNames, ImmichStartupError } from 'src/utils/misc'; type JobMapItem = { @@ -31,7 +20,7 @@ type JobMapItem = { }; @Injectable() -export class JobRepository implements IJobRepository { +export class JobRepository { private workers: Partial> = {}; private handlers: Partial> = {}; diff --git a/server/src/repositories/memory.repository.ts b/server/src/repositories/memory.repository.ts index 042738fe4c0f6..7af363012d6c3 100644 --- a/server/src/repositories/memory.repository.ts +++ b/server/src/repositories/memory.repository.ts @@ -4,7 +4,7 @@ import { jsonArrayFrom } from 'kysely/helpers/postgres'; import { InjectKysely } from 'nestjs-kysely'; import { DB, Memories } from 'src/db'; import { Chunked, ChunkedSet, DummyValue, GenerateSql } from 'src/decorators'; -import { IBulkAsset } from 'src/utils/asset.util'; +import { IBulkAsset } from 'src/types'; @Injectable() export class MemoryRepository implements IBulkAsset { diff --git a/server/src/repositories/notification.repository.ts b/server/src/repositories/notification.repository.ts index fdb74cfdb2c08..91f03b928bb1e 100644 --- a/server/src/repositories/notification.repository.ts +++ b/server/src/repositories/notification.repository.ts @@ -7,12 +7,7 @@ import { AlbumUpdateEmail } from 'src/emails/album-update.email'; import { TestEmail } from 'src/emails/test.email'; import { WelcomeEmail } from 'src/emails/welcome.email'; import { LoggingRepository } from 'src/repositories/logging.repository'; - -export type EmailImageAttachment = { - filename: string; - path: string; - cid: string; -}; +import { EmailImageAttachment } from 'src/types'; export type SendEmailOptions = { from: string; diff --git a/server/src/services/asset-media.service.spec.ts b/server/src/services/asset-media.service.spec.ts index e52f086df054a..97736b905c06a 100644 --- a/server/src/services/asset-media.service.spec.ts +++ b/server/src/services/asset-media.service.spec.ts @@ -9,8 +9,7 @@ import { AssetMediaStatus, AssetRejectReason, AssetUploadAction } from 'src/dtos import { AssetMediaCreateDto, AssetMediaReplaceDto, AssetMediaSize, UploadFieldName } from 'src/dtos/asset-media.dto'; import { AssetFileEntity } from 'src/entities/asset-files.entity'; import { ASSET_CHECKSUM_CONSTRAINT, AssetEntity } from 'src/entities/asset.entity'; -import { AssetFileType, AssetStatus, AssetType, CacheControl } from 'src/enum'; -import { JobName } from 'src/interfaces/job.interface'; +import { AssetFileType, AssetStatus, AssetType, CacheControl, JobName } from 'src/enum'; import { AuthRequest } from 'src/middleware/auth.guard'; import { AssetMediaService } from 'src/services/asset-media.service'; import { ImmichFileResponse } from 'src/utils/file'; diff --git a/server/src/services/asset-media.service.ts b/server/src/services/asset-media.service.ts index fab836db94b32..09ebd9db71547 100644 --- a/server/src/services/asset-media.service.ts +++ b/server/src/services/asset-media.service.ts @@ -21,29 +21,22 @@ import { } from 'src/dtos/asset-media.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { ASSET_CHECKSUM_CONSTRAINT, AssetEntity } from 'src/entities/asset.entity'; -import { AssetStatus, AssetType, CacheControl, Permission, StorageFolder } from 'src/enum'; -import { JobName } from 'src/interfaces/job.interface'; +import { AssetStatus, AssetType, CacheControl, JobName, Permission, StorageFolder } from 'src/enum'; import { AuthRequest } from 'src/middleware/auth.guard'; import { BaseService } from 'src/services/base.service'; +import { UploadFile } from 'src/types'; import { requireUploadAccess } from 'src/utils/access'; import { asRequest, getAssetFiles, onBeforeLink } from 'src/utils/asset.util'; import { getFilenameExtension, getFileNameWithoutExtension, ImmichFileResponse } from 'src/utils/file'; import { mimeTypes } from 'src/utils/mime-types'; import { fromChecksum } from 'src/utils/request'; -export interface UploadRequest { + +interface UploadRequest { auth: AuthDto | null; fieldName: UploadFieldName; file: UploadFile; } -export interface UploadFile { - uuid: string; - checksum: Buffer; - originalPath: string; - originalName: string; - size: number; -} - @Injectable() export class AssetMediaService extends BaseService { async getUploadAssetIdByChecksum(auth: AuthDto, checksum?: string): Promise { diff --git a/server/src/services/asset.service.spec.ts b/server/src/services/asset.service.spec.ts index 3c9cf3739fe5d..336c3ac8f0acd 100755 --- a/server/src/services/asset.service.spec.ts +++ b/server/src/services/asset.service.spec.ts @@ -3,8 +3,7 @@ import { DateTime } from 'luxon'; import { mapAsset } from 'src/dtos/asset-response.dto'; import { AssetJobName, AssetStatsResponseDto } from 'src/dtos/asset.dto'; import { AssetEntity } from 'src/entities/asset.entity'; -import { AssetStatus, AssetType } from 'src/enum'; -import { JobName, JobStatus } from 'src/interfaces/job.interface'; +import { AssetStatus, AssetType, JobName, JobStatus } from 'src/enum'; import { AssetStats } from 'src/repositories/asset.repository'; import { AssetService } from 'src/services/asset.service'; import { assetStub } from 'test/fixtures/asset.stub'; diff --git a/server/src/services/asset.service.ts b/server/src/services/asset.service.ts index 99ddbb29cc9da..a9b723c9f91a9 100644 --- a/server/src/services/asset.service.ts +++ b/server/src/services/asset.service.ts @@ -1,6 +1,7 @@ -import { BadRequestException } from '@nestjs/common'; +import { BadRequestException, Injectable } from '@nestjs/common'; import _ from 'lodash'; import { DateTime, Duration } from 'luxon'; +import { JOBS_ASSET_PAGINATION_SIZE } from 'src/constants'; import { OnJob } from 'src/decorators'; import { AssetResponseDto, @@ -20,20 +21,13 @@ import { import { AuthDto } from 'src/dtos/auth.dto'; import { MemoryLaneDto } from 'src/dtos/search.dto'; import { AssetEntity } from 'src/entities/asset.entity'; -import { AssetStatus, Permission } from 'src/enum'; -import { - ISidecarWriteJob, - JOBS_ASSET_PAGINATION_SIZE, - JobItem, - JobName, - JobOf, - JobStatus, - QueueName, -} from 'src/interfaces/job.interface'; +import { AssetStatus, JobName, JobStatus, Permission, QueueName } from 'src/enum'; import { BaseService } from 'src/services/base.service'; +import { ISidecarWriteJob, JobItem, JobOf } from 'src/types'; import { getAssetFiles, getMyPartnerIds, onAfterUnlink, onBeforeLink, onBeforeUnlink } from 'src/utils/asset.util'; import { usePagination } from 'src/utils/pagination'; +@Injectable() export class AssetService extends BaseService { async getMemoryLane(auth: AuthDto, dto: MemoryLaneDto): Promise { const partnerIds = await getMyPartnerIds({ diff --git a/server/src/services/audit.service.spec.ts b/server/src/services/audit.service.spec.ts index b459ecb473dde..c64f6f2071661 100644 --- a/server/src/services/audit.service.spec.ts +++ b/server/src/services/audit.service.spec.ts @@ -1,7 +1,14 @@ import { BadRequestException } from '@nestjs/common'; import { FileReportItemDto } from 'src/dtos/audit.dto'; -import { AssetFileType, AssetPathType, DatabaseAction, EntityType, PersonPathType, UserPathType } from 'src/enum'; -import { JobStatus } from 'src/interfaces/job.interface'; +import { + AssetFileType, + AssetPathType, + DatabaseAction, + EntityType, + JobStatus, + PersonPathType, + UserPathType, +} from 'src/enum'; import { AuditService } from 'src/services/audit.service'; import { auditStub } from 'test/fixtures/audit.stub'; import { authStub } from 'test/fixtures/auth.stub'; diff --git a/server/src/services/audit.service.ts b/server/src/services/audit.service.ts index 611f8f69d3488..a952a0e64f17a 100644 --- a/server/src/services/audit.service.ts +++ b/server/src/services/audit.service.ts @@ -1,7 +1,7 @@ import { BadRequestException, Injectable } from '@nestjs/common'; import { DateTime } from 'luxon'; import { resolve } from 'node:path'; -import { AUDIT_LOG_MAX_DURATION } from 'src/constants'; +import { AUDIT_LOG_MAX_DURATION, JOBS_ASSET_PAGINATION_SIZE } from 'src/constants'; import { StorageCore } from 'src/cores/storage.core'; import { OnJob } from 'src/decorators'; import { @@ -17,12 +17,14 @@ import { AssetFileType, AssetPathType, DatabaseAction, + JobName, + JobStatus, Permission, PersonPathType, + QueueName, StorageFolder, UserPathType, } from 'src/enum'; -import { JobName, JOBS_ASSET_PAGINATION_SIZE, JobStatus, QueueName } from 'src/interfaces/job.interface'; import { BaseService } from 'src/services/base.service'; import { getAssetFiles } from 'src/utils/asset.util'; import { usePagination } from 'src/utils/pagination'; diff --git a/server/src/services/backup.service.spec.ts b/server/src/services/backup.service.spec.ts index fbed87a6d33ef..567859ac010a7 100644 --- a/server/src/services/backup.service.spec.ts +++ b/server/src/services/backup.service.spec.ts @@ -1,8 +1,7 @@ import { PassThrough } from 'node:stream'; import { defaults, SystemConfig } from 'src/config'; import { StorageCore } from 'src/cores/storage.core'; -import { ImmichWorker, StorageFolder } from 'src/enum'; -import { JobStatus } from 'src/interfaces/job.interface'; +import { ImmichWorker, JobStatus, StorageFolder } from 'src/enum'; import { BackupService } from 'src/services/backup.service'; import { systemConfigStub } from 'test/fixtures/system-config.stub'; import { mockSpawn, newTestService, ServiceMocks } from 'test/utils'; diff --git a/server/src/services/backup.service.ts b/server/src/services/backup.service.ts index dee8113792f5a..e4fe791b190b5 100644 --- a/server/src/services/backup.service.ts +++ b/server/src/services/backup.service.ts @@ -3,9 +3,7 @@ import { default as path } from 'node:path'; import semver from 'semver'; import { StorageCore } from 'src/cores/storage.core'; import { OnEvent, OnJob } from 'src/decorators'; -import { ImmichWorker, StorageFolder } from 'src/enum'; -import { JobName, JobStatus, QueueName } from 'src/interfaces/job.interface'; -import { DatabaseLock } from 'src/repositories/database.repository'; +import { DatabaseLock, ImmichWorker, JobName, JobStatus, QueueName, StorageFolder } from 'src/enum'; import { ArgOf } from 'src/repositories/event.repository'; import { BaseService } from 'src/services/base.service'; import { handlePromiseError } from 'src/utils/misc'; diff --git a/server/src/services/base.service.ts b/server/src/services/base.service.ts index 259248e49b6f9..f476adba11391 100644 --- a/server/src/services/base.service.ts +++ b/server/src/services/base.service.ts @@ -1,4 +1,4 @@ -import { BadRequestException, Inject } from '@nestjs/common'; +import { BadRequestException, Injectable } from '@nestjs/common'; import { Insertable } from 'kysely'; import sanitize from 'sanitize-filename'; import { SystemConfig } from 'src/config'; @@ -6,7 +6,6 @@ import { SALT_ROUNDS } from 'src/constants'; import { StorageCore } from 'src/cores/storage.core'; import { Users } from 'src/db'; import { UserEntity } from 'src/entities/user.entity'; -import { IJobRepository } from 'src/interfaces/job.interface'; import { AccessRepository } from 'src/repositories/access.repository'; import { ActivityRepository } from 'src/repositories/activity.repository'; import { AlbumUserRepository } from 'src/repositories/album-user.repository'; @@ -19,6 +18,7 @@ import { CronRepository } from 'src/repositories/cron.repository'; import { CryptoRepository } from 'src/repositories/crypto.repository'; import { DatabaseRepository } from 'src/repositories/database.repository'; import { EventRepository } from 'src/repositories/event.repository'; +import { JobRepository } from 'src/repositories/job.repository'; import { LibraryRepository } from 'src/repositories/library.repository'; import { LoggingRepository } from 'src/repositories/logging.repository'; import { MachineLearningRepository } from 'src/repositories/machine-learning.repository'; @@ -48,6 +48,7 @@ import { ViewRepository } from 'src/repositories/view-repository'; import { AccessRequest, checkAccess, requireAccess } from 'src/utils/access'; import { getConfig, updateConfig } from 'src/utils/config'; +@Injectable() export class BaseService { protected storageCore: StorageCore; @@ -64,7 +65,7 @@ export class BaseService { protected cryptoRepository: CryptoRepository, protected databaseRepository: DatabaseRepository, protected eventRepository: EventRepository, - @Inject(IJobRepository) protected jobRepository: IJobRepository, + protected jobRepository: JobRepository, protected keyRepository: ApiKeyRepository, protected libraryRepository: LibraryRepository, protected machineLearningRepository: MachineLearningRepository, diff --git a/server/src/services/database.service.spec.ts b/server/src/services/database.service.spec.ts index d50b7facf6b0a..1314d5327e8e2 100644 --- a/server/src/services/database.service.spec.ts +++ b/server/src/services/database.service.spec.ts @@ -1,6 +1,7 @@ +import { EXTENSION_NAMES } from 'src/constants'; import { DatabaseExtension } from 'src/enum'; -import { EXTENSION_NAMES, VectorExtension } from 'src/repositories/database.repository'; import { DatabaseService } from 'src/services/database.service'; +import { VectorExtension } from 'src/types'; import { mockEnvData } from 'test/repositories/config.repository.mock'; import { newTestService, ServiceMocks } from 'test/utils'; diff --git a/server/src/services/database.service.ts b/server/src/services/database.service.ts index 249b47c99cffb..36f4c0917719e 100644 --- a/server/src/services/database.service.ts +++ b/server/src/services/database.service.ts @@ -1,10 +1,11 @@ import { Injectable } from '@nestjs/common'; import { Duration } from 'luxon'; import semver from 'semver'; +import { EXTENSION_NAMES } from 'src/constants'; import { OnEvent } from 'src/decorators'; -import { BootstrapEventPriority, DatabaseExtension } from 'src/enum'; -import { DatabaseLock, EXTENSION_NAMES, VectorExtension, VectorIndex } from 'src/repositories/database.repository'; +import { BootstrapEventPriority, DatabaseExtension, DatabaseLock, VectorIndex } from 'src/enum'; import { BaseService } from 'src/services/base.service'; +import { VectorExtension } from 'src/types'; type CreateFailedArgs = { name: string; extension: string; otherName: string }; type UpdateFailedArgs = { name: string; extension: string; availableVersion: string }; diff --git a/server/src/services/duplicate.service.spec.ts b/server/src/services/duplicate.service.spec.ts index 7a8b9ed27bf0c..30b8cd345185c 100644 --- a/server/src/services/duplicate.service.spec.ts +++ b/server/src/services/duplicate.service.spec.ts @@ -1,4 +1,4 @@ -import { JobName, JobStatus } from 'src/interfaces/job.interface'; +import { JobName, JobStatus } from 'src/enum'; import { WithoutProperty } from 'src/repositories/asset.repository'; import { DuplicateService } from 'src/services/duplicate.service'; import { SearchService } from 'src/services/search.service'; diff --git a/server/src/services/duplicate.service.ts b/server/src/services/duplicate.service.ts index 1b0d583cc3024..5600033b47520 100644 --- a/server/src/services/duplicate.service.ts +++ b/server/src/services/duplicate.service.ts @@ -1,13 +1,15 @@ import { Injectable } from '@nestjs/common'; +import { JOBS_ASSET_PAGINATION_SIZE } from 'src/constants'; import { OnJob } from 'src/decorators'; import { mapAsset } from 'src/dtos/asset-response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { DuplicateResponseDto } from 'src/dtos/duplicate.dto'; import { AssetEntity } from 'src/entities/asset.entity'; -import { JOBS_ASSET_PAGINATION_SIZE, JobName, JobOf, JobStatus, QueueName } from 'src/interfaces/job.interface'; +import { JobName, JobStatus, QueueName } from 'src/enum'; import { WithoutProperty } from 'src/repositories/asset.repository'; import { AssetDuplicateResult } from 'src/repositories/search.repository'; import { BaseService } from 'src/services/base.service'; +import { JobOf } from 'src/types'; import { getAssetFiles } from 'src/utils/asset.util'; import { isDuplicateDetectionEnabled } from 'src/utils/misc'; import { usePagination } from 'src/utils/pagination'; diff --git a/server/src/services/job.service.spec.ts b/server/src/services/job.service.spec.ts index 8b0b5c408c55d..6797ffc396e23 100644 --- a/server/src/services/job.service.spec.ts +++ b/server/src/services/job.service.spec.ts @@ -1,8 +1,8 @@ import { BadRequestException } from '@nestjs/common'; import { defaults, SystemConfig } from 'src/config'; -import { ImmichWorker } from 'src/enum'; -import { JobCommand, JobItem, JobName, JobStatus, QueueName } from 'src/interfaces/job.interface'; +import { ImmichWorker, JobCommand, JobName, JobStatus, QueueName } from 'src/enum'; import { JobService } from 'src/services/job.service'; +import { JobItem } from 'src/types'; import { assetStub } from 'test/fixtures/asset.stub'; import { newTestService, ServiceMocks } from 'test/utils'; diff --git a/server/src/services/job.service.ts b/server/src/services/job.service.ts index 00d9a398fdc9c..8e3919a2b1a6e 100644 --- a/server/src/services/job.service.ts +++ b/server/src/services/job.service.ts @@ -3,18 +3,19 @@ import { snakeCase } from 'lodash'; import { OnEvent } from 'src/decorators'; import { mapAsset } from 'src/dtos/asset-response.dto'; import { AllJobStatusResponseDto, JobCommandDto, JobCreateDto, JobStatusDto } from 'src/dtos/job.dto'; -import { AssetType, ImmichWorker, ManualJobName } from 'src/enum'; import { - ConcurrentQueueName, + AssetType, + ImmichWorker, JobCommand, - JobItem, JobName, JobStatus, + ManualJobName, QueueCleanType, QueueName, -} from 'src/interfaces/job.interface'; +} from 'src/enum'; import { ArgOf, ArgsOf } from 'src/repositories/event.repository'; import { BaseService } from 'src/services/base.service'; +import { ConcurrentQueueName, JobItem } from 'src/types'; const asJobItem = (dto: JobCreateDto): JobItem => { switch (dto.name) { diff --git a/server/src/services/library.service.spec.ts b/server/src/services/library.service.spec.ts index 24b1265ae9667..ded7e0630a4ee 100644 --- a/server/src/services/library.service.spec.ts +++ b/server/src/services/library.service.spec.ts @@ -1,17 +1,12 @@ import { BadRequestException } from '@nestjs/common'; import { Stats } from 'node:fs'; import { defaults, SystemConfig } from 'src/config'; +import { JOBS_LIBRARY_PAGINATION_SIZE } from 'src/constants'; import { mapLibrary } from 'src/dtos/library.dto'; import { UserEntity } from 'src/entities/user.entity'; -import { AssetType, ImmichWorker } from 'src/enum'; -import { - ILibraryAssetJob, - ILibraryFileJob, - JobName, - JOBS_LIBRARY_PAGINATION_SIZE, - JobStatus, -} from 'src/interfaces/job.interface'; +import { AssetType, ImmichWorker, JobName, JobStatus } from 'src/enum'; import { LibraryService } from 'src/services/library.service'; +import { ILibraryAssetJob, ILibraryFileJob } from 'src/types'; import { assetStub } from 'test/fixtures/asset.stub'; import { authStub } from 'test/fixtures/auth.stub'; import { libraryStub } from 'test/fixtures/library.stub'; diff --git a/server/src/services/library.service.ts b/server/src/services/library.service.ts index fb748276565c6..4a9614e010237 100644 --- a/server/src/services/library.service.ts +++ b/server/src/services/library.service.ts @@ -2,6 +2,7 @@ import { BadRequestException, Injectable } from '@nestjs/common'; import { R_OK } from 'node:constants'; import path, { basename, isAbsolute, parse } from 'node:path'; import picomatch from 'picomatch'; +import { JOBS_LIBRARY_PAGINATION_SIZE } from 'src/constants'; import { StorageCore } from 'src/cores/storage.core'; import { OnEvent, OnJob } from 'src/decorators'; import { @@ -16,11 +17,10 @@ import { } from 'src/dtos/library.dto'; import { AssetEntity } from 'src/entities/asset.entity'; import { LibraryEntity } from 'src/entities/library.entity'; -import { AssetType, ImmichWorker } from 'src/enum'; -import { JobName, JobOf, JOBS_LIBRARY_PAGINATION_SIZE, JobStatus, QueueName } from 'src/interfaces/job.interface'; -import { DatabaseLock } from 'src/repositories/database.repository'; +import { AssetType, DatabaseLock, ImmichWorker, JobName, JobStatus, QueueName } from 'src/enum'; import { ArgOf } from 'src/repositories/event.repository'; import { BaseService } from 'src/services/base.service'; +import { JobOf } from 'src/types'; import { mimeTypes } from 'src/utils/mime-types'; import { handlePromiseError } from 'src/utils/misc'; import { usePagination } from 'src/utils/pagination'; diff --git a/server/src/services/map.service.ts b/server/src/services/map.service.ts index 860a782e79a0b..94eca77a60447 100644 --- a/server/src/services/map.service.ts +++ b/server/src/services/map.service.ts @@ -1,8 +1,10 @@ +import { Injectable } from '@nestjs/common'; import { AuthDto } from 'src/dtos/auth.dto'; import { MapMarkerDto, MapMarkerResponseDto, MapReverseGeocodeDto } from 'src/dtos/map.dto'; import { BaseService } from 'src/services/base.service'; import { getMyPartnerIds } from 'src/utils/asset.util'; +@Injectable() export class MapService extends BaseService { async getMapMarkers(auth: AuthDto, options: MapMarkerDto): Promise { const userIds = [auth.user.id]; diff --git a/server/src/services/media.service.spec.ts b/server/src/services/media.service.spec.ts index 52ccab1c9194c..d98cff866fc4d 100644 --- a/server/src/services/media.service.spec.ts +++ b/server/src/services/media.service.spec.ts @@ -9,14 +9,15 @@ import { AudioCodec, Colorspace, ImageFormat, + JobName, + JobStatus, TranscodeHWAccel, TranscodePolicy, VideoCodec, } from 'src/enum'; -import { JobCounts, JobName, JobStatus } from 'src/interfaces/job.interface'; import { WithoutProperty } from 'src/repositories/asset.repository'; import { MediaService } from 'src/services/media.service'; -import { RawImageInfo } from 'src/types'; +import { JobCounts, RawImageInfo } from 'src/types'; import { assetStub } from 'test/fixtures/asset.stub'; import { faceStub } from 'test/fixtures/face.stub'; import { probeStub } from 'test/fixtures/media.stub'; diff --git a/server/src/services/media.service.ts b/server/src/services/media.service.ts index 58621c1b196d5..54540dff66531 100644 --- a/server/src/services/media.service.ts +++ b/server/src/services/media.service.ts @@ -1,5 +1,6 @@ import { Injectable } from '@nestjs/common'; import { dirname } from 'node:path'; +import { JOBS_ASSET_PAGINATION_SIZE } from 'src/constants'; import { StorageCore } from 'src/cores/storage.core'; import { OnEvent, OnJob } from 'src/decorators'; import { SystemConfigFFmpegDto } from 'src/dtos/system-config.dto'; @@ -10,7 +11,10 @@ import { AssetType, AudioCodec, Colorspace, + JobName, + JobStatus, LogLevel, + QueueName, StorageFolder, TranscodeHWAccel, TranscodePolicy, @@ -18,17 +22,9 @@ import { VideoCodec, VideoContainer, } from 'src/enum'; -import { - JOBS_ASSET_PAGINATION_SIZE, - JobItem, - JobName, - JobOf, - JobStatus, - QueueName, -} from 'src/interfaces/job.interface'; import { UpsertFileOptions, WithoutProperty } from 'src/repositories/asset.repository'; import { BaseService } from 'src/services/base.service'; -import { AudioStreamInfo, VideoFormat, VideoInterfaces, VideoStreamInfo } from 'src/types'; +import { AudioStreamInfo, JobItem, JobOf, VideoFormat, VideoInterfaces, VideoStreamInfo } from 'src/types'; import { getAssetFiles } from 'src/utils/asset.util'; import { BaseConfig, ThumbnailConfig } from 'src/utils/media'; import { mimeTypes } from 'src/utils/mime-types'; diff --git a/server/src/services/metadata.service.spec.ts b/server/src/services/metadata.service.spec.ts index c7c675ab3ecb2..0e0c6546ca481 100644 --- a/server/src/services/metadata.service.spec.ts +++ b/server/src/services/metadata.service.spec.ts @@ -4,8 +4,7 @@ import { Stats } from 'node:fs'; import { constants } from 'node:fs/promises'; import { AssetEntity } from 'src/entities/asset.entity'; import { ExifEntity } from 'src/entities/exif.entity'; -import { AssetType, ExifOrientation, ImmichWorker, SourceType } from 'src/enum'; -import { JobName, JobStatus } from 'src/interfaces/job.interface'; +import { AssetType, ExifOrientation, ImmichWorker, JobName, JobStatus, SourceType } from 'src/enum'; import { WithoutProperty } from 'src/repositories/asset.repository'; import { ImmichTags } from 'src/repositories/metadata.repository'; import { MetadataService } from 'src/services/metadata.service'; diff --git a/server/src/services/metadata.service.ts b/server/src/services/metadata.service.ts index 33db5d3149450..8c2e3646a0243 100644 --- a/server/src/services/metadata.service.ts +++ b/server/src/services/metadata.service.ts @@ -7,20 +7,29 @@ import { Duration } from 'luxon'; import { constants } from 'node:fs/promises'; import path from 'node:path'; import { SystemConfig } from 'src/config'; +import { JOBS_ASSET_PAGINATION_SIZE } from 'src/constants'; import { StorageCore } from 'src/cores/storage.core'; import { Exif } from 'src/db'; import { OnEvent, OnJob } from 'src/decorators'; import { AssetFaceEntity } from 'src/entities/asset-face.entity'; import { AssetEntity } from 'src/entities/asset.entity'; import { PersonEntity } from 'src/entities/person.entity'; -import { AssetType, ExifOrientation, ImmichWorker, SourceType } from 'src/enum'; -import { JobName, JobOf, JOBS_ASSET_PAGINATION_SIZE, JobStatus, QueueName } from 'src/interfaces/job.interface'; +import { + AssetType, + DatabaseLock, + ExifOrientation, + ImmichWorker, + JobName, + JobStatus, + QueueName, + SourceType, +} from 'src/enum'; import { WithoutProperty } from 'src/repositories/asset.repository'; -import { DatabaseLock } from 'src/repositories/database.repository'; import { ArgOf } from 'src/repositories/event.repository'; import { ReverseGeocodeResult } from 'src/repositories/map.repository'; import { ImmichTags } from 'src/repositories/metadata.repository'; import { BaseService } from 'src/services/base.service'; +import { JobOf } from 'src/types'; import { isFaceImportEnabled } from 'src/utils/misc'; import { usePagination } from 'src/utils/pagination'; import { upsertTags } from 'src/utils/tag'; diff --git a/server/src/services/notification.service.spec.ts b/server/src/services/notification.service.spec.ts index 35f1601c728d6..038ab1180c8b7 100644 --- a/server/src/services/notification.service.spec.ts +++ b/server/src/services/notification.service.spec.ts @@ -3,10 +3,10 @@ import { defaults, SystemConfig } from 'src/config'; import { SystemConfigDto } from 'src/dtos/system-config.dto'; import { AlbumUserEntity } from 'src/entities/album-user.entity'; import { AssetFileEntity } from 'src/entities/asset-files.entity'; -import { AssetFileType, UserMetadataKey } from 'src/enum'; -import { INotifyAlbumUpdateJob, JobName, JobStatus } from 'src/interfaces/job.interface'; +import { AssetFileType, JobName, JobStatus, UserMetadataKey } from 'src/enum'; import { EmailTemplate } from 'src/repositories/notification.repository'; import { NotificationService } from 'src/services/notification.service'; +import { INotifyAlbumUpdateJob } from 'src/types'; import { albumStub } from 'test/fixtures/album.stub'; import { assetStub } from 'test/fixtures/asset.stub'; import { userStub } from 'test/fixtures/user.stub'; diff --git a/server/src/services/notification.service.ts b/server/src/services/notification.service.ts index f9a2194088651..003b320997d95 100644 --- a/server/src/services/notification.service.ts +++ b/server/src/services/notification.service.ts @@ -2,18 +2,11 @@ import { BadRequestException, Injectable } from '@nestjs/common'; import { OnEvent, OnJob } from 'src/decorators'; import { SystemConfigSmtpDto } from 'src/dtos/system-config.dto'; import { AlbumEntity } from 'src/entities/album.entity'; -import { - IEntityJob, - INotifyAlbumUpdateJob, - JobItem, - JobName, - JobOf, - JobStatus, - QueueName, -} from 'src/interfaces/job.interface'; +import { JobName, JobStatus, QueueName } from 'src/enum'; import { ArgOf } from 'src/repositories/event.repository'; -import { EmailImageAttachment, EmailTemplate } from 'src/repositories/notification.repository'; +import { EmailTemplate } from 'src/repositories/notification.repository'; import { BaseService } from 'src/services/base.service'; +import { EmailImageAttachment, IEntityJob, INotifyAlbumUpdateJob, JobItem, JobOf } from 'src/types'; import { getAssetFiles } from 'src/utils/asset.util'; import { getFilenameExtension } from 'src/utils/file'; import { getExternalDomain } from 'src/utils/misc'; diff --git a/server/src/services/person.service.spec.ts b/server/src/services/person.service.spec.ts index 8e1cff302fdc9..ba327ddae9a52 100644 --- a/server/src/services/person.service.spec.ts +++ b/server/src/services/person.service.spec.ts @@ -2,8 +2,7 @@ import { BadRequestException, NotFoundException } from '@nestjs/common'; import { BulkIdErrorReason } from 'src/dtos/asset-ids.response.dto'; import { mapFaces, mapPerson, PersonResponseDto } from 'src/dtos/person.dto'; import { AssetFaceEntity } from 'src/entities/asset-face.entity'; -import { CacheControl, Colorspace, ImageFormat, SourceType, SystemMetadataKey } from 'src/enum'; -import { JobName, JobStatus } from 'src/interfaces/job.interface'; +import { CacheControl, Colorspace, ImageFormat, JobName, JobStatus, SourceType, SystemMetadataKey } from 'src/enum'; import { WithoutProperty } from 'src/repositories/asset.repository'; import { DetectedFaces } from 'src/repositories/machine-learning.repository'; import { FaceSearchResult } from 'src/repositories/search.repository'; diff --git a/server/src/services/person.service.ts b/server/src/services/person.service.ts index e9933b421cb16..ecb8677f716db 100644 --- a/server/src/services/person.service.ts +++ b/server/src/services/person.service.ts @@ -1,5 +1,5 @@ import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common'; -import { FACE_THUMBNAIL_SIZE } from 'src/constants'; +import { FACE_THUMBNAIL_SIZE, JOBS_ASSET_PAGINATION_SIZE } from 'src/constants'; import { StorageCore } from 'src/cores/storage.core'; import { OnJob } from 'src/decorators'; import { BulkIdErrorReason, BulkIdResponseDto } from 'src/dtos/asset-ids.response.dto'; @@ -27,24 +27,19 @@ import { AssetType, CacheControl, ImageFormat, + JobName, + JobStatus, Permission, PersonPathType, + QueueName, SourceType, SystemMetadataKey, } from 'src/enum'; -import { - JOBS_ASSET_PAGINATION_SIZE, - JobItem, - JobName, - JobOf, - JobStatus, - QueueName, -} from 'src/interfaces/job.interface'; import { WithoutProperty } from 'src/repositories/asset.repository'; import { BoundingBox } from 'src/repositories/machine-learning.repository'; import { UpdateFacesData } from 'src/repositories/person.repository'; import { BaseService } from 'src/services/base.service'; -import { CropOptions, ImageDimensions, InputDimensions } from 'src/types'; +import { CropOptions, ImageDimensions, InputDimensions, JobItem, JobOf } from 'src/types'; import { getAssetFiles } from 'src/utils/asset.util'; import { ImmichFileResponse } from 'src/utils/file'; import { mimeTypes } from 'src/utils/mime-types'; diff --git a/server/src/services/session.service.spec.ts b/server/src/services/session.service.spec.ts index c25c0feb82215..8c22abb7f0c8c 100644 --- a/server/src/services/session.service.spec.ts +++ b/server/src/services/session.service.spec.ts @@ -1,4 +1,4 @@ -import { JobStatus } from 'src/interfaces/job.interface'; +import { JobStatus } from 'src/enum'; import { SessionService } from 'src/services/session.service'; import { authStub } from 'test/fixtures/auth.stub'; import { sessionStub } from 'test/fixtures/session.stub'; diff --git a/server/src/services/session.service.ts b/server/src/services/session.service.ts index 68df7828ad784..6b0632cd447fc 100644 --- a/server/src/services/session.service.ts +++ b/server/src/services/session.service.ts @@ -3,8 +3,7 @@ import { DateTime } from 'luxon'; import { OnJob } from 'src/decorators'; import { AuthDto } from 'src/dtos/auth.dto'; import { SessionResponseDto, mapSession } from 'src/dtos/session.dto'; -import { Permission } from 'src/enum'; -import { JobName, JobStatus, QueueName } from 'src/interfaces/job.interface'; +import { JobName, JobStatus, Permission, QueueName } from 'src/enum'; import { BaseService } from 'src/services/base.service'; @Injectable() diff --git a/server/src/services/smart-info.service.spec.ts b/server/src/services/smart-info.service.spec.ts index 403c6e9a6a65b..aef83a813d560 100644 --- a/server/src/services/smart-info.service.spec.ts +++ b/server/src/services/smart-info.service.spec.ts @@ -1,6 +1,5 @@ import { SystemConfig } from 'src/config'; -import { ImmichWorker } from 'src/enum'; -import { JobName, JobStatus } from 'src/interfaces/job.interface'; +import { ImmichWorker, JobName, JobStatus } from 'src/enum'; import { WithoutProperty } from 'src/repositories/asset.repository'; import { SmartInfoService } from 'src/services/smart-info.service'; import { getCLIPModelInfo } from 'src/utils/misc'; diff --git a/server/src/services/smart-info.service.ts b/server/src/services/smart-info.service.ts index 0a03c27a55949..063bb0bd3b79f 100644 --- a/server/src/services/smart-info.service.ts +++ b/server/src/services/smart-info.service.ts @@ -1,12 +1,12 @@ import { Injectable } from '@nestjs/common'; import { SystemConfig } from 'src/config'; +import { JOBS_ASSET_PAGINATION_SIZE } from 'src/constants'; import { OnEvent, OnJob } from 'src/decorators'; -import { ImmichWorker } from 'src/enum'; -import { JOBS_ASSET_PAGINATION_SIZE, JobName, JobOf, JobStatus, QueueName } from 'src/interfaces/job.interface'; +import { DatabaseLock, ImmichWorker, JobName, JobStatus, QueueName } from 'src/enum'; import { WithoutProperty } from 'src/repositories/asset.repository'; -import { DatabaseLock } from 'src/repositories/database.repository'; import { ArgOf } from 'src/repositories/event.repository'; import { BaseService } from 'src/services/base.service'; +import { JobOf } from 'src/types'; import { getAssetFiles } from 'src/utils/asset.util'; import { getCLIPModelInfo, isSmartSearchEnabled } from 'src/utils/misc'; import { usePagination } from 'src/utils/pagination'; diff --git a/server/src/services/storage-template.service.spec.ts b/server/src/services/storage-template.service.spec.ts index cf272c7e5f261..0a055d0e6d6ae 100644 --- a/server/src/services/storage-template.service.spec.ts +++ b/server/src/services/storage-template.service.spec.ts @@ -1,8 +1,7 @@ import { Stats } from 'node:fs'; import { defaults, SystemConfig } from 'src/config'; import { AssetEntity } from 'src/entities/asset.entity'; -import { AssetPathType } from 'src/enum'; -import { JobStatus } from 'src/interfaces/job.interface'; +import { AssetPathType, JobStatus } from 'src/enum'; import { StorageTemplateService } from 'src/services/storage-template.service'; import { albumStub } from 'test/fixtures/album.stub'; import { assetStub } from 'test/fixtures/asset.stub'; diff --git a/server/src/services/storage-template.service.ts b/server/src/services/storage-template.service.ts index 6fd139c10d1e4..24a9fcd4594a5 100644 --- a/server/src/services/storage-template.service.ts +++ b/server/src/services/storage-template.service.ts @@ -3,15 +3,15 @@ import handlebar from 'handlebars'; import { DateTime } from 'luxon'; import path from 'node:path'; import sanitize from 'sanitize-filename'; +import { JOBS_ASSET_PAGINATION_SIZE } from 'src/constants'; import { StorageCore } from 'src/cores/storage.core'; import { OnEvent, OnJob } from 'src/decorators'; import { SystemConfigTemplateStorageOptionDto } from 'src/dtos/system-config.dto'; import { AssetEntity } from 'src/entities/asset.entity'; -import { AssetPathType, AssetType, StorageFolder } from 'src/enum'; -import { JobName, JobOf, JOBS_ASSET_PAGINATION_SIZE, JobStatus, QueueName } from 'src/interfaces/job.interface'; -import { DatabaseLock } from 'src/repositories/database.repository'; +import { AssetPathType, AssetType, DatabaseLock, JobName, JobStatus, QueueName, StorageFolder } from 'src/enum'; import { ArgOf } from 'src/repositories/event.repository'; import { BaseService } from 'src/services/base.service'; +import { JobOf } from 'src/types'; import { getLivePhotoMotionFilename } from 'src/utils/file'; import { usePagination } from 'src/utils/pagination'; diff --git a/server/src/services/storage.service.ts b/server/src/services/storage.service.ts index 6921d3356055a..c0c7a00ae7931 100644 --- a/server/src/services/storage.service.ts +++ b/server/src/services/storage.service.ts @@ -3,10 +3,9 @@ import { join } from 'node:path'; import { StorageCore } from 'src/cores/storage.core'; import { OnEvent, OnJob } from 'src/decorators'; import { SystemFlags } from 'src/entities/system-metadata.entity'; -import { StorageFolder, SystemMetadataKey } from 'src/enum'; -import { JobName, JobOf, JobStatus, QueueName } from 'src/interfaces/job.interface'; -import { DatabaseLock } from 'src/repositories/database.repository'; +import { DatabaseLock, JobName, JobStatus, QueueName, StorageFolder, SystemMetadataKey } from 'src/enum'; import { BaseService } from 'src/services/base.service'; +import { JobOf } from 'src/types'; import { ImmichStartupError } from 'src/utils/misc'; const docsMessage = `Please see https://immich.app/docs/administration/system-integrity#folder-checks for more information.`; diff --git a/server/src/services/sync.service.ts b/server/src/services/sync.service.ts index f85200db489fa..fe967e37e07b3 100644 --- a/server/src/services/sync.service.ts +++ b/server/src/services/sync.service.ts @@ -1,3 +1,4 @@ +import { Injectable } from '@nestjs/common'; import { DateTime } from 'luxon'; import { AUDIT_LOG_MAX_DURATION } from 'src/constants'; import { AssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto'; @@ -10,6 +11,7 @@ import { setIsEqual } from 'src/utils/set'; const FULL_SYNC = { needsFullSync: true, deleted: [], upserted: [] }; +@Injectable() export class SyncService extends BaseService { async getFullSync(auth: AuthDto, dto: AssetFullSyncDto): Promise { // mobile implementation is faster if this is a single id diff --git a/server/src/services/system-config.service.spec.ts b/server/src/services/system-config.service.spec.ts index 027bcc1c157ba..8a06a883c2c82 100644 --- a/server/src/services/system-config.service.spec.ts +++ b/server/src/services/system-config.service.spec.ts @@ -6,13 +6,13 @@ import { CQMode, ImageFormat, LogLevel, + QueueName, ToneMapping, TranscodeHWAccel, TranscodePolicy, VideoCodec, VideoContainer, } from 'src/enum'; -import { QueueName } from 'src/interfaces/job.interface'; import { SystemConfigService } from 'src/services/system-config.service'; import { DeepPartial } from 'src/types'; import { mockEnvData } from 'test/repositories/config.repository.mock'; diff --git a/server/src/services/system-config.service.ts b/server/src/services/system-config.service.ts index cc32ef0c341d6..2dd8dcf0ee544 100644 --- a/server/src/services/system-config.service.ts +++ b/server/src/services/system-config.service.ts @@ -3,7 +3,7 @@ import { instanceToPlain } from 'class-transformer'; import _ from 'lodash'; import { defaults } from 'src/config'; import { OnEvent } from 'src/decorators'; -import { SystemConfigDto, mapConfig } from 'src/dtos/system-config.dto'; +import { mapConfig, SystemConfigDto } from 'src/dtos/system-config.dto'; import { BootstrapEventPriority } from 'src/enum'; import { ArgOf } from 'src/repositories/event.repository'; import { BaseService } from 'src/services/base.service'; diff --git a/server/src/services/tag.service.spec.ts b/server/src/services/tag.service.spec.ts index 48d1b0037994c..f1385eb8c8b09 100644 --- a/server/src/services/tag.service.spec.ts +++ b/server/src/services/tag.service.spec.ts @@ -1,6 +1,6 @@ import { BadRequestException } from '@nestjs/common'; import { BulkIdErrorReason } from 'src/dtos/asset-ids.response.dto'; -import { JobStatus } from 'src/interfaces/job.interface'; +import { JobStatus } from 'src/enum'; import { TagService } from 'src/services/tag.service'; import { authStub } from 'test/fixtures/auth.stub'; import { tagResponseStub, tagStub } from 'test/fixtures/tag.stub'; diff --git a/server/src/services/tag.service.ts b/server/src/services/tag.service.ts index 83d4b40340b3d..c241f59a80c10 100644 --- a/server/src/services/tag.service.ts +++ b/server/src/services/tag.service.ts @@ -12,8 +12,7 @@ import { mapTag, } from 'src/dtos/tag.dto'; import { TagEntity } from 'src/entities/tag.entity'; -import { Permission } from 'src/enum'; -import { JobName, JobStatus, QueueName } from 'src/interfaces/job.interface'; +import { JobName, JobStatus, Permission, QueueName } from 'src/enum'; import { AssetTagItem } from 'src/repositories/tag.repository'; import { BaseService } from 'src/services/base.service'; import { addAssets, removeAssets } from 'src/utils/asset.util'; diff --git a/server/src/services/timeline.service.ts b/server/src/services/timeline.service.ts index bc4c7fad734ac..4c2332afaa306 100644 --- a/server/src/services/timeline.service.ts +++ b/server/src/services/timeline.service.ts @@ -1,4 +1,4 @@ -import { BadRequestException } from '@nestjs/common'; +import { BadRequestException, Injectable } from '@nestjs/common'; import { AssetResponseDto, SanitizedAssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { TimeBucketAssetDto, TimeBucketDto, TimeBucketResponseDto } from 'src/dtos/time-bucket.dto'; @@ -7,6 +7,7 @@ import { TimeBucketOptions } from 'src/repositories/asset.repository'; import { BaseService } from 'src/services/base.service'; import { getMyPartnerIds } from 'src/utils/asset.util'; +@Injectable() export class TimelineService extends BaseService { async getTimeBuckets(auth: AuthDto, dto: TimeBucketDto): Promise { await this.timeBucketChecks(auth, dto); diff --git a/server/src/services/trash.service.spec.ts b/server/src/services/trash.service.spec.ts index 536fb65f9a68b..e7eccd374cb13 100644 --- a/server/src/services/trash.service.spec.ts +++ b/server/src/services/trash.service.spec.ts @@ -1,5 +1,5 @@ import { BadRequestException } from '@nestjs/common'; -import { JobName, JobStatus } from 'src/interfaces/job.interface'; +import { JobName, JobStatus } from 'src/enum'; import { TrashService } from 'src/services/trash.service'; import { authStub } from 'test/fixtures/auth.stub'; import { newTestService, ServiceMocks } from 'test/utils'; diff --git a/server/src/services/trash.service.ts b/server/src/services/trash.service.ts index d66461ef94b0b..f33b24982360e 100644 --- a/server/src/services/trash.service.ts +++ b/server/src/services/trash.service.ts @@ -1,11 +1,13 @@ +import { Injectable } from '@nestjs/common'; +import { JOBS_ASSET_PAGINATION_SIZE } from 'src/constants'; import { OnEvent, OnJob } from 'src/decorators'; import { BulkIdsDto } from 'src/dtos/asset-ids.response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { TrashResponseDto } from 'src/dtos/trash.dto'; -import { Permission } from 'src/enum'; -import { JOBS_ASSET_PAGINATION_SIZE, JobName, JobStatus, QueueName } from 'src/interfaces/job.interface'; +import { JobName, JobStatus, Permission, QueueName } from 'src/enum'; import { BaseService } from 'src/services/base.service'; +@Injectable() export class TrashService extends BaseService { async restoreAssets(auth: AuthDto, dto: BulkIdsDto): Promise { const { ids } = dto; diff --git a/server/src/services/user-admin.service.spec.ts b/server/src/services/user-admin.service.spec.ts index 604062c97adb5..3e613bc485c74 100644 --- a/server/src/services/user-admin.service.spec.ts +++ b/server/src/services/user-admin.service.spec.ts @@ -1,7 +1,6 @@ import { BadRequestException, ForbiddenException } from '@nestjs/common'; import { mapUserAdmin } from 'src/dtos/user.dto'; -import { UserStatus } from 'src/enum'; -import { JobName } from 'src/interfaces/job.interface'; +import { JobName, UserStatus } from 'src/enum'; import { UserAdminService } from 'src/services/user-admin.service'; import { authStub } from 'test/fixtures/auth.stub'; import { userStub } from 'test/fixtures/user.stub'; diff --git a/server/src/services/user-admin.service.ts b/server/src/services/user-admin.service.ts index 3df9a218f334a..37c3c1e004bd4 100644 --- a/server/src/services/user-admin.service.ts +++ b/server/src/services/user-admin.service.ts @@ -10,8 +10,7 @@ import { UserAdminUpdateDto, mapUserAdmin, } from 'src/dtos/user.dto'; -import { UserMetadataKey, UserStatus } from 'src/enum'; -import { JobName } from 'src/interfaces/job.interface'; +import { JobName, UserMetadataKey, UserStatus } from 'src/enum'; import { UserFindOptions } from 'src/repositories/user.repository'; import { BaseService } from 'src/services/base.service'; import { getPreferences, getPreferencesPartial, mergePreferences } from 'src/utils/preferences'; diff --git a/server/src/services/user.service.spec.ts b/server/src/services/user.service.spec.ts index 8762c7c766f32..06c928da149d2 100644 --- a/server/src/services/user.service.spec.ts +++ b/server/src/services/user.service.spec.ts @@ -1,7 +1,6 @@ import { BadRequestException, InternalServerErrorException, NotFoundException } from '@nestjs/common'; import { UserEntity } from 'src/entities/user.entity'; -import { CacheControl, UserMetadataKey } from 'src/enum'; -import { JobName } from 'src/interfaces/job.interface'; +import { CacheControl, JobName, UserMetadataKey } from 'src/enum'; import { UserService } from 'src/services/user.service'; import { ImmichFileResponse } from 'src/utils/file'; import { authStub } from 'test/fixtures/auth.stub'; diff --git a/server/src/services/user.service.ts b/server/src/services/user.service.ts index dfd9c7715f8c2..3ec6281009e13 100644 --- a/server/src/services/user.service.ts +++ b/server/src/services/user.service.ts @@ -10,10 +10,10 @@ import { CreateProfileImageResponseDto } from 'src/dtos/user-profile.dto'; import { UserAdminResponseDto, UserResponseDto, UserUpdateMeDto, mapUser, mapUserAdmin } from 'src/dtos/user.dto'; import { UserMetadataEntity } from 'src/entities/user-metadata.entity'; import { UserEntity } from 'src/entities/user.entity'; -import { CacheControl, StorageFolder, UserMetadataKey } from 'src/enum'; -import { JobName, JobOf, JobStatus, QueueName } from 'src/interfaces/job.interface'; +import { CacheControl, JobName, JobStatus, QueueName, StorageFolder, UserMetadataKey } from 'src/enum'; import { UserFindOptions } from 'src/repositories/user.repository'; import { BaseService } from 'src/services/base.service'; +import { JobOf } from 'src/types'; import { ImmichFileResponse } from 'src/utils/file'; import { getPreferences, getPreferencesPartial, mergePreferences } from 'src/utils/preferences'; diff --git a/server/src/services/version.service.spec.ts b/server/src/services/version.service.spec.ts index 32378c52df53f..500478e9e724e 100644 --- a/server/src/services/version.service.spec.ts +++ b/server/src/services/version.service.spec.ts @@ -1,8 +1,7 @@ import { DateTime } from 'luxon'; import { SemVer } from 'semver'; import { serverVersion } from 'src/constants'; -import { ImmichEnvironment, SystemMetadataKey } from 'src/enum'; -import { JobName, JobStatus } from 'src/interfaces/job.interface'; +import { ImmichEnvironment, JobName, JobStatus, SystemMetadataKey } from 'src/enum'; import { VersionService } from 'src/services/version.service'; import { mockEnvData } from 'test/repositories/config.repository.mock'; import { newTestService, ServiceMocks } from 'test/utils'; diff --git a/server/src/services/version.service.ts b/server/src/services/version.service.ts index 9679ac4b4b6c0..c5240b82c1b73 100644 --- a/server/src/services/version.service.ts +++ b/server/src/services/version.service.ts @@ -5,9 +5,7 @@ import { serverVersion } from 'src/constants'; import { OnEvent, OnJob } from 'src/decorators'; import { ReleaseNotification, ServerVersionResponseDto } from 'src/dtos/server.dto'; import { VersionCheckMetadata } from 'src/entities/system-metadata.entity'; -import { ImmichEnvironment, SystemMetadataKey } from 'src/enum'; -import { JobName, JobStatus, QueueName } from 'src/interfaces/job.interface'; -import { DatabaseLock } from 'src/repositories/database.repository'; +import { DatabaseLock, ImmichEnvironment, JobName, JobStatus, QueueName, SystemMetadataKey } from 'src/enum'; import { ArgOf } from 'src/repositories/event.repository'; import { BaseService } from 'src/services/base.service'; diff --git a/server/src/services/view.service.ts b/server/src/services/view.service.ts index f1ef40a810213..5871b04b32f54 100644 --- a/server/src/services/view.service.ts +++ b/server/src/services/view.service.ts @@ -1,8 +1,10 @@ +import { Injectable } from '@nestjs/common'; import { AssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; import { AssetEntity } from 'src/entities/asset.entity'; import { BaseService } from 'src/services/base.service'; +@Injectable() export class ViewService extends BaseService { getUniqueOriginalPaths(auth: AuthDto): Promise { return this.viewRepository.getUniqueOriginalPaths(auth.user.id); diff --git a/server/src/types.ts b/server/src/types.ts index e0523333d8bba..47a6d207978a3 100644 --- a/server/src/types.ts +++ b/server/src/types.ts @@ -1,5 +1,14 @@ import { UserEntity } from 'src/entities/user.entity'; -import { ExifOrientation, ImageFormat, Permission, TranscodeTarget, VideoCodec } from 'src/enum'; +import { + DatabaseExtension, + ExifOrientation, + ImageFormat, + JobName, + Permission, + QueueName, + TranscodeTarget, + VideoCodec, +} from 'src/enum'; import { ActivityRepository } from 'src/repositories/activity.repository'; import { ApiKeyRepository } from 'src/repositories/api-key.repository'; import { MemoryRepository } from 'src/repositories/memory.repository'; @@ -167,3 +176,245 @@ export interface VideoInterfaces { dri: string[]; mali: boolean; } + +export type ConcurrentQueueName = Exclude< + QueueName, + | QueueName.STORAGE_TEMPLATE_MIGRATION + | QueueName.FACIAL_RECOGNITION + | QueueName.DUPLICATE_DETECTION + | QueueName.BACKUP_DATABASE +>; + +export type Jobs = { [K in JobItem['name']]: (JobItem & { name: K })['data'] }; +export type JobOf = Jobs[T]; + +export interface IBaseJob { + force?: boolean; +} + +export interface IDelayedJob extends IBaseJob { + /** The minimum time to wait to execute this job, in milliseconds. */ + delay?: number; +} + +export interface IEntityJob extends IBaseJob { + id: string; + source?: 'upload' | 'sidecar-write' | 'copy'; + notify?: boolean; +} + +export interface IAssetDeleteJob extends IEntityJob { + deleteOnDisk: boolean; +} + +export interface ILibraryFileJob extends IEntityJob { + ownerId: string; + assetPath: string; +} + +export interface ILibraryAssetJob extends IEntityJob { + importPaths: string[]; + exclusionPatterns: string[]; +} + +export interface IBulkEntityJob extends IBaseJob { + ids: string[]; +} + +export interface IDeleteFilesJob extends IBaseJob { + files: Array; +} + +export interface ISidecarWriteJob extends IEntityJob { + description?: string; + dateTimeOriginal?: string; + latitude?: number; + longitude?: number; + rating?: number; + tags?: true; +} + +export interface IDeferrableJob extends IEntityJob { + deferred?: boolean; +} + +export interface INightlyJob extends IBaseJob { + nightly?: boolean; +} + +export type EmailImageAttachment = { + filename: string; + path: string; + cid: string; +}; + +export interface IEmailJob { + to: string; + subject: string; + html: string; + text: string; + imageAttachments?: EmailImageAttachment[]; +} + +export interface INotifySignupJob extends IEntityJob { + tempPassword?: string; +} + +export interface INotifyAlbumInviteJob extends IEntityJob { + recipientId: string; +} + +export interface INotifyAlbumUpdateJob extends IEntityJob, IDelayedJob { + recipientIds: string[]; +} + +export interface JobCounts { + active: number; + completed: number; + failed: number; + delayed: number; + waiting: number; + paused: number; +} + +export interface QueueStatus { + isActive: boolean; + isPaused: boolean; +} + +export type JobItem = + // Backups + | { name: JobName.BACKUP_DATABASE; data?: IBaseJob } + + // Transcoding + | { name: JobName.QUEUE_VIDEO_CONVERSION; data: IBaseJob } + | { name: JobName.VIDEO_CONVERSION; data: IEntityJob } + + // Thumbnails + | { name: JobName.QUEUE_GENERATE_THUMBNAILS; data: IBaseJob } + | { name: JobName.GENERATE_THUMBNAILS; data: IEntityJob } + + // User + | { name: JobName.USER_DELETE_CHECK; data?: IBaseJob } + | { name: JobName.USER_DELETION; data: IEntityJob } + | { name: JobName.USER_SYNC_USAGE; data?: IBaseJob } + + // Storage Template + | { name: JobName.STORAGE_TEMPLATE_MIGRATION; data?: IBaseJob } + | { name: JobName.STORAGE_TEMPLATE_MIGRATION_SINGLE; data: IEntityJob } + + // Migration + | { name: JobName.QUEUE_MIGRATION; data?: IBaseJob } + | { name: JobName.MIGRATE_ASSET; data: IEntityJob } + | { name: JobName.MIGRATE_PERSON; data: IEntityJob } + + // Metadata Extraction + | { name: JobName.QUEUE_METADATA_EXTRACTION; data: IBaseJob } + | { name: JobName.METADATA_EXTRACTION; data: IEntityJob } + | { name: JobName.LINK_LIVE_PHOTOS; data: IEntityJob } + // Sidecar Scanning + | { name: JobName.QUEUE_SIDECAR; data: IBaseJob } + | { name: JobName.SIDECAR_DISCOVERY; data: IEntityJob } + | { name: JobName.SIDECAR_SYNC; data: IEntityJob } + | { name: JobName.SIDECAR_WRITE; data: ISidecarWriteJob } + + // Facial Recognition + | { name: JobName.QUEUE_FACE_DETECTION; data: IBaseJob } + | { name: JobName.FACE_DETECTION; data: IEntityJob } + | { name: JobName.QUEUE_FACIAL_RECOGNITION; data: INightlyJob } + | { name: JobName.FACIAL_RECOGNITION; data: IDeferrableJob } + | { name: JobName.GENERATE_PERSON_THUMBNAIL; data: IEntityJob } + + // Smart Search + | { name: JobName.QUEUE_SMART_SEARCH; data: IBaseJob } + | { name: JobName.SMART_SEARCH; data: IEntityJob } + | { name: JobName.QUEUE_TRASH_EMPTY; data?: IBaseJob } + + // Duplicate Detection + | { name: JobName.QUEUE_DUPLICATE_DETECTION; data: IBaseJob } + | { name: JobName.DUPLICATE_DETECTION; data: IEntityJob } + + // Filesystem + | { name: JobName.DELETE_FILES; data: IDeleteFilesJob } + + // Cleanup + | { name: JobName.CLEAN_OLD_AUDIT_LOGS; data?: IBaseJob } + | { name: JobName.CLEAN_OLD_SESSION_TOKENS; data?: IBaseJob } + + // Tags + | { name: JobName.TAG_CLEANUP; data?: IBaseJob } + + // Asset Deletion + | { name: JobName.PERSON_CLEANUP; data?: IBaseJob } + | { name: JobName.ASSET_DELETION; data: IAssetDeleteJob } + | { name: JobName.ASSET_DELETION_CHECK; data?: IBaseJob } + + // Library Management + | { name: JobName.LIBRARY_SYNC_FILE; data: ILibraryFileJob } + | { name: JobName.LIBRARY_QUEUE_SYNC_FILES; data: IEntityJob } + | { name: JobName.LIBRARY_QUEUE_SYNC_ASSETS; data: IEntityJob } + | { name: JobName.LIBRARY_SYNC_ASSET; data: ILibraryAssetJob } + | { name: JobName.LIBRARY_DELETE; data: IEntityJob } + | { name: JobName.LIBRARY_QUEUE_SYNC_ALL; data?: IBaseJob } + | { name: JobName.LIBRARY_QUEUE_CLEANUP; data: IBaseJob } + + // Notification + | { name: JobName.SEND_EMAIL; data: IEmailJob } + | { name: JobName.NOTIFY_ALBUM_INVITE; data: INotifyAlbumInviteJob } + | { name: JobName.NOTIFY_ALBUM_UPDATE; data: INotifyAlbumUpdateJob } + | { name: JobName.NOTIFY_SIGNUP; data: INotifySignupJob } + + // Version check + | { name: JobName.VERSION_CHECK; data: IBaseJob }; + +export type VectorExtension = DatabaseExtension.VECTOR | DatabaseExtension.VECTORS; + +export type DatabaseConnectionURL = { + connectionType: 'url'; + url: string; +}; + +export type DatabaseConnectionParts = { + connectionType: 'parts'; + host: string; + port: number; + username: string; + password: string; + database: string; +}; + +export type DatabaseConnectionParams = DatabaseConnectionURL | DatabaseConnectionParts; + +export interface ExtensionVersion { + availableVersion: string | null; + installedVersion: string | null; +} + +export interface VectorUpdateResult { + restartRequired: boolean; +} + +export interface ImmichFile extends Express.Multer.File { + /** sha1 hash of file */ + uuid: string; + checksum: Buffer; +} + +export interface UploadFile { + uuid: string; + checksum: Buffer; + originalPath: string; + originalName: string; + size: number; +} + +export interface UploadFiles { + assetData: ImmichFile[]; + sidecarData: ImmichFile[]; +} + +export interface IBulkAsset { + getAssetIds: (id: string, assetIds: string[]) => Promise>; + addAssetIds: (id: string, assetIds: string[]) => Promise; + removeAssetIds: (id: string, assetIds: string[]) => Promise; +} diff --git a/server/src/utils/asset.util.ts b/server/src/utils/asset.util.ts index 5183bb2164e50..de64720a82a31 100644 --- a/server/src/utils/asset.util.ts +++ b/server/src/utils/asset.util.ts @@ -6,20 +6,13 @@ import { AuthDto } from 'src/dtos/auth.dto'; import { AssetFileEntity } from 'src/entities/asset-files.entity'; import { AssetFileType, AssetType, Permission } from 'src/enum'; import { AuthRequest } from 'src/middleware/auth.guard'; -import { ImmichFile } from 'src/middleware/file-upload.interceptor'; import { AccessRepository } from 'src/repositories/access.repository'; import { AssetRepository } from 'src/repositories/asset.repository'; import { EventRepository } from 'src/repositories/event.repository'; import { PartnerRepository } from 'src/repositories/partner.repository'; -import { UploadFile } from 'src/services/asset-media.service'; +import { IBulkAsset, ImmichFile, UploadFile } from 'src/types'; import { checkAccess } from 'src/utils/access'; -export interface IBulkAsset { - getAssetIds: (id: string, assetIds: string[]) => Promise>; - addAssetIds: (id: string, assetIds: string[]) => Promise; - removeAssetIds: (id: string, assetIds: string[]) => Promise; -} - const getFileByType = (files: AssetFileEntity[] | undefined, type: AssetFileType) => { return (files || []).find((file) => file.type === type); }; diff --git a/server/src/utils/config.ts b/server/src/utils/config.ts index 30f965c37f3d6..4dee1c348e45b 100644 --- a/server/src/utils/config.ts +++ b/server/src/utils/config.ts @@ -5,9 +5,8 @@ import { load as loadYaml } from 'js-yaml'; import * as _ from 'lodash'; import { SystemConfig, defaults } from 'src/config'; import { SystemConfigDto } from 'src/dtos/system-config.dto'; -import { SystemMetadataKey } from 'src/enum'; +import { DatabaseLock, SystemMetadataKey } from 'src/enum'; import { ConfigRepository } from 'src/repositories/config.repository'; -import { DatabaseLock } from 'src/repositories/database.repository'; import { LoggingRepository } from 'src/repositories/logging.repository'; import { SystemMetadataRepository } from 'src/repositories/system-metadata.repository'; import { DeepPartial } from 'src/types'; diff --git a/server/test/repositories/job.repository.mock.ts b/server/test/repositories/job.repository.mock.ts index e9557af59bae7..f0f4fdda00918 100644 --- a/server/test/repositories/job.repository.mock.ts +++ b/server/test/repositories/job.repository.mock.ts @@ -1,7 +1,8 @@ -import { IJobRepository } from 'src/interfaces/job.interface'; +import { JobRepository } from 'src/repositories/job.repository'; +import { RepositoryInterface } from 'src/types'; import { Mocked, vitest } from 'vitest'; -export const newJobRepositoryMock = (): Mocked => { +export const newJobRepositoryMock = (): Mocked> => { return { setup: vitest.fn(), startWorkers: vitest.fn(), diff --git a/server/test/utils.ts b/server/test/utils.ts index fbff7ba00ddad..d1dda3eedf5df 100644 --- a/server/test/utils.ts +++ b/server/test/utils.ts @@ -194,12 +194,12 @@ export const newTestService = ( albumMock as RepositoryInterface as AlbumRepository, albumUserMock as RepositoryInterface as AlbumUserRepository, assetMock as RepositoryInterface as AssetRepository, - configMock, + configMock as RepositoryInterface as ConfigRepository, cronMock as RepositoryInterface as CronRepository, cryptoMock as RepositoryInterface as CryptoRepository, databaseMock as RepositoryInterface as DatabaseRepository, eventMock as RepositoryInterface as EventRepository, - jobMock, + jobMock as RepositoryInterface as JobRepository, apiKeyMock as RepositoryInterface as ApiKeyRepository, libraryMock as RepositoryInterface as LibraryRepository, machineLearningMock as RepositoryInterface as MachineLearningRepository,