Browse Source

#468: posting quotas

Rafał Pitoń 10 years ago
parent
commit
5040e3a1ed
3 changed files with 43 additions and 3 deletions
  1. 12 0
      docs/developers/settings.rst
  2. 7 0
      misago/conf/defaults.py
  3. 24 3
      misago/threads/posting/floodprotection.py

+ 12 - 0
docs/developers/settings.rst

@@ -223,6 +223,12 @@ MISAGO_CONTENT_COUNTING_FREQUENCY
 Maximum allowed age of content counts cache in minutes. The lower the number, the more accurate will be numbers of new and unread threads in navbar, but greater the stress on database.
 
 
+MISAGO_DIALY_POST_LIMIT
+-----------------------
+
+Dialy limit of posts that may be posted from single account. Fail-safe for situations when forum is flooded by spam bot. Change to 0 to lift this restriction.
+
+
 MISAGO_DYNAMIC_AVATAR_DRAWER
 ----------------------------
 
@@ -234,6 +240,12 @@ MISAGO_FRESH_CONTENT_PERIOD
 Controls amount of data used in building "New threads" and "Threads with unread replies" lists. Active forums can try lowering this value while less active ones may wish to increase this number.
 
 
+MISAGO_HOURL_POST_LIMIT
+-----------------------
+
+Hourly limit of posts that may be posted from single account. Fail-safe for situations when forum is flooded by spam bot. Change to 0 to lift this restriction.
+
+
 MISAGO_MAILER_BATCH_SIZE
 ------------------------
 

+ 7 - 0
misago/conf/defaults.py

@@ -283,6 +283,13 @@ MISAGO_ADMIN_SESSION_EXPIRATION = 60
 MISAGO_NOTIFICATIONS_MAX_AGE = 40
 
 
+# Fail-safe limits in case forum is raided by spambot
+# No user may exceed those limits, however you may disable
+# them by changing them to 0
+MISAGO_DIALY_POST_LIMIT = 600
+MISAGO_HOURLY_POST_LIMIT = 100
+
+
 # Function used for generating individual avatar for user
 MISAGO_DYNAMIC_AVATAR_DRAWER = 'misago.users.avatars.dynamic.draw_default'
 

+ 24 - 3
misago/threads/posting/floodprotection.py

@@ -1,3 +1,6 @@
+from datetime import timedelta
+
+from django.conf import settings
 from django.utils import timezone
 from django.utils.translation import ugettext as _
 
@@ -9,11 +12,29 @@ MIN_POSTING_PAUSE = 3
 
 class FloodProtectionMiddleware(PostingMiddleware):
     def interrupt_posting(self, form):
-        message = _("You can't post message so quickly after previous one.")
+        now = timezone.now()
+
         if self.user.last_posted_on:
-            previous_post = timezone.now() - self.user.last_posted_on
+            previous_post = now - self.user.last_posted_on
             if previous_post.total_seconds() < MIN_POSTING_PAUSE:
-                raise PostingInterrupt(message)
+                raise PostingInterrupt(_("You can't post message so "
+                                         "quickly after previous one."))
 
         self.user.last_posted_on = timezone.now()
         self.user.update_fields.append('last_posted_on')
+
+        if settings.MISAGO_HOURLY_POST_LIMIT:
+            cutoff = now - timedelta(hours=24)
+            count_qs = self.user.post_set.filter(posted_on__gte=cutoff)
+            posts_count = count_qs.count()
+            if posts_count > settings.MISAGO_HOURLY_POST_LIMIT:
+                raise PostingInterrupt(_("Your account has excceed "
+                                         "hourly post limit."))
+
+        if settings.MISAGO_DIALY_POST_LIMIT:
+            cutoff = now - timedelta(hours=1)
+            count_qs = self.user.post_set.filter(posted_on__gte=cutoff)
+            posts_count = count_qs.count()
+            if posts_count > settings.MISAGO_DIALY_POST_LIMIT:
+                raise PostingInterrupt(_("Your account has excceed "
+                                         "dialy post limit."))