3 use wcf\data\conversation\label\ConversationLabel
;
4 use wcf\data\conversation\label\ConversationLabelList
;
5 use wcf\data\conversation\UserConversationList
;
6 use wcf\system\clipboard\ClipboardHandler
;
7 use wcf\system\database\util\PreparedStatementConditionBuilder
;
8 use wcf\system\exception\IllegalLinkException
;
9 use wcf\system\page\PageLocationManager
;
10 use wcf\system\request\LinkHandler
;
12 use wcf\util\ArrayUtil
;
13 use wcf\util\HeaderUtil
;
16 * Shows a list of conversations.
19 * @copyright 2001-2019 WoltLab GmbH
20 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
21 * @package WoltLabSuite\Core\Page
23 * @property UserConversationList $objectList
25 class ConversationListPage
extends SortablePage
{
29 public $defaultSortField = CONVERSATION_LIST_DEFAULT_SORT_FIELD
;
34 public $defaultSortOrder = CONVERSATION_LIST_DEFAULT_SORT_ORDER
;
39 public $validSortFields = ['subject', 'time', 'username', 'lastPostTime', 'replies', 'participants'];
44 public $itemsPerPage = CONVERSATIONS_PER_PAGE
;
49 public $loginRequired = true;
54 public $neededModules = ['MODULE_CONVERSATION'];
59 public $neededPermissions = ['user.conversation.canUseConversation'];
75 * @var ConversationLabelList
80 * number of conversations (no filter)
83 public $conversationCount = 0;
89 public $draftCount = 0;
92 * number of hidden conversations
95 public $hiddenCount = 0;
98 * number of sent conversations
101 public $outboxCount = 0;
107 public $participants = [];
112 public function readParameters() {
113 parent
::readParameters();
115 if (isset($_REQUEST['filter'])) $this->filter
= $_REQUEST['filter'];
116 if (!in_array($this->filter
, UserConversationList
::$availableFilters)) $this->filter
= '';
119 /** @noinspection PhpUndefinedFieldInspection */
120 if (WCF
::getUser()->conversationsPerPage
) {
121 /** @noinspection PhpUndefinedFieldInspection */
122 $this->itemsPerPage
= WCF
::getUser()->conversationsPerPage
;
126 $this->labelList
= ConversationLabel
::getLabelsByUser();
127 if (!empty($_REQUEST['labelID'])) {
128 $this->labelID
= intval($_REQUEST['labelID']);
131 foreach ($this->labelList
as $label) {
132 if ($label->labelID
== $this->labelID
) {
139 throw new IllegalLinkException();
143 if (isset($_REQUEST['participants'])) $this->participants
= array_slice(ArrayUtil
::trim(explode(',', $_REQUEST['participants'])), 0, 20);
145 if (!empty($_POST)) {
146 $participantsParameter = '';
147 foreach ($this->participants
as $participant) {
148 if (!empty($participantsParameter)) $participantsParameter .= ',';
149 $participantsParameter .= \rawurlencode
($participant);
151 if (!empty($participantsParameter)) {
152 $participantsParameter = '&participants=' . $participantsParameter;
155 HeaderUtil
::redirect(LinkHandler
::getInstance()->getLink('ConversationList', [], 'sortField='.$this->sortField
.'&sortOrder='.$this->sortOrder
.'&filter='.$this->filter
.'&labelID='.$this->labelID
.'&pageNo='.$this->pageNo
.$participantsParameter));
160 /** @noinspection PhpMissingParentCallCommonInspection */
164 protected function initObjectList() {
165 $this->objectList
= new UserConversationList(WCF
::getUser()->userID
, $this->filter
, $this->labelID
);
166 $this->objectList
->setLabelList($this->labelList
);
168 if (!empty($this->participants
)) {
169 // The column `conversation_to_user.username` has no index, causing full table scans when
170 // trying to filter by it, therefore we'll read the user ids in advance.
171 $conditions = new PreparedStatementConditionBuilder();
172 $conditions->add('username IN (?)', [$this->participants
]);
173 $sql = "SELECT userID
174 FROM wcf".WCF_N
."_user
176 $statement = WCF
::getDB()->prepareStatement($sql);
177 $statement->execute($conditions->getParameters());
179 while ($userID = $statement->fetchColumn()) {
180 $userIDs[] = $userID;
183 if (!empty($userIDs)) {
184 // The condition is split into two branches in order to account for invisible participants.
185 // Invisible participants are only visible to the conversation starter and remain invisible
186 // until the write their first message.
188 // We need to protect these users from being exposed as participants by including them for
189 // any conversation that the current user has started. For all other conversations, users
190 // flagged with `isInvisible = 0` must be excluded.
192 // See https://github.com/WoltLab/com.woltlab.wcf.conversation/issues/131
193 $this->objectList
->getConditionBuilder()->add('
196 conversation.userID = ?
198 conversation.conversationID IN (
199 SELECT conversationID
200 FROM wcf'.WCF_N
.'_conversation_to_user
201 WHERE participantID IN (?)
202 GROUP BY conversationID
203 HAVING COUNT(conversationID) = ?
208 conversation.userID <> ?
210 conversation.conversationID IN (
211 SELECT conversationID
212 FROM wcf'.WCF_N
.'_conversation_to_user
213 WHERE participantID IN (?)
215 GROUP BY conversationID
216 HAVING COUNT(conversationID) = ?
220 // Parameters for the first condition.
221 WCF
::getUser()->userID
,
225 // Parameters for the second condition.
226 WCF
::getUser()->userID
,
238 public function readData() {
239 // if sort field is `username`, `conversation.` has to prepended because `username`
240 // alone is ambiguous
241 if ($this->sortField
=== 'username') {
242 $this->sortField
= 'conversation.username';
247 // change back to old value
248 if ($this->sortField
=== 'conversation.username') {
249 $this->sortField
= 'username';
252 if ($this->filter
!= '') {
253 // `-1` = pseudo object id to have to pages with identifier `com.woltlab.wcf.conversation.ConversationList`
254 PageLocationManager
::getInstance()->addParentLocation('com.woltlab.wcf.conversation.ConversationList', -1);
258 if (!$this->labelID
&& empty($this->participants
)) {
259 switch ($this->filter
) {
261 $this->conversationCount
= $this->items
;
265 $this->draftCount
= $this->items
;
269 $this->hiddenCount
= $this->items
;
273 $this->outboxCount
= $this->items
;
278 if ($this->filter
!= '' ||
$this->labelID ||
!empty($this->participants
)) {
279 $conversationList = new UserConversationList(WCF
::getUser()->userID
, '');
280 $this->conversationCount
= $conversationList->countObjects();
282 if ($this->filter
!= 'draft' ||
$this->labelID ||
!empty($this->participants
)) {
283 $conversationList = new UserConversationList(WCF
::getUser()->userID
, 'draft');
284 $this->draftCount
= $conversationList->countObjects();
286 if ($this->filter
!= 'hidden' ||
$this->labelID ||
!empty($this->participants
)) {
287 $conversationList = new UserConversationList(WCF
::getUser()->userID
, 'hidden');
288 $this->hiddenCount
= $conversationList->countObjects();
290 if ($this->filter
!= 'outbox' ||
$this->labelID ||
!empty($this->participants
)) {
291 $conversationList = new UserConversationList(WCF
::getUser()->userID
, 'outbox');
292 $this->outboxCount
= $conversationList->countObjects();
299 public function assignVariables() {
300 parent
::assignVariables();
302 WCF
::getTPL()->assign([
303 'filter' => $this->filter
,
304 'hasMarkedItems' => ClipboardHandler
::getInstance()->hasMarkedItems(ClipboardHandler
::getInstance()->getObjectTypeID('com.woltlab.wcf.conversation.conversation')),
305 'labelID' => $this->labelID
,
306 'labelList' => $this->labelList
,
307 'conversationCount' => $this->conversationCount
,
308 'draftCount' => $this->draftCount
,
309 'hiddenCount' => $this->hiddenCount
,
310 'outboxCount' => $this->outboxCount
,
311 'participants' => $this->participants
,
312 'validSortFields' => $this->validSortFields
,