updates and fixes

* seo friendly urls
* custom client serve-static module
* database fixes
* fix recent pages
* other fixes
This commit is contained in:
Philipinho
2024-05-18 03:19:42 +01:00
parent eefe63d1cd
commit 9c7c2f1163
102 changed files with 921 additions and 536 deletions
@@ -10,7 +10,7 @@ export class CreatePageDto {
icon?: string;
@IsOptional()
@IsUUID()
@IsString()
parentPageId?: string;
@IsUUID()
@@ -1,13 +1,7 @@
import {
IsString,
IsUUID,
IsOptional,
MinLength,
MaxLength,
} from 'class-validator';
import { IsString, IsOptional, MinLength, MaxLength } from 'class-validator';
export class MovePageDto {
@IsUUID()
@IsString()
pageId: string;
@IsString()
@@ -1,3 +0,0 @@
import { Page } from '@docmost/db/types/entity.types';
export type PageWithOrderingDto = Page & { childrenIds?: string[] };
+2 -2
View File
@@ -1,7 +1,7 @@
import { IsUUID } from 'class-validator';
import { IsString, IsUUID } from 'class-validator';
export class PageIdDto {
@IsUUID()
@IsString()
pageId: string;
}
@@ -1,8 +1,8 @@
import { IsOptional, IsUUID } from 'class-validator';
import { IsOptional, IsString } from 'class-validator';
import { SpaceIdDto } from './page.dto';
export class SidebarPageDto extends SpaceIdDto {
@IsOptional()
@IsUUID()
@IsString()
pageId: string;
}
@@ -1,8 +1,8 @@
import { PartialType } from '@nestjs/mapped-types';
import { CreatePageDto } from './create-page.dto';
import { IsUUID } from 'class-validator';
import { IsString } from 'class-validator';
export class UpdatePageDto extends PartialType(CreatePageDto) {
@IsUUID()
@IsString()
pageId: string;
}
+26 -7
View File
@@ -12,7 +12,7 @@ import { PageService } from './services/page.service';
import { CreatePageDto } from './dto/create-page.dto';
import { UpdatePageDto } from './dto/update-page.dto';
import { MovePageDto } from './dto/move-page.dto';
import { PageHistoryIdDto, PageIdDto, SpaceIdDto } from './dto/page.dto';
import { PageHistoryIdDto, PageIdDto } from './dto/page.dto';
import { PageHistoryService } from './services/page-history.service';
import { AuthUser } from '../../decorators/auth-user.decorator';
import { AuthWorkspace } from '../../decorators/auth-workspace.decorator';
@@ -118,18 +118,23 @@ export class PageController {
@HttpCode(HttpStatus.OK)
@Post('recent')
async getRecentSpacePages(
@Body() spaceIdDto: SpaceIdDto,
@Body() pagination: PaginationOptions,
@AuthUser() user: User,
@AuthWorkspace() workspace: Workspace,
) {
const ability = await this.spaceAbility.createForUser(
user,
spaceIdDto.spaceId,
workspace.defaultSpaceId,
);
if (ability.cannot(SpaceCaslAction.Read, SpaceCaslSubject.Page)) {
throw new ForbiddenException();
}
return this.pageService.getRecentSpacePages(spaceIdDto.spaceId, pagination);
return this.pageService.getRecentSpacePages(
workspace.defaultSpaceId,
pagination,
);
}
// TODO: scope to workspaces
@@ -146,7 +151,7 @@ export class PageController {
throw new ForbiddenException();
}
return this.pageHistoryService.findHistoryByPageId(dto.pageId, pagination);
return this.pageHistoryService.findHistoryByPageId(page.id, pagination);
}
@HttpCode(HttpStatus.OK)
@@ -181,7 +186,17 @@ export class PageController {
if (ability.cannot(SpaceCaslAction.Read, SpaceCaslSubject.Page)) {
throw new ForbiddenException();
}
return this.pageService.getSidebarPages(dto, pagination);
let pageId = null;
if (dto.pageId) {
const page = await this.pageRepo.findById(dto.pageId);
if (page.spaceId !== dto.spaceId) {
throw new ForbiddenException();
}
pageId = page.id;
}
return this.pageService.getSidebarPages(dto.spaceId, pagination, pageId);
}
@HttpCode(HttpStatus.OK)
@@ -207,10 +222,14 @@ export class PageController {
@Post('/breadcrumbs')
async getPageBreadcrumbs(@Body() dto: PageIdDto, @AuthUser() user: User) {
const page = await this.pageRepo.findById(dto.pageId);
if (!page) {
throw new NotFoundException('Page not found');
}
const ability = await this.spaceAbility.createForUser(user, page.spaceId);
if (ability.cannot(SpaceCaslAction.Read, SpaceCaslSubject.Page)) {
throw new ForbiddenException();
}
return this.pageService.getPageBreadCrumbs(dto.pageId);
return this.pageService.getPageBreadCrumbs(page.id);
}
}
@@ -18,7 +18,7 @@ import { generateJitteredKeyBetween } from 'fractional-indexing-jittered';
import { MovePageDto } from '../dto/move-page.dto';
import { ExpressionBuilder } from 'kysely';
import { DB } from '@docmost/db/types/db';
import { SidebarPageDto } from '../dto/sidebar-page.dto';
import { genPageShortId } from '../../../helpers/nanoid.utils';
@Injectable()
export class PageService {
@@ -40,14 +40,19 @@ export class PageService {
workspaceId: string,
createPageDto: CreatePageDto,
): Promise<Page> {
let parentPageId = undefined;
// check if parent page exists
if (createPageDto.parentPageId) {
const parentPage = await this.pageRepo.findById(
createPageDto.parentPageId,
);
if (!parentPage || parentPage.spaceId !== createPageDto.spaceId)
if (!parentPage || parentPage.spaceId !== createPageDto.spaceId) {
throw new NotFoundException('Parent page not found');
}
parentPageId = parentPage.id;
}
let pagePosition: string;
@@ -59,10 +64,10 @@ export class PageService {
.orderBy('position', 'desc')
.limit(1);
if (createPageDto.parentPageId) {
if (parentPageId) {
// check for children of this page
const lastPage = await lastPageQuery
.where('parentPageId', '=', createPageDto.parentPageId)
.where('parentPageId', '=', parentPageId)
.executeTakeFirst();
if (!lastPage) {
@@ -87,10 +92,11 @@ export class PageService {
}
const createdPage = await this.pageRepo.insertPage({
slugId: genPageShortId(),
title: createPageDto.title,
position: pagePosition,
icon: createPageDto.icon,
parentPageId: createPageDto.parentPageId,
parentPageId: parentPageId,
spaceId: createPageDto.spaceId,
creatorId: userId,
workspaceId: workspaceId,
@@ -110,6 +116,7 @@ export class PageService {
title: updatePageDto.title,
icon: updatePageDto.icon,
lastUpdatedById: userId,
updatedAt: new Date(),
},
pageId,
);
@@ -135,13 +142,15 @@ export class PageService {
}
async getSidebarPages(
dto: SidebarPageDto,
spaceId: string,
pagination: PaginationOptions,
pageId?: string,
): Promise<any> {
let query = this.db
.selectFrom('pages')
.select([
'id',
'slugId',
'title',
'icon',
'position',
@@ -151,10 +160,10 @@ export class PageService {
])
.select((eb) => this.withHasChildren(eb))
.orderBy('position', 'asc')
.where('spaceId', '=', dto.spaceId);
.where('spaceId', '=', spaceId);
if (dto.pageId) {
query = query.where('parentPageId', '=', dto.pageId);
if (pageId) {
query = query.where('parentPageId', '=', pageId);
} else {
query = query.where('parentPageId', 'is', null);
}
@@ -185,8 +194,8 @@ export class PageService {
if (!parentPage || parentPage.spaceId !== movedPage.spaceId) {
throw new NotFoundException('Parent page not found');
}
parentPageId = parentPage.id;
}
parentPageId = dto.parentPageId;
}
await this.pageRepo.updatePage(
@@ -205,6 +214,7 @@ export class PageService {
.selectFrom('pages')
.select([
'id',
'slugId',
'title',
'icon',
'position',
@@ -218,6 +228,7 @@ export class PageService {
.selectFrom('pages as p')
.select([
'p.id',
'p.slugId',
'p.title',
'p.icon',
'p.position',
@@ -255,10 +266,7 @@ export class PageService {
spaceId: string,
pagination: PaginationOptions,
): Promise<PaginationResult<Page>> {
const pages = await this.pageRepo.getRecentPagesInSpace(
spaceId,
pagination,
);
const pages = await this.pageRepo.getRecentPageUpdates(spaceId, pagination);
return pages;
}
@@ -267,6 +275,7 @@ export class PageService {
await this.pageRepo.deletePage(pageId);
}
}
/*
// TODO: page deletion and restoration
async delete(pageId: string): Promise<void> {