Browse Source

Hide/Unhide actions

Alec Nikolas Reiter 7 years ago
parent
commit
8155004b16
3 changed files with 145 additions and 51 deletions
  1. 79 37
      flaskbb/forum/models.py
  2. 34 1
      flaskbb/forum/views.py
  3. 32 13
      flaskbb/utils/helpers.py

+ 79 - 37
flaskbb/forum/models.py

@@ -559,53 +559,95 @@ class Topic(HideableCRUDMixin, db.Model):
 
         :param users: A list with user objects
         """
+        forum = self.forum
+        db.session.delete(self)
+        self._fix_user_post_counts(users or self.involved_users().all())
+        self._fix_forum_counts(forum)
+        db.session.commit()
+        return self
+
+    def hide(self, users=None):
+        """Soft deletes a topic from a forum
+        """
+        self._remove_topic_from_forum()
+        super(Topic, self).hide()
+        self._fix_user_post_counts(users or self.involved_users().all())
+        self._fix_forum_counts(self.forum)
+        db.session.commit()
+        return self
+
+    def unhide(self, users=None):
+        """Restores a hidden topic to a forum
+        """
+        super(Topic, self).unhide()
+        self._restore_topic_to_forum()
+        self._fix_user_post_counts(users or self.involved_users().all())
+        self.forum.recalculate()
+        db.session.commit()
+        return self
+
+    def _remove_topic_from_forum(self):
         # Grab the second last topic in the forum + parents/childs
-        topic = Topic.query.\
-            filter_by(forum_id=self.forum_id).\
-            order_by(Topic.last_post_id.desc()).limit(2).offset(0).all()
+        topics = Topic.query.filter(
+            Topic.forum_id == self.forum_id
+        ).order_by(
+            Topic.last_post_id.desc()
+        ).limit(2).offset(0).all()
 
         # do we want to delete the topic with the last post in the forum?
-        if topic and topic[0] == self:
-            try:
-                # Now the second last post will be the last post
-                self.forum.last_post = topic[1].last_post
-                self.forum.last_post_title = topic[1].title
-                self.forum.last_post_user = topic[1].user
-                self.forum.last_post_username = topic[1].username
-                self.forum.last_post_created = topic[1].last_updated
-            # Catch an IndexError when you delete the last topic in the forum
-            # There is no second last post
-            except IndexError:
-                self.forum.last_post = None
-                self.forum.last_post_title = None
-                self.forum.last_post_user = None
-                self.forum.last_post_username = None
-                self.forum.last_post_created = None
-
-        # These things needs to be stored in a variable before they are deleted
-        forum = self.forum
+        if len(topics) > 1 and topics[0] == self:
+            # Now the second last post will be the last post
+            self.forum.last_post = topics[1].last_post
+            self.forum.last_post_title = topics[1].title
+            self.forum.last_post_user = topics[1].user
+            self.forum.last_post_username = topics[1].username
+            self.forum.last_post_created = topics[1].last_updated
+        else:
+            self.forum.last_post = None
+            self.forum.last_post_title = None
+            self.forum.last_post_user = None
+            self.forum.last_post_username = None
+            self.forum.last_post_created = None
 
         TopicsRead.query.filter_by(topic_id=self.id).delete()
 
-        # Delete the topic
-        db.session.delete(self)
-
+    def _fix_user_post_counts(self, users=None):
         # Update the post counts
         if users:
             for user in users:
-                user.post_count = Post.query.filter_by(user_id=user.id).count()
-
-        forum.topic_count = Topic.query.\
-            filter_by(forum_id=self.forum_id).\
-            count()
-
-        forum.post_count = Post.query.\
-            filter(Post.topic_id == Topic.id,
-                   Topic.forum_id == self.forum_id).\
-            count()
+                user.post_count = Post.query.filter(
+                    Post.user_id == user.id,
+                    Topic.id == Post.topic_id,
+                    Topic.hidden == False
+                ).count()
+
+    def _fix_forum_counts(self, forum):
+        forum.topic_count = Topic.query.filter_by(
+            forum_id=self.forum_id
+        ).count()
+
+        forum.post_count = Post.query.filter(
+            Post.topic_id == Topic.id,
+            Topic.forum_id == self.forum_id,
+            Topic.hidden == False
+        ).count()
+
+    def _restore_topic_to_forum(self):
+        if self.forum.last_post is None or self.forum.last_post_created < self.last_updated:
+            self.forum.last_post = self.last_post
+            self.forum.last_post_title = self.title
+            self.forum.last_post_user = self.user
+            self.forum.last_post_username = self.username
+            self.forum.last_post_created = self.last_updated
+
+    def involved_users(self):
+        """
+        Returns a query of all users involved in the topic
+        """
+        # todo: Find circular import and break it
+        from flaskbb.user.models import User
+        return User.query.filter(Post.topic_id == self.id, User.id == Post.user_id)
 
-        db.session.commit()
-        return self
 
 
 @make_comparable

+ 34 - 1
flaskbb/forum/views.py

@@ -25,7 +25,7 @@ from flaskbb.utils.helpers import (get_online_users, time_diff, time_utcnow,
 from flaskbb.utils.requirements import (CanAccessForum, CanAccessTopic,
                                         CanDeletePost, CanDeleteTopic,
                                         CanEditPost, CanPostReply,
-                                        CanPostTopic,
+                                        CanPostTopic, Has,
                                         IsAtleastModeratorInForum)
 from flaskbb.forum.models import (Category, Forum, Topic, Post, ForumsRead,
                                   TopicsRead)
@@ -270,6 +270,39 @@ def trivialize_topic(topic_id=None, slug=None):
     return redirect(topic.url)
 
 
+@forum.route("/topic/<int:topic_id>/hide", methods=["POST"])
+@forum.route("/topic/<int:topic_id>-<slug>/hide", methods=["POST"])
+@login_required
+def hide_topic(topic_id, slug=None):
+    topic = Topic.query.with_hidden().filter_by(id=topic_id).first_or_404()
+    if not Permission(Has('makehidden') & IsAtleastModeratorInForum(forum=topic.forum)):
+        flash(_("You do not have permission to hide this topic"),
+                "danger")
+        return redirect(topic.url)
+    involved_users = User.query.filter(Post.topic_id == topic.id,
+                                       User.id == Post.user_id).all()
+    topic.hide(involved_users)
+    topic.save()
+    return redirect(url_for('forum.view_forum', forum_id=topic.forum.id, slug=topic.forum.slug))
+
+
+@forum.route("/topic/<int:topic_id>/unhide", methods=["POST"])
+@forum.route("/topic/<int:topic_id>-<slug>/unhide", methods=["POST"])
+@login_required
+@allows.requires(Has('viewhidden'))
+def unhide_topic(topic_id, slug=None):
+    topic = Topic.query.with_hidden().filter_by(id=topic_id).first_or_404()
+    if not Permission(Has('makehidden') & IsAtleastModeratorInForum(forum=topic.forum)):
+        flash(_("You do not have permission to unhide this topic"),
+                "danger")
+        return redirect(topic.url)
+    involved_users = User.query.filter(Post.topic_id == topic.id,
+                                       User.id == Post.user_id).all()
+    topic.unhide(involved_users)
+    topic.save()
+    return redirect(topic.url)
+
+
 @forum.route("/forum/<int:forum_id>/edit", methods=["POST", "GET"])
 @forum.route("/forum/<int:forum_id>-<slug>/edit", methods=["POST", "GET"])
 @login_required

+ 32 - 13
flaskbb/utils/helpers.py

@@ -88,11 +88,11 @@ def do_topic_action(topics, user, action, reverse):
                     For example, to unlock a topic, ``reverse`` should be
                     set to ``True``.
     """
