refactor(server): auth dto (#5593)

* refactor: AuthUserDto => AuthDto

* refactor: reorganize auth-dto

* refactor: AuthUser() => Auth()
This commit is contained in:
Jason Rasmussen
2023-12-09 23:34:12 -05:00
committed by GitHub
parent 8057c375ba
commit 33529d1d9b
60 changed files with 1033 additions and 1065 deletions
@@ -41,7 +41,7 @@ describe(SharedLinkService.name, () => {
sharedLinkResponseStub.expired,
sharedLinkResponseStub.valid,
]);
expect(shareMock.getAll).toHaveBeenCalledWith(authStub.user1.id);
expect(shareMock.getAll).toHaveBeenCalledWith(authStub.user1.user.id);
});
});
@@ -55,21 +55,21 @@ describe(SharedLinkService.name, () => {
const authDto = authStub.adminSharedLink;
shareMock.get.mockResolvedValue(sharedLinkStub.valid);
await expect(sut.getMine(authDto, {})).resolves.toEqual(sharedLinkResponseStub.valid);
expect(shareMock.get).toHaveBeenCalledWith(authDto.id, authDto.sharedLinkId);
expect(shareMock.get).toHaveBeenCalledWith(authDto.user.id, authDto.sharedLink?.id);
});
it('should not return metadata', async () => {
const authDto = authStub.adminSharedLinkNoExif;
shareMock.get.mockResolvedValue(sharedLinkStub.readonlyNoExif);
await expect(sut.getMine(authDto, {})).resolves.toEqual(sharedLinkResponseStub.readonlyNoMetadata);
expect(shareMock.get).toHaveBeenCalledWith(authDto.id, authDto.sharedLinkId);
expect(shareMock.get).toHaveBeenCalledWith(authDto.user.id, authDto.sharedLink?.id);
});
it('should throw an error for an password protected shared link', async () => {
const authDto = authStub.adminSharedLink;
shareMock.get.mockResolvedValue(sharedLinkStub.passwordRequired);
await expect(sut.getMine(authDto, {})).rejects.toBeInstanceOf(UnauthorizedException);
expect(shareMock.get).toHaveBeenCalledWith(authDto.id, authDto.sharedLinkId);
expect(shareMock.get).toHaveBeenCalledWith(authDto.user.id, authDto.sharedLink?.id);
});
});
@@ -77,14 +77,14 @@ describe(SharedLinkService.name, () => {
it('should throw an error for an invalid shared link', async () => {
shareMock.get.mockResolvedValue(null);
await expect(sut.get(authStub.user1, 'missing-id')).rejects.toBeInstanceOf(BadRequestException);
expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.id, 'missing-id');
expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.user.id, 'missing-id');
expect(shareMock.update).not.toHaveBeenCalled();
});
it('should get a shared link by id', async () => {
shareMock.get.mockResolvedValue(sharedLinkStub.valid);
await expect(sut.get(authStub.user1, sharedLinkStub.valid.id)).resolves.toEqual(sharedLinkResponseStub.valid);
expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.id, sharedLinkStub.valid.id);
expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.user.id, sharedLinkStub.valid.id);
});
});
@@ -120,12 +120,12 @@ describe(SharedLinkService.name, () => {
await sut.create(authStub.admin, { type: SharedLinkType.ALBUM, albumId: albumStub.oneAsset.id });
expect(accessMock.album.checkOwnerAccess).toHaveBeenCalledWith(
authStub.admin.id,
authStub.admin.user.id,
new Set([albumStub.oneAsset.id]),
);
expect(shareMock.create).toHaveBeenCalledWith({
type: SharedLinkType.ALBUM,
userId: authStub.admin.id,
userId: authStub.admin.user.id,
albumId: albumStub.oneAsset.id,
allowDownload: true,
allowUpload: true,
@@ -149,10 +149,13 @@ describe(SharedLinkService.name, () => {
allowUpload: true,
});
expect(accessMock.asset.checkOwnerAccess).toHaveBeenCalledWith(authStub.admin.id, new Set([assetStub.image.id]));
expect(accessMock.asset.checkOwnerAccess).toHaveBeenCalledWith(
authStub.admin.user.id,
new Set([assetStub.image.id]),
);
expect(shareMock.create).toHaveBeenCalledWith({
type: SharedLinkType.INDIVIDUAL,
userId: authStub.admin.id,
userId: authStub.admin.user.id,
albumId: null,
allowDownload: true,
allowUpload: true,
@@ -169,7 +172,7 @@ describe(SharedLinkService.name, () => {
it('should throw an error for an invalid shared link', async () => {
shareMock.get.mockResolvedValue(null);
await expect(sut.update(authStub.user1, 'missing-id', {})).rejects.toBeInstanceOf(BadRequestException);
expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.id, 'missing-id');
expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.user.id, 'missing-id');
expect(shareMock.update).not.toHaveBeenCalled();
});
@@ -177,10 +180,10 @@ describe(SharedLinkService.name, () => {
shareMock.get.mockResolvedValue(sharedLinkStub.valid);
shareMock.update.mockResolvedValue(sharedLinkStub.valid);
await sut.update(authStub.user1, sharedLinkStub.valid.id, { allowDownload: false });
expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.id, sharedLinkStub.valid.id);
expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.user.id, sharedLinkStub.valid.id);
expect(shareMock.update).toHaveBeenCalledWith({
id: sharedLinkStub.valid.id,
userId: authStub.user1.id,
userId: authStub.user1.user.id,
allowDownload: false,
});
});
@@ -190,14 +193,14 @@ describe(SharedLinkService.name, () => {
it('should throw an error for an invalid shared link', async () => {
shareMock.get.mockResolvedValue(null);
await expect(sut.remove(authStub.user1, 'missing-id')).rejects.toBeInstanceOf(BadRequestException);
expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.id, 'missing-id');
expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.user.id, 'missing-id');
expect(shareMock.update).not.toHaveBeenCalled();
});
it('should remove a key', async () => {
shareMock.get.mockResolvedValue(sharedLinkStub.valid);
await sut.remove(authStub.user1, sharedLinkStub.valid.id);
expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.id, sharedLinkStub.valid.id);
expect(shareMock.get).toHaveBeenCalledWith(authStub.user1.user.id, sharedLinkStub.valid.id);
expect(shareMock.remove).toHaveBeenCalledWith(sharedLinkStub.valid);
});
});
@@ -2,7 +2,7 @@ import { AssetEntity, SharedLinkEntity, SharedLinkType } from '@app/infra/entiti
import { BadRequestException, ForbiddenException, Inject, Injectable, UnauthorizedException } from '@nestjs/common';
import { AccessCore, Permission } from '../access';
import { AssetIdErrorReason, AssetIdsDto, AssetIdsResponseDto } from '../asset';
import { AuthUserDto } from '../auth';
import { AuthDto } from '../auth';
import { IAccessRepository, ICryptoRepository, ISharedLinkRepository } from '../repositories';
import { SharedLinkResponseDto, mapSharedLink, mapSharedLinkWithoutMetadata } from './shared-link-response.dto';
import { SharedLinkCreateDto, SharedLinkEditDto, SharedLinkPasswordDto } from './shared-link.dto';
@@ -19,42 +19,36 @@ export class SharedLinkService {
this.access = AccessCore.create(accessRepository);
}
getAll(authUser: AuthUserDto): Promise<SharedLinkResponseDto[]> {
return this.repository.getAll(authUser.id).then((links) => links.map(mapSharedLink));
getAll(auth: AuthDto): Promise<SharedLinkResponseDto[]> {
return this.repository.getAll(auth.user.id).then((links) => links.map(mapSharedLink));
}
async getMine(authUser: AuthUserDto, dto: SharedLinkPasswordDto): Promise<SharedLinkResponseDto> {
const { sharedLinkId: id, isPublicUser, isShowMetadata: isShowExif } = authUser;
if (!isPublicUser || !id) {
async getMine(auth: AuthDto, dto: SharedLinkPasswordDto): Promise<SharedLinkResponseDto> {
if (!auth.sharedLink) {
throw new ForbiddenException();
}
const sharedLink = await this.findOrFail(authUser, id);
let newToken;
const sharedLink = await this.findOrFail(auth, auth.sharedLink.id);
const response = this.map(sharedLink, { withExif: sharedLink.showExif });
if (sharedLink.password) {
newToken = this.validateAndRefreshToken(sharedLink, dto);
response.token = this.validateAndRefreshToken(sharedLink, dto);
}
return {
...this.map(sharedLink, { withExif: isShowExif ?? true }),
token: newToken,
};
return response;
}
async get(authUser: AuthUserDto, id: string): Promise<SharedLinkResponseDto> {
const sharedLink = await this.findOrFail(authUser, id);
async get(auth: AuthDto, id: string): Promise<SharedLinkResponseDto> {
const sharedLink = await this.findOrFail(auth, id);
return this.map(sharedLink, { withExif: true });
}
async create(authUser: AuthUserDto, dto: SharedLinkCreateDto): Promise<SharedLinkResponseDto> {
async create(auth: AuthDto, dto: SharedLinkCreateDto): Promise<SharedLinkResponseDto> {
switch (dto.type) {
case SharedLinkType.ALBUM:
if (!dto.albumId) {
throw new BadRequestException('Invalid albumId');
}
await this.access.requirePermission(authUser, Permission.ALBUM_SHARE, dto.albumId);
await this.access.requirePermission(auth, Permission.ALBUM_SHARE, dto.albumId);
break;
case SharedLinkType.INDIVIDUAL:
@@ -62,14 +56,14 @@ export class SharedLinkService {
throw new BadRequestException('Invalid assetIds');
}
await this.access.requirePermission(authUser, Permission.ASSET_SHARE, dto.assetIds);
await this.access.requirePermission(auth, Permission.ASSET_SHARE, dto.assetIds);
break;
}
const sharedLink = await this.repository.create({
key: this.cryptoRepository.randomBytes(50),
userId: authUser.id,
userId: auth.user.id,
type: dto.type,
albumId: dto.albumId || null,
assets: (dto.assetIds || []).map((id) => ({ id }) as AssetEntity),
@@ -84,11 +78,11 @@ export class SharedLinkService {
return this.map(sharedLink, { withExif: true });
}
async update(authUser: AuthUserDto, id: string, dto: SharedLinkEditDto) {
await this.findOrFail(authUser, id);
async update(auth: AuthDto, id: string, dto: SharedLinkEditDto) {
await this.findOrFail(auth, id);
const sharedLink = await this.repository.update({
id,
userId: authUser.id,
userId: auth.user.id,
description: dto.description,
password: dto.password,
expiresAt: dto.changeExpiryTime && !dto.expiresAt ? null : dto.expiresAt,
@@ -99,21 +93,21 @@ export class SharedLinkService {
return this.map(sharedLink, { withExif: true });
}
async remove(authUser: AuthUserDto, id: string): Promise<void> {
const sharedLink = await this.findOrFail(authUser, id);
async remove(auth: AuthDto, id: string): Promise<void> {
const sharedLink = await this.findOrFail(auth, id);
await this.repository.remove(sharedLink);
}
private async findOrFail(authUser: AuthUserDto, id: string) {
const sharedLink = await this.repository.get(authUser.id, id);
private async findOrFail(auth: AuthDto, id: string) {
const sharedLink = await this.repository.get(auth.user.id, id);
if (!sharedLink) {
throw new BadRequestException('Shared link not found');
}
return sharedLink;
}
async addAssets(authUser: AuthUserDto, id: string, dto: AssetIdsDto): Promise<AssetIdsResponseDto[]> {
const sharedLink = await this.findOrFail(authUser, id);
async addAssets(auth: AuthDto, id: string, dto: AssetIdsDto): Promise<AssetIdsResponseDto[]> {
const sharedLink = await this.findOrFail(auth, id);
if (sharedLink.type !== SharedLinkType.INDIVIDUAL) {
throw new BadRequestException('Invalid shared link type');
@@ -121,7 +115,7 @@ export class SharedLinkService {
const existingAssetIds = new Set(sharedLink.assets.map((asset) => asset.id));
const notPresentAssetIds = dto.assetIds.filter((assetId) => !existingAssetIds.has(assetId));
const allowedAssetIds = await this.access.checkAccess(authUser, Permission.ASSET_SHARE, notPresentAssetIds);
const allowedAssetIds = await this.access.checkAccess(auth, Permission.ASSET_SHARE, notPresentAssetIds);
const results: AssetIdsResponseDto[] = [];
for (const assetId of dto.assetIds) {
@@ -146,8 +140,8 @@ export class SharedLinkService {
return results;
}
async removeAssets(authUser: AuthUserDto, id: string, dto: AssetIdsDto): Promise<AssetIdsResponseDto[]> {
const sharedLink = await this.findOrFail(authUser, id);
async removeAssets(auth: AuthDto, id: string, dto: AssetIdsDto): Promise<AssetIdsResponseDto[]> {
const sharedLink = await this.findOrFail(auth, id);
if (sharedLink.type !== SharedLinkType.INDIVIDUAL) {
throw new BadRequestException('Invalid shared link type');