376 lines
10 KiB
TypeScript
376 lines
10 KiB
TypeScript
import { App, CustomError } from '@kevisual/router';
|
||
import { AppModel, AppListModel } from './module/index.ts';
|
||
import { app, redis } from '@/app.ts';
|
||
import { uniqBy } from 'lodash-es';
|
||
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
|
||
.route({
|
||
path: 'app',
|
||
key: 'list',
|
||
middleware: ['auth'],
|
||
})
|
||
.define(async (ctx) => {
|
||
const tokenUser = ctx.state.tokenUser;
|
||
const data = ctx.query.data || {};
|
||
if (!data.key) {
|
||
throw new CustomError('key is required');
|
||
}
|
||
const list = await AppListModel.findAll({
|
||
order: [['updatedAt', 'DESC']],
|
||
where: {
|
||
uid: tokenUser.id,
|
||
key: data.key,
|
||
},
|
||
logging: false,
|
||
});
|
||
ctx.body = list.map((item) => prefixFix(item, tokenUser.username));
|
||
return ctx;
|
||
})
|
||
.addTo(app);
|
||
|
||
app
|
||
.route({
|
||
path: 'app',
|
||
key: 'get',
|
||
middleware: ['auth'],
|
||
})
|
||
.define(async (ctx) => {
|
||
const tokenUser = ctx.state.tokenUser;
|
||
const id = ctx.query.id;
|
||
const { key, version } = ctx.query?.data || {};
|
||
if (!id && (!key || !version)) {
|
||
throw new CustomError('id is required');
|
||
}
|
||
let am: AppListModel;
|
||
if (id) {
|
||
am = await AppListModel.findByPk(id);
|
||
} else if (key && version) {
|
||
am = await AppListModel.findOne({
|
||
where: {
|
||
key,
|
||
version,
|
||
uid: tokenUser.id,
|
||
},
|
||
});
|
||
}
|
||
if (!am) {
|
||
throw new CustomError('app not found');
|
||
}
|
||
ctx.body = prefixFix(am, tokenUser.username);
|
||
})
|
||
.addTo(app);
|
||
|
||
app
|
||
.route({
|
||
path: 'app',
|
||
key: 'update',
|
||
middleware: ['auth'],
|
||
})
|
||
.define(async (ctx) => {
|
||
const tokenUser = ctx.state.tokenUser;
|
||
const { data, id, ...rest } = ctx.query.data;
|
||
if (id) {
|
||
const app = await AppListModel.findByPk(id);
|
||
if (app) {
|
||
const newData = { ...app.data, ...data };
|
||
const newApp = await app.update({ data: newData, ...rest });
|
||
ctx.body = newApp;
|
||
setExpire(newApp.id, 'test');
|
||
} else {
|
||
throw new CustomError('app not found');
|
||
}
|
||
return;
|
||
}
|
||
|
||
if (!rest.key) {
|
||
throw new CustomError('key is required');
|
||
}
|
||
const app = await AppListModel.create({ data, ...rest, uid: tokenUser.id });
|
||
ctx.body = app;
|
||
return ctx;
|
||
})
|
||
.addTo(app);
|
||
|
||
app
|
||
.route({
|
||
path: 'app',
|
||
key: 'delete',
|
||
middleware: ['auth'],
|
||
})
|
||
.define(async (ctx) => {
|
||
const id = ctx.query.id;
|
||
const deleteFile = !!ctx.query.deleteFile; // 是否删除文件, 默认不删除
|
||
if (!id) {
|
||
throw new CustomError('id is required');
|
||
}
|
||
const app = await AppListModel.findByPk(id);
|
||
if (!app) {
|
||
throw new CustomError('app not found');
|
||
}
|
||
const am = await AppModel.findOne({ where: { key: app.key, uid: app.uid } });
|
||
if (!am) {
|
||
throw new CustomError('app not found');
|
||
}
|
||
if (am.version === app.version) {
|
||
throw new CustomError('app is published');
|
||
}
|
||
const files = app.data.files || [];
|
||
if (deleteFile && files.length > 0) {
|
||
await deleteFiles(files.map((item) => item.path));
|
||
}
|
||
await app.destroy({
|
||
force: true,
|
||
});
|
||
ctx.body = 'success';
|
||
return ctx;
|
||
})
|
||
.addTo(app);
|
||
app
|
||
.route({
|
||
path: 'app',
|
||
key: 'canUploadFiles',
|
||
middleware: ['auth'],
|
||
})
|
||
.define(async (ctx) => {
|
||
const tokenUser = ctx.state.tokenUser;
|
||
const { appKey, version } = ctx.query.data;
|
||
if (!appKey) {
|
||
throw new CustomError('appKey is required');
|
||
}
|
||
const app = await AppListModel.findOne({ where: { version: version, key: appKey, uid: tokenUser.id } });
|
||
if (!app) {
|
||
throw new CustomError('app not found');
|
||
}
|
||
ctx.body = app;
|
||
})
|
||
.addTo(app);
|
||
app
|
||
.route({
|
||
path: 'app',
|
||
key: 'uploadFiles',
|
||
middleware: ['auth'],
|
||
isDebug: true,
|
||
})
|
||
.define(async (ctx) => {
|
||
try {
|
||
const tokenUser = ctx.state.tokenUser;
|
||
const { appKey, files, version, username, description } = ctx.query.data;
|
||
if (!appKey) {
|
||
throw new CustomError('appKey is required');
|
||
}
|
||
if (!files || !files.length) {
|
||
throw new CustomError('files is required');
|
||
}
|
||
let uid = tokenUser.id;
|
||
let userPrefix = tokenUser.username;
|
||
if (username) {
|
||
try {
|
||
const _user = await User.getUserByToken(ctx.query.token);
|
||
if (_user.hasUser(username)) {
|
||
const upUser = await User.findOne({ where: { username } });
|
||
uid = upUser.id;
|
||
userPrefix = username;
|
||
}
|
||
} catch (e) {
|
||
console.log('getUserByToken error', e);
|
||
throw new CustomError('user not found');
|
||
}
|
||
}
|
||
let am = await AppModel.findOne({ where: { key: appKey, uid } });
|
||
let appIsNew = false;
|
||
if (!am) {
|
||
appIsNew = true;
|
||
am = await AppModel.create({
|
||
user: userPrefix,
|
||
key: appKey,
|
||
uid,
|
||
version: version || '0.0.0',
|
||
title: appKey,
|
||
proxy: appKey.includes('center') ? false : true,
|
||
description: description || '',
|
||
data: {
|
||
files: files || [],
|
||
},
|
||
});
|
||
}
|
||
let app = await AppListModel.findOne({ where: { version: version, key: appKey, uid: uid } });
|
||
if (!app) {
|
||
app = await AppListModel.create({
|
||
key: appKey,
|
||
version,
|
||
uid: uid,
|
||
data: {
|
||
files: [],
|
||
},
|
||
});
|
||
}
|
||
const dataFiles = app.data.files || [];
|
||
const newFiles = uniqBy([...dataFiles, ...files], 'name');
|
||
const res = await app.update({ data: { ...app.data, files: newFiles } });
|
||
if (version === am.version && !appIsNew) {
|
||
await am.update({ data: { ...am.data, files: newFiles } });
|
||
}
|
||
setExpire(app.id, 'test');
|
||
ctx.body = prefixFix(res, userPrefix);
|
||
} catch (e) {
|
||
console.log('update error', e);
|
||
throw new CustomError(e.message);
|
||
}
|
||
})
|
||
.addTo(app);
|
||
|
||
app
|
||
.route({
|
||
path: 'app',
|
||
key: 'publish',
|
||
middleware: ['auth'],
|
||
})
|
||
.define(async (ctx) => {
|
||
const tokenUser = ctx.state.tokenUser;
|
||
const { id, username, appKey, version } = ctx.query.data;
|
||
if (!id && !appKey) {
|
||
throw new CustomError('id or appKey is required');
|
||
}
|
||
|
||
const uid = await getUidByUsername(app, ctx, username);
|
||
let appList: AppListModel | null = null;
|
||
if (id) {
|
||
appList = await AppListModel.findByPk(id);
|
||
if (appList?.uid !== uid) {
|
||
throw new CustomError('no permission');
|
||
}
|
||
}
|
||
if (!appList && appKey) {
|
||
if (!version) {
|
||
throw new CustomError('version is required');
|
||
}
|
||
appList = await AppListModel.findOne({ where: { key: appKey, version, uid } });
|
||
}
|
||
if (!appList) {
|
||
throw new CustomError('app not found');
|
||
}
|
||
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: appList.version });
|
||
setExpire(appList.key, am.user);
|
||
ctx.body = {
|
||
key: appList.key,
|
||
version: appList.version,
|
||
appManager: am,
|
||
user: am.user,
|
||
};
|
||
})
|
||
.addTo(app);
|
||
|
||
app
|
||
.route({
|
||
path: 'app',
|
||
key: 'getApp',
|
||
})
|
||
.define(async (ctx) => {
|
||
const { user, key, id } = ctx.query.data;
|
||
let app;
|
||
if (id) {
|
||
app = await AppModel.findByPk(id);
|
||
} else if (user && key) {
|
||
app = await AppModel.findOne({ where: { user, key } });
|
||
} else {
|
||
throw new CustomError('user or key is required');
|
||
}
|
||
if (!app) {
|
||
throw new CustomError('app not found');
|
||
}
|
||
ctx.body = app;
|
||
})
|
||
.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: 'detectVersionList',
|
||
description: '检测版本列表,minio中的数据自己上传后,根据版本信息,进行替换',
|
||
middleware: ['auth'],
|
||
})
|
||
.define(async (ctx) => {
|
||
const tokenUser = ctx.state.tokenUser;
|
||
let { appKey, version, username } = ctx.query?.data || {};
|
||
if (!appKey || !version) {
|
||
throw new CustomError('appKey and version are required');
|
||
}
|
||
const uid = await getUidByUsername(app, ctx, username);
|
||
let appList = await AppListModel.findOne({ where: { key: appKey, version, uid } });
|
||
if (!appList) {
|
||
appList = await AppListModel.create({
|
||
key: appKey,
|
||
version,
|
||
uid,
|
||
data: {
|
||
files: [],
|
||
},
|
||
});
|
||
}
|
||
const checkUsername = username || tokenUser.username;
|
||
const files = await getMinioListAndSetToAppList({ username: checkUsername, appKey, version });
|
||
const newFiles = files.map((item) => {
|
||
return {
|
||
name: item.name.replace(`${checkUsername}/${appKey}/${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.name === item.name) {
|
||
return { ...findFile, ...item };
|
||
}
|
||
return item;
|
||
});
|
||
await appList.update({ data: { files: needAddFiles } });
|
||
setExpire(appList.id, 'test');
|
||
let am = await AppModel.findOne({ where: { key: appKey, uid } });
|
||
if (!am) {
|
||
am = await AppModel.create({
|
||
title: appKey,
|
||
key: appKey,
|
||
version: version || '0.0.0',
|
||
user: checkUsername,
|
||
uid,
|
||
data: { files: needAddFiles },
|
||
proxy: appKey.includes('center') ? false : true,
|
||
});
|
||
} else {
|
||
const appModel = await AppModel.findOne({ where: { key: appKey, version, uid } });
|
||
if (appModel) {
|
||
await appModel.update({ data: { files: needAddFiles } });
|
||
setExpire(appModel.key, appModel.user);
|
||
}
|
||
}
|
||
|
||
ctx.body = appList;
|
||
})
|
||
.addTo(app);
|