refactor(server): library service (#8050)

* refactor: library service

* chore: open api

* fix: checks
This commit is contained in:
Jason Rasmussen 2024-03-18 15:59:53 -05:00 committed by GitHub
parent 761e7fdd2d
commit 40262c30cb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 198 additions and 335 deletions

View file

@ -8,8 +8,7 @@ import { EventEmitter } from 'node:events';
import { Stats } from 'node:fs';
import path, { basename, parse } from 'node:path';
import picomatch from 'picomatch';
import { AccessCore, Permission } from '../access';
import { AuthDto } from '../auth';
import { AccessCore } from '../access';
import { mimeTypes } from '../domain.constant';
import { handlePromiseError, usePagination, validateCronExpression } from '../domain.util';
import { IBaseJob, IEntityJob, ILibraryFileJob, ILibraryRefreshJob, JOBS_ASSET_PAGINATION_SIZE, JobName } from '../job';
@ -226,24 +225,17 @@ export class LibraryService extends EventEmitter {
}
}
async getStatistics(auth: AuthDto, id: string): Promise<LibraryStatsResponseDto> {
await this.access.requirePermission(auth, Permission.LIBRARY_READ, id);
async getStatistics(id: string): Promise<LibraryStatsResponseDto> {
await this.findOrFail(id);
return this.repository.getStatistics(id);
}
async getCount(auth: AuthDto): Promise<number> {
return this.repository.getCountForUser(auth.user.id);
}
async get(auth: AuthDto, id: string): Promise<LibraryResponseDto> {
await this.access.requirePermission(auth, Permission.LIBRARY_READ, id);
async get(id: string): Promise<LibraryResponseDto> {
const library = await this.findOrFail(id);
return mapLibrary(library);
}
async getAll(auth: AuthDto, dto: SearchLibraryDto): Promise<LibraryResponseDto[]> {
async getAll(dto: SearchLibraryDto): Promise<LibraryResponseDto[]> {
const libraries = await this.repository.getAll(false, dto.type);
return libraries.map((library) => mapLibrary(library));
}
@ -257,7 +249,7 @@ export class LibraryService extends EventEmitter {
return JobStatus.SUCCESS;
}
async create(auth: AuthDto, dto: CreateLibraryDto): Promise<LibraryResponseDto> {
async create(dto: CreateLibraryDto): Promise<LibraryResponseDto> {
switch (dto.type) {
case LibraryType.EXTERNAL: {
if (!dto.name) {
@ -282,14 +274,8 @@ export class LibraryService extends EventEmitter {
}
}
let ownerId = auth.user.id;
if (dto.ownerId) {
ownerId = dto.ownerId;
}
const library = await this.repository.create({
ownerId,
ownerId: dto.ownerId,
name: dto.name,
type: dto.type,
importPaths: dto.importPaths ?? [],
@ -297,7 +283,7 @@ export class LibraryService extends EventEmitter {
isVisible: dto.isVisible ?? true,
});
this.logger.log(`Creating ${dto.type} library for user ${auth.user.name}`);
this.logger.log(`Creating ${dto.type} library for ${dto.ownerId}}`);
if (dto.type === LibraryType.EXTERNAL) {
await this.watch(library.id);
@ -364,29 +350,19 @@ export class LibraryService extends EventEmitter {
return validation;
}
public async validate(auth: AuthDto, id: string, dto: ValidateLibraryDto): Promise<ValidateLibraryResponseDto> {
await this.access.requirePermission(auth, Permission.LIBRARY_UPDATE, id);
const response = new ValidateLibraryResponseDto();
if (dto.importPaths) {
response.importPaths = await Promise.all(
dto.importPaths.map(async (importPath) => {
return await this.validateImportPath(importPath);
}),
);
}
return response;
async validate(id: string, dto: ValidateLibraryDto): Promise<ValidateLibraryResponseDto> {
const importPaths = await Promise.all(
(dto.importPaths || []).map((importPath) => this.validateImportPath(importPath)),
);
return { importPaths };
}
async update(auth: AuthDto, id: string, dto: UpdateLibraryDto): Promise<LibraryResponseDto> {
await this.access.requirePermission(auth, Permission.LIBRARY_UPDATE, id);
async update(id: string, dto: UpdateLibraryDto): Promise<LibraryResponseDto> {
await this.findOrFail(id);
const library = await this.repository.update({ id, ...dto });
if (dto.importPaths) {
const validation = await this.validate(auth, id, { importPaths: dto.importPaths });
const validation = await this.validate(id, { importPaths: dto.importPaths });
if (validation.importPaths) {
for (const path of validation.importPaths) {
if (!path.isValid) {
@ -404,11 +380,9 @@ export class LibraryService extends EventEmitter {
return mapLibrary(library);
}
async delete(auth: AuthDto, id: string) {
await this.access.requirePermission(auth, Permission.LIBRARY_DELETE, id);
async delete(id: string) {
const library = await this.findOrFail(id);
const uploadCount = await this.repository.getUploadLibraryCount(auth.user.id);
const uploadCount = await this.repository.getUploadLibraryCount(library.ownerId);
if (library.type === LibraryType.UPLOAD && uploadCount <= 1) {
throw new BadRequestException('Cannot delete the last upload library');
}
@ -565,11 +539,9 @@ export class LibraryService extends EventEmitter {
return JobStatus.SUCCESS;
}
async queueScan(auth: AuthDto, id: string, dto: ScanLibraryDto) {
await this.access.requirePermission(auth, Permission.LIBRARY_UPDATE, id);
const library = await this.repository.get(id);
if (!library || library.type !== LibraryType.EXTERNAL) {
async queueScan(id: string, dto: ScanLibraryDto) {
const library = await this.findOrFail(id);
if (library.type !== LibraryType.EXTERNAL) {
throw new BadRequestException('Can only refresh external libraries');
}
@ -583,16 +555,9 @@ export class LibraryService extends EventEmitter {
});
}
async queueRemoveOffline(auth: AuthDto, id: string) {
async queueRemoveOffline(id: string) {
this.logger.verbose(`Removing offline files from library: ${id}`);
await this.access.requirePermission(auth, Permission.LIBRARY_UPDATE, id);
await this.jobRepository.queue({
name: JobName.LIBRARY_REMOVE_OFFLINE,
data: {
id,
},
});
await this.jobRepository.queue({ name: JobName.LIBRARY_REMOVE_OFFLINE, data: { id } });
}
async handleQueueAllScan(job: IBaseJob): Promise<JobStatus> {