feat: readonly album sharing (#8720)

* rename albums_shared_users_users to album_permissions and add readonly column

* disable synchronize on the original join table

* remove unnecessary FK names

* set readonly=true as default for new album shares

* separate and implement album READ and WRITE permission

* expose albumPermissions on the API, deprecate sharedUsers

* generate openapi

* create readonly view on frontend

* ??? move slideshow button out from ellipsis menu so that non-owners can have access too

* correct sharedUsers joins

* add album permission repository

* remove a log

* fix assetCount getting reset when adding users

* fix lint

* add set permission endpoint and UI

* sort users

* remove log

* Revert "??? move slideshow button out from ellipsis menu so that non-owners can have access too"

This reverts commit 1343bfa311.

* rename stuff

* fix db schema annotations

* sql generate

* change readonly default to follow migration

* fix deprecation notice

* change readonly boolean to role enum

* fix joincolumn as primary key

* rename albumUserRepository in album service

* clean up userId and albumId

* add write access to shared link

* fix existing tests

* switch to vitest

* format and fix tests on web

* add new test

* fix one e2e test

* rename new API field to albumUsers

* capitalize serverside enum

* remove unused ReadWrite type

* missed rename from previous commit

* rename to albumUsers in album entity as well

* remove outdated Equals calls

* unnecessary relation

* rename to updateUser in album service

* minor renamery

* move sorting to backend

* rename and separate ALBUM_WRITE as ADD_ASSET and REMOVE_ASSET

* fix tests

* fix "should migrate single moving picture" test failing on European system timezone

* generated changes after merge

* lint fix

* fix correct page to open after removing user from album

* fix e2e tests and some bugs

* rename updateAlbumUser rest endpoint

* add new e2e tests for updateAlbumUser endpoint

* small optimizations

* refactor album e2e test, add new album shared with viewer

* add new test to check if viewer can see the album

* add new e2e tests for readonly share

* failing test: User delete doesn't cascade to UserAlbum entity

* fix: handle deleted users

* use lodash for sort

* add role to addUsersToAlbum endpoint

* add UI for adding editors

* lint fixes

* change role back to editor as DB default

* fix server tests

* redesign user selection modal editor selector

* style tweaks

* fix type error

* Revert "style tweaks"

This reverts commit ab604f4c8f.

* Revert "redesign user selection modal editor selector"

This reverts commit e6f344856c.

* chore: cleanup and improve add user modal

* chore: open api

* small styling

---------

Co-authored-by: mgabor <>
Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
mgabor
2024-04-25 06:19:49 +02:00
committed by GitHub
parent 0b3373c552
commit 2943f93098
56 changed files with 1778 additions and 370 deletions

View File

@@ -1,3 +1,4 @@
import { AlbumUserRole } from 'src/entities/album-user.entity';
import { AlbumEntity, AssetOrder } from 'src/entities/album.entity';
import { assetStub } from 'test/fixtures/asset.stub';
import { authStub } from 'test/fixtures/auth.stub';
@@ -17,7 +18,7 @@ export const albumStub = {
updatedAt: new Date(),
deletedAt: null,
sharedLinks: [],
sharedUsers: [],
albumUsers: [],
isActivityEnabled: true,
order: AssetOrder.DESC,
}),
@@ -34,7 +35,15 @@ export const albumStub = {
updatedAt: new Date(),
deletedAt: null,
sharedLinks: [],
sharedUsers: [userStub.user1],
albumUsers: [
{
user: userStub.user1,
album: undefined as unknown as AlbumEntity,
role: AlbumUserRole.EDITOR,
userId: userStub.user1.id,
albumId: 'album-2',
},
],
isActivityEnabled: true,
order: AssetOrder.DESC,
}),
@@ -51,7 +60,22 @@ export const albumStub = {
updatedAt: new Date(),
deletedAt: null,
sharedLinks: [],
sharedUsers: [userStub.user1, userStub.user2],
albumUsers: [
{
user: userStub.user1,
album: undefined as unknown as AlbumEntity,
role: AlbumUserRole.EDITOR,
userId: userStub.user1.id,
albumId: 'album-3',
},
{
user: userStub.user2,
album: undefined as unknown as AlbumEntity,
role: AlbumUserRole.EDITOR,
userId: userStub.user2.id,
albumId: 'album-3',
},
],
isActivityEnabled: true,
order: AssetOrder.DESC,
}),
@@ -68,7 +92,15 @@ export const albumStub = {
updatedAt: new Date(),
deletedAt: null,
sharedLinks: [],
sharedUsers: [userStub.admin],
albumUsers: [
{
user: userStub.admin,
album: undefined as unknown as AlbumEntity,
role: AlbumUserRole.EDITOR,
userId: userStub.admin.id,
albumId: 'album-3',
},
],
isActivityEnabled: true,
order: AssetOrder.DESC,
}),
@@ -85,7 +117,7 @@ export const albumStub = {
updatedAt: new Date(),
deletedAt: null,
sharedLinks: [],
sharedUsers: [],
albumUsers: [],
isActivityEnabled: true,
order: AssetOrder.DESC,
}),
@@ -102,7 +134,7 @@ export const albumStub = {
updatedAt: new Date(),
deletedAt: null,
sharedLinks: [],
sharedUsers: [],
albumUsers: [],
isActivityEnabled: true,
order: AssetOrder.DESC,
}),
@@ -119,7 +151,7 @@ export const albumStub = {
updatedAt: new Date(),
deletedAt: null,
sharedLinks: [],
sharedUsers: [],
albumUsers: [],
isActivityEnabled: true,
order: AssetOrder.DESC,
}),
@@ -136,7 +168,7 @@ export const albumStub = {
updatedAt: new Date(),
deletedAt: null,
sharedLinks: [],
sharedUsers: [],
albumUsers: [],
isActivityEnabled: true,
order: AssetOrder.DESC,
}),
@@ -153,7 +185,7 @@ export const albumStub = {
updatedAt: new Date(),
deletedAt: null,
sharedLinks: [],
sharedUsers: [],
albumUsers: [],
isActivityEnabled: true,
order: AssetOrder.DESC,
}),
@@ -170,7 +202,7 @@ export const albumStub = {
updatedAt: new Date(),
deletedAt: null,
sharedLinks: [],
sharedUsers: [],
albumUsers: [],
isActivityEnabled: true,
order: AssetOrder.DESC,
}),

