feat: save single html and update redis

This commit is contained in:
xion 2024-10-27 17:46:59 +08:00
parent c6539439e9
commit e032c092d9
5 changed files with 97 additions and 23 deletions

View File

@ -66,6 +66,7 @@ app
const newData = { ...app.data, ...data }; const newData = { ...app.data, ...data };
const newApp = await app.update({ data: newData, ...rest }); const newApp = await app.update({ data: newData, ...rest });
ctx.body = newApp; ctx.body = newApp;
setExpire(newApp.id, tokenUser.username);
} else { } else {
throw new CustomError('app not found'); throw new CustomError('app not found');
} }
@ -177,7 +178,7 @@ app
const dataFiles = app.data.files || []; const dataFiles = app.data.files || [];
const newFiles = _.uniqBy([...dataFiles, ...files], 'name'); const newFiles = _.uniqBy([...dataFiles, ...files], 'name');
const res = await app.update({ data: { ...app.data, files: newFiles } }); const res = await app.update({ data: { ...app.data, files: newFiles } });
setExpire(app.id, 'test');
ctx.body = prefixFix(res, tokenUser.username); ctx.body = prefixFix(res, tokenUser.username);
} catch (e) { } catch (e) {
console.log('update error', e); console.log('update error', e);

View File

@ -5,7 +5,7 @@ import { AppData, AppType, AppStatus } from './app.ts';
export type AppList = Partial<InstanceType<typeof AppListModel>>; export type AppList = Partial<InstanceType<typeof AppListModel>>;
/** /**
* APP List * APP List
*/ */
export class AppListModel extends Model { export class AppListModel extends Model {
declare id: string; declare id: string;

View File

@ -46,29 +46,29 @@ const add = app.route({
add.run = async (ctx) => { add.run = async (ctx) => {
const tokenUser = ctx.state.tokenUser; const tokenUser = ctx.state.tokenUser;
const data = ctx.query.data; const data = ctx.query.data;
const _data: Container = {
title: '',
description: '',
code: '',
type: '',
};
const container = { const container = {
..._data,
...data, ...data,
}; };
let containerModel: any = null; let containerModel: any = null;
if (container.id) { if (container.id) {
containerModel = await ContainerModel.findByPk(container.id); containerModel = await ContainerModel.findByPk(container.id);
if (containerModel) { if (containerModel) {
containerModel.update(container); containerModel.update({
...container,
publish: {
...containerModel.publish,
...container.publish,
},
});
await containerModel.save(); await containerModel.save();
if (containerModel.code || containerModel.source || containerModel.sourceType) {
ctx.emit?.('pageEdit', { ctx.emit?.('pageEdit', {
source: 'container', source: 'container',
data: containerModel.toJSON(), data: containerModel.toJSON(),
operation: 'edit', operation: 'edit',
}); });
} }
}
} else { } else {
try { try {
containerModel = await ContainerModel.create({ containerModel = await ContainerModel.create({
@ -123,7 +123,7 @@ app
} }
container.publish = publish; container.publish = publish;
await container.save(); await container.save();
const { title, description, key, version, fileName } = publish; const { title, description, key, version, fileName, saveHTML } = publish;
ctx.body = container; ctx.body = container;
if (!key || !version || !fileName) { if (!key || !version || !fileName) {
return; return;
@ -134,6 +134,7 @@ app
version: version, version: version,
code: container.code, code: container.code,
filePath: fileName, filePath: fileName,
saveHTML
}); });
await ctx.call({ await ctx.call({
path: 'app', path: 'app',
@ -143,7 +144,7 @@ app
data: { data: {
appKey: key, appKey: key,
version, version,
files: [uploadResult], files: uploadResult,
}, },
}, },
}); });

View File

@ -5,7 +5,7 @@ import { Op } from 'sequelize';
import { getContainerData } from './get-container.ts'; import { getContainerData } from './get-container.ts';
import path from 'path'; import path from 'path';
import fs from 'fs'; import fs from 'fs';
import { getHTML, getDataJs } from './file-template.ts'; import { getHTML, getDataJs, getOneHTML } from './file-template.ts';
import { minioClient } from '@/app.ts'; import { minioClient } from '@/app.ts';
import { bucketName } from '@/modules/minio.ts'; import { bucketName } from '@/modules/minio.ts';
import { getContentType } from '@/utils/get-content-type.ts'; import { getContentType } from '@/utils/get-content-type.ts';
@ -65,24 +65,43 @@ export const cachePage = async (page: PageModel, opts: { tokenUser: any; key; ve
}, },
]; ];
}; };
export const uploadMinioContainer = async ({ tokenUser, key, version, code, filePath }) => { export const uploadMinioContainer = async ({ tokenUser, key, version, code, filePath, saveHTML }) => {
if ((filePath as string).includes('..')) { if ((filePath as string).includes('..')) {
throw new CustomError('file path is invalid'); throw new CustomError('file path is invalid');
} }
const uploadFiles = [];
const minioKeyVersion = `${tokenUser.username}/${key}/${version}`; const minioKeyVersion = `${tokenUser.username}/${key}/${version}`;
const minioPath = path.join(minioKeyVersion, filePath); const minioPath = path.join(minioKeyVersion, filePath);
const minioFileName = path.basename(minioPath);
if (!minioFileName.endsWith('.js')) {
saveHTML = false;
}
console.log('minioPath', minioPath); console.log('minioPath', minioPath);
// const isHTML = filePath.endsWith('.html'); // const isHTML = filePath.endsWith('.html');
const name = minioPath.replace(minioKeyVersion + '/', ''); const name = minioPath.replace(minioKeyVersion + '/', '');
await minioClient.putObject(bucketName, minioPath, code, code.length, { await minioClient.putObject(bucketName, minioPath, code, code.length, {
'Content-Type': getContentType(filePath), 'Content-Type': getContentType(filePath),
'app-source': 'user-app', 'app-source': 'user-app',
'Cache-Control': 'no-cache', // 缓存一年 'Cache-Control': 'no-cache', // no-cache
}); });
return { uploadFiles.push({
name, name,
path: minioPath, path: minioPath,
}; });
if (saveHTML) {
const htmlPath = minioPath.replace('.js', '.html');
const code = getOneHTML({ title: 'Kevisual', file: minioFileName.replace('.js', '') });
await minioClient.putObject(bucketName, htmlPath, code, code.length, {
'Content-Type': 'text/html',
'app-source': 'user-app',
'Cache-Control': 'max-age=31536000, immutable',
});
uploadFiles.push({
name: 'index.html',
path: htmlPath,
});
}
return uploadFiles;
}; };
export const uploadMinio = async ({ tokenUser, key, version, path, filePath }) => { export const uploadMinio = async ({ tokenUser, key, version, path, filePath }) => {
const minioPath = `${tokenUser.username}/${key}/${version}/${path}`; const minioPath = `${tokenUser.username}/${key}/${version}/${path}`;

View File

@ -3,6 +3,11 @@ type HTMLOptions = {
rootId: string; rootId: string;
dataKey?: string; dataKey?: string;
}; };
/**
* data list
* @param opts
* @returns
*/
export const getHTML = (opts: HTMLOptions) => { export const getHTML = (opts: HTMLOptions) => {
return `<!DOCTYPE html> return `<!DOCTYPE html>
<html lang="zh-CN"> <html lang="zh-CN">
@ -45,3 +50,51 @@ export const getHTML = (opts: HTMLOptions) => {
export const getDataJs = (result: any) => { export const getDataJs = (result: any) => {
return 'export const data=' + JSON.stringify(result); return 'export const data=' + JSON.stringify(result);
}; };
type OneHTMLOptions = {
title?: string;
file: string;
}
/**
* one data
* @param opts
* @returns
*/
export const getOneHTML = (opts: OneHTMLOptions) => {
return `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="https://envision.xiongxiao.me/resources/root/avatar.png"/>
<title>${opts.title || 'Kevisual'}</title>
<style>
html,
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
body {
font-size: 16px;
}
</style>
</head>
<body>
<div id="root"></div>
<script type="module">
import { ContainerOne } from 'https://kevisual.xiongxiao.me/system/lib/container.js'
import { render, unmount } from './${opts.file}.js'
const container = new ContainerOne({
root: '#root',
});
container.renderOne({
code: {render, unmount}
});
</script>
</body>
</html>`;
};