Enforce `user.conversation.floodControlTime`
authorTim Düsterhus <duesterhus@woltlab.com>
Mon, 8 Mar 2021 14:06:54 +0000 (15:06 +0100)
committerTim Düsterhus <duesterhus@woltlab.com>
Mon, 8 Mar 2021 14:06:54 +0000 (15:06 +0100)
Resolves #135

files/lib/data/conversation/message/ConversationMessageAction.class.php
files/lib/form/ConversationAddForm.class.php
files/lib/system/conversation/ConversationHandler.class.php
language/de.xml
language/en.xml

index 5394fd701ea7e5429555b5ad76e93b8486daa64c..858872e6d227b574ad7a68ee98d0551c1ce1755c 100644 (file)
@@ -13,8 +13,11 @@ use wcf\data\IMessageQuoteAction;
 use wcf\data\smiley\SmileyCache;
 use wcf\system\attachment\AttachmentHandler;
 use wcf\system\bbcode\BBCodeHandler;
+use wcf\system\conversation\ConversationHandler;
+use wcf\system\exception\NamedUserException;
 use wcf\system\exception\PermissionDeniedException;
 use wcf\system\exception\UserInputException;
+use wcf\system\flood\FloodControl;
 use wcf\system\html\input\HtmlInputProcessor;
 use wcf\system\message\censorship\Censorship;
 use wcf\system\message\embedded\object\MessageEmbeddedObjectManager;
