feat(server): memory includes partners assets on timeline (#7993)

* feat(server): memory includes partners assets on timeline

* remove unsued code, generate sql

* fix test

* add test
This commit is contained in:
Alex 2024-03-18 14:46:52 -05:00 committed by GitHub
parent cd8a124b25
commit 761e7fdd2d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 28 additions and 89 deletions

View File

@ -15,6 +15,8 @@ import {
newStorageRepositoryMock,
newSystemConfigRepositoryMock,
newUserRepositoryMock,
partnerStub,
userStub,
} from '@test';
import { when } from 'jest-when';
import { JobName } from '../job';
@ -317,6 +319,7 @@ describe(AssetService.name, () => {
});
it('should set the title correctly', async () => {
partnerMock.getAll.mockResolvedValue([]);
assetMock.getByDayOfYear.mockResolvedValue([assetStub.image, assetStub.imageFrom2015]);
await expect(sut.getMemoryLane(authStub.admin, { day: 15, month: 1 })).resolves.toEqual([
@ -324,7 +327,17 @@ describe(AssetService.name, () => {
{ title: '9 years since...', assets: [mapAsset(assetStub.imageFrom2015)] },
]);
expect(assetMock.getByDayOfYear.mock.calls).toEqual([[authStub.admin.user.id, { day: 15, month: 1 }]]);
expect(assetMock.getByDayOfYear.mock.calls).toEqual([[[authStub.admin.user.id], { day: 15, month: 1 }]]);
});
it('should get memories with partners with inTimeline enabled', async () => {
partnerMock.getAll.mockResolvedValue([partnerStub.user1ToAdmin1]);
await sut.getMemoryLane(authStub.admin, { day: 15, month: 1 });
expect(assetMock.getByDayOfYear.mock.calls).toEqual([
[[authStub.admin.user.id, userStub.user1.id], { day: 15, month: 1 }],
]);
});
});

View File

@ -172,7 +172,16 @@ export class AssetService {
async getMemoryLane(auth: AuthDto, dto: MemoryLaneDto): Promise<MemoryLaneResponseDto[]> {
const currentYear = new Date().getFullYear();
const assets = await this.assetRepository.getByDayOfYear(auth.user.id, dto);
// get partners id
const userIds: string[] = [auth.user.id];
const partners = await this.partnerRepository.getAll(auth.user.id);
const partnersIds = partners
.filter((partner) => partner.sharedBy && partner.inTimeline)
.map((partner) => partner.sharedById);
userIds.push(...partnersIds);
const assets = await this.assetRepository.getByDayOfYear(userIds, dto);
return _.chain(assets)
.filter((asset) => asset.localDateTime.getFullYear() < currentYear)

View File

@ -123,7 +123,7 @@ export interface IAssetRepository {
select?: FindOptionsSelect<AssetEntity>,
): Promise<AssetEntity[]>;
getByIdsWithAllRelations(ids: string[]): Promise<AssetEntity[]>;
getByDayOfYear(ownerId: string, monthDay: MonthDay): Promise<AssetEntity[]>;
getByDayOfYear(ownerIds: string[], monthDay: MonthDay): Promise<AssetEntity[]>;
getByChecksum(userId: string, checksum: Buffer): Promise<AssetEntity | null>;
getByAlbumId(pagination: PaginationOptions, albumId: string): Paginated<AssetEntity>;
getByUserId(pagination: PaginationOptions, userId: string, options?: AssetSearchOptions): Paginated<AssetEntity>;

View File

@ -109,18 +109,18 @@ export class AssetRepository implements IAssetRepository {
}
@GenerateSql({ params: [DummyValue.UUID, { day: 1, month: 1 }] })
getByDayOfYear(ownerId: string, { day, month }: MonthDay): Promise<AssetEntity[]> {
getByDayOfYear(ownerIds: string[], { day, month }: MonthDay): Promise<AssetEntity[]> {
return this.repository
.createQueryBuilder('entity')
.where(
`entity.ownerId = :ownerId
`entity.ownerId IN (:...ownerIds)
AND entity.isVisible = true
AND entity.isArchived = false
AND entity.resizePath IS NOT NULL
AND EXTRACT(DAY FROM entity.localDateTime AT TIME ZONE 'UTC') = :day
AND EXTRACT(MONTH FROM entity.localDateTime AT TIME ZONE 'UTC') = :month`,
{
ownerId,
ownerIds,
day,
month,
},

View File

@ -76,89 +76,6 @@ WHERE
ORDER BY
"AssetEntity"."fileCreatedAt" DESC
-- AssetRepository.getByDayOfYear
SELECT
"entity"."id" AS "entity_id",
"entity"."deviceAssetId" AS "entity_deviceAssetId",
"entity"."ownerId" AS "entity_ownerId",
"entity"."libraryId" AS "entity_libraryId",
"entity"."deviceId" AS "entity_deviceId",
"entity"."type" AS "entity_type",
"entity"."originalPath" AS "entity_originalPath",
"entity"."resizePath" AS "entity_resizePath",
"entity"."webpPath" AS "entity_webpPath",
"entity"."thumbhash" AS "entity_thumbhash",
"entity"."encodedVideoPath" AS "entity_encodedVideoPath",
"entity"."createdAt" AS "entity_createdAt",
"entity"."updatedAt" AS "entity_updatedAt",
"entity"."deletedAt" AS "entity_deletedAt",
"entity"."fileCreatedAt" AS "entity_fileCreatedAt",
"entity"."localDateTime" AS "entity_localDateTime",
"entity"."fileModifiedAt" AS "entity_fileModifiedAt",
"entity"."isFavorite" AS "entity_isFavorite",
"entity"."isArchived" AS "entity_isArchived",
"entity"."isExternal" AS "entity_isExternal",
"entity"."isReadOnly" AS "entity_isReadOnly",
"entity"."isOffline" AS "entity_isOffline",
"entity"."checksum" AS "entity_checksum",
"entity"."duration" AS "entity_duration",
"entity"."isVisible" AS "entity_isVisible",
"entity"."livePhotoVideoId" AS "entity_livePhotoVideoId",
"entity"."originalFileName" AS "entity_originalFileName",
"entity"."sidecarPath" AS "entity_sidecarPath",
"entity"."stackId" AS "entity_stackId",
"exifInfo"."assetId" AS "exifInfo_assetId",
"exifInfo"."description" AS "exifInfo_description",
"exifInfo"."exifImageWidth" AS "exifInfo_exifImageWidth",
"exifInfo"."exifImageHeight" AS "exifInfo_exifImageHeight",
"exifInfo"."fileSizeInByte" AS "exifInfo_fileSizeInByte",
"exifInfo"."orientation" AS "exifInfo_orientation",
"exifInfo"."dateTimeOriginal" AS "exifInfo_dateTimeOriginal",
"exifInfo"."modifyDate" AS "exifInfo_modifyDate",
"exifInfo"."timeZone" AS "exifInfo_timeZone",
"exifInfo"."latitude" AS "exifInfo_latitude",
"exifInfo"."longitude" AS "exifInfo_longitude",
"exifInfo"."projectionType" AS "exifInfo_projectionType",
"exifInfo"."city" AS "exifInfo_city",
"exifInfo"."livePhotoCID" AS "exifInfo_livePhotoCID",
"exifInfo"."autoStackId" AS "exifInfo_autoStackId",
"exifInfo"."state" AS "exifInfo_state",
"exifInfo"."country" AS "exifInfo_country",
"exifInfo"."make" AS "exifInfo_make",
"exifInfo"."model" AS "exifInfo_model",
"exifInfo"."lensModel" AS "exifInfo_lensModel",
"exifInfo"."fNumber" AS "exifInfo_fNumber",
"exifInfo"."focalLength" AS "exifInfo_focalLength",
"exifInfo"."iso" AS "exifInfo_iso",
"exifInfo"."exposureTime" AS "exifInfo_exposureTime",
"exifInfo"."profileDescription" AS "exifInfo_profileDescription",
"exifInfo"."colorspace" AS "exifInfo_colorspace",
"exifInfo"."bitsPerSample" AS "exifInfo_bitsPerSample",
"exifInfo"."fps" AS "exifInfo_fps"
FROM
"assets" "entity"
LEFT JOIN "exif" "exifInfo" ON "exifInfo"."assetId" = "entity"."id"
WHERE
(
"entity"."ownerId" = $1
AND "entity"."isVisible" = true
AND "entity"."isArchived" = false
AND "entity"."resizePath" IS NOT NULL
AND EXTRACT(
DAY
FROM
"entity"."localDateTime" AT TIME ZONE 'UTC'
) = $2
AND EXTRACT(
MONTH
FROM
"entity"."localDateTime" AT TIME ZONE 'UTC'
) = $3
)
AND ("entity"."deletedAt" IS NULL)
ORDER BY
"entity"."localDateTime" DESC
-- AssetRepository.getByIds
SELECT
"AssetEntity"."id" AS "AssetEntity_id",