mirror of
				https://github.com/KevinMidboe/immich.git
				synced 2025-10-29 17:40:28 +00:00 
			
		
		
		
	refactor(server): common (#2066)
This commit is contained in:
		| @@ -1,4 +1,4 @@ | ||||
| import { immichAppConfig } from '@app/common/config'; | ||||
| import { immichAppConfig } from '@app/domain'; | ||||
| import { Module, OnModuleInit } from '@nestjs/common'; | ||||
| import { AssetModule } from './api-v1/asset/asset.module'; | ||||
| import { ConfigModule } from '@nestjs/config'; | ||||
|   | ||||
| @@ -9,7 +9,7 @@ import { AppModule } from './app.module'; | ||||
| import { RedisIoAdapter } from './middlewares/redis-io.adapter.middleware'; | ||||
| import { json } from 'body-parser'; | ||||
| import { patchOpenAPI } from './utils/patch-open-api.util'; | ||||
| import { getLogLevels, MACHINE_LEARNING_ENABLED } from '@app/common'; | ||||
| import { getLogLevels, MACHINE_LEARNING_ENABLED } from '@app/domain'; | ||||
| import { SERVER_VERSION, IMMICH_ACCESS_COOKIE, SearchService } from '@app/domain'; | ||||
|  | ||||
| const logger = new Logger('ImmichServer'); | ||||
|   | ||||
| @@ -8,7 +8,6 @@ | ||||
|     "^.+\\.(t|j)s$": "ts-jest" | ||||
|   }, | ||||
|   "moduleNameMapper": { | ||||
|     "^@app/common": "<rootDir>../../../libs/common/src", | ||||
|     "^@app/infra(|/.*)$": "<rootDir>../../../libs/infra/src/$1", | ||||
|     "^@app/domain(|/.*)$": "<rootDir>../../../libs/domain/src/$1" | ||||
|   } | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| import { Logger } from '@nestjs/common'; | ||||
| import { NestFactory } from '@nestjs/core'; | ||||
| import { SERVER_VERSION } from '@app/domain'; | ||||
| import { getLogLevels } from '@app/common'; | ||||
| import { getLogLevels } from '@app/domain'; | ||||
| import { RedisIoAdapter } from '../../immich/src/middlewares/redis-io.adapter.middleware'; | ||||
| import { MicroservicesModule } from './microservices.module'; | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| import { immichAppConfig } from '@app/common/config'; | ||||
| import { immichAppConfig } from '@app/domain'; | ||||
| import { DomainModule } from '@app/domain'; | ||||
| import { ExifEntity, InfraModule } from '@app/infra'; | ||||
| import { Module } from '@nestjs/common'; | ||||
|   | ||||
| @@ -1 +0,0 @@ | ||||
| export * from './app.config'; | ||||
| @@ -1,10 +0,0 @@ | ||||
| import { BadRequestException } from '@nestjs/common'; | ||||
|  | ||||
| export const MACHINE_LEARNING_URL = process.env.IMMICH_MACHINE_LEARNING_URL || 'http://immich-machine-learning:3003'; | ||||
| export const MACHINE_LEARNING_ENABLED = MACHINE_LEARNING_URL !== 'false'; | ||||
|  | ||||
| export function assertMachineLearningEnabled() { | ||||
|   if (!MACHINE_LEARNING_ENABLED) { | ||||
|     throw new BadRequestException('Machine learning is not enabled.'); | ||||
|   } | ||||
| } | ||||
| @@ -1,3 +0,0 @@ | ||||
| export * from './config'; | ||||
| export * from './constants'; | ||||
| export * from './utils'; | ||||
| @@ -1,20 +0,0 @@ | ||||
| import { assetUtils } from './asset-utils'; | ||||
|  | ||||
| describe('Asset Utilities', () => { | ||||
|   describe('isWebPlayable', () => { | ||||
|     it('Check that it returns true with mimetype webm', () => { | ||||
|       const result = assetUtils.isWebPlayable('video/webm'); | ||||
|       expect(result).toBeTruthy(); | ||||
|     }); | ||||
|  | ||||
|     it('Check that returns true with mimetype mp4', () => { | ||||
|       const result = assetUtils.isWebPlayable('video/mp4'); | ||||
|       expect(result).toBeTruthy(); | ||||
|     }); | ||||
|  | ||||
|     it('Check that returns false with mimetype quicktime', () => { | ||||
|       const result = assetUtils.isWebPlayable('video/quicktime'); | ||||
|       expect(result).toBeFalsy(); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
| @@ -1,48 +0,0 @@ | ||||
| import { AssetEntity } from '@app/infra/db/entities'; | ||||
| import { AssetResponseDto } from '@app/domain'; | ||||
| import fs from 'fs'; | ||||
|  | ||||
| const deleteFiles = (asset: AssetEntity | AssetResponseDto) => { | ||||
|   fs.unlink(asset.originalPath, (err) => { | ||||
|     if (err) { | ||||
|       console.log('error deleting ', asset.originalPath); | ||||
|     } | ||||
|   }); | ||||
|  | ||||
|   // TODO: what if there is no asset.resizePath. Should fail the Job? | ||||
|   // => panoti report: Job not fail | ||||
|   if (asset.resizePath) { | ||||
|     fs.unlink(asset.resizePath, (err) => { | ||||
|       if (err) { | ||||
|         console.log('error deleting ', asset.resizePath); | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   if (asset.webpPath) { | ||||
|     fs.unlink(asset.webpPath, (err) => { | ||||
|       if (err) { | ||||
|         console.log('error deleting ', asset.webpPath); | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   if (asset.encodedVideoPath) { | ||||
|     fs.unlink(asset.encodedVideoPath, (err) => { | ||||
|       if (err) { | ||||
|         console.log('error deleting ', asset.encodedVideoPath); | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| const isWebPlayable = (mimeType: string | null): boolean => { | ||||
|   const WEB_PLAYABLE = ['video/webm', 'video/mp4']; | ||||
|  | ||||
|   if (mimeType !== null) { | ||||
|     return WEB_PLAYABLE.includes(mimeType); | ||||
|   } | ||||
|   return false; | ||||
| }; | ||||
|  | ||||
| export const assetUtils = { deleteFiles, isWebPlayable }; | ||||
| @@ -1,14 +0,0 @@ | ||||
| import { LogLevel } from '@nestjs/common'; | ||||
|  | ||||
| export * from './time-utils'; | ||||
| export * from './asset-utils'; | ||||
|  | ||||
| export function getLogLevels() { | ||||
|   const LOG_LEVELS: LogLevel[] = ['verbose', 'debug', 'log', 'warn', 'error']; | ||||
|   let logLevel = process.env.LOG_LEVEL || 'log'; | ||||
|   if (logLevel === 'simple') { | ||||
|     logLevel = 'log'; | ||||
|   } | ||||
|   const logLevelIndex = LOG_LEVELS.indexOf(logLevel as LogLevel); | ||||
|   return logLevelIndex === -1 ? [] : LOG_LEVELS.slice(logLevelIndex); | ||||
| } | ||||
| @@ -1,43 +0,0 @@ | ||||
| // create unit test for time utils | ||||
|  | ||||
| import { timeUtils } from './time-utils'; | ||||
|  | ||||
| describe('Time Utilities', () => { | ||||
|   describe('timezone', () => { | ||||
|     it('should always be UTC', () => { | ||||
|       expect(new Date().getTimezoneOffset()).toBe(0); | ||||
|     }); | ||||
|   }); | ||||
|  | ||||
|   describe('checkValidTimestamp', () => { | ||||
|     it('check for year 0000', () => { | ||||
|       const result = timeUtils.checkValidTimestamp('0000-00-00T00:00:00.000Z'); | ||||
|       expect(result).toBeFalsy(); | ||||
|     }); | ||||
|  | ||||
|     it('check for 6-digits year with plus sign', () => { | ||||
|       const result = timeUtils.checkValidTimestamp('+12345-00-00T00:00:00.000Z'); | ||||
|       expect(result).toBeFalsy(); | ||||
|     }); | ||||
|  | ||||
|     it('check for 6-digits year with negative sign', () => { | ||||
|       const result = timeUtils.checkValidTimestamp('-12345-00-00T00:00:00.000Z'); | ||||
|       expect(result).toBeFalsy(); | ||||
|     }); | ||||
|  | ||||
|     it('check for current date', () => { | ||||
|       const result = timeUtils.checkValidTimestamp(new Date().toISOString()); | ||||
|       expect(result).toBeTruthy(); | ||||
|     }); | ||||
|  | ||||
|     it('check for year before 1583', () => { | ||||
|       const result = timeUtils.checkValidTimestamp('1582-12-31T23:59:59.999Z'); | ||||
|       expect(result).toBeFalsy(); | ||||
|     }); | ||||
|  | ||||
|     it('check for year after 9999', () => { | ||||
|       const result = timeUtils.checkValidTimestamp('10000-00-00T00:00:00.000Z'); | ||||
|       expect(result).toBeFalsy(); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
| @@ -1,21 +0,0 @@ | ||||
| function createTimeUtils() { | ||||
|   const checkValidTimestamp = (timestamp: string): boolean => { | ||||
|     const parsedTimestamp = Date.parse(timestamp); | ||||
|  | ||||
|     if (isNaN(parsedTimestamp)) { | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     const date = new Date(parsedTimestamp); | ||||
|  | ||||
|     if (date.getFullYear() < 1583 || date.getFullYear() > 9999) { | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     return date.getFullYear() > 0; | ||||
|   }; | ||||
|  | ||||
|   return { checkValidTimestamp }; | ||||
| } | ||||
|  | ||||
| export const timeUtils = createTimeUtils(); | ||||
| @@ -1,9 +0,0 @@ | ||||
| { | ||||
|   "extends": "../../tsconfig.json", | ||||
|   "compilerOptions": { | ||||
|     "declaration": true, | ||||
|     "outDir": "../../dist/libs/common" | ||||
|   }, | ||||
|   "include": ["src/**/*"], | ||||
|   "exclude": ["node_modules", "dist", "test", "**/*spec.ts"] | ||||
| } | ||||
| @@ -1,3 +1,5 @@ | ||||
| // TODO: remove nestjs references from domain
 | ||||
| import { LogLevel } from '@nestjs/common'; | ||||
| import { ConfigModuleOptions } from '@nestjs/config'; | ||||
| import Joi from 'joi'; | ||||
| 
 | ||||
| @@ -29,3 +31,13 @@ export const immichAppConfig: ConfigModuleOptions = { | ||||
|     SERVER_PORT: Joi.number().optional(), | ||||
|   }), | ||||
| }; | ||||
| 
 | ||||
| export function getLogLevels() { | ||||
|   const LOG_LEVELS: LogLevel[] = ['verbose', 'debug', 'log', 'warn', 'error']; | ||||
|   let logLevel = process.env.LOG_LEVEL || 'log'; | ||||
|   if (logLevel === 'simple') { | ||||
|     logLevel = 'log'; | ||||
|   } | ||||
|   const logLevelIndex = LOG_LEVELS.indexOf(logLevel as LogLevel); | ||||
|   return logLevelIndex === -1 ? [] : LOG_LEVELS.slice(logLevelIndex); | ||||
| } | ||||
| @@ -1,3 +1,4 @@ | ||||
| import { BadRequestException } from '@nestjs/common'; | ||||
| import pkg from '../../../package.json'; | ||||
|  | ||||
| const [major, minor, patch] = pkg.version.split('.'); | ||||
| @@ -17,3 +18,12 @@ export const serverVersion: IServerVersion = { | ||||
| export const SERVER_VERSION = `${serverVersion.major}.${serverVersion.minor}.${serverVersion.patch}`; | ||||
|  | ||||
| export const APP_UPLOAD_LOCATION = './upload'; | ||||
|  | ||||
| export const MACHINE_LEARNING_URL = process.env.IMMICH_MACHINE_LEARNING_URL || 'http://immich-machine-learning:3003'; | ||||
| export const MACHINE_LEARNING_ENABLED = MACHINE_LEARNING_URL !== 'false'; | ||||
|  | ||||
| export function assertMachineLearningEnabled() { | ||||
|   if (!MACHINE_LEARNING_ENABLED) { | ||||
|     throw new BadRequestException('Machine learning is not enabled.'); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -5,6 +5,7 @@ export * from './auth'; | ||||
| export * from './communication'; | ||||
| export * from './crypto'; | ||||
| export * from './device-info'; | ||||
| export * from './domain.config'; | ||||
| export * from './domain.constant'; | ||||
| export * from './domain.module'; | ||||
| export * from './domain.util'; | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import { assertMachineLearningEnabled } from '@app/common'; | ||||
| import { BadRequestException, Inject, Injectable, Logger } from '@nestjs/common'; | ||||
| import { assertMachineLearningEnabled } from '../domain.constant'; | ||||
| import { JobCommandDto } from './dto'; | ||||
| import { JobCommand, JobName, QueueName } from './job.constants'; | ||||
| import { IJobRepository } from './job.repository'; | ||||
|   | ||||
| @@ -1,4 +1,3 @@ | ||||
| import { MACHINE_LEARNING_ENABLED } from '@app/common'; | ||||
| import { AlbumEntity, AssetEntity } from '@app/infra/db/entities'; | ||||
| import { BadRequestException, Inject, Injectable, Logger } from '@nestjs/common'; | ||||
| import { ConfigService } from '@nestjs/config'; | ||||
| @@ -7,6 +6,7 @@ import { IAlbumRepository } from '../album/album.repository'; | ||||
| import { mapAsset } from '../asset'; | ||||
| import { IAssetRepository } from '../asset/asset.repository'; | ||||
| import { AuthUserDto } from '../auth'; | ||||
| import { MACHINE_LEARNING_ENABLED } from '../domain.constant'; | ||||
| import { IBulkEntityJob, IJobRepository, JobName } from '../job'; | ||||
| import { IMachineLearningRepository } from '../smart-info'; | ||||
| import { SearchDto } from './dto'; | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import { MACHINE_LEARNING_ENABLED } from '@app/common'; | ||||
| import { Inject, Injectable, Logger } from '@nestjs/common'; | ||||
| import { IAssetRepository, WithoutProperty } from '../asset'; | ||||
| import { MACHINE_LEARNING_ENABLED } from '../domain.constant'; | ||||
| import { IAssetJob, IBaseJob, IJobRepository, JobName } from '../job'; | ||||
| import { IMachineLearningRepository } from './machine-learning.interface'; | ||||
| import { ISmartInfoRepository } from './smart-info.repository'; | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| import { MACHINE_LEARNING_URL } from '@app/common'; | ||||
| import { IMachineLearningRepository, MachineLearningInput } from '@app/domain'; | ||||
| import { IMachineLearningRepository, MachineLearningInput, MACHINE_LEARNING_URL } from '@app/domain'; | ||||
| import { Injectable } from '@nestjs/common'; | ||||
| import axios from 'axios'; | ||||
|  | ||||
|   | ||||
| @@ -153,7 +153,6 @@ | ||||
|       "<rootDir>/libs/" | ||||
|     ], | ||||
|     "moduleNameMapper": { | ||||
|       "@app/common": "<rootDir>/libs/common/src", | ||||
|       "^@app/infra(|/.*)$": "<rootDir>/libs/infra/src/$1", | ||||
|       "^@app/domain(|/.*)$": "<rootDir>/libs/domain/src/$1" | ||||
|     }, | ||||
|   | ||||
| @@ -16,8 +16,6 @@ | ||||
|     "esModuleInterop": true, | ||||
|     "baseUrl": "./", | ||||
|     "paths": { | ||||
|       "@app/common": ["libs/common/src"], | ||||
|       "@app/common/*": ["libs/common/src/*"], | ||||
|       "@app/infra": ["libs/infra/src"], | ||||
|       "@app/infra/*": ["libs/infra/src/*"], | ||||
|       "@app/domain": ["libs/domain/src"], | ||||
|   | ||||
		Reference in New Issue
	
	Block a user