mirror of
https://github.com/immich-app/immich.git
synced 2024-12-26 10:50:29 +02:00
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:
parent
877207a2e6
commit
6e6deec40c
@ -9,7 +9,7 @@ import { UserService } from 'src/services/user.service';
|
||||
export class ResetAdminPasswordCommand extends CommandRunner {
|
||||
constructor(
|
||||
private userService: UserService,
|
||||
private readonly inquirer: InquirerService,
|
||||
private inquirer: InquirerService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ import { UUIDParamDto } from 'src/validation';
|
||||
@Controller('shared-link')
|
||||
@Authenticated()
|
||||
export class SharedLinkController {
|
||||
constructor(private readonly service: SharedLinkService) {}
|
||||
constructor(private service: SharedLinkService) {}
|
||||
|
||||
@Get()
|
||||
getAllSharedLinks(@Auth() auth: AuthDto): Promise<SharedLinkResponseDto[]> {
|
||||
|
@ -8,7 +8,7 @@ import { SystemConfigService } from 'src/services/system-config.service';
|
||||
@Controller('system-config')
|
||||
@Authenticated({ admin: true })
|
||||
export class SystemConfigController {
|
||||
constructor(private readonly service: SystemConfigService) {}
|
||||
constructor(private service: SystemConfigService) {}
|
||||
|
||||
@Get()
|
||||
getConfig(): Promise<SystemConfigDto> {
|
||||
|
@ -7,11 +7,11 @@ import { PersonEntity } from 'src/entities/person.entity';
|
||||
import { ImageFormat } from 'src/entities/system-config.entity';
|
||||
import { IAssetRepository } from 'src/interfaces/asset.interface';
|
||||
import { ICryptoRepository } from 'src/interfaces/crypto.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 { ImmichLogger } from 'src/utils/logger';
|
||||
|
||||
export enum StorageFolder {
|
||||
ENCODED_VIDEO = 'encoded-video',
|
||||
@ -41,35 +41,37 @@ export type GeneratedAssetType = GeneratedImageType | AssetPathType.ENCODED_VIDE
|
||||
let instance: StorageCore | null;
|
||||
|
||||
export class StorageCore {
|
||||
private logger = new ImmichLogger(StorageCore.name);
|
||||
private configCore;
|
||||
private constructor(
|
||||
private assetRepository: IAssetRepository,
|
||||
private cryptoRepository: ICryptoRepository,
|
||||
private moveRepository: IMoveRepository,
|
||||
private personRepository: IPersonRepository,
|
||||
private cryptoRepository: ICryptoRepository,
|
||||
private repository: IStorageRepository,
|
||||
private storageRepository: IStorageRepository,
|
||||
systemConfigRepository: ISystemConfigRepository,
|
||||
private logger: ILoggerRepository,
|
||||
) {
|
||||
this.configCore = SystemConfigCore.create(systemConfigRepository);
|
||||
this.configCore = SystemConfigCore.create(systemConfigRepository, this.logger);
|
||||
}
|
||||
|
||||
static create(
|
||||
assetRepository: IAssetRepository,
|
||||
cryptoRepository: ICryptoRepository,
|
||||
moveRepository: IMoveRepository,
|
||||
personRepository: IPersonRepository,
|
||||
cryptoRepository: ICryptoRepository,
|
||||
configRepository: ISystemConfigRepository,
|
||||
repository: IStorageRepository,
|
||||
storageRepository: IStorageRepository,
|
||||
systemConfigRepository: ISystemConfigRepository,
|
||||
logger: ILoggerRepository,
|
||||
) {
|
||||
if (!instance) {
|
||||
instance = new StorageCore(
|
||||
assetRepository,
|
||||
cryptoRepository,
|
||||
moveRepository,
|
||||
personRepository,
|
||||
cryptoRepository,
|
||||
repository,
|
||||
configRepository,
|
||||
storageRepository,
|
||||
systemConfigRepository,
|
||||
logger,
|
||||
);
|
||||
}
|
||||
|
||||
@ -170,8 +172,8 @@ export class StorageCore {
|
||||
let move = await this.moveRepository.getByEntity(entityId, pathType);
|
||||
if (move) {
|
||||
this.logger.log(`Attempting to finish incomplete move: ${move.oldPath} => ${move.newPath}`);
|
||||
const oldPathExists = await this.repository.checkFileExists(move.oldPath);
|
||||
const newPathExists = await this.repository.checkFileExists(move.newPath);
|
||||
const oldPathExists = await this.storageRepository.checkFileExists(move.oldPath);
|
||||
const newPathExists = await this.storageRepository.checkFileExists(move.newPath);
|
||||
const newPathCheck = newPathExists ? move.newPath : null;
|
||||
const actualPath = oldPathExists ? move.oldPath : newPathCheck;
|
||||
if (!actualPath) {
|
||||
@ -205,7 +207,7 @@ export class StorageCore {
|
||||
if (move.oldPath !== newPath) {
|
||||
try {
|
||||
this.logger.debug(`Attempting to rename file: ${move.oldPath} => ${newPath}`);
|
||||
await this.repository.rename(move.oldPath, newPath);
|
||||
await this.storageRepository.rename(move.oldPath, newPath);
|
||||
} catch (error: any) {
|
||||
if (error.code !== 'EXDEV') {
|
||||
this.logger.warn(
|
||||
@ -214,19 +216,19 @@ export class StorageCore {
|
||||
return;
|
||||
}
|
||||
this.logger.debug(`Unable to rename file. Falling back to copy, verify and delete`);
|
||||
await this.repository.copyFile(move.oldPath, newPath);
|
||||
await this.storageRepository.copyFile(move.oldPath, newPath);
|
||||
|
||||
if (!(await this.verifyNewPathContentsMatchesExpected(move.oldPath, newPath, assetInfo))) {
|
||||
this.logger.warn(`Skipping move due to file size mismatch`);
|
||||
await this.repository.unlink(newPath);
|
||||
await this.storageRepository.unlink(newPath);
|
||||
return;
|
||||
}
|
||||
|
||||
const { atime, mtime } = await this.repository.stat(move.oldPath);
|
||||
await this.repository.utimes(newPath, atime, mtime);
|
||||
const { atime, mtime } = await this.storageRepository.stat(move.oldPath);
|
||||
await this.storageRepository.utimes(newPath, atime, mtime);
|
||||
|
||||
try {
|
||||
await this.repository.unlink(move.oldPath);
|
||||
await this.storageRepository.unlink(move.oldPath);
|
||||
} catch (error: any) {
|
||||
this.logger.warn(`Unable to delete old file, it will now no longer be tracked by Immich: ${error.message}`);
|
||||
}
|
||||
@ -242,8 +244,8 @@ export class StorageCore {
|
||||
newPath: string,
|
||||
assetInfo?: { sizeInBytes: number; checksum: Buffer },
|
||||
) {
|
||||
const oldStat = await this.repository.stat(oldPath);
|
||||
const newStat = await this.repository.stat(newPath);
|
||||
const oldStat = await this.storageRepository.stat(oldPath);
|
||||
const newStat = await this.storageRepository.stat(newPath);
|
||||
const oldPathSize = assetInfo ? assetInfo.sizeInBytes : oldStat.size;
|
||||
const newPathSize = newStat.size;
|
||||
this.logger.debug(`File size check: ${newPathSize} === ${oldPathSize}`);
|
||||
@ -269,11 +271,11 @@ export class StorageCore {
|
||||
}
|
||||
|
||||
ensureFolders(input: string) {
|
||||
this.repository.mkdirSync(dirname(input));
|
||||
this.storageRepository.mkdirSync(dirname(input));
|
||||
}
|
||||
|
||||
removeEmptyDirs(folder: StorageFolder) {
|
||||
return this.repository.removeEmptyDirs(StorageCore.getBaseFolder(folder));
|
||||
return this.storageRepository.removeEmptyDirs(StorageCore.getBaseFolder(folder));
|
||||
}
|
||||
|
||||
private savePath(pathType: PathType, id: string, newPath: string) {
|
||||
|
@ -22,8 +22,8 @@ import {
|
||||
VideoCodec,
|
||||
} from 'src/entities/system-config.entity';
|
||||
import { QueueName } from 'src/interfaces/job.interface';
|
||||
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
||||
import { ISystemConfigRepository } from 'src/interfaces/system-config.interface';
|
||||
import { ImmichLogger } from 'src/utils/logger';
|
||||
|
||||
export type SystemConfigValidator = (config: SystemConfig, newConfig: SystemConfig) => void | Promise<void>;
|
||||
|
||||
@ -169,16 +169,18 @@ let instance: SystemConfigCore | null;
|
||||
|
||||
@Injectable()
|
||||
export class SystemConfigCore {
|
||||
private logger = new ImmichLogger(SystemConfigCore.name);
|
||||
private configCache: SystemConfigEntity<SystemConfigValue>[] | null = null;
|
||||
|
||||
public config$ = new Subject<SystemConfig>();
|
||||
|
||||
private constructor(private repository: ISystemConfigRepository) {}
|
||||
private constructor(
|
||||
private repository: ISystemConfigRepository,
|
||||
private logger: ILoggerRepository,
|
||||
) {}
|
||||
|
||||
static create(repository: ISystemConfigRepository) {
|
||||
static create(repository: ISystemConfigRepository, logger: ILoggerRepository) {
|
||||
if (!instance) {
|
||||
instance = new SystemConfigCore(repository);
|
||||
instance = new SystemConfigCore(repository, logger);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ async function bootstrapMicroservices() {
|
||||
const host = String(process.env.HOST || '0.0.0.0');
|
||||
const port = Number(process.env.MICROSERVICES_PORT) || 3002;
|
||||
const app = await NestFactory.create(MicroservicesModule, { bufferLogs: true });
|
||||
const logger = app.get(ILoggerRepository);
|
||||
const logger = await app.resolve(ILoggerRepository);
|
||||
logger.setContext('ImmichMicroservice');
|
||||
app.useLogger(logger);
|
||||
app.useWebSocketAdapter(new WebSocketAdapter(app));
|
||||
@ -36,7 +36,7 @@ async function bootstrapApi() {
|
||||
const host = String(process.env.HOST || '0.0.0.0');
|
||||
const port = Number(process.env.SERVER_PORT) || 3001;
|
||||
const app = await NestFactory.create<NestExpressApplication>(ApiModule, { bufferLogs: true });
|
||||
const logger = app.get(ILoggerRepository);
|
||||
const logger = await app.resolve(ILoggerRepository);
|
||||
|
||||
logger.setContext('ImmichServer');
|
||||
app.useLogger(logger);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
|
||||
import { CallHandler, ExecutionContext, Inject, Injectable, NestInterceptor } from '@nestjs/common';
|
||||
import { PATH_METADATA } from '@nestjs/common/constants';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import { transformException } from '@nestjs/platform-express/multer/multer/multer.utils';
|
||||
@ -7,9 +7,9 @@ import multer, { StorageEngine, diskStorage } from 'multer';
|
||||
import { createHash, randomUUID } from 'node:crypto';
|
||||
import { Observable } from 'rxjs';
|
||||
import { UploadFieldName } from 'src/dtos/asset.dto';
|
||||
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
||||
import { AuthRequest } from 'src/middleware/auth.guard';
|
||||
import { AssetService, UploadFile } from 'src/services/asset.service';
|
||||
import { ImmichLogger } from 'src/utils/logger';
|
||||
|
||||
export enum Route {
|
||||
ASSET = 'asset',
|
||||
@ -59,8 +59,6 @@ const asRequest = (request: AuthRequest, file: Express.Multer.File) => {
|
||||
|
||||
@Injectable()
|
||||
export class FileUploadInterceptor implements NestInterceptor {
|
||||
private logger = new ImmichLogger(FileUploadInterceptor.name);
|
||||
|
||||
private handlers: {
|
||||
userProfile: RequestHandler;
|
||||
assetUpload: RequestHandler;
|
||||
@ -70,7 +68,10 @@ export class FileUploadInterceptor implements NestInterceptor {
|
||||
constructor(
|
||||
private reflect: Reflector,
|
||||
private assetService: AssetService,
|
||||
@Inject(ILoggerRepository) private logger: ILoggerRepository,
|
||||
) {
|
||||
this.logger.setContext(FileUploadInterceptor.name);
|
||||
|
||||
this.defaultStorage = diskStorage({
|
||||
filename: this.filename.bind(this),
|
||||
destination: this.destination.bind(this),
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { ChunkedSet, DummyValue, GenerateSql } from 'src/decorators';
|
||||
import { ActivityEntity } from 'src/entities/activity.entity';
|
||||
@ -25,6 +26,7 @@ type IPersonAccess = IAccessRepository['person'];
|
||||
type IPartnerAccess = IAccessRepository['partner'];
|
||||
|
||||
@Instrumentation()
|
||||
@Injectable()
|
||||
class ActivityAccess implements IActivityAccess {
|
||||
constructor(
|
||||
private activityRepository: Repository<ActivityEntity>,
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { AuditEntity } from 'src/entities/audit.entity';
|
||||
import { AuditSearch, IAuditRepository } from 'src/interfaces/audit.interface';
|
||||
@ -5,6 +6,7 @@ import { Instrumentation } from 'src/utils/instrumentation';
|
||||
import { In, LessThan, MoreThan, Repository } from 'typeorm';
|
||||
|
||||
@Instrumentation()
|
||||
@Injectable()
|
||||
export class AuditRepository implements IAuditRepository {
|
||||
constructor(@InjectRepository(AuditEntity) private repository: Repository<AuditEntity>) {}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { InjectDataSource } from '@nestjs/typeorm';
|
||||
import AsyncLock from 'async-lock';
|
||||
import { vectorExt } from 'src/database.config';
|
||||
@ -11,8 +11,8 @@ import {
|
||||
VectorUpdateResult,
|
||||
extName,
|
||||
} from 'src/interfaces/database.interface';
|
||||
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
||||
import { Instrumentation } from 'src/utils/instrumentation';
|
||||
import { ImmichLogger } from 'src/utils/logger';
|
||||
import { Version, VersionType } from 'src/utils/version';
|
||||
import { isValidInteger } from 'src/validation';
|
||||
import { DataSource, EntityManager, QueryRunner } from 'typeorm';
|
||||
@ -20,10 +20,14 @@ import { DataSource, EntityManager, QueryRunner } from 'typeorm';
|
||||
@Instrumentation()
|
||||
@Injectable()
|
||||
export class DatabaseRepository implements IDatabaseRepository {
|
||||
private logger = new ImmichLogger(DatabaseRepository.name);
|
||||
readonly asyncLock = new AsyncLock();
|
||||
|
||||
constructor(@InjectDataSource() private dataSource: DataSource) {}
|
||||
constructor(
|
||||
@InjectDataSource() private dataSource: DataSource,
|
||||
@Inject(ILoggerRepository) private logger: ILoggerRepository,
|
||||
) {
|
||||
this.logger.setContext(DatabaseRepository.name);
|
||||
}
|
||||
|
||||
async getExtensionVersion(extension: DatabaseExtension): Promise<Version | null> {
|
||||
const res = await this.dataSource.query(`SELECT extversion FROM pg_extension WHERE extname = $1`, [extension]);
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import {
|
||||
OnGatewayConnection,
|
||||
@ -14,9 +15,9 @@ import {
|
||||
ServerEvent,
|
||||
ServerEventMap,
|
||||
} from 'src/interfaces/event.interface';
|
||||
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
||||
import { AuthService } from 'src/services/auth.service';
|
||||
import { Instrumentation } from 'src/utils/instrumentation';
|
||||
import { ImmichLogger } from 'src/utils/logger';
|
||||
|
||||
@Instrumentation()
|
||||
@WebSocketGateway({
|
||||
@ -24,16 +25,18 @@ import { ImmichLogger } from 'src/utils/logger';
|
||||
path: '/api/socket.io',
|
||||
transports: ['websocket'],
|
||||
})
|
||||
@Injectable()
|
||||
export class EventRepository implements OnGatewayConnection, OnGatewayDisconnect, OnGatewayInit, IEventRepository {
|
||||
private logger = new ImmichLogger(EventRepository.name);
|
||||
|
||||
@WebSocketServer()
|
||||
private server?: Server;
|
||||
|
||||
constructor(
|
||||
private authService: AuthService,
|
||||
private eventEmitter: EventEmitter2,
|
||||
) {}
|
||||
@Inject(ILoggerRepository) private logger: ILoggerRepository,
|
||||
) {
|
||||
this.logger.setContext(EventRepository.name);
|
||||
}
|
||||
|
||||
afterInit(server: Server) {
|
||||
this.logger.log('Initialized websocket server');
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { getQueueToken } from '@nestjs/bullmq';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { ModuleRef } from '@nestjs/core';
|
||||
import { SchedulerRegistry } from '@nestjs/schedule';
|
||||
import { Job, JobsOptions, Processor, Queue, Worker, WorkerOptions } from 'bullmq';
|
||||
@ -15,8 +15,8 @@ import {
|
||||
QueueName,
|
||||
QueueStatus,
|
||||
} from 'src/interfaces/job.interface';
|
||||
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
||||
import { Instrumentation } from 'src/utils/instrumentation';
|
||||
import { ImmichLogger } from 'src/utils/logger';
|
||||
|
||||
export const JOBS_TO_QUEUE: Record<JobName, QueueName> = {
|
||||
// misc
|
||||
@ -83,12 +83,14 @@ export const JOBS_TO_QUEUE: Record<JobName, QueueName> = {
|
||||
@Injectable()
|
||||
export class JobRepository implements IJobRepository {
|
||||
private workers: Partial<Record<QueueName, Worker>> = {};
|
||||
private logger = new ImmichLogger(JobRepository.name);
|
||||
|
||||
constructor(
|
||||
private moduleReference: ModuleRef,
|
||||
private schedulerReqistry: SchedulerRegistry,
|
||||
) {}
|
||||
@Inject(ILoggerRepository) private logger: ILoggerRepository,
|
||||
) {
|
||||
this.logger.setContext(JobRepository.name);
|
||||
}
|
||||
|
||||
addHandler(queueName: QueueName, concurrency: number, handler: (item: JobItem) => Promise<void>) {
|
||||
const workerHandler: Processor = async (job: Job) => handler(job as JobItem);
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Injectable, Scope } from '@nestjs/common';
|
||||
import { ClsService } from 'nestjs-cls';
|
||||
import { LogLevel } from 'src/entities/system-config.entity';
|
||||
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
||||
import { ImmichLogger } from 'src/utils/logger';
|
||||
|
||||
@Injectable()
|
||||
@Injectable({ scope: Scope.TRANSIENT })
|
||||
export class LoggerRepository extends ImmichLogger implements ILoggerRepository {
|
||||
constructor(private cls: ClsService) {
|
||||
super(LoggerRepository.name);
|
||||
|
@ -1,9 +1,11 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import ffmpeg, { FfprobeData } from 'fluent-ffmpeg';
|
||||
import fs from 'node:fs/promises';
|
||||
import { Writable } from 'node:stream';
|
||||
import { promisify } from 'node:util';
|
||||
import sharp from 'sharp';
|
||||
import { Colorspace } from 'src/entities/system-config.entity';
|
||||
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
||||
import {
|
||||
CropOptions,
|
||||
IMediaRepository,
|
||||
@ -12,7 +14,6 @@ import {
|
||||
VideoInfo,
|
||||
} from 'src/interfaces/media.interface';
|
||||
import { Instrumentation } from 'src/utils/instrumentation';
|
||||
import { ImmichLogger } from 'src/utils/logger';
|
||||
import { handlePromiseError } from 'src/utils/misc';
|
||||
|
||||
const probe = promisify<string, FfprobeData>(ffmpeg.ffprobe);
|
||||
@ -20,9 +21,11 @@ sharp.concurrency(0);
|
||||
sharp.cache({ files: 0 });
|
||||
|
||||
@Instrumentation()
|
||||
@Injectable()
|
||||
export class MediaRepository implements IMediaRepository {
|
||||
private logger = new ImmichLogger(MediaRepository.name);
|
||||
|
||||
constructor(@Inject(ILoggerRepository) private logger: ILoggerRepository) {
|
||||
this.logger.setContext(MediaRepository.name);
|
||||
}
|
||||
crop(input: string | Buffer, options: CropOptions): Promise<Buffer> {
|
||||
return sharp(input, { failOn: 'none' })
|
||||
.pipelineColorspace('rgb16')
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Inject } from '@nestjs/common';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
|
||||
import { DefaultReadTaskOptions, Tags, exiftool } from 'exiftool-vendored';
|
||||
import geotz from 'geo-tz';
|
||||
@ -11,24 +11,26 @@ import { DummyValue, GenerateSql } from 'src/decorators';
|
||||
import { ExifEntity } from 'src/entities/exif.entity';
|
||||
import { GeodataPlacesEntity } from 'src/entities/geodata-places.entity';
|
||||
import { SystemMetadataKey } from 'src/entities/system-metadata.entity';
|
||||
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
||||
import { GeoPoint, IMetadataRepository, ImmichTags, ReverseGeocodeResult } from 'src/interfaces/metadata.interface';
|
||||
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
||||
import { Instrumentation } from 'src/utils/instrumentation';
|
||||
import { ImmichLogger } from 'src/utils/logger';
|
||||
import { DataSource, QueryRunner, Repository } from 'typeorm';
|
||||
import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity.js';
|
||||
|
||||
@Instrumentation()
|
||||
@Injectable()
|
||||
export class MetadataRepository implements IMetadataRepository {
|
||||
constructor(
|
||||
@InjectRepository(ExifEntity) private exifRepository: Repository<ExifEntity>,
|
||||
@InjectRepository(GeodataPlacesEntity) private readonly geodataPlacesRepository: Repository<GeodataPlacesEntity>,
|
||||
@InjectRepository(GeodataPlacesEntity) private geodataPlacesRepository: Repository<GeodataPlacesEntity>,
|
||||
@Inject(ISystemMetadataRepository)
|
||||
private readonly systemMetadataRepository: ISystemMetadataRepository,
|
||||
private systemMetadataRepository: ISystemMetadataRepository,
|
||||
@InjectDataSource() private dataSource: DataSource,
|
||||
) {}
|
||||
|
||||
private logger = new ImmichLogger(MetadataRepository.name);
|
||||
@Inject(ILoggerRepository) private logger: ILoggerRepository,
|
||||
) {
|
||||
this.logger.setContext(MetadataRepository.name);
|
||||
}
|
||||
|
||||
async init(): Promise<void> {
|
||||
this.logger.log('Initializing metadata repository');
|
||||
|
@ -6,7 +6,7 @@ import { apiMetrics, hostMetrics, jobMetrics, repoMetrics } from 'src/utils/inst
|
||||
|
||||
class MetricGroupRepository implements IMetricGroupRepository {
|
||||
private enabled = false;
|
||||
constructor(private readonly metricService: MetricService) {}
|
||||
constructor(private metricService: MetricService) {}
|
||||
|
||||
addToCounter(name: string, value: number, options?: MetricOptions): void {
|
||||
if (this.enabled) {
|
||||
|
@ -8,7 +8,7 @@ import { DeepPartial, Repository } from 'typeorm';
|
||||
@Instrumentation()
|
||||
@Injectable()
|
||||
export class PartnerRepository implements IPartnerRepository {
|
||||
constructor(@InjectRepository(PartnerEntity) private readonly repository: Repository<PartnerEntity>) {}
|
||||
constructor(@InjectRepository(PartnerEntity) private repository: Repository<PartnerEntity>) {}
|
||||
|
||||
getAll(userId: string): Promise<PartnerEntity[]> {
|
||||
return this.repository.find({ where: [{ sharedWithId: userId }, { sharedById: userId }] });
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import _ from 'lodash';
|
||||
import { ChunkedArray, DummyValue, GenerateSql } from 'src/decorators';
|
||||
@ -19,6 +20,7 @@ import { Paginated, PaginationOptions, paginate } from 'src/utils/pagination';
|
||||
import { FindManyOptions, FindOptionsRelations, FindOptionsSelect, In, Repository } from 'typeorm';
|
||||
|
||||
@Instrumentation()
|
||||
@Injectable()
|
||||
export class PersonRepository implements IPersonRepository {
|
||||
constructor(
|
||||
@InjectRepository(AssetEntity) private assetRepository: Repository<AssetEntity>,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { vectorExt } from 'src/database.config';
|
||||
import { DummyValue, GenerateSql } from 'src/decorators';
|
||||
@ -8,6 +8,7 @@ import { GeodataPlacesEntity } from 'src/entities/geodata-places.entity';
|
||||
import { SmartInfoEntity } from 'src/entities/smart-info.entity';
|
||||
import { SmartSearchEntity } from 'src/entities/smart-search.entity';
|
||||
import { DatabaseExtension } from 'src/interfaces/database.interface';
|
||||
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
||||
import {
|
||||
AssetSearchOptions,
|
||||
FaceEmbeddingSearch,
|
||||
@ -18,7 +19,6 @@ import {
|
||||
} from 'src/interfaces/search.interface';
|
||||
import { asVector, searchAssetBuilder } from 'src/utils/database';
|
||||
import { Instrumentation } from 'src/utils/instrumentation';
|
||||
import { ImmichLogger } from 'src/utils/logger';
|
||||
import { getCLIPModelInfo } from 'src/utils/misc';
|
||||
import { Paginated, PaginationMode, PaginationResult, paginatedBuilder } from 'src/utils/pagination';
|
||||
import { isValidInteger } from 'src/validation';
|
||||
@ -27,7 +27,6 @@ import { Repository, SelectQueryBuilder } from 'typeorm';
|
||||
@Instrumentation()
|
||||
@Injectable()
|
||||
export class SearchRepository implements ISearchRepository {
|
||||
private logger = new ImmichLogger(SearchRepository.name);
|
||||
private faceColumns: string[];
|
||||
private assetsByCityQuery: string;
|
||||
|
||||
@ -36,8 +35,10 @@ export class SearchRepository implements ISearchRepository {
|
||||
@InjectRepository(AssetEntity) private assetRepository: Repository<AssetEntity>,
|
||||
@InjectRepository(AssetFaceEntity) private assetFaceRepository: Repository<AssetFaceEntity>,
|
||||
@InjectRepository(SmartSearchEntity) private smartSearchRepository: Repository<SmartSearchEntity>,
|
||||
@InjectRepository(GeodataPlacesEntity) private readonly geodataPlacesRepository: Repository<GeodataPlacesEntity>,
|
||||
@InjectRepository(GeodataPlacesEntity) private geodataPlacesRepository: Repository<GeodataPlacesEntity>,
|
||||
@Inject(ILoggerRepository) private logger: ILoggerRepository,
|
||||
) {
|
||||
this.logger.setContext(SearchRepository.name);
|
||||
this.faceColumns = this.assetFaceRepository.manager.connection
|
||||
.getMetadata(AssetFaceEntity)
|
||||
.ownColumns.map((column) => column.propertyName)
|
||||
|
@ -1,6 +1,8 @@
|
||||
import mockfs from 'mock-fs';
|
||||
import { CrawlOptionsDto } from 'src/dtos/library.dto';
|
||||
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
||||
import { StorageRepository } from 'src/repositories/storage.repository';
|
||||
import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock';
|
||||
|
||||
interface Test {
|
||||
test: string;
|
||||
@ -181,9 +183,11 @@ const tests: Test[] = [
|
||||
|
||||
describe(StorageRepository.name, () => {
|
||||
let sut: StorageRepository;
|
||||
let logger: ILoggerRepository;
|
||||
|
||||
beforeEach(() => {
|
||||
sut = new StorageRepository();
|
||||
logger = newLoggerRepositoryMock();
|
||||
sut = new StorageRepository(logger);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import archiver from 'archiver';
|
||||
import chokidar, { WatchOptions } from 'chokidar';
|
||||
import { glob, globStream } from 'fast-glob';
|
||||
@ -5,6 +6,7 @@ import { constants, createReadStream, existsSync, mkdirSync } from 'node:fs';
|
||||
import fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { CrawlOptionsDto } from 'src/dtos/library.dto';
|
||||
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
||||
import {
|
||||
DiskUsage,
|
||||
IStorageRepository,
|
||||
@ -13,12 +15,14 @@ import {
|
||||
WatchEvents,
|
||||
} from 'src/interfaces/storage.interface';
|
||||
import { Instrumentation } from 'src/utils/instrumentation';
|
||||
import { ImmichLogger } from 'src/utils/logger';
|
||||
import { mimeTypes } from 'src/utils/mime-types';
|
||||
|
||||
@Instrumentation()
|
||||
@Injectable()
|
||||
export class StorageRepository implements IStorageRepository {
|
||||
private logger = new ImmichLogger(StorageRepository.name);
|
||||
constructor(@Inject(ILoggerRepository) private logger: ILoggerRepository) {
|
||||
this.logger.setContext(StorageRepository.name);
|
||||
}
|
||||
|
||||
readdir(folder: string): Promise<string[]> {
|
||||
return fs.readdir(folder);
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { Chunked, DummyValue, GenerateSql } from 'src/decorators';
|
||||
@ -7,6 +8,7 @@ import { Instrumentation } from 'src/utils/instrumentation';
|
||||
import { In, Repository } from 'typeorm';
|
||||
|
||||
@Instrumentation()
|
||||
@Injectable()
|
||||
export class SystemConfigRepository implements ISystemConfigRepository {
|
||||
constructor(
|
||||
@InjectRepository(SystemConfigEntity)
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { SystemMetadata, SystemMetadataEntity } from 'src/entities/system-metadata.entity';
|
||||
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
||||
@ -5,6 +6,7 @@ import { Instrumentation } from 'src/utils/instrumentation';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
@Instrumentation()
|
||||
@Injectable()
|
||||
export class SystemMetadataRepository implements ISystemMetadataRepository {
|
||||
constructor(
|
||||
@InjectRepository(SystemMetadataEntity)
|
||||
|
@ -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() {
|
||||
|
@ -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(
|
||||
|
@ -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]);
|
||||
|
@ -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 {
|
||||
|
@ -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', () => {
|
||||
|
@ -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> {
|
||||
|
@ -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 });
|
||||
}
|
||||
|
@ -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();
|
||||
},
|
||||
);
|
||||
});
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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 },
|
||||
|
@ -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> {
|
||||
|
@ -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,
|
||||
|
@ -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() {
|
||||
|
@ -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', () => {
|
||||
|
@ -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,
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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', () => {
|
||||
|
@ -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', () => {
|
||||
|
@ -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]);
|
||||
});
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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', () => {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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),
|
||||
|
@ -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[]> {
|
||||
|
@ -17,12 +17,12 @@ import {
|
||||
IMMICH_API_KEY_NAME,
|
||||
serverVersion,
|
||||
} from 'src/constants';
|
||||
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
||||
import { Metadata } from 'src/middleware/auth.guard';
|
||||
import { ImmichLogger } from 'src/utils/logger';
|
||||
|
||||
export const isConnectionAborted = (error: Error | any) => error.code === 'ECONNABORTED';
|
||||
|
||||
export const handlePromiseError = <T>(promise: Promise<T>, logger: ImmichLogger): void => {
|
||||
export const handlePromiseError = <T>(promise: Promise<T>, logger: ILoggerRepository): void => {
|
||||
promise.catch((error: Error | any) => logger.error(`Promise error: ${error}`, error?.stack));
|
||||
};
|
||||
|
||||
|
@ -12,6 +12,7 @@ import { format } from 'sql-formatter';
|
||||
import { databaseConfig } from 'src/database.config';
|
||||
import { GENERATE_SQL_KEY, GenerateSqlQueries } from 'src/decorators';
|
||||
import { entities } from 'src/entities';
|
||||
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
||||
import { repositories } from 'src/repositories';
|
||||
import { AccessRepository } from 'src/repositories/access.repository';
|
||||
import { AuthService } from 'src/services/auth.service';
|
||||
@ -58,6 +59,9 @@ class SqlGenerator {
|
||||
try {
|
||||
await this.setup();
|
||||
for (const repository of repositories) {
|
||||
if (repository.provide === ILoggerRepository) {
|
||||
continue;
|
||||
}
|
||||
await this.process(repository);
|
||||
}
|
||||
await this.write();
|
||||
|
Loading…
Reference in New Issue
Block a user