fix(server): skip existing users when sharing albums (#28884)

Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
This commit is contained in:
Jeevan Mohan Pawar 2026-06-17 14:54:20 +01:00 committed by GitHub
parent f9db76433e
commit a364b56b1c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 44 additions and 11 deletions

View file

@ -730,8 +730,8 @@ describe('/albums', () => {
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ albumUsers: [{ userId: user1.userId, role: AlbumUserRole.Editor }] });
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest('User already added'));
expect(status).toBe(200);
expect(body.albumUsers.length).toEqual(1);
});
it('should not be able to add existing user to shared album', async () => {
@ -745,8 +745,8 @@ describe('/albums', () => {
.set('Authorization', `Bearer ${user1.accessToken}`)
.send({ albumUsers: [{ userId: user2.userId, role: AlbumUserRole.Editor }] });
expect(status).toBe(400);
expect(body).toEqual(errorDto.badRequest('User already added'));
expect(status).toBe(200);
expect(body.albumUsers.length).toEqual(2);
});
});

View file

@ -472,17 +472,19 @@ describe(AlbumService.name, () => {
expect(mocks.album.update).not.toHaveBeenCalled();
});
it('should throw an error if the userId is already added', async () => {
it('should skip if the userId is already added', async () => {
const userId = newUuid();
const album = AlbumFactory.from().albumUser({ userId }).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));
await expect(
sut.addUsers(AuthFactory.create(owner), album.id, { albumUsers: [{ userId }] }),
).rejects.toBeInstanceOf(BadRequestException);
await expect(sut.addUsers(AuthFactory.create(owner), album.id, { albumUsers: [{ userId }] })).resolves.toEqual(
expect.objectContaining({ id: album.id }),
);
expect(mocks.album.update).not.toHaveBeenCalled();
expect(mocks.user.get).not.toHaveBeenCalled();
expect(mocks.albumUser.create).not.toHaveBeenCalled();
expect(mocks.event.emit).not.toHaveBeenCalled();
});
it('should throw an error if the userId does not exist', async () => {
@ -498,7 +500,7 @@ describe(AlbumService.name, () => {
expect(mocks.user.get).toHaveBeenCalledWith('unknown-user', {});
});
it('should throw an error if the userId is the ownerId', async () => {
it('should skip if the userId is the ownerId', async () => {
const album = AlbumFactory.create();
const { user: owner } = album.albumUsers.find(({ role }) => role === AlbumUserRole.Owner)!;
mocks.access.album.checkOwnerAccess.mockResolvedValue(new Set([album.id]));
@ -507,9 +509,11 @@ describe(AlbumService.name, () => {
sut.addUsers(AuthFactory.create(owner), album.id, {
albumUsers: [{ userId: owner.id }],
}),
).rejects.toBeInstanceOf(BadRequestException);
).resolves.toEqual(expect.objectContaining({ id: album.id }));
expect(mocks.album.update).not.toHaveBeenCalled();
expect(mocks.user.get).not.toHaveBeenCalled();
expect(mocks.albumUser.create).not.toHaveBeenCalled();
expect(mocks.event.emit).not.toHaveBeenCalled();
});
it('should add valid shared users', async () => {
@ -534,6 +538,35 @@ describe(AlbumService.name, () => {
senderName: owner.name,
});
});
it('should add new users when already-added users are included', async () => {
const existingUserId = newUuid();
const album = AlbumFactory.from().albumUser({ userId: existingUserId }).build();
const { user: owner } = album.albumUsers.find(({ role }) => role === AlbumUserRole.Owner)!;
const user = UserFactory.create();
mocks.access.album.checkOwnerAccess.mockResolvedValue(new Set([album.id]));
mocks.album.getById.mockResolvedValue(getForAlbum(album));
mocks.user.get.mockResolvedValue(user);
mocks.albumUser.create.mockResolvedValue(AlbumUserFactory.from().album(album).user(user).build());
await sut.addUsers(AuthFactory.create(owner), album.id, {
albumUsers: [{ userId: existingUserId }, { userId: user.id }],
});
expect(mocks.user.get).toHaveBeenCalledTimes(1);
expect(mocks.user.get).toHaveBeenCalledWith(user.id, {});
expect(mocks.albumUser.create).toHaveBeenCalledTimes(1);
expect(mocks.albumUser.create).toHaveBeenCalledWith({
userId: user.id,
albumId: album.id,
});
expect(mocks.event.emit).toHaveBeenCalledTimes(1);
expect(mocks.event.emit).toHaveBeenCalledWith('AlbumInvite', {
id: album.id,
userId: user.id,
senderName: owner.name,
});
});
});
describe('removeUser', () => {

View file

@ -290,7 +290,7 @@ export class AlbumService extends BaseService {
const exists = album.albumUsers.find(({ user: { id } }) => id === userId);
if (exists) {
throw new BadRequestException('User already added');
continue;
}
const user = await this.userRepository.get(userId, {});