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

View File

@@ -253,4 +253,19 @@ export abstract class BaseService<T> {
async findOne(options: FindOneOptions<T>) {
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不能为空');
}
}

View File

@@ -29,6 +29,7 @@ onMounted(async () => {
function handleMenuClick({ key }: any) {
projectStore.changeCurrentProject(key);
window.location.reload();
}
</script>
<style lang="less">

View File

@@ -28,9 +28,11 @@ export class OpenCertController extends BaseOpenController {
async get(@Body(ALL) bean: CertGetReq, @Query(ALL) query: CertGetReq) {
const openKey: OpenKey = this.ctx.openKey;
const userId = openKey.userId;
if (!userId) {
throw new CodeException(Constants.res.openKeyError);
}
const projectId = openKey.projectId;
const req = merge({}, bean, query)
@@ -39,7 +41,8 @@ export class OpenCertController extends BaseOpenController {
domains: req.domains,
certId: req.certId,
autoApply: req.autoApply??false,
format: req.format
format: req.format,
projectId,
});
return this.ok(res);
}

View File

@@ -158,23 +158,18 @@ export class SiteInfoController extends CrudController<SiteInfoService> {
@Post("/setting/get", { summary: Constants.per.authOnly })
async get() {
const { userId } = await this.getProjectUserIdRead()
const setting = await this.service.getSetting(userId)
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 })
async save(@Body(ALL) bean: any) {
const { userId } = await this.getProjectUserIdWrite()
if(userId === 0){
if(!this.isAdmin()){
throw new Error("仅管理员可以修改");
}
}
const { userId, projectId} = await this.getProjectUserIdWrite()
const setting = new UserSiteMonitorSetting();
merge(setting, bean);
await this.service.saveSetting(userId, setting);
await this.service.saveSetting(userId, projectId,setting);
return this.ok({});
}

View File

@@ -257,7 +257,7 @@ export class HistoryController extends CrudController<HistoryService> {
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) {
//不允许管理员查看
throw new PermissionException("该流水线的用户还未授权管理员下载证书,请先让用户在”设置->授权委托“中打开开关");

View File

@@ -103,11 +103,12 @@ export class PipelineController extends CrudController<PipelineService> {
@Post('/save', { summary: Constants.per.authOnly })
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) {
await this.checkOwner(this.getService(), bean.id,"write",true);
} else {
bean.userId = userId;
bean.projectId = projectId;
}
if (!this.isAdmin()) {
@@ -124,6 +125,7 @@ export class PipelineController extends CrudController<PipelineService> {
await this.siteInfoService.doImport({
text: bean.addToMonitorDomains,
userId: userId,
projectId: projectId,
});
}
}

View File

@@ -84,7 +84,7 @@ export class AutoCRegisterCron {
if(!setting?.cron){
continue
}
await this.siteInfoService.registerSiteMonitorJob(item.userId)
await this.siteInfoService.registerSiteMonitorJob(item.userId,item.projectId)
}
if (this.immediateTriggerSiteMonitor) {

View File

@@ -135,23 +135,23 @@ export class EmailService implements IEmailService {
}
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;
}
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);
await this.settingsService.saveSetting(userId, userEmailSetting)
await this.settingsService.saveSetting(userId, null, userEmailSetting)
}
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)) {
return
}
userEmailSetting.list.unshift(email)
await this.settingsService.saveSetting(userId, userEmailSetting)
await this.settingsService.saveSetting(userId, null, userEmailSetting)
}

View File

