refactor(server): stacks (#11453)

* refactor: stacks

* mobile: get it built

* chore: feedback

* fix: sync and duplicates

* mobile: remove old stack reference

* chore: add primary asset id

* revert change to asset entity

* mobile: refactor mobile api

* mobile: sync stack info after creating stack

* mobile: update timeline after deleting stack

* server: update asset updatedAt when stack is deleted

* mobile: simplify action

* mobile: rename to match dto property

* fix: web test

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
Jason Rasmussen 2024-08-19 13:37:15 -04:00 committed by GitHub
parent ca52cbace1
commit 8338657eaa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
63 changed files with 2321 additions and 1152 deletions

View file

@ -0,0 +1,84 @@
import { BadRequestException, Inject, Injectable } from '@nestjs/common';
import { AccessCore } from 'src/cores/access.core';
import { BulkIdsDto } from 'src/dtos/asset-ids.response.dto';
import { AuthDto } from 'src/dtos/auth.dto';
import { StackCreateDto, StackResponseDto, StackSearchDto, StackUpdateDto, mapStack } from 'src/dtos/stack.dto';
import { Permission } from 'src/enum';
import { IAccessRepository } from 'src/interfaces/access.interface';
import { ClientEvent, IEventRepository } from 'src/interfaces/event.interface';
import { IStackRepository } from 'src/interfaces/stack.interface';
@Injectable()
export class StackService {
private access: AccessCore;
constructor(
@Inject(IAccessRepository) accessRepository: IAccessRepository,
@Inject(IEventRepository) private eventRepository: IEventRepository,
@Inject(IStackRepository) private stackRepository: IStackRepository,
) {
this.access = AccessCore.create(accessRepository);
}
async search(auth: AuthDto, dto: StackSearchDto): Promise<StackResponseDto[]> {
const stacks = await this.stackRepository.search({
ownerId: auth.user.id,
primaryAssetId: dto.primaryAssetId,
});
return stacks.map((stack) => mapStack(stack, { auth }));
}
async create(auth: AuthDto, dto: StackCreateDto): Promise<StackResponseDto> {
await this.access.requirePermission(auth, Permission.ASSET_UPDATE, dto.assetIds);
const stack = await this.stackRepository.create({ ownerId: auth.user.id, assetIds: dto.assetIds });
this.eventRepository.clientSend(ClientEvent.ASSET_STACK_UPDATE, auth.user.id, []);
return mapStack(stack, { auth });
}
async get(auth: AuthDto, id: string): Promise<StackResponseDto> {
await this.access.requirePermission(auth, Permission.STACK_READ, id);
const stack = await this.findOrFail(id);
return mapStack(stack, { auth });
}
async update(auth: AuthDto, id: string, dto: StackUpdateDto): Promise<StackResponseDto> {
await this.access.requirePermission(auth, Permission.STACK_UPDATE, id);
const stack = await this.findOrFail(id);
if (dto.primaryAssetId && !stack.assets.some(({ id }) => id === dto.primaryAssetId)) {
throw new BadRequestException('Primary asset must be in the stack');
}
const updatedStack = await this.stackRepository.update({ id, primaryAssetId: dto.primaryAssetId });
this.eventRepository.clientSend(ClientEvent.ASSET_STACK_UPDATE, auth.user.id, []);
return mapStack(updatedStack, { auth });
}
async delete(auth: AuthDto, id: string): Promise<void> {
await this.access.requirePermission(auth, Permission.STACK_DELETE, id);
await this.stackRepository.delete(id);
this.eventRepository.clientSend(ClientEvent.ASSET_STACK_UPDATE, auth.user.id, []);
}
async deleteAll(auth: AuthDto, dto: BulkIdsDto): Promise<void> {
await this.access.requirePermission(auth, Permission.STACK_DELETE, dto.ids);
await this.stackRepository.deleteAll(dto.ids);
this.eventRepository.clientSend(ClientEvent.ASSET_STACK_UPDATE, auth.user.id, []);
}
private async findOrFail(id: string) {
const stack = await this.stackRepository.getById(id);
if (!stack) {
throw new Error('Asset stack not found');
}
return stack;
}
}