feat: use ILoggerRepository (#8855)

* Migrate ImmichLogger over to injected ILoggerRepository

* chore: cleanup and tests

---------

Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
This commit is contained in:
AmAn Sharma
2024-04-17 03:00:31 +05:30
committed by GitHub
parent 877207a2e6
commit 6e6deec40c
59 changed files with 352 additions and 191 deletions
+6 -5
View File
@@ -1,9 +1,10 @@
import { Injectable } from '@nestjs/common';
import { Inject, Injectable } from '@nestjs/common';
import { Cron, CronExpression, Interval } from '@nestjs/schedule';
import { NextFunction, Request, Response } from 'express';
import { readFileSync } from 'node:fs';
import { join } from 'node:path';
import { ONE_HOUR, WEB_ROOT } from 'src/constants';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { AuthService } from 'src/services/auth.service';
import { DatabaseService } from 'src/services/database.service';
import { JobService } from 'src/services/job.service';
@@ -11,7 +12,6 @@ import { ServerInfoService } from 'src/services/server-info.service';
import { SharedLinkService } from 'src/services/shared-link.service';
import { StorageService } from 'src/services/storage.service';
import { SystemConfigService } from 'src/services/system-config.service';
import { ImmichLogger } from 'src/utils/logger';
import { OpenGraphTags } from 'src/utils/misc';
const render = (index: string, meta: OpenGraphTags) => {
@@ -36,8 +36,6 @@ const render = (index: string, meta: OpenGraphTags) => {
@Injectable()
export class ApiService {
private logger = new ImmichLogger(ApiService.name);
constructor(
private authService: AuthService,
private configService: SystemConfigService,
@@ -46,7 +44,10 @@ export class ApiService {
private sharedLinkService: SharedLinkService,
private storageService: StorageService,
private databaseService: DatabaseService,
) {}
@Inject(ILoggerRepository) private logger: ILoggerRepository,
) {
this.logger.setContext(ApiService.name);
}
@Interval(ONE_HOUR.as('milliseconds'))
async onVersionCheck() {
+14 -1
View File
@@ -6,6 +6,7 @@ import { IAssetRepositoryV1 } from 'src/interfaces/asset-v1.interface';
import { IAssetRepository } from 'src/interfaces/asset.interface';
import { IJobRepository, JobName } from 'src/interfaces/job.interface';
import { ILibraryRepository } from 'src/interfaces/library.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface';
import { IUserRepository } from 'src/interfaces/user.interface';
import { AssetServiceV1 } from 'src/services/asset-v1.service';
@@ -16,6 +17,7 @@ import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositorie
import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock';
import { newJobRepositoryMock } from 'test/repositories/job.repository.mock';
import { newLibraryRepositoryMock } from 'test/repositories/library.repository.mock';
import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock';
import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
import { newUserRepositoryMock } from 'test/repositories/user.repository.mock';
import { QueryFailedError } from 'typeorm';
@@ -66,6 +68,7 @@ describe('AssetService', () => {
let assetMock: Mocked<IAssetRepository>;
let jobMock: Mocked<IJobRepository>;
let libraryMock: Mocked<ILibraryRepository>;
let loggerMock: Mocked<ILoggerRepository>;
let storageMock: Mocked<IStorageRepository>;
let userMock: Mocked<IUserRepository>;
@@ -85,10 +88,20 @@ describe('AssetService', () => {
assetMock = newAssetRepositoryMock();
jobMock = newJobRepositoryMock();
libraryMock = newLibraryRepositoryMock();
loggerMock = newLoggerRepositoryMock();
storageMock = newStorageRepositoryMock();
userMock = newUserRepositoryMock();
sut = new AssetServiceV1(accessMock, assetRepositoryMockV1, assetMock, jobMock, libraryMock, storageMock, userMock);
sut = new AssetServiceV1(
accessMock,
assetRepositoryMockV1,
assetMock,
jobMock,
libraryMock,
storageMock,
userMock,
loggerMock,
);
assetRepositoryMockV1.get.mockImplementation((assetId) =>
Promise.resolve(
+3 -2
View File
@@ -33,18 +33,17 @@ import { IAssetRepositoryV1 } from 'src/interfaces/asset-v1.interface';
import { IAssetRepository } from 'src/interfaces/asset.interface';
import { IJobRepository, JobName } from 'src/interfaces/job.interface';
import { ILibraryRepository } from 'src/interfaces/library.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface';
import { IUserRepository } from 'src/interfaces/user.interface';
import { UploadFile } from 'src/services/asset.service';
import { CacheControl, ImmichFileResponse, getLivePhotoMotionFilename } from 'src/utils/file';
import { ImmichLogger } from 'src/utils/logger';
import { mimeTypes } from 'src/utils/mime-types';
import { QueryFailedError } from 'typeorm';
@Injectable()
/** @deprecated */
export class AssetServiceV1 {
readonly logger = new ImmichLogger(AssetServiceV1.name);
private access: AccessCore;
constructor(
@@ -55,8 +54,10 @@ export class AssetServiceV1 {
@Inject(ILibraryRepository) private libraryRepository: ILibraryRepository,
@Inject(IStorageRepository) private storageRepository: IStorageRepository,
@Inject(IUserRepository) private userRepository: IUserRepository,
@Inject(ILoggerRepository) private logger: ILoggerRepository,
) {
this.access = AccessCore.create(accessRepository);
this.logger.setContext(AssetServiceV1.name);
}
public async uploadFile(
@@ -6,6 +6,7 @@ import { IAssetStackRepository } from 'src/interfaces/asset-stack.interface';
import { AssetStats, IAssetRepository } from 'src/interfaces/asset.interface';
import { ClientEvent, IEventRepository } from 'src/interfaces/event.interface';
import { IJobRepository, JobName } from 'src/interfaces/job.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IPartnerRepository } from 'src/interfaces/partner.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemConfigRepository } from 'src/interfaces/system-config.interface';
@@ -21,6 +22,7 @@ import { newAssetStackRepositoryMock } from 'test/repositories/asset-stack.repos
import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock';
import { newEventRepositoryMock } from 'test/repositories/event.repository.mock';
import { newJobRepositoryMock } from 'test/repositories/job.repository.mock';
import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock';
import { newPartnerRepositoryMock } from 'test/repositories/partner.repository.mock';
import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
@@ -156,6 +158,7 @@ describe(AssetService.name, () => {
let configMock: Mocked<ISystemConfigRepository>;
let partnerMock: Mocked<IPartnerRepository>;
let assetStackMock: Mocked<IAssetStackRepository>;
let loggerMock: Mocked<ILoggerRepository>;
it('should work', () => {
expect(sut).toBeDefined();
@@ -177,6 +180,7 @@ describe(AssetService.name, () => {
configMock = newSystemConfigRepositoryMock();
partnerMock = newPartnerRepositoryMock();
assetStackMock = newAssetStackRepositoryMock();
loggerMock = newLoggerRepositoryMock();
sut = new AssetService(
accessMock,
@@ -188,6 +192,7 @@ describe(AssetService.name, () => {
eventMock,
partnerMock,
assetStackMock,
loggerMock,
);
mockGetById([assetStub.livePhotoStillAsset, assetStub.livePhotoMotionAsset]);
+4 -3
View File
@@ -40,11 +40,11 @@ import {
JobName,
JobStatus,
} from 'src/interfaces/job.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IPartnerRepository } from 'src/interfaces/partner.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemConfigRepository } from 'src/interfaces/system-config.interface';
import { IUserRepository } from 'src/interfaces/user.interface';
import { ImmichLogger } from 'src/utils/logger';
import { mimeTypes } from 'src/utils/mime-types';
import { usePagination } from 'src/utils/pagination';
@@ -63,7 +63,6 @@ export interface UploadFile {
}
export class AssetService {
private logger = new ImmichLogger(AssetService.name);
private access: AccessCore;
private configCore: SystemConfigCore;
@@ -77,9 +76,11 @@ export class AssetService {
@Inject(IEventRepository) private eventRepository: IEventRepository,
@Inject(IPartnerRepository) private partnerRepository: IPartnerRepository,
@Inject(IAssetStackRepository) private assetStackRepository: IAssetStackRepository,
@Inject(ILoggerRepository) private logger: ILoggerRepository,
) {
this.logger.setContext(AssetService.name);
this.access = AccessCore.create(accessRepository);
this.configCore = SystemConfigCore.create(configRepository);
this.configCore = SystemConfigCore.create(configRepository, this.logger);
}
canUploadFile({ auth, fieldName, file }: UploadRequest): true {
+5 -1
View File
@@ -3,6 +3,7 @@ import { IAssetRepository } from 'src/interfaces/asset.interface';
import { IAuditRepository } from 'src/interfaces/audit.interface';
import { ICryptoRepository } from 'src/interfaces/crypto.interface';
import { JobStatus } from 'src/interfaces/job.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IPersonRepository } from 'src/interfaces/person.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface';
import { IUserRepository } from 'src/interfaces/user.interface';
@@ -13,6 +14,7 @@ import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositorie
import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock';
import { newAuditRepositoryMock } from 'test/repositories/audit.repository.mock';
import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.mock';
import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock';
import { newPersonRepositoryMock } from 'test/repositories/person.repository.mock';
import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
import { newUserRepositoryMock } from 'test/repositories/user.repository.mock';
@@ -27,6 +29,7 @@ describe(AuditService.name, () => {
let personMock: Mocked<IPersonRepository>;
let storageMock: Mocked<IStorageRepository>;
let userMock: Mocked<IUserRepository>;
let loggerMock: Mocked<ILoggerRepository>;
beforeEach(() => {
accessMock = newAccessRepositoryMock();
@@ -36,7 +39,8 @@ describe(AuditService.name, () => {
personMock = newPersonRepositoryMock();
storageMock = newStorageRepositoryMock();
userMock = newUserRepositoryMock();
sut = new AuditService(accessMock, assetMock, cryptoMock, personMock, auditMock, storageMock, userMock);
loggerMock = newLoggerRepositoryMock();
sut = new AuditService(accessMock, assetMock, cryptoMock, personMock, auditMock, storageMock, userMock, loggerMock);
});
it('should work', () => {
+3 -2
View File
@@ -20,16 +20,15 @@ import { IAssetRepository } from 'src/interfaces/asset.interface';
import { IAuditRepository } from 'src/interfaces/audit.interface';
import { ICryptoRepository } from 'src/interfaces/crypto.interface';
import { JOBS_ASSET_PAGINATION_SIZE, JobStatus } from 'src/interfaces/job.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IPersonRepository } from 'src/interfaces/person.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface';
import { IUserRepository } from 'src/interfaces/user.interface';
import { ImmichLogger } from 'src/utils/logger';
import { usePagination } from 'src/utils/pagination';
@Injectable()
export class AuditService {
private access: AccessCore;
private logger = new ImmichLogger(AuditService.name);
constructor(
@Inject(IAccessRepository) accessRepository: IAccessRepository,
@@ -39,8 +38,10 @@ export class AuditService {
@Inject(IAuditRepository) private repository: IAuditRepository,
@Inject(IStorageRepository) private storageRepository: IStorageRepository,
@Inject(IUserRepository) private userRepository: IUserRepository,
@Inject(ILoggerRepository) private logger: ILoggerRepository,
) {
this.access = AccessCore.create(accessRepository);
this.logger.setContext(AuditService.name);
}
async handleCleanup(): Promise<JobStatus> {
+3 -3
View File
@@ -89,10 +89,10 @@ export class AuthService {
@Inject(ISharedLinkRepository) private sharedLinkRepository: ISharedLinkRepository,
@Inject(IKeyRepository) private keyRepository: IKeyRepository,
) {
this.access = AccessCore.create(accessRepository);
this.configCore = SystemConfigCore.create(configRepository);
this.userCore = UserCore.create(cryptoRepository, libraryRepository, userRepository);
this.logger.setContext(AuthService.name);
this.access = AccessCore.create(accessRepository);
this.configCore = SystemConfigCore.create(configRepository, logger);
this.userCore = UserCore.create(cryptoRepository, libraryRepository, userRepository);
custom.setHttpOptionsDefaults({ timeout: 30_000 });
}
+21 -31
View File
@@ -1,18 +1,20 @@
import { DatabaseExtension, IDatabaseRepository, VectorIndex } from 'src/interfaces/database.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { DatabaseService } from 'src/services/database.service';
import { ImmichLogger } from 'src/utils/logger';
import { Version, VersionType } from 'src/utils/version';
import { newDatabaseRepositoryMock } from 'test/repositories/database.repository.mock';
import { MockInstance, Mocked, vitest } from 'vitest';
import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock';
import { Mocked } from 'vitest';
describe(DatabaseService.name, () => {
let sut: DatabaseService;
let databaseMock: Mocked<IDatabaseRepository>;
let loggerMock: Mocked<ILoggerRepository>;
beforeEach(() => {
databaseMock = newDatabaseRepositoryMock();
sut = new DatabaseService(databaseMock);
loggerMock = newLoggerRepositoryMock();
sut = new DatabaseService(databaseMock, loggerMock);
});
it('should work', () => {
@@ -23,18 +25,11 @@ describe(DatabaseService.name, () => {
[{ vectorExt: DatabaseExtension.VECTORS, extName: 'pgvecto.rs', minVersion: new Version(0, 1, 1) }],
[{ vectorExt: DatabaseExtension.VECTOR, extName: 'pgvector', minVersion: new Version(0, 5, 0) }],
] as const)('init', ({ vectorExt, extName, minVersion }) => {
let fatalLog: MockInstance;
let errorLog: MockInstance;
let warnLog: MockInstance;
beforeEach(() => {
fatalLog = vitest.spyOn(ImmichLogger.prototype, 'fatal');
errorLog = vitest.spyOn(ImmichLogger.prototype, 'error');
warnLog = vitest.spyOn(ImmichLogger.prototype, 'warn');
databaseMock.getPreferredVectorExtension.mockReturnValue(vectorExt);
databaseMock.getExtensionVersion.mockResolvedValue(minVersion);
sut = new DatabaseService(databaseMock);
sut = new DatabaseService(databaseMock, loggerMock);
sut.minVectorVersion = minVersion;
sut.minVectorsVersion = minVersion;
@@ -42,11 +37,6 @@ describe(DatabaseService.name, () => {
sut.vectorsVersionPin = VersionType.MINOR;
});
afterEach(() => {
fatalLog.mockRestore();
warnLog.mockRestore();
});
it(`should resolve successfully if minimum supported PostgreSQL and ${extName} version are installed`, async () => {
databaseMock.getPostgresVersion.mockResolvedValueOnce(new Version(14, 0, 0));
@@ -57,7 +47,7 @@ describe(DatabaseService.name, () => {
expect(databaseMock.createExtension).toHaveBeenCalledTimes(1);
expect(databaseMock.getExtensionVersion).toHaveBeenCalled();
expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1);
expect(fatalLog).not.toHaveBeenCalled();
expect(loggerMock.fatal).not.toHaveBeenCalled();
});
it('should throw an error if PostgreSQL version is below minimum supported version', async () => {
@@ -74,7 +64,7 @@ describe(DatabaseService.name, () => {
expect(databaseMock.createExtension).toHaveBeenCalledWith(vectorExt);
expect(databaseMock.createExtension).toHaveBeenCalledTimes(1);
expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1);
expect(fatalLog).not.toHaveBeenCalled();
expect(loggerMock.fatal).not.toHaveBeenCalled();
});
it(`should throw an error if ${extName} version is not installed even after createVectorExtension`, async () => {
@@ -134,7 +124,7 @@ describe(DatabaseService.name, () => {
await expect(sut.init()).rejects.toThrow('Failed to create extension');
expect(fatalLog).toHaveBeenCalledTimes(1);
expect(loggerMock.fatal).toHaveBeenCalledTimes(1);
expect(databaseMock.createExtension).toHaveBeenCalledTimes(1);
expect(databaseMock.runMigrations).not.toHaveBeenCalled();
});
@@ -148,7 +138,7 @@ describe(DatabaseService.name, () => {
expect(databaseMock.updateVectorExtension).toHaveBeenCalledWith(vectorExt, version);
expect(databaseMock.updateVectorExtension).toHaveBeenCalledTimes(1);
expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1);
expect(fatalLog).not.toHaveBeenCalled();
expect(loggerMock.fatal).not.toHaveBeenCalled();
});
it(`should not update ${extName} if a newer version is higher than the maximum`, async () => {
@@ -159,7 +149,7 @@ describe(DatabaseService.name, () => {
expect(databaseMock.updateVectorExtension).not.toHaveBeenCalled();
expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1);
expect(fatalLog).not.toHaveBeenCalled();
expect(loggerMock.fatal).not.toHaveBeenCalled();
});
it(`should warn if attempted to update ${extName} and failed`, async () => {
@@ -169,10 +159,10 @@ describe(DatabaseService.name, () => {
await expect(sut.init()).resolves.toBeUndefined();
expect(warnLog).toHaveBeenCalledTimes(1);
expect(warnLog.mock.calls[0][0]).toContain(extName);
expect(errorLog).toHaveBeenCalledTimes(1);
expect(fatalLog).not.toHaveBeenCalled();
expect(loggerMock.warn).toHaveBeenCalledTimes(1);
expect(loggerMock.warn.mock.calls[0][0]).toContain(extName);
expect(loggerMock.error).toHaveBeenCalledTimes(1);
expect(loggerMock.fatal).not.toHaveBeenCalled();
expect(databaseMock.updateVectorExtension).toHaveBeenCalledWith(vectorExt, version);
expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1);
});
@@ -184,11 +174,11 @@ describe(DatabaseService.name, () => {
await expect(sut.init()).resolves.toBeUndefined();
expect(warnLog).toHaveBeenCalledTimes(1);
expect(warnLog.mock.calls[0][0]).toContain(extName);
expect(loggerMock.warn).toHaveBeenCalledTimes(1);
expect(loggerMock.warn.mock.calls[0][0]).toContain(extName);
expect(databaseMock.updateVectorExtension).toHaveBeenCalledWith(vectorExt, version);
expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1);
expect(fatalLog).not.toHaveBeenCalled();
expect(loggerMock.fatal).not.toHaveBeenCalled();
});
it.each([{ index: VectorIndex.CLIP }, { index: VectorIndex.FACE }])(
@@ -203,7 +193,7 @@ describe(DatabaseService.name, () => {
expect(databaseMock.reindex).toHaveBeenCalledWith(index);
expect(databaseMock.reindex).toHaveBeenCalledTimes(1);
expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1);
expect(fatalLog).not.toHaveBeenCalled();
expect(loggerMock.fatal).not.toHaveBeenCalled();
},
);
@@ -217,7 +207,7 @@ describe(DatabaseService.name, () => {
expect(databaseMock.shouldReindex).toHaveBeenCalledTimes(2);
expect(databaseMock.reindex).not.toHaveBeenCalled();
expect(databaseMock.runMigrations).toHaveBeenCalledTimes(1);
expect(fatalLog).not.toHaveBeenCalled();
expect(loggerMock.fatal).not.toHaveBeenCalled();
},
);
});
+6 -3
View File
@@ -7,12 +7,11 @@ import {
VectorIndex,
extName,
} from 'src/interfaces/database.interface';
import { ImmichLogger } from 'src/utils/logger';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { Version, VersionType } from 'src/utils/version';
@Injectable()
export class DatabaseService {
private logger = new ImmichLogger(DatabaseService.name);
private vectorExt: VectorExtension;
minPostgresVersion = 14;
minVectorsVersion = new Version(0, 2, 0);
@@ -20,7 +19,11 @@ export class DatabaseService {
minVectorVersion = new Version(0, 5, 0);
vectorVersionPin = VersionType.MAJOR;
constructor(@Inject(IDatabaseRepository) private databaseRepository: IDatabaseRepository) {
constructor(
@Inject(IDatabaseRepository) private databaseRepository: IDatabaseRepository,
@Inject(ILoggerRepository) private logger: ILoggerRepository,
) {
this.logger.setContext(DatabaseService.name);
this.vectorExt = this.databaseRepository.getPreferredVectorExtension();
}
+6 -2
View File
@@ -12,6 +12,7 @@ import {
JobStatus,
QueueName,
} from 'src/interfaces/job.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IMetricRepository } from 'src/interfaces/metric.interface';
import { IPersonRepository } from 'src/interfaces/person.interface';
import { ISystemConfigRepository } from 'src/interfaces/system-config.interface';
@@ -20,6 +21,7 @@ import { assetStub } from 'test/fixtures/asset.stub';
import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock';
import { newEventRepositoryMock } from 'test/repositories/event.repository.mock';
import { newJobRepositoryMock } from 'test/repositories/job.repository.mock';
import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock';
import { newMetricRepositoryMock } from 'test/repositories/metric.repository.mock';
import { newPersonRepositoryMock } from 'test/repositories/person.repository.mock';
import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
@@ -41,6 +43,7 @@ describe(JobService.name, () => {
let jobMock: Mocked<IJobRepository>;
let personMock: Mocked<IPersonRepository>;
let metricMock: Mocked<IMetricRepository>;
let loggerMock: Mocked<ILoggerRepository>;
beforeEach(() => {
assetMock = newAssetRepositoryMock();
@@ -49,7 +52,8 @@ describe(JobService.name, () => {
jobMock = newJobRepositoryMock();
personMock = newPersonRepositoryMock();
metricMock = newMetricRepositoryMock();
sut = new JobService(assetMock, eventMock, jobMock, configMock, personMock, metricMock);
loggerMock = newLoggerRepositoryMock();
sut = new JobService(assetMock, eventMock, jobMock, configMock, personMock, metricMock, loggerMock);
});
it('should work', () => {
@@ -235,7 +239,7 @@ describe(JobService.name, () => {
it('should subscribe to config changes', async () => {
await sut.init(makeMockHandlers(JobStatus.FAILED));
SystemConfigCore.create(newSystemConfigRepositoryMock(false)).config$.next({
SystemConfigCore.create(newSystemConfigRepositoryMock(false), newLoggerRepositoryMock()).config$.next({
job: {
[QueueName.BACKGROUND_TASK]: { concurrency: 10 },
[QueueName.SMART_SEARCH]: { concurrency: 10 },
+4 -3
View File
@@ -17,14 +17,13 @@ import {
QueueCleanType,
QueueName,
} from 'src/interfaces/job.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IMetricRepository } from 'src/interfaces/metric.interface';
import { IPersonRepository } from 'src/interfaces/person.interface';
import { ISystemConfigRepository } from 'src/interfaces/system-config.interface';
import { ImmichLogger } from 'src/utils/logger';
@Injectable()
export class JobService {
private logger = new ImmichLogger(JobService.name);
private configCore: SystemConfigCore;
constructor(
@@ -34,8 +33,10 @@ export class JobService {
@Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository,
@Inject(IPersonRepository) private personRepository: IPersonRepository,
@Inject(IMetricRepository) private metricRepository: IMetricRepository,
@Inject(ILoggerRepository) private logger: ILoggerRepository,
) {
this.configCore = SystemConfigCore.create(configRepository);
this.logger.setContext(JobService.name);
this.configCore = SystemConfigCore.create(configRepository, logger);
}
async handleCommand(queueName: QueueName, dto: JobCommandDto): Promise<JobStatusDto> {
+15 -2
View File
@@ -11,6 +11,7 @@ import { ICryptoRepository } from 'src/interfaces/crypto.interface';
import { IDatabaseRepository } from 'src/interfaces/database.interface';
import { IJobRepository, ILibraryFileJob, ILibraryRefreshJob, JobName, JobStatus } from 'src/interfaces/job.interface';
import { ILibraryRepository } from 'src/interfaces/library.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemConfigRepository } from 'src/interfaces/system-config.interface';
import { LibraryService } from 'src/services/library.service';
@@ -24,6 +25,7 @@ import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.moc
import { newDatabaseRepositoryMock } from 'test/repositories/database.repository.mock';
import { newJobRepositoryMock } from 'test/repositories/job.repository.mock';
import { newLibraryRepositoryMock } from 'test/repositories/library.repository.mock';
import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock';
import { makeMockWatcher, newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
import { Mocked, vitest } from 'vitest';
@@ -38,6 +40,7 @@ describe(LibraryService.name, () => {
let libraryMock: Mocked<ILibraryRepository>;
let storageMock: Mocked<IStorageRepository>;
let databaseMock: Mocked<IDatabaseRepository>;
let loggerMock: Mocked<ILoggerRepository>;
beforeEach(() => {
configMock = newSystemConfigRepositoryMock();
@@ -47,8 +50,18 @@ describe(LibraryService.name, () => {
cryptoMock = newCryptoRepositoryMock();
storageMock = newStorageRepositoryMock();
databaseMock = newDatabaseRepositoryMock();
loggerMock = newLoggerRepositoryMock();
sut = new LibraryService(assetMock, configMock, cryptoMock, jobMock, libraryMock, storageMock, databaseMock);
sut = new LibraryService(
assetMock,
configMock,
cryptoMock,
jobMock,
libraryMock,
storageMock,
databaseMock,
loggerMock,
);
databaseMock.tryLock.mockResolvedValue(true);
});
@@ -68,7 +81,7 @@ describe(LibraryService.name, () => {
expect(configMock.load).toHaveBeenCalled();
expect(jobMock.addCronJob).toHaveBeenCalled();
SystemConfigCore.create(newSystemConfigRepositoryMock(false)).config$.next({
SystemConfigCore.create(newSystemConfigRepositoryMock(false), newLoggerRepositoryMock()).config$.next({
library: {
scan: {
enabled: true,
+4 -3
View File
@@ -36,9 +36,9 @@ import {
JobStatus,
} from 'src/interfaces/job.interface';
import { ILibraryRepository } from 'src/interfaces/library.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemConfigRepository } from 'src/interfaces/system-config.interface';
import { ImmichLogger } from 'src/utils/logger';
import { mimeTypes } from 'src/utils/mime-types';
import { handlePromiseError } from 'src/utils/misc';
import { usePagination } from 'src/utils/pagination';
@@ -48,7 +48,6 @@ const LIBRARY_SCAN_BATCH_SIZE = 5000;
@Injectable()
export class LibraryService {
readonly logger = new ImmichLogger(LibraryService.name);
private configCore: SystemConfigCore;
private watchLibraries = false;
private watchLock = false;
@@ -62,8 +61,10 @@ export class LibraryService {
@Inject(ILibraryRepository) private repository: ILibraryRepository,
@Inject(IStorageRepository) private storageRepository: IStorageRepository,
@Inject(IDatabaseRepository) private databaseRepository: IDatabaseRepository,
@Inject(ILoggerRepository) private logger: ILoggerRepository,
) {
this.configCore = SystemConfigCore.create(configRepository);
this.logger.setContext(LibraryService.name);
this.configCore = SystemConfigCore.create(configRepository, this.logger);
}
async init() {
+15 -1
View File
@@ -14,6 +14,7 @@ import {
import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface';
import { ICryptoRepository } from 'src/interfaces/crypto.interface';
import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IMediaRepository } from 'src/interfaces/media.interface';
import { IMoveRepository } from 'src/interfaces/move.interface';
import { IPersonRepository } from 'src/interfaces/person.interface';
@@ -27,6 +28,7 @@ import { personStub } from 'test/fixtures/person.stub';
import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock';
import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.mock';
import { newJobRepositoryMock } from 'test/repositories/job.repository.mock';
import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock';
import { newMediaRepositoryMock } from 'test/repositories/media.repository.mock';
import { newMoveRepositoryMock } from 'test/repositories/move.repository.mock';
import { newPersonRepositoryMock } from 'test/repositories/person.repository.mock';
@@ -44,6 +46,7 @@ describe(MediaService.name, () => {
let personMock: Mocked<IPersonRepository>;
let storageMock: Mocked<IStorageRepository>;
let cryptoMock: Mocked<ICryptoRepository>;
let loggerMock: Mocked<ILoggerRepository>;
beforeEach(() => {
assetMock = newAssetRepositoryMock();
@@ -54,8 +57,19 @@ describe(MediaService.name, () => {
personMock = newPersonRepositoryMock();
storageMock = newStorageRepositoryMock();
cryptoMock = newCryptoRepositoryMock();
loggerMock = newLoggerRepositoryMock();
sut = new MediaService(assetMock, personMock, jobMock, mediaMock, storageMock, configMock, moveMock, cryptoMock);
sut = new MediaService(
assetMock,
personMock,
jobMock,
mediaMock,
storageMock,
configMock,
moveMock,
cryptoMock,
loggerMock,
);
});
it('should be defined', () => {
+7 -5
View File
@@ -25,12 +25,12 @@ import {
JobStatus,
QueueName,
} from 'src/interfaces/job.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { AudioStreamInfo, IMediaRepository, VideoCodecHWConfig, VideoStreamInfo } from 'src/interfaces/media.interface';
import { IMoveRepository } from 'src/interfaces/move.interface';
import { IPersonRepository } from 'src/interfaces/person.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemConfigRepository } from 'src/interfaces/system-config.interface';
import { ImmichLogger } from 'src/utils/logger';
import {
AV1Config,
H264Config,
@@ -46,7 +46,6 @@ import { usePagination } from 'src/utils/pagination';
@Injectable()
export class MediaService {
private logger = new ImmichLogger(MediaService.name);
private configCore: SystemConfigCore;
private storageCore: StorageCore;
private hasOpenCL?: boolean = undefined;
@@ -60,15 +59,18 @@ export class MediaService {
@Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository,
@Inject(IMoveRepository) moveRepository: IMoveRepository,
@Inject(ICryptoRepository) cryptoRepository: ICryptoRepository,
@Inject(ILoggerRepository) private logger: ILoggerRepository,
) {
this.configCore = SystemConfigCore.create(configRepository);
this.logger.setContext(MediaService.name);
this.configCore = SystemConfigCore.create(configRepository, this.logger);
this.storageCore = StorageCore.create(
assetRepository,
cryptoRepository,
moveRepository,
personRepository,
cryptoRepository,
configRepository,
storageRepository,
configRepository,
this.logger,
);
}
@@ -11,6 +11,7 @@ import { ICryptoRepository } from 'src/interfaces/crypto.interface';
import { IDatabaseRepository } from 'src/interfaces/database.interface';
import { ClientEvent, IEventRepository } from 'src/interfaces/event.interface';
import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IMediaRepository } from 'src/interfaces/media.interface';
import { IMetadataRepository, ImmichTags } from 'src/interfaces/metadata.interface';
import { IMoveRepository } from 'src/interfaces/move.interface';
@@ -27,6 +28,7 @@ import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.moc
import { newDatabaseRepositoryMock } from 'test/repositories/database.repository.mock';
import { newEventRepositoryMock } from 'test/repositories/event.repository.mock';
import { newJobRepositoryMock } from 'test/repositories/job.repository.mock';
import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock';
import { newMediaRepositoryMock } from 'test/repositories/media.repository.mock';
import { newMetadataRepositoryMock } from 'test/repositories/metadata.repository.mock';
import { newMoveRepositoryMock } from 'test/repositories/move.repository.mock';
@@ -48,6 +50,7 @@ describe(MetadataService.name, () => {
let storageMock: Mocked<IStorageRepository>;
let eventMock: Mocked<IEventRepository>;
let databaseMock: Mocked<IDatabaseRepository>;
let loggerMock: Mocked<ILoggerRepository>;
let sut: MetadataService;
beforeEach(() => {
@@ -63,6 +66,7 @@ describe(MetadataService.name, () => {
storageMock = newStorageRepositoryMock();
mediaMock = newMediaRepositoryMock();
databaseMock = newDatabaseRepositoryMock();
loggerMock = newLoggerRepositoryMock();
sut = new MetadataService(
albumMock,
@@ -77,6 +81,7 @@ describe(MetadataService.name, () => {
personMock,
storageMock,
configMock,
loggerMock,
);
});
+7 -5
View File
@@ -25,13 +25,13 @@ import {
JobStatus,
QueueName,
} from 'src/interfaces/job.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IMediaRepository } from 'src/interfaces/media.interface';
import { IMetadataRepository, ImmichTags } from 'src/interfaces/metadata.interface';
import { IMoveRepository } from 'src/interfaces/move.interface';
import { IPersonRepository } from 'src/interfaces/person.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemConfigRepository } from 'src/interfaces/system-config.interface';
import { ImmichLogger } from 'src/utils/logger';
import { handlePromiseError } from 'src/utils/misc';
import { usePagination } from 'src/utils/pagination';
@@ -97,7 +97,6 @@ const validate = <T>(value: T): NonNullable<T> | null => {
@Injectable()
export class MetadataService {
private logger = new ImmichLogger(MetadataService.name);
private storageCore: StorageCore;
private configCore: SystemConfigCore;
private subscription: Subscription | null = null;
@@ -115,15 +114,18 @@ export class MetadataService {
@Inject(IPersonRepository) personRepository: IPersonRepository,
@Inject(IStorageRepository) private storageRepository: IStorageRepository,
@Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository,
@Inject(ILoggerRepository) private logger: ILoggerRepository,
) {
this.configCore = SystemConfigCore.create(configRepository);
this.logger.setContext(MetadataService.name);
this.configCore = SystemConfigCore.create(configRepository, this.logger);
this.storageCore = StorageCore.create(
assetRepository,
cryptoRepository,
moveRepository,
personRepository,
cryptoRepository,
configRepository,
storageRepository,
configRepository,
this.logger,
);
}
@@ -6,6 +6,7 @@ import { Colorspace, SystemConfigKey } from 'src/entities/system-config.entity';
import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface';
import { ICryptoRepository } from 'src/interfaces/crypto.interface';
import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface';
import { IMediaRepository } from 'src/interfaces/media.interface';
import { IMoveRepository } from 'src/interfaces/move.interface';
@@ -23,6 +24,7 @@ import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositorie
import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock';
import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.mock';
import { newJobRepositoryMock } from 'test/repositories/job.repository.mock';
import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock';
import { newMachineLearningRepositoryMock } from 'test/repositories/machine-learning.repository.mock';
import { newMediaRepositoryMock } from 'test/repositories/media.repository.mock';
import { newMoveRepositoryMock } from 'test/repositories/move.repository.mock';
@@ -72,6 +74,7 @@ describe(PersonService.name, () => {
let storageMock: Mocked<IStorageRepository>;
let searchMock: Mocked<ISearchRepository>;
let cryptoMock: Mocked<ICryptoRepository>;
let loggerMock: Mocked<ILoggerRepository>;
let sut: PersonService;
beforeEach(() => {
@@ -86,6 +89,7 @@ describe(PersonService.name, () => {
storageMock = newStorageRepositoryMock();
searchMock = newSearchRepositoryMock();
cryptoMock = newCryptoRepositoryMock();
loggerMock = newLoggerRepositoryMock();
sut = new PersonService(
accessMock,
assetMock,
@@ -98,6 +102,7 @@ describe(PersonService.name, () => {
jobMock,
searchMock,
cryptoMock,
loggerMock,
);
mediaMock.crop.mockResolvedValue(croppedFace);
+7 -5
View File
@@ -38,6 +38,7 @@ import {
JobStatus,
QueueName,
} from 'src/interfaces/job.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface';
import { CropOptions, IMediaRepository } from 'src/interfaces/media.interface';
import { IMoveRepository } from 'src/interfaces/move.interface';
@@ -46,7 +47,6 @@ import { ISearchRepository } from 'src/interfaces/search.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemConfigRepository } from 'src/interfaces/system-config.interface';
import { CacheControl, ImmichFileResponse } from 'src/utils/file';
import { ImmichLogger } from 'src/utils/logger';
import { mimeTypes } from 'src/utils/mime-types';
import { usePagination } from 'src/utils/pagination';
import { IsNull } from 'typeorm';
@@ -56,7 +56,6 @@ export class PersonService {
private access: AccessCore;
private configCore: SystemConfigCore;
private storageCore: StorageCore;
readonly logger = new ImmichLogger(PersonService.name);
constructor(
@Inject(IAccessRepository) accessRepository: IAccessRepository,
@@ -70,16 +69,19 @@ export class PersonService {
@Inject(IJobRepository) private jobRepository: IJobRepository,
@Inject(ISearchRepository) private smartInfoRepository: ISearchRepository,
@Inject(ICryptoRepository) cryptoRepository: ICryptoRepository,
@Inject(ILoggerRepository) private logger: ILoggerRepository,
) {
this.access = AccessCore.create(accessRepository);
this.configCore = SystemConfigCore.create(configRepository);
this.logger.setContext(PersonService.name);
this.configCore = SystemConfigCore.create(configRepository, this.logger);
this.storageCore = StorageCore.create(
assetRepository,
cryptoRepository,
moveRepository,
repository,
cryptoRepository,
configRepository,
storageRepository,
configRepository,
this.logger,
);
}
+14 -1
View File
@@ -2,6 +2,7 @@ import { mapAsset } from 'src/dtos/asset-response.dto';
import { SearchDto } from 'src/dtos/search.dto';
import { SystemConfigKey } from 'src/entities/system-config.entity';
import { IAssetRepository } from 'src/interfaces/asset.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface';
import { IMetadataRepository } from 'src/interfaces/metadata.interface';
import { IPartnerRepository } from 'src/interfaces/partner.interface';
@@ -13,6 +14,7 @@ import { assetStub } from 'test/fixtures/asset.stub';
import { authStub } from 'test/fixtures/auth.stub';
import { personStub } from 'test/fixtures/person.stub';
import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock';
import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock';
import { newMachineLearningRepositoryMock } from 'test/repositories/machine-learning.repository.mock';
import { newMetadataRepositoryMock } from 'test/repositories/metadata.repository.mock';
import { newPartnerRepositoryMock } from 'test/repositories/partner.repository.mock';
@@ -32,6 +34,7 @@ describe(SearchService.name, () => {
let searchMock: Mocked<ISearchRepository>;
let partnerMock: Mocked<IPartnerRepository>;
let metadataMock: Mocked<IMetadataRepository>;
let loggerMock: Mocked<ILoggerRepository>;
beforeEach(() => {
assetMock = newAssetRepositoryMock();
@@ -41,8 +44,18 @@ describe(SearchService.name, () => {
searchMock = newSearchRepositoryMock();
partnerMock = newPartnerRepositoryMock();
metadataMock = newMetadataRepositoryMock();
loggerMock = newLoggerRepositoryMock();
sut = new SearchService(configMock, machineMock, personMock, searchMock, assetMock, partnerMock, metadataMock);
sut = new SearchService(
configMock,
machineMock,
personMock,
searchMock,
assetMock,
partnerMock,
metadataMock,
loggerMock,
);
});
it('should work', () => {
+4 -1
View File
@@ -18,6 +18,7 @@ import {
import { AssetOrder } from 'src/entities/album.entity';
import { AssetEntity } from 'src/entities/asset.entity';
import { IAssetRepository } from 'src/interfaces/asset.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface';
import { IMetadataRepository } from 'src/interfaces/metadata.interface';
import { IPartnerRepository } from 'src/interfaces/partner.interface';
@@ -37,8 +38,10 @@ export class SearchService {
@Inject(IAssetRepository) private assetRepository: IAssetRepository,
@Inject(IPartnerRepository) private partnerRepository: IPartnerRepository,
@Inject(IMetadataRepository) private metadataRepository: IMetadataRepository,
@Inject(ILoggerRepository) private logger: ILoggerRepository,
) {
this.configCore = SystemConfigCore.create(configRepository);
this.logger.setContext(SearchService.name);
this.configCore = SystemConfigCore.create(configRepository, logger);
}
async searchPerson(auth: AuthDto, dto: SearchPeopleDto): Promise<PersonResponseDto[]> {
@@ -1,6 +1,7 @@
import { serverVersion } from 'src/constants';
import { SystemMetadataKey } from 'src/entities/system-metadata.entity';
import { IEventRepository } from 'src/interfaces/event.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IServerInfoRepository } from 'src/interfaces/server-info.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemConfigRepository } from 'src/interfaces/system-config.interface';
@@ -8,6 +9,7 @@ import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interf
import { IUserRepository } from 'src/interfaces/user.interface';
import { ServerInfoService } from 'src/services/server-info.service';
import { newEventRepositoryMock } from 'test/repositories/event.repository.mock';
import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock';
import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
import { newServerInfoRepositoryMock } from 'test/repositories/system-info.repository.mock';
@@ -23,6 +25,7 @@ describe(ServerInfoService.name, () => {
let storageMock: Mocked<IStorageRepository>;
let userMock: Mocked<IUserRepository>;
let systemMetadataMock: Mocked<ISystemMetadataRepository>;
let loggerMock: Mocked<ILoggerRepository>;
beforeEach(() => {
configMock = newSystemConfigRepositoryMock();
@@ -31,8 +34,17 @@ describe(ServerInfoService.name, () => {
storageMock = newStorageRepositoryMock();
userMock = newUserRepositoryMock();
systemMetadataMock = newSystemMetadataRepositoryMock();
loggerMock = newLoggerRepositoryMock();
sut = new ServerInfoService(eventMock, configMock, userMock, serverInfoMock, storageMock, systemMetadataMock);
sut = new ServerInfoService(
eventMock,
configMock,
userMock,
serverInfoMock,
storageMock,
systemMetadataMock,
loggerMock,
);
});
it('should work', () => {
+5 -4
View File
@@ -15,19 +15,18 @@ import {
} from 'src/dtos/server-info.dto';
import { SystemMetadataKey } from 'src/entities/system-metadata.entity';
import { ClientEvent, IEventRepository, ServerEvent, ServerEventMap } from 'src/interfaces/event.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IServerInfoRepository } from 'src/interfaces/server-info.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemConfigRepository } from 'src/interfaces/system-config.interface';
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
import { IUserRepository, UserStatsQueryResponse } from 'src/interfaces/user.interface';
import { asHumanReadable } from 'src/utils/bytes';
import { ImmichLogger } from 'src/utils/logger';
import { mimeTypes } from 'src/utils/mime-types';
import { Version } from 'src/utils/version';
@Injectable()
export class ServerInfoService {
private logger = new ImmichLogger(ServerInfoService.name);
private configCore: SystemConfigCore;
private releaseVersion = serverVersion;
private releaseVersionCheckedAt: DateTime | null = null;
@@ -38,9 +37,11 @@ export class ServerInfoService {
@Inject(IUserRepository) private userRepository: IUserRepository,
@Inject(IServerInfoRepository) private repository: IServerInfoRepository,
@Inject(IStorageRepository) private storageRepository: IStorageRepository,
@Inject(ISystemMetadataRepository) private readonly systemMetadataRepository: ISystemMetadataRepository,
@Inject(ISystemMetadataRepository) private systemMetadataRepository: ISystemMetadataRepository,
@Inject(ILoggerRepository) private logger: ILoggerRepository,
) {
this.configCore = SystemConfigCore.create(configRepository);
this.logger.setContext(ServerInfoService.name);
this.configCore = SystemConfigCore.create(configRepository, this.logger);
}
onConnect() {}
@@ -3,6 +3,7 @@ import { SystemConfigKey } from 'src/entities/system-config.entity';
import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface';
import { IDatabaseRepository } from 'src/interfaces/database.interface';
import { IJobRepository, JobName } from 'src/interfaces/job.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface';
import { ISearchRepository } from 'src/interfaces/search.interface';
import { ISystemConfigRepository } from 'src/interfaces/system-config.interface';
@@ -12,6 +13,7 @@ import { assetStub } from 'test/fixtures/asset.stub';
import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock';
import { newDatabaseRepositoryMock } from 'test/repositories/database.repository.mock';
import { newJobRepositoryMock } from 'test/repositories/job.repository.mock';
import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock';
import { newMachineLearningRepositoryMock } from 'test/repositories/machine-learning.repository.mock';
import { newSearchRepositoryMock } from 'test/repositories/search.repository.mock';
import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
@@ -30,6 +32,7 @@ describe(SmartInfoService.name, () => {
let searchMock: Mocked<ISearchRepository>;
let machineMock: Mocked<IMachineLearningRepository>;
let databaseMock: Mocked<IDatabaseRepository>;
let loggerMock: Mocked<ILoggerRepository>;
beforeEach(() => {
assetMock = newAssetRepositoryMock();
@@ -38,7 +41,8 @@ describe(SmartInfoService.name, () => {
jobMock = newJobRepositoryMock();
machineMock = newMachineLearningRepositoryMock();
databaseMock = newDatabaseRepositoryMock();
sut = new SmartInfoService(assetMock, databaseMock, jobMock, machineMock, searchMock, configMock);
loggerMock = newLoggerRepositoryMock();
sut = new SmartInfoService(assetMock, databaseMock, jobMock, machineMock, searchMock, configMock, loggerMock);
assetMock.getByIds.mockResolvedValue([asset]);
});
+4 -3
View File
@@ -11,16 +11,15 @@ import {
JobStatus,
QueueName,
} from 'src/interfaces/job.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface';
import { ISearchRepository } from 'src/interfaces/search.interface';
import { ISystemConfigRepository } from 'src/interfaces/system-config.interface';
import { ImmichLogger } from 'src/utils/logger';
import { usePagination } from 'src/utils/pagination';
@Injectable()
export class SmartInfoService {
private configCore: SystemConfigCore;
private logger = new ImmichLogger(SmartInfoService.name);
constructor(
@Inject(IAssetRepository) private assetRepository: IAssetRepository,
@@ -29,8 +28,10 @@ export class SmartInfoService {
@Inject(IMachineLearningRepository) private machineLearning: IMachineLearningRepository,
@Inject(ISearchRepository) private repository: ISearchRepository,
@Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository,
@Inject(ILoggerRepository) private logger: ILoggerRepository,
) {
this.configCore = SystemConfigCore.create(configRepository);
this.logger.setContext(SmartInfoService.name);
this.configCore = SystemConfigCore.create(configRepository, this.logger);
}
async init() {
@@ -8,6 +8,7 @@ import { IAssetRepository } from 'src/interfaces/asset.interface';
import { ICryptoRepository } from 'src/interfaces/crypto.interface';
import { IDatabaseRepository } from 'src/interfaces/database.interface';
import { JobStatus } from 'src/interfaces/job.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IMoveRepository } from 'src/interfaces/move.interface';
import { IPersonRepository } from 'src/interfaces/person.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface';
@@ -20,6 +21,7 @@ import { newAlbumRepositoryMock } from 'test/repositories/album.repository.mock'
import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock';
import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.mock';
import { newDatabaseRepositoryMock } from 'test/repositories/database.repository.mock';
import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock';
import { newMoveRepositoryMock } from 'test/repositories/move.repository.mock';
import { newPersonRepositoryMock } from 'test/repositories/person.repository.mock';
import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
@@ -38,6 +40,7 @@ describe(StorageTemplateService.name, () => {
let userMock: Mocked<IUserRepository>;
let cryptoMock: Mocked<ICryptoRepository>;
let databaseMock: Mocked<IDatabaseRepository>;
let loggerMock: Mocked<ILoggerRepository>;
it('should work', () => {
expect(sut).toBeDefined();
@@ -53,6 +56,7 @@ describe(StorageTemplateService.name, () => {
userMock = newUserRepositoryMock();
cryptoMock = newCryptoRepositoryMock();
databaseMock = newDatabaseRepositoryMock();
loggerMock = newLoggerRepositoryMock();
configMock.load.mockResolvedValue([{ key: SystemConfigKey.STORAGE_TEMPLATE_ENABLED, value: true }]);
@@ -66,9 +70,10 @@ describe(StorageTemplateService.name, () => {
userMock,
cryptoMock,
databaseMock,
loggerMock,
);
SystemConfigCore.create(configMock).config$.next(defaults);
SystemConfigCore.create(configMock, loggerMock).config$.next(defaults);
});
describe('onValidateConfig', () => {
@@ -24,13 +24,13 @@ import { ICryptoRepository } from 'src/interfaces/crypto.interface';
import { DatabaseLock, IDatabaseRepository } from 'src/interfaces/database.interface';
import { ServerAsyncEvent, ServerAsyncEventMap } from 'src/interfaces/event.interface';
import { IEntityJob, JOBS_ASSET_PAGINATION_SIZE, JobStatus } from 'src/interfaces/job.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IMoveRepository } from 'src/interfaces/move.interface';
import { IPersonRepository } from 'src/interfaces/person.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemConfigRepository } from 'src/interfaces/system-config.interface';
import { IUserRepository } from 'src/interfaces/user.interface';
import { getLivePhotoMotionFilename } from 'src/utils/file';
import { ImmichLogger } from 'src/utils/logger';
import { usePagination } from 'src/utils/pagination';
export interface MoveAssetMetadata {
@@ -47,7 +47,6 @@ interface RenderMetadata {
@Injectable()
export class StorageTemplateService {
private logger = new ImmichLogger(StorageTemplateService.name);
private configCore: SystemConfigCore;
private storageCore: StorageCore;
private _template: {
@@ -73,16 +72,19 @@ export class StorageTemplateService {
@Inject(IUserRepository) private userRepository: IUserRepository,
@Inject(ICryptoRepository) cryptoRepository: ICryptoRepository,
@Inject(IDatabaseRepository) private databaseRepository: IDatabaseRepository,
@Inject(ILoggerRepository) private logger: ILoggerRepository,
) {
this.configCore = SystemConfigCore.create(configRepository);
this.logger.setContext(StorageTemplateService.name);
this.configCore = SystemConfigCore.create(configRepository, this.logger);
this.configCore.config$.subscribe((config) => this.onConfig(config));
this.storageCore = StorageCore.create(
assetRepository,
cryptoRepository,
moveRepository,
personRepository,
cryptoRepository,
configRepository,
storageRepository,
configRepository,
this.logger,
);
}
+5 -1
View File
@@ -1,15 +1,19 @@
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface';
import { StorageService } from 'src/services/storage.service';
import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock';
import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
import { Mocked } from 'vitest';
describe(StorageService.name, () => {
let sut: StorageService;
let storageMock: Mocked<IStorageRepository>;
let loggerMock: Mocked<ILoggerRepository>;
beforeEach(() => {
storageMock = newStorageRepositoryMock();
sut = new StorageService(storageMock);
loggerMock = newLoggerRepositoryMock();
sut = new StorageService(storageMock, loggerMock);
});
it('should work', () => {
+7 -4
View File
@@ -1,14 +1,17 @@
import { Inject, Injectable } from '@nestjs/common';
import { StorageCore, StorageFolder } from 'src/cores/storage.core';
import { IDeleteFilesJob, JobStatus } from 'src/interfaces/job.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ImmichLogger } from 'src/utils/logger';
@Injectable()
export class StorageService {
private logger = new ImmichLogger(StorageService.name);
constructor(@Inject(IStorageRepository) private storageRepository: IStorageRepository) {}
constructor(
@Inject(IStorageRepository) private storageRepository: IStorageRepository,
@Inject(ILoggerRepository) private logger: ILoggerRepository,
) {
this.logger.setContext(StorageService.name);
}
init() {
const libraryBase = StorageCore.getBaseFolder(StorageFolder.LIBRARY);
@@ -20,11 +20,10 @@ import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { ISearchRepository } from 'src/interfaces/search.interface';
import { ISystemConfigRepository } from 'src/interfaces/system-config.interface';
import { SystemConfigService } from 'src/services/system-config.service';
import { ImmichLogger } from 'src/utils/logger';
import { newEventRepositoryMock } from 'test/repositories/event.repository.mock';
import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock';
import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
import { MockInstance, Mocked, vitest } from 'vitest';
import { Mocked } from 'vitest';
const updates: SystemConfigEntity[] = [
{ key: SystemConfigKey.FFMPEG_CRF, value: 30 },
@@ -184,16 +183,6 @@ describe(SystemConfigService.name, () => {
});
describe('getConfig', () => {
let warnLog: MockInstance;
beforeEach(() => {
warnLog = vitest.spyOn(ImmichLogger.prototype, 'warn');
});
afterEach(() => {
warnLog.mockRestore();
});
it('should return the default config', async () => {
configMock.load.mockResolvedValue([]);
@@ -271,7 +260,7 @@ describe(SystemConfigService.name, () => {
configMock.readFile.mockResolvedValue(partialConfig);
await sut.getConfig();
expect(warnLog).toHaveBeenCalled();
expect(loggerMock.warn).toHaveBeenCalled();
});
const tests = [
@@ -290,7 +279,7 @@ describe(SystemConfigService.name, () => {
if (test.warn) {
await sut.getConfig();
expect(warnLog).toHaveBeenCalled();
expect(loggerMock.warn).toHaveBeenCalled();
} else {
await expect(sut.getConfig()).rejects.toBeInstanceOf(Error);
}
+2 -2
View File
@@ -36,9 +36,9 @@ export class SystemConfigService {
@Inject(ILoggerRepository) private logger: ILoggerRepository,
@Inject(ISearchRepository) private smartInfoRepository: ISearchRepository,
) {
this.core = SystemConfigCore.create(repository);
this.core.config$.subscribe((config) => this.setLogLevel(config));
this.logger.setContext(SystemConfigService.name);
this.core = SystemConfigCore.create(repository, this.logger);
this.core.config$.subscribe((config) => this.setLogLevel(config));
}
async init() {
+14 -1
View File
@@ -10,6 +10,7 @@ import { IAlbumRepository } from 'src/interfaces/album.interface';
import { ICryptoRepository } from 'src/interfaces/crypto.interface';
import { IJobRepository, JobName } from 'src/interfaces/job.interface';
import { ILibraryRepository } from 'src/interfaces/library.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemConfigRepository } from 'src/interfaces/system-config.interface';
import { IUserRepository } from 'src/interfaces/user.interface';
@@ -22,6 +23,7 @@ import { newAlbumRepositoryMock } from 'test/repositories/album.repository.mock'
import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.mock';
import { newJobRepositoryMock } from 'test/repositories/job.repository.mock';
import { newLibraryRepositoryMock } from 'test/repositories/library.repository.mock';
import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock';
import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
import { newUserRepositoryMock } from 'test/repositories/user.repository.mock';
@@ -43,6 +45,7 @@ describe(UserService.name, () => {
let libraryMock: Mocked<ILibraryRepository>;
let storageMock: Mocked<IStorageRepository>;
let configMock: Mocked<ISystemConfigRepository>;
let loggerMock: Mocked<ILoggerRepository>;
beforeEach(() => {
albumMock = newAlbumRepositoryMock();
@@ -52,8 +55,18 @@ describe(UserService.name, () => {
libraryMock = newLibraryRepositoryMock();
storageMock = newStorageRepositoryMock();
userMock = newUserRepositoryMock();
loggerMock = newLoggerRepositoryMock();
sut = new UserService(albumMock, cryptoRepositoryMock, jobMock, libraryMock, storageMock, configMock, userMock);
sut = new UserService(
albumMock,
cryptoRepositoryMock,
jobMock,
libraryMock,
storageMock,
configMock,
userMock,
loggerMock,
);
userMock.get.mockImplementation((userId) =>
Promise.resolve([userStub.admin, userStub.user1].find((user) => user.id === userId) ?? null),
+4 -3
View File
@@ -11,16 +11,15 @@ import { IAlbumRepository } from 'src/interfaces/album.interface';
import { ICryptoRepository } from 'src/interfaces/crypto.interface';
import { IEntityJob, IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface';
import { ILibraryRepository } from 'src/interfaces/library.interface';
import { ILoggerRepository } from 'src/interfaces/logger.interface';
import { IStorageRepository } from 'src/interfaces/storage.interface';
import { ISystemConfigRepository } from 'src/interfaces/system-config.interface';
import { IUserRepository, UserFindOptions } from 'src/interfaces/user.interface';
import { CacheControl, ImmichFileResponse } from 'src/utils/file';
import { ImmichLogger } from 'src/utils/logger';
@Injectable()
export class UserService {
private configCore: SystemConfigCore;
private logger = new ImmichLogger(UserService.name);
private userCore: UserCore;
constructor(
@@ -31,9 +30,11 @@ export class UserService {
@Inject(IStorageRepository) private storageRepository: IStorageRepository,
@Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository,
@Inject(IUserRepository) private userRepository: IUserRepository,
@Inject(ILoggerRepository) private logger: ILoggerRepository,
) {
this.userCore = UserCore.create(cryptoRepository, libraryRepository, userRepository);
this.configCore = SystemConfigCore.create(configRepository);
this.logger.setContext(UserService.name);
this.configCore = SystemConfigCore.create(configRepository, this.logger);
}
async getAll(auth: AuthDto, isAll: boolean): Promise<UserResponseDto[]> {