diff --git a/src/backend/internal/report.js b/src/backend/internal/report.js new file mode 100644 index 0000000..da4dcc6 --- /dev/null +++ b/src/backend/internal/report.js @@ -0,0 +1,25 @@ +'use strict'; + +const _ = require('lodash'); +const error = require('../lib/error'); + +const internalReport = { + + /** + * @param {Access} access + * @return {Promise} + */ + getHostsReport: access => { + return access.can('reports:hosts', 1) + .then(() => { + return { + proxy: 12, + redirection: 2, + stream: 1, + '404': 0 + }; + }); + } +}; + +module.exports = internalReport; diff --git a/src/backend/lib/access/reports-hosts.json b/src/backend/lib/access/reports-hosts.json new file mode 100644 index 0000000..4b02c77 --- /dev/null +++ b/src/backend/lib/access/reports-hosts.json @@ -0,0 +1,7 @@ +{ + "anyOf": [ + { + "$ref": "roles#/definitions/user" + } + ] +} diff --git a/src/backend/routes/api/main.js b/src/backend/routes/api/main.js index eff3fe9..107047e 100644 --- a/src/backend/routes/api/main.js +++ b/src/backend/routes/api/main.js @@ -2,6 +2,7 @@ const express = require('express'); const pjson = require('../../../../package.json'); +const error = require('../../lib/error'); let router = express.Router({ caseSensitive: true, @@ -28,5 +29,16 @@ router.get('/', (req, res/*, next*/) => { router.use('/tokens', require('./tokens')); router.use('/users', require('./users')); +router.use('/reports', require('./reports')); + +/** + * API 404 for all other routes + * + * ALL /api/* + */ +router.all(/(.+)/, function (req, res, next) { + req.params.page = req.params['0']; + next(new error.ItemNotFoundError(req.params.page)); +}); module.exports = router; diff --git a/src/backend/routes/api/reports.js b/src/backend/routes/api/reports.js new file mode 100644 index 0000000..d14d8bd --- /dev/null +++ b/src/backend/routes/api/reports.js @@ -0,0 +1,31 @@ +'use strict'; + +const express = require('express'); +const jwtdecode = require('../../lib/express/jwt-decode'); +const internalReport = require('../../internal/report'); + +let router = express.Router({ + caseSensitive: true, + strict: true, + mergeParams: true +}); + +router + .route('/hosts') + .options((req, res) => { + res.sendStatus(204); + }) + + /** + * GET /reports/hosts + */ + .get(jwtdecode(), (req, res, next) => { + internalReport.getHostsReport(res.locals.access) + .then(data => { + res.status(200) + .send(data); + }) + .catch(next); + }); + +module.exports = router; diff --git a/src/frontend/js/app/api.js b/src/frontend/js/app/api.js index 26886ef..1f23e16 100644 --- a/src/frontend/js/app/api.js +++ b/src/frontend/js/app/api.js @@ -225,5 +225,15 @@ module.exports = { loginAs: function (id) { return fetch('post', 'users/' + id + '/login'); } + }, + + Reports: { + + /** + * @returns {Promise} + */ + getHostStats: function () { + return fetch('get', 'reports/hosts'); + }, } }; diff --git a/src/frontend/js/app/controller.js b/src/frontend/js/app/controller.js index 19738f2..7e02d9c 100644 --- a/src/frontend/js/app/controller.js +++ b/src/frontend/js/app/controller.js @@ -94,6 +94,66 @@ module.exports = { }); }, + /** + * Nginx Proxy Hosts + */ + showNginxProxy: function () { + let controller = this; + + require(['./main', './nginx/proxy/main'], (App, View) => { + controller.navigate('/nginx/proxy'); + App.UI.showAppContent(new View()); + }); + }, + + /** + * Nginx Redirection Hosts + */ + showNginxRedirection: function () { + let controller = this; + + require(['./main', './nginx/redirection/main'], (App, View) => { + controller.navigate('/nginx/redirection'); + App.UI.showAppContent(new View()); + }); + }, + + /** + * Nginx Stream Hosts + */ + showNginxStream: function () { + let controller = this; + + require(['./main', './nginx/stream/main'], (App, View) => { + controller.navigate('/nginx/stream'); + App.UI.showAppContent(new View()); + }); + }, + + /** + * Nginx 404 Hosts + */ + showNginx404: function () { + let controller = this; + + require(['./main', './nginx/404/main'], (App, View) => { + controller.navigate('/nginx/404'); + App.UI.showAppContent(new View()); + }); + }, + + /** + * Nginx Access + */ + showNginxAccess: function () { + let controller = this; + + require(['./main', './nginx/access/main'], (App, View) => { + controller.navigate('/nginx/access'); + App.UI.showAppContent(new View()); + }); + }, + /** * Dashboard */ diff --git a/src/frontend/js/app/dashboard/main.ejs b/src/frontend/js/app/dashboard/main.ejs index 40816a2..e752b88 100644 --- a/src/frontend/js/app/dashboard/main.ejs +++ b/src/frontend/js/app/dashboard/main.ejs @@ -1 +1,57 @@ -Hi \ No newline at end of file + + +
+
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+
\ No newline at end of file diff --git a/src/frontend/js/app/dashboard/main.js b/src/frontend/js/app/dashboard/main.js index 6694281..6f1e644 100644 --- a/src/frontend/js/app/dashboard/main.js +++ b/src/frontend/js/app/dashboard/main.js @@ -1,10 +1,61 @@ 'use strict'; -const Mn = require('backbone.marionette'); -const template = require('./main.ejs'); +const Mn = require('backbone.marionette'); +const Cache = require('../cache'); +const Controller = require('../controller'); +const Api = require('../api'); +const Helpers = require('../../lib/helpers'); +const template = require('./main.ejs'); module.exports = Mn.View.extend({ template: template, - id: 'dashboard' -}); + id: 'dashboard', + stats: {}, + + ui: { + links: 'a' + }, + + events: { + 'click @ui.links': function (e) { + e.preventDefault(); + Controller.navigate($(e.currentTarget).attr('href'), true); + } + }, + + templateContext: function () { + let view = this; + + return { + getUserName: function () { + return Cache.User.get('nickname') || Cache.User.get('name'); + }, + + getHostStat: function (type) { + if (view.stats && typeof view.stats.hosts !== 'undefined' && typeof view.stats.hosts[type] !== 'undefined') { + return Helpers.niceNumber(view.stats.hosts[type]); + } + + return '-'; + } + } + }, + + onRender: function () { + let view = this; + + if (typeof view.stats.hosts === 'undefined') { + Api.Reports.getHostStats() + .then(response => { + if (!view.isDestroyed()) { + view.stats.hosts = response; + view.render(); + } + }) + .catch(err => { + console.log(err); + }); + } + } +}); diff --git a/src/frontend/js/app/nginx/404/main.ejs b/src/frontend/js/app/nginx/404/main.ejs new file mode 100644 index 0000000..57db2e9 --- /dev/null +++ b/src/frontend/js/app/nginx/404/main.ejs @@ -0,0 +1 @@ +404 \ No newline at end of file diff --git a/src/frontend/js/app/nginx/404/main.js b/src/frontend/js/app/nginx/404/main.js new file mode 100644 index 0000000..5cf54ca --- /dev/null +++ b/src/frontend/js/app/nginx/404/main.js @@ -0,0 +1,9 @@ +'use strict'; + +const Mn = require('backbone.marionette'); +const template = require('./main.ejs'); + +module.exports = Mn.View.extend({ + template: template, + id: 'nginx-404' +}); diff --git a/src/frontend/js/app/nginx/access/main.ejs b/src/frontend/js/app/nginx/access/main.ejs new file mode 100644 index 0000000..dd8b772 --- /dev/null +++ b/src/frontend/js/app/nginx/access/main.ejs @@ -0,0 +1 @@ +access \ No newline at end of file diff --git a/src/frontend/js/app/nginx/access/main.js b/src/frontend/js/app/nginx/access/main.js new file mode 100644 index 0000000..73dd931 --- /dev/null +++ b/src/frontend/js/app/nginx/access/main.js @@ -0,0 +1,9 @@ +'use strict'; + +const Mn = require('backbone.marionette'); +const template = require('./main.ejs'); + +module.exports = Mn.View.extend({ + template: template, + id: 'nginx-access' +}); diff --git a/src/frontend/js/app/nginx/proxy/main.ejs b/src/frontend/js/app/nginx/proxy/main.ejs new file mode 100644 index 0000000..18cd353 --- /dev/null +++ b/src/frontend/js/app/nginx/proxy/main.ejs @@ -0,0 +1 @@ +proxy \ No newline at end of file diff --git a/src/frontend/js/app/nginx/proxy/main.js b/src/frontend/js/app/nginx/proxy/main.js new file mode 100644 index 0000000..2cfa7a4 --- /dev/null +++ b/src/frontend/js/app/nginx/proxy/main.js @@ -0,0 +1,9 @@ +'use strict'; + +const Mn = require('backbone.marionette'); +const template = require('./main.ejs'); + +module.exports = Mn.View.extend({ + template: template, + id: 'nginx-proxy' +}); diff --git a/src/frontend/js/app/nginx/redirection/main.ejs b/src/frontend/js/app/nginx/redirection/main.ejs new file mode 100644 index 0000000..d3c485c --- /dev/null +++ b/src/frontend/js/app/nginx/redirection/main.ejs @@ -0,0 +1 @@ +redirection \ No newline at end of file diff --git a/src/frontend/js/app/nginx/redirection/main.js b/src/frontend/js/app/nginx/redirection/main.js new file mode 100644 index 0000000..858b38c --- /dev/null +++ b/src/frontend/js/app/nginx/redirection/main.js @@ -0,0 +1,9 @@ +'use strict'; + +const Mn = require('backbone.marionette'); +const template = require('./main.ejs'); + +module.exports = Mn.View.extend({ + template: template, + id: 'nginx-redirection' +}); diff --git a/src/frontend/js/app/nginx/stream/main.ejs b/src/frontend/js/app/nginx/stream/main.ejs new file mode 100644 index 0000000..36d357d --- /dev/null +++ b/src/frontend/js/app/nginx/stream/main.ejs @@ -0,0 +1 @@ +stream \ No newline at end of file diff --git a/src/frontend/js/app/nginx/stream/main.js b/src/frontend/js/app/nginx/stream/main.js new file mode 100644 index 0000000..ad1565c --- /dev/null +++ b/src/frontend/js/app/nginx/stream/main.js @@ -0,0 +1,9 @@ +'use strict'; + +const Mn = require('backbone.marionette'); +const template = require('./main.ejs'); + +module.exports = Mn.View.extend({ + template: template, + id: 'nginx-stream' +}); diff --git a/src/frontend/js/app/router.js b/src/frontend/js/app/router.js index 91825e7..b708c8e 100644 --- a/src/frontend/js/app/router.js +++ b/src/frontend/js/app/router.js @@ -5,10 +5,15 @@ const Controller = require('./controller'); module.exports = Mn.AppRouter.extend({ appRoutes: { - users: 'showUsers', - profile: 'showProfile', - logout: 'logout', - '*default': 'showDashboard' + users: 'showUsers', + profile: 'showProfile', + logout: 'logout', + 'nginx/proxy': 'showNginxProxy', + 'nginx/redirection': 'showNginxRedirection', + 'nginx/404': 'showNginx404', + 'nginx/stream': 'showNginxStream', + 'nginx/access': 'showNginxAccess', + '*default': 'showDashboard' }, initialize: function () { diff --git a/src/frontend/js/app/ui/menu/main.ejs b/src/frontend/js/app/ui/menu/main.ejs index 0cd83c3..bf0271f 100644 --- a/src/frontend/js/app/ui/menu/main.ejs +++ b/src/frontend/js/app/ui/menu/main.ejs @@ -2,6 +2,9 @@
- \ No newline at end of file + diff --git a/src/frontend/js/app/ui/menu/main.js b/src/frontend/js/app/ui/menu/main.js index a7c45a1..0279323 100644 --- a/src/frontend/js/app/ui/menu/main.js +++ b/src/frontend/js/app/ui/menu/main.js @@ -12,22 +12,13 @@ module.exports = Mn.View.extend({ template: template, ui: { - link: 'a' + links: 'a' }, events: { - 'click @ui.link': function (e) { + 'click @ui.links': function (e) { e.preventDefault(); - let href = $(e.currentTarget).attr('href'); - - switch (href) { - case '/': - Controller.showDashboard(); - break; - case '/users': - Controller.showUsers(); - break; - } + Controller.navigate($(e.currentTarget).attr('href'), true); } }, diff --git a/src/frontend/js/app/user/form.ejs b/src/frontend/js/app/user/form.ejs index 401c344..aa6c042 100644 --- a/src/frontend/js/app/user/form.ejs +++ b/src/frontend/js/app/user/form.ejs @@ -22,6 +22,7 @@
+
<% if (!isSelf()) { %> diff --git a/src/frontend/js/app/user/form.js b/src/frontend/js/app/user/form.js index 7d8ee3b..5f0b11b 100644 --- a/src/frontend/js/app/user/form.js +++ b/src/frontend/js/app/user/form.js @@ -18,13 +18,15 @@ module.exports = Mn.View.extend({ form: 'form', buttons: '.modal-footer button', cancel: 'button.cancel', - save: 'button.save' + save: 'button.save', + error: '.secret-error' }, events: { 'click @ui.save': function (e) { e.preventDefault(); + this.ui.error.hide(); let view = this; let data = this.ui.form.serializeJSON(); @@ -59,7 +61,7 @@ module.exports = Mn.View.extend({ App.UI.closeModal(); }) .catch(err => { - alert(err.message); + this.ui.error.text(err.message).show(); this.ui.buttons.prop('disabled', false).removeClass('btn-disabled'); }); }