Database initialization wizard
This commit is contained in:
1 parent
b51c97e97a
commit
6cb0d0449b
10 files changed
+613
-19
No files matched your search
@@ -65,12 +65,9 @@ This serves the web based user interface. It listens on port 3000 by default.
|
||||
The argument *--ui-jwt-secret* supplies the key used for signing browser
|
||||
cookies.
|
||||
|
||||
The UI has plenty of configuration options. To populate the an initial sample
|
||||
configuration, run:
|
||||
|
||||
./dist/tools/configure-ui
|
||||
|
||||
Use admin/admin credentials to log in.
|
||||
The UI has plenty of configuration options. When you open GenieACS's UI in a
|
||||
browser you'll be greeted with a database initialization wizard to help you
|
||||
populate some initial configuration.
|
||||
|
||||
## Support
|
||||
|
||||
|
||||
+1
-1
@@ -169,7 +169,7 @@ async function generateCss(): Promise<void> {
|
||||
}
|
||||
|
||||
async function generateToolsJs(): Promise<void> {
|
||||
for (const bin of ["configure-ui", "dump-data-model"]) {
|
||||
for (const bin of ["dump-data-model"]) {
|
||||
const inputFile = path.resolve(INPUT_DIR, `tools/${bin}`);
|
||||
const outputFile = path.resolve(OUTPUT_DIR, `tools/${bin}`);
|
||||
const bundle = await rollup({
|
||||
|
||||
+425
@@ -0,0 +1,425 @@
|
||||
/**
|
||||
* Copyright 2013-2019 GenieACS Inc.
|
||||
*
|
||||
* This file is part of GenieACS.
|
||||
*
|
||||
* GenieACS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* GenieACS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with GenieACS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import * as localCache from "./local-cache";
|
||||
import { generateSalt, hashPassword } from "./auth";
|
||||
import * as db from "./ui/db";
|
||||
import { del } from "./cache";
|
||||
|
||||
interface Status {
|
||||
users: boolean;
|
||||
presets: boolean;
|
||||
filters: boolean;
|
||||
device: boolean;
|
||||
index: boolean;
|
||||
overview: boolean;
|
||||
}
|
||||
|
||||
const BOOTSTRAP_SCRIPT = `
|
||||
const now = Date.now();
|
||||
|
||||
// Clear cached data model to force a refresh
|
||||
clear("Device", now);
|
||||
clear("InternetGatewayDevice", now);
|
||||
`.trim();
|
||||
|
||||
const DEFAULT_SCRIPT = `
|
||||
const hourly = Date.now(3600000);
|
||||
|
||||
// Refresh basic parameters hourly
|
||||
declare("InternetGatewayDevice.DeviceInfo.HardwareVersion", {path: hourly, value: hourly});
|
||||
declare("InternetGatewayDevice.DeviceInfo.SoftwareVersion", {path: hourly, value: hourly});
|
||||
declare("InternetGatewayDevice.WANDevice.*.WANConnectionDevice.*.WANIPConnection.*.MACAddress", {path: hourly, value: hourly});
|
||||
declare("InternetGatewayDevice.WANDevice.*.WANConnectionDevice.*.WANIPConnection.*.ExternalIPAddress", {path: hourly, value: hourly});
|
||||
declare("InternetGatewayDevice.LANDevice.*.WLANConfiguration.*.SSID", {path: hourly, value: hourly});
|
||||
// Don't refresh password field periodically because CPEs always report blank passowrds for security reasons
|
||||
declare("InternetGatewayDevice.LANDevice.*.WLANConfiguration.*.KeyPassphrase", {path: hourly, value: 1});
|
||||
declare("InternetGatewayDevice.LANDevice.*.Hosts.Host.*.HostName", {path: hourly, value: hourly});
|
||||
declare("InternetGatewayDevice.LANDevice.*.Hosts.Host.*.IPAddress", {path: hourly, value: hourly});
|
||||
declare("InternetGatewayDevice.LANDevice.*.Hosts.Host.*.MACAddress", {path: hourly, value: hourly});
|
||||
`.trim();
|
||||
|
||||
const INFORM_SCRIPT = `
|
||||
// Device ID as user name
|
||||
const username = declare("DeviceID.ID", {value: 1}).value[0]
|
||||
|
||||
// Password will be fixed a given device because Math.random() is seeded with devcie ID by default.
|
||||
const password = "" + Math.random();
|
||||
|
||||
const informInterval = 300;
|
||||
|
||||
// Refresh values daily
|
||||
const daily = Date.now(86400000);
|
||||
|
||||
// Unique inform offset per device for better load distribution
|
||||
const informTime = daily % 86400000;
|
||||
|
||||
declare("InternetGatewayDevice.ManagementServer.ConnectionRequestUsername", {value: daily}, {value: username});
|
||||
declare("InternetGatewayDevice.ManagementServer.ConnectionRequestPassword", {value: daily}, {value: password});
|
||||
declare("InternetGatewayDevice.ManagementServer.PeriodicInformEnable", {value: daily}, {value: true});
|
||||
declare("InternetGatewayDevice.ManagementServer.PeriodicInformInterval", {value: daily}, {value: informInterval});
|
||||
declare("InternetGatewayDevice.ManagementServer.PeriodicInformTime", {value: daily}, {value: informTime});
|
||||
|
||||
declare("Device.ManagementServer.ConnectionRequestUsername", {value: daily}, {value: username});
|
||||
declare("Device.ManagementServer.ConnectionRequestPassword", {value: daily}, {value: password});
|
||||
declare("Device.ManagementServer.PeriodicInformEnable", {value: daily}, {value: true});
|
||||
declare("Device.ManagementServer.PeriodicInformInterval", {value: daily}, {value: informInterval});
|
||||
declare("Device.ManagementServer.PeriodicInformTime", {value: daily}, {value: informTime});
|
||||
`.trim();
|
||||
|
||||
export async function getStatus(): Promise<Status> {
|
||||
const configSnapshot = await localCache.getCurrentSnapshot();
|
||||
const users = localCache.getUsers(configSnapshot);
|
||||
const presets = localCache.getPresets(configSnapshot);
|
||||
const ui = localCache.getUiConfig(configSnapshot);
|
||||
|
||||
return {
|
||||
users: !Object.keys(users).length,
|
||||
presets: !presets.length,
|
||||
filters: !Object.keys(ui["filters"]).length,
|
||||
device: !Object.keys(ui["device"]).length,
|
||||
index: !Object.keys(ui["index"]).length,
|
||||
overview: !Object.keys(ui["overview"]).length
|
||||
};
|
||||
}
|
||||
|
||||
export async function seed(options): Promise<void> {
|
||||
const resources = {};
|
||||
const proms = [];
|
||||
|
||||
if (options.users) {
|
||||
resources["permissions"] = [
|
||||
{ role: "admin", resource: "devices", access: 3, validate: "true" },
|
||||
{ role: "admin", resource: "faults", access: 3, validate: "true" },
|
||||
{ role: "admin", resource: "files", access: 3, validate: "true" },
|
||||
{ role: "admin", resource: "presets", access: 3, validate: "true" },
|
||||
{ role: "admin", resource: "provisions", access: 3, validate: "true" },
|
||||
{ role: "admin", resource: "config", access: 3, validate: "true" },
|
||||
{ role: "admin", resource: "permissions", access: 3, validate: "true" },
|
||||
{ role: "admin", resource: "users", access: 3, validate: "true" },
|
||||
{
|
||||
role: "admin",
|
||||
resource: "virtualParameters",
|
||||
access: 3,
|
||||
validate: "true"
|
||||
}
|
||||
];
|
||||
|
||||
resources["users"] = [
|
||||
{ username: "admin", password: "admin", roles: ["admin"] }
|
||||
];
|
||||
}
|
||||
|
||||
if (options.filters) {
|
||||
resources["config"] = (resources["config"] || []).concat([
|
||||
{ _id: "ui.filters.0.label", value: "'Serial number'" },
|
||||
{ _id: "ui.filters.0.parameter", value: "DeviceID.SerialNumber" },
|
||||
{ _id: "ui.filters.0.type", value: "'string'" },
|
||||
{ _id: "ui.filters.1.label", value: "'Product class'" },
|
||||
{ _id: "ui.filters.1.parameter", value: "DeviceID.ProductClass" },
|
||||
{ _id: "ui.filters.1.type", value: "'string'" },
|
||||
{ _id: "ui.filters.2.label", value: "'Tag'" },
|
||||
{ _id: "ui.filters.2.parameter", value: "tag" },
|
||||
{ _id: "ui.filters.2.type", value: "'string'" }
|
||||
]);
|
||||
}
|
||||
|
||||
if (options.device) {
|
||||
resources["config"] = (resources["config"] || []).concat([
|
||||
{ _id: "ui.device.0.type", value: "'tags'" },
|
||||
{ _id: "ui.device.1.type", value: "'ping'" },
|
||||
{ _id: "ui.device.2.type", value: "'parameter-list'" },
|
||||
{ _id: "ui.device.2.parameters.0.type", value: "'container'" },
|
||||
{ _id: "ui.device.2.parameters.0.element", value: "'span.inform'" },
|
||||
{ _id: "ui.device.2.parameters.0.label", value: "'Last inform'" },
|
||||
{
|
||||
_id: "ui.device.2.parameters.0.components.0.type",
|
||||
value: "'parameter'"
|
||||
},
|
||||
{ _id: "ui.device.2.parameters.0.components.1.chart", value: "'online'" },
|
||||
{
|
||||
_id: "ui.device.2.parameters.0.components.1.type",
|
||||
value: "'overview-dot'"
|
||||
},
|
||||
{
|
||||
_id: "ui.device.2.parameters.0.components.2.type",
|
||||
value: "'summon-button'"
|
||||
},
|
||||
{
|
||||
_id: "ui.device.2.parameters.0.components.2.parameters.0",
|
||||
value: "InternetGatewayDevice.DeviceInfo.HardwareVersion"
|
||||
},
|
||||
{
|
||||
_id: "ui.device.2.parameters.0.components.2.parameters.1",
|
||||
value: "InternetGatewayDevice.DeviceInfo.SoftwareVersion"
|
||||
},
|
||||
{
|
||||
_id: "ui.device.2.parameters.0.components.2.parameters.2",
|
||||
value:
|
||||
"InternetGatewayDevice.WANDevice.*.WANConnectionDevice.*.WANIPConnection.*.MACAddress"
|
||||
},
|
||||
{
|
||||
_id: "ui.device.2.parameters.0.components.2.parameters.3",
|
||||
value:
|
||||
"InternetGatewayDevice.WANDevice.*.WANConnectionDevice.*.WANIPConnection.*.ExternalIPAddress"
|
||||
},
|
||||
{
|
||||
_id: "ui.device.2.parameters.0.components.2.parameters.4",
|
||||
value: "InternetGatewayDevice.LANDevice.*.WLANConfiguration.*.SSID"
|
||||
},
|
||||
{
|
||||
_id: "ui.device.2.parameters.0.components.2.parameters.5",
|
||||
value:
|
||||
"InternetGatewayDevice.LANDevice.*.WLANConfiguration.*.KeyPassphrase"
|
||||
},
|
||||
{
|
||||
_id: "ui.device.2.parameters.0.components.2.parameters.6",
|
||||
value: "InternetGatewayDevice.LANDevice.*.Hosts.Host.*.HostName"
|
||||
},
|
||||
{
|
||||
_id: "ui.device.2.parameters.0.components.2.parameters.7",
|
||||
value: "InternetGatewayDevice.LANDevice.*.Hosts.Host.*.IPAddress"
|
||||
},
|
||||
{
|
||||
_id: "ui.device.2.parameters.0.components.2.parameters.8",
|
||||
value: "InternetGatewayDevice.LANDevice.*.Hosts.Host.*.MACAddress"
|
||||
},
|
||||
{
|
||||
_id: "ui.device.2.parameters.0.parameter",
|
||||
value: "DATE_STRING(Events.Inform)"
|
||||
},
|
||||
{ _id: "ui.device.2.parameters.1.label", value: "'Serial number'" },
|
||||
{
|
||||
_id: "ui.device.2.parameters.1.parameter",
|
||||
value: "DeviceID.SerialNumber"
|
||||
},
|
||||
{ _id: "ui.device.2.parameters.2.label", value: "'Product class'" },
|
||||
{
|
||||
_id: "ui.device.2.parameters.2.parameter",
|
||||
value: "DeviceID.ProductClass"
|
||||
},
|
||||
{ _id: "ui.device.2.parameters.3.label", value: "'OUI'" },
|
||||
{
|
||||
_id: "ui.device.2.parameters.3.parameter",
|
||||
value: "DeviceID.OUI"
|
||||
},
|
||||
{ _id: "ui.device.2.parameters.4.label", value: "'Manufacturer'" },
|
||||
{
|
||||
_id: "ui.device.2.parameters.4.parameter",
|
||||
value: "DeviceID.Manufacturer"
|
||||
},
|
||||
{ _id: "ui.device.2.parameters.5.label", value: "'Hardware version'" },
|
||||
{
|
||||
_id: "ui.device.2.parameters.5.parameter",
|
||||
value: "InternetGatewayDevice.DeviceInfo.HardwareVersion"
|
||||
},
|
||||
{ _id: "ui.device.2.parameters.6.label", value: "'Software version'" },
|
||||
{
|
||||
_id: "ui.device.2.parameters.6.parameter",
|
||||
value: "InternetGatewayDevice.DeviceInfo.SoftwareVersion"
|
||||
},
|
||||
{ _id: "ui.device.2.parameters.7.label", value: "'MAC'" },
|
||||
{
|
||||
_id: "ui.device.2.parameters.7.parameter",
|
||||
value:
|
||||
"InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANIPConnection.1.MACAddress"
|
||||
},
|
||||
{ _id: "ui.device.2.parameters.8.label", value: "'IP'" },
|
||||
{
|
||||
_id: "ui.device.2.parameters.8.parameter",
|
||||
value:
|
||||
"InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANIPConnection.1.ExternalIPAddress"
|
||||
},
|
||||
{ _id: "ui.device.2.parameters.9.label", value: "'WLAN SSID'" },
|
||||
{
|
||||
_id: "ui.device.2.parameters.9.parameter",
|
||||
value: "InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.SSID"
|
||||
},
|
||||
{ _id: "ui.device.2.parameters.10.label", value: "'WLAN passphrase'" },
|
||||
{
|
||||
_id: "ui.device.2.parameters.10.parameter",
|
||||
value:
|
||||
"InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.KeyPassphrase"
|
||||
},
|
||||
{ _id: "ui.device.3.type", value: "'parameter-table'" },
|
||||
{ _id: "ui.device.3.label", value: "'WLAN hosts'" },
|
||||
{
|
||||
_id: "ui.device.3.parameter",
|
||||
value: "InternetGatewayDevice.LANDevice.1.Hosts.Host"
|
||||
},
|
||||
{ _id: "ui.device.3.childParameters.0.label", value: "'Host name'" },
|
||||
{ _id: "ui.device.3.childParameters.0.parameter", value: "HostName" },
|
||||
{ _id: "ui.device.3.childParameters.1.label", value: "'IP address'" },
|
||||
{ _id: "ui.device.3.childParameters.1.parameter", value: "IPAddress" },
|
||||
{ _id: "ui.device.3.childParameters.2.label", value: "'MAC address'" },
|
||||
{ _id: "ui.device.3.childParameters.2.parameter", value: "MACAddress" },
|
||||
{ _id: "ui.device.4.type", value: "'container'" },
|
||||
{ _id: "ui.device.4.element", value: "'div'" },
|
||||
{ _id: "ui.device.4.components.0.components.0", value: "'Faults'" },
|
||||
{ _id: "ui.device.4.components.0.element", value: "'h3'" },
|
||||
{ _id: "ui.device.4.components.0.type", value: "'container'" },
|
||||
{ _id: "ui.device.4.components.1.type", value: "'device-faults'" },
|
||||
{ _id: "ui.device.5.type", value: "'container'" },
|
||||
{ _id: "ui.device.5.element", value: "'div.container-full-width'" },
|
||||
{
|
||||
_id: "ui.device.5.components.0.components.0",
|
||||
value: "'All parameters'"
|
||||
},
|
||||
{ _id: "ui.device.5.components.0.element", value: "'h3'" },
|
||||
{ _id: "ui.device.5.components.0.type", value: "'container'" },
|
||||
{ _id: "ui.device.5.components.1.type", value: "'all-parameters'" },
|
||||
{ _id: "ui.device.6.type", value: "'device-actions'" }
|
||||
]);
|
||||
}
|
||||
|
||||
if (options.index) {
|
||||
resources["config"] = (resources["config"] || []).concat([
|
||||
{ _id: "ui.index.0.type", value: "'device-link'" },
|
||||
{ _id: "ui.index.0.label", value: "'Serial number'" },
|
||||
{ _id: "ui.index.0.parameter", value: "DeviceID.SerialNumber" },
|
||||
{ _id: "ui.index.0.components.0.type", value: "'parameter'" },
|
||||
{ _id: "ui.index.1.label", value: "'Product class'" },
|
||||
{ _id: "ui.index.1.parameter", value: "DeviceID.ProductClass" },
|
||||
{ _id: "ui.index.2.label", value: "'Software version'" },
|
||||
{
|
||||
_id: "ui.index.2.parameter",
|
||||
value: "InternetGatewayDevice.DeviceInfo.SoftwareVersion"
|
||||
},
|
||||
{ _id: "ui.index.3.label", value: "'IP'" },
|
||||
{
|
||||
_id: "ui.index.3.parameter",
|
||||
value:
|
||||
"InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANIPConnection.1.ExternalIPAddress"
|
||||
},
|
||||
{ _id: "ui.index.4.label", value: "'SSID'" },
|
||||
{
|
||||
_id: "ui.index.4.parameter",
|
||||
value: "InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.SSID"
|
||||
},
|
||||
{ _id: "ui.index.5.type", value: "'container'" },
|
||||
{ _id: "ui.index.5.label", value: "'Last inform'" },
|
||||
{ _id: "ui.index.5.element", value: "'span.inform'" },
|
||||
{ _id: "ui.index.5.parameter", value: "DATE_STRING(Events.Inform)" },
|
||||
{ _id: "ui.index.5.components.0.type", value: "'parameter'" },
|
||||
{ _id: "ui.index.5.components.1.chart", value: "'online'" },
|
||||
{ _id: "ui.index.5.components.1.type", value: "'overview-dot'" },
|
||||
{ _id: "ui.index.6.type", value: "'tags'" },
|
||||
{ _id: "ui.index.6.label", value: "'Tags'" },
|
||||
{ _id: "ui.index.6.parameter", value: "Tags" },
|
||||
{ _id: "ui.index.6.unsortable", value: "true" },
|
||||
{ _id: "ui.index.6.writable", value: "false" }
|
||||
]);
|
||||
}
|
||||
|
||||
if (options.overview) {
|
||||
resources["config"] = (resources["config"] || []).concat([
|
||||
{ _id: "ui.overview.charts.online.label", value: "'Online status'" },
|
||||
{
|
||||
_id: "ui.overview.charts.online.slices.1_onlineNow.color",
|
||||
value: "'#31a354'"
|
||||
},
|
||||
{
|
||||
_id: "ui.overview.charts.online.slices.1_onlineNow.filter",
|
||||
value: "Events.Inform > NOW() - 5 * 60 * 1000"
|
||||
},
|
||||
{
|
||||
_id: "ui.overview.charts.online.slices.1_onlineNow.label",
|
||||
value: "'Online now'"
|
||||
},
|
||||
{
|
||||
_id: "ui.overview.charts.online.slices.2_past24.color",
|
||||
value: "'#a1d99b'"
|
||||
},
|
||||
{
|
||||
_id: "ui.overview.charts.online.slices.2_past24.filter",
|
||||
value:
|
||||
"Events.Inform > (NOW() - 5 * 60 * 1000) - (24 * 60 * 60 * 1000) AND Events.Inform < (NOW() - 5 * 60 * 1000)"
|
||||
},
|
||||
{
|
||||
_id: "ui.overview.charts.online.slices.2_past24.label",
|
||||
value: "'Past 24 hours'"
|
||||
},
|
||||
{
|
||||
_id: "ui.overview.charts.online.slices.3_others.color",
|
||||
value: "'#e5f5e0'"
|
||||
},
|
||||
{
|
||||
_id: "ui.overview.charts.online.slices.3_others.filter",
|
||||
value: "Events.Inform < (NOW() - 5 * 60 * 1000) - (24 * 60 * 60 * 1000)"
|
||||
},
|
||||
{
|
||||
_id: "ui.overview.charts.online.slices.3_others.label",
|
||||
value: "'Others'"
|
||||
},
|
||||
{ _id: "ui.overview.groups.online.label", value: "''" },
|
||||
{ _id: "ui.overview.groups.online.charts.0", value: "'online'" }
|
||||
]);
|
||||
}
|
||||
|
||||
if (options.presets) {
|
||||
resources["presets"] = [
|
||||
{
|
||||
_id: "bootstrap",
|
||||
weight: 0,
|
||||
channel: "bootstrap",
|
||||
provision: "bootstrap"
|
||||
},
|
||||
{ _id: "default", weight: 0, channel: "default", provision: "default" },
|
||||
{ _id: "inform", weight: 0, channel: "inform", provision: "inform" }
|
||||
];
|
||||
|
||||
resources["provisions"] = [
|
||||
{ _id: "bootstrap", script: BOOTSTRAP_SCRIPT },
|
||||
{ _id: "default", script: DEFAULT_SCRIPT },
|
||||
{ _id: "inform", script: INFORM_SCRIPT }
|
||||
];
|
||||
}
|
||||
|
||||
if (resources["permissions"]) {
|
||||
for (const p of resources["permissions"]) {
|
||||
p["_id"] = `${p["role"]}:${p["resource"]}:${p["access"]}`;
|
||||
proms.push(db.putPermission(p["_id"], p));
|
||||
}
|
||||
}
|
||||
|
||||
if (resources["users"]) {
|
||||
for (const u of resources["users"]) {
|
||||
u["salt"] = await generateSalt(64);
|
||||
u["password"] = await hashPassword(u["password"], u["salt"]);
|
||||
u["roles"] = (u["roles"] || []).join(",");
|
||||
u["_id"] = u["username"];
|
||||
delete u["username"];
|
||||
proms.push(db.putUser(u["_id"], u));
|
||||
}
|
||||
}
|
||||
|
||||
if (resources["provisions"]) {
|
||||
for (const p of resources["provisions"])
|
||||
proms.push(db.putProvision(p["_id"], p));
|
||||
}
|
||||
|
||||
if (resources["presets"])
|
||||
for (const p of resources["presets"]) proms.push(db.putPreset(p["_id"], p));
|
||||
|
||||
if (resources["config"])
|
||||
for (const c of resources["config"]) proms.push(db.putConfig(c["_id"], c));
|
||||
|
||||
await proms;
|
||||
return del("presets_hash");
|
||||
}
|
||||
+1
-10
@@ -340,7 +340,7 @@ async function fetchConfig(): Promise<[{}, {}]> {
|
||||
filters: {},
|
||||
device: {},
|
||||
index: {},
|
||||
overview: { charts: {}, groups: {} }
|
||||
overview: {}
|
||||
};
|
||||
const _config = {};
|
||||
|
||||
@@ -362,15 +362,6 @@ async function fetchConfig(): Promise<[{}, {}]> {
|
||||
}
|
||||
}
|
||||
|
||||
if (!Object.keys(ui["index"]).length) {
|
||||
ui["index"] = {
|
||||
"0": {
|
||||
label: "ID",
|
||||
parameter: ["PARAM", "DeviceID.ID"]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return [_config, ui];
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import * as logger from "./logger";
|
||||
import * as localCache from "./local-cache";
|
||||
import { PermissionSet } from "./types";
|
||||
import { authSimple } from "./ui/api-functions";
|
||||
import * as init from "./init";
|
||||
|
||||
declare module "koa" {
|
||||
interface Request {
|
||||
@@ -142,11 +143,57 @@ koa.use(async (ctx, next) => {
|
||||
koa.use(koaBodyParser());
|
||||
router.use("/api", api.routes(), api.allowedMethods());
|
||||
|
||||
router.get("/init", async ctx => {
|
||||
const status = await init.getStatus();
|
||||
if (Object.keys(localCache.getUsers(ctx.state.configSnapshot)).length) {
|
||||
if (!ctx.state.authorizer.hasAccess("users", 3)) status["users"] = false;
|
||||
if (!ctx.state.authorizer.hasAccess("permissions", 3))
|
||||
status["users"] = false;
|
||||
if (!ctx.state.authorizer.hasAccess("config", 3)) {
|
||||
status["filters"] = false;
|
||||
status["device"] = false;
|
||||
status["index"] = false;
|
||||
status["overview"] = false;
|
||||
}
|
||||
if (!ctx.state.authorizer.hasAccess("presets", 3))
|
||||
status["presets"] = false;
|
||||
if (!ctx.state.authorizer.hasAccess("provisions", 3))
|
||||
status["presets"] = false;
|
||||
}
|
||||
|
||||
ctx.body = status;
|
||||
});
|
||||
|
||||
router.post("/init", async ctx => {
|
||||
const status = ctx.request.body;
|
||||
if (Object.keys(localCache.getUsers(ctx.state.configSnapshot)).length) {
|
||||
if (!ctx.state.authorizer.hasAccess("users", 3)) status["users"] = false;
|
||||
if (!ctx.state.authorizer.hasAccess("permissions", 3))
|
||||
status["users"] = false;
|
||||
if (!ctx.state.authorizer.hasAccess("config", 3)) {
|
||||
status["filters"] = false;
|
||||
status["device"] = false;
|
||||
status["index"] = false;
|
||||
status["overview"] = false;
|
||||
}
|
||||
if (!ctx.state.authorizer.hasAccess("presets", 3))
|
||||
status["presets"] = false;
|
||||
if (!ctx.state.authorizer.hasAccess("provisions", 3))
|
||||
status["presets"] = false;
|
||||
}
|
||||
await init.seed(status);
|
||||
ctx.body = "";
|
||||
});
|
||||
|
||||
router.get("/", async ctx => {
|
||||
let permissionSets = [];
|
||||
if (ctx.state.user && ctx.state.user.username)
|
||||
permissionSets = getPermissionSets(ctx);
|
||||
|
||||
let wizard = "";
|
||||
if (!Object.keys(localCache.getUsers(ctx.state.configSnapshot)).length)
|
||||
wizard = '<script>window.location.hash = "#!/wizard";</script>';
|
||||
|
||||
ctx.body = `
|
||||
<html>
|
||||
<head>
|
||||
@@ -165,7 +212,7 @@ router.get("/", async ctx => {
|
||||
)};
|
||||
window.permissionSets = ${JSON.stringify(permissionSets)};
|
||||
</script>
|
||||
<script src="app.js"></script>
|
||||
<script src="app.js"></script>${wizard}
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
import m, { RouteResolver } from "mithril";
|
||||
import layout from "./layout";
|
||||
import * as store from "./store";
|
||||
import * as wizardPage from "./wizard-page";
|
||||
import * as loginPage from "./login-page";
|
||||
import * as overviewPage from "./overview-page";
|
||||
import * as devicesPage from "./devices-page";
|
||||
@@ -136,6 +137,7 @@ function redirectAdminPage(): RouteResolver {
|
||||
}
|
||||
|
||||
m.route(document.body, "/overview", {
|
||||
"/wizard": pagify("wizard", wizardPage),
|
||||
"/login": pagify("login", loginPage),
|
||||
"/overview": pagify("overview", overviewPage),
|
||||
"/devices": pagify("devices", devicesPage),
|
||||
|
||||
@@ -716,3 +716,12 @@ span.parameter-value {
|
||||
color: #aaa;
|
||||
}
|
||||
}
|
||||
|
||||
.wizard-dialog {
|
||||
max-width: 720px;
|
||||
margin: 10px auto;
|
||||
padding: 10px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--color1);
|
||||
box-shadow: 0 0 10px #ccc;
|
||||
}
|
||||
@@ -69,6 +69,12 @@ export function init(args): Promise<{}> {
|
||||
const filter = args.hasOwnProperty("filter") ? "" + args["filter"] : "";
|
||||
const sort = args.hasOwnProperty("sort") ? "" + args["sort"] : "";
|
||||
const indexParameters = Object.values(config.ui.index);
|
||||
if (!indexParameters.length) {
|
||||
indexParameters.push({
|
||||
label: "ID",
|
||||
parameter: ["PARAM", "DeviceID.ID"]
|
||||
});
|
||||
}
|
||||
resolve({ filter, indexParameters, sort });
|
||||
});
|
||||
}
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ import config from "./config";
|
||||
import * as store from "./store";
|
||||
import pieChartComponent from "./pie-chart-component";
|
||||
|
||||
const GROUPS = config.ui.overview.groups;
|
||||
const GROUPS = config.ui.overview.groups || {};
|
||||
const CHARTS = {};
|
||||
for (const group of Object.values(GROUPS)) {
|
||||
for (const chartName of Object.values(group["charts"]) as string[])
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* Copyright 2013-2019 GenieACS Inc.
|
||||
*
|
||||
* This file is part of GenieACS.
|
||||
*
|
||||
* GenieACS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* GenieACS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with GenieACS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import m, { ClosureComponent, Component } from "mithril";
|
||||
import * as notifications from "./notifications";
|
||||
|
||||
export async function init(): Promise<{}> {
|
||||
return m.request({ url: "/init" });
|
||||
}
|
||||
|
||||
export const component: ClosureComponent = (vnode): Component => {
|
||||
let options = vnode.attrs;
|
||||
const selected = new Set();
|
||||
for (const [k, v] of Object.entries(options)) if (v) selected.add(k);
|
||||
|
||||
return {
|
||||
view: () => {
|
||||
document.title = "Initialization wizard - GenieACS";
|
||||
|
||||
const checkboxes = [
|
||||
"users",
|
||||
"presets",
|
||||
"filters",
|
||||
"device",
|
||||
"index",
|
||||
"overview"
|
||||
].map(s => {
|
||||
if (!options[s]) selected.delete(s);
|
||||
return m("input", {
|
||||
type: "checkbox",
|
||||
checked: selected.has(s),
|
||||
disabled: !options[s],
|
||||
style: "display: inline; margin-right: 0.5em;",
|
||||
onclick: e => {
|
||||
if (e.target.checked) selected.add(s);
|
||||
else selected.delete(s);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return m(".wizard-dialog", [
|
||||
m("h1", "Initialization wizard"),
|
||||
m(
|
||||
"p",
|
||||
"This wizard will seed the database with a minimal initial configuration to serve as a starting point. Select what you want to initialize and click 'ABRACADABRA!'."
|
||||
),
|
||||
m("div", m("label", checkboxes[0], "Users, roles and permissions")),
|
||||
m("div", m("label", checkboxes[1], "Presets and provisions")),
|
||||
m(
|
||||
"div",
|
||||
m("label", checkboxes[2], "Devices predefined search filters")
|
||||
),
|
||||
m("div", m("label", checkboxes[3], "Device details page")),
|
||||
m("div", m("label", checkboxes[4], "Devices listing page")),
|
||||
m("div", m("label", checkboxes[5], "Overview page")),
|
||||
m(
|
||||
"button.primary",
|
||||
{
|
||||
style: "margin: 10px;",
|
||||
disabled: selected.size === 0,
|
||||
onclick: e => {
|
||||
e.target.disabled = true;
|
||||
|
||||
const opts = {};
|
||||
for (const s of selected) opts[s] = true;
|
||||
|
||||
m.request({
|
||||
method: "POST",
|
||||
url: "/init",
|
||||
data: opts
|
||||
})
|
||||
.then(() => {
|
||||
setTimeout(() => {
|
||||
m.request({ url: "/init" }).then(o => {
|
||||
e.target.disabled = false;
|
||||
options = o;
|
||||
notifications.push("success", "Initialization complete", {
|
||||
"Open Sesame!": () => {
|
||||
m.route.set("/login");
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
});
|
||||
}, 3000);
|
||||
if (opts["users"]) {
|
||||
alert(
|
||||
"An administrator user has been created for you. Use admin/admin to log in. Don't forget to change the default password."
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
notifications.push("error", err.message);
|
||||
});
|
||||
}
|
||||
},
|
||||
"ABRACADABRA!"
|
||||
)
|
||||
]);
|
||||
}
|
||||
};
|
||||
};
|
||||
Reference in new issue
Block a user