fix(server): include album owner for album shared links (#31990)
fix(server): include album owner for album shared links (#31837) (cherry picked from commit fd97f3e5a62a4af1a8e17d2e766eb952eefae24a) Co-authored-by: Mees Frensel <33722705+meesfrensel@users.noreply.github.com>
This commit is contained in:
co-authored by
Mees Frensel
parent
882da7cab8
commit
843051f0f5
@@ -64,6 +64,40 @@ from
|
||||
left join lateral (
|
||||
select
|
||||
"album".*,
|
||||
(
|
||||
select
|
||||
coalesce(json_agg(agg), '[]')
|
||||
from
|
||||
(
|
||||
select
|
||||
"album_user"."role",
|
||||
(
|
||||
select
|
||||
to_json(obj)
|
||||
from
|
||||
(
|
||||
select
|
||||
"id",
|
||||
"name",
|
||||
"email",
|
||||
"avatarColor",
|
||||
"profileImagePath",
|
||||
"profileChangedAt"
|
||||
from
|
||||
(
|
||||
select
|
||||
1
|
||||
) as "dummy"
|
||||
) as obj
|
||||
) as "user"
|
||||
from
|
||||
"album_user"
|
||||
inner join "user" on "user"."id" = "album_user"."userId"
|
||||
where
|
||||
"album_user"."role" = 'owner'
|
||||
and "album_user"."albumId" = "album"."id"
|
||||
) as agg
|
||||
) as "albumUsers",
|
||||
coalesce(
|
||||
json_agg(
|
||||
"assets"
|
||||
@@ -74,8 +108,7 @@ from
|
||||
"assets"."id" is not null
|
||||
),
|
||||
'[]'
|
||||
) as "assets",
|
||||
to_json("owner") as "owner"
|
||||
) as "assets"
|
||||
from
|
||||
"album"
|
||||
left join "album_asset" on "album_asset"."albumId" = "album"."id"
|
||||
@@ -128,34 +161,11 @@ from
|
||||
order by
|
||||
"asset"."fileCreatedAt" asc
|
||||
) as "assets" on true
|
||||
inner join lateral (
|
||||
select
|
||||
"id",
|
||||
"name",
|
||||
"email",
|
||||
"avatarColor",
|
||||
"profileImagePath",
|
||||
"profileChangedAt"
|
||||
from
|
||||
"user"
|
||||
where
|
||||
exists (
|
||||
select
|
||||
from
|
||||
"album_user"
|
||||
where
|
||||
"album_user"."role" = 'owner'
|
||||
and "album_user"."albumId" = "album"."id"
|
||||
and "album_user"."userId" = "user"."id"
|
||||
)
|
||||
and "user"."deletedAt" is null
|
||||
) as "owner" on true
|
||||
where
|
||||
"album"."id" = "shared_link"."albumId"
|
||||
and "album"."deletedAt" is null
|
||||
group by
|
||||
"album"."id",
|
||||
"owner".*
|
||||
"album"."id"
|
||||
) as "album" on true
|
||||
where
|
||||
"shared_link"."id" = $1
|
||||
@@ -195,31 +205,42 @@ from
|
||||
left join lateral (
|
||||
select
|
||||
"album".*,
|
||||
to_json("owner") as "owner"
|
||||
from
|
||||
"album"
|
||||
inner join lateral (
|
||||
(
|
||||
select
|
||||
"id",
|
||||
"name",
|
||||
"email",
|
||||
"avatarColor",
|
||||
"profileImagePath",
|
||||
"profileChangedAt"
|
||||
coalesce(json_agg(agg), '[]')
|
||||
from
|
||||
"user"
|
||||
where
|
||||
exists (
|
||||
(
|
||||
select
|
||||
"album_user"."role",
|
||||
(
|
||||
select
|
||||
to_json(obj)
|
||||
from
|
||||
(
|
||||
select
|
||||
"id",
|
||||
"name",
|
||||
"email",
|
||||
"avatarColor",
|
||||
"profileImagePath",
|
||||
"profileChangedAt"
|
||||
from
|
||||
(
|
||||
select
|
||||
1
|
||||
) as "dummy"
|
||||
) as obj
|
||||
) as "user"
|
||||
from
|
||||
"album_user"
|
||||
inner join "user" on "user"."id" = "album_user"."userId"
|
||||
where
|
||||
"album_user"."role" = 'owner'
|
||||
and "album_user"."albumId" = "album"."id"
|
||||
and "album_user"."userId" = "user"."id"
|
||||
)
|
||||
and "user"."deletedAt" is null
|
||||
) as "owner" on true
|
||||
) as agg
|
||||
) as "albumUsers"
|
||||
from
|
||||
"album"
|
||||
where
|
||||
"album"."id" = "shared_link"."albumId"
|
||||
and "album"."deletedAt" is null
|
||||
|
||||
@@ -18,6 +18,7 @@ import { DB } from 'src/schema/index.js';
|
||||
import { AssetExifTable } from 'src/schema/tables/asset-exif.table.js';
|
||||
import { AssetTable } from 'src/schema/tables/asset.table.js';
|
||||
import { SharedLinkTable } from 'src/schema/tables/shared-link.table.js';
|
||||
import { dummy } from 'src/utils/database.js';
|
||||
|
||||
export type SharedLinkSearchOptions = {
|
||||
userId: string;
|
||||
@@ -43,22 +44,18 @@ export const withExifInfo = (eb: ExpressionBuilder<DB, 'asset'>) => {
|
||||
.as('exifInfo');
|
||||
};
|
||||
|
||||
const withAlbumOwner = (eb: ExpressionBuilder<DB, 'album'>) => {
|
||||
return eb
|
||||
.selectFrom('user')
|
||||
.select(columns.user)
|
||||
.where((eb) =>
|
||||
eb.exists(
|
||||
eb
|
||||
.selectFrom('album_user')
|
||||
.where('album_user.role', '=', sql.lit(AlbumUserRole.Owner))
|
||||
.whereRef('album_user.albumId', '=', 'album.id')
|
||||
.whereRef('album_user.userId', '=', 'user.id'),
|
||||
),
|
||||
)
|
||||
.where('user.deletedAt', 'is', null)
|
||||
.as('owner');
|
||||
};
|
||||
const withAlbumOwner = (eb: ExpressionBuilder<DB, 'album'>) =>
|
||||
jsonArrayFrom(
|
||||
eb
|
||||
.selectFrom('album_user')
|
||||
.innerJoin('user', 'user.id', 'album_user.userId')
|
||||
.where('album_user.role', '=', sql.lit(AlbumUserRole.Owner))
|
||||
.whereRef('album_user.albumId', '=', 'album.id')
|
||||
.select('album_user.role')
|
||||
.select((eb) => jsonObjectFrom(eb.selectFrom(dummy).select(columns.user)).$notNull().as('user')),
|
||||
)
|
||||
.$notNull()
|
||||
.as('albumUsers');
|
||||
|
||||
const withSharedLinkAlbum = (eb: ExpressionBuilder<DB, 'shared_link'>) => {
|
||||
return eb
|
||||
@@ -101,7 +98,7 @@ export class SharedLinkRepository {
|
||||
.as('assets'),
|
||||
(join) => join.onTrue(),
|
||||
)
|
||||
.innerJoinLateral(withAlbumOwner, (join) => join.onTrue())
|
||||
.select(withAlbumOwner)
|
||||
.select((eb) =>
|
||||
eb.fn
|
||||
.coalesce(
|
||||
@@ -114,8 +111,7 @@ export class SharedLinkRepository {
|
||||
)
|
||||
.as('assets'),
|
||||
)
|
||||
.select((eb) => eb.fn.toJson('owner').as('owner'))
|
||||
.groupBy(['album.id', sql`"owner".*`])
|
||||
.groupBy('album.id')
|
||||
.as('album'),
|
||||
(join) => join.onTrue(),
|
||||
)
|
||||
@@ -135,11 +131,7 @@ export class SharedLinkRepository {
|
||||
.select((eb) => jsonArrayFrom(withSharedAssets(eb).limit(1)).as('assets'))
|
||||
.where('shared_link.userId', '=', userId)
|
||||
.leftJoinLateral(
|
||||
(eb) =>
|
||||
withSharedLinkAlbum(eb)
|
||||
.innerJoinLateral(withAlbumOwner, (join) => join.onTrue())
|
||||
.select((eb) => eb.fn.toJson('owner').as('owner'))
|
||||
.as('album'),
|
||||
(eb) => withSharedLinkAlbum(eb).select(withAlbumOwner).as('album'),
|
||||
(join) => join.onTrue(),
|
||||
)
|
||||
.select((eb) => eb.fn.toJson('album').$castTo<ShallowDehydrateObject<Album> | null>().as('album'))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Kysely } from 'kysely';
|
||||
import { randomBytes } from 'node:crypto';
|
||||
import { SharedLinkType } from 'src/enum.js';
|
||||
import { AlbumUserRole, SharedLinkType } from 'src/enum.js';
|
||||
import { AccessRepository } from 'src/repositories/access.repository.js';
|
||||
import { DatabaseRepository } from 'src/repositories/database.repository.js';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository.js';
|
||||
@@ -236,12 +236,14 @@ describe(SharedLinkService.name, () => {
|
||||
expect(result[0].id).toBe(link1.id);
|
||||
});
|
||||
|
||||
it('should return album shared links with album data', async () => {
|
||||
it('should return album shared links with album data and (only) the owner', async () => {
|
||||
const { sut, ctx } = setup();
|
||||
const { user } = await ctx.newUser();
|
||||
const { user: albumContributor } = await ctx.newUser();
|
||||
const auth = factory.auth({ user });
|
||||
|
||||
const { album } = await ctx.newAlbum({ ownerId: user.id });
|
||||
await ctx.newAlbumUser({ albumId: album.id, userId: albumContributor.id, role: AlbumUserRole.Editor });
|
||||
|
||||
const sharedLinkRepo = ctx.get(SharedLinkRepository);
|
||||
|
||||
@@ -258,6 +260,9 @@ describe(SharedLinkService.name, () => {
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].album).toBeDefined();
|
||||
expect(result[0].album!.id).toBe(album.id);
|
||||
expect(result[0].album!.albumUsers.length).toBe(1);
|
||||
expect(result[0].album!.albumUsers[0].role).toBe(AlbumUserRole.Owner);
|
||||
expect(result[0].album!.albumUsers[0].user.id).toBe(user.id);
|
||||
});
|
||||
|
||||
it('should return multiple album shared links without sql error from json group by', async () => {
|
||||
|
||||
Reference in New Issue
Block a user