Move UI configs to DB
This commit is contained in:
1 parent
192ed6b034
commit
1cceba3f8b
22 files changed
+335
-446
No files matched your search
+12
-1
@@ -11,6 +11,7 @@ const cluster = require("../lib/cluster");
|
|||||||
const server = require("../lib/server");
|
const server = require("../lib/server");
|
||||||
const ui = require("../lib/ui");
|
const ui = require("../lib/ui");
|
||||||
const db = require("../lib/ui/db");
|
const db = require("../lib/ui/db");
|
||||||
|
const db2 = require("../lib/db");
|
||||||
const cache = require("../lib/cache");
|
const cache = require("../lib/cache");
|
||||||
|
|
||||||
const VERSION = require("../package.json").version;
|
const VERSION = require("../package.json").version;
|
||||||
@@ -22,6 +23,7 @@ const SERVICE_PORT = config.get("UI_PORT");
|
|||||||
|
|
||||||
function exitWorkerGracefully() {
|
function exitWorkerGracefully() {
|
||||||
db.disconnect();
|
db.disconnect();
|
||||||
|
db2.disconnect();
|
||||||
cache.disconnect();
|
cache.disconnect();
|
||||||
cluster.worker.disconnect();
|
cluster.worker.disconnect();
|
||||||
}
|
}
|
||||||
@@ -105,8 +107,17 @@ if (!cluster.worker) {
|
|||||||
ui.listener(req, res);
|
ui.listener(req, res);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
db2.connect(err => {
|
||||||
|
if (err) throw err;
|
||||||
cache.connect(err => {
|
cache.connect(err => {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
server.start(SERVICE_PORT, SERVICE_ADDRESS, ssl, listener, ui.onConnection);
|
server.start(
|
||||||
|
SERVICE_PORT,
|
||||||
|
SERVICE_ADDRESS,
|
||||||
|
ssl,
|
||||||
|
listener,
|
||||||
|
ui.onConnection
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -78,7 +78,6 @@ async function copyStatic() {
|
|||||||
"CHANGELOG.md",
|
"CHANGELOG.md",
|
||||||
"npm-shrinkwrap.json",
|
"npm-shrinkwrap.json",
|
||||||
"config/config-sample.json",
|
"config/config-sample.json",
|
||||||
"config/config-ui-sample.json",
|
|
||||||
"config/auth-sample.js",
|
"config/auth-sample.js",
|
||||||
"config/ext-sample.js",
|
"config/ext-sample.js",
|
||||||
"public/logo.svg",
|
"public/logo.svg",
|
||||||
|
|||||||
@@ -10,5 +10,6 @@
|
|||||||
"FS_HOSTNAME" : "acs.example.com",
|
"FS_HOSTNAME" : "acs.example.com",
|
||||||
"UI_INTERFACE" : "0.0.0.0",
|
"UI_INTERFACE" : "0.0.0.0",
|
||||||
"UI_PORT" : 3000,
|
"UI_PORT" : 3000,
|
||||||
|
"UI_JWT_SECRET": "",
|
||||||
"DEBUG" : false
|
"DEBUG" : false
|
||||||
}
|
}
|
||||||
@@ -1,313 +0,0 @@
|
|||||||
{
|
|
||||||
"server": {
|
|
||||||
"nbi": "http://127.0.0.1:7557/",
|
|
||||||
"mongodbConnectionUrl": "mongodb://127.0.0.1:27017",
|
|
||||||
"jwtSecret": "jwtSecret"
|
|
||||||
},
|
|
||||||
"auth": {
|
|
||||||
"simple": {
|
|
||||||
"users": {
|
|
||||||
"admin": {
|
|
||||||
"password": "admin",
|
|
||||||
"roles": "admin"
|
|
||||||
},
|
|
||||||
"view": {
|
|
||||||
"password": "view",
|
|
||||||
"roles": "view"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"permissions": {
|
|
||||||
"admin": [
|
|
||||||
{
|
|
||||||
"devices": {
|
|
||||||
"access": 3,
|
|
||||||
"validate": {
|
|
||||||
"pass": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"faults": {
|
|
||||||
"access": 3,
|
|
||||||
"validate": {
|
|
||||||
"pass": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"presets": {
|
|
||||||
"access": 3,
|
|
||||||
"validate": {
|
|
||||||
"pass": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"provisions" : {
|
|
||||||
"access": 3,
|
|
||||||
"validate": {
|
|
||||||
"pass": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"virtualParameters" : {
|
|
||||||
"access": 3,
|
|
||||||
"validate": {
|
|
||||||
"pass": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"files": {
|
|
||||||
"access": 3,
|
|
||||||
"validate": {
|
|
||||||
"pass": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"view": [
|
|
||||||
{
|
|
||||||
"devices": {
|
|
||||||
"access": 2
|
|
||||||
},
|
|
||||||
"faults": {
|
|
||||||
"access": 2
|
|
||||||
},
|
|
||||||
"presets": {
|
|
||||||
"access": 2
|
|
||||||
},
|
|
||||||
"provisions": {
|
|
||||||
"access": 2
|
|
||||||
},
|
|
||||||
"virtualParameters": {
|
|
||||||
"access": 2
|
|
||||||
},
|
|
||||||
"files": {
|
|
||||||
"access": 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"ui": {
|
|
||||||
"pageSize": 10,
|
|
||||||
"filters": [
|
|
||||||
{
|
|
||||||
"label": "Serial number",
|
|
||||||
"parameter": "DeviceID.SerialNumber",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Product class",
|
|
||||||
"parameter": "DeviceID.ProductClass",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Tag",
|
|
||||||
"parameter": "tag",
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"index": [
|
|
||||||
{
|
|
||||||
"label": "Serial number",
|
|
||||||
"parameter": "DeviceID.SerialNumber",
|
|
||||||
"type": "device-link",
|
|
||||||
"components": [
|
|
||||||
{
|
|
||||||
"type": "parameter"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Product class",
|
|
||||||
"parameter": "DeviceID.ProductClass"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Software version",
|
|
||||||
"parameter": "InternetGatewayDevice.DeviceInfo.SoftwareVersion"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "IP",
|
|
||||||
"parameter": "InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANIPConnection.1.ExternalIPAddress"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "SSID",
|
|
||||||
"parameter": "InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.SSID"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Last inform",
|
|
||||||
"parameter": "DATE_STRING(Events.Inform)",
|
|
||||||
"type": "container",
|
|
||||||
"element": "span.inform",
|
|
||||||
"components": [
|
|
||||||
{
|
|
||||||
"type": "parameter"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "overview-dot",
|
|
||||||
"chart": "online"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Tags",
|
|
||||||
"parameter": "Tags",
|
|
||||||
"type": "tags",
|
|
||||||
"writable": false,
|
|
||||||
"unsortable": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"overview": {
|
|
||||||
"groups": {
|
|
||||||
"online": {
|
|
||||||
"label": "",
|
|
||||||
"charts": [
|
|
||||||
"online"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"charts": {
|
|
||||||
"online": {
|
|
||||||
"label": "Online status",
|
|
||||||
"slices": {
|
|
||||||
"onlineNow": {
|
|
||||||
"label": "Online now",
|
|
||||||
"color": "#31a354",
|
|
||||||
"filter": "Events.Inform > NOW() - 5 * 60 * 1000"
|
|
||||||
},
|
|
||||||
"past24": {
|
|
||||||
"label": "Past 24 hours",
|
|
||||||
"color": "#addd8e",
|
|
||||||
"filter": "Events.Inform > (NOW() - 5 * 60 * 1000) - (24 * 60 * 60 * 1000) AND Events.Inform < (NOW() - 5 * 60 * 1000)"
|
|
||||||
},
|
|
||||||
"others": {
|
|
||||||
"label": "Others",
|
|
||||||
"color": "#f7fcb9",
|
|
||||||
"filter": "Events.Inform < (NOW() - 5 * 60 * 1000) - (24 * 60 * 60 * 1000)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"device": [
|
|
||||||
{
|
|
||||||
"type": "tags"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "ping"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "parameter-list",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "container",
|
|
||||||
"label": "Last inform",
|
|
||||||
"element": "span.inform",
|
|
||||||
"parameter": "DATE_STRING(Events.Inform)",
|
|
||||||
"components": [
|
|
||||||
{
|
|
||||||
"type": "parameter"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "overview-dot",
|
|
||||||
"chart": "online"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "summon-button",
|
|
||||||
"parameters": [
|
|
||||||
"InternetGatewayDevice.DeviceInfo.HardwareVersion",
|
|
||||||
"InternetGatewayDevice.DeviceInfo.SoftwareVersion",
|
|
||||||
"InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANIPConnection.1.MACAddress",
|
|
||||||
"InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANIPConnection.1.ExternalIPAddress",
|
|
||||||
"InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.SSID",
|
|
||||||
"InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.KeyPassphrase",
|
|
||||||
"InternetGatewayDevice.LANDevice.1.Hosts.Host"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Serial number",
|
|
||||||
"parameter": "InternetGatewayDevice.DeviceInfo.SerialNumber"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Product class",
|
|
||||||
"parameter": "InternetGatewayDevice.DeviceInfo.ProductClass"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "OUI",
|
|
||||||
"parameter": "InternetGatewayDevice.DeviceInfo.ManufacturerOUI"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Manufacturer",
|
|
||||||
"parameter": "InternetGatewayDevice.DeviceInfo.Manufacturer"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Hardware version",
|
|
||||||
"parameter": "InternetGatewayDevice.DeviceInfo.HardwareVersion"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Software version",
|
|
||||||
"parameter": "InternetGatewayDevice.DeviceInfo.SoftwareVersion"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "MAC",
|
|
||||||
"parameter": "InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANIPConnection.1.MACAddress"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "IP",
|
|
||||||
"parameter": "InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANIPConnection.1.ExternalIPAddress"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "WLAN SSID",
|
|
||||||
"parameter": "InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.SSID"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "WLAN passphrase",
|
|
||||||
"parameter": "InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.KeyPassphrase"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "parameter-table",
|
|
||||||
"label": "WLAN hosts",
|
|
||||||
"parameter": "InternetGatewayDevice.LANDevice.1.Hosts.Host",
|
|
||||||
"childParameters": [
|
|
||||||
{
|
|
||||||
"label": "Host name",
|
|
||||||
"parameter": "HostName"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "IP address",
|
|
||||||
"parameter": "IPAddress"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "MAC address",
|
|
||||||
"parameter": "MACAddress"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "container",
|
|
||||||
"element": "div",
|
|
||||||
"components": [
|
|
||||||
{
|
|
||||||
"type": "container",
|
|
||||||
"element": "h3",
|
|
||||||
"components": ["Faults"]
|
|
||||||
},
|
|
||||||
{"type": "device-faults"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "container",
|
|
||||||
"element": "div.container-full-width",
|
|
||||||
"components": [
|
|
||||||
{
|
|
||||||
"type": "container",
|
|
||||||
"element": "h3",
|
|
||||||
"components": ["All parameters"]
|
|
||||||
},
|
|
||||||
{"type": "all-parameters"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "device-actions"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -59,6 +59,7 @@ const options = {
|
|||||||
UI_SSL: { type: "bool", default: false },
|
UI_SSL: { type: "bool", default: false },
|
||||||
UI_LOG_FILE: { type: "path", default: "" },
|
UI_LOG_FILE: { type: "path", default: "" },
|
||||||
UI_ACCESS_LOG_FILE: { type: "path", default: "" },
|
UI_ACCESS_LOG_FILE: { type: "path", default: "" },
|
||||||
|
UI_JWT_SECRET: { type: "string", default: "" },
|
||||||
|
|
||||||
UDP_CONNECTION_REQUEST_PORT: { type: "int", default: 0 },
|
UDP_CONNECTION_REQUEST_PORT: { type: "int", default: 0 },
|
||||||
|
|
||||||
|
|||||||
+62
-3
@@ -307,8 +307,30 @@ function refresh(callback) {
|
|||||||
db.getConfig((err, conf) => {
|
db.getConfig((err, conf) => {
|
||||||
if (err) return void reject(err);
|
if (err) return void reject(err);
|
||||||
|
|
||||||
|
conf.sort((a, b) => (a.id > b.id ? 1 : a.id < b.id ? -1 : 0));
|
||||||
|
|
||||||
const _config = {};
|
const _config = {};
|
||||||
for (const c of conf) _config[c.id] = c.value;
|
|
||||||
|
for (const c of conf) {
|
||||||
|
if (
|
||||||
|
c.id.startsWith("auth.") ||
|
||||||
|
c.id.startsWith("permissions.") ||
|
||||||
|
c.id.startsWith("ui.")
|
||||||
|
) {
|
||||||
|
const keys = c.id.split(".");
|
||||||
|
let ref = _config;
|
||||||
|
while (keys.length > 1) {
|
||||||
|
const k = keys.shift();
|
||||||
|
if (typeof ref[k] !== "object") ref[k] = {};
|
||||||
|
ref = ref[k];
|
||||||
|
}
|
||||||
|
// Evaluate expressions to simplify them
|
||||||
|
ref[keys[0]] = expression.evaluate(c.value);
|
||||||
|
} else {
|
||||||
|
// Evaluate expressions to simplify them
|
||||||
|
_config[c.id] = expression.evaluate(c.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
resolve(_config);
|
resolve(_config);
|
||||||
});
|
});
|
||||||
@@ -348,10 +370,23 @@ function refresh(callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getCurrentSnapshot(callback) {
|
function getCurrentSnapshot(callback) {
|
||||||
if (Date.now() < nextRefresh) return void callback(null, currentSnapshot);
|
if (Date.now() < nextRefresh) {
|
||||||
refresh(err => {
|
if (callback) return callback(null, currentSnapshot);
|
||||||
|
return Promise.resolve(currentSnapshot);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
return refresh(err => {
|
||||||
callback(err, currentSnapshot);
|
callback(err, currentSnapshot);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
refresh(err => {
|
||||||
|
if (err) return void reject(err);
|
||||||
|
resolve(currentSnapshot);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasSnapshot(hash) {
|
function hasSnapshot(hash) {
|
||||||
@@ -410,6 +445,27 @@ function getConfig(snapshotKey, key, context, now) {
|
|||||||
return expression.evaluate(snapshot.config[key], context, now || Date.now());
|
return expression.evaluate(snapshot.config[key], context, now || Date.now());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getAuthConfig(snapshotKey) {
|
||||||
|
const snapshot = snapshots.get(snapshotKey);
|
||||||
|
if (!snapshot) throw new Error("Cache snapshot does not exist");
|
||||||
|
|
||||||
|
return snapshot.config.auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPermissionsConfig(snapshotKey) {
|
||||||
|
const snapshot = snapshots.get(snapshotKey);
|
||||||
|
if (!snapshot) throw new Error("Cache snapshot does not exist");
|
||||||
|
|
||||||
|
return snapshot.config.permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUiConfig(snapshotKey) {
|
||||||
|
const snapshot = snapshots.get(snapshotKey);
|
||||||
|
if (!snapshot) throw new Error("Cache snapshot does not exist");
|
||||||
|
|
||||||
|
return snapshot.config.ui;
|
||||||
|
}
|
||||||
|
|
||||||
exports.getCurrentSnapshot = getCurrentSnapshot;
|
exports.getCurrentSnapshot = getCurrentSnapshot;
|
||||||
exports.hasSnapshot = hasSnapshot;
|
exports.hasSnapshot = hasSnapshot;
|
||||||
exports.getPresets = getPresets;
|
exports.getPresets = getPresets;
|
||||||
@@ -417,3 +473,6 @@ exports.getProvisions = getProvisions;
|
|||||||
exports.getVirtualParameters = getVirtualParameters;
|
exports.getVirtualParameters = getVirtualParameters;
|
||||||
exports.getFiles = getFiles;
|
exports.getFiles = getFiles;
|
||||||
exports.getConfig = getConfig;
|
exports.getConfig = getConfig;
|
||||||
|
exports.getAuthConfig = getAuthConfig;
|
||||||
|
exports.getPermissionsConfig = getPermissionsConfig;
|
||||||
|
exports.getUiConfig = getUiConfig;
|
||||||
@@ -8,21 +8,24 @@ const koaBodyParser = require("koa-bodyparser");
|
|||||||
const koaJwt = require("koa-jwt");
|
const koaJwt = require("koa-jwt");
|
||||||
const jwt = require("jsonwebtoken");
|
const jwt = require("jsonwebtoken");
|
||||||
|
|
||||||
const config = require("./ui/config");
|
const config = require("./config");
|
||||||
const api = require("./ui/api");
|
const api = require("./ui/api");
|
||||||
const Authorizer = require("./common/authorizer");
|
const Authorizer = require("./common/authorizer");
|
||||||
const expression = require("./common/expression");
|
const expression = require("./common/expression");
|
||||||
const logger = require("./logger");
|
const logger = require("./logger");
|
||||||
|
const localCache = require("./local-cache");
|
||||||
|
|
||||||
const koa = new Koa();
|
const koa = new Koa();
|
||||||
const router = new Router();
|
const router = new Router();
|
||||||
|
|
||||||
const JWT_SECRET = config.server.jwtSecret;
|
const JWT_SECRET = config.get("UI_JWT_SECRET");
|
||||||
const JWT_COOKIE = "genieacs-ui-jwt";
|
const JWT_COOKIE = "genieacs-ui-jwt";
|
||||||
|
|
||||||
function getPermissionSets(roles) {
|
function getPermissionSets(ctx) {
|
||||||
const allPermissions = config.permissions;
|
const allPermissions = localCache.getPermissionsConfig(
|
||||||
const permissionSets = roles.map(role => {
|
ctx.state.configSnapshot
|
||||||
|
);
|
||||||
|
const permissionSets = ctx.state.user.roles.map(role => {
|
||||||
return Object.values(allPermissions[role] || {}).map(p => {
|
return Object.values(allPermissions[role] || {}).map(p => {
|
||||||
p = Object.assign({}, p);
|
p = Object.assign({}, p);
|
||||||
for (let [k, v] of Object.entries(p)) {
|
for (let [k, v] of Object.entries(p)) {
|
||||||
@@ -47,8 +50,9 @@ function getPermissionSets(roles) {
|
|||||||
return permissionSets;
|
return permissionSets;
|
||||||
}
|
}
|
||||||
|
|
||||||
function authSimple(username, password) {
|
function authSimple(ctx, username, password) {
|
||||||
const user = config.auth.simple.users[username];
|
const authConfig = localCache.getAuthConfig(ctx.state.configSnapshot);
|
||||||
|
const user = authConfig.simple.users[username];
|
||||||
if (user && user.password === password) {
|
if (user && user.password === password) {
|
||||||
const roles = user.roles.split(",").map(s => s.trim());
|
const roles = user.roles.split(",").map(s => s.trim());
|
||||||
return Promise.resolve(roles);
|
return Promise.resolve(roles);
|
||||||
@@ -60,6 +64,12 @@ koa.on("error", async err => {
|
|||||||
throw err;
|
throw err;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
koa.use(async (ctx, next) => {
|
||||||
|
const configSnapshot = await localCache.getCurrentSnapshot();
|
||||||
|
ctx.state.configSnapshot = configSnapshot;
|
||||||
|
return next();
|
||||||
|
});
|
||||||
|
|
||||||
koa.use(
|
koa.use(
|
||||||
koaJwt({
|
koaJwt({
|
||||||
secret: JWT_SECRET,
|
secret: JWT_SECRET,
|
||||||
@@ -69,18 +79,21 @@ koa.use(
|
|||||||
);
|
);
|
||||||
|
|
||||||
koa.use(async (ctx, next) => {
|
koa.use(async (ctx, next) => {
|
||||||
if (ctx.state.user && ctx.state.user.roles) {
|
if (ctx.state.user && ctx.state.user.roles)
|
||||||
ctx.state.authorizer = new Authorizer(
|
ctx.state.authorizer = new Authorizer(getPermissionSets(ctx));
|
||||||
getPermissionSets(ctx.state.user.roles)
|
else ctx.state.authorizer = new Authorizer([]);
|
||||||
);
|
|
||||||
} else {
|
|
||||||
ctx.state.authorizer = new Authorizer([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return next();
|
return next();
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post("/login", async ctx => {
|
router.post("/login", async ctx => {
|
||||||
|
if (!JWT_SECRET) {
|
||||||
|
ctx.status = 500;
|
||||||
|
ctx.body = "UI_JWT_SECRET is not set";
|
||||||
|
logger.error({ message: "UI_JWT_SECRET is not set" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const username = ctx.request.body.username;
|
const username = ctx.request.body.username;
|
||||||
const password = ctx.request.body.password;
|
const password = ctx.request.body.password;
|
||||||
|
|
||||||
@@ -105,7 +118,7 @@ router.post("/login", async ctx => {
|
|||||||
logger.accessWarn(log);
|
logger.accessWarn(log);
|
||||||
}
|
}
|
||||||
|
|
||||||
const roles = await authSimple(username, password);
|
const roles = await authSimple(ctx, username, password);
|
||||||
|
|
||||||
if (roles) return void success(roles, "simple");
|
if (roles) return void success(roles, "simple");
|
||||||
|
|
||||||
@@ -135,7 +148,7 @@ router.use("/api", api.routes(), api.allowedMethods());
|
|||||||
router.get("/", async ctx => {
|
router.get("/", async ctx => {
|
||||||
let permissionSets = [];
|
let permissionSets = [];
|
||||||
if (ctx.state.user && ctx.state.user.roles)
|
if (ctx.state.user && ctx.state.user.roles)
|
||||||
permissionSets = getPermissionSets(ctx.state.user.roles);
|
permissionSets = getPermissionSets(ctx);
|
||||||
|
|
||||||
ctx.body = `
|
ctx.body = `
|
||||||
<html>
|
<html>
|
||||||
@@ -146,7 +159,9 @@ router.get("/", async ctx => {
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script>
|
<script>
|
||||||
window.clientConfig = ${JSON.stringify(config.getClientConfig())};
|
window.clientConfig = ${JSON.stringify({
|
||||||
|
ui: localCache.getUiConfig(ctx.state.configSnapshot)
|
||||||
|
})};
|
||||||
window.username = ${JSON.stringify(
|
window.username = ${JSON.stringify(
|
||||||
ctx.state.user ? ctx.state.user.username : ""
|
ctx.state.user ? ctx.state.user.username : ""
|
||||||
)};
|
)};
|
||||||
|
|||||||
+19
-9
@@ -4,7 +4,7 @@ const http = require("http");
|
|||||||
const https = require("https");
|
const https = require("https");
|
||||||
const url = require("url");
|
const url = require("url");
|
||||||
|
|
||||||
const config = require("./config");
|
const config = require("../config");
|
||||||
const db = require("./db");
|
const db = require("./db");
|
||||||
const mongodbFunctions = require("./mongodb-functions");
|
const mongodbFunctions = require("./mongodb-functions");
|
||||||
|
|
||||||
@@ -71,7 +71,9 @@ function deleteResource(resource, id) {
|
|||||||
const resourceUrl =
|
const resourceUrl =
|
||||||
resource === "virtualParameters" ? "virtual_parameters" : resource;
|
resource === "virtualParameters" ? "virtual_parameters" : resource;
|
||||||
const options = url.parse(
|
const options = url.parse(
|
||||||
`${config.server.nbi}${resourceUrl}/${encodeURIComponent(id)}`
|
`http://127.0.0.1:${config.get(
|
||||||
|
"NBI_PORT"
|
||||||
|
)}/${resourceUrl}/${encodeURIComponent(id)}`
|
||||||
);
|
);
|
||||||
|
|
||||||
options.method = "DELETE";
|
options.method = "DELETE";
|
||||||
@@ -91,9 +93,9 @@ function deleteResource(resource, id) {
|
|||||||
|
|
||||||
function postTask(task, connectionRequest, callback) {
|
function postTask(task, connectionRequest, callback) {
|
||||||
const options = url.parse(
|
const options = url.parse(
|
||||||
`${config.server.nbi}devices/${encodeURIComponent(task.device)}/tasks${
|
`http://127.0.0.1:${config.get("NBI_PORT")}/devices/${encodeURIComponent(
|
||||||
connectionRequest ? "?connection_request" : ""
|
task.device
|
||||||
}`
|
)}/tasks${connectionRequest ? "?connection_request" : ""}`
|
||||||
);
|
);
|
||||||
options.method = "POST";
|
options.method = "POST";
|
||||||
const _http = options.protocol === "https:" ? https : http;
|
const _http = options.protocol === "https:" ? https : http;
|
||||||
@@ -210,7 +212,9 @@ function updateTags(deviceId, tags) {
|
|||||||
([tag, onOff]) =>
|
([tag, onOff]) =>
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
const options = url.parse(
|
const options = url.parse(
|
||||||
`${config.server.nbi}devices/${encodeURIComponent(
|
`http://127.0.0.1:${config.get(
|
||||||
|
"NBI_PORT"
|
||||||
|
)}/devices/${encodeURIComponent(
|
||||||
deviceId
|
deviceId
|
||||||
)}/tags/${encodeURIComponent(tag)}`
|
)}/tags/${encodeURIComponent(tag)}`
|
||||||
);
|
);
|
||||||
@@ -234,7 +238,9 @@ function updateTags(deviceId, tags) {
|
|||||||
function ping(host) {
|
function ping(host) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const options = url.parse(
|
const options = url.parse(
|
||||||
`${config.server.nbi}ping/${encodeURIComponent(host)}`
|
`http://127.0.0.1:${config.get("NBI_PORT")}/ping/${encodeURIComponent(
|
||||||
|
host
|
||||||
|
)}`
|
||||||
);
|
);
|
||||||
|
|
||||||
const _http = options.protocol === "https:" ? https : http;
|
const _http = options.protocol === "https:" ? https : http;
|
||||||
@@ -294,7 +300,9 @@ function putResource(resource, id, data) {
|
|||||||
const resourceUrl =
|
const resourceUrl =
|
||||||
resource === "virtualParameters" ? "virtual_parameters" : resource;
|
resource === "virtualParameters" ? "virtual_parameters" : resource;
|
||||||
const options = url.parse(
|
const options = url.parse(
|
||||||
`${config.server.nbi}${resourceUrl}/${encodeURIComponent(id)}`
|
`http://127.0.0.1:${config.get(
|
||||||
|
"NBI_PORT"
|
||||||
|
)}/${resourceUrl}/${encodeURIComponent(id)}`
|
||||||
);
|
);
|
||||||
|
|
||||||
options.method = "PUT";
|
options.method = "PUT";
|
||||||
@@ -343,7 +351,9 @@ function putResource(resource, id, data) {
|
|||||||
function putFile(id, metadata, fileStream) {
|
function putFile(id, metadata, fileStream) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const options = url.parse(
|
const options = url.parse(
|
||||||
`${config.server.nbi}files/${encodeURIComponent(id)}`
|
`http://127.0.0.1:${config.get("NBI_PORT")}/files/${encodeURIComponent(
|
||||||
|
id
|
||||||
|
)}`
|
||||||
);
|
);
|
||||||
|
|
||||||
options.method = "PUT";
|
options.method = "PUT";
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
|
|
||||||
const fs = require("fs");
|
|
||||||
const configFile = JSON.parse(fs.readFileSync("./config/config-ui.json"));
|
|
||||||
|
|
||||||
const config = loadConfig(configFile);
|
|
||||||
|
|
||||||
function getClientConfig() {
|
|
||||||
return Object.assign({}, config, {
|
|
||||||
server: null,
|
|
||||||
auth: null,
|
|
||||||
permissions: null
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadConfig(conf, root = {}) {
|
|
||||||
for (const [key, value] of Object.entries(conf)) {
|
|
||||||
const keys = key.split(".");
|
|
||||||
let ref = root;
|
|
||||||
while (keys.length > 1) {
|
|
||||||
const k = keys.shift();
|
|
||||||
if (typeof ref[k] !== "object") ref[k] = {};
|
|
||||||
ref = ref[k];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof value === "object") {
|
|
||||||
if (typeof ref[keys[0]] !== "object") ref[keys[0]] = {};
|
|
||||||
loadConfig(value, ref[keys[0]]);
|
|
||||||
} else {
|
|
||||||
ref[keys[0]] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = Object.assign({}, config, { getClientConfig });
|
|
||||||
+6
-17
@@ -1,7 +1,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const mongodb = require("mongodb");
|
const mongodb = require("mongodb");
|
||||||
const config = require("./config");
|
const config = require("../config");
|
||||||
const mongodbFunctions = require("./mongodb-functions");
|
const mongodbFunctions = require("./mongodb-functions");
|
||||||
const expression = require("../common/expression");
|
const expression = require("../common/expression");
|
||||||
|
|
||||||
@@ -9,24 +9,13 @@ const CACHE_TTL = 300000;
|
|||||||
|
|
||||||
let _clientPromise = null;
|
let _clientPromise = null;
|
||||||
|
|
||||||
const RESOURCE_DB = {
|
|
||||||
devices: "genieacs",
|
|
||||||
faults: "genieacs",
|
|
||||||
tasks: "genieacs",
|
|
||||||
presets: "genieacs",
|
|
||||||
provisions: "genieacs",
|
|
||||||
virtualParameters: "genieacs",
|
|
||||||
files: "genieacs",
|
|
||||||
cache: "genieacs-ui"
|
|
||||||
};
|
|
||||||
|
|
||||||
const RESOURCE_COLLECTION = {
|
const RESOURCE_COLLECTION = {
|
||||||
files: "fs.files"
|
files: "fs.files"
|
||||||
};
|
};
|
||||||
|
|
||||||
function ensureIndexes(client) {
|
function ensureIndexes(client) {
|
||||||
client
|
client
|
||||||
.db(RESOURCE_DB["cache"])
|
.db()
|
||||||
.collection("cache")
|
.collection("cache")
|
||||||
.createIndex({ expire: 1 }, { expireAfterSeconds: 0 });
|
.createIndex({ expire: 1 }, { expireAfterSeconds: 0 });
|
||||||
}
|
}
|
||||||
@@ -34,7 +23,7 @@ function ensureIndexes(client) {
|
|||||||
function getClient() {
|
function getClient() {
|
||||||
if (!_clientPromise) {
|
if (!_clientPromise) {
|
||||||
_clientPromise = new Promise((resolve, reject) => {
|
_clientPromise = new Promise((resolve, reject) => {
|
||||||
const CONNECTION_URL = config.server.mongodbConnectionUrl;
|
const CONNECTION_URL = config.get("MONGODB_CONNECTION_URL");
|
||||||
mongodb.MongoClient.connect(
|
mongodb.MongoClient.connect(
|
||||||
CONNECTION_URL,
|
CONNECTION_URL,
|
||||||
{ useNewUrlParser: true },
|
{ useNewUrlParser: true },
|
||||||
@@ -54,7 +43,7 @@ function cache(key, valueGetter, ttl) {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
getClient()
|
getClient()
|
||||||
.then(client => {
|
.then(client => {
|
||||||
const collection = client.db(RESOURCE_DB["cache"]).collection("cache");
|
const collection = client.db().collection("cache");
|
||||||
collection.findOne({ _id: key }, (err, doc) => {
|
collection.findOne({ _id: key }, (err, doc) => {
|
||||||
if (err) return void reject(err);
|
if (err) return void reject(err);
|
||||||
if (doc != null) return void resolve(JSON.parse(doc.value));
|
if (doc != null) return void resolve(JSON.parse(doc.value));
|
||||||
@@ -103,7 +92,7 @@ function query(resource, filter, options, callback) {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
getClient().then(client => {
|
getClient().then(client => {
|
||||||
const collection = client
|
const collection = client
|
||||||
.db(RESOURCE_DB[resource])
|
.db()
|
||||||
.collection(RESOURCE_COLLECTION[resource] || resource);
|
.collection(RESOURCE_COLLECTION[resource] || resource);
|
||||||
const cursor = collection.find(q);
|
const cursor = collection.find(q);
|
||||||
if (options.projection) {
|
if (options.projection) {
|
||||||
@@ -188,7 +177,7 @@ function count(resource, filter) {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
getClient().then(client => {
|
getClient().then(client => {
|
||||||
const collection = client
|
const collection = client
|
||||||
.db(RESOURCE_DB[resource])
|
.db()
|
||||||
.collection(RESOURCE_COLLECTION[resource] || resource);
|
.collection(RESOURCE_COLLECTION[resource] || resource);
|
||||||
collection.find(q).count((err, c) => {
|
collection.find(q).count((err, c) => {
|
||||||
if (err) reject(err);
|
if (err) reject(err);
|
||||||
|
|||||||
+1
-1
@@ -53,7 +53,7 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"compile": "echo 'Compile step no longer required, skipping.'",
|
"compile": "echo 'Compile step no longer required, skipping.'",
|
||||||
"configure": "if [ ! -f ./config/config.json ]; then cp ./config/config-sample.json ./config/config.json; cp ./config/config-ui-sample.json ./config/config-ui.json; fi",
|
"configure": "if [ ! -f ./config/config.json ]; then cp ./config/config-sample.json ./config/config.json; fi",
|
||||||
"install": "npm run configure",
|
"install": "npm run configure",
|
||||||
"test": "node test",
|
"test": "node test",
|
||||||
"lint": "eslint --fix lib ui build bin/*; prettier --write \"lib/**/*.js\" \"ui/**/*.js\" \"build/**/*.js\" bin/*",
|
"lint": "eslint --fix lib ui build bin/*; prettier --write \"lib/**/*.js\" \"ui/**/*.js\" \"build/**/*.js\" bin/*",
|
||||||
|
|||||||
Executable
+175
@@ -0,0 +1,175 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const mongodb = require("mongodb");
|
||||||
|
const config = require("../lib/config");
|
||||||
|
|
||||||
|
const configData = {
|
||||||
|
"auth.simple.users.admin.password": "'admin'",
|
||||||
|
"auth.simple.users.admin.roles": "'admin'",
|
||||||
|
"auth.simple.users.view.password": "'view'",
|
||||||
|
"auth.simple.users.view.roles": "'view'",
|
||||||
|
"permissions.admin.0.devices.access": "3",
|
||||||
|
"permissions.admin.0.devices.validate.pass": "true",
|
||||||
|
"permissions.admin.0.faults.access": "3",
|
||||||
|
"permissions.admin.0.faults.validate.pass": "true",
|
||||||
|
"permissions.admin.0.files.access": "3",
|
||||||
|
"permissions.admin.0.files.validate.pass": "true",
|
||||||
|
"permissions.admin.0.presets.access": "3",
|
||||||
|
"permissions.admin.0.presets.validate.pass": "true",
|
||||||
|
"permissions.admin.0.provisions.access": "3",
|
||||||
|
"permissions.admin.0.provisions.validate.pass": "true",
|
||||||
|
"permissions.admin.0.virtualParameters.access": "3",
|
||||||
|
"permissions.admin.0.virtualParameters.validate.pass": "true",
|
||||||
|
"permissions.view.0.devices.access": "2",
|
||||||
|
"permissions.view.0.faults.access": "2",
|
||||||
|
"permissions.view.0.files.access": "2",
|
||||||
|
"permissions.view.0.presets.access": "2",
|
||||||
|
"permissions.view.0.provisions.access": "2",
|
||||||
|
"permissions.view.0.virtualParameters.access": "2",
|
||||||
|
"ui.device.0.type": "'tags'",
|
||||||
|
"ui.device.1.type": "'ping'",
|
||||||
|
"ui.device.2.parameters.0.components.0.type": "'parameter'",
|
||||||
|
"ui.device.2.parameters.0.components.1.chart": "'online'",
|
||||||
|
"ui.device.2.parameters.0.components.1.type": "'overview-dot'",
|
||||||
|
"ui.device.2.parameters.0.components.2.parameters.0":
|
||||||
|
"InternetGatewayDevice.DeviceInfo.HardwareVersion",
|
||||||
|
"ui.device.2.parameters.0.components.2.parameters.1":
|
||||||
|
"InternetGatewayDevice.DeviceInfo.SoftwareVersion",
|
||||||
|
"ui.device.2.parameters.0.components.2.parameters.2":
|
||||||
|
"InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANIPConnection.1.MACAddress",
|
||||||
|
"ui.device.2.parameters.0.components.2.parameters.3":
|
||||||
|
"InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANIPConnection.1.ExternalIPAddress",
|
||||||
|
"ui.device.2.parameters.0.components.2.parameters.4":
|
||||||
|
"InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.SSID",
|
||||||
|
"ui.device.2.parameters.0.components.2.parameters.5":
|
||||||
|
"InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.KeyPassphrase",
|
||||||
|
"ui.device.2.parameters.0.components.2.parameters.6":
|
||||||
|
"InternetGatewayDevice.LANDevice.1.Hosts.Host",
|
||||||
|
"ui.device.2.parameters.0.components.2.type": "'summon-button'",
|
||||||
|
"ui.device.2.parameters.0.element": "'span.inform'",
|
||||||
|
"ui.device.2.parameters.0.label": "'Last inform'",
|
||||||
|
"ui.device.2.parameters.0.parameter": "DATE_STRING(Events.Inform)",
|
||||||
|
"ui.device.2.parameters.0.type": "'container'",
|
||||||
|
"ui.device.2.parameters.1.label": "'Serial number'",
|
||||||
|
"ui.device.2.parameters.1.parameter":
|
||||||
|
"InternetGatewayDevice.DeviceInfo.SerialNumber",
|
||||||
|
"ui.device.2.parameters.10.label": "'WLAN passphrase'",
|
||||||
|
"ui.device.2.parameters.10.parameter":
|
||||||
|
"InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.KeyPassphrase",
|
||||||
|
"ui.device.2.parameters.2.label": "'Product class'",
|
||||||
|
"ui.device.2.parameters.2.parameter":
|
||||||
|
"InternetGatewayDevice.DeviceInfo.ProductClass",
|
||||||
|
"ui.device.2.parameters.3.label": "'OUI'",
|
||||||
|
"ui.device.2.parameters.3.parameter":
|
||||||
|
"InternetGatewayDevice.DeviceInfo.ManufacturerOUI",
|
||||||
|
"ui.device.2.parameters.4.label": "'Manufacturer'",
|
||||||
|
"ui.device.2.parameters.4.parameter":
|
||||||
|
"InternetGatewayDevice.DeviceInfo.Manufacturer",
|
||||||
|
"ui.device.2.parameters.5.label": "'Hardware version'",
|
||||||
|
"ui.device.2.parameters.5.parameter":
|
||||||
|
"InternetGatewayDevice.DeviceInfo.HardwareVersion",
|
||||||
|
"ui.device.2.parameters.6.label": "'Software version'",
|
||||||
|
"ui.device.2.parameters.6.parameter":
|
||||||
|
"InternetGatewayDevice.DeviceInfo.SoftwareVersion",
|
||||||
|
"ui.device.2.parameters.7.label": "'MAC'",
|
||||||
|
"ui.device.2.parameters.7.parameter":
|
||||||
|
"InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANIPConnection.1.MACAddress",
|
||||||
|
"ui.device.2.parameters.8.label": "'IP'",
|
||||||
|
"ui.device.2.parameters.8.parameter":
|
||||||
|
"InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANIPConnection.1.ExternalIPAddress",
|
||||||
|
"ui.device.2.parameters.9.label": "'WLAN SSID'",
|
||||||
|
"ui.device.2.parameters.9.parameter":
|
||||||
|
"InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.SSID",
|
||||||
|
"ui.device.2.type": "'parameter-list'",
|
||||||
|
"ui.device.3.childParameters.0.label": "'Host name'",
|
||||||
|
"ui.device.3.childParameters.0.parameter": "HostName",
|
||||||
|
"ui.device.3.childParameters.1.label": "'IP address'",
|
||||||
|
"ui.device.3.childParameters.1.parameter": "IPAddress",
|
||||||
|
"ui.device.3.childParameters.2.label": "'MAC address'",
|
||||||
|
"ui.device.3.childParameters.2.parameter": "MACAddress",
|
||||||
|
"ui.device.3.label": "'WLAN hosts'",
|
||||||
|
"ui.device.3.parameter": "InternetGatewayDevice.LANDevice.1.Hosts.Host",
|
||||||
|
"ui.device.3.type": "'parameter-table'",
|
||||||
|
"ui.device.4.components.0.components.0": "'Faults'",
|
||||||
|
"ui.device.4.components.0.element": "'h3'",
|
||||||
|
"ui.device.4.components.0.type": "'container'",
|
||||||
|
"ui.device.4.components.1.type": "'device-faults'",
|
||||||
|
"ui.device.4.element": "'div'",
|
||||||
|
"ui.device.4.type": "'container'",
|
||||||
|
"ui.device.5.components.0.components.0": "'All parameters'",
|
||||||
|
"ui.device.5.components.0.element": "'h3'",
|
||||||
|
"ui.device.5.components.0.type": "'container'",
|
||||||
|
"ui.device.5.components.1.type": "'all-parameters'",
|
||||||
|
"ui.device.5.element": "'div.container-full-width'",
|
||||||
|
"ui.device.5.type": "'container'",
|
||||||
|
"ui.device.6.type": "'device-actions'",
|
||||||
|
"ui.filters.0.label": "'Serial number'",
|
||||||
|
"ui.filters.0.parameter": "DeviceID.SerialNumber",
|
||||||
|
"ui.filters.0.type": "'string'",
|
||||||
|
"ui.filters.1.label": "'Product class'",
|
||||||
|
"ui.filters.1.parameter": "DeviceID.ProductClass",
|
||||||
|
"ui.filters.1.type": "'string'",
|
||||||
|
"ui.filters.2.label": "'Tag'",
|
||||||
|
"ui.filters.2.parameter": "tag",
|
||||||
|
"ui.filters.2.type": "'string'",
|
||||||
|
"ui.index.0.components.0.type": "'parameter'",
|
||||||
|
"ui.index.0.label": "'Serial number'",
|
||||||
|
"ui.index.0.parameter": "DeviceID.SerialNumber",
|
||||||
|
"ui.index.0.type": "'device-link'",
|
||||||
|
"ui.index.1.label": "'Product class'",
|
||||||
|
"ui.index.1.parameter": "DeviceID.ProductClass",
|
||||||
|
"ui.index.2.label": "'Software version'",
|
||||||
|
"ui.index.2.parameter": "InternetGatewayDevice.DeviceInfo.SoftwareVersion",
|
||||||
|
"ui.index.3.label": "'IP'",
|
||||||
|
"ui.index.3.parameter":
|
||||||
|
"InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANIPConnection.1.ExternalIPAddress",
|
||||||
|
"ui.index.4.label": "'SSID'",
|
||||||
|
"ui.index.4.parameter":
|
||||||
|
"InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.SSID",
|
||||||
|
"ui.index.5.components.0.type": "'parameter'",
|
||||||
|
"ui.index.5.components.1.chart": "'online'",
|
||||||
|
"ui.index.5.components.1.type": "'overview-dot'",
|
||||||
|
"ui.index.5.element": "'span.inform'",
|
||||||
|
"ui.index.5.label": "'Last inform'",
|
||||||
|
"ui.index.5.parameter": "DATE_STRING(Events.Inform)",
|
||||||
|
"ui.index.5.type": "'container'",
|
||||||
|
"ui.index.6.label": "'Tags'",
|
||||||
|
"ui.index.6.parameter": "Tags",
|
||||||
|
"ui.index.6.type": "'tags'",
|
||||||
|
"ui.index.6.unsortable": "true",
|
||||||
|
"ui.index.6.writable": "false",
|
||||||
|
"ui.overview.charts.online.label": "'Online status'",
|
||||||
|
"ui.overview.charts.online.slices.1_onlineNow.color": "'#31a354'",
|
||||||
|
"ui.overview.charts.online.slices.1_onlineNow.filter":
|
||||||
|
"Events.Inform > NOW() - 5 * 60 * 1000",
|
||||||
|
"ui.overview.charts.online.slices.1_onlineNow.label": "'Online now'",
|
||||||
|
"ui.overview.charts.online.slices.2_past24.color": "'#addd8e'",
|
||||||
|
"ui.overview.charts.online.slices.2_past24.filter":
|
||||||
|
"Events.Inform > (NOW() - 5 * 60 * 1000) - (24 * 60 * 60 * 1000) AND Events.Inform < (NOW() - 5 * 60 * 1000)",
|
||||||
|
"ui.overview.charts.online.slices.2_past24.label": "'Past 24 hours'",
|
||||||
|
"ui.overview.charts.online.slices.3_others.color": "'#f7fcb9'",
|
||||||
|
"ui.overview.charts.online.slices.3_others.filter":
|
||||||
|
"Events.Inform < (NOW() - 5 * 60 * 1000) - (24 * 60 * 60 * 1000)",
|
||||||
|
"ui.overview.charts.online.slices.3_others.label": "'Others'",
|
||||||
|
"ui.overview.groups.online.charts.0": "'online'",
|
||||||
|
"ui.overview.groups.online.label": "''",
|
||||||
|
"ui.pageSize": "10"
|
||||||
|
};
|
||||||
|
|
||||||
|
async function run() {
|
||||||
|
const client = await mongodb.MongoClient.connect(
|
||||||
|
config.get("MONGODB_CONNECTION_URL"),
|
||||||
|
{ useNewUrlParser: true }
|
||||||
|
);
|
||||||
|
const collection = client.db().collection("config");
|
||||||
|
await collection.deleteMany({});
|
||||||
|
const objs = Object.entries(configData).map(c => ({
|
||||||
|
_id: c[0],
|
||||||
|
value: c[1]
|
||||||
|
}));
|
||||||
|
await collection.insertMany(objs);
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
run();
|
||||||
@@ -4,6 +4,10 @@ import m from "mithril";
|
|||||||
import * as components from "../components";
|
import * as components from "../components";
|
||||||
import * as taskQueue from "../task-queue";
|
import * as taskQueue from "../task-queue";
|
||||||
import longTextComponent from "../long-text-component";
|
import longTextComponent from "../long-text-component";
|
||||||
|
import * as expression from "../../lib/common/expression";
|
||||||
|
import memoize from "../../lib/common/memoize";
|
||||||
|
|
||||||
|
const memoizedParse = memoize(expression.parse);
|
||||||
|
|
||||||
function escapeRegExp(str) {
|
function escapeRegExp(str) {
|
||||||
return str.replace(/[-[\]/{}()*+?.\\^$|]/g, "\\$&");
|
return str.replace(/[-[\]/{}()*+?.\\^$|]/g, "\\$&");
|
||||||
@@ -47,7 +51,7 @@ const component = {
|
|||||||
val.push(
|
val.push(
|
||||||
m(
|
m(
|
||||||
components.get("parameter"),
|
components.get("parameter"),
|
||||||
Object.assign({ device: device, parameter: k })
|
Object.assign({ device: device, parameter: memoizedParse(k) })
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
} else if (p.object && p.writable) {
|
} else if (p.object && p.writable) {
|
||||||
|
|||||||
@@ -3,16 +3,12 @@
|
|||||||
import m from "mithril";
|
import m from "mithril";
|
||||||
import * as components from "../components";
|
import * as components from "../components";
|
||||||
import * as store from "../store";
|
import * as store from "../store";
|
||||||
import * as expression from "../../lib/common/expression";
|
|
||||||
import memoize from "../../lib/common/memoize";
|
|
||||||
|
|
||||||
const memoizedParse = memoize(expression.parse);
|
|
||||||
|
|
||||||
const component = {
|
const component = {
|
||||||
view: vnode => {
|
view: vnode => {
|
||||||
if (vnode.attrs.filter) {
|
if (vnode.attrs.filter) {
|
||||||
const filter = memoizedParse(vnode.attrs.filter);
|
if (!store.evaluateExpression(vnode.attrs.filter, vnode.attrs.device))
|
||||||
if (!store.evaluateExpression(filter, vnode.attrs.device)) return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const children = Object.values(vnode.attrs.components).map(c => {
|
const children = Object.values(vnode.attrs.components).map(c => {
|
||||||
|
|||||||
@@ -3,10 +3,6 @@
|
|||||||
import m from "mithril";
|
import m from "mithril";
|
||||||
import config from "../config";
|
import config from "../config";
|
||||||
import * as store from "../store";
|
import * as store from "../store";
|
||||||
import * as expression from "../../lib/common/expression";
|
|
||||||
import memoize from "../../lib/common/memoize";
|
|
||||||
|
|
||||||
const memoizedParse = memoize(expression.parse);
|
|
||||||
|
|
||||||
const CHARTS = config.ui.overview.charts;
|
const CHARTS = config.ui.overview.charts;
|
||||||
|
|
||||||
@@ -15,7 +11,7 @@ const component = {
|
|||||||
const device = vnode.attrs.device;
|
const device = vnode.attrs.device;
|
||||||
const chart = CHARTS[vnode.attrs.chart];
|
const chart = CHARTS[vnode.attrs.chart];
|
||||||
for (const slice of Object.values(chart.slices)) {
|
for (const slice of Object.values(chart.slices)) {
|
||||||
const filter = memoizedParse(slice.filter);
|
const filter = slice.filter;
|
||||||
if (store.evaluateExpression(filter, device)) {
|
if (store.evaluateExpression(filter, device)) {
|
||||||
const dot = m(
|
const dot = m(
|
||||||
"svg",
|
"svg",
|
||||||
|
|||||||
@@ -4,25 +4,15 @@ import m from "mithril";
|
|||||||
import * as components from "../components";
|
import * as components from "../components";
|
||||||
import * as taskQueue from "../task-queue";
|
import * as taskQueue from "../task-queue";
|
||||||
import * as store from "../store";
|
import * as store from "../store";
|
||||||
import * as expression from "../../lib/common/expression";
|
|
||||||
import * as expressionParser from "../../lib/common/expression-parser";
|
import * as expressionParser from "../../lib/common/expression-parser";
|
||||||
import memoize from "../../lib/common/memoize";
|
|
||||||
|
|
||||||
const memoizeParse = memoize(expression.parse);
|
|
||||||
|
|
||||||
const component = {
|
const component = {
|
||||||
oninit: vnode => {
|
oninit: vnode => {
|
||||||
const obj = expression.parse(vnode.attrs.parameter);
|
const obj = vnode.attrs.parameter;
|
||||||
if (!Array.isArray(obj) || !obj[0] === "PARAM")
|
if (!Array.isArray(obj) || !obj[0] === "PARAM")
|
||||||
throw new Error("Object must be a parameter path");
|
throw new Error("Object must be a parameter path");
|
||||||
vnode.state.object = obj[1];
|
vnode.state.object = obj[1];
|
||||||
vnode.state.parameters = Object.values(vnode.attrs.childParameters).map(
|
vnode.state.parameters = Object.values(vnode.attrs.childParameters);
|
||||||
parameter => {
|
|
||||||
return Object.assign({}, parameter, {
|
|
||||||
parameter: expression.parse(parameter.parameter)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
view: vnode => {
|
view: vnode => {
|
||||||
const device = vnode.attrs.device;
|
const device = vnode.attrs.device;
|
||||||
@@ -47,8 +37,7 @@ const component = {
|
|||||||
|
|
||||||
const rows = [];
|
const rows = [];
|
||||||
for (const i of instances) {
|
for (const i of instances) {
|
||||||
let filter =
|
let filter = vnode.attrs.filter != null ? vnode.attrs.filter : true;
|
||||||
vnode.attrs.filter != null ? memoizeParse(vnode.attrs.filter) : true;
|
|
||||||
|
|
||||||
filter = expressionParser.map(filter, e => {
|
filter = expressionParser.map(filter, e => {
|
||||||
if (Array.isArray(e) && e[0] === "PARAM")
|
if (Array.isArray(e) && e[0] === "PARAM")
|
||||||
@@ -70,7 +59,7 @@ const component = {
|
|||||||
components.get(p.type || "parameter"),
|
components.get(p.type || "parameter"),
|
||||||
Object.assign({}, p, {
|
Object.assign({}, p, {
|
||||||
device: device,
|
device: device,
|
||||||
parameter: expressionParser.stringify(param),
|
parameter: param,
|
||||||
label: ""
|
label: ""
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,12 +8,10 @@ import memoize from "../../lib/common/memoize";
|
|||||||
import timeAgo from "../timeago";
|
import timeAgo from "../timeago";
|
||||||
import longTextComponent from "../long-text-component";
|
import longTextComponent from "../long-text-component";
|
||||||
|
|
||||||
const memoizedParse = memoize(expression.parse);
|
|
||||||
|
|
||||||
const evaluateParam = memoize((exp, obj, now) => {
|
const evaluateParam = memoize((exp, obj, now) => {
|
||||||
let timestamp = now;
|
let timestamp = now;
|
||||||
const params = new Set();
|
const params = new Set();
|
||||||
const value = expression.evaluate(memoizedParse(exp), obj, now, e => {
|
const value = expression.evaluate(exp, obj, now, e => {
|
||||||
if (Array.isArray(e)) {
|
if (Array.isArray(e)) {
|
||||||
if (e[0] === "PARAM") {
|
if (e[0] === "PARAM") {
|
||||||
params.add(e[1]);
|
params.add(e[1]);
|
||||||
|
|||||||
@@ -4,10 +4,6 @@ import m from "mithril";
|
|||||||
import * as taskQueue from "../task-queue";
|
import * as taskQueue from "../task-queue";
|
||||||
import * as store from "../store";
|
import * as store from "../store";
|
||||||
import * as notifications from "../notifications";
|
import * as notifications from "../notifications";
|
||||||
import * as expression from "../../lib/common/expression";
|
|
||||||
import memoize from "../../lib/common/memoize";
|
|
||||||
|
|
||||||
const memoizedParse = memoize(expression.parse);
|
|
||||||
|
|
||||||
const component = {
|
const component = {
|
||||||
view: vnode => {
|
view: vnode => {
|
||||||
@@ -20,8 +16,7 @@ const component = {
|
|||||||
onclick: e => {
|
onclick: e => {
|
||||||
e.target.disabled = true;
|
e.target.disabled = true;
|
||||||
const params = Object.values(vnode.attrs.parameters)
|
const params = Object.values(vnode.attrs.parameters)
|
||||||
.map(p => {
|
.map(exp => {
|
||||||
const exp = memoizedParse(p);
|
|
||||||
if (!Array.isArray(exp) || !exp[0] === "PARAM") return null;
|
if (!Array.isArray(exp) || !exp[0] === "PARAM") return null;
|
||||||
return store.evaluateExpression(exp[1], device);
|
return store.evaluateExpression(exp[1], device);
|
||||||
})
|
})
|
||||||
|
|||||||
+4
-3
@@ -17,8 +17,8 @@ const PAGE_SIZE = config.ui.pageSize || 10;
|
|||||||
|
|
||||||
const memoizedParse = memoize(expression.parse);
|
const memoizedParse = memoize(expression.parse);
|
||||||
const memoizedJsonParse = memoize(JSON.parse);
|
const memoizedJsonParse = memoize(JSON.parse);
|
||||||
const memoizedGetSortable = memoize(str => {
|
const memoizedGetSortable = memoize(p => {
|
||||||
const expressionParams = expression.extractParams(expression.parse(str));
|
const expressionParams = expression.extractParams(p);
|
||||||
if (expressionParams.length === 1) {
|
if (expressionParams.length === 1) {
|
||||||
const param = expression.evaluate(expressionParams[0]);
|
const param = expression.evaluate(expressionParams[0]);
|
||||||
if (typeof param === "string") return param;
|
if (typeof param === "string") return param;
|
||||||
@@ -28,7 +28,8 @@ const memoizedGetSortable = memoize(str => {
|
|||||||
|
|
||||||
const getDownloadUrl = memoize((filter, indexParameters) => {
|
const getDownloadUrl = memoize((filter, indexParameters) => {
|
||||||
const columns = {};
|
const columns = {};
|
||||||
for (const p of indexParameters) columns[p.label] = p.parameter;
|
for (const p of indexParameters)
|
||||||
|
columns[p.label] = expression.stringify(p.parameter);
|
||||||
return `/api/devices.csv?${m.buildQueryString({
|
return `/api/devices.csv?${m.buildQueryString({
|
||||||
filter: filter,
|
filter: filter,
|
||||||
columns: JSON.stringify(columns)
|
columns: JSON.stringify(columns)
|
||||||
|
|||||||
+1
-5
@@ -4,10 +4,6 @@ import m from "mithril";
|
|||||||
import config from "./config";
|
import config from "./config";
|
||||||
import * as store from "./store";
|
import * as store from "./store";
|
||||||
import pieChartComponent from "./pie-chart-component";
|
import pieChartComponent from "./pie-chart-component";
|
||||||
import * as expression from "../lib/common/expression";
|
|
||||||
import memoize from "../lib/common/memoize";
|
|
||||||
|
|
||||||
const memoizedParse = memoize(expression.parse);
|
|
||||||
|
|
||||||
const GROUPS = config.ui.overview.groups;
|
const GROUPS = config.ui.overview.groups;
|
||||||
const CHARTS = {};
|
const CHARTS = {};
|
||||||
@@ -22,7 +18,7 @@ function queryCharts(charts) {
|
|||||||
charts[chartName] = chart = Object.assign({}, chart);
|
charts[chartName] = chart = Object.assign({}, chart);
|
||||||
chart.slices = Object.assign({}, chart.slices);
|
chart.slices = Object.assign({}, chart.slices);
|
||||||
for (let [sliceName, slice] of Object.entries(chart.slices)) {
|
for (let [sliceName, slice] of Object.entries(chart.slices)) {
|
||||||
const filter = memoizedParse(slice.filter);
|
const filter = slice.filter;
|
||||||
chart.slices[sliceName] = slice = Object.assign({}, slice);
|
chart.slices[sliceName] = slice = Object.assign({}, slice);
|
||||||
slice.count = store.count("devices", filter);
|
slice.count = store.count("devices", filter);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import m from "mithril";
|
import m from "mithril";
|
||||||
|
import * as expression from "../lib/common/expression";
|
||||||
|
import memoize from "../lib/common/memoize";
|
||||||
|
|
||||||
|
const memoizedStringify = memoize(expression.stringify);
|
||||||
|
|
||||||
const drawChart = function(chartData) {
|
const drawChart = function(chartData) {
|
||||||
const slices = chartData.slices;
|
const slices = chartData.slices;
|
||||||
@@ -28,7 +32,7 @@ const drawChart = function(chartData) {
|
|||||||
"a",
|
"a",
|
||||||
{
|
{
|
||||||
href: `/#!/devices/?${m.buildQueryString({
|
href: `/#!/devices/?${m.buildQueryString({
|
||||||
filter: slice.filter
|
filter: memoizedStringify(slice.filter)
|
||||||
})}`
|
})}`
|
||||||
},
|
},
|
||||||
slice.count.value || 0
|
slice.count.value || 0
|
||||||
@@ -68,7 +72,7 @@ const drawChart = function(chartData) {
|
|||||||
"a",
|
"a",
|
||||||
{
|
{
|
||||||
"xlink:href": `/#!/devices/?${m.buildQueryString({
|
"xlink:href": `/#!/devices/?${m.buildQueryString({
|
||||||
filter: slice.filter
|
filter: memoizedStringify(slice.filter)
|
||||||
})}`
|
})}`
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
|
|||||||
+1
-2
@@ -1,7 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import config from "./config";
|
import config from "./config";
|
||||||
import * as expression from "../lib/common/expression";
|
|
||||||
|
|
||||||
const resources = {
|
const resources = {
|
||||||
devices: {},
|
devices: {},
|
||||||
@@ -37,7 +36,7 @@ const resources = {
|
|||||||
|
|
||||||
for (const v of Object.values(config.ui.filters)) {
|
for (const v of Object.values(config.ui.filters)) {
|
||||||
resources.devices[v.label] = {
|
resources.devices[v.label] = {
|
||||||
parameter: expression.parse(v.parameter),
|
parameter: v.parameter,
|
||||||
type: (v.type || "").split(",").map(s => s.trim())
|
type: (v.type || "").split(",").map(s => s.trim())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user