feat: 添加发布应用目录功能,增强应用版本管理和权限校验
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
import { App as AppType, AppList, AppData } from './module/app-drizzle.ts';
|
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 { uniqBy } from 'es-toolkit';
|
||||||
import { getUidByUsername, prefixFix } from './util.ts';
|
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 { setExpire } from './revoke.ts';
|
||||||
import { User } from '@/models/user.ts';
|
import { User } from '@/models/user.ts';
|
||||||
import { callDetectAppVersion } from './export.ts';
|
import { callDetectAppVersion } from './export.ts';
|
||||||
@@ -47,6 +47,16 @@ app
|
|||||||
key: 'get',
|
key: 'get',
|
||||||
middleware: ['auth'],
|
middleware: ['auth'],
|
||||||
description: '获取应用详情,可以通过id,或者key+version来获取',
|
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) => {
|
.define(async (ctx) => {
|
||||||
console.log('get app manager called');
|
console.log('get app manager called');
|
||||||
@@ -376,11 +386,88 @@ app
|
|||||||
})
|
})
|
||||||
.addTo(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<true>({ 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
|
app
|
||||||
.route({
|
.route({
|
||||||
path: 'app',
|
path: 'app',
|
||||||
key: 'getApp',
|
key: 'getApp',
|
||||||
description: '获取应用信息,可以通过id,或者key+version来获取, 参数在data中传入',
|
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) => {
|
.define(async (ctx) => {
|
||||||
const { user, key, id } = ctx.query.data;
|
const { user, key, id } = ctx.query.data;
|
||||||
|
|||||||
Reference in New Issue
Block a user