From 12cdc8a6f1173f1304599c661bcfa3abdc9dada0 Mon Sep 17 00:00:00 2001 From: Zaid Abdulla Date: Sun, 23 Dec 2018 04:43:59 -0800 Subject: [PATCH] Add functions for DB access --- client/css/app.css | 5 +++ config.json | 1 + package.json | 1 + server/api-functions.js | 13 ++++---- server/api.js | 53 ++++++++++++++++++++------------ server/db.js | 67 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 114 insertions(+), 26 deletions(-) create mode 100644 server/db.js diff --git a/client/css/app.css b/client/css/app.css index b0bae5a..5e46ab5 100644 --- a/client/css/app.css +++ b/client/css/app.css @@ -266,6 +266,11 @@ table.table { & td { margin: 0; padding: 0.2em 0.5em; + + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 400px; } & tfoot td > a { diff --git a/config.json b/config.json index fd29d20..685fbf0 100644 --- a/config.json +++ b/config.json @@ -1,6 +1,7 @@ { "server.port": 3000, "server.nbi": "http://127.0.0.1:7557/", + "server.mongodbConnectionUrl": "mongodb://127.0.0.1:27017", "server.jwtSecret": "jwtSecret", "auth.simple.users.admin.password": "admin", "auth.simple.users.admin.roles": "admin", diff --git a/package.json b/package.json index 345137e..4789d22 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "koa-router": "^7.4.0", "koa-static": "^4.0.2", "mithril": "^1.1.6", + "mongodb": "^3.0.10", "parsimmon": "^1.7.2" }, "devDependencies": { diff --git a/server/api-functions.js b/server/api-functions.js index 8eaf815..78a8bb2 100644 --- a/server/api-functions.js +++ b/server/api-functions.js @@ -24,20 +24,20 @@ function unpackTimestamps(filter) { }); } -function filterToQuery(filter, negate = false, res = {}) { +function filterToMongoQuery(filter, negate = false, res = {}) { const op = filter[0]; if ((!negate && op === "AND") || (negate && op === "OR")) { res["$and"] = res["$and"] || []; for (let i = 1; i < filter.length; ++i) - res["$and"].push(filterToQuery(filter[i], negate)); + res["$and"].push(filterToMongoQuery(filter[i], negate)); } else if ((!negate && op === "OR") || (negate && op === "AND")) { res["$or"] = res["$or"] || []; for (let i = 1; i < filter.length; ++i) - res["$or"].push(filterToQuery(filter[i], negate)); + res["$or"].push(filterToMongoQuery(filter[i], negate)); } else if (op === "NOT") { - filterToQuery(filter[1], !negate, res); + filterToMongoQuery(filter[1], !negate, res); } else if (op === "=") { let p = (res[filter[1]] = res[filter[1]] || {}); if (negate) p["$ne"] = filter[2]; @@ -84,7 +84,7 @@ function count(resource, filter, limit) { filter = filter.evaluateExpressions(); let ast = unpackTimestamps(filter.ast); - let q = filterToQuery(ast); + let q = filterToMongoQuery(ast); if (resource === "devices") q = device.transposeQuery(q); qs.query = JSON.stringify(q); } @@ -121,7 +121,7 @@ function query(resource, filter, limit, skip, projection, callback) { filter = filter.evaluateExpressions(); let ast = unpackTimestamps(filter.ast); - let q = filterToQuery(ast); + let q = filterToMongoQuery(ast); if (resource === "devices") q = device.transposeQuery(q); qs.query = JSON.stringify(q); @@ -372,3 +372,4 @@ exports.count = count; exports.postTasks = postTasks; exports.deleteResource = deleteResource; exports.updateTags = updateTags; +exports.filterToMongoQuery = filterToMongoQuery; diff --git a/server/api.js b/server/api.js index c9b78fb..cf47d7d 100644 --- a/server/api.js +++ b/server/api.js @@ -2,22 +2,26 @@ const Router = require("koa-router"); +const db = require("./db"); const apiFunctions = require("./api-functions"); const Filter = require("../common/filter"); const router = new Router(); +const RESOURCE_DELETE = 1 << 0; +const RESOURCE_DB = 1 << 1; + const resources = { - devices: true, - presets: true, - provisions: true, - files: true, - virtual_parameters: true, - faults: true, - tasks: false + devices: 0 | RESOURCE_DELETE, + presets: 0 | RESOURCE_DELETE, + provisions: 0 | RESOURCE_DELETE, + files: 0 | RESOURCE_DELETE, + virtual_parameters: 0 | RESOURCE_DELETE, + faults: 0 | RESOURCE_DELETE, + tasks: 0 }; -for (let [resource, update] of Object.entries(resources)) { +for (let [resource, flags] of Object.entries(resources)) { router.head(`/${resource}`, async (ctx, next) => { let filter, limit; if (ctx.request.query.filter) filter = new Filter(ctx.request.query.filter); @@ -31,16 +35,20 @@ for (let [resource, update] of Object.entries(resources)) { filter = f.and(filter); } - let count = await apiFunctions.count(resource, filter, limit); + let count; + if (flags & RESOURCE_DB) count = await db.count(resource, filter, limit); + else count = await apiFunctions.count(resource, filter, limit); + ctx.set("X-Total-Count", count); ctx.body = ""; }); router.get(`/${resource}`, async (ctx, next) => { - let filter, limit, skip; + let filter, limit, skip, projection; if (ctx.request.query.filter) filter = new Filter(ctx.request.query.filter); if (ctx.request.query.limit) limit = +ctx.request.query.limit; if (ctx.request.query.skip) skip = +ctx.request.query.skip; + if (ctx.request.query.projection) projection = ctx.request.query.projection; if (!ctx.state.authorizer.hasAccess(resource, 2)) return next(); @@ -50,20 +58,23 @@ for (let [resource, update] of Object.entries(resources)) { filter = f.and(filter); } - ctx.body = await apiFunctions.query( - resource, - filter, - limit, - skip, - ctx.request.query.projection - ); + let res; + if (flags & RESOURCE_DB) + res = await db.query(resource, filter, limit, skip); + else + res = await apiFunctions.query(resource, filter, limit, skip, projection); + + ctx.body = res; }); router.head(`/${resource}/:id`, async (ctx, next) => { let filter = new Filter(`DeviceID.ID = "${ctx.params.id}"`); if (!ctx.state.authorizer.hasAccess(resource, 2)) return next(); - let res = await apiFunctions.query(resource, filter); + let res; + if (flags & RESOURCE_DB) res = await db.query(resource, filter); + else res = await apiFunctions.query(resource, filter); + if (!res.length) return next(); ctx.body = ""; }); @@ -72,13 +83,15 @@ for (let [resource, update] of Object.entries(resources)) { let filter = new Filter(`DeviceID.ID = "${ctx.params.id}"`); if (!ctx.state.authorizer.hasAccess(resource, 2)) return next(); - let res = await apiFunctions.query(resource, filter); + let res; + if (flags & RESOURCE_DB) res = await db.query(resource, filter); + else res = await apiFunctions.query(resource, filter); if (!res.length) return next(); ctx.body = res[0]; }); // TODO add PUT, PATCH routes - if (update) + if (flags & RESOURCE_DELETE && !(flags & RESOURCE_DB)) router.delete(`/${resource}/:id`, async (ctx, next) => { const authorizer = ctx.state.authorizer; let filter = new Filter(`DeviceID.ID = "${ctx.params.id}"`); diff --git a/server/db.js b/server/db.js new file mode 100644 index 0000000..0cb0418 --- /dev/null +++ b/server/db.js @@ -0,0 +1,67 @@ +"use strict"; + +const MongoClient = require("mongodb").MongoClient; +const config = require("./config"); +const apiFunctions = require("./api-functions"); + +let _client = null; + +function getClient() { + if (_client) return Promise.resolve(_client); + + return new Promise((resolve, reject) => { + const CONNECTION_URL = config.get("server.mongodbConnectionUrl"); + MongoClient.connect(CONNECTION_URL, (err, client) => { + if (err) return reject(err); + resolve((_client = client.db("genieacs-ui"))); + }); + }); +} + +function query(resource, filter, limit, skip, callback) { + let q; + if (filter && filter.ast) q = apiFunctions.filterToMongoQuery(filter.ast); + + return new Promise((resolve, reject) => { + getClient().then(client => { + const collection = client.collection(resource); + if (!callback) + collection + .find(q) + .skip(skip || 0) + .limit(limit || 0) + .toArray((err, docs) => { + if (err) return reject(err); + return resolve(docs); + }); + else + collection.find(q).forEach( + doc => { + callback(doc); + }, + err => { + if (err) reject(err); + else resolve(); + } + ); + }); + }); +} + +function count(resource, filter) { + let q; + if (filter && filter.ast) q = apiFunctions.filterToMongoQuery(filter.ast); + + return new Promise((resolve, reject) => { + getClient().then(client => { + const collection = client.collection(resource); + collection.find(q).count((err, c) => { + if (err) reject(err); + else resolve(c); + }); + }); + }); +} + +exports.query = query; +exports.count = count;