@@ -60,7 +60,7 @@ app.getInstance().addHook('onRequest', (request, reply, done) => {
|
||||
})
|
||||
|
||||
app.register(fastifyCookie, {
|
||||
secret: 'cookie-secret', // 这个 secret 不太重要, 不存鉴权相关, 无关紧要
|
||||
secret: 'cookie-secret', // 这个 secret 不太重要,不存鉴权相关,无关紧要
|
||||
})
|
||||
|
||||
const logWarn = (desc: string, req: FastifyRequest, context: string) => {
|
||||
|
||||
@@ -3,11 +3,11 @@ import { sample } from 'lodash'
|
||||
import { NotFoundException } from '@nestjs/common'
|
||||
|
||||
export const NotFoundMessage = [
|
||||
'真不巧, 内容走丢了 o(╥﹏╥)o',
|
||||
'真不巧,内容走丢了 o(╥﹏╥)o',
|
||||
'电波无法到达 ωω',
|
||||
'数据..不小心丢失了啦 π_π',
|
||||
'404, 这也不是我的错啦 (๐•̆ ·̭ •̆๐)',
|
||||
'嘿, 这里空空如也, 不如别处走走?',
|
||||
'嘿,这里空空如也,不如别处走走?',
|
||||
]
|
||||
|
||||
export class CannotFindException extends NotFoundException {
|
||||
|
||||
@@ -128,7 +128,7 @@ export class AllExceptionsFilter implements ExceptionFilter {
|
||||
} else {
|
||||
const ip = getIp(request)
|
||||
this.logger.warn(
|
||||
`IP: ${ip} 错误信息: (${status}) ${message} Path: ${decodeURI(url)}`,
|
||||
`IP: ${ip} 错误信息:(${status}) ${message} Path: ${decodeURI(url)}`,
|
||||
)
|
||||
}
|
||||
// @ts-ignore
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* 处理 Article 类型响应, 增加计数
|
||||
* 处理 Article 类型响应,增加计数
|
||||
* @author Innei
|
||||
*/
|
||||
import { map } from 'rxjs'
|
||||
|
||||
@@ -28,17 +28,17 @@ import { registerJSONGlobal } from './json.global'
|
||||
function mkdirs() {
|
||||
if (!CLUSTER.enable || cluster.isPrimary) {
|
||||
mkdirSync(DATA_DIR, { recursive: true })
|
||||
Logger.log(chalk.blue(`数据目录已经建好: ${DATA_DIR}`))
|
||||
Logger.log(chalk.blue(`数据目录已经建好:${DATA_DIR}`))
|
||||
mkdirSync(TEMP_DIR, { recursive: true })
|
||||
Logger.log(chalk.blue(`临时目录已经建好: ${TEMP_DIR}`))
|
||||
Logger.log(chalk.blue(`临时目录已经建好:${TEMP_DIR}`))
|
||||
mkdirSync(LOG_DIR, { recursive: true })
|
||||
Logger.log(chalk.blue(`日志目录已经建好: ${LOG_DIR}`))
|
||||
Logger.log(chalk.blue(`日志目录已经建好:${LOG_DIR}`))
|
||||
mkdirSync(USER_ASSET_DIR, { recursive: true })
|
||||
Logger.log(chalk.blue(`资源目录已经建好: ${USER_ASSET_DIR}`))
|
||||
Logger.log(chalk.blue(`资源目录已经建好:${USER_ASSET_DIR}`))
|
||||
mkdirSync(STATIC_FILE_DIR, { recursive: true })
|
||||
Logger.log(chalk.blue(`文件存放目录已经建好: ${STATIC_FILE_DIR}`))
|
||||
Logger.log(chalk.blue(`文件存放目录已经建好:${STATIC_FILE_DIR}`))
|
||||
mkdirSync(THEME_DIR, { recursive: true })
|
||||
// Logger.log(chalk.blue(`主题目录已经建好: ${THEME_DIR}`))
|
||||
// Logger.log(chalk.blue(`主题目录已经建好:${THEME_DIR}`))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ export class BackupService {
|
||||
this.logger.log('--> 备份成功')
|
||||
} catch (e) {
|
||||
this.logger.error(
|
||||
`--> 备份失败, 请确保已安装 zip 或 mongo-tools, mongo-tools 的版本需要与 mongod 版本一致, ${e.message}` ||
|
||||
`--> 备份失败,请确保已安装 zip 或 mongo-tools, mongo-tools 的版本需要与 mongod 版本一致,${e.message}` ||
|
||||
e.stderr,
|
||||
)
|
||||
throw e
|
||||
@@ -169,7 +169,7 @@ export class BackupService {
|
||||
try {
|
||||
// 验证
|
||||
if (!existsSync(join(dirPath, 'mx-space'))) {
|
||||
throw new InternalServerErrorException('备份文件错误, 目录不存在')
|
||||
throw new InternalServerErrorException('备份文件错误,目录不存在')
|
||||
}
|
||||
|
||||
cd(dirPath)
|
||||
|
||||
@@ -178,7 +178,7 @@ export class CategoryController {
|
||||
category._id,
|
||||
)
|
||||
if (postsInCategory.length > 0) {
|
||||
throw new BadRequestException('该分类中有其他文章, 无法被删除')
|
||||
throw new BadRequestException('该分类中有其他文章,无法被删除')
|
||||
}
|
||||
const res = await this.categoryService.model.deleteOne({
|
||||
_id: category._id,
|
||||
|
||||
@@ -38,7 +38,7 @@ export class MultiCategoriesQueryDto {
|
||||
@IsOptional()
|
||||
@IsMongoId({
|
||||
each: true,
|
||||
message: '多分类查询使用逗号分隔, 应为 mongoID',
|
||||
message: '多分类查询使用逗号分隔,应为 mongoID',
|
||||
})
|
||||
@Transform(({ value: v }) => uniq(v.split(',')))
|
||||
ids?: Array<string>
|
||||
|
||||
@@ -151,7 +151,7 @@ export class CommentOptionsDto {
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@JSONSchemaNumberField('超时时间', {
|
||||
description: '获取 IP 归属地的超时时间。单位: 毫秒。如获取超时则不记录',
|
||||
description: '获取 IP 归属地的超时时间。单位:毫秒。如获取超时则不记录',
|
||||
})
|
||||
fetchLocationTimeout?: number
|
||||
}
|
||||
@@ -161,7 +161,7 @@ export class BackupOptionsDto {
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
@JSONSchemaToggleField('开启自动备份', {
|
||||
description: '填写以下 COS 信息, 将同时上传备份到 COS',
|
||||
description: '填写以下 COS 信息,将同时上传备份到 COS',
|
||||
})
|
||||
enable: boolean
|
||||
|
||||
@@ -314,7 +314,7 @@ export class BarkOptionsDto {
|
||||
@IsUrl()
|
||||
@IsOptional()
|
||||
@JSONSchemaPlainField('服务器 URL', {
|
||||
description: '如果不填写, 则使用默认的服务器, https://day.app/',
|
||||
description: '如果不填写,则使用默认的服务器,https://day.app/',
|
||||
})
|
||||
serverUrl: string
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ export class FeedController {
|
||||
<published>${item.created}</published>
|
||||
<updated>${item.modified}</updated>
|
||||
<content type='html'><![CDATA[
|
||||
${`<blockquote>该渲染由 marked 生成,可能存在排版问题,最佳体验请前往: <a href='${xss(
|
||||
${`<blockquote>该渲染由 marked 生成,可能存在排版问题,最佳体验请前往:<a href='${xss(
|
||||
item.link,
|
||||
)}'>${xss(item.link)}</a></blockquote>
|
||||
${await this.markdownService
|
||||
|
||||
@@ -47,7 +47,7 @@ export class InitController {
|
||||
) {
|
||||
const { isInit } = await this.isInit()
|
||||
if (isInit) {
|
||||
throw new BadRequestException('已经完成初始化, 请登录后进行设置')
|
||||
throw new BadRequestException('已经完成初始化,请登录后进行设置')
|
||||
}
|
||||
if (typeof body !== 'object') {
|
||||
throw new UnprocessableEntityException('body must be object')
|
||||
|
||||
@@ -108,9 +108,9 @@ export class LinkService {
|
||||
console.log(`
|
||||
To: ${model.email}
|
||||
你的友链已通过
|
||||
站点标题: ${model.name}
|
||||
站点网站: ${model.url}
|
||||
站点描述: ${model.description}`)
|
||||
站点标题:${model.name}
|
||||
站点网站:${model.url}
|
||||
站点描述:${model.description}`)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -123,10 +123,10 @@ export class LinkService {
|
||||
async sendToMaster(authorName: string, model: LinkModel) {
|
||||
const enable = (await this.configs.get('mailOptions')).enable
|
||||
if (!enable || isDev) {
|
||||
console.log(`来自 ${authorName} 的友链请求:
|
||||
站点标题: ${model.name}
|
||||
站点网站: ${model.url}
|
||||
站点描述: ${model.description}`)
|
||||
console.log(`来自 ${authorName} 的友链请求:
|
||||
站点标题:${model.name}
|
||||
站点网站:${model.url}
|
||||
站点描述:${model.description}`)
|
||||
return
|
||||
}
|
||||
process.nextTick(async () => {
|
||||
@@ -164,12 +164,12 @@ export class LinkService {
|
||||
: `嘿!~, 主人已通过你的友链申请!~`,
|
||||
text:
|
||||
template === LinkApplyEmailType.ToMaster
|
||||
? `来自 ${model.name} 的友链请求:
|
||||
站点标题: ${model.name}
|
||||
站点网站: ${model.url}
|
||||
站点描述: ${model.description}
|
||||
? `来自 ${model.name} 的友链请求:
|
||||
站点标题:${model.name}
|
||||
站点网站:${model.url}
|
||||
站点描述:${model.description}
|
||||
`
|
||||
: `你的友链申请: ${model.name}, ${model.url} 已通过`,
|
||||
: `你的友链申请:${model.name}, ${model.url} 已通过`,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ export class LinkService {
|
||||
const health = await Promise.all(
|
||||
links.map(({ id, url }) => {
|
||||
Logger.debug(
|
||||
`检查友链 ${id} 的健康状态: GET -> ${url}`,
|
||||
`检查友链 ${id} 的健康状态:GET -> ${url}`,
|
||||
LinkService.name,
|
||||
)
|
||||
return this.http.axiosRef
|
||||
@@ -232,7 +232,7 @@ export class LinkService {
|
||||
const { seo, mailOptions } = await this.configsService.waitForConfigReady()
|
||||
const { enable } = mailOptions
|
||||
if (!enable || isDev) {
|
||||
console.log(`友链结果通知: ${reason}, 状态: ${state}`)
|
||||
console.log(`友链结果通知:${reason}, 状态:${state}`)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -242,7 +242,7 @@ export class LinkService {
|
||||
from,
|
||||
to: doc.email,
|
||||
subject: `嘿!~, 主人已处理你的友链申请!~`,
|
||||
text: `申请结果: ${LinkStateMap[state]}\n原因: ${reason}`,
|
||||
text: `申请结果:${LinkStateMap[state]}\n原因:${reason}`,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ export class NoteService {
|
||||
)
|
||||
|
||||
// 是否存在上一条记录 (旧记录)
|
||||
// 统一: next 为较老的记录 prev 为较新的记录
|
||||
// 统一:next 为较老的记录 prev 为较新的记录
|
||||
// FIXME may cause bug
|
||||
const next = await this.noteModel
|
||||
.findOne({
|
||||
|
||||
@@ -20,7 +20,7 @@ export class EmailOptionController {
|
||||
return {
|
||||
template,
|
||||
props: {
|
||||
author: '评论人Kemmer',
|
||||
author: '评论人 Kemmer',
|
||||
link: 'https://example.com',
|
||||
mail: 'example@example.com',
|
||||
text: '这是一段回复评论',
|
||||
|
||||
@@ -101,7 +101,7 @@ export class PageProxyController {
|
||||
await this.service.getAdminLastestVersionFromGHRelease()
|
||||
} catch (e) {
|
||||
reply.type('application/json').status(500).send({
|
||||
message: '从获取 GitHub 获取数据失败, 连接超时',
|
||||
message: '从获取 GitHub 获取数据失败,连接超时',
|
||||
})
|
||||
throw e
|
||||
}
|
||||
@@ -124,7 +124,7 @@ export class PageProxyController {
|
||||
}
|
||||
|
||||
return await Promise.any(tasks).catch((e) => {
|
||||
const err = '网络连接异常, 所有请求均失败, 无法获取后台入口文件'
|
||||
const err = '网络连接异常,所有请求均失败,无法获取后台入口文件'
|
||||
reply.type('application/json').status(500).send({ message: err })
|
||||
throw new InternalServerErrorException(err)
|
||||
})
|
||||
|
||||
@@ -32,7 +32,7 @@ export class PageProxyDebugDto {
|
||||
__version?: string
|
||||
|
||||
/**
|
||||
* 无缓存访问, redis no
|
||||
* 无缓存访问,redis no
|
||||
*/
|
||||
@IsBoolean()
|
||||
@Transform(({ value }) => (value === 'true' ? true : false))
|
||||
|
||||
@@ -113,7 +113,7 @@ export class RenderEjsController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 后台预览 Markdown 可用接口, 传入 `title` 和 `md`
|
||||
* 后台预览 Markdown 可用接口,传入 `title` 和 `md`
|
||||
*/
|
||||
@Post('/markdown')
|
||||
@HttpCache.disable
|
||||
|
||||
@@ -20,7 +20,7 @@ export class SearchDto extends PagerDto {
|
||||
@Transform(({ value: val }) => parseInt(val))
|
||||
@IsEnum([1, -1])
|
||||
@IsOptional()
|
||||
@ApiProperty({ description: '倒序|正序', enum: [1, -1], required: false })
|
||||
@ApiProperty({ description: '倒序 | 正序', enum: [1, -1], required: false })
|
||||
order: number
|
||||
|
||||
@IsOptional()
|
||||
|
||||
@@ -31,7 +31,7 @@ const len = 10
|
||||
|
||||
`require` 进行了重新处理,是一个异步函数。
|
||||
|
||||
使用方法:
|
||||
使用方法:
|
||||
|
||||
```js
|
||||
// require built-in module
|
||||
@@ -52,13 +52,13 @@ const remoteModule =
|
||||
await require('https://gist.githubusercontent.com/Innei/865b40849d61c2200f1c6ec99c48f716/raw/b4ceb3af6b5a52040a1f31594e5ee53154b8b6d5/case-1.js') // ok
|
||||
```
|
||||
|
||||
目前受信任的三方库前缀: `@mx-space` `@innei` `mx-function-`
|
||||
目前受信任的三方库前缀:`@mx-space` `@innei` `mx-function-`
|
||||
|
||||
受信任的三方库,可在 `snippet.service.ts` 中找到。
|
||||
|
||||
**注意**:这是一个完全隔离(可能存在逃逸,请及时指出)的执行上下文,你不能编写某些在 NodeJS 运行时正常执行的代码。
|
||||
|
||||
比如: `process` 中只有只读的 env 可以获取,其他方法都被移除; `setTimeout` 等 API 被移除。但是你可以在独立模块中使用这些 API,需要注意,内存泄漏和安全性。
|
||||
比如:`process` 中只有只读的 env 可以获取,其他方法都被移除; `setTimeout` 等 API 被移除。但是你可以在独立模块中使用这些 API,需要注意,内存泄漏和安全性。
|
||||
|
||||
`require(id, useCache)` require 支持第二个参数,默认为 true,这是 NodeJS 的默认行为,可以设定为 `false` 以禁用 `require` 的缓存,但是会增加性能开销。
|
||||
|
||||
@@ -110,7 +110,7 @@ import * as ejs from 'ejs'
|
||||
|
||||
`context.reference` same as model.reference
|
||||
|
||||
`context.writeAsset(path: string, data: any, options)` 该方法用于写入配置文件。考虑安全性,会对 path 进行简单转化,删除所有返回上级的符号, e.g. `./../a` => `./a`
|
||||
`context.writeAsset(path: string, data: any, options)` 该方法用于写入配置文件。考虑安全性,会对 path 进行简单转化,删除所有返回上级的符号,e.g. `./../a` => `./a`
|
||||
|
||||
`context.readAsset(path: string, data: any, options)` 该方法用于读取配置文件。
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ export class SnippetModel extends BaseModel {
|
||||
@IsOptional()
|
||||
comment?: string
|
||||
|
||||
// 元数据类型 (预留二级类型,暂时不用)
|
||||
// 元数据类型(预留二级类型,暂时不用)
|
||||
@prop({ maxlength: 20 })
|
||||
@MaxLength(20)
|
||||
@IsString()
|
||||
|
||||
@@ -204,7 +204,7 @@ export class SnippetService {
|
||||
/**
|
||||
*
|
||||
* @param name
|
||||
* @param reference 引用类型, 可以理解为 type, 或者一级分类
|
||||
* @param reference 引用类型,可以理解为 type, 或者一级分类
|
||||
* @returns
|
||||
*/
|
||||
async getSnippetByName(name: string, reference: string) {
|
||||
|
||||
@@ -62,7 +62,7 @@ export class ToolService {
|
||||
return res
|
||||
}
|
||||
} catch (e) {
|
||||
throw new BizException(`IP API 调用失败, ${e.message}`)
|
||||
throw new BizException(`IP API 调用失败,${e.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ export class UserService {
|
||||
.select(`${getLoginIp ? ' +lastLoginIp' : ''}`)
|
||||
.lean({ virtuals: true })
|
||||
if (!user) {
|
||||
throw new BadRequestException('没有完成初始化!')
|
||||
throw new BadRequestException('没有完成初始化!')
|
||||
}
|
||||
const avatar = user.avatar ?? getAvatar(user.mail)
|
||||
return { ...user, avatar }
|
||||
@@ -85,7 +85,7 @@ export class UserService {
|
||||
* 修改密码
|
||||
*
|
||||
* @async
|
||||
* @param {DocumentType} user - 用户查询结果, 已经挂载在 req.user
|
||||
* @param {DocumentType} user - 用户查询结果,已经挂载在 req.user
|
||||
* @param {Partial} data - 部分修改数据
|
||||
*/
|
||||
async patchUserData(user: UserDocument, data: Partial<UserModel>) {
|
||||
@@ -118,7 +118,7 @@ export class UserService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录登陆的足迹(ip, 时间)
|
||||
* 记录登陆的足迹 (ip, 时间)
|
||||
*
|
||||
* @async
|
||||
* @param {string} ip - string
|
||||
@@ -138,7 +138,7 @@ export class UserService {
|
||||
lastLoginIp: ip,
|
||||
})
|
||||
|
||||
this.Logger.warn(`主人已登录, IP: ${ip}`)
|
||||
this.Logger.warn(`主人已登录,IP: ${ip}`)
|
||||
return PrevFootstep as any
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,6 @@ export class DanmakuDto {
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@MaxLength(50, { message: '长度不能超过50个字符' })
|
||||
@MaxLength(50, { message: '长度不能超过 50 个字符' })
|
||||
text: string
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import { USER_ASSET_DIR } from '~/constants/path.constant'
|
||||
|
||||
import { HttpService } from './helper.http.service'
|
||||
|
||||
// 先从 ASSET_DIR 找用户自定义的资源, 没有就从默认的 ASSET_DIR 找, 没有就从网上拉取, 存到默认的 ASSET_DIR
|
||||
// 先从 ASSET_DIR 找用户自定义的资源,没有就从默认的 ASSET_DIR 找,没有就从网上拉取,存到默认的 ASSET_DIR
|
||||
@Injectable()
|
||||
export class AssetService {
|
||||
private logger: Logger
|
||||
|
||||
@@ -46,7 +46,7 @@ export class BarkPushService {
|
||||
|
||||
await this.push({
|
||||
title: '收到一条新评论',
|
||||
body: `${comment.author} 评论了你的文章: ${comment.text}`,
|
||||
body: `${comment.author} 评论了你的文章:${comment.text}`,
|
||||
icon: comment.avatar,
|
||||
url: `${adminUrl}#/comments`,
|
||||
})
|
||||
|
||||
@@ -212,10 +212,10 @@ export class CronService {
|
||||
},
|
||||
},
|
||||
)
|
||||
this.logger.log(`百度站长提交结果: ${JSON.stringify(res.data)}`)
|
||||
this.logger.log(`百度站长提交结果:${JSON.stringify(res.data)}`)
|
||||
return res.data
|
||||
} catch (e) {
|
||||
this.logger.error(`百度推送错误: ${e.message}`)
|
||||
this.logger.error(`百度推送错误:${e.message}`)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
@@ -309,7 +309,7 @@ export class CronService {
|
||||
|
||||
this.logger.log('--> 推送到 algoliasearch 成功')
|
||||
} catch (err) {
|
||||
Logger.error('algolia推送错误', 'AlgoliaSearch')
|
||||
Logger.error('algolia 推送错误', 'AlgoliaSearch')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ export class UploadService {
|
||||
const data = await req.file()
|
||||
|
||||
if (!data) {
|
||||
throw new BadRequestException('仅供上传文件!')
|
||||
throw new BadRequestException('仅供上传文件!')
|
||||
}
|
||||
if (data.fieldname != 'file') {
|
||||
throw new BadRequestException('字段必须为 file')
|
||||
|
||||
Reference in New Issue
Block a user