1
0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2025-01-23 20:22:45 +01:00

chore(server): use absolute import paths ()

update server to use absolute import paths
This commit is contained in:
Daniel Dietzler 2024-03-20 19:32:04 +01:00 committed by GitHub
parent 591a641d8d
commit 30f499cf2e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
347 changed files with 1962 additions and 2274 deletions
.vscode
server
.eslintrc.js
e2e
package.json
src/domain
access
activity
album
api-key
asset
audit
auth
database
domain.config.tsdomain.constant.spec.tsdomain.constant.tsdomain.module.tsdomain.util.ts
download
index.ts
job
library
media
metadata
partner
person
repositories

30
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,30 @@
{
"editor.formatOnSave": true,
"[javascript][typescript][css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.tabSize": 2,
"editor.formatOnSave": true
},
"[svelte]": {
"editor.defaultFormatter": "svelte.svelte-vscode",
"editor.tabSize": 2
},
"svelte.enable-ts-plugin": true,
"eslint.validate": [
"javascript",
"svelte"
],
"typescript.preferences.importModuleSpecifier": "non-relative",
"[dart]": {
"editor.formatOnSave": true,
"editor.selectionHighlight": false,
"editor.suggest.snippetsPreventQuickSuggestions": false,
"editor.suggestSelection": "first",
"editor.tabCompletion": "onlySnippets",
"editor.wordBasedSuggestions": "off",
"editor.defaultFormatter": "Dart-Code.dart-code"
},
"cSpell.words": [
"immich"
],
}

View file

@ -33,5 +33,6 @@ module.exports = {
'@typescript-eslint/require-await': 'error', '@typescript-eslint/require-await': 'error',
curly: 2, curly: 2,
'prettier/prettier': 0, 'prettier/prettier': 0,
'no-restricted-imports': ['error', { patterns: [{ group: ['.*'], message: 'Relative imports are not allowed.' }] }],
}, },
}; };

View file

