Added delete feature for nodes.
This commit is contained in:
parent
39e7af6238
commit
79aadc85c2
20 changed files with 300 additions and 20 deletions
|
@ -49,6 +49,7 @@
|
|||
<script src="scripts/controllers/main.js"></script>
|
||||
<script src="scripts/controllers/newNodeCtrl.js"></script>
|
||||
<script src="scripts/controllers/updateNodeCtrl.js"></script>
|
||||
<script src="scripts/controllers/deleteNodeCtrl.js"></script>
|
||||
|
||||
<script src="scripts/services/nodeService.js"></script>
|
||||
|
||||
|
@ -58,6 +59,7 @@
|
|||
<script src="scripts/directives/nodeSaved.js"></script>
|
||||
<script src="scripts/directives/tokenForm.js"></script>
|
||||
|
||||
<script src="scripts/dialogs/confirmDeletionDialog.js"></script>
|
||||
<script src="scripts/dialogs/outsideOfCommunityDialog.js"></script>
|
||||
|
||||
<script src="scripts/validation/constraints.js"></script>
|
||||
|
|
|
@ -25,6 +25,11 @@ angular.module('ffffng', [
|
|||
controller: 'UpdateNodeCtrl',
|
||||
title: 'Knotendaten ändern'
|
||||
})
|
||||
.when('/delete', {
|
||||
templateUrl: 'views/deleteNodeForm.html',
|
||||
controller: 'DeleteNodeCtrl',
|
||||
title: 'Knoten löschen'
|
||||
})
|
||||
.otherwise({
|
||||
redirectTo: '/'
|
||||
});
|
||||
|
@ -39,6 +44,9 @@ angular.module('ffffng', [
|
|||
},
|
||||
updateNode: function () {
|
||||
$location.url('/update');
|
||||
},
|
||||
deleteNode: function () {
|
||||
$location.url('/delete');
|
||||
}
|
||||
};
|
||||
})
|
||||
|
|
26
app/scripts/controllers/deleteNodeCtrl.js
Normal file
26
app/scripts/controllers/deleteNodeCtrl.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('ffffng')
|
||||
.controller('DeleteNodeCtrl', function ($scope, Navigator, NodeService, config, ConfirmDeletionDialog) {
|
||||
$scope.config = config;
|
||||
$scope.token = undefined;
|
||||
$scope.deleted = false;
|
||||
|
||||
$scope.onSubmitToken = function (token) {
|
||||
$scope.token = token;
|
||||
return NodeService.getNode(token)
|
||||
.success(function (node) {
|
||||
ConfirmDeletionDialog.open(node).result.then(function () {
|
||||
NodeService.deleteNode(token)
|
||||
.success(function () {
|
||||
$scope.deleted = true;
|
||||
$scope.hostname = node.hostname;
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.cancel = function () {
|
||||
Navigator.home();
|
||||
};
|
||||
});
|
|
@ -11,4 +11,8 @@ angular.module('ffffng')
|
|||
$scope.updateNode = function () {
|
||||
Navigator.updateNode();
|
||||
};
|
||||
|
||||
$scope.deleteNode = function () {
|
||||
Navigator.deleteNode();
|
||||
};
|
||||
});
|
||||
|
|
29
app/scripts/dialogs/confirmDeletionDialog.js
Normal file
29
app/scripts/dialogs/confirmDeletionDialog.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('ffffng')
|
||||
.factory('ConfirmDeletionDialog', function ($uibModal, config) {
|
||||
var ctrl = function ($scope, $uibModalInstance, node) {
|
||||
$scope.node = node;
|
||||
$scope.config = config;
|
||||
|
||||
$scope.proceed = function () {
|
||||
$uibModalInstance.close();
|
||||
};
|
||||
|
||||
$scope.cancel = function () {
|
||||
$uibModalInstance.dismiss('cancel');
|
||||
};
|
||||
};
|
||||
|
||||
return {
|
||||
open: function (node) {
|
||||
return $uibModal.open({
|
||||
controller: ctrl,
|
||||
templateUrl: 'views/dialogs/confirmDeletionDialog.html',
|
||||
resolve: {
|
||||
node: function () { return node; }
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
|
@ -33,7 +33,9 @@ angular.module('ffffng')
|
|||
'templateUrl': 'views/directives/tokenForm.html',
|
||||
'scope': {
|
||||
'onSubmit': '=fSubmit',
|
||||
'onCancel': '=fCancel'
|
||||
'onCancel': '=fCancel',
|
||||
'submitIcon': '@fSubmitIcon',
|
||||
'submitLabel': '@fSubmitLabel'
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
@ -11,6 +11,10 @@ angular.module('ffffng')
|
|||
return $http.put('/api/node/' + token, node);
|
||||
},
|
||||
|
||||
'deleteNode': function (token) {
|
||||
return $http.delete('/api/node/' + token);
|
||||
},
|
||||
|
||||
'getNode': function (token) {
|
||||
return $http.get('/api/node/' + token);
|
||||
}
|
||||
|
|
|
@ -8,10 +8,12 @@
|
|||
@import "views/_main";
|
||||
@import "views/_newNodeForm";
|
||||
@import "views/_updateNodeForm";
|
||||
@import "views/_deleteNodeForm";
|
||||
@import "views/directives/_help";
|
||||
@import "views/directives/_nodeForm";
|
||||
@import "views/directives/_nodeSaved";
|
||||
@import "views/directives/_tokenForm";
|
||||
@import "views/dialogs/_confirmDeletionDialog";
|
||||
@import "views/dialogs/_outsideOfCommunityDialog";
|
||||
|
||||
body {
|
||||
|
|
44
app/styles/views/_deleteNodeForm.scss
Normal file
44
app/styles/views/_deleteNodeForm.scss
Normal file
|
@ -0,0 +1,44 @@
|
|||
.delete-node-form {
|
||||
@extend .container;
|
||||
}
|
||||
|
||||
.node-deleted {
|
||||
@extend .jumbotron, .container;
|
||||
|
||||
.summary, .actions {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.actions {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.token-hint {
|
||||
font: {
|
||||
weight: bold;
|
||||
size: 32px;
|
||||
}
|
||||
|
||||
text-align: center;
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
.summary {
|
||||
.node {
|
||||
@extend .well;
|
||||
|
||||
border: 3px dashed $gray;
|
||||
font-family: monospace;
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
margin: {
|
||||
top: 30px;
|
||||
bottom: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.back-button {
|
||||
@extend .btn, .btn-lg, .btn-info;
|
||||
}
|
||||
}
|
|
@ -9,11 +9,19 @@
|
|||
bottom: 25px;
|
||||
}
|
||||
|
||||
.new-node, .update-node {
|
||||
@extend .col-md-5;
|
||||
.new-node, .update-node, .delete-node {
|
||||
@extend .col-md-4;
|
||||
|
||||
button {
|
||||
@extend .btn, .btn-lg, .btn-block;
|
||||
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
|
||||
padding: {
|
||||
left: 10px;
|
||||
right: 10px;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,10 +37,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
.or {
|
||||
@extend .col-md-2;
|
||||
|
||||
text-align: center;
|
||||
.delete-node {
|
||||
button {
|
||||
//@extend .btn-link;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
33
app/styles/views/dialogs/_confirmDeletionDialog.scss
Normal file
33
app/styles/views/dialogs/_confirmDeletionDialog.scss
Normal file
|
@ -0,0 +1,33 @@
|
|||
.confirm-deletion-dialog {
|
||||
.modal-header {
|
||||
h3 {
|
||||
@extend .modal-title;
|
||||
}
|
||||
|
||||
.cancel-icon {
|
||||
@extend .fa, .fa-times;
|
||||
|
||||
position: relative;
|
||||
float: right;
|
||||
|
||||
top: 10px;
|
||||
right: 0;
|
||||
|
||||
margin-left: 15px;
|
||||
|
||||
cursor: pointer;
|
||||
color: $gray;
|
||||
}
|
||||
}
|
||||
.modal-footer {
|
||||
.proceed {
|
||||
@extend .btn;
|
||||
|
||||
margin-left: 5px;
|
||||
|
||||
&.proceed {
|
||||
@extend .btn-primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,8 @@
|
|||
f-token-form {
|
||||
form {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.main-error {
|
||||
@extend .alert, .alert-danger;
|
||||
}
|
||||
|
|
56
app/views/deleteNodeForm.html
Normal file
56
app/views/deleteNodeForm.html
Normal file
|
@ -0,0 +1,56 @@
|
|||
<div class="delete-node-form" ng-if="!deleted">
|
||||
<h2>Knoten löschen</h2>
|
||||
|
||||
<div>
|
||||
<p>
|
||||
Um die Daten Deines Knotens zu löschen, benötigen wir den passenden Token (eine 16-stellige Folge aus
|
||||
Ziffern und Buchstaben). Diesen hast Du beim ersten Anmelden Deines Knotens erhalten. Sinn des Tokens ist,
|
||||
Dich davor zu schützen, dass Dritte unbefugt Deine Daten einsehen oder ändern können.
|
||||
</p>
|
||||
<p>
|
||||
<strong>
|
||||
Solltest Du den Token nicht mehr haben, wende Dich einfach per E-Mail an
|
||||
<a href="mailto:{{ config.community.contactEmail }}">{{ config.community.contactEmail }}</a>.
|
||||
</strong>
|
||||
</p>
|
||||
<f-token-form f-submit="onSubmitToken" f-cancel="cancel" f-submit-icon="fa-trash" f-submit-label="Knoten löschen"></f-token-form>
|
||||
|
||||
<p>
|
||||
<em>
|
||||
Hinweis: Nach dem Löschen kann der Knoten ggf. weiterhin in der Knotenkarte angezeigt werden. Dies
|
||||
ist dann der Fall, wenn der Knoten eingeschaltet ist und in Reichweite eines anderen aktiven Knotens
|
||||
steht. Die angezeigten Daten sind dann die während der Einrichtung des Knotens im Config-Mode
|
||||
(Konfigurationsoberfläche des Routers) hinterlegten.
|
||||
</em>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="node-deleted" ng-if="deleted">
|
||||
<h1>Erledigt!</h1>
|
||||
<p>
|
||||
Die Daten Deines Freifunk-Knotens sind gelöscht worden. Es kann jetzt noch bis zu 20 Minuten dauern,
|
||||
bis die Änderungen überall wirksam werden und sich im <a href="{{ config.map.graphUrl }}" target="_blank">Knotengraph</a>
|
||||
und in der <a href="{{ config.map.mapUrl }}" target="_blank">Knotenkarte</a> auswirken.
|
||||
</p>
|
||||
|
||||
<div class="summary">
|
||||
<span class="node">
|
||||
<i class="fa fa-trash"></i>
|
||||
{{hostname}}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button class="back-button" ng-click="goHome()"><i class="fa fa-reply"></i> Zurück zum Anfang</button>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<em>
|
||||
Hinweis: Nach dem Löschen kann der Knoten ggf. weiterhin in der Knotenkarte angezeigt werden. Dies
|
||||
ist dann der Fall, wenn der Knoten eingeschaltet ist und in Reichweite eines anderen aktiven Knotens
|
||||
steht. Die angezeigten Daten sind dann die während der Einrichtung des Knotens im Config-Mode
|
||||
(Konfigurationsoberfläche des Routers) hinterlegten.
|
||||
</em>
|
||||
</p>
|
||||
</div>
|
18
app/views/dialogs/confirmDeletionDialog.html
Normal file
18
app/views/dialogs/confirmDeletionDialog.html
Normal file
|
@ -0,0 +1,18 @@
|
|||
<div class="confirm-deletion-dialog">
|
||||
<div class="modal-header">
|
||||
<i class="cancel-icon" ng-click="cancel()"></i>
|
||||
<h3>Soll der Knoten wirklich gelöscht werden?</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>
|
||||
Soll der Knoten „{{node.hostname}}“ wirklich endgültig gelöscht werden?
|
||||
Du kannst ihn selbstverständlich später jederzeit erneut anmelden!
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="cancel" ng-click="cancel()">Abbrechen</button>
|
||||
<button class="proceed" ng-click="proceed()">
|
||||
<i class="fa fa-trash"></i> Knoten löschen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
|
@ -10,7 +10,7 @@
|
|||
</div>
|
||||
<div class="buttons">
|
||||
<button class="submit" type="submit">
|
||||
<i class="fa fa-pencil"></i> Knotendaten ändern
|
||||
<i class="fa {{submitIcon}}"></i> {{submitLabel}}
|
||||
</button>
|
||||
<button class="cancel" type="reset" ng-click="onCancel()">
|
||||
<i class="fa fa-times"></i> Abbrechen
|
||||
|
|
|
@ -2,22 +2,24 @@
|
|||
<h1>Willkommen!</h1>
|
||||
<p>
|
||||
Du hast einen neuen {{ config.community.name }} Router (Knoten), den Du in Betrieb nehmen möchtest? Du hast
|
||||
schon einen Knoten in Betrieb und möchtest seine Daten ändern? Dann bist Du hier richtig!
|
||||
schon einen Knoten in Betrieb und möchtest seine Daten ändern? Oder Du möchtest einen Knoten, der nicht mehr
|
||||
in Betrieb ist löschen? Dann bist Du hier richtig!
|
||||
</p>
|
||||
<div class="select-action">
|
||||
<div class="new-node">
|
||||
<button ng-click="newNode()"><i class="fa fa-dot-circle-o"></i> Melde einen neuen Knoten an</button>
|
||||
<button ng-click="newNode()">
|
||||
<i class="fa fa-dot-circle-o"></i> Neuen Knoten anmelden
|
||||
</button>
|
||||
</div>
|
||||
<div class="or">oder</div>
|
||||
<div class="update-node">
|
||||
<button ng-click="updateNode()"><i class="fa fa-pencil"></i> Ändere die Daten Deines Knotens</button>
|
||||
<button ng-click="updateNode()">
|
||||
<i class="fa fa-pencil"></i> Knotendaten ändern
|
||||
</button>
|
||||
</div>
|
||||
<div class="delete-node">
|
||||
<button ng-click="deleteNode()">
|
||||
<i class="fa fa-trash"></i> Knoten löschen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
<strong>
|
||||
Hinweis:
|
||||
Zum Entfernen von Knoten wende Dich bitte per E-Mail an
|
||||
<a href="mailto:{{ config.community.contactEmail }}">{{ config.community.contactEmail }}</a>.
|
||||
</strong>
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<a href="mailto:{{ config.community.contactEmail }}">{{ config.community.contactEmail }}</a>.
|
||||
</strong>
|
||||
</p>
|
||||
<f-token-form f-submit="onSubmitToken" f-cancel="cancel"></f-token-form>
|
||||
<f-token-form f-submit="onSubmitToken" f-cancel="cancel" f-submit-icon="fa-pencil" f-submit-label="Knotendaten ändern"></f-token-form>
|
||||
</div>
|
||||
|
||||
<div ng-if="hasData()">
|
||||
|
|
|
@ -80,6 +80,22 @@ angular.module('ffffng').factory('NodeResource', function (
|
|||
});
|
||||
},
|
||||
|
||||
delete: function (req, res) {
|
||||
var data = getData(req);
|
||||
|
||||
var token = Strings.normalizeString(data.token);
|
||||
if (!isValidToken(token)) {
|
||||
return error(res, {data: 'Invalid token.', type: ErrorTypes.badRequest});
|
||||
}
|
||||
|
||||
return NodeService.deleteNode(token, function (err) {
|
||||
if (err) {
|
||||
return error(res, err);
|
||||
}
|
||||
return success(res, {});
|
||||
});
|
||||
},
|
||||
|
||||
get: function (req, res) {
|
||||
var token = Strings.normalizeString(getData(req).token);
|
||||
if (!isValidToken(token)) {
|
||||
|
|
|
@ -5,6 +5,7 @@ angular.module('ffffng').factory('Router', function (app, NodeResource) {
|
|||
init: function () {
|
||||
app.post('/api/node', NodeResource.create);
|
||||
app.put('/api/node/:token', NodeResource.update);
|
||||
app.delete('/api/node/:token', NodeResource.delete);
|
||||
app.get('/api/node/:token', NodeResource.get);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -101,6 +101,23 @@ angular.module('ffffng')
|
|||
return callback(null, token, node);
|
||||
}
|
||||
|
||||
function deleteNodeFile(token, callback) {
|
||||
var files = findNodeFiles('*@*@*@' + token);
|
||||
if (files.length !== 1) {
|
||||
return callback({data: 'Node not found.', type: ErrorTypes.notFound});
|
||||
}
|
||||
|
||||
try {
|
||||
fs.unlinkSync(files[0]);
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error);
|
||||
return callback({data: 'Could not delete node.', type: ErrorTypes.internalError});
|
||||
}
|
||||
|
||||
return callback(null);
|
||||
}
|
||||
|
||||
function parseNodeFile(file, callback) {
|
||||
var lines = fs.readFileSync(file).toString();
|
||||
|
||||
|
@ -140,6 +157,10 @@ angular.module('ffffng')
|
|||
writeNodeFile(true, token, node, callback);
|
||||
},
|
||||
|
||||
deleteNode: function (token, callback) {
|
||||
deleteNodeFile(token, callback);
|
||||
},
|
||||
|
||||
getNodeData: function (token, callback) {
|
||||
var files = findNodeFiles('*@*@*@' + token);
|
||||
|
||||
|
|
Loading…
Reference in a new issue