mirror of
https://github.com/Art051/immich.git
synced 2025-08-11 19:29:00 +00:00
refactor(server): auth dto (#5593)
* refactor: AuthUserDto => AuthDto * refactor: reorganize auth-dto * refactor: AuthUser() => Auth()
This commit is contained in:
@@ -48,9 +48,9 @@ describe(AlbumService.name, () => {
|
||||
notShared: 0,
|
||||
});
|
||||
|
||||
expect(albumMock.getOwned).toHaveBeenCalledWith(authStub.admin.id);
|
||||
expect(albumMock.getShared).toHaveBeenCalledWith(authStub.admin.id);
|
||||
expect(albumMock.getNotShared).toHaveBeenCalledWith(authStub.admin.id);
|
||||
expect(albumMock.getOwned).toHaveBeenCalledWith(authStub.admin.user.id);
|
||||
expect(albumMock.getShared).toHaveBeenCalledWith(authStub.admin.user.id);
|
||||
expect(albumMock.getNotShared).toHaveBeenCalledWith(authStub.admin.user.id);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -188,7 +188,7 @@ describe(AlbumService.name, () => {
|
||||
});
|
||||
|
||||
expect(albumMock.create).toHaveBeenCalledWith({
|
||||
ownerId: authStub.admin.id,
|
||||
ownerId: authStub.admin.user.id,
|
||||
albumName: albumStub.empty.albumName,
|
||||
description: albumStub.empty.description,
|
||||
sharedUsers: [{ id: 'user-id' }],
|
||||
@@ -312,7 +312,7 @@ describe(AlbumService.name, () => {
|
||||
accessMock.album.checkOwnerAccess.mockResolvedValue(new Set([albumStub.sharedWithAdmin.id]));
|
||||
albumMock.getById.mockResolvedValue(albumStub.sharedWithAdmin);
|
||||
await expect(
|
||||
sut.addUsers(authStub.user1, albumStub.sharedWithAdmin.id, { sharedUserIds: [authStub.admin.id] }),
|
||||
sut.addUsers(authStub.user1, albumStub.sharedWithAdmin.id, { sharedUserIds: [authStub.admin.user.id] }),
|
||||
).rejects.toBeInstanceOf(BadRequestException);
|
||||
expect(albumMock.update).not.toHaveBeenCalled();
|
||||
});
|
||||
@@ -332,11 +332,11 @@ describe(AlbumService.name, () => {
|
||||
albumMock.getById.mockResolvedValue(_.cloneDeep(albumStub.sharedWithAdmin));
|
||||
albumMock.update.mockResolvedValue(albumStub.sharedWithAdmin);
|
||||
userMock.get.mockResolvedValue(userStub.user2);
|
||||
await sut.addUsers(authStub.user1, albumStub.sharedWithAdmin.id, { sharedUserIds: [authStub.user2.id] });
|
||||
await sut.addUsers(authStub.user1, albumStub.sharedWithAdmin.id, { sharedUserIds: [authStub.user2.user.id] });
|
||||
expect(albumMock.update).toHaveBeenCalledWith({
|
||||
id: albumStub.sharedWithAdmin.id,
|
||||
updatedAt: expect.any(Date),
|
||||
sharedUsers: [userStub.admin, { id: authStub.user2.id }],
|
||||
sharedUsers: [userStub.admin, { id: authStub.user2.user.id }],
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -370,12 +370,12 @@ describe(AlbumService.name, () => {
|
||||
albumMock.getById.mockResolvedValue(albumStub.sharedWithMultiple);
|
||||
|
||||
await expect(
|
||||
sut.removeUser(authStub.user1, albumStub.sharedWithMultiple.id, authStub.user2.id),
|
||||
sut.removeUser(authStub.user1, albumStub.sharedWithMultiple.id, authStub.user2.user.id),
|
||||
).rejects.toBeInstanceOf(BadRequestException);
|
||||
|
||||
expect(albumMock.update).not.toHaveBeenCalled();
|
||||
expect(accessMock.album.checkOwnerAccess).toHaveBeenCalledWith(
|
||||
authStub.user1.id,
|
||||
authStub.user1.user.id,
|
||||
new Set([albumStub.sharedWithMultiple.id]),
|
||||
);
|
||||
});
|
||||
@@ -383,7 +383,7 @@ describe(AlbumService.name, () => {
|
||||
it('should allow a shared user to remove themselves', async () => {
|
||||
albumMock.getById.mockResolvedValue(albumStub.sharedWithUser);
|
||||
|
||||
await sut.removeUser(authStub.user1, albumStub.sharedWithUser.id, authStub.user1.id);
|
||||
await sut.removeUser(authStub.user1, albumStub.sharedWithUser.id, authStub.user1.user.id);
|
||||
|
||||
expect(albumMock.update).toHaveBeenCalledTimes(1);
|
||||
expect(albumMock.update).toHaveBeenCalledWith({
|
||||
@@ -409,7 +409,7 @@ describe(AlbumService.name, () => {
|
||||
it('should not allow the owner to be removed', async () => {
|
||||
albumMock.getById.mockResolvedValue(albumStub.empty);
|
||||
|
||||
await expect(sut.removeUser(authStub.admin, albumStub.empty.id, authStub.admin.id)).rejects.toBeInstanceOf(
|
||||
await expect(sut.removeUser(authStub.admin, albumStub.empty.id, authStub.admin.user.id)).rejects.toBeInstanceOf(
|
||||
BadRequestException,
|
||||
);
|
||||
|
||||
@@ -444,7 +444,7 @@ describe(AlbumService.name, () => {
|
||||
|
||||
expect(albumMock.getById).toHaveBeenCalledWith(albumStub.oneAsset.id, { withAssets: true });
|
||||
expect(accessMock.album.checkOwnerAccess).toHaveBeenCalledWith(
|
||||
authStub.admin.id,
|
||||
authStub.admin.user.id,
|
||||
new Set([albumStub.oneAsset.id]),
|
||||
);
|
||||
});
|
||||
@@ -465,7 +465,7 @@ describe(AlbumService.name, () => {
|
||||
|
||||
expect(albumMock.getById).toHaveBeenCalledWith('album-123', { withAssets: true });
|
||||
expect(accessMock.album.checkSharedLinkAccess).toHaveBeenCalledWith(
|
||||
authStub.adminSharedLink.sharedLinkId,
|
||||
authStub.adminSharedLink.sharedLink?.id,
|
||||
new Set(['album-123']),
|
||||
);
|
||||
});
|
||||
@@ -485,14 +485,20 @@ describe(AlbumService.name, () => {
|
||||
await sut.get(authStub.user1, 'album-123', {});
|
||||
|
||||
expect(albumMock.getById).toHaveBeenCalledWith('album-123', { withAssets: true });
|
||||
expect(accessMock.album.checkSharedAlbumAccess).toHaveBeenCalledWith(authStub.user1.id, new Set(['album-123']));
|
||||
expect(accessMock.album.checkSharedAlbumAccess).toHaveBeenCalledWith(
|
||||
authStub.user1.user.id,
|
||||
new Set(['album-123']),
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw an error for no access', async () => {
|
||||
await expect(sut.get(authStub.admin, 'album-123', {})).rejects.toBeInstanceOf(BadRequestException);
|
||||
|
||||
expect(accessMock.album.checkOwnerAccess).toHaveBeenCalledWith(authStub.admin.id, new Set(['album-123']));
|
||||
expect(accessMock.album.checkSharedAlbumAccess).toHaveBeenCalledWith(authStub.admin.id, new Set(['album-123']));
|
||||
expect(accessMock.album.checkOwnerAccess).toHaveBeenCalledWith(authStub.admin.user.id, new Set(['album-123']));
|
||||
expect(accessMock.album.checkSharedAlbumAccess).toHaveBeenCalledWith(
|
||||
authStub.admin.user.id,
|
||||
new Set(['album-123']),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -590,7 +596,7 @@ describe(AlbumService.name, () => {
|
||||
});
|
||||
|
||||
expect(accessMock.album.checkSharedLinkAccess).toHaveBeenCalledWith(
|
||||
authStub.adminSharedLink.sharedLinkId,
|
||||
authStub.adminSharedLink.sharedLink?.id,
|
||||
new Set(['album-123']),
|
||||
);
|
||||
});
|
||||
@@ -610,7 +616,7 @@ describe(AlbumService.name, () => {
|
||||
updatedAt: expect.any(Date),
|
||||
albumThumbnailAssetId: 'asset-1',
|
||||
});
|
||||
expect(accessMock.asset.checkPartnerAccess).toHaveBeenCalledWith(authStub.admin.id, new Set(['asset-1']));
|
||||
expect(accessMock.asset.checkPartnerAccess).toHaveBeenCalledWith(authStub.admin.user.id, new Set(['asset-1']));
|
||||
});
|
||||
|
||||
it('should skip duplicate assets', async () => {
|
||||
@@ -635,8 +641,8 @@ describe(AlbumService.name, () => {
|
||||
{ success: false, id: 'asset-1', error: BulkIdErrorReason.NO_PERMISSION },
|
||||
]);
|
||||
|
||||
expect(accessMock.asset.checkOwnerAccess).toHaveBeenCalledWith(authStub.admin.id, new Set(['asset-1']));
|
||||
expect(accessMock.asset.checkPartnerAccess).toHaveBeenCalledWith(authStub.admin.id, new Set(['asset-1']));
|
||||
expect(accessMock.asset.checkOwnerAccess).toHaveBeenCalledWith(authStub.admin.user.id, new Set(['asset-1']));
|
||||
expect(accessMock.asset.checkPartnerAccess).toHaveBeenCalledWith(authStub.admin.user.id, new Set(['asset-1']));
|
||||
});
|
||||
|
||||
it('should not allow unauthorized access to the album', async () => {
|
||||
@@ -729,7 +735,7 @@ describe(AlbumService.name, () => {
|
||||
|
||||
// // await expect(
|
||||
// // sut.removeAssetsFromAlbum(
|
||||
// // authUser,
|
||||
// // auth,
|
||||
// // {
|
||||
// // ids: ['1'],
|
||||
// // },
|
||||
@@ -755,6 +761,6 @@ describe(AlbumService.name, () => {
|
||||
// albumRepositoryMock.get.mockImplementation(() => Promise.resolve<AlbumEntity>(albumEntity));
|
||||
// albumRepositoryMock.addAssets.mockImplementation(() => Promise.resolve<AddAssetsResponseDto>(albumResponse));
|
||||
|
||||
// await expect(sut.removeAssets(authUser, albumId, { ids: ['1'] })).rejects.toBeInstanceOf(ForbiddenException);
|
||||
// await expect(sut.removeAssets(auth, albumId, { ids: ['1'] })).rejects.toBeInstanceOf(ForbiddenException);
|
||||
// });
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@ import { AlbumEntity, AssetEntity, UserEntity } from '@app/infra/entities';
|
||||
import { BadRequestException, Inject, Injectable } from '@nestjs/common';
|
||||
import { AccessCore, Permission } from '../access';
|
||||
import { BulkIdErrorReason, BulkIdResponseDto, BulkIdsDto } from '../asset';
|
||||
import { AuthUserDto } from '../auth';
|
||||
import { AuthDto } from '../auth';
|
||||
import { setUnion } from '../domain.util';
|
||||
import {
|
||||
AlbumAssetCount,
|
||||
@@ -35,11 +35,11 @@ export class AlbumService {
|
||||
this.access = AccessCore.create(accessRepository);
|
||||
}
|
||||
|
||||
async getCount(authUser: AuthUserDto): Promise<AlbumCountResponseDto> {
|
||||
async getCount(auth: AuthDto): Promise<AlbumCountResponseDto> {
|
||||
const [owned, shared, notShared] = await Promise.all([
|
||||
this.albumRepository.getOwned(authUser.id),
|
||||
this.albumRepository.getShared(authUser.id),
|
||||
this.albumRepository.getNotShared(authUser.id),
|
||||
this.albumRepository.getOwned(auth.user.id),
|
||||
this.albumRepository.getShared(auth.user.id),
|
||||
this.albumRepository.getNotShared(auth.user.id),
|
||||
]);
|
||||
|
||||
return {
|
||||
@@ -49,7 +49,7 @@ export class AlbumService {
|
||||
};
|
||||
}
|
||||
|
||||
async getAll({ id: ownerId }: AuthUserDto, { assetId, shared }: GetAlbumsDto): Promise<AlbumResponseDto[]> {
|
||||
async getAll({ user: { id: ownerId } }: AuthDto, { assetId, shared }: GetAlbumsDto): Promise<AlbumResponseDto[]> {
|
||||
const invalidAlbumIds = await this.albumRepository.getInvalidThumbnail();
|
||||
for (const albumId of invalidAlbumIds) {
|
||||
const newThumbnail = await this.assetRepository.getFirstAssetForAlbumId(albumId);
|
||||
@@ -98,8 +98,8 @@ export class AlbumService {
|
||||
);
|
||||
}
|
||||
|
||||
async get(authUser: AuthUserDto, id: string, dto: AlbumInfoDto): Promise<AlbumResponseDto> {
|
||||
await this.access.requirePermission(authUser, Permission.ALBUM_READ, id);
|
||||
async get(auth: AuthDto, id: string, dto: AlbumInfoDto): Promise<AlbumResponseDto> {
|
||||
await this.access.requirePermission(auth, Permission.ALBUM_READ, id);
|
||||
await this.albumRepository.updateThumbnails();
|
||||
const withAssets = dto.withoutAssets === undefined ? true : !dto.withoutAssets;
|
||||
const album = await this.findOrFail(id, { withAssets });
|
||||
@@ -113,7 +113,7 @@ export class AlbumService {
|
||||
};
|
||||
}
|
||||
|
||||
async create(authUser: AuthUserDto, dto: CreateAlbumDto): Promise<AlbumResponseDto> {
|
||||
async create(auth: AuthDto, dto: CreateAlbumDto): Promise<AlbumResponseDto> {
|
||||
for (const userId of dto.sharedWithUserIds || []) {
|
||||
const exists = await this.userRepository.get(userId, {});
|
||||
if (!exists) {
|
||||
@@ -122,7 +122,7 @@ export class AlbumService {
|
||||
}
|
||||
|
||||
const album = await this.albumRepository.create({
|
||||
ownerId: authUser.id,
|
||||
ownerId: auth.user.id,
|
||||
albumName: dto.albumName,
|
||||
description: dto.description,
|
||||
sharedUsers: dto.sharedWithUserIds?.map((value) => ({ id: value }) as UserEntity) ?? [],
|
||||
@@ -133,8 +133,8 @@ export class AlbumService {
|
||||
return mapAlbumWithAssets(album);
|
||||
}
|
||||
|
||||
async update(authUser: AuthUserDto, id: string, dto: UpdateAlbumDto): Promise<AlbumResponseDto> {
|
||||
await this.access.requirePermission(authUser, Permission.ALBUM_UPDATE, id);
|
||||
async update(auth: AuthDto, id: string, dto: UpdateAlbumDto): Promise<AlbumResponseDto> {
|
||||
await this.access.requirePermission(auth, Permission.ALBUM_UPDATE, id);
|
||||
|
||||
const album = await this.findOrFail(id, { withAssets: true });
|
||||
|
||||
@@ -155,22 +155,22 @@ export class AlbumService {
|
||||
return mapAlbumWithoutAssets(updatedAlbum);
|
||||
}
|
||||
|
||||
async delete(authUser: AuthUserDto, id: string): Promise<void> {
|
||||
await this.access.requirePermission(authUser, Permission.ALBUM_DELETE, id);
|
||||
async delete(auth: AuthDto, id: string): Promise<void> {
|
||||
await this.access.requirePermission(auth, Permission.ALBUM_DELETE, id);
|
||||
|
||||
const album = await this.findOrFail(id, { withAssets: false });
|
||||
|
||||
await this.albumRepository.delete(album);
|
||||
}
|
||||
|
||||
async addAssets(authUser: AuthUserDto, id: string, dto: BulkIdsDto): Promise<BulkIdResponseDto[]> {
|
||||
async addAssets(auth: AuthDto, id: string, dto: BulkIdsDto): Promise<BulkIdResponseDto[]> {
|
||||
const album = await this.findOrFail(id, { withAssets: false });
|
||||
|
||||
await this.access.requirePermission(authUser, Permission.ALBUM_READ, id);
|
||||
await this.access.requirePermission(auth, Permission.ALBUM_READ, id);
|
||||
|
||||
const existingAssetIds = await this.albumRepository.getAssetIds(id, dto.ids);
|
||||
const notPresentAssetIds = dto.ids.filter((id) => !existingAssetIds.has(id));
|
||||
const allowedAssetIds = await this.access.checkAccess(authUser, Permission.ASSET_SHARE, notPresentAssetIds);
|
||||
const allowedAssetIds = await this.access.checkAccess(auth, Permission.ASSET_SHARE, notPresentAssetIds);
|
||||
|
||||
const results: BulkIdResponseDto[] = [];
|
||||
for (const assetId of dto.ids) {
|
||||
@@ -202,14 +202,14 @@ export class AlbumService {
|
||||
return results;
|
||||
}
|
||||
|
||||
async removeAssets(authUser: AuthUserDto, id: string, dto: BulkIdsDto): Promise<BulkIdResponseDto[]> {
|
||||
async removeAssets(auth: AuthDto, id: string, dto: BulkIdsDto): Promise<BulkIdResponseDto[]> {
|
||||
const album = await this.findOrFail(id, { withAssets: false });
|
||||
|
||||
await this.access.requirePermission(authUser, Permission.ALBUM_READ, id);
|
||||
await this.access.requirePermission(auth, Permission.ALBUM_READ, id);
|
||||
|
||||
const existingAssetIds = await this.albumRepository.getAssetIds(id, dto.ids);
|
||||
const canRemove = await this.access.checkAccess(authUser, Permission.ALBUM_REMOVE_ASSET, existingAssetIds);
|
||||
const canShare = await this.access.checkAccess(authUser, Permission.ASSET_SHARE, existingAssetIds);
|
||||
const canRemove = await this.access.checkAccess(auth, Permission.ALBUM_REMOVE_ASSET, existingAssetIds);
|
||||
const canShare = await this.access.checkAccess(auth, Permission.ASSET_SHARE, existingAssetIds);
|
||||
const allowedAssetIds = setUnion(canRemove, canShare);
|
||||
|
||||
const results: BulkIdResponseDto[] = [];
|
||||
@@ -241,8 +241,8 @@ export class AlbumService {
|
||||
return results;
|
||||
}
|
||||
|
||||
async addUsers(authUser: AuthUserDto, id: string, dto: AddUsersDto): Promise<AlbumResponseDto> {
|
||||
await this.access.requirePermission(authUser, Permission.ALBUM_SHARE, id);
|
||||
async addUsers(auth: AuthDto, id: string, dto: AddUsersDto): Promise<AlbumResponseDto> {
|
||||
await this.access.requirePermission(auth, Permission.ALBUM_SHARE, id);
|
||||
|
||||
const album = await this.findOrFail(id, { withAssets: false });
|
||||
|
||||
@@ -273,9 +273,9 @@ export class AlbumService {
|
||||
.then(mapAlbumWithoutAssets);
|
||||
}
|
||||
|
||||
async removeUser(authUser: AuthUserDto, id: string, userId: string | 'me'): Promise<void> {
|
||||
async removeUser(auth: AuthDto, id: string, userId: string | 'me'): Promise<void> {
|
||||
if (userId === 'me') {
|
||||
userId = authUser.id;
|
||||
userId = auth.user.id;
|
||||
}
|
||||
|
||||
const album = await this.findOrFail(id, { withAssets: false });
|
||||
@@ -290,8 +290,8 @@ export class AlbumService {
|
||||
}
|
||||
|
||||
// non-admin can remove themselves
|
||||
if (authUser.id !== userId) {
|
||||
await this.access.requirePermission(authUser, Permission.ALBUM_SHARE, id);
|
||||
if (auth.user.id !== userId) {
|
||||
await this.access.requirePermission(auth, Permission.ALBUM_SHARE, id);
|
||||
}
|
||||
|
||||
await this.albumRepository.update({
|
||||
|
||||
Reference in New Issue
Block a user