From adf25488e4151d0cd378adc6edaa08c7f92293dc Mon Sep 17 00:00:00 2001 From: metacryst Date: Tue, 13 Jan 2026 17:24:52 -0600 Subject: [PATCH] changes --- package.json | 4 +- server/db.js | 149 -------------------------------- server/handlers.js | 18 ++++ server/index.js | 5 +- server/util.js | 17 ++++ ui/app/{components => }/Home.js | 6 +- ui/app/index.html | 4 +- ui/app/index.js | 2 +- ui/app/ws/Connection.js | 2 +- 9 files changed, 47 insertions(+), 160 deletions(-) delete mode 100644 server/db.js create mode 100644 server/util.js rename ui/app/{components => }/Home.js (72%) diff --git a/package.json b/package.json index b9e698f..459bb2d 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "author": "", "license": "ISC", "dependencies": { + "argon2": "^0.44.0", "chalk": "^5.6.2", "cors": "^2.8.5", "csv-parser": "^3.2.0", @@ -19,6 +20,7 @@ "http-proxy": "^1.18.1", "jsonwebtoken": "^9.0.2", "moment": "^2.30.1", - "ws": "^8.18.3" + "ws": "^8.18.3", + "zod": "^4.3.5" } } diff --git a/server/db.js b/server/db.js deleted file mode 100644 index 50dec09..0000000 --- a/server/db.js +++ /dev/null @@ -1,149 +0,0 @@ -import chalk from 'chalk' -import path from 'path'; -import fs from 'fs/promises'; -import { pathToFileURL } from 'url'; -import parse from "csv-parser" -import Node from "../model/Node.js" - -export default class Database { - #nodes; - #edges; - #labels = {} - - constructor() { - this.getData() - } - - async getData() { - const dbData = await fs.readFile(path.join(process.cwd(), 'db/db.json'), 'utf8'); - let dbJson; - try { - dbJson = JSON.parse(dbData); - } catch { - dbJson = [] - } - this.#nodes = dbJson["nodes"]; - this.#edges = dbJson["edges"]; - - console.log(chalk.yellow("DB established.")) - 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 = [] - } - - dbJson[superKey][key] = value; - - await fs.writeFile(path.join(process.cwd(), 'db/db.json'), JSON.stringify(dbJson, null, 2), 'utf8') - } - - async getLabelModels() { - const labelHandlers = {}; - const labelDir = path.join(process.cwd(), 'src/model/labels'); - 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 - } - - generateUserID() { - let id = this.#labels["User"].length + 1; - while (this.get.user(`user-${id}`)) { - id++; - } - return `user-${id}`; // O(1) most of the time - } - - async getAll() { - return { nodes: this.#nodes } - } - - async loadCSV(csvString) { - if (!csvString || typeof csvString !== 'string') { - throw new Error('loadCSVAsync: input must be a non-empty string'); - } - - return new Promise((resolve, reject) => { - const records = []; - - const parser = parse({ - columns: true, - skip_empty_lines: true, - trim: true, - relax_column_count: true, - bom: true - }); - - parser.on('readable', () => { - let row; - while ((row = parser.read()) !== null) { - records.push(this.cleanRow(row)); - } - }); - - parser.on('error', (err) => { - reject(err); - }); - - parser.on('end', () => { - resolve(records); - }); - - // Feed the CSV string - parser.write(csvString); - parser.end(); - }); - } - - cleanRow(row) { - const cleaned = {}; - - for (let [key, value] of Object.entries(row)) { - // 1. Clean header - key = key - .replace(/ -MyData/g, '') - .replace(/[^a-zA-Z0-9]/g, ' ') - .trim() - .replace(/\s+(.)/g, (_, c) => c.toUpperCase()) - .replace(/^(.)/, c => c.toLowerCase()); - - // 2. Empty → null - if (value === '' || value == null) { - cleaned[key] = null; - continue; - } - - // 3. Type conversion - if (key === 'registrationStatus') { - cleaned[key] = value === 'True' ? true : value === 'False' ? false : null; - } - else if (['confidences', 'personId', 'uid', 'stateVoterId'].includes(key)) { - const num = parseFloat(value); - cleaned[key] = isNaN(num) ? null : num; - } - else { - cleaned[key] = value; - } - } - - return cleaned; - } -} \ No newline at end of file diff --git a/server/handlers.js b/server/handlers.js index 51132c4..bf016de 100644 --- a/server/handlers.js +++ b/server/handlers.js @@ -1,10 +1,28 @@ +import path from 'path' +import fs from 'fs' import { broadcast } from './ws.js'; +const CSV_PATH = path.join(process.cwd(), 'db/logs.csv') + +function appendToCSV(row) { + const exists = fs.existsSync(CSV_PATH) + + const header = 'name,latitude,longitude,timestamp\n' + const line = `${row.name},${row.latitude},${row.longitude},${row.timestamp}\n` + + if (!exists) { + fs.appendFileSync(CSV_PATH, header + line, 'utf8') + } else { + fs.appendFileSync(CSV_PATH, line, 'utf8') + } +} + const handlers = { updateLocation(req, res) { const { name, latitude, longitude, timestamp } = req.body; console.log(`Received location: (${name}, ${latitude}, ${longitude}) at ${timestamp}`); broadcast("update-location", { name, latitude, longitude, timestamp }); + appendToCSV({ name, latitude, longitude, timestamp }) res.json({ success: true }); }, diff --git a/server/index.js b/server/index.js index d44996b..2290d8e 100644 --- a/server/index.js +++ b/server/index.js @@ -5,8 +5,8 @@ import chalk from 'chalk' import moment from 'moment' import path from 'path'; import { initWebSocket } from './ws.js' +import "./util.js" -import Database from "./db.js" import AuthHandler from './auth.js'; import handlers from "./handlers.js"; @@ -116,7 +116,6 @@ class Server { } constructor() { - global.db = new Database() this.auth = new AuthHandler() const app = express(); app.use(cors({ origin: '*' })); @@ -131,7 +130,7 @@ class Server { const server = http.createServer(app); initWebSocket(server); - const PORT = 3008; + const PORT = 3009; server.listen(PORT, () => { console.log("\n") console.log(chalk.yellow("**************Blockcatcher*************")) diff --git a/server/util.js b/server/util.js new file mode 100644 index 0000000..b59cfa9 --- /dev/null +++ b/server/util.js @@ -0,0 +1,17 @@ +global.currentTime = function () { + const now = new Date(); + + const month = String(now.getMonth() + 1).padStart(2, "0"); + const day = String(now.getDate()).padStart(2, "0"); + const year = now.getFullYear(); + + let hours = now.getHours(); + const ampm = hours >= 12 ? "pm" : "am"; + hours = hours % 12 || 12; // convert to 12-hour format + + const minutes = String(now.getMinutes()).padStart(2, "0"); + const seconds = String(now.getSeconds()).padStart(2, "0"); + const ms = String(now.getMilliseconds()).padStart(4, "0"); // 4-digit like "5838" + + return `${month}.${day}.${year}-${hours}:${minutes}:${seconds}${ms}${ampm}`; +} \ No newline at end of file diff --git a/ui/app/components/Home.js b/ui/app/Home.js similarity index 72% rename from ui/app/components/Home.js rename to ui/app/Home.js index 1234f8c..b338c9c 100644 --- a/ui/app/components/Home.js +++ b/ui/app/Home.js @@ -1,6 +1,6 @@ -import "./LocationList.js" -import "./Sidebar.js" -import "./MainPanel.js" +import "./components/LocationList.js" +import "./components/Sidebar.js" +import "./components/MainPanel.js" class Home extends Shadow { render() { diff --git a/ui/app/index.html b/ui/app/index.html index 6177617..848ca39 100644 --- a/ui/app/index.html +++ b/ui/app/index.html @@ -1,9 +1,9 @@ - Blockcatcher + Blockcatcher Admin - + diff --git a/ui/app/index.js b/ui/app/index.js index 2174181..3d72afe 100644 --- a/ui/app/index.js +++ b/ui/app/index.js @@ -1,5 +1,5 @@ import ConnectionHandler from "./ws/Connection.js" window.ConnectionHandler = new ConnectionHandler() -import "./components/Home.js" +import "./Home.js" Home() \ No newline at end of file diff --git a/ui/app/ws/Connection.js b/ui/app/ws/Connection.js index 1470e89..8e915d1 100644 --- a/ui/app/ws/Connection.js +++ b/ui/app/ws/Connection.js @@ -10,7 +10,7 @@ class Connection { init() { if(window.location.hostname === "localhost") { - this.ws = new WebSocket("ws://" + "localhost:3008") + this.ws = new WebSocket("ws://" + "localhost:3009") } else { this.ws = new WebSocket("wss://" + window.location.hostname + window.location.pathname) }