Alec Nikolas Reiter 9 лет назад
Родитель
Сommit
aa10f6298b
3 измененных файлов с 50 добавлено и 28 удалено
  1. 11 7
      flaskbb/forum/views.py
  2. 6 5
      flaskbb/utils/helpers.py
  3. 33 16
      flaskbb/utils/requirements.py

+ 11 - 7
flaskbb/forum/views.py

@@ -220,7 +220,7 @@ def delete_topic(topic_id=None, slug=None):
 def lock_topic(topic_id=None, slug=None):
     topic = Topic.query.filter_by(id=topic_id).first_or_404()
 
-    if not Permission(IsAtleastModeratorInForum(topic.forum.id)):
+    if not Permission(IsAtleastModeratorInForum(forum=topic.forum)):
         flash(_("You do not have the permissions to lock this topic."),
               "danger")
         return redirect(topic.url)
@@ -236,7 +236,7 @@ def lock_topic(topic_id=None, slug=None):
 def unlock_topic(topic_id=None, slug=None):
     topic = Topic.query.filter_by(id=topic_id).first_or_404()
 
-    if not Permission(IsAtleastModeratorInForum(topic.forum.id)):
+    if not Permission(IsAtleastModeratorInForum(forum=topic.forum)):
         flash(_("You do not have the permissions to unlock this topic."),
               "danger")
         return redirect(topic.url)
@@ -252,7 +252,7 @@ def unlock_topic(topic_id=None, slug=None):
 def highlight_topic(topic_id=None, slug=None):
     topic = Topic.query.filter_by(id=topic_id).first_or_404()
 
-    if not Permission(IsAtleastModeratorInForum(topic.forum.id)):
+    if not Permission(IsAtleastModeratorInForum(forum=topic.forum)):
         flash(_("You do not have the permissions to highlight this topic."),
               "danger")
         return redirect(topic.url)
@@ -269,7 +269,7 @@ def trivialize_topic(topic_id=None, slug=None):
     topic = Topic.query.filter_by(id=topic_id).first_or_404()
 
     # Unlock is basically the same as lock
-    if not Permission(IsAtleastModeratorInForum(topic.forum.id)):
+    if not Permission(IsAtleastModeratorInForum(forum=topic.forum)):
         flash(_("You do not have the permissions to trivialize this topic."),
               "danger")
         return redirect(topic.url)
@@ -292,7 +292,7 @@ def manage_forum(forum_id, slug=None):
     available_forums = Forum.query.order_by(Forum.position).all()
     available_forums.remove(forum_instance)
 
-    if not Permission(IsAtleastModeratorInForum()):
+    if not Permission(IsAtleastModeratorInForum(forum=forum_instance)):
         flash(_("You do not have the permissions to moderate this forum."),
               "danger")
         return redirect(forum_instance.url)
@@ -359,8 +359,12 @@ def manage_forum(forum_id, slug=None):
             new_forum = Forum.query.filter_by(id=new_forum_id).first_or_404()
             # check the permission in the current forum and in the new forum
 
-            if not Permission(And(IsAtleastModeratorInForum(new_forum_id),
-                                  IsAtleastModeratorInForum(forum_instance.id))):
+            if not Permission(
+                And(
+                    IsAtleastModeratorInForum(forum_id=new_forum_id),
+                    IsAtleastModeratorInForum(forum=forum_instance)
+                )
+            ):
                 flash(_("You do not have the permissions to move this topic."),
                       "danger")
                 return redirect(mod_forum_url)

+ 6 - 5
flaskbb/utils/helpers.py

@@ -75,14 +75,15 @@ def do_topic_action(topics, user, action, reverse):
     from flaskbb.user.models import User
     from flaskbb.forum.models import Post
 
+    if not Permission(IsAtleastModeratorInForum(forum=topics[0].forum)):
+        flash(_("You do not have the permissions to execute this "
+                "action."), "danger")
+        return False
+
     modified_topics = 0
     if action != "delete":
