]> BookStack Code Mirror - bookstack/commitdiff
#47 - Adds functionality to delete a comment. Also reduces the number of watchers.
authorAbijeet <redacted>
Sun, 4 Jun 2017 13:22:44 +0000 (18:52 +0530)
committerAbijeet <redacted>
Sun, 4 Jun 2017 13:22:44 +0000 (18:52 +0530)
app/Http/Controllers/CommentController.php
app/Repos/CommentRepo.php
database/migrations/2017_06_04_060012_comments_add_active_col.php [new file with mode: 0644]
resources/assets/js/controllers.js
resources/assets/js/directives.js
resources/views/comments/list-item.blade.php

index 3a267193d5b155cd59e06798949ddc1a774a6d52..a08279e8cc3b96e9d2277c0911552c387179f03d 100644 (file)
@@ -67,6 +67,14 @@ class CommentController extends Controller
     public function destroy($id) {
         $comment = $this->comment->findOrFail($id);
         $this->checkOwnablePermission('comment-delete', $comment);
+        $this->commentRepo->delete($comment);
+        $comment = $this->commentRepo->getCommentById($comment->id);
+
+        return response()->json([
+            'success' => true,
+            'message' => trans('entities.comment_deleted'),
+            'comment' => $comment
+        ]);
     }
 
 
index 83847239f1be6e10bb45992b17aa87e3b2ae6c5b..55af0fe12ebac8508348847fa25d244a41e19ed4 100644 (file)
@@ -31,10 +31,26 @@ class CommentRepo {
         return $comment;
     }
 
-    public function update($comment, $input) {
+    public function update($comment, $input, $activeOnly = true) {
         $userId = user()->id;
         $comment->updated_by = $userId;
         $comment->fill($input);
+
+        // only update active comments by default.
+        $whereClause = ['active' => 1];
+        if (!$activeOnly) {
+            $whereClause = [];
+        }
+        $comment->update($whereClause);
+        return $comment;
+    }
+
+    public function delete($comment) {
+        $comment->text = trans('errors.cannot_add_comment_to_draft');
+        $comment->html = trans('errors.cannot_add_comment_to_draft');
+        $comment->active = false;
+        $userId = user()->id;
+        $comment->updated_by = $userId;
         $comment->save();
         return $comment;
     }
diff --git a/database/migrations/2017_06_04_060012_comments_add_active_col.php b/database/migrations/2017_06_04_060012_comments_add_active_col.php
new file mode 100644 (file)
index 0000000..3c6dd1f
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+
+use Illuminate\Support\Facades\Schema;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Database\Migrations\Migration;
+
+class CommentsAddActiveCol extends Migration
+{
+    /**
+     * Run the migrations.
+     *
+     * @return void
+     */
+    public function up()
+    {
+        Schema::table('comments', function (Blueprint $table) {
+            // add column active
+            $table->boolean('active')->default(true);
+            $table->dropIndex('comments_page_id_parent_id_index');
+            $table->index(['page_id']);
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     *
+     * @return void
+     */
+    public function down()
+    {
+        Schema::table('comments', function (Blueprint $table) {
+            // reversing the schema
+            $table->dropIndex('comments_page_id_index');
+            $table->dropColumn('active');
+            $table->index(['page_id', 'parent_id']);
+        });
+    }
+}
index 4763f986745e1f639091fb1191d3b2e2507ebbaf..0a4e7b33331871b654255a37fac148b80ee0c476 100644 (file)
@@ -683,11 +683,12 @@ module.exports = function (ngApp, events) {
         }]);
 
     // CommentCrudController
-    ngApp.controller('CommentReplyController', ['$scope', '$http', function ($scope, $http) {
+    ngApp.controller('CommentReplyController', ['$scope', '$http', '$timeout', function ($scope, $http, $timeout) {
         const MarkdownIt = require("markdown-it");
         const md = new MarkdownIt({html: true});
         let vm = this;
         $scope.errors = {};
+
         vm.saveComment = function () {
             let pageId = $scope.comment.pageId || $scope.pageId;
             let comment = $scope.comment.text;
@@ -713,11 +714,9 @@ module.exports = function (ngApp, events) {
                 if (!resp.data || resp.data.status !== 'success') {
                      return events.emit('error', trans('error'));
                 }
+                // hide the comments first, and then retrigger the refresh
                 if ($scope.isEdit) {
-                    $scope.comment.html = resp.data.comment.html;
-                    $scope.comment.text = resp.data.comment.text;
-                    $scope.comment.updated = resp.data.comment.updated;
-                    $scope.comment.updated_by = resp.data.comment.updated_by;
+                    updateComment($scope.comment, resp.data);
                     $scope.$emit('evt.comment-success', $scope.comment.id);
                 } else {
                     $scope.comment.text = '';
@@ -728,6 +727,11 @@ module.exports = function (ngApp, events) {
                     }
                     $scope.$emit('evt.comment-success', null, true);
                 }
+                $scope.comment.is_hidden = true;
+                $timeout(function() {
+                    $scope.comment.is_hidden = false;
+                });
+
                 events.emit('success', trans(resp.data.message));
 
             }, checkError(errorOp));
@@ -748,6 +752,24 @@ module.exports = function (ngApp, events) {
         }
     }]);
 
+    ngApp.controller('CommentDeleteController', ['$scope', '$http', '$timeout', function ($scope, $http, $timeout) {
+        let vm = this;
+
+        vm.delete = function(comment) {
+            $http.delete(window.baseUrl(`/ajax/comment/${comment.id}`)).then(resp => {
+                if (!resp.data || resp.data.success !== true) {
+                    return;
+                }
+                updateComment(comment, resp.data, $timeout, true);
+            }, function (resp) {
+                if (!resp || !resp.data || resp.data.success !== true) {
+                    events.emit('error', trans('entities.comment_delete_fail'));
+                } else {
+                    events.emit('success', trans('entities.comment_delete_success'));
+                }
+            });
+        };
+    }]);
 
     // CommentListController
     ngApp.controller('CommentListController', ['$scope', '$http', '$timeout', function ($scope, $http, $timeout) {
@@ -766,6 +788,9 @@ module.exports = function (ngApp, events) {
         });
 
         vm.canEdit = function (comment) {
+            if (!comment.active) {
+                return false;
+            }
             if (vm.permissions.comment_update_all) {
                 return true;
             }
@@ -774,11 +799,11 @@ module.exports = function (ngApp, events) {
                 return true;
             }
             return false;
-        }
+        };
 
         vm.canComment = function () {
             return vm.permissions.comment_create;
-        }
+        };
 
         $timeout(function() {
             $http.get(window.baseUrl(`/ajax/page/${$scope.pageId}/comments/`)).then(resp => {
@@ -797,7 +822,7 @@ module.exports = function (ngApp, events) {
                 } else if (vm.totalComments === 1) {
                     vm.totalCommentsStr = '1 Comments';
                 } else {
-                    vm.totalCommentsStr = vm.totalComments + ' Comments'
+                    vm.totalCommentsStr = vm.totalComments + ' Comments';
                 }
             }, checkError('app'));
         });
@@ -806,8 +831,29 @@ module.exports = function (ngApp, events) {
             $scope.errors[errorGroupName] = {};
             return function(response) {
                 console.log(response);
-            }
+            };
         }
     }]);
 
+    function updateComment(comment, resp, $timeout, isDelete) {
+        if (isDelete && !resp.comment.active) {
+            comment.html = trans('entities.comment_deleted');
+        }
+        comment.text = resp.comment.text;
+        comment.updated = resp.comment.updated;
+        comment.updated_by = resp.comment.updated_by;
+        comment.active = resp.comment.active;
+        if (isDelete && !resp.comment.active) {
+            comment.html = trans('entities.comment_deleted');
+        } else {
+            comment.html = resp.comment.html;
+        }
+        if (!$timeout) {
+            return;
+        }
+        comment.is_hidden = true;
+        $timeout(function() {
+            comment.is_hidden = false;
+        });
+    }
 };
