Skip to content

Commit

Permalink
feat: demo mode
Browse files Browse the repository at this point in the history
  • Loading branch information
Innei committed May 25, 2022
1 parent f3f452e commit ad1b5f6
Show file tree
Hide file tree
Showing 20 changed files with 114 additions and 9 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
*.paw filter=lfs diff=lfs merge=lfs -text
demo-data.zip filter=lfs diff=lfs merge=lfs -text
5 changes: 4 additions & 1 deletion src/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import { cwd, isDev, isTest } from './global/env.global'

export const PORT = argv.port || process.env.PORT || 2333
export const API_VERSION = 2

export const isInDemoMode = argv.demo || false

export const CROSS_DOMAIN = {
allowedOrigins: argv.allowed_origins
? argv.allowed_origins?.split?.(',')
Expand All @@ -23,7 +26,7 @@ export const CROSS_DOMAIN = {
}

export const MONGO_DB = {
dbName: argv.collection_name || 'mx-space',
dbName: argv.collection_name || (isInDemoMode ? 'mx-space_demo' : 'mx-space'),
host: argv.db_host || '127.0.0.1',
port: argv.db_port || 27017,
get uri() {
Expand Down
3 changes: 2 additions & 1 deletion src/app.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { ApiTags } from '@nestjs/swagger'
import { InjectModel } from '~/transformers/model.transformer'

import PKG from '../package.json'
import { isInDemoMode } from './app.config'
import { Auth } from './common/decorator/auth.decorator'
import { HttpCache } from './common/decorator/cache.decorator'
import { IpLocation, IpRecord } from './common/decorator/ip.decorator'
Expand All @@ -35,7 +36,7 @@ export class AppController {
return {
name: PKG.name,
author: PKG.author,
version: isDev ? 'dev' : PKG.version,
version: isDev ? 'dev' : `${isInDemoMode ? 'demo/' : ''}${PKG.version}`,
homepage: PKG.homepage,
issues: PKG.issues,
}
Expand Down
3 changes: 3 additions & 0 deletions src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { MiddlewareConsumer, Module, NestModule, Type } from '@nestjs/common'
import { APP_FILTER, APP_GUARD, APP_INTERCEPTOR } from '@nestjs/core'

import { isInDemoMode } from './app.config'
import { AppController } from './app.controller'
import { AllExceptionsFilter } from './common/filters/any-exception.filter'
import { RolesGuard } from './common/guard/roles.guard'
Expand All @@ -19,6 +20,7 @@ import { CategoryModule } from './modules/category/category.module'
import { CommentModule } from './modules/comment/comment.module'
import { ConfigsModule } from './modules/configs/configs.module'
import { DebugModule } from './modules/debug/debug.module'
import { DemoModule } from './modules/demo/demo.module'
import { FeedModule } from './modules/feed/feed.module'
import { FileModule } from './modules/file/file.module'
import { HealthModule } from './modules/health/health.module'
Expand Down Expand Up @@ -60,6 +62,7 @@ import { LoggerModule } from './processors/logger/logger.module'
CategoryModule,
CommentModule,
ConfigsModule,
isInDemoMode && DemoModule,
FeedModule,
FileModule,
HealthModule,
Expand Down
13 changes: 13 additions & 0 deletions src/common/decorator/demo.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Observable } from 'rxjs'

import { CanActivate, UseGuards, applyDecorators } from '@nestjs/common'

import { banInDemo } from '~/utils'

class DemoGuard implements CanActivate {
canActivate(): boolean | Promise<boolean> | Observable<boolean> {
banInDemo()
return true
}
}
export const BanInDemo = applyDecorators(UseGuards(DemoGuard))
9 changes: 9 additions & 0 deletions src/common/exceptions/ban-in-demo.exception.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ErrorCodeEnum } from '~/constants/error-code.constant'

import { BusinessException } from './business.exception'

export class BanInDemoExcpetion extends BusinessException {
constructor() {
super(ErrorCodeEnum.BanInDemo)
}
}
4 changes: 4 additions & 0 deletions src/constants/error-code.constant.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
export enum ErrorCodeEnum {
SlugNotAvailable = 'slug_not_available',

BanInDemo = 'ban_in_demo',
}

export const ErrorCode = Object.freeze<Record<ErrorCodeEnum, [string, number]>>(
{
[ErrorCodeEnum.SlugNotAvailable]: ['slug 不可用', 400],

[ErrorCodeEnum.BanInDemo]: ['Demo 模式下此操作不可用', 400],
},
)
2 changes: 2 additions & 0 deletions src/modules/backup/backup.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
import { ApiProperty, ApiResponseProperty } from '@nestjs/swagger'

import { Auth } from '~/common/decorator/auth.decorator'
import { BanInDemo } from '~/common/decorator/demo.decorator'
import { HTTPDecorators } from '~/common/decorator/http.decorator'
import { ApiName } from '~/common/decorator/openapi.decorator'
import { UploadService } from '~/processors/helper/helper.upload.service'
Expand All @@ -28,6 +29,7 @@ import { BackupService } from './backup.service'
@Controller({ path: 'backups', scope: Scope.REQUEST })
@ApiName
@Auth()
@BanInDemo
export class BackupController {
constructor(
private readonly backupService: BackupService,
Expand Down
4 changes: 3 additions & 1 deletion src/modules/backup/backup.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ export class BackupService {
await $`mongodump -h ${MONGO_DB.host} --port ${MONGO_DB.port} -d ${MONGO_DB.dbName} --excludeCollection analyzes -o ${backupDirPath} >/dev/null 2>&1`
// 打包 DB
cd(backupDirPath)
await quiet($`zip -r backup-${dateDir} mx-space/* && rm -rf mx-space`)
await nothrow(quiet($`mv ${MONGO_DB.dbName} mx-space`))
await quiet($`zip -r backup-${dateDir} mx-space/* && rm -rf mx-space`)

// 打包数据目录

Expand Down Expand Up @@ -204,6 +205,7 @@ export class BackupService {
this.cacheService.cleanAllRedisKey(),
this.cacheService.cleanCatch(),
])
await rm(join(dirPath, 'backup_data'), { force: true, recursive: true })
}

async rollbackTo(dirname: string) {
Expand Down
9 changes: 5 additions & 4 deletions src/modules/configs/configs.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ import { EventEmitter2 } from '@nestjs/event-emitter'
import { DocumentType, ReturnModelType } from '@typegoose/typegoose'
import { BeAnObject } from '@typegoose/typegoose/lib/types'

import { isInDemoMode } from '~/app.config'
import { RedisKeys } from '~/constants/cache.constant'
import { EventBusEvents } from '~/constants/event-bus.constant'
import { CacheService } from '~/processors/cache/cache.service'
import { InjectModel } from '~/transformers/model.transformer'
import { sleep } from '~/utils'
import { banInDemo, sleep } from '~/utils'
import { getRedisKey } from '~/utils/redis.util'

import * as optionDtos from '../configs/configs.dto'
Expand Down Expand Up @@ -61,14 +62,13 @@ const generateDefaultConfig: () => IConfig = () => ({
mailOptions: {} as MailOptionsDto,
commentOptions: { antiSpam: false },
friendLinkOptions: { allowApply: true },
backupOptions: { enable: true } as BackupOptionsDto,
backupOptions: { enable: isInDemoMode ? false : true } as BackupOptionsDto,
baiduSearchOptions: { enable: false },
algoliaSearchOptions: { enable: false, apiKey: '', appId: '', indexName: '' },
adminExtra: {
enableAdminProxy: true,
title: 'おかえり~',
background:
'https://gitee.com/xun7788/my-imagination/raw/master/images/88426823_p0.jpg',
background: '',
gaodemapKey: null!,
},
terminalOptions: {
Expand Down Expand Up @@ -209,6 +209,7 @@ export class ConfigsService {
key: T,
value: Partial<IConfig[T]>,
) {
banInDemo()
value = camelcaseKeys(value, { deep: true }) as any

switch (key) {
Expand Down
27 changes: 27 additions & 0 deletions src/modules/demo/demo.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { resolve } from 'path'

import { Module } from '@nestjs/common'
import { Cron, CronExpression } from '@nestjs/schedule'

import { AssetService } from '~/processors/helper/helper.asset.service'

import { BackupModule } from '../backup/backup.module'
import { BackupService } from '../backup/backup.service'

@Module({
imports: [BackupModule],
})
export class DemoModule {
constructor(
private readonly backupService: BackupService,
private readonly assetService: AssetService,
) {
this.reset()
}
@Cron(CronExpression.EVERY_DAY_AT_1AM)
reset() {
this.backupService.restore(
resolve(this.assetService.embedAssetPath, 'demo-data.zip'),
)
}
}
3 changes: 3 additions & 0 deletions src/modules/file/file.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Readable } from 'stream'
import { BadRequestException, Injectable } from '@nestjs/common'

import { STATIC_FILE_DIR } from '~/constants/path.constant'
import { banInDemo } from '~/utils'

import { ConfigsService } from '../configs/configs.service'
import { FileType } from './file.type'
Expand Down Expand Up @@ -33,6 +34,7 @@ export class FileService {
data: Readable,
encoding?: BufferEncoding,
) {
banInDemo()
// eslint-disable-next-line no-async-promise-executor
return new Promise(async (resolve, reject) => {
const filePath = this.resolveFilePath(type, name)
Expand All @@ -58,6 +60,7 @@ export class FileService {
}

deleteFile(type: FileType, name: string) {
banInDemo()
return fs.unlink(this.resolveFilePath(type, name)).catch(() => null)
}

Expand Down
2 changes: 2 additions & 0 deletions src/modules/health/health.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { Reflector } from '@nestjs/core'
import { SchedulerRegistry } from '@nestjs/schedule'

import { Auth } from '~/common/decorator/auth.decorator'
import { BanInDemo } from '~/common/decorator/demo.decorator'
import { HTTPDecorators } from '~/common/decorator/http.decorator'
import { ApiName } from '~/common/decorator/openapi.decorator'
import { CRON_DESCRIPTION } from '~/constants/meta.constant'
Expand Down Expand Up @@ -73,6 +74,7 @@ export class HealthController {
}

@Post('/cron/run/:name')
@BanInDemo
async runCron(@Param('name') name: string) {
if (!isString(name)) {
throw new UnprocessableEntityException('name must be string')
Expand Down
2 changes: 2 additions & 0 deletions src/modules/option/controllers/base.option.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
UnprocessableEntityException,
} from '@nestjs/common'

import { BanInDemo } from '~/common/decorator/demo.decorator'
import { HTTPDecorators } from '~/common/decorator/http.decorator'
import { IConfig } from '~/modules/configs/configs.interface'
import { ConfigsService } from '~/modules/configs/configs.service'
Expand Down Expand Up @@ -50,6 +51,7 @@ export class BaseOptionController {
}

@Patch('/:key')
@BanInDemo
patch(@Param() params: ConfigKeyDto, @Body() body: Record<string, any>) {
if (typeof body !== 'object') {
throw new UnprocessableEntityException('body must be object')
Expand Down
12 changes: 12 additions & 0 deletions src/modules/pty/pty.gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
WebSocketGateway,
} from '@nestjs/websockets'

import { isInDemoMode } from '~/app.config'
import { BusinessEvents } from '~/constants/business-event.constant'
import { RedisKeys } from '~/constants/cache.constant'
import { DATA_DIR } from '~/constants/path.constant'
Expand Down Expand Up @@ -42,6 +43,17 @@ export class PTYGateway
client: Socket,
data?: { password?: string; cols: number; rows: number },
) {
if (isInDemoMode) {
client.send(
this.gatewayMessageFormat(
BusinessEvents.PTY_MESSAGE,
'PTY 在演示模式下不可用',
),
)

return
}

const password = data?.password
const terminalOptions = await this.configService.get('terminalOptions')
if (!terminalOptions.enable) {
Expand Down
4 changes: 4 additions & 0 deletions src/modules/snippet/snippet.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from '@nestjs/common'

import { Auth } from '~/common/decorator/auth.decorator'
import { BanInDemo } from '~/common/decorator/demo.decorator'
import { HTTPDecorators } from '~/common/decorator/http.decorator'
import { ApiName } from '~/common/decorator/openapi.decorator'
import { IsMaster } from '~/common/decorator/role.decorator'
Expand Down Expand Up @@ -74,6 +75,7 @@ export class SnippetController {

@Post('/')
@Auth()
@BanInDemo
async create(@Body() body: SnippetModel) {
return await this.snippetService.create(body)
}
Expand Down Expand Up @@ -146,6 +148,7 @@ export class SnippetController {

@Put('/:id')
@Auth()
@BanInDemo
async update(@Param() param: MongoIdDto, @Body() body: SnippetModel) {
const { id } = param

Expand All @@ -154,6 +157,7 @@ export class SnippetController {

@Delete('/:id')
@Auth()
@BanInDemo
async delete(@Param() param: MongoIdDto) {
const { id } = param
await this.snippetService.delete(id)
Expand Down
3 changes: 2 additions & 1 deletion src/modules/user/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { MasterLostException } from '~/common/exceptions/master-lost.exception'
import { RedisKeys } from '~/constants/cache.constant'
import { CacheService } from '~/processors/cache/cache.service'
import { InjectModel } from '~/transformers/model.transformer'
import { getAvatar, sleep } from '~/utils'
import { banInDemo, getAvatar, sleep } from '~/utils'
import { getRedisKey } from '~/utils/redis.util'

import { AuthService } from '../auth/auth.service'
Expand Down Expand Up @@ -95,6 +95,7 @@ export class UserService {
* @param {Partial} data - 部分修改数据
*/
async patchUserData(user: UserDocument, data: Partial<UserModel>) {
banInDemo()
const { password } = data
const doc = { ...data }
if (password !== undefined) {
Expand Down
5 changes: 4 additions & 1 deletion src/processors/helper/helper.cron.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { Inject, Injectable, Logger, forwardRef } from '@nestjs/common'
import { OnEvent } from '@nestjs/event-emitter'
import { Cron, CronExpression } from '@nestjs/schedule'

import { isMainCluster } from '~/app.config'
import { isInDemoMode, isMainCluster } from '~/app.config'
import { CronDescription } from '~/common/decorator/cron-description.decorator'
import { RedisKeys } from '~/constants/cache.constant'
import { EventBusEvents } from '~/constants/event-bus.constant'
Expand Down Expand Up @@ -82,6 +82,9 @@ export class CronService {
@Cron(CronExpression.EVERY_DAY_AT_1AM, { name: 'backupDB' })
@CronDescription('备份 DB 并上传 COS')
async backupDB({ uploadCOS = true }: { uploadCOS?: boolean } = {}) {
if (isInDemoMode) {
return
}
const backup = await this.backupService.backup()
if (!backup) {
this.logger.log('没有开启备份')
Expand Down
11 changes: 11 additions & 0 deletions src/utils/demo.util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { isInDemoMode } from '~/app.config'
import { BanInDemoExcpetion } from '~/common/exceptions/ban-in-demo.exception'

/**
* 检查是否在 demo 模式下,禁用此功能
*/
export const banInDemo = () => {
if (isInDemoMode) {
throw new BanInDemoExcpetion()
}
}
1 change: 1 addition & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './redis.util'
export * from './system.util'
export * from './time.util'
export * from './tool.util'
export * from './demo.util'

0 comments on commit ad1b5f6

Please sign in to comment.