mirror of
https://github.com/KevinMidboe/immich.git
synced 2026-01-11 03:35:50 +00:00
refactor(server): partner core (#2678)
* refactor(server): partner core * refactor(server): partner access check
This commit is contained in:
6
server/libs/domain/src/access/access.repository.ts
Normal file
6
server/libs/domain/src/access/access.repository.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export const IAccessRepository = 'IAccessRepository';
|
||||
|
||||
export interface IAccessRepository {
|
||||
hasPartnerAccess(userId: string, partnerId: string): Promise<boolean>;
|
||||
hasPartnerAssetAccess(userId: string, assetId: string): Promise<boolean>;
|
||||
}
|
||||
1
server/libs/domain/src/access/index.ts
Normal file
1
server/libs/domain/src/access/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './access.repository';
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './access';
|
||||
export * from './album';
|
||||
export * from './api-key';
|
||||
export * from './asset';
|
||||
@@ -13,10 +14,10 @@ export * from './job';
|
||||
export * from './media';
|
||||
export * from './metadata';
|
||||
export * from './oauth';
|
||||
export * from './partner';
|
||||
export * from './person';
|
||||
export * from './search';
|
||||
export * from './server-info';
|
||||
export * from './partner';
|
||||
export * from './shared-link';
|
||||
export * from './smart-info';
|
||||
export * from './storage';
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
export * from './partner.core';
|
||||
export * from './partner.repository';
|
||||
export * from './partner.service';
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
import { PartnerEntity } from '@app/infra/entities';
|
||||
import { IPartnerRepository, PartnerIds } from './partner.repository';
|
||||
|
||||
export enum PartnerDirection {
|
||||
SharedBy = 'shared-by',
|
||||
SharedWith = 'shared-with',
|
||||
}
|
||||
|
||||
export class PartnerCore {
|
||||
constructor(private repository: IPartnerRepository) {}
|
||||
|
||||
async getAll(userId: string, direction: PartnerDirection): Promise<PartnerEntity[]> {
|
||||
const partners = await this.repository.getAll(userId);
|
||||
const key = direction === PartnerDirection.SharedBy ? 'sharedById' : 'sharedWithId';
|
||||
return partners.filter((partner) => partner[key] === userId);
|
||||
}
|
||||
|
||||
get(ids: PartnerIds): Promise<PartnerEntity | null> {
|
||||
return this.repository.get(ids);
|
||||
}
|
||||
|
||||
async create(ids: PartnerIds): Promise<PartnerEntity> {
|
||||
return this.repository.create(ids);
|
||||
}
|
||||
|
||||
async remove(ids: PartnerIds): Promise<void> {
|
||||
await this.repository.remove(ids as PartnerEntity);
|
||||
}
|
||||
|
||||
hasAssetAccess(assetId: string, userId: string): Promise<boolean> {
|
||||
return this.repository.hasAssetAccess(assetId, userId);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,11 @@ export interface PartnerIds {
|
||||
sharedWithId: string;
|
||||
}
|
||||
|
||||
export enum PartnerDirection {
|
||||
SharedBy = 'shared-by',
|
||||
SharedWith = 'shared-with',
|
||||
}
|
||||
|
||||
export const IPartnerRepository = 'IPartnerRepository';
|
||||
|
||||
export interface IPartnerRepository {
|
||||
@@ -12,5 +17,4 @@ export interface IPartnerRepository {
|
||||
get(partner: PartnerIds): Promise<PartnerEntity | null>;
|
||||
create(partner: PartnerIds): Promise<PartnerEntity>;
|
||||
remove(entity: PartnerEntity): Promise<void>;
|
||||
hasAssetAccess(assetId: string, userId: string): Promise<boolean>;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { BadRequestException } from '@nestjs/common';
|
||||
import { authStub, newPartnerRepositoryMock, partnerStub } from '../../test';
|
||||
import { PartnerDirection } from './partner.core';
|
||||
import { IPartnerRepository } from './partner.repository';
|
||||
import { IPartnerRepository, PartnerDirection } from './partner.repository';
|
||||
import { PartnerService } from './partner.service';
|
||||
|
||||
const responseDto = {
|
||||
|
||||
@@ -1,41 +1,38 @@
|
||||
import { PartnerEntity } from '@app/infra/entities';
|
||||
import { BadRequestException, Inject, Injectable } from '@nestjs/common';
|
||||
import { AuthUserDto } from '../auth';
|
||||
import { IPartnerRepository, PartnerCore, PartnerDirection, PartnerIds } from '../partner';
|
||||
import { IPartnerRepository, PartnerDirection, PartnerIds } from '../partner';
|
||||
import { mapUser, UserResponseDto } from '../user';
|
||||
|
||||
@Injectable()
|
||||
export class PartnerService {
|
||||
private partnerCore: PartnerCore;
|
||||
|
||||
constructor(@Inject(IPartnerRepository) partnerRepository: IPartnerRepository) {
|
||||
this.partnerCore = new PartnerCore(partnerRepository);
|
||||
}
|
||||
constructor(@Inject(IPartnerRepository) private repository: IPartnerRepository) {}
|
||||
|
||||
async create(authUser: AuthUserDto, sharedWithId: string): Promise<UserResponseDto> {
|
||||
const partnerId: PartnerIds = { sharedById: authUser.id, sharedWithId };
|
||||
const exists = await this.partnerCore.get(partnerId);
|
||||
const exists = await this.repository.get(partnerId);
|
||||
if (exists) {
|
||||
throw new BadRequestException(`Partner already exists`);
|
||||
}
|
||||
|
||||
const partner = await this.partnerCore.create(partnerId);
|
||||
const partner = await this.repository.create(partnerId);
|
||||
return this.map(partner, PartnerDirection.SharedBy);
|
||||
}
|
||||
|
||||
async remove(authUser: AuthUserDto, sharedWithId: string): Promise<void> {
|
||||
const partnerId: PartnerIds = { sharedById: authUser.id, sharedWithId };
|
||||
const partner = await this.partnerCore.get(partnerId);
|
||||
const partner = await this.repository.get(partnerId);
|
||||
if (!partner) {
|
||||
throw new BadRequestException('Partner not found');
|
||||
}
|
||||
|
||||
await this.partnerCore.remove(partner);
|
||||
await this.repository.remove(partner);
|
||||
}
|
||||
|
||||
async getAll(authUser: AuthUserDto, direction: PartnerDirection): Promise<UserResponseDto[]> {
|
||||
const partners = await this.partnerCore.getAll(authUser.id, direction);
|
||||
return partners.map((partner) => this.map(partner, direction));
|
||||
const partners = await this.repository.getAll(authUser.id);
|
||||
const key = direction === PartnerDirection.SharedBy ? 'sharedById' : 'sharedWithId';
|
||||
return partners.filter((partner) => partner[key] === authUser.id).map((partner) => this.map(partner, direction));
|
||||
}
|
||||
|
||||
private map(partner: PartnerEntity, direction: PartnerDirection): UserResponseDto {
|
||||
|
||||
8
server/libs/domain/test/access.repository.mock.ts
Normal file
8
server/libs/domain/test/access.repository.mock.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { IAccessRepository } from '../src';
|
||||
|
||||
export const newAccessRepositoryMock = (): jest.Mocked<IAccessRepository> => {
|
||||
return {
|
||||
hasPartnerAccess: jest.fn(),
|
||||
hasPartnerAssetAccess: jest.fn(),
|
||||
};
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './access.repository.mock';
|
||||
export * from './album.repository.mock';
|
||||
export * from './api-key.repository.mock';
|
||||
export * from './asset.repository.mock';
|
||||
|
||||
@@ -6,6 +6,5 @@ export const newPartnerRepositoryMock = (): jest.Mocked<IPartnerRepository> => {
|
||||
remove: jest.fn(),
|
||||
getAll: jest.fn(),
|
||||
get: jest.fn(),
|
||||
hasAssetAccess: jest.fn(),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
IAccessRepository,
|
||||
IAlbumRepository,
|
||||
IAssetRepository,
|
||||
ICommunicationRepository,
|
||||
@@ -30,6 +31,7 @@ import { databaseConfig } from './database.config';
|
||||
import { databaseEntities } from './entities';
|
||||
import { bullConfig, bullQueues } from './infra.config';
|
||||
import {
|
||||
AccessRepository,
|
||||
AlbumRepository,
|
||||
APIKeyRepository,
|
||||
AssetRepository,
|
||||
@@ -53,6 +55,7 @@ import {
|
||||
} from './repositories';
|
||||
|
||||
const providers: Provider[] = [
|
||||
{ provide: IAccessRepository, useClass: AccessRepository },
|
||||
{ provide: IAlbumRepository, useClass: AlbumRepository },
|
||||
{ provide: IAssetRepository, useClass: AssetRepository },
|
||||
{ provide: ICommunicationRepository, useClass: CommunicationRepository },
|
||||
|
||||
38
server/libs/infra/src/repositories/access.repository.ts
Normal file
38
server/libs/infra/src/repositories/access.repository.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { IAccessRepository } from '@app/domain';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { PartnerEntity } from '../entities';
|
||||
|
||||
export class AccessRepository implements IAccessRepository {
|
||||
constructor(@InjectRepository(PartnerEntity) private partnerRepository: Repository<PartnerEntity>) {}
|
||||
|
||||
hasPartnerAccess(userId: string, partnerId: string): Promise<boolean> {
|
||||
return this.partnerRepository.exist({
|
||||
where: {
|
||||
sharedWithId: userId,
|
||||
sharedById: partnerId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
hasPartnerAssetAccess(userId: string, assetId: string): Promise<boolean> {
|
||||
return this.partnerRepository.exist({
|
||||
where: {
|
||||
sharedWith: {
|
||||
id: userId,
|
||||
},
|
||||
sharedBy: {
|
||||
assets: {
|
||||
id: assetId,
|
||||
},
|
||||
},
|
||||
},
|
||||
relations: {
|
||||
sharedWith: true,
|
||||
sharedBy: {
|
||||
assets: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './access.repository';
|
||||
export * from './album.repository';
|
||||
export * from './api-key.repository';
|
||||
export * from './asset.repository';
|
||||
|
||||
@@ -24,27 +24,4 @@ export class PartnerRepository implements IPartnerRepository {
|
||||
async remove(entity: PartnerEntity): Promise<void> {
|
||||
await this.repository.remove(entity);
|
||||
}
|
||||
|
||||
async hasAssetAccess(assetId: string, userId: string): Promise<boolean> {
|
||||
const count = await this.repository.count({
|
||||
where: {
|
||||
sharedWith: {
|
||||
id: userId,
|
||||
},
|
||||
sharedBy: {
|
||||
assets: {
|
||||
id: assetId,
|
||||
},
|
||||
},
|
||||
},
|
||||
relations: {
|
||||
sharedWith: true,
|
||||
sharedBy: {
|
||||
assets: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return count == 1;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user