diff --git a/paw.paw b/paw.paw index c0d04aa9..fa83f3d3 100644 Binary files a/paw.paw and b/paw.paw differ diff --git a/src/app.module.ts b/src/app.module.ts index 0619bb50..52af18f1 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -25,6 +25,7 @@ import { ConfigsModule } from './modules/configs/configs.module' import { InitModule } from './modules/init/init.module' import { NoteModule } from './modules/note/note.module' import { OptionModule } from './modules/option/option.module' +import { PageModule } from './modules/page/page.module' import { PostModule } from './modules/post/post.module' import { UserModule } from './modules/user/user.module' import { CacheModule } from './processors/cache/cache.module' @@ -51,6 +52,7 @@ import { HelperModule } from './processors/helper/helper.module' UserModule, PostModule, NoteModule, + PageModule, CategoryModule, AuthModule, UserModule, diff --git a/src/modules/option/option.controller.ts b/src/modules/option/option.controller.ts index 11cec519..708ff3c6 100644 --- a/src/modules/option/option.controller.ts +++ b/src/modules/option/option.controller.ts @@ -1,4 +1,5 @@ import { + BadRequestException, Body, Controller, Get, @@ -24,16 +25,16 @@ class ConfigKeyDto { @Auth() export class OptionController { constructor( - private readonly adminService: OptionService, + private readonly optionService: OptionService, private readonly configs: ConfigsService, ) {} - @Get() + @Get('/') getOption() { return this.configs.getConfig() } - @Get(':key') + @Get('/:key') getOptionKey(@Param('key') key: keyof IConfig) { if (typeof key !== 'string' && !key) { throw new UnprocessableEntityException( @@ -42,16 +43,16 @@ export class OptionController { } const value = this.configs.get(key) if (!value) { - throw new UnprocessableEntityException('key is not exists.') + throw new BadRequestException('key is not exists.') } return { data: value } } - @Patch(':key') + @Patch('/:key') patch(@Param() params: ConfigKeyDto, @Body() body: Record) { if (typeof body !== 'object') { throw new UnprocessableEntityException('body must be object') } - return this.adminService.patchAndValid(params.key, body) + return this.optionService.patchAndValid(params.key, body) } } diff --git a/src/modules/page/page.controller.ts b/src/modules/page/page.controller.ts new file mode 100644 index 00000000..e3615364 --- /dev/null +++ b/src/modules/page/page.controller.ts @@ -0,0 +1,97 @@ +import { + Body, + Controller, + Delete, + Get, + HttpCode, + Param, + Patch, + Post, + Put, + Query, +} from '@nestjs/common' +import { Auth } from '~/common/decorator/auth.decorator' +import { Paginator } from '~/common/decorator/http.decorator' +import { ApiName } from '~/common/decorator/openapi.decorator' +import { CannotFindException } from '~/common/exceptions/cant-find.exception' +import { MongoIdDto } from '~/shared/dto/id.dto' +import { PagerDto } from '~/shared/dto/pager.dto' +import { PageModel, PartialPageModel } from './page.model' +import { PageService } from './page.service' + +@Controller('pages') +@ApiName +export class PageController { + constructor(private readonly pageService: PageService) {} + + @Get('/') + @Paginator + async getPagesSummary(@Query() query: PagerDto) { + const { size, select, page } = query + + return await this.pageService.model.paginate( + {}, + { + limit: size, + page, + select, + }, + ) + } + + @Get('/:id') + async getPageById(@Param() params: MongoIdDto) { + const page = this.pageService.model.findById(params.id) + if (!page) { + throw new CannotFindException() + } + return page + } + + @Get('/slug/:slug') + async getPageBySlug(@Param('slug') slug: string) { + const page = await this.pageService.model.findOne({ + slug, + }) + + if (!page) { + throw new CannotFindException() + } + return page + } + + @Post('/') + @Auth() + async create(@Body() body: PageModel) { + return await this.pageService.create(body) + } + + @Put('/:id') + @Auth() + async modify(@Body() body: PageModel, @Param() params: MongoIdDto) { + const { id } = params + await this.pageService.updateById(id, body) + + return await this.pageService.model.findById(id) + } + + @Patch('/:id') + @Auth() + @HttpCode(204) + async patch(@Body() body: PartialPageModel, @Param() params: MongoIdDto) { + const { id } = params + await this.pageService.updateById(id, body) + + return + } + + @Delete('/:id') + @Auth() + @HttpCode(204) + async deletePage(@Param() params: MongoIdDto) { + await this.pageService.model.deleteOne({ + _id: params.id, + }) + return + } +} diff --git a/src/modules/page/page.model.ts b/src/modules/page/page.model.ts index 51cf840f..1ea88237 100644 --- a/src/modules/page/page.model.ts +++ b/src/modules/page/page.model.ts @@ -1,3 +1,4 @@ +import { PartialType } from '@nestjs/mapped-types' import { ApiProperty } from '@nestjs/swagger' import { modelOptions, prop } from '@typegoose/typegoose' import { Transform } from 'class-transformer' @@ -11,7 +12,6 @@ import { } from 'class-validator' import { WriteBaseModel } from '~/shared/model/base.model' import { IsNilOrString } from '~/utils/validator/isNilOrString' - export const pageType = ['md', 'html', 'frame'] @modelOptions({ @@ -51,3 +51,5 @@ export class PageModel extends WriteBaseModel { @IsOptional() type?: string } + +export class PartialPageModel extends PartialType(PageModel) {} diff --git a/src/modules/page/page.module.ts b/src/modules/page/page.module.ts new file mode 100644 index 00000000..c51d1a3d --- /dev/null +++ b/src/modules/page/page.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common' +import { GatewayModule } from '~/processors/gateway/gateway.module' +import { PageController } from './page.controller' +import { PageService } from './page.service' + +@Module({ + imports: [GatewayModule], + controllers: [PageController], + providers: [PageService], + exports: [PageService], +}) +export class PageModule {} diff --git a/src/modules/page/page.service.ts b/src/modules/page/page.service.ts new file mode 100644 index 00000000..c58a1869 --- /dev/null +++ b/src/modules/page/page.service.ts @@ -0,0 +1,44 @@ +import { Injectable } from '@nestjs/common' +import { InjectModel } from 'nestjs-typegoose' +import { EventTypes } from '~/processors/gateway/events.types' +import { WebEventsGateway } from '~/processors/gateway/web/events.gateway' +import { ImageService } from '~/processors/helper/helper.image.service' +import { PageModel } from './page.model' + +@Injectable() +export class PageService { + constructor( + @InjectModel(PageModel) + private readonly pageModel: MongooseModel, + private readonly imageService: ImageService, + private readonly webgateService: WebEventsGateway, + ) {} + + public get model() { + return this.pageModel + } + + public async create(doc: PageModel) { + const res = await this.model.create(doc) + process.nextTick(async () => { + await Promise.all([ + this.imageService.recordImageDimensions(this.pageModel, res._id), + ]) + }) + return res + } + + public async updateById(id: string, doc: Partial) { + await this.model.updateOne({ _id: id }, doc) + process.nextTick(async () => { + await Promise.all([ + this.imageService.recordImageDimensions(this.pageModel, id), + this.pageModel + .findById(id) + .then((doc) => + this.webgateService.broadcast(EventTypes.PAGE_UPDATED, doc), + ), + ]) + }) + } +}