@@ -290,6 +293,12 @@ class ConversationMessageAction extends AbstractDatabaseObjectAction implements
      */
     public function validateQuickReply()
     {
+        try {
+            ConversationHandler::getInstance()->enforceFloodControl(true);
+        } catch (NamedUserException $e) {
+            throw new UserInputException('message', $e->getMessage());
+        }
+
         QuickReplyManager::getInstance()->setDisallowedBBCodes(\explode(
             ',',
             WCF::getSession()->getPermission('user.message.disallowedBBCodes')
@@ -302,13 +311,17 @@ class ConversationMessageAction extends AbstractDatabaseObjectAction implements
      */
     public function quickReply()
     {
-        return QuickReplyManager::getInstance()->createMessage(
+        $returnValues = QuickReplyManager::getInstance()->createMessage(
             $this,
             $this->parameters,
             ConversationAction::class,
             CONVERSATION_LIST_DEFAULT_SORT_ORDER,
             'conversationMessageList'
         );
+
+        FloodControl::getInstance()->registerContent('com.woltlab.wcf.conversation.message');
+
+        return $returnValues;
     }
 
     /**
index cdfa9d52f7f311765405f3dc4a1852639e84a377..c3478be12a2fba65cffdaaa17ba110d71897efd6 100644 (file)
@@ -121,7 +121,7 @@ class ConversationAddForm extends MessageForm
             ));
         }
 
-        ConversationHandler::getInstance()->enforceFloodControl();
+        ConversationHandler::getInstance()->enforceFloodControl(false);
 
         if (isset($_REQUEST['userID'])) {
             $userID = \intval($_REQUEST['userID']);
@@ -300,6 +300,7 @@ class ConversationAddForm extends MessageForm
         MessageQuoteManager::getInstance()->saved();
 
         FloodControl::getInstance()->registerContent('com.woltlab.wcf.conversation');
+        FloodControl::getInstance()->registerContent('com.woltlab.wcf.conversation.message');
 
         $this->saved();
 
index 82ae57d050847303ed0885c7d65ee665a98dcbf6..3490d20d4dff0cff4cb7a75a5ef9ad6ed78d6653 100644 (file)
@@ -150,24 +150,44 @@ class ConversationHandler extends SingletonFactory
     /**
      * Enforces the flood control.
      */
-    public function enforceFloodControl()
-    {
-        $limit = WCF::getSession()->getPermission('user.conversation.maxStartedConversationsPer24Hours');
-        if ($limit == -1) {
-            return;
-        } elseif ($limit == 0) {
-            // `0` is not a valid value, but the interface logic does not permit and exclusion
-            // while also allowing the special value `-1`. Therefore, `0` behaves like the
-            // 'canStartConversation' permission added in WoltLab Suite 5.2.
-            throw new PermissionDeniedException();
+    public function enforceFloodControl(
+        bool $isReply = false
+    ) {
+        if (!$isReply) {
+            // 1. Check for the maximum conversations per 24 hours.
+            $limit = WCF::getSession()->getPermission('user.conversation.maxStartedConversationsPer24Hours');
+            if ($limit == 0) {
+                // `0` is not a valid value, but the interface logic does not permit and exclusion
+                // while also allowing the special value `-1`. Therefore, `0` behaves like the
+                // 'canStartConversation' permission added in WoltLab Suite 5.2.
+                throw new PermissionDeniedException();
+            }
+
+            if ($limit != -1) {
+                $count = FloodControl::getInstance()->countContent('com.woltlab.wcf.conversation', new \DateInterval('P1D'));
+                if ($count['count'] >= $limit) {
+                    throw new NamedUserException(WCF::getLanguage()->getDynamicVariable(
+                        'wcf.conversation.error.floodControl',
+                        [
+                            'limit' => $count['count'],
+                            'notBefore' => $count['earliestTime'] + 86400,
+                        ]
+                    ));
+                }
+            }
         }
 
-        $count = FloodControl::getInstance()->countContent('com.woltlab.wcf.conversation', new \DateInterval('P1D'));
-        if ($count['count'] >= $limit) {
-            throw new NamedUserException(WCF::getLanguage()->getDynamicVariable('wcf.conversation.error.floodControl', [
-                'limit' => $count['count'],
-                'notBefore' => $count['earliestTime'] + 86400,
-            ]));
+        // 2. Check the time between conversation messages.
+        $floodControlTime = WCF::getSession()->getPermission('user.conversation.floodControlTime');
+        $lastTime = FloodControl::getInstance()->getLastTime('com.woltlab.wcf.conversation.message');
+        if ($lastTime !== null && $lastTime > TIME_NOW - $floodControlTime) {
+            throw new NamedUserException(WCF::getLanguage()->getDynamicVariable(
+                'wcf.conversation.message.error.floodControl',
+                [
+                    'lastMessageTime' => $lastTime,
+                    'waitTime' => $lastTime + $floodControlTime - TIME_NOW,
+                ]
+            ));
         }
     }
 }
index 392100718fec0c82ef7b33303fa7d1d98ac22f77..ee510a3c5cc20e92656852b12acf658e5b93afd3 100644 (file)
                <item name="wcf.conversation.time"><![CDATA[Erstellung]]></item>
                <item name="wcf.conversation.username"><![CDATA[Autor]]></item>
                <item name="wcf.conversation.error.floodControl"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Du hast{else}Sie haben{/if} innerhalb der letzten 24 Stunden bereits {if $limit == 1}eine Konversation{else}{#$limit} Konversationen{/if} gestartet. Bitte {if LANGUAGE_USE_INFORMAL_VARIANT}warte{else}warten Sie{/if} bis zum <strong>{@$notBefore|time}</strong>, bevor {if LANGUAGE_USE_INFORMAL_VARIANT}du{else}Sie{/if} eine neue Konversation {if LANGUAGE_USE_INFORMAL_VARIANT}startest{else}starten{/if}.]]></item>
+               <item name="wcf.conversation.message.error.floodControl"><![CDATA[{if LANGUAGE_USE_INFORMAL_VARIANT}Du hast{else}Sie haben{/if} bereits eine Nachricht innerhalb der letzten {plural value=$__wcf->getSession()->getPermission('user.conversation.floodControlTime') 1='Sekunde' other='# Sekunden'} versendet. {if LANGUAGE_USE_INFORMAL_VARIANT}Du kannst{else}Sie können{/if} erst in {plural value=$waitTime 1='Sekunde' other='# Sekunden'} eine neue Nachricht verfassen.]]></item>
        </category>
        <category name="wcf.conversation.edit">
                <item name="wcf.conversation.edit.addParticipants"><![CDATA[Teilnehmer hinzufügen]]></item>
index 0048a0dfdfd91ac591fb7a9be954f71eb66e1200..e22804e22c5b3454db5d58cd6e0eab43ac8d87c2 100644 (file)
                <item name="wcf.conversation.time"><![CDATA[Creation]]></item>
                <item name="wcf.conversation.username"><![CDATA[Author]]></item>
                <item name="wcf.conversation.error.floodControl"><![CDATA[You have already started {if $limit == 1}one conversation{else}{#$limit} conversations{/if} in the past 24 hours. Please wait until <strong>{@$notBefore|time}</strong> before you start a new conversation.]]></item>
+               <item name="wcf.conversation.message.error.floodControl"><![CDATA[You have already sent a message within the last {plural value=$__wcf->getSession()->getPermission('user.conversation.floodControlTime') 1='second' other='# seconds'}. You must wait at least {plural value=$waitTime 1='second' other='# seconds'} before attempting to write a new message.]]></item>
        </category>
        <category name="wcf.conversation.edit">
                <item name="wcf.conversation.edit.addParticipants"><![CDATA[Add Participants]]></item>