From 79aadc85c2992cb504bcfc477b7ba838c52fd1aa Mon Sep 17 00:00:00 2001 From: baldo Date: Mon, 16 May 2016 18:27:03 +0200 Subject: [PATCH] Added delete feature for nodes. --- app/index.html | 2 + app/scripts/app.js | 8 +++ app/scripts/controllers/deleteNodeCtrl.js | 26 +++++++++ app/scripts/controllers/main.js | 4 ++ app/scripts/dialogs/confirmDeletionDialog.js | 29 ++++++++++ app/scripts/directives/tokenForm.js | 4 +- app/scripts/services/nodeService.js | 4 ++ app/styles/main.scss | 2 + app/styles/views/_deleteNodeForm.scss | 44 +++++++++++++++ app/styles/views/_main.scss | 20 +++++-- .../views/dialogs/_confirmDeletionDialog.scss | 33 +++++++++++ app/styles/views/directives/_tokenForm.scss | 4 ++ app/views/deleteNodeForm.html | 56 +++++++++++++++++++ app/views/dialogs/confirmDeletionDialog.html | 18 ++++++ app/views/directives/tokenForm.html | 2 +- app/views/main.html | 24 ++++---- app/views/updateNodeForm.html | 2 +- server/resources/nodeResource.js | 16 ++++++ server/router.js | 1 + server/services/nodeService.js | 21 +++++++ 20 files changed, 300 insertions(+), 20 deletions(-) create mode 100644 app/scripts/controllers/deleteNodeCtrl.js create mode 100644 app/scripts/dialogs/confirmDeletionDialog.js create mode 100644 app/styles/views/_deleteNodeForm.scss create mode 100644 app/styles/views/dialogs/_confirmDeletionDialog.scss create mode 100644 app/views/deleteNodeForm.html create mode 100644 app/views/dialogs/confirmDeletionDialog.html diff --git a/app/index.html b/app/index.html index 445591b..dd1d66a 100644 --- a/app/index.html +++ b/app/index.html @@ -49,6 +49,7 @@ + @@ -58,6 +59,7 @@ + diff --git a/app/scripts/app.js b/app/scripts/app.js index 7c24975..a5f9d85 100644 --- a/app/scripts/app.js +++ b/app/scripts/app.js @@ -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'); } }; }) diff --git a/app/scripts/controllers/deleteNodeCtrl.js b/app/scripts/controllers/deleteNodeCtrl.js new file mode 100644 index 0000000..c935854 --- /dev/null +++ b/app/scripts/controllers/deleteNodeCtrl.js @@ -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(); + }; +}); diff --git a/app/scripts/controllers/main.js b/app/scripts/controllers/main.js index a845ca2..7dd0518 100644 --- a/app/scripts/controllers/main.js +++ b/app/scripts/controllers/main.js @@ -11,4 +11,8 @@ angular.module('ffffng') $scope.updateNode = function () { Navigator.updateNode(); }; + + $scope.deleteNode = function () { + Navigator.deleteNode(); + }; }); diff --git a/app/scripts/dialogs/confirmDeletionDialog.js b/app/scripts/dialogs/confirmDeletionDialog.js new file mode 100644 index 0000000..23e00e3 --- /dev/null +++ b/app/scripts/dialogs/confirmDeletionDialog.js @@ -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; } + } + }); + } + }; +}); diff --git a/app/scripts/directives/tokenForm.js b/app/scripts/directives/tokenForm.js index 749b43a..2c19f4f 100644 --- a/app/scripts/directives/tokenForm.js +++ b/app/scripts/directives/tokenForm.js @@ -33,7 +33,9 @@ angular.module('ffffng') 'templateUrl': 'views/directives/tokenForm.html', 'scope': { 'onSubmit': '=fSubmit', - 'onCancel': '=fCancel' + 'onCancel': '=fCancel', + 'submitIcon': '@fSubmitIcon', + 'submitLabel': '@fSubmitLabel' } }; }); diff --git a/app/scripts/services/nodeService.js b/app/scripts/services/nodeService.js index 7bd9825..67f68b3 100644 --- a/app/scripts/services/nodeService.js +++ b/app/scripts/services/nodeService.js @@ -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); } diff --git a/app/styles/main.scss b/app/styles/main.scss index 1f404f5..948806b 100644 --- a/app/styles/main.scss +++ b/app/styles/main.scss @@ -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 { diff --git a/app/styles/views/_deleteNodeForm.scss b/app/styles/views/_deleteNodeForm.scss new file mode 100644 index 0000000..8cebebd --- /dev/null +++ b/app/styles/views/_deleteNodeForm.scss @@ -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; + } +} diff --git a/app/styles/views/_main.scss b/app/styles/views/_main.scss index 2101100..c213b19 100644 --- a/app/styles/views/_main.scss +++ b/app/styles/views/_main.scss @@ -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; + } } } } diff --git a/app/styles/views/dialogs/_confirmDeletionDialog.scss b/app/styles/views/dialogs/_confirmDeletionDialog.scss new file mode 100644 index 0000000..efee618 --- /dev/null +++ b/app/styles/views/dialogs/_confirmDeletionDialog.scss @@ -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; + } + } + } +} diff --git a/app/styles/views/directives/_tokenForm.scss b/app/styles/views/directives/_tokenForm.scss index 51e57da..977fd86 100644 --- a/app/styles/views/directives/_tokenForm.scss +++ b/app/styles/views/directives/_tokenForm.scss @@ -1,4 +1,8 @@ f-token-form { + form { + margin-bottom: 10px; + } + .main-error { @extend .alert, .alert-danger; } diff --git a/app/views/deleteNodeForm.html b/app/views/deleteNodeForm.html new file mode 100644 index 0000000..2e93085 --- /dev/null +++ b/app/views/deleteNodeForm.html @@ -0,0 +1,56 @@ +
+