-        for topic in topics:
-            if not Permission(IsAtleastModeratorInForum(topic.forum)):
-                flash(_("You do not have the permissions to execute this "
-                        "action."), "danger")
-                return False
 
+        for topic in topics:
             if getattr(topic, action) and not reverse:
                 continue
 

+ 33 - 16
flaskbb/utils/requirements.py

@@ -18,6 +18,9 @@ class Has(Requirement):
     def __init__(self, permission):
         self.permission = permission
 
+    def __repr__(self):
+        return "<Has({!s})>".format(self.permission)
+
     def fulfill(self, user, request):
         return user.permissions.get(self.permission, False)
 
@@ -86,17 +89,26 @@ class TopicNotLocked(Requirement):
         self._topic_id = topic_id
 
     def fulfill(self, user, request):
-        return not self._is_topic_or_forum_locked(request)
+        return not any(self._determine_locked(request))
 
-    def _is_topic_or_forum_locked(self, request):
-        topic = self._determine_topic(request)
-        return topic.locked or topic.forum.locked
+    def _determine_locked(self, request):
+        """
+        Returns a pair of booleans:
+            * Is the topic locked?
+            * Is the forum the topic belongs to locked?
 
-    def _determine_topic(self, request):
+        Except in the case of a topic instance being provided to the constructor,
+        all of these tuples are SQLA KeyedTuples
+        """
         if self._topic is not None:
-            return self._topic
+            return self._topic.locked, self._topic.forum.locked
         elif self._topic_id is not None:
-            return Topic.query.get(self._topic_id)
+            return (
+                Topic.query.join(Forum, Forum.id == Topic.forum_id)
+                .filter(Topic.id == self._topic_id)
+                .with_entities(Topic.locked, Forum.locked)
+                .first()
+            )
         else:
             return self._get_topic_from_request(request)
 
@@ -105,14 +117,20 @@ class TopicNotLocked(Requirement):
         if 'post_id' in view_args:
             return (
                 Topic.query.join(Post, Post.topic_id == Topic.id)
+                .join(Forum, Forum.id == Topic.forum_id)
                 .filter(Post.id == view_args['post_id'])
-                .with_entities(Topic.locked)
+                .with_entities(Topic.locked, Forum.locked)
                 .first()
             )
         elif 'topic_id' in view_args:
-            return Topic.query.get(view_args['topic_id'])
+            return (
+                Topic.query.join(Forum, Forum.id == Topic.forum_id)
+                .filter(Topic.id == view_args['topic_id'])
+                .with_entities(Topic.locked, Forum.locked)
+                .first()
+            )
         else:
-            raise FlaskBBError
+            raise FlaskBBError("How did you get this to happen?")
 
 
 class ForumNotLocked(Requirement):
@@ -201,9 +219,8 @@ CanBanUser = Or(IsAtleastSuperModerator, Has('mod_banuser'))
 
 CanEditUser = Or(IsAtleastSuperModerator, Has('mod_edituser'))
 
-CanEditPost = Or(And(IsSameUser(), Has('editpost'), TopicNotLocked()),
-                 IsAtleastSuperModerator,
-                 And(IsModeratorInForum(), Has('editpost')))
+CanEditPost = Or(IsAtleastSuperModerator, And(IsModeratorInForum(), Has('editpost')),
+                 And(IsSameUser(), Has('editpost'), TopicNotLocked()))
 
 CanDeletePost = CanEditPost
 
@@ -215,9 +232,9 @@ CanPostTopic = Or(And(Has('posttopic'), ForumNotLocked()),
                   IsAtleastSuperModerator,
                   IsModeratorInForum())
 
-CanDeleteTopic = Or(And(IsSameUser(), Has('deletetopic'), TopicNotLocked()),
-                    IsAtleastSuperModerator,
-                    And(IsModeratorInForum(), Has('deletetopic')))
+CanDeleteTopic = Or(IsAtleastSuperModerator,
+                    And(IsModeratorInForum(), Has('deletetopic')),
+                    And(IsSameUser(), Has('deletetopic'), TopicNotLocked()))
 
 
 # Template Allowances -- gross, I know