@ -1,4 +1,4 @@
import { AssetResponseDto } from '@app/domain'; import { AssetResponseDto } from 'src/domain/asset/response-dto/asset-response.dto';
import request from 'supertest'; import request from 'supertest';
export const assetApi = { export const assetApi = {

View file

@ -1,6 +1,7 @@
import { LoginResponseDto, UserResponseDto } from '@app/domain'; import { LoginResponseDto } from 'src/domain/auth/auth.dto';
import { adminSignupStub, loginResponseStub, loginStub } from '@test'; import { UserResponseDto } from 'src/domain/user/response-dto/user-response.dto';
import request from 'supertest'; import request from 'supertest';
import { adminSignupStub, loginResponseStub, loginStub } from 'test/fixtures/auth.stub';
export const authApi = { export const authApi = {
adminSignUp: async (server: any) => { adminSignUp: async (server: any) => {

View file

@ -1,6 +1,6 @@
import { assetApi } from './asset-api'; import { assetApi } from 'e2e/client/asset-api';
import { authApi } from './auth-api'; import { authApi } from 'e2e/client/auth-api';
import { libraryApi } from './library-api'; import { libraryApi } from 'e2e/client/library-api';
export const api = { export const api = {
authApi, authApi,

View file

@ -1,4 +1,4 @@
import { CreateLibraryDto, LibraryResponseDto, ScanLibraryDto } from '@app/domain'; import { CreateLibraryDto, LibraryResponseDto, ScanLibraryDto } from 'src/domain/library/library.dto';
import request from 'supertest'; import request from 'supertest';
export const libraryApi = { export const libraryApi = {

View file

@ -16,9 +16,7 @@
], ],
"coverageDirectory": "./coverage", "coverageDirectory": "./coverage",
"moduleNameMapper": { "moduleNameMapper": {
"^@test(|/.*)$": "<rootDir>/test/$1", "^test(|/.*)$": "<rootDir>/test/$1",
"^@app/immich(|/.*)$": "<rootDir>/src/immich/$1", "^src(|/.*)$": "<rootDir>/src/$1"
"^@app/infra(|/.*)$": "<rootDir>/src/infra/$1",
"^@app/domain(|/.*)$": "<rootDir>/src/domain/$1"
} }
} }

View file

@ -1,15 +1,19 @@
import { LibraryResponseDto, LibraryService, LoginResponseDto, StorageEventType } from '@app/domain'; import { api } from 'e2e/client';
import { AssetType, LibraryType } from '@app/infra/entities';
import fs from 'node:fs/promises'; import fs from 'node:fs/promises';
import path from 'node:path'; import path from 'node:path';
import { LoginResponseDto } from 'src/domain/auth/auth.dto';
import { LibraryResponseDto } from 'src/domain/library/library.dto';
import { LibraryService } from 'src/domain/library/library.service';
import { StorageEventType } from 'src/domain/repositories/storage.repository';
import { AssetType } from 'src/infra/entities/asset.entity';
import { LibraryType } from 'src/infra/entities/library.entity';
import { import {
IMMICH_TEST_ASSET_PATH, IMMICH_TEST_ASSET_PATH,
IMMICH_TEST_ASSET_TEMP_PATH, IMMICH_TEST_ASSET_TEMP_PATH,
restoreTempFolder, restoreTempFolder,
testApp, testApp,
waitForEvent, waitForEvent,
} from '../../../src/test-utils/utils'; } from 'src/test-utils/utils';
import { api } from '../../client';
describe(`Library watcher (e2e)`, () => { describe(`Library watcher (e2e)`, () => {
let server: any; let server: any;

View file

@ -1,17 +1,13 @@
import { LoginResponseDto } from '@app/domain'; import { api } from 'e2e/client';
import { LibraryController } from '@app/immich'; import fs from 'node:fs';
import { LibraryType } from '@app/infra/entities'; import { LoginResponseDto } from 'src/domain/auth/auth.dto';
import { errorStub, uuidStub } from '@test/fixtures'; import { LibraryController } from 'src/immich/controllers/library.controller';
import * as fs from 'node:fs'; import { LibraryType } from 'src/infra/entities/library.entity';
import { IMMICH_TEST_ASSET_PATH, IMMICH_TEST_ASSET_TEMP_PATH, restoreTempFolder, testApp } from 'src/test-utils/utils';
import request from 'supertest'; import request from 'supertest';
import { errorStub } from 'test/fixtures/error.stub';
import { uuidStub } from 'test/fixtures/uuid.stub';
import { utimes } from 'utimes'; import { utimes } from 'utimes';
import {
IMMICH_TEST_ASSET_PATH,
IMMICH_TEST_ASSET_TEMP_PATH,
restoreTempFolder,
testApp,
} from '../../../src/test-utils/utils';
import { api } from '../../client';
describe(`${LibraryController.name} (e2e)`, () => { describe(`${LibraryController.name} (e2e)`, () => {
let server: any; let server: any;

View file

@ -155,16 +155,14 @@
"./src/domain/": { "./src/domain/": {
"branches": 75, "branches": 75,
"functions": 80, "functions": 80,
"lines": 90, "lines": 85,
"statements": 90 "statements": 85
} }
}, },
"testEnvironment": "node", "testEnvironment": "node",
"moduleNameMapper": { "moduleNameMapper": {
"^@test(|/.*)$": "<rootDir>/test/$1", "^test(|/.*)$": "<rootDir>/test/$1",
"^@app/immich(|/.*)$": "<rootDir>/src/immich/$1", "^src(|/.*)$": "<rootDir>/src/$1"
"^@app/infra(|/.*)$": "<rootDir>/src/infra/$1",
"^@app/domain(|/.*)$": "<rootDir>/src/domain/$1"
}, },
"globalSetup": "<rootDir>/test/global-setup.js" "globalSetup": "<rootDir>/test/global-setup.js"
}, },

View file

@ -1,8 +1,8 @@
import { BadRequestException, UnauthorizedException } from '@nestjs/common'; import { BadRequestException, UnauthorizedException } from '@nestjs/common';
import { SharedLinkEntity } from '../../infra/entities'; import { AuthDto } from 'src/domain/auth/auth.dto';
import { AuthDto } from '../auth'; import { setDifference, setIsEqual, setUnion } from 'src/domain/domain.util';
import { setDifference, setIsEqual, setUnion } from '../domain.util'; import { IAccessRepository } from 'src/domain/repositories/access.repository';
import { IAccessRepository } from '../repositories'; import { SharedLinkEntity } from 'src/infra/entities/shared-link.entity';
export enum Permission { export enum Permission {
ACTIVITY_CREATE = 'activity.create', ACTIVITY_CREATE = 'activity.create',

View file

@ -1 +0,0 @@
export * from './access.core';

View file

@ -1,8 +1,8 @@
import { ActivityEntity } from '@app/infra/entities';
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { IsEnum, IsNotEmpty, IsString, ValidateIf } from 'class-validator'; import { IsEnum, IsNotEmpty, IsString, ValidateIf } from 'class-validator';
import { Optional, ValidateUUID } from '../domain.util'; import { Optional, ValidateUUID } from 'src/domain/domain.util';
import { UserDto, mapSimpleUser } from '../user/response-dto'; import { UserDto, mapSimpleUser } from 'src/domain/user/response-dto/user-response.dto';
import { ActivityEntity } from 'src/infra/entities/activity.entity';
export enum ReactionType { export enum ReactionType {
COMMENT = 'comment', COMMENT = 'comment',

View file

@ -1,8 +1,5 @@
import { ActivityEntity } from '@app/infra/entities';
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { AccessCore, Permission } from '../access'; import { AccessCore, Permission } from 'src/domain/access/access.core';
import { AuthDto } from '../auth';
import { IAccessRepository, IActivityRepository } from '../repositories';
import { import {
ActivityCreateDto, ActivityCreateDto,
ActivityDto, ActivityDto,
@ -13,7 +10,11 @@ import {
ReactionLevel, ReactionLevel,
ReactionType, ReactionType,
mapActivity, mapActivity,
} from './activity.dto'; } from 'src/domain/activity/activity.dto';
import { AuthDto } from 'src/domain/auth/auth.dto';
import { IAccessRepository } from 'src/domain/repositories/access.repository';
import { IActivityRepository } from 'src/domain/repositories/activity.repository';
import { ActivityEntity } from 'src/infra/entities/activity.entity';
@Injectable() @Injectable()
export class ActivityService { export class ActivityService {

View file

@ -1,10 +1,11 @@
import { BadRequestException } from '@nestjs/common'; import { BadRequestException } from '@nestjs/common';
import { authStub, IAccessRepositoryMock, newAccessRepositoryMock } from '@test'; import { ReactionType } from 'src/domain/activity/activity.dto';
import { activityStub } from '@test/fixtures/activity.stub'; import { ActivityService } from 'src/domain/activity/activity.service';
import { newActivityRepositoryMock } from '@test/repositories/activity.repository.mock'; import { IActivityRepository } from 'src/domain/repositories/activity.repository';
import { IActivityRepository } from '../repositories'; import { activityStub } from 'test/fixtures/activity.stub';
import { ReactionType } from './activity.dto'; import { authStub } from 'test/fixtures/auth.stub';
import { ActivityService } from './activity.service'; import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositories/access.repository.mock';
import { newActivityRepositoryMock } from 'test/repositories/activity.repository.mock';
describe(ActivityService.name, () => { describe(ActivityService.name, () => {
let sut: ActivityService; let sut: ActivityService;

View file

@ -1,2 +0,0 @@
export * from './activity.dto';
export * from './activity.service';

View file

@ -1,5 +1,5 @@
import { albumStub } from '@test'; import { mapAlbum } from 'src/domain/album/album-response.dto';
import { mapAlbum } from './album-response.dto'; import { albumStub } from 'test/fixtures/album.stub';
describe('mapAlbum', () => { describe('mapAlbum', () => {
it('should set start and end dates', () => { it('should set start and end dates', () => {

View file

@ -1,9 +1,9 @@
import { AlbumEntity, AssetOrder } from '@app/infra/entities';
import { Optional } from '@nestjs/common';
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { AssetResponseDto, mapAsset } from '../asset'; import { AssetResponseDto, mapAsset } from 'src/domain/asset/response-dto/asset-response.dto';
import { AuthDto } from '../auth/auth.dto'; import { AuthDto } from 'src/domain/auth/auth.dto';
import { UserResponseDto, mapUser } from '../user'; import { Optional } from 'src/domain/domain.util';
import { UserResponseDto, mapUser } from 'src/domain/user/response-dto/user-response.dto';
import { AlbumEntity, AssetOrder } from 'src/infra/entities/album.entity';
export class AlbumResponseDto { export class AlbumResponseDto {
id!: string; id!: string;

View file

@ -1,36 +1,32 @@
import { BadRequestException } from '@nestjs/common'; import { BadRequestException } from '@nestjs/common';
import {
albumStub,
authStub,
IAccessRepositoryMock,
newAccessRepositoryMock,
newAlbumRepositoryMock,
newAssetRepositoryMock,
newJobRepositoryMock,
newUserRepositoryMock,
userStub,
} from '@test';
import _ from 'lodash'; import _ from 'lodash';
import { BulkIdErrorReason } from '../asset'; import { AlbumService } from 'src/domain/album/album.service';
import { IAlbumRepository, IAssetRepository, IJobRepository, IUserRepository } from '../repositories'; import { BulkIdErrorReason } from 'src/domain/asset/response-dto/asset-ids-response.dto';
import { AlbumService } from './album.service'; import { IAlbumRepository } from 'src/domain/repositories/album.repository';
import { IAssetRepository } from 'src/domain/repositories/asset.repository';
import { IUserRepository } from 'src/domain/repositories/user.repository';
import { albumStub } from 'test/fixtures/album.stub';
import { authStub } from 'test/fixtures/auth.stub';
import { userStub } from 'test/fixtures/user.stub';
import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositories/access.repository.mock';
import { newAlbumRepositoryMock } from 'test/repositories/album.repository.mock';
import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock';
import { newUserRepositoryMock } from 'test/repositories/user.repository.mock';
describe(AlbumService.name, () => { describe(AlbumService.name, () => {
let sut: AlbumService; let sut: AlbumService;
let accessMock: IAccessRepositoryMock; let accessMock: IAccessRepositoryMock;
let albumMock: jest.Mocked<IAlbumRepository>; let albumMock: jest.Mocked<IAlbumRepository>;
let assetMock: jest.Mocked<IAssetRepository>; let assetMock: jest.Mocked<IAssetRepository>;
let jobMock: jest.Mocked<IJobRepository>;
let userMock: jest.Mocked<IUserRepository>; let userMock: jest.Mocked<IUserRepository>;
beforeEach(() => { beforeEach(() => {
accessMock = newAccessRepositoryMock(); accessMock = newAccessRepositoryMock();
albumMock = newAlbumRepositoryMock(); albumMock = newAlbumRepositoryMock();
assetMock = newAssetRepositoryMock(); assetMock = newAssetRepositoryMock();
jobMock = newJobRepositoryMock();
userMock = newUserRepositoryMock(); userMock = newUserRepositoryMock();
sut = new AlbumService(accessMock, albumMock, assetMock, jobMock, userMock); sut = new AlbumService(accessMock, albumMock, assetMock, userMock);
}); });
it('should work', () => { it('should work', () => {

View file

@ -1,26 +1,27 @@
import { AlbumEntity, AssetEntity, UserEntity } from '@app/infra/entities';
import { BadRequestException, Inject, Injectable } from '@nestjs/common'; import { BadRequestException, Inject, Injectable } from '@nestjs/common';
import { AccessCore, Permission } from '../access'; import { AccessCore, Permission } from 'src/domain/access/access.core';
import { BulkIdErrorReason, BulkIdResponseDto, BulkIdsDto } from '../asset';
import { AuthDto } from '../auth';
import { setUnion } from '../domain.util';
import {
AlbumAssetCount,
AlbumInfoOptions,
IAccessRepository,
IAlbumRepository,
IAssetRepository,
IJobRepository,
IUserRepository,
} from '../repositories';
import { import {
AlbumCountResponseDto, AlbumCountResponseDto,
AlbumResponseDto, AlbumResponseDto,
mapAlbum, mapAlbum,
mapAlbumWithAssets, mapAlbumWithAssets,
mapAlbumWithoutAssets, mapAlbumWithoutAssets,
} from './album-response.dto'; } from 'src/domain/album/album-response.dto';
import { AddUsersDto, AlbumInfoDto, CreateAlbumDto, GetAlbumsDto, UpdateAlbumDto } from './dto'; import { AddUsersDto } from 'src/domain/album/dto/album-add-users.dto';
import { CreateAlbumDto } from 'src/domain/album/dto/album-create.dto';
import { UpdateAlbumDto } from 'src/domain/album/dto/album-update.dto';
import { AlbumInfoDto } from 'src/domain/album/dto/album.dto';
import { GetAlbumsDto } from 'src/domain/album/dto/get-albums.dto';
import { BulkIdErrorReason, BulkIdResponseDto, BulkIdsDto } from 'src/domain/asset/response-dto/asset-ids-response.dto';
import { AuthDto } from 'src/domain/auth/auth.dto';
import { setUnion } from 'src/domain/domain.util';
import { IAccessRepository } from 'src/domain/repositories/access.repository';
import { AlbumAssetCount, AlbumInfoOptions, IAlbumRepository } from 'src/domain/repositories/album.repository';
import { IAssetRepository } from 'src/domain/repositories/asset.repository';
import { IUserRepository } from 'src/domain/repositories/user.repository';
import { AlbumEntity } from 'src/infra/entities/album.entity';
import { AssetEntity } from 'src/infra/entities/asset.entity';
import { UserEntity } from 'src/infra/entities/user.entity';
@Injectable() @Injectable()
export class AlbumService { export class AlbumService {
@ -29,7 +30,6 @@ export class AlbumService {
@Inject(IAccessRepository) accessRepository: IAccessRepository, @Inject(IAccessRepository) accessRepository: IAccessRepository,
@Inject(IAlbumRepository) private albumRepository: IAlbumRepository, @Inject(IAlbumRepository) private albumRepository: IAlbumRepository,
@Inject(IAssetRepository) private assetRepository: IAssetRepository, @Inject(IAssetRepository) private assetRepository: IAssetRepository,
@Inject(IJobRepository) private jobRepository: IJobRepository,
@Inject(IUserRepository) private userRepository: IUserRepository, @Inject(IUserRepository) private userRepository: IUserRepository,
) { ) {
this.access = AccessCore.create(accessRepository); this.access = AccessCore.create(accessRepository);

View file

@ -1,5 +1,5 @@
import { ArrayNotEmpty } from 'class-validator'; import { ArrayNotEmpty } from 'class-validator';
import { ValidateUUID } from '../../domain.util'; import { ValidateUUID } from 'src/domain/domain.util';
export class AddUsersDto { export class AddUsersDto {
@ValidateUUID({ each: true }) @ValidateUUID({ each: true })

View file

@ -1,6 +1,6 @@
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { IsString } from 'class-validator'; import { IsString } from 'class-validator';
import { Optional, ValidateUUID } from '../../domain.util'; import { Optional, ValidateUUID } from 'src/domain/domain.util';
export class CreateAlbumDto { export class CreateAlbumDto {
@IsString() @IsString()

View file

@ -1,7 +1,7 @@
import { AssetOrder } from '@app/infra/entities';
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { IsEnum, IsString } from 'class-validator'; import { IsEnum, IsString } from 'class-validator';
import { Optional, ValidateBoolean, ValidateUUID } from '../../domain.util'; import { Optional, ValidateBoolean, ValidateUUID } from 'src/domain/domain.util';
import { AssetOrder } from 'src/infra/entities/album.entity';
export class UpdateAlbumDto { export class UpdateAlbumDto {
@Optional() @Optional()

View file

@ -1,4 +1,4 @@
import { ValidateBoolean } from '../../domain.util'; import { ValidateBoolean } from 'src/domain/domain.util';
export class AlbumInfoDto { export class AlbumInfoDto {
@ValidateBoolean({ optional: true }) @ValidateBoolean({ optional: true })

View file

@ -1,4 +1,4 @@
import { ValidateBoolean, ValidateUUID } from '../../domain.util'; import { ValidateBoolean, ValidateUUID } from 'src/domain/domain.util';
export class GetAlbumsDto { export class GetAlbumsDto {
@ValidateBoolean({ optional: true }) @ValidateBoolean({ optional: true })

View file

@ -1,5 +0,0 @@
export * from './album-add-users.dto';
export * from './album-create.dto';
export * from './album-update.dto';
export * from './album.dto';
export * from './get-albums.dto';

View file

@ -1,3 +0,0 @@
export * from './album-response.dto';
export * from './album.service';
export * from './dto';

View file

@ -1,5 +1,5 @@
import { IsNotEmpty, IsString } from 'class-validator'; import { IsNotEmpty, IsString } from 'class-validator';
import { Optional } from '../domain.util'; import { Optional } from 'src/domain/domain.util';
export class APIKeyCreateDto { export class APIKeyCreateDto {
@IsString() @IsString()
@IsNotEmpty() @IsNotEmpty()

View file

@ -1,7 +1,11 @@
import { BadRequestException } from '@nestjs/common'; import { BadRequestException } from '@nestjs/common';
import { authStub, keyStub, newCryptoRepositoryMock, newKeyRepositoryMock } from '@test'; import { APIKeyService } from 'src/domain/api-key/api-key.service';
import { ICryptoRepository, IKeyRepository } from '../repositories'; import { IKeyRepository } from 'src/domain/repositories/api-key.repository';
import { APIKeyService } from './api-key.service'; import { ICryptoRepository } from 'src/domain/repositories/crypto.repository';
import { keyStub } from 'test/fixtures/api-key.stub';
import { authStub } from 'test/fixtures/auth.stub';
import { newKeyRepositoryMock } from 'test/repositories/api-key.repository.mock';
import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.mock';
describe(APIKeyService.name, () => { describe(APIKeyService.name, () => {
let sut: APIKeyService; let sut: APIKeyService;

View file

@ -1,8 +1,9 @@
import { APIKeyEntity } from '@app/infra/entities';
import { BadRequestException, Inject, Injectable } from '@nestjs/common'; import { BadRequestException, Inject, Injectable } from '@nestjs/common';
import { AuthDto } from '../auth'; import { APIKeyCreateDto, APIKeyCreateResponseDto, APIKeyResponseDto } from 'src/domain/api-key/api-key.dto';
import { ICryptoRepository, IKeyRepository } from '../repositories'; import { AuthDto } from 'src/domain/auth/auth.dto';
import { APIKeyCreateDto, APIKeyCreateResponseDto, APIKeyResponseDto } from './api-key.dto'; import { IKeyRepository } from 'src/domain/repositories/api-key.repository';
import { ICryptoRepository } from 'src/domain/repositories/crypto.repository';
import { APIKeyEntity } from 'src/infra/entities/api-key.entity';
@Injectable() @Injectable()
export class APIKeyService { export class APIKeyService {

View file

@ -1,2 +0,0 @@
export * from './api-key.dto';
export * from './api-key.service';

View file

@ -1,42 +1,33 @@
import { AssetEntity, AssetType } from '@app/infra/entities';
import { BadRequestException, UnauthorizedException } from '@nestjs/common'; import { BadRequestException, UnauthorizedException } from '@nestjs/common';
import {
IAccessRepositoryMock,
assetStackStub,
assetStub,
authStub,
faceStub,
newAccessRepositoryMock,
newAssetRepositoryMock,
newAssetStackRepositoryMock,
newCommunicationRepositoryMock,
newJobRepositoryMock,
newPartnerRepositoryMock,
newStorageRepositoryMock,
newSystemConfigRepositoryMock,
newUserRepositoryMock,
partnerStub,
userStub,
} from '@test';
import { when } from 'jest-when'; import { when } from 'jest-when';
import { JobName } from '../job'; import { AssetService, UploadFieldName } from 'src/domain/asset/asset.service';
import { import { AssetJobName } from 'src/domain/asset/dto/asset-ids.dto';
AssetStats, import { AssetStatsResponseDto } from 'src/domain/asset/dto/asset-statistics.dto';
ClientEvent, import { mapAsset } from 'src/domain/asset/response-dto/asset-response.dto';
IAssetRepository, import { JobName } from 'src/domain/job/job.constants';
IAssetStackRepository, import { IAssetStackRepository } from 'src/domain/repositories/asset-stack.repository';
ICommunicationRepository, import { AssetStats, IAssetRepository, TimeBucketSize } from 'src/domain/repositories/asset.repository';
IJobRepository, import { ClientEvent, ICommunicationRepository } from 'src/domain/repositories/communication.repository';
IPartnerRepository, import { IJobRepository, JobItem } from 'src/domain/repositories/job.repository';
IStorageRepository, import { IPartnerRepository } from 'src/domain/repositories/partner.repository';
ISystemConfigRepository, import { IStorageRepository } from 'src/domain/repositories/storage.repository';
IUserRepository, import { ISystemConfigRepository } from 'src/domain/repositories/system-config.repository';
JobItem, import { IUserRepository } from 'src/domain/repositories/user.repository';
TimeBucketSize, import { AssetEntity, AssetType } from 'src/infra/entities/asset.entity';
} from '../repositories'; import { assetStackStub, assetStub } from 'test/fixtures/asset.stub';
import { AssetService, UploadFieldName } from './asset.service'; import { authStub } from 'test/fixtures/auth.stub';
import { AssetJobName, AssetStatsResponseDto } from './dto'; import { faceStub } from 'test/fixtures/face.stub';
import { mapAsset } from './response-dto'; import { partnerStub } from 'test/fixtures/partner.stub';
import { userStub } from 'test/fixtures/user.stub';
import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositories/access.repository.mock';
import { newAssetStackRepositoryMock } from 'test/repositories/asset-stack.repository.mock';
import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock';
import { newCommunicationRepositoryMock } from 'test/repositories/communication.repository.mock';
import { newJobRepositoryMock } from 'test/repositories/job.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';
import { newUserRepositoryMock } from 'test/repositories/user.repository.mock';
const stats: AssetStats = { const stats: AssetStats = {
[AssetType.IMAGE]: 10, [AssetType.IMAGE]: 10,

View file

@ -1,54 +1,43 @@
import { AssetEntity, LibraryType } from '@app/infra/entities';
import { ImmichLogger } from '@app/infra/logger';
import { BadRequestException, Inject } from '@nestjs/common'; import { BadRequestException, Inject } from '@nestjs/common';
import _ from 'lodash'; import _ from 'lodash';
import { DateTime, Duration } from 'luxon'; import { DateTime, Duration } from 'luxon';
import { extname } from 'node:path'; import { extname } from 'node:path';
import sanitize from 'sanitize-filename'; import sanitize from 'sanitize-filename';
import { AccessCore, Permission } from '../access'; import { AccessCore, Permission } from 'src/domain/access/access.core';
import { AuthDto } from '../auth'; import { AssetJobName, AssetJobsDto } from 'src/domain/asset/dto/asset-ids.dto';
import { mimeTypes } from '../domain.constant'; import { UpdateStackParentDto } from 'src/domain/asset/dto/asset-stack.dto';
import { usePagination } from '../domain.util'; import { AssetStatsDto, mapStats } from 'src/domain/asset/dto/asset-statistics.dto';
import { IAssetDeletionJob, ISidecarWriteJob, JOBS_ASSET_PAGINATION_SIZE, JobName } from '../job'; import { AssetBulkDeleteDto, AssetBulkUpdateDto, UpdateAssetDto } from 'src/domain/asset/dto/asset.dto';
import { import { MapMarkerDto } from 'src/domain/asset/dto/map-marker.dto';
ClientEvent, import { MemoryLaneDto } from 'src/domain/asset/dto/memory-lane.dto';
IAccessRepository, import { TimeBucketAssetDto, TimeBucketDto } from 'src/domain/asset/dto/time-bucket.dto';
IAssetRepository,
IAssetStackRepository,
ICommunicationRepository,
IJobRepository,
IPartnerRepository,
IStorageRepository,
ISystemConfigRepository,
IUserRepository,
JobItem,
JobStatus,
TimeBucketOptions,
} from '../repositories';
import { StorageCore, StorageFolder } from '../storage';
import { SystemConfigCore } from '../system-config';
import {
AssetBulkDeleteDto,
AssetBulkUpdateDto,
AssetJobName,
AssetJobsDto,
AssetStatsDto,
MapMarkerDto,
MemoryLaneDto,
TimeBucketAssetDto,
TimeBucketDto,
UpdateAssetDto,
UpdateStackParentDto,
mapStats,
} from './dto';
import { import {
AssetResponseDto, AssetResponseDto,
MapMarkerResponseDto,
MemoryLaneResponseDto, MemoryLaneResponseDto,
SanitizedAssetResponseDto, SanitizedAssetResponseDto,
TimeBucketResponseDto,
mapAsset, mapAsset,
} from './response-dto'; } from 'src/domain/asset/response-dto/asset-response.dto';
import { MapMarkerResponseDto } from 'src/domain/asset/response-dto/map-marker-response.dto';
import { TimeBucketResponseDto } from 'src/domain/asset/response-dto/time-bucket-response.dto';
import { AuthDto } from 'src/domain/auth/auth.dto';
import { mimeTypes } from 'src/domain/domain.constant';
import { usePagination } from 'src/domain/domain.util';
import { JOBS_ASSET_PAGINATION_SIZE, JobName } from 'src/domain/job/job.constants';
import { IAssetDeletionJob, ISidecarWriteJob } from 'src/domain/job/job.interface';
import { IAccessRepository } from 'src/domain/repositories/access.repository';
import { IAssetStackRepository } from 'src/domain/repositories/asset-stack.repository';
import { IAssetRepository, TimeBucketOptions } from 'src/domain/repositories/asset.repository';
import { ClientEvent, ICommunicationRepository } from 'src/domain/repositories/communication.repository';
import { IJobRepository, JobItem, JobStatus } from 'src/domain/repositories/job.repository';
import { IPartnerRepository } from 'src/domain/repositories/partner.repository';
import { IStorageRepository } from 'src/domain/repositories/storage.repository';
import { ISystemConfigRepository } from 'src/domain/repositories/system-config.repository';
import { IUserRepository } from 'src/domain/repositories/user.repository';
import { StorageCore, StorageFolder } from 'src/domain/storage/storage.core';
import { SystemConfigCore } from 'src/domain/system-config/system-config.core';
import { AssetEntity } from 'src/infra/entities/asset.entity';
import { LibraryType } from 'src/infra/entities/library.entity';
import { ImmichLogger } from 'src/infra/logger';
export enum UploadFieldName { export enum UploadFieldName {
ASSET_DATA = 'assetData', ASSET_DATA = 'assetData',

View file

@ -1,6 +1,6 @@
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { IsEnum } from 'class-validator'; import { IsEnum } from 'class-validator';
import { ValidateUUID } from '../../domain.util'; import { ValidateUUID } from 'src/domain/domain.util';
export class AssetIdsDto { export class AssetIdsDto {
@ValidateUUID({ each: true }) @ValidateUUID({ each: true })

View file

@ -1,4 +1,4 @@
import { ValidateUUID } from '../../domain.util'; import { ValidateUUID } from 'src/domain/domain.util';
export class UpdateStackParentDto { export class UpdateStackParentDto {
@ValidateUUID() @ValidateUUID()

View file

@ -1,7 +1,7 @@
import { AssetType } from '@app/infra/entities';
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { ValidateBoolean } from '../../domain.util'; import { ValidateBoolean } from 'src/domain/domain.util';
import { AssetStats } from '../../repositories'; import { AssetStats } from 'src/domain/repositories/asset.repository';
import { AssetType } from 'src/infra/entities/asset.entity';
export class AssetStatsDto { export class AssetStatsDto {
@ValidateBoolean({ optional: true }) @ValidateBoolean({ optional: true })

View file

@ -9,8 +9,8 @@ import {
IsString, IsString,
ValidateIf, ValidateIf,
} from 'class-validator'; } from 'class-validator';
import { Optional, ValidateBoolean, ValidateUUID } from '../../domain.util'; import { BulkIdsDto } from 'src/domain/asset/response-dto/asset-ids-response.dto';
import { BulkIdsDto } from '../response-dto'; import { Optional, ValidateBoolean, ValidateUUID } from 'src/domain/domain.util';
export class DeviceIdDto { export class DeviceIdDto {
@IsNotEmpty() @IsNotEmpty()

View file

@ -1,7 +0,0 @@
export * from './asset-ids.dto';
export * from './asset-stack.dto';
export * from './asset-statistics.dto';
export * from './asset.dto';
export * from './map-marker.dto';
export * from './memory-lane.dto';
export * from './time-bucket.dto';

View file

@ -1,4 +1,4 @@
import { ValidateBoolean, ValidateDate } from '../../domain.util'; import { ValidateBoolean, ValidateDate } from 'src/domain/domain.util';
export class MapMarkerDto { export class MapMarkerDto {
@ValidateBoolean({ optional: true }) @ValidateBoolean({ optional: true })

View file

@ -1,8 +1,8 @@
import { AssetOrder } from '@app/infra/entities';
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { IsEnum, IsNotEmpty, IsString } from 'class-validator'; import { IsEnum, IsNotEmpty, IsString } from 'class-validator';
import { Optional, ValidateBoolean, ValidateUUID } from '../../domain.util'; import { Optional, ValidateBoolean, ValidateUUID } from 'src/domain/domain.util';
import { TimeBucketSize } from '../../repositories'; import { TimeBucketSize } from 'src/domain/repositories/asset.repository';
import { AssetOrder } from 'src/infra/entities/album.entity';
export class TimeBucketDto { export class TimeBucketDto {
@IsNotEmpty() @IsNotEmpty()

View file

@ -1,3 +0,0 @@
export * from './asset.service';
export * from './dto';
export * from './response-dto';

View file

@ -1,4 +1,4 @@
import { ValidateUUID } from '../../domain.util'; import { ValidateUUID } from 'src/domain/domain.util';
/** @deprecated Use `BulkIdResponseDto` instead */ /** @deprecated Use `BulkIdResponseDto` instead */
export enum AssetIdErrorReason { export enum AssetIdErrorReason {

View file

@ -1,11 +1,12 @@
import { AuthDto } from '@app/domain/auth/auth.dto';
import { AssetEntity, AssetFaceEntity, AssetType } from '@app/infra/entities';
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { PersonWithFacesResponseDto, mapFacesWithoutPerson, mapPerson } from '../../person/person.dto'; import { ExifResponseDto, mapExif } from 'src/domain/asset/response-dto/exif-response.dto';
import { TagResponseDto, mapTag } from '../../tag'; import { SmartInfoResponseDto, mapSmartInfo } from 'src/domain/asset/response-dto/smart-info-response.dto';
import { UserResponseDto, mapUser } from '../../user/response-dto/user-response.dto'; import { AuthDto } from 'src/domain/auth/auth.dto';
import { ExifResponseDto, mapExif } from './exif-response.dto'; import { PersonWithFacesResponseDto, mapFacesWithoutPerson, mapPerson } from 'src/domain/person/person.dto';
import { SmartInfoResponseDto, mapSmartInfo } from './smart-info-response.dto'; import { TagResponseDto, mapTag } from 'src/domain/tag/tag-response.dto';
import { UserResponseDto, mapUser } from 'src/domain/user/response-dto/user-response.dto';
import { AssetFaceEntity } from 'src/infra/entities/asset-face.entity';
import { AssetEntity, AssetType } from 'src/infra/entities/asset.entity';
export class SanitizedAssetResponseDto { export class SanitizedAssetResponseDto {
id!: string; id!: string;

View file

@ -1,5 +1,5 @@
import { ExifEntity } from '@app/infra/entities';
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { ExifEntity } from 'src/infra/entities/exif.entity';
export class ExifResponseDto { export class ExifResponseDto {
make?: string | null = null; make?: string | null = null;

View file

@ -1,6 +0,0 @@
export * from './asset-ids-response.dto';
export * from './asset-response.dto';
export * from './exif-response.dto';
export * from './map-marker-response.dto';
export * from './smart-info-response.dto';
export * from './time-bucket-response.dto';

View file

@ -1,4 +1,4 @@
import { SmartInfoEntity } from '@app/infra/entities'; import { SmartInfoEntity } from 'src/infra/entities/smart-info.entity';
export class SmartInfoResponseDto { export class SmartInfoResponseDto {
tags?: string[] | null; tags?: string[] | null;

View file

@ -1,8 +1,9 @@
import { AssetPathType, EntityType, PathType, PersonPathType, UserPathType } from '@app/infra/entities';
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { Type } from 'class-transformer'; import { Type } from 'class-transformer';
import { IsArray, IsEnum, IsString, IsUUID, ValidateNested } from 'class-validator'; import { IsArray, IsEnum, IsString, IsUUID, ValidateNested } from 'class-validator';
import { Optional, ValidateDate, ValidateUUID } from '../domain.util'; import { Optional, ValidateDate, ValidateUUID } from 'src/domain/domain.util';
import { EntityType } from 'src/infra/entities/audit.entity';
import { AssetPathType, PathType, PersonPathType, UserPathType } from 'src/infra/entities/move.entity';
const PathEnum = Object.values({ ...AssetPathType, ...PersonPathType, ...UserPathType }); const PathEnum = Object.values({ ...AssetPathType, ...PersonPathType, ...UserPathType });

View file

@ -1,26 +1,21 @@
import { DatabaseAction, EntityType } from '@app/infra/entities'; import { AuditService } from 'src/domain/audit/audit.service';
import { import { IAssetRepository } from 'src/domain/repositories/asset.repository';
IAccessRepositoryMock, import { IAuditRepository } from 'src/domain/repositories/audit.repository';
auditStub, import { ICryptoRepository } from 'src/domain/repositories/crypto.repository';
authStub, import { JobStatus } from 'src/domain/repositories/job.repository';
newAccessRepositoryMock, import { IPersonRepository } from 'src/domain/repositories/person.repository';
newAssetRepositoryMock, import { IStorageRepository } from 'src/domain/repositories/storage.repository';
newAuditRepositoryMock, import { IUserRepository } from 'src/domain/repositories/user.repository';
newCryptoRepositoryMock, import { DatabaseAction, EntityType } from 'src/infra/entities/audit.entity';
newPersonRepositoryMock, import { auditStub } from 'test/fixtures/audit.stub';
newStorageRepositoryMock, import { authStub } from 'test/fixtures/auth.stub';
newUserRepositoryMock, import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositories/access.repository.mock';
} from '@test'; import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock';
import { import { newAuditRepositoryMock } from 'test/repositories/audit.repository.mock';
IAssetRepository, import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.mock';
IAuditRepository, import { newPersonRepositoryMock } from 'test/repositories/person.repository.mock';
ICryptoRepository, import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
IPersonRepository, import { newUserRepositoryMock } from 'test/repositories/user.repository.mock';
IStorageRepository,
IUserRepository,
JobStatus,
} from '../repositories';
import { AuditService } from './audit.service';
describe(AuditService.name, () => { describe(AuditService.name, () => {
let sut: AuditService; let sut: AuditService;

View file

@ -1,24 +1,7 @@
import { AssetPathType, DatabaseAction, PersonPathType, UserPathType } from '@app/infra/entities';
import { ImmichLogger } from '@app/infra/logger';
import { BadRequestException, Inject, Injectable } from '@nestjs/common'; import { BadRequestException, Inject, Injectable } from '@nestjs/common';
import { DateTime } from 'luxon'; import { DateTime } from 'luxon';
import { resolve } from 'node:path'; import { resolve } from 'node:path';
import { AccessCore, Permission } from '../access'; import { AccessCore, Permission } from 'src/domain/access/access.core';
import { AuthDto } from '../auth';
import { AUDIT_LOG_MAX_DURATION } from '../domain.constant';
import { usePagination } from '../domain.util';
import { JOBS_ASSET_PAGINATION_SIZE } from '../job';
import {
IAccessRepository,
IAssetRepository,
IAuditRepository,
ICryptoRepository,
IPersonRepository,
IStorageRepository,
IUserRepository,
JobStatus,
} from '../repositories';
import { StorageCore, StorageFolder } from '../storage';
import { import {
AuditDeletesDto, AuditDeletesDto,
AuditDeletesResponseDto, AuditDeletesResponseDto,
@ -26,7 +9,23 @@ import {
FileChecksumResponseDto, FileChecksumResponseDto,
FileReportItemDto, FileReportItemDto,
PathEntityType, PathEntityType,
} from './audit.dto'; } from 'src/domain/audit/audit.dto';
import { AuthDto } from 'src/domain/auth/auth.dto';
import { AUDIT_LOG_MAX_DURATION } from 'src/domain/domain.constant';
import { usePagination } from 'src/domain/domain.util';
import { JOBS_ASSET_PAGINATION_SIZE } from 'src/domain/job/job.constants';
import { IAccessRepository } from 'src/domain/repositories/access.repository';
import { IAssetRepository } from 'src/domain/repositories/asset.repository';
import { IAuditRepository } from 'src/domain/repositories/audit.repository';
import { ICryptoRepository } from 'src/domain/repositories/crypto.repository';
import { JobStatus } from 'src/domain/repositories/job.repository';
import { IPersonRepository } from 'src/domain/repositories/person.repository';
import { IStorageRepository } from 'src/domain/repositories/storage.repository';
import { IUserRepository } from 'src/domain/repositories/user.repository';
import { StorageCore, StorageFolder } from 'src/domain/storage/storage.core';
import { DatabaseAction } from 'src/infra/entities/audit.entity';
import { AssetPathType, PersonPathType, UserPathType } from 'src/infra/entities/move.entity';
import { ImmichLogger } from 'src/infra/logger';
@Injectable() @Injectable()
export class AuditService { export class AuditService {

View file

@ -1,2 +0,0 @@
export * from './audit.dto';
export * from './audit.service';

View file

@ -1,7 +1,10 @@
import { APIKeyEntity, SharedLinkEntity, UserEntity, UserTokenEntity } from '@app/infra/entities';
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { Transform } from 'class-transformer'; import { Transform } from 'class-transformer';
import { IsEmail, IsNotEmpty, IsString, MinLength } from 'class-validator'; import { IsEmail, IsNotEmpty, IsString, MinLength } from 'class-validator';
import { APIKeyEntity } from 'src/infra/entities/api-key.entity';
import { SharedLinkEntity } from 'src/infra/entities/shared-link.entity';
import { UserTokenEntity } from 'src/infra/entities/user-token.entity';
import { UserEntity } from 'src/infra/entities/user.entity';
export class AuthDto { export class AuthDto {
user!: UserEntity; user!: UserEntity;

View file

@ -1,38 +1,32 @@
import { UserEntity } from '@app/infra/entities';
import { BadRequestException, UnauthorizedException } from '@nestjs/common'; import { BadRequestException, UnauthorizedException } from '@nestjs/common';
import {
IAccessRepositoryMock,
authStub,
keyStub,
loginResponseStub,
newAccessRepositoryMock,
newCryptoRepositoryMock,
newKeyRepositoryMock,
newLibraryRepositoryMock,
newSharedLinkRepositoryMock,
newSystemConfigRepositoryMock,
newUserRepositoryMock,
newUserTokenRepositoryMock,
sharedLinkStub,
systemConfigStub,
userStub,
userTokenStub,
} from '@test';
import { IncomingHttpHeaders } from 'node:http'; import { IncomingHttpHeaders } from 'node:http';
import { Issuer, generators } from 'openid-client'; import { Issuer, generators } from 'openid-client';
import { Socket } from 'socket.io'; import { Socket } from 'socket.io';
import { import { AuthType } from 'src/domain/auth/auth.constant';
ICryptoRepository, import { AuthDto, SignUpDto } from 'src/domain/auth/auth.dto';
IKeyRepository, import { AuthService } from 'src/domain/auth/auth.service';
ILibraryRepository, import { IKeyRepository } from 'src/domain/repositories/api-key.repository';
ISharedLinkRepository, import { ICryptoRepository } from 'src/domain/repositories/crypto.repository';
ISystemConfigRepository, import { ILibraryRepository } from 'src/domain/repositories/library.repository';
IUserRepository, import { ISharedLinkRepository } from 'src/domain/repositories/shared-link.repository';
IUserTokenRepository, import { ISystemConfigRepository } from 'src/domain/repositories/system-config.repository';
} from '../repositories'; import { IUserTokenRepository } from 'src/domain/repositories/user-token.repository';
import { AuthType } from './auth.constant'; import { IUserRepository } from 'src/domain/repositories/user.repository';
import { AuthDto, SignUpDto } from './auth.dto'; import { UserEntity } from 'src/infra/entities/user.entity';
import { AuthService } from './auth.service'; import { keyStub } from 'test/fixtures/api-key.stub';
import { authStub, loginResponseStub } from 'test/fixtures/auth.stub';
import { sharedLinkStub } from 'test/fixtures/shared-link.stub';
import { systemConfigStub } from 'test/fixtures/system-config.stub';
import { userTokenStub } from 'test/fixtures/user-token.stub';
import { userStub } from 'test/fixtures/user.stub';
import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositories/access.repository.mock';
import { newKeyRepositoryMock } from 'test/repositories/api-key.repository.mock';
import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.mock';
import { newLibraryRepositoryMock } from 'test/repositories/library.repository.mock';
import { newSharedLinkRepositoryMock } from 'test/repositories/shared-link.repository.mock';
import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
import { newUserTokenRepositoryMock } from 'test/repositories/user-token.repository.mock';
import { newUserRepositoryMock } from 'test/repositories/user.repository.mock';
// const token = Buffer.from('my-api-key', 'utf8').toString('base64'); // const token = Buffer.from('my-api-key', 'utf8').toString('base64');

View file

@ -1,5 +1,3 @@
import { SystemConfig, UserEntity } from '@app/infra/entities';
import { ImmichLogger } from '@app/infra/logger';
import { import {
BadRequestException, BadRequestException,
Inject, Inject,
@ -12,20 +10,7 @@ import cookieParser from 'cookie';
import { DateTime } from 'luxon'; import { DateTime } from 'luxon';
import { IncomingHttpHeaders } from 'node:http'; import { IncomingHttpHeaders } from 'node:http';
import { ClientMetadata, Issuer, UserinfoResponse, custom, generators } from 'openid-client'; import { ClientMetadata, Issuer, UserinfoResponse, custom, generators } from 'openid-client';
import { AccessCore, Permission } from '../access'; import { AccessCore, Permission } from 'src/domain/access/access.core';
import { HumanReadableSize } from '../domain.util';
import {
IAccessRepository,
ICryptoRepository,
IKeyRepository,
ILibraryRepository,
ISharedLinkRepository,
ISystemConfigRepository,
IUserRepository,
IUserTokenRepository,
} from '../repositories';
import { SystemConfigCore } from '../system-config/system-config.core';
import { UserCore, UserResponseDto, mapUser } from '../user';
import { import {
AuthType, AuthType,
IMMICH_ACCESS_COOKIE, IMMICH_ACCESS_COOKIE,
@ -34,7 +19,7 @@ import {
IMMICH_IS_AUTHENTICATED, IMMICH_IS_AUTHENTICATED,
LOGIN_URL, LOGIN_URL,
MOBILE_REDIRECT, MOBILE_REDIRECT,
} from './auth.constant'; } from 'src/domain/auth/auth.constant';
import { import {
AuthDeviceResponseDto, AuthDeviceResponseDto,
AuthDto, AuthDto,
@ -48,7 +33,22 @@ import {
SignUpDto, SignUpDto,
mapLoginResponse, mapLoginResponse,
mapUserToken, mapUserToken,
} from './auth.dto'; } from 'src/domain/auth/auth.dto';
import { HumanReadableSize } from 'src/domain/domain.util';
import { IAccessRepository } from 'src/domain/repositories/access.repository';
import { IKeyRepository } from 'src/domain/repositories/api-key.repository';
import { ICryptoRepository } from 'src/domain/repositories/crypto.repository';
import { ILibraryRepository } from 'src/domain/repositories/library.repository';
import { ISharedLinkRepository } from 'src/domain/repositories/shared-link.repository';
import { ISystemConfigRepository } from 'src/domain/repositories/system-config.repository';
import { IUserTokenRepository } from 'src/domain/repositories/user-token.repository';
import { IUserRepository } from 'src/domain/repositories/user.repository';
import { SystemConfigCore } from 'src/domain/system-config/system-config.core';
import { UserResponseDto, mapUser } from 'src/domain/user/response-dto/user-response.dto';
import { UserCore } from 'src/domain/user/user.core';
import { SystemConfig } from 'src/infra/entities/system-config.entity';
import { UserEntity } from 'src/infra/entities/user.entity';
import { ImmichLogger } from 'src/infra/logger';
export interface LoginDetails { export interface LoginDetails {
isSecure: boolean; isSecure: boolean;

View file

@ -1,3 +0,0 @@
export * from './auth.constant';
export * from './auth.dto';
export * from './auth.service';

View file

@ -1,13 +1,8 @@
import { import { DatabaseService } from 'src/domain/database/database.service';
DatabaseExtension, import { Version, VersionType } from 'src/domain/domain.constant';
DatabaseService, import { DatabaseExtension, IDatabaseRepository, VectorIndex } from 'src/domain/repositories/database.repository';
IDatabaseRepository, import { ImmichLogger } from 'src/infra/logger';
VectorIndex, import { newDatabaseRepositoryMock } from 'test/repositories/database.repository.mock';
Version,
VersionType,
} from '@app/domain';
import { ImmichLogger } from '@app/infra/logger';
import { newDatabaseRepositoryMock } from '@test';
describe(DatabaseService.name, () => { describe(DatabaseService.name, () => {
let sut: DatabaseService; let sut: DatabaseService;

View file

@ -1,6 +1,5 @@
import { ImmichLogger } from '@app/infra/logger';
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { Version, VersionType } from '../domain.constant'; import { Version, VersionType } from 'src/domain/domain.constant';
import { import {
DatabaseExtension, DatabaseExtension,
DatabaseLock, DatabaseLock,
@ -8,7 +7,8 @@ import {
VectorExtension, VectorExtension,
VectorIndex, VectorIndex,
extName, extName,
} from '../repositories'; } from 'src/domain/repositories/database.repository';
import { ImmichLogger } from 'src/infra/logger';
@Injectable() @Injectable()
export class DatabaseService { export class DatabaseService {

View file

@ -1 +0,0 @@
export * from './database.service';

View file

@ -1,7 +1,7 @@
// TODO: remove nestjs references from domain // TODO: remove nestjs references from domain
import { LogLevel } from '@app/infra/entities';
import { ConfigModuleOptions } from '@nestjs/config'; import { ConfigModuleOptions } from '@nestjs/config';
import Joi from 'joi'; import Joi from 'joi';
import { LogLevel } from 'src/infra/entities/system-config.entity';
const WHEN_DB_URL_SET = Joi.when('DB_URL', { const WHEN_DB_URL_SET = Joi.when('DB_URL', {
is: Joi.exist(), is: Joi.exist(),

View file

@ -1,4 +1,4 @@
import { Version, VersionType, mimeTypes } from './domain.constant'; import { mimeTypes, Version, VersionType } from 'src/domain/domain.constant';
describe('mimeTypes', () => { describe('mimeTypes', () => {
for (const { mimetype, extension } of [ for (const { mimetype, extension } of [

View file

@ -1,7 +1,7 @@
import { AssetType } from '@app/infra/entities';
import { Duration } from 'luxon'; import { Duration } from 'luxon';
import { readFileSync } from 'node:fs'; import { readFileSync } from 'node:fs';
import { extname, join } from 'node:path'; import { extname, join } from 'node:path';
import { AssetType } from 'src/infra/entities/asset.entity';
export const AUDIT_LOG_MAX_DURATION = Duration.fromObject({ days: 100 }); export const AUDIT_LOG_MAX_DURATION = Duration.fromObject({ days: 100 });
export const ONE_HOUR = Duration.fromObject({ hours: 1 }); export const ONE_HOUR = Duration.fromObject({ hours: 1 });

View file

@ -1,29 +1,29 @@
import { ImmichLogger } from '@app/infra/logger';
import { Global, Module, Provider } from '@nestjs/common'; import { Global, Module, Provider } from '@nestjs/common';
import { ActivityService } from './activity'; import { ActivityService } from 'src/domain/activity/activity.service';
import { AlbumService } from './album'; import { AlbumService } from 'src/domain/album/album.service';
import { APIKeyService } from './api-key'; import { APIKeyService } from 'src/domain/api-key/api-key.service';
import { AssetService } from './asset'; import { AssetService } from 'src/domain/asset/asset.service';
import { AuditService } from './audit'; import { AuditService } from 'src/domain/audit/audit.service';
import { AuthService } from './auth'; import { AuthService } from 'src/domain/auth/auth.service';
import { DatabaseService } from './database'; import { DatabaseService } from 'src/domain/database/database.service';
import { DownloadService } from './download'; import { DownloadService } from 'src/domain/download/download.service';
import { JobService } from './job'; import { JobService } from 'src/domain/job/job.service';
import { LibraryService } from './library'; import { LibraryService } from 'src/domain/library/library.service';
import { MediaService } from './media'; import { MediaService } from 'src/domain/media/media.service';
import { MetadataService } from './metadata'; import { MetadataService } from 'src/domain/metadata/metadata.service';
import { PartnerService } from './partner'; import { PartnerService } from 'src/domain/partner/partner.service';
import { PersonService } from './person'; import { PersonService } from 'src/domain/person/person.service';
import { SearchService } from './search'; import { SearchService } from 'src/domain/search/search.service';
import { ServerInfoService } from './server-info'; import { ServerInfoService } from 'src/domain/server-info/server-info.service';
import { SharedLinkService } from './shared-link'; import { SharedLinkService } from 'src/domain/shared-link/shared-link.service';
import { SmartInfoService } from './smart-info'; import { SmartInfoService } from 'src/domain/smart-info/smart-info.service';
import { StorageService } from './storage'; import { StorageTemplateService } from 'src/domain/storage-template/storage-template.service';
import { StorageTemplateService } from './storage-template'; import { StorageService } from 'src/domain/storage/storage.service';
import { SystemConfigService } from './system-config'; import { SystemConfigService } from 'src/domain/system-config/system-config.service';
import { TagService } from './tag'; import { TagService } from 'src/domain/tag/tag.service';
import { TrashService } from './trash'; import { TrashService } from 'src/domain/trash/trash.service';
import { UserService } from './user'; import { UserService } from 'src/domain/user/user.service';
import { ImmichLogger } from 'src/infra/logger';
const providers: Provider[] = [ const providers: Provider[] = [
APIKeyService, APIKeyService,

View file

@ -1,4 +1,3 @@
import { ImmichLogger } from '@app/infra/logger';
import { BadRequestException, applyDecorators } from '@nestjs/common'; import { BadRequestException, applyDecorators } from '@nestjs/common';
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { Transform } from 'class-transformer'; import { Transform } from 'class-transformer';
@ -18,6 +17,7 @@ import { CronJob } from 'cron';
import _ from 'lodash'; import _ from 'lodash';
import { basename, extname } from 'node:path'; import { basename, extname } from 'node:path';
import sanitize from 'sanitize-filename'; import sanitize from 'sanitize-filename';
import { ImmichLogger } from 'src/infra/logger';
export enum CacheControl { export enum CacheControl {
PRIVATE_WITH_CACHE = 'private_with_cache', PRIVATE_WITH_CACHE = 'private_with_cache',

View file

@ -1,6 +1,6 @@
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { IsInt, IsPositive } from 'class-validator'; import { IsInt, IsPositive } from 'class-validator';
import { Optional, ValidateUUID } from '../domain.util'; import { Optional, ValidateUUID } from 'src/domain/domain.util';
export class DownloadInfoDto { export class DownloadInfoDto {
@ValidateUUID({ each: true, optional: true }) @ValidateUUID({ each: true, optional: true })

View file

@ -1,18 +1,16 @@
import { BadRequestException } from '@nestjs/common'; import { BadRequestException } from '@nestjs/common';
import {
IAccessRepositoryMock,
assetStub,
authStub,
newAccessRepositoryMock,
newAssetRepositoryMock,
newStorageRepositoryMock,
} from '@test';
import { when } from 'jest-when'; import { when } from 'jest-when';
import { CacheControl, ImmichFileResponse } from 'src/domain/domain.util';
import { DownloadResponseDto } from 'src/domain/download/download.dto';
import { DownloadService } from 'src/domain/download/download.service';
import { IAssetRepository } from 'src/domain/repositories/asset.repository';
import { IStorageRepository } from 'src/domain/repositories/storage.repository';
import { assetStub } from 'test/fixtures/asset.stub';
import { authStub } from 'test/fixtures/auth.stub';
import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositories/access.repository.mock';
import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock';
import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
import { Readable } from 'typeorm/platform/PlatformTools.js'; import { Readable } from 'typeorm/platform/PlatformTools.js';
import { CacheControl, ImmichFileResponse } from '../domain.util';
import { IAssetRepository, IStorageRepository } from '../repositories';
import { DownloadResponseDto } from './download.dto';
import { DownloadService } from './download.service';
const downloadResponse: DownloadResponseDto = { const downloadResponse: DownloadResponseDto = {
totalSize: 105_000, totalSize: 105_000,

View file

@ -1,13 +1,15 @@
import { AssetEntity } from '@app/infra/entities';
import { BadRequestException, Inject, Injectable } from '@nestjs/common'; import { BadRequestException, Inject, Injectable } from '@nestjs/common';
import { parse } from 'node:path'; import { parse } from 'node:path';
import { AccessCore, Permission } from '../access'; import { AccessCore, Permission } from 'src/domain/access/access.core';
import { AssetIdsDto } from '../asset'; import { AssetIdsDto } from 'src/domain/asset/dto/asset-ids.dto';
import { AuthDto } from '../auth'; import { AuthDto } from 'src/domain/auth/auth.dto';
import { mimeTypes } from '../domain.constant'; import { mimeTypes } from 'src/domain/domain.constant';
import { CacheControl, HumanReadableSize, ImmichFileResponse, usePagination } from '../domain.util'; import { CacheControl, HumanReadableSize, ImmichFileResponse, usePagination } from 'src/domain/domain.util';
import { IAccessRepository, IAssetRepository, IStorageRepository, ImmichReadStream } from '../repositories'; import { DownloadArchiveInfo, DownloadInfoDto, DownloadResponseDto } from 'src/domain/download/download.dto';
import { DownloadArchiveInfo, DownloadInfoDto, DownloadResponseDto } from './download.dto'; import { IAccessRepository } from 'src/domain/repositories/access.repository';
import { IAssetRepository } from 'src/domain/repositories/asset.repository';
import { IStorageRepository, ImmichReadStream } from 'src/domain/repositories/storage.repository';
import { AssetEntity } from 'src/infra/entities/asset.entity';
@Injectable() @Injectable()
export class DownloadService { export class DownloadService {

View file

@ -1,2 +0,0 @@
export * from './download.dto';
export * from './download.service';

View file

@ -1,30 +0,0 @@
export * from './access';
export * from './activity';
export * from './album';
export * from './api-key';
export * from './asset';
export * from './audit';
export * from './auth';
export * from './database';
export * from './domain.config';
export * from './domain.constant';
export * from './domain.module';
export * from './domain.util';
export * from './download';
export * from './job';
export * from './library';
export * from './media';
export * from './metadata';
export * from './partner';
export * from './person';
export * from './repositories';
export * from './search';
export * from './server-info';
export * from './shared-link';
export * from './smart-info';
export * from './storage';
export * from './storage-template';
export * from './system-config';
export * from './tag';
export * from './trash';
export * from './user';

View file

@ -1,4 +0,0 @@
export * from './job.constants';
export * from './job.dto';
export * from './job.interface';
export * from './job.service';

View file

@ -1,7 +1,7 @@
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { IsEnum, IsNotEmpty } from 'class-validator'; import { IsEnum, IsNotEmpty } from 'class-validator';
import { ValidateBoolean } from '../domain.util'; import { ValidateBoolean } from 'src/domain/domain.util';
import { JobCommand, QueueName } from './job.constants'; import { JobCommand, QueueName } from 'src/domain/job/job.constants';
export class JobIdParamDto { export class JobIdParamDto {
@IsNotEmpty() @IsNotEmpty()

View file

@ -1,26 +1,19 @@
import { SystemConfig, SystemConfigKey } from '@app/infra/entities';
import { BadRequestException } from '@nestjs/common'; import { BadRequestException } from '@nestjs/common';
import { import { JobCommand, JobName, QueueName } from 'src/domain/job/job.constants';
assetStub, import { JobService } from 'src/domain/job/job.service';
newAssetRepositoryMock, import { IAssetRepository } from 'src/domain/repositories/asset.repository';
newCommunicationRepositoryMock, import { ICommunicationRepository } from 'src/domain/repositories/communication.repository';
newJobRepositoryMock, import { IJobRepository, JobHandler, JobItem, JobStatus } from 'src/domain/repositories/job.repository';
newPersonRepositoryMock, import { IPersonRepository } from 'src/domain/repositories/person.repository';
newSystemConfigRepositoryMock, import { ISystemConfigRepository } from 'src/domain/repositories/system-config.repository';
} from '@test'; import { FeatureFlag, SystemConfigCore } from 'src/domain/system-config/system-config.core';
import { import { SystemConfig, SystemConfigKey } from 'src/infra/entities/system-config.entity';
IAssetRepository, import { assetStub } from 'test/fixtures/asset.stub';
ICommunicationRepository, import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock';
IJobRepository, import { newCommunicationRepositoryMock } from 'test/repositories/communication.repository.mock';
IPersonRepository, import { newJobRepositoryMock } from 'test/repositories/job.repository.mock';
ISystemConfigRepository, import { newPersonRepositoryMock } from 'test/repositories/person.repository.mock';
JobHandler, import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
JobItem,
JobStatus,
} from '../repositories';
import { FeatureFlag, SystemConfigCore } from '../system-config/system-config.core';
import { JobCommand, JobName, QueueName } from './job.constants';
import { JobService } from './job.service';
const makeMockHandlers = (status: JobStatus) => { const makeMockHandlers = (status: JobStatus) => {
const mock = jest.fn().mockResolvedValue(status); const mock = jest.fn().mockResolvedValue(status);

View file

@ -1,22 +1,15 @@
import { AssetType } from '@app/infra/entities';
import { ImmichLogger } from '@app/infra/logger';
import { BadRequestException, Inject, Injectable } from '@nestjs/common'; import { BadRequestException, Inject, Injectable } from '@nestjs/common';
import { mapAsset } from '../asset'; import { mapAsset } from 'src/domain/asset/response-dto/asset-response.dto';
import { import { ConcurrentQueueName, JobCommand, JobName, QueueName } from 'src/domain/job/job.constants';
ClientEvent, import { AllJobStatusResponseDto, JobCommandDto, JobStatusDto } from 'src/domain/job/job.dto';
IAssetRepository, import { IAssetRepository } from 'src/domain/repositories/asset.repository';
ICommunicationRepository, import { ClientEvent, ICommunicationRepository } from 'src/domain/repositories/communication.repository';
IJobRepository, import { IJobRepository, JobHandler, JobItem, JobStatus, QueueCleanType } from 'src/domain/repositories/job.repository';
IPersonRepository, import { IPersonRepository } from 'src/domain/repositories/person.repository';
ISystemConfigRepository, import { ISystemConfigRepository } from 'src/domain/repositories/system-config.repository';
JobHandler, import { FeatureFlag, SystemConfigCore } from 'src/domain/system-config/system-config.core';
JobItem, import { AssetType } from 'src/infra/entities/asset.entity';
JobStatus, import { ImmichLogger } from 'src/infra/logger';
QueueCleanType,
} from '../repositories';
import { FeatureFlag, SystemConfigCore } from '../system-config/system-config.core';
import { ConcurrentQueueName, JobCommand, JobName, QueueName } from './job.constants';
import { AllJobStatusResponseDto, JobCommandDto, JobStatusDto } from './job.dto';
@Injectable() @Injectable()
export class JobService { export class JobService {

View file

@ -1,2 +0,0 @@
export * from './library.dto';
export * from './library.service';

View file

@ -1,7 +1,7 @@
import { LibraryEntity, LibraryType } from '@app/infra/entities';
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { ArrayMaxSize, ArrayUnique, IsEnum, IsNotEmpty, IsString } from 'class-validator'; import { ArrayMaxSize, ArrayUnique, IsEnum, IsNotEmpty, IsString } from 'class-validator';
import { Optional, ValidateBoolean, ValidateUUID } from '../domain.util'; import { Optional, ValidateBoolean, ValidateUUID } from 'src/domain/domain.util';
import { LibraryEntity, LibraryType } from 'src/infra/entities/library.entity';
export class CreateLibraryDto { export class CreateLibraryDto {
@IsEnum(LibraryType) @IsEnum(LibraryType)

View file

@ -1,45 +1,39 @@
import { AssetType, LibraryType, SystemConfig, SystemConfigKey, UserEntity } from '@app/infra/entities';
import { BadRequestException } from '@nestjs/common'; import { BadRequestException } from '@nestjs/common';
import {
IAccessRepositoryMock,
assetStub,
authStub,
libraryStub,
makeMockWatcher,
newAccessRepositoryMock,
newAssetRepositoryMock,
newCryptoRepositoryMock,
newDatabaseRepositoryMock,
newJobRepositoryMock,
newLibraryRepositoryMock,
newStorageRepositoryMock,
newSystemConfigRepositoryMock,
systemConfigStub,
userStub,
} from '@test';
import { when } from 'jest-when'; import { when } from 'jest-when';
import { R_OK } from 'node:constants'; import { R_OK } from 'node:constants';
import { Stats } from 'node:fs'; import { Stats } from 'node:fs';
import { ILibraryFileJob, ILibraryRefreshJob, JobName } from '../job'; import { JobName } from 'src/domain/job/job.constants';
import { import { ILibraryFileJob, ILibraryRefreshJob } from 'src/domain/job/job.interface';
IAssetRepository, import { mapLibrary } from 'src/domain/library/library.dto';
ICryptoRepository, import { LibraryService } from 'src/domain/library/library.service';
IDatabaseRepository, import { IAssetRepository } from 'src/domain/repositories/asset.repository';
IJobRepository, import { ICryptoRepository } from 'src/domain/repositories/crypto.repository';
ILibraryRepository, import { IDatabaseRepository } from 'src/domain/repositories/database.repository';
IStorageRepository, import { IJobRepository, JobStatus } from 'src/domain/repositories/job.repository';
ISystemConfigRepository, import { ILibraryRepository } from 'src/domain/repositories/library.repository';
JobStatus, import { IStorageRepository, StorageEventType } from 'src/domain/repositories/storage.repository';
StorageEventType, import { ISystemConfigRepository } from 'src/domain/repositories/system-config.repository';
} from '../repositories'; import { SystemConfigCore } from 'src/domain/system-config/system-config.core';
import { SystemConfigCore } from '../system-config/system-config.core'; import { AssetType } from 'src/infra/entities/asset.entity';
import { mapLibrary } from './library.dto'; import { LibraryType } from 'src/infra/entities/library.entity';
import { LibraryService } from './library.service'; import { SystemConfig, SystemConfigKey } from 'src/infra/entities/system-config.entity';
import { UserEntity } from 'src/infra/entities/user.entity';
import { assetStub } from 'test/fixtures/asset.stub';
import { authStub } from 'test/fixtures/auth.stub';
import { libraryStub } from 'test/fixtures/library.stub';
import { systemConfigStub } from 'test/fixtures/system-config.stub';
import { userStub } from 'test/fixtures/user.stub';
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 { newJobRepositoryMock } from 'test/repositories/job.repository.mock';
import { newLibraryRepositoryMock } from 'test/repositories/library.repository.mock';
import { makeMockWatcher, newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
describe(LibraryService.name, () => { describe(LibraryService.name, () => {
let sut: LibraryService; let sut: LibraryService;
let accessMock: IAccessRepositoryMock;
let assetMock: jest.Mocked<IAssetRepository>; let assetMock: jest.Mocked<IAssetRepository>;
let configMock: jest.Mocked<ISystemConfigRepository>; let configMock: jest.Mocked<ISystemConfigRepository>;
let cryptoMock: jest.Mocked<ICryptoRepository>; let cryptoMock: jest.Mocked<ICryptoRepository>;
@ -49,7 +43,6 @@ describe(LibraryService.name, () => {
let databaseMock: jest.Mocked<IDatabaseRepository>; let databaseMock: jest.Mocked<IDatabaseRepository>;
beforeEach(() => { beforeEach(() => {
accessMock = newAccessRepositoryMock();
configMock = newSystemConfigRepositoryMock(); configMock = newSystemConfigRepositoryMock();
libraryMock = newLibraryRepositoryMock(); libraryMock = newLibraryRepositoryMock();
assetMock = newAssetRepositoryMock(); assetMock = newAssetRepositoryMock();
@ -58,19 +51,7 @@ describe(LibraryService.name, () => {
storageMock = newStorageRepositoryMock(); storageMock = newStorageRepositoryMock();
databaseMock = newDatabaseRepositoryMock(); databaseMock = newDatabaseRepositoryMock();
// Always validate owner access for library. sut = new LibraryService(assetMock, configMock, cryptoMock, jobMock, libraryMock, storageMock, databaseMock);
accessMock.library.checkOwnerAccess.mockImplementation((_, libraryIds) => Promise.resolve(libraryIds));
sut = new LibraryService(
accessMock,
assetMock,
configMock,
cryptoMock,
jobMock,
libraryMock,
storageMock,
databaseMock,
);
databaseMock.tryLock.mockResolvedValue(true); databaseMock.tryLock.mockResolvedValue(true);
}); });

View file

@ -1,5 +1,3 @@
import { AssetType, LibraryEntity, LibraryType } from '@app/infra/entities';
import { ImmichLogger } from '@app/infra/logger';
import { BadRequestException, Inject, Injectable } from '@nestjs/common'; import { BadRequestException, Inject, Injectable } from '@nestjs/common';
import { OnEvent } from '@nestjs/event-emitter'; import { OnEvent } from '@nestjs/event-emitter';
import { Trie } from 'mnemonist'; import { Trie } from 'mnemonist';
@ -8,28 +6,10 @@ import { EventEmitter } from 'node:events';
import { Stats } from 'node:fs'; import { Stats } from 'node:fs';
import path, { basename, parse } from 'node:path'; import path, { basename, parse } from 'node:path';
import picomatch from 'picomatch'; import picomatch from 'picomatch';
import { AccessCore } from '../access'; import { mimeTypes } from 'src/domain/domain.constant';
import { mimeTypes } from '../domain.constant'; import { handlePromiseError, usePagination, validateCronExpression } from 'src/domain/domain.util';
import { handlePromiseError, usePagination, validateCronExpression } from '../domain.util'; import { JOBS_ASSET_PAGINATION_SIZE, JobName } from 'src/domain/job/job.constants';
import { IBaseJob, IEntityJob, ILibraryFileJob, ILibraryRefreshJob, JOBS_ASSET_PAGINATION_SIZE, JobName } from '../job'; import { IBaseJob, IEntityJob, ILibraryFileJob, ILibraryRefreshJob } from 'src/domain/job/job.interface';
import {
DatabaseLock,
IAccessRepository,
IAssetRepository,
ICryptoRepository,
IDatabaseRepository,
IJobRepository,
ILibraryRepository,
IStorageRepository,
ISystemConfigRepository,
InternalEvent,
InternalEventMap,
JobStatus,
StorageEventType,
WithProperty,
} from '../repositories';
import { StorageCore } from '../storage';
import { SystemConfigCore } from '../system-config';
import { import {
CreateLibraryDto, CreateLibraryDto,
LibraryResponseDto, LibraryResponseDto,
@ -41,21 +21,32 @@ import {
ValidateLibraryImportPathResponseDto, ValidateLibraryImportPathResponseDto,
ValidateLibraryResponseDto, ValidateLibraryResponseDto,
mapLibrary, mapLibrary,
} from './library.dto'; } from 'src/domain/library/library.dto';
import { IAssetRepository, WithProperty } from 'src/domain/repositories/asset.repository';
import { InternalEvent, InternalEventMap } from 'src/domain/repositories/communication.repository';
import { ICryptoRepository } from 'src/domain/repositories/crypto.repository';
import { DatabaseLock, IDatabaseRepository } from 'src/domain/repositories/database.repository';
import { IJobRepository, JobStatus } from 'src/domain/repositories/job.repository';
import { ILibraryRepository } from 'src/domain/repositories/library.repository';
import { IStorageRepository, StorageEventType } from 'src/domain/repositories/storage.repository';
import { ISystemConfigRepository } from 'src/domain/repositories/system-config.repository';
import { StorageCore } from 'src/domain/storage/storage.core';
import { SystemConfigCore } from 'src/domain/system-config/system-config.core';
import { AssetType } from 'src/infra/entities/asset.entity';
import { LibraryEntity, LibraryType } from 'src/infra/entities/library.entity';
import { ImmichLogger } from 'src/infra/logger';
const LIBRARY_SCAN_BATCH_SIZE = 5000; const LIBRARY_SCAN_BATCH_SIZE = 5000;
@Injectable() @Injectable()
export class LibraryService extends EventEmitter { export class LibraryService extends EventEmitter {
readonly logger = new ImmichLogger(LibraryService.name); readonly logger = new ImmichLogger(LibraryService.name);
private access: AccessCore;
private configCore: SystemConfigCore; private configCore: SystemConfigCore;
private watchLibraries = false; private watchLibraries = false;
private watchLock = false; private watchLock = false;
private watchers: Record<string, () => Promise<void>> = {}; private watchers: Record<string, () => Promise<void>> = {};
constructor( constructor(
@Inject(IAccessRepository) accessRepository: IAccessRepository,
@Inject(IAssetRepository) private assetRepository: IAssetRepository, @Inject(IAssetRepository) private assetRepository: IAssetRepository,
@Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository, @Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository,
@Inject(ICryptoRepository) private cryptoRepository: ICryptoRepository, @Inject(ICryptoRepository) private cryptoRepository: ICryptoRepository,
@ -65,7 +56,6 @@ export class LibraryService extends EventEmitter {
@Inject(IDatabaseRepository) private databaseRepository: IDatabaseRepository, @Inject(IDatabaseRepository) private databaseRepository: IDatabaseRepository,
) { ) {
super(); super();
this.access = AccessCore.create(accessRepository);
this.configCore = SystemConfigCore.create(configRepository); this.configCore = SystemConfigCore.create(configRepository);
} }

View file

@ -1,2 +0,0 @@
export * from './media.constant';
export * from './media.service';

View file

@ -1,43 +1,37 @@
import { Stats } from 'node:fs';
import { JobName } from 'src/domain/job/job.constants';
import { MediaService } from 'src/domain/media/media.service';
import { IAssetRepository, WithoutProperty } from 'src/domain/repositories/asset.repository';
import { ICryptoRepository } from 'src/domain/repositories/crypto.repository';
import { IJobRepository, JobStatus } from 'src/domain/repositories/job.repository';
import { IMediaRepository } from 'src/domain/repositories/media.repository';
import { IMoveRepository } from 'src/domain/repositories/move.repository';
import { IPersonRepository } from 'src/domain/repositories/person.repository';
import { IStorageRepository } from 'src/domain/repositories/storage.repository';
import { ISystemConfigRepository } from 'src/domain/repositories/system-config.repository';
import { AssetType } from 'src/infra/entities/asset.entity';
import { ExifEntity } from 'src/infra/entities/exif.entity';
import { import {
AssetType,
AudioCodec, AudioCodec,
Colorspace, Colorspace,
ExifEntity,
SystemConfigKey, SystemConfigKey,
ToneMapping, ToneMapping,
TranscodeHWAccel, TranscodeHWAccel,
TranscodePolicy, TranscodePolicy,
VideoCodec, VideoCodec,
} from '@app/infra/entities'; } from 'src/infra/entities/system-config.entity';
import { import { assetStub } from 'test/fixtures/asset.stub';
assetStub, import { faceStub } from 'test/fixtures/face.stub';
faceStub, import { probeStub } from 'test/fixtures/media.stub';
newAssetRepositoryMock, import { personStub } from 'test/fixtures/person.stub';
newCryptoRepositoryMock, import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock';
newJobRepositoryMock, import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.mock';
newMediaRepositoryMock, import { newJobRepositoryMock } from 'test/repositories/job.repository.mock';
newMoveRepositoryMock, import { newMediaRepositoryMock } from 'test/repositories/media.repository.mock';
newPersonRepositoryMock, import { newMoveRepositoryMock } from 'test/repositories/move.repository.mock';
newStorageRepositoryMock, import { newPersonRepositoryMock } from 'test/repositories/person.repository.mock';
newSystemConfigRepositoryMock, import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
personStub, import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
probeStub,
} from '@test';
import { Stats } from 'node:fs';
import { JobName } from '../job';
import {
IAssetRepository,
ICryptoRepository,
IJobRepository,
IMediaRepository,
IMoveRepository,
IPersonRepository,
IStorageRepository,
ISystemConfigRepository,
JobStatus,
WithoutProperty,
} from '../repositories';
import { MediaService } from './media.service';
describe(MediaService.name, () => { describe(MediaService.name, () => {
let sut: MediaService; let sut: MediaService;

View file

@ -1,37 +1,7 @@
import {
AssetEntity,
AssetPathType,
AssetType,
AudioCodec,
Colorspace,
TranscodeHWAccel,
TranscodePolicy,
TranscodeTarget,
VideoCodec,
} from '@app/infra/entities';
import { ImmichLogger } from '@app/infra/logger';
import { Inject, Injectable, UnsupportedMediaTypeException } from '@nestjs/common'; import { Inject, Injectable, UnsupportedMediaTypeException } from '@nestjs/common';
import { usePagination } from '../domain.util'; import { usePagination } from 'src/domain/domain.util';
import { IBaseJob, IEntityJob, JOBS_ASSET_PAGINATION_SIZE, JobName, QueueName } from '../job'; import { JOBS_ASSET_PAGINATION_SIZE, JobName, QueueName } from 'src/domain/job/job.constants';
import { import { IBaseJob, IEntityJob } from 'src/domain/job/job.interface';
AudioStreamInfo,
IAssetRepository,
ICryptoRepository,
IJobRepository,
IMediaRepository,
IMoveRepository,
IPersonRepository,
IStorageRepository,
ISystemConfigRepository,
JobItem,
JobStatus,
VideoCodecHWConfig,
VideoStreamInfo,
WithoutProperty,
} from '../repositories';
import { StorageCore, StorageFolder } from '../storage';
import { SystemConfigFFmpegDto } from '../system-config';
import { SystemConfigCore } from '../system-config/system-config.core';
import { import {
H264Config, H264Config,
HEVCConfig, HEVCConfig,
@ -41,7 +11,34 @@ import {
ThumbnailConfig, ThumbnailConfig,
VAAPIConfig, VAAPIConfig,
VP9Config, VP9Config,
} from './media.util'; } from 'src/domain/media/media.util';
import { IAssetRepository, WithoutProperty } from 'src/domain/repositories/asset.repository';
import { ICryptoRepository } from 'src/domain/repositories/crypto.repository';
import { IJobRepository, JobItem, JobStatus } from 'src/domain/repositories/job.repository';
import {
AudioStreamInfo,
IMediaRepository,
VideoCodecHWConfig,
VideoStreamInfo,
} from 'src/domain/repositories/media.repository';
import { IMoveRepository } from 'src/domain/repositories/move.repository';
import { IPersonRepository } from 'src/domain/repositories/person.repository';
import { IStorageRepository } from 'src/domain/repositories/storage.repository';
import { ISystemConfigRepository } from 'src/domain/repositories/system-config.repository';
import { StorageCore, StorageFolder } from 'src/domain/storage/storage.core';
import { SystemConfigFFmpegDto } from 'src/domain/system-config/dto/system-config-ffmpeg.dto';
import { SystemConfigCore } from 'src/domain/system-config/system-config.core';
import { AssetEntity, AssetType } from 'src/infra/entities/asset.entity';
import { AssetPathType } from 'src/infra/entities/move.entity';
import {
AudioCodec,
Colorspace,
TranscodeHWAccel,
TranscodePolicy,
TranscodeTarget,
VideoCodec,
} from 'src/infra/entities/system-config.entity';
import { ImmichLogger } from 'src/infra/logger';
@Injectable() @Injectable()
export class MediaService { export class MediaService {
@ -58,7 +55,7 @@ export class MediaService {
@Inject(IStorageRepository) private storageRepository: IStorageRepository, @Inject(IStorageRepository) private storageRepository: IStorageRepository,
@Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository, @Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository,
@Inject(IMoveRepository) moveRepository: IMoveRepository, @Inject(IMoveRepository) moveRepository: IMoveRepository,
@Inject(ICryptoRepository) private cryptoRepository: ICryptoRepository, @Inject(ICryptoRepository) cryptoRepository: ICryptoRepository,
) { ) {
this.configCore = SystemConfigCore.create(configRepository); this.configCore = SystemConfigCore.create(configRepository);
this.storageCore = StorageCore.create( this.storageCore = StorageCore.create(

View file

@ -1,4 +1,3 @@
import { CQMode, ToneMapping, TranscodeHWAccel, TranscodeTarget, VideoCodec } from '@app/infra/entities';
import { import {
AudioStreamInfo, AudioStreamInfo,
BitrateDistribution, BitrateDistribution,
@ -6,8 +5,16 @@ import {
VideoCodecHWConfig, VideoCodecHWConfig,
VideoCodecSWConfig, VideoCodecSWConfig,
VideoStreamInfo, VideoStreamInfo,
} from '../repositories'; } from 'src/domain/repositories/media.repository';
import { SystemConfigFFmpegDto } from '../system-config/dto'; import { SystemConfigFFmpegDto } from 'src/domain/system-config/dto/system-config-ffmpeg.dto';
import {
CQMode,
ToneMapping,
TranscodeHWAccel,
TranscodeTarget,
VideoCodec,
} from 'src/infra/entities/system-config.entity';
class BaseConfig implements VideoCodecSWConfig { class BaseConfig implements VideoCodecSWConfig {
presets = ['veryslow', 'slower', 'slow', 'medium', 'fast', 'faster', 'veryfast', 'superfast', 'ultrafast']; presets = ['veryslow', 'slower', 'slow', 'medium', 'fast', 'faster', 'veryfast', 'superfast', 'ultrafast'];
constructor(protected config: SystemConfigFFmpegDto) {} constructor(protected config: SystemConfigFFmpegDto) {}

View file

@ -1 +0,0 @@
export * from './metadata.service';

View file

@ -1,46 +1,40 @@
import { AssetType, ExifEntity, SystemConfigKey } from '@app/infra/entities';
import {
assetStub,
fileStub,
newAlbumRepositoryMock,
newAssetRepositoryMock,
newCommunicationRepositoryMock,
newCryptoRepositoryMock,
newDatabaseRepositoryMock,
newJobRepositoryMock,
newMediaRepositoryMock,
newMetadataRepositoryMock,
newMoveRepositoryMock,
newPersonRepositoryMock,
newStorageRepositoryMock,
newSystemConfigRepositoryMock,
probeStub,
} from '@test';
import { BinaryField } from 'exiftool-vendored'; import { BinaryField } from 'exiftool-vendored';
import { when } from 'jest-when'; import { when } from 'jest-when';
import { randomBytes } from 'node:crypto'; import { randomBytes } from 'node:crypto';
import { Stats } from 'node:fs'; import { Stats } from 'node:fs';
import { constants } from 'node:fs/promises'; import { constants } from 'node:fs/promises';
import { JobName } from '../job'; import { JobName } from 'src/domain/job/job.constants';
import { import { MetadataService, Orientation } from 'src/domain/metadata/metadata.service';
ClientEvent, import { IAlbumRepository } from 'src/domain/repositories/album.repository';
IAlbumRepository, import { IAssetRepository, WithoutProperty } from 'src/domain/repositories/asset.repository';
IAssetRepository, import { ClientEvent, ICommunicationRepository } from 'src/domain/repositories/communication.repository';
ICommunicationRepository, import { ICryptoRepository } from 'src/domain/repositories/crypto.repository';
ICryptoRepository, import { IDatabaseRepository } from 'src/domain/repositories/database.repository';
IDatabaseRepository, import { IJobRepository, JobStatus } from 'src/domain/repositories/job.repository';
IJobRepository, import { IMediaRepository } from 'src/domain/repositories/media.repository';
IMediaRepository, import { IMetadataRepository, ImmichTags } from 'src/domain/repositories/metadata.repository';
IMetadataRepository, import { IMoveRepository } from 'src/domain/repositories/move.repository';
IMoveRepository, import { IPersonRepository } from 'src/domain/repositories/person.repository';
IPersonRepository, import { IStorageRepository } from 'src/domain/repositories/storage.repository';
IStorageRepository, import { ISystemConfigRepository } from 'src/domain/repositories/system-config.repository';
ISystemConfigRepository, import { AssetType } from 'src/infra/entities/asset.entity';
ImmichTags, import { ExifEntity } from 'src/infra/entities/exif.entity';
JobStatus, import { SystemConfigKey } from 'src/infra/entities/system-config.entity';
WithoutProperty, import { assetStub } from 'test/fixtures/asset.stub';
} from '../repositories'; import { fileStub } from 'test/fixtures/file.stub';
import { MetadataService, Orientation } from './metadata.service'; import { probeStub } from 'test/fixtures/media.stub';
import { newAlbumRepositoryMock } from 'test/repositories/album.repository.mock';
import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock';
import { newCommunicationRepositoryMock } from 'test/repositories/communication.repository.mock';
import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.mock';
import { newDatabaseRepositoryMock } from 'test/repositories/database.repository.mock';
import { newJobRepositoryMock } from 'test/repositories/job.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';
import { newPersonRepositoryMock } from 'test/repositories/person.repository.mock';
import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
describe(MetadataService.name, () => { describe(MetadataService.name, () => {
let albumMock: jest.Mocked<IAlbumRepository>; let albumMock: jest.Mocked<IAlbumRepository>;

View file

@ -1,5 +1,3 @@
import { AssetEntity, AssetType, ExifEntity } from '@app/infra/entities';
import { ImmichLogger } from '@app/infra/logger';
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { ExifDateTime, Tags } from 'exiftool-vendored'; import { ExifDateTime, Tags } from 'exiftool-vendored';
import { firstDateTime } from 'exiftool-vendored/dist/FirstDateTime'; import { firstDateTime } from 'exiftool-vendored/dist/FirstDateTime';
@ -8,29 +6,26 @@ import { Duration } from 'luxon';
import { constants } from 'node:fs/promises'; import { constants } from 'node:fs/promises';
import path from 'node:path'; import path from 'node:path';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { handlePromiseError, usePagination } from '../domain.util'; import { handlePromiseError, usePagination } from 'src/domain/domain.util';
import { IBaseJob, IEntityJob, ISidecarWriteJob, JOBS_ASSET_PAGINATION_SIZE, JobName, QueueName } from '../job'; import { JOBS_ASSET_PAGINATION_SIZE, JobName, QueueName } from 'src/domain/job/job.constants';
import { import { IBaseJob, IEntityJob, ISidecarWriteJob } from 'src/domain/job/job.interface';
ClientEvent, import { IAlbumRepository } from 'src/domain/repositories/album.repository';
DatabaseLock, import { IAssetRepository, WithoutProperty } from 'src/domain/repositories/asset.repository';
IAlbumRepository, import { ClientEvent, ICommunicationRepository } from 'src/domain/repositories/communication.repository';
IAssetRepository, import { ICryptoRepository } from 'src/domain/repositories/crypto.repository';
ICommunicationRepository, import { DatabaseLock, IDatabaseRepository } from 'src/domain/repositories/database.repository';
ICryptoRepository, import { IJobRepository, JobStatus } from 'src/domain/repositories/job.repository';
IDatabaseRepository, import { IMediaRepository } from 'src/domain/repositories/media.repository';
IJobRepository, import { IMetadataRepository, ImmichTags } from 'src/domain/repositories/metadata.repository';
IMediaRepository, import { IMoveRepository } from 'src/domain/repositories/move.repository';
IMetadataRepository, import { IPersonRepository } from 'src/domain/repositories/person.repository';
IMoveRepository, import { IStorageRepository } from 'src/domain/repositories/storage.repository';
IPersonRepository, import { ISystemConfigRepository } from 'src/domain/repositories/system-config.repository';
IStorageRepository, import { StorageCore } from 'src/domain/storage/storage.core';
ISystemConfigRepository, import { FeatureFlag, SystemConfigCore } from 'src/domain/system-config/system-config.core';
ImmichTags, import { AssetEntity, AssetType } from 'src/infra/entities/asset.entity';
JobStatus, import { ExifEntity } from 'src/infra/entities/exif.entity';
WithoutProperty, import { ImmichLogger } from 'src/infra/logger';
} from '../repositories';
import { StorageCore } from '../storage';
import { FeatureFlag, SystemConfigCore } from '../system-config';
/** look for a date from these tags (in order) */ /** look for a date from these tags (in order) */
const EXIF_DATE_TAGS: Array<keyof Tags> = [ const EXIF_DATE_TAGS: Array<keyof Tags> = [

View file

@ -1,2 +0,0 @@
export * from './partner.dto';
export * from './partner.service';

View file

@ -1,5 +1,5 @@
import { IsNotEmpty } from 'class-validator'; import { IsNotEmpty } from 'class-validator';
import { UserResponseDto } from '../user'; import { UserResponseDto } from 'src/domain/user/response-dto/user-response.dto';
export class UpdatePartnerDto { export class UpdatePartnerDto {
@IsNotEmpty() @IsNotEmpty()

View file

@ -1,9 +1,12 @@
import { UserAvatarColor } from '@app/infra/entities';
import { BadRequestException } from '@nestjs/common'; import { BadRequestException } from '@nestjs/common';
import { authStub, newPartnerRepositoryMock, partnerStub } from '@test'; import { PartnerResponseDto } from 'src/domain/partner/partner.dto';
import { IAccessRepository, IPartnerRepository, PartnerDirection } from '../repositories'; import { PartnerService } from 'src/domain/partner/partner.service';
import { PartnerResponseDto } from './partner.dto'; import { IAccessRepository } from 'src/domain/repositories/access.repository';
import { PartnerService } from './partner.service'; import { IPartnerRepository, PartnerDirection } from 'src/domain/repositories/partner.repository';
import { UserAvatarColor } from 'src/infra/entities/user.entity';
import { authStub } from 'test/fixtures/auth.stub';
import { partnerStub } from 'test/fixtures/partner.stub';
import { newPartnerRepositoryMock } from 'test/repositories/partner.repository.mock';
const responseDto = { const responseDto = {
admin: <PartnerResponseDto>{ admin: <PartnerResponseDto>{

View file

@ -1,10 +1,11 @@
import { PartnerEntity } from '@app/infra/entities';
import { BadRequestException, Inject, Injectable } from '@nestjs/common'; import { BadRequestException, Inject, Injectable } from '@nestjs/common';
import { AccessCore, Permission } from '../access'; import { AccessCore, Permission } from 'src/domain/access/access.core';
import { AuthDto } from '../auth'; import { AuthDto } from 'src/domain/auth/auth.dto';
import { IAccessRepository, IPartnerRepository, PartnerDirection, PartnerIds } from '../repositories'; import { PartnerResponseDto, UpdatePartnerDto } from 'src/domain/partner/partner.dto';
import { mapUser } from '../user'; import { IAccessRepository } from 'src/domain/repositories/access.repository';
import { PartnerResponseDto, UpdatePartnerDto } from './partner.dto'; import { IPartnerRepository, PartnerDirection, PartnerIds } from 'src/domain/repositories/partner.repository';
import { mapUser } from 'src/domain/user/response-dto/user-response.dto';
import { PartnerEntity } from 'src/infra/entities/partner.entity';
@Injectable() @Injectable()
export class PartnerService { export class PartnerService {

View file

@ -1,2 +0,0 @@
export * from './person.dto';
export * from './person.service';

View file

@ -1,9 +1,10 @@
import { AssetFaceEntity, PersonEntity } from '@app/infra/entities';
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { Type } from 'class-transformer'; import { Type } from 'class-transformer';
import { IsArray, IsNotEmpty, IsString, MaxDate, ValidateNested } from 'class-validator'; import { IsArray, IsNotEmpty, IsString, MaxDate, ValidateNested } from 'class-validator';
import { AuthDto } from '../auth'; import { AuthDto } from 'src/domain/auth/auth.dto';
import { Optional, ValidateBoolean, ValidateDate, ValidateUUID } from '../domain.util'; import { Optional, ValidateBoolean, ValidateDate, ValidateUUID } from 'src/domain/domain.util';
import { AssetFaceEntity } from 'src/infra/entities/asset-face.entity';
import { PersonEntity } from 'src/infra/entities/person.entity';
export class PersonCreateDto { export class PersonCreateDto {
/** /**

View file

@ -1,44 +1,37 @@
import { AssetFaceEntity, Colorspace, SystemConfigKey } from '@app/infra/entities';
import { BadRequestException, NotFoundException } from '@nestjs/common'; import { BadRequestException, NotFoundException } from '@nestjs/common';
import { import { BulkIdErrorReason } from 'src/domain/asset/response-dto/asset-ids-response.dto';
IAccessRepositoryMock, import { CacheControl, ImmichFileResponse } from 'src/domain/domain.util';
assetStub, import { JobName } from 'src/domain/job/job.constants';
authStub, import { PersonResponseDto, mapFaces, mapPerson } from 'src/domain/person/person.dto';
faceStub, import { PersonService } from 'src/domain/person/person.service';
newAccessRepositoryMock, import { IAssetRepository, WithoutProperty } from 'src/domain/repositories/asset.repository';
newAssetRepositoryMock, import { ICryptoRepository } from 'src/domain/repositories/crypto.repository';
newCryptoRepositoryMock, import { IJobRepository, JobStatus } from 'src/domain/repositories/job.repository';
newJobRepositoryMock, import { IMachineLearningRepository } from 'src/domain/repositories/machine-learning.repository';
newMachineLearningRepositoryMock, import { IMediaRepository } from 'src/domain/repositories/media.repository';
newMediaRepositoryMock, import { IMoveRepository } from 'src/domain/repositories/move.repository';
newMoveRepositoryMock, import { IPersonRepository } from 'src/domain/repositories/person.repository';
newPersonRepositoryMock, import { FaceSearchResult, ISearchRepository } from 'src/domain/repositories/search.repository';
newSearchRepositoryMock, import { IStorageRepository } from 'src/domain/repositories/storage.repository';
newStorageRepositoryMock, import { ISystemConfigRepository } from 'src/domain/repositories/system-config.repository';
newSystemConfigRepositoryMock, import { AssetFaceEntity } from 'src/infra/entities/asset-face.entity';
personStub, import { Colorspace, SystemConfigKey } from 'src/infra/entities/system-config.entity';
} from '@test'; import { assetStub } from 'test/fixtures/asset.stub';
import { authStub } from 'test/fixtures/auth.stub';
import { faceStub } from 'test/fixtures/face.stub';
import { personStub } from 'test/fixtures/person.stub';
import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositories/access.repository.mock';
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 { newMachineLearningRepositoryMock } from 'test/repositories/machine-learning.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';
import { newSearchRepositoryMock } from 'test/repositories/search.repository.mock';
import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
import { IsNull } from 'typeorm'; import { IsNull } from 'typeorm';
import { BulkIdErrorReason } from '../asset';
import { CacheControl, ImmichFileResponse } from '../domain.util';
import { JobName } from '../job';
import {
FaceSearchResult,
IAssetRepository,
ICryptoRepository,
IJobRepository,
IMachineLearningRepository,
IMediaRepository,
IMoveRepository,
IPersonRepository,
ISearchRepository,
IStorageRepository,
ISystemConfigRepository,
JobStatus,
WithoutProperty,
} from '../repositories';
import { PersonResponseDto, mapFaces, mapPerson } from './person.dto';
import { PersonService } from './person.service';
const responseDto: PersonResponseDto = { const responseDto: PersonResponseDto = {
id: 'person-1', id: 'person-1',

View file

@ -1,35 +1,13 @@
import { PersonEntity } from '@app/infra/entities';
import { PersonPathType } from '@app/infra/entities/move.entity';
import { ImmichLogger } from '@app/infra/logger';
import { BadRequestException, Inject, Injectable, NotFoundException } from '@nestjs/common'; import { BadRequestException, Inject, Injectable, NotFoundException } from '@nestjs/common';
import { IsNull } from 'typeorm'; import { AccessCore, Permission } from 'src/domain/access/access.core';
import { AccessCore, Permission } from '../access'; import { BulkIdErrorReason, BulkIdResponseDto } from 'src/domain/asset/response-dto/asset-ids-response.dto';
import { AssetResponseDto, BulkIdErrorReason, BulkIdResponseDto, mapAsset } from '../asset'; import { AssetResponseDto, mapAsset } from 'src/domain/asset/response-dto/asset-response.dto';
import { AuthDto } from '../auth'; import { AuthDto } from 'src/domain/auth/auth.dto';
import { mimeTypes } from '../domain.constant'; import { mimeTypes } from 'src/domain/domain.constant';
import { CacheControl, ImmichFileResponse, usePagination } from '../domain.util'; import { CacheControl, ImmichFileResponse, usePagination } from 'src/domain/domain.util';
import { IBaseJob, IDeferrableJob, IEntityJob, JOBS_ASSET_PAGINATION_SIZE, JobName, QueueName } from '../job'; import { JOBS_ASSET_PAGINATION_SIZE, JobName, QueueName } from 'src/domain/job/job.constants';
import { FACE_THUMBNAIL_SIZE } from '../media'; import { IBaseJob, IDeferrableJob, IEntityJob } from 'src/domain/job/job.interface';
import { import { FACE_THUMBNAIL_SIZE } from 'src/domain/media/media.constant';
CropOptions,
IAccessRepository,
IAssetRepository,
ICryptoRepository,
IJobRepository,
IMachineLearningRepository,
IMediaRepository,
IMoveRepository,
IPersonRepository,
ISearchRepository,
IStorageRepository,
ISystemConfigRepository,
JobItem,
JobStatus,
UpdateFacesData,
WithoutProperty,
} from '../repositories';
import { StorageCore } from '../storage';
import { SystemConfigCore } from '../system-config';
import { import {
AssetFaceResponseDto, AssetFaceResponseDto,
AssetFaceUpdateDto, AssetFaceUpdateDto,
@ -44,7 +22,24 @@ import {
PersonUpdateDto, PersonUpdateDto,
mapFaces, mapFaces,
mapPerson, mapPerson,
} from './person.dto'; } from 'src/domain/person/person.dto';
import { IAccessRepository } from 'src/domain/repositories/access.repository';
import { IAssetRepository, WithoutProperty } from 'src/domain/repositories/asset.repository';
import { ICryptoRepository } from 'src/domain/repositories/crypto.repository';
import { IJobRepository, JobItem, JobStatus } from 'src/domain/repositories/job.repository';
import { IMachineLearningRepository } from 'src/domain/repositories/machine-learning.repository';
import { CropOptions, IMediaRepository } from 'src/domain/repositories/media.repository';
import { IMoveRepository } from 'src/domain/repositories/move.repository';
import { IPersonRepository, UpdateFacesData } from 'src/domain/repositories/person.repository';
import { ISearchRepository } from 'src/domain/repositories/search.repository';
import { IStorageRepository } from 'src/domain/repositories/storage.repository';
import { ISystemConfigRepository } from 'src/domain/repositories/system-config.repository';
import { StorageCore } from 'src/domain/storage/storage.core';
import { SystemConfigCore } from 'src/domain/system-config/system-config.core';
import { PersonPathType } from 'src/infra/entities/move.entity';
import { PersonEntity } from 'src/infra/entities/person.entity';
import { ImmichLogger } from 'src/infra/logger';
import { IsNull } from 'typeorm';
@Injectable() @Injectable()
export class PersonService { export class PersonService {
@ -64,7 +59,7 @@ export class PersonService {
@Inject(IStorageRepository) private storageRepository: IStorageRepository, @Inject(IStorageRepository) private storageRepository: IStorageRepository,
@Inject(IJobRepository) private jobRepository: IJobRepository, @Inject(IJobRepository) private jobRepository: IJobRepository,
@Inject(ISearchRepository) private smartInfoRepository: ISearchRepository, @Inject(ISearchRepository) private smartInfoRepository: ISearchRepository,
@Inject(ICryptoRepository) private cryptoRepository: ICryptoRepository, @Inject(ICryptoRepository) cryptoRepository: ICryptoRepository,
) { ) {
this.access = AccessCore.create(accessRepository); this.access = AccessCore.create(accessRepository);
this.configCore = SystemConfigCore.create(configRepository); this.configCore = SystemConfigCore.create(configRepository);

View file

@ -1,5 +1,5 @@
import { ActivityEntity } from '@app/infra/entities/activity.entity'; import { ActivityEntity } from 'src/infra/entities/activity.entity';
import { ActivitySearch } from '@app/infra/repositories'; import { ActivitySearch } from 'src/infra/repositories/activity.repository';
export const IActivityRepository = 'IActivityRepository'; export const IActivityRepository = 'IActivityRepository';

View file

@ -1,4 +1,4 @@
import { AlbumEntity } from '@app/infra/entities'; import { AlbumEntity } from 'src/infra/entities/album.entity';
export const IAlbumRepository = 'IAlbumRepository'; export const IAlbumRepository = 'IAlbumRepository';

View file

@ -1,4 +1,4 @@
import { APIKeyEntity } from '@app/infra/entities'; import { APIKeyEntity } from 'src/infra/entities/api-key.entity';
export const IKeyRepository = 'IKeyRepository'; export const IKeyRepository = 'IKeyRepository';

View file

@ -1,4 +1,4 @@
import { AssetStackEntity } from '@app/infra/entities/asset-stack.entity'; import { AssetStackEntity } from 'src/infra/entities/asset-stack.entity';
export const IAssetStackRepository = 'IAssetStackRepository'; export const IAssetStackRepository = 'IAssetStackRepository';

View file

@ -1,7 +1,11 @@
import { AssetSearchOptions, ReverseGeocodeResult, SearchExploreItem } from '@app/domain'; import { Paginated, PaginationOptions } from 'src/domain/domain.util';
import { AssetEntity, AssetJobStatusEntity, AssetOrder, AssetType, ExifEntity } from '@app/infra/entities'; import { ReverseGeocodeResult } from 'src/domain/repositories/metadata.repository';
import { AssetSearchOptions, SearchExploreItem } from 'src/domain/repositories/search.repository';
import { AssetOrder } from 'src/infra/entities/album.entity';
import { AssetJobStatusEntity } from 'src/infra/entities/asset-job-status.entity';
import { AssetEntity, AssetType } from 'src/infra/entities/asset.entity';
import { ExifEntity } from 'src/infra/entities/exif.entity';
import { FindOptionsRelations, FindOptionsSelect } from 'typeorm'; import { FindOptionsRelations, FindOptionsSelect } from 'typeorm';
import { Paginated, PaginationOptions } from '../domain.util';
export type AssetStats = Record<AssetType, number>; export type AssetStats = Record<AssetType, number>;

View file

@ -1,4 +1,4 @@
import { AuditEntity, DatabaseAction, EntityType } from '@app/infra/entities'; import { AuditEntity, DatabaseAction, EntityType } from 'src/infra/entities/audit.entity';
export const IAuditRepository = 'IAuditRepository'; export const IAuditRepository = 'IAuditRepository';

View file

@ -1,5 +1,6 @@
import { AssetResponseDto, ReleaseNotification, ServerVersionResponseDto } from '@app/domain'; import { AssetResponseDto } from 'src/domain/asset/response-dto/asset-response.dto';
import { SystemConfig } from '@app/infra/entities'; import { ReleaseNotification, ServerVersionResponseDto } from 'src/domain/server-info/server-info.dto';
import { SystemConfig } from 'src/infra/entities/system-config.entity';
export const ICommunicationRepository = 'ICommunicationRepository'; export const ICommunicationRepository = 'ICommunicationRepository';

View file

@ -1,4 +1,4 @@
import { Version } from '../domain.constant'; import { Version } from 'src/domain/domain.constant';
export enum DatabaseExtension { export enum DatabaseExtension {
CUBE = 'cube', CUBE = 'cube',

View file

@ -1,27 +0,0 @@
export * from './access.repository';
export * from './activity.repository';
export * from './album.repository';
export * from './api-key.repository';
export * from './asset-stack.repository';
export * from './asset.repository';
export * from './audit.repository';
export * from './communication.repository';
export * from './crypto.repository';
export * from './database.repository';
export * from './job.repository';
export * from './library.repository';
export * from './machine-learning.repository';
export * from './media.repository';
export * from './metadata.repository';
export * from './move.repository';
export * from './partner.repository';
export * from './person.repository';
export * from './search.repository';
export * from './server-info.repository';
export * from './shared-link.repository';
export * from './storage.repository';
export * from './system-config.repository';
export * from './system-metadata.repository';
export * from './tag.repository';
export * from './user-token.repository';
export * from './user.repository';

View file

@ -1,5 +1,4 @@
import { JobName, QueueName } from '../job/job.constants'; import { JobName, QueueName } from 'src/domain/job/job.constants';
import { import {
IAssetDeletionJob, IAssetDeletionJob,
IBaseJob, IBaseJob,
@ -9,7 +8,7 @@ import {
ILibraryFileJob, ILibraryFileJob,
ILibraryRefreshJob, ILibraryRefreshJob,
ISidecarWriteJob, ISidecarWriteJob,
} from '../job/job.interface'; } from 'src/domain/job/job.interface';
export interface JobCounts { export interface JobCounts {
active: number; active: number;

Some files were not shown because too many files have changed in this diff Show more