View File

@@ -467,6 +467,7 @@ export const assetStub = {
library: libraryStub.uploadLibrary1,
exifInfo: {
fileSizeInByte: 100_000,
timeZone: `America/New_York`,
},
} as AssetEntity),
@@ -483,6 +484,7 @@ export const assetStub = {
library: libraryStub.uploadLibrary1,
exifInfo: {
fileSizeInByte: 25_000,
timeZone: `America/New_York`,
},
} as AssetEntity),

View File

@@ -103,6 +103,7 @@ const albumResponse: AlbumResponseDto = {
ownerId: 'admin_id',
owner: mapUser(userStub.admin),
sharedUsers: [],
albumUsers: [],
shared: false,
hasSharedLink: false,
assets: [],
@@ -186,7 +187,7 @@ export const sharedLinkStub = {
deletedAt: null,
albumThumbnailAsset: null,
albumThumbnailAssetId: null,
sharedUsers: [],
albumUsers: [],
sharedLinks: [],
isActivityEnabled: true,
order: AssetOrder.DESC,

View File

@@ -0,0 +1,10 @@
import { IAlbumUserRepository } from 'src/interfaces/album-user.interface';
import { Mocked } from 'vitest';
export const newAlbumUserRepositoryMock = (): Mocked<IAlbumUserRepository> => {
return {
create: vitest.fn(),
delete: vitest.fn(),
update: vitest.fn(),
};
};