@@ -1,17 +0,0 @@
|
||||
assets/types/type.declare.ts
|
||||
|
||||
node_modules
|
||||
dist
|
||||
out
|
||||
packages/*/node_modules
|
||||
packages/*/dist
|
||||
packages/*/out
|
||||
packages/*/lib
|
||||
packages/*/build
|
||||
packages/*/coverage
|
||||
packages/*/test
|
||||
packages/*/tests
|
||||
packages/*/esm
|
||||
packages/*/types
|
||||
|
||||
test/**/*.db.ts
|
||||
@@ -1,37 +0,0 @@
|
||||
module.exports = {
|
||||
extends: ['@innei/eslint-config-ts'],
|
||||
root: true,
|
||||
parserOptions: {
|
||||
emitDecoratorMetadata: true,
|
||||
},
|
||||
plugins: ['unused-imports', '@typescript-eslint'],
|
||||
rules: {
|
||||
'no-empty': 'warn',
|
||||
'no-fallthrough': 'error',
|
||||
'no-unused-vars': 'off', // or "@typescript-eslint/no-unused-vars": "off",
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'unused-imports/no-unused-imports': 'error',
|
||||
|
||||
'unused-imports/no-unused-vars': [
|
||||
'warn',
|
||||
{
|
||||
vars: 'all',
|
||||
varsIgnorePattern: '^_',
|
||||
args: 'after-used',
|
||||
argsIgnorePattern: '^_',
|
||||
},
|
||||
],
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: [
|
||||
'apps/core/src/migration/**/*.ts',
|
||||
'apps/core/src/modules/serverless/pack/**/*.ts',
|
||||
'apps/core/test/**/*.ts',
|
||||
],
|
||||
rules: {
|
||||
'import/no-default-export': 'off',
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { factory } from '@innei/prettier'
|
||||
export default {
|
||||
...factory({
|
||||
tailwindcss: false,
|
||||
importSort: false,
|
||||
}),
|
||||
importOrderParserPlugins: ['typescript', 'jsx', 'decorators-legacy'],
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
/* eslint-disable @typescript-eslint/consistent-type-imports */
|
||||
|
||||
import type { AxiosRequestConfig } from 'axios'
|
||||
|
||||
export const PORT = process.env.PORT || 2333
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
/* eslint-disable @typescript-eslint/consistent-type-imports */
|
||||
import { readFileSync } from 'fs'
|
||||
import path from 'path'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { program } from 'commander'
|
||||
import { load as yamlLoad } from 'js-yaml'
|
||||
import { machineIdSync } from 'node-machine-id'
|
||||
import type { AxiosRequestConfig } from 'axios'
|
||||
|
||||
import { isDebugMode, isDev } from './global/env.global'
|
||||
import { parseBooleanishValue } from './utils'
|
||||
import type { AxiosRequestConfig } from 'axios'
|
||||
|
||||
const commander = program
|
||||
.option('-p, --port <number>', 'server port')
|
||||
@@ -166,9 +165,7 @@ export const ENCRYPT = {
|
||||
algorithm: argv.encrypt_algorithm || 'aes-256-ecb',
|
||||
}
|
||||
|
||||
if (ENCRYPT.enable) {
|
||||
if (!ENCRYPT.key || ENCRYPT.key.length !== 64)
|
||||
throw new Error(
|
||||
`你开启了 Key 加密(MX_ENCRYPT_KEY or --encrypt_key),但是 Key 的长度不为 64,当前:${ENCRYPT.key.length}`,
|
||||
)
|
||||
}
|
||||
if (ENCRYPT.enable && (!ENCRYPT.key || ENCRYPT.key.length !== 64))
|
||||
throw new Error(
|
||||
`你开启了 Key 加密(MX_ENCRYPT_KEY or --encrypt_key),但是 Key 的长度不为 64,当前:${ENCRYPT.key.length}`,
|
||||
)
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
import { LoggerModule } from 'nestjs-pretty-logger'
|
||||
import type {
|
||||
DynamicModule,
|
||||
MiddlewareConsumer,
|
||||
NestModule,
|
||||
Type,
|
||||
} from '@nestjs/common'
|
||||
|
||||
import { Module } from '@nestjs/common'
|
||||
import { APP_FILTER, APP_GUARD, APP_INTERCEPTOR } from '@nestjs/core'
|
||||
@@ -66,6 +60,12 @@ import { DatabaseModule } from './processors/database/database.module'
|
||||
import { GatewayModule } from './processors/gateway/gateway.module'
|
||||
import { HelperModule } from './processors/helper/helper.module'
|
||||
import { RedisModule } from './processors/redis/redis.module'
|
||||
import type {
|
||||
DynamicModule,
|
||||
MiddlewareConsumer,
|
||||
NestModule,
|
||||
Type,
|
||||
} from '@nestjs/common'
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import cluster from 'cluster'
|
||||
import { performance } from 'perf_hooks'
|
||||
import cluster from 'node:cluster'
|
||||
import { performance } from 'node:perf_hooks'
|
||||
import { Logger } from 'nestjs-pretty-logger'
|
||||
import wcmatch from 'wildcard-match'
|
||||
import type { LogLevel } from '@nestjs/common'
|
||||
import type { NestFastifyApplication } from '@nestjs/platform-fastify'
|
||||
|
||||
import { NestFactory } from '@nestjs/core'
|
||||
|
||||
@@ -18,6 +16,8 @@ import { logger } from './global/consola.global'
|
||||
import { isMainProcess, isTest } from './global/env.global'
|
||||
import { migrateDatabase } from './migration/migrate'
|
||||
import { checkInit } from './utils/check-init.util'
|
||||
import type { NestFastifyApplication } from '@nestjs/platform-fastify'
|
||||
import type { LogLevel } from '@nestjs/common'
|
||||
|
||||
const Origin: false | string[] = Array.isArray(CROSS_DOMAIN.allowedOrigins)
|
||||
? [...CROSS_DOMAIN.allowedOrigins, '*.shizuri.net', '22333322.xyz']
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import cluster from 'cluster'
|
||||
import os from 'os'
|
||||
import cluster from 'node:cluster'
|
||||
import os from 'node:os'
|
||||
|
||||
import { logger } from './global/consola.global'
|
||||
|
||||
export class Cluster {
|
||||
static register(workers: number, callback: Function): void {
|
||||
export const Cluster = {
|
||||
register(workers: number, callback: Function): void {
|
||||
if (cluster.isPrimary) {
|
||||
const cpus = os.cpus().length
|
||||
|
||||
@@ -38,7 +38,7 @@ export class Cluster {
|
||||
cluster.on('online', (worker) => {
|
||||
logger.info('Worker %s is online', worker.process.pid)
|
||||
})
|
||||
cluster.on('exit', (worker, code, signal) => {
|
||||
cluster.on('exit', (worker, code, _signal) => {
|
||||
if (code !== 0) {
|
||||
logger.info(`Worker ${worker.process.pid} died. Restarting`)
|
||||
cluster.fork()
|
||||
@@ -47,5 +47,5 @@ export class Cluster {
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import type { FastifyRequest } from 'fastify'
|
||||
|
||||
import fastifyCookie from '@fastify/cookie'
|
||||
import FastifyMultipart from '@fastify/multipart'
|
||||
import { Logger } from '@nestjs/common'
|
||||
import { FastifyAdapter } from '@nestjs/platform-fastify'
|
||||
|
||||
import { getIp } from '~/utils'
|
||||
import type { FastifyRequest } from 'fastify'
|
||||
|
||||
const app: FastifyAdapter = new FastifyAdapter({
|
||||
trustProxy: true,
|
||||
@@ -39,7 +38,7 @@ app.getInstance().addHook('onRequest', (request, reply, done) => {
|
||||
logWarn('PHP 是世界上最好的语言!!!!!', request, 'GodPHP')
|
||||
|
||||
return reply.code(418).send()
|
||||
} else if (url.match(/\/(adminer|admin|wp-login|phpMyAdmin|\.env)$/gi)) {
|
||||
} else if (/\/(adminer|admin|wp-login|phpmyadmin|\.env)$/gi.test(url)) {
|
||||
const isMxSpaceClient = ua?.match('mx-space')
|
||||
reply.raw.statusMessage = 'Hey, What the fuck are you doing!'
|
||||
reply.raw.statusCode = isMxSpaceClient ? 666 : 200
|
||||
@@ -53,7 +52,7 @@ app.getInstance().addHook('onRequest', (request, reply, done) => {
|
||||
}
|
||||
|
||||
// skip favicon request
|
||||
if (url.match(/favicon\.ico$/) || url.match(/manifest\.json$/)) {
|
||||
if (/favicon\.ico$/.test(url) || /manifest\.json$/.test(url)) {
|
||||
return reply.code(204).send()
|
||||
}
|
||||
|
||||
@@ -64,7 +63,7 @@ app.register(fastifyCookie, {
|
||||
secret: 'cookie-secret', // 这个 secret 不太重要,不存鉴权相关,无关紧要
|
||||
})
|
||||
|
||||
const logWarn = (desc: string, req: FastifyRequest, context: string) => {
|
||||
const logWarn = (desc: string, req: FastifyRequest, _context: string) => {
|
||||
const ua = req.raw.headers['user-agent']
|
||||
Logger.warn(
|
||||
// prettier-ignore
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import type { Server } from 'socket.io'
|
||||
|
||||
import { IoAdapter } from '@nestjs/platform-socket.io'
|
||||
import { createAdapter } from '@socket.io/redis-adapter'
|
||||
|
||||
import { redisSubPub } from '~/utils/redis-subpub.util'
|
||||
import type { Server } from 'socket.io'
|
||||
|
||||
export const RedisIoAdapterKey = 'mx-core-socket'
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// @reference https://github.com/ever-co/ever-gauzy/blob/d36b4f40b1446f3c33d02e0ba00b53a83109d950/packages/core/src/core/context/request-context.ts
|
||||
import * as cls from 'cls-hooked'
|
||||
import type { UserDocument } from '~/modules/user/user.model'
|
||||
import type { IncomingMessage, ServerResponse } from 'http'
|
||||
|
||||
import { UnauthorizedException } from '@nestjs/common'
|
||||
import type { UserDocument } from '~/modules/user/user.model'
|
||||
import type { IncomingMessage, ServerResponse } from 'node:http'
|
||||
|
||||
type Nullable<T> = T | null
|
||||
export class RequestContext {
|
||||
@@ -40,7 +39,7 @@ export class RequestContext {
|
||||
const requestContext = RequestContext.currentRequestContext()
|
||||
|
||||
if (requestContext) {
|
||||
const user: UserDocument = requestContext.request['user']
|
||||
const user: UserDocument = requestContext.request.user
|
||||
|
||||
if (user) {
|
||||
return user
|
||||
@@ -59,8 +58,8 @@ export class RequestContext {
|
||||
|
||||
if (requestContext) {
|
||||
const isAuthenticated =
|
||||
requestContext.request['isAuthenticated'] ||
|
||||
requestContext.request['isAuthenticated']
|
||||
requestContext.request.isAuthenticated ||
|
||||
requestContext.request.isAuthenticated
|
||||
|
||||
return !!isAuthenticated
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import type { ControllerOptions } from '@nestjs/common'
|
||||
|
||||
import { Controller } from '@nestjs/common'
|
||||
|
||||
import { API_VERSION } from '~/app.config'
|
||||
import { isDev } from '~/global/env.global'
|
||||
import type { ControllerOptions } from '@nestjs/common'
|
||||
|
||||
export const apiRoutePrefix = isDev ? '' : `/api/v${API_VERSION}`
|
||||
export const ApiController: (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { applyDecorators, UseGuards } from '@nestjs/common'
|
||||
import { UseGuards, applyDecorators } from '@nestjs/common'
|
||||
|
||||
import { AuthGuard } from '../guards/auth.guard'
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ export function HttpCache(option: ICacheOption): MethodDecorator {
|
||||
if (key) {
|
||||
CacheKey(key)(descriptor.value)
|
||||
}
|
||||
if (typeof ttl === 'number' && !isNaN(ttl)) {
|
||||
if (typeof ttl === 'number' && !Number.isNaN(ttl)) {
|
||||
CacheTTL(ttl)(descriptor.value)
|
||||
}
|
||||
return descriptor
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { createParamDecorator } from '@nestjs/common'
|
||||
import type { ExecutionContext } from '@nestjs/common'
|
||||
import type { FastifyRequest } from 'fastify'
|
||||
|
||||
import { createParamDecorator } from '@nestjs/common'
|
||||
|
||||
export const Cookies = createParamDecorator(
|
||||
(data: string, ctx: ExecutionContext) => {
|
||||
const request = ctx.switchToHttp().getRequest<FastifyRequest>()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import cluster from 'cluster'
|
||||
import cluster from 'node:cluster'
|
||||
|
||||
import { Cron } from '@nestjs/schedule'
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import type { ExecutionContext } from '@nestjs/common'
|
||||
|
||||
import { createParamDecorator } from '@nestjs/common'
|
||||
|
||||
import { getNestExecutionContextRequest } from '~/transformers/get-req.transformer'
|
||||
import type { ExecutionContext } from '@nestjs/common'
|
||||
|
||||
export const CurrentUser = createParamDecorator(
|
||||
(data: unknown, ctx: ExecutionContext) => {
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { UseGuards, applyDecorators } from '@nestjs/common'
|
||||
import { banInDemo } from '~/utils'
|
||||
import type { CanActivate } from '@nestjs/common'
|
||||
import type { Observable } from 'rxjs'
|
||||
|
||||
import { applyDecorators, UseGuards } from '@nestjs/common'
|
||||
|
||||
import { banInDemo } from '~/utils'
|
||||
|
||||
class DemoGuard implements CanActivate {
|
||||
canActivate(): boolean | Promise<boolean> | Observable<boolean> {
|
||||
banInDemo()
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import type { IdempotenceOption } from '../interceptors/idempotence.interceptor'
|
||||
|
||||
import { SetMetadata } from '@nestjs/common'
|
||||
|
||||
import {
|
||||
@@ -7,6 +5,7 @@ import {
|
||||
HTTP_RES_TRANSFORM_PAGINATE,
|
||||
} from '~/constants/meta.constant'
|
||||
import * as SYSTEM from '~/constants/system.constant'
|
||||
import type { IdempotenceOption } from '../interceptors/idempotence.interceptor'
|
||||
|
||||
/**
|
||||
* @description 分页转换
|
||||
|
||||
@@ -6,13 +6,11 @@
|
||||
* @FilePath: /mx-server/src/core/decorators/ip.decorator.ts
|
||||
* @Coding with Love
|
||||
*/
|
||||
import { createParamDecorator } from '@nestjs/common'
|
||||
import { getIp } from '~/utils/ip.util'
|
||||
import type { ExecutionContext } from '@nestjs/common'
|
||||
import type { FastifyRequest } from 'fastify'
|
||||
|
||||
import { createParamDecorator } from '@nestjs/common'
|
||||
|
||||
import { getIp } from '~/utils/ip.util'
|
||||
|
||||
export type IpRecord = {
|
||||
ip: string
|
||||
agent: string
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import type { ExecutionContext } from '@nestjs/common'
|
||||
|
||||
import { createParamDecorator } from '@nestjs/common'
|
||||
|
||||
import { isTest } from '~/global/env.global'
|
||||
import { getNestExecutionContextRequest } from '~/transformers/get-req.transformer'
|
||||
import type { ExecutionContext } from '@nestjs/common'
|
||||
|
||||
export const IsGuest = createParamDecorator(
|
||||
(data: unknown, ctx: ExecutionContext) => {
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import { resolve } from 'path'
|
||||
import type { ArgumentsHost, ExceptionFilter } from '@nestjs/common'
|
||||
import type { FastifyReply, FastifyRequest } from 'fastify'
|
||||
import type { WriteStream } from 'fs'
|
||||
import { resolve } from 'node:path'
|
||||
|
||||
import {
|
||||
Catch,
|
||||
@@ -24,6 +21,9 @@ import { EventManagerService } from '~/processors/helper/helper.event.service'
|
||||
import { getIp } from '../../utils/ip.util'
|
||||
import { BizException } from '../exceptions/biz.exception'
|
||||
import { LoggingInterceptor } from '../interceptors/logging.interceptor'
|
||||
import type { WriteStream } from 'node:fs'
|
||||
import type { FastifyReply, FastifyRequest } from 'fastify'
|
||||
import type { ArgumentsHost, ExceptionFilter } from '@nestjs/common'
|
||||
|
||||
type myError = {
|
||||
readonly status: number
|
||||
@@ -50,11 +50,11 @@ export class AllExceptionsFilter implements ExceptionFilter {
|
||||
return
|
||||
}
|
||||
process.on('unhandledRejection', (reason: any) => {
|
||||
console.error('unhandledRejection: ', reason)
|
||||
console.error('unhandledRejection:', reason)
|
||||
})
|
||||
|
||||
process.on('uncaughtException', (err) => {
|
||||
console.error('uncaughtException: ', err)
|
||||
console.error('uncaughtException:', err)
|
||||
this.eventManager.broadcast(
|
||||
EventBusEvents.SystemException,
|
||||
{ message: err?.message ?? err, stack: err?.stack || '' },
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import { isJWT } from 'class-validator'
|
||||
import type { CanActivate, ExecutionContext } from '@nestjs/common'
|
||||
import type { UserModel } from '~/modules/user/user.model'
|
||||
import type { FastifyBizRequest } from '~/transformers/get-req.transformer'
|
||||
|
||||
import { Injectable, UnauthorizedException } from '@nestjs/common'
|
||||
|
||||
@@ -9,6 +6,9 @@ import { AuthService } from '~/modules/auth/auth.service'
|
||||
import { ConfigsService } from '~/modules/configs/configs.service'
|
||||
import { UserService } from '~/modules/user/user.service'
|
||||
import { getNestExecutionContextRequest } from '~/transformers/get-req.transformer'
|
||||
import type { FastifyBizRequest } from '~/transformers/get-req.transformer'
|
||||
import type { UserModel } from '~/modules/user/user.model'
|
||||
import type { CanActivate, ExecutionContext } from '@nestjs/common'
|
||||
|
||||
/**
|
||||
* JWT auth guard
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import type { CanActivate, ExecutionContext } from '@nestjs/common'
|
||||
|
||||
import { Injectable } from '@nestjs/common'
|
||||
|
||||
import { AuthService } from '~/modules/auth/auth.service'
|
||||
@@ -8,6 +6,7 @@ import { UserService } from '~/modules/user/user.service'
|
||||
import { getNestExecutionContextRequest } from '~/transformers/get-req.transformer'
|
||||
|
||||
import { AuthGuard } from './auth.guard'
|
||||
import type { CanActivate, ExecutionContext } from '@nestjs/common'
|
||||
|
||||
/**
|
||||
* 区分游客和主人的守卫
|
||||
@@ -29,7 +28,6 @@ export class RolesGuard extends AuthGuard implements CanActivate {
|
||||
try {
|
||||
await super.canActivate(context)
|
||||
isAuthenticated = true
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch {}
|
||||
|
||||
request.isGuest = !isAuthenticated
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
* @description 禁止爬虫的守卫
|
||||
* @author Innei <https://innei.ren>
|
||||
*/
|
||||
import type { CanActivate, ExecutionContext } from '@nestjs/common'
|
||||
import type { Observable } from 'rxjs'
|
||||
|
||||
import { ForbiddenException, Injectable } from '@nestjs/common'
|
||||
|
||||
import { isDev } from '~/global/env.global'
|
||||
import { getNestExecutionContextRequest } from '~/transformers/get-req.transformer'
|
||||
import type { Observable } from 'rxjs'
|
||||
import type { CanActivate, ExecutionContext } from '@nestjs/common'
|
||||
|
||||
@Injectable()
|
||||
export class SpiderGuard implements CanActivate {
|
||||
@@ -24,8 +24,8 @@ export class SpiderGuard implements CanActivate {
|
||||
const headers = request.headers
|
||||
const ua: string = headers['user-agent'] || ''
|
||||
const isSpiderUA =
|
||||
!!ua.match(/(Scrapy|HttpClient|axios|python|requests)/i) &&
|
||||
!ua.match(/(mx-space|rss|google|baidu|bing)/gi)
|
||||
!!/(scrapy|httpclient|axios|python|requests)/i.test(ua) &&
|
||||
!/(mx-space|rss|google|baidu|bing)/gi.test(ua)
|
||||
if (ua && !isSpiderUA) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import type { ExecutionContext } from '@nestjs/common'
|
||||
import type { FastifyBizRequest } from '~/transformers/get-req.transformer'
|
||||
|
||||
import { Injectable } from '@nestjs/common'
|
||||
import { ThrottlerGuard } from '@nestjs/throttler'
|
||||
|
||||
import { getNestExecutionContextRequest } from '~/transformers/get-req.transformer'
|
||||
import { getIp } from '~/utils'
|
||||
import type { FastifyBizRequest } from '~/transformers/get-req.transformer'
|
||||
import type { ExecutionContext } from '@nestjs/common'
|
||||
|
||||
@Injectable()
|
||||
export class ExtendThrottlerGuard extends ThrottlerGuard {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { RequestMethod } from '@nestjs/common'
|
||||
import type {
|
||||
CallHandler,
|
||||
ExecutionContext,
|
||||
@@ -5,8 +6,6 @@ import type {
|
||||
} from '@nestjs/common'
|
||||
import type { FastifyReply } from 'fastify'
|
||||
|
||||
import { RequestMethod } from '@nestjs/common'
|
||||
|
||||
export class AllowAllCorsInterceptor implements NestInterceptor {
|
||||
intercept(context: ExecutionContext, next: CallHandler<any>) {
|
||||
const handle = next.handle()
|
||||
|
||||
@@ -4,15 +4,9 @@
|
||||
* @module interceptor/analyze
|
||||
* @author Innei <https://github.com/Innei>
|
||||
*/
|
||||
import { URL } from 'url'
|
||||
import { URL } from 'node:url'
|
||||
import { isbot } from 'isbot'
|
||||
import UAParser from 'ua-parser-js'
|
||||
import type {
|
||||
CallHandler,
|
||||
ExecutionContext,
|
||||
NestInterceptor,
|
||||
} from '@nestjs/common'
|
||||
import type { Observable } from 'rxjs'
|
||||
|
||||
import { Inject, Injectable } from '@nestjs/common'
|
||||
import { Reflector } from '@nestjs/core'
|
||||
@@ -29,6 +23,12 @@ import { InjectModel } from '~/transformers/model.transformer'
|
||||
import { scheduleManager } from '~/utils'
|
||||
import { getIp } from '~/utils/ip.util'
|
||||
import { getRedisKey } from '~/utils/redis.util'
|
||||
import type { Observable } from 'rxjs'
|
||||
import type {
|
||||
CallHandler,
|
||||
ExecutionContext,
|
||||
NestInterceptor,
|
||||
} from '@nestjs/common'
|
||||
|
||||
@Injectable()
|
||||
export class AnalyzeInterceptor implements NestInterceptor {
|
||||
@@ -141,8 +141,8 @@ export class AnalyzeInterceptor implements NestInterceptor {
|
||||
})
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -6,13 +6,6 @@
|
||||
* @author Innei <https://innei.ren>
|
||||
*/
|
||||
import { of, tap } from 'rxjs'
|
||||
import type {
|
||||
CallHandler,
|
||||
ExecutionContext,
|
||||
NestInterceptor,
|
||||
} from '@nestjs/common'
|
||||
import type { FastifyReply } from 'fastify'
|
||||
import type { Observable } from 'rxjs'
|
||||
|
||||
import { Inject, Injectable, Logger, RequestMethod } from '@nestjs/common'
|
||||
import { HttpAdapterHost, Reflector } from '@nestjs/core'
|
||||
@@ -23,6 +16,13 @@ import * as META from '~/constants/meta.constant'
|
||||
import * as SYSTEM from '~/constants/system.constant'
|
||||
import { CacheService } from '~/processors/redis/cache.service'
|
||||
import { getNestExecutionContextRequest } from '~/transformers/get-req.transformer'
|
||||
import type { Observable } from 'rxjs'
|
||||
import type { FastifyReply } from 'fastify'
|
||||
import type {
|
||||
CallHandler,
|
||||
ExecutionContext,
|
||||
NestInterceptor,
|
||||
} from '@nestjs/common'
|
||||
|
||||
/**
|
||||
* @class HttpCacheInterceptor
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import qs from 'qs'
|
||||
import { Injectable } from '@nestjs/common'
|
||||
import { getNestExecutionContextRequest } from '~/transformers/get-req.transformer'
|
||||
import type {
|
||||
CallHandler,
|
||||
ExecutionContext,
|
||||
@@ -6,10 +8,6 @@ import type {
|
||||
} from '@nestjs/common'
|
||||
import type { Observable } from 'rxjs'
|
||||
|
||||
import { Injectable } from '@nestjs/common'
|
||||
|
||||
import { getNestExecutionContextRequest } from '~/transformers/get-req.transformer'
|
||||
|
||||
/** 此拦截器用于转换 req.query.query -> js object,用于直接数据库查询,需要鉴权 */
|
||||
@Injectable()
|
||||
export class DbQueryInterceptor implements NestInterceptor {
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
import { catchError, tap } from 'rxjs'
|
||||
import type {
|
||||
CallHandler,
|
||||
ExecutionContext,
|
||||
NestInterceptor,
|
||||
} from '@nestjs/common'
|
||||
import type { FastifyRequest } from 'fastify'
|
||||
|
||||
import {
|
||||
ConflictException,
|
||||
@@ -21,6 +15,12 @@ import {
|
||||
import { REFLECTOR } from '~/constants/system.constant'
|
||||
import { CacheService } from '~/processors/redis/cache.service'
|
||||
import { getIp, getRedisKey, hashString } from '~/utils'
|
||||
import type { FastifyRequest } from 'fastify'
|
||||
import type {
|
||||
CallHandler,
|
||||
ExecutionContext,
|
||||
NestInterceptor,
|
||||
} from '@nestjs/common'
|
||||
|
||||
const IdempotenceHeaderKey = 'x-idempotence'
|
||||
|
||||
@@ -89,8 +89,8 @@ export class IdempotenceInterceptor implements NestInterceptor {
|
||||
const key = disableGenerateKey
|
||||
? undefined
|
||||
: options.generateKey
|
||||
? options.generateKey(request)
|
||||
: this.generateKey(request)
|
||||
? options.generateKey(request)
|
||||
: this.generateKey(request)
|
||||
|
||||
const idempotenceKey =
|
||||
!!(idempotence || key) && getRedisKey(`idempotence:${idempotence || key}`)
|
||||
|
||||
@@ -5,17 +5,17 @@
|
||||
import { isObjectLike } from 'lodash'
|
||||
import { map } from 'rxjs'
|
||||
import snakecaseKeys from 'snakecase-keys'
|
||||
import type {
|
||||
CallHandler,
|
||||
ExecutionContext,
|
||||
NestInterceptor,
|
||||
} from '@nestjs/common'
|
||||
import type { Observable } from 'rxjs'
|
||||
|
||||
import { Injectable } from '@nestjs/common'
|
||||
import { Reflector } from '@nestjs/core'
|
||||
|
||||
import { RESPONSE_PASSTHROUGH_METADATA } from '~/constants/system.constant'
|
||||
import type { Observable } from 'rxjs'
|
||||
import type {
|
||||
CallHandler,
|
||||
ExecutionContext,
|
||||
NestInterceptor,
|
||||
} from '@nestjs/common'
|
||||
|
||||
@Injectable()
|
||||
export class JSONTransformInterceptor implements NestInterceptor {
|
||||
|
||||
@@ -6,17 +6,17 @@
|
||||
* @author Innei <https://github.com/Innei>
|
||||
*/
|
||||
import { tap } from 'rxjs/operators'
|
||||
import type {
|
||||
CallHandler,
|
||||
ExecutionContext,
|
||||
NestInterceptor,
|
||||
} from '@nestjs/common'
|
||||
import type { Observable } from 'rxjs'
|
||||
|
||||
import { Injectable, Logger, SetMetadata } from '@nestjs/common'
|
||||
|
||||
import { HTTP_REQUEST_TIME } from '~/constants/meta.constant'
|
||||
import { getNestExecutionContextRequest } from '~/transformers/get-req.transformer'
|
||||
import type { Observable } from 'rxjs'
|
||||
import type {
|
||||
CallHandler,
|
||||
ExecutionContext,
|
||||
NestInterceptor,
|
||||
} from '@nestjs/common'
|
||||
|
||||
@Injectable()
|
||||
export class LoggingInterceptor implements NestInterceptor {
|
||||
|
||||
@@ -4,12 +4,6 @@
|
||||
*/
|
||||
import { isArrayLike } from 'lodash'
|
||||
import { map } from 'rxjs/operators'
|
||||
import type {
|
||||
CallHandler,
|
||||
ExecutionContext,
|
||||
NestInterceptor,
|
||||
} from '@nestjs/common'
|
||||
import type { Observable } from 'rxjs'
|
||||
|
||||
import { Injectable } from '@nestjs/common'
|
||||
import { Reflector } from '@nestjs/core'
|
||||
@@ -17,6 +11,12 @@ import { Reflector } from '@nestjs/core'
|
||||
import { HTTP_RES_TRANSFORM_PAGINATE } from '~/constants/meta.constant'
|
||||
import * as SYSTEM from '~/constants/system.constant'
|
||||
import { transformDataToPaginate } from '~/transformers/paginate.transformer'
|
||||
import type { Observable } from 'rxjs'
|
||||
import type {
|
||||
CallHandler,
|
||||
ExecutionContext,
|
||||
NestInterceptor,
|
||||
} from '@nestjs/common'
|
||||
|
||||
export interface Response<T> {
|
||||
data: T
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
// https://github.dev/ever-co/ever-gauzy/packages/core/src/core/context/request-context.middleware.ts
|
||||
|
||||
import * as cls from 'cls-hooked'
|
||||
import type { NestMiddleware } from '@nestjs/common'
|
||||
import type { IncomingMessage, ServerResponse } from 'http'
|
||||
|
||||
import { Injectable } from '@nestjs/common'
|
||||
|
||||
import { RequestContext } from '../contexts/request.context'
|
||||
import type { NestMiddleware } from '@nestjs/common'
|
||||
import type { IncomingMessage, ServerResponse } from 'node:http'
|
||||
|
||||
@Injectable()
|
||||
export class RequestContextMiddleware implements NestMiddleware {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import type { ValidationPipeOptions } from '@nestjs/common'
|
||||
|
||||
import { Injectable, ValidationPipe } from '@nestjs/common'
|
||||
|
||||
import { isDev } from '~/global/env.global'
|
||||
import type { ValidationPipeOptions } from '@nestjs/common'
|
||||
|
||||
@Injectable()
|
||||
export class ExtendedValidationPipe extends ValidationPipe {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/prefer-literal-enum-member */
|
||||
export enum BusinessEvents {
|
||||
GATEWAY_CONNECT = 'GATEWAY_CONNECT',
|
||||
GATEWAY_DISCONNECT = 'GATEWAY_DISCONNECT',
|
||||
@@ -57,7 +58,6 @@ export enum BusinessEvents {
|
||||
|
||||
ARTICLE_READ_COUNT_UPDATE = 'ARTICLE_READ_COUNT_UPDATE',
|
||||
}
|
||||
|
||||
export enum EventScope {
|
||||
TO_VISITOR = 1 << 0,
|
||||
TO_ADMIN = 1 << 1,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/prefer-literal-enum-member */
|
||||
export enum RedisKeys {
|
||||
AccessIp = 'access_ip',
|
||||
Like = 'like',
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/prefer-literal-enum-member */
|
||||
export const MIGRATE_COLLECTION_NAME = 'migrations'
|
||||
export const CHECKSUM_COLLECTION_NAME = 'checksum'
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { homedir } from 'os'
|
||||
import { join } from 'path'
|
||||
import { homedir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
|
||||
import { cwd, isDev } from '~/global/env.global'
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { isURL } from 'class-validator'
|
||||
import type { ValidationOptions } from 'class-validator'
|
||||
|
||||
import { validatorFactory } from '../simpleValidatorFactory'
|
||||
import type { ValidationOptions } from 'class-validator'
|
||||
|
||||
export const IsAllowedUrl = (validationOptions?: ValidationOptions) => {
|
||||
return validatorFactory((val) =>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { isString } from 'class-validator'
|
||||
import { isBoolean, merge } from 'lodash'
|
||||
import type { ValidationOptions } from 'class-validator'
|
||||
|
||||
import { validatorFactory } from '../simpleValidatorFactory'
|
||||
import type { ValidationOptions } from 'class-validator'
|
||||
|
||||
export function IsBooleanOrString(validationOptions?: ValidationOptions) {
|
||||
return validatorFactory((value) => isBoolean(value) || isString(value))(
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { isInt, isMongoId } from 'class-validator'
|
||||
import { merge } from 'lodash'
|
||||
import type { ValidationOptions } from 'class-validator'
|
||||
|
||||
import { validatorFactory } from '../simpleValidatorFactory'
|
||||
import type { ValidationOptions } from 'class-validator'
|
||||
|
||||
export function IsBooleanOrString(validationOptions?: ValidationOptions) {
|
||||
return validatorFactory((value) => isInt(value) || isMongoId(value))(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
ValidatorConstraint,
|
||||
isString,
|
||||
registerDecorator,
|
||||
ValidatorConstraint,
|
||||
} from 'class-validator'
|
||||
import { isNil } from 'lodash'
|
||||
import type {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* @FilePath: /mx-server/src/common/decorators/simpleValidatorFactory.ts
|
||||
* @Coding with Love
|
||||
*/
|
||||
import { registerDecorator, ValidatorConstraint } from 'class-validator'
|
||||
import { ValidatorConstraint, registerDecorator } from 'class-validator'
|
||||
import type {
|
||||
ValidationArguments,
|
||||
ValidationOptions,
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
/* eslint-disable prefer-rest-params */
|
||||
|
||||
/* eslint-disable prefer-rest-params */
|
||||
import { createLogger, Logger } from 'nestjs-pretty-logger'
|
||||
import { Logger, createLogger } from 'nestjs-pretty-logger'
|
||||
|
||||
import { LOG_DIR } from '~/constants/path.constant'
|
||||
|
||||
@@ -18,7 +15,7 @@ Logger.setLoggerInstance(logger)
|
||||
if (!isTest) {
|
||||
try {
|
||||
logger.wrapAll()
|
||||
} catch (error) {
|
||||
} catch {
|
||||
logger.warn('wrap console failed')
|
||||
}
|
||||
logger.onData((data) => {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import cluster from 'cluster'
|
||||
import cluster from 'node:cluster'
|
||||
|
||||
import { parseBooleanishValue } from '~/utils/tool.util'
|
||||
|
||||
export const isMainCluster =
|
||||
process.env.NODE_APP_INSTANCE && parseInt(process.env.NODE_APP_INSTANCE) === 0
|
||||
process.env.NODE_APP_INSTANCE &&
|
||||
Number.parseInt(process.env.NODE_APP_INSTANCE) === 0
|
||||
export const isMainProcess = cluster.isPrimary || isMainCluster
|
||||
|
||||
export const isDev = process.env.NODE_ENV == 'development'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint-disable import/order */
|
||||
import cluster from 'cluster'
|
||||
import { mkdirSync } from 'fs'
|
||||
import cluster from 'node:cluster'
|
||||
import { mkdirSync } from 'node:fs'
|
||||
|
||||
import { Logger } from '@nestjs/common'
|
||||
|
||||
@@ -60,7 +60,7 @@ function registerGlobal() {
|
||||
function nodeEnvInjection() {
|
||||
// # https://github.com/kriszyp/cbor-x/blob/master/node-index.js#L16 https://github.com/kriszyp/cbor-x/blob/master/node-index.js#L10
|
||||
// # ncc not support runtime require so disable ACCELERATION
|
||||
process.env['CBOR_NATIVE_ACCELERATION_DISABLED'] = 'true'
|
||||
process.env.CBOR_NATIVE_ACCELERATION_DISABLED = 'true'
|
||||
}
|
||||
|
||||
export function register() {
|
||||
|
||||
@@ -12,7 +12,7 @@ export const registerJSONGlobal = () => {
|
||||
JSON.safeParse = (...rest) => {
|
||||
try {
|
||||
return JSON5.parse(...rest)
|
||||
} catch (error) {
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!env node
|
||||
// register global
|
||||
import cluster from 'cluster'
|
||||
import cluster from 'node:cluster'
|
||||
|
||||
import { logger } from './global/consola.global'
|
||||
import { isMainCluster } from './global/env.global'
|
||||
@@ -41,7 +41,10 @@ async function main() {
|
||||
}
|
||||
|
||||
if (CLUSTER.enable) {
|
||||
Cluster.register(parseInt(CLUSTER.workers) || os.cpus().length, bootstrap)
|
||||
Cluster.register(
|
||||
Number.parseInt(CLUSTER.workers) || os.cpus().length,
|
||||
bootstrap,
|
||||
)
|
||||
} else {
|
||||
bootstrap()
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@ import { plainToInstance } from 'class-transformer'
|
||||
|
||||
import 'reflect-metadata'
|
||||
|
||||
import type { IConfigKeys } from '~/modules/configs/configs.interface'
|
||||
|
||||
import { ENCRYPT } from '~/app.config'
|
||||
import { register } from '~/global/index.global'
|
||||
import { generateDefaultConfig } from '~/modules/configs/configs.default'
|
||||
@@ -11,6 +9,7 @@ import * as optionDtos from '~/modules/configs/configs.dto'
|
||||
import { encryptObject } from '~/modules/configs/configs.encrypt.util'
|
||||
import { IConfig } from '~/modules/configs/configs.interface'
|
||||
import { getDatabaseConnection } from '~/utils/database.util'
|
||||
import type { IConfigKeys } from '~/modules/configs/configs.interface'
|
||||
|
||||
console.log(ENCRYPT)
|
||||
|
||||
|
||||
@@ -26,9 +26,9 @@ export async function migrateDatabase() {
|
||||
} else {
|
||||
await migrate.run(db, connection)
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error(`[Database] migrate ${migrate.name} failed`, err)
|
||||
throw err
|
||||
} catch (error) {
|
||||
logger.error(`[Database] migrate ${migrate.name} failed`, error)
|
||||
throw error
|
||||
}
|
||||
|
||||
await db.collection(MIGRATE_COLLECTION_NAME).insertOne({
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import type { Db } from 'mongodb'
|
||||
|
||||
import {
|
||||
NOTE_COLLECTION_NAME,
|
||||
POST_COLLECTION_NAME,
|
||||
} from '~/constants/db.constant'
|
||||
import type { Db } from 'mongodb'
|
||||
|
||||
export default (async function v4_6_0__4(db: Db) {
|
||||
const countDefault = {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// patch for version lower than v4.6.0
|
||||
import type { Db } from 'mongodb'
|
||||
|
||||
import {
|
||||
CATEGORY_COLLECTION_NAME,
|
||||
@@ -10,6 +9,7 @@ import {
|
||||
TOPIC_COLLECTION_NAME,
|
||||
} from '~/constants/db.constant'
|
||||
import { md5 } from '~/utils'
|
||||
import type { Db } from 'mongodb'
|
||||
|
||||
export default (async function v4_6_0(db: Db) {
|
||||
await Promise.all([
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
|
||||
import { defineMigration } from '../helper'
|
||||
|
||||
export default defineMigration('v4.6.2__0', async (db, connection) => {
|
||||
export default defineMigration('v4.6.2__0', async (db, _connection) => {
|
||||
try {
|
||||
await Promise.all([
|
||||
db
|
||||
@@ -66,8 +66,8 @@ export default defineMigration('v4.6.2__0', async (db, connection) => {
|
||||
},
|
||||
},
|
||||
])
|
||||
} catch (err) {
|
||||
} catch (error) {
|
||||
console.error('v4.6.2 migration failed')
|
||||
throw err
|
||||
throw error
|
||||
}
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@ import { NOTE_COLLECTION_NAME } from '~/constants/db.constant'
|
||||
|
||||
import { defineMigration } from '../helper'
|
||||
|
||||
export default defineMigration('v5.0.0-1', async (db, connection) => {
|
||||
export default defineMigration('v5.0.0-1', async (db) => {
|
||||
try {
|
||||
await Promise.all([
|
||||
db.collection(NOTE_COLLECTION_NAME).updateMany(
|
||||
@@ -29,9 +29,9 @@ export default defineMigration('v5.0.0-1', async (db, connection) => {
|
||||
},
|
||||
},
|
||||
)
|
||||
} catch (err) {
|
||||
} catch (error) {
|
||||
console.error('v5.0.0-1 migration failed')
|
||||
|
||||
throw err
|
||||
throw error
|
||||
}
|
||||
})
|
||||
|
||||
@@ -5,13 +5,11 @@ import {
|
||||
|
||||
import { defineMigration } from '../helper'
|
||||
|
||||
export default defineMigration('v5.1.1', async (db, connection) => {
|
||||
await Promise.all([
|
||||
db
|
||||
.collection(COMMENT_COLLECTION_NAME)
|
||||
.updateMany(
|
||||
{ refType: 'Recently' },
|
||||
{ $set: { refType: RECENTLY_COLLECTION_NAME } },
|
||||
),
|
||||
])
|
||||
export default defineMigration('v5.1.1', async (db) => {
|
||||
await db
|
||||
.collection(COMMENT_COLLECTION_NAME)
|
||||
.updateMany(
|
||||
{ refType: 'Recently' },
|
||||
{ $set: { refType: RECENTLY_COLLECTION_NAME } },
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { plainToInstance } from 'class-transformer'
|
||||
import { validateSync } from 'class-validator'
|
||||
import { FastifyReply, FastifyRequest } from 'fastify'
|
||||
import type { CountModel } from '~/shared/model/count.model'
|
||||
import { FastifyReply } from 'fastify'
|
||||
|
||||
import { Body, HttpCode, Inject, Post, Req, Res } from '@nestjs/common'
|
||||
import { Body, HttpCode, Inject, Post, Res } from '@nestjs/common'
|
||||
|
||||
import { ApiController } from '~/common/decorators/api-controller.decorator'
|
||||
import { Cookies } from '~/common/decorators/cookie.decorator'
|
||||
@@ -15,6 +14,7 @@ import { CountingService } from '~/processors/helper/helper.counting.service'
|
||||
import { CacheService } from '~/processors/redis/cache.service'
|
||||
|
||||
import { AckDto, AckEventType, AckReadPayloadDto } from './ack.dto'
|
||||
import type { CountModel } from '~/shared/model/count.model'
|
||||
|
||||
@ApiController('ack')
|
||||
export class AckController {
|
||||
@@ -33,11 +33,9 @@ export class AckController {
|
||||
@Body() body: AckDto,
|
||||
@Cookies() cookies: Record<string, string>,
|
||||
@Res() res: FastifyReply,
|
||||
@Req() req: FastifyRequest,
|
||||
) {
|
||||
const { type, payload } = body
|
||||
|
||||
const uuidReq = req.headers['x-session-uuid']
|
||||
switch (type) {
|
||||
case AckEventType.READ: {
|
||||
const validPayload = plainToInstance(AckReadPayloadDto, payload)
|
||||
@@ -45,7 +43,7 @@ export class AckController {
|
||||
validPayload,
|
||||
ExtendedValidationPipe.options,
|
||||
)
|
||||
if (errors.length) {
|
||||
if (errors.length > 0) {
|
||||
const error = this.validatePipe.createExceptionFactory()(
|
||||
errors as any[],
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { forwardRef, Module } from '@nestjs/common'
|
||||
import { Module, forwardRef } from '@nestjs/common'
|
||||
|
||||
import { GatewayModule } from '~/processors/gateway/gateway.module'
|
||||
|
||||
|
||||
@@ -1,25 +1,12 @@
|
||||
import { omit, pick, uniqBy } from 'lodash'
|
||||
import { Types } from 'mongoose'
|
||||
import type { OnModuleDestroy, OnModuleInit } from '@nestjs/common'
|
||||
import type { Collection } from 'mongodb'
|
||||
import type { Socket } from 'socket.io'
|
||||
import type { NoteModel } from '../note/note.model'
|
||||
import type { PageModel } from '../page/page.model'
|
||||
import type { PostModel } from '../post/post.model'
|
||||
import type { RecentlyModel } from '../recently/recently.model'
|
||||
import type {
|
||||
ActivityLikePayload,
|
||||
ActivityLikeSupportType,
|
||||
ActivityPresence,
|
||||
} from './activity.interface'
|
||||
import type { UpdatePresenceDto } from './dtos/presence.dto'
|
||||
|
||||
import {
|
||||
BadRequestException,
|
||||
forwardRef,
|
||||
Inject,
|
||||
Injectable,
|
||||
Logger,
|
||||
forwardRef,
|
||||
} from '@nestjs/common'
|
||||
|
||||
import { ArticleTypeEnum } from '~/constants/article.constant'
|
||||
@@ -50,6 +37,19 @@ import {
|
||||
isValidRoomName,
|
||||
parseRoomName,
|
||||
} from './activity.util'
|
||||
import type { UpdatePresenceDto } from './dtos/presence.dto'
|
||||
import type {
|
||||
ActivityLikePayload,
|
||||
ActivityLikeSupportType,
|
||||
ActivityPresence,
|
||||
} from './activity.interface'
|
||||
import type { RecentlyModel } from '../recently/recently.model'
|
||||
import type { PostModel } from '../post/post.model'
|
||||
import type { PageModel } from '../page/page.model'
|
||||
import type { NoteModel } from '../note/note.model'
|
||||
import type { Socket } from 'socket.io'
|
||||
import type { Collection } from 'mongodb'
|
||||
import type { OnModuleDestroy, OnModuleInit } from '@nestjs/common'
|
||||
|
||||
declare module '~/types/socket-meta' {
|
||||
interface SocketMetadata {
|
||||
@@ -285,8 +285,8 @@ export class ActivityService implements OnModuleInit, OnModuleDestroy {
|
||||
if (!res) {
|
||||
throw new BadRequestException('你已经支持过啦!')
|
||||
}
|
||||
} catch (e: any) {
|
||||
throw new BadRequestException(e)
|
||||
} catch (error: any) {
|
||||
throw new BadRequestException(error)
|
||||
}
|
||||
|
||||
const refModel = await this.databaseService
|
||||
@@ -389,6 +389,7 @@ export class ActivityService implements OnModuleInit, OnModuleDestroy {
|
||||
socketMeta
|
||||
.filter((x) => x?.presence)
|
||||
.map((x) => {
|
||||
// eslint-disable-next-line array-callback-return
|
||||
if (!x.presence) return
|
||||
|
||||
return {
|
||||
@@ -639,7 +640,7 @@ export class ActivityService implements OnModuleInit, OnModuleDestroy {
|
||||
* 获取过去一年的文章发布
|
||||
*/
|
||||
async getLastYearPublication() {
|
||||
const $gte = new Date(new Date().getTime() - 365 * 24 * 60 * 60 * 1000)
|
||||
const $gte = new Date(Date.now() - 365 * 24 * 60 * 60 * 1000)
|
||||
const [posts, notes] = await Promise.all([
|
||||
this.postService.model
|
||||
.find({
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Transform } from 'class-transformer'
|
||||
import { IsEnum, IsInt, IsOptional, IsString, Max, Min } from 'class-validator'
|
||||
|
||||
export class TopQueryDto {
|
||||
@Transform(({ value: val }) => parseInt(val))
|
||||
@Transform(({ value: val }) => Number.parseInt(val))
|
||||
@Min(1)
|
||||
@Max(10)
|
||||
@IsOptional()
|
||||
@@ -26,7 +26,7 @@ export class TimelineQueryDto {
|
||||
|
||||
@IsEnum(TimelineType)
|
||||
@IsOptional()
|
||||
@Transform(({ value: v }) => v | 0)
|
||||
@Transform(({ value: v }) => Math.trunc(v))
|
||||
type?: TimelineType
|
||||
}
|
||||
|
||||
@@ -45,6 +45,6 @@ export enum ReadAndLikeCountDocumentType {
|
||||
export class ReadAndLikeCountTypeDto {
|
||||
@IsEnum(ReadAndLikeCountDocumentType)
|
||||
@IsOptional()
|
||||
@Transform(({ value: v }) => v | 0)
|
||||
@Transform(({ value: v }) => Math.trunc(v))
|
||||
type?: ReadAndLikeCountDocumentType
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { forwardRef, Module } from '@nestjs/common'
|
||||
import { Module, forwardRef } from '@nestjs/common'
|
||||
|
||||
import { GatewayModule } from '~/processors/gateway/gateway.module'
|
||||
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
import { URL } from 'url'
|
||||
import { URL } from 'node:url'
|
||||
import { pick } from 'lodash'
|
||||
import type { ReturnModelType } from '@typegoose/typegoose'
|
||||
import type { AnyParamConstructor } from '@typegoose/typegoose/lib/types'
|
||||
import type { PipelineStage } from 'mongoose'
|
||||
import type { CategoryModel } from '../category/category.model'
|
||||
import type { RSSProps } from './aggregate.interface'
|
||||
|
||||
import { forwardRef, Inject, Injectable } from '@nestjs/common'
|
||||
import { Inject, Injectable, forwardRef } from '@nestjs/common'
|
||||
import { OnEvent } from '@nestjs/event-emitter'
|
||||
|
||||
import {
|
||||
@@ -35,6 +30,11 @@ import { RecentlyService } from '../recently/recently.service'
|
||||
import { SayService } from '../say/say.service'
|
||||
import { UserService } from '../user/user.service'
|
||||
import { ReadAndLikeCountDocumentType, TimelineType } from './aggregate.dto'
|
||||
import type { RSSProps } from './aggregate.interface'
|
||||
import type { CategoryModel } from '../category/category.model'
|
||||
import type { PipelineStage } from 'mongoose'
|
||||
import type { AnyParamConstructor } from '@typegoose/typegoose/lib/types'
|
||||
import type { ReturnModelType } from '@typegoose/typegoose'
|
||||
|
||||
@Injectable()
|
||||
export class AggregateService {
|
||||
|
||||
@@ -87,10 +87,11 @@ export class AiController {
|
||||
}
|
||||
}
|
||||
|
||||
if (!dbStored) {
|
||||
if (!aiConfig.enableSummary || !aiConfig.enableAutoGenerateSummary) {
|
||||
throw new BizException(ErrorCodeEnum.AINotEnabled)
|
||||
}
|
||||
if (
|
||||
!dbStored &&
|
||||
(!aiConfig.enableSummary || !aiConfig.enableAutoGenerateSummary)
|
||||
) {
|
||||
throw new BizException(ErrorCodeEnum.AINotEnabled)
|
||||
}
|
||||
|
||||
return dbStored
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import OpenAI from 'openai'
|
||||
import removeMdCodeblock from 'remove-md-codeblock'
|
||||
import type { PagerDto } from '~/shared/dto/pager.dto'
|
||||
|
||||
import { Injectable, Logger } from '@nestjs/common'
|
||||
import { OnEvent } from '@nestjs/event-emitter'
|
||||
@@ -17,6 +16,7 @@ import { md5 } from '~/utils'
|
||||
|
||||
import { ConfigsService } from '../configs/configs.service'
|
||||
import { AISummaryModel } from './ai-summary.model'
|
||||
import type { PagerDto } from '~/shared/dto/pager.dto'
|
||||
|
||||
@Injectable()
|
||||
export class AiService {
|
||||
@@ -83,7 +83,7 @@ export class AiService {
|
||||
|
||||
this.cachedTaskId2AiPromise.set(taskId, taskPromise)
|
||||
return await taskPromise
|
||||
// eslint-disable-next-line no-inner-declarations
|
||||
|
||||
async function handle(this: AiService, id: string, text: string) {
|
||||
// 等待 30s
|
||||
await redis.set(taskId, 'processing', 'EX', 30)
|
||||
@@ -119,10 +119,12 @@ CONCISE SUMMARY:`,
|
||||
|
||||
return doc
|
||||
}
|
||||
} catch (er) {
|
||||
this.logger.error(`OpenAI 在处理文章 ${articleId} 时出错:${er.message}`)
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`OpenAI 在处理文章 ${articleId} 时出错:${error.message}`,
|
||||
)
|
||||
|
||||
throw new BizException(ErrorCodeEnum.AIException, er.message)
|
||||
throw new BizException(ErrorCodeEnum.AIException, error.message)
|
||||
} finally {
|
||||
this.cachedTaskId2AiPromise.delete(taskId)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import dayjs from 'dayjs'
|
||||
import type { PagerDto } from '~/shared/dto/pager.dto'
|
||||
|
||||
import { Delete, Get, HttpCode, Query } from '@nestjs/common'
|
||||
|
||||
@@ -13,6 +12,7 @@ import { getTodayEarly, getWeekStart } from '~/utils/time.util'
|
||||
|
||||
import { AnalyzeDto } from './analyze.dto'
|
||||
import { AnalyzeService } from './analyze.service'
|
||||
import type { PagerDto } from '~/shared/dto/pager.dto'
|
||||
|
||||
@ApiController({ path: 'analyze' })
|
||||
@Auth()
|
||||
@@ -28,7 +28,7 @@ export class AnalyzeController {
|
||||
const { from, to = new Date(), page = 1, size = 50 } = query
|
||||
|
||||
const data = await this.service.getRangeAnalyzeData(from, to, {
|
||||
limit: size | 0,
|
||||
limit: Math.trunc(size),
|
||||
page,
|
||||
})
|
||||
|
||||
@@ -42,7 +42,7 @@ export class AnalyzeController {
|
||||
const today = new Date()
|
||||
const todayEarly = getTodayEarly(today)
|
||||
return await this.service.getRangeAnalyzeData(todayEarly, today, {
|
||||
limit: ~~size,
|
||||
limit: Math.trunc(size),
|
||||
page,
|
||||
})
|
||||
}
|
||||
@@ -64,7 +64,7 @@ export class AnalyzeController {
|
||||
const getIpAndPvAggregate = async () => {
|
||||
const day = await this.service.getIpAndPvAggregate('day', true)
|
||||
|
||||
const dayData = Array(24)
|
||||
const dayData = Array.from({ length: 24 })
|
||||
.fill(undefined)
|
||||
.map((v, i) => {
|
||||
return [
|
||||
|
||||
@@ -2,12 +2,12 @@ import { Transform } from 'class-transformer'
|
||||
import { IsDate, IsOptional } from 'class-validator'
|
||||
|
||||
export class AnalyzeDto {
|
||||
@Transform(({ value: v }) => new Date(parseInt(v)))
|
||||
@Transform(({ value: v }) => new Date(Number.parseInt(v)))
|
||||
@IsOptional()
|
||||
@IsDate()
|
||||
from?: Date
|
||||
|
||||
@Transform(({ value: v }) => new Date(parseInt(v)))
|
||||
@Transform(({ value: v }) => new Date(Number.parseInt(v)))
|
||||
@IsOptional()
|
||||
@IsDate()
|
||||
to?: Date
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { SchemaTypes } from 'mongoose'
|
||||
import { UAParser } from 'ua-parser-js'
|
||||
|
||||
import { index, modelOptions, prop, Severity } from '@typegoose/typegoose'
|
||||
import { Severity, index, modelOptions, prop } from '@typegoose/typegoose'
|
||||
|
||||
import { ANALYZE_COLLECTION_NAME } from '~/constants/db.constant'
|
||||
import { BaseModel } from '~/shared/model/base.model'
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import dayjs from 'dayjs'
|
||||
import { merge } from 'lodash'
|
||||
import type { PipelineStage } from 'mongoose'
|
||||
|
||||
import { Injectable } from '@nestjs/common'
|
||||
import { ReturnModelType } from '@typegoose/typegoose'
|
||||
@@ -12,6 +11,7 @@ import { getRedisKey } from '~/utils/redis.util'
|
||||
|
||||
import { OptionModel } from '../configs/configs.model'
|
||||
import { AnalyzeModel } from './analyze.model'
|
||||
import type { PipelineStage } from 'mongoose'
|
||||
|
||||
@Injectable()
|
||||
export class AnalyzeService {
|
||||
@@ -248,7 +248,7 @@ export class AnalyzeService {
|
||||
}
|
||||
|
||||
async getRangeOfTopPathVisitor(from?: Date, to?: Date): Promise<any[]> {
|
||||
from = from ?? new Date(new Date().getTime() - 1000 * 24 * 3600 * 7)
|
||||
from = from ?? new Date(Date.now() - 1000 * 24 * 3600 * 7)
|
||||
to = to ?? new Date()
|
||||
|
||||
const pipeline: PipelineStage[] = [
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Transform } from 'class-transformer'
|
||||
import {
|
||||
IsDate,
|
||||
isMongoId,
|
||||
IsNotEmpty,
|
||||
IsOptional,
|
||||
IsString,
|
||||
isMongoId,
|
||||
} from 'class-validator'
|
||||
|
||||
import {
|
||||
|
||||
@@ -2,13 +2,10 @@ import dayjs from 'dayjs'
|
||||
import jwt from 'jsonwebtoken'
|
||||
import { isDate, omit } from 'lodash'
|
||||
import { LRUCache } from 'lru-cache'
|
||||
import type { ClerkClient } from '@clerk/clerk-sdk-node'
|
||||
import type { TokenModel, UserModel } from '~/modules/user/user.model'
|
||||
import type { TokenDto } from './auth.controller'
|
||||
|
||||
import { createClerkClient } from '@clerk/clerk-sdk-node'
|
||||
import { nanoid } from '@mx-space/external'
|
||||
import { forwardRef, Inject, Injectable, Logger } from '@nestjs/common'
|
||||
import { Inject, Injectable, Logger, forwardRef } from '@nestjs/common'
|
||||
import { ReturnModelType } from '@typegoose/typegoose'
|
||||
|
||||
import { alphabet } from '~/constants/other.constant'
|
||||
@@ -17,6 +14,9 @@ import { JWTService } from '~/processors/helper/helper.jwt.service'
|
||||
import { InjectModel } from '~/transformers/model.transformer'
|
||||
|
||||
import { ConfigsService } from '../configs/configs.service'
|
||||
import type { TokenDto } from './auth.controller'
|
||||
import type { TokenModel, UserModel } from '~/modules/user/user.model'
|
||||
import type { ClerkClient } from '@clerk/clerk-sdk-node'
|
||||
|
||||
const { customAlphabet } = nanoid
|
||||
|
||||
|
||||
@@ -37,8 +37,8 @@ export class AuthnController {
|
||||
|
||||
@Post('/authentication')
|
||||
@HTTPDecorators.Bypass
|
||||
async newAuthentication(@CurrentUser() user: UserDocument) {
|
||||
return await this.authnService.generateAuthenticationOptions(user)
|
||||
async newAuthentication() {
|
||||
return await this.authnService.generateAuthenticationOptions()
|
||||
}
|
||||
|
||||
@Post('/authentication/verify')
|
||||
|
||||
@@ -6,7 +6,7 @@ type CredentialDeviceType = 'singleDevice' | 'multiDevice'
|
||||
|
||||
const uint8ArrayGetterSetter = {
|
||||
get(uint8string: string) {
|
||||
const base64String = uint8string.replace(/-/g, '+').replace(/_/g, '/') // 将 URL 安全字符转换回标准 Base64 字符
|
||||
const base64String = uint8string.replaceAll('-', '+').replaceAll('_', '/') // 将 URL 安全字符转换回标准 Base64 字符
|
||||
const buffer = Buffer.from(base64String, 'base64')
|
||||
return buffer.buffer.slice(
|
||||
buffer.byteOffset,
|
||||
@@ -16,8 +16,8 @@ const uint8ArrayGetterSetter = {
|
||||
set(value: Uint8Array) {
|
||||
return Buffer.from(value)
|
||||
.toString('base64')
|
||||
.replace(/\+/g, '-')
|
||||
.replace(/\//g, '_')
|
||||
.replaceAll('+', '-')
|
||||
.replaceAll('/', '_')
|
||||
.replace(/=+$/, '')
|
||||
},
|
||||
|
||||
|
||||
@@ -1,14 +1,3 @@
|
||||
import type {
|
||||
VerifiedAuthenticationResponse,
|
||||
VerifiedRegistrationResponse,
|
||||
} from '@simplewebauthn/server'
|
||||
import type {
|
||||
AuthenticationResponseJSON,
|
||||
CredentialDeviceType,
|
||||
RegistrationResponseJSON,
|
||||
} from '@simplewebauthn/server/script/deps'
|
||||
import type { UserDocument } from '../user/user.model'
|
||||
|
||||
import { BadRequestException, Injectable } from '@nestjs/common'
|
||||
import {
|
||||
generateAuthenticationOptions,
|
||||
@@ -25,6 +14,16 @@ import { getRedisKey } from '~/utils'
|
||||
|
||||
import { ConfigsService } from '../configs/configs.service'
|
||||
import { AuthnModel } from './authn.model'
|
||||
import type { UserDocument } from '../user/user.model'
|
||||
import type {
|
||||
AuthenticationResponseJSON,
|
||||
CredentialDeviceType,
|
||||
RegistrationResponseJSON,
|
||||
} from '@simplewebauthn/server/script/deps'
|
||||
import type {
|
||||
VerifiedAuthenticationResponse,
|
||||
VerifiedRegistrationResponse,
|
||||
} from '@simplewebauthn/server'
|
||||
|
||||
@Injectable()
|
||||
export class AuthnService {
|
||||
@@ -163,7 +162,7 @@ export class AuthnService {
|
||||
return verification
|
||||
}
|
||||
|
||||
async generateAuthenticationOptions(user: UserDocument) {
|
||||
async generateAuthenticationOptions() {
|
||||
const userAuthenticators: Authenticator[] = await this.authnModel
|
||||
.find()
|
||||
.lean({ getters: true })
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Readable } from 'stream'
|
||||
import { Readable } from 'node:stream'
|
||||
import { FastifyRequest } from 'fastify'
|
||||
|
||||
import {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { existsSync, statSync } from 'fs'
|
||||
import { readdir, readFile, rm, writeFile } from 'fs/promises'
|
||||
import { join, resolve } from 'path'
|
||||
import { existsSync, statSync } from 'node:fs'
|
||||
import { readFile, readdir, rm, writeFile } from 'node:fs/promises'
|
||||
import { join, resolve } from 'node:path'
|
||||
import { flatten } from 'lodash'
|
||||
import { mkdirp } from 'mkdirp'
|
||||
|
||||
@@ -114,26 +114,26 @@ export class BackupService {
|
||||
|
||||
// 打包数据目录
|
||||
|
||||
const flags = excludeFolders.map((item) => ['--exclude', item]).flat(1)
|
||||
const flags = excludeFolders.flatMap((item) => ['--exclude', item])
|
||||
cd(DATA_DIR)
|
||||
await rm(join(DATA_DIR, 'backup_data'), { recursive: true, force: true })
|
||||
await rm(join(DATA_DIR, 'temp_copy_need'), {
|
||||
recursive: true,
|
||||
force: true,
|
||||
})
|
||||
// eslint-disable-next-line no-empty
|
||||
|
||||
await $`rsync -a . ./temp_copy_need --exclude temp_copy_need ${flags} && mv temp_copy_need backup_data && zip -r ${join(
|
||||
backupDirPath,
|
||||
`backup-${dateDir}`,
|
||||
)} ./backup_data && rm -rf backup_data`
|
||||
|
||||
this.logger.log('--> 备份成功')
|
||||
} catch (e) {
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`--> 备份失败,请确保已安装 zip 或 mongo-tools, mongo-tools 的版本需要与 mongod 版本一致,${e.message}` ||
|
||||
e.stderr,
|
||||
`--> 备份失败,请确保已安装 zip 或 mongo-tools, mongo-tools 的版本需要与 mongod 版本一致,${error.message}` ||
|
||||
error.stderr,
|
||||
)
|
||||
throw e
|
||||
throw error
|
||||
}
|
||||
const path = join(backupDirPath, `backup-${dateDir}.zip`)
|
||||
|
||||
@@ -206,9 +206,9 @@ export class BackupService {
|
||||
await $`mongorestore --uri ${MONGO_DB.customConnectionString || MONGO_DB.uri} -d ${MONGO_DB.dbName} ./mx-space --drop >/dev/null 2>&1`
|
||||
|
||||
await migrateDatabase()
|
||||
} catch (e) {
|
||||
this.logger.error(e)
|
||||
throw e
|
||||
} catch (error) {
|
||||
this.logger.error(error)
|
||||
throw error
|
||||
} finally {
|
||||
await rm(join(dirPath, 'mx-space'), { recursive: true, force: true })
|
||||
}
|
||||
@@ -238,13 +238,13 @@ export class BackupService {
|
||||
await Promise.all(
|
||||
Object.entries(pkg.dependencies).map(([name, version]) => {
|
||||
this.logger.log(`--> 安装依赖 ${name}@${version}`)
|
||||
return installPKG(`${name}@${version}`, DATA_DIR).catch((er) => {
|
||||
this.logger.error(`--> 依赖安装失败:${er.message}`)
|
||||
return installPKG(`${name}@${version}`, DATA_DIR).catch((error) => {
|
||||
this.logger.error(`--> 依赖安装失败:${error.message}`)
|
||||
})
|
||||
}),
|
||||
)
|
||||
}
|
||||
} catch (er) {}
|
||||
} catch {}
|
||||
|
||||
await Promise.all([
|
||||
this.cacheService.cleanAllRedisKey(),
|
||||
@@ -316,9 +316,9 @@ export class BackupService {
|
||||
})
|
||||
|
||||
this.logger.log('--> 开始上传到 S3')
|
||||
await s3.send(command).catch((err) => {
|
||||
await s3.send(command).catch((error) => {
|
||||
this.logger.error('--> 上传失败了')
|
||||
throw err
|
||||
throw error
|
||||
})
|
||||
this.logger.log('--> 上传成功')
|
||||
})
|
||||
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
BadRequestException,
|
||||
Body,
|
||||
Delete,
|
||||
forwardRef,
|
||||
Get,
|
||||
HttpCode,
|
||||
Inject,
|
||||
@@ -13,6 +12,7 @@ import {
|
||||
Post,
|
||||
Put,
|
||||
Query,
|
||||
forwardRef,
|
||||
} from '@nestjs/common'
|
||||
|
||||
import { ApiController } from '~/common/decorators/api-controller.decorator'
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { IsEnum, IsNotEmpty, IsOptional, IsString } from 'class-validator'
|
||||
import type { DocumentType } from '@typegoose/typegoose'
|
||||
|
||||
import { PartialType } from '@nestjs/mapped-types'
|
||||
import { index, modelOptions, prop } from '@typegoose/typegoose'
|
||||
|
||||
import { CATEGORY_COLLECTION_NAME } from '~/constants/db.constant'
|
||||
import { BaseModel } from '~/shared/model/base.model'
|
||||
import type { DocumentType } from '@typegoose/typegoose'
|
||||
|
||||
export type CategoryDocument = DocumentType<CategoryModel>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { forwardRef, Module } from '@nestjs/common'
|
||||
import { Module, forwardRef } from '@nestjs/common'
|
||||
|
||||
import { PostModule } from '../post/post.module'
|
||||
import { SlugTrackerModule } from '../slug-tracker/slug-tracker.module'
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
import { omit } from 'lodash'
|
||||
import type { DocumentType } from '@typegoose/typegoose'
|
||||
import type { FilterQuery } from 'mongoose'
|
||||
import type { PostModel } from '../post/post.model'
|
||||
|
||||
import {
|
||||
BadRequestException,
|
||||
forwardRef,
|
||||
Inject,
|
||||
Injectable,
|
||||
forwardRef,
|
||||
} from '@nestjs/common'
|
||||
import { ReturnModelType } from '@typegoose/typegoose'
|
||||
|
||||
@@ -23,6 +20,9 @@ import { scheduleManager } from '~/utils'
|
||||
import { PostService } from '../post/post.service'
|
||||
import { SlugTrackerService } from '../slug-tracker/slug-tracker.service'
|
||||
import { CategoryModel, CategoryType } from './category.model'
|
||||
import type { PostModel } from '../post/post.model'
|
||||
import type { FilterQuery } from 'mongoose'
|
||||
import type { DocumentType } from '@typegoose/typegoose'
|
||||
|
||||
@Injectable()
|
||||
export class CategoryService {
|
||||
@@ -58,8 +58,8 @@ export class CategoryService {
|
||||
}),
|
||||
)
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
Reflect.set(data[i], 'count', counts[i])
|
||||
for (const [i, datum] of data.entries()) {
|
||||
Reflect.set(datum, 'count', counts[i])
|
||||
}
|
||||
|
||||
return data
|
||||
@@ -101,7 +101,7 @@ export class CategoryService {
|
||||
{ lean: true },
|
||||
)
|
||||
.populate('category')
|
||||
if (!posts.length) {
|
||||
if (posts.length === 0) {
|
||||
throw new CannotFindException()
|
||||
}
|
||||
return posts.map(({ _id, title, slug, category, created }) => ({
|
||||
@@ -207,11 +207,9 @@ export class CategoryService {
|
||||
|
||||
private clearCache() {
|
||||
return scheduleManager.batch(() =>
|
||||
Promise.all([
|
||||
this.eventManager.emit(EventBusEvents.CleanAggregateCache, null, {
|
||||
scope: EventScope.TO_SYSTEM,
|
||||
}),
|
||||
]),
|
||||
this.eventManager.emit(EventBusEvents.CleanAggregateCache, null, {
|
||||
scope: EventScope.TO_SYSTEM,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import { isUndefined } from 'lodash'
|
||||
import type { DocumentType } from '@typegoose/typegoose'
|
||||
import type { Document, FilterQuery } from 'mongoose'
|
||||
import type { CommentModel } from './comment.model'
|
||||
|
||||
import {
|
||||
Body,
|
||||
@@ -45,6 +42,9 @@ import { CommentReplyMailType } from './comment.enum'
|
||||
import { CommentFilterEmailInterceptor } from './comment.interceptor'
|
||||
import { CommentState } from './comment.model'
|
||||
import { CommentService } from './comment.service'
|
||||
import type { CommentModel } from './comment.model'
|
||||
import type { Document, FilterQuery } from 'mongoose'
|
||||
import type { DocumentType } from '@typegoose/typegoose'
|
||||
|
||||
const idempotenceMessage = '哦吼,这句话你已经说过啦'
|
||||
const NESTED_REPLY_MAX = 10
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { isDefined } from 'class-validator'
|
||||
import { cloneDeep, isArrayLike, isObjectLike } from 'lodash'
|
||||
import { map } from 'rxjs'
|
||||
import type {
|
||||
CallHandler,
|
||||
ExecutionContext,
|
||||
NestInterceptor,
|
||||
} from '@nestjs/common'
|
||||
|
||||
import { Injectable } from '@nestjs/common'
|
||||
|
||||
import { getNestExecutionContextRequest } from '~/transformers/get-req.transformer'
|
||||
import { getAvatar } from '~/utils'
|
||||
import type {
|
||||
CallHandler,
|
||||
ExecutionContext,
|
||||
NestInterceptor,
|
||||
} from '@nestjs/common'
|
||||
|
||||
@Injectable()
|
||||
export class CommentFilterEmailInterceptor implements NestInterceptor {
|
||||
@@ -48,9 +48,9 @@ export class CommentFilterEmailInterceptor implements NestInterceptor {
|
||||
}
|
||||
|
||||
return cloneDeep(data)
|
||||
} catch (e) {
|
||||
} catch (error) {
|
||||
if (isDev) {
|
||||
console.error(e)
|
||||
console.error(error)
|
||||
}
|
||||
return cloneDeep(data)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { URL } from 'url'
|
||||
import { URL } from 'node:url'
|
||||
import { Types } from 'mongoose'
|
||||
import autopopulate from 'mongoose-autopopulate'
|
||||
|
||||
import { modelOptions, plugin, prop, Ref } from '@typegoose/typegoose'
|
||||
import { Ref, modelOptions, plugin, prop } from '@typegoose/typegoose'
|
||||
|
||||
import {
|
||||
CollectionRefTypes,
|
||||
COMMENT_COLLECTION_NAME,
|
||||
CollectionRefTypes,
|
||||
} from '~/constants/db.constant'
|
||||
import { BaseModel } from '~/shared/model/base.model'
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { forwardRef, Module } from '@nestjs/common'
|
||||
import { Module, forwardRef } from '@nestjs/common'
|
||||
|
||||
import { GatewayModule } from '~/processors/gateway/gateway.module'
|
||||
|
||||
|
||||
@@ -1,23 +1,14 @@
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
import { URL } from 'url'
|
||||
import { URL } from 'node:url'
|
||||
import { render } from 'ejs'
|
||||
import { omit, pick } from 'lodash'
|
||||
import { isObjectIdOrHexString, Types } from 'mongoose'
|
||||
import type { OnModuleInit } from '@nestjs/common'
|
||||
import type { ReturnModelType } from '@typegoose/typegoose/lib/types'
|
||||
import type { WriteBaseModel } from '~/shared/model/write-base.model'
|
||||
import type { SnippetModel } from '../snippet/snippet.model'
|
||||
import type {
|
||||
CommentEmailTemplateRenderProps,
|
||||
CommentModelRenderProps,
|
||||
} from './comment.email.default'
|
||||
import { Types, isObjectIdOrHexString } from 'mongoose'
|
||||
|
||||
import {
|
||||
BadRequestException,
|
||||
forwardRef,
|
||||
Inject,
|
||||
Injectable,
|
||||
Logger,
|
||||
forwardRef,
|
||||
} from '@nestjs/common'
|
||||
import { OnEvent } from '@nestjs/event-emitter'
|
||||
|
||||
@@ -45,6 +36,14 @@ import {
|
||||
} from './comment.email.default'
|
||||
import { CommentReplyMailType } from './comment.enum'
|
||||
import { CommentModel, CommentState } from './comment.model'
|
||||
import type {
|
||||
CommentEmailTemplateRenderProps,
|
||||
CommentModelRenderProps,
|
||||
} from './comment.email.default'
|
||||
import type { SnippetModel } from '../snippet/snippet.model'
|
||||
import type { WriteBaseModel } from '~/shared/model/write-base.model'
|
||||
import type { OnModuleInit } from '@nestjs/common'
|
||||
import type { ReturnModelType } from '@typegoose/typegoose/lib/types'
|
||||
|
||||
@Injectable()
|
||||
export class CommentService implements OnModuleInit {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { IConfig } from './configs.interface'
|
||||
|
||||
import { DEMO_MODE } from '~/app.config'
|
||||
import type { IConfig } from './configs.interface'
|
||||
|
||||
export const generateDefaultConfig: () => IConfig = () => ({
|
||||
seo: {
|
||||
|
||||
@@ -3,8 +3,8 @@ import {
|
||||
ArrayUnique,
|
||||
IsBoolean,
|
||||
IsEmail,
|
||||
IsInt,
|
||||
IsIP,
|
||||
IsInt,
|
||||
IsNotEmpty,
|
||||
IsOptional,
|
||||
IsString,
|
||||
@@ -17,7 +17,6 @@ import { IsAllowedUrl } from '~/decorators/dto/isAllowedUrl'
|
||||
|
||||
import { Encrypt } from './configs.encrypt.util'
|
||||
import {
|
||||
halfFieldOption,
|
||||
JSONSchemaArrayField,
|
||||
JSONSchemaHalfGirdPlainField,
|
||||
JSONSchemaNumberField,
|
||||
@@ -25,6 +24,7 @@ import {
|
||||
JSONSchemaPlainField,
|
||||
JSONSchemaTextAreaField,
|
||||
JSONSchemaToggleField,
|
||||
halfFieldOption,
|
||||
} from './configs.jsonschema.decorator'
|
||||
|
||||
const SecretField = (target: Object, propertyKey: string | symbol) => {
|
||||
@@ -77,7 +77,7 @@ export class UrlDto {
|
||||
|
||||
class MailOption {
|
||||
@IsInt()
|
||||
@Transform(({ value: val }) => parseInt(val))
|
||||
@Transform(({ value: val }) => Number.parseInt(val))
|
||||
@IsOptional()
|
||||
@JSONSchemaNumberField('发件邮箱端口', halfFieldOption)
|
||||
port: number
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
import { Type } from 'class-transformer'
|
||||
import { ValidateNested } from 'class-validator'
|
||||
import { JSONSchema } from 'class-validator-jsonschema'
|
||||
import type {
|
||||
ClassConstructor,
|
||||
TypeHelpOptions,
|
||||
TypeOptions,
|
||||
} from 'class-transformer'
|
||||
|
||||
import {
|
||||
AdminExtraDto,
|
||||
AIDto,
|
||||
AdminExtraDto,
|
||||
AlgoliaSearchOptionsDto,
|
||||
AuthSecurityDto,
|
||||
BackupOptionsDto,
|
||||
@@ -25,6 +19,11 @@ import {
|
||||
ThirdPartyServiceIntegrationDto,
|
||||
UrlDto,
|
||||
} from './configs.dto'
|
||||
import type {
|
||||
ClassConstructor,
|
||||
TypeHelpOptions,
|
||||
TypeOptions,
|
||||
} from 'class-transformer'
|
||||
|
||||
export const configDtoMapping = {} as Record<string, ClassConstructor<any>>
|
||||
const ConfigField =
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Schema } from 'mongoose'
|
||||
|
||||
import { modelOptions, prop, Severity } from '@typegoose/typegoose'
|
||||
import { Severity, modelOptions, prop } from '@typegoose/typegoose'
|
||||
|
||||
@modelOptions({
|
||||
options: { allowMixed: Severity.ALLOW, customName: 'Option' },
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import cluster from 'cluster'
|
||||
import cluster from 'node:cluster'
|
||||
import { plainToInstance } from 'class-transformer'
|
||||
import { validateSync } from 'class-validator'
|
||||
import { cloneDeep, mergeWith } from 'lodash'
|
||||
import type { ClassConstructor } from 'class-transformer'
|
||||
|
||||
import { createClerkClient } from '@clerk/clerk-sdk-node'
|
||||
import {
|
||||
@@ -28,8 +27,9 @@ import { getRedisKey } from '~/utils/redis.util'
|
||||
|
||||
import { generateDefaultConfig } from './configs.default'
|
||||
import { decryptObject, encryptObject } from './configs.encrypt.util'
|
||||
import { configDtoMapping, IConfig } from './configs.interface'
|
||||
import { IConfig, configDtoMapping } from './configs.interface'
|
||||
import { OptionModel } from './configs.model'
|
||||
import type { ClassConstructor } from 'class-transformer'
|
||||
|
||||
const configsKeySet = new Set(Object.keys(configDtoMapping))
|
||||
|
||||
@@ -133,13 +133,13 @@ export class ConfigsService {
|
||||
) as any as IConfig
|
||||
|
||||
return decryptObject(instanceConfigsValue)
|
||||
} catch (err) {
|
||||
} catch (error) {
|
||||
await this.configInit()
|
||||
if (errorRetryCount > 0) {
|
||||
return await this.getConfig(--errorRetryCount)
|
||||
}
|
||||
this.logger.error('获取配置失败')
|
||||
throw err
|
||||
throw error
|
||||
}
|
||||
} else {
|
||||
await this.configInit()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { resolve } from 'path'
|
||||
import { resolve } from 'node:path'
|
||||
|
||||
import { Module } from '@nestjs/common'
|
||||
import { CronExpression } from '@nestjs/schedule'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { readFile } from 'fs/promises'
|
||||
import { readFile } from 'node:fs/promises'
|
||||
import { Observable } from 'rxjs'
|
||||
|
||||
import { BadRequestException, Get, Query, Sse } from '@nestjs/common'
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import RemoveMarkdown from 'remove-markdown'
|
||||
import xss from 'xss'
|
||||
import type { CategoryModel } from '../category/category.model'
|
||||
|
||||
import { CacheKey, CacheTTL } from '@nestjs/cache-manager'
|
||||
import { Controller, Get, Header } from '@nestjs/common'
|
||||
@@ -13,6 +12,7 @@ import { AggregateService } from '../aggregate/aggregate.service'
|
||||
import { ConfigsService } from '../configs/configs.service'
|
||||
import { MarkdownService } from '../markdown/markdown.service'
|
||||
import { UserService } from '../user/user.service'
|
||||
import type { CategoryModel } from '../category/category.model'
|
||||
|
||||
@Controller()
|
||||
export class FeedController {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import fs from 'fs/promises'
|
||||
import fs from 'node:fs/promises'
|
||||
import { FastifyReply, FastifyRequest } from 'fastify'
|
||||
import { lookup } from 'mime-types'
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { createWriteStream } from 'fs'
|
||||
import { resolve } from 'path'
|
||||
import type { Readable } from 'stream'
|
||||
import type { FileType } from './file.type'
|
||||
import { createWriteStream } from 'node:fs'
|
||||
import { resolve } from 'node:path'
|
||||
|
||||
import {
|
||||
BadRequestException,
|
||||
@@ -16,6 +14,8 @@ import {
|
||||
} from '~/constants/path.constant'
|
||||
|
||||
import { ConfigsService } from '../configs/configs.service'
|
||||
import type { FileType } from './file.type'
|
||||
import type { Readable } from 'node:stream'
|
||||
|
||||
@Injectable()
|
||||
export class FileService {
|
||||
@@ -80,8 +80,8 @@ export class FileService {
|
||||
const path = this.resolveFilePath(type, name)
|
||||
|
||||
await fs.rename(path, resolve(STATIC_FILE_TRASH_DIR, name))
|
||||
} catch (e) {
|
||||
this.logger.error('删除文件失败', e)
|
||||
} catch (error) {
|
||||
this.logger.error('删除文件失败', error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -102,8 +102,8 @@ export class FileService {
|
||||
const newPath = this.resolveFilePath(type, newName)
|
||||
try {
|
||||
await fs.rename(oldPath, newPath)
|
||||
} catch (e) {
|
||||
this.logger.error('重命名文件失败', e.message)
|
||||
} catch (error) {
|
||||
this.logger.error('重命名文件失败', error.message)
|
||||
throw new BadRequestException('重命名文件失败')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,10 +23,10 @@ export class HealthController {
|
||||
@Get('/email/test')
|
||||
@Auth()
|
||||
async testEmail() {
|
||||
return this.emailService.sendTestEmail().catch((err) => {
|
||||
return this.emailService.sendTestEmail().catch((error) => {
|
||||
return {
|
||||
message: err.message,
|
||||
trace: err.stack,
|
||||
message: error.message,
|
||||
trace: error.stack,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import type { Readable } from 'form-data'
|
||||
|
||||
import {
|
||||
BadRequestException,
|
||||
Delete,
|
||||
@@ -19,6 +17,7 @@ import { formatByteSize } from '~/utils'
|
||||
import { getTodayLogFilePath } from '~/utils/path.util'
|
||||
|
||||
import { LogQueryDto, LogTypeDto } from '../health.dto'
|
||||
import type { Readable } from 'form-data'
|
||||
|
||||
@ApiController('health/log')
|
||||
@Auth()
|
||||
@@ -72,7 +71,7 @@ export class HealthLogController {
|
||||
switch (type) {
|
||||
case 'pm2':
|
||||
_type = file.split('-')[2].split('.')[0]
|
||||
index = parseInt(file.split('-')[3], 10) || 0
|
||||
index = Number.parseInt(file.split('-')[3], 10) || 0
|
||||
break
|
||||
case 'native':
|
||||
_type = 'log'
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { CanActivate } from '@nestjs/common'
|
||||
|
||||
import { checkInit } from '~/utils/check-init.util'
|
||||
import type { CanActivate } from '@nestjs/common'
|
||||
|
||||
export class InitGuard implements CanActivate {
|
||||
async canActivate() {
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import type mongoose from 'mongoose'
|
||||
|
||||
import {
|
||||
Body,
|
||||
ForbiddenException,
|
||||
@@ -26,6 +24,7 @@ import { scheduleManager } from '~/utils'
|
||||
import { AuditReasonDto, LinkDto } from './link.dto'
|
||||
import { LinkModel, LinkState } from './link.model'
|
||||
import { LinkService } from './link.service'
|
||||
import type mongoose from 'mongoose'
|
||||
|
||||
const paths = ['links', 'friends']
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { URL } from 'url'
|
||||
import { URL } from 'node:url'
|
||||
import { Transform } from 'class-transformer'
|
||||
import {
|
||||
IsEmail,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user