Knoten löschen

+ +
+

+ 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. +

+

+ + Solltest Du den Token nicht mehr haben, wende Dich einfach per E-Mail an + {{ config.community.contactEmail }}. + +

+ + +

+ + 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. + +

+
+
+ +
+

Erledigt!

+

+ 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 Knotengraph + und in der Knotenkarte auswirken. +

+ +
+ + + {{hostname}} + +
+ +
+ +
+ +

+ + 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. + +

+
diff --git a/app/views/dialogs/confirmDeletionDialog.html b/app/views/dialogs/confirmDeletionDialog.html new file mode 100644 index 0000000..33e56af --- /dev/null +++ b/app/views/dialogs/confirmDeletionDialog.html @@ -0,0 +1,18 @@ +
+ + + +
diff --git a/app/views/directives/tokenForm.html b/app/views/directives/tokenForm.html index 2c4cb98..edf205f 100644 --- a/app/views/directives/tokenForm.html +++ b/app/views/directives/tokenForm.html @@ -10,7 +10,7 @@
+
-
oder
- + +
+
+
-

- - Hinweis: - Zum Entfernen von Knoten wende Dich bitte per E-Mail an - {{ config.community.contactEmail }}. - -

diff --git a/app/views/updateNodeForm.html b/app/views/updateNodeForm.html index 67ab42a..2498bc5 100644 --- a/app/views/updateNodeForm.html +++ b/app/views/updateNodeForm.html @@ -13,7 +13,7 @@ {{ config.community.contactEmail }}.

- +
diff --git a/server/resources/nodeResource.js b/server/resources/nodeResource.js index 130a112..33233df 100644 --- a/server/resources/nodeResource.js +++ b/server/resources/nodeResource.js @@ -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)) { diff --git a/server/router.js b/server/router.js index 802554e..0fb78b4 100644 --- a/server/router.js +++ b/server/router.js @@ -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); } }; diff --git a/server/services/nodeService.js b/server/services/nodeService.js index 07a946b..5dc24d0 100644 --- a/server/services/nodeService.js +++ b/server/services/nodeService.js @@ -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);