diff --git a/api/liberouterapi/bootstrap.py b/api/liberouterapi/bootstrap.py index 6ef5421..24fb554 100644 --- a/api/liberouterapi/bootstrap.py +++ b/api/liberouterapi/bootstrap.py @@ -104,6 +104,13 @@ def setup(): raise ApiException("API is already setup") settings = request.get_json() db = dbConnector() + + if len(settings['username']) == 0: + raise ApiException("Missing username") + + if len(settings['password']) == 0: + raise ApiException("Missing password") + try: # Insert user to database via user module from .modules.users import unprotected_add_user diff --git a/api/liberouterapi/modules/configuration.py b/api/liberouterapi/modules/configuration.py new file mode 100644 index 0000000..c52a517 --- /dev/null +++ b/api/liberouterapi/modules/configuration.py @@ -0,0 +1,148 @@ +""" +Configuration REST API + +Configuration is separated into documents where each document is identified by +name of the module, where 'liberoutergui' module is reserved for future use +in case we need something globally configurable in the Liberouter GUI. + +When inserting a configuration 'name' must be unique. +""" + +from flask import request + +from liberouterapi import auth, dbConnector +from liberouterapi.error import ApiException +from .module import Module +from bson import json_util as json +from pymongo import ReturnDocument + +class ConfError(ApiException): + status_code = 400 + +# Initialize connector to the configuration collection +connector = dbConnector() +conf_db = connector.db["configuration"] + +conf = Module('configuration', __name__, url_prefix='/configuration', no_version = True) + +@conf.route('', methods=['GET']) +#@auth.required() +def get_conf(): + res = list(conf_db.find()) + return (json.dumps(res)) + +def unprotected_get_module_conf(module): + """ + Get module's configuration specified by the module's name + + Prevent from storing module liberoutergui (reserved for future use). + + Each module name is converted to lowercase + """ + if module == 'liberoutergui': + raise ConfError("'liberoutergui' module name is reserved", status_code=409) + + res = conf_db.find_one({ + 'name' : module.lower() + }) + + if not res: + raise ConfError("Module '%s' not found" % module, status_code=404) + + return(res) + + +@conf.route('/', methods=['GET']) +def get_module_conf(module): + """ + Get module by its name using the unprotected function + """ + return (json.dumps(unprotected_get_module_conf(module))) + +@conf.route('/', methods=['PUT']) +def update_conf(module): + """ + Update a module's configuration specified by its name + + 'name' mustn't be specified in data and data must be non-empty + """ + + data = request.get_json() + + if not data: + raise ConfError("Nothing to update") + + if "name" in data: + del data["name"] + + if "_id" in data: + del data["_id"] + + res = conf_db.find_one_and_update({ + "name" : str(module).lower() + }, + { + "$set" : data + }, + return_document=ReturnDocument.AFTER) + + if not res: + raise ConfError("Can't update module '%s'" % str(module).lower()) + + return(json.dumps(res)) + +@conf.route('', methods=['POST']) +def insert_conf(): + """ + Insert module's configuration, the configuration name mustn't be present in + the collection + + 'name' is a mandatory key + """ + + conf = request.get_json() + res = {} + + if 'name' not in conf: + raise ConfError("'name' must be specified in configuration") + + try: + # We expect it to raise ConfError (config not found) + res = unprotected_get_module_conf(conf['name']) + except ConfError: + # Name must be lowercase + conf['name'] = conf['name'].lower() + + res = conf_db.insert_one(conf) + + try: + res = conf_db.find_one({ + "_id" : res.inserted_id + }) + except Exception as e: + raise ConfError(str(e)) + else: + raise ConfError("Configuration with name '%s' already exists" % conf['name']) + + return(json.dumps(res)) + +@conf.route('/', methods=['DELETE']) +def remove_conf(module): + """ + Remove specified module from db + + Module is identified by its name in lowercase + """ + + # Get the original document + orig_config = unprotected_get_module_conf(module) + + res = conf_db.delete_one({ + 'name' : str(module).lower() + }) + + if res.deleted_count != 1: + raise ConfError("Module '%s' wasn't deleted" % module, status_code=404) + + return(json.dumps(orig_config)) + diff --git a/api/liberouterapi/modules/nemea-reporter-rest b/api/liberouterapi/modules/nemea-reporter-rest new file mode 120000 index 0000000..36cfd0b --- /dev/null +++ b/api/liberouterapi/modules/nemea-reporter-rest @@ -0,0 +1 @@ +../../../modules/Nemea-Dashboard/api/modules/nemea/reporter-rest \ No newline at end of file diff --git a/modules/Nemea-Dashboard b/modules/Nemea-Dashboard index 8d85015..4b1aa0a 160000 --- a/modules/Nemea-Dashboard +++ b/modules/Nemea-Dashboard @@ -1 +1 @@ -Subproject commit 8d85015253c459c77784435b4b0d366b532c2413 +Subproject commit 4b1aa0a81ce9aa308b5486189e6cab8af1602f9e diff --git a/www/.angular-cli.json b/www/.angular-cli.json new file mode 100644 index 0000000..3a76d08 --- /dev/null +++ b/www/.angular-cli.json @@ -0,0 +1,68 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "project": { + "version": "0.2.0", + "name": "liberouter-gui" + }, + "apps": [ + { + "root": "src", + "outDir": "dist", + "assets": [ + "assets", + "favicon.ico", + ".htaccess", + "../node_modules/font-awesome/fonts/*.+(otf|eot|svg|ttf|woff|woff2)" + ], + "index": "index.html", + "main": "main.ts", + "polyfills": "polyfills.ts", + "test": "test.ts", + "tsconfig": "tsconfig.app.json", + "testTsconfig": "tsconfig.spec.json", + "prefix": "app", + "styles": [ + "styles/main.scss", + "../node_modules/bootstrap/dist/css/bootstrap.min.css", + "../node_modules/codemirror/lib/codemirror.css" + ], + "scripts": [], + "environmentSource": "environments/environment.ts", + "environments": { + "dev": "environments/environment.ts", + "prod": "environments/environment.prod.ts" + } + } + ], + "sassCompiler" : { + "includePaths": ["src/styles"] + }, + "e2e": { + "protractor": { + "config": "./protractor.conf.js" + } + }, + "lint": [ + { + "project": "src/tsconfig.app.json" + }, + { + "project": "src/tsconfig.spec.json" + }, + { + "project": "e2e/tsconfig.e2e.json" + } + ], + "test": { + "karma": { + "config": "./karma.conf.js" + } + }, + "defaults": { + "styleExt": "scss", + "component": { + "inlineTemplate": false, + "spec": true + } + } +} diff --git a/www/.editorconfig b/www/.editorconfig index 6e87a00..2e8b0ef 100644 --- a/www/.editorconfig +++ b/www/.editorconfig @@ -3,8 +3,8 @@ root = true [*] charset = utf-8 -indent_style = space -indent_size = 2 +indent_style = tab +indent_size = 4 insert_final_newline = true trim_trailing_whitespace = true diff --git a/www/.gitignore b/www/.gitignore index fe6f8a7..35c5fee 100644 --- a/www/.gitignore +++ b/www/.gitignore @@ -38,3 +38,5 @@ testem.log #System Files .DS_Store Thumbs.db + +config.json diff --git a/www/.htaccess b/www/.htaccess index 4081df4..e7e7a52 100644 --- a/www/.htaccess +++ b/www/.htaccess @@ -1,9 +1,9 @@ RewriteEngine On - RewriteRule ^$ /liberouter-gui/www/dist [L] + RewriteRule ^$ / [L] RewriteBase /dist RewriteRule ^index\.html$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d - RewriteRule . /liberouter-gui/www/dist/index.html [L] + RewriteRule . /index.html [L] diff --git a/www/README.md b/www/README.md index 14b91d4..86fb151 100644 --- a/www/README.md +++ b/www/README.md @@ -22,6 +22,9 @@ Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github. Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). Before running the tests make sure you are serving the app via `ng serve`. -## Further help +## Building production Liberouter GUI +Because of some weird bug in Angular CLI or TypeScript one has to build the production version of Liberouter GUI like this: -To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). +1. run `ng build --prod --bh="/liberouter-gui/www/dist/" --aot=false -w` This will give you an error `ERROR in AppModule is not an NgModule` +2. Trigger the watch routine of Angular CLI (i.e. open and save some file inside the src folder). +3. Build finishes sucessfully. diff --git a/www/angular-cli.json b/www/angular-cli.json deleted file mode 100644 index 32872b3..0000000 --- a/www/angular-cli.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "project": { - "version": "1.0.0-beta.31", - "name": "www" - }, - "apps": [ - { - "root": "src", - "outDir": "dist", - "assets": [ - "assets", - "favicon.ico" - ], - "index": "index.html", - "main": "main.ts", - "polyfills": "polyfills.ts", - "test": "test.ts", - "tsconfig": "tsconfig.json", - "prefix": "app", - "styles": [ - "styles/main.scss", - "../node_modules/font-awesome/css/font-awesome.css", - "../node_modules/bootstrap/dist/css/bootstrap.min.css" - ], - "scripts": [], - "environments": { - "source": "environments/environment.ts", - "dev": "environments/environment.ts", - "prod": "environments/environment.prod.ts" - } - } - ], - "addons" : [ - "../node_modules/font-awesome/fonts/*.+(otf|eot|svg|ttf|woff|woff2)" - ], - "sassCompiler" : { - "includePaths": ["src/styles"] - }, - "e2e": { - "protractor": { - "config": "./protractor.conf.js" - } - }, - "lint": [ - { - "files": "src/**/*.ts", - "project": "src/tsconfig.json" - }, - { - "files": "e2e/**/*.ts", - "project": "e2e/tsconfig.json" - } - ], - "test": { - "karma": { - "config": "./karma.conf.js" - } - }, - "defaults": { - "styleExt": "scss", - "prefixInterfaces": false, - "inline": { - "style": false, - "template": false - }, - "spec": { - "class": false, - "component": true, - "directive": true, - "module": false, - "pipe": true, - "service": true - } - } -} diff --git a/www/karma.conf.js b/www/karma.conf.js index 437f2d0..1685601 100644 --- a/www/karma.conf.js +++ b/www/karma.conf.js @@ -8,29 +8,21 @@ module.exports = function (config) { plugins: [ require('karma-jasmine'), require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), require('karma-coverage-istanbul-reporter'), require('@angular/cli/plugins/karma') ], - files: [ - { pattern: './src/test.ts', watched: false } - ], - preprocessors: { - './src/test.ts': ['@angular/cli'] - }, - mime: { - 'text/x-typescript': ['ts','tsx'] + client:{ + clearContext: false // leave Jasmine Spec Runner output visible in browser }, coverageIstanbulReporter: { reports: [ 'html', 'lcovonly' ], fixWebpackSourcePaths: true }, angularCli: { - config: './angular-cli.json', environment: 'dev' }, - reporters: config.angularCli && config.angularCli.codeCoverage - ? ['progress', 'coverage-istanbul'] - : ['progress'], + reporters: ['progress', 'kjhtml'], port: 9876, colors: true, logLevel: config.LOG_INFO, @@ -39,3 +31,4 @@ module.exports = function (config) { singleRun: false }); }; + diff --git a/www/package.json b/www/package.json index fa03587..793db03 100644 --- a/www/package.json +++ b/www/package.json @@ -1,52 +1,66 @@ { - "name": "Liberouter GUI", - "version": "0.2.0-beta", + "name": "liberouter-gui", + "version": "0.3.0", "license": "MIT", "angular-cli": {}, "scripts": { "ng": "ng", "start": "ng serve", + "build": "ng build", "test": "ng test", "lint": "ng lint", - "scss": "node-sass --include-path scss src/styles/base.scss src/styles/main.css -o dist", "e2e": "ng e2e" }, "private": true, "dependencies": { - "@angular/cli": "^1.0.0-beta.31", - "@angular/common": "^2.4.0", - "@angular/compiler": "^2.4.0", - "@angular/core": "^2.4.0", - "@angular/forms": "^2.4.0", - "@angular/http": "^2.4.0", - "@angular/platform-browser": "^2.4.0", - "@angular/platform-browser-dynamic": "^2.4.0", - "@angular/router": "^3.4.0", + "@angular/animations": "^4.0.0", + "@angular/cli": "^1.1.2", + "@angular/common": "^4.0.0", + "@angular/compiler": "^4.0.0", + "@angular/core": "^4.0.0", + "@angular/forms": "^4.0.0", + "@angular/http": "^4.0.0", + "@angular/platform-browser": "^4.0.0", + "@angular/platform-browser-dynamic": "^4.0.0", + "@angular/router": "^4.0.0", "@ng-bootstrap/ng-bootstrap": "^1.0.0-alpha.20", + "@swimlane/ngx-charts": "^5.3.1", + "angular2-grid": "^2.0.2", "bootstrap": "^4.0.0-alpha.6", "core-js": "^2.4.1", + "d3": "^4.9.1", "font-awesome": "^4.7.0", - "node-sass": "^4.5.0", - "rxjs": "^5.0.1", - "ts-helpers": "^1.1.1", - "zone.js": "^0.7.2" + "ng2-codemirror": "^1.1.1", + "rxjs": "^5.1.0", + "zone.js": "^0.8.4" }, "devDependencies": { - "@angular/cli": "1.0.0-beta.31", - "@angular/compiler-cli": "^2.4.0", - "@types/jasmine": "2.5.38", - "@types/node": "^6.0.42", - "codelyzer": "~2.0.0-beta.1", - "jasmine-core": "2.5.2", - "jasmine-spec-reporter": "2.5.0", - "karma": "1.2.0", - "karma-chrome-launcher": "^2.0.0", - "karma-cli": "^1.0.1", - "karma-jasmine": "^1.0.2", - "karma-coverage-istanbul-reporter": "^0.2.0", - "protractor": "~5.1.0", - "ts-node": "1.2.1", - "tslint": "^4.3.0", - "typescript": "~2.0.0" - } + "@angular/compiler-cli": "^4.0.0", + "@angular/language-service": "^4.0.0", + "@types/jasmine": "2.5.45", + "@types/node": "~6.0.60", + "codelyzer": "~3.0.1", + "jasmine-core": "~2.6.2", + "jasmine-spec-reporter": "~4.1.0", + "karma": "~1.7.0", + "karma-chrome-launcher": "~2.1.1", + "karma-cli": "~1.0.1", + "karma-coverage-istanbul-reporter": "^1.2.1", + "karma-jasmine": "~1.1.0", + "karma-jasmine-html-reporter": "^0.2.2", + "protractor": "~5.1.2", + "ts-node": "~3.0.4", + "tslint": "~5.3.2", + "typescript": "^2.2.2" + }, + "description": "Web interface for Liberouter GUI. Built using webpack.", + "repository": { + "type": "git", + "url": "git+https://github.com/CESNET/liberouter-gui.git" + }, + "author": "", + "bugs": { + "url": "https://github.com/CESNET/liberouter-gui/issues" + }, + "homepage": "https://github.com/CESNET/liberouter-gui#readme" } diff --git a/www/protractor.conf.js b/www/protractor.conf.js index ffded70..1891703 100644 --- a/www/protractor.conf.js +++ b/www/protractor.conf.js @@ -1,8 +1,7 @@ // Protractor configuration file, see link for more information // https://github.com/angular/protractor/blob/master/lib/config.ts -/*global jasmine */ -var SpecReporter = require('jasmine-spec-reporter'); +const { SpecReporter } = require('jasmine-spec-reporter'); exports.config = { allScriptsTimeout: 11000, @@ -20,13 +19,11 @@ exports.config = { defaultTimeoutInterval: 30000, print: function() {} }, - useAllAngular2AppRoots: true, - beforeLaunch: function() { + onPrepare() { require('ts-node').register({ - project: 'e2e' + project: 'e2e/tsconfig.e2e.json' }); - }, - onPrepare: function() { - jasmine.getEnv().addReporter(new SpecReporter()); + jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); } }; + diff --git a/www/src/app/app.component.html b/www/src/app/app.component.html index 22631bc..643309c 100644 --- a/www/src/app/app.component.html +++ b/www/src/app/app.component.html @@ -2,13 +2,13 @@