-    from flaskbb.utils.requirements import (IsAtleastModeratorInForum,
-                                            CanDeleteTopic)
+    if not topics:
+        return False
 
-    from flaskbb.user.models import User
-    from flaskbb.forum.models import Post
+    from flaskbb.utils.requirements import (IsAtleastModeratorInForum,
+                                            CanDeleteTopic, Has)
 
     if not Permission(IsAtleastModeratorInForum(forum=topics[0].forum)):
         flash(_("You do not have the permissions to execute this "
@@ -100,8 +100,7 @@ def do_topic_action(topics, user, action, reverse):
         return False
 
     modified_topics = 0
-    if action != "delete":
-
+    if action not in {'delete', 'hide', 'unhide'}:
         for topic in topics:
             if getattr(topic, action) and not reverse:
                 continue
@@ -109,17 +108,37 @@ def do_topic_action(topics, user, action, reverse):
             setattr(topic, action, not reverse)
             modified_topics += 1
             topic.save()
+
     elif action == "delete":
+        if not Permission(CanDeleteTopic):
+            flash(_("You do not have the permissions to delete these topics."), "danger")
+            return False
+
         for topic in topics:
-            if not Permission(CanDeleteTopic):
-                flash(_("You do not have the permissions to delete this "
-                        "topic."), "danger")
-                return False
+            modified_topics += 1
+            topic.delete()
 
-            involved_users = User.query.filter(Post.topic_id == topic.id,
-                                               User.id == Post.user_id).all()
+    elif action == 'hide':
+        if not Permission(Has('makehidden')):
+            flash(_("You do not have the permissions to hide these topics."), "danger")
+            return False
+
+        for topic in topics:
+            if topic.hidden:
+                continue
+            modified_topics += 1
+            topic.hide()
+
+    elif action == 'unhide':
+        if not Permission(Has('makehidden')):
+            flash(_("You do not have the permissions to unhide these topics."), "danger")
+            return False
+
+        for topic in topics:
+            if not topic.hidden:
+                continue
             modified_topics += 1
-            topic.delete(involved_users)
+            topic.unhide()
 
     return modified_topics