mirror of
https://github.com/docmost/docmost.git
synced 2026-05-19 07:54:05 +08:00
updates and fixes
* seo friendly urls * custom client serve-static module * database fixes * fix recent pages * other fixes
This commit is contained in:
@@ -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[] };
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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> {
|
||||
|
||||
Reference in New Issue
Block a user