index 0929a9cf4b2d83a67974c13009209179a41d679d..18217633ffe05a8d89801ddc65d90547b474f3a3 100644 (file)
@@ -870,7 +870,7 @@ module.exports = function (ngApp, events) {
     }]);
 
 
-    ngApp.directive('commentReplyLink', ['$document', '$compile', '$http', function ($document, $compile, $http) {
+    ngApp.directive('commentReplyLink', ['$document', '$compile', function ($document, $compile) {
         return {
             scope: {
                 comment: '='
@@ -916,4 +916,24 @@ module.exports = function (ngApp, events) {
             $existingElement.remove();
         }
     }]);
+
+    ngApp.directive('commentDeleteLink', ['$window', function ($window) {
+        return {
+            controller: 'CommentDeleteController',
+            scope: {
+                comment: '='
+            },
+            link: function (scope, element, attr, ctrl) {
+
+                element.on('click', function() {
+                   var resp = $window.confirm('This will remove the content of the comment, are you sure you want to continue?');
+                   if (!resp) {
+                       return;
+                   }
+
+                   ctrl.delete(scope.comment);
+                });
+            }
+        };
+    }]);
 };
index 67355c586001eb8a4dc1241294eaccf621055214..22cbb24c05fe39f2095c1791e317b681d3306af1 100644 (file)
@@ -6,16 +6,20 @@
         <div class="comment-header">
             <a href="@{{::comment.created_by.profile_url}}">@{{ ::comment.created_by.name }}</a>
         </div>
-        <div ng-bind-html="comment.html" class="comment-body">
+        <div ng-bind-html="comment.html" ng-if="::comment.active" class="comment-body">
 
+        </div>
+        <div ng-if="::!comment.active" class="comment-body">
+            {{ trans('entites.comment_deleted') }}
         </div>
         <div class="comment-actions">
-            <ul>
+            <ul ng-if="!comment.is_hidden">
                 <li ng-if="::(level < 3 && vm.canComment())"><a href="#" comment-reply-link no-comment-reply-dupe="true" comment="comment" is-reply="true">Reply</a></li>
                 <li ng-if="::vm.canEdit(comment)"><a href="#" comment-reply-link no-comment-reply-dupe="true" comment="comment" >Edit</a></li>
+                <li ng-if="::vm.canEdit(comment, true)"><a href="#" comment-delete-link comment="comment" >Delete</a></li>
                 <li>Created <a title="@{{::comment.created.day_time_str}}" href="#comment-@{{::comment.id}}-@{{::pageId}}">@{{::comment.created.diff}}</a></li>
-                <li ng-if="comment.updated"><span title="@{{comment.updated.day_time_str}}">Updated @{{comment.updated.diff}} by
-                    <a href="@{{comment.updated_by.profile_url}}">@{{comment.updated_by.name}}</a></span></li>
+                <li ng-if="::comment.updated"><span title="@{{::comment.updated.day_time_str}}">Updated @{{::comment.updated.diff}} by
+                    <a href="@{{::comment.updated_by.profile_url}}">@{{::comment.updated_by.name}}</a></span></li>
             </ul>
         </div>
         <div class="comment-box" ng-repeat="comment in comments = comment.sub_comments track by comment.id" ng-init="level = level + 1">