@@ -23,7 +23,7 @@ export class TwoFactorService {
const { authenticator } = await import("otplib");
authenticatorSetting.secret = authenticator.generateSecret()
await this.userSettingsService.saveSetting(userId, setting);
await this.userSettingsService.saveSetting(userId, null, setting);
}
const user = await this.userService.info(userId);
@@ -59,7 +59,7 @@ export class TwoFactorService {
authenticatorSetting.enabled = true;
authenticatorSetting.verified = true;
await this.userSettingsService.saveSetting(userId, setting);
await this.userSettingsService.saveSetting(userId, null, setting);
}
async offAuthenticator(userId:number) {
@@ -71,11 +71,11 @@ export class TwoFactorService {
setting.authenticator.enabled = false;
setting.authenticator.verified = false;
setting.authenticator.secret = '';
await this.userSettingsService.saveSetting(userId, setting);
await this.userSettingsService.saveSetting(userId, null, setting);
}
async getSetting(userId:number) {
return await this.userSettingsService.getSetting<UserTwoFactorSetting>(userId, UserTwoFactorSetting);
return await this.userSettingsService.getSetting<UserTwoFactorSetting>(userId, null, UserTwoFactorSetting);
}

View File

@@ -38,10 +38,10 @@ export class UserSettingsService extends BaseService<UserSettingsEntity> {
}
async getByKey(key: string, userId: number, projectId: number): Promise<UserSettingsEntity | null> {
if(!userId){
if(userId == null){
throw new Error('userId is required');
}
if (!key || !userId) {
if (!key) {
return null;
}
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> {
if(!userId){
if(userId == null){
throw new Error('userId is required');
}
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> {
if(!userId){
if(userId==null){
throw new Error('userId is required');
}
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) {
if(!userId){
if(userId == null){
throw new Error('userId is required');
}
const old = await this.getSetting(userId, projectId,bean.constructor)

View File

@@ -27,10 +27,10 @@ export class CertInfoFacade {
@Inject()
userSettingsService : UserSettingsService
async getCertInfo(req: { domains?: string; certId?: number; userId: number,autoApply?:boolean,format?:string }) {
const { domains, certId, userId } = req;
async getCertInfo(req: { domains?: string; certId?: number; userId: number, projectId:number, autoApply?:boolean,format?:string }) {
const { domains, certId, userId,projectId } = req;
if (certId) {
return await this.certInfoService.getCertInfoById({ id: certId, userId });
return await this.certInfoService.getCertInfoById({ id: certId, userId, projectId });
}
if (!domains) {
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){
throw new CodeException(Constants.res.openEmailNotFound)
}
@@ -134,7 +134,7 @@ export class CertInfoFacade {
domains: req.domains,
email,
userId: req.userId,
from:"OpenAPI"
from: "OpenAPI"
})
}

View File

@@ -11,6 +11,7 @@ export type UploadCertReq = {
certReader: CertReader;
fromType?: string;
userId?: number;
projectId?: number;
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);
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);
}
@@ -167,7 +171,8 @@ export class CertInfoService extends BaseService<CertInfoEntity> {
bean.effectiveTime = certReader.effective;
bean.expiresTime = certReader.expires;
bean.certProvider = certReader.detail.issuer.commonName;
bean.userId = userId
bean.userId = userId;
bean.projectId = req.projectId;
if(req.file){
bean.certFile = req.file
}

View File

@@ -110,7 +110,7 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
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
let customDns = null
if (dnsServer && dnsServer.length > 0) {
@@ -162,7 +162,7 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
}
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
await this.checkAllIp(site,retryTimes,setting);
@@ -356,16 +356,17 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
async checkList(sites: SiteInfoEntity[],isCommon: boolean) {
const cache = {}
const getFromCache = async (userId: number) =>{
if (cache[userId]) {
return cache[userId];
const getFromCache = async (userId: number,projectId?: number) =>{
const key = `${userId}-${projectId??""}`
if (cache[key]) {
return cache[key];
}
const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(userId, UserSiteMonitorSetting)
cache[userId] = setting
const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(userId,projectId, UserSiteMonitorSetting)
cache[key] = setting
return setting;
}
for (const site of sites) {
const setting = await getFromCache(site.userId)
const setting = await getFromCache(site.userId,site.projectId)
if (isCommon) {
//公共的检查排除有设置cron的用户
if (setting?.cron) {
@@ -381,17 +382,17 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
}
}
async getSetting(userId: number) {
return await this.userSettingsService.getSetting<UserSiteMonitorSetting>(userId, UserSiteMonitorSetting);
async getSetting(userId: number,projectId?: number) {
return await this.userSettingsService.getSetting<UserSiteMonitorSetting>(userId,projectId, UserSiteMonitorSetting);
}
async saveSetting(userId: number, bean: UserSiteMonitorSetting) {
await this.userSettingsService.saveSetting(userId, bean);
async saveSetting(userId: number,projectId: number, bean: UserSiteMonitorSetting) {
await this.userSettingsService.saveSetting(userId,projectId, bean);
if(bean.cron){
//注册job
await this.registerSiteMonitorJob(userId);
await this.registerSiteMonitorJob(userId,projectId);
}else{
this.clearSiteMonitorJob(userId);
this.clearSiteMonitorJob(userId,projectId);
}
}
@@ -476,13 +477,13 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
await batchAdd(list);
}
clearSiteMonitorJob(userId: number) {
this.cron.remove(`siteMonitor-${userId}`);
clearSiteMonitorJob(userId: number,projectId?: number) {
this.cron.remove(`siteMonitor-${userId}-${projectId||""}`);
}
async registerSiteMonitorJob(userId?: number) {
async registerSiteMonitorJob(userId?: number,projectId?: number) {
if(!userId){
if(userId == null){
//注册公共job
logger.info(`注册站点证书检查定时任务`)
this.cron.register({
@@ -494,27 +495,30 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
});
logger.info(`注册站点证书检查定时任务完成`)
}else{
const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(userId, UserSiteMonitorSetting);
const setting = await this.userSettingsService.getSetting<UserSiteMonitorSetting>(userId,projectId, UserSiteMonitorSetting);
if (!setting.cron) {
return;
}
//注册个人的
//注册个人的 或项目的
this.cron.register({
name: `siteMonitor-${userId}`,
name: `siteMonitor-${userId}-${projectId||""}`,
cron: setting.cron,
job: () => this.triggerJobOnce(userId),
job: () => this.triggerJobOnce(userId,projectId),
});
}
}
async triggerJobOnce(userId?:number) {
logger.info(`站点证书检查开始执行[${userId??'所有用户'}]`);
async triggerJobOnce(userId?:number,projectId?:number) {
logger.info(`站点证书检查开始执行[${userId??'所有用户'}-${projectId??'所有项目'}]`);
const query:any = { disabled: false };
if(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) {
return;
}
@@ -536,7 +540,7 @@ export class SiteInfoService extends BaseService<SiteInfoEntity> {
await this.checkList(records,isCommon);
}
logger.info(`站点证书检查完成[${userId??'所有用户'}]`);
logger.info(`站点证书检查完成[${userId??'所有用户'}-${projectId??'所有项目'}]`);
}
async batchDelete(ids: number[], userId: number,projectId?:number): Promise<void> {

View File

@@ -67,7 +67,7 @@ export class SiteIpService extends BaseService<SiteIpEntity> {
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
let resolver = dns

View File

@@ -9,6 +9,7 @@ import dayjs from 'dayjs';
export type OpenKey = {
userId: number;
projectId?: number;
keyId: string;
keySecret: string;
encrypt: boolean;
@@ -30,15 +31,16 @@ export class OpenKeyService extends BaseService<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 secretKey = crypto.randomBytes(32);
const keySecret = Buffer.from(secretKey).toString('hex');
const entity = new OpenKeyEntity();
entity.userId = userId;
entity.projectId = projectId;
entity.keyId = keyId;
entity.keySecret = keySecret;
entity.scope = scope ?? 'open';
@@ -80,7 +82,7 @@ export class OpenKeyService extends BaseService<OpenKeyEntity> {
throw new CodeException(Constants.res.openKeySignError);
}
if (!entity.userId) {
if (entity.userId==null) {
throw new CodeException(Constants.res.openKeyError);
}
@@ -89,6 +91,7 @@ export class OpenKeyService extends BaseService<OpenKeyEntity> {
keyId: entity.keyId,
keySecret: entity.keySecret,
encrypt: encrypt,
projectId: entity.projectId,
scope: entity.scope,
};
}

View File

@@ -6,7 +6,7 @@ export async function getEmailSettings(sysSettingService: SysSettingsService, us
let conf = await sysSettingService.getSetting<SysEmailConf>(SysEmailConf);
if (!conf.host || conf.usePlus == null) {
//到userSetting里面去找
const adminEmailSetting = await userSettingsService.getByKey('email', 1);
const adminEmailSetting = await userSettingsService.getByKey('email', 1,null);
if (adminEmailSetting) {
const setting = JSON.parse(adminEmailSetting.setting);
conf = _.merge(conf, setting);