Browse Source

Fix private message quota being inconsistent

Fixes #337
Peter Justin 7 years ago
parent
commit
662a5714c7
3 changed files with 47 additions and 42 deletions
  1. 36 40
      flaskbb/message/views.py
  2. 1 1
      flaskbb/templates/message/conversation_list.html
  3. 10 1
      flaskbb/user/models.py

+ 36 - 40
flaskbb/message/views.py

@@ -31,21 +31,30 @@ logger = logging.getLogger(__name__)
 message = Blueprint("message", __name__)
 
 
-def requires_message_box_space(f):
+def check_message_box_space(redirect_to=None):
+    """Checks the message quota has been exceeded. If thats the case
+    it flashes a message and redirects back to some endpoint.
+
+    :param redirect_to: The endpoint to redirect to. If set to ``None`` it
+                        will redirect to the ``message.inbox`` endpoint.
+    """
+    if current_user.message_count >= flaskbb_config["MESSAGE_QUOTA"]:
+        flash(
+            _(
+                "You cannot send any messages anymore because you have "
+                "reached your message limit."
+            ), "danger"
+        )
+        return redirect(redirect_to or url_for("message.inbox"))
+
 
+def require_message_box_space(f):
+    """Decorator for :func:`check_message_box_space`."""
+    # not sure how this can be done without explicitly providing a decorator
+    # for this
     @wraps(f)
     def wrapper(*a, **k):
-        message_count = Conversation.query.filter(Conversation.user_id == current_user.id).count()
-
-        if message_count >= flaskbb_config["MESSAGE_QUOTA"]:
-            flash(
-                _(
-                    "You cannot send any messages anymore because you have "
-                    "reached your message limit."
-                ), "danger"
-            )
-            return redirect(url_for("message.inbox"))
-        return f(*a, **k)
+        return check_message_box_space() or f(*a, **k)
 
     return wrapper
 
@@ -55,7 +64,6 @@ class Inbox(MethodView):
 
     def get(self):
         page = request.args.get('page', 1, type=int)
-
         # the inbox will display both, the recieved and the sent messages
         conversations = Conversation.query.filter(
             Conversation.user_id == current_user.id,
@@ -65,13 +73,8 @@ class Inbox(MethodView):
             page, flaskbb_config['TOPICS_PER_PAGE'], False
         )
 
-        # we can't simply do conversations.total because it would ignore
-        # drafted and trashed messages
-        message_count = Conversation.query.filter(Conversation.user_id == current_user.id).count()
-
-        return render_template(
-            "message/inbox.html", conversations=conversations, message_count=message_count
-        )
+        return render_template("message/inbox.html",
+                               conversations=conversations)
 
 
 class ViewConversation(MethodView):
@@ -89,9 +92,10 @@ class ViewConversation(MethodView):
             conversation.save()
 
         form = self.form()
-        return render_template("message/conversation.html", conversation=conversation, form=form)
+        return render_template("message/conversation.html",
+                               conversation=conversation, form=form)
 
-    @requires_message_box_space
+    @require_message_box_space
     def post(self, conversation_id):
         conversation = Conversation.query.filter_by(
             id=conversation_id, user_id=current_user.id
@@ -137,7 +141,7 @@ class ViewConversation(MethodView):
 
 
 class NewConversation(MethodView):
-    decorators = [requires_message_box_space, login_required]
+    decorators = [login_required]
     form = ConversationForm
 
     def get(self):
@@ -165,6 +169,8 @@ class NewConversation(MethodView):
             return redirect(url_for("message.drafts"))
 
         if "send_message" in request.form and form.validate():
+            check_message_box_space()
+
             to_user = User.query.filter_by(username=form.to_user.data).first()
 
             # this is the shared id between conversations because the messages
@@ -240,6 +246,8 @@ class EditConversation(MethodView):
                 return redirect(url_for("message.drafts"))
 
             if "send_message" in request.form and form.validate():
+                check_message_box_space()
+
                 to_user = User.query.filter_by(username=form.to_user.data).first()
                 # Save the message in the recievers inbox
                 form.save(
@@ -306,7 +314,7 @@ class RestoreConversation(MethodView):
 
         conversation.trash = False
         conversation.save()
-        return redirect(url_for("message.inbox"))
+        return redirect(url_for("message.trash"))
 
 
 class DeleteConversation(MethodView):
@@ -318,7 +326,7 @@ class DeleteConversation(MethodView):
         ).first_or_404()
 
         conversation.delete()
-        return redirect(url_for("message.inbox"))
+        return redirect(url_for("message.trash"))
 
 
 class SentMessages(MethodView):
@@ -338,12 +346,8 @@ class SentMessages(MethodView):
             order_by(Conversation.date_modified.desc()). \
             paginate(page, flaskbb_config['TOPICS_PER_PAGE'], False)
 
-        message_count = Conversation.query. \
-            filter(Conversation.user_id == current_user.id).\
-            count()
-
         return render_template(
-            "message/sent.html", conversations=conversations, message_count=message_count
+            "message/sent.html", conversations=conversations
         )
 
 
@@ -363,12 +367,8 @@ class DraftMessages(MethodView):
             order_by(Conversation.date_modified.desc()). \
             paginate(page, flaskbb_config['TOPICS_PER_PAGE'], False)
 
-        message_count = Conversation.query. \
-            filter(Conversation.user_id == current_user.id).\
-            count()
-
         return render_template(
-            "message/drafts.html", conversations=conversations, message_count=message_count
+            "message/drafts.html", conversations=conversations
         )
 
 
@@ -387,12 +387,8 @@ class TrashedMessages(MethodView):
             order_by(Conversation.date_modified.desc()). \
             paginate(page, flaskbb_config['TOPICS_PER_PAGE'], False)
 
-        message_count = Conversation.query. \
-            filter(Conversation.user_id == current_user.id).\
-            count()
-
         return render_template(
-            "message/trash.html", conversations=conversations, message_count=message_count
+            "message/trash.html", conversations=conversations
         )
 
 

+ 1 - 1
flaskbb/templates/message/conversation_list.html

@@ -8,7 +8,7 @@
                 </div>
 
                 <div class="pull-right">
-                    <span class="label label-info" title="The amount of all conversations" data-toggle="tooltip" data-placement="top">{{ message_count }}/{{ flaskbb_config["MESSAGE_QUOTA"] }}</span>
+                    <span class="label label-info" title="The amount of all conversations" data-toggle="tooltip" data-placement="top">{{ current_user.message_count }}/{{ flaskbb_config["MESSAGE_QUOTA"] }}</span>
                 </div>
             </div>
         </div>

+ 10 - 1
flaskbb/user/models.py

@@ -20,7 +20,7 @@ from flaskbb.utils.settings import flaskbb_config
 from flaskbb.utils.database import CRUDMixin, UTCDateTime, make_comparable
 from flaskbb.forum.models import (Post, Topic, Forum, topictracker, TopicsRead,
                                   ForumsRead)
-from flaskbb.message.models import Conversation
+from flaskbb.message.models import Conversation, Message
 
 
 logger = logging.getLogger(__name__)
@@ -187,6 +187,15 @@ class User(db.Model, UserMixin, CRUDMixin):
         return len(self.unread_messages)
 
     @property
+    def message_count(self):
+        """Returns the number of private messages of this user."""
+        return Conversation.query.filter(
+            Conversation.user_id == self.id,
+            Conversation.id == Message.conversation_id
+        ).count()
+
+
+    @property
     def days_registered(self):
         """Returns the amount of days the user is registered."""
         days_registered = (time_utcnow() - self.date_joined).days