refactor:
This commit is contained in:
parent
6b9b4cdd17
commit
88a97ee162
|
@ -33,7 +33,7 @@ import { ContractModule } from './modules/contract/contract.module';
|
||||||
expandVariables: true,
|
expandVariables: true,
|
||||||
// 指定多个 env 文件时,第一个优先级最高
|
// 指定多个 env 文件时,第一个优先级最高
|
||||||
envFilePath: ['.env.local', `.env.${process.env.NODE_ENV}`, '.env'],
|
envFilePath: ['.env.local', `.env.${process.env.NODE_ENV}`, '.env'],
|
||||||
load: [...Object.values(config)],
|
load: [...Object.values(config)]
|
||||||
}),
|
}),
|
||||||
SharedModule,
|
SharedModule,
|
||||||
DatabaseModule,
|
DatabaseModule,
|
||||||
|
@ -53,7 +53,7 @@ import { ContractModule } from './modules/contract/contract.module';
|
||||||
|
|
||||||
TodoModule,
|
TodoModule,
|
||||||
|
|
||||||
ContractModule,
|
ContractModule
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: APP_FILTER, useClass: AllExceptionsFilter },
|
{ provide: APP_FILTER, useClass: AllExceptionsFilter },
|
||||||
|
@ -64,7 +64,7 @@ import { ContractModule } from './modules/contract/contract.module';
|
||||||
{ provide: APP_INTERCEPTOR, useClass: IdempotenceInterceptor },
|
{ provide: APP_INTERCEPTOR, useClass: IdempotenceInterceptor },
|
||||||
|
|
||||||
{ provide: APP_GUARD, useClass: JwtAuthGuard },
|
{ provide: APP_GUARD, useClass: JwtAuthGuard },
|
||||||
{ provide: APP_GUARD, useClass: RbacGuard },
|
{ provide: APP_GUARD, useClass: RbacGuard }
|
||||||
],
|
]
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { FastifyAdapter } from '@nestjs/platform-fastify';
|
||||||
|
|
||||||
const app: FastifyAdapter = new FastifyAdapter({
|
const app: FastifyAdapter = new FastifyAdapter({
|
||||||
trustProxy: true,
|
trustProxy: true,
|
||||||
logger: false,
|
logger: false
|
||||||
// forceCloseConnections: true,
|
// forceCloseConnections: true,
|
||||||
});
|
});
|
||||||
export { app as fastifyApp };
|
export { app as fastifyApp };
|
||||||
|
@ -13,12 +13,12 @@ app.register(FastifyMultipart, {
|
||||||
limits: {
|
limits: {
|
||||||
fields: 10, // Max number of non-file fields
|
fields: 10, // Max number of non-file fields
|
||||||
fileSize: 1024 * 1024 * 6, // limit size 6M
|
fileSize: 1024 * 1024 * 6, // limit size 6M
|
||||||
files: 5, // Max number of file fields
|
files: 5 // Max number of file fields
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.register(FastifyCookie, {
|
app.register(FastifyCookie, {
|
||||||
secret: 'cookie-secret', // 这个 secret 不太重要,不存鉴权相关,无关紧要
|
secret: 'cookie-secret' // 这个 secret 不太重要,不存鉴权相关,无关紧要
|
||||||
});
|
});
|
||||||
|
|
||||||
app.getInstance().addHook('onRequest', (request, reply, done) => {
|
app.getInstance().addHook('onRequest', (request, reply, done) => {
|
||||||
|
|
|
@ -18,7 +18,7 @@ export class RedisIoAdapter extends IoAdapter {
|
||||||
|
|
||||||
const redisAdapter = createAdapter(pubClient, subClient, {
|
const redisAdapter = createAdapter(pubClient, subClient, {
|
||||||
key: RedisIoAdapterKey,
|
key: RedisIoAdapterKey,
|
||||||
requestsTimeout: 10000,
|
requestsTimeout: 10000
|
||||||
});
|
});
|
||||||
server.adapter(redisAdapter);
|
server.adapter(redisAdapter);
|
||||||
return server;
|
return server;
|
||||||
|
|
|
@ -16,7 +16,7 @@ function genBaseProp(type: Type<any>) {
|
||||||
export function ApiResult<TModel extends Type<any>>({
|
export function ApiResult<TModel extends Type<any>>({
|
||||||
type,
|
type,
|
||||||
isPage,
|
isPage,
|
||||||
status,
|
status
|
||||||
}: {
|
}: {
|
||||||
type?: TModel | TModel[];
|
type?: TModel | TModel[];
|
||||||
isPage?: boolean;
|
isPage?: boolean;
|
||||||
|
@ -31,7 +31,7 @@ export function ApiResult<TModel extends Type<any>>({
|
||||||
properties: {
|
properties: {
|
||||||
items: {
|
items: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
items: { $ref: getSchemaPath(type[0]) },
|
items: { $ref: getSchemaPath(type[0]) }
|
||||||
},
|
},
|
||||||
meta: {
|
meta: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
|
@ -40,15 +40,15 @@ export function ApiResult<TModel extends Type<any>>({
|
||||||
totalItems: { type: 'number', default: 0 },
|
totalItems: { type: 'number', default: 0 },
|
||||||
itemsPerPage: { type: 'number', default: 0 },
|
itemsPerPage: { type: 'number', default: 0 },
|
||||||
totalPages: { type: 'number', default: 0 },
|
totalPages: { type: 'number', default: 0 },
|
||||||
currentPage: { type: 'number', default: 0 },
|
currentPage: { type: 'number', default: 0 }
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
prop = {
|
prop = {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
items: genBaseProp(type[0]),
|
items: genBaseProp(type[0])
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else if (type) {
|
} else if (type) {
|
||||||
|
@ -68,11 +68,11 @@ export function ApiResult<TModel extends Type<any>>({
|
||||||
{ $ref: getSchemaPath(ResOp) },
|
{ $ref: getSchemaPath(ResOp) },
|
||||||
{
|
{
|
||||||
properties: {
|
properties: {
|
||||||
data: prop,
|
data: prop
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {
|
||||||
Max,
|
Max,
|
||||||
MaxLength,
|
MaxLength,
|
||||||
Min,
|
Min,
|
||||||
MinLength,
|
MinLength
|
||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
import { isNumber } from 'lodash';
|
import { isNumber } from 'lodash';
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ import {
|
||||||
ToLowerCase,
|
ToLowerCase,
|
||||||
ToNumber,
|
ToNumber,
|
||||||
ToTrim,
|
ToTrim,
|
||||||
ToUpperCase,
|
ToUpperCase
|
||||||
} from './transform.decorator';
|
} from './transform.decorator';
|
||||||
|
|
||||||
interface IOptionalOptions {
|
interface IOptionalOptions {
|
||||||
|
|
|
@ -7,7 +7,7 @@ export function IdParam() {
|
||||||
errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE,
|
errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE,
|
||||||
exceptionFactory: _error => {
|
exceptionFactory: _error => {
|
||||||
throw new NotAcceptableException('id 格式不正确');
|
throw new NotAcceptableException('id 格式不正确');
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ export class CursorDto<T = any> {
|
||||||
@Expose()
|
@Expose()
|
||||||
@IsOptional({ always: true })
|
@IsOptional({ always: true })
|
||||||
@Transform(({ value: val }) => (val ? Number.parseInt(val) : 0), {
|
@Transform(({ value: val }) => (val ? Number.parseInt(val) : 0), {
|
||||||
toClassOnly: true,
|
toClassOnly: true
|
||||||
})
|
})
|
||||||
cursor?: number;
|
cursor?: number;
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ export class CursorDto<T = any> {
|
||||||
@IsOptional({ always: true })
|
@IsOptional({ always: true })
|
||||||
@Expose()
|
@Expose()
|
||||||
@Transform(({ value: val }) => (val ? Number.parseInt(val) : 10), {
|
@Transform(({ value: val }) => (val ? Number.parseInt(val) : 10), {
|
||||||
toClassOnly: true,
|
toClassOnly: true
|
||||||
})
|
})
|
||||||
limit?: number;
|
limit?: number;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { Allow, IsEnum, IsInt, IsOptional, IsString, Max, Min } from 'class-vali
|
||||||
|
|
||||||
export enum Order {
|
export enum Order {
|
||||||
ASC = 'ASC',
|
ASC = 'ASC',
|
||||||
DESC = 'DESC',
|
DESC = 'DESC'
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PagerDto<T = any> {
|
export class PagerDto<T = any> {
|
||||||
|
@ -14,7 +14,7 @@ export class PagerDto<T = any> {
|
||||||
@Expose()
|
@Expose()
|
||||||
@IsOptional({ always: true })
|
@IsOptional({ always: true })
|
||||||
@Transform(({ value: val }) => (val ? Number.parseInt(val) : 1), {
|
@Transform(({ value: val }) => (val ? Number.parseInt(val) : 1), {
|
||||||
toClassOnly: true,
|
toClassOnly: true
|
||||||
})
|
})
|
||||||
page?: number;
|
page?: number;
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ export class PagerDto<T = any> {
|
||||||
@IsOptional({ always: true })
|
@IsOptional({ always: true })
|
||||||
@Expose()
|
@Expose()
|
||||||
@Transform(({ value: val }) => (val ? Number.parseInt(val) : 10), {
|
@Transform(({ value: val }) => (val ? Number.parseInt(val) : 10), {
|
||||||
toClassOnly: true,
|
toClassOnly: true
|
||||||
})
|
})
|
||||||
pageSize?: number;
|
pageSize?: number;
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {
|
||||||
CreateDateColumn,
|
CreateDateColumn,
|
||||||
PrimaryGeneratedColumn,
|
PrimaryGeneratedColumn,
|
||||||
UpdateDateColumn,
|
UpdateDateColumn,
|
||||||
VirtualColumn,
|
VirtualColumn
|
||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
|
|
||||||
// 如果觉得前端转换时间太麻烦,并且不考虑通用性的话,可以在服务端进行转换,eg: @UpdateDateColumn({ name: 'updated_at', transformer })
|
// 如果觉得前端转换时间太麻烦,并且不考虑通用性的话,可以在服务端进行转换,eg: @UpdateDateColumn({ name: 'updated_at', transformer })
|
||||||
|
|
|
@ -12,7 +12,7 @@ export class BusinessException extends HttpException {
|
||||||
super(
|
super(
|
||||||
HttpException.createBody({
|
HttpException.createBody({
|
||||||
code: RESPONSE_SUCCESS_CODE,
|
code: RESPONSE_SUCCESS_CODE,
|
||||||
message: error,
|
message: error
|
||||||
}),
|
}),
|
||||||
HttpStatus.OK
|
HttpStatus.OK
|
||||||
);
|
);
|
||||||
|
@ -24,7 +24,7 @@ export class BusinessException extends HttpException {
|
||||||
super(
|
super(
|
||||||
HttpException.createBody({
|
HttpException.createBody({
|
||||||
code,
|
code,
|
||||||
message,
|
message
|
||||||
}),
|
}),
|
||||||
HttpStatus.OK
|
HttpStatus.OK
|
||||||
);
|
);
|
||||||
|
|
|
@ -14,7 +14,7 @@ export class SocketException extends WsException {
|
||||||
super(
|
super(
|
||||||
HttpException.createBody({
|
HttpException.createBody({
|
||||||
code: 0,
|
code: 0,
|
||||||
message: error,
|
message: error
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
this.errorCode = 0;
|
this.errorCode = 0;
|
||||||
|
@ -25,7 +25,7 @@ export class SocketException extends WsException {
|
||||||
super(
|
super(
|
||||||
HttpException.createBody({
|
HttpException.createBody({
|
||||||
code,
|
code,
|
||||||
message,
|
message
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {
|
||||||
ExceptionFilter,
|
ExceptionFilter,
|
||||||
HttpException,
|
HttpException,
|
||||||
HttpStatus,
|
HttpStatus,
|
||||||
Logger,
|
Logger
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { FastifyReply, FastifyRequest } from 'fastify';
|
import { FastifyReply, FastifyRequest } from 'fastify';
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ export class AllExceptionsFilter implements ExceptionFilter {
|
||||||
const resBody: IBaseResponse = {
|
const resBody: IBaseResponse = {
|
||||||
code: apiErrorCode,
|
code: apiErrorCode,
|
||||||
message,
|
message,
|
||||||
data: null,
|
data: null
|
||||||
};
|
};
|
||||||
|
|
||||||
response.status(status).send(resBody);
|
response.status(status).send(resBody);
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { getRedisKey } from '~/utils/redis.util';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
HTTP_IDEMPOTENCE_KEY,
|
HTTP_IDEMPOTENCE_KEY,
|
||||||
HTTP_IDEMPOTENCE_OPTIONS,
|
HTTP_IDEMPOTENCE_OPTIONS
|
||||||
} from '../decorators/idempotence.decorator';
|
} from '../decorators/idempotence.decorator';
|
||||||
|
|
||||||
const IdempotenceHeaderKey = 'x-idempotence';
|
const IdempotenceHeaderKey = 'x-idempotence';
|
||||||
|
@ -70,7 +70,7 @@ export class IdempotenceInterceptor implements NestInterceptor {
|
||||||
pendingMessage = '相同请求正在处理中...',
|
pendingMessage = '相同请求正在处理中...',
|
||||||
handler: errorHandler,
|
handler: errorHandler,
|
||||||
expired = 60,
|
expired = 60,
|
||||||
disableGenerateKey = false,
|
disableGenerateKey = false
|
||||||
} = options;
|
} = options;
|
||||||
const redis = this.cacheService.getClient();
|
const redis = this.cacheService.getClient();
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ export class IdempotenceInterceptor implements NestInterceptor {
|
||||||
|
|
||||||
const message = {
|
const message = {
|
||||||
1: errorMessage,
|
1: errorMessage,
|
||||||
0: pendingMessage,
|
0: pendingMessage
|
||||||
}[resultValue];
|
}[resultValue];
|
||||||
throw new ConflictException(message);
|
throw new ConflictException(message);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {
|
||||||
ExecutionContext,
|
ExecutionContext,
|
||||||
Injectable,
|
Injectable,
|
||||||
NestInterceptor,
|
NestInterceptor,
|
||||||
RequestTimeoutException,
|
RequestTimeoutException
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { Observable, TimeoutError, throwError } from 'rxjs';
|
import { Observable, TimeoutError, throwError } from 'rxjs';
|
||||||
import { catchError, timeout } from 'rxjs/operators';
|
import { catchError, timeout } from 'rxjs/operators';
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {
|
||||||
ExecutionContext,
|
ExecutionContext,
|
||||||
HttpStatus,
|
HttpStatus,
|
||||||
Injectable,
|
Injectable,
|
||||||
NestInterceptor,
|
NestInterceptor
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { Reflector } from '@nestjs/core';
|
import { Reflector } from '@nestjs/core';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
|
|
@ -13,8 +13,8 @@ export const AppConfig = registerAs(appRegToken, () => ({
|
||||||
|
|
||||||
logger: {
|
logger: {
|
||||||
level: env('LOGGER_LEVEL'),
|
level: env('LOGGER_LEVEL'),
|
||||||
maxFiles: envNumber('LOGGER_MAX_FILES'),
|
maxFiles: envNumber('LOGGER_MAX_FILES')
|
||||||
},
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export type IAppConfig = ConfigType<typeof AppConfig>;
|
export type IAppConfig = ConfigType<typeof AppConfig>;
|
||||||
|
|
|
@ -24,7 +24,7 @@ const dataSourceOptions: DataSourceOptions = {
|
||||||
multipleStatements: currentScript === 'typeorm',
|
multipleStatements: currentScript === 'typeorm',
|
||||||
entities: ['dist/modules/**/*.entity{.ts,.js}'],
|
entities: ['dist/modules/**/*.entity{.ts,.js}'],
|
||||||
migrations: ['dist/migrations/*{.ts,.js}'],
|
migrations: ['dist/migrations/*{.ts,.js}'],
|
||||||
subscribers: ['dist/modules/**/*.subscriber{.ts,.js}'],
|
subscribers: ['dist/modules/**/*.subscriber{.ts,.js}']
|
||||||
};
|
};
|
||||||
export const dbRegToken = 'database';
|
export const dbRegToken = 'database';
|
||||||
|
|
||||||
|
|
|
@ -33,5 +33,5 @@ export default {
|
||||||
OssConfig,
|
OssConfig,
|
||||||
RedisConfig,
|
RedisConfig,
|
||||||
SecurityConfig,
|
SecurityConfig,
|
||||||
SwaggerConfig,
|
SwaggerConfig
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,8 +11,8 @@ export const MailerConfig = registerAs(mailerRegToken, () => ({
|
||||||
secure: true,
|
secure: true,
|
||||||
auth: {
|
auth: {
|
||||||
user: env('SMTP_USER'),
|
user: env('SMTP_USER'),
|
||||||
pass: env('SMTP_PASS'),
|
pass: env('SMTP_PASS')
|
||||||
},
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export type IMailerConfig = ConfigType<typeof MailerConfig>;
|
export type IMailerConfig = ConfigType<typeof MailerConfig>;
|
||||||
|
|
|
@ -26,7 +26,7 @@ export const OssConfig = registerAs(ossRegToken, () => ({
|
||||||
domain: env('OSS_DOMAIN'),
|
domain: env('OSS_DOMAIN'),
|
||||||
bucket: env('OSS_BUCKET'),
|
bucket: env('OSS_BUCKET'),
|
||||||
zone: parseZone(env('OSS_ZONE') || 'Zone_z2'),
|
zone: parseZone(env('OSS_ZONE') || 'Zone_z2'),
|
||||||
access: (env('OSS_ACCESS_TYPE') as any) || 'public',
|
access: (env('OSS_ACCESS_TYPE') as any) || 'public'
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export type IOssConfig = ConfigType<typeof OssConfig>;
|
export type IOssConfig = ConfigType<typeof OssConfig>;
|
||||||
|
|
|
@ -8,7 +8,7 @@ export const RedisConfig = registerAs(redisRegToken, () => ({
|
||||||
host: env('REDIS_HOST', '127.0.0.1'),
|
host: env('REDIS_HOST', '127.0.0.1'),
|
||||||
port: envNumber('REDIS_PORT', 6379),
|
port: envNumber('REDIS_PORT', 6379),
|
||||||
password: env('REDIS_PASSWORD'),
|
password: env('REDIS_PASSWORD'),
|
||||||
db: envNumber('REDIS_DB'),
|
db: envNumber('REDIS_DB')
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export type IRedisConfig = ConfigType<typeof RedisConfig>;
|
export type IRedisConfig = ConfigType<typeof RedisConfig>;
|
||||||
|
|
|
@ -8,7 +8,7 @@ export const SecurityConfig = registerAs(securityRegToken, () => ({
|
||||||
jwtSecret: env('JWT_SECRET'),
|
jwtSecret: env('JWT_SECRET'),
|
||||||
jwtExprire: envNumber('JWT_EXPIRE'),
|
jwtExprire: envNumber('JWT_EXPIRE'),
|
||||||
refreshSecret: env('REFRESH_TOKEN_SECRET'),
|
refreshSecret: env('REFRESH_TOKEN_SECRET'),
|
||||||
refreshExpire: envNumber('REFRESH_TOKEN_EXPIRE'),
|
refreshExpire: envNumber('REFRESH_TOKEN_EXPIRE')
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export type ISecurityConfig = ConfigType<typeof SecurityConfig>;
|
export type ISecurityConfig = ConfigType<typeof SecurityConfig>;
|
||||||
|
|
|
@ -6,7 +6,7 @@ export const swaggerRegToken = 'swagger';
|
||||||
|
|
||||||
export const SwaggerConfig = registerAs(swaggerRegToken, () => ({
|
export const SwaggerConfig = registerAs(swaggerRegToken, () => ({
|
||||||
enable: envBoolean('SWAGGER_ENABLE'),
|
enable: envBoolean('SWAGGER_ENABLE'),
|
||||||
path: env('SWAGGER_PATH'),
|
path: env('SWAGGER_PATH')
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export type ISwaggerConfig = ConfigType<typeof SwaggerConfig>;
|
export type ISwaggerConfig = ConfigType<typeof SwaggerConfig>;
|
||||||
|
|
|
@ -3,6 +3,6 @@ export enum RedisKeys {
|
||||||
CAPTCHA_IMG_PREFIX = 'captcha:img:',
|
CAPTCHA_IMG_PREFIX = 'captcha:img:',
|
||||||
AUTH_TOKEN_PREFIX = 'auth:token:',
|
AUTH_TOKEN_PREFIX = 'auth:token:',
|
||||||
AUTH_PERM_PREFIX = 'auth:permission:',
|
AUTH_PERM_PREFIX = 'auth:permission:',
|
||||||
AUTH_PASSWORD_V_PREFIX = 'auth:passwordVersion:',
|
AUTH_PASSWORD_V_PREFIX = 'auth:passwordVersion:'
|
||||||
}
|
}
|
||||||
export const API_CACHE_PREFIX = 'api-cache:';
|
export const API_CACHE_PREFIX = 'api-cache:';
|
||||||
|
|
|
@ -45,5 +45,5 @@ export enum ErrorEnum {
|
||||||
// OSS相关
|
// OSS相关
|
||||||
OSS_FILE_OR_DIR_EXIST = '1401:当前创建的文件或目录已存在',
|
OSS_FILE_OR_DIR_EXIST = '1401:当前创建的文件或目录已存在',
|
||||||
OSS_NO_OPERATION_REQUIRED = '1402:无需操作',
|
OSS_NO_OPERATION_REQUIRED = '1402:无需操作',
|
||||||
OSS_EXCEE_MAXIMUM_QUANTITY = '1403:已超出支持的最大处理数量',
|
OSS_EXCEE_MAXIMUM_QUANTITY = '1403:已超出支持的最大处理数量'
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
export enum EventBusEvents {
|
export enum EventBusEvents {
|
||||||
TokenExpired = 'token.expired',
|
TokenExpired = 'token.expired',
|
||||||
SystemException = 'system.exception',
|
SystemException = 'system.exception'
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,5 +11,5 @@ export enum ContentTypeEnum {
|
||||||
// form-data qs
|
// form-data qs
|
||||||
FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8',
|
FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8',
|
||||||
// form-data upload
|
// form-data upload
|
||||||
FORM_DATA = 'multipart/form-data;charset=UTF-8',
|
FORM_DATA = 'multipart/form-data;charset=UTF-8'
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ import { BaseService } from './base.service';
|
||||||
export function BaseCrudFactory<E extends new (...args: any[]) => any>({
|
export function BaseCrudFactory<E extends new (...args: any[]) => any>({
|
||||||
entity,
|
entity,
|
||||||
dto,
|
dto,
|
||||||
permissions,
|
permissions
|
||||||
}: {
|
}: {
|
||||||
entity: E;
|
entity: E;
|
||||||
dto?: Type<any>;
|
dto?: Type<any>;
|
||||||
|
@ -35,7 +35,7 @@ export function BaseCrudFactory<E extends new (...args: any[]) => any>({
|
||||||
CREATE: `${prefix}:create`,
|
CREATE: `${prefix}:create`,
|
||||||
READ: `${prefix}:read`,
|
READ: `${prefix}:read`,
|
||||||
UPDATE: `${prefix}:update`,
|
UPDATE: `${prefix}:update`,
|
||||||
DELETE: `${prefix}:delete`,
|
DELETE: `${prefix}:delete`
|
||||||
} as const);
|
} as const);
|
||||||
|
|
||||||
@Controller(pluralizeName)
|
@Controller(pluralizeName)
|
||||||
|
|
|
@ -5,7 +5,7 @@ export function createPaginationObject<T>({
|
||||||
items,
|
items,
|
||||||
totalItems,
|
totalItems,
|
||||||
currentPage,
|
currentPage,
|
||||||
limit,
|
limit
|
||||||
}: {
|
}: {
|
||||||
items: T[];
|
items: T[];
|
||||||
totalItems?: number;
|
totalItems?: number;
|
||||||
|
@ -19,7 +19,7 @@ export function createPaginationObject<T>({
|
||||||
itemCount: items.length,
|
itemCount: items.length,
|
||||||
itemsPerPage: limit,
|
itemsPerPage: limit,
|
||||||
totalPages,
|
totalPages,
|
||||||
currentPage,
|
currentPage
|
||||||
};
|
};
|
||||||
|
|
||||||
return new Pagination<T>(items, meta);
|
return new Pagination<T>(items, meta);
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {
|
||||||
FindOptionsWhere,
|
FindOptionsWhere,
|
||||||
ObjectLiteral,
|
ObjectLiteral,
|
||||||
Repository,
|
Repository,
|
||||||
SelectQueryBuilder,
|
SelectQueryBuilder
|
||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
|
|
||||||
import { createPaginationObject } from './create-pagination';
|
import { createPaginationObject } from './create-pagination';
|
||||||
|
@ -19,7 +19,7 @@ function resolveOptions(options: IPaginationOptions): [number, number, Paginatio
|
||||||
return [
|
return [
|
||||||
page || DEFAULT_PAGE,
|
page || DEFAULT_PAGE,
|
||||||
pageSize || DEFAULT_LIMIT,
|
pageSize || DEFAULT_LIMIT,
|
||||||
paginationType || PaginationTypeEnum.TAKE_AND_SKIP,
|
paginationType || PaginationTypeEnum.TAKE_AND_SKIP
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,9 +34,9 @@ async function paginateRepository<T>(
|
||||||
repository.find({
|
repository.find({
|
||||||
skip: limit * (page - 1),
|
skip: limit * (page - 1),
|
||||||
take: limit,
|
take: limit,
|
||||||
...searchOptions,
|
...searchOptions
|
||||||
}),
|
}),
|
||||||
undefined,
|
undefined
|
||||||
];
|
];
|
||||||
|
|
||||||
const [items, total] = await Promise.all(promises);
|
const [items, total] = await Promise.all(promises);
|
||||||
|
@ -45,7 +45,7 @@ async function paginateRepository<T>(
|
||||||
items,
|
items,
|
||||||
totalItems: total,
|
totalItems: total,
|
||||||
currentPage: page,
|
currentPage: page,
|
||||||
limit,
|
limit
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ async function paginateQueryBuilder<T>(
|
||||||
items,
|
items,
|
||||||
totalItems: total,
|
totalItems: total,
|
||||||
currentPage: page,
|
currentPage: page,
|
||||||
limit,
|
limit
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ export async function paginateRaw<T>(
|
||||||
? queryBuilder.limit(limit).offset((page - 1) * limit)
|
? queryBuilder.limit(limit).offset((page - 1) * limit)
|
||||||
: queryBuilder.take(limit).skip((page - 1) * limit)
|
: queryBuilder.take(limit).skip((page - 1) * limit)
|
||||||
).getRawMany<T>(),
|
).getRawMany<T>(),
|
||||||
queryBuilder.getCount(),
|
queryBuilder.getCount()
|
||||||
];
|
];
|
||||||
|
|
||||||
const [items, total] = await Promise.all(promises);
|
const [items, total] = await Promise.all(promises);
|
||||||
|
@ -89,7 +89,7 @@ export async function paginateRaw<T>(
|
||||||
items,
|
items,
|
||||||
totalItems: total,
|
totalItems: total,
|
||||||
currentPage: page,
|
currentPage: page,
|
||||||
limit,
|
limit
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ export async function paginateRawAndEntities<T>(
|
||||||
? queryBuilder.limit(limit).offset((page - 1) * limit)
|
? queryBuilder.limit(limit).offset((page - 1) * limit)
|
||||||
: queryBuilder.take(limit).skip((page - 1) * limit)
|
: queryBuilder.take(limit).skip((page - 1) * limit)
|
||||||
).getRawAndEntities<T>(),
|
).getRawAndEntities<T>(),
|
||||||
queryBuilder.getCount(),
|
queryBuilder.getCount()
|
||||||
];
|
];
|
||||||
|
|
||||||
const [itemObject, total] = await Promise.all(promises);
|
const [itemObject, total] = await Promise.all(promises);
|
||||||
|
@ -114,9 +114,9 @@ export async function paginateRawAndEntities<T>(
|
||||||
items: itemObject.entities,
|
items: itemObject.entities,
|
||||||
totalItems: total,
|
totalItems: total,
|
||||||
currentPage: page,
|
currentPage: page,
|
||||||
limit,
|
limit
|
||||||
}),
|
}),
|
||||||
itemObject.raw,
|
itemObject.raw
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { ObjectLiteral } from 'typeorm';
|
||||||
|
|
||||||
export enum PaginationTypeEnum {
|
export enum PaginationTypeEnum {
|
||||||
LIMIT_AND_OFFSET = 'limit',
|
LIMIT_AND_OFFSET = 'limit',
|
||||||
TAKE_AND_SKIP = 'take',
|
TAKE_AND_SKIP = 'take'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPaginationOptions {
|
export interface IPaginationOptions {
|
||||||
|
|
|
@ -23,7 +23,7 @@ declare const module: any;
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
const app = await NestFactory.create<NestFastifyApplication>(AppModule, fastifyApp, {
|
const app = await NestFactory.create<NestFastifyApplication>(AppModule, fastifyApp, {
|
||||||
bufferLogs: true,
|
bufferLogs: true,
|
||||||
snapshot: true,
|
snapshot: true
|
||||||
// forceCloseConnections: true,
|
// forceCloseConnections: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ async function bootstrap() {
|
||||||
const msg = e.constraints![rule];
|
const msg = e.constraints![rule];
|
||||||
return msg;
|
return msg;
|
||||||
})[0]
|
})[0]
|
||||||
),
|
)
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -14,12 +14,12 @@ export const AuthStrategy = {
|
||||||
JWT: 'jwt',
|
JWT: 'jwt',
|
||||||
|
|
||||||
GITHUB: 'github',
|
GITHUB: 'github',
|
||||||
GOOGLE: 'google',
|
GOOGLE: 'google'
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const Roles = {
|
export const Roles = {
|
||||||
ADMIN: 'admin',
|
ADMIN: 'admin',
|
||||||
USER: 'user',
|
USER: 'user'
|
||||||
// GUEST: 'guest',
|
// GUEST: 'guest',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
|
|
@ -41,18 +41,18 @@ const strategies = [LocalStrategy, JwtStrategy];
|
||||||
return {
|
return {
|
||||||
secret: jwtSecret,
|
secret: jwtSecret,
|
||||||
expires: jwtExprire,
|
expires: jwtExprire,
|
||||||
ignoreExpiration: isDev,
|
ignoreExpiration: isDev
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
inject: [ConfigService],
|
inject: [ConfigService]
|
||||||
}),
|
}),
|
||||||
UserModule,
|
UserModule,
|
||||||
RoleModule,
|
RoleModule,
|
||||||
MenuModule,
|
MenuModule,
|
||||||
LogModule,
|
LogModule
|
||||||
],
|
],
|
||||||
controllers: [...controllers],
|
controllers: [...controllers],
|
||||||
providers: [...providers, ...strategies],
|
providers: [...providers, ...strategies],
|
||||||
exports: [TypeOrmModule, JwtModule, ...providers],
|
exports: [TypeOrmModule, JwtModule, ...providers]
|
||||||
})
|
})
|
||||||
export class AuthModule {}
|
export class AuthModule {}
|
||||||
|
|
|
@ -35,11 +35,11 @@ export class CaptchaController {
|
||||||
noise: 4,
|
noise: 4,
|
||||||
width: isEmpty(width) ? 100 : width,
|
width: isEmpty(width) ? 100 : width,
|
||||||
height: isEmpty(height) ? 50 : height,
|
height: isEmpty(height) ? 50 : height,
|
||||||
charPreset: '1234567890',
|
charPreset: '1234567890'
|
||||||
});
|
});
|
||||||
const result = {
|
const result = {
|
||||||
img: `data:image/svg+xml;base64,${Buffer.from(svg.data).toString('base64')}`,
|
img: `data:image/svg+xml;base64,${Buffer.from(svg.data).toString('base64')}`,
|
||||||
id: generateUUID(),
|
id: generateUUID()
|
||||||
};
|
};
|
||||||
// 5分钟过期时间
|
// 5分钟过期时间
|
||||||
await this.redis.set(genCaptchaImgKey(result.id), svg.text, 'EX', 60 * 5);
|
await this.redis.set(genCaptchaImgKey(result.id), svg.text, 'EX', 60 * 5);
|
||||||
|
|
|
@ -57,7 +57,7 @@ export class MenuMeta extends PartialType(
|
||||||
'id',
|
'id',
|
||||||
'roles',
|
'roles',
|
||||||
'path',
|
'path',
|
||||||
'name',
|
'name'
|
||||||
] as const)
|
] as const)
|
||||||
) {
|
) {
|
||||||
title: string;
|
title: string;
|
||||||
|
@ -66,7 +66,7 @@ export class AccountMenus extends PickType(MenuEntity, [
|
||||||
'id',
|
'id',
|
||||||
'path',
|
'path',
|
||||||
'name',
|
'name',
|
||||||
'component',
|
'component'
|
||||||
] as const) {
|
] as const) {
|
||||||
meta: MenuMeta;
|
meta: MenuMeta;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ export class ImageCaptchaDto {
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
required: false,
|
required: false,
|
||||||
default: 100,
|
default: 100,
|
||||||
description: '验证码宽度',
|
description: '验证码宽度'
|
||||||
})
|
})
|
||||||
@Type(() => Number)
|
@Type(() => Number)
|
||||||
@IsInt()
|
@IsInt()
|
||||||
|
@ -16,7 +16,7 @@ export class ImageCaptchaDto {
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
required: false,
|
required: false,
|
||||||
default: 50,
|
default: 50,
|
||||||
description: '验证码宽度',
|
description: '验证码宽度'
|
||||||
})
|
})
|
||||||
@Type(() => Number)
|
@Type(() => Number)
|
||||||
@IsInt()
|
@IsInt()
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {
|
||||||
JoinColumn,
|
JoinColumn,
|
||||||
ManyToOne,
|
ManyToOne,
|
||||||
OneToOne,
|
OneToOne,
|
||||||
PrimaryGeneratedColumn,
|
PrimaryGeneratedColumn
|
||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
|
|
||||||
import { UserEntity } from '~/modules/user/user.entity';
|
import { UserEntity } from '~/modules/user/user.entity';
|
||||||
|
@ -28,12 +28,12 @@ export class AccessTokenEntity extends BaseEntity {
|
||||||
created_at!: Date;
|
created_at!: Date;
|
||||||
|
|
||||||
@OneToOne(() => RefreshTokenEntity, refreshToken => refreshToken.accessToken, {
|
@OneToOne(() => RefreshTokenEntity, refreshToken => refreshToken.accessToken, {
|
||||||
cascade: true,
|
cascade: true
|
||||||
})
|
})
|
||||||
refreshToken!: RefreshTokenEntity;
|
refreshToken!: RefreshTokenEntity;
|
||||||
|
|
||||||
@ManyToOne(() => UserEntity, user => user.accessTokens, {
|
@ManyToOne(() => UserEntity, user => user.accessTokens, {
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE'
|
||||||
})
|
})
|
||||||
@JoinColumn({ name: 'user_id' })
|
@JoinColumn({ name: 'user_id' })
|
||||||
user!: UserEntity;
|
user!: UserEntity;
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {
|
||||||
Entity,
|
Entity,
|
||||||
JoinColumn,
|
JoinColumn,
|
||||||
OneToOne,
|
OneToOne,
|
||||||
PrimaryGeneratedColumn,
|
PrimaryGeneratedColumn
|
||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
|
|
||||||
import { AccessTokenEntity } from './access-token.entity';
|
import { AccessTokenEntity } from './access-token.entity';
|
||||||
|
@ -25,7 +25,7 @@ export class RefreshTokenEntity extends BaseEntity {
|
||||||
created_at!: Date;
|
created_at!: Date;
|
||||||
|
|
||||||
@OneToOne(() => AccessTokenEntity, accessToken => accessToken.refreshToken, {
|
@OneToOne(() => AccessTokenEntity, accessToken => accessToken.refreshToken, {
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE'
|
||||||
})
|
})
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
accessToken!: AccessTokenEntity;
|
accessToken!: AccessTokenEntity;
|
||||||
|
|
|
@ -27,7 +27,7 @@ export class JwtAuthGuard extends AuthGuard(AuthStrategy.JWT) {
|
||||||
async canActivate(context: ExecutionContext): Promise<any> {
|
async canActivate(context: ExecutionContext): Promise<any> {
|
||||||
const isPublic = this.reflector.getAllAndOverride<boolean>(PUBLIC_KEY, [
|
const isPublic = this.reflector.getAllAndOverride<boolean>(PUBLIC_KEY, [
|
||||||
context.getHandler(),
|
context.getHandler(),
|
||||||
context.getClass(),
|
context.getClass()
|
||||||
]);
|
]);
|
||||||
const request = context.switchToHttp().getRequest<FastifyRequest>();
|
const request = context.switchToHttp().getRequest<FastifyRequest>();
|
||||||
// const response = context.switchToHttp().getResponse<FastifyReply>()
|
// const response = context.switchToHttp().getResponse<FastifyReply>()
|
||||||
|
|
|
@ -18,7 +18,7 @@ export class RbacGuard implements CanActivate {
|
||||||
async canActivate(context: ExecutionContext): Promise<any> {
|
async canActivate(context: ExecutionContext): Promise<any> {
|
||||||
const isPublic = this.reflector.getAllAndOverride<boolean>(PUBLIC_KEY, [
|
const isPublic = this.reflector.getAllAndOverride<boolean>(PUBLIC_KEY, [
|
||||||
context.getHandler(),
|
context.getHandler(),
|
||||||
context.getClass(),
|
context.getClass()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (isPublic) return true;
|
if (isPublic) return true;
|
||||||
|
@ -34,7 +34,7 @@ export class RbacGuard implements CanActivate {
|
||||||
|
|
||||||
const payloadPermission = this.reflector.getAllAndOverride<string | string[]>(PERMISSION_KEY, [
|
const payloadPermission = this.reflector.getAllAndOverride<string | string[]>(PERMISSION_KEY, [
|
||||||
context.getHandler(),
|
context.getHandler(),
|
||||||
context.getClass(),
|
context.getClass()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 控制器没有设置接口权限,则默认通过
|
// 控制器没有设置接口权限,则默认通过
|
||||||
|
|
|
@ -23,7 +23,7 @@ export class ResourceGuard implements CanActivate {
|
||||||
async canActivate(context: ExecutionContext): Promise<any> {
|
async canActivate(context: ExecutionContext): Promise<any> {
|
||||||
const isPublic = this.reflector.getAllAndOverride<boolean>(PUBLIC_KEY, [
|
const isPublic = this.reflector.getAllAndOverride<boolean>(PUBLIC_KEY, [
|
||||||
context.getHandler(),
|
context.getHandler(),
|
||||||
context.getClass(),
|
context.getClass()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const request = context.switchToHttp().getRequest<FastifyRequest>();
|
const request = context.switchToHttp().getRequest<FastifyRequest>();
|
||||||
|
@ -66,9 +66,9 @@ export class ResourceGuard implements CanActivate {
|
||||||
const recordQuery = {
|
const recordQuery = {
|
||||||
where: {
|
where: {
|
||||||
id: In(items),
|
id: In(items),
|
||||||
user: { id: user.uid },
|
user: { id: user.uid }
|
||||||
},
|
},
|
||||||
relations: ['user'],
|
relations: ['user']
|
||||||
};
|
};
|
||||||
|
|
||||||
const records = await repo.find(recordQuery);
|
const records = await repo.find(recordQuery);
|
||||||
|
|
|
@ -56,7 +56,7 @@ export class TokenService {
|
||||||
const payload: IAuthUser = {
|
const payload: IAuthUser = {
|
||||||
uid,
|
uid,
|
||||||
pv: 1,
|
pv: 1,
|
||||||
roles,
|
roles
|
||||||
};
|
};
|
||||||
|
|
||||||
const jwtSign = this.jwtService.sign(payload);
|
const jwtSign = this.jwtService.sign(payload);
|
||||||
|
@ -74,7 +74,7 @@ export class TokenService {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
accessToken: jwtSign,
|
accessToken: jwtSign,
|
||||||
refreshToken,
|
refreshToken
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,11 +85,11 @@ export class TokenService {
|
||||||
*/
|
*/
|
||||||
async generateRefreshToken(accessToken: AccessTokenEntity, now: dayjs.Dayjs): Promise<string> {
|
async generateRefreshToken(accessToken: AccessTokenEntity, now: dayjs.Dayjs): Promise<string> {
|
||||||
const refreshTokenPayload = {
|
const refreshTokenPayload = {
|
||||||
uuid: generateUUID(),
|
uuid: generateUUID()
|
||||||
};
|
};
|
||||||
|
|
||||||
const refreshTokenSign = this.jwtService.sign(refreshTokenPayload, {
|
const refreshTokenSign = this.jwtService.sign(refreshTokenPayload, {
|
||||||
secret: this.securityConfig.refreshSecret,
|
secret: this.securityConfig.refreshSecret
|
||||||
});
|
});
|
||||||
|
|
||||||
const refreshToken = new RefreshTokenEntity();
|
const refreshToken = new RefreshTokenEntity();
|
||||||
|
@ -110,7 +110,7 @@ export class TokenService {
|
||||||
return AccessTokenEntity.findOne({
|
return AccessTokenEntity.findOne({
|
||||||
where: { value },
|
where: { value },
|
||||||
relations: ['user', 'refreshToken'],
|
relations: ['user', 'refreshToken'],
|
||||||
cache: true,
|
cache: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ export class TokenService {
|
||||||
*/
|
*/
|
||||||
async removeAccessToken(value: string) {
|
async removeAccessToken(value: string) {
|
||||||
const accessToken = await AccessTokenEntity.findOne({
|
const accessToken = await AccessTokenEntity.findOne({
|
||||||
where: { value },
|
where: { value }
|
||||||
});
|
});
|
||||||
if (accessToken) await accessToken.remove();
|
if (accessToken) await accessToken.remove();
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,7 @@ export class TokenService {
|
||||||
async removeRefreshToken(value: string) {
|
async removeRefreshToken(value: string) {
|
||||||
const refreshToken = await RefreshTokenEntity.findOne({
|
const refreshToken = await RefreshTokenEntity.findOne({
|
||||||
where: { value },
|
where: { value },
|
||||||
relations: ['accessToken'],
|
relations: ['accessToken']
|
||||||
});
|
});
|
||||||
if (refreshToken) {
|
if (refreshToken) {
|
||||||
if (refreshToken.accessToken) await refreshToken.accessToken.remove();
|
if (refreshToken.accessToken) await refreshToken.accessToken.remove();
|
||||||
|
|
|
@ -12,7 +12,7 @@ export class JwtStrategy extends PassportStrategy(Strategy, AuthStrategy.JWT) {
|
||||||
super({
|
super({
|
||||||
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
||||||
ignoreExpiration: false,
|
ignoreExpiration: false,
|
||||||
secretOrKey: securityConfig.jwtSecret,
|
secretOrKey: securityConfig.jwtSecret
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ export class LocalStrategy extends PassportStrategy(Strategy, AuthStrategy.LOCAL
|
||||||
constructor(private authService: AuthService) {
|
constructor(private authService: AuthService) {
|
||||||
super({
|
super({
|
||||||
usernameField: 'credential',
|
usernameField: 'credential',
|
||||||
passwordField: 'password',
|
passwordField: 'password'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ export const permissions = definePermission('app:contract', {
|
||||||
CREATE: 'create',
|
CREATE: 'create',
|
||||||
READ: 'read',
|
READ: 'read',
|
||||||
UPDATE: 'update',
|
UPDATE: 'update',
|
||||||
DELETE: 'delete',
|
DELETE: 'delete'
|
||||||
} as const);
|
} as const);
|
||||||
|
|
||||||
@ApiTags('Contract - 合同')
|
@ApiTags('Contract - 合同')
|
||||||
|
|
|
@ -4,6 +4,6 @@ import { ContractService } from './contract.service';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [ContractController],
|
controllers: [ContractController],
|
||||||
providers: [ContractService],
|
providers: [ContractService]
|
||||||
})
|
})
|
||||||
export class ContractModule {}
|
export class ContractModule {}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {
|
||||||
HealthCheck,
|
HealthCheck,
|
||||||
HttpHealthIndicator,
|
HttpHealthIndicator,
|
||||||
MemoryHealthIndicator,
|
MemoryHealthIndicator,
|
||||||
TypeOrmHealthIndicator,
|
TypeOrmHealthIndicator
|
||||||
} from '@nestjs/terminus';
|
} from '@nestjs/terminus';
|
||||||
|
|
||||||
import { Perm, definePermission } from '../auth/decorators/permission.decorator';
|
import { Perm, definePermission } from '../auth/decorators/permission.decorator';
|
||||||
|
@ -15,7 +15,7 @@ export const PermissionHealth = definePermission('app:health', {
|
||||||
DB: 'database',
|
DB: 'database',
|
||||||
MH: 'memory-heap',
|
MH: 'memory-heap',
|
||||||
MR: 'memory-rss',
|
MR: 'memory-rss',
|
||||||
DISK: 'disk',
|
DISK: 'disk'
|
||||||
} as const);
|
} as const);
|
||||||
|
|
||||||
@ApiTags('Health - 健康检查')
|
@ApiTags('Health - 健康检查')
|
||||||
|
@ -65,7 +65,7 @@ export class HealthController {
|
||||||
return this.disk.checkStorage('disk', {
|
return this.disk.checkStorage('disk', {
|
||||||
// The used disk storage should not exceed 75% of the full disk size
|
// The used disk storage should not exceed 75% of the full disk size
|
||||||
thresholdPercent: 0.75,
|
thresholdPercent: 0.75,
|
||||||
path: '/',
|
path: '/'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,6 @@ import { HealthController } from './health.controller';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [TerminusModule, HttpModule],
|
imports: [TerminusModule, HttpModule],
|
||||||
controllers: [HealthController],
|
controllers: [HealthController]
|
||||||
})
|
})
|
||||||
export class HealthModule {}
|
export class HealthModule {}
|
||||||
|
|
|
@ -49,7 +49,7 @@ export class SFileInfoDetail {
|
||||||
mimeType: string;
|
mimeType: string;
|
||||||
|
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
description: '文件存储类型,2 表示归档存储,1 表示低频存储,0表示普通存储。',
|
description: '文件存储类型,2 表示归档存储,1 表示低频存储,0表示普通存储。'
|
||||||
})
|
})
|
||||||
type: number;
|
type: number;
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ import {
|
||||||
GetFileListDto,
|
GetFileListDto,
|
||||||
MKDirDto,
|
MKDirDto,
|
||||||
MarkFileDto,
|
MarkFileDto,
|
||||||
RenameDto,
|
RenameDto
|
||||||
} from './manage.dto';
|
} from './manage.dto';
|
||||||
import { NetDiskManageService } from './manage.service';
|
import { NetDiskManageService } from './manage.service';
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ export const permissions = definePermission('netdisk:manage', {
|
||||||
DOWNLOAD: 'download',
|
DOWNLOAD: 'download',
|
||||||
RENAME: 'rename',
|
RENAME: 'rename',
|
||||||
CUT: 'cut',
|
CUT: 'cut',
|
||||||
COPY: 'copy',
|
COPY: 'copy'
|
||||||
} as const);
|
} as const);
|
||||||
|
|
||||||
@ApiTags('NetDiskManage - 网盘管理模块')
|
@ApiTags('NetDiskManage - 网盘管理模块')
|
||||||
|
@ -67,7 +67,7 @@ export class NetDiskManageController {
|
||||||
checkIsDemoMode();
|
checkIsDemoMode();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
token: this.manageService.createUploadToken(`${user.uid}`),
|
token: this.manageService.createUploadToken(`${user.uid}`)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ export class NetDiskManageController {
|
||||||
@Perm(permissions.MARK)
|
@Perm(permissions.MARK)
|
||||||
async mark(@Body() dto: MarkFileDto): Promise<void> {
|
async mark(@Body() dto: MarkFileDto): Promise<void> {
|
||||||
await this.manageService.changeFileHeaders(dto.name, dto.path, {
|
await this.manageService.changeFileHeaders(dto.name, dto.path, {
|
||||||
mark: dto.mark,
|
mark: dto.mark
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {
|
||||||
ValidateNested,
|
ValidateNested,
|
||||||
ValidationArguments,
|
ValidationArguments,
|
||||||
ValidatorConstraint,
|
ValidatorConstraint,
|
||||||
ValidatorConstraintInterface,
|
ValidatorConstraintInterface
|
||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
import { isEmpty } from 'lodash';
|
import { isEmpty } from 'lodash';
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {
|
||||||
NETDISK_COPY_SUFFIX,
|
NETDISK_COPY_SUFFIX,
|
||||||
NETDISK_DELIMITER,
|
NETDISK_DELIMITER,
|
||||||
NETDISK_HANDLE_MAX_ITEM,
|
NETDISK_HANDLE_MAX_ITEM,
|
||||||
NETDISK_LIMIT,
|
NETDISK_LIMIT
|
||||||
} from '~/constants/oss.constant';
|
} from '~/constants/oss.constant';
|
||||||
|
|
||||||
import { AccountInfo } from '~/modules/user/user.model';
|
import { AccountInfo } from '~/modules/user/user.model';
|
||||||
|
@ -38,7 +38,7 @@ export class NetDiskManageService {
|
||||||
) {
|
) {
|
||||||
this.mac = new qiniu.auth.digest.Mac(this.qiniuConfig.accessKey, this.qiniuConfig.secretKey);
|
this.mac = new qiniu.auth.digest.Mac(this.qiniuConfig.accessKey, this.qiniuConfig.secretKey);
|
||||||
this.config = new qiniu.conf.Config({
|
this.config = new qiniu.conf.Config({
|
||||||
zone: this.qiniuConfig.zone,
|
zone: this.qiniuConfig.zone
|
||||||
});
|
});
|
||||||
// bucket manager
|
// bucket manager
|
||||||
this.bucketManager = new qiniu.rs.BucketManager(this.mac, this.config);
|
this.bucketManager = new qiniu.rs.BucketManager(this.mac, this.config);
|
||||||
|
@ -60,7 +60,7 @@ export class NetDiskManageService {
|
||||||
prefix: searching ? '' : prefix,
|
prefix: searching ? '' : prefix,
|
||||||
limit: NETDISK_LIMIT,
|
limit: NETDISK_LIMIT,
|
||||||
delimiter: searching ? '' : NETDISK_DELIMITER,
|
delimiter: searching ? '' : NETDISK_DELIMITER,
|
||||||
marker,
|
marker
|
||||||
},
|
},
|
||||||
(err, respBody, respInfo) => {
|
(err, respBody, respInfo) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -80,7 +80,7 @@ export class NetDiskManageService {
|
||||||
fileList.push({
|
fileList.push({
|
||||||
name: (dirPath as string).substr(0, dirPath.length - 1).replace(prefix, ''),
|
name: (dirPath as string).substr(0, dirPath.length - 1).replace(prefix, ''),
|
||||||
type: 'dir',
|
type: 'dir',
|
||||||
id: generateRandomValue(10),
|
id: generateRandomValue(10)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ export class NetDiskManageService {
|
||||||
id: generateRandomValue(10),
|
id: generateRandomValue(10),
|
||||||
name: ditName,
|
name: ditName,
|
||||||
type: 'dir',
|
type: 'dir',
|
||||||
belongTo: pathList.join(NETDISK_DELIMITER),
|
belongTo: pathList.join(NETDISK_DELIMITER)
|
||||||
});
|
});
|
||||||
} else if (name.includes(skey)) {
|
} else if (name.includes(skey)) {
|
||||||
// 文件
|
// 文件
|
||||||
|
@ -115,7 +115,7 @@ export class NetDiskManageService {
|
||||||
fsize: item.fsize,
|
fsize: item.fsize,
|
||||||
mimeType: item.mimeType,
|
mimeType: item.mimeType,
|
||||||
putTime: new Date(Number.parseInt(item.putTime) / 10000),
|
putTime: new Date(Number.parseInt(item.putTime) / 10000),
|
||||||
belongTo: pathList.join(NETDISK_DELIMITER),
|
belongTo: pathList.join(NETDISK_DELIMITER)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -128,7 +128,7 @@ export class NetDiskManageService {
|
||||||
type: 'file',
|
type: 'file',
|
||||||
fsize: item.fsize,
|
fsize: item.fsize,
|
||||||
mimeType: item.mimeType,
|
mimeType: item.mimeType,
|
||||||
putTime: new Date(Number.parseInt(item.putTime) / 10000),
|
putTime: new Date(Number.parseInt(item.putTime) / 10000)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ export class NetDiskManageService {
|
||||||
}
|
}
|
||||||
resolve({
|
resolve({
|
||||||
list: fileList,
|
list: fileList,
|
||||||
marker: respBody.marker || null,
|
marker: respBody.marker || null
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
reject(
|
reject(
|
||||||
|
@ -170,7 +170,7 @@ export class NetDiskManageService {
|
||||||
putTime: new Date(Number.parseInt(respBody.putTime) / 10000),
|
putTime: new Date(Number.parseInt(respBody.putTime) / 10000),
|
||||||
type: respBody.type,
|
type: respBody.type,
|
||||||
uploader: '',
|
uploader: '',
|
||||||
mark: respBody?.['x-qn-meta']?.['!mark'] ?? '',
|
mark: respBody?.['x-qn-meta']?.['!mark'] ?? ''
|
||||||
};
|
};
|
||||||
if (!respBody.endUser) {
|
if (!respBody.endUser) {
|
||||||
resolve(detailInfo);
|
resolve(detailInfo);
|
||||||
|
@ -295,7 +295,7 @@ export class NetDiskManageService {
|
||||||
scope: this.qiniuConfig.bucket,
|
scope: this.qiniuConfig.bucket,
|
||||||
insertOnly: 1,
|
insertOnly: 1,
|
||||||
fsizeLimit: 1024 ** 2 * 10,
|
fsizeLimit: 1024 ** 2 * 10,
|
||||||
endUser,
|
endUser
|
||||||
});
|
});
|
||||||
const uploadToken = policy.uploadToken(this.mac);
|
const uploadToken = policy.uploadToken(this.mac);
|
||||||
return uploadToken;
|
return uploadToken;
|
||||||
|
@ -310,7 +310,7 @@ export class NetDiskManageService {
|
||||||
const fileName = `${dir}${name}`;
|
const fileName = `${dir}${name}`;
|
||||||
const toFileName = `${dir}${toName}`;
|
const toFileName = `${dir}${toName}`;
|
||||||
const op = {
|
const op = {
|
||||||
force: true,
|
force: true
|
||||||
};
|
};
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.bucketManager.move(
|
this.bucketManager.move(
|
||||||
|
@ -345,7 +345,7 @@ export class NetDiskManageService {
|
||||||
const fileName = `${dir}${name}`;
|
const fileName = `${dir}${name}`;
|
||||||
const toFileName = `${toDir}${name}`;
|
const toFileName = `${toDir}${name}`;
|
||||||
const op = {
|
const op = {
|
||||||
force: true,
|
force: true
|
||||||
};
|
};
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.bucketManager.move(
|
this.bucketManager.move(
|
||||||
|
@ -383,7 +383,7 @@ export class NetDiskManageService {
|
||||||
const bn = basename(name, ext);
|
const bn = basename(name, ext);
|
||||||
const toFileName = `${toDir}${bn}${NETDISK_COPY_SUFFIX}${ext}`;
|
const toFileName = `${toDir}${bn}${NETDISK_COPY_SUFFIX}${ext}`;
|
||||||
const op = {
|
const op = {
|
||||||
force: true,
|
force: true
|
||||||
};
|
};
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.bucketManager.copy(
|
this.bucketManager.copy(
|
||||||
|
@ -420,7 +420,7 @@ export class NetDiskManageService {
|
||||||
let hasFile = true;
|
let hasFile = true;
|
||||||
let marker = '';
|
let marker = '';
|
||||||
const op = {
|
const op = {
|
||||||
force: true,
|
force: true
|
||||||
};
|
};
|
||||||
const bucketName = this.qiniuConfig.bucket;
|
const bucketName = this.qiniuConfig.bucket;
|
||||||
while (hasFile) {
|
while (hasFile) {
|
||||||
|
@ -431,7 +431,7 @@ export class NetDiskManageService {
|
||||||
{
|
{
|
||||||
prefix: dirName,
|
prefix: dirName,
|
||||||
limit: NETDISK_HANDLE_MAX_ITEM,
|
limit: NETDISK_HANDLE_MAX_ITEM,
|
||||||
marker,
|
marker
|
||||||
},
|
},
|
||||||
(err, respBody, respInfo) => {
|
(err, respBody, respInfo) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -567,7 +567,7 @@ export class NetDiskManageService {
|
||||||
{
|
{
|
||||||
prefix: dirName,
|
prefix: dirName,
|
||||||
limit: NETDISK_HANDLE_MAX_ITEM,
|
limit: NETDISK_HANDLE_MAX_ITEM,
|
||||||
marker,
|
marker
|
||||||
},
|
},
|
||||||
(err, respBody, respInfo) => {
|
(err, respBody, respInfo) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -618,7 +618,7 @@ export class NetDiskManageService {
|
||||||
async copyMultiFileOrDir(fileList: FileOpItem[], dir: string, toDir: string): Promise<void> {
|
async copyMultiFileOrDir(fileList: FileOpItem[], dir: string, toDir: string): Promise<void> {
|
||||||
const files = fileList.filter(item => item.type === 'file');
|
const files = fileList.filter(item => item.type === 'file');
|
||||||
const op = {
|
const op = {
|
||||||
force: true,
|
force: true
|
||||||
};
|
};
|
||||||
if (files.length > 0) {
|
if (files.length > 0) {
|
||||||
// 批处理文件
|
// 批处理文件
|
||||||
|
@ -671,7 +671,7 @@ export class NetDiskManageService {
|
||||||
{
|
{
|
||||||
prefix: dirName,
|
prefix: dirName,
|
||||||
limit: NETDISK_HANDLE_MAX_ITEM,
|
limit: NETDISK_HANDLE_MAX_ITEM,
|
||||||
marker,
|
marker
|
||||||
},
|
},
|
||||||
(err, respBody, respInfo) => {
|
(err, respBody, respInfo) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -729,7 +729,7 @@ export class NetDiskManageService {
|
||||||
async moveMultiFileOrDir(fileList: FileOpItem[], dir: string, toDir: string): Promise<void> {
|
async moveMultiFileOrDir(fileList: FileOpItem[], dir: string, toDir: string): Promise<void> {
|
||||||
const files = fileList.filter(item => item.type === 'file');
|
const files = fileList.filter(item => item.type === 'file');
|
||||||
const op = {
|
const op = {
|
||||||
force: true,
|
force: true
|
||||||
};
|
};
|
||||||
if (files.length > 0) {
|
if (files.length > 0) {
|
||||||
// 批处理文件
|
// 批处理文件
|
||||||
|
@ -782,7 +782,7 @@ export class NetDiskManageService {
|
||||||
{
|
{
|
||||||
prefix: dirName,
|
prefix: dirName,
|
||||||
limit: NETDISK_HANDLE_MAX_ITEM,
|
limit: NETDISK_HANDLE_MAX_ITEM,
|
||||||
marker,
|
marker
|
||||||
},
|
},
|
||||||
(err, respBody, respInfo) => {
|
(err, respBody, respInfo) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
|
@ -15,11 +15,11 @@ import { NetDiskOverviewService } from './overview/overview.service';
|
||||||
RouterModule.register([
|
RouterModule.register([
|
||||||
{
|
{
|
||||||
path: 'netdisk',
|
path: 'netdisk',
|
||||||
module: NetdiskModule,
|
module: NetdiskModule
|
||||||
},
|
}
|
||||||
]),
|
])
|
||||||
],
|
],
|
||||||
controllers: [NetDiskManageController, NetDiskOverviewController],
|
controllers: [NetDiskManageController, NetDiskOverviewController],
|
||||||
providers: [NetDiskManageService, NetDiskOverviewService],
|
providers: [NetDiskManageService, NetDiskOverviewService]
|
||||||
})
|
})
|
||||||
export class NetdiskModule {}
|
export class NetdiskModule {}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { OverviewSpaceInfo } from './overview.dto';
|
||||||
import { NetDiskOverviewService } from './overview.service';
|
import { NetDiskOverviewService } from './overview.service';
|
||||||
|
|
||||||
export const permissions = definePermission('netdisk:overview', {
|
export const permissions = definePermission('netdisk:overview', {
|
||||||
DESC: 'desc',
|
DESC: 'desc'
|
||||||
} as const);
|
} as const);
|
||||||
|
|
||||||
@ApiTags('NetDiskOverview - 网盘概览模块')
|
@ApiTags('NetDiskOverview - 网盘概览模块')
|
||||||
|
@ -35,7 +35,7 @@ export class NetDiskOverviewController {
|
||||||
hitSize: hit.datas[hit.datas.length - 1],
|
hitSize: hit.datas[hit.datas.length - 1],
|
||||||
spaceSize: space.datas[space.datas.length - 1],
|
spaceSize: space.datas[space.datas.length - 1],
|
||||||
flowTrend: flow,
|
flowTrend: flow,
|
||||||
sizeTrend: space,
|
sizeTrend: space
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ export class NetDiskOverviewService {
|
||||||
getStatisticUrl(type: string, queryParams = {}) {
|
getStatisticUrl(type: string, queryParams = {}) {
|
||||||
const defaultParams = {
|
const defaultParams = {
|
||||||
$bucket: this.qiniuConfig.bucket,
|
$bucket: this.qiniuConfig.bucket,
|
||||||
g: 'day',
|
g: 'day'
|
||||||
};
|
};
|
||||||
const searchParams = new URLSearchParams({ ...defaultParams, ...queryParams });
|
const searchParams = new URLSearchParams({ ...defaultParams, ...queryParams });
|
||||||
return decodeURIComponent(`${OSS_API}/v6/${type}?${searchParams}`);
|
return decodeURIComponent(`${OSS_API}/v6/${type}?${searchParams}`);
|
||||||
|
@ -53,8 +53,8 @@ export class NetDiskOverviewService {
|
||||||
return this.httpService.axiosRef.get(url, {
|
return this.httpService.axiosRef.get(url, {
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
Authorization: `${accessToken}`,
|
Authorization: `${accessToken}`
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ export class NetDiskOverviewService {
|
||||||
datas: data.datas,
|
datas: data.datas,
|
||||||
times: data.times.map(e => {
|
times: data.times.map(e => {
|
||||||
return dayjs.unix(e).date();
|
return dayjs.unix(e).date();
|
||||||
}),
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ export class NetDiskOverviewService {
|
||||||
times: data.times.map(e => {
|
times: data.times.map(e => {
|
||||||
return dayjs.unix(e).date();
|
return dayjs.unix(e).date();
|
||||||
}),
|
}),
|
||||||
datas: data.datas,
|
datas: data.datas
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ export class NetDiskOverviewService {
|
||||||
end,
|
end,
|
||||||
$ftype: 0,
|
$ftype: 0,
|
||||||
$src: 'origin',
|
$src: 'origin',
|
||||||
select: 'flow',
|
select: 'flow'
|
||||||
});
|
});
|
||||||
const { data } = await this.getStatisticData(url);
|
const { data } = await this.getStatisticData(url);
|
||||||
const times = [];
|
const times = [];
|
||||||
|
@ -132,7 +132,7 @@ export class NetDiskOverviewService {
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
times,
|
times,
|
||||||
datas,
|
datas
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ export class NetDiskOverviewService {
|
||||||
end,
|
end,
|
||||||
$ftype: 0,
|
$ftype: 0,
|
||||||
$src: 'inner',
|
$src: 'inner',
|
||||||
select: 'hit',
|
select: 'hit'
|
||||||
});
|
});
|
||||||
const { data } = await this.getStatisticData(url);
|
const { data } = await this.getStatisticData(url);
|
||||||
const times = [];
|
const times = [];
|
||||||
|
@ -159,7 +159,7 @@ export class NetDiskOverviewService {
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
times,
|
times,
|
||||||
datas,
|
datas
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {
|
||||||
ParseIntPipe,
|
ParseIntPipe,
|
||||||
Req,
|
Req,
|
||||||
Res,
|
Res,
|
||||||
Sse,
|
Sse
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { ApiTags } from '@nestjs/swagger';
|
import { ApiTags } from '@nestjs/swagger';
|
||||||
import { FastifyReply, FastifyRequest } from 'fastify';
|
import { FastifyReply, FastifyRequest } from 'fastify';
|
||||||
|
@ -26,7 +26,7 @@ export class SseController implements BeforeApplicationShutdown {
|
||||||
private closeAllConnect() {
|
private closeAllConnect() {
|
||||||
this.sseService.sendToAll({
|
this.sseService.sendToAll({
|
||||||
type: 'close',
|
type: 'close',
|
||||||
data: 'bye~',
|
data: 'bye~'
|
||||||
});
|
});
|
||||||
this.replyMap.forEach(reply => {
|
this.replyMap.forEach(reply => {
|
||||||
reply.raw.end().destroy();
|
reply.raw.end().destroy();
|
||||||
|
|
|
@ -7,6 +7,6 @@ import { SseService } from './sse.service';
|
||||||
imports: [],
|
imports: [],
|
||||||
controllers: [SseController],
|
controllers: [SseController],
|
||||||
providers: [SseService],
|
providers: [SseService],
|
||||||
exports: [SseService],
|
exports: [SseService]
|
||||||
})
|
})
|
||||||
export class SseModule {}
|
export class SseModule {}
|
||||||
|
|
|
@ -58,9 +58,9 @@ export class SseService {
|
||||||
const roleMenus = await RoleEntity.find({
|
const roleMenus = await RoleEntity.find({
|
||||||
where: {
|
where: {
|
||||||
menus: {
|
menus: {
|
||||||
id: In(menuIds),
|
id: In(menuIds)
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
const roleIds = roleMenus.map(n => n.id).concat(ROOT_ROLE_ID);
|
const roleIds = roleMenus.map(n => n.id).concat(ROOT_ROLE_ID);
|
||||||
await this.noticeClientToUpdateMenusByRoleIds(roleIds);
|
await this.noticeClientToUpdateMenusByRoleIds(roleIds);
|
||||||
|
@ -73,9 +73,9 @@ export class SseService {
|
||||||
const users = await UserEntity.find({
|
const users = await UserEntity.find({
|
||||||
where: {
|
where: {
|
||||||
roles: {
|
roles: {
|
||||||
id: In(roleIds),
|
id: In(roleIds)
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
if (users) {
|
if (users) {
|
||||||
const userIds = users.map(n => n.id);
|
const userIds = users.map(n => n.id);
|
||||||
|
|
|
@ -18,7 +18,7 @@ export const permissions = definePermission('system:dept', {
|
||||||
CREATE: 'create',
|
CREATE: 'create',
|
||||||
READ: 'read',
|
READ: 'read',
|
||||||
UPDATE: 'update',
|
UPDATE: 'update',
|
||||||
DELETE: 'delete',
|
DELETE: 'delete'
|
||||||
} as const);
|
} as const);
|
||||||
|
|
||||||
@ApiSecurityAuth()
|
@ApiSecurityAuth()
|
||||||
|
|
|
@ -8,7 +8,7 @@ import {
|
||||||
IsString,
|
IsString,
|
||||||
Min,
|
Min,
|
||||||
MinLength,
|
MinLength,
|
||||||
ValidateNested,
|
ValidateNested
|
||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
|
|
||||||
export class DeptDto {
|
export class DeptDto {
|
||||||
|
|
|
@ -14,6 +14,6 @@ const services = [DeptService];
|
||||||
imports: [TypeOrmModule.forFeature([DeptEntity]), UserModule, RoleModule],
|
imports: [TypeOrmModule.forFeature([DeptEntity]), UserModule, RoleModule],
|
||||||
controllers: [DeptController],
|
controllers: [DeptController],
|
||||||
providers: [...services],
|
providers: [...services],
|
||||||
exports: [TypeOrmModule, ...services],
|
exports: [TypeOrmModule, ...services]
|
||||||
})
|
})
|
||||||
export class DeptModule {}
|
export class DeptModule {}
|
||||||
|
|
|
@ -46,7 +46,7 @@ export class DeptService {
|
||||||
|
|
||||||
await this.deptRepository.save({
|
await this.deptRepository.save({
|
||||||
...data,
|
...data,
|
||||||
parent,
|
parent
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ export class DeptService {
|
||||||
await this.deptRepository.save({
|
await this.deptRepository.save({
|
||||||
...item,
|
...item,
|
||||||
...data,
|
...data,
|
||||||
parent,
|
parent
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ export class DeptService {
|
||||||
|
|
||||||
const deptTree = await this.deptRepository.findTrees({
|
const deptTree = await this.deptRepository.findTrees({
|
||||||
depth: 2,
|
depth: 2,
|
||||||
relations: ['parent'],
|
relations: ['parent']
|
||||||
});
|
});
|
||||||
|
|
||||||
deleteEmptyChildren(deptTree);
|
deleteEmptyChildren(deptTree);
|
||||||
|
|
|
@ -17,7 +17,7 @@ export const permissions = definePermission('system:dict-item', {
|
||||||
CREATE: 'create',
|
CREATE: 'create',
|
||||||
READ: 'read',
|
READ: 'read',
|
||||||
UPDATE: 'update',
|
UPDATE: 'update',
|
||||||
DELETE: 'delete',
|
DELETE: 'delete'
|
||||||
} as const);
|
} as const);
|
||||||
|
|
||||||
@ApiTags('System - 字典项模块')
|
@ApiTags('System - 字典项模块')
|
||||||
|
|
|
@ -11,6 +11,6 @@ const services = [DictItemService];
|
||||||
imports: [TypeOrmModule.forFeature([DictItemEntity])],
|
imports: [TypeOrmModule.forFeature([DictItemEntity])],
|
||||||
controllers: [DictItemController],
|
controllers: [DictItemController],
|
||||||
providers: [...services],
|
providers: [...services],
|
||||||
exports: [TypeOrmModule, ...services],
|
exports: [TypeOrmModule, ...services]
|
||||||
})
|
})
|
||||||
export class DictItemModule {}
|
export class DictItemModule {}
|
||||||
|
|
|
@ -26,7 +26,7 @@ export class DictItemService {
|
||||||
pageSize,
|
pageSize,
|
||||||
label,
|
label,
|
||||||
value,
|
value,
|
||||||
typeId,
|
typeId
|
||||||
}: DictItemQueryDto): Promise<Pagination<DictItemEntity>> {
|
}: DictItemQueryDto): Promise<Pagination<DictItemEntity>> {
|
||||||
const queryBuilder = this.dictItemRepository
|
const queryBuilder = this.dictItemRepository
|
||||||
.createQueryBuilder('dict_item')
|
.createQueryBuilder('dict_item')
|
||||||
|
@ -35,8 +35,8 @@ export class DictItemService {
|
||||||
...(label && { label: Like(`%${label}%`) }),
|
...(label && { label: Like(`%${label}%`) }),
|
||||||
...(value && { value: Like(`%${value}%`) }),
|
...(value && { value: Like(`%${value}%`) }),
|
||||||
type: {
|
type: {
|
||||||
id: typeId,
|
id: typeId
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return paginate(queryBuilder, { page, pageSize });
|
return paginate(queryBuilder, { page, pageSize });
|
||||||
|
@ -57,8 +57,8 @@ export class DictItemService {
|
||||||
await this.dictItemRepository.insert({
|
await this.dictItemRepository.insert({
|
||||||
...rest,
|
...rest,
|
||||||
type: {
|
type: {
|
||||||
id: typeId,
|
id: typeId
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,8 +70,8 @@ export class DictItemService {
|
||||||
await this.dictItemRepository.update(id, {
|
await this.dictItemRepository.update(id, {
|
||||||
...rest,
|
...rest,
|
||||||
type: {
|
type: {
|
||||||
id: typeId,
|
id: typeId
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ export const permissions = definePermission('system:dict-type', {
|
||||||
CREATE: 'create',
|
CREATE: 'create',
|
||||||
READ: 'read',
|
READ: 'read',
|
||||||
UPDATE: 'update',
|
UPDATE: 'update',
|
||||||
DELETE: 'delete',
|
DELETE: 'delete'
|
||||||
} as const);
|
} as const);
|
||||||
|
|
||||||
@ApiTags('System - 字典类型模块')
|
@ApiTags('System - 字典类型模块')
|
||||||
|
|
|
@ -11,6 +11,6 @@ const services = [DictTypeService];
|
||||||
imports: [TypeOrmModule.forFeature([DictTypeEntity])],
|
imports: [TypeOrmModule.forFeature([DictTypeEntity])],
|
||||||
controllers: [DictTypeController],
|
controllers: [DictTypeController],
|
||||||
providers: [...services],
|
providers: [...services],
|
||||||
exports: [TypeOrmModule, ...services],
|
exports: [TypeOrmModule, ...services]
|
||||||
})
|
})
|
||||||
export class DictTypeModule {}
|
export class DictTypeModule {}
|
||||||
|
|
|
@ -25,11 +25,11 @@ export class DictTypeService {
|
||||||
page,
|
page,
|
||||||
pageSize,
|
pageSize,
|
||||||
name,
|
name,
|
||||||
code,
|
code
|
||||||
}: DictTypeQueryDto): Promise<Pagination<DictTypeEntity>> {
|
}: DictTypeQueryDto): Promise<Pagination<DictTypeEntity>> {
|
||||||
const queryBuilder = this.dictTypeRepository.createQueryBuilder('dict_type').where({
|
const queryBuilder = this.dictTypeRepository.createQueryBuilder('dict_type').where({
|
||||||
...(name && { name: Like(`%${name}%`) }),
|
...(name && { name: Like(`%${name}%`) }),
|
||||||
...(code && { code: Like(`%${code}%`) }),
|
...(code && { code: Like(`%${code}%`) })
|
||||||
});
|
});
|
||||||
|
|
||||||
return paginate(queryBuilder, { page, pageSize });
|
return paginate(queryBuilder, { page, pageSize });
|
||||||
|
|
|
@ -17,7 +17,7 @@ import { TaskLogService } from './services/task-log.service';
|
||||||
export const permissions = definePermission('system:log', {
|
export const permissions = definePermission('system:log', {
|
||||||
TaskList: 'task:list',
|
TaskList: 'task:list',
|
||||||
LogList: 'login:list',
|
LogList: 'login:list',
|
||||||
CaptchaList: 'captcha:list',
|
CaptchaList: 'captcha:list'
|
||||||
} as const);
|
} as const);
|
||||||
|
|
||||||
@ApiSecurityAuth()
|
@ApiSecurityAuth()
|
||||||
|
|
|
@ -16,10 +16,10 @@ const providers = [LoginLogService, TaskLogService, CaptchaLogService];
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
TypeOrmModule.forFeature([LoginLogEntity, CaptchaLogEntity, TaskLogEntity]),
|
TypeOrmModule.forFeature([LoginLogEntity, CaptchaLogEntity, TaskLogEntity]),
|
||||||
UserModule,
|
UserModule
|
||||||
],
|
],
|
||||||
controllers: [LogController],
|
controllers: [LogController],
|
||||||
providers: [...providers],
|
providers: [...providers],
|
||||||
exports: [TypeOrmModule, ...providers],
|
exports: [TypeOrmModule, ...providers]
|
||||||
})
|
})
|
||||||
export class LogModule {}
|
export class LogModule {}
|
||||||
|
|
|
@ -25,7 +25,7 @@ export class CaptchaLogService {
|
||||||
account,
|
account,
|
||||||
code,
|
code,
|
||||||
provider,
|
provider,
|
||||||
userId: uid,
|
userId: uid
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ export class CaptchaLogService {
|
||||||
|
|
||||||
return paginate<CaptchaLogEntity>(queryBuilder, {
|
return paginate<CaptchaLogEntity>(queryBuilder, {
|
||||||
page,
|
page,
|
||||||
pageSize,
|
pageSize
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ async function parseLoginLog(e: any, parser: UAParser): Promise<LoginLogInfo> {
|
||||||
os: `${`${uaResult.os.name ?? ''} `}${uaResult.os.version}`,
|
os: `${`${uaResult.os.name ?? ''} `}${uaResult.os.version}`,
|
||||||
browser: `${`${uaResult.browser.name ?? ''} `}${uaResult.browser.version}`,
|
browser: `${`${uaResult.browser.name ?? ''} `}${uaResult.browser.version}`,
|
||||||
username: e.user_username,
|
username: e.user_username,
|
||||||
time: e.login_log_created_at,
|
time: e.login_log_created_at
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ export class LoginLogService {
|
||||||
ip,
|
ip,
|
||||||
ua,
|
ua,
|
||||||
address,
|
address,
|
||||||
user: { id: uid },
|
user: { id: uid }
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
@ -59,15 +59,15 @@ export class LoginLogService {
|
||||||
...(time && { createdAt: Between(time[0], time[1]) }),
|
...(time && { createdAt: Between(time[0], time[1]) }),
|
||||||
...(username && {
|
...(username && {
|
||||||
user: {
|
user: {
|
||||||
username: Like(`%${username}%`),
|
username: Like(`%${username}%`)
|
||||||
},
|
}
|
||||||
}),
|
})
|
||||||
})
|
})
|
||||||
.orderBy('login_log.created_at', 'DESC');
|
.orderBy('login_log.created_at', 'DESC');
|
||||||
|
|
||||||
const { items, ...rest } = await paginateRaw<LoginLogEntity>(queryBuilder, {
|
const { items, ...rest } = await paginateRaw<LoginLogEntity>(queryBuilder, {
|
||||||
page,
|
page,
|
||||||
pageSize,
|
pageSize
|
||||||
});
|
});
|
||||||
|
|
||||||
const parser = new UAParser();
|
const parser = new UAParser();
|
||||||
|
@ -75,7 +75,7 @@ export class LoginLogService {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
items: loginLogInfos,
|
items: loginLogInfos,
|
||||||
...rest,
|
...rest
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ export class TaskLogService {
|
||||||
status,
|
status,
|
||||||
detail: err,
|
detail: err,
|
||||||
time,
|
time,
|
||||||
task: { id: tid },
|
task: { id: tid }
|
||||||
});
|
});
|
||||||
return result.id;
|
return result.id;
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ export class TaskLogService {
|
||||||
|
|
||||||
return paginate<TaskLogEntity>(queryBuilder, {
|
return paginate<TaskLogEntity>(queryBuilder, {
|
||||||
page,
|
page,
|
||||||
pageSize,
|
pageSize
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {
|
||||||
Get,
|
Get,
|
||||||
Post,
|
Post,
|
||||||
Put,
|
Put,
|
||||||
Query,
|
Query
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||||
import { flattenDeep } from 'lodash';
|
import { flattenDeep } from 'lodash';
|
||||||
|
@ -17,7 +17,7 @@ import { ApiSecurityAuth } from '~/common/decorators/swagger.decorator';
|
||||||
import {
|
import {
|
||||||
Perm,
|
Perm,
|
||||||
definePermission,
|
definePermission,
|
||||||
getDefinePermissions,
|
getDefinePermissions
|
||||||
} from '~/modules/auth/decorators/permission.decorator';
|
} from '~/modules/auth/decorators/permission.decorator';
|
||||||
|
|
||||||
import { MenuDto, MenuQueryDto, MenuUpdateDto } from './menu.dto';
|
import { MenuDto, MenuQueryDto, MenuUpdateDto } from './menu.dto';
|
||||||
|
@ -29,7 +29,7 @@ export const permissions = definePermission('system:menu', {
|
||||||
CREATE: 'create',
|
CREATE: 'create',
|
||||||
READ: 'read',
|
READ: 'read',
|
||||||
UPDATE: 'update',
|
UPDATE: 'update',
|
||||||
DELETE: 'delete',
|
DELETE: 'delete'
|
||||||
} as const);
|
} as const);
|
||||||
|
|
||||||
@ApiTags('System - 菜单权限模块')
|
@ApiTags('System - 菜单权限模块')
|
||||||
|
|
|
@ -7,7 +7,7 @@ import {
|
||||||
IsString,
|
IsString,
|
||||||
Min,
|
Min,
|
||||||
MinLength,
|
MinLength,
|
||||||
ValidateIf,
|
ValidateIf
|
||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
|
|
||||||
export class MenuDto {
|
export class MenuDto {
|
||||||
|
|
|
@ -49,7 +49,7 @@ export class MenuEntity extends CommonEntity {
|
||||||
status: number;
|
status: number;
|
||||||
|
|
||||||
@ManyToMany(() => RoleEntity, role => role.menus, {
|
@ManyToMany(() => RoleEntity, role => role.menus, {
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE'
|
||||||
})
|
})
|
||||||
roles: Relation<RoleEntity[]>;
|
roles: Relation<RoleEntity[]>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,6 @@ const providers = [MenuService, SseService];
|
||||||
imports: [TypeOrmModule.forFeature([MenuEntity]), forwardRef(() => RoleModule)],
|
imports: [TypeOrmModule.forFeature([MenuEntity]), forwardRef(() => RoleModule)],
|
||||||
controllers: [MenuController],
|
controllers: [MenuController],
|
||||||
providers: [...providers],
|
providers: [...providers],
|
||||||
exports: [TypeOrmModule, ...providers],
|
exports: [TypeOrmModule, ...providers]
|
||||||
})
|
})
|
||||||
export class MenuModule {}
|
export class MenuModule {}
|
||||||
|
|
|
@ -39,9 +39,9 @@ export class MenuService {
|
||||||
...(path && { path: Like(`%${path}%`) }),
|
...(path && { path: Like(`%${path}%`) }),
|
||||||
...(permission && { permission: Like(`%${permission}%`) }),
|
...(permission && { permission: Like(`%${permission}%`) }),
|
||||||
...(component && { component: Like(`%${component}%`) }),
|
...(component && { component: Like(`%${component}%`) }),
|
||||||
...(isNumber(status) ? { status } : null),
|
...(isNumber(status) ? { status } : null)
|
||||||
},
|
},
|
||||||
order: { orderNo: 'ASC' },
|
order: { orderNo: 'ASC' }
|
||||||
});
|
});
|
||||||
const menuList = generatorMenu(menus);
|
const menuList = generatorMenu(menus);
|
||||||
|
|
||||||
|
@ -166,7 +166,7 @@ export class MenuService {
|
||||||
if (this.roleService.hasAdminRole(roleIds)) {
|
if (this.roleService.hasAdminRole(roleIds)) {
|
||||||
result = await this.menuRepository.findBy({
|
result = await this.menuRepository.findBy({
|
||||||
permission: Not(IsNull()),
|
permission: Not(IsNull()),
|
||||||
type: In([1, 2]),
|
type: In([1, 2])
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (isEmpty(roleIds)) return permission;
|
if (isEmpty(roleIds)) return permission;
|
||||||
|
@ -237,9 +237,9 @@ export class MenuService {
|
||||||
return !!(await this.menuRepository.findOne({
|
return !!(await this.menuRepository.findOne({
|
||||||
where: {
|
where: {
|
||||||
roles: {
|
roles: {
|
||||||
id,
|
id
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { OnlineService } from './online.service';
|
||||||
|
|
||||||
export const permissions = definePermission('system:online', {
|
export const permissions = definePermission('system:online', {
|
||||||
LIST: 'list',
|
LIST: 'list',
|
||||||
KICK: 'kick',
|
KICK: 'kick'
|
||||||
} as const);
|
} as const);
|
||||||
|
|
||||||
@ApiTags('System - 在线用户模块')
|
@ApiTags('System - 在线用户模块')
|
||||||
|
|
|
@ -18,10 +18,10 @@ const providers = [OnlineService];
|
||||||
forwardRef(() => SocketModule),
|
forwardRef(() => SocketModule),
|
||||||
AuthModule,
|
AuthModule,
|
||||||
UserModule,
|
UserModule,
|
||||||
RoleModule,
|
RoleModule
|
||||||
],
|
],
|
||||||
controllers: [OnlineController],
|
controllers: [OnlineController],
|
||||||
providers,
|
providers,
|
||||||
exports: [...providers],
|
exports: [...providers]
|
||||||
})
|
})
|
||||||
export class OnlineModule {}
|
export class OnlineModule {}
|
||||||
|
|
|
@ -90,7 +90,7 @@ export class OnlineService {
|
||||||
time: e.created_at,
|
time: e.created_at,
|
||||||
os: `${u.os.name} ${u.os.version}`,
|
os: `${u.os.name} ${u.os.version}`,
|
||||||
browser: `${u.browser.name} ${u.browser.version}`,
|
browser: `${u.browser.name} ${u.browser.version}`,
|
||||||
disable: currentUid === e.id || e.id === rootUserId,
|
disable: currentUid === e.id || e.id === rootUserId
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ export const permissions = definePermission('system:param-config', {
|
||||||
CREATE: 'create',
|
CREATE: 'create',
|
||||||
READ: 'read',
|
READ: 'read',
|
||||||
UPDATE: 'update',
|
UPDATE: 'update',
|
||||||
DELETE: 'delete',
|
DELETE: 'delete'
|
||||||
} as const);
|
} as const);
|
||||||
|
|
||||||
@ApiTags('System - 参数配置模块')
|
@ApiTags('System - 参数配置模块')
|
||||||
|
|
|
@ -11,6 +11,6 @@ const services = [ParamConfigService];
|
||||||
imports: [TypeOrmModule.forFeature([ParamConfigEntity])],
|
imports: [TypeOrmModule.forFeature([ParamConfigEntity])],
|
||||||
controllers: [ParamConfigController],
|
controllers: [ParamConfigController],
|
||||||
providers: [...services],
|
providers: [...services],
|
||||||
exports: [TypeOrmModule, ...services],
|
exports: [TypeOrmModule, ...services]
|
||||||
})
|
})
|
||||||
export class ParamConfigModule {}
|
export class ParamConfigModule {}
|
||||||
|
|
|
@ -24,13 +24,13 @@ export class ParamConfigService {
|
||||||
async page({
|
async page({
|
||||||
page,
|
page,
|
||||||
pageSize,
|
pageSize,
|
||||||
name,
|
name
|
||||||
}: ParamConfigQueryDto): Promise<Pagination<ParamConfigEntity>> {
|
}: ParamConfigQueryDto): Promise<Pagination<ParamConfigEntity>> {
|
||||||
const queryBuilder = this.paramConfigRepository.createQueryBuilder('config');
|
const queryBuilder = this.paramConfigRepository.createQueryBuilder('config');
|
||||||
|
|
||||||
if (name) {
|
if (name) {
|
||||||
queryBuilder.where('config.name LIKE :name', {
|
queryBuilder.where('config.name LIKE :name', {
|
||||||
name: `%${name}%`,
|
name: `%${name}%`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ export class ParamConfigService {
|
||||||
async findValueByKey(key: string): Promise<string | null> {
|
async findValueByKey(key: string): Promise<string | null> {
|
||||||
const result = await this.paramConfigRepository.findOne({
|
const result = await this.paramConfigRepository.findOne({
|
||||||
where: { key },
|
where: { key },
|
||||||
select: ['value'],
|
select: ['value']
|
||||||
});
|
});
|
||||||
if (result) return result.value;
|
if (result) return result.value;
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {
|
||||||
Get,
|
Get,
|
||||||
Post,
|
Post,
|
||||||
Put,
|
Put,
|
||||||
Query,
|
Query
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ export const permissions = definePermission('system:role', {
|
||||||
CREATE: 'create',
|
CREATE: 'create',
|
||||||
READ: 'read',
|
READ: 'read',
|
||||||
UPDATE: 'update',
|
UPDATE: 'update',
|
||||||
DELETE: 'delete',
|
DELETE: 'delete'
|
||||||
} as const);
|
} as const);
|
||||||
|
|
||||||
@ApiTags('System - 角色模块')
|
@ApiTags('System - 角色模块')
|
||||||
|
|
|
@ -37,7 +37,7 @@ export class RoleEntity extends CommonEntity {
|
||||||
@JoinTable({
|
@JoinTable({
|
||||||
name: 'sys_role_menus',
|
name: 'sys_role_menus',
|
||||||
joinColumn: { name: 'role_id', referencedColumnName: 'id' },
|
joinColumn: { name: 'role_id', referencedColumnName: 'id' },
|
||||||
inverseJoinColumn: { name: 'menu_id', referencedColumnName: 'id' },
|
inverseJoinColumn: { name: 'menu_id', referencedColumnName: 'id' }
|
||||||
})
|
})
|
||||||
menus: Relation<MenuEntity[]>;
|
menus: Relation<MenuEntity[]>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,6 @@ const providers = [RoleService, SseService];
|
||||||
imports: [TypeOrmModule.forFeature([RoleEntity]), forwardRef(() => MenuModule)],
|
imports: [TypeOrmModule.forFeature([RoleEntity]), forwardRef(() => MenuModule)],
|
||||||
controllers: [RoleController],
|
controllers: [RoleController],
|
||||||
providers: [...providers],
|
providers: [...providers],
|
||||||
exports: [TypeOrmModule, ...providers],
|
exports: [TypeOrmModule, ...providers]
|
||||||
})
|
})
|
||||||
export class RoleModule {}
|
export class RoleModule {}
|
||||||
|
|
|
@ -32,17 +32,17 @@ export class RoleService {
|
||||||
pageSize,
|
pageSize,
|
||||||
name,
|
name,
|
||||||
value,
|
value,
|
||||||
status,
|
status
|
||||||
}: RoleQueryDto): Promise<Pagination<RoleEntity>> {
|
}: RoleQueryDto): Promise<Pagination<RoleEntity>> {
|
||||||
const queryBuilder = this.roleRepository.createQueryBuilder('role').where({
|
const queryBuilder = this.roleRepository.createQueryBuilder('role').where({
|
||||||
...(name ? { name: Like(`%${name}%`) } : null),
|
...(name ? { name: Like(`%${name}%`) } : null),
|
||||||
...(value ? { value: Like(`%${value}%`) } : null),
|
...(value ? { value: Like(`%${value}%`) } : null),
|
||||||
...(isNumber(status) ? { status } : null),
|
...(isNumber(status) ? { status } : null)
|
||||||
});
|
});
|
||||||
|
|
||||||
return paginate<RoleEntity>(queryBuilder, {
|
return paginate<RoleEntity>(queryBuilder, {
|
||||||
page,
|
page,
|
||||||
pageSize,
|
pageSize
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,13 +53,13 @@ export class RoleService {
|
||||||
const info = await this.roleRepository
|
const info = await this.roleRepository
|
||||||
.createQueryBuilder('role')
|
.createQueryBuilder('role')
|
||||||
.where({
|
.where({
|
||||||
id,
|
id
|
||||||
})
|
})
|
||||||
.getOne();
|
.getOne();
|
||||||
|
|
||||||
const menus = await this.menuRepository.find({
|
const menus = await this.menuRepository.find({
|
||||||
where: { roles: { id } },
|
where: { roles: { id } },
|
||||||
select: ['id'],
|
select: ['id']
|
||||||
});
|
});
|
||||||
|
|
||||||
return { ...info, menuIds: menus.map(m => m.id) };
|
return { ...info, menuIds: menus.map(m => m.id) };
|
||||||
|
@ -76,7 +76,7 @@ export class RoleService {
|
||||||
async create({ menuIds, ...data }: RoleDto): Promise<{ roleId: number }> {
|
async create({ menuIds, ...data }: RoleDto): Promise<{ roleId: number }> {
|
||||||
const role = await this.roleRepository.save({
|
const role = await this.roleRepository.save({
|
||||||
...data,
|
...data,
|
||||||
menus: menuIds ? await this.menuRepository.findBy({ id: In(menuIds) }) : [],
|
menus: menuIds ? await this.menuRepository.findBy({ id: In(menuIds) }) : []
|
||||||
});
|
});
|
||||||
|
|
||||||
return { roleId: role.id };
|
return { roleId: role.id };
|
||||||
|
@ -92,7 +92,7 @@ export class RoleService {
|
||||||
// using transaction
|
// using transaction
|
||||||
await this.entityManager.transaction(async manager => {
|
await this.entityManager.transaction(async manager => {
|
||||||
const menus = await this.menuRepository.find({
|
const menus = await this.menuRepository.find({
|
||||||
where: { id: In(menuIds) },
|
where: { id: In(menuIds) }
|
||||||
});
|
});
|
||||||
|
|
||||||
const role = await this.roleRepository.findOne({ where: { id } });
|
const role = await this.roleRepository.findOne({ where: { id } });
|
||||||
|
@ -108,8 +108,8 @@ export class RoleService {
|
||||||
async getRoleIdsByUser(id: number): Promise<number[]> {
|
async getRoleIdsByUser(id: number): Promise<number[]> {
|
||||||
const roles = await this.roleRepository.find({
|
const roles = await this.roleRepository.find({
|
||||||
where: {
|
where: {
|
||||||
users: { id },
|
users: { id }
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!isEmpty(roles)) return roles.map(r => r.id);
|
if (!isEmpty(roles)) return roles.map(r => r.id);
|
||||||
|
@ -120,7 +120,7 @@ export class RoleService {
|
||||||
async getRoleValues(ids: number[]): Promise<string[]> {
|
async getRoleValues(ids: number[]): Promise<string[]> {
|
||||||
return (
|
return (
|
||||||
await this.roleRepository.findBy({
|
await this.roleRepository.findBy({
|
||||||
id: In(ids),
|
id: In(ids)
|
||||||
})
|
})
|
||||||
).map(r => r.value);
|
).map(r => r.value);
|
||||||
}
|
}
|
||||||
|
@ -128,8 +128,8 @@ export class RoleService {
|
||||||
async isAdminRoleByUser(uid: number): Promise<boolean> {
|
async isAdminRoleByUser(uid: number): Promise<boolean> {
|
||||||
const roles = await this.roleRepository.find({
|
const roles = await this.roleRepository.find({
|
||||||
where: {
|
where: {
|
||||||
users: { id: uid },
|
users: { id: uid }
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!isEmpty(roles)) {
|
if (!isEmpty(roles)) {
|
||||||
|
@ -149,9 +149,9 @@ export class RoleService {
|
||||||
return this.roleRepository.exist({
|
return this.roleRepository.exist({
|
||||||
where: {
|
where: {
|
||||||
users: {
|
users: {
|
||||||
roles: { id },
|
roles: { id }
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,6 @@ const providers = [ServeService];
|
||||||
imports: [forwardRef(() => SystemModule)],
|
imports: [forwardRef(() => SystemModule)],
|
||||||
controllers: [ServeController],
|
controllers: [ServeController],
|
||||||
providers: [...providers],
|
providers: [...providers],
|
||||||
exports: [...providers],
|
exports: [...providers]
|
||||||
})
|
})
|
||||||
export class ServeModule {}
|
export class ServeModule {}
|
||||||
|
|
|
@ -15,7 +15,7 @@ export class ServeService {
|
||||||
si.osInfo(),
|
si.osInfo(),
|
||||||
si.cpu(),
|
si.cpu(),
|
||||||
si.currentLoad(),
|
si.currentLoad(),
|
||||||
si.mem(),
|
si.mem()
|
||||||
])
|
])
|
||||||
).map((p: any) => p.value);
|
).map((p: any) => p.value);
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ export class ServeService {
|
||||||
npmVersion: versions.npm,
|
npmVersion: versions.npm,
|
||||||
nodeVersion: versions.node,
|
nodeVersion: versions.node,
|
||||||
os: osinfo.platform,
|
os: osinfo.platform,
|
||||||
arch: osinfo.arch,
|
arch: osinfo.arch
|
||||||
},
|
},
|
||||||
cpu: {
|
cpu: {
|
||||||
manufacturer: cpuinfo.manufacturer,
|
manufacturer: cpuinfo.manufacturer,
|
||||||
|
@ -49,15 +49,15 @@ export class ServeService {
|
||||||
coresLoad: currentLoadinfo.cpus.map(e => {
|
coresLoad: currentLoadinfo.cpus.map(e => {
|
||||||
return {
|
return {
|
||||||
rawLoad: e.rawLoad,
|
rawLoad: e.rawLoad,
|
||||||
rawLoadIdle: e.rawLoadIdle,
|
rawLoadIdle: e.rawLoadIdle
|
||||||
};
|
};
|
||||||
}),
|
})
|
||||||
},
|
},
|
||||||
disk: diskinfo,
|
disk: diskinfo,
|
||||||
memory: {
|
memory: {
|
||||||
total: meminfo.total,
|
total: meminfo.total,
|
||||||
available: meminfo.available,
|
available: meminfo.available
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ const modules = [
|
||||||
LogModule,
|
LogModule,
|
||||||
TaskModule,
|
TaskModule,
|
||||||
OnlineModule,
|
OnlineModule,
|
||||||
ServeModule,
|
ServeModule
|
||||||
];
|
];
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
|
@ -36,10 +36,10 @@ const modules = [
|
||||||
{
|
{
|
||||||
path: 'system',
|
path: 'system',
|
||||||
module: SystemModule,
|
module: SystemModule,
|
||||||
children: [...modules],
|
children: [...modules]
|
||||||
},
|
}
|
||||||
]),
|
])
|
||||||
],
|
],
|
||||||
exports: [...modules],
|
exports: [...modules]
|
||||||
})
|
})
|
||||||
export class SystemModule {}
|
export class SystemModule {}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
export enum TaskStatus {
|
export enum TaskStatus {
|
||||||
Disabled = 0,
|
Disabled = 0,
|
||||||
Activited = 1,
|
Activited = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum TaskType {
|
export enum TaskType {
|
||||||
Cron = 0,
|
Cron = 0,
|
||||||
Interval = 1,
|
Interval = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SYS_TASK_QUEUE_NAME = 'system:sys-task';
|
export const SYS_TASK_QUEUE_NAME = 'system:sys-task';
|
||||||
|
|
|
@ -20,7 +20,7 @@ export const permissions = definePermission('system:task', {
|
||||||
|
|
||||||
ONCE: 'once',
|
ONCE: 'once',
|
||||||
START: 'start',
|
START: 'start',
|
||||||
STOP: 'stop',
|
STOP: 'stop'
|
||||||
} as const);
|
} as const);
|
||||||
|
|
||||||
@ApiTags('System - 任务调度模块')
|
@ApiTags('System - 任务调度模块')
|
||||||
|
|
|
@ -13,7 +13,7 @@ import {
|
||||||
ValidateIf,
|
ValidateIf,
|
||||||
ValidationArguments,
|
ValidationArguments,
|
||||||
ValidatorConstraint,
|
ValidatorConstraint,
|
||||||
ValidatorConstraintInterface,
|
ValidatorConstraintInterface
|
||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
import * as parser from 'cron-parser';
|
import * as parser from 'cron-parser';
|
||||||
import { isEmpty } from 'lodash';
|
import { isEmpty } from 'lodash';
|
||||||
|
@ -70,7 +70,7 @@ export class TaskDto {
|
||||||
endTime: string;
|
endTime: string;
|
||||||
|
|
||||||
@ApiPropertyOptional({
|
@ApiPropertyOptional({
|
||||||
description: '限制执行次数,负数则无限制',
|
description: '限制执行次数,负数则无限制'
|
||||||
})
|
})
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsInt()
|
@IsInt()
|
||||||
|
|
|
@ -24,14 +24,14 @@ const providers = [TaskService, TaskConsumer];
|
||||||
name: SYS_TASK_QUEUE_NAME,
|
name: SYS_TASK_QUEUE_NAME,
|
||||||
useFactory: (configService: ConfigService<ConfigKeyPaths>) => ({
|
useFactory: (configService: ConfigService<ConfigKeyPaths>) => ({
|
||||||
redis: configService.get<IRedisConfig>('redis'),
|
redis: configService.get<IRedisConfig>('redis'),
|
||||||
prefix: SYS_TASK_QUEUE_PREFIX,
|
prefix: SYS_TASK_QUEUE_PREFIX
|
||||||
}),
|
}),
|
||||||
inject: [ConfigService],
|
inject: [ConfigService]
|
||||||
}),
|
}),
|
||||||
LogModule,
|
LogModule
|
||||||
],
|
],
|
||||||
controllers: [TaskController],
|
controllers: [TaskController],
|
||||||
providers: [...providers],
|
providers: [...providers],
|
||||||
exports: [TypeOrmModule, ...providers],
|
exports: [TypeOrmModule, ...providers]
|
||||||
})
|
})
|
||||||
export class TaskModule {}
|
export class TaskModule {}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {
|
||||||
Injectable,
|
Injectable,
|
||||||
Logger,
|
Logger,
|
||||||
NotFoundException,
|
NotFoundException,
|
||||||
OnModuleInit,
|
OnModuleInit
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { ModuleRef, Reflector } from '@nestjs/core';
|
import { ModuleRef, Reflector } from '@nestjs/core';
|
||||||
import { UnknownElementException } from '@nestjs/core/errors/exceptions/unknown-element.exception';
|
import { UnknownElementException } from '@nestjs/core/errors/exceptions/unknown-element.exception';
|
||||||
|
@ -69,7 +69,7 @@ export class TaskService implements OnModuleInit {
|
||||||
'failed',
|
'failed',
|
||||||
'paused',
|
'paused',
|
||||||
'waiting',
|
'waiting',
|
||||||
'completed',
|
'completed'
|
||||||
]);
|
]);
|
||||||
jobs.forEach(j => {
|
jobs.forEach(j => {
|
||||||
j.remove();
|
j.remove();
|
||||||
|
@ -90,7 +90,7 @@ export class TaskService implements OnModuleInit {
|
||||||
name,
|
name,
|
||||||
service,
|
service,
|
||||||
type,
|
type,
|
||||||
status,
|
status
|
||||||
}: TaskQueryDto): Promise<Pagination<TaskEntity>> {
|
}: TaskQueryDto): Promise<Pagination<TaskEntity>> {
|
||||||
const queryBuilder = this.taskRepository
|
const queryBuilder = this.taskRepository
|
||||||
.createQueryBuilder('task')
|
.createQueryBuilder('task')
|
||||||
|
@ -98,7 +98,7 @@ export class TaskService implements OnModuleInit {
|
||||||
...(name ? { name: Like(`%${name}%`) } : null),
|
...(name ? { name: Like(`%${name}%`) } : null),
|
||||||
...(service ? { service: Like(`%${service}%`) } : null),
|
...(service ? { service: Like(`%${service}%`) } : null),
|
||||||
...(type ? { type } : null),
|
...(type ? { type } : null),
|
||||||
...(isNumber(status) ? { status } : null),
|
...(isNumber(status) ? { status } : null)
|
||||||
})
|
})
|
||||||
.orderBy('task.id', 'ASC');
|
.orderBy('task.id', 'ASC');
|
||||||
|
|
||||||
|
@ -166,12 +166,12 @@ export class TaskService implements OnModuleInit {
|
||||||
if (task.type === 1) {
|
if (task.type === 1) {
|
||||||
// 间隔 Repeat every millis (cron setting cannot be used together with this setting.)
|
// 间隔 Repeat every millis (cron setting cannot be used together with this setting.)
|
||||||
repeat = {
|
repeat = {
|
||||||
every: task.every,
|
every: task.every
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
// cron
|
// cron
|
||||||
repeat = {
|
repeat = {
|
||||||
cron: task.cron,
|
cron: task.cron
|
||||||
};
|
};
|
||||||
// Start date when the repeat job should start repeating (only with cron).
|
// Start date when the repeat job should start repeating (only with cron).
|
||||||
if (task.startTime) repeat.startDate = task.startTime;
|
if (task.startTime) repeat.startDate = task.startTime;
|
||||||
|
@ -187,13 +187,13 @@ export class TaskService implements OnModuleInit {
|
||||||
if (job && job.opts) {
|
if (job && job.opts) {
|
||||||
await this.taskRepository.update(task.id, {
|
await this.taskRepository.update(task.id, {
|
||||||
jobOpts: JSON.stringify(job.opts.repeat),
|
jobOpts: JSON.stringify(job.opts.repeat),
|
||||||
status: 1,
|
status: 1
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// update status to 0,标识暂停任务,因为启动失败
|
// update status to 0,标识暂停任务,因为启动失败
|
||||||
await job?.remove();
|
await job?.remove();
|
||||||
await this.taskRepository.update(task.id, {
|
await this.taskRepository.update(task.id, {
|
||||||
status: TaskStatus.Disabled,
|
status: TaskStatus.Disabled
|
||||||
});
|
});
|
||||||
throw new BadRequestException('Task Start failed');
|
throw new BadRequestException('Task Start failed');
|
||||||
}
|
}
|
||||||
|
@ -208,7 +208,7 @@ export class TaskService implements OnModuleInit {
|
||||||
const exist = await this.existJob(task.id.toString());
|
const exist = await this.existJob(task.id.toString());
|
||||||
if (!exist) {
|
if (!exist) {
|
||||||
await this.taskRepository.update(task.id, {
|
await this.taskRepository.update(task.id, {
|
||||||
status: TaskStatus.Disabled,
|
status: TaskStatus.Disabled
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -218,7 +218,7 @@ export class TaskService implements OnModuleInit {
|
||||||
'failed',
|
'failed',
|
||||||
'paused',
|
'paused',
|
||||||
'waiting',
|
'waiting',
|
||||||
'completed',
|
'completed'
|
||||||
]);
|
]);
|
||||||
jobs
|
jobs
|
||||||
.filter(j => j.data.id === task.id)
|
.filter(j => j.data.id === task.id)
|
||||||
|
@ -301,7 +301,7 @@ export class TaskService implements OnModuleInit {
|
||||||
if (!methodName) throw new BadRequestException('serviceName define BadRequestException');
|
if (!methodName) throw new BadRequestException('serviceName define BadRequestException');
|
||||||
|
|
||||||
const service = await this.moduleRef.get(serviceName, {
|
const service = await this.moduleRef.get(serviceName, {
|
||||||
strict: false,
|
strict: false
|
||||||
});
|
});
|
||||||
|
|
||||||
// 安全注解检查
|
// 安全注解检查
|
||||||
|
|
|
@ -21,7 +21,7 @@ function createAliasProviders(): ExistingProvider[] {
|
||||||
for (const p of providers) {
|
for (const p of providers) {
|
||||||
aliasProviders.push({
|
aliasProviders.push({
|
||||||
provide: p.name,
|
provide: p.name,
|
||||||
useExisting: p,
|
useExisting: p
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return aliasProviders;
|
return aliasProviders;
|
||||||
|
@ -40,7 +40,7 @@ export class TasksModule {
|
||||||
module: TasksModule,
|
module: TasksModule,
|
||||||
imports: [SystemModule, LogModule],
|
imports: [SystemModule, LogModule],
|
||||||
providers: [...providers, ...aliasProviders],
|
providers: [...providers, ...aliasProviders],
|
||||||
exports: aliasProviders,
|
exports: aliasProviders
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ export const permissions = definePermission('todo', {
|
||||||
CREATE: 'create',
|
CREATE: 'create',
|
||||||
READ: 'read',
|
READ: 'read',
|
||||||
UPDATE: 'update',
|
UPDATE: 'update',
|
||||||
DELETE: 'delete',
|
DELETE: 'delete'
|
||||||
} as const);
|
} as const);
|
||||||
|
|
||||||
@ApiTags('Business - Todo模块')
|
@ApiTags('Business - Todo模块')
|
||||||
|
|
|
@ -11,6 +11,6 @@ const services = [TodoService];
|
||||||
imports: [TypeOrmModule.forFeature([TodoEntity])],
|
imports: [TypeOrmModule.forFeature([TodoEntity])],
|
||||||
controllers: [TodoController],
|
controllers: [TodoController],
|
||||||
providers: [...services],
|
providers: [...services],
|
||||||
exports: [TypeOrmModule, ...services],
|
exports: [TypeOrmModule, ...services]
|
||||||
})
|
})
|
||||||
export class TodoModule {}
|
export class TodoModule {}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue