Allow setting a monitoring flag. Confirmation mail missing.
This commit is contained in:
parent
2fb4e9a227
commit
1b173b79d4
8 changed files with 254 additions and 19 deletions
|
@ -13,6 +13,10 @@ angular.module('ffffng')
|
|||
geolib,
|
||||
OutsideOfCommunityDialog
|
||||
) {
|
||||
var initialEmail = $scope.node.email;
|
||||
var initialMonitoring = $scope.node.monitoring;
|
||||
var monitoringConfirmed = $scope.node.monitoringConfirmed;
|
||||
|
||||
$scope.config = config;
|
||||
angular.extend($scope, {
|
||||
center: {
|
||||
|
@ -119,6 +123,15 @@ angular.module('ffffng')
|
|||
return $scope.nodeForm && $scope.nodeForm[field].$invalid && submitted;
|
||||
};
|
||||
|
||||
$scope.monitoringInitialConfirmationRequired = function () {
|
||||
return $scope.node.monitoring
|
||||
&& ($scope.action === 'create' || $scope.node.email !== initialEmail || !initialMonitoring);
|
||||
};
|
||||
|
||||
$scope.monitoringConfirmationPending = function () {
|
||||
return $scope.node.monitoring && initialMonitoring && !monitoringConfirmed;
|
||||
};
|
||||
|
||||
var duplicateError = {
|
||||
hostname: 'Der Knotenname ist bereits vergeben. Bitte wähle einen anderen.',
|
||||
key: 'Für den VPN-Schlüssel gibt es bereits einen Eintrag.',
|
||||
|
|
11
app/styles/_mixins.scss
Normal file
11
app/styles/_mixins.scss
Normal file
|
@ -0,0 +1,11 @@
|
|||
@mixin not-selectable {
|
||||
user-select: none;
|
||||
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
}
|
||||
|
||||
%not-selectable {
|
||||
@include not-selectable;
|
||||
}
|
|
@ -173,9 +173,9 @@ $pager-disabled-color: $gray;
|
|||
|
||||
|
||||
// Form States
|
||||
$state-warning-text: darken($brand-warning, 10%);
|
||||
$state-warning-bg: lighten($brand-warning, 30%);
|
||||
$state-warning-border: darken(adjust-hue($state-warning-bg, -10), 3%);
|
||||
$state-warning-text: darken($brand-warning, 30%);
|
||||
$state-warning-bg: lighten($brand-warning, 20%);
|
||||
$state-warning-border: darken(adjust-hue($state-warning-bg, -10), 5%);
|
||||
$state-danger-text: darken($brand-danger, 10%);
|
||||
$state-danger-bg: lighten($brand-danger, 30%);
|
||||
$state-danger-border: darken(adjust-hue($state-danger-bg, -10), 3%);
|
||||
|
@ -184,7 +184,7 @@ $state-success-bg: lighten($brand-success, 30%);
|
|||
$state-success-border: darken(adjust-hue($state-success-bg, -10), 5%);
|
||||
$state-info-text: darken($brand-info, 20%);
|
||||
$state-info-bg: lighten($brand-info, 30%);
|
||||
$state-info-border: darken(adjust-hue($state-info-bg, -10), 7%);
|
||||
$state-info-border: darken(adjust-hue($state-info-bg, -10), 10%);
|
||||
|
||||
|
||||
// ToolTip
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
@import "_variables";
|
||||
|
||||
@import "_mixins";
|
||||
|
||||
@import "../bower_components/sass-bootstrap/lib/bootstrap";
|
||||
@import "../bower_components/font-awesome/scss/font-awesome";
|
||||
|
||||
|
@ -26,7 +28,7 @@ input {
|
|||
}
|
||||
|
||||
label {
|
||||
@extend .control-label;
|
||||
@extend .control-label, %not-selectable;
|
||||
|
||||
margin-top: 10px;
|
||||
cursor: pointer;
|
||||
|
|
|
@ -7,11 +7,11 @@ f-node-form {
|
|||
@extend .alert, .alert-danger;
|
||||
}
|
||||
|
||||
.node-data, .contact-data, .node-position {
|
||||
.node-data, .contact-data, .node-position, .monitoring-data {
|
||||
@extend .well;
|
||||
}
|
||||
|
||||
.hostname, .key, .mac, .nickname, .email, .coords {
|
||||
.hostname, .key, .mac, .nickname, .email, .coords, .monitoring {
|
||||
@extend .form-group;
|
||||
|
||||
.feedback {
|
||||
|
@ -28,6 +28,56 @@ f-node-form {
|
|||
}
|
||||
}
|
||||
|
||||
.monitoring {
|
||||
display: table;
|
||||
|
||||
label {
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
input {
|
||||
display: table-cell;
|
||||
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
|
||||
margin: {
|
||||
top: 0;
|
||||
right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.monitoring-icon {
|
||||
@extend .fa, .fa-heartbeat, .pull-left;
|
||||
|
||||
font-size: 36px;
|
||||
color: $brand-primary;
|
||||
}
|
||||
|
||||
.monitoring-confirmation-info {
|
||||
@extend .alert, .alert-info;
|
||||
}
|
||||
|
||||
.monitoring-confirmation-pending-info {
|
||||
@extend .alert, .alert-warning;
|
||||
}
|
||||
|
||||
.monitoring-confirmation-info, .monitoring-confirmation-pending-info {
|
||||
display: table;
|
||||
|
||||
.icon {
|
||||
@extend .fa, .fa-exclamation-triangle;
|
||||
|
||||
font-size: 24px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.icon, .message {
|
||||
display: table-cell;
|
||||
}
|
||||
}
|
||||
|
||||
.coords input.has-coords {
|
||||
padding-right: 25px;
|
||||
}
|
||||
|
|
|
@ -83,6 +83,65 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="monitoring-data">
|
||||
<h3>Möchtest Du Status-E-Mails bekommen?</h3>
|
||||
<i class="monitoring-icon"></i>
|
||||
<p class="help-block">
|
||||
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
|
||||
</p>
|
||||
<div class="row clearfix">
|
||||
<div class="col-md-12">
|
||||
<div class="monitoring">
|
||||
<input type="checkbox" id="monitoring" name="monitoring" ng-model="node.monitoring" />
|
||||
<label for="monitoring">
|
||||
Informiert mich, wenn mein Knoten offline ist
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12" ng-if="monitoringInitialConfirmationRequired()">
|
||||
<div class="monitoring-confirmation-info" role="alert">
|
||||
<i class="icon"></i>
|
||||
<div class="message">
|
||||
<p>
|
||||
Zur Bestätigung Deiner E-Mail-Adresse schicken wir Dir nach dem Speichern Deiner Knotendaten
|
||||
eine E-Mail mit einem Bestätiguns-Link. Erst nach der Bestätigung deiner E-Mail-Adresse
|
||||
wirst Du informiert, falls Dein Knoten längere Zeit offline ist.
|
||||
</p>
|
||||
<p>
|
||||
Die Inbetriebnahme Deines Knotens kannst Du selbstverständlich unabhängig von der Bestätigung
|
||||
immer sofort duchführen.
|
||||
</p>
|
||||
<p ng-if="node.email">
|
||||
<i class="fa fa-envelope-o"></i> <strong>{{node.email}}</strong>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12" ng-if="monitoringConfirmationPending() && !monitoringInitialConfirmationRequired()">
|
||||
<div class="monitoring-confirmation-pending-info" role="alert">
|
||||
<i class="icon"></i>
|
||||
<div class="message">
|
||||
<p>
|
||||
Deine E-Mail-Adresse ist noch nicht bestätigt. Erst nach der Bestätigung deiner E-Mail-Adresse
|
||||
wirst Du informiert, falls Dein Knoten längere Zeit offline ist.
|
||||
</p>
|
||||
<p>
|
||||
Zur Bestätigung Deiner E-Mail-Adresse schicken wir Dir nach einem Klick auf „Daten ändern“ unten
|
||||
nochmal eine E-Mail mit einem Bestätiguns-Link. Möchtest Du keine Status-E-Mails erhalten,
|
||||
entferne einfach das Häkchen oberhalb dieser Box.
|
||||
</p>
|
||||
<p>
|
||||
Die Inbetriebnahme Deines Knotens kannst Du selbstverständlich unabhängig von der Bestätigung
|
||||
immer sofort duchführen.
|
||||
</p>
|
||||
<p ng-if="node.email">
|
||||
<i class="fa fa-envelope-o"></i> <strong>{{node.email}}</strong>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<button class="save {{action}}" type="submit" ng-switch="action">
|
||||
<span ng-switch-when="create"><i class="fa fa-dot-circle-o"></i> Knoten anmelden</span>
|
||||
|
|
|
@ -12,7 +12,7 @@ angular.module('ffffng').factory('NodeResource', function (
|
|||
return _.extend({}, req.body, req.params);
|
||||
}
|
||||
|
||||
var nodeFields = ['hostname', 'key', 'email', 'nickname', 'mac', 'coords'];
|
||||
var nodeFields = ['hostname', 'key', 'email', 'nickname', 'mac', 'coords', 'monitoring'];
|
||||
|
||||
function getValidNodeData(reqData) {
|
||||
var node = {};
|
||||
|
|
|
@ -8,7 +8,9 @@ angular.module('ffffng')
|
|||
email: '# Kontakt: ',
|
||||
coords: '# Koordinaten: ',
|
||||
mac: '# MAC: ',
|
||||
token: '# Token: '
|
||||
token: '# Token: ',
|
||||
monitoring: '# Monitoring: ',
|
||||
monitoringToken: '# Monitoring-Token: '
|
||||
};
|
||||
|
||||
function generateToken() {
|
||||
|
@ -50,15 +52,34 @@ angular.module('ffffng')
|
|||
return null;
|
||||
}
|
||||
|
||||
function writeNodeFile(isUpdate, token, node, callback) {
|
||||
function writeNodeFile(isUpdate, token, node, nodeSecrets, callback) {
|
||||
var filename =
|
||||
config.server.peersPath + '/' + (node.hostname + '@' + node.mac + '@' + node.key + '@' + token).toLowerCase();
|
||||
|
||||
var data = '';
|
||||
_.each(linePrefixes, function (prefix, key) {
|
||||
var value = key === 'token' ? token : node[key];
|
||||
if (_.isUndefined(value)) {
|
||||
value = '';
|
||||
var value;
|
||||
switch (key) {
|
||||
case 'monitoring':
|
||||
if (node.monitoring && node.monitoringConfirmed) {
|
||||
value = 'aktiv';
|
||||
} else if (node.monitoring && !node.monitoringConfirmed) {
|
||||
value = 'pending';
|
||||
} else {
|
||||
value = '';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'monitoringToken':
|
||||
value = nodeSecrets.monitoringToken || '';
|
||||
break;
|
||||
|
||||
default:
|
||||
value = key === 'token' ? token : node[key];
|
||||
if (_.isUndefined(value)) {
|
||||
value = _.isUndefined(nodeSecrets[key]) ? '' : nodeSecrets[key];
|
||||
}
|
||||
break;
|
||||
}
|
||||
data += prefix + value + '\n';
|
||||
});
|
||||
|
@ -81,8 +102,14 @@ angular.module('ffffng')
|
|||
return callback(error);
|
||||
}
|
||||
|
||||
var file = files[0];
|
||||
fs.unlinkSync(file);
|
||||
try {
|
||||
var file = files[0];
|
||||
fs.unlinkSync(file);
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error);
|
||||
return callback({data: 'Could not remove old node data.', type: ErrorTypes.internalError});
|
||||
}
|
||||
} else {
|
||||
error = checkNoDuplicates(null, node);
|
||||
if (error) {
|
||||
|
@ -122,6 +149,7 @@ angular.module('ffffng')
|
|||
var lines = fs.readFileSync(file).toString();
|
||||
|
||||
var node = {};
|
||||
var nodeSecrets = {};
|
||||
|
||||
_.each(lines.split('\n'), function (line) {
|
||||
var entries = {};
|
||||
|
@ -141,20 +169,92 @@ angular.module('ffffng')
|
|||
}
|
||||
|
||||
_.each(entries, function (value, key) {
|
||||
node[key] = value;
|
||||
if (key === 'monitoring') {
|
||||
var active = value === 'aktiv';
|
||||
var pending = value === 'pending';
|
||||
node.monitoring = active || pending;
|
||||
node.monitoringConfirmed = active;
|
||||
} else if (key === 'monitoringToken') {
|
||||
nodeSecrets.monitoringToken = value;
|
||||
} else {
|
||||
node[key] = value;
|
||||
}
|
||||
});
|
||||
});
|
||||
callback(null, node);
|
||||
|
||||
callback(null, node, nodeSecrets);
|
||||
}
|
||||
|
||||
return {
|
||||
createNode: function (node, callback) {
|
||||
var token = generateToken();
|
||||
writeNodeFile(false, token, node, callback);
|
||||
var nodeSecrets = {};
|
||||
|
||||
node.monitoringConfirmed = false;
|
||||
|
||||
if (node.monitoring) {
|
||||
nodeSecrets.monitoringToken = generateToken();
|
||||
}
|
||||
|
||||
writeNodeFile(false, token, node, nodeSecrets, function (err, token, node) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (node.monitoring && !node.monitoringConfirmed) {
|
||||
// TODO: Send mail...
|
||||
}
|
||||
|
||||
return callback(null, token, node);
|
||||
});
|
||||
},
|
||||
|
||||
updateNode: function (token, node, callback) {
|
||||
writeNodeFile(true, token, node, callback);
|
||||
this.getNodeData(token, function (err, currentNode, nodeSecrets) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
var monitoringConfirmed = false;
|
||||
var monitoringToken = '';
|
||||
|
||||
if (node.monitoring) {
|
||||
if (!currentNode.monitoring) {
|
||||
// monitoring just has been enabled
|
||||
monitoringConfirmed = false;
|
||||
monitoringToken = generateToken();
|
||||
|
||||
} else {
|
||||
// monitoring is still enabled
|
||||
|
||||
if (currentNode.email != node.email) {
|
||||
// new email so we need a new token and a reconfirmation
|
||||
monitoringConfirmed = false;
|
||||
monitoringToken = generateToken();
|
||||
|
||||
} else {
|
||||
// email unchanged, keep token and confirmation state
|
||||
monitoringConfirmed = currentNode.monitoringConfirmed;
|
||||
monitoringToken = nodeSecrets.monitoringToken;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
node.monitoringConfirmed = monitoringConfirmed;
|
||||
nodeSecrets.monitoringToken = monitoringToken;
|
||||
|
||||
writeNodeFile(true, token, node, nodeSecrets, function (err, token, node) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (node.monitoring && !node.monitoringConfirmed) {
|
||||
// TODO: Send mail...
|
||||
}
|
||||
|
||||
return callback(null, token, node);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
deleteNode: function (token, callback) {
|
||||
|
|
Loading…
Reference in a new issue