mirror of
https://github.com/psforever/PSFPortal.git
synced 2026-07-11 14:34:36 +00:00
Initial commit
This commit is contained in:
commit
20946fdb43
49 changed files with 2393 additions and 0 deletions
108
api/admin.js
Normal file
108
api/admin.js
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
import express from 'express'
|
||||
import * as db from './db.js'
|
||||
import { get_pagination, fetch_user_middleware } from './util.js'
|
||||
|
||||
const api = express.Router();
|
||||
|
||||
api.param("user", fetch_user_middleware);
|
||||
|
||||
api.get('/users', async (req, res, next) => {
|
||||
const pagination = get_pagination(req);
|
||||
|
||||
try {
|
||||
const accounts = await db.get_accounts_login_info(pagination, db.ACCOUNT.CREATED, db.SQL_ORDER.DESCENDING);
|
||||
res.status(200).json({ users: accounts, page: pagination})
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
res.status(500).json({ message: 'error' });
|
||||
}
|
||||
});
|
||||
|
||||
api.post('/search', async (req, res, next) => {
|
||||
const pagination = get_pagination(req);
|
||||
|
||||
let search = req.body.search;
|
||||
|
||||
if (!search || search.length < 3) {
|
||||
res.status(400).json({ message: 'Need a longer search term' });
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const items = await db.search(search, pagination);
|
||||
res.status(200).json({ items: items, page: pagination})
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
res.status(500).json({ message: 'error' });
|
||||
}
|
||||
});
|
||||
|
||||
api.get('/user/:user', async (req, res, next) => {
|
||||
const account = req.user;
|
||||
|
||||
res.status(200).json({ id : account.id, name: account.username });
|
||||
});
|
||||
|
||||
api.post('/user/:user/add_gm', async (req, res, next) => {
|
||||
const account = req.user;
|
||||
|
||||
try {
|
||||
await db.update_account(account.id, {"gm" : true})
|
||||
res.status(200).json({});
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
res.status(500).json({ message: 'error' });
|
||||
}
|
||||
});
|
||||
|
||||
api.post('/user/:user/remove_gm', async (req, res, next) => {
|
||||
const account = req.user;
|
||||
|
||||
try {
|
||||
await db.update_account(account.id, {"gm" : false})
|
||||
res.status(200).json({});
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
res.status(500).json({ message: 'error' });
|
||||
}
|
||||
});
|
||||
|
||||
api.post('/user/:user/ban', async (req, res, next) => {
|
||||
const account = req.user;
|
||||
|
||||
try {
|
||||
// also drop GM if they had it...
|
||||
await db.update_account(account.id, {"inactive" : true, "gm" : false})
|
||||
res.status(200).json({});
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
res.status(500).json({ message: 'error' });
|
||||
}
|
||||
});
|
||||
|
||||
api.post('/user/:user/unban', async (req, res, next) => {
|
||||
const account = req.user;
|
||||
|
||||
try {
|
||||
await db.update_account(account.id, {"inactive" : false})
|
||||
res.status(200).json({});
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
res.status(500).json({ message: 'error' });
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
api.get('/characters', async (req, res, next) => {
|
||||
const pagination = get_pagination(req);
|
||||
|
||||
try {
|
||||
const characters = await db.get_characters(pagination, db.CHARACTER.LAST_LOGIN, db.SQL_ORDER.DESCENDING);
|
||||
res.status(200).json({ characters: characters, page: pagination})
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
res.status(500).json({ message: 'error' });
|
||||
}
|
||||
});
|
||||
|
||||
export default api;
|
||||
69
api/authentication.js
Normal file
69
api/authentication.js
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
import express from 'express'
|
||||
import * as db from './db.js'
|
||||
|
||||
const api = express.Router();
|
||||
|
||||
api.post('/register', async (req, res, next) => {
|
||||
const rUsername = req.body.username;
|
||||
const rPassword = req.body.password;
|
||||
const rEmail = req.body.email; // TODO: validate email regex
|
||||
// TODO: recaptcha, csrf protection
|
||||
|
||||
if (!rUsername || !rPassword || !rEmail) {
|
||||
res.status(400).json({message: "missing fields"});
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: username regex
|
||||
if (rUsername.length < 3) {
|
||||
res.status(400).json({message: "Username must be at least 3 characters"});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const account_id = await db.create_account(rUsername, rPassword);
|
||||
req.session.account_id = account_id;
|
||||
res.status(200).json({account_id: account_id});
|
||||
} catch (e) {
|
||||
if (e.code === 'UNIQUE_VIOLATION') {
|
||||
res.status(400).json({message: 'Username already taken'});
|
||||
} else {
|
||||
console.log(e)
|
||||
res.status(500).json({message: 'error'});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
api.post('/login', async (req, res, next) => {
|
||||
const rUsername = req.body.username;
|
||||
const rPassword = req.body.password;
|
||||
|
||||
if (!rUsername || !rPassword) {
|
||||
res.status(400).json({message: 'missing fields'});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const account_id = await db.validate_account(rUsername, rPassword);
|
||||
|
||||
if (account_id === undefined) {
|
||||
res.status(403).json({message: 'invalid username/password'});
|
||||
} else {
|
||||
req.session.account_id = account_id;
|
||||
res.status(200).json({account_id: account_id});
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
res.status(500).json({message: 'error'});
|
||||
}
|
||||
});
|
||||
|
||||
api.post('/logout', async (req, res, next) => {
|
||||
if (req.session) {
|
||||
req.session.destroy()
|
||||
}
|
||||
|
||||
res.status(200).json({});
|
||||
});
|
||||
|
||||
export default api;
|
||||
376
api/db.js
Normal file
376
api/db.js
Normal file
|
|
@ -0,0 +1,376 @@
|
|||
import pg from 'pg'
|
||||
import pg_error from 'pg-error-constants'
|
||||
import bcrypt from 'bcrypt'
|
||||
import assert from 'assert'
|
||||
|
||||
function objectFlip(obj) {
|
||||
const ret = {};
|
||||
Object.keys(obj).forEach(key => {
|
||||
ret[obj[key]] = key;
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
let pg_error_inv = objectFlip(pg_error)
|
||||
|
||||
export let pool;
|
||||
|
||||
const FACTION_MAP = {
|
||||
0 : ["Terran Republic", "TR"],
|
||||
1 : ["New Conglomerate", "NC"],
|
||||
2 : ["Vanu Sovereignty", "VS"],
|
||||
3 : ["Neutral", "NL"],
|
||||
}
|
||||
|
||||
const FACTION_MAP_INV = objectFlip(FACTION_MAP)
|
||||
const BCRYPT_ROUNDS = 4;
|
||||
|
||||
export const SQL_ORDER = Object.freeze({
|
||||
ASCENDING: Symbol("ASC"),
|
||||
DESCENDING: Symbol("DESC"),
|
||||
});
|
||||
|
||||
export const ACCOUNT = Object.freeze({
|
||||
THIS: Symbol("accounts"),
|
||||
ID: Symbol("id"),
|
||||
USER: Symbol("username"),
|
||||
PASSWORD: Symbol("passhash"),
|
||||
CREATED: Symbol("created"),
|
||||
MODIFIED: Symbol("last_modified"),
|
||||
BANNED: Symbol("inactive"),
|
||||
ADMIN: Symbol("gm"),
|
||||
});
|
||||
|
||||
export const CHARACTER = Object.freeze({
|
||||
THIS: Symbol("characters"),
|
||||
ID: Symbol("id"),
|
||||
NAME: Symbol("name"),
|
||||
ACCOUNT_ID: Symbol("account_id"),
|
||||
FACTION: Symbol("faction_id"),
|
||||
GENDER: Symbol("gender_id"),
|
||||
HEAD: Symbol("head_id"),
|
||||
VOICE: Symbol("void_id"),
|
||||
CREATED: Symbol("created"),
|
||||
LAST_LOGIN: Symbol("last_login"),
|
||||
LAST_MODIFIED: Symbol("last_modified"),
|
||||
DELETED: Symbol("deleted"),
|
||||
});
|
||||
|
||||
function to_sql(symbol) {
|
||||
assert(typeof symbol == 'symbol')
|
||||
return String(symbol).slice(7,-1);
|
||||
}
|
||||
|
||||
async function get_row_count(table) {
|
||||
const resp = await pool.query(`SELECT COUNT(*) FROM ${to_sql(table)}`);
|
||||
return parseInt(resp.rows[0].count);
|
||||
}
|
||||
|
||||
export async function connect_to_db() {
|
||||
pool = new pg.Pool()
|
||||
try {
|
||||
const res = await pool.query('SELECT NOW()')
|
||||
console.log(`Connected to the psql database at ${process.env.PGHOST}`)
|
||||
} catch (e) {
|
||||
console.log("Unable to connect to the database: " + e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
export async function get_account_by_id(id) {
|
||||
try {
|
||||
const account = await pool.query('SELECT * FROM accounts WHERE id=$1', [id]);
|
||||
const account_obj = account.rows[0];
|
||||
|
||||
delete account_obj.passhash;
|
||||
return account_obj;
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
export async function get_accounts(pagination, sort, order) {
|
||||
const start_id = (pagination.page-1)*pagination.items_per_page;
|
||||
const values = [start_id, pagination.items_per_page];
|
||||
|
||||
try {
|
||||
const account_count = await get_row_count(ACCOUNT.THIS);
|
||||
const accounts = await pool.query(`SELECT id, username, created, last_modified, gm, inactive FROM accounts ORDER BY ${to_sql(sort)} ${to_sql(order)} OFFSET $1 LIMIT $2`, values);
|
||||
|
||||
pagination.item_count = account_count;
|
||||
pagination.page_count = Math.ceil(pagination.item_count / pagination.items_per_page);
|
||||
accounts.rows.forEach((r) => {
|
||||
r.name = r.username;
|
||||
r.admin = r.gm;
|
||||
delete r.username;
|
||||
delete r.gm;
|
||||
});
|
||||
return accounts.rows;
|
||||
} catch (e) {
|
||||
if (e.code)
|
||||
e.code = pg_error_inv[e.code]
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
export async function get_accounts_login_info(pagination, sort, order) {
|
||||
const start_id = (pagination.page-1)*pagination.items_per_page;
|
||||
const values = [start_id, pagination.items_per_page];
|
||||
|
||||
try {
|
||||
const account_count = await get_row_count(ACCOUNT.THIS);
|
||||
|
||||
// this was a really hard query to get right...
|
||||
// https://www.gab.lc/articles/better_faster_subqueries_postgresql/
|
||||
const accounts = await pool.query(
|
||||
'SELECT accounts.*, lastLogin as login_time, l2.ip_address, l2.canonical_hostname FROM accounts' +
|
||||
' LEFT OUTER JOIN (' +
|
||||
' SELECT MAX(id) as loginId, account_id, MAX(login_time) as lastLogin' +
|
||||
' FROM logins' +
|
||||
' GROUP BY account_id' +
|
||||
' ) l ON l.account_id = accounts.id' +
|
||||
' LEFT OUTER JOIN logins l2' +
|
||||
' ON l2.id = l.loginId' +
|
||||
` ORDER BY COALESCE(l.lastLogin, TIMESTAMP \'epoch\') ${to_sql(order)} OFFSET $1 LIMIT $2`, values);
|
||||
|
||||
pagination.item_count = account_count;
|
||||
pagination.page_count = Math.ceil(pagination.item_count / pagination.items_per_page);
|
||||
|
||||
accounts.rows.forEach((r) => {
|
||||
r.name = r.username;
|
||||
r.admin = r.gm;
|
||||
|
||||
if (r.login_time !== null) {
|
||||
r.last_login = {
|
||||
time : r.login_time,
|
||||
hostname : r.canonical_hostname,
|
||||
ip : r.ip_address,
|
||||
}
|
||||
} else {
|
||||
r.last_login = {}
|
||||
}
|
||||
|
||||
delete r.login_time;
|
||||
delete r.canonical_hostname;
|
||||
delete r.ip_address;
|
||||
delete r.passhash;
|
||||
delete r.username;
|
||||
delete r.gm;
|
||||
});
|
||||
return accounts.rows;
|
||||
} catch (e) {
|
||||
if (e.code)
|
||||
e.code = pg_error_inv[e.code]
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
export async function get_characters(pagination, sort, order) {
|
||||
const start_id = (pagination.page-1)*pagination.items_per_page;
|
||||
const values = [start_id, pagination.items_per_page];
|
||||
|
||||
try {
|
||||
const char_count = await get_row_count(CHARACTER.THIS);
|
||||
const chars = await pool.query(`SELECT id, name, faction_id, created, last_login FROM characters ORDER BY ${to_sql(sort)} ${to_sql(order)} OFFSET $1 LIMIT $2`, values);
|
||||
|
||||
pagination.item_count = char_count;
|
||||
pagination.page_count = Math.ceil(pagination.item_count / pagination.items_per_page);
|
||||
|
||||
chars.rows.forEach((r) => {
|
||||
delete r.account_id;
|
||||
});
|
||||
|
||||
return chars.rows;
|
||||
} catch (e) {
|
||||
if (e.code)
|
||||
e.code = pg_error_inv[e.code]
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
export async function get_characters_by_account(account_id) {
|
||||
try {
|
||||
const characters = await pool.query('SELECT * FROM characters WHERE account_id=$1 AND deleted=false', [account_id])
|
||||
return characters.rows;
|
||||
} catch (e) {
|
||||
if (e.code)
|
||||
e.code = pg_error_inv[e.code]
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
export async function get_account_by_name(name) {
|
||||
try {
|
||||
const account = await pool.query('SELECT * FROM accounts WHERE username=$1', [name]);
|
||||
return account.rows[0];
|
||||
} catch (e) {
|
||||
if (e.code)
|
||||
e.code = pg_error_inv[e.code]
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
export async function create_account(username, password) {
|
||||
try {
|
||||
const passhash = await bcrypt.hash(password, BCRYPT_ROUNDS);
|
||||
const account_id = await pool.query('INSERT INTO accounts(username, passhash) VALUES($1, $2) RETURNING id', [username, passhash]);
|
||||
return account_id.rows[0].id;
|
||||
} catch (e) {
|
||||
if (e.code)
|
||||
e.code = pg_error_inv[e.code]
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
function build_set(fields, idx=1) {
|
||||
let SQL = []
|
||||
let values = []
|
||||
|
||||
// TODO: sort for consistency
|
||||
Object.keys(fields).forEach(key => {
|
||||
SQL.push(key+"=$"+idx++)
|
||||
values.push(fields[key])
|
||||
});
|
||||
|
||||
return [SQL.join(", "), idx, values]
|
||||
}
|
||||
|
||||
export async function update_account(account_id, fields) {
|
||||
if (fields === {}) {
|
||||
return
|
||||
}
|
||||
|
||||
const set = build_set(fields);
|
||||
set[2].push(account_id)
|
||||
|
||||
try {
|
||||
const update_result = await pool.query('UPDATE accounts SET ' + set[0] + ' WHERE id=$'+set[1],set[2]);
|
||||
return update_result.rowCount;
|
||||
} catch (e) {
|
||||
if (e.code)
|
||||
e.code = pg_error_inv[e.code]
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
export async function get_stats() {
|
||||
try {
|
||||
const account_count = await get_row_count(ACCOUNT.THIS);
|
||||
const character_count = await get_row_count(CHARACTER.THIS);
|
||||
const last_account = await pool.query('SELECT id, username, created FROM accounts ORDER BY id DESC LIMIT 1');
|
||||
const last_character = await pool.query('SELECT id, name, faction_id, created FROM characters ORDER BY id DESC LIMIT 1');
|
||||
const empires = await pool.query('SELECT faction_id, COUNT(*) FROM characters GROUP BY faction_id');
|
||||
|
||||
const stats = {}
|
||||
stats.accounts = account_count;
|
||||
stats.characters = character_count;
|
||||
stats.last = {};
|
||||
stats.last.character = last_character.rows[0];
|
||||
stats.last.account = last_account.rows[0];
|
||||
stats.last.account.name = stats.last.account.username
|
||||
delete stats.last.account.username;
|
||||
stats.empires = {};
|
||||
|
||||
empires.rows.forEach((r) =>
|
||||
stats.empires[FACTION_MAP[r.faction_id][1]] = parseInt(r.count)
|
||||
);
|
||||
return stats;
|
||||
} catch (e) {
|
||||
if (e.code)
|
||||
e.code = pg_error_inv[e.code]
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
export async function get_account_logins(account_id, pagination) {
|
||||
const start_id = (pagination.page-1)*pagination.items_per_page;
|
||||
const values = [account_id, start_id, pagination.items_per_page];
|
||||
|
||||
try {
|
||||
const logins = await pool.query('SELECT * FROM logins WHERE account_id=$1 ORDER by login_time DESC ' +
|
||||
` OFFSET $2 LIMIT $3`, values);
|
||||
pagination.item_count = 100;
|
||||
pagination.page_count = Math.ceil(pagination.item_count / pagination.items_per_page);
|
||||
|
||||
return logins.rows;
|
||||
} catch (e) {
|
||||
if (e.code)
|
||||
e.code = pg_error_inv[e.code]
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
export async function search(term, pagination) {
|
||||
const start_id = (pagination.page-1)*pagination.items_per_page;
|
||||
const values = ['%'+term.toUpperCase()+'%', start_id, pagination.items_per_page];
|
||||
|
||||
try {
|
||||
const accounts = await pool.query('SELECT id, username, gm FROM accounts ' +
|
||||
'WHERE upper(username) LIKE $1 '+
|
||||
` ORDER BY username OFFSET $2 LIMIT $3`, values);
|
||||
const characters = await pool.query('SELECT id, name, faction_id FROM characters ' +
|
||||
'WHERE name LIKE $1 '+
|
||||
` ORDER BY upper(name) OFFSET $2 LIMIT $3`, values);
|
||||
|
||||
pagination.item_count = 100;
|
||||
pagination.page_count = Math.ceil(pagination.item_count / pagination.items_per_page);
|
||||
|
||||
const results = []
|
||||
|
||||
accounts.rows.forEach((r) => {
|
||||
r.type = "account";
|
||||
r.name = r.username;
|
||||
r.admin = r.gm;
|
||||
delete r.username;
|
||||
delete r.gm;
|
||||
|
||||
results.push(r)
|
||||
});
|
||||
|
||||
characters.rows.forEach((r) => {
|
||||
r.type = "character";
|
||||
results.push(r)
|
||||
});
|
||||
|
||||
// sort by name
|
||||
results.sort(function(a, b) {
|
||||
var nameA = a.name.toUpperCase(); // ignore upper and lowercase
|
||||
var nameB = b.name.toUpperCase(); // ignore upper and lowercase
|
||||
if (nameA < nameB) {
|
||||
return -1;
|
||||
}
|
||||
if (nameA > nameB) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// names must be equal
|
||||
return 0;
|
||||
});
|
||||
|
||||
return results;
|
||||
} catch (e) {
|
||||
if (e.code)
|
||||
e.code = pg_error_inv[e.code]
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
export async function validate_account(username, password) {
|
||||
try {
|
||||
const data = await pool.query('SELECT id, passhash FROM accounts WHERE username=$1', [username]);
|
||||
|
||||
if (data.rows.length === 0) {
|
||||
return undefined;
|
||||
} else {
|
||||
const creds = data.rows[0];
|
||||
|
||||
if (await bcrypt.compare(password, creds.passhash) === true) {
|
||||
return creds.id;
|
||||
} else {
|
||||
return creds.id;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
68
api/index.js
Normal file
68
api/index.js
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
import express from 'express'
|
||||
import bodyParser from 'body-parser'
|
||||
import * as db from './db.js'
|
||||
import api_auth from './authentication.js'
|
||||
import api_user from './user.js'
|
||||
import api_info from './info.js'
|
||||
import api_admin from './admin.js'
|
||||
|
||||
const api = express.Router();
|
||||
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
const LAG = 200;
|
||||
const LAG_JITTER = 100;
|
||||
console.log("WARNING: development server simulated delay active")
|
||||
api.use((req, res, next) => {
|
||||
setTimeout(() => next(), LAG + (Math.random()-0.5)*LAG_JITTER)
|
||||
});
|
||||
}
|
||||
|
||||
async function sessionRequired(req, res, next) {
|
||||
if (!req.session || !req.session.account_id) {
|
||||
res.status(403).json({message: 'session required'})
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
}
|
||||
async function adminRequired(req, res, next) {
|
||||
if (!req.session || !req.session.account_id) {
|
||||
res.status(403).json({message: 'admin required'})
|
||||
} else {
|
||||
try {
|
||||
const account = await db.get_account_by_id(req.session.account_id);
|
||||
|
||||
if (!account) {
|
||||
console.log("ERROR: failed to lookup account from session!")
|
||||
res.status(500).json({message: 'error'});
|
||||
} else {
|
||||
if (account.gm === true && account.inactive === false) {
|
||||
next();
|
||||
} else {
|
||||
res.status(403).json({message : 'admin required'})
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
res.status(500).json({message: 'error'});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
api.use(bodyParser.json());
|
||||
api.use(bodyParser.urlencoded({ extended: true }));
|
||||
|
||||
api.use(api_auth)
|
||||
api.use(api_info)
|
||||
api.use(sessionRequired, api_user)
|
||||
api.use(adminRequired, api_admin)
|
||||
|
||||
api.post("/bad_route", async (req, res, next) => {
|
||||
console.log("BAD APP ROUTE:", req.body.route)
|
||||
res.status(200).json({message : 'received'})
|
||||
});
|
||||
|
||||
api.all('*', function(req, res){
|
||||
res.status(404).json({message : 'Unknown API route'});
|
||||
});
|
||||
|
||||
export default api;
|
||||
16
api/info.js
Normal file
16
api/info.js
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import express from 'express'
|
||||
import * as db from './db.js'
|
||||
|
||||
const api = express.Router();
|
||||
|
||||
api.get('/stats', async (req, res, next) => {
|
||||
try {
|
||||
const stats = await db.get_stats();
|
||||
res.status(200).json({ ...stats });
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
res.status(500).json({ message : 'error' });
|
||||
}
|
||||
});
|
||||
|
||||
export default api;
|
||||
59
api/user.js
Normal file
59
api/user.js
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
import express from 'express'
|
||||
import * as db from './db.js'
|
||||
import { get_pagination, fetch_user_middleware } from './util.js'
|
||||
|
||||
const api = express.Router();
|
||||
|
||||
api.param("user", fetch_user_middleware);
|
||||
|
||||
api.get('/user', async (req, res, next) => {
|
||||
try {
|
||||
const account = await db.get_account_by_id(req.session.account_id);
|
||||
res.status(200).json({ id : account.id, name: account.username, admin : account.gm });
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
res.status(500).json({ message: 'error' });
|
||||
}
|
||||
});
|
||||
|
||||
api.get('/user/profile', async (req, res, next) => {
|
||||
try {
|
||||
const account = await db.get_account_by_id(req.session.account_id);
|
||||
const characters = await db.get_characters_by_account(req.session.account_id);
|
||||
|
||||
res.status(200).json({
|
||||
id : account.id,
|
||||
name: account.username,
|
||||
//email : account.email, // TODO
|
||||
email : "bademail@email.com",
|
||||
account_created : account.created,
|
||||
admin : account.gm,
|
||||
characters: characters,
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
res.status(500).json({ message: 'error' });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
api.get('/user/:user/logins', async (req, res, next) => {
|
||||
const account = req.user;
|
||||
const pagination = get_pagination(req);
|
||||
|
||||
if (account.id !== req.session.account_id) {
|
||||
res.status(403).json({ message: 'not allowed to see for other users' });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const logins = await db.get_account_logins(account.id, pagination)
|
||||
console.log(logins)
|
||||
res.status(200).json({ logins : logins, page: pagination});
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
res.status(500).json({ message: 'error' });
|
||||
}
|
||||
});
|
||||
|
||||
export default api;
|
||||
32
api/util.js
Normal file
32
api/util.js
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import * as db from './db.js'
|
||||
|
||||
export function get_pagination(req) {
|
||||
let page = parseInt(req.query.page);
|
||||
let order = req.query.order; // TODO
|
||||
|
||||
if (!page || page < 1) {
|
||||
page = 1;
|
||||
}
|
||||
|
||||
return {
|
||||
page: page,
|
||||
items_per_page: 40,
|
||||
//order: order, // TODO
|
||||
};
|
||||
}
|
||||
|
||||
export async function fetch_user_middleware(req, res, next, id) {
|
||||
try {
|
||||
const account = await db.get_account_by_id(id);
|
||||
|
||||
if (!account) {
|
||||
res.status(404).json({message: `account ${id} does not exist`});
|
||||
} else {
|
||||
req.user = account;
|
||||
next();
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
res.status(500).json({message: 'error'});
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue