Make changes needed to use mariadb; TODO: Full suite of testing
This commit is contained in:
parent
a3e3dfc501
commit
eb7a8b3bc5
498
index.js
498
index.js
|
@ -17,21 +17,42 @@ const { execSync } = require('child_process');
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const expressSession = require('express-session');
|
const expressSession = require('express-session');
|
||||||
const ejs = require("ejs")
|
const ejs = require("ejs")
|
||||||
const sqlite3 = require('sqlite3').verbose();
|
const mariadb = require('mariadb');
|
||||||
const bcrypt = require("bcrypt")
|
const bcrypt = require("bcrypt")
|
||||||
const crypto = require("crypto")
|
const crypto = require("crypto")
|
||||||
const app = express();
|
const app = express();
|
||||||
const port = process.env.SERVER_PORT || 3000;
|
const port = process.env.SERVER_PORT || 3000;
|
||||||
|
|
||||||
const db = new sqlite3.Database('astrocom.db', (err) => {
|
const pool = mariadb.createPool({
|
||||||
if (err) {
|
host: process.env.DB_HOST || '127.0.0.1',
|
||||||
console.error('Error connecting to database:', err);
|
user: process.env.DB_USER || 'root',
|
||||||
} else {
|
password: process.env.DB_PASSWORD || '',
|
||||||
console.log('Connected to SQLite database');
|
database: process.env.DB_NAME || 'astrocom',
|
||||||
}
|
connectionLimit: 10
|
||||||
|
});
|
||||||
|
const saltRounds = 10;
|
||||||
|
|
||||||
|
pool.getConnection().then((conn) => {
|
||||||
|
require("./migrations")(pool).then(() => {
|
||||||
|
conn.query("SELECT * FROM users WHERE id = 1").then((row) => {
|
||||||
|
if (!row || process.env.RESET_ADMIN == "true") {
|
||||||
|
// delete all users (The big scary one lol)
|
||||||
|
conn.query("DELETE FROM users").then(() => {
|
||||||
|
// Generate 32 char random string
|
||||||
|
const passwd = crypto.randomBytes(32).toString('hex');
|
||||||
|
bcrypt.hash(passwd, 10).then((hash) => {
|
||||||
|
conn.query("INSERT INTO users (id, username, passwordHash) VALUES (1, 'admin', ?)",
|
||||||
|
[hash]).then(() => {
|
||||||
|
console.log(`Created admin user with password: ${passwd}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).finally(() => {
|
||||||
|
conn.release();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
// Run migrations
|
|
||||||
require("./migrations")(db)
|
|
||||||
|
|
||||||
const gitCommitHashShort = execSync('git rev-parse --short HEAD').toString().trim();
|
const gitCommitHashShort = execSync('git rev-parse --short HEAD').toString().trim();
|
||||||
const branch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim();
|
const branch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim();
|
||||||
|
@ -39,47 +60,9 @@ const version = `${gitCommitHashShort}-${branch}`;
|
||||||
|
|
||||||
console.log(`Version: ${version}`);
|
console.log(`Version: ${version}`);
|
||||||
|
|
||||||
|
|
||||||
// Check if user 1 exists, if not, create it
|
|
||||||
const saltRounds = 10;
|
|
||||||
|
|
||||||
db.get("SELECT * FROM users WHERE id = 1", [], (err, row) => {
|
|
||||||
if (err) {
|
|
||||||
console.error('Error checking for admin user:', err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!row || process.env.RESET_ADMIN == "true") {
|
|
||||||
// delete all users (The big scary one lol)
|
|
||||||
db.run("DELETE FROM users", [], (err) => {
|
|
||||||
if (err) {
|
|
||||||
console.error('Error deleting users:', err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Generate 32 char random string
|
|
||||||
const passwd = crypto.randomBytes(32).toString('hex');
|
|
||||||
bcrypt.hash(passwd, saltRounds, (err, hash) => {
|
|
||||||
if (err) {
|
|
||||||
console.error('Error creating hash:', err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
db.run("INSERT INTO users (id, username, passwordHash) VALUES (1, 'admin', ?)",
|
|
||||||
[hash],
|
|
||||||
(err) => {
|
|
||||||
if (err) {
|
|
||||||
console.error('Error creating admin user:', err);
|
|
||||||
} else {
|
|
||||||
console.log(`Created admin user with password: ${passwd}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
app.use(express.urlencoded({ extended: true }));
|
app.use(express.urlencoded({ extended: true }));
|
||||||
|
|
||||||
|
|
||||||
app.use(expressSession({
|
app.use(expressSession({
|
||||||
store: expressSession.MemoryStore(),
|
store: expressSession.MemoryStore(),
|
||||||
secret: process.env.SESSION_SECRET || 'default_secret',
|
secret: process.env.SESSION_SECRET || 'default_secret',
|
||||||
|
@ -97,19 +80,25 @@ app.set('views', __dirname + '/views');
|
||||||
app.use(express.static('public'));
|
app.use(express.static('public'));
|
||||||
|
|
||||||
const addAnalytic = (tag) => {
|
const addAnalytic = (tag) => {
|
||||||
db.get("SELECT * FROM analytics WHERE tag = ?", [tag], (err, row) => {
|
pool.getConnection().then(conn => {
|
||||||
if (err) {
|
conn.query("SELECT * FROM analytics WHERE tag = ?", [tag]).then((rows) => {
|
||||||
console.error('Error checking analytics:', err);
|
console.log(rows);
|
||||||
}
|
if (rows.length === 0) {
|
||||||
if (!row) {
|
conn.query("INSERT INTO analytics (tag, count) VALUES (?, 1)", [tag]).catch(err => {
|
||||||
db.run("INSERT INTO analytics (tag, count) VALUES (?, 1)", [tag], (err) => {
|
console.error('Error creating analytics:', err);
|
||||||
if (err) console.error('Error creating analytics:', err);
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
db.run("UPDATE analytics SET count = count + 1 WHERE tag = ?", [tag], (err) => {
|
conn.query("UPDATE analytics SET count = count + 1 WHERE tag = ?", [tag]).catch(err => {
|
||||||
if (err) console.error('Error updating analytics:', err);
|
console.error('Error updating analytics:', err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Error checking analytics:', err);
|
||||||
|
}).finally(() => {
|
||||||
|
conn.release();
|
||||||
|
});
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Error getting connection:', err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,19 +108,24 @@ const dailyAnalytic = (tag) => { // This is a bit more complex, but it's just a
|
||||||
const date = new Date();
|
const date = new Date();
|
||||||
const today = `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
|
const today = `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
|
||||||
|
|
||||||
db.get("SELECT * FROM dailyAnalytics WHERE tag = ? AND tag_date = ?", [tag, today], (err, row) => {
|
pool.getConnection().then(conn => {
|
||||||
if (err) {
|
conn.query("SELECT * FROM dailyAnalytics WHERE tag = ? AND tag_date = ?", [tag, today]).then((rows) => {
|
||||||
console.error('Error checking daily analytics:', err);
|
if (rows.length === 0) {
|
||||||
}
|
conn.query("INSERT INTO dailyAnalytics (tag, tag_date, count) VALUES (?, ?, 1)", [tag, today]).catch(err => {
|
||||||
if (!row) {
|
console.error('Error creating daily analytics:', err);
|
||||||
db.run("INSERT INTO dailyAnalytics (tag, tag_date, count) VALUES (?, ?, 1)", [tag, today], (err) => {
|
|
||||||
if (err) console.error('Error creating daily analytics:', err);
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
db.run("UPDATE dailyAnalytics SET count = count + 1 WHERE tag = ? AND tag_date = ?", [tag, today], (err) => {
|
conn.query("UPDATE dailyAnalytics SET count = count + 1 WHERE tag = ? AND tag_date = ?", [tag, today]).catch(err => {
|
||||||
if (err) console.error('Error updating daily analytics:', err);
|
console.error('Error updating daily analytics:', err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Error checking daily analytics:', err);
|
||||||
|
}).finally(() => {
|
||||||
|
conn.release();
|
||||||
|
});
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Error getting connection:', err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,29 +169,29 @@ app.get('/admin/route/:id', (req, res) => {
|
||||||
res.redirect('/admin/login');
|
res.redirect('/admin/login');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
db.get('SELECT * FROM routes WHERE id = ?', [req.params.id], (err, row) => {
|
pool.getConnection().then(conn => {
|
||||||
if (err) {
|
conn.query('SELECT * FROM routes WHERE id = ?', [req.params.id]).then((rows) => {
|
||||||
console.error('Error getting route:', err);
|
const row = rows[0];
|
||||||
res.status(500).send('Internal server error');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!row) {
|
if (!row) {
|
||||||
res.status(404).send('Not Found');
|
res.status(404).send('Not Found');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
res.render('admin/edit', { user: req.session.user, data: row });
|
res.render('admin/edit', { user: req.session.user, data: row });
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Error getting route:', err);
|
||||||
|
res.status(500).send('Internal server error');
|
||||||
|
}).finally(() => {
|
||||||
|
conn.release();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/admin/login', (req, res) => {
|
app.post('/admin/login', (req, res) => {
|
||||||
const username = req.body.username;
|
const username = req.body.username;
|
||||||
const password = req.body.password;
|
const password = req.body.password;
|
||||||
db.get("SELECT * FROM users WHERE username = ?", [String(username)], (err, row) => {
|
pool.getConnection().then(conn => {
|
||||||
if (err) {
|
conn.query("SELECT * FROM users WHERE username = ?", [String(username)]).then((rows) => {
|
||||||
console.error('Error getting user:', err);
|
const row = rows[0];
|
||||||
res.status(500).send('Internal server error');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!row) {
|
if (!row) {
|
||||||
res.status(401).send('Unauthorized (Not Found)');
|
res.status(401).send('Unauthorized (Not Found)');
|
||||||
return;
|
return;
|
||||||
|
@ -216,6 +210,12 @@ app.post('/admin/login', (req, res) => {
|
||||||
res.status(401).send('Unauthorized');
|
res.status(401).send('Unauthorized');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Error getting user:', err);
|
||||||
|
res.status(500).send('Internal server error');
|
||||||
|
}).finally(() => {
|
||||||
|
conn.release();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -224,13 +224,15 @@ app.get('/api/v1/admin/routes', (req, res) => { // Get all routes
|
||||||
res.status(401).json({ error: 'Unauthorized' });
|
res.status(401).json({ error: 'Unauthorized' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
db.all('SELECT * FROM routes', (err, rows) => {
|
pool.getConnection().then(conn => {
|
||||||
if (err) {
|
conn.query('SELECT * FROM routes').then((rows) => {
|
||||||
|
res.json(rows);
|
||||||
|
}).catch(err => {
|
||||||
console.error('Error getting routes:', err);
|
console.error('Error getting routes:', err);
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
return;
|
}).finally(() => {
|
||||||
}
|
conn.release();
|
||||||
res.json(rows);
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -239,17 +241,20 @@ app.get('/api/v1/admin/route/:id', (req, res) => { // Get route
|
||||||
res.status(401).json({ error: 'Unauthorized' });
|
res.status(401).json({ error: 'Unauthorized' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
db.get('SELECT * FROM routes WHERE id = ?', [req.params.id], (err, row) => {
|
pool.getConnection().then(conn => {
|
||||||
if (err) {
|
conn.query('SELECT * FROM routes WHERE id = ?', [req.params.id]).then((rows) => {
|
||||||
console.error('Error getting route:', err);
|
const row = rows[0];
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!row) {
|
if (!row) {
|
||||||
res.status(404).json({ error: 'Not Found' });
|
res.status(404).json({ error: 'Not Found' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
res.json(row);
|
res.json(row);
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Error getting route:', err);
|
||||||
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
|
}).finally(() => {
|
||||||
|
conn.release();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -272,27 +277,27 @@ app.post('/api/v1/admin/route', (req, res) => { // Create a new route
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Check if route already exists (OR conditions on server, and block range)
|
// Check if route already exists (OR conditions on server, and block range)
|
||||||
db.get('SELECT * FROM routes WHERE block_start <= ? AND block_start + block_length >= ?', [block_start, block_start], (err, row) => {
|
pool.getConnection().then(conn => {
|
||||||
if (err) {
|
conn.query('SELECT * FROM routes WHERE block_start <= ? AND block_start + block_length >= ?', [block_start, block_start]).then((rows) => {
|
||||||
console.error('Error checking for existing route:', err);
|
const row = rows[0];
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (row) {
|
if (row) {
|
||||||
res.status(409).json({ error: 'Conflict' });
|
res.status(409).json({ error: 'Conflict' });
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
db.run('INSERT INTO routes (server, port, auth, secret, block_start, block_length, apiKey, contact) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
|
conn.query('INSERT INTO routes (server, port, auth, secret, block_start, block_length, apiKey, contact) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
|
||||||
[server, port, auth, secret, block_start, block_length, apiKey, contact],
|
[server, port, auth, secret, block_start, block_length, apiKey, contact]).then(() => {
|
||||||
(err) => {
|
res.status(201).json({ message: 'Created' });
|
||||||
if (err) {
|
}).catch(err => {
|
||||||
console.error('Error creating route:', err);
|
console.error('Error creating route:', err);
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
return;
|
|
||||||
}
|
|
||||||
res.status(201).json({ message: 'Created' });
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Error checking for existing route:', err);
|
||||||
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
|
}).finally(() => {
|
||||||
|
conn.release();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -303,12 +308,9 @@ app.put('/api/v1/admin/route/:id', (req, res) => { // Update a route
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Check if route exists
|
// Check if route exists
|
||||||
db.get('SELECT * FROM routes WHERE id = ?', [req.params.id], (err, row) => {
|
pool.getConnection().then(conn => {
|
||||||
if (err) {
|
conn.query('SELECT * FROM routes WHERE id = ?', [req.params.id]).then((rows) => {
|
||||||
console.error('Error getting route:', err);
|
const row = rows[0];
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!row) {
|
if (!row) {
|
||||||
res.status(404).json({ error: 'Not Found' });
|
res.status(404).json({ error: 'Not Found' });
|
||||||
return;
|
return;
|
||||||
|
@ -322,15 +324,18 @@ app.put('/api/v1/admin/route/:id', (req, res) => { // Update a route
|
||||||
const block_length = req.body.block_length || row.block_length;
|
const block_length = req.body.block_length || row.block_length;
|
||||||
const contact = req.body.contact || row.contact;
|
const contact = req.body.contact || row.contact;
|
||||||
console.log(`Updating ${req.params.id} to ${server}:${port} with ${auth}:${secret} for ${block_start} - ${block_start + block_length}. Contact: ${contact}`);
|
console.log(`Updating ${req.params.id} to ${server}:${port} with ${auth}:${secret} for ${block_start} - ${block_start + block_length}. Contact: ${contact}`);
|
||||||
db.run('UPDATE routes SET server = ?, port = ?, auth = ?, secret = ?, block_start = ?, block_length = ?, contact = ? WHERE id = ?',
|
conn.query('UPDATE routes SET server = ?, port = ?, auth = ?, secret = ?, block_start = ?, block_length = ?, contact = ? WHERE id = ?',
|
||||||
[server, port, auth, secret, block_start, block_length, contact, req.params.id],
|
[server, port, auth, secret, block_start, block_length, contact, req.params.id]).then(() => {
|
||||||
(err) => {
|
res.json({ message: 'Updated' });
|
||||||
if (err) {
|
}).catch(err => {
|
||||||
console.error('Error updating route:', err);
|
console.error('Error updating route:', err);
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
return;
|
});
|
||||||
}
|
}).catch(err => {
|
||||||
res.json({ message: 'Updated' });
|
console.error('Error getting route:', err);
|
||||||
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
|
}).finally(() => {
|
||||||
|
conn.release();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -340,13 +345,15 @@ app.delete('/api/v1/admin/route/:id', (req, res) => { // Delete a route
|
||||||
res.status(401).json({ error: 'Unauthorized' });
|
res.status(401).json({ error: 'Unauthorized' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
db.run('DELETE FROM routes WHERE id = ?', [req.params.id], (err) => {
|
pool.getConnection().then(conn => {
|
||||||
if (err) {
|
conn.query('DELETE FROM routes WHERE id = ?', [req.params.id]).then(() => {
|
||||||
|
res.json({ message: 'Deleted' });
|
||||||
|
}).catch(err => {
|
||||||
console.error('Error deleting route:', err);
|
console.error('Error deleting route:', err);
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
return;
|
}).finally(() => {
|
||||||
}
|
conn.release();
|
||||||
res.json({ message: 'Deleted' });
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -360,13 +367,15 @@ app.delete('/api/v1/admin/directory/:number', (req, res) => { // Delete a direct
|
||||||
res.status(400).json({ error: 'Bad Request' });
|
res.status(400).json({ error: 'Bad Request' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
db.run('DELETE FROM directory WHERE number = ?', [number], (err) => {
|
pool.getConnection().then(conn => {
|
||||||
if (err) {
|
conn.query('DELETE FROM directory WHERE number = ?', [number]).then(() => {
|
||||||
|
res.status(200).json({ message: 'Deleted' });
|
||||||
|
}).catch(err => {
|
||||||
console.error('Error deleting directory entry:', err);
|
console.error('Error deleting directory entry:', err);
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
return;
|
}).finally(() => {
|
||||||
}
|
conn.release();
|
||||||
res.status(200).json({ message: 'Deleted' });
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -379,20 +388,20 @@ app.get("/api/v1/admin/callLogs", (req, res) => {
|
||||||
const page = Number(req.query.page) || 1;
|
const page = Number(req.query.page) || 1;
|
||||||
const offset = (page - 1) * 100;
|
const offset = (page - 1) * 100;
|
||||||
// Get full count of call logs to calculate total pages
|
// Get full count of call logs to calculate total pages
|
||||||
db.get("SELECT COUNT(*) as count FROM callLogs", [], (err, row) => {
|
pool.getConnection().then(conn => {
|
||||||
if (err) {
|
conn.query("SELECT COUNT(*) as count FROM callLogs").then((rows) => {
|
||||||
console.error('Error getting call log count:', err);
|
const totalPages = Math.ceil(rows[0].count / 100);
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
conn.query("SELECT * FROM callLogs ORDER BY timestamp DESC LIMIT 100 OFFSET ?", [offset]).then((rows) => {
|
||||||
return;
|
res.json({ totalPages, page, data: rows });
|
||||||
}
|
}).catch(err => {
|
||||||
const totalPages = Math.ceil(row.count / 100);
|
|
||||||
db.all("SELECT * FROM callLogs ORDER BY timestamp DESC LIMIT 100 OFFSET ?", [offset], (err, rows) => {
|
|
||||||
if (err) {
|
|
||||||
console.error('Error getting call logs:', err);
|
console.error('Error getting call logs:', err);
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
return;
|
});
|
||||||
}
|
}).catch(err => {
|
||||||
res.json({ totalPages, page, data: rows });
|
console.error('Error getting call log count:', err);
|
||||||
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
|
}).finally(() => {
|
||||||
|
conn.release();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -414,12 +423,9 @@ app.get('/user/login', (req, res) => {
|
||||||
|
|
||||||
app.post('/user/login', (req, res) => {
|
app.post('/user/login', (req, res) => {
|
||||||
const apiKey = req.body.apiKey;
|
const apiKey = req.body.apiKey;
|
||||||
db.get("SELECT * FROM routes WHERE apiKey = ?", [apiKey], (err, row) => {
|
pool.getConnection().then(conn => {
|
||||||
if (err) {
|
conn.query("SELECT * FROM routes WHERE apiKey = ?", [apiKey]).then((rows) => {
|
||||||
console.error('Error getting route:', err);
|
const row = rows[0];
|
||||||
res.status(500).send('Internal server error');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!row) {
|
if (!row) {
|
||||||
res.status(401).send('Unauthorized');
|
res.status(401).send('Unauthorized');
|
||||||
return;
|
return;
|
||||||
|
@ -427,6 +433,12 @@ app.post('/user/login', (req, res) => {
|
||||||
req.session.userAuthenticated = true;
|
req.session.userAuthenticated = true;
|
||||||
req.session.userData = row;
|
req.session.userData = row;
|
||||||
res.redirect('/user');
|
res.redirect('/user');
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Error getting route:', err);
|
||||||
|
res.status(500).send('Internal server error');
|
||||||
|
}).finally(() => {
|
||||||
|
conn.release();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -447,7 +459,7 @@ app.get("/user/edit", (req, res) => {
|
||||||
auth: req.session.userData.auth,
|
auth: req.session.userData.auth,
|
||||||
secret: req.session.userData.secret
|
secret: req.session.userData.secret
|
||||||
}
|
}
|
||||||
res.render('user/edit', {data: responseData});
|
res.render('user/edit', { data: responseData });
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/api/v1/user/route', (req, res) => { // Get route
|
app.get('/api/v1/user/route', (req, res) => { // Get route
|
||||||
|
@ -473,19 +485,20 @@ app.put('/api/v1/user/route', (req, res) => { // Update route
|
||||||
const port = req.body.port || req.session.userData.port;
|
const port = req.body.port || req.session.userData.port;
|
||||||
const auth = req.body.auth || req.session.userData.auth;
|
const auth = req.body.auth || req.session.userData.auth;
|
||||||
const secret = req.body.secret || req.session.userData.secret;
|
const secret = req.body.secret || req.session.userData.secret;
|
||||||
db.run('UPDATE routes SET server = ?, port = ?, auth = ?, secret = ? WHERE apiKey = ?',
|
pool.getConnection().then(conn => {
|
||||||
[server, port, auth, secret, req.session.userData.apiKey],
|
conn.query('UPDATE routes SET server = ?, port = ?, auth = ?, secret = ? WHERE apiKey = ?',
|
||||||
(err) => {
|
[server, port, auth, secret, req.session.userData.apiKey]).then(() => {
|
||||||
if (err) {
|
|
||||||
console.error('Error updating route:', err);
|
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
req.session.userData.server = server;
|
req.session.userData.server = server;
|
||||||
req.session.userData.port = port;
|
req.session.userData.port = port;
|
||||||
req.session.userData.auth = auth;
|
req.session.userData.auth = auth;
|
||||||
req.session.userData.secret = secret;
|
req.session.userData.secret = secret;
|
||||||
res.json({ message: 'Updated' });
|
res.json({ message: 'Updated' });
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Error updating route:', err);
|
||||||
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
|
}).finally(() => {
|
||||||
|
conn.release();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -494,13 +507,15 @@ app.get('/api/v1/user/directory', (req, res) => { // Get directory entries creat
|
||||||
res.status(401).json({ error: 'Unauthorized' });
|
res.status(401).json({ error: 'Unauthorized' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
db.all('SELECT * FROM directory WHERE route = ?', [req.session.userData.id], (err, rows) => {
|
pool.getConnection().then(conn => {
|
||||||
if (err) {
|
conn.query('SELECT * FROM directory WHERE route = ?', [req.session.userData.id]).then((rows) => {
|
||||||
|
res.json(rows);
|
||||||
|
}).catch(err => {
|
||||||
console.error('Error getting routes:', err);
|
console.error('Error getting routes:', err);
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
return;
|
}).finally(() => {
|
||||||
}
|
conn.release();
|
||||||
res.json(rows);
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -528,35 +543,32 @@ app.post('/api/v1/user/directory', (req, res) => { // Create a new directory ent
|
||||||
|
|
||||||
const route = req.session.userData.id;
|
const route = req.session.userData.id;
|
||||||
// If number already exists, update, otherwise insert
|
// If number already exists, update, otherwise insert
|
||||||
db.get('SELECT * FROM directory WHERE number = ? AND route = ?', [number, route], (err, row) => {
|
pool.getConnection().then(conn => {
|
||||||
if (err) {
|
conn.query('SELECT * FROM directory WHERE number = ? AND route = ?', [number, route]).then((rows) => {
|
||||||
console.error('Error checking for existing directory entry:', err);
|
const row = rows[0];
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (row) {
|
if (row) {
|
||||||
db.run('UPDATE directory SET name = ? WHERE number = ? AND route = ?',
|
conn.query('UPDATE directory SET name = ? WHERE number = ? AND route = ?',
|
||||||
[name, number, route],
|
[name, number, route]).then(() => {
|
||||||
(err) => {
|
res.json({ message: 'Updated' });
|
||||||
if (err) {
|
}).catch(err => {
|
||||||
console.error('Error updating directory entry:', err);
|
console.error('Error updating directory entry:', err);
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
return;
|
|
||||||
}
|
|
||||||
res.json({ message: 'Updated' });
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
db.run('INSERT INTO directory (number, name, route) VALUES (?, ?, ?)',
|
conn.query('INSERT INTO directory (number, name, route) VALUES (?, ?, ?)',
|
||||||
[number, name, route],
|
[number, name, route]).then(() => {
|
||||||
(err) => {
|
res.status(201).json({ message: 'Created' });
|
||||||
if (err) {
|
}).catch(err => {
|
||||||
console.error('Error creating directory entry:', err);
|
console.error('Error creating directory entry:', err);
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
return;
|
|
||||||
}
|
|
||||||
res.status(201).json({ message: 'Created' });
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Error checking for existing directory entry:', err);
|
||||||
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
|
}).finally(() => {
|
||||||
|
conn.release();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -570,13 +582,15 @@ app.delete('/api/v1/user/directory/:number', (req, res) => { // Delete a directo
|
||||||
res.status(400).json({ error: 'Bad Request' });
|
res.status(400).json({ error: 'Bad Request' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
db.run('DELETE FROM directory WHERE number = ? AND route = ?', [number, req.session.userData.id], (err) => {
|
pool.getConnection().then(conn => {
|
||||||
if (err) {
|
conn.query('DELETE FROM directory WHERE number = ? AND route = ?', [number, req.session.userData.id]).then(() => {
|
||||||
|
res.status(200).json({ message: 'Deleted' });
|
||||||
|
}).catch(err => {
|
||||||
console.error('Error deleting directory entry:', err);
|
console.error('Error deleting directory entry:', err);
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
return;
|
}).finally(() => {
|
||||||
}
|
conn.release();
|
||||||
res.status(200).json({ message: 'Deleted' });
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -585,13 +599,15 @@ app.delete('/api/v1/user/directory/:number', (req, res) => { // Delete a directo
|
||||||
// == Directory routes == (unauthenticated)
|
// == Directory routes == (unauthenticated)
|
||||||
|
|
||||||
app.get("/api/v1/directory", (req, res) => {
|
app.get("/api/v1/directory", (req, res) => {
|
||||||
db.all("SELECT * FROM directory", (err, rows) => {
|
pool.getConnection().then(conn => {
|
||||||
if (err) {
|
conn.query("SELECT * FROM directory").then((rows) => {
|
||||||
|
res.json(rows);
|
||||||
|
}).catch(err => {
|
||||||
console.error('Error getting directory:', err);
|
console.error('Error getting directory:', err);
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
return;
|
}).finally(() => {
|
||||||
}
|
conn.release();
|
||||||
res.json(rows);
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -618,18 +634,9 @@ app.get("/discord", (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/api/analytics", (req, res) => {
|
app.get("/api/analytics", (req, res) => {
|
||||||
db.all("SELECT * FROM analytics", (err, total) => {
|
pool.getConnection().then(conn => {
|
||||||
if (err) {
|
conn.query("SELECT * FROM analytics").then((total) => {
|
||||||
console.error('Error getting analytics:', err);
|
conn.query("SELECT * FROM dailyAnalytics").then((daily) => {
|
||||||
res.status(500).send('Internal server error');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
db.all("SELECT * FROM dailyAnalytics", (err, daily) => {
|
|
||||||
if (err) {
|
|
||||||
console.error('Error getting daily analytics:', err);
|
|
||||||
res.status(500).send('Internal server error');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Find the latest date and add "current:true" to it
|
// Find the latest date and add "current:true" to it
|
||||||
var latest = { tag_date: "1970-01-01", count: 0 };
|
var latest = { tag_date: "1970-01-01", count: 0 };
|
||||||
daily.forEach((entry) => {
|
daily.forEach((entry) => {
|
||||||
|
@ -639,6 +646,15 @@ app.get("/api/analytics", (req, res) => {
|
||||||
});
|
});
|
||||||
latest.current = true;
|
latest.current = true;
|
||||||
res.json({ total, daily });
|
res.json({ total, daily });
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Error getting daily analytics:', err);
|
||||||
|
res.status(500).send('Internal server error');
|
||||||
|
});
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Error getting analytics:', err);
|
||||||
|
res.status(500).send('Internal server error');
|
||||||
|
}).finally(() => {
|
||||||
|
conn.release();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -654,38 +670,46 @@ app.get("/api/v1/checkAvailability/:number", (req, res) => {
|
||||||
res.status(400).json({ error: `Number is outside valid range` });
|
res.status(400).json({ error: `Number is outside valid range` });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
db.get('SELECT * FROM routes WHERE block_start <= ? AND block_start + block_length >= ?', [number, number], (err, row) => {
|
pool.getConnection().then(conn => {
|
||||||
if (err) {
|
conn.query('SELECT * FROM routes WHERE block_start <= ? AND block_start + block_length >= ?', [number, number]).then((rows) => {
|
||||||
console.error('Error getting route:', err);
|
const row = rows[0];
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (row) {
|
if (row) {
|
||||||
res.json({ available: false, block: row.block_start });
|
res.json({ available: false, block: row.block_start });
|
||||||
} else {
|
} else {
|
||||||
res.json({ available: true });
|
res.json({ available: true });
|
||||||
}
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Error getting route:', err);
|
||||||
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
|
}).finally(() => {
|
||||||
|
conn.release();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/api/healthcheck", (req, res) => {
|
app.get("/api/healthcheck", (req, res) => {
|
||||||
// Check ability to connect to database with select * from routes
|
// Check ability to connect to database with select * from routes
|
||||||
db.get('SELECT * FROM routes', [], (err, row) => {
|
pool.getConnection().then(conn => {
|
||||||
if (err) {
|
conn.query('SELECT * FROM routes').then(() => {
|
||||||
|
res.status(200).send('OK');
|
||||||
|
}).catch(err => {
|
||||||
console.error('Error checking health:', err);
|
console.error('Error checking health:', err);
|
||||||
res.status(500).send('Internal server error');
|
res.status(500).send('Internal server error');
|
||||||
return;
|
}).finally(() => {
|
||||||
}
|
conn.release();
|
||||||
res.status(200).send('OK');
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// logCall function (caller, callee)
|
// logCall function (caller, callee)
|
||||||
const logCall = (caller, callee) => {
|
const logCall = (caller, callee) => {
|
||||||
db.run('INSERT INTO callLogs (caller, callee, timestamp) VALUES (?, ?, ?)',
|
pool.getConnection().then(conn => {
|
||||||
[caller, callee, Math.floor(Date.now())],
|
conn.query('INSERT INTO callLogs (caller, callee, timestamp) VALUES (?, ?, ?)',
|
||||||
(err) => {
|
[caller, callee, Math.floor(Date.now())]).catch(err => {
|
||||||
if (err) console.error('Error logging call:', err);
|
console.error('Error logging call:', err);
|
||||||
|
}).finally(() => {
|
||||||
|
conn.release();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -694,18 +718,17 @@ app.get('/api/v1/route/:apiKey/:ani/:number', (req, res) => {
|
||||||
const apiKey = req.params.apiKey;
|
const apiKey = req.params.apiKey;
|
||||||
const number = Number(req.params.number);
|
const number = Number(req.params.number);
|
||||||
const ani = Number(req.params.ani);
|
const ani = Number(req.params.ani);
|
||||||
db.get("SELECT * FROM routes WHERE apiKey = ? AND block_start <= ? AND block_start + block_length >= ?", [apiKey, ani, ani], (err, row) => {
|
pool.getConnection().then(conn => {
|
||||||
|
conn.query("SELECT * FROM routes WHERE apiKey = ? AND block_start <= ? AND block_start + block_length >= ?", [apiKey, ani, ani]).then((rows) => {
|
||||||
|
const row = rows[0];
|
||||||
// If no row or error, return 401
|
// If no row or error, return 401
|
||||||
if (err || !row) {
|
if (!row) {
|
||||||
console.error(err);
|
|
||||||
res.status(401).send(`${process.env.MSG_ROUTE_ADDRESS}/401`)
|
res.status(401).send(`${process.env.MSG_ROUTE_ADDRESS}/401`)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
db.get('SELECT * FROM routes WHERE block_start <= ? AND block_start + block_length >= ?', [number, number], (err, row) => {
|
conn.query('SELECT * FROM routes WHERE block_start <= ? AND block_start + block_length >= ?', [number, number]).then((rows) => {
|
||||||
if (err) {
|
const row = rows[0];
|
||||||
console.error('Error getting route:', err);
|
if (row) {
|
||||||
res.status(500).send(`${process.env.MSG_ROUTE_ADDRESS}/500`)
|
|
||||||
} else if (row) {
|
|
||||||
// Check if the ANI is within the block range
|
// Check if the ANI is within the block range
|
||||||
// If it is, return `local`
|
// If it is, return `local`
|
||||||
console.log(`New Call: ${ani} -> ${number}`);
|
console.log(`New Call: ${ani} -> ${number}`);
|
||||||
|
@ -721,6 +744,15 @@ app.get('/api/v1/route/:apiKey/:ani/:number', (req, res) => {
|
||||||
} else {
|
} else {
|
||||||
res.status(404).send(`${process.env.MSG_ROUTE_ADDRESS}/404`);
|
res.status(404).send(`${process.env.MSG_ROUTE_ADDRESS}/404`);
|
||||||
}
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Error getting route:', err);
|
||||||
|
res.status(500).send(`${process.env.MSG_ROUTE_ADDRESS}/500`)
|
||||||
|
});
|
||||||
|
}).catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
res.status(401).send(`${process.env.MSG_ROUTE_ADDRESS}/401`)
|
||||||
|
}).finally(() => {
|
||||||
|
conn.release();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -729,18 +761,17 @@ app.get('/api/v1', (req, res) => { // Backwards compatibility with TandmX cause
|
||||||
const apiKey = req.query.auth;
|
const apiKey = req.query.auth;
|
||||||
const number = Number(req.query.number);
|
const number = Number(req.query.number);
|
||||||
const ani = Number(req.query.ani);
|
const ani = Number(req.query.ani);
|
||||||
db.get("SELECT * FROM routes WHERE apiKey = ? AND block_start <= ? AND block_start + block_length >= ?", [apiKey, ani, ani], (err, row) => {
|
pool.getConnection().then(conn => {
|
||||||
|
conn.query("SELECT * FROM routes WHERE apiKey = ? AND block_start <= ? AND block_start + block_length >= ?", [apiKey, ani, ani]).then((rows) => {
|
||||||
|
const row = rows[0];
|
||||||
// If no row or error, return 401
|
// If no row or error, return 401
|
||||||
if (err || !row) {
|
if (!row) {
|
||||||
console.error(err);
|
|
||||||
res.status(401).send(`${process.env.MSG_ROUTE_ADDRESS}/401`)
|
res.status(401).send(`${process.env.MSG_ROUTE_ADDRESS}/401`)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
db.get('SELECT * FROM routes WHERE block_start <= ? AND block_start + block_length >= ?', [number, number], (err, row) => {
|
conn.query('SELECT * FROM routes WHERE block_start <= ? AND block_start + block_length >= ?', [number, number]).then((rows) => {
|
||||||
if (err) {
|
const row = rows[0];
|
||||||
console.error('Error getting route:', err);
|
if (row) {
|
||||||
res.status(500).send(`${process.env.MSG_ROUTE_ADDRESS}/500`)
|
|
||||||
} else if (row) {
|
|
||||||
// Check if the ANI is within the block range
|
// Check if the ANI is within the block range
|
||||||
// If it is, return `local`
|
// If it is, return `local`
|
||||||
console.log(`New Call: ${ani} -> ${number}`);
|
console.log(`New Call: ${ani} -> ${number}`);
|
||||||
|
@ -755,6 +786,15 @@ app.get('/api/v1', (req, res) => { // Backwards compatibility with TandmX cause
|
||||||
} else {
|
} else {
|
||||||
res.status(404).send(`${process.env.MSG_ROUTE_ADDRESS}/404`);
|
res.status(404).send(`${process.env.MSG_ROUTE_ADDRESS}/404`);
|
||||||
}
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Error getting route:', err);
|
||||||
|
res.status(500).send(`${process.env.MSG_ROUTE_ADDRESS}/500`)
|
||||||
|
});
|
||||||
|
}).catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
res.status(401).send(`${process.env.MSG_ROUTE_ADDRESS}/401`)
|
||||||
|
}).finally(() => {
|
||||||
|
conn.release();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,23 +1,27 @@
|
||||||
const sqlite3 = require('sqlite3').verbose();
|
const mariadb = require('mariadb');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const util = require("util");
|
const util = require("util")
|
||||||
|
|
||||||
function runMigrations(db) {
|
|
||||||
|
function runMigrations(pool) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const migrationDir = path.join(__dirname, 'migrations');
|
let connection;
|
||||||
|
|
||||||
const runQuery = util.promisify(db.run.bind(db));
|
pool.getConnection()
|
||||||
const getQuery = util.promisify(db.get.bind(db));
|
.then(conn => {
|
||||||
|
connection = conn;
|
||||||
|
|
||||||
// Ensure a migrations table exists to track applied migrations
|
// Ensure a migrations table exists to track applied migrations
|
||||||
runQuery(`CREATE TABLE IF NOT EXISTS migrations (
|
return connection.query(`CREATE TABLE IF NOT EXISTS migrations (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
name TEXT NOT NULL,
|
name VARCHAR(255) NOT NULL,
|
||||||
applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
);`)
|
);`);
|
||||||
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// Read all migration files
|
// Read all migration files
|
||||||
|
const migrationDir = path.join(__dirname, 'migrations');
|
||||||
const files = fs.readdirSync(migrationDir).sort(); // Sort to apply in order
|
const files = fs.readdirSync(migrationDir).sort(); // Sort to apply in order
|
||||||
|
|
||||||
return files.reduce((promise, file) => {
|
return files.reduce((promise, file) => {
|
||||||
|
@ -25,22 +29,21 @@ function runMigrations(db) {
|
||||||
const migrationName = path.basename(file);
|
const migrationName = path.basename(file);
|
||||||
|
|
||||||
// Check if the migration has already been applied
|
// Check if the migration has already been applied
|
||||||
return getQuery(
|
return connection.query(
|
||||||
'SELECT 1 FROM migrations WHERE name = ? LIMIT 1',
|
'SELECT 1 FROM migrations WHERE name = ? LIMIT 1',
|
||||||
[migrationName]
|
[migrationName]
|
||||||
).then((row) => {
|
).then(([rows]) => {
|
||||||
if (row) {
|
if (Object.keys(rows || {}).length > 0) {
|
||||||
// console.log(`Skipping already applied migration: ${migrationName}`);
|
//console.log(`Skipping already applied migration: ${migrationName}`);
|
||||||
return; // Skip this migration
|
return; // Skip this migration
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read and execute the migration SQL
|
// Read and execute the migration SQL
|
||||||
const migrationPath = path.join(migrationDir, file);
|
const migrationPath = path.join(migrationDir, file);
|
||||||
const sql = fs.readFileSync(migrationPath, 'utf8');
|
const sql = fs.readFileSync(migrationPath, 'utf8');
|
||||||
|
return connection.query(sql).then(() => {
|
||||||
return runQuery(sql).then(() => {
|
|
||||||
// Record the applied migration
|
// Record the applied migration
|
||||||
return runQuery(
|
return connection.query(
|
||||||
'INSERT INTO migrations (name) VALUES (?)',
|
'INSERT INTO migrations (name) VALUES (?)',
|
||||||
[migrationName]
|
[migrationName]
|
||||||
).then(() => {
|
).then(() => {
|
||||||
|
@ -55,11 +58,15 @@ function runMigrations(db) {
|
||||||
console.log('All migrations applied successfully!');
|
console.log('All migrations applied successfully!');
|
||||||
resolve();
|
resolve();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch(err => {
|
||||||
console.error('Error running migrations:', err);
|
console.errorr('Error running migrations:', err);
|
||||||
reject(err);
|
reject(err);
|
||||||
})
|
})
|
||||||
|
.finally(() => {
|
||||||
|
if (connection) connection.release();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = runMigrations;
|
|
||||||
|
module.exports = runMigrations
|
|
@ -1,10 +1,10 @@
|
||||||
CREATE TABLE IF NOT EXISTS routes (
|
CREATE TABLE IF NOT EXISTS routes (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTO_INCREMENT,
|
||||||
server TEXT NOT NULL,
|
server VARCHAR(255) NOT NULL,
|
||||||
port INTEGER NOT NULL DEFAULT 4569,
|
port INTEGER NOT NULL DEFAULT 4569,
|
||||||
auth TEST NOT NULL DEFAULT 'from-astrocom',
|
auth VARCHAR(255) NOT NULL DEFAULT 'from-astrocom',
|
||||||
secret TEXT NOT NULL,
|
secret VARCHAR(255) NOT NULL,
|
||||||
block_start INTEGER UNIQUE NOT NULL,
|
block_start INTEGER UNIQUE NOT NULL,
|
||||||
block_length INTEGER NOT NULL DEFAULT 9999,
|
block_length INTEGER NOT NULL DEFAULT 9999,
|
||||||
apiKey TEXT NOT NULL
|
apiKey VARCHAR(255) NOT NULL
|
||||||
)
|
);
|
|
@ -1,5 +1,5 @@
|
||||||
CREATE TABLE IF NOT EXISTS users (
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTO_INCREMENT,
|
||||||
username TEXT NOT NULL,
|
username VARCHAR(255) NOT NULL,
|
||||||
passwordHash TEXT NOT NULL
|
passwordHash VARCHAR(255) NOT NULL
|
||||||
)
|
);
|
|
@ -1,6 +1,6 @@
|
||||||
CREATE TABLE IF NOT EXISTS directory (
|
CREATE TABLE IF NOT EXISTS directory (
|
||||||
number INTEGER PRIMARY KEY NOT NULL, -- This is the directory phone number
|
number INTEGER PRIMARY KEY NOT NULL, -- This is the directory phone number
|
||||||
name TEXT NOT NULL, -- This is the text of the entry, set by the user.
|
name VARCHAR(255) NOT NULL, -- This is the VARCHAR(255) of the entry, set by the user.
|
||||||
route INTEGER NOT NULL, -- This is the ID of the route that owns this entry. Foreign key to routes.id
|
route INTEGER NOT NULL, -- This is the ID of the route that owns this entry. Foreign key to routes.id
|
||||||
FOREIGN KEY(route) REFERENCES routes(id)
|
FOREIGN KEY(route) REFERENCES routes(id)
|
||||||
)
|
);
|
|
@ -1,4 +1,4 @@
|
||||||
CREATE TABLE IF NOT EXISTS analytics (
|
CREATE TABLE IF NOT EXISTS analytics (
|
||||||
tag TEXT NOT NULL PRIMARY KEY,
|
tag VARCHAR(255) NOT NULL PRIMARY KEY,
|
||||||
count INTEGER NOT NULL DEFAULT 0
|
count INTEGER NOT NULL DEFAULT 0
|
||||||
);
|
);
|
|
@ -1,6 +1,6 @@
|
||||||
CREATE TABLE IF NOT EXISTS dailyAnalytics (
|
CREATE TABLE IF NOT EXISTS dailyAnalytics (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTO_INCREMENT,
|
||||||
tag TEXT NOT NULL,
|
tag VARCHAR(255) NOT NULL,
|
||||||
count INTEGER NOT NULL DEFAULT 0,
|
count INTEGER NOT NULL DEFAULT 0,
|
||||||
tag_date TEXT NOT NULL
|
tag_date VARCHAR(255) NOT NULL
|
||||||
);
|
);
|
|
@ -1,6 +1,6 @@
|
||||||
CREATE TABLE callLogs (
|
CREATE TABLE callLogs (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTO_INCREMENT,
|
||||||
timestamp TEXT NOT NULL,
|
timestamp VARCHAR(255) NOT NULL,
|
||||||
caller TEXT NOT NULL,
|
caller VARCHAR(255) NOT NULL,
|
||||||
callee TEXT NOT NULL
|
callee VARCHAR(255) NOT NULL
|
||||||
);
|
);
|
|
@ -1,2 +1 @@
|
||||||
ALTER TABLE routes
|
ALTER TABLE routes ADD COLUMN contact VARCHAR(255);
|
||||||
ADD COLUMN contact TEXT;
|
|
65
package-lock.json
generated
65
package-lock.json
generated
|
@ -16,6 +16,7 @@
|
||||||
"escape-html": "^1.0.3",
|
"escape-html": "^1.0.3",
|
||||||
"express": "^4.21.2",
|
"express": "^4.21.2",
|
||||||
"express-session": "^1.18.1",
|
"express-session": "^1.18.1",
|
||||||
|
"mariadb": "^3.4.0",
|
||||||
"session-file-store": "^1.5.0",
|
"session-file-store": "^1.5.0",
|
||||||
"sqlite3": "^5.1.7"
|
"sqlite3": "^5.1.7"
|
||||||
}
|
}
|
||||||
|
@ -131,6 +132,21 @@
|
||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/geojson": {
|
||||||
|
"version": "7946.0.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.15.tgz",
|
||||||
|
"integrity": "sha512-9oSxFzDCT2Rj6DfcHF8G++jxBKS7mBqXl5xrRW+Kbvjry6Uduya2iiwqHPhVXpasAVMBYKkEPGgKhd3+/HZ6xA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@types/node": {
|
||||||
|
"version": "22.10.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz",
|
||||||
|
"integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~6.20.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/abbrev": {
|
"node_modules/abbrev": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||||
|
@ -680,6 +696,15 @@
|
||||||
"integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==",
|
"integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/denque": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/depd": {
|
"node_modules/depd": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||||
|
@ -1566,6 +1591,40 @@
|
||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mariadb": {
|
||||||
|
"version": "3.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mariadb/-/mariadb-3.4.0.tgz",
|
||||||
|
"integrity": "sha512-hdRPcAzs+MTxK5VG1thBW18gGTlw6yWBe9YnLB65GLo7q0fO5DWsgomIevV/pXSaWRmD3qi6ka4oSFRTExRiEQ==",
|
||||||
|
"license": "LGPL-2.1-or-later",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/geojson": "^7946.0.14",
|
||||||
|
"@types/node": "^22.5.4",
|
||||||
|
"denque": "^2.1.0",
|
||||||
|
"iconv-lite": "^0.6.3",
|
||||||
|
"lru-cache": "^10.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mariadb/node_modules/iconv-lite": {
|
||||||
|
"version": "0.6.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||||
|
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mariadb/node_modules/lru-cache": {
|
||||||
|
"version": "10.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
||||||
|
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
"node_modules/math-intrinsics": {
|
"node_modules/math-intrinsics": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.0.0.tgz",
|
||||||
|
@ -2729,6 +2788,12 @@
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/undici-types": {
|
||||||
|
"version": "6.20.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
|
||||||
|
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/unique-filename": {
|
"node_modules/unique-filename": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
"escape-html": "^1.0.3",
|
"escape-html": "^1.0.3",
|
||||||
"express": "^4.21.2",
|
"express": "^4.21.2",
|
||||||
"express-session": "^1.18.1",
|
"express-session": "^1.18.1",
|
||||||
|
"mariadb": "^3.4.0",
|
||||||
"session-file-store": "^1.5.0",
|
"session-file-store": "^1.5.0",
|
||||||
"sqlite3": "^5.1.7"
|
"sqlite3": "^5.1.7"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue