Redirect to GET request after using the participant filter
[GitHub/WoltLab/com.woltlab.wcf.conversation.git] / files / lib / page / ConversationListPage.class.php
index c02ea272275e03d6aa5bcec0cce6587954f913ab..8dce6f794098bc2703f9621d232035147c76337a 100644 (file)
@@ -4,16 +4,19 @@ use wcf\data\conversation\label\ConversationLabel;
 use wcf\data\conversation\label\ConversationLabelList;
 use wcf\data\conversation\UserConversationList;
 use wcf\system\clipboard\ClipboardHandler;
+use wcf\system\database\util\PreparedStatementConditionBuilder;
 use wcf\system\exception\IllegalLinkException;
 use wcf\system\page\PageLocationManager;
+use wcf\system\request\LinkHandler;
 use wcf\system\WCF;
 use wcf\util\ArrayUtil;
+use wcf\util\HeaderUtil;
 
 /**
  * Shows a list of conversations.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2018 WoltLab GmbH
+ * @copyright  2001-2019 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    WoltLabSuite\Core\Page
  * 
@@ -121,7 +124,7 @@ class ConversationListPage extends SortablePage {
                
                // labels
                $this->labelList = ConversationLabel::getLabelsByUser();
-               if (isset($_REQUEST['labelID'])) {
+               if (!empty($_REQUEST['labelID'])) {
                        $this->labelID = intval($_REQUEST['labelID']);
                        
                        $validLabel = false;
@@ -137,7 +140,21 @@ class ConversationListPage extends SortablePage {
                        }
                }
                
-               if (isset($_REQUEST['participants'])) $this->participants = ArrayUtil::trim(explode(',', $_REQUEST['participants']));
+               if (isset($_REQUEST['participants'])) $this->participants = array_slice(ArrayUtil::trim(explode(',', $_REQUEST['participants'])), 0, 20);
+
+               if (!empty($_POST)) {
+                       $participantsParameter = '';
+                       foreach ($this->participants as $participant) {
+                               if (!empty($participantsParameter)) $participantsParameter .= ',';
+                               $participantsParameter .= \rawurlencode($participant);
+                       }
+                       if (!empty($participantsParameter)) {
+                               $participantsParameter = '&participants=' . $participantsParameter;
+                       }
+
+                       HeaderUtil::redirect(LinkHandler::getInstance()->getLink('ConversationList', [], 'sortField='.$this->sortField.'&sortOrder='.$this->sortOrder.'&filter='.$this->filter.'&labelID='.$this->labelID.'&pageNo='.$this->pageNo.$participantsParameter));
+                       exit;
+               }
        }
        
        /** @noinspection PhpMissingParentCallCommonInspection */
@@ -149,10 +166,69 @@ class ConversationListPage extends SortablePage {
                $this->objectList->setLabelList($this->labelList);
                
                if (!empty($this->participants)) {
-                       $this->objectList->getConditionBuilder()->add('conversation.conversationID IN (SELECT conversationID FROM wcf'.WCF_N.'_conversation_to_user WHERE username IN (?) GROUP BY conversationID HAVING COUNT(conversationID) = ?)', [
-                               $this->participants,
-                               count($this->participants)
-                       ]);
+                       // The column `conversation_to_user.username` has no index, causing full table scans when
+                       // trying to filter by it, therefore we'll read the user ids in advance.
+                       $conditions = new PreparedStatementConditionBuilder();
+                       $conditions->add('username IN (?)', [$this->participants]);
+                       $sql = "SELECT  userID
+                               FROM    wcf".WCF_N."_user
+                               ".$conditions;
+                       $statement = WCF::getDB()->prepareStatement($sql);
+                       $statement->execute($conditions->getParameters());
+                       $userIDs = [];
+                       while ($userID = $statement->fetchColumn()) {
+                               $userIDs[] = $userID;
+                       }
+                       
+                       if (!empty($userIDs)) {
+                               // The condition is split into two branches in order to account for invisible participants.
+                               // Invisible participants are only visible to the conversation starter and remain invisible
+                               // until the write their first message.
+                               //
+                               // We need to protect these users from being exposed as participants by including them for
+                               // any conversation that the current user has started. For all other conversations, users
+                               // flagged with `isInvisible = 0` must be excluded.
+                               //
+                               // See https://github.com/WoltLab/com.woltlab.wcf.conversation/issues/131
+                               $this->objectList->getConditionBuilder()->add('
+                                       (
+                                               (
+                                                       conversation.userID = ?
+                                                       AND
+                                                       conversation.conversationID IN (
+                                                               SELECT          conversationID
+                                                               FROM            wcf'.WCF_N.'_conversation_to_user
+                                                               WHERE           participantID IN (?)
+                                                               GROUP BY        conversationID
+                                                               HAVING          COUNT(conversationID) = ?
+                                                       )
+                                               )
+                                               OR
+                                               (
+                                                       conversation.userID <> ?
+                                                       AND
+                                                       conversation.conversationID IN (
+                                                               SELECT          conversationID
+                                                               FROM            wcf'.WCF_N.'_conversation_to_user
+                                                               WHERE           participantID IN (?)
+                                                                               AND isInvisible = ?
+                                                               GROUP BY        conversationID
+                                                               HAVING          COUNT(conversationID) = ?
+                                                       )
+                                               )
+                                       )', [
+                                       // Parameters for the first condition.
+                                       WCF::getUser()->userID,
+                                       $userIDs,
+                                       count($userIDs),
+                                       
+                                       // Parameters for the second condition.
+                                       WCF::getUser()->userID,
+                                       $userIDs,
+                                       0,
+                                       count($userIDs),
+                               ]);
+                       }
                }
        }
        
@@ -232,7 +308,8 @@ class ConversationListPage extends SortablePage {
                        'draftCount' => $this->draftCount,
                        'hiddenCount' => $this->hiddenCount,
                        'outboxCount' => $this->outboxCount,
-                       'participants' => $this->participants
+                       'participants' => $this->participants,
+                       'validSortFields' => $this->validSortFields,
                ]);
        }
 }