chore: project

This commit is contained in:
xiaojunnuo
2026-02-13 22:24:04 +08:00
parent 4ee6e38a94
commit cfd5b388f1
16 changed files with 95 additions and 67 deletions
@@ -253,4 +253,19 @@ export abstract class BaseService<T> {
async findOne(options: FindOneOptions<T>) { async findOne(options: FindOneOptions<T>) {
return await this.getRepository().findOne(options); return await this.getRepository().findOne(options);
} }
} }
export function checkUserProjectParam(userId: number, projectId: number) {
if (projectId != null ){
if( userId !==0) {
throw new ValidateException('userId projectId 错误');
}
return true
}else{
if( userId > 0) {
return true
}
throw new ValidateException('userId不能为空');
}
}
@@ -29,6 +29,7 @@ onMounted(async () => {
function handleMenuClick({ key }: any) { function handleMenuClick({ key }: any) {
projectStore.changeCurrentProject(key); projectStore.changeCurrentProject(key);
window.location.reload();
} }
</script> </script>
<style lang="less"> <style lang="less">
@@ -28,9 +28,11 @@ export class OpenCertController extends BaseOpenController {
async get(@Body(ALL) bean: CertGetReq, @Query(ALL) query: CertGetReq) { async get(@Body(ALL) bean: CertGetReq, @Query(ALL) query: CertGetReq) {
const openKey: OpenKey = this.ctx.openKey; const openKey: OpenKey = this.ctx.openKey;
const userId = openKey.userId; const userId = openKey.userId;
if (!userId) { if (!userId) {
throw new CodeException(Constants.res.openKeyError); throw new CodeException(Constants.res.openKeyError);
} }
const projectId = openKey.projectId;
const req = merge({}, bean, query) const req = merge({}, bean, query)
@@ -39,7 +41,8 @@ export class OpenCertController extends BaseOpenController {
domains: req.domains, domains: req.domains,
certId: req.certId, certId: req.certId,
autoApply: req.autoApply??false, autoApply: req.autoApply??false,
format: req.format format: req.format,
projectId,
}); });
return this.ok(res); return this.ok(res);
} }
@@ -158,23 +158,18 @@ export class SiteInfoController extends CrudController<SiteInfoService> {
@Post("/setting/get", { summary: Constants.per.authOnly }) @Post("/setting/get", { summary: Constants.per.authOnly })
async get() { async get() {
const { userId } = await this.getProjectUserIdRead() const { userId, projectId } = await this.getProjectUserIdRead()
const setting = await this.service.getSetting(userId) const setting = await this.service.getSetting(userId, projectId)
return this.ok(setting); return this.ok(setting);
} }
@Post("/setting/save", { summary: Constants.per.authOnly }) @Post("/setting/save", { summary: Constants.per.authOnly })
async save(@Body(ALL) bean: any) { async save(@Body(ALL) bean: any) {
const { userId } = await this.getProjectUserIdWrite() const { userId, projectId} = await this.getProjectUserIdWrite()
if(userId === 0){
if(!this.isAdmin()){
throw new Error("仅管理员可以修改");
}
}
const setting = new UserSiteMonitorSetting(); const setting = new UserSiteMonitorSetting();
merge(setting, bean); merge(setting, bean);
await this.service.saveSetting(userId, setting); await this.service.saveSetting(userId, projectId,setting);
return this.ok({}); return this.ok({});
} }
@@ -257,7 +257,7 @@ export class HistoryController extends CrudController<HistoryService> {
throw new PermissionException(); throw new PermissionException();
} }
// 是否允许管理员查看 // 是否允许管理员查看
const setting = await this.userSettingsService.getSetting<UserGrantSetting>(history.userId, UserGrantSetting, false); const setting = await this.userSettingsService.getSetting<UserGrantSetting>(history.userId, null, UserGrantSetting, false);
if (setting?.allowAdminViewCerts!==true) { if (setting?.allowAdminViewCerts!==true) {
//不允许管理员查看 //不允许管理员查看
throw new PermissionException("该流水线的用户还未授权管理员下载证书,请先让用户在”设置->授权委托“中打开开关"); throw new PermissionException("该流水线的用户还未授权管理员下载证书,请先让用户在”设置->授权委托“中打开开关");
@@ -103,11 +103,12 @@ export class PipelineController extends CrudController<PipelineService> {
@Post('/save', { summary: Constants.per.authOnly }) @Post('/save', { summary: Constants.per.authOnly })
async save(@Body(ALL) bean: { addToMonitorEnabled: boolean, addToMonitorDomains: string } & PipelineEntity) { async save(@Body(ALL) bean: { addToMonitorEnabled: boolean, addToMonitorDomains: string } & PipelineEntity) {
const { userId } = await this.getProjectUserIdWrite() const { userId ,projectId} = await this.getProjectUserIdWrite()
if (bean.id > 0) { if (bean.id > 0) {
await this.checkOwner(this.getService(), bean.id,"write",true); await this.checkOwner(this.getService(), bean.id,"write",true);
} else { } else {
bean.userId = userId; bean.userId = userId;
bean.projectId = projectId;
} }
if (!this.isAdmin()) { if (!this.isAdmin()) {
@@ -124,6 +125,7 @@ export class PipelineController extends CrudController<PipelineService> {
await this.siteInfoService.doImport({ await this.siteInfoService.doImport({
text: bean.addToMonitorDomains, text: bean.addToMonitorDomains,
userId: userId, userId: userId,
projectId: projectId,
}); });
} }
} }
@@ -84,7 +84,7 @@ export class AutoCRegisterCron {
if(!setting?.cron){ if(!setting?.cron){
continue continue
} }
await this.siteInfoService.registerSiteMonitorJob(item.userId) await this.siteInfoService.registerSiteMonitorJob(item.userId,item.projectId)
} }
if (this.immediateTriggerSiteMonitor) { if (this.immediateTriggerSiteMonitor) {
@@ -135,23 +135,23 @@ export class EmailService implements IEmailService {
} }
async list(userId: any) { async list(userId: any) {
const userEmailSetting = await this.settingsService.getSetting<UserEmailSetting>(userId, UserEmailSetting) const userEmailSetting = await this.settingsService.getSetting<UserEmailSetting>(userId,null, UserEmailSetting)
return userEmailSetting.list; return userEmailSetting.list;
} }
async delete(userId: any, email: string) { async delete(userId: any, email: string) {
const userEmailSetting = await this.settingsService.getSetting<UserEmailSetting>(userId, UserEmailSetting) const userEmailSetting = await this.settingsService.getSetting<UserEmailSetting>(userId, null, UserEmailSetting)
userEmailSetting.list = userEmailSetting.list.filter(item => item !== email); userEmailSetting.list = userEmailSetting.list.filter(item => item !== email);
await this.settingsService.saveSetting(userId, userEmailSetting) await this.settingsService.saveSetting(userId, null, userEmailSetting)
} }
async add(userId: any, email: string) { async add(userId: any, email: string) {
const userEmailSetting = await this.settingsService.getSetting<UserEmailSetting>(userId, UserEmailSetting) const userEmailSetting = await this.settingsService.getSetting<UserEmailSetting>(userId, null, UserEmailSetting)
//如果已存在 //如果已存在
if (userEmailSetting.list.includes(email)) { if (userEmailSetting.list.includes(email)) {
return return
} }
userEmailSetting.list.unshift(email) userEmailSetting.list.unshift(email)
await this.settingsService.saveSetting(userId, userEmailSetting) await this.settingsService.saveSetting(userId, null, userEmailSetting)
} }
@@ -23,7 +23,7 @@ export class TwoFactorService {
const { authenticator } = await import("otplib"); const { authenticator } = await import("otplib");
authenticatorSetting.secret = authenticator.generateSecret() authenticatorSetting.secret = authenticator.generateSecret()
await this.userSettingsService.saveSetting(userId, setting); await this.userSettingsService.saveSetting(userId, null, setting);
} }
const user = await this.userService.info(userId); const user = await this.userService.info(userId);
@@ -59,7 +59,7 @@ export class TwoFactorService {
authenticatorSetting.enabled = true; authenticatorSetting.enabled = true;
authenticatorSetting.verified = true; authenticatorSetting.verified = true;
await this.userSettingsService.saveSetting(userId, setting); await this.userSettingsService.saveSetting(userId, null, setting);
} }
async offAuthenticator(userId:number) { async offAuthenticator(userId:number) {
@@ -71,11 +71,11 @@ export class TwoFactorService {
setting.authenticator.enabled = false; setting.authenticator.enabled = false;
setting.authenticator.verified = false; setting.authenticator.verified = false;
setting.authenticator.secret = ''; setting.authenticator.secret = '';
await this.userSettingsService.saveSetting(userId, setting); await this.userSettingsService.saveSetting(userId, null, setting);
} }
async getSetting(userId:number) { async getSetting(userId:number) {
return await this.userSettingsService.getSetting<UserTwoFactorSetting>(userId, UserTwoFactorSetting); return await this.userSettingsService.getSetting<UserTwoFactorSetting>(userId, null, UserTwoFactorSetting);
} }
@@ -38,10 +38,10 @@ export class UserSettingsService extends BaseService<UserSettingsEntity> {
} }
async getByKey(key: string, userId: number, projectId: number): Promise<UserSettingsEntity | null> { async getByKey(key: string, userId: number, projectId: number): Promise<UserSettingsEntity | null> {
if(!userId){ if(userId == null){
throw new Error('userId is required'); throw new Error('userId is required');
} }
if (!key || !userId) { if (!key) {
return null; return null;
} }
return await this.repository.findOne({ return await this.repository.findOne({
@@ -54,7 +54,7 @@ export class UserSettingsService extends BaseService<UserSettingsEntity> {
} }
async getSettingByKey(key: string, userId: number, projectId: number): Promise<any | null> { async getSettingByKey(key: string, userId: number, projectId: number): Promise<any | null> {
if(!userId){ if(userId == null){
throw new Error('userId is required'); throw new Error('userId is required');
} }
const entity = await this.getByKey(key, userId, projectId); const entity = await this.getByKey(key, userId, projectId);
@@ -83,7 +83,7 @@ export class UserSettingsService extends BaseService<UserSettingsEntity> {
async getSetting<T>( userId: number, projectId: number,type: any, cache:boolean = false): Promise<T> { async getSetting<T>( userId: number, projectId: number,type: any, cache:boolean = false): Promise<T> {
if(!userId){ if(userId==null){
throw new Error('userId is required'); throw new Error('userId is required');
} }
const key = type.__key__; const key = type.__key__;
@@ -110,7 +110,7 @@ export class UserSettingsService extends BaseService<UserSettingsEntity> {
} }
async saveSetting<T extends BaseSettings>(userId:number, projectId: number,bean: T) { async saveSetting<T extends BaseSettings>(userId:number, projectId: number,bean: T) {
if(!userId){ if(userId == null){
throw new Error('userId is required'); throw new Error('userId is required');
} }
const old = await this.getSetting(userId, projectId,bean.constructor) const old = await this.getSetting(userId, projectId,bean.constructor)
@@ -27,10 +27,10 @@ export class CertInfoFacade {
@Inject() @Inject()
userSettingsService : UserSettingsService userSettingsService : UserSettingsService
async getCertInfo(req: { domains?: string; certId?: number; userId: number,autoApply?:boolean,format?:string }) { async getCertInfo(req: { domains?: string; certId?: number; userId: number, projectId:number, autoApply?:boolean,format?:string }) {
const { domains, certId, userId } = req; const { domains, certId, userId,projectId } = req;
if (certId) { if (certId) {
return await this.certInfoService.getCertInfoById({ id: certId, userId }); return await this.certInfoService.getCertInfoById({ id: certId, userId, projectId });
} }
if (!domains) { if (!domains) {
throw new CodeException({ throw new CodeException({
@@ -69,7 +69,7 @@ export class CertInfoFacade {
} }
} }
return await this.certInfoService.getCertInfoById({ id: matched.id, userId: userId,format:req.format }); return await this.certInfoService.getCertInfoById({ id: matched.id, userId: userId,projectId,format:req.format });
@@ -124,7 +124,7 @@ export class CertInfoFacade {
} }
} }
const userEmailSetting = await this.userSettingsService.getSetting<UserEmailSetting>(req.userId,UserEmailSetting) const userEmailSetting = await this.userSettingsService.getSetting<UserEmailSetting>(req.userId,null, UserEmailSetting)
if(!userEmailSetting.list){ if(!userEmailSetting.list){
throw new CodeException(Constants.res.openEmailNotFound) throw new CodeException(Constants.res.openEmailNotFound)
} }
@@ -134,7 +134,7 @@ export class CertInfoFacade {
domains: req.domains, domains: req.domains,
email, email,
userId: req.userId, userId: req.userId,
from:"OpenAPI" from: "OpenAPI"
}) })
} }
@@ -11,6 +11,7 @@ export type UploadCertReq = {
certReader: CertReader; certReader: CertReader;
fromType?: string; fromType?: string;
userId?: number; userId?: number;
projectId?: number;
file?:any file?:any
}; };
@@ -113,9 +114,12 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
}); });
} }
async getCertInfoById(req: { id: number; userId: number,format?:string }) { async getCertInfoById(req: { id: number; userId: number,projectId:number,format?:string }) {
const entity = await this.info(req.id); const entity = await this.info(req.id);
if (!entity || entity.userId !== req.userId) { if (!entity || entity.userId !== req.userId ) {
throw new CodeException(Constants.res.openCertNotFound);
}
if (req.projectId && entity.projectId !== req.projectId) {
throw new CodeException(Constants.res.openCertNotFound); throw new CodeException(Constants.res.openCertNotFound);
} }
@@ -167,7 +171,8 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
bean.effectiveTime = certReader.effective; bean.effectiveTime = certReader.effective;
bean.expiresTime = certReader.expires; bean.expiresTime = certReader.expires;
bean.certProvider = certReader.detail.issuer.commonName; bean.certProvider = certReader.detail.issuer.commonName;
bean.userId = userId bean.userId = userId;
bean.projectId = req.projectId;
if(req.file){ if(req.file){
bean.certFile = req.file bean.certFile = req.file
} }
@@ -110,7 +110,7 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
throw new Error("站点域名不能为空"); throw new Error("站点域名不能为空");
} }
const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(site.userId, UserSiteMonitorSetting); const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(site.userId,site.projectId, UserSiteMonitorSetting);
const dnsServer = setting.dnsServer const dnsServer = setting.dnsServer
let customDns = null let customDns = null
if (dnsServer && dnsServer.length > 0) { if (dnsServer && dnsServer.length > 0) {
@@ -162,7 +162,7 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
} }
await this.update(updateData); await this.update(updateData);
const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(site.userId, UserSiteMonitorSetting) const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(site.userId,site.projectId, UserSiteMonitorSetting)
//检查ip //检查ip
await this.checkAllIp(site,retryTimes,setting); await this.checkAllIp(site,retryTimes,setting);
@@ -356,16 +356,17 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
async checkList(sites: SiteInfoEntity[],isCommon: boolean) { async checkList(sites: SiteInfoEntity[],isCommon: boolean) {
const cache = {} const cache = {}
const getFromCache = async (userId: number) =>{ const getFromCache = async (userId: number,projectId?: number) =>{
if (cache[userId]) { const key = `${userId}-${projectId??""}`
return cache[userId]; if (cache[key]) {
return cache[key];
} }
const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(userId, UserSiteMonitorSetting) const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(userId,projectId, UserSiteMonitorSetting)
cache[userId] = setting cache[key] = setting
return setting; return setting;
} }
for (const site of sites) { for (const site of sites) {
const setting = await getFromCache(site.userId) const setting = await getFromCache(site.userId,site.projectId)
if (isCommon) { if (isCommon) {
//公共的检查,排除有设置cron的用户 //公共的检查,排除有设置cron的用户
if (setting?.cron) { if (setting?.cron) {
@@ -381,17 +382,17 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
} }
} }
async getSetting(userId: number) { async getSetting(userId: number,projectId?: number) {
return await this.userSettingsService.getSetting<UserSiteMonitorSetting>(userId, UserSiteMonitorSetting); return await this.userSettingsService.getSetting<UserSiteMonitorSetting>(userId,projectId, UserSiteMonitorSetting);
} }
async saveSetting(userId: number, bean: UserSiteMonitorSetting) { async saveSetting(userId: number,projectId: number, bean: UserSiteMonitorSetting) {
await this.userSettingsService.saveSetting(userId, bean); await this.userSettingsService.saveSetting(userId,projectId, bean);
if(bean.cron){ if(bean.cron){
//注册job //注册job
await this.registerSiteMonitorJob(userId); await this.registerSiteMonitorJob(userId,projectId);
}else{ }else{
this.clearSiteMonitorJob(userId); this.clearSiteMonitorJob(userId,projectId);
} }
} }
@@ -476,13 +477,13 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
await batchAdd(list); await batchAdd(list);
} }
clearSiteMonitorJob(userId: number) { clearSiteMonitorJob(userId: number,projectId?: number) {
this.cron.remove(`siteMonitor-${userId}`); this.cron.remove(`siteMonitor-${userId}-${projectId||""}`);
} }
async registerSiteMonitorJob(userId?: number) { async registerSiteMonitorJob(userId?: number,projectId?: number) {
if(!userId){ if(userId == null){
//注册公共job //注册公共job
logger.info(`注册站点证书检查定时任务`) logger.info(`注册站点证书检查定时任务`)
this.cron.register({ this.cron.register({
@@ -494,27 +495,30 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
}); });
logger.info(`注册站点证书检查定时任务完成`) logger.info(`注册站点证书检查定时任务完成`)
}else{ }else{
const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(userId, UserSiteMonitorSetting); const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(userId,projectId, UserSiteMonitorSetting);
if (!setting.cron) { if (!setting.cron) {
return; return;
} }
//注册个人的 //注册个人的 或项目的
this.cron.register({ this.cron.register({
name: `siteMonitor-${userId}`, name: `siteMonitor-${userId}-${projectId||""}`,
cron: setting.cron, cron: setting.cron,
job: () => this.triggerJobOnce(userId), job: () => this.triggerJobOnce(userId,projectId),
}); });
} }
} }
async triggerJobOnce(userId?:number) { async triggerJobOnce(userId?:number,projectId?:number) {
logger.info(`站点证书检查开始执行[${userId??'所有用户'}]`); logger.info(`站点证书检查开始执行[${userId??'所有用户'}-${projectId??'所有项目'}]`);
const query:any = { disabled: false }; const query:any = { disabled: false };
if(userId){ if(userId){
query.userId = userId; query.userId = userId;
if(projectId){
query.projectId = projectId;
}
//判断是否已关闭 //判断是否已关闭
const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(userId, UserSiteMonitorSetting); const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(userId,projectId, UserSiteMonitorSetting);
if (!setting.cron) { if (!setting.cron) {
return; return;
} }
@@ -536,7 +540,7 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
await this.checkList(records,isCommon); await this.checkList(records,isCommon);
} }
logger.info(`站点证书检查完成[${userId??'所有用户'}]`); logger.info(`站点证书检查完成[${userId??'所有用户'}-${projectId??'所有项目'}]`);
} }
async batchDelete(ids: number[], userId: number,projectId?:number): Promise<void> { async batchDelete(ids: number[], userId: number,projectId?:number): Promise<void> {
@@ -67,7 +67,7 @@ export class SiteIpService extends BaseService<SiteIpEntity> {
const domain = entity.domain; const domain = entity.domain;
const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(entity.userId, UserSiteMonitorSetting); const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(entity.userId,entity.projectId, UserSiteMonitorSetting);
const dnsServer = setting.dnsServer const dnsServer = setting.dnsServer
let resolver = dns let resolver = dns
@@ -9,6 +9,7 @@ import dayjs from 'dayjs';
export type OpenKey = { export type OpenKey = {
userId: number; userId: number;
projectId?: number;
keyId: string; keyId: string;
keySecret: string; keySecret: string;
encrypt: boolean; encrypt: boolean;
@@ -30,15 +31,16 @@ export class OpenKeyService extends BaseService<OpenKeyEntity> {
} }
async add(bean: OpenKeyEntity) { async add(bean: OpenKeyEntity) {
return await this.generate(bean.userId, bean.scope); return await this.generate(bean.userId,bean.projectId, bean.scope);
} }
async generate(userId: number, scope: string) { async generate(userId: number, projectId?: number, scope: string = 'open') {
const keyId = utils.id.simpleNanoId(18) + '_key'; const keyId = utils.id.simpleNanoId(18) + '_key';
const secretKey = crypto.randomBytes(32); const secretKey = crypto.randomBytes(32);
const keySecret = Buffer.from(secretKey).toString('hex'); const keySecret = Buffer.from(secretKey).toString('hex');
const entity = new OpenKeyEntity(); const entity = new OpenKeyEntity();
entity.userId = userId; entity.userId = userId;
entity.projectId = projectId;
entity.keyId = keyId; entity.keyId = keyId;
entity.keySecret = keySecret; entity.keySecret = keySecret;
entity.scope = scope ?? 'open'; entity.scope = scope ?? 'open';
@@ -80,7 +82,7 @@ export class OpenKeyService extends BaseService<OpenKeyEntity> {
throw new CodeException(Constants.res.openKeySignError); throw new CodeException(Constants.res.openKeySignError);
} }
if (!entity.userId) { if (entity.userId==null) {
throw new CodeException(Constants.res.openKeyError); throw new CodeException(Constants.res.openKeyError);
} }
@@ -89,6 +91,7 @@ export class OpenKeyService extends BaseService<OpenKeyEntity> {
keyId: entity.keyId, keyId: entity.keyId,
keySecret: entity.keySecret, keySecret: entity.keySecret,
encrypt: encrypt, encrypt: encrypt,
projectId: entity.projectId,
scope: entity.scope, scope: entity.scope,
}; };
} }
@@ -6,7 +6,7 @@ export async function getEmailSettings(sysSettingService: SysSettingsService, us
let conf = await sysSettingService.getSetting<SysEmailConf>(SysEmailConf); let conf = await sysSettingService.getSetting<SysEmailConf>(SysEmailConf);
if (!conf.host || conf.usePlus == null) { if (!conf.host || conf.usePlus == null) {
//到userSetting里面去找 //到userSetting里面去找
const adminEmailSetting = await userSettingsService.getByKey('email', 1); const adminEmailSetting = await userSettingsService.getByKey('email', 1,null);
if (adminEmailSetting) { if (adminEmailSetting) {
const setting = JSON.parse(adminEmailSetting.setting); const setting = JSON.parse(adminEmailSetting.setting);
conf = _.merge(conf, setting); conf = _.merge(conf, setting);