Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4cb0d7cdad | ||
|
|
8795337a11 | ||
|
|
c0b667de46 |
+13
-8
@@ -17,10 +17,6 @@ import koaMount from 'koa-mount';
|
||||
import ConfigHelper from './ConfigHelper.mjs';
|
||||
import DBHelper from './DBHelper.mjs';
|
||||
|
||||
|
||||
const __dirname = dirname(fileURLToPath(
|
||||
import.meta.url));
|
||||
|
||||
ConfigHelper.initConfig();
|
||||
|
||||
(async () => await DBHelper.init())();
|
||||
@@ -32,14 +28,20 @@ export default CreateServer
|
||||
* 创建服务
|
||||
* port: 服务端口号
|
||||
*/
|
||||
function CreateServer(port = 4873) {
|
||||
async function CreateServer(port = 4873) {
|
||||
const __dirname = dirname(fileURLToPath(
|
||||
import.meta.url));
|
||||
const rootDir = process.cwd();
|
||||
|
||||
// console.log(__dirname, rootDir);
|
||||
|
||||
const router = new getRouter();
|
||||
const app = new Koa();
|
||||
app.use(koaBody());
|
||||
const staticPath = './static'
|
||||
app.use(
|
||||
koaMount('/resource/static', koaStatic(
|
||||
path.join(__dirname, staticPath), {}
|
||||
path.join(rootDir, staticPath), {}
|
||||
))
|
||||
)
|
||||
|
||||
@@ -50,7 +52,7 @@ function CreateServer(port = 4873) {
|
||||
|
||||
|
||||
// 初始化路由
|
||||
const initRouter = (folderPath: string) => {
|
||||
const initRouter = async (folderPath: string) => {
|
||||
// 读取文件夹中的文件列表
|
||||
fs.readdir(folderPath, async (err, files) => {
|
||||
if (err) {
|
||||
@@ -73,6 +75,8 @@ function CreateServer(port = 4873) {
|
||||
const filePath = path.join(folderPath, file);
|
||||
// 动态导入文件
|
||||
const module = await import("./" + path.relative(__dirname, filePath));
|
||||
// console.log(path.relative(__dirname, filePath),__dirname,filePath);
|
||||
// const module = await import("./" +filePath);
|
||||
// 在这里可以对导入的模块进行处理,例如调用其中的函数或使用其导出的对象
|
||||
module.default(router);
|
||||
// console.log(module);
|
||||
@@ -84,7 +88,7 @@ function CreateServer(port = 4873) {
|
||||
});
|
||||
}
|
||||
|
||||
(async () => {
|
||||
await (async () => {
|
||||
// 目标文件夹的路径
|
||||
const folderPath = './routers';
|
||||
|
||||
@@ -105,6 +109,7 @@ function CreateServer(port = 4873) {
|
||||
}
|
||||
|
||||
startServer();
|
||||
return app;
|
||||
}
|
||||
|
||||
// const bH = new BackupHelper();
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
import { default as Koa } from 'koa';
|
||||
export default CreateServer;
|
||||
/**
|
||||
* 创建服务
|
||||
* port: 服务端口号
|
||||
*/
|
||||
declare function CreateServer(port?: number): void;
|
||||
declare function CreateServer(port?: number): Promise<Koa<Koa.DefaultState, Koa.DefaultContext>>;
|
||||
|
||||
+194
-193
@@ -1,46 +1,46 @@
|
||||
import F from "yaml";
|
||||
import B from "fs";
|
||||
import G from "cuid";
|
||||
import U from "lodash";
|
||||
import w, { dirname as R, join as h } from "path";
|
||||
import G from "yaml";
|
||||
import k from "fs";
|
||||
import U from "cuid";
|
||||
import A from "lodash";
|
||||
import w, { dirname as P, join as h } from "path";
|
||||
import { JSONFile as m, Low as D } from "lowdb";
|
||||
import { fileURLToPath as $ } from "url";
|
||||
import A from "koa";
|
||||
import M from "koa-router";
|
||||
import T from "koa-body";
|
||||
import z from "koa-static";
|
||||
import C from "koa-mount";
|
||||
const j = class j {
|
||||
import M from "koa";
|
||||
import T from "koa-router";
|
||||
import z from "koa-body";
|
||||
import C from "koa-static";
|
||||
import E from "koa-mount";
|
||||
const v = class v {
|
||||
static initConfig() {
|
||||
this.config = F.parse(B.readFileSync("./config.yml").toString());
|
||||
this.config = G.parse(k.readFileSync("./config.yml").toString());
|
||||
}
|
||||
};
|
||||
j.config = null;
|
||||
let u = j;
|
||||
const b = R($(
|
||||
v.config = null;
|
||||
let u = v;
|
||||
const b = P($(
|
||||
import.meta.url
|
||||
)), L = (n, a) => {
|
||||
let t = "";
|
||||
return u.config && u.config.db && u.config.db[n] ? t = u.config.path + u.config.db[n] : t = a, t;
|
||||
}, E = async () => {
|
||||
let n = L("db", h(b, "db.json"));
|
||||
const a = new m(n), t = new D(a);
|
||||
return await t.read(), t;
|
||||
)), L = (n, t) => {
|
||||
let a = "";
|
||||
return u.config && u.config.db && u.config.db[n] ? a = u.config.path + u.config.db[n] : a = t, a;
|
||||
}, I = async () => {
|
||||
let n = L("resourceDB", h(b, "resourceDB.json"));
|
||||
const a = new m(n), t = new D(a);
|
||||
return await t.read(), t;
|
||||
let n = L("db", h(b, "db.json"));
|
||||
const t = new m(n), a = new D(t);
|
||||
return await a.read(), a;
|
||||
}, O = async () => {
|
||||
let n = L("backupDB", h(b, "backupDB.json"));
|
||||
const a = new m(n), t = new D(a);
|
||||
return await t.read(), t;
|
||||
let n = L("resourceDB", h(b, "resourceDB.json"));
|
||||
const t = new m(n), a = new D(t);
|
||||
return await a.read(), a;
|
||||
}, J = async () => {
|
||||
let n = L("backupDB", h(b, "backupDB.json"));
|
||||
const t = new m(n), a = new D(t);
|
||||
return await a.read(), a;
|
||||
}, K = async () => {
|
||||
let n = L("logDB", h(b, "logDB.json"));
|
||||
const a = new m(n), t = new D(a);
|
||||
return await t.read(), t;
|
||||
}, y = class y {
|
||||
const t = new m(n), a = new D(t);
|
||||
return await a.read(), a;
|
||||
}, f = class f {
|
||||
static async init() {
|
||||
this.baseDB = await E(), this.resourceDB = await I(), this.backupDB = await O(), this.logDB = await J();
|
||||
this.baseDB = await I(), this.resourceDB = await O(), this.backupDB = await J(), this.logDB = await K();
|
||||
}
|
||||
static getBackupDb() {
|
||||
return this.backupDB;
|
||||
@@ -49,22 +49,22 @@ const b = R($(
|
||||
return this.logDB;
|
||||
}
|
||||
};
|
||||
y.baseDB = null, y.resourceDB = null, y.backupDB = null, y.logDB = null;
|
||||
let g = y;
|
||||
class v {
|
||||
f.baseDB = null, f.resourceDB = null, f.backupDB = null, f.logDB = null;
|
||||
let y = f;
|
||||
class R {
|
||||
static async addDataLog({
|
||||
tableName: a,
|
||||
type: t,
|
||||
tableName: t,
|
||||
type: a,
|
||||
data: i
|
||||
}) {
|
||||
const e = await g.getLogDb();
|
||||
const e = await y.getLogDb();
|
||||
return p.create({
|
||||
db: e,
|
||||
name: "dataLog",
|
||||
data: {
|
||||
dataId: i.id,
|
||||
type: t,
|
||||
tableName: a,
|
||||
type: a,
|
||||
tableName: t,
|
||||
data: i,
|
||||
// 待生效
|
||||
status: 0,
|
||||
@@ -73,20 +73,20 @@ class v {
|
||||
});
|
||||
}
|
||||
static async modifyDataLogStatus({
|
||||
id: a
|
||||
id: t
|
||||
}) {
|
||||
const t = await g.getLogDb(), {
|
||||
const a = await y.getLogDb(), {
|
||||
data: i,
|
||||
code: e
|
||||
} = await p.retrieveSingle({
|
||||
db: t,
|
||||
db: a,
|
||||
name: "dataLog",
|
||||
params: {
|
||||
id: a
|
||||
id: t
|
||||
}
|
||||
});
|
||||
e == 0 && await p.update({
|
||||
db: t,
|
||||
db: a,
|
||||
name: "dataLog",
|
||||
data: {
|
||||
...i,
|
||||
@@ -96,38 +96,38 @@ class v {
|
||||
});
|
||||
}
|
||||
}
|
||||
class S {
|
||||
class j {
|
||||
constructor({
|
||||
name: a,
|
||||
type: t
|
||||
name: t,
|
||||
type: a
|
||||
}) {
|
||||
this.name = "", this.type = "", this.id = null, this.name = a, this.type = t;
|
||||
this.name = "", this.type = "", this.id = null, this.name = t, this.type = a;
|
||||
}
|
||||
async addDataLog({
|
||||
data: a
|
||||
data: t
|
||||
}) {
|
||||
const {
|
||||
name: t,
|
||||
name: a,
|
||||
type: i
|
||||
} = this;
|
||||
if (t != "dataLog") {
|
||||
if (a != "dataLog") {
|
||||
const {
|
||||
data: e
|
||||
} = await v.addDataLog({
|
||||
tableName: t,
|
||||
} = await R.addDataLog({
|
||||
tableName: a,
|
||||
type: i,
|
||||
data: a
|
||||
data: t
|
||||
});
|
||||
this.id = e.id;
|
||||
}
|
||||
}
|
||||
async modifyDataLogStatus() {
|
||||
const {
|
||||
name: a,
|
||||
id: t
|
||||
name: t,
|
||||
id: a
|
||||
} = this;
|
||||
a != "dataLog" && t && await v.modifyDataLogStatus({
|
||||
id: t
|
||||
t != "dataLog" && a && await R.modifyDataLogStatus({
|
||||
id: a
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -138,25 +138,25 @@ class p {
|
||||
* @returns
|
||||
*/
|
||||
static async retrieveList({
|
||||
db: a,
|
||||
name: t,
|
||||
db: t,
|
||||
name: a,
|
||||
params: i
|
||||
}) {
|
||||
await a.read();
|
||||
const e = a.data[t].filter((c) => {
|
||||
let l = !0;
|
||||
await t.read();
|
||||
const e = t.data[a].filter((l) => {
|
||||
let c = !0;
|
||||
for (let r in i)
|
||||
if (!["page", "pageSize"].includes(r) && (typeof c[r] == "string" ? l = c[r].indexOf(i[r]) > -1 : typeof c[r] == "number" ? l = c[r] == i[r] : c[r] instanceof Array && (l = c[r].includes(i[r])), !l))
|
||||
if (!["page", "pageSize"].includes(r) && (typeof l[r] == "string" ? c = l[r].indexOf(i[r]) > -1 : typeof l[r] == "number" ? c = l[r] == i[r] : l[r] instanceof Array && (c = l[r].includes(i[r])), !c))
|
||||
break;
|
||||
return l;
|
||||
return c;
|
||||
}), {
|
||||
page: o,
|
||||
pageSize: s
|
||||
page: s,
|
||||
pageSize: o
|
||||
} = i;
|
||||
let d = e;
|
||||
return o && s && (d = e.slice((o - 1) * s, o * s)), {
|
||||
return s && o && (d = e.slice((s - 1) * o, s * o)), {
|
||||
code: 0,
|
||||
data: d.sort((c, l) => c.sort - l.sort) || [],
|
||||
data: d.sort((l, c) => l.sort - c.sort) || [],
|
||||
total: e.length
|
||||
};
|
||||
}
|
||||
@@ -165,16 +165,16 @@ class p {
|
||||
* @param {*} param0
|
||||
*/
|
||||
static async retrieveSingle({
|
||||
db: a,
|
||||
name: t,
|
||||
db: t,
|
||||
name: a,
|
||||
params: i
|
||||
}) {
|
||||
await a.read();
|
||||
const e = a.data[t], o = i;
|
||||
let s = {};
|
||||
return o.id && e && (s = e.find((d) => d.id == o.id)), {
|
||||
await t.read();
|
||||
const e = t.data[a], s = i;
|
||||
let o = {};
|
||||
return s.id && e && (o = e.find((d) => d.id == s.id)), {
|
||||
code: 0,
|
||||
data: s || {}
|
||||
data: o || {}
|
||||
};
|
||||
}
|
||||
/**
|
||||
@@ -182,22 +182,22 @@ class p {
|
||||
* @param {*} param0
|
||||
*/
|
||||
static async update({
|
||||
db: a,
|
||||
name: t,
|
||||
db: t,
|
||||
name: a,
|
||||
data: i
|
||||
}) {
|
||||
await a.read(), a.data[t] || (a.data[t] = []);
|
||||
const e = a.data[t], o = i.id;
|
||||
if (o && e) {
|
||||
const s = e.find((c) => c.id == o);
|
||||
s && U.merge(s, i);
|
||||
const d = new S({
|
||||
name: t,
|
||||
await t.read(), t.data[a] || (t.data[a] = []);
|
||||
const e = t.data[a], s = i.id;
|
||||
if (s && e) {
|
||||
const o = e.find((l) => l.id == s);
|
||||
o && A.merge(o, i);
|
||||
const d = new j({
|
||||
name: a,
|
||||
type: "upd"
|
||||
});
|
||||
await d.addDataLog({
|
||||
data: s
|
||||
}), await a.write(), await d.modifyDataLogStatus();
|
||||
data: o
|
||||
}), await t.write(), await d.modifyDataLogStatus();
|
||||
}
|
||||
return {
|
||||
code: 0
|
||||
@@ -208,20 +208,20 @@ class p {
|
||||
* @param {*} param0
|
||||
*/
|
||||
static async create({
|
||||
db: a,
|
||||
name: t,
|
||||
db: t,
|
||||
name: a,
|
||||
data: i
|
||||
}) {
|
||||
await a.read(), a.data[t] || (a.data[t] = []);
|
||||
const e = a.data[t];
|
||||
i.id = G(), i.createTime = /* @__PURE__ */ new Date(), e.push(i);
|
||||
const o = new S({
|
||||
name: t,
|
||||
await t.read(), t.data[a] || (t.data[a] = []);
|
||||
const e = t.data[a];
|
||||
i.id = U(), i.createTime = /* @__PURE__ */ new Date(), e.push(i);
|
||||
const s = new j({
|
||||
name: a,
|
||||
type: "add"
|
||||
});
|
||||
return await o.addDataLog({
|
||||
return await s.addDataLog({
|
||||
data: i
|
||||
}), await a.write(), await o.modifyDataLogStatus(), {
|
||||
}), await t.write(), await s.modifyDataLogStatus(), {
|
||||
code: 0,
|
||||
data: i
|
||||
};
|
||||
@@ -232,58 +232,58 @@ class p {
|
||||
* @returns
|
||||
*/
|
||||
static async delete({
|
||||
db: a,
|
||||
name: t,
|
||||
db: t,
|
||||
name: a,
|
||||
data: i
|
||||
}) {
|
||||
await a.read(), a.data[t] || (a.data[t] = []);
|
||||
const e = a.data[t], o = i.ids;
|
||||
if (o.length > 0 && e) {
|
||||
let s = null;
|
||||
await t.read(), t.data[a] || (t.data[a] = []);
|
||||
const e = t.data[a], s = i.ids;
|
||||
if (s.length > 0 && e) {
|
||||
let o = null;
|
||||
const d = [];
|
||||
for (let l = 0; l < o.length; l++) {
|
||||
s = o[l];
|
||||
const r = e.findIndex((f) => f.id == s);
|
||||
for (let c = 0; c < s.length; c++) {
|
||||
o = s[c];
|
||||
const r = e.findIndex((S) => S.id == o);
|
||||
r != -1 && (d.push(e[r]), e.splice(r, 1));
|
||||
}
|
||||
const c = new S({
|
||||
name: t,
|
||||
const l = new j({
|
||||
name: a,
|
||||
type: "del"
|
||||
});
|
||||
await c.addDataLog({
|
||||
await l.addDataLog({
|
||||
data: d
|
||||
}), await a.write(), await c.modifyDataLogStatus();
|
||||
}), await t.write(), await l.modifyDataLogStatus();
|
||||
}
|
||||
return {
|
||||
code: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
class et {
|
||||
class it {
|
||||
constructor({
|
||||
router: a,
|
||||
db: t,
|
||||
router: t,
|
||||
db: a,
|
||||
name: i
|
||||
}) {
|
||||
this.name = "", this.db = null, this.router = null, this.router = a, this.db = t, this.name = i;
|
||||
this.name = "", this.db = null, this.router = null, this.router = t, this.db = a, this.name = i;
|
||||
}
|
||||
/**
|
||||
* 创建列表数据路由
|
||||
*/
|
||||
createGetList() {
|
||||
const {
|
||||
name: a,
|
||||
db: t,
|
||||
name: t,
|
||||
db: a,
|
||||
router: i
|
||||
} = this;
|
||||
i.post(`/api/${a}/list`, async (e) => {
|
||||
i.post(`/api/${t}/list`, async (e) => {
|
||||
e.type = "application/json";
|
||||
const o = e.request.body, s = await p.retrieveList({
|
||||
db: t,
|
||||
name: a,
|
||||
params: o
|
||||
const s = e.request.body, o = await p.retrieveList({
|
||||
db: a,
|
||||
name: t,
|
||||
params: s
|
||||
});
|
||||
e.body = s;
|
||||
e.body = o;
|
||||
});
|
||||
}
|
||||
/**
|
||||
@@ -291,18 +291,18 @@ class et {
|
||||
*/
|
||||
createGetDetail() {
|
||||
const {
|
||||
name: a,
|
||||
db: t,
|
||||
name: t,
|
||||
db: a,
|
||||
router: i
|
||||
} = this;
|
||||
i.get(`/api/${a}`, async (e) => {
|
||||
i.get(`/api/${t}`, async (e) => {
|
||||
e.type = "application/json";
|
||||
const o = e.request.query, s = await p.retrieveSingle({
|
||||
db: t,
|
||||
name: a,
|
||||
params: o
|
||||
const s = e.request.query, o = await p.retrieveSingle({
|
||||
db: a,
|
||||
name: t,
|
||||
params: s
|
||||
});
|
||||
e.body = s;
|
||||
e.body = o;
|
||||
});
|
||||
}
|
||||
/**
|
||||
@@ -310,18 +310,18 @@ class et {
|
||||
*/
|
||||
createUpdate() {
|
||||
const {
|
||||
name: a,
|
||||
db: t,
|
||||
name: t,
|
||||
db: a,
|
||||
router: i
|
||||
} = this;
|
||||
i.post(`/api/${a}/upd`, async (e) => {
|
||||
i.post(`/api/${t}/upd`, async (e) => {
|
||||
e.type = "application/json";
|
||||
const o = e.request.body, s = await p.update({
|
||||
db: t,
|
||||
name: a,
|
||||
data: o
|
||||
const s = e.request.body, o = await p.update({
|
||||
db: a,
|
||||
name: t,
|
||||
data: s
|
||||
});
|
||||
e.body = s;
|
||||
e.body = o;
|
||||
});
|
||||
}
|
||||
/**
|
||||
@@ -329,18 +329,18 @@ class et {
|
||||
*/
|
||||
createAdd() {
|
||||
const {
|
||||
name: a,
|
||||
db: t,
|
||||
name: t,
|
||||
db: a,
|
||||
router: i
|
||||
} = this;
|
||||
i.post(`/api/${a}/add`, async (e) => {
|
||||
i.post(`/api/${t}/add`, async (e) => {
|
||||
e.type = "application/json";
|
||||
const o = e.request.body, s = await p.create({
|
||||
db: t,
|
||||
name: a,
|
||||
data: o
|
||||
const s = e.request.body, o = await p.create({
|
||||
db: a,
|
||||
name: t,
|
||||
data: s
|
||||
});
|
||||
e.body = s;
|
||||
e.body = o;
|
||||
});
|
||||
}
|
||||
/**
|
||||
@@ -348,76 +348,77 @@ class et {
|
||||
*/
|
||||
createDelete() {
|
||||
const {
|
||||
name: a,
|
||||
db: t,
|
||||
name: t,
|
||||
db: a,
|
||||
router: i
|
||||
} = this;
|
||||
i.post(`/api/${a}/delete`, async (e) => {
|
||||
i.post(`/api/${t}/delete`, async (e) => {
|
||||
e.type = "application/json";
|
||||
const o = e.request.body, s = await p.delete({
|
||||
db: t,
|
||||
name: a,
|
||||
data: o
|
||||
const s = e.request.body, o = await p.delete({
|
||||
db: a,
|
||||
name: t,
|
||||
data: s
|
||||
});
|
||||
e.body = s;
|
||||
e.body = o;
|
||||
});
|
||||
}
|
||||
creaetBaseRouter() {
|
||||
this.createGetList(), this.createGetDetail(), this.createAdd(), this.createUpdate(), this.createDelete();
|
||||
}
|
||||
}
|
||||
const q = R($(
|
||||
import.meta.url
|
||||
));
|
||||
u.initConfig();
|
||||
(async () => await g.init())();
|
||||
function it(n = 4873) {
|
||||
const a = new M(), t = new A();
|
||||
t.use(T()), t.use(
|
||||
C("/resource/static", z(
|
||||
w.join(q, "./static"),
|
||||
(async () => await y.init())();
|
||||
async function st(n = 4873) {
|
||||
const t = P($(
|
||||
import.meta.url
|
||||
)), a = process.cwd(), i = new T(), e = new M();
|
||||
e.use(z()), e.use(
|
||||
E("/resource/static", C(
|
||||
w.join(a, "./static"),
|
||||
{}
|
||||
))
|
||||
), t.use(a.routes()), t.use(a.allowedMethods());
|
||||
const e = (d) => {
|
||||
B.readdir(d, async (c, l) => {
|
||||
if (c) {
|
||||
console.error("Error reading directory:", c);
|
||||
), e.use(i.routes()), e.use(i.allowedMethods());
|
||||
const o = async (c) => {
|
||||
k.readdir(c, async (r, S) => {
|
||||
if (r) {
|
||||
console.error("Error reading directory:", r);
|
||||
return;
|
||||
}
|
||||
for (const r of l)
|
||||
for (const B of S)
|
||||
try {
|
||||
const f = w.join(d, r), k = await B.statSync(f);
|
||||
if (k.isDirectory())
|
||||
await e(f);
|
||||
else if (k.isFile()) {
|
||||
const P = w.join(d, r);
|
||||
(await import("./" + w.relative(q, P))).default(a);
|
||||
const g = w.join(c, B), q = await k.statSync(g);
|
||||
if (q.isDirectory())
|
||||
await o(g);
|
||||
else if (q.isFile()) {
|
||||
const F = w.join(c, B);
|
||||
(await import("./" + w.relative(t, F))).default(i);
|
||||
}
|
||||
} catch (f) {
|
||||
console.error(`Error importing ${r}:`, f);
|
||||
} catch (g) {
|
||||
console.error(`Error importing ${B}:`, g);
|
||||
}
|
||||
});
|
||||
};
|
||||
(async () => await e("./routers"))();
|
||||
let o = null;
|
||||
(() => {
|
||||
o = t.listen(n, () => {
|
||||
console.log("server is listen in ", n);
|
||||
}), o.on("close", (d, c) => {
|
||||
o = null, console.log("server is close");
|
||||
});
|
||||
await (async () => {
|
||||
await o("./routers");
|
||||
})();
|
||||
let d = null;
|
||||
return (() => {
|
||||
d = e.listen(n, () => {
|
||||
console.log("server is listen in ", n);
|
||||
}), d.on("close", (c, r) => {
|
||||
d = null, console.log("server is close");
|
||||
});
|
||||
})(), e;
|
||||
}
|
||||
export {
|
||||
p as CURDHelper,
|
||||
u as ConfigHelper,
|
||||
it as CreateServer,
|
||||
g as DBHelper,
|
||||
v as LogHelper,
|
||||
et as RouterFactor,
|
||||
O as getBackupDb,
|
||||
E as getDb,
|
||||
J as getLogDb,
|
||||
I as getResourceDb
|
||||
st as CreateServer,
|
||||
y as DBHelper,
|
||||
R as LogHelper,
|
||||
it as RouterFactor,
|
||||
J as getBackupDb,
|
||||
I as getDb,
|
||||
K as getLogDb,
|
||||
O as getResourceDb
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user