From bb844642169d4e5a68a30f19001839e283d06dd7 Mon Sep 17 00:00:00 2001 From: Jason Rasmussen Date: Wed, 1 Feb 2023 15:55:06 -0500 Subject: [PATCH] refactor(server): device info (#1490) * refactor(server): device info * fix: export device service --------- Co-authored-by: Alex Tran --- .../device-info/device-info.controller.ts | 24 --- .../api-v1/device-info/device-info.module.ts | 12 -- .../api-v1/device-info/device-info.service.ts | 31 --- server/apps/immich/src/app.module.ts | 5 +- .../src/controllers/device-info.controller.ts | 23 +++ server/apps/immich/src/controllers/index.ts | 1 + server/immich-openapi-specs.json | 188 +++++++++--------- .../src/device-info/device-info.core.ts | 23 +++ .../src/device-info/device-info.repository.ts | 8 + .../device-info/device-info.service.spec.ts | 28 ++- .../src/device-info/device-info.service.ts | 20 ++ .../libs/domain/src/device-info/dto/index.ts | 1 + .../device-info/dto/upsert-device-info.dto.ts | 2 +- server/libs/domain/src/device-info/index.ts | 4 + .../response-dto/device-info-response.dto.ts | 2 +- .../src/device-info/response-dto/index.ts | 1 + server/libs/domain/src/domain.module.ts | 2 + server/libs/domain/src/index.ts | 1 + .../test/device-info.repository.mock.ts | 8 + server/libs/domain/test/index.ts | 1 + .../db/repository/device-info.repository.ts | 16 ++ server/libs/infra/src/db/repository/index.ts | 4 +- server/libs/infra/src/infra.module.ts | 33 ++- 23 files changed, 249 insertions(+), 189 deletions(-) delete mode 100644 server/apps/immich/src/api-v1/device-info/device-info.controller.ts delete mode 100644 server/apps/immich/src/api-v1/device-info/device-info.module.ts delete mode 100644 server/apps/immich/src/api-v1/device-info/device-info.service.ts create mode 100644 server/apps/immich/src/controllers/device-info.controller.ts create mode 100644 server/libs/domain/src/device-info/device-info.core.ts create mode 100644 server/libs/domain/src/device-info/device-info.repository.ts rename server/{apps/immich/src/api-v1 => libs/domain/src}/device-info/device-info.service.spec.ts (64%) create mode 100644 server/libs/domain/src/device-info/device-info.service.ts create mode 100644 server/libs/domain/src/device-info/dto/index.ts rename server/{apps/immich/src/api-v1 => libs/domain/src}/device-info/dto/upsert-device-info.dto.ts (86%) create mode 100644 server/libs/domain/src/device-info/index.ts rename server/{apps/immich/src/api-v1 => libs/domain/src}/device-info/response-dto/device-info-response.dto.ts (89%) create mode 100644 server/libs/domain/src/device-info/response-dto/index.ts create mode 100644 server/libs/domain/test/device-info.repository.mock.ts create mode 100644 server/libs/infra/src/db/repository/device-info.repository.ts diff --git a/server/apps/immich/src/api-v1/device-info/device-info.controller.ts b/server/apps/immich/src/api-v1/device-info/device-info.controller.ts deleted file mode 100644 index 779b3fbe91..0000000000 --- a/server/apps/immich/src/api-v1/device-info/device-info.controller.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Body, Controller, Put, ValidationPipe } from '@nestjs/common'; -import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; -import { AuthUserDto, GetAuthUser } from '../../decorators/auth-user.decorator'; -import { Authenticated } from '../../decorators/authenticated.decorator'; -import { DeviceInfoService } from './device-info.service'; -import { UpsertDeviceInfoDto } from './dto/upsert-device-info.dto'; -import { DeviceInfoResponseDto, mapDeviceInfoResponse } from './response-dto/device-info-response.dto'; - -@Authenticated() -@ApiBearerAuth() -@ApiTags('Device Info') -@Controller('device-info') -export class DeviceInfoController { - constructor(private readonly deviceInfoService: DeviceInfoService) {} - - @Put() - public async upsertDeviceInfo( - @GetAuthUser() user: AuthUserDto, - @Body(ValidationPipe) dto: UpsertDeviceInfoDto, - ): Promise { - const deviceInfo = await this.deviceInfoService.upsert({ ...dto, userId: user.id }); - return mapDeviceInfoResponse(deviceInfo); - } -} diff --git a/server/apps/immich/src/api-v1/device-info/device-info.module.ts b/server/apps/immich/src/api-v1/device-info/device-info.module.ts deleted file mode 100644 index b2982ceba9..0000000000 --- a/server/apps/immich/src/api-v1/device-info/device-info.module.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Module } from '@nestjs/common'; -import { DeviceInfoService } from './device-info.service'; -import { DeviceInfoController } from './device-info.controller'; -import { TypeOrmModule } from '@nestjs/typeorm'; -import { DeviceInfoEntity } from '@app/infra'; - -@Module({ - imports: [TypeOrmModule.forFeature([DeviceInfoEntity])], - controllers: [DeviceInfoController], - providers: [DeviceInfoService], -}) -export class DeviceInfoModule {} diff --git a/server/apps/immich/src/api-v1/device-info/device-info.service.ts b/server/apps/immich/src/api-v1/device-info/device-info.service.ts deleted file mode 100644 index 4c28d0b746..0000000000 --- a/server/apps/immich/src/api-v1/device-info/device-info.service.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { DeviceInfoEntity } from '@app/infra'; -import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; -import { Repository } from 'typeorm'; - -type EntityKeys = Pick; -type Entity = EntityKeys & Partial; - -@Injectable() -export class DeviceInfoService { - constructor( - @InjectRepository(DeviceInfoEntity) - private repository: Repository, - ) {} - - public async upsert(entity: Entity): Promise { - const { deviceId, userId } = entity; - const exists = await this.repository.findOne({ where: { userId, deviceId } }); - - if (!exists) { - if (!entity.isAutoBackup) { - entity.isAutoBackup = false; - } - return await this.repository.save(entity); - } - - exists.isAutoBackup = entity.isAutoBackup ?? exists.isAutoBackup; - exists.deviceType = entity.deviceType ?? exists.deviceType; - return await this.repository.save(exists); - } -} diff --git a/server/apps/immich/src/app.module.ts b/server/apps/immich/src/app.module.ts index 7b75fb546c..37f47dca78 100644 --- a/server/apps/immich/src/app.module.ts +++ b/server/apps/immich/src/app.module.ts @@ -1,7 +1,6 @@ import { immichAppConfig } from '@app/common/config'; import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common'; import { AssetModule } from './api-v1/asset/asset.module'; -import { DeviceInfoModule } from './api-v1/device-info/device-info.module'; import { ConfigModule } from '@nestjs/config'; import { ServerInfoModule } from './api-v1/server-info/server-info.module'; import { CommunicationModule } from './api-v1/communication/communication.module'; @@ -16,6 +15,7 @@ import { InfraModule } from '@app/infra'; import { APIKeyController, AuthController, + DeviceInfoController, OAuthController, ShareController, SystemConfigController, @@ -34,8 +34,6 @@ import { AuthGuard } from './middlewares/auth.guard'; AssetModule, - DeviceInfoModule, - ServerInfoModule, CommunicationModule, @@ -55,6 +53,7 @@ import { AuthGuard } from './middlewares/auth.guard'; AppController, APIKeyController, AuthController, + DeviceInfoController, OAuthController, ShareController, SystemConfigController, diff --git a/server/apps/immich/src/controllers/device-info.controller.ts b/server/apps/immich/src/controllers/device-info.controller.ts new file mode 100644 index 0000000000..7b2b5e8adb --- /dev/null +++ b/server/apps/immich/src/controllers/device-info.controller.ts @@ -0,0 +1,23 @@ +import { + AuthUserDto, + DeviceInfoResponseDto as ResponseDto, + DeviceInfoService, + UpsertDeviceInfoDto as UpsertDto, +} from '@app/domain'; +import { Body, Controller, Put, ValidationPipe } from '@nestjs/common'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { GetAuthUser } from '../decorators/auth-user.decorator'; +import { Authenticated } from '../decorators/authenticated.decorator'; + +@Authenticated() +@ApiBearerAuth() +@ApiTags('Device Info') +@Controller('device-info') +export class DeviceInfoController { + constructor(private readonly service: DeviceInfoService) {} + + @Put() + upsertDeviceInfo(@GetAuthUser() authUser: AuthUserDto, @Body(ValidationPipe) dto: UpsertDto): Promise { + return this.service.upsert(authUser, dto); + } +} diff --git a/server/apps/immich/src/controllers/index.ts b/server/apps/immich/src/controllers/index.ts index 44498d3c3c..d09e5687d6 100644 --- a/server/apps/immich/src/controllers/index.ts +++ b/server/apps/immich/src/controllers/index.ts @@ -1,5 +1,6 @@ export * from './api-key.controller'; export * from './auth.controller'; +export * from './device-info.controller'; export * from './oauth.controller'; export * from './share.controller'; export * from './system-config.controller'; diff --git a/server/immich-openapi-specs.json b/server/immich-openapi-specs.json index d3ed92ad09..8b8055fb9b 100644 --- a/server/immich-openapi-specs.json +++ b/server/immich-openapi-specs.json @@ -301,6 +301,43 @@ ] } }, + "/device-info": { + "put": { + "operationId": "upsertDeviceInfo", + "description": "", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpsertDeviceInfoDto" + } + } + } + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeviceInfoResponseDto" + } + } + } + } + }, + "tags": [ + "Device Info" + ], + "security": [ + { + "bearer": [] + } + ] + } + }, "/oauth/mobile-redirect": { "get": { "operationId": "mobileRedirect", @@ -2505,43 +2542,6 @@ ] } }, - "/device-info": { - "put": { - "operationId": "upsertDeviceInfo", - "description": "", - "parameters": [], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpsertDeviceInfoDto" - } - } - } - }, - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeviceInfoResponseDto" - } - } - } - } - }, - "tags": [ - "Device Info" - ], - "security": [ - { - "bearer": [] - } - ] - } - }, "/server-info": { "get": { "operationId": "getServerInfo", @@ -2993,6 +2993,63 @@ "redirectUri" ] }, + "DeviceTypeEnum": { + "type": "string", + "enum": [ + "IOS", + "ANDROID", + "WEB" + ] + }, + "UpsertDeviceInfoDto": { + "type": "object", + "properties": { + "deviceType": { + "$ref": "#/components/schemas/DeviceTypeEnum" + }, + "deviceId": { + "type": "string" + }, + "isAutoBackup": { + "type": "boolean" + } + }, + "required": [ + "deviceType", + "deviceId" + ] + }, + "DeviceInfoResponseDto": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "deviceType": { + "$ref": "#/components/schemas/DeviceTypeEnum" + }, + "userId": { + "type": "string" + }, + "deviceId": { + "type": "string" + }, + "createdAt": { + "type": "string" + }, + "isAutoBackup": { + "type": "boolean" + } + }, + "required": [ + "id", + "deviceType", + "userId", + "deviceId", + "createdAt", + "isAutoBackup" + ] + }, "OAuthConfigDto": { "type": "object", "properties": { @@ -4265,63 +4322,6 @@ "albumId" ] }, - "DeviceTypeEnum": { - "type": "string", - "enum": [ - "IOS", - "ANDROID", - "WEB" - ] - }, - "UpsertDeviceInfoDto": { - "type": "object", - "properties": { - "deviceType": { - "$ref": "#/components/schemas/DeviceTypeEnum" - }, - "deviceId": { - "type": "string" - }, - "isAutoBackup": { - "type": "boolean" - } - }, - "required": [ - "deviceType", - "deviceId" - ] - }, - "DeviceInfoResponseDto": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "deviceType": { - "$ref": "#/components/schemas/DeviceTypeEnum" - }, - "userId": { - "type": "string" - }, - "deviceId": { - "type": "string" - }, - "createdAt": { - "type": "string" - }, - "isAutoBackup": { - "type": "boolean" - } - }, - "required": [ - "id", - "deviceType", - "userId", - "deviceId", - "createdAt", - "isAutoBackup" - ] - }, "ServerInfoResponseDto": { "type": "object", "properties": { diff --git a/server/libs/domain/src/device-info/device-info.core.ts b/server/libs/domain/src/device-info/device-info.core.ts new file mode 100644 index 0000000000..dc1cf727b9 --- /dev/null +++ b/server/libs/domain/src/device-info/device-info.core.ts @@ -0,0 +1,23 @@ +import { DeviceInfoEntity } from '@app/infra/db/entities'; +import { IDeviceInfoRepository } from './device-info.repository'; + +type UpsertKeys = Pick; +type UpsertEntity = UpsertKeys & Partial; + +export class DeviceInfoCore { + constructor(private repository: IDeviceInfoRepository) {} + + async upsert(entity: UpsertEntity) { + const exists = await this.repository.get(entity.userId, entity.deviceId); + if (!exists) { + if (!entity.isAutoBackup) { + entity.isAutoBackup = false; + } + return this.repository.save(entity); + } + + exists.isAutoBackup = entity.isAutoBackup ?? exists.isAutoBackup; + exists.deviceType = entity.deviceType ?? exists.deviceType; + return this.repository.save(exists); + } +} diff --git a/server/libs/domain/src/device-info/device-info.repository.ts b/server/libs/domain/src/device-info/device-info.repository.ts new file mode 100644 index 0000000000..5a48cc8c0c --- /dev/null +++ b/server/libs/domain/src/device-info/device-info.repository.ts @@ -0,0 +1,8 @@ +import { DeviceInfoEntity } from '@app/infra/db/entities'; + +export const IDeviceInfoRepository = 'IDeviceInfoRepository'; + +export interface IDeviceInfoRepository { + get(userId: string, deviceId: string): Promise; + save(entity: Partial): Promise; +} diff --git a/server/apps/immich/src/api-v1/device-info/device-info.service.spec.ts b/server/libs/domain/src/device-info/device-info.service.spec.ts similarity index 64% rename from server/apps/immich/src/api-v1/device-info/device-info.service.spec.ts rename to server/libs/domain/src/device-info/device-info.service.spec.ts index 565e38872b..784b6682a8 100644 --- a/server/apps/immich/src/api-v1/device-info/device-info.service.spec.ts +++ b/server/libs/domain/src/device-info/device-info.service.spec.ts @@ -1,5 +1,6 @@ import { DeviceInfoEntity, DeviceType } from '@app/infra'; -import { Repository } from 'typeorm'; +import { authStub, newDeviceInfoRepositoryMock } from '../../test'; +import { IDeviceInfoRepository } from './device-info.repository'; import { DeviceInfoService } from './device-info.service'; const deviceId = 'device-123'; @@ -7,13 +8,10 @@ const userId = 'user-123'; describe('DeviceInfoService', () => { let sut: DeviceInfoService; - let repositoryMock: jest.Mocked>; + let repositoryMock: jest.Mocked; beforeEach(async () => { - repositoryMock = { - findOne: jest.fn(), - save: jest.fn(), - } as unknown as jest.Mocked>; + repositoryMock = newDeviceInfoRepositoryMock(); sut = new DeviceInfoService(repositoryMock); }); @@ -27,12 +25,12 @@ describe('DeviceInfoService', () => { const request = { deviceId, userId, deviceType: DeviceType.IOS } as DeviceInfoEntity; const response = { ...request, id: 1 } as DeviceInfoEntity; - repositoryMock.findOne.mockResolvedValue(null); + repositoryMock.get.mockResolvedValue(null); repositoryMock.save.mockResolvedValue(response); - await expect(sut.upsert(request)).resolves.toEqual(response); + await expect(sut.upsert(authStub.user1, request)).resolves.toEqual(response); - expect(repositoryMock.findOne).toHaveBeenCalledTimes(1); + expect(repositoryMock.get).toHaveBeenCalledTimes(1); expect(repositoryMock.save).toHaveBeenCalledTimes(1); }); @@ -40,12 +38,12 @@ describe('DeviceInfoService', () => { const request = { deviceId, userId, deviceType: DeviceType.IOS, isAutoBackup: true } as DeviceInfoEntity; const response = { ...request, id: 1 } as DeviceInfoEntity; - repositoryMock.findOne.mockResolvedValue(response); + repositoryMock.get.mockResolvedValue(response); repositoryMock.save.mockResolvedValue(response); - await expect(sut.upsert(request)).resolves.toEqual(response); + await expect(sut.upsert(authStub.user1, request)).resolves.toEqual(response); - expect(repositoryMock.findOne).toHaveBeenCalledTimes(1); + expect(repositoryMock.get).toHaveBeenCalledTimes(1); expect(repositoryMock.save).toHaveBeenCalledTimes(1); }); @@ -53,12 +51,12 @@ describe('DeviceInfoService', () => { const request = { deviceId, userId } as DeviceInfoEntity; const response = { id: 1, isAutoBackup: true, deviceId, userId, deviceType: DeviceType.WEB } as DeviceInfoEntity; - repositoryMock.findOne.mockResolvedValue(response); + repositoryMock.get.mockResolvedValue(response); repositoryMock.save.mockResolvedValue(response); - await expect(sut.upsert(request)).resolves.toEqual(response); + await expect(sut.upsert(authStub.user1, request)).resolves.toEqual(response); - expect(repositoryMock.findOne).toHaveBeenCalledTimes(1); + expect(repositoryMock.get).toHaveBeenCalledTimes(1); expect(repositoryMock.save).toHaveBeenCalledTimes(1); }); }); diff --git a/server/libs/domain/src/device-info/device-info.service.ts b/server/libs/domain/src/device-info/device-info.service.ts new file mode 100644 index 0000000000..8c6cb0ef35 --- /dev/null +++ b/server/libs/domain/src/device-info/device-info.service.ts @@ -0,0 +1,20 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { AuthUserDto } from '../auth'; +import { DeviceInfoCore } from './device-info.core'; +import { IDeviceInfoRepository } from './device-info.repository'; +import { UpsertDeviceInfoDto } from './dto'; +import { DeviceInfoResponseDto, mapDeviceInfoResponse } from './response-dto'; + +@Injectable() +export class DeviceInfoService { + private core: DeviceInfoCore; + + constructor(@Inject(IDeviceInfoRepository) repository: IDeviceInfoRepository) { + this.core = new DeviceInfoCore(repository); + } + + public async upsert(authUser: AuthUserDto, dto: UpsertDeviceInfoDto): Promise { + const deviceInfo = await this.core.upsert({ ...dto, userId: authUser.id }); + return mapDeviceInfoResponse(deviceInfo); + } +} diff --git a/server/libs/domain/src/device-info/dto/index.ts b/server/libs/domain/src/device-info/dto/index.ts new file mode 100644 index 0000000000..2a270e229d --- /dev/null +++ b/server/libs/domain/src/device-info/dto/index.ts @@ -0,0 +1 @@ +export * from './upsert-device-info.dto'; diff --git a/server/apps/immich/src/api-v1/device-info/dto/upsert-device-info.dto.ts b/server/libs/domain/src/device-info/dto/upsert-device-info.dto.ts similarity index 86% rename from server/apps/immich/src/api-v1/device-info/dto/upsert-device-info.dto.ts rename to server/libs/domain/src/device-info/dto/upsert-device-info.dto.ts index 88f480255e..f764a1b7ba 100644 --- a/server/apps/immich/src/api-v1/device-info/dto/upsert-device-info.dto.ts +++ b/server/libs/domain/src/device-info/dto/upsert-device-info.dto.ts @@ -1,5 +1,5 @@ import { IsNotEmpty, IsOptional } from 'class-validator'; -import { DeviceType } from '@app/infra'; +import { DeviceType } from '@app/infra/db/entities'; import { ApiProperty } from '@nestjs/swagger'; export class UpsertDeviceInfoDto { diff --git a/server/libs/domain/src/device-info/index.ts b/server/libs/domain/src/device-info/index.ts new file mode 100644 index 0000000000..fd30bcb299 --- /dev/null +++ b/server/libs/domain/src/device-info/index.ts @@ -0,0 +1,4 @@ +export * from './device-info.repository'; +export * from './device-info.service'; +export * from './dto'; +export * from './response-dto'; diff --git a/server/apps/immich/src/api-v1/device-info/response-dto/device-info-response.dto.ts b/server/libs/domain/src/device-info/response-dto/device-info-response.dto.ts similarity index 89% rename from server/apps/immich/src/api-v1/device-info/response-dto/device-info-response.dto.ts rename to server/libs/domain/src/device-info/response-dto/device-info-response.dto.ts index 3f2d3b4455..07edb2e129 100644 --- a/server/apps/immich/src/api-v1/device-info/response-dto/device-info-response.dto.ts +++ b/server/libs/domain/src/device-info/response-dto/device-info-response.dto.ts @@ -1,4 +1,4 @@ -import { DeviceInfoEntity, DeviceType } from '@app/infra'; +import { DeviceInfoEntity, DeviceType } from '@app/infra/db/entities'; import { ApiProperty } from '@nestjs/swagger'; export class DeviceInfoResponseDto { diff --git a/server/libs/domain/src/device-info/response-dto/index.ts b/server/libs/domain/src/device-info/response-dto/index.ts new file mode 100644 index 0000000000..b8ffdeb11f --- /dev/null +++ b/server/libs/domain/src/device-info/response-dto/index.ts @@ -0,0 +1 @@ +export * from './device-info-response.dto'; diff --git a/server/libs/domain/src/domain.module.ts b/server/libs/domain/src/domain.module.ts index 1961b95a8d..273e1a60b3 100644 --- a/server/libs/domain/src/domain.module.ts +++ b/server/libs/domain/src/domain.module.ts @@ -1,6 +1,7 @@ import { DynamicModule, Global, Module, ModuleMetadata, Provider } from '@nestjs/common'; import { APIKeyService } from './api-key'; import { AuthService } from './auth'; +import { DeviceInfoService } from './device-info'; import { JobService } from './job'; import { OAuthService } from './oauth'; import { ShareService } from './share'; @@ -10,6 +11,7 @@ import { UserService } from './user'; const providers: Provider[] = [ APIKeyService, AuthService, + DeviceInfoService, JobService, OAuthService, SystemConfigService, diff --git a/server/libs/domain/src/index.ts b/server/libs/domain/src/index.ts index 5ed33f1956..3113aa1dd0 100644 --- a/server/libs/domain/src/index.ts +++ b/server/libs/domain/src/index.ts @@ -3,6 +3,7 @@ export * from './api-key'; export * from './asset'; export * from './auth'; export * from './crypto'; +export * from './device-info'; export * from './domain.module'; export * from './job'; export * from './oauth'; diff --git a/server/libs/domain/test/device-info.repository.mock.ts b/server/libs/domain/test/device-info.repository.mock.ts new file mode 100644 index 0000000000..e7aebdc341 --- /dev/null +++ b/server/libs/domain/test/device-info.repository.mock.ts @@ -0,0 +1,8 @@ +import { IDeviceInfoRepository } from '../src'; + +export const newDeviceInfoRepositoryMock = (): jest.Mocked => { + return { + get: jest.fn(), + save: jest.fn(), + }; +}; diff --git a/server/libs/domain/test/index.ts b/server/libs/domain/test/index.ts index b6a3ad7f24..dfec3ffa49 100644 --- a/server/libs/domain/test/index.ts +++ b/server/libs/domain/test/index.ts @@ -1,5 +1,6 @@ export * from './api-key.repository.mock'; export * from './crypto.repository.mock'; +export * from './device-info.repository.mock'; export * from './fixtures'; export * from './job.repository.mock'; export * from './shared-link.repository.mock'; diff --git a/server/libs/infra/src/db/repository/device-info.repository.ts b/server/libs/infra/src/db/repository/device-info.repository.ts new file mode 100644 index 0000000000..80da45fcbc --- /dev/null +++ b/server/libs/infra/src/db/repository/device-info.repository.ts @@ -0,0 +1,16 @@ +import { IDeviceInfoRepository } from '@app/domain'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { DeviceInfoEntity } from '../entities'; + +export class DeviceInfoRepository implements IDeviceInfoRepository { + constructor(@InjectRepository(DeviceInfoEntity) private repository: Repository) {} + + get(userId: string, deviceId: string): Promise { + return this.repository.findOne({ where: { userId, deviceId } }); + } + + save(entity: Partial): Promise { + return this.repository.save(entity); + } +} diff --git a/server/libs/infra/src/db/repository/index.ts b/server/libs/infra/src/db/repository/index.ts index 056c960573..e8d73b0833 100644 --- a/server/libs/infra/src/db/repository/index.ts +++ b/server/libs/infra/src/db/repository/index.ts @@ -1,4 +1,6 @@ export * from './api-key.repository'; +export * from './device-info.repository'; export * from './shared-link.repository'; -export * from './user.repository'; +export * from './system-config.repository'; export * from './user-token.repository'; +export * from './user.repository'; diff --git a/server/libs/infra/src/infra.module.ts b/server/libs/infra/src/infra.module.ts index 0f37221f2b..df16c1dfd8 100644 --- a/server/libs/infra/src/infra.module.ts +++ b/server/libs/infra/src/infra.module.ts @@ -1,5 +1,6 @@ import { ICryptoRepository, + IDeviceInfoRepository, IJobRepository, IKeyRepository, ISharedLinkRepository, @@ -7,20 +8,31 @@ import { IUserRepository, QueueName, } from '@app/domain'; -import { databaseConfig, UserEntity, UserTokenEntity } from './db'; +import { IUserTokenRepository } from '@app/domain/user-token'; +import { UserTokenRepository } from '@app/infra/db/repository/user-token.repository'; import { BullModule } from '@nestjs/bull'; import { Global, Module, Provider } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; -import { APIKeyEntity, SharedLinkEntity, SystemConfigEntity, UserRepository } from './db'; -import { APIKeyRepository, SharedLinkRepository } from './db/repository'; import { CryptoRepository } from './auth/crypto.repository'; -import { SystemConfigRepository } from './db/repository/system-config.repository'; +import { + APIKeyEntity, + APIKeyRepository, + databaseConfig, + DeviceInfoEntity, + DeviceInfoRepository, + SharedLinkEntity, + SharedLinkRepository, + SystemConfigEntity, + SystemConfigRepository, + UserEntity, + UserRepository, + UserTokenEntity, +} from './db'; import { JobRepository } from './job'; -import { IUserTokenRepository } from '@app/domain/user-token'; -import { UserTokenRepository } from '@app/infra/db/repository/user-token.repository'; const providers: Provider[] = [ { provide: ICryptoRepository, useClass: CryptoRepository }, + { provide: IDeviceInfoRepository, useClass: DeviceInfoRepository }, { provide: IKeyRepository, useClass: APIKeyRepository }, { provide: IJobRepository, useClass: JobRepository }, { provide: ISharedLinkRepository, useClass: SharedLinkRepository }, @@ -33,7 +45,14 @@ const providers: Provider[] = [ @Module({ imports: [ TypeOrmModule.forRoot(databaseConfig), - TypeOrmModule.forFeature([APIKeyEntity, UserEntity, SharedLinkEntity, SystemConfigEntity, UserTokenEntity]), + TypeOrmModule.forFeature([ + APIKeyEntity, + DeviceInfoEntity, + UserEntity, + SharedLinkEntity, + SystemConfigEntity, + UserTokenEntity, + ]), BullModule.forRootAsync({ useFactory: async () => ({ prefix: 'immich_bull',