diff --git a/server/src/controllers/duplicate.controller.ts b/server/src/controllers/duplicate.controller.ts index ecabc0ee74..57a200ac39 100644 --- a/server/src/controllers/duplicate.controller.ts +++ b/server/src/controllers/duplicate.controller.ts @@ -1,7 +1,7 @@ import { Controller, Get } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; -import { AssetResponseDto } from 'src/dtos/asset-response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; +import { DuplicateResponseDto } from 'src/dtos/duplicate.dto'; import { Auth, Authenticated } from 'src/middleware/auth.guard'; import { DuplicateService } from 'src/services/duplicate.service'; @@ -12,7 +12,7 @@ export class DuplicateController { @Get() @Authenticated() - getAssetDuplicates(@Auth() auth: AuthDto): Promise { + getAssetDuplicates(@Auth() auth: AuthDto): Promise { return this.service.getDuplicates(auth); } } diff --git a/server/src/dtos/asset-response.dto.ts b/server/src/dtos/asset-response.dto.ts index 0afc906c95..879d358e8e 100644 --- a/server/src/dtos/asset-response.dto.ts +++ b/server/src/dtos/asset-response.dto.ts @@ -50,6 +50,7 @@ export class AssetResponseDto extends SanitizedAssetResponseDto { stack?: AssetResponseDto[]; @ApiProperty({ type: 'integer' }) stackCount!: number | null; + duplicateId?: string | null; } export type AssetMapOptions = { @@ -130,6 +131,7 @@ export function mapAsset(entity: AssetEntity, options: AssetMapOptions = {}): As isExternal: false, isReadOnly: false, hasMetadata: true, + duplicateId: entity.duplicateId, }; } diff --git a/server/src/dtos/duplicate.dto.ts b/server/src/dtos/duplicate.dto.ts new file mode 100644 index 0000000000..cdfeed056f --- /dev/null +++ b/server/src/dtos/duplicate.dto.ts @@ -0,0 +1,19 @@ +import { groupBy } from 'lodash'; +import { AssetResponseDto } from 'src/dtos/asset-response.dto'; + +export class DuplicateResponseDto { + duplicateId!: string; + assets!: AssetResponseDto[]; +} + +export function mapDuplicateResponse(assets: AssetResponseDto[]): DuplicateResponseDto[] { + const result = []; + + const grouped = groupBy(assets, (a) => a.duplicateId); + + for (const [duplicateId, assets] of Object.entries(grouped)) { + result.push({ duplicateId, assets }); + } + + return result; +} diff --git a/server/src/services/duplicate.service.ts b/server/src/services/duplicate.service.ts index a01e1b866a..95a12bd18e 100644 --- a/server/src/services/duplicate.service.ts +++ b/server/src/services/duplicate.service.ts @@ -1,7 +1,8 @@ import { Inject, Injectable } from '@nestjs/common'; import { SystemConfigCore } from 'src/cores/system-config.core'; -import { AssetResponseDto, mapAsset } from 'src/dtos/asset-response.dto'; +import { mapAsset } from 'src/dtos/asset-response.dto'; import { AuthDto } from 'src/dtos/auth.dto'; +import { DuplicateResponseDto, mapDuplicateResponse } from 'src/dtos/duplicate.dto'; import { AssetEntity } from 'src/entities/asset.entity'; import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface'; import { ICryptoRepository } from 'src/interfaces/crypto.interface'; @@ -35,9 +36,10 @@ export class DuplicateService { this.configCore = SystemConfigCore.create(systemMetadataRepository, logger); } - async getDuplicates(auth: AuthDto): Promise { + async getDuplicates(auth: AuthDto): Promise { const res = await this.assetRepository.getDuplicates({ userIds: [auth.user.id] }); - return res.map((a) => mapAsset(a, { auth })); + + return mapDuplicateResponse(res.map((a) => mapAsset(a, { auth }))); } async handleQueueSearchDuplicates({ force }: IBaseJob): Promise {