import { knex, validation } from '../../lib/ormish.js'; import logging from "../../lib/logging.js"; import { developer_admin, API } from '../../lib/api.js'; const log = logging.create("api/admin/table.js"); export const get = async (req, res) => { const api = new API(req, res); const { name, search, row_id, currentPage } = req.query; try { const page = parseInt(currentPage || "0", 10); if(!api.admin_authenticated) { return api.error(401, "Admin rights required."); } else if(name && search) { // get the list of columns to search const col_info = await knex(name).columnInfo(); const query = knex(name); let columns = Object.getOwnPropertyNames(col_info); for(let col of columns) { // SECURITY: string interpolation but not sure how to do this without it query.orWhere(col, "like", `%${search}%`); } // loop through and construct a mega where clause let result = await query.paginate({perPage: 20, currentPage: page}); return api.reply(200, result); } else if(name && !row_id) { // TODO: restrict the tables that can be queried? let result = await knex(name).paginate({perPage: 20, currentPage: page}); return api.reply(200, result); } else if(name && row_id) { let result = await knex(name).where({id: row_id}).first(); return api.reply(200, result); } else { return api.error(500, "name query parameter required, or name and row_id."); } } catch(error) { log.error(error); return api.error(500, "Internal server error."); } } get.authenticated = !developer_admin; export const del = async (req, res) => { const api = new API(req, res); const { name, row_id } = req.query; try { if(!api.admin_authenticated) { return api.error(401, "Admin rights required."); } else if(name && row_id) { let res = await knex(name).where({id: row_id}).delete(); return api.reply(200, {message: "OK", result: res}); } else { return api.error(500, "name and row_id required for delete"); } } catch(error) { log.error(error); return api.error(500, "Internal server error."); } } del.authenticated = !developer_admin; export const post = async (req, res) => { const api = new API(req, res); const { name, row_id } = req.query; try { if(!api.admin_authenticated) { return api.error(401, "Admin rights required."); } else if(name && row_id) { // normally the validation rules come from the // model class once and placed at the top of the // module, but here we get it dynamically based // on the name. const rules = validation(name, {}, true); const data = api.validate(rules); // remove the id since they can't set it delete data["id"]; if(!data._valid) { return api.validation_error(res, data); } else { // remove id so it's not updated too api.clean_form(data, rules, ["id"]); let res = await knex(name). where({id: row_id}).update(data); return api.reply(200, {message: "OK", result: res}); } } else { return api.error(500, "name and row_id required for delete"); } } catch(error) { log.error(error); return api.error(500, error.message || "Internal server error."); } } post.authenticated = !developer_admin; export const put = async (req, res) => { const api = new API(req, res); const { name } = req.query; try { if(!api.admin_authenticated) { return api.error(401, "Admin rights required."); } else if(name) { const rules = validation(name, {}, true); // don't validate id or accept it const data = api.validate(rules); // remove the id since they can't set it delete data["id"]; if(!data._valid) { return api.validation_error(res, data); } else { api.clean_form(data, rules, ["id"]); let res = await knex(name).insert(data); return api.reply(200, {message: "OK", id: res[0]}); } } else { return api.error(500, "name required for delete"); } } catch(error) { log.error(error); return api.error(500, "Internal server error."); } } put.authenticated = !developer_admin;