added recycle bin modal, updated api routes

This commit is contained in:
Eddy Oyieko
2024-09-18 11:18:32 +03:00
parent 4e69f91420
commit bda2dda12d
10 changed files with 316 additions and 3 deletions

View File

@ -0,0 +1,7 @@
import { IsOptional, IsString } from 'class-validator';
export class DeletedPageDto {
@IsOptional()
@IsString()
spaceId: string;
}

View File

@ -27,6 +27,7 @@ import {
import SpaceAbilityFactory from '../casl/abilities/space-ability.factory';
import { PageRepo } from '@docmost/db/repos/page/page.repo';
import { RecentPageDto } from './dto/recent-page.dto';
import { DeletedPageDto } from './dto/deleted-page.dto';
@UseGuards(JwtAuthGuard)
@Controller('pages')
@ -112,6 +113,23 @@ export class PageController {
await this.pageService.forceDelete(pageIdDto.pageId);
}
@HttpCode(HttpStatus.OK)
@Post('remove')
async remove(@Body() pageIdDto: PageIdDto, @AuthUser() user: User) {
const page = await this.pageRepo.findById(pageIdDto.pageId);
if (!page) {
throw new NotFoundException('Page not found');
}
const ability = await this.spaceAbility.createForUser(user, page.spaceId);
if (ability.cannot(SpaceCaslAction.Manage, SpaceCaslSubject.Page)) {
throw new ForbiddenException();
}
await this.pageService.remove(pageIdDto.pageId);
}
@HttpCode(HttpStatus.OK)
@Post('restore')
async restore(@Body() pageIdDto: PageIdDto) {
@ -144,6 +162,30 @@ export class PageController {
return this.pageService.getRecentPages(user.id, pagination);
}
@HttpCode(HttpStatus.OK)
@Post('deleted')
async getDeletedPages(
@Body() deletedPageDto: DeletedPageDto,
@Body() pagination: PaginationOptions,
@AuthUser() user: User,
) {
if (deletedPageDto.spaceId) {
const ability = await this.spaceAbility.createForUser(
user,
deletedPageDto.spaceId,
);
if (ability.cannot(SpaceCaslAction.Read, SpaceCaslSubject.Page)) {
throw new ForbiddenException();
}
return this.pageService.getDeletedSpacePages(
deletedPageDto.spaceId,
pagination,
);
}
}
// TODO: scope to workspaces
@HttpCode(HttpStatus.OK)
@Post('/history')

View File

@ -228,6 +228,7 @@ export class PageService {
])
.select((eb) => this.withHasChildren(eb))
.where('id', '=', childPageId)
.where('deletedAt', 'is not', null)
.unionAll((exp) =>
exp
.selectFrom('pages as p')
@ -281,10 +282,21 @@ export class PageService {
return await this.pageRepo.getRecentPages(userId, pagination);
}
async getDeletedSpacePages(
spaceId: string,
pagination: PaginationOptions,
): Promise<PaginationResult<Page>> {
return await this.pageRepo.getDeletedPagesInSpace(spaceId, pagination);
}
async forceDelete(pageId: string): Promise<void> {
await this.pageRepo.deletePage(pageId);
}
async remove(pageId: string): Promise<void> {
await this.pageRepo.removePage(pageId);
}
async restore(pageId: string): Promise<void> {
await this.pageRepo.restorePage(pageId);
}

View File

@ -106,7 +106,7 @@ export class PageRepo {
.executeTakeFirst();
}
async deletePage(pageId: string): Promise<void> {
async removePage(pageId: string): Promise<void> {
let query = this.db.updateTable('pages').set({ deletedAt: new Date() });
if (isValidUUID(pageId)) {
@ -118,6 +118,18 @@ export class PageRepo {
await query.execute();
}
async deletePage(pageId: string): Promise<void> {
let query = this.db.deleteFrom('pages');
if (isValidUUID(pageId)) {
query = query.where('id', '=', pageId);
} else {
query = query.where('slugId', '=', pageId);
}
await query.execute();
}
async restorePage(pageId: string): Promise<void> {
let query = this.db.updateTable('pages').set({ deletedAt: null });
@ -164,6 +176,23 @@ export class PageRepo {
return result;
}
async getDeletedPagesInSpace(spaceId: string, pagination: PaginationOptions) {
const query = this.db
.selectFrom('pages')
.select(this.baseFields)
.select((eb) => this.withSpace(eb))
.where('spaceId', '=', spaceId)
.where('deletedAt', 'is not', null)
.orderBy('updatedAt', 'desc');
const result = executeWithPagination(query, {
page: pagination.page,
perPage: pagination.limit,
});
return result;
}
withSpace(eb: ExpressionBuilder<DB, 'pages'>) {
return jsonObjectFrom(
eb