From 0084f9878bfd81296e1ae690675881f98ce68432 Mon Sep 17 00:00:00 2001 From: abearxiong Date: Thu, 26 Feb 2026 14:13:16 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=8F=91=E5=B8=83?= =?UTF-8?q?=E5=BA=94=E7=94=A8=E7=9B=AE=E5=BD=95=E5=8A=9F=E8=83=BD=EF=BC=8C?= =?UTF-8?q?=E5=A2=9E=E5=BC=BA=E5=BA=94=E7=94=A8=E7=89=88=E6=9C=AC=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=92=8C=E6=9D=83=E9=99=90=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/app-manager/list.ts | 91 +++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 2 deletions(-) diff --git a/src/routes/app-manager/list.ts b/src/routes/app-manager/list.ts index 6016da4..33c4c5b 100644 --- a/src/routes/app-manager/list.ts +++ b/src/routes/app-manager/list.ts @@ -1,8 +1,8 @@ import { App as AppType, AppList, AppData } from './module/app-drizzle.ts'; -import { app, db, schema } from '@/app.ts'; +import { app, db, oss, schema } from '@/app.ts'; import { uniqBy } from 'es-toolkit'; import { getUidByUsername, prefixFix } from './util.ts'; -import { deleteFiles, getMinioListAndSetToAppList } from '../file/index.ts'; +import { deleteFiles, getMinioList, getMinioListAndSetToAppList } from '../file/index.ts'; import { setExpire } from './revoke.ts'; import { User } from '@/models/user.ts'; import { callDetectAppVersion } from './export.ts'; @@ -47,6 +47,16 @@ app key: 'get', middleware: ['auth'], description: '获取应用详情,可以通过id,或者key+version来获取', + metadata: { + args: { + data: z.object({ + id: z.string().optional(), + version: z.string().optional(), + key: z.string().optional(), + create: z.boolean().optional().describe('如果应用版本不存在,是否创建应用版本记录,默认false'), + }) + } + } }) .define(async (ctx) => { console.log('get app manager called'); @@ -376,11 +386,88 @@ app }) .addTo(app); +app.route({ + path: 'app', + key: 'publishDirectory', + middleware: ['auth'], + description: '发布应用目录,将某个版本的应用目录设置为当前应用的版本', + metadata: { + args: { + data: z.object({ + key: z.string().describe('应用的唯一标识'), + version: z.string().describe('应用版本'), + directory: z.string().describe('应用目录'), + }) + } + } +}).define(async (ctx) => { + const tokenUser = ctx.state.tokenUser; + const { key, version, directory } = ctx.query.data; + if (!key || !version || !directory) { + ctx.throw('key, version and directory are required'); + } + const username = tokenUser.username; + const chunks = directory.split('/').filter((item) => item); + const [_username, appWay, ...rest] = chunks; + if (username !== _username) { + ctx.throw('没有权限'); + } + let newChunks = []; + if (appWay === 'resources') { + newChunks = [username, ...rest]; + } else if (appWay === 'ai') { + newChunks = [username, 'ai', '1.0.0', ...rest]; + } + const [_, originAppKey, originVersion] = newChunks.filter((item) => item); + if (!originAppKey || !originVersion) { + ctx.throw('目录不合法'); + } + const pub = async () => { + return await app.run({ + path: 'app', + key: 'publish', + payload: { + data: { + appKey: key, + version, + detect: true, + }, + token: ctx.query.token, + }, + }) + } + // 如果发布的版本和当前版本不一致,则将目录下的文件复制到新的目录下 + if (originAppKey !== key || originVersion !== version) { + const oldPrefix = newChunks.join('/') + '/'; + const newPrefix = `${username}/${key}/${version}/`; + const listSource = await getMinioList({ prefix: oldPrefix, recursive: true }); + for (const item of listSource) { + const newName = item.name.slice(oldPrefix.length); + await oss.copyObject(item.name, `${newPrefix}${newName}`); + } + } + const appRes = await app.run({ path: 'app', key: 'get', payload: { data: { key, version, create: true }, token: ctx.query.token } }); + if (appRes.code !== 200) { + ctx.throw(appRes.message || '获取应用信息失败'); + } + const res = await pub(); + ctx.forward(res); + +}).addTo(app); app .route({ path: 'app', key: 'getApp', description: '获取应用信息,可以通过id,或者key+version来获取, 参数在data中传入', + metadata: { + args: { + data: z.object({ + id: z.string().optional(), + key: z.string().optional(), + version: z.string().optional(), + }) + } + } }) .define(async (ctx) => { const { user, key, id } = ctx.query.data;