diff --git a/package.json b/package.json index e7129f7..ba77f6b 100644 --- a/package.json +++ b/package.json @@ -12,9 +12,12 @@ "dev:watch": "cross-env NODE_ENV=development concurrently -n \"Watch,Dev\" -c \"green,blue\" \"npm run watch\" \"sleep 1 && npm run dev\" ", "build": "rimraf dist && rollup -c rollup.config.mjs", "deploy": "rsync -avz --delete ./dist/ --exclude='app.config.json5' light:~/apps/codecenter/dist", + "deploy:sky": "rsync -avz --delete ./dist/ --exclude='app.config.json5' sky:~/kevisual/dist", "clean": "rm -rf dist", "reload": "ssh light pm2 restart codecenter", + "reload:sky": "ssh sky pm2 restart codecenter", "pub:me": "npm run build && npm run deploy && npm run reload", + "pub:sky": "npm run build && npm run deploy:sky && npm run reload:sky", "start": "pm2 start dist/app.mjs --name codecenter", "release": "node ./config/release/index.mjs", "pub": "envision pack -p -u", diff --git a/src/routes/app-manager/list.ts b/src/routes/app-manager/list.ts index 26ad9a3..0f1b60a 100644 --- a/src/routes/app-manager/list.ts +++ b/src/routes/app-manager/list.ts @@ -2,8 +2,8 @@ import { App, CustomError } from '@kevisual/router'; import { AppModel, AppListModel } from './module/index.ts'; import { app, redis } from '@/app.ts'; import _ from 'lodash'; -import { prefixFix } from './util.ts'; -import { deleteFiles } from '../file/index.ts'; +import { getUidByUsername, prefixFix } from './util.ts'; +import { deleteFiles, getMinioListAndSetToAppList } from '../file/index.ts'; import { setExpire } from './revoke.ts'; import { User } from '@/models/user.ts'; app @@ -67,7 +67,7 @@ app const newData = { ...app.data, ...data }; const newApp = await app.update({ data: newData, ...rest }); ctx.body = newApp; - setExpire(newApp.id, tokenUser.username); + setExpire(newApp.id, 'test'); } else { throw new CustomError('app not found'); } @@ -194,7 +194,7 @@ app const dataFiles = app.data.files || []; const newFiles = _.uniqBy([...dataFiles, ...files], 'name'); const res = await app.update({ data: { ...app.data, files: newFiles } }); - setExpire(app.id, userPrefix); + setExpire(app.id, 'test'); ctx.body = prefixFix(res, userPrefix); } catch (e) { console.log('update error', e); @@ -211,24 +211,26 @@ app }) .define(async (ctx) => { const tokenUser = ctx.state.tokenUser; - const { id } = ctx.query.data; + const { id, username } = ctx.query.data; if (!id) { throw new CustomError('id is required'); } - const app = await AppListModel.findByPk(id); - if (!app) { + + const uid = await getUidByUsername(app, ctx, username); + const appList = await AppListModel.findByPk(id); + if (!appList) { throw new CustomError('app not found'); } - const files = app.data.files || []; - const am = await AppModel.findOne({ where: { key: app.key, uid: tokenUser.id } }); + const files = appList.data.files || []; + const am = await AppModel.findOne({ where: { key: appList.key, uid: uid } }); if (!am) { throw new CustomError('app not found'); } - await am.update({ data: { ...am.data, files }, version: app.version }); - setExpire(app.key, am.user); + await am.update({ data: { ...am.data, files }, version: appList.version }); + setExpire(appList.key, am.user); ctx.body = { - key: app.key, - version: app.version, + key: appList.key, + version: appList.version, appManager: am, user: am.user, }; @@ -274,3 +276,66 @@ app return ctx; }) .addTo(app); + +app + .route({ + path: 'app', + key: 'get-minio-list', + description: '获取minio列表', + middleware: ['auth'], + }) + .define(async (ctx) => { + const tokenUser = ctx.state.tokenUser; + const { key, version } = ctx.query?.data || {}; + if (!key || !version) { + throw new CustomError('key and version are required'); + } + const files = await getMinioListAndSetToAppList({ username: tokenUser.username, appKey: key, version }); + ctx.body = files; + }) + .addTo(app); + +app + .route({ + path: 'app', + key: 'detect-version-list', + description: '检测版本列表,minio中的数据自己上传后,根据版本信息,进行替换', + middleware: ['auth'], + }) + .define(async (ctx) => { + const tokenUser = ctx.state.tokenUser; + let { key, version, username } = ctx.query?.data || {}; + if (!key || !version) { + throw new CustomError('key and version are required'); + } + const uid = await getUidByUsername(app, ctx, username); + const appList = await AppListModel.findOne({ where: { key, version, uid: uid } }); + if (!appList) { + throw new CustomError('app not found'); + } + const checkUsername = username || tokenUser.username; + const files = await getMinioListAndSetToAppList({ username: checkUsername, appKey: key, version }); + const newFiles = files.map((item) => { + return { + name: item.name.replace(`${checkUsername}/${key}/${version}/`, ''), + path: item.name, + }; + }); + let appListFiles = appList.data?.files || []; + const needAddFiles = newFiles.map((item) => { + const findFile = appListFiles.find((appListFile) => appListFile.name === item.name); + if (findFile && findFile.path === item.path) { + return findFile; + } + return item; + }); + await appList.update({ data: { files: needAddFiles } }); + setExpire(appList.id, 'test'); + const appModel = await AppModel.findOne({ where: { key, version, uid: uid } }); + if (appModel) { + await appModel.update({ data: { files: needAddFiles } }); + setExpire(appModel.key, appModel.user); + } + ctx.body = appList; + }) + .addTo(app); diff --git a/src/routes/app-manager/user-app.ts b/src/routes/app-manager/user-app.ts index 943835b..e857b9c 100644 --- a/src/routes/app-manager/user-app.ts +++ b/src/routes/app-manager/user-app.ts @@ -2,6 +2,8 @@ import { CustomError } from '@kevisual/router'; import { AppModel, AppListModel } from './module/index.ts'; import { app } from '@/app.ts'; import { setExpire } from './revoke.ts'; +import { getMinioListAndSetToAppList } from '../file/index.ts'; +import { getUidByUsername } from './util.ts'; app .route({ @@ -111,6 +113,9 @@ app if (!am) { throw new CustomError('app not found'); } + if (am.uid !== tokenUser.id) { + throw new CustomError('app not found'); + } const list = await AppListModel.findAll({ where: { key: am.key, uid: tokenUser.id } }); await am.destroy({ force: true }); await Promise.all(list.map((item) => item.destroy({ force: true }))); @@ -123,6 +128,7 @@ app .route({ path: 'user-app', key: 'test', + description: '对user-app的数据进行测试, 获取版本的信息', }) .define(async (ctx) => { const id = ctx.query.id; @@ -133,6 +139,12 @@ app if (!am) { throw new CustomError('app not found'); } - ctx.body = am; + const amJson = am.toJSON(); + ctx.body = { + ...amJson, + proxy: true, + }; }) .addTo(app); + + diff --git a/src/routes/app-manager/util.ts b/src/routes/app-manager/util.ts index 7ff6e5b..dcdda04 100644 --- a/src/routes/app-manager/util.ts +++ b/src/routes/app-manager/util.ts @@ -1,3 +1,5 @@ +import { App } from '@kevisual/router'; + type Opts = { prefix: string; }; @@ -13,3 +15,34 @@ export const prefixFix = (data: any, prefix: string, opts?: Opts) => { } return data; }; + +/** + * 根据username获取uid + * @param app + * @param ctx + * @param username + * @returns + */ +export const getUidByUsername = async (app: App, ctx: any, username?: string) => { + const tokenUser = ctx.state.tokenUser; + let uid = tokenUser.id; // TODO: 需要根据username来判断 + if (username) { + // 这个用户的数据,tokenUser具有这个org的权限才行。真实用户的那个org + const res = await app.call({ + path: 'org', + key: 'hasUser', + payload: { + data: { + username, + }, + token: ctx.query.token, + }, + }); + if (res.code === 200 && res.body?.uid) { + uid = res.body.uid; + } else { + ctx.throw(500, 'user not found'); + } + } + return uid; +}; diff --git a/src/routes/file/list.ts b/src/routes/file/list.ts index 31f11f9..8f982db 100644 --- a/src/routes/file/list.ts +++ b/src/routes/file/list.ts @@ -12,6 +12,12 @@ const handlePrefix = (prefix: string) => { } return prefix; }; +/** + * 根据用户名获取prefix + * @param data + * @param tokenUser + * @returns + */ const getPrefixByUser = (data: { prefix: string }, tokenUser: { username: string }) => { const prefixBase = '/' + tokenUser.username; const _prefix = handlePrefix(data.prefix); @@ -63,3 +69,28 @@ app return ctx; }) .addTo(app); + +app + .route({ + path: 'file', + key: 'me-all-file-stat', + middleware: ['auth'], + }) + .define(async (ctx) => { + const tokenUser = ctx.state.tokenUser; + const list = await getMinioList({ prefix: '' + tokenUser.username, recursive: true }); + const size = list.reduce((acc, item) => { + if ('size' in item) { + return acc + item.size; + } + return acc; + }, 0); + const sizeMb = size / 1024 / 1024; + ctx.body = { + list, + total: list.length, + size, + sizeMb, + }; + }) + .addTo(app); diff --git a/src/routes/file/module/get-minio-list.ts b/src/routes/file/module/get-minio-list.ts index f52becc..96a4bd6 100644 --- a/src/routes/file/module/get-minio-list.ts +++ b/src/routes/file/module/get-minio-list.ts @@ -77,3 +77,16 @@ export const deleteFiles = async (prefixs: string[]): Promise => { return false; } }; + +type GetMinioListAndSetToAppListOpts = { + username: string; + appKey: string; + version: string; +}; +// 批量列出文件,并设置到appList的files中 +export const getMinioListAndSetToAppList = async (opts: GetMinioListAndSetToAppListOpts) => { + const { username, appKey, version } = opts; + const minioList = await getMinioList({ prefix: `${username}/${appKey}/${version}`, recursive: true }); + const files = minioList; + return files as MinioFile[]; +}; diff --git a/src/routes/index.ts b/src/routes/index.ts index e4b388b..2eee2aa 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -12,6 +12,6 @@ import './app-manager/index.ts'; import './file/index.ts'; -import './packages/index.ts'; +// import './packages/index.ts'; import './micro-app/index.ts'; diff --git a/src/routes/user/org.ts b/src/routes/user/org.ts index b753942..c8fd386 100644 --- a/src/routes/user/org.ts +++ b/src/routes/user/org.ts @@ -64,6 +64,7 @@ app if (!user) { ctx.throw('user not found'); } + user.setTokenUser(tokenUser); const orgs = await user.getOrgs(); if (!orgs.includes('admin')) { ctx.throw('Permission denied'); @@ -136,3 +137,38 @@ app }; }) .addTo(app); + +app + .route({ + path: 'org', + key: 'hasUser', + middleware: ['auth'], + }) + .define(async (ctx) => { + const tokenUser = ctx.state.tokenUser; + const { username } = ctx.query.data; + const user = await User.findByPk(tokenUser.id); + if (!user) { + ctx.throw('user not found'); + } + user.setTokenUser(tokenUser); + const userOrgs = await user.hasUser(username, true); + if (!userOrgs) { + ctx.body = { + uid: null, + }; + return; + } + const usernameUser = await User.findOne({ where: { username } }); + if (!usernameUser) { + ctx.body = { + uid: null, + }; + return; + } + ctx.body = { + uid: usernameUser.id, + user: usernameUser, + }; + }) + .addTo(app);