Compare commits
No commits in common. "main" and "testing" have entirely different histories.
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -131,6 +131,4 @@ dist
|
||||||
|
|
||||||
*.db
|
*.db
|
||||||
sessions/*
|
sessions/*
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
test/*
|
|
||||||
115
migrations.js
115
migrations.js
|
|
@ -1,72 +1,65 @@
|
||||||
const mariadb = require('mariadb');
|
const sqlite3 = require('sqlite3').verbose();
|
||||||
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) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const migrationDir = path.join(__dirname, 'migrations');
|
||||||
|
|
||||||
function runMigrations(pool) {
|
const runQuery = util.promisify(db.run.bind(db));
|
||||||
return new Promise((resolve, reject) => {
|
const getQuery = util.promisify(db.get.bind(db));
|
||||||
let connection;
|
|
||||||
|
|
||||||
pool.getConnection()
|
// Ensure a migrations table exists to track applied migrations
|
||||||
.then(conn => {
|
runQuery(`CREATE TABLE IF NOT EXISTS migrations (
|
||||||
connection = conn;
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);`)
|
||||||
|
.then(() => {
|
||||||
|
// Read all migration files
|
||||||
|
const files = fs.readdirSync(migrationDir).sort(); // Sort to apply in order
|
||||||
|
|
||||||
// Ensure a migrations table exists to track applied migrations
|
return files.reduce((promise, file) => {
|
||||||
return connection.query(`CREATE TABLE IF NOT EXISTS migrations (
|
return promise.then(() => {
|
||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
const migrationName = path.basename(file);
|
||||||
name VARCHAR(255) NOT NULL,
|
|
||||||
applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
||||||
);`);
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
// Read all migration files
|
|
||||||
const migrationDir = path.join(__dirname, 'migrations');
|
|
||||||
const files = fs.readdirSync(migrationDir).sort(); // Sort to apply in order
|
|
||||||
|
|
||||||
return files.reduce((promise, file) => {
|
// Check if the migration has already been applied
|
||||||
return promise.then(() => {
|
return getQuery(
|
||||||
const migrationName = path.basename(file);
|
'SELECT 1 FROM migrations WHERE name = ? LIMIT 1',
|
||||||
|
[migrationName]
|
||||||
|
).then((row) => {
|
||||||
|
if (row) {
|
||||||
|
// console.log(`Skipping already applied migration: ${migrationName}`);
|
||||||
|
return; // Skip this migration
|
||||||
|
}
|
||||||
|
|
||||||
// Check if the migration has already been applied
|
// Read and execute the migration SQL
|
||||||
return connection.query(
|
const migrationPath = path.join(migrationDir, file);
|
||||||
'SELECT 1 FROM migrations WHERE name = ? LIMIT 1',
|
const sql = fs.readFileSync(migrationPath, 'utf8');
|
||||||
[migrationName]
|
|
||||||
).then(([rows]) => {
|
|
||||||
if (Object.keys(rows || {}).length > 0) {
|
|
||||||
//console.log(`Skipping already applied migration: ${migrationName}`);
|
|
||||||
return; // Skip this migration
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read and execute the migration SQL
|
return runQuery(sql).then(() => {
|
||||||
const migrationPath = path.join(migrationDir, file);
|
// Record the applied migration
|
||||||
const sql = fs.readFileSync(migrationPath, 'utf8');
|
return runQuery(
|
||||||
return connection.query(sql).then(() => {
|
'INSERT INTO migrations (name) VALUES (?)',
|
||||||
// Record the applied migration
|
[migrationName]
|
||||||
return connection.query(
|
).then(() => {
|
||||||
'INSERT INTO migrations (name) VALUES (?)',
|
console.log(`Applied migration: ${migrationName}`);
|
||||||
[migrationName]
|
});
|
||||||
).then(() => {
|
});
|
||||||
console.log(`Applied migration: ${migrationName}`);
|
});
|
||||||
});
|
});
|
||||||
});
|
}, Promise.resolve());
|
||||||
});
|
})
|
||||||
});
|
.then(() => {
|
||||||
}, Promise.resolve());
|
console.log('All migrations applied successfully!');
|
||||||
})
|
resolve();
|
||||||
.then(() => {
|
})
|
||||||
console.log('All migrations applied successfully!');
|
.catch((err) => {
|
||||||
resolve();
|
console.error('Error running migrations:', err);
|
||||||
})
|
reject(err);
|
||||||
.catch(err => {
|
})
|
||||||
console.error('Error running migrations:', 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 AUTO_INCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
server VARCHAR(255) NOT NULL,
|
server TEXT NOT NULL,
|
||||||
port INTEGER NOT NULL DEFAULT 4569,
|
port INTEGER NOT NULL DEFAULT 4569,
|
||||||
auth VARCHAR(255) NOT NULL DEFAULT 'from-astrocom',
|
auth TEST NOT NULL DEFAULT 'from-astrocom',
|
||||||
secret VARCHAR(255) NOT NULL,
|
secret TEXT 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 VARCHAR(255) NOT NULL
|
apiKey TEXT NOT NULL
|
||||||
);
|
)
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
CREATE TABLE IF NOT EXISTS users (
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
id INTEGER PRIMARY KEY AUTO_INCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
username VARCHAR(255) NOT NULL,
|
username TEXT NOT NULL,
|
||||||
passwordHash VARCHAR(255) NOT NULL
|
passwordHash TEXT 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 VARCHAR(255) NOT NULL, -- This is the VARCHAR(255) of the entry, set by the user.
|
name TEXT NOT NULL, -- This is the text 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 VARCHAR(255) NOT NULL PRIMARY KEY,
|
tag TEXT 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 AUTO_INCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
tag VARCHAR(255) NOT NULL,
|
tag TEXT NOT NULL,
|
||||||
count INTEGER NOT NULL DEFAULT 0,
|
count INTEGER NOT NULL DEFAULT 0,
|
||||||
tag_date VARCHAR(255) NOT NULL
|
tag_date TEXT NOT NULL
|
||||||
);
|
);
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
CREATE TABLE callLogs (
|
CREATE TABLE callLogs (
|
||||||
id INTEGER PRIMARY KEY AUTO_INCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
timestamp VARCHAR(255) NOT NULL,
|
timestamp TEXT NOT NULL,
|
||||||
caller VARCHAR(255) NOT NULL,
|
caller TEXT NOT NULL,
|
||||||
callee VARCHAR(255) NOT NULL
|
callee TEXT NOT NULL
|
||||||
);
|
);
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
ALTER TABLE routes ADD COLUMN contact VARCHAR(255);
|
ALTER TABLE routes
|
||||||
|
ADD COLUMN contact TEXT;
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
CREATE TABLE IF NOT EXISTS admin_invites (
|
|
||||||
code VARCHAR(36) PRIMARY KEY NOT NULL DEFAULT (UUID()),
|
|
||||||
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
maxUses INTEGER NOT NULL DEFAULT 1,
|
|
||||||
uses INTEGER NOT NULL DEFAULT 0,
|
|
||||||
expiresAt TIMESTAMP,
|
|
||||||
createdBy INTEGER,
|
|
||||||
FOREIGN KEY (createdBy) REFERENCES users(id) ON DELETE SET NULL
|
|
||||||
);
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
CREATE TABLE IF NOT EXISTS blocklist (
|
|
||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
||||||
ownerId INT NOT NULL,
|
|
||||||
blockType INT NOT NULL,
|
|
||||||
blockValue VARCHAR(255) NOT NULL,
|
|
||||||
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
FOREIGN KEY (ownerId) REFERENCES routes(id) ON DELETE CASCADE
|
|
||||||
);
|
|
||||||
1467
package-lock.json
generated
1467
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -11,12 +11,13 @@
|
||||||
"description": "",
|
"description": "",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
"dotenv": "^16.6.1",
|
"connect-sqlite": "^0.0.1",
|
||||||
|
"dotenv": "^16.4.7",
|
||||||
"ejs": "^3.1.10",
|
"ejs": "^3.1.10",
|
||||||
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,6 @@ function getDirectoryEntries() {
|
||||||
row.innerHTML = `<td>${entry.number}</td><td>${entry.name}</td><td><button class="btn btn-danger" onclick="deleteDirectoryEntry(${entry.number})">Delete</button></td>`;
|
row.innerHTML = `<td>${entry.number}</td><td>${entry.name}</td><td><button class="btn btn-danger" onclick="deleteDirectoryEntry(${entry.number})">Delete</button></td>`;
|
||||||
table.appendChild(row);
|
table.appendChild(row);
|
||||||
});
|
});
|
||||||
const dirCount = document.getElementById('dirCount');
|
|
||||||
dirCount.textContent = data.length;
|
|
||||||
})
|
})
|
||||||
.catch(error => console.error('Error fetching directory:', error));
|
.catch(error => console.error('Error fetching directory:', error));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
const editForm = document.getElementById('editForm');
|
|
||||||
editForm.addEventListener('submit', async (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
const formData = new FormData(editForm);
|
|
||||||
const data = {};
|
|
||||||
|
|
||||||
for (const [key, value] of formData.entries()) {
|
|
||||||
data[key] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await fetch(`/api/v1/user/route`, {
|
|
||||||
method: 'PUT',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify(data)
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
window.location.href = '/user';
|
|
||||||
} else {
|
|
||||||
alert('Failed to update entry');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
@ -6,29 +6,12 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="stylesheet" href="/assets/css/bootstrap.min.css">
|
<link rel="stylesheet" href="/assets/css/bootstrap.min.css">
|
||||||
<title>AstroCom Directory</title>
|
<title>AstroCom Directory</title>
|
||||||
<script>
|
|
||||||
(function (d, t) {
|
|
||||||
var BASE_URL = "https://support.chrischro.me";
|
|
||||||
var g = d.createElement(t), s = d.getElementsByTagName(t)[0];
|
|
||||||
g.src = BASE_URL + "/packs/js/sdk.js";
|
|
||||||
g.defer = true;
|
|
||||||
g.async = true;
|
|
||||||
s.parentNode.insertBefore(g, s);
|
|
||||||
g.onload = function () {
|
|
||||||
window.chatwootSDK.run({
|
|
||||||
websiteToken: '1Epwwnhnmieqzu2dm3jYH3Qp',
|
|
||||||
baseUrl: BASE_URL
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})(document, "script");
|
|
||||||
</script>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="bg-dark text-white">
|
<body class="bg-dark text-white">
|
||||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<a class="navbar-brand" href="/">AstroCom</a>
|
<a class="navbar-brand" href="/">AstroCom</a>
|
||||||
<span id="footer"></span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="ms-auto d-flex text-nowrap">
|
<div class="ms-auto d-flex text-nowrap">
|
||||||
<a href="/user" class="btn btn-outline-light me-2">User Login</a>
|
<a href="/user" class="btn btn-outline-light me-2">User Login</a>
|
||||||
|
|
@ -57,11 +40,6 @@
|
||||||
<script src="/assets/js/bootstrap.min.js"></script>
|
<script src="/assets/js/bootstrap.min.js"></script>
|
||||||
<script src="/assets/js/bootstrap.bundle.min.js"></script>
|
<script src="/assets/js/bootstrap.bundle.min.js"></script>
|
||||||
<script src="/assets/js/jquery.min.js"></script>
|
<script src="/assets/js/jquery.min.js"></script>
|
||||||
<script>
|
|
||||||
$(function() {
|
|
||||||
$("#footer").load("/footer");
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -1,179 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
||||||
<link rel="stylesheet" href="/assets/css/bootstrap.min.css">
|
|
||||||
<title>AstroCom API Docs</title>
|
|
||||||
<script>
|
|
||||||
(function (d, t) {
|
|
||||||
var BASE_URL = "https://support.chrischro.me";
|
|
||||||
var g = d.createElement(t), s = d.getElementsByTagName(t)[0];
|
|
||||||
g.src = BASE_URL + "/packs/js/sdk.js";
|
|
||||||
g.defer = true;
|
|
||||||
g.async = true;
|
|
||||||
s.parentNode.insertBefore(g, s);
|
|
||||||
g.onload = function () {
|
|
||||||
window.chatwootSDK.run({
|
|
||||||
websiteToken: '1Epwwnhnmieqzu2dm3jYH3Qp',
|
|
||||||
baseUrl: BASE_URL
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})(document, "script");
|
|
||||||
</script>
|
|
||||||
<style>
|
|
||||||
.doc-section { max-width: 900px; margin: 1.5rem auto; }
|
|
||||||
.endpoint { background: rgba(255,255,255,0.03); padding: 1rem; border-radius: .4rem; margin-bottom: .75rem; }
|
|
||||||
.code { background:#0d1117; color:#9ad8ff; padding:.5rem; border-radius:.25rem; font-family:monospace; white-space:pre-wrap; }
|
|
||||||
.small-muted { color: rgba(255,255,255,0.6); font-size:.9rem; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class="bg-dark text-white">
|
|
||||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
|
||||||
<div class="container-fluid">
|
|
||||||
<a class="navbar-brand" href="/">AstroCom</a>
|
|
||||||
<span id="footer"></span>
|
|
||||||
</div>
|
|
||||||
<div class="ms-auto d-flex text-nowrap">
|
|
||||||
<a href="/user" class="btn btn-outline-light me-2">User Login</a>
|
|
||||||
<a href="/admin" class="btn btn-outline-light">Admin Login</a>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div class="container doc-section">
|
|
||||||
<h2 class="mb-1">API Documentation</h2>
|
|
||||||
<p class="small-muted">This page lists only endpoints that are fully unauthenticated or accept an API key via Bearer token.</p>
|
|
||||||
|
|
||||||
<h4 class="mt-4">Unauthenticated (public) endpoints</h4>
|
|
||||||
|
|
||||||
<div class="endpoint">
|
|
||||||
<h5>GET /api/v1/directory</h5>
|
|
||||||
<p class="small-muted">Returns all directory entries.</p>
|
|
||||||
<div class="mb-2"><strong>Request</strong></div>
|
|
||||||
<div class="code">curl -s -X GET https://astrocom.tel/api/v1/directory</div>
|
|
||||||
<div class="mb-2 mt-2"><strong>Response (200)</strong></div>
|
|
||||||
<div class="code">[{"id":1,"number":4472000,"name":"Example","route":2}, ...]</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="endpoint">
|
|
||||||
<h5>GET /api/v1/directory/openBlocks</h5>
|
|
||||||
<p class="small-muted">Returns a list of available 10k blocks (block start numbers).</p>
|
|
||||||
<div class="code">curl -s https://astrocom.tel/api/v1/directory/openBlocks</div>
|
|
||||||
<div class="code">[1000000,1010000, ...]</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="endpoint">
|
|
||||||
<h5>GET /api/v1/checkAvailability/:number</h5>
|
|
||||||
<p class="small-muted">Checks availability for a 7-digit number (rounded to NXX0000). Returns available: true/false.</p>
|
|
||||||
<div class="code">curl -s https://astrocom.tel/api/v1/checkAvailability/4472001</div>
|
|
||||||
<div class="code">{"available":true}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="endpoint">
|
|
||||||
<h5>GET /api/analytics</h5>
|
|
||||||
<p class="small-muted">Public analytics (total and daily counts).</p>
|
|
||||||
<div class="code">curl -s https://astrocom.tel/api/analytics</div>
|
|
||||||
<div class="code">{"total":[{"tag":"apiCalls","count":123}], "daily":[{"tag":"apiCalls","tag_date":"2025-10-27","count":10}]}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="endpoint">
|
|
||||||
<h5>GET /discord</h5>
|
|
||||||
<p class="small-muted">Redirects to the configured Discord invite (server-side fetch from WIDGET_URL).</p>
|
|
||||||
<div class="code">curl -i https://astrocom.tel/discord</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="endpoint">
|
|
||||||
<h5>GET /api/v1/provision/:apiKey</h5>
|
|
||||||
<p class="small-muted">Provisioning info for a route identified by API key. Returns server/port/iax creds and block.</p>
|
|
||||||
<div class="code">curl -s https://astrocom.tel/api/v1/provision/REPLACE_API_KEY</div>
|
|
||||||
<div class="code">{
|
|
||||||
"server":"iax.example.net",
|
|
||||||
"port":4569,
|
|
||||||
"inbound_context":"from-astrocom",
|
|
||||||
"iax_secret":"...secret...",
|
|
||||||
"block":4470000,
|
|
||||||
"api_key":"REPLACE_API_KEY"
|
|
||||||
}</div>
|
|
||||||
<p class="small-muted">Response may include "warning" if DNS IP doesn't match requester.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="endpoint">
|
|
||||||
<h5>GET /api/v1/route/:apiKey/:ani/:number</h5>
|
|
||||||
<p class="small-muted">Primary routing endpoint. Returns "local" or an IAX2 dial string for the callee.</p>
|
|
||||||
<div class="code">curl -s https://astrocom.tel/api/v1/route/REPLACE_API_KEY/4472001/4473005</div>
|
|
||||||
<div class="code">local
|
|
||||||
-- or --
|
|
||||||
IAX2/from-astrocom:secret@iax.example.net:4569/4473005</div>
|
|
||||||
<p class="small-muted">Also available as legacy query form:</p>
|
|
||||||
<div class="code">GET /api/v1?auth=APIKEY&ani=4472001&number=4473005</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<hr class="border-secondary">
|
|
||||||
|
|
||||||
<h4 class="mt-4">Bearer token endpoints (Authorization: Bearer <API_KEY>)</h4>
|
|
||||||
|
|
||||||
<div class="endpoint">
|
|
||||||
<h5>PATCH /api/v1/user/update</h5>
|
|
||||||
<p class="small-muted">Update server/port/auth/secret for the route identified by Bearer API key (used by automated scripts).</p>
|
|
||||||
<div class="code">curl -s -X PATCH \
|
|
||||||
-H "Authorization: Bearer REPLACE_API_KEY" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"server":"iax.example.net","port":4569,"auth":"from-astrocom","secret":"new-secret"}' \
|
|
||||||
https://astrocom.tel/api/v1/user/update</div>
|
|
||||||
<div class="code">{"message":"Updated"}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="endpoint">
|
|
||||||
<h5>POST /api/v1/user/dir/newEntry</h5>
|
|
||||||
<p class="small-muted">Create or update a single directory entry for the route belonging to the API key.</p>
|
|
||||||
<div class="code">curl -s -X POST \
|
|
||||||
-H "Authorization: Bearer REPLACE_API_KEY" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"number":4472005,"name":"Alice"}' \
|
|
||||||
https://astrocom.tel/api/v1/user/dir/newEntry</div>
|
|
||||||
<div class="code">{"message":"Created"} or {"message":"Updated"}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="endpoint">
|
|
||||||
<h5>DELETE /api/v1/user/dir/deleteEntry/:number</h5>
|
|
||||||
<p class="small-muted">Delete a directory entry owned by the API key's route.</p>
|
|
||||||
<div class="code">curl -s -X DELETE -H "Authorization: Bearer REPLACE_API_KEY" https://astrocom.tel/api/v1/user/dir/deleteEntry/4472005</div>
|
|
||||||
<div class="code">{"message":"Deleted"}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="endpoint">
|
|
||||||
<h5>POST /api/v1/user/dir/massUpdate</h5>
|
|
||||||
<p class="small-muted">Mass-insert/update directory entries. Body must be {"entries":[{number,name},...],"replace":true|false}.</p>
|
|
||||||
<div class="code">curl -s -X POST \
|
|
||||||
-H "Authorization: Bearer REPLACE_API_KEY" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"replace":false,"entries":[{"number":4472001,"name":"Bob"},{"number":4472002,"name":"Carol"}]}' \
|
|
||||||
https://astrocom.tel/api/v1/user/dir/massUpdate</div>
|
|
||||||
<div class="code">{"message":"Mass update completed"}</div>
|
|
||||||
<p class="small-muted">All numbers must be within the route's block range.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<hr class="border-secondary">
|
|
||||||
|
|
||||||
<p class="small-muted">Notes:</p>
|
|
||||||
<ul class="small-muted">
|
|
||||||
<li>Bearer endpoints accept header Authorization: Bearer <API_KEY>.</li>
|
|
||||||
<li>Unauthenticated endpoints that accept an API key in the path/query do not require Authorization header.</li>
|
|
||||||
<li>All numeric "number" and "ani" values must be 7-digit integers (1,000,000–9,999,999) where applicable.</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="/assets/js/directory.js"></script>
|
|
||||||
<script src="/assets/js/bootstrap.min.js"></script>
|
|
||||||
<script src="/assets/js/bootstrap.bundle.min.js"></script>
|
|
||||||
<script src="/assets/js/jquery.min.js"></script>
|
|
||||||
<script>
|
|
||||||
$(function() {
|
|
||||||
$("#footer").load("/footer");
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
|
@ -20,22 +20,6 @@
|
||||||
<script type="application/ld+json">
|
<script type="application/ld+json">
|
||||||
{"name":"AstroCom","description":"Simplifying communication.","@type":"WebSite","url":"https://astrocom.tel/","headline":"AstroCom","@context":"http://schema.org"}
|
{"name":"AstroCom","description":"Simplifying communication.","@type":"WebSite","url":"https://astrocom.tel/","headline":"AstroCom","@context":"http://schema.org"}
|
||||||
</script>
|
</script>
|
||||||
<script>
|
|
||||||
(function (d, t) {
|
|
||||||
var BASE_URL = "https://support.chrischro.me";
|
|
||||||
var g = d.createElement(t), s = d.getElementsByTagName(t)[0];
|
|
||||||
g.src = BASE_URL + "/packs/js/sdk.js";
|
|
||||||
g.defer = true;
|
|
||||||
g.async = true;
|
|
||||||
s.parentNode.insertBefore(g, s);
|
|
||||||
g.onload = function () {
|
|
||||||
window.chatwootSDK.run({
|
|
||||||
websiteToken: '1Epwwnhnmieqzu2dm3jYH3Qp',
|
|
||||||
baseUrl: BASE_URL
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})(document, "script");
|
|
||||||
</script>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
@ -52,8 +36,6 @@
|
||||||
<div class="links">
|
<div class="links">
|
||||||
<a href="/about">About (WIP)</a><span> </span>
|
<a href="/about">About (WIP)</a><span> </span>
|
||||||
<a href="/directory">Directory</a><span> </span>
|
<a href="/directory">Directory</a><span> </span>
|
||||||
<a href="/validator">Block Availability</a> <span> </span>
|
|
||||||
<a href="/status" class="disabled" aria-disabled="true" tabindex="-1" style="pointer-events: none; opacity: 0.5;">Status (WIP)</a><span> </span>
|
|
||||||
<a href="/discord">Discord Server</a>
|
<a href="/discord">Discord Server</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
User-agent: *
|
|
||||||
Disallow: /
|
|
||||||
Allow: /$
|
|
||||||
Allow: /discord$
|
|
||||||
|
|
@ -6,29 +6,12 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="stylesheet" href="/assets/css/bootstrap.min.css">
|
<link rel="stylesheet" href="/assets/css/bootstrap.min.css">
|
||||||
<title>AstroCom Availability Checker</title>
|
<title>AstroCom Availability Checker</title>
|
||||||
<script>
|
|
||||||
(function (d, t) {
|
|
||||||
var BASE_URL = "https://support.chrischro.me";
|
|
||||||
var g = d.createElement(t), s = d.getElementsByTagName(t)[0];
|
|
||||||
g.src = BASE_URL + "/packs/js/sdk.js";
|
|
||||||
g.defer = true;
|
|
||||||
g.async = true;
|
|
||||||
s.parentNode.insertBefore(g, s);
|
|
||||||
g.onload = function () {
|
|
||||||
window.chatwootSDK.run({
|
|
||||||
websiteToken: '1Epwwnhnmieqzu2dm3jYH3Qp',
|
|
||||||
baseUrl: BASE_URL
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})(document, "script");
|
|
||||||
</script>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="bg-dark text-white">
|
<body class="bg-dark text-white">
|
||||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<a class="navbar-brand" href="/">AstroCom</a>
|
<a class="navbar-brand" href="/">AstroCom</a>
|
||||||
<span id="footer"></span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="ms-auto d-flex text-nowrap">
|
<div class="ms-auto d-flex text-nowrap">
|
||||||
<a href="/user" class="btn btn-outline-light me-2">User Login</a>
|
<a href="/user" class="btn btn-outline-light me-2">User Login</a>
|
||||||
|
|
@ -50,47 +33,6 @@
|
||||||
<button type="submit" class="btn btn-primary mt-3">Submit</button>
|
<button type="submit" class="btn btn-primary mt-3">Submit</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="container mt-4" style="max-width: 400px;">
|
|
||||||
<h4>Available Blocks</h4>
|
|
||||||
<table class="table table-dark table-bordered">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th id="availHeader" scope="col">Available Blocks</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody id="availableBlocksTable">
|
|
||||||
<tr><td>Loading...</td></tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<script>
|
|
||||||
async function loadAvailableBlocks() {
|
|
||||||
const tableBody = document.getElementById('availableBlocksTable');
|
|
||||||
try {
|
|
||||||
const res = await fetch('/api/v1/directory/openBlocks');
|
|
||||||
const blocks = await res.json();
|
|
||||||
tableBody.innerHTML = '';
|
|
||||||
if (Array.isArray(blocks) && blocks.length > 0) {
|
|
||||||
blocks.forEach(block => {
|
|
||||||
const row = document.createElement('tr');
|
|
||||||
const cell = document.createElement('td');
|
|
||||||
cell.textContent = block;
|
|
||||||
row.appendChild(cell);
|
|
||||||
tableBody.appendChild(row);
|
|
||||||
});
|
|
||||||
// Set header text to "Available Blocks (X total)" where X is the number of available blocks
|
|
||||||
document.getElementById('availHeader').textContent = `${blocks.length} Available Blocks`;
|
|
||||||
} else {
|
|
||||||
tableBody.innerHTML = '<tr><td>No blocks available</td></tr>';
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
tableBody.innerHTML = '<tr><td>Error loading blocks</td></tr>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
loadAvailableBlocks();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.querySelector('form').addEventListener('submit', async (e) => {
|
document.querySelector('form').addEventListener('submit', async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
@ -115,11 +57,6 @@
|
||||||
<script src="/assets/js/bootstrap.min.js"></script>
|
<script src="/assets/js/bootstrap.min.js"></script>
|
||||||
<script src="/assets/js/bootstrap.bundle.min.js"></script>
|
<script src="/assets/js/bootstrap.bundle.min.js"></script>
|
||||||
<script src="/assets/js/jquery.min.js"></script>
|
<script src="/assets/js/jquery.min.js"></script>
|
||||||
<script>
|
|
||||||
$(function () {
|
|
||||||
$("#footer").load("/footer");
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
# AstroCom Dynamic IP Update Script
|
|
||||||
# Gets current public IP from https://myip.wtf/text and posts it to the AstroCom API
|
|
||||||
# Requires: curl
|
|
||||||
|
|
||||||
# Configuration
|
|
||||||
API_KEY="Your ASTROCOM API Key" # Replace with your AstroCom API Key!
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Get current IP
|
|
||||||
CURRENT_IP=$(curl -s https://myip.wtf/text)
|
|
||||||
if [[ -z "$CURRENT_IP" ]]; then
|
|
||||||
echo "Failed to retrieve current IP address."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "Current IP: $CURRENT_IP"
|
|
||||||
# Update IP via AstroCom API PATCH https://astrocom.tel/api/v1/user/update; JSON body: {"server": "current_ip"}
|
|
||||||
curl -s -X PATCH https://astrocom.tel/api/v1/user/update -H "Content-Type: application/json" -H "Authorization: Bearer $API_KEY" -d "{\"server\": \"$CURRENT_IP\"}"
|
|
||||||
|
|
@ -61,11 +61,5 @@
|
||||||
<script src="/assets/js/bootstrap.min.js"></script>
|
<script src="/assets/js/bootstrap.min.js"></script>
|
||||||
<script src="/assets/js/bootstrap.bundle.min.js"></script>
|
<script src="/assets/js/bootstrap.bundle.min.js"></script>
|
||||||
<script src="/assets/js/jquery.min.js"></script>
|
<script src="/assets/js/jquery.min.js"></script>
|
||||||
<div id="footer"></div>
|
|
||||||
<script>
|
|
||||||
$(function() {
|
|
||||||
$("#footer").load("/footer");
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -10,7 +10,6 @@
|
||||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<a class="navbar-brand" href="#">AstroCom</a>
|
<a class="navbar-brand" href="#">AstroCom</a>
|
||||||
<span id="footer"></span>
|
|
||||||
<div class="navbar-nav ms-auto">
|
<div class="navbar-nav ms-auto">
|
||||||
<span class="navbar-text me-3">
|
<span class="navbar-text me-3">
|
||||||
Welcome, <%= user %>
|
Welcome, <%= user %>
|
||||||
|
|
@ -42,10 +41,5 @@
|
||||||
<script src="/assets/js/bootstrap.min.js"></script>
|
<script src="/assets/js/bootstrap.min.js"></script>
|
||||||
<script src="/assets/js/bootstrap.bundle.min.js"></script>
|
<script src="/assets/js/bootstrap.bundle.min.js"></script>
|
||||||
<script src="/assets/js/jquery.min.js"></script>
|
<script src="/assets/js/jquery.min.js"></script>
|
||||||
<script>
|
|
||||||
$(function() {
|
|
||||||
$("#footer").load("/footer");
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -1,18 +1,15 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="stylesheet" href="/assets/css/bootstrap.min.css">
|
<link rel="stylesheet" href="/assets/css/bootstrap.min.css">
|
||||||
<title>AstroCom Admin</title>
|
<title>AstroCom Admin</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="bg-dark text-white">
|
<body class="bg-dark text-white">
|
||||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<a class="navbar-brand" href="#">AstroCom</a>
|
<a class="navbar-brand" href="#">AstroCom</a>
|
||||||
<span id="footer"></span>
|
|
||||||
<div class="navbar-nav ms-auto">
|
<div class="navbar-nav ms-auto">
|
||||||
<span class="navbar-text me-3">
|
<span class="navbar-text me-3">
|
||||||
Welcome, <%= user %>
|
Welcome, <%= user %>
|
||||||
|
|
@ -21,58 +18,57 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="d-flex align-items-center gap-3 mb-3">
|
|
||||||
<h2 class="m-0">Admin Dashboard</h2>
|
|
||||||
<a href="/admin/create" class="btn btn-primary">Create New Server</a>
|
|
||||||
<p class="m-0">Total Servers: <span id="serverCount">0</span> | Total Directory Entries: <span
|
|
||||||
id="dirCount">0</span></p>
|
|
||||||
</div>
|
|
||||||
<div class="flex-grow-1 mb-3">
|
|
||||||
<table class="table table-striped table-dark" id="adminTable">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>ID</th>
|
|
||||||
<th>Hostname:Port</th>
|
|
||||||
<th>IAX Username/Context</th>
|
|
||||||
<th>IAX2 Secret</th>
|
|
||||||
<th>Number Block</th>
|
|
||||||
<th>API Key</th>
|
|
||||||
<th>Contact</th>
|
|
||||||
<th>Actions</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<!-- Data will be dynamically populated by adminMain.js -->
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="flex-grow-1">
|
|
||||||
<div class="d-flex align-items-center gap-3 mb-3">
|
<div class="d-flex align-items-center gap-3 mb-3">
|
||||||
<h2 class="m-0">Directory Management</h2>
|
<h2 class="m-0">Admin Dashboard</h2>
|
||||||
|
<a href="/admin/create" class="btn btn-primary">Create New Server</a>
|
||||||
|
<p class="m-0">Total Servers: <span id="serverCount">0</span> | Total Directory Entries: <span id="dirCount">0</span></p>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex">
|
||||||
|
<div class="flex-grow-1">
|
||||||
|
<table class="table table-striped table-dark" id="adminTable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Hostname:Port</th>
|
||||||
|
<th>IAX Username/Context</th>
|
||||||
|
<th>IAX2 Secret</th>
|
||||||
|
<th>Number Block</th>
|
||||||
|
<th>API Key</th>
|
||||||
|
<th>Contact</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<!-- Data will be dynamically populated by adminMain.js -->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex">
|
||||||
|
<div class="flex-grow-1">
|
||||||
|
<!-- Original table is already in place above -->
|
||||||
|
</div>
|
||||||
|
<div class="ms-3 flex-grow-1">
|
||||||
|
<div class="d-flex align-items-center gap-3 mb-3">
|
||||||
|
<h2 class="m-0">Directory Management</h2>
|
||||||
|
</div>
|
||||||
|
<table class="table table-striped table-dark" id="directoryTable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Number</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="directoryList">
|
||||||
|
<!-- Data will be dynamically populated by adminMain.js -->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table class="table table-striped table-dark" id="directoryTable">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Number</th>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Actions</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody id="directoryList">
|
|
||||||
<!-- Data will be dynamically populated by adminMain.js -->
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<script src="/assets/js/adminDirectory.js"></script>
|
<script src="/assets/js/adminDirectory.js"></script>
|
||||||
<script src="/assets/js/adminMain.js"></script>
|
<script src="/assets/js/adminMain.js"></script>
|
||||||
<script src="/assets/js/bootstrap.min.js"></script>
|
<script src="/assets/js/bootstrap.min.js"></script>
|
||||||
<script src="/assets/js/bootstrap.bundle.min.js"></script>
|
<script src="/assets/js/bootstrap.bundle.min.js"></script>
|
||||||
<script src="/assets/js/jquery.min.js"></script>
|
<script src="/assets/js/jquery.min.js"></script>
|
||||||
<script>
|
|
||||||
$(function () {
|
|
||||||
$("#footer").load("/footer");
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -29,14 +29,9 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="footer" class="text-light mt-5"></div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<script src="/assets/js/bootstrap.min.js"></script>
|
||||||
<script src="/assets/js/bootstrap.bundle.min.js"></script>
|
<script src="/assets/js/bootstrap.bundle.min.js"></script>
|
||||||
<script src="/assets/js/jquery.min.js"></script>
|
<script src="/assets/js/jquery.min.js"></script>
|
||||||
<script>
|
|
||||||
$(function() {
|
|
||||||
$("#footer").load("/footer");
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<link rel="stylesheet" href="/assets/css/bootstrap.min.css">
|
|
||||||
<title>AstroCom Admin Registration</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body class="bg-dark">
|
|
||||||
<div class="container">
|
|
||||||
<div class="row justify-content-center mt-5">
|
|
||||||
<div class="col-md-6 col-lg-4">
|
|
||||||
<div class="card bg-dark text-light shadow">
|
|
||||||
<div class="card-body p-4">
|
|
||||||
<h2 class="text-center mb-4">Admin Registration</h2>
|
|
||||||
<% if (typeof notice !== 'undefined') { %>
|
|
||||||
<div class="alert alert-info text-center mb-3"><%= notice %></div>
|
|
||||||
<% } %>
|
|
||||||
<% if (typeof info !== 'undefined') { %>
|
|
||||||
<div class="alert alert-primary text-center mb-3"><%= info %></div>
|
|
||||||
<% } %>
|
|
||||||
<% if (typeof warn !== 'undefined') { %>
|
|
||||||
<div class="alert alert-warning text-center mb-3"><%= warn %></div>
|
|
||||||
<% } %>
|
|
||||||
<% if (typeof error !== 'undefined') { %>
|
|
||||||
<div class="alert alert-danger text-center mb-3"><%= error %></div>
|
|
||||||
<% } %>
|
|
||||||
<form action="#" method="POST">
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="username" class="form-label">Username:</label>
|
|
||||||
<input type="text" class="form-control" id="username" name="username" required>
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="password" class="form-label">Password:</label>
|
|
||||||
<input type="password" class="form-control" id="password" name="password" required>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-primary w-100">Register</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="footer" class="text-light mt-5"></div>
|
|
||||||
</div>
|
|
||||||
<script src="/assets/js/bootstrap.bundle.min.js"></script>
|
|
||||||
<script src="/assets/js/jquery.min.js"></script>
|
|
||||||
<script>
|
|
||||||
$(function() {
|
|
||||||
$("#footer").load("/footer");
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
0
views/directory.ejs
Normal file
0
views/directory.ejs
Normal file
|
|
@ -1,21 +0,0 @@
|
||||||
<footer class="footer mt-auto py-3 bg-dark text-white">
|
|
||||||
<div class="container text-center">
|
|
||||||
<span>© <%= new Date().getFullYear() %> AstroCom <%= version %></span>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
<script>
|
|
||||||
(function (d, t) {
|
|
||||||
var BASE_URL = "https://support.chrischro.me";
|
|
||||||
var g = d.createElement(t), s = d.getElementsByTagName(t)[0];
|
|
||||||
g.src = BASE_URL + "/packs/js/sdk.js";
|
|
||||||
g.defer = true;
|
|
||||||
g.async = true;
|
|
||||||
s.parentNode.insertBefore(g, s);
|
|
||||||
g.onload = function () {
|
|
||||||
window.chatwootSDK.run({
|
|
||||||
websiteToken: '1Epwwnhnmieqzu2dm3jYH3Qp',
|
|
||||||
baseUrl: BASE_URL
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})(document, "script");
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<link rel="stylesheet" href="/assets/css/bootstrap.min.css">
|
|
||||||
<title>AstroCom User - Edit</title>
|
|
||||||
</head>
|
|
||||||
<body class="bg-dark text-white">
|
|
||||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
|
||||||
<div class="container-fluid">
|
|
||||||
<a class="navbar-brand" href="#">AstroCom</a>
|
|
||||||
<span id="footer"></span>
|
|
||||||
<div class="navbar-nav ms-auto">
|
|
||||||
<span class="navbar-text me-3">
|
|
||||||
Welcome
|
|
||||||
</span>
|
|
||||||
<a href="/user/logout" class="btn btn-danger">Logout</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
<div class="container mt-4">
|
|
||||||
<h2>Edit Server Information</h2>
|
|
||||||
<form id="editForm" onsubmit="return false;" class="mt-4">
|
|
||||||
<% for (const [key, value] of Object.entries(data)) { %>
|
|
||||||
<% if (key !== 'id') { %>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="<%= key %>" class="form-label"><%= key.charAt(0).toUpperCase() + key.slice(1) %></label>
|
|
||||||
<input type="text" class="form-control bg-dark text-white" id="<%= key %>" name="<%= key %>" value="<%= value %>">
|
|
||||||
</div>
|
|
||||||
<% } %>
|
|
||||||
<% } %>
|
|
||||||
<button type="submit" class="btn btn-primary">Update</button>
|
|
||||||
<a href="/user" class="btn btn-secondary">Cancel</a>
|
|
||||||
</form>
|
|
||||||
<script>
|
|
||||||
const route = <%= data.id %>;
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
<script src="/assets/js/userEdit.js"></script>
|
|
||||||
</div>
|
|
||||||
<script src="/assets/js/bootstrap.min.js"></script>
|
|
||||||
<script src="/assets/js/bootstrap.bundle.min.js"></script>
|
|
||||||
<script src="/assets/js/jquery.min.js"></script>
|
|
||||||
<script>
|
|
||||||
$(function() {
|
|
||||||
$("#footer").load("/footer");
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -12,7 +12,6 @@
|
||||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<a class="navbar-brand" href="#">AstroCom</a>
|
<a class="navbar-brand" href="#">AstroCom</a>
|
||||||
<span id="footer"></span>
|
|
||||||
<div class="navbar-nav ms-auto">
|
<div class="navbar-nav ms-auto">
|
||||||
<span class="navbar-text me-3">
|
<span class="navbar-text me-3">
|
||||||
Welcome!
|
Welcome!
|
||||||
|
|
@ -28,7 +27,7 @@
|
||||||
<div class="card bg-secondary mb-4 text-white">
|
<div class="card bg-secondary mb-4 text-white">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="position-absolute top-0 end-0 m-3">
|
<div class="position-absolute top-0 end-0 m-3">
|
||||||
<a href="/user/edit" class="btn btn-primary" id="editInfoBtn">Edit Information</a>
|
<a href="/user/edit" class="btn btn-primary disabled" id="editInfoBtn">Edit Information (Coming Soon)</a>
|
||||||
</div>
|
</div>
|
||||||
<h5 class="card-title">Your Route Information</h5>
|
<h5 class="card-title">Your Route Information</h5>
|
||||||
<p class="card-text">
|
<p class="card-text">
|
||||||
|
|
@ -73,11 +72,6 @@
|
||||||
<script src="/assets/js/bootstrap.min.js"></script>
|
<script src="/assets/js/bootstrap.min.js"></script>
|
||||||
<script src="/assets/js/bootstrap.bundle.min.js"></script>
|
<script src="/assets/js/bootstrap.bundle.min.js"></script>
|
||||||
<script src="/assets/js/jquery.min.js"></script>
|
<script src="/assets/js/jquery.min.js"></script>
|
||||||
<script>
|
|
||||||
$(function() {
|
|
||||||
$("#footer").load("/footer");
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -18,22 +18,16 @@
|
||||||
<form action="/user/login" method="POST">
|
<form action="/user/login" method="POST">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="apiKey" class="form-label">API Key:</label>
|
<label for="apiKey" class="form-label">API Key:</label>
|
||||||
<input type="password" class="form-control" id="apiKey" name="apiKey" required>
|
<input type="text" class="form-control" id="apiKey" name="apiKey" required>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-primary w-100">Login</button>
|
<button type="submit" class="btn btn-primary w-100">Login</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="footer" class="text-light mt-5"></div>
|
|
||||||
</div>
|
</div>
|
||||||
<script src="/assets/js/bootstrap.min.js"></script>
|
<script src="/assets/js/bootstrap.min.js"></script>
|
||||||
<script src="/assets/js/bootstrap.bundle.min.js"></script>
|
<script src="/assets/js/bootstrap.bundle.min.js"></script>
|
||||||
<script src="/assets/js/jquery.min.js"></script>
|
<script src="/assets/js/jquery.min.js"></script>
|
||||||
<script>
|
|
||||||
$(function() {
|
|
||||||
$("#footer").load("/footer");
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Loading…
Reference in a new issue