From c33a49e8176f3dd71587cddbf7997de26e82153c Mon Sep 17 00:00:00 2001 From: "HRG @ SCExC" Date: Sun, 2 Jun 2024 10:20:01 -0400 Subject: [PATCH] add templater --- .gitignore | 2 + index.js | 103 ++++++++++++++++++++++++-- migrations/000_bootstrap_db.sql | 4 +- package-lock.json | 52 +++++++++++++ package.json | 1 + views/workshop/new_template_modal.eta | 36 +++++---- views/workshop/sidebar.eta | 8 +- views/workshop/template.eta | 69 +++++++++++++++++ 8 files changed, 248 insertions(+), 27 deletions(-) create mode 100644 views/workshop/template.eta diff --git a/.gitignore b/.gitignore index 3c3629e..172b172 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ node_modules +.DS_Store +dbs diff --git a/index.js b/index.js index 2ea2328..1949442 100644 --- a/index.js +++ b/index.js @@ -3,6 +3,7 @@ const vm = require("node:vm"); const path = require("path"); const express = require("express"); const session = require("express-session"); +const fileUpload = require("express-fileupload"); const SQLiteStore = require("better-sqlite3-session-store")(session); const betterSqlite3 = require("better-sqlite3"); const { Eta } = require("eta"); @@ -20,6 +21,7 @@ const routes = { GET: [], POST: [], PUT: [], DELETE: [] }; app.use(bodyParser.urlencoded({ extended: true })); app.use(express.static("public")); +app.use(fileUpload()); const db = betterSqlite3("./prime.db"); @@ -209,12 +211,42 @@ function updateDb(db, appDb) { db.prepare(sql).run(...values); } +function updateTemplate(db, template) { + const fields = ["content", "name", "test_object"]; + const values = fields.map((field) => template[field]); + const placeholders = fields.map((field) => `${field} = ?`).join(", "); + + const sql = `UPDATE templates SET ${placeholders} WHERE id = ?`; + values.push(template.id); + db.prepare(sql).run(...values); +} + function getTemplates(db, structureId) { return db .prepare("SELECT * from templates where structure_id = ?") .all(structureId); } +function getTemplate(db, templateId) { + return db.prepare("SELECT * from templates where id = ?").get(templateId); +} + +function getTemplateContentByName(db, structId, name) { + return db + .prepare( + "SELECT content from templates where structure_id = ? AND name = ?" + ) + .get(structId, name); +} + +function createTemplate(db, structureId, name, content, testObjectString) { + return db + .prepare( + "INSERT INTO templates (structure_id, name, content, test_object) VALUES (?, ?, ?, ?)" + ) + .run(structureId, name, content, testObjectString).lastInsertRowid; +} + function getDbsForStructure(db, structureId) { return db .prepare( @@ -280,8 +312,6 @@ function createDb(db, structId, name) { } const { LRUCache } = require("lru-cache"); -const { templateSettings } = require("dot"); -// we'll figure out max size later const templateCache = new LRUCache({ max: 100 }); function getTemplater(structId) { @@ -293,7 +323,7 @@ function getTemplater(structId) { return path; }; etaInstance.readFile = function (templateAlias) { - return getTemplateString(db, templateAlias, structId); + return getTemplateContentByName(db, structId, templateAlias).content; }; templateCache.set(structId, etaInstance); } @@ -315,9 +345,8 @@ function getDbInstance(dbId) { return dbInstance; } -function bootstrapTemplateWithHTMXetc(htmlString, blissRoute) { - console.log(htmlString); - if (htmlString.startsWith("")) { +function bootstrapTemplateWithHTMXetc(htmlString, blissRoute, wrapHTML) { + if (htmlString.startsWith("") || wrapHTML) { const $ = cheerio.load(htmlString); let head = $("head"); @@ -487,6 +516,63 @@ app.post("/workshop/:structure_id/db/:db_id/repl", (req, res) => { } }); +app.post("/workshop/:structure_id/template", (req, res) => { + let name = req.body.name; + + const template = createTemplate( + db, + req.params.structure_id, + name, + "
henlo <%= it.name %>
", + "it = { name: 'templates!' };" + ); + + return smartRedirect( + req, + res, + `/workshop/${req.params.structure_id}/template/${template}` + ); +}); + +app.put("/workshop/:structure_id/template/:template_id", (req, res) => { + let id = req.params.template_id; + let content = req.body.content; + let test_object = req.body.test_object; + + updateTemplate(db, { ...getTemplate(db, id), content, test_object }); + + return res.send("good"); +}); + +app.get("/workshop/:structure_id/template/:template_id", (req, res) => { + const template = getTemplate(db, req.params.template_id); + + return res.send( + bootstrapTemplateWithHTMXetc( + eta.render("workshop/template", { + template: template, + ...sidebarStuff(db, req.params.structure_id), + }) + ) + ); +}); + +app.get("/workshop/:structure_id/template/:template_id/preview", (req, res) => { + const template = getTemplate(db, req.params.template_id); + const eta = getTemplater(req.params.structure_id); + + const context = vm.createContext({ it: null }); + vm.runInContext(template.test_object, context); + + return res.send( + bootstrapTemplateWithHTMXetc( + eta.render(template.name, context.it), + null, + true + ) + ); +}); + app.get("/workshop/:structure_id/route/:id", (req, res) => { const route = getRoute(db, req.params.id); return res.send( @@ -581,7 +667,6 @@ app.all("*", (req, res) => { res.rawSend = res.send; res.send = (...args) => { - console.log(args[0], args[1], "bingo") res.rawSend( bootstrapTemplateWithHTMXetc( args[0], @@ -589,6 +674,10 @@ app.all("*", (req, res) => { ) ); }; + res.render = (template, context) => { + const eta = getTemplater(route.structure_id); + res.send(bootstrapTemplateWithHTMXetc(eta.render(template, context))); + }; return vm.runInContext( (route.handler += `\n\nhandler(req, res)`), context diff --git a/migrations/000_bootstrap_db.sql b/migrations/000_bootstrap_db.sql index eba2524..bd91527 100644 --- a/migrations/000_bootstrap_db.sql +++ b/migrations/000_bootstrap_db.sql @@ -32,13 +32,13 @@ CREATE TABLE templates ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, content TEXT, - user_id INTEGER, structure_id INTEGER, + test_object TEXT DEFAULT "it = {}", engine TEXT NOT NULL DEFAULT "eta", created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY(user_id) REFERENCES users(id), FOREIGN KEY(structure_id) REFERENCES structures(id) + UNIQUE(name, structure_id) ); CREATE TABLE routes ( diff --git a/package-lock.json b/package-lock.json index a438cc8..2d751cf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "ejs": "^3.1.9", "eta": "^3.2.0", "express": "^4.18.2", + "express-fileupload": "^1.5.0", "express-session": "^1.18.0", "jsdom": "^24.1.0", "lru-cache": "^10.2.0", @@ -290,6 +291,17 @@ "ieee754": "^1.1.13" } }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -829,6 +841,17 @@ "node": ">= 0.10.0" } }, + "node_modules/express-fileupload": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/express-fileupload/-/express-fileupload-1.5.0.tgz", + "integrity": "sha512-jSW3w9evqM37VWkEPkL2Ck5wUo2a8qa03MH+Ou/0ZSTpNlQFBvSLjU12k2nYcHhaMPv4JVvv6+Ac1OuLgUZb7w==", + "dependencies": { + "busboy": "^1.6.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/express-session": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.0.tgz", @@ -2189,6 +2212,14 @@ "node": ">= 0.8" } }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -2711,6 +2742,14 @@ "ieee754": "^1.1.13" } }, + "busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "requires": { + "streamsearch": "^1.1.0" + } + }, "bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -3136,6 +3175,14 @@ } } }, + "express-fileupload": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/express-fileupload/-/express-fileupload-1.5.0.tgz", + "integrity": "sha512-jSW3w9evqM37VWkEPkL2Ck5wUo2a8qa03MH+Ou/0ZSTpNlQFBvSLjU12k2nYcHhaMPv4JVvv6+Ac1OuLgUZb7w==", + "requires": { + "busboy": "^1.6.0" + } + }, "express-session": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.0.tgz", @@ -4075,6 +4122,11 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" }, + "streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" + }, "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", diff --git a/package.json b/package.json index 8957a79..b87ffa7 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "ejs": "^3.1.9", "eta": "^3.2.0", "express": "^4.18.2", + "express-fileupload": "^1.5.0", "express-session": "^1.18.0", "jsdom": "^24.1.0", "lru-cache": "^10.2.0", diff --git a/views/workshop/new_template_modal.eta b/views/workshop/new_template_modal.eta index 21f5138..7f6cdf7 100644 --- a/views/workshop/new_template_modal.eta +++ b/views/workshop/new_template_modal.eta @@ -1,16 +1,22 @@ -
-
-
Command Prompt
-
- - - +
+
+
+
Create Template
+
+ +
-
-
-
Microsoft❮R❯ Windows DOS 
-  ❮C❯ Copyright Microsoft Corp 1990-2001.
-        
C:\WINDOWS\SYSTEM32> You can build a command line easily with a window and pre tag -
-
-
\ No newline at end of file +
+
+
+ + +
+
+ + +
+
+
+
+
\ No newline at end of file diff --git a/views/workshop/sidebar.eta b/views/workshop/sidebar.eta index cb753ba..294abbb 100644 --- a/views/workshop/sidebar.eta +++ b/views/workshop/sidebar.eta @@ -24,7 +24,9 @@
    <% it.templates.map(template => { %>
  • - <%= template.alias %> + + <%= template.name %> +
  • <% }) %>
  • @@ -41,8 +43,8 @@
      <% it.dbs.map(db => { %>
    • - - <%= db.alias %> + + <%= db.alias %>
    • <% }) %> diff --git a/views/workshop/template.eta b/views/workshop/template.eta new file mode 100644 index 0000000..fbe00f1 --- /dev/null +++ b/views/workshop/template.eta @@ -0,0 +1,69 @@ + + + + + + + + +
      +
      +
      Workshop - <%~ include('/workshop/structure_name', {structure: it.structure}) %> +
      +
      +
      +
      + <%~ include('/workshop/sidebar', it) %> +
      +
      +
      + Template +
      <%= it.template.content %>
      + Test Object +
      <%= it.template.test_object %>
      + +
      +
      +
      + +
      + +
      +
      +
      +
      + + + + + \ No newline at end of file