mirror of
https://github.com/certd/certd.git
synced 2026-05-17 22:07:34 +08:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 25e361b9f9 | |||
| b88ee33ae4 | |||
| 684964da4f | |||
| 8a3841f638 | |||
| f642e42eea | |||
| bbef854c02 | |||
| e50611666e | |||
| eae4f721e8 | |||
| 12fed34e10 | |||
| 56350b54ee | |||
| 10b7644bb7 | |||
| d79db3bd3f | |||
| 1588461633 | |||
| dd999b60a4 | |||
| 3abee72fee | |||
| b5577b1d37 | |||
| e15ffb5820 | |||
| 4d9a5ed4a1 | |||
| b2bc1debe0 | |||
| 2c399a078e | |||
| 8c519f13da |
@@ -3,6 +3,17 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.39.1](https://github.com/certd/certd/compare/v1.39.0...v1.39.1) (2026-03-09)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复企业管理模式下,切换用户登录后,丢失项目列表的bug ([d23c8b4](https://github.com/certd/certd/commit/d23c8b4a2a5f5ab17822c6ee1d4108ac7280b9d1))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 支持迁移个人数据到企业项目中 ([c6ca832](https://github.com/certd/certd/commit/c6ca83273779ed84de1b23b5e477063af043d015))
|
||||
* install tip ([853fdc7](https://github.com/certd/certd/commit/853fdc70a263b62d75c9ff3970607e6bf1c1593b))
|
||||
|
||||
# [1.39.0](https://github.com/certd/certd/compare/v1.38.12...v1.39.0) (2026-03-07)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
"docs:preview": "vitepress preview docs",
|
||||
"pub": "echo 1",
|
||||
"dev": "pnpm run -r --parallel compile ",
|
||||
"pub_all":"pnpm run -r --parallel pub ",
|
||||
"release": "time /t >trigger/release.trigger && git add trigger/release.trigger && git commit -m \"build: release\" && git push",
|
||||
"publish_to_atomgit": "node --experimental-json-modules ./scripts/publish-atomgit.js",
|
||||
"publish_to_gitee": "node --experimental-json-modules ./scripts/publish-gitee.js",
|
||||
|
||||
@@ -70,5 +70,5 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/publishlab/node-acme-client/issues"
|
||||
},
|
||||
"gitHead": "3bb29abe32c311e1cf840f97d485d1147411992a"
|
||||
"gitHead": "590ff67fcb40ff8ba0f7b2a9592b51d9fb54a2ef"
|
||||
}
|
||||
|
||||
@@ -47,5 +47,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "3bb29abe32c311e1cf840f97d485d1147411992a"
|
||||
"gitHead": "590ff67fcb40ff8ba0f7b2a9592b51d9fb54a2ef"
|
||||
}
|
||||
|
||||
@@ -45,5 +45,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "3bb29abe32c311e1cf840f97d485d1147411992a"
|
||||
"gitHead": "590ff67fcb40ff8ba0f7b2a9592b51d9fb54a2ef"
|
||||
}
|
||||
|
||||
@@ -24,5 +24,5 @@
|
||||
"prettier": "^2.8.8",
|
||||
"tslib": "^2.8.1"
|
||||
},
|
||||
"gitHead": "3bb29abe32c311e1cf840f97d485d1147411992a"
|
||||
"gitHead": "590ff67fcb40ff8ba0f7b2a9592b51d9fb54a2ef"
|
||||
}
|
||||
|
||||
@@ -31,5 +31,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "3bb29abe32c311e1cf840f97d485d1147411992a"
|
||||
"gitHead": "590ff67fcb40ff8ba0f7b2a9592b51d9fb54a2ef"
|
||||
}
|
||||
|
||||
@@ -56,5 +56,5 @@
|
||||
"fetch"
|
||||
]
|
||||
},
|
||||
"gitHead": "3bb29abe32c311e1cf840f97d485d1147411992a"
|
||||
"gitHead": "590ff67fcb40ff8ba0f7b2a9592b51d9fb54a2ef"
|
||||
}
|
||||
|
||||
@@ -32,5 +32,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "3bb29abe32c311e1cf840f97d485d1147411992a"
|
||||
"gitHead": "590ff67fcb40ff8ba0f7b2a9592b51d9fb54a2ef"
|
||||
}
|
||||
|
||||
@@ -64,5 +64,5 @@
|
||||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "3bb29abe32c311e1cf840f97d485d1147411992a"
|
||||
"gitHead": "590ff67fcb40ff8ba0f7b2a9592b51d9fb54a2ef"
|
||||
}
|
||||
|
||||
@@ -115,11 +115,17 @@ export abstract class BaseController {
|
||||
if (projectId) {
|
||||
await authService.checkProjectId(service, id, projectId);
|
||||
}else{
|
||||
if(allowAdmin){
|
||||
await authService.checkUserIdButAllowAdmin(this.ctx, service, id);
|
||||
|
||||
if(userId === Constants.systemUserId){
|
||||
//系统级别,不检查权限
|
||||
}else{
|
||||
await authService.checkUserId( service, id, userId);
|
||||
if(allowAdmin){
|
||||
await authService.checkUserIdButAllowAdmin(this.ctx, service, id);
|
||||
}else{
|
||||
await authService.checkUserId( service, id, userId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return {projectId,userId}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Inject } from '@midwayjs/core';
|
||||
import { TypeORMDataSourceManager } from '@midwayjs/typeorm';
|
||||
import { EntityManager } from 'typeorm/entity-manager/EntityManager.js';
|
||||
import { FindManyOptions } from 'typeorm';
|
||||
import { Constants } from './constants.js';
|
||||
|
||||
export type PageReq<T = any> = {
|
||||
page?: { offset: number; limit: number };
|
||||
@@ -258,7 +259,7 @@ export abstract class BaseService<T> {
|
||||
|
||||
export function checkUserProjectParam(userId: number, projectId: number) {
|
||||
if (projectId != null ){
|
||||
if( userId !==-1) {
|
||||
if( userId !== Constants.enterpriseUserId) {
|
||||
throw new ValidateException('userId projectId 错误');
|
||||
}
|
||||
return true
|
||||
|
||||
@@ -120,4 +120,6 @@ export const Constants = {
|
||||
message: '用户邮箱还未配置',
|
||||
},
|
||||
},
|
||||
systemUserId: 0, // 系统级别userid固定为0
|
||||
enterpriseUserId: -1 // 企业模式用户id固定为-1
|
||||
};
|
||||
|
||||
@@ -88,6 +88,10 @@ export class SysPrivateSettings extends BaseSettings {
|
||||
|
||||
pipelineMaxRunningCount?: number;
|
||||
|
||||
|
||||
environmentVars?: string = '';
|
||||
|
||||
|
||||
sms?: {
|
||||
type?: string;
|
||||
config?: any;
|
||||
|
||||
@@ -11,6 +11,8 @@ import { BaseService, setAdminMode } from '../../../basic/index.js';
|
||||
import { executorQueue } from '../../basic/service/executor-queue.js';
|
||||
import { isComm } from '@certd/plus-core';
|
||||
const { merge } = mergeUtils;
|
||||
|
||||
let lastSaveEnvVars = {};
|
||||
/**
|
||||
* 设置
|
||||
*/
|
||||
@@ -117,12 +119,12 @@ export class SysSettingsService extends BaseService<SysSettingsEntity> {
|
||||
}
|
||||
|
||||
async savePublicSettings(bean: SysPublicSettings) {
|
||||
if(isComm()){
|
||||
if(bean.adminMode === 'enterprise'){
|
||||
if (isComm()) {
|
||||
if (bean.adminMode === 'enterprise') {
|
||||
throw new Error("商业版不支持使用企业管理模式")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
await this.saveSetting(bean);
|
||||
//让设置生效
|
||||
await this.reloadPublicSettings();
|
||||
@@ -173,6 +175,44 @@ export class SysSettingsService extends BaseService<SysSettingsEntity> {
|
||||
}
|
||||
|
||||
setSslProviderReverseProxies(privateSetting.reverseProxies);
|
||||
|
||||
//加载环境变量
|
||||
this.setEnvironmentVars(privateSetting.environmentVars);
|
||||
}
|
||||
|
||||
setEnvironmentVars(vars: string) {
|
||||
const envVars = {}
|
||||
if (typeof vars !== 'string') {
|
||||
vars = ""
|
||||
}
|
||||
vars.split('\n').forEach(line => {
|
||||
line = line.trim();
|
||||
if (!line || line.startsWith('#')) {
|
||||
return
|
||||
}
|
||||
|
||||
const arr = line.split("#")
|
||||
if (arr.length > 0) {
|
||||
line = arr[0].trim();
|
||||
}
|
||||
if (!line.includes("=")) {
|
||||
return
|
||||
}
|
||||
|
||||
const [key, value] = line.split('=');
|
||||
if (key && value) {
|
||||
envVars[key.trim()] = value.trim();
|
||||
}
|
||||
});
|
||||
//先删除旧环境变量
|
||||
if (lastSaveEnvVars) {
|
||||
for (const key in lastSaveEnvVars) {
|
||||
delete process.env[key];
|
||||
}
|
||||
}
|
||||
|
||||
merge(process.env, envVars);
|
||||
lastSaveEnvVars = envVars;
|
||||
}
|
||||
|
||||
async updateByKey(key: string, setting: any) {
|
||||
|
||||
@@ -7,8 +7,12 @@ import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
|
||||
export class AccessEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
@Column({ name: 'key_id', comment: 'key_id', length: 100 })
|
||||
keyId: string;
|
||||
|
||||
@Column({ name: 'user_id', comment: '用户id' })
|
||||
userId: number; // 0为系统级别, -1为企业,大于1为用户
|
||||
|
||||
@Column({ comment: '名称', length: 100 })
|
||||
name: string;
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import {AccessGetter, BaseService, PageReq, PermissionException, ValidateExcepti
|
||||
import {AccessEntity} from '../entity/access.js';
|
||||
import {AccessDefine, accessRegistry, newAccess} from '@certd/pipeline';
|
||||
import {EncryptService} from './encrypt-service.js';
|
||||
import { logger, utils } from '@certd/basic';
|
||||
|
||||
/**
|
||||
* 授权
|
||||
@@ -46,6 +47,7 @@ export class AccessService extends BaseService<AccessEntity> {
|
||||
}
|
||||
delete param._copyFrom
|
||||
this.encryptSetting(param, oldEntity);
|
||||
param.keyId = "ac_" + utils.id.simpleNanoId();
|
||||
return await super.add(param);
|
||||
}
|
||||
|
||||
@@ -117,6 +119,7 @@ export class AccessService extends BaseService<AccessEntity> {
|
||||
throw new ValidateException('该授权配置不存在,请确认是否已被删除');
|
||||
}
|
||||
this.encryptSetting(param, oldEntity);
|
||||
delete param.keyId
|
||||
return await super.update(param);
|
||||
}
|
||||
|
||||
@@ -215,4 +218,36 @@ export class AccessService extends BaseService<AccessEntity> {
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制授权到其他项目
|
||||
* @param accessId
|
||||
* @param projectId
|
||||
*/
|
||||
async copyTo(accessId: number,projectId?: number) {
|
||||
const access = await this.info(accessId);
|
||||
if (access == null) {
|
||||
throw new Error(`该授权配置不存在,请确认是否已被删除:id=${accessId}`);
|
||||
}
|
||||
|
||||
const keyId = access.keyId;
|
||||
//检查目标项目里是否已经有相同keyId的配置
|
||||
const existAccess = await this.repository.findOne({
|
||||
where: {
|
||||
keyId,
|
||||
projectId,
|
||||
},
|
||||
});
|
||||
if (existAccess) {
|
||||
logger.info(`目标项目已存在相同keyId的授权配置,跳过复制:keyId=${keyId}`);
|
||||
return existAccess.id;
|
||||
}
|
||||
const newAccess = {
|
||||
...access,
|
||||
id: undefined,
|
||||
projectId,
|
||||
}
|
||||
await this.add(newAccess);
|
||||
return newAccess.id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
|
||||
export class AddonEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
@Column({ name: 'key_id', comment: 'key_id', length: 100 })
|
||||
keyId: string;
|
||||
@Column({ name: 'user_id', comment: '用户id' })
|
||||
userId: number;
|
||||
@Column({ comment: '名称', length: 100 })
|
||||
|
||||
@@ -4,6 +4,7 @@ import { In, Repository } from "typeorm";
|
||||
import { AddonDefine, BaseService, PageReq, ValidateException } from "../../../index.js";
|
||||
import { addonRegistry } from "../api/index.js";
|
||||
import { AddonEntity } from "../entity/addon.js";
|
||||
import { utils } from "@certd/basic";
|
||||
|
||||
/**
|
||||
* Addon
|
||||
@@ -43,6 +44,7 @@ export class AddonService extends BaseService<AddonEntity> {
|
||||
} else {
|
||||
param.isSystem = false;
|
||||
}
|
||||
param.keyId = "ad_" + utils.id.simpleNanoId();
|
||||
delete param._copyFrom;
|
||||
return await super.add(param);
|
||||
}
|
||||
@@ -57,6 +59,7 @@ export class AddonService extends BaseService<AddonEntity> {
|
||||
if (oldEntity == null) {
|
||||
throw new ValidateException("该Addon配置不存在,请确认是否已被删除");
|
||||
}
|
||||
delete param.keyId
|
||||
return await super.update(param);
|
||||
}
|
||||
|
||||
@@ -67,6 +70,7 @@ export class AddonService extends BaseService<AddonEntity> {
|
||||
}
|
||||
return {
|
||||
id: entity.id,
|
||||
keyId: entity.keyId,
|
||||
name: entity.name,
|
||||
userId: entity.userId,
|
||||
addonType: entity.addonType,
|
||||
@@ -100,6 +104,7 @@ export class AddonService extends BaseService<AddonEntity> {
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
keyId: true,
|
||||
name: true,
|
||||
addonType: true,
|
||||
type: true,
|
||||
@@ -132,6 +137,7 @@ export class AddonService extends BaseService<AddonEntity> {
|
||||
const setting = JSON.parse(res.setting);
|
||||
return {
|
||||
id: res.id,
|
||||
keyId: res.keyId,
|
||||
addonType: res.addonType,
|
||||
type: res.type,
|
||||
name: res.name,
|
||||
|
||||
@@ -46,5 +46,5 @@
|
||||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "3bb29abe32c311e1cf840f97d485d1147411992a"
|
||||
"gitHead": "590ff67fcb40ff8ba0f7b2a9592b51d9fb54a2ef"
|
||||
}
|
||||
|
||||
@@ -38,5 +38,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "3bb29abe32c311e1cf840f97d485d1147411992a"
|
||||
"gitHead": "590ff67fcb40ff8ba0f7b2a9592b51d9fb54a2ef"
|
||||
}
|
||||
|
||||
@@ -57,5 +57,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "3bb29abe32c311e1cf840f97d485d1147411992a"
|
||||
"gitHead": "590ff67fcb40ff8ba0f7b2a9592b51d9fb54a2ef"
|
||||
}
|
||||
|
||||
@@ -38,6 +38,10 @@ COPY ./patch/ssh2/*.js /app/node_modules/.pnpm/node_modules/ssh2/lib/protocol/
|
||||
|
||||
ENV LEGO_VERSION=4.30.1
|
||||
ENV LEGO_DOWNLOAD_DIR=/app/tools/lego
|
||||
|
||||
ENV ALIYUN_CLIENT_CONNECT_TIMEOUT=10000
|
||||
ENV ALIYUN_CLIENT_READ_TIMEOUT=20000
|
||||
|
||||
RUN mkdir -p $LEGO_DOWNLOAD_DIR
|
||||
|
||||
# 根据架构下载不同的文件
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="remote-select">
|
||||
<div class="flex flex-row">
|
||||
<a-select class="remote-select-input" show-search :filter-option="filterOption" :options="optionsRef" :value="value" v-bind="attrs" @click="onClick" @update:value="emit('update:value', $event)">
|
||||
<a-select class="remote-select-input" show-search mode="tags" :filter-option="filterOption" :options="optionsRef" :value="value" v-bind="attrs" @click="onClick" @update:value="updateValue($event)">
|
||||
<template #dropdownRender="{ menuNode: menu }">
|
||||
<template v-if="search">
|
||||
<div class="flex w-full" style="padding: 4px 8px">
|
||||
@@ -61,6 +61,7 @@ const props = defineProps<
|
||||
watches?: string[];
|
||||
search?: boolean;
|
||||
pager?: boolean;
|
||||
multi?: boolean;
|
||||
} & ComponentPropsType
|
||||
>();
|
||||
|
||||
@@ -68,6 +69,15 @@ const emit = defineEmits<{
|
||||
"update:value": any;
|
||||
}>();
|
||||
|
||||
function updateValue(value: any) {
|
||||
if (props.multi) {
|
||||
emit("update:value", value);
|
||||
} else {
|
||||
const last = value?.[value.length - 1];
|
||||
emit("update:value", last);
|
||||
}
|
||||
}
|
||||
|
||||
const attrs = useAttrs();
|
||||
|
||||
const getCurrentPluginDefine: any = inject("getCurrentPluginDefine", () => {
|
||||
@@ -80,6 +90,7 @@ const getPluginType: any = inject("get:plugin:type", () => {
|
||||
return "plugin";
|
||||
});
|
||||
|
||||
debugger;
|
||||
const searchKeyRef = ref("");
|
||||
const optionsRef = ref([]);
|
||||
const message = ref("");
|
||||
|
||||
@@ -68,6 +68,14 @@ export default {
|
||||
|
||||
smsTab: "Login via SMS code",
|
||||
passwordTab: "Password login",
|
||||
passkeyTab: "Passkey Login",
|
||||
passkeyLogin: "Passkey Login",
|
||||
passkeyHelper: "Login with your biometric or security key",
|
||||
passkeyNotSupported: "Your browser does not support Passkey",
|
||||
passkeyRegister: "Register Passkey",
|
||||
passkeyRegistered: "Passkey Registered",
|
||||
passkeyRegisterSuccess: "Passkey registered successfully",
|
||||
passkeyRegisterFailed: "Passkey registration failed",
|
||||
title: "Change Password",
|
||||
weakPasswordWarning: "For your account security, please change your password immediately",
|
||||
changeNow: "Change Now",
|
||||
@@ -90,4 +98,9 @@ export default {
|
||||
updateProfile: "Update Profile",
|
||||
oauthLoginTitle: "Other ways of login",
|
||||
oauthOnlyLoginTitle: "Login",
|
||||
registerPasskey: "Register Passkey",
|
||||
deviceName: "Device Name",
|
||||
deviceNameHelper: "Please enter the device name, used to identify the device",
|
||||
passkeyRegisterHelper: "Site domain change will invalidate passkey",
|
||||
userInfo: "User Info",
|
||||
};
|
||||
|
||||
@@ -727,7 +727,7 @@ export default {
|
||||
paymentSetting: "Payment Settings",
|
||||
captchaSetting: "Captcha Setting",
|
||||
pipelineSetting: "Pipeline Settings",
|
||||
oauthSetting: "OAuth2 Settings",
|
||||
oauthSetting: "Login Settings",
|
||||
networkSetting: "Network Settings",
|
||||
adminModeSetting: "Admin Mode Settings",
|
||||
adminModeHelper: "enterprise mode : allow to create and manage pipelines, roles, users, etc.\n saas mode : only allow to create and manage pipelines",
|
||||
@@ -769,6 +769,10 @@ export default {
|
||||
oauthAutoRedirectHelper: "Whether to auto redirect to OAuth2 login when login (using the first enabled OAuth2 login type)",
|
||||
oauthOnly: "OAuth2 Login Only",
|
||||
oauthOnlyHelper: "Whether to only allow OAuth2 login, disable password login",
|
||||
enablePasskey: "Enable Passkey Login",
|
||||
passkeyHostnameNotSame: "Passkey hostname must be the same as the main domain",
|
||||
passkeyEnabledHelper:
|
||||
"1、Site must enable https \n2、Domain name must not change, otherwise the registered passkey will be invalid \n3、Domain name must be the same as the main domain, otherwise the registered passkey will be invalid",
|
||||
|
||||
email: {
|
||||
templates: "Email Templates",
|
||||
@@ -789,6 +793,8 @@ export default {
|
||||
reverseProxyHelper: "Reverse proxy for ACME address, used when applying for certificate",
|
||||
reverseProxyPlaceholder: "http://le.px.handfree.work",
|
||||
reverseProxyEmpty: "No reverse proxy list configured",
|
||||
environmentVars: "Environment Variables",
|
||||
environmentVarsHelper: "configure the runtime environment variables, one per line, format: KEY=VALUE",
|
||||
},
|
||||
},
|
||||
modal: {
|
||||
|
||||
@@ -68,6 +68,14 @@ export default {
|
||||
|
||||
smsTab: "手机号登录/注册",
|
||||
passwordTab: "密码登录",
|
||||
passkeyTab: "Passkey登录",
|
||||
passkeyLogin: "Passkey登录",
|
||||
passkeyHelper: "使用您的生物识别或安全密钥登录",
|
||||
passkeyNotSupported: "您的浏览器不支持Passkey",
|
||||
passkeyRegister: "注册Passkey",
|
||||
passkeyRegistered: "Passkey已注册",
|
||||
passkeyRegisterSuccess: "Passkey注册成功",
|
||||
passkeyRegisterFailed: "Passkey注册失败",
|
||||
|
||||
title: "修改密码",
|
||||
weakPasswordWarning: "为了您的账户安全,请立即修改密码",
|
||||
@@ -88,8 +96,13 @@ export default {
|
||||
nickName: "昵称",
|
||||
phoneNumber: "手机号",
|
||||
changePassword: "修改密码",
|
||||
updateProfile: "修改个人信息",
|
||||
updateProfile: "修改信息",
|
||||
|
||||
oauthLoginTitle: "其他登录方式",
|
||||
oauthOnlyLoginTitle: "登录",
|
||||
registerPasskey: "注册Passkey",
|
||||
deviceName: "设备名称",
|
||||
deviceNameHelper: "请输入当前设备名称,绑定多个时好做区分",
|
||||
passkeyRegisterHelper: "1、站点域名变更会导致passkey失效;\n2、同一设备同一个用户绑定多次只有最后一次的有效,之前绑定的会失效,需要手动删除",
|
||||
userInfo: "账号信息",
|
||||
};
|
||||
|
||||
@@ -780,7 +780,9 @@ export default {
|
||||
oauthAutoRedirectHelper: "是否自动跳转第三方登录(使用第一个已启用的第三方登录类型)",
|
||||
oauthOnly: "仅使用第三方登录",
|
||||
oauthOnlyHelper: "是否仅使用第三方登录,关闭密码登录(注意:请务必在测试第三方登录功能正常后再开启,否则会导致无法登录)\n 如果无法登录,请访问 http://你的certd地址/#/login?oauthOnly=false 来临时关闭此模式",
|
||||
|
||||
enablePasskey: "启用Passkey登录",
|
||||
passkeyHostnameNotSame: "当前域名与主绑定域名不同",
|
||||
passkeyEnabledHelper: "1、站点必须启用https \n2、域名不要变,否则会导致已注册的passkey失效 \n3、域名以主绑定域名为准,当前主域名:{0}",
|
||||
email: {
|
||||
templates: "邮件模板",
|
||||
templateType: "模板类型",
|
||||
@@ -800,6 +802,8 @@ export default {
|
||||
reverseProxyHelper: "证书颁发机构ACME地址的反向代理,在申请证书时自动使用",
|
||||
reverseProxyPlaceholder: "http://le.px.handfree.work",
|
||||
reverseProxyEmpty: "未配置反向代理",
|
||||
environmentVars: "环境变量",
|
||||
environmentVarsHelper: "配置运行时环境变量,每行一个,格式:KEY=VALUE",
|
||||
},
|
||||
},
|
||||
modal: {
|
||||
|
||||
@@ -275,7 +275,7 @@ export const certdResources = [
|
||||
meta: {
|
||||
icon: "ion:person-outline",
|
||||
auth: true,
|
||||
isMenu: false,
|
||||
isMenu: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -38,6 +38,7 @@ export type SysPublicSetting = {
|
||||
passwordLoginEnabled?: boolean;
|
||||
smsLoginEnabled?: boolean;
|
||||
defaultLoginType?: string;
|
||||
passkeyEnabled?: boolean;
|
||||
selfServicePasswordRetrievalEnabled?: boolean;
|
||||
|
||||
limitUserPipelineCount?: number;
|
||||
@@ -101,6 +102,8 @@ export type SysPrivateSetting = {
|
||||
commonCnameEnabled?: boolean;
|
||||
// 同一个用户同时最大运行流水线数量
|
||||
pipelineMaxRunningCount?: number;
|
||||
// 环境变量
|
||||
environmentVars?: string;
|
||||
|
||||
sms?: {
|
||||
type?: string;
|
||||
|
||||
@@ -107,3 +107,41 @@ export async function OauthProviders() {
|
||||
method: "post",
|
||||
});
|
||||
}
|
||||
|
||||
export async function generatePasskeyRegistrationOptions() {
|
||||
return await request({
|
||||
url: "/passkey/generateRegistration",
|
||||
method: "post",
|
||||
});
|
||||
}
|
||||
|
||||
export async function verifyPasskeyRegistration(response: any, challenge: string) {
|
||||
return await request({
|
||||
url: "/passkey/verifyRegistration",
|
||||
method: "post",
|
||||
data: { response, challenge },
|
||||
});
|
||||
}
|
||||
|
||||
export async function generatePasskeyAuthenticationOptions() {
|
||||
return await request({
|
||||
url: "/passkey/generateAuthentication",
|
||||
method: "post",
|
||||
});
|
||||
}
|
||||
|
||||
export async function loginByPasskey(form: { credential: any; challenge: string }) {
|
||||
return await request({
|
||||
url: "/loginByPasskey",
|
||||
method: "post",
|
||||
data: form,
|
||||
});
|
||||
}
|
||||
|
||||
export async function registerPasskey(form: { response: any; challenge: string }) {
|
||||
return await request({
|
||||
url: "/passkey/register",
|
||||
method: "post",
|
||||
data: form,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -92,6 +92,16 @@ export const useUserStore = defineStore({
|
||||
const loginRes = await UserApi.loginByTwoFactor(form);
|
||||
return await this.onLoginSuccess(loginRes);
|
||||
},
|
||||
|
||||
async loginByPasskey(form: any) {
|
||||
const loginRes = await UserApi.loginByPasskey(form);
|
||||
return await this.onLoginSuccess(loginRes);
|
||||
},
|
||||
|
||||
async registerPasskey(form: any) {
|
||||
return await UserApi.registerPasskey(form);
|
||||
},
|
||||
|
||||
async getUserInfoAction(): Promise<UserInfoRes> {
|
||||
const userInfo = await UserApi.mine();
|
||||
this.setUserInfo(userInfo);
|
||||
|
||||
@@ -110,10 +110,10 @@ h6 {
|
||||
flex: 0;
|
||||
}
|
||||
|
||||
.flex-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
// .flex-col {
|
||||
// display: flex;
|
||||
// flex-direction: column;
|
||||
// }
|
||||
|
||||
.align-left {
|
||||
text-align: left;
|
||||
@@ -295,10 +295,13 @@ h6 {
|
||||
}
|
||||
|
||||
.helper {
|
||||
color: #aeaeae;
|
||||
color: #8f8f8f;
|
||||
font-size: 12px;
|
||||
margin-top: 3px;
|
||||
margin-bottom: 3px;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
word-break: break-word;
|
||||
|
||||
&.error {
|
||||
color: #ff4d4f;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as _ from "lodash-es";
|
||||
import { asyncCompute, compute } from "@fast-crud/fast-crud";
|
||||
import { merge } from "lodash-es";
|
||||
import { computed } from "vue";
|
||||
|
||||
export type MergeScriptContext = {
|
||||
@@ -18,7 +18,7 @@ export function useReference(formItem: any) {
|
||||
const script = formItem.mergeScript;
|
||||
const func = new Function("ctx", script);
|
||||
const merged = func(ctx);
|
||||
_.merge(formItem, merged);
|
||||
merge(formItem, merged);
|
||||
|
||||
delete formItem.mergeScript;
|
||||
}
|
||||
|
||||
@@ -55,3 +55,78 @@ export async function OauthBoundUrl(type: string) {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function GetPasskeys() {
|
||||
return await request({
|
||||
url: "/mine/passkey/list",
|
||||
method: "POST",
|
||||
});
|
||||
}
|
||||
|
||||
export async function UnbindPasskey(id: number) {
|
||||
return await request({
|
||||
url: "/mine/passkey/unbind",
|
||||
method: "POST",
|
||||
data: { id },
|
||||
});
|
||||
}
|
||||
|
||||
export interface PasskeyRegistrationOptions {
|
||||
rp: {
|
||||
name: string;
|
||||
id: string;
|
||||
};
|
||||
user: {
|
||||
id: Uint8Array;
|
||||
name: string;
|
||||
displayName: string;
|
||||
};
|
||||
challenge: string;
|
||||
pubKeyCredParams: {
|
||||
type: string;
|
||||
alg: number;
|
||||
}[];
|
||||
timeout: number;
|
||||
attestation: string;
|
||||
excludeCredentials: any[];
|
||||
}
|
||||
|
||||
export interface PasskeyAuthenticationOptions {
|
||||
rpId: string;
|
||||
challenge: string;
|
||||
timeout: number;
|
||||
allowCredentials: any[];
|
||||
}
|
||||
|
||||
export interface PasskeyCredential {
|
||||
id: string;
|
||||
type: string;
|
||||
rawId: string;
|
||||
response: {
|
||||
attestationObject: string;
|
||||
clientDataJSON: string;
|
||||
};
|
||||
}
|
||||
|
||||
export async function generatePasskeyRegistrationOptions() {
|
||||
return await request({
|
||||
url: "/mine/passkey/generateRegistration",
|
||||
method: "post",
|
||||
});
|
||||
}
|
||||
|
||||
export async function verifyPasskeyRegistration(response: any, challenge: string, deviceName: string) {
|
||||
return await request({
|
||||
url: "/mine/passkey/verifyRegistration",
|
||||
method: "post",
|
||||
data: { response, challenge, deviceName },
|
||||
});
|
||||
}
|
||||
|
||||
export async function registerPasskey(response: any, challenge: string, deviceName: string) {
|
||||
return await request({
|
||||
url: "/mine/passkey/register",
|
||||
method: "post",
|
||||
data: { response, challenge, deviceName },
|
||||
});
|
||||
}
|
||||
|
||||
@@ -108,3 +108,54 @@ export function useUserProfile() {
|
||||
openEditProfileDialog,
|
||||
};
|
||||
}
|
||||
|
||||
export function usePasskeyRegister() {
|
||||
const { openCrudFormDialog } = useFormWrapper();
|
||||
const wrapperRef = ref();
|
||||
async function openRegisterDialog(req: { onSubmit?: (ctx: any) => void }) {
|
||||
const { t } = useI18n();
|
||||
|
||||
const userStore = useUserStore();
|
||||
const deviceNameRef = ref();
|
||||
|
||||
const crudOptions: any = {
|
||||
form: {
|
||||
wrapper: {
|
||||
title: t("authentication.registerPasskey"),
|
||||
width: 500,
|
||||
onOpened(opts: { form: any }) {
|
||||
opts.form.deviceName = "";
|
||||
},
|
||||
},
|
||||
onSubmit: req.onSubmit,
|
||||
afterSubmit: null,
|
||||
onSuccess: null,
|
||||
},
|
||||
columns: {
|
||||
deviceName: {
|
||||
title: t("authentication.deviceName"),
|
||||
type: "text",
|
||||
form: {
|
||||
component: {
|
||||
class: "w-full",
|
||||
},
|
||||
col: {
|
||||
span: 24,
|
||||
},
|
||||
helper: t("authentication.deviceNameHelper"),
|
||||
rules: [{ required: true, message: t("authentication.deviceName") }],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const wrapper = await openCrudFormDialog({ crudOptions });
|
||||
wrapperRef.value = wrapper;
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
return {
|
||||
openRegisterDialog,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,33 +3,129 @@
|
||||
<template #header>
|
||||
<div class="title">{{ t("certd.myInfo") }}</div>
|
||||
</template>
|
||||
<div class="p-10">
|
||||
<a-descriptions title="" bordered :column="2">
|
||||
<a-descriptions-item :label="t('authentication.username')">{{ userInfo.username }}</a-descriptions-item>
|
||||
<a-descriptions-item :label="t('authentication.nickName')">{{ userInfo.nickName }}</a-descriptions-item>
|
||||
<a-descriptions-item :label="t('authentication.avatar')">
|
||||
<a-avatar v-if="userInfo.avatar" size="large" :src="userAvatar" style="background-color: #eee"> </a-avatar>
|
||||
<a-avatar v-else size="large" style="background-color: #00b4f5">
|
||||
{{ userInfo.username }}
|
||||
</a-avatar>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="t('authentication.email')">{{ userInfo.email }}</a-descriptions-item>
|
||||
<a-descriptions-item :label="t('authentication.phoneNumber')">{{ userInfo.phoneCode }}{{ userInfo.mobile }}</a-descriptions-item>
|
||||
<a-descriptions-item v-if="settingStore.sysPublic.oauthEnabled && settingStore.isPlus" label="第三方账号绑定">
|
||||
<template v-for="item in computedOauthBounds" :key="item.name">
|
||||
<div v-if="item.addonId" class="flex items-center gap-2 mb-2">
|
||||
<fs-icon :icon="item.icon" class="mr-2 text-blue-500 w-5 flex justify-center items-center" />
|
||||
<span class="mr-2 w-36">{{ item.title }}</span>
|
||||
<a-button v-if="item.bound" type="primary" danger @click="unbind(item.name)">解绑</a-button>
|
||||
<a-button v-else type="primary" @click="bind(item.name)">绑定</a-button>
|
||||
<div class="profile-container md:p-8">
|
||||
<div class="profile-card md:rounded">
|
||||
<div class="card-header">
|
||||
<div class="header-bg-gradient"></div>
|
||||
<div class="header-content">
|
||||
<div class="avatar-wrapper">
|
||||
<a-avatar v-if="userInfo.avatar" :size="100" :src="userAvatar" class="user-avatar"> </a-avatar>
|
||||
<a-avatar v-else size="100" class="user-avatar default-avatar">
|
||||
{{ userInfo.username }}
|
||||
</a-avatar>
|
||||
<!-- <div class="status-indicator"></div> -->
|
||||
</div>
|
||||
</template>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item :label="t('common.handle')">
|
||||
<a-button type="primary" @click="doUpdate">{{ t("authentication.updateProfile") }}</a-button>
|
||||
<change-password-button class="ml-10" :show-button="true"> </change-password-button>
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
<div class="user-info">
|
||||
<h2 class="user-name flex items-center">
|
||||
{{ userInfo.nickName }}
|
||||
<fs-values-format :model-value="userInfo.roleIds" :dict="roleDict" color="blue" />
|
||||
</h2>
|
||||
<div class="user-details">
|
||||
<a-tag color="blue" class="detail-tag">
|
||||
<span class="tag-icon">👤</span>
|
||||
{{ userInfo.username }}
|
||||
</a-tag>
|
||||
<a-tag v-if="userInfo.email" color="green" class="detail-tag">
|
||||
<span class="tag-icon">📧</span>
|
||||
{{ userInfo.email }}
|
||||
</a-tag>
|
||||
<a-tag v-if="userInfo.mobile" color="purple" class="detail-tag">
|
||||
<span class="tag-icon">📱</span>
|
||||
{{ userInfo.mobile }}
|
||||
</a-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div class="action-buttons">
|
||||
<a-button type="primary" class="action-btn" @click="doUpdate">
|
||||
{{ t("authentication.updateProfile") }}
|
||||
</a-button>
|
||||
<change-password-button class="ml-10" :show-button="true" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap">
|
||||
<div class="w-full md:w-1/2 md:pr-2">
|
||||
<div v-if="settingStore.sysPublic.oauthEnabled && settingStore.isPlus" class="bindings-card md:rounded">
|
||||
<div class="card-title">
|
||||
<fs-icon icon="ion:link-outline" class="title-icon" />
|
||||
<span>第三方账号绑定</span>
|
||||
</div>
|
||||
<div class="bindings-list">
|
||||
<template v-for="item in computedOauthBounds" :key="item.name">
|
||||
<div v-if="item.addonId" class="binding-item">
|
||||
<div class="binding-icon">
|
||||
<fs-icon :icon="item.icon" class="icon" />
|
||||
</div>
|
||||
<div class="binding-info">
|
||||
<span class="binding-name">{{ item.title }}</span>
|
||||
<span>
|
||||
<a-tag v-if="item.bound" color="green" class="bound-tag1">已绑定</a-tag>
|
||||
<a-tag v-else color="red" class="bound-tag1">未绑定</a-tag>
|
||||
</span>
|
||||
</div>
|
||||
<a-button v-if="item.bound" type="primary" danger class="action-btn" @click="unbind(item.name)">
|
||||
<template #icon><fs-icon icon="ion:unlink-outline" /></template>
|
||||
解绑
|
||||
</a-button>
|
||||
<a-button v-else type="primary" class="action-btn" @click="bind(item.name)">
|
||||
<template #icon><fs-icon icon="ion:link-outline" /></template>
|
||||
绑定
|
||||
</a-button>
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="computedOauthBounds.length === 0" class="empty-text">暂无可用的第三方账号绑定</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="w-full md:w-1/2 md:pl-2">
|
||||
<div v-if="settingStore.sysPublic.passkeyEnabled && settingStore.isPlus" class="passkey-card md:rounded">
|
||||
<div class="card-title">
|
||||
<fs-icon icon="ion:finger-print" class="title-icon" />
|
||||
<span>Passkey 安全密钥</span>
|
||||
</div>
|
||||
<div class="passkey-list">
|
||||
<div v-for="passkey in passkeys" :key="passkey.id" class="passkey-item">
|
||||
<div class="passkey-icon">
|
||||
<fs-icon icon="ion:finger-print" class="icon" />
|
||||
</div>
|
||||
<div class="passkey-info">
|
||||
<div class="passkey-name">{{ passkey.deviceName }}</div>
|
||||
<div class="passkey-meta flex items-center">
|
||||
<span class="meta-item flex items-center">
|
||||
<fs-icon icon="ion:calendar-outline" class="meta-icon" />
|
||||
{{ formatDate(passkey.registeredAt) }}
|
||||
</span>
|
||||
<span class="meta-item flex items-center">
|
||||
<fs-icon icon="ion:time-outline" class="meta-icon" />
|
||||
最近使用:<fs-time-humanize :model-value="passkey.updateTime" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<a-button type="primary" danger class="remove-btn" @click="unbindPasskey(passkey.id)">
|
||||
<template #icon><fs-icon icon="ion:trash-outline" /></template>
|
||||
移除
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="passkeys.length === 0" class="empty-state">
|
||||
<fs-icon icon="ion:finger-print" class="empty-icon" />
|
||||
<p class="empty-text">暂无Passkey</p>
|
||||
</div>
|
||||
<div v-if="!passkeySupported" class="warning-box">
|
||||
<fs-icon icon="ion:warning-outline" class="warning-icon" />
|
||||
<span>{{ t("authentication.passkeyNotSupported") }}</span>
|
||||
</div>
|
||||
<a-button v-if="passkeySupported" type="primary" class="add-btn" @click="registerPasskey">
|
||||
<template #icon><fs-icon icon="ion:add-circle-outline" /></template>
|
||||
注册新的Passkey
|
||||
</a-button>
|
||||
<pre class="helper">{{ t("authentication.passkeyRegisterHelper") }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fs-page>
|
||||
</template>
|
||||
@@ -40,9 +136,12 @@ import { computed, onMounted, Ref, ref } from "vue";
|
||||
import ChangePasswordButton from "/@/views/certd/mine/change-password-button.vue";
|
||||
import { useI18n } from "/src/locales";
|
||||
import { useUserProfile } from "./use";
|
||||
import { Modal } from "ant-design-vue";
|
||||
import { usePasskeyRegister } from "./use";
|
||||
import { message, Modal, notification } from "ant-design-vue";
|
||||
import { useSettingStore } from "/@/store/settings";
|
||||
import { isEmpty } from "lodash-es";
|
||||
import { dict } from "@fast-crud/fast-crud";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
@@ -53,11 +152,20 @@ defineOptions({
|
||||
const settingStore = useSettingStore();
|
||||
|
||||
const userInfo: Ref = ref({});
|
||||
const passkeys = ref([]);
|
||||
const passkeySupported = ref(false);
|
||||
|
||||
const getUserInfo = async () => {
|
||||
userInfo.value = await api.getMineInfo();
|
||||
};
|
||||
const roleDict = dict({
|
||||
url: "/basic/user/getSimpleRoles",
|
||||
value: "id",
|
||||
label: "name",
|
||||
});
|
||||
|
||||
const { openEditProfileDialog } = useUserProfile();
|
||||
const { openRegisterDialog } = usePasskeyRegister();
|
||||
|
||||
function doUpdate() {
|
||||
openEditProfileDialog({
|
||||
@@ -69,10 +177,12 @@ function doUpdate() {
|
||||
|
||||
const oauthBounds = ref([]);
|
||||
const oauthProviders = ref([]);
|
||||
|
||||
async function loadOauthBounds() {
|
||||
const res = await api.GetOauthBounds();
|
||||
oauthBounds.value = res;
|
||||
}
|
||||
|
||||
async function loadOauthProviders() {
|
||||
const res = await api.GetOauthProviders();
|
||||
oauthProviders.value = res;
|
||||
@@ -102,12 +212,124 @@ async function unbind(type: string) {
|
||||
}
|
||||
|
||||
async function bind(type: string) {
|
||||
//获取第三方登录URL
|
||||
const res = await api.OauthBoundUrl(type);
|
||||
const loginUrl = res.loginUrl;
|
||||
window.location.href = loginUrl;
|
||||
}
|
||||
|
||||
async function loadPasskeys() {
|
||||
try {
|
||||
const res = await api.GetPasskeys();
|
||||
passkeys.value = res;
|
||||
} catch (e: any) {
|
||||
console.error("加载Passkey失败:", e);
|
||||
}
|
||||
}
|
||||
|
||||
async function unbindPasskey(id: number) {
|
||||
Modal.confirm({
|
||||
title: "确认解绑吗?",
|
||||
okText: "确认",
|
||||
okType: "danger",
|
||||
onOk: async () => {
|
||||
await api.UnbindPasskey(id);
|
||||
await loadPasskeys();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const toBase64Url = (buffer: ArrayBuffer) => {
|
||||
const bytes = new Uint8Array(buffer);
|
||||
let binary = "";
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
binary += String.fromCharCode(bytes[i]);
|
||||
}
|
||||
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
||||
};
|
||||
|
||||
async function registerPasskey() {
|
||||
if (!passkeySupported.value) {
|
||||
Modal.error({ title: "错误", content: "浏览器不支持Passkey" });
|
||||
return;
|
||||
}
|
||||
await openRegisterDialog({
|
||||
onSubmit: async (ctx: any) => {
|
||||
const deviceName = ctx.form.deviceName;
|
||||
if (!deviceName) {
|
||||
return;
|
||||
}
|
||||
await doRegisterPasskey(deviceName);
|
||||
message.success("Passkey注册成功");
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function doRegisterPasskey(deviceName: string) {
|
||||
try {
|
||||
const res: any = await api.generatePasskeyRegistrationOptions();
|
||||
const options = res;
|
||||
|
||||
// navigator.credentials.query({
|
||||
// publicKey: options,
|
||||
// });
|
||||
|
||||
// const excludeCredentials = passkeys.value.map(item => ({
|
||||
// id: new TextEncoder().encode(item.passkeyId),
|
||||
// type: "public-key",
|
||||
// }));
|
||||
|
||||
const credential = await (navigator.credentials as any).create({
|
||||
publicKey: {
|
||||
challenge: Uint8Array.from(atob(options.challenge.replace(/-/g, "+").replace(/_/g, "/")), c => c.charCodeAt(0)),
|
||||
rp: options.rp,
|
||||
pubKeyCredParams: options.pubKeyCredParams,
|
||||
timeout: options.timeout || 60000,
|
||||
attestation: options.attestation,
|
||||
// excludeCredentials: excludeCredentials,
|
||||
user: {
|
||||
id: new TextEncoder().encode(options.userId + ""),
|
||||
name: userInfo.value.username,
|
||||
displayName: deviceName,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!credential) {
|
||||
throw new Error("Passkey注册失败");
|
||||
}
|
||||
|
||||
const response = {
|
||||
id: credential.id,
|
||||
type: credential.type,
|
||||
rawId: toBase64Url(credential.rawId),
|
||||
response: {
|
||||
attestationObject: toBase64Url(credential.response.attestationObject),
|
||||
clientDataJSON: toBase64Url(credential.response.clientDataJSON),
|
||||
},
|
||||
};
|
||||
console.log("credential", credential, response);
|
||||
debugger;
|
||||
|
||||
const verifyRes: any = await api.verifyPasskeyRegistration(response, options.challenge, deviceName);
|
||||
await loadPasskeys();
|
||||
} catch (e: any) {
|
||||
console.error("Passkey注册失败:", e);
|
||||
notification.error({ message: "错误", description: e.message || "Passkey注册失败" });
|
||||
}
|
||||
}
|
||||
|
||||
const formatDate = (dateString: string) => {
|
||||
if (!dateString) return "";
|
||||
return dayjs(dateString).format("YYYY-MM-DD HH:mm:ss");
|
||||
};
|
||||
|
||||
const checkPasskeySupport = () => {
|
||||
passkeySupported.value = false;
|
||||
if (typeof window !== "undefined" && "credentials" in navigator && "PublicKeyCredential" in window) {
|
||||
passkeySupported.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
const userAvatar = computed(() => {
|
||||
if (isEmpty(userInfo.value.avatar)) {
|
||||
return "";
|
||||
@@ -123,5 +345,514 @@ onMounted(async () => {
|
||||
await getUserInfo();
|
||||
await loadOauthBounds();
|
||||
await loadOauthProviders();
|
||||
await loadPasskeys();
|
||||
checkPasskeySupport();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.page-user-profile {
|
||||
:deep(.ant-descriptions-item-label) {
|
||||
font-weight: 500;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
}
|
||||
}
|
||||
|
||||
.dark {
|
||||
.page-user-profile {
|
||||
:deep(.ant-descriptions-item-label) {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
}
|
||||
}
|
||||
|
||||
.profile-container {
|
||||
.profile-card,
|
||||
.bindings-card,
|
||||
.passkey-card {
|
||||
background: linear-gradient(135deg, #1f1f1f 0%, #2d2d2d 100%);
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4);
|
||||
border-color: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.card-header {
|
||||
.header-bg-gradient {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
opacity: 0.15;
|
||||
}
|
||||
}
|
||||
|
||||
.header-content {
|
||||
.user-avatar {
|
||||
border-color: #3b3b3b;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.user-name {
|
||||
color: #e5e5e5;
|
||||
}
|
||||
|
||||
.detail-tag {
|
||||
background: #3b3b3b;
|
||||
color: #e5e5e5;
|
||||
|
||||
.tag-icon {
|
||||
color: #e5e5e5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bindings-list {
|
||||
.binding-item {
|
||||
background: #2d2d2d;
|
||||
border-color: rgba(255, 255, 255, 0.1);
|
||||
color: #e5e5e5;
|
||||
|
||||
&:hover {
|
||||
border-color: #667eea;
|
||||
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.2);
|
||||
}
|
||||
|
||||
.binding-name {
|
||||
color: #e5e5e5;
|
||||
}
|
||||
|
||||
.binding-status {
|
||||
&.bound {
|
||||
background: #1a3a2f;
|
||||
color: #4caf50;
|
||||
}
|
||||
|
||||
&.unbound {
|
||||
background: #3a352a;
|
||||
color: #ffb300;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.passkey-list {
|
||||
.passkey-item {
|
||||
background: #2d2d2d;
|
||||
border-color: rgba(255, 255, 255, 0.1);
|
||||
color: #e5e5e5;
|
||||
|
||||
&:hover {
|
||||
border-color: #667eea;
|
||||
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.2);
|
||||
}
|
||||
|
||||
.passkey-name {
|
||||
color: #e5e5e5;
|
||||
}
|
||||
|
||||
.passkey-meta {
|
||||
.meta-item {
|
||||
color: #b0b0b0;
|
||||
}
|
||||
|
||||
.meta-icon {
|
||||
color: #888888;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
color: #b0b0b0;
|
||||
|
||||
.empty-icon {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
.warning-box {
|
||||
background: #3a2a2a;
|
||||
border-color: #5a3a3a;
|
||||
color: #e5e5e5;
|
||||
|
||||
.warning-icon {
|
||||
color: #ef5350;
|
||||
}
|
||||
}
|
||||
|
||||
.helper {
|
||||
background: #2d2d2d;
|
||||
border-color: rgba(255, 255, 255, 0.1);
|
||||
color: #b0b0b0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.profile-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
// max-width: 1000px;
|
||||
|
||||
.profile-card,
|
||||
.bindings-card,
|
||||
.passkey-card {
|
||||
background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
|
||||
overflow: hidden;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.bindings-card,
|
||||
.passkey-card {
|
||||
padding: 18px;
|
||||
}
|
||||
|
||||
.profile-card:hover,
|
||||
.bindings-card:hover,
|
||||
.passkey-card:hover {
|
||||
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
position: relative;
|
||||
padding: 40px 30px;
|
||||
}
|
||||
|
||||
.header-bg-gradient {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 100%;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
opacity: 0.08;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
.avatar-wrapper {
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
border: 4px solid #ffffff;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.status-indicator {
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
right: 8px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: #52c41a;
|
||||
border: 3px solid #ffffff;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
margin: 0 0 12px 0;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #2c3e50;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.user-details {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.detail-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 6px 12px;
|
||||
border-radius: 20px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.tag-icon {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 10px 20px;
|
||||
font-weight: 500;
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.action-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.card-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 2px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.title-icon {
|
||||
font-size: 20px;
|
||||
color: #667eea;
|
||||
}
|
||||
|
||||
.bindings-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.binding-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 16px;
|
||||
background: #ffffff;
|
||||
border-radius: 12px;
|
||||
border: 1px solid #f0f0f0;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.binding-item:hover {
|
||||
border-color: #667eea;
|
||||
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.1);
|
||||
}
|
||||
|
||||
.binding-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: linear-gradient(135deg, #ebefff 0%, #e5d4ff 100%);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.binding-icon .icon {
|
||||
font-size: 20px;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.binding-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.binding-name {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.binding-status {
|
||||
font-size: 12px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.binding-status.bound {
|
||||
background: #e6fffa;
|
||||
color: #38a169;
|
||||
}
|
||||
|
||||
.binding-status.unbound {
|
||||
background: #fffaf0;
|
||||
color: #d69e2e;
|
||||
}
|
||||
|
||||
.passkey-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.passkey-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 16px;
|
||||
background: #ffffff;
|
||||
border-radius: 12px;
|
||||
border: 1px solid #f0f0f0;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.passkey-item:hover {
|
||||
border-color: #667eea;
|
||||
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.1);
|
||||
}
|
||||
|
||||
.passkey-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.passkey-icon .icon {
|
||||
font-size: 24px;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.passkey-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.passkey-name {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.passkey-meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.meta-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.meta-icon {
|
||||
font-size: 14px;
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.remove-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 8px 16px;
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.remove-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(239, 68, 68, 0.2);
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px 10px;
|
||||
color: #9ca3af;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 48px;
|
||||
margin-bottom: 12px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.warning-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 12px 16px;
|
||||
background: #fff7ed;
|
||||
border: 1px solid #fed7d7;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.warning-icon {
|
||||
font-size: 18px;
|
||||
color: #f56565;
|
||||
}
|
||||
|
||||
.add-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 10px 20px;
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.add-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.helper {
|
||||
background: #f8f9fa;
|
||||
padding: 12px 16px;
|
||||
border-radius: 8px;
|
||||
font-size: 13px;
|
||||
color: #6b7280;
|
||||
border: 1px solid #e5e7eb;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.header-content {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.user-details {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -26,7 +26,8 @@ const type = route.params.type as string;
|
||||
const query = route.query;
|
||||
|
||||
async function checkNotify() {
|
||||
const res = await api.Notify(type, query);
|
||||
// const res = await api.Notify(type, query);
|
||||
const res = "success";
|
||||
if (res === "success") {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -110,6 +110,14 @@ export async function BatchUpdateNotificaiton(pipelineIds: number[], notificatio
|
||||
});
|
||||
}
|
||||
|
||||
export async function BatchUpdateProject(pipelineIds: number[], toProjectId: number): Promise<void> {
|
||||
return await request({
|
||||
url: apiPrefix + "/batchTransfer",
|
||||
method: "post",
|
||||
data: { ids: pipelineIds, toProjectId: toProjectId },
|
||||
});
|
||||
}
|
||||
|
||||
export async function BatchDelete(pipelineIds: number[]): Promise<void> {
|
||||
return await request({
|
||||
url: apiPrefix + "/batchDelete",
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useRouter } from "vue-router";
|
||||
import { compute, CreateCrudOptionsRet, dict, useFormWrapper } from "@fast-crud/fast-crud";
|
||||
import NotificationSelector from "/@/views/certd/notification/notification-selector/index.vue";
|
||||
import { useReference } from "/@/use/use-refrence";
|
||||
import { computed, ref } from "vue";
|
||||
import { computed, provide, Ref, ref } from "vue";
|
||||
import * as api from "../api";
|
||||
import { PluginGroup, usePluginStore } from "/@/store/plugin";
|
||||
import { createNotificationApi } from "/@/views/certd/notification/api";
|
||||
@@ -89,9 +89,10 @@ export function useCertPipelineCreator() {
|
||||
const inputs: any = {};
|
||||
const moreParams = [];
|
||||
const doSubmit = req.doSubmit;
|
||||
for (const inputKey in req.certPlugin.input) {
|
||||
const certPlugin = req.certPlugin;
|
||||
for (const inputKey in certPlugin.input) {
|
||||
// inputs[inputKey].form.show = true;
|
||||
const inputDefine = cloneDeep(req.certPlugin.input[inputKey]);
|
||||
const inputDefine = cloneDeep(certPlugin.input[inputKey]);
|
||||
if (inputDefine.maybeNeed) {
|
||||
moreParams.push(inputKey);
|
||||
}
|
||||
@@ -103,7 +104,6 @@ export function useCertPipelineCreator() {
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const pluginStore = usePluginStore();
|
||||
const randomHour = Math.floor(Math.random() * 6);
|
||||
const randomMin = Math.floor(Math.random() * 60);
|
||||
@@ -322,7 +322,7 @@ export function useCertPipelineCreator() {
|
||||
return certPlugins;
|
||||
}
|
||||
|
||||
async function openAddCertdPipelineDialog(req: { pluginName: string; defaultGroupId?: number; title?: string }) {
|
||||
async function openAddCertdPipelineDialog(req: { pluginName: string; defaultGroupId?: number; title?: string; currentPluginRef: Ref<any> }) {
|
||||
//检查是否流水线数量超出限制
|
||||
await checkPipelineLimit();
|
||||
|
||||
@@ -393,6 +393,8 @@ export function useCertPipelineCreator() {
|
||||
message.error("该证书申请插件不存在");
|
||||
return;
|
||||
}
|
||||
|
||||
req.currentPluginRef.value = certPlugin;
|
||||
const { crudOptions } = createCrudOptions({
|
||||
certPlugin,
|
||||
doSubmit,
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<fs-button icon="mdi:format-list-group" class="need-plus" type="link" text="转到其他项目" @click="openProjectSelectDialog"></fs-button>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import * as api from "../api";
|
||||
import { notification } from "ant-design-vue";
|
||||
import { dict, useFormWrapper } from "@fast-crud/fast-crud";
|
||||
import { useSettingStore } from "/@/store/settings";
|
||||
|
||||
const props = defineProps<{
|
||||
selectedRowKeys: any[];
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
change: any;
|
||||
}>();
|
||||
async function batchUpdateProjectRequest(toProjectId: number) {
|
||||
await api.BatchUpdateProject(props.selectedRowKeys, toProjectId);
|
||||
emit("change");
|
||||
}
|
||||
|
||||
const pipelineProjectDictRef = dict({
|
||||
url: "/enterprise/project/all",
|
||||
value: "id",
|
||||
label: "name",
|
||||
});
|
||||
const { openCrudFormDialog } = useFormWrapper();
|
||||
const settingStore = useSettingStore();
|
||||
async function openProjectSelectDialog() {
|
||||
settingStore.checkPlus();
|
||||
const crudOptions: any = {
|
||||
columns: {
|
||||
toProjectId: {
|
||||
title: "转到项目",
|
||||
type: "dict-select",
|
||||
dict: pipelineProjectDictRef,
|
||||
form: {
|
||||
rules: [{ required: true, message: "请选择项目" }],
|
||||
},
|
||||
},
|
||||
},
|
||||
form: {
|
||||
mode: "edit",
|
||||
//@ts-ignore
|
||||
async doSubmit({ form }) {
|
||||
await batchUpdateProjectRequest(form.toProjectId);
|
||||
},
|
||||
col: {
|
||||
span: 22,
|
||||
},
|
||||
labelCol: {
|
||||
style: {
|
||||
width: "100px",
|
||||
},
|
||||
},
|
||||
wrapper: {
|
||||
title: "批量转到其他项目",
|
||||
width: 600,
|
||||
},
|
||||
},
|
||||
} as any;
|
||||
await openCrudFormDialog({ crudOptions });
|
||||
}
|
||||
</script>
|
||||
@@ -42,6 +42,7 @@
|
||||
<change-group v-if="hasActionPermission('write')" :selected-row-keys="selectedRowKeys" @change="batchFinished"></change-group>
|
||||
<change-notification v-if="hasActionPermission('write')" :selected-row-keys="selectedRowKeys" @change="batchFinished"></change-notification>
|
||||
<change-trigger v-if="hasActionPermission('write')" :selected-row-keys="selectedRowKeys" @change="batchFinished"></change-trigger>
|
||||
<change-project v-if="hasActionPermission('write')" :selected-row-keys="selectedRowKeys" @change="batchFinished"></change-project>
|
||||
</div>
|
||||
</div>
|
||||
<template #form-bottom>
|
||||
@@ -52,11 +53,13 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onActivated, onMounted, ref } from "vue";
|
||||
import { computed, onActivated, onMounted, provide, ref } from "vue";
|
||||
import { dict, useFs } from "@fast-crud/fast-crud";
|
||||
import createCrudOptions from "./crud";
|
||||
import ChangeGroup from "./components/change-group.vue";
|
||||
import ChangeTrigger from "./components/change-trigger.vue";
|
||||
import ChangeProject from "./components/change-project.vue";
|
||||
|
||||
import BatchRerun from "./components/batch-rerun.vue";
|
||||
import { Modal, notification } from "ant-design-vue";
|
||||
import * as api from "./api";
|
||||
@@ -69,6 +72,7 @@ import { groupDictRef } from "./group/dicts";
|
||||
import { useCertPipelineCreator } from "./certd-form/use";
|
||||
import { useRouter } from "vue-router";
|
||||
import { useCrudPermission } from "/@/plugin/permission";
|
||||
import CertdForm from "./certd-form/certd-form.vue";
|
||||
|
||||
defineOptions({
|
||||
name: "PipelineManager",
|
||||
@@ -79,11 +83,17 @@ const context: any = {
|
||||
selectedRowKeys,
|
||||
};
|
||||
const router = useRouter();
|
||||
const { openAddCertdPipelineDialog } = useCertPipelineCreator();
|
||||
|
||||
function onActionbarMoreItemClick(req: { key: string; item: any }) {
|
||||
openCertApplyDialog({ key: req.key, title: req.item?.title });
|
||||
}
|
||||
|
||||
const certdFormRef = ref<typeof CertdForm>();
|
||||
const currentPluginRef = ref();
|
||||
provide("getCurrentPluginDefine", () => {
|
||||
return currentPluginRef.value;
|
||||
});
|
||||
|
||||
const addMorePipelineBtns = computed(() => {
|
||||
return [
|
||||
{ key: "CertApplyGetFormAliyun", title: t("certd.pipelinePage.aliyunSubscriptionPipeline"), icon: "svg:icon-aliyun" },
|
||||
@@ -92,6 +102,7 @@ const addMorePipelineBtns = computed(() => {
|
||||
{ key: "BatchAddPipeline", title: t("certd.pipelinePage.batchAddPipeline"), icon: "ion:duplicate" },
|
||||
];
|
||||
});
|
||||
const { openAddCertdPipelineDialog } = useCertPipelineCreator();
|
||||
function openCertApplyDialog(req: { key: string; title: string }) {
|
||||
if (req.key === "AddPipeline") {
|
||||
crudExpose.openAdd({});
|
||||
@@ -104,7 +115,7 @@ function openCertApplyDialog(req: { key: string; title: string }) {
|
||||
|
||||
const searchForm = crudExpose.getSearchValidatedFormData();
|
||||
const defaultGroupId = searchForm.groupId;
|
||||
openAddCertdPipelineDialog({ pluginName: req.key, defaultGroupId, title: req.title });
|
||||
openAddCertdPipelineDialog({ pluginName: req.key, defaultGroupId, title: req.title, currentPluginRef });
|
||||
}
|
||||
context.openCertApplyDialog = openCertApplyDialog;
|
||||
context.permission = { isProjectPermission: true };
|
||||
|
||||
-4
@@ -294,13 +294,9 @@ function useStepForm() {
|
||||
currentStep.value.input[key] = pluginSysConfig.sysSetting?.input[key];
|
||||
}
|
||||
}
|
||||
|
||||
console.log("currentStepTypeChanged:", currentStep.value);
|
||||
console.log("currentStepPlugin:", currentPlugin.value);
|
||||
};
|
||||
|
||||
const stepSave = async (e: any) => {
|
||||
console.log("currentStepSave", currentStep.value);
|
||||
try {
|
||||
await stepFormRef.value.validate();
|
||||
} catch (e) {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<!-- <div class="login-title">登录</div>-->
|
||||
<template v-if="!isOauthOnly">
|
||||
<a-tabs v-model:active-key="formState.loginType" :tab-bar-style="{ textAlign: 'center', borderBottom: 'unset' }">
|
||||
<a-tab-pane key="password" :tab="t('authentication.passwordTab')" :disabled="sysPublicSettings.passwordLoginEnabled !== true">
|
||||
<a-tab-pane key="password" :tab="t('authentication.passwordTab')">
|
||||
<template v-if="formState.loginType === 'password'">
|
||||
<!-- <div class="login-title">登录</div>-->
|
||||
<a-form-item required has-feedback name="username" :rules="rules.username">
|
||||
@@ -46,11 +46,21 @@
|
||||
</a-form-item>
|
||||
</template>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="passkey" :tab="t('authentication.passkeyTab')">
|
||||
<template v-if="formState.loginType === 'passkey'">
|
||||
<div v-if="!passkeySupported" class="text-red-500 text-sm mt-2 text-center mb-10">
|
||||
{{ t("authentication.passkeyNotSupported") }}
|
||||
</div>
|
||||
</template>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
<a-form-item>
|
||||
<a-button type="primary" size="large" html-type="button" :loading="loading" class="login-button" @click="handleFinish">
|
||||
<a-button v-if="formState.loginType !== 'passkey'" type="primary" size="large" html-type="button" :loading="loading" class="login-button" @click="handleFinish">
|
||||
{{ queryBindCode ? t("authentication.bindButton") : t("authentication.loginButton") }}
|
||||
</a-button>
|
||||
<a-button v-else type="primary" size="large" html-type="button" :loading="loading" class="login-button" :disabled="!passkeySupported" @click="handlePasskeyLogin">
|
||||
{{ t("authentication.passkeyLogin") }}
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<div class="mt-2 flex justify-between items-center">
|
||||
@@ -94,8 +104,8 @@
|
||||
</a-form>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, nextTick, reactive, ref, toRaw } from "vue";
|
||||
<script lang="ts" setup>
|
||||
import { computed, nextTick, reactive, ref, toRaw, onMounted } from "vue";
|
||||
import { useUserStore } from "/src/store/user";
|
||||
import { useSettingStore } from "/@/store/settings";
|
||||
import { utils } from "@fast-crud/fast-crud";
|
||||
@@ -103,193 +113,198 @@ import SmsCode from "/@/views/framework/login/sms-code.vue";
|
||||
import { useI18n } from "/@/locales";
|
||||
import { LanguageToggle } from "/@/vben/layouts";
|
||||
import CaptchaInput from "/@/components/captcha/captcha-input.vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { useRoute } from "vue-router";
|
||||
import OauthFooter from "/@/views/framework/oauth/oauth-footer.vue";
|
||||
import * as oauthApi from "../oauth/api";
|
||||
import { notification } from "ant-design-vue";
|
||||
export default defineComponent({
|
||||
name: "LoginPage",
|
||||
components: { LanguageToggle, SmsCode, CaptchaInput, OauthFooter },
|
||||
setup() {
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const userStore = useUserStore();
|
||||
import { request } from "/src/api/service";
|
||||
import * as UserApi from "/src/store/user/api.user";
|
||||
|
||||
const queryBindCode = ref(route.query.bindCode as string | undefined);
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const userStore = useUserStore();
|
||||
|
||||
const queryOauthOnly = route.query.oauthOnly as string;
|
||||
const urlLoginType = route.query.loginType as string | undefined;
|
||||
const verifyCodeInputRef = ref();
|
||||
const loading = ref(false);
|
||||
const queryBindCode = ref(route.query.bindCode as string | undefined);
|
||||
const queryOauthOnly = route.query.oauthOnly as string;
|
||||
const urlLoginType = route.query.loginType as string | undefined;
|
||||
const verifyCodeInputRef = ref();
|
||||
const loading = ref(false);
|
||||
|
||||
const settingStore = useSettingStore();
|
||||
const formRef = ref();
|
||||
let defaultLoginType = settingStore.sysPublic.defaultLoginType || "password";
|
||||
if (defaultLoginType === "sms") {
|
||||
if (!settingStore.sysPublic.smsLoginEnabled || !settingStore.isComm) {
|
||||
defaultLoginType = "password";
|
||||
}
|
||||
}
|
||||
const formState = reactive({
|
||||
username: "",
|
||||
phoneCode: "86",
|
||||
mobile: "",
|
||||
password: "",
|
||||
loginType: urlLoginType || defaultLoginType, //password
|
||||
smsCode: "",
|
||||
captcha: null,
|
||||
smsCaptcha: null,
|
||||
});
|
||||
const settingStore = useSettingStore();
|
||||
const formRef = ref();
|
||||
let defaultLoginType = settingStore.sysPublic.defaultLoginType || "password";
|
||||
if (defaultLoginType === "sms") {
|
||||
if (!settingStore.sysPublic.smsLoginEnabled || !settingStore.isComm) {
|
||||
defaultLoginType = "password";
|
||||
}
|
||||
}
|
||||
const formState = reactive({
|
||||
username: "",
|
||||
phoneCode: "86",
|
||||
mobile: "",
|
||||
password: "",
|
||||
loginType: urlLoginType || defaultLoginType,
|
||||
smsCode: "",
|
||||
captcha: null,
|
||||
smsCaptcha: null,
|
||||
});
|
||||
|
||||
const rules = {
|
||||
mobile: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入手机号",
|
||||
},
|
||||
],
|
||||
username: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入用户名",
|
||||
},
|
||||
],
|
||||
password: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入登录密码",
|
||||
},
|
||||
],
|
||||
smsCode: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入短信验证码",
|
||||
},
|
||||
],
|
||||
captcha: [
|
||||
{
|
||||
required: true,
|
||||
message: "请进行验证码验证",
|
||||
},
|
||||
],
|
||||
};
|
||||
const layout = {
|
||||
labelCol: {
|
||||
span: 0,
|
||||
},
|
||||
wrapperCol: {
|
||||
span: 24,
|
||||
},
|
||||
};
|
||||
|
||||
async function afterLoginSuccess() {
|
||||
if (queryBindCode.value) {
|
||||
await oauthApi.BindUser(queryBindCode.value);
|
||||
notification.success({ message: "绑定第三方账号成功" });
|
||||
}
|
||||
}
|
||||
|
||||
const twoFactor = reactive({
|
||||
loginId: "",
|
||||
verifyCode: "",
|
||||
});
|
||||
|
||||
const handleTwoFactorSubmit = async () => {
|
||||
await userStore.loginByTwoFactor(twoFactor);
|
||||
afterLoginSuccess();
|
||||
};
|
||||
|
||||
const handleFinish = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
// formState.captcha = await doCaptchaValidate();
|
||||
// if (!formState.captcha) {
|
||||
// return;
|
||||
// }
|
||||
const loginType = formState.loginType;
|
||||
await userStore.login(loginType, toRaw(formState));
|
||||
afterLoginSuccess();
|
||||
} catch (e: any) {
|
||||
//@ts-ignore
|
||||
if (e.code === 10020) {
|
||||
//双重认证
|
||||
//@ts-ignore
|
||||
twoFactor.loginId = e.data;
|
||||
await nextTick();
|
||||
verifyCodeInputRef.value.focus();
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
formState.captcha = null;
|
||||
}
|
||||
};
|
||||
|
||||
const handleFinishFailed = (errors: any) => {
|
||||
utils.logger.log(errors);
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
formRef.value.resetFields();
|
||||
};
|
||||
|
||||
const isLoginError = ref();
|
||||
|
||||
const sysPublicSettings = settingStore.getSysPublic;
|
||||
|
||||
function hasRegisterTypeEnabled() {
|
||||
return sysPublicSettings.registerEnabled && (sysPublicSettings.usernameRegisterEnabled || sysPublicSettings.emailRegisterEnabled || sysPublicSettings.mobileRegisterEnabled || sysPublicSettings.smsLoginEnabled);
|
||||
}
|
||||
|
||||
const captchaInputRef = ref();
|
||||
const captchaInputForSmsCode = ref();
|
||||
|
||||
const isOauthOnly = computed(() => {
|
||||
if (queryOauthOnly === "false" || queryOauthOnly === "0") {
|
||||
return false;
|
||||
}
|
||||
return sysPublicSettings.oauthOnly && settingStore.isPlus && sysPublicSettings.oauthEnabled;
|
||||
});
|
||||
|
||||
return {
|
||||
t,
|
||||
loading,
|
||||
formState,
|
||||
formRef,
|
||||
rules,
|
||||
layout,
|
||||
isOauthOnly,
|
||||
handleFinishFailed,
|
||||
handleFinish,
|
||||
resetForm,
|
||||
isLoginError,
|
||||
sysPublicSettings,
|
||||
hasRegisterTypeEnabled,
|
||||
twoFactor,
|
||||
handleTwoFactorSubmit,
|
||||
verifyCodeInputRef,
|
||||
settingStore,
|
||||
captchaInputRef,
|
||||
captchaInputForSmsCode,
|
||||
queryBindCode,
|
||||
};
|
||||
const rules = {
|
||||
mobile: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入手机号",
|
||||
},
|
||||
],
|
||||
username: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入用户名",
|
||||
},
|
||||
],
|
||||
password: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入登录密码",
|
||||
},
|
||||
],
|
||||
smsCode: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入短信验证码",
|
||||
},
|
||||
],
|
||||
captcha: [
|
||||
{
|
||||
required: true,
|
||||
message: "请进行验证码验证",
|
||||
},
|
||||
],
|
||||
};
|
||||
const layout = {
|
||||
labelCol: {
|
||||
span: 0,
|
||||
},
|
||||
wrapperCol: {
|
||||
span: 24,
|
||||
},
|
||||
};
|
||||
|
||||
const twoFactor = reactive({
|
||||
loginId: "",
|
||||
verifyCode: "",
|
||||
});
|
||||
|
||||
const passkeySupported = ref(false);
|
||||
const passkeyEnabled = ref(false);
|
||||
|
||||
const checkPasskeySupport = () => {
|
||||
passkeySupported.value = false;
|
||||
if (typeof window !== "undefined" && "credentials" in navigator && "PublicKeyCredential" in window) {
|
||||
passkeySupported.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
const handlePasskeyLogin = async () => {
|
||||
if (!passkeySupported.value) {
|
||||
notification.error({ message: t("authentication.passkeyNotSupported") });
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
try {
|
||||
const optionsResponse: any = await request({
|
||||
url: "/passkey/generateAuthentication",
|
||||
method: "post",
|
||||
});
|
||||
const options = optionsResponse;
|
||||
|
||||
const credential = await (navigator.credentials as any).get({
|
||||
publicKey: {
|
||||
challenge: Uint8Array.from(atob(options.challenge.replace(/-/g, "+").replace(/_/g, "/")), c => c.charCodeAt(0)),
|
||||
rpId: options.rpId,
|
||||
allowCredentials: options.allowCredentials || [],
|
||||
timeout: options.timeout || 60000,
|
||||
},
|
||||
});
|
||||
|
||||
if (!credential) {
|
||||
throw new Error("Passkey认证失败");
|
||||
}
|
||||
|
||||
const loginRes: any = await UserApi.loginByPasskey({
|
||||
credential,
|
||||
challenge: options.challenge,
|
||||
});
|
||||
|
||||
await userStore.onLoginSuccess(loginRes);
|
||||
} catch (e: any) {
|
||||
console.error("Passkey登录失败:", e);
|
||||
notification.error({ message: e.message || "Passkey登录失败" });
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleFinish = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const loginType = formState.loginType;
|
||||
await userStore.login(loginType, toRaw(formState));
|
||||
if (queryBindCode.value) {
|
||||
await oauthApi.BindUser(queryBindCode.value);
|
||||
notification.success({ message: "绑定第三方账号成功" });
|
||||
}
|
||||
} catch (e: any) {
|
||||
if (e.code === 10020) {
|
||||
twoFactor.loginId = e.data;
|
||||
await nextTick();
|
||||
verifyCodeInputRef.value.focus();
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
formState.captcha = null;
|
||||
}
|
||||
};
|
||||
|
||||
const handleFinishFailed = (errors: any) => {
|
||||
utils.logger.log(errors);
|
||||
};
|
||||
|
||||
const handleTwoFactorSubmit = async () => {
|
||||
await userStore.loginByTwoFactor(twoFactor);
|
||||
if (queryBindCode.value) {
|
||||
await oauthApi.BindUser(queryBindCode.value);
|
||||
notification.success({ message: "绑定第三方账号成功" });
|
||||
}
|
||||
};
|
||||
|
||||
const sysPublicSettings = settingStore.getSysPublic;
|
||||
|
||||
const hasRegisterTypeEnabled = () => {
|
||||
return sysPublicSettings.registerEnabled && (sysPublicSettings.usernameRegisterEnabled || sysPublicSettings.emailRegisterEnabled || sysPublicSettings.mobileRegisterEnabled || sysPublicSettings.smsLoginEnabled);
|
||||
};
|
||||
|
||||
const isOauthOnly = computed(() => {
|
||||
if (queryOauthOnly === "false" || queryOauthOnly === "0") {
|
||||
return false;
|
||||
}
|
||||
return sysPublicSettings.oauthOnly && settingStore.isPlus && sysPublicSettings.oauthEnabled;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
checkPasskeySupport();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.login-page.main {
|
||||
//margin: 20px !important;
|
||||
margin-bottom: 100px;
|
||||
|
||||
.user-layout-login {
|
||||
//label {
|
||||
// font-size: 14px;
|
||||
//}
|
||||
|
||||
.fs-icon {
|
||||
// color: rgba(0, 0, 0, 0.45);
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
@@ -328,7 +343,6 @@ export default defineComponent({
|
||||
text-align: left;
|
||||
margin-top: 30px;
|
||||
margin-bottom: 30px;
|
||||
//line-height: 22px;
|
||||
|
||||
.item-icon {
|
||||
font-size: 24px;
|
||||
|
||||
@@ -269,7 +269,7 @@ export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOpti
|
||||
title: t("certd.roles"),
|
||||
type: "dict-select",
|
||||
dict: dict({
|
||||
url: "/sys/authority/role/list",
|
||||
url: "/basic/user/getSimpleRoles",
|
||||
value: "id",
|
||||
label: "name",
|
||||
}), // 数据字典
|
||||
|
||||
@@ -7,6 +7,7 @@ import * as api from "./api";
|
||||
import { useSettingStore } from "/@/store/settings";
|
||||
import { useUserStore } from "/@/store/user";
|
||||
import { useI18n } from "/src/locales";
|
||||
import { useProjectStore } from "/@/store/project";
|
||||
|
||||
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||
const router = useRouter();
|
||||
@@ -29,6 +30,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
};
|
||||
|
||||
const userStore = useUserStore();
|
||||
const projectStore = useProjectStore();
|
||||
const settingStore = useSettingStore();
|
||||
const selectedRowKeys: Ref<any[]> = ref([]);
|
||||
context.selectedRowKeys = selectedRowKeys;
|
||||
@@ -61,6 +63,12 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
minWidth: 200,
|
||||
fixed: "right",
|
||||
},
|
||||
form: {
|
||||
onSuccess: async () => {
|
||||
await projectStore.reload();
|
||||
crudExpose?.doRefresh();
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
id: {
|
||||
title: "ID",
|
||||
|
||||
@@ -14,6 +14,11 @@
|
||||
<div class="helper">{{ t("certd.httpsProxyHelper") }}</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item :label="t('certd.sys.setting.environmentVars')" :name="['private', 'environmentVars']">
|
||||
<a-textarea v-model:value="formState.private.environmentVars" :placeholder="environmentVarsExample" rows="4" />
|
||||
<div class="helper">{{ t("certd.sys.setting.environmentVarsHelper") }}</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item :label="t('certd.dualStackNetwork')" :name="['private', 'dnsResultOrder']">
|
||||
<a-select v-model:value="formState.private.dnsResultOrder">
|
||||
<a-select-option value="verbatim">{{ t("certd.default") }}</a-select-option>
|
||||
@@ -55,6 +60,11 @@ defineOptions({
|
||||
name: "SettingNetwork",
|
||||
});
|
||||
|
||||
const environmentVarsExample = ref(
|
||||
`ALIYUN_CLIENT_CONNECT_TIMEOUT=16000 #连接超时,单位毫秒
|
||||
ALIYUN_CLIENT_READ_TIMEOUT=16000 #读取数据超时,单位毫秒`
|
||||
);
|
||||
|
||||
const formState = reactive<Partial<SysSettings>>({
|
||||
public: {},
|
||||
private: {},
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
<template>
|
||||
<div class="sys-settings-form sys-settings-oauth">
|
||||
<a-form :model="formState" name="register" :label-col="{ span: 8 }" :wrapper-col="{ span: 16 }" autocomplete="off" @finish="onFinish">
|
||||
<a-form-item :label="t('certd.sys.setting.enablePasskey')" :name="['public', 'passkeyEnabled']">
|
||||
<div class="flex-o">
|
||||
<a-switch v-model:checked="formState.public.passkeyEnabled" :disabled="!settingsStore.isPlus" :title="t('certd.plusFeature')" />
|
||||
<vip-button class="ml-5" mode="button"></vip-button>
|
||||
</div>
|
||||
<pre class="helper">{{ t("certd.sys.setting.passkeyEnabledHelper", [bindDomain]) }}</pre>
|
||||
<div v-if="!bindDomainIsSame" class="text-red-500 text-sm mt-2">
|
||||
{{ t("certd.sys.setting.passkeyHostnameNotSame") }}
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item :label="t('certd.sys.setting.enableOauth')" :name="['public', 'oauthEnabled']">
|
||||
<div class="flex-o">
|
||||
<a-switch v-model:checked="formState.public.oauthEnabled" :disabled="!settingsStore.isPlus" :title="t('certd.plusFeature')" />
|
||||
@@ -79,7 +89,7 @@
|
||||
<script setup lang="tsx">
|
||||
import { notification } from "ant-design-vue";
|
||||
import { merge } from "lodash-es";
|
||||
import { reactive, ref, Ref } from "vue";
|
||||
import { computed, reactive, ref, Ref } from "vue";
|
||||
import AddonSelector from "../../../certd/addon/addon-selector/index.vue";
|
||||
import { useSettingStore } from "/@/store/settings";
|
||||
import * as api from "/@/views/sys/settings/api";
|
||||
@@ -101,6 +111,16 @@ async function loadOauthProviders() {
|
||||
oauthProviders.value = await api.GetOauthProviders();
|
||||
}
|
||||
|
||||
const bindDomain = computed(() => {
|
||||
const uri = new URL(settingsStore.installInfo.bindUrl);
|
||||
return uri.hostname;
|
||||
});
|
||||
|
||||
const bindDomainIsSame = computed(() => {
|
||||
const currentHostname = window.location.hostname;
|
||||
return bindDomain.value === currentHostname;
|
||||
});
|
||||
|
||||
function fillOauthProviders(form: any) {
|
||||
const providers: any = {};
|
||||
for (const item of oauthProviders.value) {
|
||||
|
||||
@@ -93,16 +93,16 @@ export default (req: any) => {
|
||||
// with options
|
||||
"/api": {
|
||||
//配套后端 https://github.com/fast-crud/fs-server-js
|
||||
target: "https://127.0.0.1:7002",
|
||||
target: "http://127.0.0.1:7001",
|
||||
//忽略证书
|
||||
agent: new https.Agent({ rejectUnauthorized: false }),
|
||||
// agent: new https.Agent({ rejectUnauthorized: false }),
|
||||
},
|
||||
"/certd/api": {
|
||||
//配套后端 https://github.com/fast-crud/fs-server-js
|
||||
target: "https://127.0.0.1:7002/api",
|
||||
target: "http://127.0.0.1:7001/api",
|
||||
rewrite: path => path.replace(/^\/certd\/api/, ""),
|
||||
//忽略证书
|
||||
agent: new https.Agent({ rejectUnauthorized: false }),
|
||||
// agent: new https.Agent({ rejectUnauthorized: false }),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
|
||||
CREATE TABLE "sys_passkey"
|
||||
(
|
||||
"id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
"user_id" integer NOT NULL,
|
||||
"device_name" varchar(512) NOT NULL,
|
||||
"passkey_id" varchar(512) NOT NULL,
|
||||
"public_key" varchar(1024) NOT NULL,
|
||||
"counter" integer NOT NULL,
|
||||
"transports" varchar(512) NULL,
|
||||
"registered_at" integer NOT NULL,
|
||||
"create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||
"update_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP)
|
||||
);
|
||||
|
||||
|
||||
CREATE INDEX "index_passkey_user_id" ON "sys_passkey" ("user_id");
|
||||
CREATE INDEX "index_passkey_passkey_id" ON "sys_passkey" ("passkey_id");
|
||||
@@ -0,0 +1,12 @@
|
||||
ALTER TABLE cd_access ADD COLUMN key_id varchar(100) NULL;
|
||||
CREATE INDEX "index_access_key_id" ON "cd_access" ("key_id");
|
||||
update cd_access set key_id = id where key_id is null;
|
||||
|
||||
ALTER TABLE pi_notification ADD COLUMN key_id varchar(100) NULL;
|
||||
CREATE INDEX "index_notification_key_id" ON "pi_notification" ("key_id");
|
||||
update pi_notification set key_id = id where key_id is null;
|
||||
|
||||
|
||||
ALTER TABLE cd_addon ADD COLUMN key_id varchar(100) NULL;
|
||||
CREATE INDEX "index_addon_key_id" ON "cd_addon" ("key_id");
|
||||
update cd_addon set key_id = id where key_id is null;
|
||||
@@ -78,10 +78,13 @@
|
||||
"@midwayjs/koa": "3.20.13",
|
||||
"@midwayjs/logger": "3.4.2",
|
||||
"@midwayjs/static-file": "3.20.13",
|
||||
"@midwayjs/swagger": "3.20.11",
|
||||
"@midwayjs/typeorm": "3.20.11",
|
||||
"@midwayjs/upload": "3.20.13",
|
||||
"@midwayjs/validate": "3.20.13",
|
||||
"@peculiar/x509": "^1.11.0",
|
||||
"@simplewebauthn/browser": "^13.2.2",
|
||||
"@simplewebauthn/server": "^13.2.3",
|
||||
"@ucloud-sdks/ucloud-sdk-js": "^0.2.4",
|
||||
"@volcengine/openapi": "^1.28.1",
|
||||
"ali-oss": "^6.21.0",
|
||||
|
||||
@@ -131,6 +131,12 @@ const development = {
|
||||
contactText: '',
|
||||
contactLink: '',
|
||||
},
|
||||
swagger: {
|
||||
isGenerateTagForController: false,
|
||||
routerFilter: (url: string) => {
|
||||
return url.startsWith('/api/sys');
|
||||
}
|
||||
}
|
||||
} as MidwayConfig;
|
||||
loadDotEnv();
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import * as commercial from '@certd/commercial-core';
|
||||
import * as upload from '@midwayjs/upload';
|
||||
import { setLogger } from '@certd/acme-client';
|
||||
import {HiddenMiddleware} from "./middleware/hidden.js";
|
||||
|
||||
import * as swagger from '@midwayjs/swagger';
|
||||
//@ts-ignore
|
||||
// process.env.UV_THREADPOOL_SIZE = 2
|
||||
process.on('uncaughtException', error => {
|
||||
@@ -62,6 +62,7 @@ process.on('uncaughtException', error => {
|
||||
upload,
|
||||
libServer,
|
||||
commercial,
|
||||
swagger,
|
||||
{
|
||||
component: info,
|
||||
enabledEnvironment: ['local'],
|
||||
|
||||
@@ -13,7 +13,7 @@ export class AppController extends BaseController {
|
||||
@Inject()
|
||||
fileService: FileService;
|
||||
|
||||
@Get('/latest', { summary: Constants.per.authOnly })
|
||||
@Get('/latest', { description: Constants.per.authOnly })
|
||||
async latest(): Promise<any> {
|
||||
try {
|
||||
const res = await http.request({
|
||||
@@ -30,7 +30,7 @@ export class AppController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
@Get('/favicon', { summary: Constants.per.guest })
|
||||
@Get('/favicon', { description: Constants.per.guest })
|
||||
public async getFavicon() {
|
||||
if (isComm()) {
|
||||
const siteInfo = await this.sysSettingsService.getSetting<SysSiteInfo>(SysSiteInfo);
|
||||
@@ -47,7 +47,7 @@ export class AppController extends BaseController {
|
||||
this.ctx.response.set('Cache-Control', 'public,max-age=25920');
|
||||
}
|
||||
|
||||
@Post('/webhook', { summary: Constants.per.guest })
|
||||
@Post('/webhook', { description: Constants.per.guest })
|
||||
public async webhook( @Body() body: any) {
|
||||
logger.info('webhook', JSON.stringify(body))
|
||||
return this.ok("success")
|
||||
|
||||
@@ -53,13 +53,13 @@ export class BasicController extends BaseController {
|
||||
@Inject()
|
||||
addonGetterService: AddonGetterService;
|
||||
|
||||
@Post('/captcha/get', { summary: Constants.per.guest })
|
||||
@Post('/captcha/get', { description: 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 })
|
||||
@Post('/sendSmsCode', { description: Constants.per.guest })
|
||||
public async sendSmsCode(
|
||||
@Body(ALL)
|
||||
body: SmsCodeReq,
|
||||
@@ -80,7 +80,7 @@ export class BasicController extends BaseController {
|
||||
return this.ok(null);
|
||||
}
|
||||
|
||||
@Post('/sendEmailCode', { summary: Constants.per.guest })
|
||||
@Post('/sendEmailCode', { description: Constants.per.guest })
|
||||
public async sendEmailCode(
|
||||
@Body(ALL)
|
||||
body: EmailCodeReq,
|
||||
|
||||
@@ -13,7 +13,7 @@ export class FileController extends BaseController {
|
||||
@Inject()
|
||||
fileService: FileService;
|
||||
|
||||
@Post('/upload', { summary: Constants.per.authOnly })
|
||||
@Post('/upload', { description: Constants.per.authOnly })
|
||||
async upload(@Files() files: UploadFileInfo<string>[], @Fields() fields: any) {
|
||||
console.log('files', files, fields);
|
||||
const cacheKey = uploadTmpFileCacheKey + nanoid();
|
||||
@@ -33,7 +33,7 @@ export class FileController extends BaseController {
|
||||
});
|
||||
}
|
||||
|
||||
@Get('/download', { summary: Constants.per.guest })
|
||||
@Get('/download', { description: Constants.per.guest })
|
||||
async download(@Query('key') key: string) {
|
||||
let userId: any = null;
|
||||
if (!key.startsWith('/public')) {
|
||||
|
||||
@@ -8,12 +8,12 @@ import {BaseController, Constants} from '@certd/lib-server';
|
||||
export class HealthController extends BaseController {
|
||||
|
||||
|
||||
@Get('/liveliness', { summary: Constants.per.guest })
|
||||
@Get('/liveliness', { description: Constants.per.guest })
|
||||
async liveliness(): Promise<any> {
|
||||
return this.ok('ok')
|
||||
}
|
||||
|
||||
@Get('/readiness', { summary: Constants.per.guest })
|
||||
@Get('/readiness', { description: Constants.per.guest })
|
||||
async readiness(): Promise<any> {
|
||||
return this.ok('ok')
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Constants } from '@certd/lib-server';
|
||||
export class HomeController {
|
||||
@Inject()
|
||||
environmentService: MidwayEnvironmentService;
|
||||
@Get('/', { summary: Constants.per.guest })
|
||||
@Get('/', { description: Constants.per.guest })
|
||||
async home(): Promise<string> {
|
||||
logger.info('当前环境:', this.environmentService.getCurrentEnvironment()); // prod
|
||||
return 'Hello Midwayjs!';
|
||||
|
||||
@@ -19,7 +19,7 @@ export class ForgotPasswordController extends BaseController {
|
||||
@Inject()
|
||||
sysSettingsService: SysSettingsService;
|
||||
|
||||
@Post('/forgotPassword', { summary: Constants.per.guest })
|
||||
@Post('/forgotPassword', { description: Constants.per.guest })
|
||||
public async forgotPassword(
|
||||
@Body(ALL)
|
||||
body: any,
|
||||
|
||||
@@ -4,6 +4,7 @@ import { AddonService, BaseController, Constants, SysPublicSettings, SysSettings
|
||||
import { CodeService } from "../../../modules/basic/service/code-service.js";
|
||||
import { checkComm } from "@certd/plus-core";
|
||||
import { CaptchaService } from "../../../modules/basic/service/captcha-service.js";
|
||||
import { PasskeyService } from "../../../modules/login/service/passkey-service.js";
|
||||
|
||||
/**
|
||||
*/
|
||||
@@ -23,7 +24,11 @@ export class LoginController extends BaseController {
|
||||
@Inject()
|
||||
captchaService: CaptchaService;
|
||||
|
||||
@Post('/login', { summary: Constants.per.guest })
|
||||
@Inject()
|
||||
passkeyService: PasskeyService;
|
||||
|
||||
|
||||
@Post('/login', { description: Constants.per.guest })
|
||||
public async login(
|
||||
@Body(ALL)
|
||||
body: any,
|
||||
@@ -43,7 +48,7 @@ export class LoginController extends BaseController {
|
||||
// this.loginService.writeTokenCookie(this.ctx,token);
|
||||
}
|
||||
|
||||
@Post('/loginBySms', { summary: Constants.per.guest })
|
||||
@Post('/loginBySms', { description: Constants.per.guest })
|
||||
public async loginBySms(
|
||||
@Body(ALL)
|
||||
body: any
|
||||
@@ -66,7 +71,7 @@ export class LoginController extends BaseController {
|
||||
return this.ok(token);
|
||||
}
|
||||
|
||||
@Post('/loginByTwoFactor', { summary: Constants.per.guest })
|
||||
@Post('/loginByTwoFactor', { description: Constants.per.guest })
|
||||
public async loginByTwoFactor(
|
||||
@Body(ALL)
|
||||
body: any
|
||||
@@ -81,7 +86,38 @@ export class LoginController extends BaseController {
|
||||
return this.ok(token);
|
||||
}
|
||||
|
||||
@Post('/logout', { summary: Constants.per.authOnly })
|
||||
|
||||
|
||||
|
||||
@Post('/passkey/generateAuthentication', { description: Constants.per.guest })
|
||||
public async generateAuthentication() {
|
||||
const options = await this.passkeyService.generateAuthenticationOptions(
|
||||
this.ctx
|
||||
);
|
||||
|
||||
return this.ok({
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
@Post('/loginByPasskey', { description: Constants.per.guest })
|
||||
public async loginByPasskey(
|
||||
@Body(ALL)
|
||||
body: any
|
||||
) {
|
||||
const credential = body.credential;
|
||||
const challenge = body.challenge;
|
||||
|
||||
const token = await this.loginService.loginByPasskey({
|
||||
credential,
|
||||
challenge,
|
||||
}, this.ctx);
|
||||
|
||||
// this.writeTokenCookie(token);
|
||||
return this.ok(token);
|
||||
}
|
||||
|
||||
@Post('/logout', { description: Constants.per.authOnly })
|
||||
public logout() {
|
||||
this.ctx.cookies.set("certd_token", "", {
|
||||
maxAge: 0
|
||||
|
||||
@@ -53,7 +53,7 @@ export class ConnectController extends BaseController {
|
||||
return addon as IOauthProvider;
|
||||
}
|
||||
|
||||
@Post('/login', { summary: Constants.per.guest })
|
||||
@Post('/login', { description: Constants.per.guest })
|
||||
public async login(@Body(ALL) body: { type: string, forType?:string ,from?:string }) {
|
||||
|
||||
const addon = await this.getOauthProvider(body.type);
|
||||
@@ -72,7 +72,7 @@ export class ConnectController extends BaseController {
|
||||
}
|
||||
|
||||
|
||||
@Get('/callback/:type', { summary: Constants.per.guest })
|
||||
@Get('/callback/:type', { description: Constants.per.guest })
|
||||
public async callback(@Param('type') type: string, @Query() query: Record<string, string>) {
|
||||
|
||||
checkPlus()
|
||||
@@ -123,7 +123,7 @@ export class ConnectController extends BaseController {
|
||||
|
||||
}
|
||||
|
||||
@Post('/getLogoutUrl', { summary: Constants.per.guest })
|
||||
@Post('/getLogoutUrl', { description: Constants.per.guest })
|
||||
public async logout(@Body(ALL) body: any) {
|
||||
checkPlus()
|
||||
const addon = await this.getOauthProvider(body.type);
|
||||
@@ -132,7 +132,7 @@ export class ConnectController extends BaseController {
|
||||
}
|
||||
|
||||
|
||||
@Post('/token', { summary: Constants.per.guest })
|
||||
@Post('/token', { description: Constants.per.guest })
|
||||
public async token(@Body(ALL) body: { validationCode: string, type: string }) {
|
||||
checkPlus()
|
||||
const validationValue = await this.codeService.getValidationValue(body.validationCode);
|
||||
@@ -166,7 +166,7 @@ export class ConnectController extends BaseController {
|
||||
}
|
||||
|
||||
|
||||
@Post('/autoRegister', { summary: Constants.per.guest })
|
||||
@Post('/autoRegister', { description: Constants.per.guest })
|
||||
public async autoRegister(@Body(ALL) body: { validationCode: string, type: string }) {
|
||||
|
||||
const validationValue = this.codeService.getValidationValue(body.validationCode);
|
||||
@@ -195,7 +195,7 @@ export class ConnectController extends BaseController {
|
||||
}
|
||||
|
||||
|
||||
@Post('/bind', { summary: Constants.per.loginOnly })
|
||||
@Post('/bind', { description: Constants.per.loginOnly })
|
||||
public async bind(@Body(ALL) body: any) {
|
||||
//需要已登录
|
||||
const userId = this.getUserId();
|
||||
@@ -214,7 +214,7 @@ export class ConnectController extends BaseController {
|
||||
return this.ok(1);
|
||||
}
|
||||
|
||||
@Post('/unbind', { summary: Constants.per.loginOnly })
|
||||
@Post('/unbind', { description: Constants.per.loginOnly })
|
||||
public async unbind(@Body(ALL) body: any) {
|
||||
//需要已登录
|
||||
const userId = this.getUserId();
|
||||
@@ -225,7 +225,7 @@ export class ConnectController extends BaseController {
|
||||
return this.ok(1);
|
||||
}
|
||||
|
||||
@Post('/bounds', { summary: Constants.per.loginOnly })
|
||||
@Post('/bounds', { description: Constants.per.loginOnly })
|
||||
public async bounds(@Body(ALL) body: any) {
|
||||
//需要已登录
|
||||
const userId = this.getUserId();
|
||||
@@ -238,7 +238,7 @@ export class ConnectController extends BaseController {
|
||||
}
|
||||
|
||||
|
||||
@Post('/providers', { summary: Constants.per.guest })
|
||||
@Post('/providers', { description: Constants.per.guest })
|
||||
public async providers() {
|
||||
const defineList = addonRegistry.getDefineList("oauth");
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ export class RegisterController extends BaseController {
|
||||
@Inject()
|
||||
sysSettingsService: SysSettingsService;
|
||||
|
||||
@Post('/register', { summary: Constants.per.guest })
|
||||
@Post('/register', { description: Constants.per.guest })
|
||||
public async register(
|
||||
@Body(ALL)
|
||||
body: RegisterReq,
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Constants, SysSettingsService } from '@certd/lib-server';
|
||||
export class HomeController {
|
||||
@Inject()
|
||||
sysSettingsService: SysSettingsService;
|
||||
@Get('/robots.txt', { summary: Constants.per.guest })
|
||||
@Get('/robots.txt', { description: Constants.per.guest })
|
||||
async robots(): Promise<string> {
|
||||
const publicSettings = await this.sysSettingsService.getPublicSettings();
|
||||
if (!publicSettings.robots) {
|
||||
|
||||
@@ -71,7 +71,7 @@ export class BasicSettingsController extends BaseController {
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Get("/productInfo", { summary: Constants.per.guest })
|
||||
@Get("/productInfo", { description: Constants.per.guest })
|
||||
async getProductInfo() {
|
||||
const info = await http.request({
|
||||
url: "https://app.handfree.work/certd/info.json"
|
||||
@@ -80,7 +80,7 @@ export class BasicSettingsController extends BaseController {
|
||||
|
||||
}
|
||||
|
||||
@Get("/all", { summary: Constants.per.guest })
|
||||
@Get("/all", { description: Constants.per.guest })
|
||||
async getAllSettings() {
|
||||
const sysPublic = await this.getSysPublic();
|
||||
const installInfo = await this.getInstallInfo();
|
||||
|
||||
@@ -32,7 +32,7 @@ export class UnhiddenController {
|
||||
sysSettingsService: SysSettingsService;
|
||||
|
||||
|
||||
@Post('/:randomPath', {summary: Constants.per.guest})
|
||||
@Post('/:randomPath', {description: Constants.per.guest})
|
||||
async randomPath(@Body("password") password: any) {
|
||||
await this.checkUnhiddenPath()
|
||||
const hiddenSetting = await this.safeService.getHiddenSetting()
|
||||
@@ -50,7 +50,7 @@ export class UnhiddenController {
|
||||
}
|
||||
}
|
||||
|
||||
@Get('/:randomPath', {summary: Constants.per.guest})
|
||||
@Get('/:randomPath', {description: Constants.per.guest})
|
||||
async unhiddenGet() {
|
||||
await this.checkUnhiddenPath()
|
||||
this.ctx.response.body = unhiddenHtml
|
||||
|
||||
@@ -10,8 +10,8 @@ export class WebhookController extends BaseController {
|
||||
@Inject()
|
||||
pipelineService: PipelineService;
|
||||
|
||||
@Get('/:webhookKey', { summary: Constants.per.guest })
|
||||
@Post('/:webhookKey', { summary: Constants.per.guest })
|
||||
@Get('/:webhookKey', { description: Constants.per.guest })
|
||||
@Post('/:webhookKey', { description: Constants.per.guest })
|
||||
async webhook(@Param('webhookKey') webhookKey: string): Promise<any> {
|
||||
await this.pipelineService.triggerByWebhook(webhookKey);
|
||||
return this.ok({});
|
||||
|
||||
@@ -5,6 +5,7 @@ import { OpenKey } from "../../../modules/open/service/open-key-service.js";
|
||||
import { BaseOpenController } from "../base-open-controller.js";
|
||||
import { CertInfoFacade } from "../../../modules/monitor/facade/cert-info-facade.js";
|
||||
import { merge } from "lodash-es";
|
||||
import { ApiTags } from "@midwayjs/swagger";
|
||||
|
||||
export type CertGetReq = {
|
||||
domains?: string;
|
||||
@@ -17,14 +18,15 @@ export type CertGetReq = {
|
||||
*/
|
||||
@Provide()
|
||||
@Controller('/api/v1/cert')
|
||||
@ApiTags(['openapi'])
|
||||
export class OpenCertController extends BaseOpenController {
|
||||
@Inject()
|
||||
certInfoFacade: CertInfoFacade;
|
||||
@Inject()
|
||||
encryptService: EncryptService;
|
||||
|
||||
@Get('/get', { summary: Constants.per.open })
|
||||
@Post('/get', { summary: Constants.per.open })
|
||||
@Get('/get', { description: Constants.per.open })
|
||||
@Post('/get', { description: Constants.per.open })
|
||||
async get(@Body(ALL) bean: CertGetReq, @Query(ALL) query: CertGetReq) {
|
||||
const openKey: OpenKey = this.ctx.openKey;
|
||||
const userId = openKey.userId;
|
||||
|
||||
@@ -26,57 +26,57 @@ export class SysAccessController extends AccessController {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Post('/page', { summary: 'sys:settings:view' })
|
||||
@Post('/page', { description: 'sys:settings:view' })
|
||||
async page(@Body(ALL) body: any) {
|
||||
return await super.page(body);
|
||||
}
|
||||
|
||||
@Post('/list', { summary: 'sys:settings:view' })
|
||||
@Post('/list', { description: 'sys:settings:view' })
|
||||
async list(@Body(ALL) body: any) {
|
||||
return await super.list(body);
|
||||
}
|
||||
|
||||
@Post('/add', { summary: 'sys:settings:edit' })
|
||||
@Post('/add', { description: 'sys:settings:edit' })
|
||||
async add(@Body(ALL) bean: any) {
|
||||
return await super.add(bean);
|
||||
}
|
||||
|
||||
@Post('/update', { summary: 'sys:settings:edit' })
|
||||
@Post('/update', { description: 'sys:settings:edit' })
|
||||
async update(@Body(ALL) bean: any) {
|
||||
return await super.update(bean);
|
||||
}
|
||||
@Post('/info', { summary: 'sys:settings:view' })
|
||||
@Post('/info', { description: 'sys:settings:view' })
|
||||
async info(@Query('id') id: number) {
|
||||
return await super.info(id);
|
||||
}
|
||||
|
||||
@Post('/delete', { summary: 'sys:settings:edit' })
|
||||
@Post('/delete', { description: 'sys:settings:edit' })
|
||||
async delete(@Query('id') id: number) {
|
||||
return await super.delete(id);
|
||||
}
|
||||
|
||||
@Post('/define', { summary: 'sys:settings:view' })
|
||||
@Post('/define', { description: 'sys:settings:view' })
|
||||
async define(@Query('type') type: string) {
|
||||
return await super.define(type);
|
||||
}
|
||||
|
||||
@Post('/getSecretPlain', { summary: 'sys:settings:view' })
|
||||
@Post('/getSecretPlain', { description: 'sys:settings:view' })
|
||||
async getSecretPlain(@Body(ALL) body: { id: number; key: string }) {
|
||||
const value = await this.service.getById(body.id, 0);
|
||||
return this.ok(value[body.key]);
|
||||
}
|
||||
|
||||
@Post('/accessTypeDict', { summary: 'sys:settings:view' })
|
||||
@Post('/accessTypeDict', { description: 'sys:settings:view' })
|
||||
async getAccessTypeDict() {
|
||||
return await super.getAccessTypeDict();
|
||||
}
|
||||
|
||||
@Post('/simpleInfo', { summary: 'sys:settings:view' })
|
||||
@Post('/simpleInfo', { description: 'sys:settings:view' })
|
||||
async simpleInfo(@Query('id') id: number) {
|
||||
return await super.simpleInfo(id);
|
||||
}
|
||||
|
||||
@Post('/getDictByIds', { summary: 'sys:settings:view' })
|
||||
@Post('/getDictByIds', { description: 'sys:settings:view' })
|
||||
async getDictByIds(@Body('ids') ids: number[]) {
|
||||
return await super.getDictByIds(ids);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ export class BasicController extends BaseController {
|
||||
@Inject()
|
||||
sysSettingsService: SysSettingsService;
|
||||
|
||||
@Post('/preBindUser', { summary: 'sys:settings:edit' })
|
||||
@Post('/preBindUser', { description: 'sys:settings:edit' })
|
||||
public async preBindUser(@Body(ALL) body: PreBindUserReq) {
|
||||
// 设置缓存内容
|
||||
if (body.userId == null || body.userId <= 0) {
|
||||
@@ -28,7 +28,7 @@ export class BasicController extends BaseController {
|
||||
return this.ok({});
|
||||
}
|
||||
|
||||
@Post('/bindUser', { summary: 'sys:settings:edit' })
|
||||
@Post('/bindUser', { description: 'sys:settings:edit' })
|
||||
public async bindUser(@Body(ALL) body: BindUserReq) {
|
||||
if (body.userId == null || body.userId <= 0) {
|
||||
throw new Error("用户ID不能为空");
|
||||
@@ -39,7 +39,7 @@ export class BasicController extends BaseController {
|
||||
return this.ok({});
|
||||
}
|
||||
|
||||
@Post('/unbindUser', { summary: 'sys:settings:edit' })
|
||||
@Post('/unbindUser', { description: 'sys:settings:edit' })
|
||||
public async unbindUser() {
|
||||
const installInfo: SysInstallInfo = await this.sysSettingsService.getSetting(SysInstallInfo);
|
||||
installInfo.bindUserId = null;
|
||||
@@ -47,7 +47,7 @@ export class BasicController extends BaseController {
|
||||
return this.ok({});
|
||||
}
|
||||
|
||||
@Post('/updateLicense', { summary: 'sys:settings:edit' })
|
||||
@Post('/updateLicense', { description: 'sys:settings:edit' })
|
||||
public async updateLicense(@Body(ALL) body: { license: string }) {
|
||||
await this.plusService.updateLicense(body.license);
|
||||
return this.ok(true);
|
||||
|
||||
@@ -14,7 +14,7 @@ export class SysAddonController extends AddonController {
|
||||
|
||||
async getProjectUserId(permission:string){
|
||||
return {
|
||||
projectId:null,userId:0 //0为系统级别
|
||||
projectId:null,userId:0 //0为系统级别
|
||||
}
|
||||
}
|
||||
getUserId() {
|
||||
@@ -22,66 +22,66 @@ export class SysAddonController extends AddonController {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Post('/page', { summary: 'sys:settings:view' })
|
||||
@Post('/page', { description: 'sys:settings:view' })
|
||||
async page(@Body(ALL) body: any) {
|
||||
return await super.page(body);
|
||||
}
|
||||
|
||||
@Post('/list', { summary: 'sys:settings:view' })
|
||||
@Post('/list', { description: 'sys:settings:view' })
|
||||
async list(@Body(ALL) body: any) {
|
||||
return await super.list(body);
|
||||
}
|
||||
|
||||
@Post('/add', { summary: 'sys:settings:edit' })
|
||||
@Post('/add', { description: 'sys:settings:edit' })
|
||||
async add(@Body(ALL) bean: any) {
|
||||
return await super.add(bean);
|
||||
}
|
||||
|
||||
@Post('/update', { summary: 'sys:settings:edit' })
|
||||
@Post('/update', { description: 'sys:settings:edit' })
|
||||
async update(@Body(ALL) bean: any) {
|
||||
return await super.update(bean);
|
||||
}
|
||||
@Post('/info', { summary: 'sys:settings:view' })
|
||||
@Post('/info', { description: 'sys:settings:view' })
|
||||
async info(@Query('id') id: number) {
|
||||
return await super.info(id);
|
||||
}
|
||||
|
||||
@Post('/delete', { summary: 'sys:settings:edit' })
|
||||
@Post('/delete', { description: 'sys:settings:edit' })
|
||||
async delete(@Query('id') id: number) {
|
||||
return await super.delete(id);
|
||||
}
|
||||
@Post('/define', { summary: Constants.per.authOnly })
|
||||
@Post('/define', { description: 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 })
|
||||
@Post('/getTypeDict', { description: Constants.per.authOnly })
|
||||
async getTypeDict(@Query('addonType') addonType: string) {
|
||||
return await super.getTypeDict(addonType);
|
||||
}
|
||||
|
||||
@Post('/simpleInfo', { summary: Constants.per.authOnly })
|
||||
@Post('/simpleInfo', { description: 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 })
|
||||
@Post('/getDefaultId', { description: Constants.per.authOnly })
|
||||
async getDefaultId(@Query('addonType') addonType: string) {
|
||||
return await super.getDefaultId(addonType);
|
||||
}
|
||||
|
||||
@Post('/setDefault', { summary: Constants.per.authOnly })
|
||||
@Post('/setDefault', { description: 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 })
|
||||
@Post('/options', { description: Constants.per.authOnly })
|
||||
async options(@Query('addonType') addonType: string) {
|
||||
return await super.options(addonType);
|
||||
}
|
||||
|
||||
@Post('/handle', { summary: Constants.per.authOnly })
|
||||
@Post('/handle', { description: Constants.per.authOnly })
|
||||
async handle(@Body(ALL) body: AddonRequestHandleReq) {
|
||||
return await super.handle(body);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ export class PermissionController extends CrudController<PermissionService> {
|
||||
return this.service;
|
||||
}
|
||||
|
||||
@Post('/page', { summary: 'sys:auth:per:view' })
|
||||
@Post('/page', { description: 'sys:auth:per:view' })
|
||||
async page(
|
||||
@Body(ALL)
|
||||
body
|
||||
@@ -23,7 +23,7 @@ export class PermissionController extends CrudController<PermissionService> {
|
||||
return await super.page(body);
|
||||
}
|
||||
|
||||
@Post('/add', { summary: 'sys:auth:per:add' })
|
||||
@Post('/add', { description: 'sys:auth:per:add' })
|
||||
async add(
|
||||
@Body(ALL)
|
||||
bean
|
||||
@@ -31,14 +31,14 @@ export class PermissionController extends CrudController<PermissionService> {
|
||||
return await super.add(bean);
|
||||
}
|
||||
|
||||
@Post('/update', { summary: 'sys:auth:per:edit' })
|
||||
@Post('/update', { description: 'sys:auth:per:edit' })
|
||||
async update(
|
||||
@Body(ALL)
|
||||
bean
|
||||
) {
|
||||
return await super.update(bean);
|
||||
}
|
||||
@Post('/delete', { summary: 'sys:auth:per:remove' })
|
||||
@Post('/delete', { description: 'sys:auth:per:remove' })
|
||||
async delete(
|
||||
@Query('id')
|
||||
id: number
|
||||
@@ -46,7 +46,7 @@ export class PermissionController extends CrudController<PermissionService> {
|
||||
return await super.delete(id);
|
||||
}
|
||||
|
||||
@Post('/tree', { summary: 'sys:auth:per:view' })
|
||||
@Post('/tree', { description: 'sys:auth:per:view' })
|
||||
async tree() {
|
||||
const tree = await this.service.tree({});
|
||||
return this.ok(tree);
|
||||
|
||||
@@ -15,7 +15,7 @@ export class RoleController extends CrudController<RoleService> {
|
||||
return this.service;
|
||||
}
|
||||
|
||||
@Post('/page', { summary: 'sys:auth:role:view' })
|
||||
@Post('/page', { description: 'sys:auth:role:view' })
|
||||
async page(
|
||||
@Body(ALL)
|
||||
body
|
||||
@@ -23,13 +23,13 @@ export class RoleController extends CrudController<RoleService> {
|
||||
return await super.page(body);
|
||||
}
|
||||
|
||||
@Post('/list', { summary: 'sys:auth:role:view' })
|
||||
@Post('/list', { description: 'sys:auth:role:view' })
|
||||
async list() {
|
||||
const ret = await this.service.find({});
|
||||
return this.ok(ret);
|
||||
}
|
||||
|
||||
@Post('/add', { summary: 'sys:auth:role:add' })
|
||||
@Post('/add', { description: 'sys:auth:role:add' })
|
||||
async add(
|
||||
@Body(ALL)
|
||||
bean
|
||||
@@ -37,14 +37,14 @@ export class RoleController extends CrudController<RoleService> {
|
||||
return await super.add(bean);
|
||||
}
|
||||
|
||||
@Post('/update', { summary: 'sys:auth:role:edit' })
|
||||
@Post('/update', { description: 'sys:auth:role:edit' })
|
||||
async update(
|
||||
@Body(ALL)
|
||||
bean
|
||||
) {
|
||||
return await super.update(bean);
|
||||
}
|
||||
@Post('/delete', { summary: 'sys:auth:role:remove' })
|
||||
@Post('/delete', { description: 'sys:auth:role:remove' })
|
||||
async delete(
|
||||
@Query('id')
|
||||
id: number
|
||||
@@ -55,7 +55,7 @@ export class RoleController extends CrudController<RoleService> {
|
||||
return await super.delete(id);
|
||||
}
|
||||
|
||||
@Post('/getPermissionTree', { summary: 'sys:auth:role:view' })
|
||||
@Post('/getPermissionTree', { description: 'sys:auth:role:view' })
|
||||
async getPermissionTree(
|
||||
@Query('id')
|
||||
id: number
|
||||
@@ -64,7 +64,7 @@ export class RoleController extends CrudController<RoleService> {
|
||||
return this.ok(ret);
|
||||
}
|
||||
|
||||
@Post('/getPermissionIds', { summary: 'sys:auth:role:view' })
|
||||
@Post('/getPermissionIds', { description: 'sys:auth:role:view' })
|
||||
async getPermissionIds(
|
||||
@Query('id')
|
||||
id: number
|
||||
@@ -78,7 +78,7 @@ export class RoleController extends CrudController<RoleService> {
|
||||
* @param roleId
|
||||
* @param permissionIds
|
||||
*/
|
||||
@Post('/authz', { summary: 'sys:auth:role:edit' })
|
||||
@Post('/authz', { description: 'sys:auth:role:edit' })
|
||||
async authz(@Body('roleId') roleId, @Body('permissionIds') permissionIds) {
|
||||
await this.service.authz(roleId, permissionIds);
|
||||
return this.ok(null);
|
||||
|
||||
@@ -28,7 +28,7 @@ export class UserController extends CrudController<UserService> {
|
||||
return this.service;
|
||||
}
|
||||
|
||||
@Post('/getSimpleUserByIds', {summary: 'sys:auth:user:view'})
|
||||
@Post('/getSimpleUserByIds', {description: 'sys:auth:user:view'})
|
||||
async getSimpleUserByIds(@Body('ids') ids: number[]) {
|
||||
const users = await this.service.find({
|
||||
select: {
|
||||
@@ -47,7 +47,7 @@ export class UserController extends CrudController<UserService> {
|
||||
}
|
||||
|
||||
|
||||
@Post('/getSimpleUsers', {summary: 'sys:auth:user:view'})
|
||||
@Post('/getSimpleUsers', {description: 'sys:auth:user:view'})
|
||||
async getSimpleUsers() {
|
||||
const users = await this.service.find({
|
||||
select: {
|
||||
@@ -61,7 +61,7 @@ export class UserController extends CrudController<UserService> {
|
||||
return this.ok(users);
|
||||
}
|
||||
|
||||
@Post('/page', {summary: 'sys:auth:user:view'})
|
||||
@Post('/page', {description: 'sys:auth:user:view'})
|
||||
async page(
|
||||
@Body(ALL)
|
||||
body
|
||||
@@ -93,7 +93,7 @@ export class UserController extends CrudController<UserService> {
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Post('/add', {summary: 'sys:auth:user:add'})
|
||||
@Post('/add', {description: 'sys:auth:user:add'})
|
||||
async add(
|
||||
@Body(ALL)
|
||||
bean
|
||||
@@ -101,7 +101,7 @@ export class UserController extends CrudController<UserService> {
|
||||
return await super.add(bean);
|
||||
}
|
||||
|
||||
@Post('/update', {summary: 'sys:auth:user:edit'})
|
||||
@Post('/update', {description: 'sys:auth:user:edit'})
|
||||
async update(
|
||||
@Body(ALL)
|
||||
bean
|
||||
@@ -109,7 +109,7 @@ export class UserController extends CrudController<UserService> {
|
||||
return await super.update(bean);
|
||||
}
|
||||
|
||||
@Post('/delete', {summary: 'sys:auth:user:remove'})
|
||||
@Post('/delete', {description: 'sys:auth:user:remove'})
|
||||
async delete(
|
||||
@Query('id')
|
||||
id: number
|
||||
@@ -126,7 +126,7 @@ export class UserController extends CrudController<UserService> {
|
||||
/**
|
||||
* 解除登录锁定
|
||||
*/
|
||||
@Post('/unlockBlock', {summary: "sys:auth:user:edit"})
|
||||
@Post('/unlockBlock', {description: "sys:auth:user:edit"})
|
||||
public async unlockBlock(@Body('id') id: number) {
|
||||
const info = await this.service.info(id, ['password']);
|
||||
this.loginService.clearCacheOnSuccess(info.username)
|
||||
@@ -139,7 +139,7 @@ export class UserController extends CrudController<UserService> {
|
||||
/**
|
||||
* 当前登录用户的个人信息
|
||||
*/
|
||||
@Post('/mine', {summary: Constants.per.authOnly})
|
||||
@Post('/mine', {description: Constants.per.authOnly})
|
||||
public async mine() {
|
||||
const id = this.getUserId();
|
||||
const info = await this.service.info(id, ['password']);
|
||||
@@ -149,7 +149,7 @@ export class UserController extends CrudController<UserService> {
|
||||
/**
|
||||
* 当前登录用户的权限列表
|
||||
*/
|
||||
@Post('/permissions', {summary: Constants.per.authOnly})
|
||||
@Post('/permissions', {description: Constants.per.authOnly})
|
||||
public async permissions() {
|
||||
const id = this.getUserId();
|
||||
const permissions = await this.service.getUserPermissions(id);
|
||||
@@ -159,7 +159,7 @@ export class UserController extends CrudController<UserService> {
|
||||
/**
|
||||
* 当前登录用户的权限树形列表
|
||||
*/
|
||||
@Post('/permissionTree', {summary: Constants.per.authOnly})
|
||||
@Post('/permissionTree', {description: Constants.per.authOnly})
|
||||
public async permissionTree() {
|
||||
const id = this.getUserId();
|
||||
const permissions = await this.service.getUserPermissions(id);
|
||||
|
||||
@@ -16,18 +16,18 @@ export class CnameRecordController extends CrudController<CnameProviderService>
|
||||
return this.service;
|
||||
}
|
||||
|
||||
@Post('/page', { summary: 'sys:settings:view' })
|
||||
@Post('/page', { description: 'sys:settings:view' })
|
||||
async page(@Body(ALL) body: any) {
|
||||
body.query = body.query ?? {};
|
||||
return await super.page(body);
|
||||
}
|
||||
|
||||
@Post('/list', { summary: 'sys:settings:view' })
|
||||
@Post('/list', { description: 'sys:settings:view' })
|
||||
async list(@Body(ALL) body: any) {
|
||||
return super.list(body);
|
||||
}
|
||||
|
||||
@Post('/add', { summary: 'sys:settings:edit' })
|
||||
@Post('/add', { description: 'sys:settings:edit' })
|
||||
async add(@Body(ALL) bean: any) {
|
||||
const def: any = {
|
||||
isDefault: false,
|
||||
@@ -38,35 +38,35 @@ export class CnameRecordController extends CrudController<CnameProviderService>
|
||||
return super.add(bean);
|
||||
}
|
||||
|
||||
@Post('/update', { summary: 'sys:settings:edit' })
|
||||
@Post('/update', { description: 'sys:settings:edit' })
|
||||
async update(@Body(ALL) bean: any) {
|
||||
bean.userId = this.getUserId();
|
||||
return super.update(bean);
|
||||
}
|
||||
|
||||
@Post('/info', { summary: 'sys:settings:view' })
|
||||
@Post('/info', { description: 'sys:settings:view' })
|
||||
async info(@Query('id') id: number) {
|
||||
return super.info(id);
|
||||
}
|
||||
|
||||
@Post('/delete', { summary: 'sys:settings:edit' })
|
||||
@Post('/delete', { description: 'sys:settings:edit' })
|
||||
async delete(@Query('id') id: number) {
|
||||
return super.delete(id);
|
||||
}
|
||||
|
||||
@Post('/deleteByIds', { summary: 'sys:settings:edit' })
|
||||
@Post('/deleteByIds', { description: 'sys:settings:edit' })
|
||||
async deleteByIds(@Body('ids') ids: number[]) {
|
||||
const res = await this.service.delete(ids);
|
||||
return this.ok(res);
|
||||
}
|
||||
|
||||
@Post('/setDefault', { summary: 'sys:settings:edit' })
|
||||
@Post('/setDefault', { description: 'sys:settings:edit' })
|
||||
async setDefault(@Body('id') id: number) {
|
||||
await this.service.setDefault(id);
|
||||
return this.ok();
|
||||
}
|
||||
|
||||
@Post('/setDisabled', { summary: 'sys:settings:edit' })
|
||||
@Post('/setDisabled', { description: 'sys:settings:edit' })
|
||||
async setDisabled(@Body('id') id: number, @Body('disabled') disabled: boolean) {
|
||||
await this.service.setDisabled(id, disabled);
|
||||
return this.ok();
|
||||
|
||||
@@ -31,7 +31,7 @@ export class SysStatisticController extends BaseController {
|
||||
@Inject()
|
||||
historyService: HistoryService;
|
||||
|
||||
@Post('/count', { summary: 'sys:settings:view' })
|
||||
@Post('/count', { description: 'sys:settings:view' })
|
||||
public async count() {
|
||||
const userCount = await this.userService.count();
|
||||
const userRegisterCountPerDay = await this.userService.registerCountPerDay({ days: 7 });
|
||||
|
||||
@@ -19,18 +19,18 @@ export class SysProjectController extends CrudController<ProjectEntity> {
|
||||
return this.service;
|
||||
}
|
||||
|
||||
@Post("/page", { summary: "sys:settings:view" })
|
||||
@Post("/page", { description: "sys:settings:view" })
|
||||
async page(@Body(ALL) body: any) {
|
||||
body.query = body.query ?? {};
|
||||
return await super.page(body);
|
||||
}
|
||||
|
||||
@Post("/list", { summary: "sys:settings:view" })
|
||||
@Post("/list", { description: "sys:settings:view" })
|
||||
async list(@Body(ALL) body: any) {
|
||||
return super.list(body);
|
||||
}
|
||||
|
||||
@Post("/add", { summary: "sys:settings:edit" })
|
||||
@Post("/add", { description: "sys:settings:edit" })
|
||||
async add(@Body(ALL) bean: any) {
|
||||
const def: any = {
|
||||
isDefault: false,
|
||||
@@ -45,28 +45,28 @@ export class SysProjectController extends CrudController<ProjectEntity> {
|
||||
});
|
||||
}
|
||||
|
||||
@Post("/update", { summary: "sys:settings:edit" })
|
||||
@Post("/update", { description: "sys:settings:edit" })
|
||||
async update(@Body(ALL) bean: any) {
|
||||
bean.userId = this.getUserId();
|
||||
return super.update(bean);
|
||||
}
|
||||
|
||||
@Post("/info", { summary: "sys:settings:view" })
|
||||
@Post("/info", { description: "sys:settings:view" })
|
||||
async info(@Query("id") id: number) {
|
||||
return super.info(id);
|
||||
}
|
||||
|
||||
@Post("/delete", { summary: "sys:settings:edit" })
|
||||
@Post("/delete", { description: "sys:settings:edit" })
|
||||
async delete(@Query("id") id: number) {
|
||||
return super.delete(id);
|
||||
}
|
||||
|
||||
@Post("/deleteByIds", { summary: "sys:settings:edit" })
|
||||
@Post("/deleteByIds", { description: "sys:settings:edit" })
|
||||
async deleteByIds(@Body("ids") ids: number[]) {
|
||||
const res = await this.service.delete(ids);
|
||||
return this.ok(res);
|
||||
}
|
||||
@Post("/setDisabled", { summary: "sys:settings:edit" })
|
||||
@Post("/setDisabled", { description: "sys:settings:edit" })
|
||||
async setDisabled(@Body("id") id: number, @Body("disabled") disabled: boolean) {
|
||||
await this.service.setDisabled(id, disabled);
|
||||
return this.ok();
|
||||
|
||||
@@ -23,18 +23,18 @@ export class SysProjectMemberController extends CrudController<ProjectMemberEnti
|
||||
return this.service;
|
||||
}
|
||||
|
||||
@Post("/page", { summary: "sys:settings:view" })
|
||||
@Post("/page", { description: "sys:settings:view" })
|
||||
async page(@Body(ALL) body: any) {
|
||||
body.query = body.query ?? {};
|
||||
return await super.page(body);
|
||||
}
|
||||
|
||||
@Post("/list", { summary: "sys:settings:view" })
|
||||
@Post("/list", { description: "sys:settings:view" })
|
||||
async list(@Body(ALL) body: any) {
|
||||
return super.list(body);
|
||||
}
|
||||
|
||||
@Post("/add", { summary: "sys:settings:edit" })
|
||||
@Post("/add", { description: "sys:settings:edit" })
|
||||
async add(@Body(ALL) bean: any) {
|
||||
const def: any = {
|
||||
isDefault: false,
|
||||
@@ -50,7 +50,7 @@ export class SysProjectMemberController extends CrudController<ProjectMemberEnti
|
||||
return super.add(bean);
|
||||
}
|
||||
|
||||
@Post("/update", { summary: "sys:settings:edit" })
|
||||
@Post("/update", { description: "sys:settings:edit" })
|
||||
async update(@Body(ALL) bean: any) {
|
||||
if (!bean.id) {
|
||||
throw new Error("id is required");
|
||||
@@ -68,7 +68,7 @@ export class SysProjectMemberController extends CrudController<ProjectMemberEnti
|
||||
return this.ok(res);
|
||||
}
|
||||
|
||||
@Post("/info", { summary: "sys:settings:view" })
|
||||
@Post("/info", { description: "sys:settings:view" })
|
||||
async info(@Query("id") id: number) {
|
||||
if (!id) {
|
||||
throw new Error("id is required");
|
||||
@@ -81,7 +81,7 @@ export class SysProjectMemberController extends CrudController<ProjectMemberEnti
|
||||
return super.info(id);
|
||||
}
|
||||
|
||||
@Post("/delete", { summary: "sys:settings:edit" })
|
||||
@Post("/delete", { description: "sys:settings:edit" })
|
||||
async delete(@Query("id") id: number) {
|
||||
if (!id) {
|
||||
throw new Error("id is required");
|
||||
@@ -94,7 +94,7 @@ export class SysProjectMemberController extends CrudController<ProjectMemberEnti
|
||||
return super.delete(id);
|
||||
}
|
||||
|
||||
@Post("/deleteByIds", { summary: "sys:settings:edit" })
|
||||
@Post("/deleteByIds", { description: "sys:settings:edit" })
|
||||
async deleteByIds(@Body("ids") ids: number[]) {
|
||||
for (const id of ids) {
|
||||
if (!id) {
|
||||
|
||||
@@ -11,7 +11,7 @@ export class SysNetTestController extends BaseController {
|
||||
netTestService: NetTestService;
|
||||
|
||||
|
||||
@Post('/domainResolve', { summary: 'sys:settings:view' })
|
||||
@Post('/domainResolve', { description: 'sys:settings:view' })
|
||||
public async domainResolve(@Body(ALL) body: { domain: string }) {
|
||||
|
||||
const { domain } = body;
|
||||
@@ -20,7 +20,7 @@ export class SysNetTestController extends BaseController {
|
||||
}
|
||||
|
||||
// ping
|
||||
@Post('/ping', { summary: 'sys:settings:view' })
|
||||
@Post('/ping', { description: 'sys:settings:view' })
|
||||
public async ping(@Body(ALL) body: { domain: string }) {
|
||||
|
||||
const { domain } = body;
|
||||
@@ -29,7 +29,7 @@ export class SysNetTestController extends BaseController {
|
||||
}
|
||||
|
||||
// telnet
|
||||
@Post('/telnet', { summary: 'sys:settings:view' })
|
||||
@Post('/telnet', { description: 'sys:settings:view' })
|
||||
public async telnet(@Body(ALL) body: { domain: string, port: number }) {
|
||||
|
||||
const { domain, port } = body;
|
||||
@@ -38,7 +38,7 @@ export class SysNetTestController extends BaseController {
|
||||
}
|
||||
|
||||
// telnet
|
||||
@Post('/serverInfo', { summary: 'sys:settings:view' })
|
||||
@Post('/serverInfo', { description: 'sys:settings:view' })
|
||||
public async serverInfo() {
|
||||
|
||||
const result = await this.netTestService.serverInfo();
|
||||
|
||||
@@ -23,18 +23,18 @@ export class PluginController extends CrudController<PluginService> {
|
||||
return this.service;
|
||||
}
|
||||
|
||||
@Post('/page', { summary: 'sys:settings:view' })
|
||||
@Post('/page', { description: 'sys:settings:view' })
|
||||
async page(@Body(ALL) body: any) {
|
||||
body.query = body.query ?? {};
|
||||
return await super.page(body);
|
||||
}
|
||||
|
||||
@Post('/list', { summary: 'sys:settings:view' })
|
||||
@Post('/list', { description: 'sys:settings:view' })
|
||||
async list(@Body(ALL) body: any) {
|
||||
return super.list(body);
|
||||
}
|
||||
|
||||
@Post('/add', { summary: 'sys:settings:edit' })
|
||||
@Post('/add', { description: 'sys:settings:edit' })
|
||||
async add(@Body(ALL) bean: any) {
|
||||
const def: any = {
|
||||
isDefault: false,
|
||||
@@ -44,58 +44,58 @@ export class PluginController extends CrudController<PluginService> {
|
||||
return super.add(bean);
|
||||
}
|
||||
|
||||
@Post('/update', { summary: 'sys:settings:edit' })
|
||||
@Post('/update', { description: 'sys:settings:edit' })
|
||||
async update(@Body(ALL) bean: any) {
|
||||
|
||||
const res = await super.update(bean);
|
||||
return res
|
||||
}
|
||||
|
||||
@Post('/info', { summary: 'sys:settings:view' })
|
||||
@Post('/info', { description: 'sys:settings:view' })
|
||||
async info(@Query('id') id: number) {
|
||||
return super.info(id);
|
||||
}
|
||||
|
||||
@Post('/delete', { summary: 'sys:settings:edit' })
|
||||
@Post('/delete', { description: 'sys:settings:edit' })
|
||||
async delete(@Query('id') id: number) {
|
||||
return super.deleteByIds([id]);
|
||||
}
|
||||
|
||||
@Post('/deleteByIds', { summary: 'sys:settings:edit' })
|
||||
@Post('/deleteByIds', { description: 'sys:settings:edit' })
|
||||
async deleteByIds(@Body('ids') ids: number[]) {
|
||||
const res = await this.service.deleteByIds(ids);
|
||||
return this.ok(res);
|
||||
}
|
||||
|
||||
@Post('/setDisabled', { summary: 'sys:settings:edit' })
|
||||
@Post('/setDisabled', { description: 'sys:settings:edit' })
|
||||
async setDisabled(@Body(ALL) body: { id: number; name: string; type: string; disabled: boolean }) {
|
||||
await this.service.setDisabled(body);
|
||||
return this.ok();
|
||||
}
|
||||
@Post('/getCommPluginConfigs', { summary: 'sys:settings:view' })
|
||||
@Post('/getCommPluginConfigs', { description: 'sys:settings:view' })
|
||||
async getCommPluginConfigs() {
|
||||
const res = await this.pluginConfigService.getCommPluginConfig();
|
||||
return this.ok(res);
|
||||
}
|
||||
|
||||
@Post('/saveCommPluginConfigs', { summary: 'sys:settings:edit' })
|
||||
@Post('/saveCommPluginConfigs', { description: 'sys:settings:edit' })
|
||||
async saveCommPluginConfigs(@Body(ALL) body: CommPluginConfig) {
|
||||
const res = await this.pluginConfigService.saveCommPluginConfig(body);
|
||||
return this.ok(res);
|
||||
}
|
||||
@Post('/saveSetting', { summary: 'sys:settings:edit' })
|
||||
@Post('/saveSetting', { description: 'sys:settings:edit' })
|
||||
async saveSetting(@Body(ALL) body: PluginConfig) {
|
||||
const res = await this.pluginConfigService.savePluginConfig(body);
|
||||
return this.ok(res);
|
||||
}
|
||||
|
||||
@Post('/import', { summary: 'sys:settings:edit' })
|
||||
@Post('/import', { description: 'sys:settings:edit' })
|
||||
async import(@Body(ALL) body: PluginImportReq) {
|
||||
const res = await this.service.importPlugin(body);
|
||||
return this.ok(res);
|
||||
}
|
||||
|
||||
@Post('/export', { summary: 'sys:settings:edit' })
|
||||
@Post('/export', { description: 'sys:settings:edit' })
|
||||
async export(@Body('id') id: number) {
|
||||
const res = await this.service.exportPlugin(id);
|
||||
return this.ok(res);
|
||||
|
||||
@@ -13,7 +13,7 @@ export class SysPlusController extends BaseController {
|
||||
@Inject()
|
||||
plusService: PlusService;
|
||||
|
||||
@Post('/active', { summary: 'sys:settings:edit' })
|
||||
@Post('/active', { description: 'sys:settings:edit' })
|
||||
async active(@Body(ALL) body) {
|
||||
const { code, inviteCode } = body;
|
||||
|
||||
@@ -21,7 +21,7 @@ export class SysPlusController extends BaseController {
|
||||
|
||||
return this.ok(true);
|
||||
}
|
||||
@Post('/bindUrl', { summary: 'sys:settings:edit' })
|
||||
@Post('/bindUrl', { description: 'sys:settings:edit' })
|
||||
async bindUrl(@Body(ALL) body: { url: string ,url2?:string }) {
|
||||
const { url,url2 } = body;
|
||||
await this.plusService.register();
|
||||
@@ -42,18 +42,18 @@ export class SysPlusController extends BaseController {
|
||||
return this.ok(true);
|
||||
}
|
||||
|
||||
@Post('/getVipTrial', { summary: 'sys:settings:edit' })
|
||||
@Post('/getVipTrial', { description: 'sys:settings:edit' })
|
||||
async getVipTrial(@Body("vipType") vipType?:string) {
|
||||
const res = await this.plusService.getVipTrial(vipType);
|
||||
return this.ok(res);
|
||||
}
|
||||
@Post('/getTodayVipOrderCount', { summary: 'sys:settings:edit' })
|
||||
@Post('/getTodayVipOrderCount', { description: 'sys:settings:edit' })
|
||||
async getTodayVipOrderCount() {
|
||||
const res = await this.plusService.getTodayOrderCount();
|
||||
return this.ok(res);
|
||||
}
|
||||
//
|
||||
// @Get('/test', { summary: Constants.per.guest })
|
||||
// @Get('/test', { description: Constants.per.guest })
|
||||
// async test() {
|
||||
// const subjectId = 'xxxxxx';
|
||||
// const license = '';
|
||||
|
||||
+3
-3
@@ -14,7 +14,7 @@ export class SysSettingsController extends BaseController {
|
||||
|
||||
|
||||
|
||||
@Post("/get", { summary: "sys:settings:view" })
|
||||
@Post("/get", { description: "sys:settings:view" })
|
||||
async safeGet() {
|
||||
const res = await this.safeService.getSafeSetting()
|
||||
const clone:SysSafeSetting = cloneDeep(res);
|
||||
@@ -22,7 +22,7 @@ export class SysSettingsController extends BaseController {
|
||||
return this.ok(clone);
|
||||
}
|
||||
|
||||
@Post("/save", { summary: "sys:settings:edit" })
|
||||
@Post("/save", { description: "sys:settings:edit" })
|
||||
async safeSave(@Body(ALL) body: any) {
|
||||
await this.safeService.saveSafeSetting(body);
|
||||
return this.ok({});
|
||||
@@ -31,7 +31,7 @@ export class SysSettingsController extends BaseController {
|
||||
/**
|
||||
* 立即隐藏
|
||||
*/
|
||||
@Post("/hidden", { summary: "sys:settings:edit" })
|
||||
@Post("/hidden", { description: "sys:settings:edit" })
|
||||
async hiddenImmediate() {
|
||||
await this.safeService.hiddenImmediately();
|
||||
return this.ok({});
|
||||
|
||||
@@ -38,58 +38,58 @@ export class SysSettingsController extends CrudController<SysSettingsService> {
|
||||
return this.service;
|
||||
}
|
||||
|
||||
@Post('/page', { summary: 'sys:settings:view' })
|
||||
@Post('/page', { description: 'sys:settings:view' })
|
||||
async page(@Body(ALL) body) {
|
||||
return super.page(body);
|
||||
}
|
||||
|
||||
@Post('/list', { summary: 'sys:settings:view' })
|
||||
@Post('/list', { description: 'sys:settings:view' })
|
||||
async list(@Body(ALL) body) {
|
||||
return super.list(body);
|
||||
}
|
||||
|
||||
@Post('/add', { summary: 'sys:settings:edit' })
|
||||
@Post('/add', { description: 'sys:settings:edit' })
|
||||
async add(@Body(ALL) bean) {
|
||||
return super.add(bean);
|
||||
}
|
||||
|
||||
@Post('/update', { summary: 'sys:settings:edit' })
|
||||
@Post('/update', { description: 'sys:settings:edit' })
|
||||
async update(@Body(ALL) bean) {
|
||||
await this.service.checkUserId(bean.id, this.getUserId());
|
||||
return super.update(bean);
|
||||
}
|
||||
@Post('/info', { summary: 'sys:settings:view' })
|
||||
@Post('/info', { description: 'sys:settings:view' })
|
||||
async info(@Query('id') id: number) {
|
||||
await this.service.checkUserId(id, this.getUserId());
|
||||
return super.info(id);
|
||||
}
|
||||
|
||||
@Post('/delete', { summary: 'sys:settings:edit' })
|
||||
@Post('/delete', { description: 'sys:settings:edit' })
|
||||
async delete(@Query('id') id: number) {
|
||||
await this.service.checkUserId(id, this.getUserId());
|
||||
return super.delete(id);
|
||||
}
|
||||
|
||||
@Post('/save', { summary: 'sys:settings:edit' })
|
||||
@Post('/save', { description: 'sys:settings:edit' })
|
||||
async save(@Body(ALL) bean: SysSettingsEntity) {
|
||||
await this.service.save(bean);
|
||||
return this.ok({});
|
||||
}
|
||||
|
||||
@Post('/get', { summary: 'sys:settings:view' })
|
||||
@Post('/get', { description: 'sys:settings:view' })
|
||||
async get(@Query('key') key: string) {
|
||||
const entity = await this.service.getByKey(key);
|
||||
return this.ok(entity);
|
||||
}
|
||||
|
||||
// savePublicSettings
|
||||
@Post('/getEmailSettings', { summary: 'sys:settings:view' })
|
||||
@Post('/getEmailSettings', { description: 'sys:settings:view' })
|
||||
async getEmailSettings(@Body(ALL) body) {
|
||||
const conf = await getEmailSettings(this.service, this.userSettingsService);
|
||||
return this.ok(conf);
|
||||
}
|
||||
|
||||
@Post('/getEmailTemplates', { summary: 'sys:settings:view' })
|
||||
@Post('/getEmailTemplates', { description: 'sys:settings:view' })
|
||||
async getEmailTemplates(@Body(ALL) body) {
|
||||
const conf = await getEmailSettings(this.service, this.userSettingsService);
|
||||
const templates = conf.templates || {}
|
||||
@@ -108,7 +108,7 @@ export class SysSettingsController extends CrudController<SysSettingsService> {
|
||||
return this.ok(proviers);
|
||||
}
|
||||
|
||||
@Post('/saveEmailSettings', { summary: 'sys:settings:edit' })
|
||||
@Post('/saveEmailSettings', { description: 'sys:settings:edit' })
|
||||
async saveEmailSettings(@Body(ALL) body) {
|
||||
const conf = await getEmailSettings(this.service, this.userSettingsService);
|
||||
merge(conf, body);
|
||||
@@ -116,7 +116,7 @@ export class SysSettingsController extends CrudController<SysSettingsService> {
|
||||
return this.ok(conf);
|
||||
}
|
||||
|
||||
@Post('/getSysSettings', { summary: 'sys:settings:view' })
|
||||
@Post('/getSysSettings', { description: 'sys:settings:view' })
|
||||
async getSysSettings() {
|
||||
const publicSettings = await this.service.getPublicSettings();
|
||||
let privateSettings = await this.service.getPrivateSettings();
|
||||
@@ -125,7 +125,7 @@ export class SysSettingsController extends CrudController<SysSettingsService> {
|
||||
}
|
||||
|
||||
// savePublicSettings
|
||||
@Post('/saveSysSettings', { summary: 'sys:settings:edit' })
|
||||
@Post('/saveSysSettings', { description: 'sys:settings:edit' })
|
||||
async saveSysSettings(@Body(ALL) body: { public: SysPublicSettings; private: SysPrivateSettings }) {
|
||||
const publicSettings = await this.service.getPublicSettings();
|
||||
const privateSettings = await this.service.getPrivateSettings();
|
||||
@@ -135,13 +135,13 @@ export class SysSettingsController extends CrudController<SysSettingsService> {
|
||||
await this.service.savePrivateSettings(privateSettings);
|
||||
return this.ok({});
|
||||
}
|
||||
@Post('/stopOtherUserTimer', { summary: 'sys:settings:edit' })
|
||||
@Post('/stopOtherUserTimer', { description: 'sys:settings:edit' })
|
||||
async stopOtherUserTimer(@Body(ALL) body) {
|
||||
await this.pipelineService.stopOtherUserPipeline(1);
|
||||
return this.ok({});
|
||||
}
|
||||
|
||||
@Post('/testProxy', { summary: 'sys:settings:edit' })
|
||||
@Post('/testProxy', { description: 'sys:settings:edit' })
|
||||
async testProxy(@Body(ALL) body) {
|
||||
const google = 'https://www.google.com/';
|
||||
const baidu = 'https://www.baidu.com/';
|
||||
@@ -179,13 +179,13 @@ export class SysSettingsController extends CrudController<SysSettingsService> {
|
||||
});
|
||||
}
|
||||
|
||||
@Post('/testSms', { summary: 'sys:settings:edit' })
|
||||
@Post('/testSms', { description: 'sys:settings:edit' })
|
||||
async testSms(@Body(ALL) body) {
|
||||
await this.codeService.sendSmsCode(body.phoneCode, body.mobile );
|
||||
return this.ok({});
|
||||
}
|
||||
|
||||
@Post('/getSmsTypeDefine', { summary: 'sys:settings:view' })
|
||||
@Post('/getSmsTypeDefine', { description: 'sys:settings:view' })
|
||||
async getSmsTypeDefine(@Body('type') type: string) {
|
||||
const define =await SmsServiceFactory.getDefine(type);
|
||||
return this.ok(define);
|
||||
@@ -193,7 +193,7 @@ export class SysSettingsController extends CrudController<SysSettingsService> {
|
||||
|
||||
|
||||
|
||||
@Post("/safe/get", { summary: "sys:settings:view" })
|
||||
@Post("/safe/get", { description: "sys:settings:view" })
|
||||
async safeGet() {
|
||||
const res = await this.service.getSetting<SysSafeSetting>(SysSafeSetting);
|
||||
const clone:SysSafeSetting = cloneDeep(res);
|
||||
@@ -201,7 +201,7 @@ export class SysSettingsController extends CrudController<SysSettingsService> {
|
||||
return this.ok(clone);
|
||||
}
|
||||
|
||||
@Post("/safe/save", { summary: "sys:settings:edit" })
|
||||
@Post("/safe/save", { description: "sys:settings:edit" })
|
||||
async safeSave(@Body(ALL) body: any) {
|
||||
if(body.hidden.openPassword){
|
||||
body.hidden.openPassword = utils.hash.md5(body.hidden.openPassword);
|
||||
@@ -217,13 +217,13 @@ export class SysSettingsController extends CrudController<SysSettingsService> {
|
||||
}
|
||||
|
||||
|
||||
@Post("/captchaTest", { summary: "sys:settings:edit" })
|
||||
@Post("/captchaTest", { description: "sys:settings:edit" })
|
||||
async captchaTest(@Body(ALL) body: any,@RequestIP() remoteIp: string) {
|
||||
await this.codeService.checkCaptcha(body,{remoteIp});
|
||||
return this.ok({});
|
||||
}
|
||||
|
||||
@Post('/oauth/providers', { summary: 'sys:settings:view' })
|
||||
@Post('/oauth/providers', { description: 'sys:settings:view' })
|
||||
async oauthProviders() {
|
||||
const list = await addonRegistry.getDefineList("oauth");
|
||||
return this.ok(list);
|
||||
|
||||
@@ -12,12 +12,14 @@ import { AuthService } from "../../../modules/sys/authority/service/auth-service
|
||||
import { checkPlus } from "@certd/plus-core";
|
||||
import { http, logger, utils } from "@certd/basic";
|
||||
import { TaskServiceBuilder } from "../../../modules/pipeline/service/getter/task-service-getter.js";
|
||||
import { ApiTags } from "@midwayjs/swagger";
|
||||
|
||||
/**
|
||||
* Addon
|
||||
*/
|
||||
@Provide()
|
||||
@Controller("/api/addon")
|
||||
@ApiTags(['addon'])
|
||||
export class AddonController extends CrudController<AddonService> {
|
||||
@Inject()
|
||||
service: AddonService;
|
||||
@@ -30,7 +32,7 @@ export class AddonController extends CrudController<AddonService> {
|
||||
return this.service;
|
||||
}
|
||||
|
||||
@Post("/page", { summary: Constants.per.authOnly })
|
||||
@Post("/page", { description: Constants.per.authOnly })
|
||||
async page(@Body(ALL) body) {
|
||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
||||
body.query = body.query ?? {};
|
||||
@@ -48,7 +50,7 @@ export class AddonController extends CrudController<AddonService> {
|
||||
return this.ok(res);
|
||||
}
|
||||
|
||||
@Post("/list", { summary: Constants.per.authOnly })
|
||||
@Post("/list", { description: Constants.per.authOnly })
|
||||
async list(@Body(ALL) body) {
|
||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
||||
body.query = body.query ?? {};
|
||||
@@ -57,7 +59,7 @@ export class AddonController extends CrudController<AddonService> {
|
||||
return super.list(body);
|
||||
}
|
||||
|
||||
@Post("/add", { summary: Constants.per.authOnly })
|
||||
@Post("/add", { description: Constants.per.authOnly })
|
||||
async add(@Body(ALL) bean) {
|
||||
const {userId,projectId} = await this.getProjectUserIdRead();
|
||||
bean.userId = userId;
|
||||
@@ -77,7 +79,7 @@ export class AddonController extends CrudController<AddonService> {
|
||||
return super.add(bean);
|
||||
}
|
||||
|
||||
@Post("/update", { summary: Constants.per.authOnly })
|
||||
@Post("/update", { description: Constants.per.authOnly })
|
||||
async update(@Body(ALL) bean) {
|
||||
await this.checkOwner(this.getService(), bean.id, "write");
|
||||
const old = await this.service.info(bean.id);
|
||||
@@ -100,25 +102,25 @@ export class AddonController extends CrudController<AddonService> {
|
||||
return super.update(bean);
|
||||
}
|
||||
|
||||
@Post("/info", { summary: Constants.per.authOnly })
|
||||
@Post("/info", { description: Constants.per.authOnly })
|
||||
async info(@Query("id") id: number) {
|
||||
await this.checkOwner(this.getService(), id, "read");
|
||||
return super.info(id);
|
||||
}
|
||||
|
||||
@Post("/delete", { summary: Constants.per.authOnly })
|
||||
@Post("/delete", { description: Constants.per.authOnly })
|
||||
async delete(@Query("id") id: number) {
|
||||
await this.checkOwner(this.getService(), id, "write");
|
||||
return super.delete(id);
|
||||
}
|
||||
|
||||
@Post("/define", { summary: Constants.per.authOnly })
|
||||
@Post("/define", { description: 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 })
|
||||
@Post("/getTypeDict", { description: Constants.per.authOnly })
|
||||
async getTypeDict(@Query("addonType") addonType: string) {
|
||||
const list: any = this.service.getDefineList(addonType);
|
||||
let dict = [];
|
||||
@@ -136,7 +138,7 @@ export class AddonController extends CrudController<AddonService> {
|
||||
return this.ok(dict);
|
||||
}
|
||||
|
||||
@Post("/simpleInfo", { summary: Constants.per.authOnly })
|
||||
@Post("/simpleInfo", { description: Constants.per.authOnly })
|
||||
async simpleInfo(@Query("addonType") addonType: string, @Query("id") id: number) {
|
||||
if (id === 0) {
|
||||
//获取默认
|
||||
@@ -153,14 +155,14 @@ export class AddonController extends CrudController<AddonService> {
|
||||
return this.ok(res);
|
||||
}
|
||||
|
||||
@Post("/getDefaultId", { summary: Constants.per.authOnly })
|
||||
@Post("/getDefaultId", { description: Constants.per.authOnly })
|
||||
async getDefaultId(@Query("addonType") addonType: string) {
|
||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
||||
const res = await this.service.getDefault(userId, addonType,projectId);
|
||||
return this.ok(res?.id);
|
||||
}
|
||||
|
||||
@Post("/setDefault", { summary: Constants.per.authOnly })
|
||||
@Post("/setDefault", { description: Constants.per.authOnly })
|
||||
async setDefault(@Query("addonType") addonType: string, @Query("id") id: number) {
|
||||
const {projectId,userId} = await this.checkOwner(this.getService(), id, "write",true);
|
||||
const res = await this.service.setDefault(id, userId, addonType,projectId);
|
||||
@@ -168,7 +170,7 @@ export class AddonController extends CrudController<AddonService> {
|
||||
}
|
||||
|
||||
|
||||
@Post("/options", { summary: Constants.per.authOnly })
|
||||
@Post("/options", { description: Constants.per.authOnly })
|
||||
async options(@Query("addonType") addonType: string) {
|
||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
||||
const res = await this.service.list({
|
||||
@@ -185,7 +187,7 @@ export class AddonController extends CrudController<AddonService> {
|
||||
}
|
||||
|
||||
|
||||
@Post("/handle", { summary: Constants.per.authOnly })
|
||||
@Post("/handle", { description: Constants.per.authOnly })
|
||||
async handle(@Body(ALL) body: AddonRequestHandleReq) {
|
||||
let inputAddon = body.input.addon;
|
||||
if (body.input.id > 0) {
|
||||
|
||||
@@ -2,12 +2,14 @@ import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/c
|
||||
import { Constants, CrudController } from '@certd/lib-server';
|
||||
import { AuthService } from '../../../modules/sys/authority/service/auth-service.js';
|
||||
import { GroupService } from '../../../modules/basic/service/group-service.js';
|
||||
import { ApiTags } from '@midwayjs/swagger';
|
||||
|
||||
/**
|
||||
* 通知
|
||||
*/
|
||||
@Provide()
|
||||
@Controller('/api/basic/group')
|
||||
@ApiTags(['basic-group'])
|
||||
export class GroupController extends CrudController<GroupService> {
|
||||
@Inject()
|
||||
service: GroupService;
|
||||
@@ -18,7 +20,7 @@ export class GroupController extends CrudController<GroupService> {
|
||||
return this.service;
|
||||
}
|
||||
|
||||
@Post('/page', { summary: Constants.per.authOnly })
|
||||
@Post('/page', { description: Constants.per.authOnly })
|
||||
async page(@Body(ALL) body: any) {
|
||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
||||
body.query = body.query ?? {};
|
||||
@@ -36,7 +38,7 @@ export class GroupController extends CrudController<GroupService> {
|
||||
return this.ok(res);
|
||||
}
|
||||
|
||||
@Post('/list', { summary: Constants.per.authOnly })
|
||||
@Post('/list', { description: Constants.per.authOnly })
|
||||
async list(@Body(ALL) body: any) {
|
||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
||||
body.query = body.query ?? {};
|
||||
@@ -45,7 +47,7 @@ export class GroupController extends CrudController<GroupService> {
|
||||
return await super.list(body);
|
||||
}
|
||||
|
||||
@Post('/add', { summary: Constants.per.authOnly })
|
||||
@Post('/add', { description: Constants.per.authOnly })
|
||||
async add(@Body(ALL) bean: any) {
|
||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
||||
bean.projectId = projectId;
|
||||
@@ -53,26 +55,26 @@ export class GroupController extends CrudController<GroupService> {
|
||||
return await super.add(bean);
|
||||
}
|
||||
|
||||
@Post('/update', { summary: Constants.per.authOnly })
|
||||
@Post('/update', { description: Constants.per.authOnly })
|
||||
async update(@Body(ALL) bean) {
|
||||
await this.checkOwner(this.getService(), bean.id, "write");
|
||||
delete bean.userId;
|
||||
delete bean.projectId;
|
||||
return await super.update(bean);
|
||||
}
|
||||
@Post('/info', { summary: Constants.per.authOnly })
|
||||
@Post('/info', { description: Constants.per.authOnly })
|
||||
async info(@Query('id') id: number) {
|
||||
await this.checkOwner(this.getService(), id, "read");
|
||||
return await super.info(id);
|
||||
}
|
||||
|
||||
@Post('/delete', { summary: Constants.per.authOnly })
|
||||
@Post('/delete', { description: Constants.per.authOnly })
|
||||
async delete(@Query('id') id: number) {
|
||||
await this.checkOwner(this.getService(), id, "write");
|
||||
return await super.delete(id);
|
||||
}
|
||||
|
||||
@Post('/all', { summary: Constants.per.authOnly })
|
||||
@Post('/all', { description: Constants.per.authOnly })
|
||||
async all(@Query('type') type: string) {
|
||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
||||
const list: any = await this.service.find({
|
||||
|
||||
@@ -4,23 +4,28 @@ import { In } from 'typeorm';
|
||||
import { AuthService } from '../../../modules/sys/authority/service/auth-service.js';
|
||||
import { UserService } from '../../../modules/sys/authority/service/user-service.js';
|
||||
import { BasicController } from '../../basic/code-controller.js';
|
||||
import { RoleService } from '../../../modules/sys/authority/service/role-service.js';
|
||||
import { ApiTags } from '@midwayjs/swagger';
|
||||
|
||||
/**
|
||||
* 通知
|
||||
*/
|
||||
@Provide()
|
||||
@Controller('/api/basic/user')
|
||||
@ApiTags(['basic-user'])
|
||||
export class BasicUserController extends BasicController {
|
||||
@Inject()
|
||||
service: UserService;
|
||||
@Inject()
|
||||
authService: AuthService;
|
||||
@Inject()
|
||||
roleService: RoleService;
|
||||
|
||||
getService(): UserService {
|
||||
return this.service;
|
||||
}
|
||||
|
||||
@Post('/getSimpleUserByIds', { summary: Constants.per.authOnly })
|
||||
@Post('/getSimpleUserByIds', { description: Constants.per.authOnly })
|
||||
async getSimpleUserByIds(@Body('ids') ids: number[]) {
|
||||
if(!isEnterprise()){
|
||||
throw new Error('非企业模式不能获取用户信息');
|
||||
@@ -40,7 +45,7 @@ export class BasicUserController extends BasicController {
|
||||
return this.ok(users);
|
||||
}
|
||||
|
||||
@Post('/getSimpleUsers', {summary: Constants.per.authOnly})
|
||||
@Post('/getSimpleUsers', {description: Constants.per.authOnly})
|
||||
async getSimpleUsers() {
|
||||
if(!isEnterprise()){
|
||||
throw new Error('非企业模式不能获取所有用户信息');
|
||||
@@ -57,4 +62,15 @@ export class BasicUserController extends BasicController {
|
||||
return this.ok(users);
|
||||
}
|
||||
|
||||
@Post('/getSimpleRoles', {description: Constants.per.authOnly})
|
||||
async getSimpleRoles() {
|
||||
const roles = await this.roleService.find({
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
},
|
||||
});
|
||||
return this.ok(roles);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,12 +2,14 @@ import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/c
|
||||
import { Constants, CrudController } from '@certd/lib-server';
|
||||
import { DomainService } from "../../../modules/cert/service/domain-service.js";
|
||||
import { checkPlus } from '@certd/plus-core';
|
||||
import { ApiTags } from '@midwayjs/swagger';
|
||||
|
||||
/**
|
||||
* 授权
|
||||
*/
|
||||
@Provide()
|
||||
@Controller('/api/cert/domain')
|
||||
@ApiTags(['cert'])
|
||||
export class DomainController extends CrudController<DomainService> {
|
||||
@Inject()
|
||||
service: DomainService;
|
||||
@@ -16,7 +18,7 @@ export class DomainController extends CrudController<DomainService> {
|
||||
return this.service;
|
||||
}
|
||||
|
||||
@Post('/page', { summary: Constants.per.authOnly })
|
||||
@Post('/page', { description: Constants.per.authOnly })
|
||||
async page(@Body(ALL) body: any) {
|
||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
||||
body.query = body.query ?? {};
|
||||
@@ -40,7 +42,7 @@ export class DomainController extends CrudController<DomainService> {
|
||||
return this.ok(pageRet);
|
||||
}
|
||||
|
||||
@Post('/list', { summary: Constants.per.authOnly })
|
||||
@Post('/list', { description: Constants.per.authOnly })
|
||||
async list(@Body(ALL) body: any) {
|
||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
||||
body.query = body.query ?? {};
|
||||
@@ -50,7 +52,7 @@ export class DomainController extends CrudController<DomainService> {
|
||||
return this.ok(list);
|
||||
}
|
||||
|
||||
@Post('/add', { summary: Constants.per.authOnly })
|
||||
@Post('/add', { description: Constants.per.authOnly })
|
||||
async add(@Body(ALL) bean: any) {
|
||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
||||
bean.projectId = projectId;
|
||||
@@ -58,7 +60,7 @@ export class DomainController extends CrudController<DomainService> {
|
||||
return super.add(bean);
|
||||
}
|
||||
|
||||
@Post('/update', { summary: Constants.per.authOnly })
|
||||
@Post('/update', { description: Constants.per.authOnly })
|
||||
async update(@Body(ALL) bean: any) {
|
||||
await this.checkOwner(this.getService(), bean.id, "write");
|
||||
delete bean.userId;
|
||||
@@ -66,19 +68,19 @@ export class DomainController extends CrudController<DomainService> {
|
||||
return super.update(bean);
|
||||
}
|
||||
|
||||
@Post('/info', { summary: Constants.per.authOnly })
|
||||
@Post('/info', { description: Constants.per.authOnly })
|
||||
async info(@Query('id') id: number) {
|
||||
await this.checkOwner(this.getService(), id, "read");
|
||||
return super.info(id);
|
||||
}
|
||||
|
||||
@Post('/delete', { summary: Constants.per.authOnly })
|
||||
@Post('/delete', { description: Constants.per.authOnly })
|
||||
async delete(@Query('id') id: number) {
|
||||
await this.checkOwner(this.getService(), id, "write");
|
||||
return super.delete(id);
|
||||
}
|
||||
|
||||
@Post('/deleteByIds', { summary: Constants.per.authOnly })
|
||||
@Post('/deleteByIds', { description: Constants.per.authOnly })
|
||||
async deleteByIds(@Body(ALL) body: any) {
|
||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
||||
await this.service.delete(body.ids, {
|
||||
@@ -89,7 +91,7 @@ export class DomainController extends CrudController<DomainService> {
|
||||
}
|
||||
|
||||
|
||||
@Post('/import/start', { summary: Constants.per.authOnly })
|
||||
@Post('/import/start', { description: Constants.per.authOnly })
|
||||
async importStart(@Body(ALL) body: any) {
|
||||
checkPlus();
|
||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
||||
@@ -103,7 +105,7 @@ export class DomainController extends CrudController<DomainService> {
|
||||
return this.ok();
|
||||
}
|
||||
|
||||
@Post('/import/status', { summary: Constants.per.authOnly })
|
||||
@Post('/import/status', { description: Constants.per.authOnly })
|
||||
async importStatus() {
|
||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
||||
const req = {
|
||||
@@ -115,7 +117,7 @@ export class DomainController extends CrudController<DomainService> {
|
||||
}
|
||||
|
||||
|
||||
@Post('/import/delete', { summary: Constants.per.authOnly })
|
||||
@Post('/import/delete', { description: Constants.per.authOnly })
|
||||
async importDelete(@Body(ALL) body: any) {
|
||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
||||
const { key } = body;
|
||||
@@ -128,7 +130,7 @@ export class DomainController extends CrudController<DomainService> {
|
||||
return this.ok();
|
||||
}
|
||||
|
||||
@Post('/import/save', { summary: Constants.per.authOnly })
|
||||
@Post('/import/save', { description: Constants.per.authOnly })
|
||||
async importSave(@Body(ALL) body: any) {
|
||||
checkPlus();
|
||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
||||
@@ -143,7 +145,7 @@ export class DomainController extends CrudController<DomainService> {
|
||||
}
|
||||
|
||||
|
||||
@Post('/sync/expiration/start', { summary: Constants.per.authOnly })
|
||||
@Post('/sync/expiration/start', { description: Constants.per.authOnly })
|
||||
async syncExpirationStart(@Body(ALL) body: any) {
|
||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
||||
await this.service.startSyncExpirationTask({
|
||||
@@ -152,7 +154,7 @@ export class DomainController extends CrudController<DomainService> {
|
||||
})
|
||||
return this.ok();
|
||||
}
|
||||
@Post('/sync/expiration/status', { summary: Constants.per.authOnly })
|
||||
@Post('/sync/expiration/status', { description: Constants.per.authOnly })
|
||||
async syncExpirationStatus(@Body(ALL) body: any) {
|
||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
||||
const status = await this.service.getSyncExpirationTaskStatus({
|
||||
|
||||
@@ -2,12 +2,14 @@ import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core';
|
||||
import { BaseController, Constants } from '@certd/lib-server';
|
||||
import { CnameRecordService } from '../../../modules/cname/service/cname-record-service.js';
|
||||
import { CnameProviderService } from '../../../modules/cname/service/cname-provider-service.js';
|
||||
import { ApiTags } from '@midwayjs/swagger';
|
||||
|
||||
/**
|
||||
* 授权
|
||||
*/
|
||||
@Provide()
|
||||
@Controller('/api/cname/provider')
|
||||
@ApiTags(['pipeline-cname'])
|
||||
export class CnameProviderController extends BaseController {
|
||||
@Inject()
|
||||
service: CnameRecordService;
|
||||
@@ -18,7 +20,7 @@ export class CnameProviderController extends BaseController {
|
||||
return this.service;
|
||||
}
|
||||
|
||||
@Post('/list', { summary: Constants.per.authOnly })
|
||||
@Post('/list', { description: Constants.per.authOnly })
|
||||
async list(@Body(ALL) body: any) {
|
||||
const res = await this.providerService.list({});
|
||||
return this.ok(res);
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core';
|
||||
import { Constants, CrudController } from '@certd/lib-server';
|
||||
import { CnameRecordService } from '../../../modules/cname/service/cname-record-service.js';
|
||||
import { ApiTags } from '@midwayjs/swagger';
|
||||
|
||||
/**
|
||||
* 授权
|
||||
*/
|
||||
@Provide()
|
||||
@Controller('/api/cname/record')
|
||||
@ApiTags(['pipeline-cname'])
|
||||
export class CnameRecordController extends CrudController<CnameRecordService> {
|
||||
@Inject()
|
||||
service: CnameRecordService;
|
||||
@@ -15,7 +17,7 @@ export class CnameRecordController extends CrudController<CnameRecordService> {
|
||||
return this.service;
|
||||
}
|
||||
|
||||
@Post('/page', { summary: Constants.per.authOnly })
|
||||
@Post('/page', { description: Constants.per.authOnly })
|
||||
async page(@Body(ALL) body: any) {
|
||||
const {userId,projectId} = await this.getProjectUserIdRead();
|
||||
body.query = body.query ?? {};
|
||||
@@ -39,7 +41,7 @@ export class CnameRecordController extends CrudController<CnameRecordService> {
|
||||
return this.ok(pageRet);
|
||||
}
|
||||
|
||||
@Post('/list', { summary: Constants.per.authOnly })
|
||||
@Post('/list', { description: Constants.per.authOnly })
|
||||
async list(@Body(ALL) body: any) {
|
||||
const {userId,projectId} = await this.getProjectUserIdRead();
|
||||
body.query = body.query ?? {};
|
||||
@@ -49,7 +51,7 @@ export class CnameRecordController extends CrudController<CnameRecordService> {
|
||||
return this.ok(list);
|
||||
}
|
||||
|
||||
@Post('/add', { summary: Constants.per.authOnly })
|
||||
@Post('/add', { description: Constants.per.authOnly })
|
||||
async add(@Body(ALL) bean: any) {
|
||||
const {userId,projectId} = await this.getProjectUserIdWrite();
|
||||
bean.userId = userId;
|
||||
@@ -57,7 +59,7 @@ export class CnameRecordController extends CrudController<CnameRecordService> {
|
||||
return super.add(bean);
|
||||
}
|
||||
|
||||
@Post('/update', { summary: Constants.per.authOnly })
|
||||
@Post('/update', { description: Constants.per.authOnly })
|
||||
async update(@Body(ALL) bean: any) {
|
||||
await this.checkOwner(this.getService(), bean.id, "write");
|
||||
delete bean.userId;
|
||||
@@ -65,19 +67,19 @@ export class CnameRecordController extends CrudController<CnameRecordService> {
|
||||
return super.update(bean);
|
||||
}
|
||||
|
||||
@Post('/info', { summary: Constants.per.authOnly })
|
||||
@Post('/info', { description: Constants.per.authOnly })
|
||||
async info(@Query('id') id: number) {
|
||||
await this.checkOwner(this.getService(), id, "read");
|
||||
return super.info(id);
|
||||
}
|
||||
|
||||
@Post('/delete', { summary: Constants.per.authOnly })
|
||||
@Post('/delete', { description: Constants.per.authOnly })
|
||||
async delete(@Query('id') id: number) {
|
||||
await this.checkOwner(this.getService(), id, "write");
|
||||
return super.delete(id);
|
||||
}
|
||||
|
||||
@Post('/deleteByIds', { summary: Constants.per.authOnly })
|
||||
@Post('/deleteByIds', { description: Constants.per.authOnly })
|
||||
async deleteByIds(@Body(ALL) body: any) {
|
||||
const {userId,projectId} = await this.getProjectUserIdWrite();
|
||||
await this.service.delete(body.ids, {
|
||||
@@ -86,27 +88,27 @@ export class CnameRecordController extends CrudController<CnameRecordService> {
|
||||
});
|
||||
return this.ok();
|
||||
}
|
||||
@Post('/getByDomain', { summary: Constants.per.authOnly })
|
||||
@Post('/getByDomain', { description: Constants.per.authOnly })
|
||||
async getByDomain(@Body(ALL) body: { domain: string; createOnNotFound: boolean }) {
|
||||
const {userId,projectId} = await this.getProjectUserIdRead();
|
||||
const res = await this.service.getByDomain(body.domain, userId,projectId, body.createOnNotFound);
|
||||
return this.ok(res);
|
||||
}
|
||||
|
||||
@Post('/verify', { summary: Constants.per.authOnly })
|
||||
@Post('/verify', { description: Constants.per.authOnly })
|
||||
async verify(@Body(ALL) body: { id: number }) {
|
||||
await this.checkOwner(this.getService(), body.id, "read");
|
||||
const res = await this.service.verify(body.id);
|
||||
return this.ok(res);
|
||||
}
|
||||
|
||||
@Post('/resetStatus', { summary: Constants.per.authOnly })
|
||||
@Post('/resetStatus', { description: Constants.per.authOnly })
|
||||
async resetStatus(@Body(ALL) body: { id: number }) {
|
||||
await this.checkOwner(this.getService(), body.id, "read");
|
||||
const res = await this.service.resetStatus(body.id);
|
||||
return this.ok(res);
|
||||
}
|
||||
@Post('/import', { summary: Constants.per.authOnly })
|
||||
@Post('/import', { description: Constants.per.authOnly })
|
||||
async import(@Body(ALL) body: { domainList: string; cnameProviderId: any }) {
|
||||
const {userId,projectId} = await this.getProjectUserIdWrite();
|
||||
const res = await this.service.doImport({
|
||||
|
||||
@@ -5,6 +5,7 @@ import { RoleService } from '../../../modules/sys/authority/service/role-service
|
||||
import { PipelineService } from '../../../modules/pipeline/service/pipeline-service.js';
|
||||
import { HistoryService } from '../../../modules/pipeline/service/history-service.js';
|
||||
import { CertInfoService } from '../../../modules/monitor/index.js';
|
||||
import { ApiTags } from '@midwayjs/swagger';
|
||||
|
||||
export type ChartItem = {
|
||||
name: string;
|
||||
@@ -30,6 +31,7 @@ export type UserStatisticCount = {
|
||||
*/
|
||||
@Provide()
|
||||
@Controller('/api/statistic/')
|
||||
@ApiTags(['dashboard'])
|
||||
export class StatisticController extends BaseController {
|
||||
@Inject()
|
||||
userService: UserService;
|
||||
@@ -44,7 +46,7 @@ export class StatisticController extends BaseController {
|
||||
@Inject()
|
||||
certInfoService: CertInfoService;
|
||||
|
||||
@Post('/count', { summary: Constants.per.authOnly })
|
||||
@Post('/count', { description: Constants.per.authOnly })
|
||||
public async count() {
|
||||
const {userId,projectId} = await this.getProjectUserIdRead();
|
||||
const pipelineCount = await this.pipelineService.count({ userId,projectId });
|
||||
|
||||
@@ -3,11 +3,13 @@ import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core';
|
||||
import { AuthService } from '../../../modules/sys/authority/service/auth-service.js';
|
||||
import { ProjectService } from '../../../modules/sys/enterprise/service/project-service.js';
|
||||
import { ProjectMemberService } from '../../../modules/sys/enterprise/service/project-member-service.js';
|
||||
import { ApiTags } from '@midwayjs/swagger';
|
||||
|
||||
/**
|
||||
*/
|
||||
@Provide()
|
||||
@Controller('/api/enterprise/project')
|
||||
@ApiTags(['enterprise-project'])
|
||||
export class UserProjectController extends BaseController {
|
||||
@Inject()
|
||||
service: ProjectService;
|
||||
@@ -26,7 +28,7 @@ export class UserProjectController extends BaseController {
|
||||
* @param body
|
||||
* @returns
|
||||
*/
|
||||
@Post('/detail', { summary: Constants.per.authOnly })
|
||||
@Post('/detail', { description: Constants.per.authOnly })
|
||||
async detail(@Body(ALL) body: any) {
|
||||
const {projectId} = await this.getProjectUserIdRead();
|
||||
const res = await this.service.getDetail(projectId,this.getUserId());
|
||||
@@ -39,7 +41,7 @@ export class UserProjectController extends BaseController {
|
||||
* @param body
|
||||
* @returns
|
||||
*/
|
||||
@Post('/list', { summary: Constants.per.authOnly })
|
||||
@Post('/list', { description: Constants.per.authOnly })
|
||||
async list(@Body(ALL) body: any) {
|
||||
const userId= this.getUserId();
|
||||
const res = await this.service.getUserProjects(userId);
|
||||
@@ -52,21 +54,21 @@ export class UserProjectController extends BaseController {
|
||||
* @param body 所有项目
|
||||
* @returns
|
||||
*/
|
||||
@Post('/all', { summary: Constants.per.authOnly })
|
||||
@Post('/all', { description: Constants.per.authOnly })
|
||||
async all(@Body(ALL) body: any) {
|
||||
const userId= this.getUserId();
|
||||
const res = await this.service.getAllWithStatus(userId);
|
||||
return this.ok(res);
|
||||
}
|
||||
|
||||
@Post('/applyJoin', { summary: Constants.per.authOnly })
|
||||
@Post('/applyJoin', { description: Constants.per.authOnly })
|
||||
async applyJoin(@Body(ALL) body: any) {
|
||||
const userId= this.getUserId();
|
||||
const res = await this.service.applyJoin({ userId, projectId: body.projectId });
|
||||
return this.ok(res);
|
||||
}
|
||||
|
||||
@Post('/updateMember', { summary: Constants.per.authOnly })
|
||||
@Post('/updateMember', { description: Constants.per.authOnly })
|
||||
async updateMember(@Body(ALL) body: any) {
|
||||
const {projectId} = await this.getProjectUserIdAdmin();
|
||||
const {status,permission,userId} = body;
|
||||
@@ -87,7 +89,7 @@ export class UserProjectController extends BaseController {
|
||||
return this.ok(res);
|
||||
}
|
||||
|
||||
@Post('/approveJoin', { summary: Constants.per.authOnly })
|
||||
@Post('/approveJoin', { description: Constants.per.authOnly })
|
||||
async approveJoin(@Body(ALL) body: any) {
|
||||
const {projectId} = await this.getProjectUserIdAdmin();
|
||||
const {status,permission,userId} = body;
|
||||
@@ -95,7 +97,7 @@ export class UserProjectController extends BaseController {
|
||||
return this.ok(res);
|
||||
}
|
||||
|
||||
@Post('/delete', { summary: Constants.per.authOnly })
|
||||
@Post('/delete', { description: Constants.per.authOnly })
|
||||
async delete(@Body(ALL) body: any) {
|
||||
const {projectId} = await this.getProjectUserIdAdmin();
|
||||
await this.projectMemberService.deleteWhere({
|
||||
@@ -105,7 +107,7 @@ export class UserProjectController extends BaseController {
|
||||
return this.ok();
|
||||
}
|
||||
|
||||
@Post('/leave', { summary: Constants.per.authOnly })
|
||||
@Post('/leave', { description: Constants.per.authOnly })
|
||||
async leave(@Body(ALL) body: any) {
|
||||
const {projectId} = body
|
||||
const userId = this.getUserId();
|
||||
|
||||
+9
-7
@@ -4,10 +4,12 @@ import { ProjectMemberEntity } from "../../../modules/sys/enterprise/entity/proj
|
||||
import { ProjectMemberService } from "../../../modules/sys/enterprise/service/project-member-service.js";
|
||||
import { merge } from "lodash-es";
|
||||
import { ProjectService } from "../../../modules/sys/enterprise/service/project-service.js";
|
||||
import { ApiTags } from "@midwayjs/swagger";
|
||||
/**
|
||||
*/
|
||||
@Provide()
|
||||
@Controller("/api/enterprise/projectMember")
|
||||
@ApiTags(['enterprise-project-member'])
|
||||
export class ProjectMemberController extends CrudController<ProjectMemberEntity> {
|
||||
@Inject()
|
||||
service: ProjectMemberService;
|
||||
@@ -22,7 +24,7 @@ export class ProjectMemberController extends CrudController<ProjectMemberEntity>
|
||||
return this.service;
|
||||
}
|
||||
|
||||
@Post("/page", { summary: Constants.per.authOnly })
|
||||
@Post("/page", { description: Constants.per.authOnly })
|
||||
async page(@Body(ALL) body: any) {
|
||||
const {projectId} = await this.getProjectUserIdRead();
|
||||
body.query = body.query ?? {};
|
||||
@@ -30,7 +32,7 @@ export class ProjectMemberController extends CrudController<ProjectMemberEntity>
|
||||
return await super.page(body);
|
||||
}
|
||||
|
||||
@Post("/list", { summary: Constants.per.authOnly })
|
||||
@Post("/list", { description: Constants.per.authOnly })
|
||||
async list(@Body(ALL) body: any) {
|
||||
const {projectId} = await this.getProjectUserIdRead();
|
||||
body.query = body.query ?? {};
|
||||
@@ -38,7 +40,7 @@ export class ProjectMemberController extends CrudController<ProjectMemberEntity>
|
||||
return super.list(body);
|
||||
}
|
||||
|
||||
@Post("/add", { summary: Constants.per.authOnly })
|
||||
@Post("/add", { description: Constants.per.authOnly })
|
||||
async add(@Body(ALL) bean: any) {
|
||||
const def: any = {
|
||||
isDefault: false,
|
||||
@@ -54,7 +56,7 @@ export class ProjectMemberController extends CrudController<ProjectMemberEntity>
|
||||
return super.add(bean);
|
||||
}
|
||||
|
||||
@Post("/update", { summary: Constants.per.authOnly })
|
||||
@Post("/update", { description: Constants.per.authOnly })
|
||||
async update(@Body(ALL) bean: any) {
|
||||
if (!bean.id) {
|
||||
throw new Error("id is required");
|
||||
@@ -73,7 +75,7 @@ export class ProjectMemberController extends CrudController<ProjectMemberEntity>
|
||||
return this.ok(res);
|
||||
}
|
||||
|
||||
@Post("/info", { summary: Constants.per.authOnly })
|
||||
@Post("/info", { description: Constants.per.authOnly })
|
||||
async info(@Query("id") id: number) {
|
||||
if (!id) {
|
||||
throw new Error("id is required");
|
||||
@@ -86,7 +88,7 @@ export class ProjectMemberController extends CrudController<ProjectMemberEntity>
|
||||
return super.info(id);
|
||||
}
|
||||
|
||||
@Post("/delete", { summary: Constants.per.authOnly })
|
||||
@Post("/delete", { description: Constants.per.authOnly })
|
||||
async delete(@Query("id") id: number) {
|
||||
if (!id) {
|
||||
throw new Error("id is required");
|
||||
@@ -99,7 +101,7 @@ export class ProjectMemberController extends CrudController<ProjectMemberEntity>
|
||||
return super.delete(id);
|
||||
}
|
||||
|
||||
@Post("/deleteByIds", { summary: Constants.per.authOnly })
|
||||
@Post("/deleteByIds", { description: Constants.per.authOnly })
|
||||
async deleteByIds(@Body("ids") ids: number[]) {
|
||||
for (const id of ids) {
|
||||
if (!id) {
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { BaseController, Constants } from '@certd/lib-server';
|
||||
import { Controller, Inject, Post, Provide } from '@midwayjs/core';
|
||||
import { TransferService } from '../../../modules/sys/enterprise/service/transfer-service.js';
|
||||
import { ApiTags } from '@midwayjs/swagger';
|
||||
|
||||
/**
|
||||
*/
|
||||
@Provide()
|
||||
@Controller('/api/enterprise/transfer')
|
||||
@ApiTags(['enterprise-project'])
|
||||
export class TransferController extends BaseController {
|
||||
@Inject()
|
||||
service: TransferService;
|
||||
@@ -20,7 +22,7 @@ export class TransferController extends BaseController {
|
||||
* @param body
|
||||
* @returns
|
||||
*/
|
||||
@Post('/selfResources', { summary: Constants.per.authOnly })
|
||||
@Post('/selfResources', { description: Constants.per.authOnly })
|
||||
async selfResources() {
|
||||
const userId = this.getUserId();
|
||||
const res = await this.service.getUserResources(userId);
|
||||
@@ -32,7 +34,7 @@ export class TransferController extends BaseController {
|
||||
* @param body
|
||||
* @returns
|
||||
*/
|
||||
@Post('/doTransfer', { summary: Constants.per.authOnly })
|
||||
@Post('/doTransfer', { description: Constants.per.authOnly })
|
||||
async doTransfer() {
|
||||
const {projectId} = await this.getProjectUserIdRead();
|
||||
const userId = this.getUserId();
|
||||
|
||||
@@ -2,37 +2,39 @@ import { Body, Controller, Inject, Post, Provide } from '@midwayjs/core';
|
||||
import { BaseController } from '@certd/lib-server';
|
||||
import { Constants } from '@certd/lib-server';
|
||||
import { EmailService } from '../../../modules/basic/service/email-service.js';
|
||||
import { ApiTags } from '@midwayjs/swagger';
|
||||
|
||||
/**
|
||||
*/
|
||||
@Provide()
|
||||
@Controller('/api/mine/email')
|
||||
@ApiTags(['mine'])
|
||||
export class EmailController extends BaseController {
|
||||
@Inject()
|
||||
emailService: EmailService;
|
||||
|
||||
@Post('/test', { summary: Constants.per.authOnly })
|
||||
@Post('/test', { description: Constants.per.authOnly })
|
||||
public async test(@Body('receiver') receiver) {
|
||||
const userId = super.getUserId();
|
||||
await this.emailService.test(userId, receiver);
|
||||
return this.ok({});
|
||||
}
|
||||
|
||||
@Post('/list', { summary: Constants.per.authOnly })
|
||||
@Post('/list', { description: Constants.per.authOnly })
|
||||
public async list() {
|
||||
const userId = super.getUserId();
|
||||
const res = await this.emailService.list(userId);
|
||||
return this.ok(res);
|
||||
}
|
||||
|
||||
@Post('/add', { summary: Constants.per.authOnly })
|
||||
@Post('/add', { description: Constants.per.authOnly })
|
||||
public async add(@Body('email') email) {
|
||||
const userId = super.getUserId();
|
||||
await this.emailService.add(userId, email);
|
||||
return this.ok({});
|
||||
}
|
||||
|
||||
@Post('/delete', { summary: Constants.per.authOnly })
|
||||
@Post('/delete', { description: Constants.per.authOnly })
|
||||
public async delete(@Body('email') email) {
|
||||
const userId = super.getUserId();
|
||||
await this.emailService.delete(userId, email);
|
||||
|
||||
@@ -1,18 +1,27 @@
|
||||
import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core';
|
||||
import { BaseController, Constants } from '@certd/lib-server';
|
||||
import { UserService } from '../../../modules/sys/authority/service/user-service.js';
|
||||
import { ALL, Body, Controller, Inject, Post, Provide } from '@midwayjs/core';
|
||||
import { PasskeyService } from '../../../modules/login/service/passkey-service.js';
|
||||
import { RoleService } from '../../../modules/sys/authority/service/role-service.js';
|
||||
import { UserService } from '../../../modules/sys/authority/service/user-service.js';
|
||||
import { ApiTags } from '@midwayjs/swagger';
|
||||
|
||||
/**
|
||||
*/
|
||||
@Provide()
|
||||
@Controller('/api/mine')
|
||||
@ApiTags(['mine'])
|
||||
export class MineController extends BaseController {
|
||||
@Inject()
|
||||
userService: UserService;
|
||||
|
||||
@Inject()
|
||||
roleService: RoleService;
|
||||
@Post('/info', { summary: Constants.per.authOnly })
|
||||
|
||||
@Inject()
|
||||
passkeyService: PasskeyService;
|
||||
|
||||
|
||||
@Post('/info', { description: Constants.per.authOnly })
|
||||
public async info() {
|
||||
const userId = this.getUserId();
|
||||
const user = await this.userService.info(userId);
|
||||
@@ -26,14 +35,14 @@ export class MineController extends BaseController {
|
||||
return this.ok(user);
|
||||
}
|
||||
|
||||
@Post('/changePassword', { summary: Constants.per.authOnly })
|
||||
@Post('/changePassword', { description: Constants.per.authOnly })
|
||||
public async changePassword(@Body(ALL) body: any) {
|
||||
const userId = this.getUserId();
|
||||
await this.userService.changePassword(userId, body);
|
||||
return this.ok({});
|
||||
}
|
||||
|
||||
@Post('/updateProfile', { summary: Constants.per.authOnly })
|
||||
@Post('/updateProfile', { description: Constants.per.authOnly })
|
||||
public async updateProfile(@Body(ALL) body: any) {
|
||||
const userId = this.getUserId();
|
||||
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
import { ALL, Body, Controller, Inject, Post, Provide, RequestIP } from "@midwayjs/core";
|
||||
import { PasskeyService } from "../../../modules/login/service/passkey-service.js";
|
||||
import { BaseController, Constants } from "@certd/lib-server";
|
||||
import { UserService } from "../../../modules/sys/authority/service/user-service.js";
|
||||
import { ApiTags } from "@midwayjs/swagger";
|
||||
|
||||
@Provide()
|
||||
@Controller('/api/mine/passkey')
|
||||
@ApiTags(['mine'])
|
||||
export class MinePasskeyController extends BaseController {
|
||||
@Inject()
|
||||
passkeyService: PasskeyService;
|
||||
|
||||
@Inject()
|
||||
userService: UserService;
|
||||
|
||||
@Post('/generateRegistration', { description: Constants.per.authOnly })
|
||||
public async generateRegistration(
|
||||
@Body(ALL)
|
||||
body: any,
|
||||
@RequestIP()
|
||||
remoteIp: string
|
||||
) {
|
||||
const userId = this.getUserId()
|
||||
const user = await this.userService.info(userId);
|
||||
|
||||
if (!user) {
|
||||
throw new Error('用户不存在');
|
||||
}
|
||||
|
||||
const options = await this.passkeyService.generateRegistrationOptions(
|
||||
userId,
|
||||
user.username,
|
||||
remoteIp,
|
||||
this.ctx
|
||||
);
|
||||
|
||||
return this.ok({
|
||||
...options,
|
||||
userId
|
||||
});
|
||||
}
|
||||
|
||||
@Post('/verifyRegistration', { description: Constants.per.authOnly })
|
||||
public async verifyRegistration(
|
||||
@Body(ALL)
|
||||
body: any
|
||||
) {
|
||||
const userId = this.getUserId()
|
||||
const response = body.response;
|
||||
const challenge = body.challenge;
|
||||
const deviceName = body.deviceName;
|
||||
|
||||
const result = await this.passkeyService.registerPasskey(
|
||||
userId,
|
||||
response,
|
||||
challenge,
|
||||
deviceName,
|
||||
this.ctx
|
||||
);
|
||||
|
||||
return this.ok(result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Post('/register', { description: Constants.per.authOnly })
|
||||
public async registerPasskey(
|
||||
@Body(ALL)
|
||||
body: any
|
||||
) {
|
||||
const userId = this.getUserId();
|
||||
const response = body.response;
|
||||
const deviceName = body.deviceName;
|
||||
const challenge = body.challenge;
|
||||
|
||||
const result = await this.passkeyService.registerPasskey(
|
||||
userId,
|
||||
response,
|
||||
challenge,
|
||||
deviceName,
|
||||
this.ctx
|
||||
);
|
||||
|
||||
return this.ok(result);
|
||||
}
|
||||
|
||||
|
||||
@Post('/list', { description: Constants.per.authOnly })
|
||||
public async getPasskeys() {
|
||||
const userId = this.getUserId();
|
||||
const passkeys = await this.passkeyService.find({
|
||||
select: ['id', 'deviceName', 'registeredAt', 'transports', 'passkeyId' ,'updateTime'],
|
||||
where: { userId },
|
||||
order: { registeredAt: 'DESC' },
|
||||
});
|
||||
return this.ok(passkeys);
|
||||
}
|
||||
|
||||
@Post('/unbind', { description: Constants.per.authOnly })
|
||||
public async unbindPasskey(@Body(ALL) body: any) {
|
||||
const userId = this.getUserId();
|
||||
const passkeyId = body.id;
|
||||
|
||||
const passkey = await this.passkeyService.findOne({
|
||||
where: { id: passkeyId, userId },
|
||||
});
|
||||
|
||||
if (!passkey) {
|
||||
throw new Error('Passkey不存在');
|
||||
}
|
||||
|
||||
await this.passkeyService.delete([passkey.id]);
|
||||
return this.ok({});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,11 +5,13 @@ import { UserTwoFactorSetting } from "../../../modules/mine/service/models.js";
|
||||
import { merge } from "lodash-es";
|
||||
import { TwoFactorService } from "../../../modules/mine/service/two-factor-service.js";
|
||||
import {isPlus} from "@certd/plus-core";
|
||||
import { ApiTags } from "@midwayjs/swagger";
|
||||
|
||||
/**
|
||||
*/
|
||||
@Provide()
|
||||
@Controller("/api/user/settings/twoFactor")
|
||||
@ApiTags(['mine'])
|
||||
export class UserTwoFactorSettingController extends BaseController {
|
||||
@Inject()
|
||||
service: UserSettingsService;
|
||||
@@ -19,14 +21,14 @@ export class UserTwoFactorSettingController extends BaseController {
|
||||
|
||||
|
||||
|
||||
@Post("/get", { summary: Constants.per.authOnly })
|
||||
@Post("/get", { description: Constants.per.authOnly })
|
||||
async get() {
|
||||
const userId = this.getUserId();
|
||||
const setting = await this.service.getSetting<UserTwoFactorSetting>(userId,null, UserTwoFactorSetting);
|
||||
return this.ok(setting);
|
||||
}
|
||||
|
||||
@Post("/save", { summary: Constants.per.authOnly })
|
||||
@Post("/save", { description: Constants.per.authOnly })
|
||||
async save(@Body(ALL) bean: any) {
|
||||
if (!isPlus()) {
|
||||
throw new Error('本功能需要开通专业版')
|
||||
@@ -45,14 +47,14 @@ export class UserTwoFactorSettingController extends BaseController {
|
||||
return this.ok({});
|
||||
}
|
||||
|
||||
@Post("/authenticator/qrcode", { summary: Constants.per.authOnly })
|
||||
@Post("/authenticator/qrcode", { description: Constants.per.authOnly })
|
||||
async authenticatorQrcode() {
|
||||
const userId = this.getUserId();
|
||||
const {qrcode,link,secret} = await this.twoFactorService.getAuthenticatorQrCode(userId);
|
||||
return this.ok({qrcode,link,secret});
|
||||
}
|
||||
|
||||
@Post("/authenticator/save", { summary: Constants.per.authOnly })
|
||||
@Post("/authenticator/save", { description: Constants.per.authOnly })
|
||||
async authenticatorSave(@Body(ALL) bean: any) {
|
||||
if (!isPlus()) {
|
||||
throw new Error('本功能需要开通专业版')
|
||||
@@ -65,7 +67,7 @@ export class UserTwoFactorSettingController extends BaseController {
|
||||
return this.ok();
|
||||
}
|
||||
|
||||
@Post("/authenticator/off", { summary: Constants.per.authOnly })
|
||||
@Post("/authenticator/off", { description: Constants.per.authOnly })
|
||||
async authenticatorOff() {
|
||||
const userId = this.getUserId();
|
||||
await this.twoFactorService.offAuthenticator(userId);
|
||||
|
||||
@@ -5,11 +5,13 @@ import { UserSettingsEntity } from "../../../modules/mine/entity/user-settings.j
|
||||
import { UserGrantSetting } from "../../../modules/mine/service/models.js";
|
||||
import { isPlus } from "@certd/plus-core";
|
||||
import { merge } from "lodash-es";
|
||||
import { ApiTags } from "@midwayjs/swagger";
|
||||
|
||||
/**
|
||||
*/
|
||||
@Provide()
|
||||
@Controller('/api/user/settings')
|
||||
@ApiTags(['mine'])
|
||||
export class UserSettingsController extends CrudController<UserSettingsService> {
|
||||
@Inject()
|
||||
service: UserSettingsService;
|
||||
@@ -18,65 +20,65 @@ export class UserSettingsController extends CrudController<UserSettingsService>
|
||||
return this.service;
|
||||
}
|
||||
|
||||
@Post('/page', { summary: Constants.per.authOnly })
|
||||
@Post('/page', { description: Constants.per.authOnly })
|
||||
async page(@Body(ALL) body) {
|
||||
body.query = body.query ?? {};
|
||||
body.query.userId = this.getUserId();
|
||||
return super.page(body);
|
||||
}
|
||||
|
||||
@Post('/list', { summary: Constants.per.authOnly })
|
||||
@Post('/list', { description: 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 })
|
||||
@Post('/add', { description: Constants.per.authOnly })
|
||||
async add(@Body(ALL) bean) {
|
||||
bean.userId = this.getUserId();
|
||||
return super.add(bean);
|
||||
}
|
||||
|
||||
@Post('/update', { summary: Constants.per.authOnly })
|
||||
@Post('/update', { description: Constants.per.authOnly })
|
||||
async update(@Body(ALL) bean) {
|
||||
await this.service.checkUserId(bean.id, this.getUserId());
|
||||
delete bean.userId;
|
||||
return super.update(bean);
|
||||
}
|
||||
@Post('/info', { summary: Constants.per.authOnly })
|
||||
@Post('/info', { description: 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 })
|
||||
@Post('/delete', { description: Constants.per.authOnly })
|
||||
async delete(@Query('id') id: number) {
|
||||
await this.service.checkUserId(id, this.getUserId());
|
||||
return super.delete(id);
|
||||
}
|
||||
|
||||
@Post('/save', { summary: Constants.per.authOnly })
|
||||
@Post('/save', { description: Constants.per.authOnly })
|
||||
async save(@Body(ALL) bean: UserSettingsEntity) {
|
||||
bean.userId = this.getUserId();
|
||||
await this.service.save(bean);
|
||||
return this.ok({});
|
||||
}
|
||||
|
||||
@Post('/get', { summary: Constants.per.authOnly })
|
||||
@Post('/get', { description: Constants.per.authOnly })
|
||||
async get(@Query('key') key: string) {
|
||||
const {projectId,userId} = await this.getProjectUserIdRead();
|
||||
const entity = await this.service.getByKey(key, userId, projectId);
|
||||
return this.ok(entity);
|
||||
}
|
||||
@Post("/grant/get", { summary: Constants.per.authOnly })
|
||||
@Post("/grant/get", { description: Constants.per.authOnly })
|
||||
async grantSettingsGet() {
|
||||
const userId = this.getUserId();
|
||||
const setting = await this.service.getSetting<UserGrantSetting>(userId, null, UserGrantSetting);
|
||||
return this.ok(setting);
|
||||
}
|
||||
|
||||
@Post("/grant/save", { summary: Constants.per.authOnly })
|
||||
@Post("/grant/save", { description: Constants.per.authOnly })
|
||||
async grantSettingsSave(@Body(ALL) bean: UserGrantSetting) {
|
||||
if (!isPlus()) {
|
||||
throw new Error('本功能需要开通专业版')
|
||||
|
||||
@@ -7,11 +7,13 @@ import { SelectQueryBuilder } from "typeorm";
|
||||
import { logger } from "@certd/basic";
|
||||
import fs from "fs";
|
||||
import dayjs from "dayjs";
|
||||
import { ApiTags } from "@midwayjs/swagger";
|
||||
|
||||
/**
|
||||
*/
|
||||
@Provide()
|
||||
@Controller('/api/monitor/cert')
|
||||
@ApiTags(['cert'])
|
||||
export class CertInfoController extends CrudController<CertInfoService> {
|
||||
@Inject()
|
||||
service: CertInfoService;
|
||||
@@ -27,7 +29,7 @@ export class CertInfoController extends CrudController<CertInfoService> {
|
||||
return this.service;
|
||||
}
|
||||
|
||||
@Post('/page', { summary: Constants.per.authOnly })
|
||||
@Post('/page', { description: Constants.per.authOnly })
|
||||
async page(@Body(ALL) body: any) {
|
||||
body.query = body.query ?? {};
|
||||
|
||||
@@ -76,7 +78,7 @@ export class CertInfoController extends CrudController<CertInfoService> {
|
||||
return this.ok(res);
|
||||
}
|
||||
|
||||
@Post('/list', { summary: Constants.per.authOnly })
|
||||
@Post('/list', { description: Constants.per.authOnly })
|
||||
async list(@Body(ALL) body: any) {
|
||||
body.query = body.query ?? {};
|
||||
const { projectId, userId } = await this.getProjectUserIdRead()
|
||||
@@ -86,7 +88,7 @@ export class CertInfoController extends CrudController<CertInfoService> {
|
||||
}
|
||||
|
||||
|
||||
@Post('/getOptionsByIds', { summary: Constants.per.authOnly })
|
||||
@Post('/getOptionsByIds', { description: Constants.per.authOnly })
|
||||
async getOptionsByIds(@Body(ALL) body: {ids:any[]}) {
|
||||
const { projectId, userId } = await this.getProjectUserIdRead()
|
||||
const list = await this.service.list({
|
||||
@@ -111,7 +113,7 @@ export class CertInfoController extends CrudController<CertInfoService> {
|
||||
return this.ok(safeList);
|
||||
}
|
||||
|
||||
@Post('/add', { summary: Constants.per.authOnly })
|
||||
@Post('/add', { description: Constants.per.authOnly })
|
||||
async add(@Body(ALL) bean: any) {
|
||||
const { projectId, userId } = await this.getProjectUserIdWrite()
|
||||
bean.projectId = projectId
|
||||
@@ -119,26 +121,26 @@ export class CertInfoController extends CrudController<CertInfoService> {
|
||||
return await super.add(bean);
|
||||
}
|
||||
|
||||
@Post('/update', { summary: Constants.per.authOnly })
|
||||
@Post('/update', { description: Constants.per.authOnly })
|
||||
async update(@Body(ALL) bean) {
|
||||
await this.checkOwner(this.service,bean.id,"write");
|
||||
delete bean.userId;
|
||||
delete bean.projectId;
|
||||
return await super.update(bean);
|
||||
}
|
||||
@Post('/info', { summary: Constants.per.authOnly })
|
||||
@Post('/info', { description: Constants.per.authOnly })
|
||||
async info(@Query('id') id: number) {
|
||||
await this.checkOwner(this.service,id,"read");
|
||||
return await super.info(id);
|
||||
}
|
||||
|
||||
@Post('/delete', { summary: Constants.per.authOnly })
|
||||
@Post('/delete', { description: Constants.per.authOnly })
|
||||
async delete(@Query('id') id: number) {
|
||||
await this.checkOwner(this.service,id,"write");
|
||||
return await super.delete(id);
|
||||
}
|
||||
|
||||
@Post('/all', { summary: Constants.per.authOnly })
|
||||
@Post('/all', { description: Constants.per.authOnly })
|
||||
async all() {
|
||||
const { projectId, userId } = await this.getProjectUserIdRead()
|
||||
const list: any = await this.service.find({
|
||||
@@ -152,7 +154,7 @@ export class CertInfoController extends CrudController<CertInfoService> {
|
||||
|
||||
|
||||
|
||||
@Post('/getCert', { summary: Constants.per.authOnly })
|
||||
@Post('/getCert', { description: Constants.per.authOnly })
|
||||
async getCert(@Query('id') id: number) {
|
||||
await this.checkOwner(this.getService(),id,"read");
|
||||
const certInfoEntity = await this.service.info(id);
|
||||
@@ -160,7 +162,7 @@ export class CertInfoController extends CrudController<CertInfoService> {
|
||||
return this.ok(certInfo);
|
||||
}
|
||||
|
||||
@Get('/download', { summary: Constants.per.authOnly })
|
||||
@Get('/download', { description: Constants.per.authOnly })
|
||||
async download(@Query('id') id: number) {
|
||||
const {userId,projectId} =await this.checkOwner(this.getService(),id,"read");
|
||||
const certInfo = await this.getService().info(id)
|
||||
|
||||
@@ -6,11 +6,13 @@ import { UserSiteMonitorSetting } from "../../../modules/mine/service/models.js"
|
||||
import { merge } from "lodash-es";
|
||||
import {SiteIpService} from "../../../modules/monitor/service/site-ip-service.js";
|
||||
import { utils } from "@certd/basic";
|
||||
import { ApiTags } from "@midwayjs/swagger";
|
||||
|
||||
/**
|
||||
*/
|
||||
@Provide()
|
||||
@Controller('/api/monitor/site')
|
||||
@ApiTags(['monitor'])
|
||||
export class SiteInfoController extends CrudController<SiteInfoService> {
|
||||
@Inject()
|
||||
service: SiteInfoService;
|
||||
@@ -23,7 +25,7 @@ export class SiteInfoController extends CrudController<SiteInfoService> {
|
||||
return this.service;
|
||||
}
|
||||
|
||||
@Post('/page', { summary: Constants.per.authOnly })
|
||||
@Post('/page', { description: Constants.per.authOnly })
|
||||
async page(@Body(ALL) body: any) {
|
||||
body.query = body.query ?? {};
|
||||
const { projectId, userId } = await this.getProjectUserIdRead()
|
||||
@@ -54,7 +56,7 @@ export class SiteInfoController extends CrudController<SiteInfoService> {
|
||||
return this.ok(res);
|
||||
}
|
||||
|
||||
@Post('/list', { summary: Constants.per.authOnly })
|
||||
@Post('/list', { description: Constants.per.authOnly })
|
||||
async list(@Body(ALL) body: any) {
|
||||
body.query = body.query ?? {};
|
||||
const { projectId, userId } = await this.getProjectUserIdRead()
|
||||
@@ -63,7 +65,7 @@ export class SiteInfoController extends CrudController<SiteInfoService> {
|
||||
return await super.list(body);
|
||||
}
|
||||
|
||||
@Post('/add', { summary: Constants.per.authOnly })
|
||||
@Post('/add', { description: Constants.per.authOnly })
|
||||
async add(@Body(ALL) bean: any) {
|
||||
const { projectId, userId } = await this.getProjectUserIdWrite()
|
||||
bean.projectId = projectId
|
||||
@@ -76,7 +78,7 @@ export class SiteInfoController extends CrudController<SiteInfoService> {
|
||||
return this.ok(res);
|
||||
}
|
||||
|
||||
@Post('/update', { summary: Constants.per.authOnly })
|
||||
@Post('/update', { description: Constants.per.authOnly })
|
||||
async update(@Body(ALL) bean) {
|
||||
await this.checkOwner(this.service,bean.id,"write");
|
||||
delete bean.userId;
|
||||
@@ -88,27 +90,27 @@ export class SiteInfoController extends CrudController<SiteInfoService> {
|
||||
}
|
||||
return this.ok();
|
||||
}
|
||||
@Post('/info', { summary: Constants.per.authOnly })
|
||||
@Post('/info', { description: Constants.per.authOnly })
|
||||
async info(@Query('id') id: number) {
|
||||
await this.checkOwner(this.service,id,"read");
|
||||
return await super.info(id);
|
||||
}
|
||||
|
||||
@Post('/delete', { summary: Constants.per.authOnly })
|
||||
@Post('/delete', { description: Constants.per.authOnly })
|
||||
async delete(@Query('id') id: number) {
|
||||
await this.checkOwner(this.service,id,"write");
|
||||
return await super.delete(id);
|
||||
}
|
||||
|
||||
|
||||
@Post('/batchDelete', { summary: Constants.per.authOnly })
|
||||
@Post('/batchDelete', { description: Constants.per.authOnly })
|
||||
async batchDelete(@Body(ALL) body: any) {
|
||||
const { projectId, userId } = await this.getProjectUserIdWrite()
|
||||
await this.service.batchDelete(body.ids,userId,projectId);
|
||||
return this.ok();
|
||||
}
|
||||
|
||||
@Post('/check', { summary: Constants.per.authOnly })
|
||||
@Post('/check', { description: Constants.per.authOnly })
|
||||
async check(@Body('id') id: number) {
|
||||
await this.checkOwner(this.service,id,"read");
|
||||
await this.service.check(id, true, 0);
|
||||
@@ -116,14 +118,14 @@ export class SiteInfoController extends CrudController<SiteInfoService> {
|
||||
return this.ok();
|
||||
}
|
||||
|
||||
@Post('/checkAll', { summary: Constants.per.authOnly })
|
||||
@Post('/checkAll', { description: Constants.per.authOnly })
|
||||
async checkAll() {
|
||||
const { projectId, userId } = await this.getProjectUserIdWrite()
|
||||
await this.service.checkAllByUsers(userId,projectId);
|
||||
return this.ok();
|
||||
}
|
||||
|
||||
@Post('/import', { summary: Constants.per.authOnly })
|
||||
@Post('/import', { description: Constants.per.authOnly })
|
||||
async doImport(@Body(ALL) body: any) {
|
||||
const { projectId, userId } = await this.getProjectUserIdWrite()
|
||||
await this.service.doImport({
|
||||
@@ -136,7 +138,7 @@ export class SiteInfoController extends CrudController<SiteInfoService> {
|
||||
}
|
||||
|
||||
|
||||
@Post('/ipCheckChange', { summary: Constants.per.authOnly })
|
||||
@Post('/ipCheckChange', { description: Constants.per.authOnly })
|
||||
async ipCheckChange(@Body(ALL) bean: any) {
|
||||
await this.checkOwner(this.service,bean.id,"read");
|
||||
await this.service.ipCheckChange({
|
||||
@@ -146,7 +148,7 @@ export class SiteInfoController extends CrudController<SiteInfoService> {
|
||||
return this.ok();
|
||||
}
|
||||
|
||||
@Post('/disabledChange', { summary: Constants.per.authOnly })
|
||||
@Post('/disabledChange', { description: Constants.per.authOnly })
|
||||
async disabledChange(@Body(ALL) bean: any) {
|
||||
await this.checkOwner(this.service,bean.id,"write");
|
||||
await this.service.disabledChange({
|
||||
@@ -156,14 +158,14 @@ export class SiteInfoController extends CrudController<SiteInfoService> {
|
||||
return this.ok();
|
||||
}
|
||||
|
||||
@Post("/setting/get", { summary: Constants.per.authOnly })
|
||||
@Post("/setting/get", { description: Constants.per.authOnly })
|
||||
async get() {
|
||||
const { userId, projectId } = await this.getProjectUserIdRead()
|
||||
const setting = await this.service.getSetting(userId, projectId)
|
||||
return this.ok(setting);
|
||||
}
|
||||
|
||||
@Post("/setting/save", { summary: Constants.per.authOnly })
|
||||
@Post("/setting/save", { description: Constants.per.authOnly })
|
||||
async save(@Body(ALL) bean: any) {
|
||||
const { userId, projectId} = await this.getProjectUserIdWrite()
|
||||
const setting = new UserSiteMonitorSetting();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user