feat: save single html and update redis
This commit is contained in:
		| @@ -66,6 +66,7 @@ app | ||||
|         const newData = { ...app.data, ...data }; | ||||
|         const newApp = await app.update({ data: newData, ...rest }); | ||||
|         ctx.body = newApp; | ||||
|         setExpire(newApp.id, tokenUser.username); | ||||
|       } else { | ||||
|         throw new CustomError('app not found'); | ||||
|       } | ||||
| @@ -177,7 +178,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, 'test'); | ||||
|       ctx.body = prefixFix(res, tokenUser.username); | ||||
|     } catch (e) { | ||||
|       console.log('update error', e); | ||||
|   | ||||
| @@ -5,7 +5,7 @@ import { AppData, AppType, AppStatus } from './app.ts'; | ||||
| export type AppList = Partial<InstanceType<typeof AppListModel>>; | ||||
|  | ||||
| /** | ||||
|  * APP List 管理 | ||||
|  * APP List 管理 历史版本管理 | ||||
|  */ | ||||
| export class AppListModel extends Model { | ||||
|   declare id: string; | ||||
|   | ||||
| @@ -46,29 +46,29 @@ const add = app.route({ | ||||
| add.run = async (ctx) => { | ||||
|   const tokenUser = ctx.state.tokenUser; | ||||
|   const data = ctx.query.data; | ||||
|  | ||||
|   const _data: Container = { | ||||
|     title: '', | ||||
|     description: '', | ||||
|     code: '', | ||||
|     type: '', | ||||
|   }; | ||||
|   const container = { | ||||
|     ..._data, | ||||
|     ...data, | ||||
|   }; | ||||
|   let containerModel: any = null; | ||||
|   if (container.id) { | ||||
|     containerModel = await ContainerModel.findByPk(container.id); | ||||
|     if (containerModel) { | ||||
|       containerModel.update(container); | ||||
|       containerModel.update({ | ||||
|         ...container, | ||||
|         publish: { | ||||
|           ...containerModel.publish, | ||||
|           ...container.publish, | ||||
|         }, | ||||
|       }); | ||||
|       await containerModel.save(); | ||||
|       if (containerModel.code || containerModel.source || containerModel.sourceType) { | ||||
|         ctx.emit?.('pageEdit', { | ||||
|           source: 'container', | ||||
|           data: containerModel.toJSON(), | ||||
|           operation: 'edit', | ||||
|         }); | ||||
|       } | ||||
|     } | ||||
|   } else { | ||||
|     try { | ||||
|       containerModel = await ContainerModel.create({ | ||||
| @@ -123,7 +123,7 @@ app | ||||
|     } | ||||
|     container.publish = publish; | ||||
|     await container.save(); | ||||
|     const { title, description, key, version, fileName } = publish; | ||||
|     const { title, description, key, version, fileName, saveHTML } = publish; | ||||
|     ctx.body = container; | ||||
|     if (!key || !version || !fileName) { | ||||
|       return; | ||||
| @@ -134,6 +134,7 @@ app | ||||
|       version: version, | ||||
|       code: container.code, | ||||
|       filePath: fileName, | ||||
|       saveHTML | ||||
|     }); | ||||
|     await ctx.call({ | ||||
|       path: 'app', | ||||
| @@ -143,7 +144,7 @@ app | ||||
|         data: { | ||||
|           appKey: key, | ||||
|           version, | ||||
|           files: [uploadResult], | ||||
|           files: uploadResult, | ||||
|         }, | ||||
|       }, | ||||
|     }); | ||||
|   | ||||
| @@ -5,7 +5,7 @@ import { Op } from 'sequelize'; | ||||
| import { getContainerData } from './get-container.ts'; | ||||
| import path from 'path'; | ||||
| 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 { bucketName } from '@/modules/minio.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('..')) { | ||||
|     throw new CustomError('file path is invalid'); | ||||
|   } | ||||
|   const uploadFiles = []; | ||||
|   const minioKeyVersion = `${tokenUser.username}/${key}/${version}`; | ||||
|   const minioPath = path.join(minioKeyVersion, filePath); | ||||
|   const minioFileName = path.basename(minioPath); | ||||
|   if (!minioFileName.endsWith('.js')) { | ||||
|     saveHTML = false; | ||||
|   } | ||||
|   console.log('minioPath', minioPath); | ||||
|   // const isHTML = filePath.endsWith('.html'); | ||||
|   const name = minioPath.replace(minioKeyVersion + '/', ''); | ||||
|   await minioClient.putObject(bucketName, minioPath, code, code.length, { | ||||
|     'Content-Type': getContentType(filePath), | ||||
|     'app-source': 'user-app', | ||||
|     'Cache-Control': 'no-cache', // 缓存一年 | ||||
|     'Cache-Control': 'no-cache', // no-cache | ||||
|   }); | ||||
|   return { | ||||
|   uploadFiles.push({ | ||||
|     name, | ||||
|     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 }) => { | ||||
|   const minioPath = `${tokenUser.username}/${key}/${version}/${path}`; | ||||
|   | ||||
| @@ -3,6 +3,11 @@ type HTMLOptions = { | ||||
|   rootId: string; | ||||
|   dataKey?: string; | ||||
| }; | ||||
| /** | ||||
|  * data list | ||||
|  * @param opts | ||||
|  * @returns | ||||
|  */ | ||||
| export const getHTML = (opts: HTMLOptions) => { | ||||
|   return `<!DOCTYPE html> | ||||
| <html lang="zh-CN"> | ||||
| @@ -45,3 +50,51 @@ export const getHTML = (opts: HTMLOptions) => { | ||||
| export const getDataJs = (result: any) => { | ||||
|   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>`; | ||||
| }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user