Allow serving everything beneath a baseUrl with a path.
See: https://github.com/freifunkhamburg/ffffng/issues/44
This commit is contained in:
parent
3d6fb5feec
commit
8de06a0a8a
|
@ -108,7 +108,7 @@ cp $FFFFNG_HOME/node_modules/ffffng/config.json.example $FFFFNG_HOME/config.json
|
||||||
Dann die `config.json` anpassen nach belieben. Es gibt die folgenden Konfigurations-Optionen:
|
Dann die `config.json` anpassen nach belieben. Es gibt die folgenden Konfigurations-Optionen:
|
||||||
|
|
||||||
* **`server.baseUrl`** Basis-URL unter der die Knotenverwaltung erreichbar ist, z. B.:
|
* **`server.baseUrl`** Basis-URL unter der die Knotenverwaltung erreichbar ist, z. B.:
|
||||||
`"https://formular.musterstadt.freifunk.net"`
|
`"https://formular.musterstadt.freifunk.net"` oder `"https://musterstadt.freifunk.net/formular"`
|
||||||
* **`server.port`** Port unter dem der Server lokal läuft, z. B.: `8080`
|
* **`server.port`** Port unter dem der Server lokal läuft, z. B.: `8080`
|
||||||
|
|
||||||
* **`server.databaseFile`** Pfad zur Datenbank-Datei, z. B.: `"$FFFFNG_HOME/ffffng.sqlite"`
|
* **`server.databaseFile`** Pfad zur Datenbank-Datei, z. B.: `"$FFFFNG_HOME/ffffng.sqlite"`
|
||||||
|
|
|
@ -80,6 +80,6 @@
|
||||||
<script src="js/views/taskActionButton.js"></script>
|
<script src="js/views/taskActionButton.js"></script>
|
||||||
|
|
||||||
<script src="js/main.js"></script>
|
<script src="js/main.js"></script>
|
||||||
<script src="/config.js"></script>
|
<script src="../../config.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -40,6 +40,8 @@ angular.module('ffffngAdmin').config(function(NgAdminConfigurationProvider, Rest
|
||||||
var admin = nga.application(title);
|
var admin = nga.application(title);
|
||||||
document.title = title;
|
document.title = title;
|
||||||
|
|
||||||
|
var pathPrefix = config.rootPath === '/' ? '' : config.rootPath;
|
||||||
|
|
||||||
admin
|
admin
|
||||||
.header(
|
.header(
|
||||||
'<div class="navbar-header">' +
|
'<div class="navbar-header">' +
|
||||||
|
@ -59,12 +61,12 @@ angular.module('ffffngAdmin').config(function(NgAdminConfigurationProvider, Rest
|
||||||
'</a>' +
|
'</a>' +
|
||||||
'</p>' +
|
'</p>' +
|
||||||
'<p class="navbar-text navbar-right">' +
|
'<p class="navbar-text navbar-right">' +
|
||||||
'<a href="/" target="_blank">' +
|
'<a href="' + pathPrefix + '/" target="_blank">' +
|
||||||
'<i class="fa fa-external-link" aria-hidden="true"></i> Frontend' +
|
'<i class="fa fa-external-link" aria-hidden="true"></i> Frontend' +
|
||||||
'</a>' +
|
'</a>' +
|
||||||
'</p>'
|
'</p>'
|
||||||
)
|
)
|
||||||
.baseApiUrl('/internal/api/')
|
.baseApiUrl(pathPrefix + '/internal/api/')
|
||||||
.debug(true);
|
.debug(true);
|
||||||
|
|
||||||
function nodeClasses(node) {
|
function nodeClasses(node) {
|
||||||
|
@ -374,7 +376,7 @@ angular.module('ffffngAdmin').config(function(NgAdminConfigurationProvider, Rest
|
||||||
.addChild(nga
|
.addChild(nga
|
||||||
.menu()
|
.menu()
|
||||||
.template(
|
.template(
|
||||||
'<a href="/internal/admin">' +
|
'<a href="' + pathPrefix + '/internal/admin">' +
|
||||||
'<span class="fa fa-dashboard"></span> Dashboard / Statistics' +
|
'<span class="fa fa-dashboard"></span> Dashboard / Statistics' +
|
||||||
'</a>'
|
'</a>'
|
||||||
)
|
)
|
||||||
|
@ -398,7 +400,7 @@ angular.module('ffffngAdmin').config(function(NgAdminConfigurationProvider, Rest
|
||||||
.addChild(nga
|
.addChild(nga
|
||||||
.menu()
|
.menu()
|
||||||
.template(
|
.template(
|
||||||
'<a href="/internal/logs" target="_blank">' +
|
'<a href="' + pathPrefix + '/internal/logs" target="_blank">' +
|
||||||
'<span class="fa fa-list"></span> Logs' +
|
'<span class="fa fa-list"></span> Logs' +
|
||||||
'</a>'
|
'</a>'
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('ffffngAdmin')
|
angular.module('ffffngAdmin')
|
||||||
.directive('faDashboardStats', function ($http, $state, notification) {
|
.directive('faDashboardStats', function ($http, $state, notification, config) {
|
||||||
|
var pathPrefix = config.rootPath === '/' ? '' : config.rootPath;
|
||||||
|
|
||||||
var link = function (scope) {
|
var link = function (scope) {
|
||||||
scope.stats = {};
|
scope.stats = {};
|
||||||
$http.get('/internal/api/statistics')
|
$http.get(pathPrefix + '/internal/api/statistics')
|
||||||
.then(function (result) { scope.stats = result.data; })
|
.then(function (result) { scope.stats = result.data; })
|
||||||
.catch(function (e) {
|
.catch(function (e) {
|
||||||
notification.log('Error: ' + e.data, { addnCls: 'humane-flatty-error' });
|
notification.log('Error: ' + e.data, { addnCls: 'humane-flatty-error' });
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('ffffngAdmin')
|
angular.module('ffffngAdmin')
|
||||||
.directive('faMailActionButton', function (Restangular, $state, notification) {
|
.directive('faMailActionButton', function (Restangular, $state, notification, config) {
|
||||||
|
var pathPrefix = config.rootPath === '/' ? '' : config.rootPath;
|
||||||
|
|
||||||
var link = function (scope) {
|
var link = function (scope) {
|
||||||
scope.label = scope.label || 'ACTION';
|
scope.label = scope.label || 'ACTION';
|
||||||
scope.icon = scope.icon || 'envelope';
|
scope.icon = scope.icon || 'envelope';
|
||||||
|
@ -11,7 +13,7 @@ angular.module('ffffngAdmin')
|
||||||
var mail = scope.mail();
|
var mail = scope.mail();
|
||||||
|
|
||||||
Restangular
|
Restangular
|
||||||
.one('/internal/api/mails/' + scope.action, mail.values.id).put()
|
.one(pathPrefix + '/internal/api/mails/' + scope.action, mail.values.id).put()
|
||||||
.then(function () { $state.reload() })
|
.then(function () { $state.reload() })
|
||||||
.then(function () { notification.log('Done', { addnCls: 'humane-flatty-success' }); })
|
.then(function () { notification.log('Done', { addnCls: 'humane-flatty-success' }); })
|
||||||
.catch(function (e) {
|
.catch(function (e) {
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('ffffngAdmin')
|
angular.module('ffffngAdmin')
|
||||||
.directive('faTaskActionButton', function (Restangular, $state, notification) {
|
.directive('faTaskActionButton', function (Restangular, $state, notification, config) {
|
||||||
|
var pathPrefix = config.rootPath === '/' ? '' : config.rootPath;
|
||||||
|
|
||||||
var link = function (scope) {
|
var link = function (scope) {
|
||||||
scope.label = scope.label || 'ACTION';
|
scope.label = scope.label || 'ACTION';
|
||||||
scope.icon = scope.icon || 'play';
|
scope.icon = scope.icon || 'play';
|
||||||
|
@ -11,7 +13,7 @@ angular.module('ffffngAdmin')
|
||||||
var task = scope.task();
|
var task = scope.task();
|
||||||
|
|
||||||
Restangular
|
Restangular
|
||||||
.one('/internal/api/tasks/' + scope.action, task.values.id).put()
|
.one(pathPrefix + '/internal/api/tasks/' + scope.action, task.values.id).put()
|
||||||
.then(function () { $state.reload() })
|
.then(function () { $state.reload() })
|
||||||
.then(function () { notification.log('Done', { addnCls: 'humane-flatty-success' }); })
|
.then(function () { notification.log('Done', { addnCls: 'humane-flatty-success' }); })
|
||||||
.catch(function (e) {
|
.catch(function (e) {
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('ffffngAdmin')
|
angular.module('ffffngAdmin')
|
||||||
.directive('faVersion', function ($http, $state, notification) {
|
.directive('faVersion', function ($http, $state, notification, config) {
|
||||||
|
var pathPrefix = config.rootPath === '/' ? '' : config.rootPath;
|
||||||
|
|
||||||
var link = function (scope) {
|
var link = function (scope) {
|
||||||
scope.version = '?';
|
scope.version = '?';
|
||||||
$http.get('/api/version')
|
$http.get(pathPrefix + '/api/version')
|
||||||
.then(function (result) { scope.version = result.data.version; })
|
.then(function (result) { scope.version = result.data.version; })
|
||||||
.catch(function (e) {
|
.catch(function (e) {
|
||||||
notification.log('Error: ' + e.data, { addnCls: 'humane-flatty-error' });
|
notification.log('Error: ' + e.data, { addnCls: 'humane-flatty-error' });
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('ffffng')
|
angular.module('ffffng')
|
||||||
.directive('fFooter', function ($http) {
|
.directive('fFooter', function ($http, config) {
|
||||||
|
var pathPrefix = config.rootPath === '/' ? '' : config.rootPath;
|
||||||
|
|
||||||
var ctrl = function ($scope) {
|
var ctrl = function ($scope) {
|
||||||
$scope.version = '?';
|
$scope.version = '?';
|
||||||
$http.get('/api/version')
|
$http.get(pathPrefix + '/api/version')
|
||||||
.then(function (result) { $scope.version = result.data.version; });
|
.then(function (result) { $scope.version = result.data.version; });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,22 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('ffffng')
|
angular.module('ffffng')
|
||||||
.service('MonitoringService', function ($http, $q) {
|
.service('MonitoringService', function ($http, $q, config) {
|
||||||
|
var pathPrefix = config.rootPath === '/' ? '' : config.rootPath;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'confirm': function (token) {
|
'confirm': function (token) {
|
||||||
if (!token) {
|
if (!token) {
|
||||||
return $q.reject({});
|
return $q.reject({});
|
||||||
}
|
}
|
||||||
return $http.put('/api/monitoring/confirm/' + token);
|
return $http.put(pathPrefix + '/api/monitoring/confirm/' + token);
|
||||||
},
|
},
|
||||||
|
|
||||||
'disable': function (token) {
|
'disable': function (token) {
|
||||||
if (!token) {
|
if (!token) {
|
||||||
return $q.reject({});
|
return $q.reject({});
|
||||||
}
|
}
|
||||||
return $http.put('/api/monitoring/disable/' + token);
|
return $http.put(pathPrefix + '/api/monitoring/disable/' + token);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,22 +1,24 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('ffffng')
|
angular.module('ffffng')
|
||||||
.service('NodeService', function ($http) {
|
.service('NodeService', function ($http, config) {
|
||||||
|
var pathPrefix = config.rootPath === '/' ? '' : config.rootPath;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'createNode': function (node) {
|
'createNode': function (node) {
|
||||||
return $http.post('/api/node', node);
|
return $http.post(pathPrefix + '/api/node', node);
|
||||||
},
|
},
|
||||||
|
|
||||||
'updateNode': function (node, token) {
|
'updateNode': function (node, token) {
|
||||||
return $http.put('/api/node/' + token, node);
|
return $http.put(pathPrefix + '/api/node/' + token, node);
|
||||||
},
|
},
|
||||||
|
|
||||||
'deleteNode': function (token) {
|
'deleteNode': function (token) {
|
||||||
return $http.delete('/api/node/' + token);
|
return $http.delete(pathPrefix + '/api/node/' + token);
|
||||||
},
|
},
|
||||||
|
|
||||||
'getNode': function (token) {
|
'getNode': function (token) {
|
||||||
return $http.get('/api/node/' + token);
|
return $http.get(pathPrefix + '/api/node/' + token);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,6 +7,7 @@ angular.module('ffffng').factory('app', function (fs, config, _) {
|
||||||
var compress = require('compression');
|
var compress = require('compression');
|
||||||
|
|
||||||
var app = express();
|
var app = express();
|
||||||
|
var router = express.Router();
|
||||||
|
|
||||||
// urls beneath /internal are protected
|
// urls beneath /internal are protected
|
||||||
var internalAuth = auth.basic(
|
var internalAuth = auth.basic(
|
||||||
|
@ -21,10 +22,10 @@ angular.module('ffffng').factory('app', function (fs, config, _) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
app.use('/internal', auth.connect(internalAuth));
|
router.use('/internal', auth.connect(internalAuth));
|
||||||
|
|
||||||
app.use(bodyParser.json());
|
router.use(bodyParser.json());
|
||||||
app.use(bodyParser.urlencoded({ extended: true }));
|
router.use(bodyParser.urlencoded({ extended: true }));
|
||||||
|
|
||||||
var adminDir = __dirname + '/../admin';
|
var adminDir = __dirname + '/../admin';
|
||||||
var clientDir = __dirname + '/../client';
|
var clientDir = __dirname + '/../client';
|
||||||
|
@ -34,7 +35,7 @@ angular.module('ffffng').factory('app', function (fs, config, _) {
|
||||||
'/config.js'
|
'/config.js'
|
||||||
];
|
];
|
||||||
|
|
||||||
app.use(compress());
|
router.use(compress());
|
||||||
|
|
||||||
function serveTemplate(mimeType, req, res, next) {
|
function serveTemplate(mimeType, req, res, next) {
|
||||||
return fs.readFile(templateDir + '/' + req.path, 'utf8', function (err, body) {
|
return fs.readFile(templateDir + '/' + req.path, 'utf8', function (err, body) {
|
||||||
|
@ -49,15 +50,17 @@ angular.module('ffffng').factory('app', function (fs, config, _) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
app.use(function (req, res, next) {
|
router.use(function (req, res, next) {
|
||||||
if (jsTemplateFiles.indexOf(req.path) >= 0) {
|
if (jsTemplateFiles.indexOf(req.path) >= 0) {
|
||||||
return serveTemplate('application/javascript', req, res, next);
|
return serveTemplate('application/javascript', req, res, next);
|
||||||
}
|
}
|
||||||
return next();
|
return next();
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use('/internal/admin', express.static(adminDir + '/'));
|
router.use('/internal/admin', express.static(adminDir + '/'));
|
||||||
app.use('/', express.static(clientDir + '/'));
|
router.use('/', express.static(clientDir + '/'));
|
||||||
|
|
||||||
|
app.use(config.server.rootPath, router);
|
||||||
|
|
||||||
return app;
|
return app;
|
||||||
});
|
});
|
||||||
|
|
|
@ -140,6 +140,10 @@ var config = deepExtend({}, defaultConfig, configJSON);
|
||||||
stripTrailingSlash(config.server, 'baseUrl');
|
stripTrailingSlash(config.server, 'baseUrl');
|
||||||
stripTrailingSlash(config.client.map, 'mapUrl');
|
stripTrailingSlash(config.client.map, 'mapUrl');
|
||||||
|
|
||||||
|
var url = require('url');
|
||||||
|
config.server.rootPath = url.parse(config.server.baseUrl).pathname;
|
||||||
|
config.client.rootPath = config.server.rootPath;
|
||||||
|
|
||||||
module.exports = config;
|
module.exports = config;
|
||||||
|
|
||||||
angular.module('ffffng').constant('config', config);
|
angular.module('ffffng').constant('config', config);
|
||||||
|
|
|
@ -38,7 +38,8 @@ angular.module('ffffng').factory('Logger', function (app) {
|
||||||
app.use(scribe.express.logger());
|
app.use(scribe.express.logger());
|
||||||
}
|
}
|
||||||
if (config.server.internal.active) {
|
if (config.server.internal.active) {
|
||||||
app.use('/internal/logs', scribe.webPanel());
|
var prefix = config.server.rootPath === '/' ? '' : config.server.rootPath;
|
||||||
|
app.use(prefix + '/internal/logs', scribe.webPanel());
|
||||||
}
|
}
|
||||||
|
|
||||||
return process.console;
|
return process.console;
|
||||||
|
|
|
@ -8,40 +8,46 @@ angular.module('ffffng').factory('Router', function (
|
||||||
NodeResource,
|
NodeResource,
|
||||||
MonitoringResource,
|
MonitoringResource,
|
||||||
TaskResource,
|
TaskResource,
|
||||||
MailResource
|
MailResource,
|
||||||
|
config
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
init: function () {
|
init: function () {
|
||||||
app.post('/', FrontendResource.render);
|
var express = require('express');
|
||||||
|
var router = express.Router();
|
||||||
|
|
||||||
app.get('/api/version', VersionResource.get);
|
router.post('/', FrontendResource.render);
|
||||||
|
|
||||||
app.post('/api/node', NodeResource.create);
|
router.get('/api/version', VersionResource.get);
|
||||||
app.put('/api/node/:token', NodeResource.update);
|
|
||||||
app.delete('/api/node/:token', NodeResource.delete);
|
|
||||||
app.get('/api/node/:token', NodeResource.get);
|
|
||||||
|
|
||||||
app.put('/api/monitoring/confirm/:token', MonitoringResource.confirm);
|
router.post('/api/node', NodeResource.create);
|
||||||
app.put('/api/monitoring/disable/:token', MonitoringResource.disable);
|
router.put('/api/node/:token', NodeResource.update);
|
||||||
|
router.delete('/api/node/:token', NodeResource.delete);
|
||||||
|
router.get('/api/node/:token', NodeResource.get);
|
||||||
|
|
||||||
app.get('/internal/api/statistics', StatisticsResource.get);
|
router.put('/api/monitoring/confirm/:token', MonitoringResource.confirm);
|
||||||
|
router.put('/api/monitoring/disable/:token', MonitoringResource.disable);
|
||||||
|
|
||||||
app.get('/internal/api/tasks', TaskResource.getAll);
|
router.get('/internal/api/statistics', StatisticsResource.get);
|
||||||
app.put('/internal/api/tasks/run/:id', TaskResource.run);
|
|
||||||
app.put('/internal/api/tasks/enable/:id', TaskResource.enable);
|
|
||||||
app.put('/internal/api/tasks/disable/:id', TaskResource.disable);
|
|
||||||
|
|
||||||
app.get('/internal/api/monitoring', MonitoringResource.getAll);
|
router.get('/internal/api/tasks', TaskResource.getAll);
|
||||||
|
router.put('/internal/api/tasks/run/:id', TaskResource.run);
|
||||||
|
router.put('/internal/api/tasks/enable/:id', TaskResource.enable);
|
||||||
|
router.put('/internal/api/tasks/disable/:id', TaskResource.disable);
|
||||||
|
|
||||||
app.get('/internal/api/mails', MailResource.getAll);
|
router.get('/internal/api/monitoring', MonitoringResource.getAll);
|
||||||
app.get('/internal/api/mails/:id', MailResource.get);
|
|
||||||
app.delete('/internal/api/mails/:id', MailResource.delete);
|
|
||||||
app.put('/internal/api/mails/reset/:id', MailResource.resetFailures);
|
|
||||||
|
|
||||||
app.put('/internal/api/nodes/:token', NodeResource.update);
|
router.get('/internal/api/mails', MailResource.getAll);
|
||||||
app.delete('/internal/api/nodes/:token', NodeResource.delete);
|
router.get('/internal/api/mails/:id', MailResource.get);
|
||||||
app.get('/internal/api/nodes', NodeResource.getAll);
|
router.delete('/internal/api/mails/:id', MailResource.delete);
|
||||||
app.get('/internal/api/nodes/:token', NodeResource.get);
|
router.put('/internal/api/mails/reset/:id', MailResource.resetFailures);
|
||||||
|
|
||||||
|
router.put('/internal/api/nodes/:token', NodeResource.update);
|
||||||
|
router.delete('/internal/api/nodes/:token', NodeResource.delete);
|
||||||
|
router.get('/internal/api/nodes', NodeResource.getAll);
|
||||||
|
router.get('/internal/api/nodes/:token', NodeResource.get);
|
||||||
|
|
||||||
|
app.use(config.server.rootPath, router);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue