mirror of https://github.com/certd/certd
				
				
				
			feat: save files
							parent
							
								
									2851a33eb2
								
							
						
					
					
						commit
						671d273e2f
					
				| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
import { ConcurrencyStrategy, NotificationWhen, Pipeline, ResultType, Runnable, RunStrategy, Stage, Step, Task } from "../d.ts";
 | 
			
		||||
import _ from "lodash";
 | 
			
		||||
import { RunHistory, RunnableCollection } from "./run-history";
 | 
			
		||||
import { AbstractTaskPlugin, PluginDefine, pluginRegistry } from "../plugin";
 | 
			
		||||
import { AbstractTaskPlugin, PluginDefine, pluginRegistry, TaskInstanceContext } from "../plugin";
 | 
			
		||||
import { ContextFactory, IContext } from "./context";
 | 
			
		||||
import { IStorage } from "./storage";
 | 
			
		||||
import { logger } from "../utils/util.log";
 | 
			
		||||
| 
						 | 
				
			
			@ -11,6 +11,7 @@ import { IAccessService } from "../access";
 | 
			
		|||
import { RegistryItem } from "../registry";
 | 
			
		||||
import { Decorator } from "../decorator";
 | 
			
		||||
import { IEmailService } from "../service";
 | 
			
		||||
import { FileStore } from "./file-store";
 | 
			
		||||
 | 
			
		||||
