improved frontend, started csv upload endpoint

This commit is contained in:
metacryst
2026-01-09 13:53:41 -06:00
parent 620d50cad7
commit 75cbcbb879
21 changed files with 357 additions and 840 deletions

View File

@@ -2,6 +2,7 @@ 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 {
@@ -74,4 +75,75 @@ export default class Database {
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;
}
}

View File

@@ -6,6 +6,13 @@ const handlers = {
console.log(`Received location: (${name}, ${latitude}, ${longitude}) at ${timestamp}`);
broadcast("update-location", { name, latitude, longitude, timestamp });
res.json({ success: true });
},
async uploadCSV(req, res) {
const csvString = req.body;
console.log(csvString);
await global.db.uploadCSV(csvString)
res.json({ ok: true });
}
}

View File

@@ -22,6 +22,7 @@ class Server {
registerRoutes(router) {
router.post('/api/location', handlers.updateLocation)
router.post('/csv', handlers.uploadCSV)
router.post('/login', this.login)
router.get('/*', this.get)
return router
@@ -115,7 +116,7 @@ class Server {
}
constructor() {
this.db = new Database()
global.db = new Database()
this.auth = new AuthHandler()
const app = express();
app.use(cors({ origin: '*' }));