From cd61d08dc0073b327110aab45a6e40aeb5881e3f Mon Sep 17 00:00:00 2001 From: ChunghwaMC <92585552+ChunghwaMC@users.noreply.github.com> Date: Wed, 7 Aug 2024 23:09:21 +0800 Subject: [PATCH 1/7] add README_JP.md link --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c4bf2799..bf2b1469 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ [Official Website](http://mcsmanager.com/) | [Docs](https://docs.mcsmanager.com/) | [Discord](https://discord.gg/BNpYMVX7Cd) -[English](README.md) | [简体中文](README_ZH.md) | [繁體中文](README_TW.md) | [Português BR](README_PTBR.md) - +[English](README.md) | [简体中文](README_ZH.md) | [繁體中文](README_TW.md) | [Português BR](README_PTBR.md) | +[日本語](README_JP.md)
From 454fdd43bf0cddecf1cf4c33e7050681f00e4905 Mon Sep 17 00:00:00 2001 From: ChunghwaMC <92585552+ChunghwaMC@users.noreply.github.com> Date: Wed, 7 Aug 2024 23:09:34 +0800 Subject: [PATCH 2/7] add README_JP.md link --- README_ZH.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README_ZH.md b/README_ZH.md index 63cffabf..b4740804 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -16,7 +16,8 @@ [官方网站](http://mcsmanager.com/) | [使用文档](https://docs.mcsmanager.com/#/zh-cn/) | [QQ 群](https://jq.qq.com/?_wv=1027&k=Pgl9ScGw) | [TG 群](https://t.me/MCSManager_dev) | [成为赞助者](https://afdian.net/a/mcsmanager) -[English](README.md) | [简体中文](README_ZH.md) | [繁體中文](README_TW.md) | [Português BR](README_PTBR.md) +[English](README.md) | [简体中文](README_ZH.md) | [繁體中文](README_TW.md) | [Português BR](README_PTBR.md) | +[日本語](README_JP.md) From aed4ac1550e74cc047e4f2d598932f3657421ab9 Mon Sep 17 00:00:00 2001 From: ChunghwaMC <92585552+ChunghwaMC@users.noreply.github.com> Date: Wed, 7 Aug 2024 23:10:03 +0800 Subject: [PATCH 3/7] add README_JP.md link --- README_TW.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README_TW.md b/README_TW.md index 45589dee..6977bc39 100644 --- a/README_TW.md +++ b/README_TW.md @@ -16,7 +16,8 @@ [官方網站](http://mcsmanager.com/) | [教學說明](https://docs.mcsmanager.com/#/zh-cn/) | [TG 群組](https://t.me/MCSManager_dev) | [成為贊助者](https://afdian.net/a/mcsmanager) -[English](README.md) | [简体中文](README_ZH.md) | [繁體中文](README_TW.md) | [Português BR](README_PTBR.md) +[English](README.md) | [简体中文](README_ZH.md) | [繁體中文](README_TW.md) | [Português BR](README_PTBR.md) | +[日本語](README_JP.md) From 772d9537eecccbccd8901a6715a4003617e77f58 Mon Sep 17 00:00:00 2001 From: ChunghwaMC <92585552+ChunghwaMC@users.noreply.github.com> Date: Wed, 7 Aug 2024 23:10:16 +0800 Subject: [PATCH 4/7] add README_JP.md link --- README_PTBR.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README_PTBR.md b/README_PTBR.md index 9bf9e72e..0b9207e1 100644 --- a/README_PTBR.md +++ b/README_PTBR.md @@ -16,7 +16,8 @@ [Website Oficial](http://mcsmanager.com/) | [Documentação](https://docs.mcsmanager.com/) | [Discord](https://discord.gg/BNpYMVX7Cd) -[English](README.md) | [简体中文](README_ZH.md) | [繁體中文](README_TW.md) | [Português BR](README_PTBR.md) +[English](README.md) | [简体中文](README_ZH.md) | [繁體中文](README_TW.md) | [Português BR](README_PTBR.md) | +[日本語](README_JP.md) From 874ac73a2ab0f87b91ff7cc70446fef1a8372f01 Mon Sep 17 00:00:00 2001 From: Unitwk Date: Thu, 8 Aug 2024 12:00:10 +0800 Subject: [PATCH 5/7] Feat: Exchange Platform API --- panel/package-lock.json | 23 +++++ panel/package.json | 1 + panel/src/app/index.ts | 16 +-- panel/src/app/routers/general_user_router.ts | 80 ++------------- .../app/routers/instance_exchange_router.ts | 38 ++++++++ panel/src/app/service/exchange_service.ts | 97 +++++++++++++++++++ panel/src/app/service/instance_service.ts | 74 ++++++++++++++ panel/src/app/service/remote_command.ts | 7 +- 8 files changed, 249 insertions(+), 87 deletions(-) create mode 100755 panel/src/app/routers/instance_exchange_router.ts create mode 100644 panel/src/app/service/exchange_service.ts diff --git a/panel/package-lock.json b/panel/package-lock.json index a295f787..ecdbc0af 100644 --- a/panel/package-lock.json +++ b/panel/package-lock.json @@ -25,6 +25,7 @@ "log4js": "^6.4.0", "md5": "^2.3.0", "module-alias": "^2.2.3", + "nanoid": "^5.0.7", "node-schedule": "^2.0.0", "open": "^8.4.0", "os-utils": "0.0.14", @@ -3268,6 +3269,23 @@ "mustache": "bin/mustache" } }, + "node_modules/nanoid": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.7.tgz", + "integrity": "sha512-oLxFY2gd2IqnjcYyOXD8XGCftpGtZP2AbHbOkthDkvRywH5ayNtPVy9YlOPcHckXzbLTCHpkb7FB+yuxKV13pQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -7355,6 +7373,11 @@ "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==" }, + "nanoid": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.7.tgz", + "integrity": "sha512-oLxFY2gd2IqnjcYyOXD8XGCftpGtZP2AbHbOkthDkvRywH5ayNtPVy9YlOPcHckXzbLTCHpkb7FB+yuxKV13pQ==" + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", diff --git a/panel/package.json b/panel/package.json index 6b132999..739f73da 100644 --- a/panel/package.json +++ b/panel/package.json @@ -34,6 +34,7 @@ "log4js": "^6.4.0", "md5": "^2.3.0", "module-alias": "^2.2.3", + "nanoid": "^5.0.7", "node-schedule": "^2.0.0", "open": "^8.4.0", "os-utils": "0.0.14", diff --git a/panel/src/app/index.ts b/panel/src/app/index.ts index bdfd7dbc..b8306a6c 100755 --- a/panel/src/app/index.ts +++ b/panel/src/app/index.ts @@ -1,39 +1,27 @@ -// Define subsystem loading and routing loading for the application - import Koa from "koa"; import Router from "@koa/router"; -// Load subsystem import "./service/user_service"; import "./service/visual_data"; import "./service/remote_service"; import "./service/user_statistics"; -// Load routes import overviewRouter from "./routers/overview_router"; - import userRouter from "./routers/user_overview_router"; import loginRouter from "./routers/login_router"; import lowUserRouter from "./routers/general_user_router"; - import settingsRouter from "./routers/settings_router"; - import instanceRouter from "./routers/instance_admin_router"; import userInstanceRouter from "./routers/instance_operate_router"; - import serviceRouter from "./routers/daemon_router"; import filemanager_router from "./routers/filemananger_router"; - import businessInstanceRouter from "./routers/business_instance_router"; import businessUserRouter from "./routers/manage_user_router"; - import scheduleRouter from "./routers/schedule_router"; - import environmentRouter from "./routers/environment_router"; +import exchangeRouter from "./routers/instance_exchange_router"; -// all routes load entry points export function mountRouters(app: Koa) { - // API router const apiRouter = new Router({ prefix: "/api" }); apiRouter.use(overviewRouter.routes()).use(overviewRouter.allowedMethods()); apiRouter.use(userInstanceRouter.routes()).use(userInstanceRouter.allowedMethods()); @@ -48,7 +36,7 @@ export function mountRouters(app: Koa) { apiRouter.use(scheduleRouter.routes()).use(scheduleRouter.allowedMethods()); apiRouter.use(settingsRouter.routes()).use(settingsRouter.allowedMethods()); apiRouter.use(environmentRouter.routes()).use(environmentRouter.allowedMethods()); + apiRouter.use(exchangeRouter.routes()).use(exchangeRouter.allowedMethods()); - // Top router app.use(apiRouter.routes()).use(apiRouter.allowedMethods()); } diff --git a/panel/src/app/routers/general_user_router.ts b/panel/src/app/routers/general_user_router.ts index c854004a..51dad05c 100755 --- a/panel/src/app/routers/general_user_router.ts +++ b/panel/src/app/routers/general_user_router.ts @@ -4,13 +4,13 @@ import permission from "../middleware/permission"; import { bind2FA, confirm2FaQRCode, getUserUuid, logout } from "../service/passport_service"; import userSystem from "../service/user_service"; import { getToken, isAjax } from "../service/passport_service"; -import RemoteServiceSubsystem from "../service/remote_service"; -import RemoteRequest from "../service/remote_command"; import { isTopPermissionByUuid } from "../service/permission_service"; import validator from "../middleware/validator"; import { v4 } from "uuid"; import { $t } from "../i18n"; import { ROLE } from "../entity/user"; +import { getInstancesByUuid } from "../service/instance_service"; +import { toBoolean } from "common"; const router = new Router({ prefix: "/auth" }); @@ -36,79 +36,15 @@ router.get("/", permission({ level: ROLE.USER, token: false, speedLimit: false } let uuid = getUserUuid(ctx); // The front end can choose to require advanced data const advanced = ctx.query.advanced; + // Admin permissions can be obtained from anyone - if (isTopPermissionByUuid(uuid)) { - if (ctx.query.uuid) uuid = String(ctx.query.uuid); - } + if (isTopPermissionByUuid(uuid) && ctx.query.uuid) uuid = String(ctx.query.uuid); + // Some and only Ajax requests grant access if (isAjax(ctx)) { - const user = userSystem.getInstance(uuid); - if (!user) throw new Error("The UID does not exist"); - - // Advanced functions are optional, analyze each instance data - let resInstances = []; - if (advanced) { - const instances = user.instances; - for (const iterator of instances) { - const remoteService = RemoteServiceSubsystem.getInstance(iterator.daemonId); - // If the remote service doesn't exist at all, load a deleted prompt - if (!remoteService) { - resInstances.push({ - hostIp: "-- Unknown --", - instanceUuid: iterator.instanceUuid, - daemonId: iterator.daemonId, - status: -1, - nickname: "--", - remarks: "--" - }); - continue; - } - try { - // Note: UUID can be integrated here to save the returned traffic, and this optimization will not be done for the time being - let instancesInfo = await new RemoteRequest(remoteService).request("instance/section", { - instanceUuids: [iterator.instanceUuid] - }); - instancesInfo = instancesInfo[0]; - resInstances.push({ - hostIp: `${remoteService.config.ip}:${remoteService.config.port}`, - remarks: remoteService.config.remarks, - instanceUuid: instancesInfo.instanceUuid, - daemonId: remoteService.uuid, - status: instancesInfo.status, - nickname: instancesInfo.config.nickname, - ie: instancesInfo.config.ie, - oe: instancesInfo.config.oe, - endTime: instancesInfo.config.endTime, - lastDatetime: instancesInfo.config.lastDatetime, - stopCommand: instancesInfo.config.stopCommand - }); - } catch (error: any) { - resInstances.push({ - hostIp: `${remoteService.config.ip}:${remoteService.config.port}`, - instanceUuid: iterator.instanceUuid, - daemonId: iterator.daemonId, - status: -1, - nickname: "--" - }); - } - } - } else { - resInstances = user.instances; - } - // respond to user data - ctx.body = { - uuid: user.uuid, - userName: user.userName, - loginTime: user.loginTime, - registerTime: user.registerTime, - instances: resInstances, - permission: user.permission, - token: getToken(ctx), - apiKey: user.apiKey, - isInit: user.isInit, - open2FA: user.open2FA, - secret: user.secret - }; + const res = await getInstancesByUuid(uuid, toBoolean(advanced) || false); + res.token = getToken(ctx); + ctx.body = res; } }); diff --git a/panel/src/app/routers/instance_exchange_router.ts b/panel/src/app/routers/instance_exchange_router.ts new file mode 100755 index 00000000..22595443 --- /dev/null +++ b/panel/src/app/routers/instance_exchange_router.ts @@ -0,0 +1,38 @@ +import Router from "@koa/router"; +import permission from "../middleware/permission"; +import validator from "../middleware/validator"; +import { ROLE } from "../entity/user"; +import { + buyOrRenewInstance, + queryInstanceByUserId, + RequestAction +} from "../service/exchange_service"; + +const router = new Router({ prefix: "/exchange" }); + +router.post( + "/", + permission({ level: ROLE.ADMIN }), + validator({ + body: { + request_action: String + } + }), + async (ctx) => { + try { + const requestAction = ctx.request.body.request_action; + const params = ctx.request.body.data ?? {}; + if ([RequestAction.RENEW, RequestAction.BUY].includes(requestAction)) { + ctx.body = await buyOrRenewInstance(requestAction, params); + return; + } + if (requestAction === RequestAction.QUERY_INSTANCE) { + ctx.body = await queryInstanceByUserId(params); + } + } catch (err) { + ctx.body = err; + } + } +); + +export default router; diff --git a/panel/src/app/service/exchange_service.ts b/panel/src/app/service/exchange_service.ts new file mode 100644 index 00000000..b6d7ab14 --- /dev/null +++ b/panel/src/app/service/exchange_service.ts @@ -0,0 +1,97 @@ +import RemoteServiceSubsystem from "../service/remote_service"; +import RemoteRequest from "../service/remote_command"; +import user_service from "../service/user_service"; +import { customAlphabet } from "nanoid"; +import { t } from "i18next"; +import { toNumber, toText } from "common"; +import { getInstancesByUuid } from "./instance_service"; + +const getNanoId = customAlphabet( + "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", + 6 +); + +export enum RequestAction { + BUY = "buy", + RENEW = "sell", + QUERY_INSTANCE = "query_instance" +} + +export async function buyOrRenewInstance( + request_action: RequestAction, + params: Record +) { + const node_id = toText(params.node_id) ?? ""; + const instance_id = toText(params.instance_id) ?? ""; + const username = toText(params.username) ?? ""; + const hours = toNumber(params.hours) ?? 0; + const payload = params.payload ?? {}; + + const remoteService = RemoteServiceSubsystem.getInstance(node_id || ""); + if (!remoteService?.available) { + throw new Error(t("远程节点处于离线状态,请联系管理员检查面板在线状态!")); + } + + const { request: remoteRequest } = new RemoteRequest(remoteService); + + if (request_action === RequestAction.BUY) { + payload.endTime = (payload.endTime ? payload.endTime : Date.now()) + hours * 3600 * 1000; + const { instanceUuid: newInstanceId, config: newInstanceConfig } = await remoteRequest( + "instance/new", + payload + ); + if (!newInstanceId) throw new Error(t("创建实例失败,请稍后重试")); + const newPassword = getNanoId(12); + const newUser = await user_service.create({ + userName: username + "-" + getNanoId(6), + passWord: newPassword, + permission: 1, + instances: [ + { + instanceUuid: newInstanceId, + daemonId: node_id + } + ] + }); + + return { + instance_id: newInstanceId, + instance_config: newInstanceConfig, + username: newUser.userName, + password: newPassword, + uuid: newUser.uuid, + expire: toNumber(newInstanceConfig.endTime) + }; + } + + if (request_action === RequestAction.RENEW) { + const instanceInfo = await remoteRequest("instance/detail", { + instanceUuid: instance_id + }); + if (!instanceInfo.config) throw new Error(t("获取指定实例详情失败,请重试!")); + instanceInfo.config.endTime = + (instanceInfo.config?.endTime ? instanceInfo.config.endTime : Date.now()) + + hours * 3600 * 1000; + await remoteRequest("instance/update", { + instanceUuid: instance_id, + config: instanceInfo.config + }); + return { + instance_id, + instance_config: instanceInfo.config, + expire: toNumber(instanceInfo.config.endTime), + username: "", + password: "", + uuid: "" + }; + } + + throw new Error(t("请求类型错误,请重试!")); +} + +export async function queryInstanceByUserId(params: Record) { + const uuid = toText(params.uuid) || ""; + const user = user_service.getInstance(uuid); + if (!user) throw new Error(t("用户不存在,请重试")); + return await getInstancesByUuid(uuid, false); +} diff --git a/panel/src/app/service/instance_service.ts b/panel/src/app/service/instance_service.ts index f067443d..4a5c026e 100755 --- a/panel/src/app/service/instance_service.ts +++ b/panel/src/app/service/instance_service.ts @@ -1,3 +1,7 @@ +import userSystem from "../service/user_service"; +import RemoteServiceSubsystem from "../service/remote_service"; +import RemoteRequest from "../service/remote_command"; + // Multi-forward operation method export function multiOperationForwarding( instances: any[], @@ -22,3 +26,73 @@ export function multiOperationForwarding( callback(daemonId, instanceUuids); } } + +export async function getInstancesByUuid(uuid: string, advanced: boolean = false) { + const user = userSystem.getInstance(uuid); + if (!user) throw new Error("The UID does not exist"); + + // Advanced functions are optional, analyze each instance data + let resInstances = []; + if (advanced) { + const instances = user.instances; + for (const iterator of instances) { + const remoteService = RemoteServiceSubsystem.getInstance(iterator.daemonId); + // If the remote service doesn't exist at all, load a deleted prompt + if (!remoteService) { + resInstances.push({ + hostIp: "-- Unknown --", + instanceUuid: iterator.instanceUuid, + daemonId: iterator.daemonId, + status: -1, + nickname: "--", + remarks: "--" + }); + continue; + } + try { + // Note: UUID can be integrated here to save the returned traffic, and this optimization will not be done for the time being + let instancesInfo = await new RemoteRequest(remoteService).request("instance/section", { + instanceUuids: [iterator.instanceUuid] + }); + instancesInfo = instancesInfo[0]; + resInstances.push({ + hostIp: `${remoteService.config.ip}:${remoteService.config.port}`, + remarks: remoteService.config.remarks, + instanceUuid: instancesInfo.instanceUuid, + daemonId: remoteService.uuid, + status: instancesInfo.status, + nickname: instancesInfo.config.nickname, + ie: instancesInfo.config.ie, + oe: instancesInfo.config.oe, + endTime: instancesInfo.config.endTime, + lastDatetime: instancesInfo.config.lastDatetime, + stopCommand: instancesInfo.config.stopCommand + }); + } catch (error: any) { + resInstances.push({ + hostIp: `${remoteService.config.ip}:${remoteService.config.port}`, + instanceUuid: iterator.instanceUuid, + daemonId: iterator.daemonId, + status: -1, + nickname: "--" + }); + } + } + } else { + resInstances = user.instances; + } + // respond to user data + return { + uuid: user.uuid, + userName: user.userName, + loginTime: user.loginTime, + registerTime: user.registerTime, + instances: resInstances, + permission: user.permission, + apiKey: user.apiKey, + isInit: user.isInit, + open2FA: user.open2FA, + secret: user.secret, + token: "" + }; +} diff --git a/panel/src/app/service/remote_command.ts b/panel/src/app/service/remote_command.ts index 4cff2399..b21e1f70 100755 --- a/panel/src/app/service/remote_command.ts +++ b/panel/src/app/service/remote_command.ts @@ -23,7 +23,12 @@ export default class RemoteRequest { } // request to remote daemon - public async request(event: string, data?: any, timeout = 6000, force = false): Promise { + public async request( + event: string, + data?: any, + timeout = 6000, + force = false + ): Promise { if (!this.rService || !this.rService.socket) throw new Error($t("TXT_CODE_3d94ea16")); if (!this.rService.available && !force) throw new Error($t("TXT_CODE_b7d38e78") + ` IP: ${this.rService.config.ip}`); From 04c4c978578c3af9e2d199b805f0fc2a58c23f5f Mon Sep 17 00:00:00 2001 From: Unitwk Date: Thu, 8 Aug 2024 12:01:45 +0800 Subject: [PATCH 6/7] Feat: i18n --- languages/zh_CN.json | 7 ++++++- panel/src/app/service/exchange_service.ts | 10 +++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/languages/zh_CN.json b/languages/zh_CN.json index a0b1c259..e3a47418 100644 --- a/languages/zh_CN.json +++ b/languages/zh_CN.json @@ -1901,5 +1901,10 @@ "TXT_CODE_23a3bd72": "异常", "TXT_CODE_6b4a27dd": "网页前端无法与节点建立 WebSocket 连接,请检查网络代理配置或防火墙配置!", "TXT_CODE_a788e3eb": "内存 & 处理器", - "TXT_CODE_c5ed896f": "此刻瞬时输出内容过长,已拒绝显示..." + "TXT_CODE_c5ed896f": "此刻瞬时输出内容过长,已拒绝显示...", + "TXT_CODE_bed32084": "远程节点处于离线状态,请联系管理员检查面板在线状态!", + "TXT_CODE_728fdabf": "创建实例失败,请稍后重试", + "TXT_CODE_348c9098": "获取指定实例详情失败,请重试!", + "TXT_CODE_4aaec75c": "请求类型错误,请重试!", + "TXT_CODE_903b6c50": "用户不存在,请重试" } diff --git a/panel/src/app/service/exchange_service.ts b/panel/src/app/service/exchange_service.ts index b6d7ab14..5c48adb9 100644 --- a/panel/src/app/service/exchange_service.ts +++ b/panel/src/app/service/exchange_service.ts @@ -29,7 +29,7 @@ export async function buyOrRenewInstance( const remoteService = RemoteServiceSubsystem.getInstance(node_id || ""); if (!remoteService?.available) { - throw new Error(t("远程节点处于离线状态,请联系管理员检查面板在线状态!")); + throw new Error(t("TXT_CODE_bed32084")); } const { request: remoteRequest } = new RemoteRequest(remoteService); @@ -40,7 +40,7 @@ export async function buyOrRenewInstance( "instance/new", payload ); - if (!newInstanceId) throw new Error(t("创建实例失败,请稍后重试")); + if (!newInstanceId) throw new Error(t("TXT_CODE_728fdabf")); const newPassword = getNanoId(12); const newUser = await user_service.create({ userName: username + "-" + getNanoId(6), @@ -68,7 +68,7 @@ export async function buyOrRenewInstance( const instanceInfo = await remoteRequest("instance/detail", { instanceUuid: instance_id }); - if (!instanceInfo.config) throw new Error(t("获取指定实例详情失败,请重试!")); + if (!instanceInfo.config) throw new Error(t("TXT_CODE_348c9098")); instanceInfo.config.endTime = (instanceInfo.config?.endTime ? instanceInfo.config.endTime : Date.now()) + hours * 3600 * 1000; @@ -86,12 +86,12 @@ export async function buyOrRenewInstance( }; } - throw new Error(t("请求类型错误,请重试!")); + throw new Error(t("TXT_CODE_4aaec75c")); } export async function queryInstanceByUserId(params: Record) { const uuid = toText(params.uuid) || ""; const user = user_service.getInstance(uuid); - if (!user) throw new Error(t("用户不存在,请重试")); + if (!user) throw new Error(t("TXT_CODE_903b6c50")); return await getInstancesByUuid(uuid, false); } From d326814e0d7e790da46b6fc780307f1f44a31ca0 Mon Sep 17 00:00:00 2001 From: Unitwk Date: Thu, 8 Aug 2024 12:02:46 +0800 Subject: [PATCH 7/7] Feat: i18n --- languages/en_US.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/languages/en_US.json b/languages/en_US.json index 40250526..ccc82f91 100644 --- a/languages/en_US.json +++ b/languages/en_US.json @@ -1901,5 +1901,10 @@ "TXT_CODE_930d2524": "Direct connection to web page", "TXT_CODE_e039b9b5": "normal", "TXT_CODE_a788e3eb": "Memory & Processor", - "TXT_CODE_c5ed896f": "The instantaneous output content is too long and has been rejected...." + "TXT_CODE_c5ed896f": "The instantaneous output content is too long and has been rejected....", + "TXT_CODE_bed32084": "The remote node is offline, please contact the administrator to check the online status of the panel!", + "TXT_CODE_728fdabf": "Failed to create the instance, please try again later", + "TXT_CODE_348c9098": "Failed to obtain the details of the specified instance, please try again!", + "TXT_CODE_4aaec75c": "Wrong request type, please try again!", + "TXT_CODE_903b6c50": "User does not exist, please try again" }