export type ExecutorOptions = {
 | 
			
		||||
  userId: any;
 | 
			
		||||
| 
						 | 
				
			
			@ -19,6 +20,7 @@ export type ExecutorOptions = {
 | 
			
		|||
  onChanged: (history: RunHistory) => Promise<void>;
 | 
			
		||||
  accessService: IAccessService;
 | 
			
		||||
  emailService: IEmailService;
 | 
			
		||||
  fileRootDir?: string;
 | 
			
		||||
};
 | 
			
		||||
export class Executor {
 | 
			
		||||
  pipeline: Pipeline;
 | 
			
		||||
| 
						 | 
				
			
			@ -59,7 +61,7 @@ export class Executor {
 | 
			
		|||
      });
 | 
			
		||||
      await this.notification("success");
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      await this.notification("error");
 | 
			
		||||
      await this.notification("error", e);
 | 
			
		||||
      this.logger.error("pipeline 执行失败", e);
 | 
			
		||||
    } finally {
 | 
			
		||||
      await this.pipelineContext.setObj("lastRuntime", this.runtime);
 | 
			
		||||
| 
						 | 
				
			
			@ -185,28 +187,38 @@ export class Executor {
 | 
			
		|||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const context: any = {
 | 
			
		||||
    const taskCtx: TaskInstanceContext = {
 | 
			
		||||
      pipeline: this.pipeline,
 | 
			
		||||
      step,
 | 
			
		||||
      lastStatus,
 | 
			
		||||
      http: request,
 | 
			
		||||
      logger: this.runtime._loggers[step.id],
 | 
			
		||||
      accessService: this.options.accessService,
 | 
			
		||||
      emailService: this.options.emailService,
 | 
			
		||||
      pipelineContext: this.pipelineContext,
 | 
			
		||||
      lastStatus,
 | 
			
		||||
      userContext: this.contextFactory.getContext("user", this.options.userId),
 | 
			
		||||
      http: request,
 | 
			
		||||
      fileStore: new FileStore({
 | 
			
		||||
        scope: this.pipeline.id,
 | 
			
		||||
        parent: this.runtime.id,
 | 
			
		||||
        rootDir: this.options.fileRootDir,
 | 
			
		||||
      }),
 | 
			
		||||
    };
 | 
			
		||||
    Decorator.inject(define.autowire, instance, context);
 | 
			
		||||
    instance.setCtx(taskCtx);
 | 
			
		||||
 | 
			
		||||
    await instance.onInstance();
 | 
			
		||||
    await instance.execute();
 | 
			
		||||
 | 
			
		||||
    if (instance.result.clearLastStatus) {
 | 
			
		||||
    if (instance._result.clearLastStatus) {
 | 
			
		||||
      this.lastStatusMap.clear();
 | 
			
		||||
    }
 | 
			
		||||
    //输出到output context
 | 
			
		||||
    _.forEach(define.output, (item, key) => {
 | 
			
		||||
      step!.status!.output[key] = instance[key];
 | 
			
		||||
      step.status!.output[key] = instance[key];
 | 
			
		||||
      const stepOutputKey = `step.${step.id}.${key}`;
 | 
			
		||||
      this.runtime.context[stepOutputKey] = instance[key];
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    step.status!.files = instance.getFiles();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async notification(when: NotificationWhen, error?: any) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,38 @@
 | 
			
		|||
import { fileUtils } from "../utils/util.file";
 | 
			
		||||
import dayjs from "dayjs";
 | 
			
		||||
import path from "path";
 | 
			
		||||
import fs from "fs";
 | 
			
		||||
 | 
			
		||||
export type FileStoreOptions = {
 | 
			
		||||
  rootDir?: string;
 | 
			
		||||
  scope: string;
 | 
			
		||||
  parent: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export class FileStore {
 | 
			
		||||
  rootDir: string;
 | 
			
		||||
  scope: string;
 | 
			
		||||
  parent: string;
 | 
			
		||||
  constructor(options?: FileStoreOptions) {
 | 
			
		||||
    this.rootDir = fileUtils.getFileRootDir(options?.rootDir);
 | 
			
		||||
    this.scope = options?.scope || "0";
 | 
			
		||||
    this.parent = options?.parent || "0";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  readFile(filePath: string) {
 | 
			
		||||
    if (!fs.existsSync(filePath)) {
 | 
			
		||||
      return null;
 | 
			
		||||
    }
 | 
			
		||||
    return fs.readFileSync(filePath);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  writeFile(filename: string, file: Buffer) {
 | 
			
		||||
    const localPath = this.buildFilePath(filename);
 | 
			
		||||
    fs.writeFileSync(localPath, file);
 | 
			
		||||
    return localPath;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private buildFilePath(filename: string) {
 | 
			
		||||
    return path.join(this.rootDir, this.scope, dayjs().format("YYYY-MM-DD"), this.parent, filename);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +1,6 @@
 | 
			
		|||
import fs from "fs";
 | 
			
		||||
import path from "path";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import { fileUtils } from "../utils/util.file";
 | 
			
		||||
 | 
			
		||||
export interface IStorage {
 | 
			
		||||
  get(scope: string, namespace: string, version: string, key: string): Promise<string | null>;
 | 
			
		||||
| 
						 | 
				
			
			@ -12,15 +11,7 @@ export interface IStorage {
 | 
			
		|||
export class FileStorage implements IStorage {
 | 
			
		||||
  root: string;
 | 
			
		||||
  constructor(rootDir?: string) {
 | 
			
		||||
    if (rootDir == null) {
 | 
			
		||||
      const userHome = process.env.HOME || process.env.USERPROFILE;
 | 
			
		||||
      rootDir = userHome + "/.certd/storage/";
 | 
			
		||||
    }
 | 
			
		||||
    this.root = rootDir;
 | 
			
		||||
 | 
			
		||||
    if (!fs.existsSync(this.root)) {
 | 
			
		||||
      fs.mkdirSync(this.root, { recursive: true });
 | 
			
		||||
    }
 | 
			
		||||
    this.root = fileUtils.getFileRootDir(rootDir);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async remove(scope: string, namespace: string, version: string, key: string): Promise<void> {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,6 +55,10 @@ export type Trigger = {
 | 
			
		|||
  type: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type FileItem = {
 | 
			
		||||
  filename: string;
 | 
			
		||||
  path: string;
 | 
			
		||||
};
 | 
			
		||||
export type Runnable = {
 | 
			
		||||
  id: string;
 | 
			
		||||
  title: string;
 | 
			
		||||
| 
						 | 
				
			
			@ -64,6 +68,7 @@ export type Runnable = {
 | 
			
		|||
  default?: {
 | 
			
		||||
    [key: string]: any;
 | 
			
		||||
  };
 | 
			
		||||
  files?: FileItem[];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type EmailOptions = {
 | 
			
		||||
| 
						 | 
				
			
			@ -113,6 +118,7 @@ export type HistoryResultGroup = {
 | 
			
		|||
export type HistoryResult = {
 | 
			
		||||
  input: any;
 | 
			
		||||
  output: any;
 | 
			
		||||
  files?: FileItem[];
 | 
			
		||||
  /**
 | 
			
		||||
   * 任务状态
 | 
			
		||||
   */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,11 @@
 | 
			
		|||
import { Registrable } from "../registry";
 | 
			
		||||
import { FormItemProps } from "../d.ts";
 | 
			
		||||
import { FileItem, FormItemProps, Pipeline, Runnable, Step } from "../d.ts";
 | 
			
		||||
import { FileStore } from "../core/file-store";
 | 
			
		||||
import { Logger } from "log4js";
 | 
			
		||||
import { IAccessService } from "../access";
 | 
			
		||||
import { IEmailService } from "../service";
 | 
			
		||||
import { IContext } from "../core";
 | 
			
		||||
import { AxiosInstance } from "axios";
 | 
			
		||||
 | 
			
		||||
export enum ContextScope {
 | 
			
		||||
  global,
 | 
			
		||||
| 
						 | 
				
			
			@ -7,16 +13,11 @@ export enum ContextScope {
 | 
			
		|||
  runtime,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type Storage = {
 | 
			
		||||
  scope: ContextScope;
 | 
			
		||||
  path: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type TaskOutputDefine = {
 | 
			
		||||
  title: string;
 | 
			
		||||
  value?: any;
 | 
			
		||||
  storage?: Storage;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type TaskInputDefine = FormItemProps;
 | 
			
		||||
 | 
			
		||||
export type PluginDefine = Registrable & {
 | 
			
		||||
| 
						 | 
				
			
			@ -47,15 +48,56 @@ export type ITaskPlugin = {
 | 
			
		|||
 | 
			
		||||
export type TaskResult = {
 | 
			
		||||
  clearLastStatus?: boolean;
 | 
			
		||||
  files?: FileItem[];
 | 
			
		||||
};
 | 
			
		||||
export type TaskInstanceContext = {
 | 
			
		||||
  pipeline: Pipeline;
 | 
			
		||||
  step: Step;
 | 
			
		||||
  logger: Logger;
 | 
			
		||||
  accessService: IAccessService;
 | 
			
		||||
  emailService: IEmailService;
 | 
			
		||||
  pipelineContext: IContext;
 | 
			
		||||
  userContext: IContext;
 | 
			
		||||
  http: AxiosInstance;
 | 
			
		||||
  fileStore: FileStore;
 | 
			
		||||
  lastStatus?: Runnable;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export abstract class AbstractTaskPlugin implements ITaskPlugin {
 | 
			
		||||
  result: TaskResult = {};
 | 
			
		||||
  _result: TaskResult = { clearLastStatus: false, files: [] };
 | 
			
		||||
  ctx!: TaskInstanceContext;
 | 
			
		||||
  clearLastStatus() {
 | 
			
		||||
    this.result.clearLastStatus = true;
 | 
			
		||||
    this._result.clearLastStatus = true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getFiles() {
 | 
			
		||||
    return this._result.files;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setCtx(ctx: TaskInstanceContext) {
 | 
			
		||||
    this.ctx = ctx;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  saveFile(filename: string, file: Buffer) {
 | 
			
		||||
    const filePath = this.ctx.fileStore.writeFile(filename, file);
 | 
			
		||||
    this._result.files!.push({
 | 
			
		||||
      filename,
 | 
			
		||||
      path: filePath,
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get pipeline() {
 | 
			
		||||
    return this.ctx.pipeline;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get step() {
 | 
			
		||||
    return this.ctx.step;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async onInstance(): Promise<void> {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  abstract execute(): Promise<void>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,3 +61,11 @@ export function TaskOutput(output?: TaskOutputDefine): PropertyDecorator {
 | 
			
		|||
    Reflect.defineMetadata(PLUGIN_OUTPUT_KEY, output, target, propertyKey);
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const PLUGIN_DOWNLOAD_KEY = "pipeline:plugin:download";
 | 
			
		||||
export function TaskDownload(output?: TaskOutputDefine): PropertyDecorator {
 | 
			
		||||
  return (target, propertyKey) => {
 | 
			
		||||
    target = Decorator.target(target, propertyKey);
 | 
			
		||||
    Reflect.defineMetadata(PLUGIN_DOWNLOAD_KEY, output, target, propertyKey);
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,16 @@
 | 
			
		|||
import fs from "fs";
 | 
			
		||||
function getFileRootDir(rootDir?: string) {
 | 
			
		||||
  if (rootDir == null) {
 | 
			
		||||
    const userHome = process.env.HOME || process.env.USERPROFILE;
 | 
			
		||||
    rootDir = userHome + "/.certd/storage/";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!fs.existsSync(rootDir)) {
 | 
			
		||||
    fs.mkdirSync(rootDir, { recursive: true });
 | 
			
		||||
  }
 | 
			
		||||
  return rootDir;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const fileUtils = {
 | 
			
		||||
  getFileRootDir,
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
import { AbstractTaskPlugin, Autowire, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput, utils } from "@certd/pipeline";
 | 
			
		||||
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput, utils } from "@certd/pipeline";
 | 
			
		||||
// @ts-ignore
 | 
			
		||||
import { ROAClient } from "@alicloud/pop-core";
 | 
			
		||||
import { AliyunAccess } from "../../access";
 | 
			
		||||
| 
						 | 
				
			
			@ -103,11 +103,13 @@ export class DeployCertToAliyunAckIngressPlugin extends AbstractTaskPlugin {
 | 
			
		|||
  })
 | 
			
		||||
  accessId!: string;
 | 
			
		||||
 | 
			
		||||
  @Autowire()
 | 
			
		||||
  accessService!: IAccessService;
 | 
			
		||||
  @Autowire()
 | 
			
		||||
  logger!: ILogger;
 | 
			
		||||
 | 
			
		||||
  async onInstance(): Promise<void> {
 | 
			
		||||
    this.accessService = this.ctx.accessService;
 | 
			
		||||
    this.logger = this.ctx.logger;
 | 
			
		||||
  }
 | 
			
		||||
  async execute(): Promise<void> {
 | 
			
		||||
    console.log("开始部署证书到阿里云cdn");
 | 
			
		||||
    const { regionId, ingressClass, clusterId, isPrivateIpAddress, cert } = this;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
import { AbstractTaskPlugin, Autowire, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput } from "@certd/pipeline";
 | 
			
		||||
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput } from "@certd/pipeline";
 | 
			
		||||
import dayjs from "dayjs";
 | 
			
		||||
import Core from "@alicloud/pop-core";
 | 
			
		||||
import RPCClient from "@alicloud/pop-core";
 | 
			
		||||
| 
						 | 
				
			
			@ -17,7 +17,7 @@ import { AliyunAccess } from "../../access";
 | 
			
		|||
export class DeployCertToAliyunCDN extends AbstractTaskPlugin {
 | 
			
		||||
  @TaskInput({
 | 
			
		||||
    title: "CDN加速域名",
 | 
			
		||||
    helper: "你在阿里云上配置的CDN加速域名,比如certd.docmirror.cn",
 | 
			
		||||
    helper: "你在阿里云上配置的CDN加速域名,比如:certd.docmirror.cn",
 | 
			
		||||
    required: true,
 | 
			
		||||
  })
 | 
			
		||||
  domainName!: string;
 | 
			
		||||
| 
						 | 
				
			
			@ -49,13 +49,13 @@ export class DeployCertToAliyunCDN extends AbstractTaskPlugin {
 | 
			
		|||
  })
 | 
			
		||||
  accessId!: string;
 | 
			
		||||
 | 
			
		||||
  @Autowire()
 | 
			
		||||
  accessService!: IAccessService;
 | 
			
		||||
 | 
			
		||||
  @Autowire()
 | 
			
		||||
  logger!: ILogger;
 | 
			
		||||
  // eslint-disable-next-line @typescript-eslint/no-empty-function
 | 
			
		||||
  async onInstance() {}
 | 
			
		||||
 | 
			
		||||
  async onInstance() {
 | 
			
		||||
    this.accessService = this.ctx.accessService;
 | 
			
		||||
    this.logger = this.ctx.logger;
 | 
			
		||||
  }
 | 
			
		||||
  async execute(): Promise<void> {
 | 
			
		||||
    console.log("开始部署证书到阿里云cdn");
 | 
			
		||||
    const access = (await this.accessService.getById(this.accessId)) as AliyunAccess;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
import { AbstractTaskPlugin, Autowire, IAccessService, IsTaskPlugin, RunStrategy, TaskInput, TaskOutput } from "@certd/pipeline";
 | 
			
		||||
import { AbstractTaskPlugin, IAccessService, IsTaskPlugin, RunStrategy, TaskInput, TaskOutput } from "@certd/pipeline";
 | 
			
		||||
import Core from "@alicloud/pop-core";
 | 
			
		||||
import { AliyunAccess } from "../../access";
 | 
			
		||||
import { appendTimeSuffix, checkRet, ZoneOptions } from "../../utils";
 | 
			
		||||
| 
						 | 
				
			
			@ -59,14 +59,13 @@ export class UploadCertToAliyun extends AbstractTaskPlugin {
 | 
			
		|||
  })
 | 
			
		||||
  aliyunCertId!: string;
 | 
			
		||||
 | 
			
		||||
  @Autowire()
 | 
			
		||||
  accessService!: IAccessService;
 | 
			
		||||
 | 
			
		||||
  @Autowire()
 | 
			
		||||
  logger!: Logger;
 | 
			
		||||
 | 
			
		||||
  // eslint-disable-next-line @typescript-eslint/no-empty-function
 | 
			
		||||
  async onInstance() {}
 | 
			
		||||
  async onInstance() {
 | 
			
		||||
    this.accessService = this.ctx.accessService;
 | 
			
		||||
    this.logger = this.ctx.logger;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async execute(): Promise<void> {
 | 
			
		||||
    console.log("开始部署证书到阿里云cdn");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,8 @@
 | 
			
		|||
import { AbstractTaskPlugin, Autowire, HttpClient, IAccessService, IContext, IsTaskPlugin, RunStrategy, Step, TaskInput, TaskOutput } from "@certd/pipeline";
 | 
			
		||||
import { AbstractTaskPlugin, Decorator, HttpClient, IAccessService, IContext, IsTaskPlugin, RunStrategy, Step, TaskInput, TaskOutput } from "@certd/pipeline";
 | 
			
		||||
import dayjs from "dayjs";
 | 
			
		||||
import { AcmeService, CertInfo } from "./acme";
 | 
			
		||||
import _ from "lodash";
 | 
			
		||||
import { Logger } from "log4js";
 | 
			
		||||
import { Decorator } from "@certd/pipeline";
 | 
			
		||||
import { DnsProviderDefine, dnsProviderRegistry } from "../../dns-provider";
 | 
			
		||||
import { CertReader } from "./cert-reader";
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -109,22 +108,11 @@ export class CertApplyPlugin extends AbstractTaskPlugin {
 | 
			
		|||
  })
 | 
			
		||||
  csrInfo: any;
 | 
			
		||||
 | 
			
		||||
  // @ts-ignore
 | 
			
		||||
  acme: AcmeService;
 | 
			
		||||
 | 
			
		||||
  @Autowire()
 | 
			
		||||
  acme!: AcmeService;
 | 
			
		||||
  logger!: Logger;
 | 
			
		||||
 | 
			
		||||
  @Autowire()
 | 
			
		||||
  userContext!: IContext;
 | 
			
		||||
 | 
			
		||||
  @Autowire()
 | 
			
		||||
  accessService!: IAccessService;
 | 
			
		||||
 | 
			
		||||
  @Autowire()
 | 
			
		||||
  http!: HttpClient;
 | 
			
		||||
 | 
			
		||||
  @Autowire()
 | 
			
		||||
  lastStatus!: Step;
 | 
			
		||||
 | 
			
		||||
  @TaskOutput({
 | 
			
		||||
| 
						 | 
				
			
			@ -133,13 +121,19 @@ export class CertApplyPlugin extends AbstractTaskPlugin {
 | 
			
		|||
  cert?: CertInfo;
 | 
			
		||||
 | 
			
		||||
  async onInstance() {
 | 
			
		||||
    this.accessService = this.ctx.accessService;
 | 
			
		||||
    this.logger = this.ctx.logger;
 | 
			
		||||
    this.userContext = this.ctx.userContext;
 | 
			
		||||
    this.http = this.ctx.http;
 | 
			
		||||
    this.lastStatus = this.ctx.lastStatus as Step;
 | 
			
		||||
 | 
			
		||||
    this.acme = new AcmeService({ userContext: this.userContext, logger: this.logger });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async execute(): Promise<void> {
 | 
			
		||||
    const oldCert = await this.condition();
 | 
			
		||||
    if (oldCert != null) {
 | 
			
		||||
      return this.output(oldCert);
 | 
			
		||||
      return this.output(oldCert.toCertInfo());
 | 
			
		||||
    }
 | 
			
		||||
    const cert = await this.doCertApply();
 | 
			
		||||
    if (cert != null) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,6 +61,9 @@ export class SshClient {
 | 
			
		|||
    return new Promise((resolve, reject) => {
 | 
			
		||||
      this.connect({
 | 
			
		||||
        connectConf,
 | 
			
		||||
        onError(err: any) {
 | 
			
		||||
          reject(err);
 | 
			
		||||
        },
 | 
			
		||||
        onReady: (conn: any) => {
 | 
			
		||||
          conn.exec(script, (err: Error, stream: any) => {
 | 
			
		||||
            if (err) {
 | 
			
		||||
| 
						 | 
				
			
			@ -98,6 +101,10 @@ export class SshClient {
 | 
			
		|||
    return new Promise((resolve, reject) => {
 | 
			
		||||
      this.connect({
 | 
			
		||||
        connectConf,
 | 
			
		||||
        onError: (err: any) => {
 | 
			
		||||
          this.logger.error(err);
 | 
			
		||||
          reject(err);
 | 
			
		||||
        },
 | 
			
		||||
        onReady: (conn: any) => {
 | 
			
		||||
          conn.shell((err: Error, stream: any) => {
 | 
			
		||||
            if (err) {
 | 
			
		||||
| 
						 | 
				
			
			@ -122,10 +129,13 @@ export class SshClient {
 | 
			
		|||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  connect(options: { connectConf: any; onReady: any }) {
 | 
			
		||||
    const { connectConf, onReady } = options;
 | 
			
		||||
  connect(options: { connectConf: any; onReady: any; onError: any }) {
 | 
			
		||||
    const { connectConf, onReady, onError } = options;
 | 
			
		||||
    const conn = new ssh2.Client();
 | 
			
		||||
    conn
 | 
			
		||||
      .on("error", (err: any) => {
 | 
			
		||||
        onError(err);
 | 
			
		||||
      })
 | 
			
		||||
      .on("ready", () => {
 | 
			
		||||
        this.logger.info("Client :: ready");
 | 
			
		||||
        onReady(conn);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
import { AbstractTaskPlugin, Autowire, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput } from "@certd/pipeline";
 | 
			
		||||
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput } from "@certd/pipeline";
 | 
			
		||||
import { SshClient } from "../../lib/ssh";
 | 
			
		||||
 | 
			
		||||
@IsTaskPlugin({
 | 
			
		||||
| 
						 | 
				
			
			@ -32,13 +32,12 @@ export class HostShellExecutePlugin extends AbstractTaskPlugin {
 | 
			
		|||
  })
 | 
			
		||||
  script!: string;
 | 
			
		||||
 | 
			
		||||
  @Autowire()
 | 
			
		||||
  accessService!: IAccessService;
 | 
			
		||||
  @Autowire()
 | 
			
		||||
  logger!: ILogger;
 | 
			
		||||
 | 
			
		||||
  // eslint-disable-next-line @typescript-eslint/no-empty-function
 | 
			
		||||
  async onInstance() {}
 | 
			
		||||
  async onInstance() {
 | 
			
		||||
    this.accessService = this.ctx.accessService;
 | 
			
		||||
    this.logger = this.ctx.logger;
 | 
			
		||||
  }
 | 
			
		||||
  async execute(): Promise<void> {
 | 
			
		||||
    const { script, accessId } = this;
 | 
			
		||||
    const connectConf = await this.accessService.getById(accessId);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
import { AbstractTaskPlugin, Autowire, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput, TaskOutput } from "@certd/pipeline";
 | 
			
		||||
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput, TaskOutput } from "@certd/pipeline";
 | 
			
		||||
import { SshClient } from "../../lib/ssh";
 | 
			
		||||
import { CertInfo, CertReader } from "@certd/plugin-cert";
 | 
			
		||||
import * as fs from "fs";
 | 
			
		||||
| 
						 | 
				
			
			@ -49,11 +49,6 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
 | 
			
		|||
  })
 | 
			
		||||
  sudo!: boolean;
 | 
			
		||||
 | 
			
		||||
  @Autowire()
 | 
			
		||||
  accessService!: IAccessService;
 | 
			
		||||
  @Autowire()
 | 
			
		||||
  logger!: ILogger;
 | 
			
		||||
 | 
			
		||||
  @TaskOutput({
 | 
			
		||||
    title: "证书保存路径",
 | 
			
		||||
  })
 | 
			
		||||
| 
						 | 
				
			
			@ -64,7 +59,13 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
 | 
			
		|||
  })
 | 
			
		||||
  hostKeyPath!: string;
 | 
			
		||||
 | 
			
		||||
  async onInstance() {}
 | 
			
		||||
  accessService!: IAccessService;
 | 
			
		||||
  logger!: ILogger;
 | 
			
		||||
 | 
			
		||||
  async onInstance() {
 | 
			
		||||
    this.accessService = this.ctx.accessService;
 | 
			
		||||
    this.logger = this.ctx.logger;
 | 
			
		||||
  }
 | 
			
		||||
  async execute(): Promise<void> {
 | 
			
		||||
    const { crtPath, keyPath, cert, accessId, sudo } = this;
 | 
			
		||||
    const certReader = new CertReader(cert);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
import { AbstractTaskPlugin, Autowire, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput } from "@certd/pipeline";
 | 
			
		||||
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput } from "@certd/pipeline";
 | 
			
		||||
import tencentcloud from "tencentcloud-sdk-nodejs/index";
 | 
			
		||||
import { TencentAccess } from "../../access";
 | 
			
		||||
import { CertInfo } from "@certd/plugin-cert";
 | 
			
		||||
| 
						 | 
				
			
			@ -47,14 +47,14 @@ export class DeployToCdnPlugin extends AbstractTaskPlugin {
 | 
			
		|||
  })
 | 
			
		||||
  domainName!: string;
 | 
			
		||||
 | 
			
		||||
  @Autowire()
 | 
			
		||||
  accessService!: IAccessService;
 | 
			
		||||
 | 
			
		||||
  @Autowire()
 | 
			
		||||
  logger!: ILogger;
 | 
			
		||||
 | 
			
		||||
  // eslint-disable-next-line @typescript-eslint/no-empty-function
 | 
			
		||||
  async onInstance() {}
 | 
			
		||||
  async onInstance() {
 | 
			
		||||
    this.accessService = this.ctx.accessService;
 | 
			
		||||
    this.logger = this.ctx.logger;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async execute(): Promise<void> {
 | 
			
		||||
    const accessProvider: TencentAccess = (await this.accessService.getById(this.accessId)) as TencentAccess;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
import { AbstractTaskPlugin, Autowire, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput, utils } from "@certd/pipeline";
 | 
			
		||||
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput, utils } from "@certd/pipeline";
 | 
			
		||||
import tencentcloud from "tencentcloud-sdk-nodejs/index";
 | 
			
		||||
import { TencentAccess } from "../../access";
 | 
			
		||||
import dayjs from "dayjs";
 | 
			
		||||
| 
						 | 
				
			
			@ -71,14 +71,13 @@ export class DeployToClbPlugin extends AbstractTaskPlugin {
 | 
			
		|||
  })
 | 
			
		||||
  accessId!: string;
 | 
			
		||||
 | 
			
		||||
  @Autowire()
 | 
			
		||||
  accessService!: IAccessService;
 | 
			
		||||
 | 
			
		||||
  @Autowire()
 | 
			
		||||
  logger!: ILogger;
 | 
			
		||||
 | 
			
		||||
  // eslint-disable-next-line @typescript-eslint/no-empty-function
 | 
			
		||||
  async onInstance() {}
 | 
			
		||||
  async onInstance() {
 | 
			
		||||
    this.accessService = this.ctx.accessService;
 | 
			
		||||
    this.logger = this.ctx.logger;
 | 
			
		||||
  }
 | 
			
		||||
  async execute(): Promise<void> {
 | 
			
		||||
    const accessProvider = (await this.accessService.getById(this.accessId)) as TencentAccess;
 | 
			
		||||
    const client = this.getClient(accessProvider, this.region);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
import { AbstractTaskPlugin, Autowire, IAccessService, IsTaskPlugin, RunStrategy, TaskInput, utils } from "@certd/pipeline";
 | 
			
		||||
import { AbstractTaskPlugin, IAccessService, IsTaskPlugin, RunStrategy, TaskInput, utils } from "@certd/pipeline";
 | 
			
		||||
import tencentcloud from "tencentcloud-sdk-nodejs/index";
 | 
			
		||||
import { K8sClient } from "@certd/plugin-util";
 | 
			
		||||
import dayjs from "dayjs";
 | 
			
		||||
| 
						 | 
				
			
			@ -80,15 +80,12 @@ export class DeployCertToTencentTKEIngressPlugin extends AbstractTaskPlugin {
 | 
			
		|||
  })
 | 
			
		||||
  cert!: any;
 | 
			
		||||
 | 
			
		||||
  @Autowire()
 | 
			
		||||
  logger!: Logger;
 | 
			
		||||
 | 
			
		||||
  @Autowire()
 | 
			
		||||
  accessService!: IAccessService;
 | 
			
		||||
 | 
			
		||||
  // eslint-disable-next-line @typescript-eslint/no-empty-function
 | 
			
		||||
  async onInstance() {}
 | 
			
		||||
 | 
			
		||||
  async onInstance() {
 | 
			
		||||
    this.accessService = this.ctx.accessService;
 | 
			
		||||
    this.logger = this.ctx.logger;
 | 
			
		||||
  }
 | 
			
		||||
  async execute(): Promise<void> {
 | 
			
		||||
    const accessProvider = this.accessService.getById(this.accessId);
 | 
			
		||||
    const tkeClient = this.getTkeClient(accessProvider, this.region);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
import { AbstractTaskPlugin, Autowire, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput, TaskOutput } from "@certd/pipeline";
 | 
			
		||||
import { AbstractTaskPlugin, IAccessService, ILogger, IsTaskPlugin, RunStrategy, TaskInput, TaskOutput } from "@certd/pipeline";
 | 
			
		||||
import tencentcloud from "tencentcloud-sdk-nodejs/index";
 | 
			
		||||
import dayjs from "dayjs";
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -42,14 +42,13 @@ export class UploadToTencentPlugin extends AbstractTaskPlugin {
 | 
			
		|||
  })
 | 
			
		||||
  tencentCertId?: string;
 | 
			
		||||
 | 
			
		||||
  @Autowire()
 | 
			
		||||
  accessService!: IAccessService;
 | 
			
		||||
 | 
			
		||||
  @Autowire()
 | 
			
		||||
  logger!: ILogger;
 | 
			
		||||
 | 
			
		||||
  // eslint-disable-next-line @typescript-eslint/no-empty-function
 | 
			
		||||
  async onInstance() {}
 | 
			
		||||
  async onInstance() {
 | 
			
		||||
    this.accessService = this.ctx.accessService;
 | 
			
		||||
    this.logger = this.ctx.logger;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async execute(): Promise<void> {
 | 
			
		||||
    const { accessId, name, cert } = this;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -63,6 +63,7 @@
 | 
			
		|||
    "@rollup/plugin-commonjs": "^23.0.4",
 | 
			
		||||
    "@rollup/plugin-node-resolve": "^15.0.1",
 | 
			
		||||
    "@types/chai": "^4.3.4",
 | 
			
		||||
    "@types/lodash": "^4.14.195",
 | 
			
		||||
    "@types/mocha": "^10.0.1",
 | 
			
		||||
    "@types/node": "^18.11.15",
 | 
			
		||||
    "@typescript-eslint/eslint-plugin": "^5.46.1",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 48 KiB  | 
| 
						 | 
				
			
			@ -1,106 +1,7 @@
 | 
			
		|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<svg
 | 
			
		||||
        xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
        width="210mm"
 | 
			
		||||
        height="210mm"
 | 
			
		||||
        viewBox="0 0 210 210"
 | 
			
		||||
        version="1.1"
 | 
			
		||||
        id="svg8"
 | 
			
		||||
>
 | 
			
		||||
    <g id="layer1" style="display:inline">
 | 
			
		||||
        <path
 | 
			
		||||
                style="fill:#002255;stroke:none;stroke-width:0.625348"
 | 
			
		||||
                d="M 35.587501,69.766667 V 59.766664 h 70.000109 69.99991 v 10.000003 9.999997 H 105.58761 35.587501 Z"
 | 
			
		||||
                id="path12" />
 | 
			
		||||
        <rect
 | 
			
		||||
                style="fill:#2a7fff;fill-rule:evenodd;stroke-width:0.214311"
 | 
			
		||||
                id="rect22-2"
 | 
			
		||||
                width="32.244232"
 | 
			
		||||
                height="20"
 | 
			
		||||
                x="71.506088"
 | 
			
		||||
                y="106.64581" />
 | 
			
		||||
        <rect
 | 
			
		||||
                style="fill:#2a7fff;fill-rule:evenodd;stroke-width:0.214311"
 | 
			
		||||
                id="rect22-8-8"
 | 
			
		||||
                width="32.244232"
 | 
			
		||||
                height="20"
 | 
			
		||||
                x="107.42467"
 | 
			
		||||
                y="106.64581" />
 | 
			
		||||
        <rect
 | 
			
		||||
                style="fill:#2a7fff;fill-rule:evenodd;stroke-width:0.214311"
 | 
			
		||||
                id="rect22-8-5-8"
 | 
			
		||||
                width="32.244232"
 | 
			
		||||
                height="20"
 | 
			
		||||
                x="143.34325"
 | 
			
		||||
                y="106.64581" />
 | 
			
		||||
        <rect
 | 
			
		||||
                style="fill:#2a7fff;fill-rule:evenodd;stroke-width:0.214311"
 | 
			
		||||
                id="rect22-2-4"
 | 
			
		||||
                width="32.244232"
 | 
			
		||||
                height="20"
 | 
			
		||||
                x="71.506088"
 | 
			
		||||
                y="129.82079" />
 | 
			
		||||
        <rect
 | 
			
		||||
                style="fill:#2a7fff;fill-rule:evenodd;stroke-width:0.214311"
 | 
			
		||||
                id="rect22-8-8-3"
 | 
			
		||||
                width="32.244232"
 | 
			
		||||
                height="20"
 | 
			
		||||
                x="107.42467"
 | 
			
		||||
                y="129.82079" />
 | 
			
		||||
        <rect
 | 
			
		||||
                style="fill:#2a7fff;fill-rule:evenodd;stroke-width:0.214311"
 | 
			
		||||
                id="rect22-8-5-8-2"
 | 
			
		||||
                width="32.244232"
 | 
			
		||||
                height="20"
 | 
			
		||||
                x="143.34325"
 | 
			
		||||
                y="129.82079" />
 | 
			
		||||
        <rect
 | 
			
		||||
                style="fill:#2a7fff;fill-rule:evenodd;stroke-width:0.214311"
 | 
			
		||||
                id="rect22-2-7"
 | 
			
		||||
                width="32.244232"
 | 
			
		||||
                height="20"
 | 
			
		||||
                x="35.587502"
 | 
			
		||||
                y="106.64581" />
 | 
			
		||||
        <rect
 | 
			
		||||
                style="fill:#2a7fff;fill-rule:evenodd;stroke-width:0.214311"
 | 
			
		||||
                id="rect22-2-4-0"
 | 
			
		||||
                width="32.244232"
 | 
			
		||||
                height="20"
 | 
			
		||||
                x="35.587502"
 | 
			
		||||
                y="129.82079" />
 | 
			
		||||
        <rect
 | 
			
		||||
                style="display:inline;fill:#2a7fff;fill-rule:evenodd;stroke-width:0.214311"
 | 
			
		||||
                id="rect22-2-9"
 | 
			
		||||
                width="32.244232"
 | 
			
		||||
                height="20"
 | 
			
		||||
                x="71.506088"
 | 
			
		||||
                y="82.941666" />
 | 
			
		||||
        <rect
 | 
			
		||||
                style="display:inline;fill:#2a7fff;fill-rule:evenodd;stroke-width:0.214311"
 | 
			
		||||
                id="rect22-8-8-37"
 | 
			
		||||
                width="32.244232"
 | 
			
		||||
                height="20"
 | 
			
		||||
                x="107.42467"
 | 
			
		||||
                y="82.941666" />
 | 
			
		||||
        <rect
 | 
			
		||||
                style="display:inline;fill:#2a7fff;fill-rule:evenodd;stroke-width:0.214311"
 | 
			
		||||
                id="rect22-8-5-8-4"
 | 
			
		||||
                width="32.244232"
 | 
			
		||||
                height="20"
 | 
			
		||||
                x="143.34325"
 | 
			
		||||
                y="82.941666" />
 | 
			
		||||
        <rect
 | 
			
		||||
                style="display:inline;fill:#2a7fff;fill-rule:evenodd;stroke-width:0.214311"
 | 
			
		||||
                id="rect22-2-7-1"
 | 
			
		||||
                width="32.244232"
 | 
			
		||||
                height="20"
 | 
			
		||||
                x="35.587502"
 | 
			
		||||
                y="82.941666" />
 | 
			
		||||
    </g>
 | 
			
		||||
    <polygon
 | 
			
		||||
            points="75.3,174.4 103.1,103.6 79.8,103.6 112.6,41.3 156.4,41.3 129.9,90.5 148.1,90.5 "
 | 
			
		||||
            fill="#f6cc00"
 | 
			
		||||
            id="polygon276"
 | 
			
		||||
            transform="matrix(1.0930933,0,0,0.99853202,-17.517362,-0.52287941)" />
 | 
			
		||||
 | 
			
		||||
<svg  version="1.0" xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
     width="500" height="500" viewBox="0 0 500.000000 500.000000"
 | 
			
		||||
     >
 | 
			
		||||
    <path d="M28.34 56.68h28.34V36.12H28.34a7.79 7.79 0 1 1 0-15.58h19.84v9.05h8.5V12H28.34a16.29 16.29 0 0 0 0 32.58h19.84v3.56H28.34a19.84 19.84 0 0 1 0-39.68h28.34V0H28.34a28.34 28.34 0 0 0 0 56.68z"
 | 
			
		||||
          transform="translate(70, 76) scale(6,6)"
 | 
			
		||||
    ></path>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
		 Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 402 B  | 
| 
						 | 
				
			
			@ -30,13 +30,19 @@ export const useResourceStore = defineStore({
 | 
			
		|||
    currentAsidePath: ""
 | 
			
		||||
  }),
 | 
			
		||||
  getters: {
 | 
			
		||||
    // @ts-ignore
 | 
			
		||||
    getAsideMenus() {
 | 
			
		||||
      // @ts-ignore
 | 
			
		||||
      return this.asideMenus;
 | 
			
		||||
    },
 | 
			
		||||
    // @ts-ignore
 | 
			
		||||
    getHeaderMenus() {
 | 
			
		||||
      // @ts-ignore
 | 
			
		||||
      return this.headerMenus;
 | 
			
		||||
    },
 | 
			
		||||
    // @ts-ignore
 | 
			
		||||
    getFrameworkMenus() {
 | 
			
		||||
      // @ts-ignore
 | 
			
		||||
      return this.frameworkMenus;
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
| 
						 | 
				
			
			@ -54,17 +60,17 @@ export const useResourceStore = defineStore({
 | 
			
		|||
      this.inited = true;
 | 
			
		||||
 | 
			
		||||
      const showMenus = _.cloneDeep(frameworkMenus[0].children);
 | 
			
		||||
      this.frameworkMenus = filterMenus(showMenus, (item) => {
 | 
			
		||||
      this.frameworkMenus = filterMenus(showMenus, (item: any) => {
 | 
			
		||||
        return item?.meta?.showOnHeader !== false;
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      this.fixedAsideMenus = findMenus(showMenus, (item) => {
 | 
			
		||||
      this.fixedAsideMenus = findMenus(showMenus, (item: any) => {
 | 
			
		||||
        return item?.meta?.fixedAside === true;
 | 
			
		||||
      });
 | 
			
		||||
      this.headerMenus = headerMenus;
 | 
			
		||||
      this.setAsideMenu();
 | 
			
		||||
    },
 | 
			
		||||
    setAsideMenu(topMenu?) {
 | 
			
		||||
    setAsideMenu(topMenu?: any) {
 | 
			
		||||
      if (this.frameworkMenus.length === 0) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			@ -74,13 +80,13 @@ export const useResourceStore = defineStore({
 | 
			
		|||
      const asideMenus = topMenu?.children || [];
 | 
			
		||||
      this.asideMenus = [...this.fixedAsideMenus, ...asideMenus];
 | 
			
		||||
    },
 | 
			
		||||
    setAsideMenuByCurrentRoute(matched) {
 | 
			
		||||
    setAsideMenuByCurrentRoute(matched: any) {
 | 
			
		||||
      const menuHeader = this.frameworkMenus;
 | 
			
		||||
      if (matched?.length <= 1) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      function findFromTree(tree, find) {
 | 
			
		||||
      function findFromTree(tree: any, find: any) {
 | 
			
		||||
        const results: Array<any> = [];
 | 
			
		||||
        for (const item of tree) {
 | 
			
		||||
          if (find(item)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -88,7 +94,7 @@ export const useResourceStore = defineStore({
 | 
			
		|||
            return results;
 | 
			
		||||
          }
 | 
			
		||||
          if (item.children && item.children.length > 0) {
 | 
			
		||||
            const found = findFromTree(item.children, find);
 | 
			
		||||
            const found: any = findFromTree(item.children, find);
 | 
			
		||||
            if (found) {
 | 
			
		||||
              results.push(item);
 | 
			
		||||
              return results.concat(found);
 | 
			
		||||
| 
						 | 
				
			
			@ -97,7 +103,7 @@ export const useResourceStore = defineStore({
 | 
			
		|||
        }
 | 
			
		||||
      }
 | 
			
		||||
      const matchedPath = matched[1].path;
 | 
			
		||||
      const _side = findFromTree(menuHeader, (menu) => menu.path === matchedPath);
 | 
			
		||||
      const _side = findFromTree(menuHeader, (menu: any) => menu.path === matchedPath);
 | 
			
		||||
      if (_side?.length > 0) {
 | 
			
		||||
        if (this.currentAsidePath === _side[0]) {
 | 
			
		||||
          return;
 | 
			
		||||
| 
						 | 
				
			
			@ -106,11 +112,11 @@ export const useResourceStore = defineStore({
 | 
			
		|||
        this.setAsideMenu(_side[0]);
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    filterByPermission(permissions) {
 | 
			
		||||
    filterByPermission(permissions: any) {
 | 
			
		||||
      this.frameworkMenus = this.filterChildrenByPermission(this.frameworkMenus, permissions);
 | 
			
		||||
    },
 | 
			
		||||
    filterChildrenByPermission(list, permissions) {
 | 
			
		||||
      const menus = list.filter((item) => {
 | 
			
		||||
    filterChildrenByPermission(list: any, permissions: any) {
 | 
			
		||||
      const menus = list.filter((item: any) => {
 | 
			
		||||
        if (item?.meta?.permission) {
 | 
			
		||||
          return permissions.includes(item.meta.permission);
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,7 +51,7 @@ export const useSettingStore = defineStore({
 | 
			
		|||
      this.persistTheme();
 | 
			
		||||
      // await changeTheme(this.theme.primaryColor);
 | 
			
		||||
    },
 | 
			
		||||
    async setPrimaryColor(color) {
 | 
			
		||||
    async setPrimaryColor(color: any) {
 | 
			
		||||
      const theme = this.theme;
 | 
			
		||||
      theme.primaryColor = color;
 | 
			
		||||
      await this.setTheme();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,13 +1,13 @@
 | 
			
		|||
import _ from "lodash";
 | 
			
		||||
export default {
 | 
			
		||||
  arrayToMap(array) {
 | 
			
		||||
  arrayToMap(array: any) {
 | 
			
		||||
    if (!array) {
 | 
			
		||||
      return {};
 | 
			
		||||
    }
 | 
			
		||||
    if (!_.isArray(array)) {
 | 
			
		||||
      return array;
 | 
			
		||||
    }
 | 
			
		||||
    const map = {};
 | 
			
		||||
    const map: any = {};
 | 
			
		||||
    for (const item of array) {
 | 
			
		||||
      if (item.key) {
 | 
			
		||||
        map[item.key] = item;
 | 
			
		||||
| 
						 | 
				
			
			@ -15,7 +15,7 @@ export default {
 | 
			
		|||
    }
 | 
			
		||||
    return map;
 | 
			
		||||
  },
 | 
			
		||||
  mapToArray(map) {
 | 
			
		||||
  mapToArray(map: any) {
 | 
			
		||||
    if (!map) {
 | 
			
		||||
      return [];
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,6 +57,9 @@ export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOpti
 | 
			
		|||
        name: {
 | 
			
		||||
          title: "名称",
 | 
			
		||||
          type: "text",
 | 
			
		||||
          search: {
 | 
			
		||||
            show: true
 | 
			
		||||
          },
 | 
			
		||||
          form: {
 | 
			
		||||
            rules: [{ required: true, message: "必填项" }]
 | 
			
		||||
          }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@
 | 
			
		|||
  <fs-page v-if="pipeline" class="page-pipeline-edit">
 | 
			
		||||
    <template #header>
 | 
			
		||||
      <div class="title">
 | 
			
		||||
        <fs-button class="back" icon="ion:chevron-back-outline" @click="goBack"></fs-button>
 | 
			
		||||
        <pi-editable v-model="pipeline.title" :hover-show="false" :disabled="!editMode"></pi-editable>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="more">
 | 
			
		||||
| 
						 | 
				
			
			@ -588,6 +589,7 @@ export default defineComponent({
 | 
			
		|||
      pipeline,
 | 
			
		||||
      currentHistory,
 | 
			
		||||
      histories,
 | 
			
		||||
      goBack,
 | 
			
		||||
      ...useTaskRet,
 | 
			
		||||
      ...useStageRet,
 | 
			
		||||
      ...useTrigger(),
 | 
			
		||||
| 
						 | 
				
			
			@ -602,6 +604,10 @@ export default defineComponent({
 | 
			
		|||
.page-pipeline-edit {
 | 
			
		||||
  .fs-page-header {
 | 
			
		||||
    .title {
 | 
			
		||||
      display: flex;
 | 
			
		||||
      .back {
 | 
			
		||||
        margin-right: 10px;
 | 
			
		||||
      }
 | 
			
		||||
      .pi-editable {
 | 
			
		||||
        width: 300px;
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 56 KiB  | 
| 
						 | 
				
			
			@ -5,7 +5,7 @@
 | 
			
		|||
    </div>
 | 
			
		||||
    <p class="d2-page-cover__sub-title">让你的证书永不过期</p>
 | 
			
		||||
    <div class="content">
 | 
			
		||||
      <img src="./image/preview.png" class="preview_img" />
 | 
			
		||||
      <img src="/images/preview.png" class="preview_img" />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="footer_box">
 | 
			
		||||
      <div class="left"></div>
 | 
			
		||||
| 
						 | 
				
			
			@ -76,6 +76,7 @@ export default defineComponent({
 | 
			
		|||
    width: 80%;
 | 
			
		||||
    .preview_img {
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      border: 1px solid #eee;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,7 +40,7 @@ export class UserController extends CrudController<UserService> {
 | 
			
		|||
    const users = ret.data.records;
 | 
			
		||||
 | 
			
		||||
    //获取roles
 | 
			
		||||
    const userIds = users.map((item) => item.id);
 | 
			
		||||
    const userIds = users.map(item => item.id);
 | 
			
		||||
    const userRoles = await this.roleService.getByUserIds(userIds);
 | 
			
		||||
    const userRolesMap = new Map();
 | 
			
		||||
    for (const ur of userRoles) {
 | 
			
		||||
| 
						 | 
				
			
			@ -116,4 +116,3 @@ export class UserController extends CrudController<UserService> {
 | 
			
		|||
    return this.ok(tree);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,7 @@ import { IEmailService } from '@certd/pipeline';
 | 
			
		|||
import nodemailer from 'nodemailer';
 | 
			
		||||
import { SettingsService } from '../../system/service/settings-service';
 | 
			
		||||
import type SMTPConnection from 'nodemailer/lib/smtp-connection';
 | 
			
		||||
import { logger } from '../../../utils/logger';
 | 
			
		||||
 | 
			
		||||
export type EmailConfig = {
 | 
			
		||||
  host: string;
 | 
			
		||||
| 
						 | 
				
			
			@ -46,7 +47,7 @@ export class EmailService implements IEmailService {
 | 
			
		|||
      text: email.content,
 | 
			
		||||
    };
 | 
			
		||||
    await transporter.sendMail(mailOptions);
 | 
			
		||||
    console.log('sendEmail success', email);
 | 
			
		||||
    logger.info('sendEmail complete: ', email);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async test(userId: number, receiver: string) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue