fix: empty and restore over 1,000 items (#12751)
This commit is contained in:
@@ -1,69 +1,86 @@
|
||||
import { Inject } from '@nestjs/common';
|
||||
import { DateTime } from 'luxon';
|
||||
import { OnEmit } from 'src/decorators';
|
||||
import { BulkIdsDto } from 'src/dtos/asset-ids.response.dto';
|
||||
import { AuthDto } from 'src/dtos/auth.dto';
|
||||
import { TrashResponseDto } from 'src/dtos/trash.dto';
|
||||
import { Permission } from 'src/enum';
|
||||
import { IAccessRepository } from 'src/interfaces/access.interface';
|
||||
import { IAssetRepository } from 'src/interfaces/asset.interface';
|
||||
import { IEventRepository } from 'src/interfaces/event.interface';
|
||||
import { IJobRepository, JOBS_ASSET_PAGINATION_SIZE, JobName } from 'src/interfaces/job.interface';
|
||||
import { IJobRepository, JOBS_ASSET_PAGINATION_SIZE, JobName, JobStatus } from 'src/interfaces/job.interface';
|
||||
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
||||
import { ITrashRepository } from 'src/interfaces/trash.interface';
|
||||
import { requireAccess } from 'src/utils/access';
|
||||
import { usePagination } from 'src/utils/pagination';
|
||||
|
||||
export class TrashService {
|
||||
constructor(
|
||||
@Inject(IAccessRepository) private access: IAccessRepository,
|
||||
@Inject(IAssetRepository) private assetRepository: IAssetRepository,
|
||||
@Inject(IJobRepository) private jobRepository: IJobRepository,
|
||||
@Inject(IEventRepository) private eventRepository: IEventRepository,
|
||||
) {}
|
||||
@Inject(IJobRepository) private jobRepository: IJobRepository,
|
||||
@Inject(ITrashRepository) private trashRepository: ITrashRepository,
|
||||
@Inject(ILoggerRepository) private logger: ILoggerRepository,
|
||||
) {
|
||||
this.logger.setContext(TrashService.name);
|
||||
}
|
||||
|
||||
async restoreAssets(auth: AuthDto, dto: BulkIdsDto): Promise<void> {
|
||||
async restoreAssets(auth: AuthDto, dto: BulkIdsDto): Promise<TrashResponseDto> {
|
||||
const { ids } = dto;
|
||||
await requireAccess(this.access, { auth, permission: Permission.ASSET_DELETE, ids });
|
||||
await this.restoreAndSend(auth, ids);
|
||||
}
|
||||
|
||||
async restore(auth: AuthDto): Promise<void> {
|
||||
const assetPagination = usePagination(JOBS_ASSET_PAGINATION_SIZE, (pagination) =>
|
||||
this.assetRepository.getByUserId(pagination, auth.user.id, {
|
||||
trashedBefore: DateTime.now().toJSDate(),
|
||||
}),
|
||||
);
|
||||
|
||||
for await (const assets of assetPagination) {
|
||||
const ids = assets.map((a) => a.id);
|
||||
await this.restoreAndSend(auth, ids);
|
||||
if (ids.length === 0) {
|
||||
return { count: 0 };
|
||||
}
|
||||
|
||||
await requireAccess(this.access, { auth, permission: Permission.ASSET_DELETE, ids });
|
||||
await this.trashRepository.restoreAll(ids);
|
||||
await this.eventRepository.emit('assets.restore', { assetIds: ids, userId: auth.user.id });
|
||||
|
||||
this.logger.log(`Restored ${ids.length} assets from trash`);
|
||||
|
||||
return { count: ids.length };
|
||||
}
|
||||
|
||||
async empty(auth: AuthDto): Promise<void> {
|
||||
async restore(auth: AuthDto): Promise<TrashResponseDto> {
|
||||
const count = await this.trashRepository.restore(auth.user.id);
|
||||
if (count > 0) {
|
||||
this.logger.log(`Restored ${count} assets from trash`);
|
||||
}
|
||||
return { count };
|
||||
}
|
||||
|
||||
async empty(auth: AuthDto): Promise<TrashResponseDto> {
|
||||
const count = await this.trashRepository.empty(auth.user.id);
|
||||
if (count > 0) {
|
||||
await this.jobRepository.queue({ name: JobName.QUEUE_TRASH_EMPTY, data: {} });
|
||||
}
|
||||
return { count };
|
||||
}
|
||||
|
||||
@OnEmit({ event: 'assets.delete' })
|
||||
async onAssetsDelete() {
|
||||
await this.jobRepository.queue({ name: JobName.QUEUE_TRASH_EMPTY, data: {} });
|
||||
}
|
||||
|
||||
async handleQueueEmptyTrash() {
|
||||
let count = 0;
|
||||
const assetPagination = usePagination(JOBS_ASSET_PAGINATION_SIZE, (pagination) =>
|
||||
this.assetRepository.getByUserId(pagination, auth.user.id, {
|
||||
trashedBefore: DateTime.now().toJSDate(),
|
||||
withArchived: true,
|
||||
}),
|
||||
this.trashRepository.getDeletedIds(pagination),
|
||||
);
|
||||
|
||||
for await (const assets of assetPagination) {
|
||||
for await (const assetIds of assetPagination) {
|
||||
this.logger.debug(`Queueing ${assetIds.length} assets for deletion from the trash`);
|
||||
count += assetIds.length;
|
||||
await this.jobRepository.queueAll(
|
||||
assets.map((asset) => ({
|
||||
assetIds.map((assetId) => ({
|
||||
name: JobName.ASSET_DELETION,
|
||||
data: {
|
||||
id: asset.id,
|
||||
id: assetId,
|
||||
deleteOnDisk: true,
|
||||
},
|
||||
})),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async restoreAndSend(auth: AuthDto, ids: string[]) {
|
||||
if (ids.length === 0) {
|
||||
return;
|
||||
}
|
||||
this.logger.log(`Queued ${count} assets for deletion from the trash`);
|
||||
|
||||
await this.assetRepository.restoreAll(ids);
|
||||
await this.eventRepository.emit('assets.restore', { assetIds: ids, userId: auth.user.id });
|
||||
return JobStatus.SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user