database basically working

This commit is contained in:
metacryst
2026-01-11 03:47:36 -06:00
parent 463dd183f5
commit 13cdff7a5f
19 changed files with 389 additions and 210 deletions

48
db/dbmore.json Normal file
View File

@@ -0,0 +1,48 @@
{
"nodes": {
"MEMBER-1": {
"id": 1,
"email": "samrussell99@pm.me",
"firstName": "Sam",
"lastName": "Russell",
"password": "$argon2id$v=19$m=65536,t=3,p=4$PDu5qx47zzY0dX0/4iQuqw$JxePLouwOEi2Q0wA4JHQQ4GwvqAvxqWhj7n9aC8HZIk",
"address": {
"address1": "2014 E 9th St",
"address2": "Unit A",
"zip": "78702",
"state": "Texas",
"city": "Austin"
},
"tokenUsed": "810387b6-851e-4883-b9a3-c59703dc0fc9",
"joined": "11.24.2025-12:54:360784am"
},
"NETWORK-1": {
"id": 1,
"name": "Comal County Young Republicans",
"apps": [
"Dashboard",
"People",
"Messages"
],
"logo": "comalyr.svg"
},
"NETWORK-2": {
"id": 2,
"name": "Hyperia",
"apps": [
"Dashboard",
"People",
"Messages"
],
"logo": "hyperia.svg"
}
},
"edges": {
"MEMBER_IN_NETWORK-1": {
"id": 1,
"to": "NETWORK-1",
"from": "MEMBER-1",
"created": "11.24.2025-12:54:360784am"
}
}
}

View File

