From 525642d04e0fbb3bb6dbf6cc8db0c4b9cbcfd06f Mon Sep 17 00:00:00 2001 From: metacryst Date: Fri, 21 Nov 2025 00:04:11 -0600 Subject: [PATCH] [Add User] Revamped db --- server/_/quilldb.js | 75 +++++-------- server/db/db.js | 104 +++++++++++++++--- server/db/model/Member.js | 43 ++++++++ server/db/model/Title.js | 33 ++++++ server/db/model/Token.js | 39 +++++++ server/db/model/User.js | 14 --- server/index.js | 2 + ui/_/code/quill.js | 32 ++++++ .../components/{JoinForm.js => SignupForm.js} | 4 +- ui/public/pages/Home.js | 4 +- 10 files changed, 269 insertions(+), 81 deletions(-) create mode 100644 server/db/model/Member.js create mode 100644 server/db/model/Title.js create mode 100644 server/db/model/Token.js delete mode 100644 server/db/model/User.js rename ui/public/components/{JoinForm.js => SignupForm.js} (98%) diff --git a/server/_/quilldb.js b/server/_/quilldb.js index dcab12d..09df8ee 100644 --- a/server/_/quilldb.js +++ b/server/_/quilldb.js @@ -23,37 +23,6 @@ export default class QuillDB { this.loadData() } - #checkLabelSchemas(id, entry, labelModels) { - entry.labels.forEach(label => { - const model = labelModels[label]; - if (!model) { - throw new Error("Data has unknown label or missing model: " + label) - } - model(entry); - this.#labels[label].push(id); - }); - } - - async getLabelModels() { - const labelHandlers = {}; - const labelDir = path.join(process.cwd(), 'server/db/model'); - const files = await fs.readdir(labelDir); - - for (const file of files) { - if (!file.endsWith('.js')) continue; - - const label = path.basename(file, '.js'); - const modulePath = path.join(labelDir, file); - const module = await import(pathToFileURL(modulePath).href); - labelHandlers[label] = module.default; - - if (!this.#labels[label]) { - this.#labels[label] = []; - } - } - return labelHandlers - } - async loadData() { const dbData = await fs.readFile(path.join(process.cwd(), 'db/db.json'), 'utf8'); let dbJson; @@ -81,27 +50,35 @@ export default class QuillDB { Object.preventExtensions(this); } - // superKey = "nodes" || "edges" - async writeData(superKey, key, value) { - const dbData = await fs.readFile(path.join(process.cwd(), 'db/db.json'), 'utf8'); - let dbJson; - try { - dbJson = JSON.parse(dbData); - } catch { - dbJson = [] + async getLabelModels() { + const labelHandlers = {}; + const labelDir = path.join(process.cwd(), 'server/db/model'); + const files = await fs.readdir(labelDir); + + for (const file of files) { + if (!file.endsWith('.js')) continue; + + const label = path.basename(file, '.js'); + const modulePath = path.join(labelDir, file); + const module = await import(pathToFileURL(modulePath).href); + labelHandlers[label] = module.default; + + if (!this.#labels[label]) { + this.#labels[label] = []; + } } - - dbJson[superKey][key] = value; - - await fs.writeFile(path.join(process.cwd(), 'db/db.json'), JSON.stringify(dbJson, null, 2), 'utf8') + return labelHandlers } - generateUserID() { - let id = this.#labels["User"].length + 1; - while (this.get.user(`user-${id}`)) { - id++; - } - return `user-${id}`; // O(1) most of the time + #checkLabelSchemas(id, entry, labelModels) { + entry.labels.forEach(label => { + const model = labelModels[label]; + if (!model) { + throw new Error("Data has unknown label or missing model: " + label) + } + model(entry); + this.#labels[label].push(id); + }); } async getAll() { diff --git a/server/db/db.js b/server/db/db.js index d433a0f..b04c2e5 100644 --- a/server/db/db.js +++ b/server/db/db.js @@ -1,21 +1,85 @@ import QuillDB from "../_/quilldb.js" import fs from 'fs/promises' import path from 'path' +import Title from "./model/Title.js" +import Member from './model/Member.js' +import Token from './model/Token.js' -export default class Database extends QuillDB { - tokens; +export default class Database { + nodes = []; + types = [ + { + validate: Title, + start: 0, + end: null, + }, + { + validate: Member, + start: null, + end: null, + }, + { + validate: Token, + start: null, + end: null, + }, + ] constructor() { - super() - this.loadTokens() + this.loadData() } - async loadTokens() { - const tokenData = await fs.readFile(path.join(process.cwd(), 'db/tokens.json'), 'utf8'); - let tokenJSON = JSON.parse(tokenData); - this.tokens = tokenJSON + async loadData() { + const dbData = await fs.readFile(path.join(process.cwd(), 'db/db.json'), 'utf8'); + let dbJson; + try { + dbJson = JSON.parse(dbData); + } catch { + dbJson = [] + } + let nodes = dbJson["nodes"]; + this.validateNodes(nodes) } - + + validateNodes(nodes) { + nodes = Object.entries(nodes) + + let t = 0 + + let currentType = () => {return this.types[t]} + let nextType = () => {return this.types[t+1]} + let selectNextType = () => { + currentType().end = t + t += 1; + currentType().start = t + } + let lastNode = (i=null) => { + if(i == null) throw new Error("must pass a param to lastNode()") + return i+1 === nodes.length + } + + for(let i=0; i { return this.nodes[id] @@ -30,10 +94,26 @@ export default class Database extends QuillDB { return null; }, token: (id) => { - return this.tokens[id] + return this.nodes[`TOKEN-${id}`] } } + add = { + user: (node) => { + let lastUser = {} + + } + } + + submitNewUser(qrCodeID, userInfo) { + let newUser = { + labels: ["User"], + ...userInfo + } + if(User(newUser)) + this.add.user(newUser) + } + generateUserID() { let id = this.labels["User"].length + 1; while (this.get.user(`user-${id}`)) { @@ -41,8 +121,4 @@ export default class Database extends QuillDB { } return `user-${id}`; // O(1) most of the time } - - async getAll() { - return { nodes: this.nodes } - } } \ No newline at end of file diff --git a/server/db/model/Member.js b/server/db/model/Member.js new file mode 100644 index 0000000..4fd501e --- /dev/null +++ b/server/db/model/Member.js @@ -0,0 +1,43 @@ +export default function Member(id, node) { + let idTraits = { + firstWord: "MEMBER", + length: 2 + } + + let fields = [ + "firstName", + "lastName", + "email", + "password" + ] + + let checkID = () => { + let split = id.split("-") + return ( + split.length === idTraits.length + && split[0] === idTraits.firstWord + && !isNaN(Number(split[1])) + ) + } + let idres = checkID() + if(!idres) { + return false + } + + let checkFields = () => { + for(let i = 0; i < fields.length; i++) { + if(!node[fields[i]]) { + throw new Error(`Member ${node.email} is missing trait ${fields[i]}`) + return false + } else { + return true + } + } + } + let fieldres = checkFields() + if(!fieldres) { + return false + } + + return true +} \ No newline at end of file diff --git a/server/db/model/Title.js b/server/db/model/Title.js new file mode 100644 index 0000000..1a5ffdb --- /dev/null +++ b/server/db/model/Title.js @@ -0,0 +1,33 @@ +export default function Title(id, node) { + let checkID = () => { + let split = id.split("-") + return ( + split.length === 2 + && split[0] === "HY" + && !isNaN(Number(split[1])) + ) + } + let idres = checkID() + if(!idres) { + return false + } + + let checkFields = () => { + let fields = [ + "fullName", + ] + for(let i = 0; i < fields.length; i++) { + if(!node[fields[i]]) { + throw new Error(`Title ${id} is missing trait ${fields[i]}`) + return false + } + } + return true + } + let fieldres = checkFields() + if(!fieldres) { + return false + } + + return true +} \ No newline at end of file diff --git a/server/db/model/Token.js b/server/db/model/Token.js new file mode 100644 index 0000000..06f0c12 --- /dev/null +++ b/server/db/model/Token.js @@ -0,0 +1,39 @@ +export default function Token(id, node) { + let idTraits = { + firstWord: "TOKEN" + } + + let fields = [ + "index", + "url", + "used" + ] + + let checkID = () => { + let split = id.split("-") + return ( + split[0] === idTraits.firstWord + ) + } + let idres = checkID() + if(!idres) { + return false + } + + let checkFields = () => { + for(let i = 0; i < fields.length; i++) { + if(!node[fields[i]]) { + throw new Error(`Token ${node.email} is missing trait ${fields[i]}`) + return false + } else { + return true + } + } + } + let fieldres = checkFields() + if(!fieldres) { + return false + } + + return true +} \ No newline at end of file diff --git a/server/db/model/User.js b/server/db/model/User.js deleted file mode 100644 index 3b8e9d3..0000000 --- a/server/db/model/User.js +++ /dev/null @@ -1,14 +0,0 @@ -export default function User(node) { - let traits = [ - "firstName", - "lastName", - "email", - "password" - ] - for(let i = 0; i < traits.length; i++) { - if(!node[traits[i]]) { - if (traits[i] == "lastName") { continue; } // Ignores optional Last Name - throw new Error(`User ${node.email} is missing trait ${traits[i]}`) - } - } -} \ No newline at end of file diff --git a/server/index.js b/server/index.js index 4378381..e4f08d7 100644 --- a/server/index.js +++ b/server/index.js @@ -49,6 +49,8 @@ class Server { } newUserSubmission = (req, res) => { + const { token } = req.query; + db.submitNewUser(token, req.body) return res.status(400).json({ error: 'Haven\t finished this bruh' }); } diff --git a/ui/_/code/quill.js b/ui/_/code/quill.js index 675699b..5659c39 100644 --- a/ui/_/code/quill.js +++ b/ui/_/code/quill.js @@ -1,6 +1,7 @@ /* Sam Russell Captured Sun + 11.20.25 - Added "pct" style unit, added alignVertical and alignHorizontal for flex boxes 11.19.25 - Allowing for "auto" values in otherwise numeric styles, adding vmin and vmax units 11.17.25.3 - Adding styles() and fixing dynamic function from earlier 11.17.25.2 - Fixing onNavigate() and onAppear() @@ -219,6 +220,7 @@ HTMLElement.prototype.rerender = function() { /* Styling */ +window.pct = "%" window.vmin = "vmin" window.vmax = "vmax" window.vh = "vh" @@ -517,6 +519,36 @@ HTMLElement.prototype.centerY = function () { return this; }; +HTMLElement.prototype.alignVertical = function (value) { + const direction = getComputedStyle(this).flexDirection; + if(!direction) { + throw new Error("alignVertical can be only be used on HStacks or VStacks!") + } + + if (direction === "column" || direction === "column-reverse") { + console.log("using justify") + this.style.justifyContent = value; + } else { + this.style.alignItems = value; + } + return this +} + +HTMLElement.prototype.alignHorizontal = function (value) { + const direction = getComputedStyle(this).flexDirection; + if(!direction) { + throw new Error("alignHorizontal can be only be used on HStacks or VStacks!") + } + + if (direction === "column" || direction === "column-reverse") { + this.style.alignItems = value; + } else { + this.style.justifyContent = value; + } + return this +} + + /* Elements */ quill.setChildren = function(el, innerContent) { diff --git a/ui/public/components/JoinForm.js b/ui/public/components/SignupForm.js similarity index 98% rename from ui/public/components/JoinForm.js rename to ui/public/components/SignupForm.js index 37da21f..2066b6a 100644 --- a/ui/public/components/JoinForm.js +++ b/ui/public/components/SignupForm.js @@ -1,4 +1,4 @@ -class JoinForm extends Shadow { +class SignupForm extends Shadow { inputStyles(el) { return el @@ -82,4 +82,4 @@ class JoinForm extends Shadow { } } -register(JoinForm) \ No newline at end of file +register(SignupForm) \ No newline at end of file diff --git a/ui/public/pages/Home.js b/ui/public/pages/Home.js index d27a05a..6456b23 100644 --- a/ui/public/pages/Home.js +++ b/ui/public/pages/Home.js @@ -1,5 +1,5 @@ import "../components/NavBar.js" -import "../components/JoinForm.js" +import "../components/SignupForm.js" import "./Why.js" import "./Events.js" import "./Join.js" @@ -57,7 +57,7 @@ class Home extends Shadow { default: if(window.location.pathname.startsWith("/signup")) { - JoinForm() + SignupForm() } }