Enable foreign profile view

This commit is contained in:
Chord 2019-12-30 13:20:50 -05:00
parent 20946fdb43
commit cb918033a6
14 changed files with 248 additions and 125 deletions

View file

@ -47,7 +47,7 @@ api.post('/user/:user/add_gm', async (req, res, next) => {
const account = req.user;
try {
await db.update_account(account.id, {"gm" : true})
await db.update_account(account.id, {[db.ACCOUNT.ADMIN] : true})
res.status(200).json({});
} catch(e) {
console.log(e);
@ -59,7 +59,7 @@ api.post('/user/:user/remove_gm', async (req, res, next) => {
const account = req.user;
try {
await db.update_account(account.id, {"gm" : false})
await db.update_account(account.id, {[db.ACCOUNT.ADMIN] : false})
res.status(200).json({});
} catch(e) {
console.log(e);
@ -72,7 +72,7 @@ api.post('/user/:user/ban', async (req, res, next) => {
try {
// also drop GM if they had it...
await db.update_account(account.id, {"inactive" : true, "gm" : false})
await db.update_account(account.id, {[db.ACCOUNT.BANNED] : true, [db.ACCOUNT.ADMIN] : false})
res.status(200).json({});
} catch(e) {
console.log(e);
@ -84,10 +84,9 @@ api.post('/user/:user/unban', async (req, res, next) => {
const account = req.user;
try {
await db.update_account(account.id, {"inactive" : false})
await db.update_account(account.id, {[db.ACCOUNT.BANNED] : false})
res.status(200).json({});
} catch(e) {
console.log(e);
res.status(500).json({ message: 'error' });
}

View file

@ -56,13 +56,59 @@ export const CHARACTER = Object.freeze({
DELETED: Symbol("deleted"),
});
export const LOGIN = Object.freeze({
THIS: Symbol("logins"),
ID: Symbol("id"),
ACCOUNT_ID: Symbol("account_id"),
});
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)}`);
function to_sql_kv(fields, idx=1) {
let SQL = [];
let values = [];
// This will ONLY get Symbols in the field dict
assert(Object.getOwnPropertySymbols(fields).length > 0, "to_sql_kv must have at least one field")
Object.getOwnPropertySymbols(fields).forEach(key => {
assert(typeof key == 'symbol')
SQL.push(to_sql(key)+"=$"+idx++);
values.push(fields[key]);
});
return {
sql: SQL,
next_idx: idx,
values: values,
}
}
function build_SET(fields, idx=1) {
const kv = to_sql_kv(fields, idx);
kv.sql = Symbol(kv.sql.join(", "));
return kv;
}
function build_WHERE(fields, idx=1) {
const kv = to_sql_kv(fields, idx);
kv.sql = Symbol(kv.sql.join(" AND "));
return kv;
}
async function get_row_count(table, filter=undefined) {
let resp;
if (filter) {
const where = build_WHERE(filter);
resp = await pool.query(`SELECT COUNT(*) FROM ${to_sql(table)} WHERE ${to_sql(where.sql)}`,
where.values);
} else {
resp = await pool.query(`SELECT COUNT(*) FROM ${to_sql(table)}`);
}
return parseInt(resp.rows[0].count);
}
@ -70,6 +116,13 @@ export async function connect_to_db() {
pool = new pg.Pool()
try {
const res = await pool.query('SELECT NOW()')
// Quick hack for query debugging (throws exception)
const _query = pool.query;
pool.query_log = (q, v) => {
console.log("QUERY LOG: ", q, v);
return _query(q, v);
}
console.log(`Connected to the psql database at ${process.env.PGHOST}`)
} catch (e) {
console.log("Unable to connect to the database: " + e.message);
@ -80,9 +133,14 @@ export async function connect_to_db() {
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];
if (account.rows.length == 0) {
return undefined;
}
const account_obj = account.rows[0];
delete account_obj.passhash;
return account_obj;
} catch (e) {
throw e;
@ -222,29 +280,16 @@ export async function create_account(username, password) {
}
}
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)
const set = build_SET(fields);
set.values.push(account_id)
try {
const update_result = await pool.query('UPDATE accounts SET ' + set[0] + ' WHERE id=$'+set[1],set[2]);
const update_result = await pool.query(`UPDATE accounts SET ${to_sql(set.sql)} WHERE id=$${set.next_idx}`, set.values);
return update_result.rowCount;
} catch (e) {
if (e.code)
@ -287,9 +332,10 @@ export async function get_account_logins(account_id, pagination) {
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;
const login_count = await get_row_count(LOGIN.THIS, { [LOGIN.ACCOUNT_ID] : account_id });
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 = login_count;
pagination.page_count = Math.ceil(pagination.item_count / pagination.items_per_page);
return logins.rows;

View file

@ -20,13 +20,6 @@ if (process.env.NODE_ENV !== "production") {
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);
@ -35,11 +28,8 @@ async function adminRequired(req, res, next) {
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'})
}
req.session_account = account;
next();
}
} catch (e) {
console.log(e)
@ -47,6 +37,18 @@ async function adminRequired(req, res, next) {
}
}
}
async function adminRequired(req, res, next) {
if (!req.session_account) {
console.log("ERROR: sessionRequired needs to be called before adminRequired")
res.status(500).json({message: ''})
} else {
if (req.session_account.gm === true && req.session_account.inactive === false) {
next();
} else {
res.status(403).json({message : 'admin required'})
}
}
}
api.use(bodyParser.json());
api.use(bodyParser.urlencoded({ extended: true }));
@ -54,7 +56,7 @@ 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.use(sessionRequired, adminRequired, api_admin)
api.post("/bad_route", async (req, res, next) => {
console.log("BAD APP ROUTE:", req.body.route)

View file

@ -16,10 +16,17 @@ api.get('/user', async (req, res, next) => {
}
});
api.get('/user/profile', async (req, res, next) => {
api.get('/user/:user/profile', async (req, res, next) => {
const target_account = req.user;
if (target_account.id !== req.session.account_id && !req.session_account.gm) {
res.status(403).json({ message: 'not allowed to see for other users' });
return;
}
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);
const account = await db.get_account_by_id(target_account.id);
const characters = await db.get_characters_by_account(target_account.id);
res.status(200).json({
id : account.id,
@ -36,19 +43,17 @@ api.get('/user/profile', async (req, res, next) => {
}
});
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) {
if (account.id !== req.session.account_id && !req.session_account.gm) {
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)

View file

@ -16,6 +16,13 @@ export function get_pagination(req) {
}
export async function fetch_user_middleware(req, res, next, id) {
id = parseInt(id);
if (id <= 0) {
res.status(500).json({message: 'error'});
return;
}
try {
const account = await db.get_account_by_id(id);