mirror of
https://github.com/certd/certd.git
synced 2026-07-16 02:37:34 +08:00
chore: format
This commit is contained in:
@@ -1,66 +1,65 @@
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
|
||||
|
||||
@Entity('pi_plugin')
|
||||
@Entity("pi_plugin")
|
||||
export class PluginEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ name: 'name', comment: 'Key' })
|
||||
@Column({ name: "name", comment: "Key" })
|
||||
name: string;
|
||||
|
||||
@Column({ name: 'icon', comment: '图标' })
|
||||
@Column({ name: "icon", comment: "图标" })
|
||||
icon: string;
|
||||
|
||||
@Column({ name: 'title', comment: '标题' })
|
||||
@Column({ name: "title", comment: "标题" })
|
||||
title: string;
|
||||
|
||||
@Column({ name: 'group', comment: '分组' })
|
||||
@Column({ name: "group", comment: "分组" })
|
||||
group: string;
|
||||
|
||||
@Column({ name: 'desc', comment: '描述' })
|
||||
@Column({ name: "desc", comment: "描述" })
|
||||
desc: string;
|
||||
|
||||
@Column({ comment: '配置', length: 40960 })
|
||||
@Column({ comment: "配置", length: 40960 })
|
||||
setting: string;
|
||||
|
||||
@Column({ name: 'sys_setting', comment: '系统配置', length: 40960 })
|
||||
@Column({ name: "sys_setting", comment: "系统配置", length: 40960 })
|
||||
sysSetting: string;
|
||||
|
||||
@Column({ comment: '脚本', length: 40960 })
|
||||
@Column({ comment: "脚本", length: 40960 })
|
||||
content: string;
|
||||
|
||||
@Column({ comment: '类型', length: 100, nullable: true })
|
||||
@Column({ comment: "类型", length: 100, nullable: true })
|
||||
type: string; // builtIn | local | download
|
||||
|
||||
@Column({ comment: '启用/禁用', default: false })
|
||||
@Column({ comment: "启用/禁用", default: false })
|
||||
disabled: boolean;
|
||||
|
||||
@Column({ comment: '版本', length: 100, nullable: true })
|
||||
@Column({ comment: "版本", length: 100, nullable: true })
|
||||
version: string;
|
||||
|
||||
@Column({ comment: '插件类型', length: 100, nullable: true })
|
||||
@Column({ comment: "插件类型", length: 100, nullable: true })
|
||||
pluginType: string;
|
||||
|
||||
@Column({ comment: '元数据', length: 40960, nullable: true })
|
||||
@Column({ comment: "元数据", length: 40960, nullable: true })
|
||||
metadata: string;
|
||||
|
||||
@Column({ comment: '额外配置', length: 40960, nullable: true })
|
||||
@Column({ comment: "额外配置", length: 40960, nullable: true })
|
||||
extra: string;
|
||||
|
||||
@Column({ comment: '作者', length: 100, nullable: true })
|
||||
@Column({ comment: "作者", length: 100, nullable: true })
|
||||
author: string;
|
||||
|
||||
|
||||
@Column({
|
||||
name: 'create_time',
|
||||
comment: '创建时间',
|
||||
default: () => 'CURRENT_TIMESTAMP',
|
||||
name: "create_time",
|
||||
comment: "创建时间",
|
||||
default: () => "CURRENT_TIMESTAMP",
|
||||
})
|
||||
createTime: Date;
|
||||
@Column({
|
||||
name: 'update_time',
|
||||
comment: '修改时间',
|
||||
default: () => 'CURRENT_TIMESTAMP',
|
||||
name: "update_time",
|
||||
comment: "修改时间",
|
||||
default: () => "CURRENT_TIMESTAMP",
|
||||
})
|
||||
updateTime: Date;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { CertApplyPluginNames } from "@certd/plugin-cert";
|
||||
|
||||
|
||||
export function getDefaultAccessPlugin() {
|
||||
const metadata = `
|
||||
input:
|
||||
@@ -18,7 +17,7 @@ input:
|
||||
component:
|
||||
name: a-input
|
||||
allowClear: true
|
||||
`
|
||||
`;
|
||||
|
||||
const script = `
|
||||
// 必须使用 await import 来引入模块
|
||||
@@ -31,19 +30,18 @@ return class DemoAccess extends BaseAccess {
|
||||
}
|
||||
`;
|
||||
return {
|
||||
metadata:metadata,
|
||||
content: script
|
||||
metadata: metadata,
|
||||
content: script,
|
||||
};
|
||||
}
|
||||
|
||||
export function getDefaultDeployPlugin() {
|
||||
|
||||
let certApplyNames = ''
|
||||
let certApplyNames = "";
|
||||
for (const name of CertApplyPluginNames) {
|
||||
certApplyNames += `
|
||||
- "${name}"`
|
||||
- "${name}"`;
|
||||
}
|
||||
const metadata =`
|
||||
const metadata = `
|
||||
input: # 插件的输入参数
|
||||
cert:
|
||||
title: 前置任务证书
|
||||
@@ -90,8 +88,7 @@ input: # 插件的输入参数
|
||||
#output: # 输出参数,一般插件都不需要配置此项
|
||||
# outputName:
|
||||
#
|
||||
`
|
||||
|
||||
`;
|
||||
|
||||
const script = `
|
||||
// 要用await来import模块
|
||||
@@ -129,10 +126,10 @@ return class DemoTask extends AbstractTaskPlugin {
|
||||
// this.outputName = xxxx //设置输出参数,可以被其他插件选择使用
|
||||
}
|
||||
}
|
||||
`
|
||||
`;
|
||||
return {
|
||||
metadata: metadata,
|
||||
content: script
|
||||
content: script,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -144,7 +141,7 @@ accessType: aliyun # 授权类型名称
|
||||
#dependLibs: # 依赖的插件,应用商店安装时会先安装依赖插件
|
||||
# aliyun: *
|
||||
|
||||
`
|
||||
`;
|
||||
|
||||
const script = `
|
||||
const { AbstractDnsProvider } = await import("@certd/pipeline")
|
||||
@@ -186,10 +183,10 @@ return class DemoDnsProvider extends AbstractDnsProvider {
|
||||
}
|
||||
}
|
||||
|
||||
`
|
||||
`;
|
||||
|
||||
return {
|
||||
metadata: metadata,
|
||||
content: script
|
||||
}
|
||||
content: script,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import { IPluginConfigService, PluginConfig } from '@certd/pipeline';
|
||||
import { PluginConfigService } from './plugin-config-service.js';
|
||||
import { Inject, Provide, Scope, ScopeEnum } from "@midwayjs/core";
|
||||
import { IPluginConfigService, PluginConfig } from "@certd/pipeline";
|
||||
import { PluginConfigService } from "./plugin-config-service.js";
|
||||
|
||||
@Provide()
|
||||
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||
@@ -11,7 +11,7 @@ export class PluginConfigGetter implements IPluginConfigService {
|
||||
async getPluginConfig(pluginName: string): Promise<PluginConfig> {
|
||||
const res = await this.pluginConfigService.getPluginConfig({
|
||||
name: pluginName,
|
||||
type: 'builtIn',
|
||||
type: "builtIn",
|
||||
});
|
||||
return {
|
||||
name: res.name,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core';
|
||||
import { PluginService } from './plugin-service.js';
|
||||
import { Inject, Provide, Scope, ScopeEnum } from "@midwayjs/core";
|
||||
import { PluginService } from "./plugin-service.js";
|
||||
|
||||
export type PluginConfig = {
|
||||
name: string;
|
||||
@@ -20,7 +20,6 @@ export type PluginFindReq = {
|
||||
type: string;
|
||||
};
|
||||
|
||||
|
||||
@Provide()
|
||||
@Scope(ScopeEnum.Request, { allowDowngrade: true })
|
||||
export class PluginConfigService {
|
||||
@@ -31,18 +30,18 @@ export class PluginConfigService {
|
||||
const configs: CommPluginConfig = {};
|
||||
|
||||
configs.CertApply = await this.getPluginConfig({
|
||||
name: 'CertApply',
|
||||
type: 'builtIn',
|
||||
name: "CertApply",
|
||||
type: "builtIn",
|
||||
});
|
||||
return configs;
|
||||
}
|
||||
|
||||
async saveCommPluginConfig(config: CommPluginConfig) {
|
||||
config.CertApply.name = 'CertApply';
|
||||
config.CertApply.name = "CertApply";
|
||||
await this.savePluginConfig(config.CertApply);
|
||||
}
|
||||
|
||||
async savePluginConfig( config: PluginConfig) {
|
||||
async savePluginConfig(config: PluginConfig) {
|
||||
const name = config.name;
|
||||
const sysSetting = config?.sysSetting;
|
||||
if (!sysSetting) {
|
||||
@@ -55,12 +54,12 @@ export class PluginConfigService {
|
||||
await this.pluginService.add({
|
||||
name,
|
||||
sysSetting: JSON.stringify(sysSetting),
|
||||
type: 'builtIn',
|
||||
type: "builtIn",
|
||||
disabled: false,
|
||||
author: "certd",
|
||||
});
|
||||
} else {
|
||||
let setting = JSON.parse(pluginEntity.sysSetting || "{}");
|
||||
const setting = JSON.parse(pluginEntity.sysSetting || "{}");
|
||||
if (sysSetting.metadata) {
|
||||
setting.metadata = sysSetting.metadata;
|
||||
}
|
||||
@@ -73,7 +72,7 @@ export class PluginConfigService {
|
||||
|
||||
async get(req: PluginFindReq) {
|
||||
if (!req.name && !req.id) {
|
||||
throw new Error('plugin s name or id is required');
|
||||
throw new Error("plugin s name or id is required");
|
||||
}
|
||||
return await this.pluginService.getRepository().findOne({
|
||||
where: {
|
||||
|
||||
@@ -15,21 +15,21 @@ import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
export type PluginImportReq = {
|
||||
content: string,
|
||||
content: string;
|
||||
override?: boolean;
|
||||
};
|
||||
|
||||
async function importer(modulePath: string) {
|
||||
async function importer(modulePath: string) {
|
||||
if (!modulePath) {
|
||||
throw new Error("modules path 不能为空")
|
||||
throw new Error("modules path 不能为空");
|
||||
}
|
||||
if (!modulePath.startsWith("/@/")) {
|
||||
return await import(modulePath)
|
||||
return await import(modulePath);
|
||||
}
|
||||
modulePath = modulePath.replace("/@/", "")
|
||||
modulePath = modulePath.replace("/@/", "");
|
||||
//替换@为相对地址
|
||||
modulePath = `../../../${modulePath}`
|
||||
return await import(modulePath)
|
||||
modulePath = `../../../${modulePath}`;
|
||||
return await import(modulePath);
|
||||
}
|
||||
|
||||
@Provide()
|
||||
@@ -48,7 +48,6 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
async page(pageReq: PageReq<PluginEntity>) {
|
||||
|
||||
if (pageReq.query.type && pageReq.query.type !== "builtIn") {
|
||||
return await super.page(pageReq);
|
||||
}
|
||||
@@ -56,7 +55,6 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
const offset = pageReq.page.offset;
|
||||
const limit = pageReq.page.limit;
|
||||
|
||||
|
||||
const builtInList = await this.getBuiltInEntityList();
|
||||
|
||||
//获取分页数据
|
||||
@@ -66,11 +64,11 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
records: data,
|
||||
total: builtInList.length,
|
||||
offset: offset,
|
||||
limit: limit
|
||||
limit: limit,
|
||||
};
|
||||
}
|
||||
|
||||
async getEnabledBuildInGroup(opts?: { isSimple?: boolean, withSetting?: boolean }) {
|
||||
async getEnabledBuildInGroup(opts?: { isSimple?: boolean; withSetting?: boolean }) {
|
||||
const groups = this.builtInPluginService.getGroups();
|
||||
if (opts?.isSimple) {
|
||||
for (const key in groups) {
|
||||
@@ -81,7 +79,6 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!isComm()) {
|
||||
return groups;
|
||||
}
|
||||
@@ -91,14 +88,14 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
sysSetting: true
|
||||
sysSetting: true,
|
||||
},
|
||||
where: {
|
||||
sysSetting: Not(IsNull())
|
||||
}
|
||||
})
|
||||
sysSetting: Not(IsNull()),
|
||||
},
|
||||
});
|
||||
//合并插件配置
|
||||
const pluginSettingMap: any = {}
|
||||
const pluginSettingMap: any = {};
|
||||
for (const item of settingPlugins) {
|
||||
if (!item.sysSetting) {
|
||||
continue;
|
||||
@@ -113,17 +110,16 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
for (const item of group.plugins) {
|
||||
const pluginSetting = pluginSettingMap[item.name];
|
||||
if (pluginSetting) {
|
||||
item.sysSetting = pluginSetting
|
||||
item.sysSetting = pluginSetting;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//排除禁用的
|
||||
const list = await this.list({
|
||||
query: {
|
||||
disabled: true
|
||||
}
|
||||
disabled: true,
|
||||
},
|
||||
});
|
||||
const disabledNames = list.map(it => it.name);
|
||||
for (const key in groups) {
|
||||
@@ -145,8 +141,8 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
const list = await this.list({
|
||||
query: {
|
||||
type: "builtIn",
|
||||
disabled: true
|
||||
}
|
||||
disabled: true,
|
||||
},
|
||||
});
|
||||
const disabledNames = list.map(it => it.name);
|
||||
|
||||
@@ -159,8 +155,8 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
const builtInList = this.builtInPluginService.getList();
|
||||
const list = await this.list({
|
||||
query: {
|
||||
type: "builtIn"
|
||||
}
|
||||
type: "builtIn",
|
||||
},
|
||||
});
|
||||
|
||||
const records: PluginEntity[] = [];
|
||||
@@ -177,7 +173,7 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
type: "builtIn",
|
||||
icon: item.icon,
|
||||
desc: item.desc,
|
||||
group: item.group
|
||||
group: item.group,
|
||||
});
|
||||
records.push(record);
|
||||
}
|
||||
@@ -215,12 +211,11 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
* @param param 数据
|
||||
*/
|
||||
async add(param: any) {
|
||||
|
||||
const old = await this.repository.findOne({
|
||||
where: {
|
||||
name: param.name,
|
||||
author: param.author
|
||||
}
|
||||
author: param.author,
|
||||
},
|
||||
});
|
||||
|
||||
if (old) {
|
||||
@@ -248,11 +243,11 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
|
||||
const res = await super.add({
|
||||
...param,
|
||||
...plugin
|
||||
...plugin,
|
||||
});
|
||||
|
||||
await this.registerById(res.id);
|
||||
return res
|
||||
return res;
|
||||
}
|
||||
|
||||
async registerById(id: any) {
|
||||
@@ -276,20 +271,20 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
}
|
||||
let name = item.name;
|
||||
if (item.author && !item.name.startsWith(`${item.author}/`)) {
|
||||
name = `${item.author}/${item.name}`
|
||||
name = `${item.author}/${item.name}`;
|
||||
}
|
||||
if (item.pluginType === "access") {
|
||||
accessRegistry.unRegister(name)
|
||||
accessRegistry.unRegister(name);
|
||||
} else if (item.pluginType === "deploy") {
|
||||
pluginRegistry.unRegister(name)
|
||||
pluginRegistry.unRegister(name);
|
||||
} else if (item.pluginType === "dnsProvider") {
|
||||
dnsProviderRegistry.unRegister(name)
|
||||
dnsProviderRegistry.unRegister(name);
|
||||
} else if (item.pluginType === "notification") {
|
||||
notificationRegistry.unRegister(name)
|
||||
}else if (item.pluginType === "addon") {
|
||||
addonRegistry.unRegister(name)
|
||||
notificationRegistry.unRegister(name);
|
||||
} else if (item.pluginType === "addon") {
|
||||
addonRegistry.unRegister(name);
|
||||
} else {
|
||||
logger.warn(`不支持的插件类型:${item.pluginType}`)
|
||||
logger.warn(`不支持的插件类型:${item.pluginType}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,8 +292,8 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
const old = await this.repository.findOne({
|
||||
where: {
|
||||
name: param.name,
|
||||
author: param.author
|
||||
}
|
||||
author: param.author,
|
||||
},
|
||||
});
|
||||
|
||||
if (old && old.id !== param.id) {
|
||||
@@ -309,22 +304,21 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
const res = await super.update(param);
|
||||
|
||||
await this.registerById(param.id);
|
||||
return res
|
||||
return res;
|
||||
}
|
||||
|
||||
async compile(code: string) {
|
||||
const ts = await import("typescript");
|
||||
return ts.transpileModule(code, {
|
||||
compilerOptions: { module: ts.ModuleKind.ESNext }
|
||||
compilerOptions: { module: ts.ModuleKind.ESNext },
|
||||
}).outputText;
|
||||
}
|
||||
|
||||
|
||||
private async getPluginClassFromFile(item: any) {
|
||||
const scriptFilePath = item.scriptFilePath;
|
||||
const res = await import((`../../..${scriptFilePath}`))
|
||||
const classNames = Object.keys(res)
|
||||
return res[classNames[classNames.length - 1]]
|
||||
const res = await import(`../../..${scriptFilePath}`);
|
||||
const classNames = Object.keys(res);
|
||||
return res[classNames[classNames.length - 1]];
|
||||
}
|
||||
|
||||
async getPluginClassFromDb(pluginName: string) {
|
||||
@@ -341,14 +335,13 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
const info = await this.find({
|
||||
where: {
|
||||
name: name,
|
||||
author: author
|
||||
}
|
||||
author: author,
|
||||
},
|
||||
});
|
||||
if (info && info.length > 0) {
|
||||
const plugin = info[0];
|
||||
try {
|
||||
const AsyncFunction = Object.getPrototypeOf(async () => {
|
||||
}).constructor;
|
||||
const AsyncFunction = Object.getPrototypeOf(async () => {}).constructor;
|
||||
// const script = await this.compile(plugin.content);
|
||||
const script = plugin.content;
|
||||
const getPluginClass = new AsyncFunction("_ctx", script);
|
||||
@@ -357,7 +350,6 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
logger.error("编译插件失败:", e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
}
|
||||
throw new Error(`插件${pluginName}不存在`);
|
||||
}
|
||||
@@ -367,11 +359,11 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
*/
|
||||
async registerFromDb() {
|
||||
const res = await this.list({
|
||||
buildQuery: ((bq) => {
|
||||
buildQuery: bq => {
|
||||
bq.andWhere("type != :type", {
|
||||
type: "builtIn"
|
||||
type: "builtIn",
|
||||
});
|
||||
})
|
||||
},
|
||||
});
|
||||
|
||||
for (const item of res) {
|
||||
@@ -382,7 +374,7 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
async registerFromLocal(localDir: string) {
|
||||
//scan path
|
||||
const files = fs.readdirSync(localDir);
|
||||
let list = []
|
||||
let list = [];
|
||||
for (const file of files) {
|
||||
if (!file.endsWith(".yaml")) {
|
||||
continue;
|
||||
@@ -390,7 +382,6 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
const item = yaml.load(fs.readFileSync(path.join(localDir, file), "utf8"));
|
||||
|
||||
list.push(item);
|
||||
|
||||
}
|
||||
//排序
|
||||
list = list.sort((a, b) => {
|
||||
@@ -408,7 +399,7 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
const item = {
|
||||
...plugin,
|
||||
...metadata,
|
||||
...extra
|
||||
...extra,
|
||||
};
|
||||
delete item.metadata;
|
||||
delete item.content;
|
||||
@@ -416,7 +407,7 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
if (item.author && !item.name.startsWith(`${item.author}/`)) {
|
||||
item.name = item.author + "/" + item.name;
|
||||
}
|
||||
let name = item.name
|
||||
let name = item.name;
|
||||
if (item.addonType) {
|
||||
name = item.addonType + ":" + name;
|
||||
}
|
||||
@@ -444,7 +435,7 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
} else {
|
||||
return await this.getPluginClassFromDb(name);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -466,35 +457,34 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
...info,
|
||||
...metadata,
|
||||
...extra,
|
||||
content
|
||||
content,
|
||||
};
|
||||
|
||||
return yaml.dump(plugin) as string;
|
||||
}
|
||||
|
||||
async importPlugin(req: PluginImportReq) {
|
||||
|
||||
const loaded = yaml.load(req.content);
|
||||
if (!loaded) {
|
||||
throw new Error("插件内容不能为空");
|
||||
}
|
||||
delete loaded.id
|
||||
delete loaded.id;
|
||||
|
||||
const old = await this.repository.findOne({
|
||||
where: {
|
||||
name: loaded.name,
|
||||
author: loaded.author
|
||||
}
|
||||
author: loaded.author,
|
||||
},
|
||||
});
|
||||
|
||||
const metadata = {
|
||||
input: loaded.input,
|
||||
output: loaded.output
|
||||
output: loaded.output,
|
||||
};
|
||||
const extra = {
|
||||
dependPlugins: loaded.dependPlugins,
|
||||
default: loaded.default,
|
||||
showRunStrategy: loaded.showRunStrategy
|
||||
showRunStrategy: loaded.showRunStrategy,
|
||||
};
|
||||
|
||||
const pluginEntity = {
|
||||
@@ -502,7 +492,7 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
metadata: yaml.dump(metadata),
|
||||
extra: yaml.dump(extra),
|
||||
content: loaded.content,
|
||||
disabled: false
|
||||
disabled: false,
|
||||
};
|
||||
if (!pluginEntity.pluginType) {
|
||||
throw new Error(`插件类型不能为空`);
|
||||
@@ -521,7 +511,7 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
//update
|
||||
await this.update(pluginEntity);
|
||||
return {
|
||||
id: pluginEntity.id
|
||||
id: pluginEntity.id,
|
||||
};
|
||||
}
|
||||
async deleteByIds(ids: any[]) {
|
||||
@@ -531,5 +521,4 @@ export class PluginService extends BaseService<PluginEntity> {
|
||||
await this.delete(id);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user