chore!: migrate album owner to album_user (#27467)

Co-authored-by: mertalev <101130780+mertalev@users.noreply.github.com>
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
This commit is contained in:
Daniel Dietzler
2026-04-22 16:52:23 +02:00
committed by GitHub
parent dfacde5af8
commit 4bfb8b36c2
75 changed files with 14750 additions and 1104 deletions
+9 -13
View File
@@ -1,7 +1,6 @@
import { ShallowDehydrateObject } from 'kysely';
import _ from 'lodash';
import { createZodDto } from 'nestjs-zod';
import { AlbumUser, AuthSharedLink, User } from 'src/database';
import { AlbumUser, AuthSharedLink } from 'src/database';
import { BulkIdErrorReasonSchema } from 'src/dtos/asset-ids.response.dto';
import { MapAsset } from 'src/dtos/asset-response.dto';
import { UserResponseSchema, mapUser } from 'src/dtos/user.dto';
@@ -104,7 +103,6 @@ const ContributorCountResponseSchema = z
export const AlbumResponseSchema = z
.object({
id: z.string().describe('Album ID'),
ownerId: z.string().describe('Owner user ID'),
albumName: z.string().describe('Album name'),
description: z.string().describe('Album description'),
// TODO: use `isoDatetimeToDate` when using `ZodSerializerDto` on the controllers.
@@ -113,9 +111,13 @@ export const AlbumResponseSchema = z
updatedAt: z.string().meta({ format: 'date-time' }).describe('Last update date'),
albumThumbnailAssetId: z.string().nullable().describe('Thumbnail asset ID'),
shared: z.boolean().describe('Is shared album'),
albumUsers: z.array(AlbumUserResponseSchema),
albumUsers: z
.array(AlbumUserResponseSchema)
.min(1)
.describe(
'First entry is always the album owner. Second entry is the auth user, if it differs from the owner. The rest are ordered alphabetically.',
),
hasSharedLink: z.boolean().describe('Has shared link'),
owner: UserResponseSchema,
assetCount: z.int().min(0).describe('Number of assets'),
// TODO: use `isoDatetimeToDate` when using `ZodSerializerDto` on the controllers.
lastModifiedAssetTimestamp: z
@@ -155,8 +157,6 @@ export type MapAlbumDto = {
createdAt: Date;
updatedAt: Date;
id: string;
ownerId: string;
owner: ShallowDehydrateObject<User>;
isActivityEnabled: boolean;
order: AssetOrder;
};
@@ -174,12 +174,10 @@ export const mapAlbum = (entity: MaybeDehydrated<MapAlbumDto>): AlbumResponseDto
}
}
const albumUsersSorted = _.orderBy(albumUsers, ['role', 'user.name']);
const assets = entity.assets || [];
const hasSharedLink = !!entity.sharedLinks && entity.sharedLinks.length > 0;
const hasSharedUser = albumUsers.length > 0;
const hasSharedUser = albumUsers.length > 1;
let startDate = assets.at(0)?.localDateTime;
let endDate = assets.at(-1)?.localDateTime;
@@ -195,9 +193,7 @@ export const mapAlbum = (entity: MaybeDehydrated<MapAlbumDto>): AlbumResponseDto
createdAt: asDateString(entity.createdAt),
updatedAt: asDateString(entity.updatedAt),
id: entity.id,
ownerId: entity.ownerId,
owner: mapUser(entity.owner),
albumUsers: albumUsersSorted,
albumUsers,
shared: hasSharedUser || hasSharedLink,
hasSharedLink,
startDate: asDateString(startDate),
+26
View File
@@ -2,6 +2,7 @@
import { createZodDto } from 'nestjs-zod';
import { AssetEditActionSchema } from 'src/dtos/editing.dto';
import {
AlbumUserRole,
AlbumUserRoleSchema,
AssetOrderSchema,
AssetTypeSchema,
@@ -211,6 +212,19 @@ const SyncAlbumV1Schema = z
})
.meta({ id: 'SyncAlbumV1' });
const SyncAlbumV2Schema = z
.object({
id: z.string().describe('Album ID'),
name: z.string().describe('Album name'),
description: z.string().describe('Album description'),
createdAt: isoDatetimeToDate.describe('Created at'),
updatedAt: isoDatetimeToDate.describe('Updated at'),
thumbnailAssetId: z.string().nullable().describe('Thumbnail asset ID'),
isActivityEnabled: z.boolean().describe('Is activity enabled'),
order: AssetOrderSchema,
})
.meta({ id: 'SyncAlbumV2' });
const SyncAlbumToAssetV1Schema = z
.object({
albumId: z.string().describe('Album ID'),
@@ -234,10 +248,21 @@ class SyncAlbumUserV1 extends createZodDto(SyncAlbumUserV1Schema) {}
@ExtraModel()
class SyncAlbumV1 extends createZodDto(SyncAlbumV1Schema) {}
@ExtraModel()
class SyncAlbumV2 extends createZodDto(SyncAlbumV2Schema) {}
@ExtraModel()
class SyncAlbumToAssetV1 extends createZodDto(SyncAlbumToAssetV1Schema) {}
@ExtraModel()
class SyncAlbumToAssetDeleteV1 extends createZodDto(SyncAlbumToAssetDeleteV1Schema) {}
export function syncAlbumV2ToV1(
albumV2: SyncAlbumV2,
albumUsers: { userId: string; role: AlbumUserRole }[],
): SyncAlbumV1 {
const owner = albumUsers.find(({ role }) => role === AlbumUserRole.Owner)!;
return { ...albumV2, ownerId: owner.userId };
}
const SyncMemoryV1Schema = z
.object({
id: z.string().describe('Memory ID'),
@@ -407,6 +432,7 @@ export type SyncItem = {
[SyncEntityType.PartnerAssetExifV1]: SyncAssetExifV1;
[SyncEntityType.PartnerAssetExifBackfillV1]: SyncAssetExifV1;
[SyncEntityType.AlbumV1]: SyncAlbumV1;
[SyncEntityType.AlbumV2]: SyncAlbumV2;
[SyncEntityType.AlbumDeleteV1]: SyncAlbumDeleteV1;
[SyncEntityType.AlbumUserV1]: SyncAlbumUserV1;
[SyncEntityType.AlbumUserBackfillV1]: SyncAlbumUserV1;