diff --git a/e2e/src/specs/server/api/album.e2e-spec.ts b/e2e/src/specs/server/api/album.e2e-spec.ts index 0aa7b7ec03..432362019c 100644 --- a/e2e/src/specs/server/api/album.e2e-spec.ts +++ b/e2e/src/specs/server/api/album.e2e-spec.ts @@ -796,5 +796,22 @@ describe('/albums', () => { expect(status).toBe(400); expect(body).toEqual(errorDto.badRequest('Not found or no album.share access')); }); + + it('should not allow an editor to change the role of an owner', async () => { + const album = await utils.createAlbum(user1.accessToken, { + albumName: 'testAlbum', + albumUsers: [{ userId: user2.userId, role: AlbumUserRole.Editor }], + }); + + expect(album.albumUsers[1].role).toEqual(AlbumUserRole.Editor); + + const { status, body } = await request(app) + .put(`/albums/${album.id}/user/${user1.userId}`) + .set('Authorization', `Bearer ${user2.accessToken}`) + .send({ role: AlbumUserRole.Editor }); + + expect(status).toBe(400); + expect(body).toEqual(errorDto.badRequest('User is owner')); + }); }); }); diff --git a/server/src/services/album.service.spec.ts b/server/src/services/album.service.spec.ts index f1d125993c..6e89c9aca8 100644 --- a/server/src/services/album.service.spec.ts +++ b/server/src/services/album.service.spec.ts @@ -663,6 +663,7 @@ describe(AlbumService.name, () => { const album = AlbumFactory.from().albumUser({ userId: user.id }).build(); const { user: owner } = album.albumUsers.find(({ role }) => role === AlbumUserRole.Owner)!; mocks.access.album.checkOwnerAccess.mockResolvedValue(new Set([album.id])); + mocks.album.getById.mockResolvedValue(getForAlbum(album)); mocks.albumUser.update.mockResolvedValue(); await sut.updateUser(AuthFactory.create(owner), album.id, user.id, { role: AlbumUserRole.Viewer }); diff --git a/server/src/services/album.service.ts b/server/src/services/album.service.ts index 5f4bc56d98..6f8f4e1dca 100644 --- a/server/src/services/album.service.ts +++ b/server/src/services/album.service.ts @@ -335,6 +335,14 @@ export class AlbumService extends BaseService { async updateUser(auth: AuthDto, id: string, userId: string, dto: UpdateAlbumUserDto): Promise { await this.requireAccess({ auth, permission: Permission.AlbumShare, ids: [id] }); + + const album = await this.findOrFail(id, userId, { withAssets: false }); + const owner = album.albumUsers[0]; + + if (owner.user.id === userId) { + throw new BadRequestException('User is owner'); + } + await this.albumUserRepository.update({ albumId: id, userId }, { role: dto.role }); }