Merge branch 'refs/heads/v2-dev' into v2-dev-buy

# Conflicts:
#	docs/.vitepress/config.ts
#	packages/ui/certd-client/src/views/certd/pipeline/sub-domain/index.vue
This commit is contained in:
xiaojunnuo
2025-09-22 22:29:59 +08:00
175 changed files with 4551 additions and 684 deletions
@@ -1,8 +1,9 @@
import { Rule, RuleType } from '@midwayjs/validate';
import { ALL, Body, Controller, Get, Inject, Post, Provide, Query } from '@midwayjs/core';
import { BaseController, Constants } from '@certd/lib-server';
import { CodeService } from '../../modules/basic/service/code-service.js';
import { EmailService } from '../../modules/basic/service/email-service.js';
import { Rule, RuleType } from "@midwayjs/validate";
import { ALL, Body, Controller, Inject, Post, Provide, Query } from "@midwayjs/core";
import { BaseController, Constants, SysSettingsService } from "@certd/lib-server";
import { CodeService } from "../../modules/basic/service/code-service.js";
import { EmailService } from "../../modules/basic/service/email-service.js";
import { CaptchaService } from "../../modules/basic/service/captcha-service.js";
export class SmsCodeReq {
@Rule(RuleType.string().required())
@@ -11,11 +12,8 @@ export class SmsCodeReq {
@Rule(RuleType.string().required())
mobile: string;
@Rule(RuleType.string().required().max(10))
randomStr: string;
@Rule(RuleType.string().required().max(4))
imgCode: string;
@Rule(RuleType.required())
captcha: any;
@Rule(RuleType.string())
verificationType: string;
@@ -25,11 +23,8 @@ export class EmailCodeReq {
@Rule(RuleType.string().required())
email: string;
@Rule(RuleType.string().required().max(10))
randomStr: string;
@Rule(RuleType.string().required().max(4))
imgCode: string;
@Rule(RuleType.required())
captcha: any;
@Rule(RuleType.string())
verificationType: string;
@@ -48,6 +43,17 @@ export class BasicController extends BaseController {
@Inject()
emailService: EmailService;
@Inject()
sysSettingsService: SysSettingsService;
@Inject()
captchaService: CaptchaService;
@Post('/captcha/get', { summary: Constants.per.guest })
async getCaptcha(@Query("captchaAddonId") captchaAddonId:number) {
const form = await this.captchaService.getCaptcha(captchaAddonId)
return this.ok(form);
}
@Post('/sendSmsCode', { summary: Constants.per.guest })
public async sendSmsCode(
@@ -64,8 +70,8 @@ export class BasicController extends BaseController {
// opts.verificationCodeLength = 6; //部分厂商这里会设置参数长度这里就不改了
}
await this.codeService.checkCaptcha(body.randomStr, body.imgCode);
await this.codeService.sendSmsCode(body.phoneCode, body.mobile, body.randomStr, opts);
await this.codeService.checkCaptcha(body.captcha);
await this.codeService.sendSmsCode(body.phoneCode, body.mobile, opts);
return this.ok(null);
}
@@ -88,16 +94,10 @@ export class BasicController extends BaseController {
opts.verificationCodeLength = 6;
}
await this.codeService.checkCaptcha(body.randomStr, body.imgCode);
await this.codeService.sendEmailCode(body.email, body.randomStr, opts);
await this.codeService.checkCaptcha(body.captcha);
await this.codeService.sendEmailCode(body.email, opts);
// 设置缓存内容
return this.ok(null);
}
@Get('/captcha', { summary: Constants.per.guest })
public async getCaptcha(@Query('randomStr') randomStr: any) {
const captcha = await this.codeService.generateCaptcha(randomStr);
this.ctx.res.setHeader('Content-Type', 'image/svg+xml');
return captcha.data;
}
}
@@ -23,7 +23,7 @@ const unhiddenHtml = `
@Provide()
@Controller('/api/unhidden')
export class HnhiddenController {
export class UnhiddenController {
@Inject()
ctx: IMidwayKoaContext;
@Inject()
@@ -0,0 +1,83 @@
import { ALL, Body, Controller, Inject, Post, Provide, Query } from "@midwayjs/core";
import { AddonRequestHandleReq, AddonService, Constants } from "@certd/lib-server";
import { AddonController } from "../../user/addon/addon-controller.js";
@Provide()
@Controller('/api/sys/addon')
export class SysAddonController extends AddonController {
@Inject()
service2: AddonService;
getService(): AddonService {
return this.service2;
}
getUserId() {
// checkComm();
return 0;
}
@Post('/page', { summary: 'sys:settings:view' })
async page(@Body(ALL) body: any) {
return await super.page(body);
}
@Post('/list', { summary: 'sys:settings:view' })
async list(@Body(ALL) body: any) {
return await super.list(body);
}
@Post('/add', { summary: 'sys:settings:edit' })
async add(@Body(ALL) bean: any) {
return await super.add(bean);
}
@Post('/update', { summary: 'sys:settings:edit' })
async update(@Body(ALL) bean: any) {
return await super.update(bean);
}
@Post('/info', { summary: 'sys:settings:view' })
async info(@Query('id') id: number) {
return await super.info(id);
}
@Post('/delete', { summary: 'sys:settings:edit' })
async delete(@Query('id') id: number) {
return await super.delete(id);
}
@Post('/define', { summary: Constants.per.authOnly })
async define(@Query('type') type: string,@Query('addonType') addonType: string) {
return await super.define(type,addonType);
}
@Post('/getTypeDict', { summary: Constants.per.authOnly })
async getTypeDict(@Query('addonType') addonType: string) {
return await super.getTypeDict(addonType);
}
@Post('/simpleInfo', { summary: Constants.per.authOnly })
async simpleInfo(@Query('addonType') addonType: string,@Query('id') id: number) {
return await super.simpleInfo(addonType,id);
}
@Post('/getDefaultId', { summary: Constants.per.authOnly })
async getDefaultId(@Query('addonType') addonType: string) {
return await super.getDefaultId(addonType);
}
@Post('/setDefault', { summary: Constants.per.authOnly })
async setDefault(@Query('addonType') addonType: string,@Query('id') id: number) {
return await super.setDefault(addonType,id);
}
@Post('/options', { summary: Constants.per.authOnly })
async options(@Query('addonType') addonType: string) {
return await super.options(addonType);
}
@Post('/handle', { summary: Constants.per.authOnly })
async handle(@Body(ALL) body: AddonRequestHandleReq) {
return await super.handle(body);
}
}
@@ -1,4 +1,4 @@
import {ALL, Body, Controller, Inject, Post, Provide, Query} from '@midwayjs/core';
import { ALL, Body, Controller, Inject, Post, Provide, Query } from "@midwayjs/core";
import {
CrudController,
SysPrivateSettings,
@@ -6,14 +6,14 @@ import {
SysSafeSetting,
SysSettingsEntity,
SysSettingsService
} from '@certd/lib-server';
import {cloneDeep, merge} from 'lodash-es';
import {PipelineService} from '../../../modules/pipeline/service/pipeline-service.js';
import {UserSettingsService} from '../../../modules/mine/service/user-settings-service.js';
import {getEmailSettings} from '../../../modules/sys/settings/fix.js';
import {http, logger, simpleNanoId, utils} from '@certd/basic';
import {CodeService} from '../../../modules/basic/service/code-service.js';
import {SmsServiceFactory} from '../../../modules/basic/sms/factory.js';
} from "@certd/lib-server";
import { cloneDeep, merge } from "lodash-es";
import { PipelineService } from "../../../modules/pipeline/service/pipeline-service.js";
import { UserSettingsService } from "../../../modules/mine/service/user-settings-service.js";
import { getEmailSettings } from "../../../modules/sys/settings/fix.js";
import { http, logger, utils } from "@certd/basic";
import { CodeService } from "../../../modules/basic/service/code-service.js";
import { SmsServiceFactory } from "../../../modules/basic/sms/factory.js";
/**
@@ -158,7 +158,7 @@ export class SysSettingsController extends CrudController<SysSettingsService> {
@Post('/testSms', { summary: 'sys:settings:edit' })
async testSms(@Body(ALL) body) {
await this.codeService.sendSmsCode(body.phoneCode, body.mobile, simpleNanoId());
await this.codeService.sendSmsCode(body.phoneCode, body.mobile );
return this.ok({});
}
@@ -0,0 +1,199 @@
import { ALL, Body, Controller, Inject, Post, Provide, Query } from "@midwayjs/core";
import {
AddonDefine,
AddonRequestHandleReq,
AddonService,
Constants,
CrudController,
newAddon,
ValidateException
} from "@certd/lib-server";
import { AuthService } from "../../../modules/sys/authority/service/auth-service.js";
import { checkPlus } from "@certd/plus-core";
import { http, logger, utils } from "@certd/basic";
/**
* Addon
*/
@Provide()
@Controller('/api/addon')
export class AddonController extends CrudController<AddonService> {
@Inject()
service: AddonService;
@Inject()
authService: AuthService;
getService(): AddonService {
return this.service;
}
@Post('/page', { summary: Constants.per.authOnly })
async page(@Body(ALL) body) {
body.query = body.query ?? {};
delete body.query.userId;
const buildQuery = qb => {
qb.andWhere('user_id = :userId', { userId: this.getUserId() });
};
const res = await this.service.page({
query: body.query,
page: body.page,
sort: body.sort,
buildQuery,
});
return this.ok(res);
}
@Post('/list', { summary: Constants.per.authOnly })
async list(@Body(ALL) body) {
body.query = body.query ?? {};
body.query.userId = this.getUserId();
return super.list(body);
}
@Post('/add', { summary: Constants.per.authOnly })
async add(@Body(ALL) bean) {
bean.userId = this.getUserId();
const type = bean.type;
const addonType = bean.addonType;
if (! type || !addonType){
throw new ValidateException('请选择Addon类型');
}
const define: AddonDefine = this.service.getDefineByType(type,addonType);
if (!define) {
throw new ValidateException('Addon类型不存在');
}
if (define.needPlus) {
checkPlus();
}
return super.add(bean);
}
@Post('/update', { summary: Constants.per.authOnly })
async update(@Body(ALL) bean) {
await this.service.checkUserId(bean.id, this.getUserId());
const old = await this.service.info(bean.id);
if (!old) {
throw new ValidateException('Addon配置不存在');
}
if (old.type !== bean.type ) {
const addonType = old.type;
const type = bean.type;
const define: AddonDefine = this.service.getDefineByType(type,addonType);
if (!define) {
throw new ValidateException('Addon类型不存在');
}
if (define.needPlus) {
checkPlus();
}
}
delete bean.userId;
return super.update(bean);
}
@Post('/info', { summary: Constants.per.authOnly })
async info(@Query('id') id: number) {
await this.service.checkUserId(id, this.getUserId());
return super.info(id);
}
@Post('/delete', { summary: Constants.per.authOnly })
async delete(@Query('id') id: number) {
await this.service.checkUserId(id, this.getUserId());
return super.delete(id);
}
@Post('/define', { summary: Constants.per.authOnly })
async define(@Query('type') type: string,@Query('addonType') addonType: string) {
const notification = this.service.getDefineByType(type,addonType);
return this.ok(notification);
}
@Post('/getTypeDict', { summary: Constants.per.authOnly })
async getTypeDict(@Query('addonType') addonType: string) {
const list: any = this.service.getDefineList(addonType);
let dict = [];
for (const item of list) {
dict.push({
value: item.name,
label: item.title,
needPlus: item.needPlus ?? false,
icon: item.icon,
});
}
dict = dict.sort(a => {
return a.needPlus ? 0 : -1;
});
return this.ok(dict);
}
@Post('/simpleInfo', { summary: Constants.per.authOnly })
async simpleInfo(@Query('addonType') addonType: string,@Query('id') id: number) {
if (id === 0) {
//获取默认
const res = await this.service.getDefault(this.getUserId(),addonType);
if (!res) {
throw new ValidateException('默认Addon配置不存在');
}
const simple = await this.service.getSimpleInfo(res.id);
return this.ok(simple);
}
await this.authService.checkEntityUserId(this.ctx, this.service, id);
const res = await this.service.getSimpleInfo(id);
return this.ok(res);
}
@Post('/getDefaultId', { summary: Constants.per.authOnly })
async getDefaultId(@Query('addonType') addonType: string) {
const res = await this.service.getDefault(this.getUserId(),addonType);
return this.ok(res?.id);
}
@Post('/setDefault', { summary: Constants.per.authOnly })
async setDefault(@Query('addonType') addonType: string,@Query('id') id: number) {
await this.service.checkUserId(id, this.getUserId());
const res = await this.service.setDefault(id, this.getUserId(),addonType);
return this.ok(res);
}
@Post('/options', { summary: Constants.per.authOnly })
async options(@Query('addonType') addonType: string) {
const res = await this.service.list({
query: {
userId: this.getUserId(),
addonType
},
});
for (const item of res) {
delete item.setting;
}
return this.ok(res);
}
@Post('/handle', { summary: Constants.per.authOnly })
async handle(@Body(ALL) body: AddonRequestHandleReq) {
const userId = this.getUserId();
let inputAddon = body.input.addon;
if (body.input.id > 0) {
const oldEntity = await this.service.info(body.input.id);
if (oldEntity) {
if (oldEntity.userId !== userId) {
throw new Error('addon not found');
}
// const param: any = {
// type: body.typeName,
// setting: JSON.stringify(body.input.access),
// };
inputAddon = JSON.parse( oldEntity.setting)
}
}
const ctx = {
http: http,
logger:logger,
utils:utils,
}
const addon = await newAddon(body.addonType,body.typeName, inputAddon,ctx);
const res = await addon.onRequest(body);
return this.ok(res);
}
}
@@ -29,25 +29,23 @@ export class LoginController extends BaseController {
throw new CommonException('暂未开启自助找回');
}
// 找回密码的验证码允许错误次数
const errorNum = 5;
const maxErrorCount = 5;
if(body.type === 'email') {
this.codeService.checkEmailCode({
verificationType: 'forgotPassword',
email: body.input,
randomStr: body.randomStr,
validateCode: body.validateCode,
errorNum,
maxErrorCount: maxErrorCount,
throwError: true,
});
} else if(body.type === 'mobile') {
await this.codeService.checkSmsCode({
verificationType: 'forgotPassword',
mobile: body.input,
randomStr: body.randomStr,
phoneCode: body.phoneCode,
smsCode: body.validateCode,
errorNum,
maxErrorCount: maxErrorCount,
throwError: true,
});
} else {
@@ -1,8 +1,9 @@
import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core';
import { LoginService } from '../../../modules/login/service/login-service.js';
import { BaseController, Constants, SysPublicSettings, SysSettingsService } from '@certd/lib-server';
import { CodeService } from '../../../modules/basic/service/code-service.js';
import { checkComm } from '@certd/plus-core';
import { ALL, Body, Controller, Inject, Post, Provide } from "@midwayjs/core";
import { LoginService } from "../../../modules/login/service/login-service.js";
import { AddonService, BaseController, Constants, SysPublicSettings, SysSettingsService } from "@certd/lib-server";
import { CodeService } from "../../../modules/basic/service/code-service.js";
import { checkComm } from "@certd/plus-core";
import { CaptchaService } from "../../../modules/basic/service/captcha-service.js";
/**
*/
@@ -16,13 +17,22 @@ export class LoginController extends BaseController {
@Inject()
sysSettingsService: SysSettingsService;
@Inject()
addonService: AddonService;
@Inject()
captchaService: CaptchaService;
@Post('/login', { summary: Constants.per.guest })
public async login(
@Body(ALL)
user: any
body: any
) {
const token = await this.loginService.loginByPassword(user);
const settings = await this.sysSettingsService.getPublicSettings()
if (settings.captchaEnabled === true) {
await this.captchaService.doValidate({form:body.captcha,must:false,captchaAddonId:settings.captchaAddonId})
}
const token = await this.loginService.loginByPassword(body);
this.writeTokenCookie(token);
return this.ok(token);
}
@@ -13,8 +13,7 @@ export type RegisterReq = {
phoneCode?: string;
validateCode: string;
imgCode: string;
randomStr: string;
captcha:any;
};
/**
@@ -52,7 +51,7 @@ export class RegisterController extends BaseController {
throw new Error('用户名不能为空');
}
await this.codeService.checkCaptcha(body.randomStr, body.imgCode);
await this.codeService.checkCaptcha(body.captcha);
const newUser = await this.userService.register(body.type, {
username: body.username,
password: body.password,
@@ -68,7 +67,6 @@ export class RegisterController extends BaseController {
mobile: body.mobile,
phoneCode: body.phoneCode,
smsCode: body.validateCode,
randomStr: body.randomStr,
throwError: true,
});
const newUser = await this.userService.register(body.type, {
@@ -85,7 +83,6 @@ export class RegisterController extends BaseController {
checkPlus();
this.codeService.checkEmailCode({
email: body.email,
randomStr: body.randomStr,
validateCode: body.validateCode,
throwError: true,
});