Commit | Line | Data |
---|---|---|
9544b6b4 MW |
1 | <?php |
2 | namespace wcf\page; | |
2e0bc870 | 3 | use wcf\data\conversation\label\ConversationLabel; |
9d25a4e3 | 4 | use wcf\data\conversation\label\ConversationLabelList; |
9544b6b4 | 5 | use wcf\data\conversation\message\ConversationMessage; |
65f1cc0b | 6 | use wcf\data\conversation\message\ViewableConversationMessageList; |
232cdc4b | 7 | use wcf\data\conversation\Conversation; |
9544b6b4 | 8 | use wcf\data\conversation\ConversationAction; |
530c5f83 | 9 | use wcf\data\conversation\ConversationParticipantList; |
2e0bc870 | 10 | use wcf\data\conversation\ViewableConversation; |
83e23d22 | 11 | use wcf\data\modification\log\ConversationLogModificationLogList; |
b2de9161 | 12 | use wcf\data\smiley\SmileyCache; |
195a4249 | 13 | use wcf\data\user\UserProfile; |
41c23899 | 14 | use wcf\system\attachment\AttachmentHandler; |
a21c8732 | 15 | use wcf\system\bbcode\BBCodeHandler; |
9544b6b4 MW |
16 | use wcf\system\exception\IllegalLinkException; |
17 | use wcf\system\exception\PermissionDeniedException; | |
2d181735 | 18 | use wcf\system\message\quote\MessageQuoteManager; |
e298db3c | 19 | use wcf\system\page\PageLocationManager; |
2163ec8f | 20 | use wcf\system\page\ParentPageLocation; |
9544b6b4 | 21 | use wcf\system\request\LinkHandler; |
a3273089 | 22 | use wcf\system\user\signature\SignatureCache; |
9544b6b4 MW |
23 | use wcf\system\WCF; |
24 | use wcf\util\HeaderUtil; | |
41c23899 | 25 | use wcf\util\StringUtil; |
9544b6b4 MW |
26 | |
27 | /** | |
28 | * Shows a conversation. | |
61f754e0 | 29 | * |
9544b6b4 | 30 | * @author Marcel Werk |
4ddaa70e | 31 | * @copyright 2001-2019 WoltLab GmbH |
9544b6b4 | 32 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> |
c032049e | 33 | * @package WoltLabSuite\Core\Page |
7e95339f MS |
34 | * |
35 | * @property ViewableConversationMessageList $objectList | |
9544b6b4 MW |
36 | */ |
37 | class ConversationPage extends MultipleLinkPage { | |
38 | /** | |
65f1cc0b | 39 | * @inheritDoc |
9544b6b4 MW |
40 | */ |
41 | public $itemsPerPage = CONVERSATION_MESSAGES_PER_PAGE; | |
42 | ||
43 | /** | |
65f1cc0b | 44 | * @inheritDoc |
9544b6b4 MW |
45 | */ |
46 | public $sortOrder = 'ASC'; | |
47 | ||
48 | /** | |
65f1cc0b | 49 | * @inheritDoc |
9544b6b4 | 50 | */ |
65f1cc0b | 51 | public $objectListClassName = ViewableConversationMessageList::class; |
9544b6b4 | 52 | |
84e18f05 | 53 | /** |
65f1cc0b | 54 | * @inheritDoc |
84e18f05 MS |
55 | */ |
56 | public $loginRequired = true; | |
57 | ||
c764783c | 58 | /** |
65f1cc0b | 59 | * @inheritDoc |
c764783c | 60 | */ |
65f1cc0b | 61 | public $neededModules = ['MODULE_CONVERSATION']; |
c764783c MW |
62 | |
63 | /** | |
65f1cc0b | 64 | * @inheritDoc |
c764783c | 65 | */ |
65f1cc0b | 66 | public $neededPermissions = ['user.conversation.canUseConversation']; |
c764783c | 67 | |
9544b6b4 MW |
68 | /** |
69 | * conversation id | |
61f754e0 | 70 | * @var integer |
9544b6b4 MW |
71 | */ |
72 | public $conversationID = 0; | |
73 | ||
74 | /** | |
a208d1f4 | 75 | * viewable conversation object |
65f1cc0b | 76 | * @var ViewableConversation |
9544b6b4 | 77 | */ |
537bf61d | 78 | public $conversation; |
9544b6b4 | 79 | |
2e0bc870 AE |
80 | /** |
81 | * conversation label list | |
65f1cc0b | 82 | * @var ConversationLabelList |
2e0bc870 | 83 | */ |
537bf61d | 84 | public $labelList; |
2e0bc870 | 85 | |
9544b6b4 MW |
86 | /** |
87 | * message id | |
61f754e0 | 88 | * @var integer |
9544b6b4 MW |
89 | */ |
90 | public $messageID = 0; | |
91 | ||
92 | /** | |
93 | * conversation message object | |
65f1cc0b | 94 | * @var ConversationMessage |
9544b6b4 | 95 | */ |
537bf61d | 96 | public $message; |
9544b6b4 | 97 | |
a208d1f4 AE |
98 | /** |
99 | * modification log list object | |
65f1cc0b | 100 | * @var ConversationLogModificationLogList |
a208d1f4 | 101 | */ |
537bf61d | 102 | public $modificationLogList; |
a208d1f4 | 103 | |
530c5f83 MW |
104 | /** |
105 | * list of participants | |
65f1cc0b | 106 | * @var ConversationParticipantList |
530c5f83 | 107 | */ |
537bf61d | 108 | public $participantList; |
530c5f83 | 109 | |
9544b6b4 | 110 | /** |
65f1cc0b | 111 | * @inheritDoc |
9544b6b4 MW |
112 | */ |
113 | public function readParameters() { | |
114 | parent::readParameters(); | |
115 | ||
116 | if (isset($_REQUEST['id'])) $this->conversationID = intval($_REQUEST['id']); | |
117 | if (isset($_REQUEST['messageID'])) $this->messageID = intval($_REQUEST['messageID']); | |
118 | if ($this->messageID) { | |
119 | $this->message = new ConversationMessage($this->messageID); | |
120 | if (!$this->message->messageID) { | |
121 | throw new IllegalLinkException(); | |
122 | } | |
c764783c | 123 | $this->conversationID = $this->message->conversationID; |
9544b6b4 MW |
124 | } |
125 | ||
126 | $this->conversation = Conversation::getUserConversation($this->conversationID, WCF::getUser()->userID); | |
127 | if ($this->conversation === null) { | |
128 | throw new IllegalLinkException(); | |
129 | } | |
130 | if (!$this->conversation->canRead()) { | |
131 | throw new PermissionDeniedException(); | |
132 | } | |
133 | ||
2e0bc870 AE |
134 | // load labels |
135 | $this->labelList = ConversationLabel::getLabelsByUser(); | |
136 | $this->conversation = ViewableConversation::getViewableConversation($this->conversation, $this->labelList); | |
137 | ||
b41c9fd6 MS |
138 | // messages per page |
139 | /** @noinspection PhpUndefinedFieldInspection */ | |
140 | if (WCF::getUser()->conversationMessagesPerPage) { | |
141 | /** @noinspection PhpUndefinedFieldInspection */ | |
142 | $this->itemsPerPage = WCF::getUser()->conversationMessagesPerPage; | |
143 | } | |
ecadd37d | 144 | |
65f1cc0b | 145 | $this->canonicalURL = LinkHandler::getInstance()->getLink('Conversation', [ |
f6eb15c3 | 146 | 'object' => $this->conversation |
65f1cc0b | 147 | ], ($this->pageNo ? 'pageNo=' . $this->pageNo : '')); |
9544b6b4 MW |
148 | } |
149 | ||
150 | /** | |
65f1cc0b | 151 | * @inheritDoc |
9544b6b4 MW |
152 | */ |
153 | protected function initObjectList() { | |
154 | parent::initObjectList(); | |
155 | ||
65f1cc0b | 156 | $this->objectList->getConditionBuilder()->add('conversation_message.conversationID = ?', [$this->conversation->conversationID]); |
28bd6cbd | 157 | $this->objectList->setConversation($this->conversation->getDecoratedObject()); |
9544b6b4 | 158 | |
219838a1 AE |
159 | // handle visibility filter |
160 | if ($this->conversation->joinedAt > 0) $this->objectList->getConditionBuilder()->add('conversation_message.time >= ?', [$this->conversation->joinedAt]); | |
80f82b0f | 161 | if ($this->conversation->leftAt > 0) $this->objectList->getConditionBuilder()->add('conversation_message.time <= ?', [$this->conversation->leftAt]); |
219838a1 | 162 | |
9544b6b4 MW |
163 | // handle jump to |
164 | if ($this->action == 'lastPost') $this->goToLastPost(); | |
165 | if ($this->action == 'firstNew') $this->goToFirstNewPost(); | |
166 | if ($this->messageID) $this->goToPost(); | |
167 | } | |
168 | ||
169 | /** | |
65f1cc0b | 170 | * @inheritDoc |
9544b6b4 MW |
171 | */ |
172 | public function readData() { | |
173 | parent::readData(); | |
174 | ||
175 | // add breadcrumbs | |
f34884b9 | 176 | if ($this->conversation->isDraft) { |
2163ec8f MS |
177 | // `-1` = pseudo object id to have to pages with identifier `com.woltlab.wcf.conversation.ConversationList` |
178 | PageLocationManager::getInstance()->addParentLocation('com.woltlab.wcf.conversation.ConversationList', -1, new ParentPageLocation( | |
179 | WCF::getLanguage()->get('wcf.conversation.folder.draft'), | |
180 | LinkHandler::getInstance()->getLink('ConversationList', ['filter' => 'draft']) | |
181 | )); | |
f34884b9 | 182 | } |
2163ec8f | 183 | PageLocationManager::getInstance()->addParentLocation('com.woltlab.wcf.conversation.ConversationList'); |
9544b6b4 MW |
184 | |
185 | // update last visit time count | |
8ab7c9b9 MS |
186 | if ( |
187 | $this->conversation->isNew() | |
188 | && ( | |
189 | $this->objectList->getMaxPostTime() > $this->conversation->lastVisitTime | |
190 | || ($this->conversation->joinedAt && !count($this->objectList)) | |
191 | ) | |
192 | ) { | |
c0dd7a12 MW |
193 | $visitTime = $this->objectList->getMaxPostTime(); |
194 | if ($visitTime == $this->conversation->lastPostTime) $visitTime = TIME_NOW; | |
65f1cc0b | 195 | $conversationAction = new ConversationAction([$this->conversation->getDecoratedObject()], 'markAsRead', ['visitTime' => $visitTime]); |
9544b6b4 MW |
196 | $conversationAction->executeAction(); |
197 | } | |
530c5f83 MW |
198 | |
199 | // get participants | |
8a6ee075 | 200 | $this->participantList = new ConversationParticipantList($this->conversationID, WCF::getUser()->userID, $this->conversation->userID == WCF::getUser()->userID); |
530c5f83 | 201 | $this->participantList->readObjects(); |
42335f61 AE |
202 | |
203 | // init quote objects | |
65f1cc0b | 204 | $messageIDs = []; |
42335f61 AE |
205 | foreach ($this->objectList as $message) { |
206 | $messageIDs[] = $message->messageID; | |
207 | } | |
208 | MessageQuoteManager::getInstance()->initObjects('com.woltlab.wcf.conversation.message', $messageIDs); | |
f7b9b1f3 | 209 | |
a3273089 JR |
210 | $userIDs = []; |
211 | foreach ($this->objectList as $message) { | |
212 | if ($message->userID) { | |
213 | $userIDs[] = $message->userID; | |
214 | } | |
215 | } | |
216 | ||
195a4249 JR |
217 | // fetch special trophies |
218 | if (MODULE_TROPHY) { | |
195a4249 JR |
219 | if (!empty($userIDs)) { |
220 | UserProfile::prepareSpecialTrophies(array_unique($userIDs)); | |
221 | } | |
222 | } | |
223 | ||
a3273089 JR |
224 | if (MODULE_USER_SIGNATURE) { |
225 | if (!empty($userIDs)) { | |
226 | SignatureCache::getInstance()->cacheUserSignature($userIDs); | |
227 | } | |
228 | } | |
229 | ||
f7b9b1f3 MW |
230 | // set attachment permissions |
231 | if ($this->objectList->getAttachmentList() !== null) { | |
65f1cc0b | 232 | $this->objectList->getAttachmentList()->setPermissions([ |
f7b9b1f3 | 233 | 'canDownload' => true, |
a480521b | 234 | 'canViewPreview' => true |
65f1cc0b | 235 | ]); |
f7b9b1f3 | 236 | } |
a208d1f4 AE |
237 | |
238 | // get timeframe for modifications | |
239 | $this->objectList->rewind(); | |
219838a1 AE |
240 | $startTime = ($this->conversation->joinedAt ?: $this->objectList->current()->time); |
241 | $endTime = ($this->conversation->leftAt ?: TIME_NOW); | |
a208d1f4 AE |
242 | |
243 | $count = count($this->objectList); | |
a7e5e13c | 244 | if ($count > 1) { |
a208d1f4 | 245 | $this->objectList->seek($count - 1); |
a7e5e13c MW |
246 | if ($this->objectList->current()->time < $this->conversation->lastPostTime) { |
247 | $sql = "SELECT time | |
248 | FROM wcf".WCF_N."_conversation_message | |
249 | WHERE conversationID = ? | |
250 | AND time > ? | |
251 | ORDER BY time"; | |
252 | $statement = WCF::getDB()->prepareStatement($sql, 1); | |
eaf1c8eb | 253 | $statement->execute([$this->conversationID, $this->objectList->current()->time]); |
a7e5e13c | 254 | $endTime = $statement->fetchSingleColumn() - 1; |
d8838bd9 | 255 | } |
a208d1f4 AE |
256 | } |
257 | $this->objectList->rewind(); | |
258 | ||
28484add AE |
259 | // get invisible participants |
260 | $invisibleParticipantIDs = []; | |
261 | if (WCF::getUser()->userID != $this->conversation->userID) { | |
262 | foreach ($this->participantList as $participant) { | |
263 | if ($participant->isInvisible) { | |
264 | $invisibleParticipantIDs[] = $participant->userID; | |
265 | } | |
266 | } | |
267 | } | |
268 | ||
a208d1f4 | 269 | // load modification log entries |
a7e5e13c | 270 | $this->modificationLogList = new ConversationLogModificationLogList($this->conversation->conversationID); |
65f1cc0b | 271 | $this->modificationLogList->getConditionBuilder()->add("modification_log.time BETWEEN ? AND ?", [$startTime, $endTime]); |
28484add AE |
272 | |
273 | if (!empty($invisibleParticipantIDs)) { | |
274 | $this->modificationLogList->getConditionBuilder()->add("(modification_log.action <> ? OR modification_log.userID NOT IN (?))", ['leave', $invisibleParticipantIDs]); | |
275 | } | |
276 | ||
a208d1f4 | 277 | $this->modificationLogList->readObjects(); |
9544b6b4 MW |
278 | } |
279 | ||
280 | /** | |
65f1cc0b | 281 | * @inheritDoc |
9544b6b4 MW |
282 | */ |
283 | public function assignVariables() { | |
284 | parent::assignVariables(); | |
285 | ||
2d181735 AE |
286 | MessageQuoteManager::getInstance()->assignVariables(); |
287 | ||
41c23899 AE |
288 | $tmpHash = StringUtil::getRandomID(); |
289 | $attachmentHandler = new AttachmentHandler('com.woltlab.wcf.conversation.message', 0, $tmpHash, 0); | |
290 | ||
65f1cc0b | 291 | WCF::getTPL()->assign([ |
41c23899 AE |
292 | 'attachmentHandler' => $attachmentHandler, |
293 | 'attachmentObjectID' => 0, | |
294 | 'attachmentObjectType' => 'com.woltlab.wcf.conversation.message', | |
295 | 'attachmentParentObjectID' => 0, | |
296 | 'tmpHash' => $tmpHash, | |
9544b6b4 | 297 | 'attachmentList' => $this->objectList->getAttachmentList(), |
2e0bc870 | 298 | 'labelList' => $this->labelList, |
a208d1f4 | 299 | 'modificationLogList' => $this->modificationLogList, |
9544b6b4 MW |
300 | 'sortOrder' => $this->sortOrder, |
301 | 'conversation' => $this->conversation, | |
530c5f83 | 302 | 'conversationID' => $this->conversationID, |
52971287 | 303 | 'participants' => $this->participantList->getObjects(), |
cadc85bd | 304 | 'defaultSmilies' => SmileyCache::getInstance()->getCategorySmilies() |
65f1cc0b | 305 | ]); |
a21c8732 | 306 | |
dfecaf59 | 307 | BBCodeHandler::getInstance()->setDisallowedBBCodes(explode(',', WCF::getSession()->getPermission('user.message.disallowedBBCodes'))); |
9544b6b4 MW |
308 | } |
309 | ||
310 | /** | |
311 | * Calculates the position of a specific post in this conversation. | |
312 | */ | |
313 | protected function goToPost() { | |
314 | $conditionBuilder = clone $this->objectList->getConditionBuilder(); | |
65f1cc0b | 315 | $conditionBuilder->add('time '.($this->sortOrder == 'ASC' ? '<=' : '>=').' ?', [$this->message->time]); |
9544b6b4 MW |
316 | |
317 | $sql = "SELECT COUNT(*) AS messages | |
a480521b | 318 | FROM wcf".WCF_N."_conversation_message conversation_message |
9544b6b4 | 319 | ".$conditionBuilder; |
a21c8732 MS |
320 | $statement = WCF::getDB()->prepareStatement($sql); |
321 | $statement->execute($conditionBuilder->getParameters()); | |
9544b6b4 MW |
322 | $row = $statement->fetchArray(); |
323 | $this->pageNo = intval(ceil($row['messages'] / $this->itemsPerPage)); | |
324 | } | |
325 | ||
326 | /** | |
327 | * Gets the id of the last post in this conversation and forwards the user to this post. | |
328 | */ | |
329 | protected function goToLastPost() { | |
4f13dcae | 330 | $sql = "SELECT conversation_message.messageID |
a480521b | 331 | FROM wcf".WCF_N."_conversation_message conversation_message |
9544b6b4 | 332 | ".$this->objectList->getConditionBuilder()." |
a480521b | 333 | ORDER BY time ".($this->sortOrder == 'ASC' ? 'DESC' : 'ASC'); |
249da2b9 MS |
334 | $statement = WCF::getDB()->prepareStatement($sql, 1); |
335 | $statement->execute($this->objectList->getConditionBuilder()->getParameters()); | |
9544b6b4 | 336 | $row = $statement->fetchArray(); |
65f1cc0b | 337 | HeaderUtil::redirect(LinkHandler::getInstance()->getLink('Conversation', [ |
655bead9 | 338 | 'encodeTitle' => true, |
9544b6b4 MW |
339 | 'object' => $this->conversation, |
340 | 'messageID' => $row['messageID'] | |
65f1cc0b | 341 | ]).'#message'.$row['messageID']); |
9544b6b4 MW |
342 | exit; |
343 | } | |
344 | ||
345 | /** | |
346 | * Forwards the user to the first new message in this conversation. | |
347 | */ | |
348 | protected function goToFirstNewPost() { | |
349 | $conditionBuilder = clone $this->objectList->getConditionBuilder(); | |
65f1cc0b | 350 | $conditionBuilder->add('time > ?', [$this->conversation->lastVisitTime]); |
9544b6b4 MW |
351 | |
352 | $sql = "SELECT conversation_message.messageID | |
a480521b | 353 | FROM wcf".WCF_N."_conversation_message conversation_message |
9544b6b4 | 354 | ".$conditionBuilder." |
a480521b | 355 | ORDER BY time ASC"; |
a21c8732 MS |
356 | $statement = WCF::getDB()->prepareStatement($sql, 1); |
357 | $statement->execute($conditionBuilder->getParameters()); | |
9544b6b4 MW |
358 | $row = $statement->fetchArray(); |
359 | if ($row !== false) { | |
65f1cc0b | 360 | HeaderUtil::redirect(LinkHandler::getInstance()->getLink('Conversation', [ |
655bead9 | 361 | 'encodeTitle' => true, |
9544b6b4 MW |
362 | 'object' => $this->conversation, |
363 | 'messageID' => $row['messageID'] | |
65f1cc0b | 364 | ]).'#message'.$row['messageID']); |
9544b6b4 MW |
365 | exit; |
366 | } | |
367 | else { | |
368 | $this->goToLastPost(); | |
369 | } | |
370 | } | |
78fd78a7 | 371 | } |