@@ -37,6 +37,7 @@ export default class AuthHandler {
const email = payload.email; const email = payload.email;
const user = db.members.getByEmail(email); const user = db.members.getByEmail(email);
const userOrgs = db.edges.getByFrom(db.members.prefix + "-" + user.id)
res.send({ email: user.email, name: user.firstName + " " + user.lastName }); res.send({ email: user.email, name: user.firstName + " " + user.lastName });
} catch (err) { } catch (err) {
res.status(401).send({ error: "Invalid token" }); res.status(401).send({ error: "Invalid token" });

View File

@@ -1,41 +1,73 @@
import fs from 'fs/promises'; import fs from 'fs/promises';
import chalk from 'chalk'; import chalk from 'chalk';
import path from 'path'; import path from 'path';
import {nodeModels, edgeModels} from './model/import.js'
import Titles from "./model/Titles.js"
import Networks from "./model/Networks.js"
import Members from './model/Members.js'
import Tokens from './model/Tokens.js'
import Payments from "./model/Payments.js"
import Posts from "./model/Forum/Posts.js"
import Conversations from "./model/Messages/Conversations.js"
import Messages from "./model/Messages/Messages.js"
export default class Database { export default class Database {
titles = new Titles()
networks = new Networks()
members = new Members()
tokens = new Tokens()
payments = new Payments()
posts = new Posts()
conversations = new Conversations()
messages = new Messages()
fromID = { nodes = new Array(10000).fill(0);
"MEMBER": this.members, edges = new Array(10000).fill(0);
"NETWORK": this.networks,
"TITLE": this.titles,
"TOKEN": this.tokens,
"PAYMENT": this.payments,
"POST": this.posts,
"CONVERSATION": this.conversations,
"DM": this.messages
}
constructor() { constructor() {
let values = Object.values(nodeModels)
for(let i = 0; i < values.length; i++) {
let key = values[i].constructor.name
key = key.toLowerCase() + "s"
this[key] = values[i]
}
let eValues = Object.values(edgeModels)
for(let i = 0; i < eValues.length; i++) {
let key = eValues[i].constructor.name
key = key.toLowerCase() + "s"
this[key] = eValues[i]
}
this.loadData() this.loadData()
} }
addNode(id, node) {
try {
let type = id.split("-")[0]
let model = nodeModels[type[0] + type.slice(1).toLowerCase()]
if(model) {
let schema = model.schema
let result = schema.safeParse(node)
if(result.success) {
this.nodes[model.indices[1]] = node
model.indices[1]++;
} else {
console.error(result.error)
throw new global.ServerError(400, "Invalid Data!");
}
} else {
throw new Error("Type does not exist for node: " + id)
}
} catch(e) {
throw e
}
}
addEdge(id, edge) {
try {
let type = id.split("-")[0]
let model = edgeModels[type]
if(model) {
let schema = model.schema
let result = schema.safeParse(edge)
if(result.success) {
this.edges[model.indices[1]] = edge
model.indices[1]++;
} else {
console.error(result.error)
throw new global.ServerError(400, "Invalid Data!");
}
} else {
throw new Error("Type does not exist for edge: " + id)
}
} catch(e) {
throw e
}
}
async loadData() { async loadData() {
const dbData = await fs.readFile(path.join(process.cwd(), 'db/db.json'), 'utf8'); const dbData = await fs.readFile(path.join(process.cwd(), 'db/db.json'), 'utf8');
let dbJson; let dbJson;
@@ -44,24 +76,21 @@ export default class Database {
} catch { } catch {
dbJson = [] dbJson = []
} }
let nodes = dbJson["nodes"]; let nodes = dbJson["nodes"];
let entries = Object.entries(nodes) let entries = Object.entries(nodes)
for(let i=0; i<entries.length; i++) { for(let i=0; i<entries.length; i++) {
let entry = entries[i] let entry = entries[i]
let id = entry[0]; let node = entry[1]; let id = entry[0]; let node = entry[1];
let type = id.split("-")[0] this.addNode(id, node)
try { }
let collection = this.fromID[type]
if(collection) {
collection.save(node, id)
} else {
throw new Error("Type does not exist for node: ", id)
}
} catch(e) {
throw e
}
let edges = dbJson["edges"];
let edgeEntries = Object.entries(edges)
for(let i=0; i<edgeEntries.length; i++) {
let entry = edgeEntries[i]
let id = entry[0]; let node = entry[1];
this.addEdge(id, node)
} }
setInterval(() => { setInterval(() => {
@@ -72,37 +101,37 @@ export default class Database {
async saveData() { async saveData() {
let data = { let data = {
"nodes": { "nodes": {},
"edges": {}
},
"edges": {
}
} }
let arrs = [
this.titles.entries, let nModels = Object.values(nodeModels)
this.members.entries, this.nodes.forEach((entry, i) => {
this.tokens.entries, if(entry) {
this.posts.entries, for(let j = 0; j < nModels.length; j++) {
this.conversations.entries, let model = nModels[j]
this.messages.entries, let indices = model.indices
this.payments.entries, if(i >= indices[0] && i < indices[1]) {
] let prefix = model.prefix
let ids = [ data.nodes[prefix + "-" + entry.id] = entry
Object.entries(this.titles.ids), }
Object.entries(this.members.ids), }
Object.entries(this.tokens.ids),
Object.entries(this.posts.ids),
Object.entries(this.conversations.ids),
Object.entries(this.messages.ids),
Object.entries(this.payments.ids),
]
for(let i=0; i<arrs.length; i++) {
let arr = arrs[i]
for(let j=0; j<arr.length; j++) {
data.nodes[ids[i][j][0]] = arr[j]
} }
} })
let eModels = Object.values(edgeModels)
this.edges.forEach((entry, i) => {
if(entry) {
for(let j = 0; j < eModels.length; j++) {
let model = eModels[j]
let indices = model.indices
if(i >= indices[0] && i < indices[1]) {
let prefix = model.prefix
data.nodes[prefix + "-" + entry.id] = entry
}
}
}
})
let string = JSON.stringify(data, null, 4) let string = JSON.stringify(data, null, 4)
await fs.writeFile(path.join(process.cwd(), 'db/db.json'), string, "utf8"); await fs.writeFile(path.join(process.cwd(), 'db/db.json'), string, "utf8");

View File

@@ -1,27 +0,0 @@
export default class OrderedObject {
entries = []
ids = {}
indexes = []
add(id, data) {
if(this.ids[id]) {
console.error(`Can't add item ${id}: id already exists`)
throw new global.ServerError(400, `Member with this email already exists`)
}
this.entries.push(data)
this.ids[id] = this.entries.length - 1
}
update(id, data) {
let index = this.ids[id]
this.entries[index] = data
}
delete(key) {
if (typeof key === "number") {
return this.entries[key]
} else {
return this.entries[this.ids[key]]
}
}
}

View File

@@ -1,52 +0,0 @@
import OrderedObject from "./OrderedObject.js"
export default class Titles extends OrderedObject {
save(newTitle) {
let id = `HY-${this.entries.length+1}`
if(this.validate(id, newTitle)) {
try {
super.add(id, newTitle)
} catch(e) {
console.error(e)
throw e
}
} else {
throw new global.ServerError(400, "Invalid Member Data!");
}
}
validate(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
}
}

View File

@@ -1,41 +0,0 @@
import OrderedObject from "./OrderedObject.js"
import { z } from 'zod';
export default class Tokens extends OrderedObject {
schema = z.object({
index: z.number(),
url: z.string(),
uuid: z.string().regex(
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
"Invalid UUID"
),
used: z.boolean(),
})
markUsed(uuid) {
let token = this.get(uuid)
token.used = true
super.update(`TOKEN-${uuid}`, token)
}
save(token) {
let id = `TOKEN-${token.uuid}`
let result = this.schema.safeParse(token)
if(result.success) {
try {
super.add(id, token)
} catch(e) {
console.error(e)
throw e
}
} else {
console.error(result.error)
throw new global.ServerError(400, "Invalid Member Data!");
}
}
get(uuid) {
return this.entries[this.ids[`TOKEN-${uuid}`]]
}
}

View File

@@ -1,7 +1,11 @@
import OrderedObject from "../OrderedObject.js"
import { z } from 'zod'; import { z } from 'zod';
export default class Conversations extends OrderedObject { export default class Conversation {
indices = null
constructor(indices) {
this.indices = indices
}
schema = z.object({ schema = z.object({
id: z.number(), id: z.number(),

View File

@@ -1,7 +1,11 @@
import OrderedObject from "../OrderedObject.js"
import { z } from 'zod'; import { z } from 'zod';
export default class Messages extends OrderedObject { export default class Message {
indices = null
constructor(indices) {
this.indices = indices
}
schema = z.object({ schema = z.object({
id: z.number(), id: z.number(),

36
server/db/model/edge.js Normal file
View File

@@ -0,0 +1,36 @@
import { z } from 'zod';
export default class Edge {
schema = z.object({
id: z.number(),
from: z.string(),
to: z.string(),
created: z.string()
})
.strict()
save(n, id) {
let result = this.schema.safeParse(n)
if(result.success) {
try {
super.add(id, n)
} catch(e) {
console.error(e)
throw e
}
} else {
console.error(result.error)
throw new global.ServerError(400, "Invalid Member Data!");
}
}
getByFrom(fromID) {
let result = []
for(let i = 0; i < this.entries.length; i++) {
if(entries[i].from === fromID) {
// let
}
}
console.log(fromID)
}
}

View File

@@ -0,0 +1,17 @@
import { z } from 'zod'
export default class MemberInNetwork {
schema = z.object({
id: z.number(),
from: z.string(),
to: z.string(),
created: z.string()
})
.strict()
indices = null
constructor(indices) {
this.indices = indices
}
}

View File

@@ -1,7 +1,12 @@
import OrderedObject from "../OrderedObject.js"
import { z } from 'zod'; import { z } from 'zod';
export default class Posts extends OrderedObject { export default class Post {
indices = null
constructor(indices) {
this.indices = indices
}
schema = z.object({ schema = z.object({
text: z.string(), text: z.string(),
time: z.string(), time: z.string(),

36
server/db/model/import.js Normal file
View File

@@ -0,0 +1,36 @@
import Title from "./title.js"
import Network from "./network.js"
import Member from './member.js'
import Payment from "./payment.js"
import Post from "./forum/post.js"
import Conversation from "./dms/conversation.js"
import DM from "./dms/dm.js"
import MemberInNetwork from "./edges/MemberInNetwork.js"
let nIndices = {
"MEMBER" : [0, 0], // [id, startIndex, nextEmptyIndex
"NETWORK" : [100, 100],
"TITLE" : [200, 200],
"PAYMENT" : [300, 300],
"POST" : [400, 400],
"CONVERSATION" : [3000, 3000],
"DM" : [6000, 6000],
}
let eIndices = {
"MEMBER_IN_NETWORK": [0, 0]
}
export let nodeModels = {
Member: new Member(nIndices.MEMBER),
Network: new Network(nIndices.NETWORK),
Title: new Title(nIndices.TITLE),
Payment: new Payment(nIndices.PAYMENT),
Post: new Post(nIndices.POST),
Conversation: new Conversation(nIndices.CONVERSATION),
DM: new DM(nIndices.DM),
}
export let edgeModels = {
MEMBER_IN_NETWORK: new MemberInNetwork(eIndices.MEMBER_IN_NETWORK)
}

View File

@@ -1,8 +1,14 @@
import OrderedObject from "./OrderedObject.js"
import argon2 from 'argon2'; import argon2 from 'argon2';
import { z } from 'zod'; import { z } from 'zod';
export default class Members extends OrderedObject { export default class Member {
prefix = "MEMBER"
indices = null
constructor(indices) {
this.indices = indices
}
addressSchema = z.object({ addressSchema = z.object({
address1: z.string(), address1: z.string(),
address2: z.string().optional(), address2: z.string().optional(),
@@ -21,14 +27,13 @@ export default class Members extends OrderedObject {
"Invalid UUID" "Invalid UUID"
), ),
joined: z.string(), joined: z.string(),
address: this.addressSchema, address: this.addressSchema
networks: z.array(z.number())
}) })
isHashed = (s) => {return s.startsWith("$argon2")} isHashed = (s) => {return s.startsWith("$argon2")}
save(member) { save(member) {
let id = `MEMBER-${member.id}` let id = `${this.prefix}-${member.id}`
let result = this.schema.safeParse(member) let result = this.schema.safeParse(member)
if(result.success) { if(result.success) {
try { try {
@@ -57,9 +62,9 @@ export default class Members extends OrderedObject {
} }
getByEmail(email) { getByEmail(email) {
for(let i=0; i<this.entries.length; i++) { for(let i=this.indices[0]; i<this.indices[1]; i++) {
if(this.entries[i].email === email) { if(global.db.nodes[i].email === email) {
return this.entries[i] return global.db.nodes[i]
} }
} }
return null return null

View File

@@ -1,13 +1,20 @@
import OrderedObject from "./OrderedObject.js"
import { z } from 'zod'; import { z } from 'zod';
export default class Networks extends OrderedObject { export default class Network {
prefix = `NETWORK` prefix = `NETWORK`
indices = null
constructor(indices) {
this.indices = indices
}
schema = z.object({ schema = z.object({
id: z.number(), id: z.number(),
name: z.string(), name: z.string(),
apps: z.array(z.string()),
logo: z.string()
}) })
.strict()
save(n) { save(n) {
let id = `${this.prefix}-${n.id}` let id = `${this.prefix}-${n.id}`

View File

@@ -1,7 +1,12 @@
import OrderedObject from "./OrderedObject.js"
import { z } from 'zod'; import { z } from 'zod';
export default class Payments extends OrderedObject { export default class Payment {
prefix = "PAYMENT"
indices = null
constructor(indices) {
this.indices = indices
}
schema = z.object({ schema = z.object({
id: z.number(), id: z.number(),
@@ -13,7 +18,7 @@ export default class Payments extends OrderedObject {
}) })
save(payment) { save(payment) {
let id = `PAYMENT-${payment.id}` let id = `${this.prefix}-${payment.id}`
let result = this.schema.safeParse(payment) let result = this.schema.safeParse(payment)
if(result.success) { if(result.success) {
try { try {
@@ -37,6 +42,6 @@ export default class Payments extends OrderedObject {
} }
get(id) { get(id) {
return this.entries[this.ids[`PAYMENT-${id}`]] return this.entries[this.ids[`${this.prefix}-${id}`]]
} }
} }

29
server/db/model/title.js Normal file
View File

@@ -0,0 +1,29 @@
import { z } from 'zod';
export default class Title {
prefix = `TITLE`
indices = null
constructor(indices) {
this.indices = indices
}
schema = z.object({
id: z.number(),
name: z.string()
})
save(newTitle) {
let id = `HY-${this.entries.length+1}`
if(this.validate(id, newTitle)) {
try {
global.db.add(id, newTitle)
} catch(e) {
console.error(e)
throw e
}
} else {
throw new global.ServerError(400, "Invalid Member Data!");
}
}
}

74
server/db/schemas.js Normal file
View File

@@ -0,0 +1,74 @@
import { z } from 'zod';
export let addressSchema = z.object({
address1: z.string(),
address2: z.string().optional(),
zip: z.string().regex(/^\d{5}(-\d{4})?$/),
state: z.string(),
city: z.string()
})
export let MEMBER = z.object({
id: z.number(),
email: z.string().email(),
firstName: z.string(),
lastName: z.string(),
password: z.string(),
tokenUsed: z.string().regex(
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
"Invalid UUID"
),
joined: z.string(),
address: addressSchema
})
export let NETWORK = z.object({
id: z.number(),
name: z.string(),
apps: z.array(z.string()),
logo: z.string()
})
.strict()
export let TITLE = z.object({
id: z.number(),
name: z.string(),
apps: z.array(z.string()),
logo: z.string()
})
.strict()
export let PAYMENT = z.object({
id: z.number(),
name: z.string(),
email: z.string(),
time: z.string(),
amount: z.number(),
product: z.string(),
})
export let POST = z.object({
text: z.string(),
time: z.string(),
sentBy: z.string()
})
export let CONVSRSATION = z.object({
id: z.number(),
between: z.array(z.string()),
lastUpdated: z.string()
}).strict()
export let DM = z.object({
id: z.number(),
conversation: z.string(),
from: z.string(),
text: z.string(),
time: z.string()
}).strict()
export let MEMBER_IN_NETWORK = z.object({
id: z.number(),
from: z.string(),
to: z.string(),
created: z.string()
}).strict()

View File

@@ -104,7 +104,6 @@ class Server {
get = async (req, res) => { get = async (req, res) => {
console.log("get")
let url = req.url let url = req.url
let publicSite = () => { let publicSite = () => {

View File

@@ -22,7 +22,7 @@ class Home extends Shadow {
VStack(() => { VStack(() => {
HStack(() => { HStack(() => {
span("The Network OS") span("The Community OS")
.fontFamily("Canterbury") .fontFamily("Canterbury")
.color("var(--accent2)") .color("var(--accent2)")
.fontSize(2.5, em) .fontSize(2.5, em)