diff --git a/e2e/src/specs/server/api/album.e2e-spec.ts b/e2e/src/specs/server/api/album.e2e-spec.ts index 55b9c44b70..1d3be1248c 100644 --- a/e2e/src/specs/server/api/album.e2e-spec.ts +++ b/e2e/src/specs/server/api/album.e2e-spec.ts @@ -504,13 +504,14 @@ describe('/albums', () => { }); }); - it('should not be able to share album with owner', async () => { + it('should deduplicate owner from albumUsers on create', async () => { const { status, body } = await request(app) .post('/albums') .send({ albumName: 'New album', albumUsers: [{ role: AlbumUserRole.Editor, userId: user1.userId }] }) .set('Authorization', `Bearer ${user1.accessToken}`); - expect(status).toBe(400); - expect(body).toEqual(errorDto.badRequest('Cannot share album with owner')); + expect(status).toBe(201); + expect(body.albumUsers).toHaveLength(1); + expect(body.albumUsers[0]).toMatchObject({ role: AlbumUserRole.Owner, user: { id: user1.userId } }); }); }); diff --git a/server/src/services/album.service.spec.ts b/server/src/services/album.service.spec.ts index 288c3c1d3c..374cd58a0e 100644 --- a/server/src/services/album.service.spec.ts +++ b/server/src/services/album.service.spec.ts @@ -348,17 +348,25 @@ describe(AlbumService.name, () => { expect(mocks.access.asset.checkOwnerAccess).toHaveBeenCalledWith(owner.id, new Set([assetId, 'asset-2']), false); }); - it('should throw an error if the userId is the ownerId', async () => { - const album = AlbumFactory.create(); - const { user: owner } = album.albumUsers.find(({ role }) => role === AlbumUserRole.Owner)!; - mocks.user.get.mockResolvedValue(owner); - await expect( - sut.create(AuthFactory.create(owner), { - albumName: 'Empty album', - albumUsers: [{ userId: owner.id, role: AlbumUserRole.Editor }], - }), - ).rejects.toBeInstanceOf(BadRequestException); - expect(mocks.album.create).not.toHaveBeenCalled(); + it('should deduplicate owner from albumUsers on create', async () => { + const auth = AuthFactory.create(); + const album = AlbumFactory.from().build(); + mocks.album.create.mockResolvedValue(getForAlbum(album)); + mocks.user.getMetadata.mockResolvedValue([]); + mocks.access.asset.checkOwnerAccess.mockResolvedValue(new Set()); + + await sut.create(auth, { + albumName: 'Empty album', + albumUsers: [{ userId: auth.user.id, role: AlbumUserRole.Editor }], + }); + + expect(mocks.user.get).not.toHaveBeenCalled(); + expect(mocks.album.create).toHaveBeenCalledWith( + expect.objectContaining({ albumName: 'Empty album' }), + [], + [{ userId: auth.user.id, role: AlbumUserRole.Owner }], + auth.user.id, + ); }); }); diff --git a/server/src/services/album.service.ts b/server/src/services/album.service.ts index 564f4bfb3f..cc0b0d899c 100644 --- a/server/src/services/album.service.ts +++ b/server/src/services/album.service.ts @@ -98,7 +98,7 @@ export class AlbumService extends BaseService { } async create(auth: AuthDto, dto: CreateAlbumDto): Promise { - const albumUsers = dto.albumUsers || []; + const albumUsers = (dto.albumUsers || []).filter(({ userId }) => userId !== auth.user.id); for (const { userId } of albumUsers) { const exists = await this.userRepository.get(userId, {}); @@ -106,10 +106,6 @@ export class AlbumService extends BaseService { this.logger.debug('Album creation failed: user not found'); throw new BadRequestException('Invalid user'); } - - if (userId == auth.user.id) { - throw new BadRequestException('Cannot share album with owner'); - } } const allowedAssetIdsSet = await this.checkAccess({