3 use wcf\data\conversation\label\ConversationLabel
;
4 use wcf\data\conversation\label\ConversationLabelList
;
5 use wcf\data\conversation\message\ConversationMessage
;
6 use wcf\data\conversation\message\ViewableConversationMessageList
;
7 use wcf\data\conversation\Conversation
;
8 use wcf\data\conversation\ConversationAction
;
9 use wcf\data\conversation\ConversationParticipantList
;
10 use wcf\data\conversation\ViewableConversation
;
11 use wcf\data\modification\log\ConversationLogModificationLogList
;
12 use wcf\data\smiley\SmileyCache
;
13 use wcf\data\user\UserProfile
;
14 use wcf\system\attachment\AttachmentHandler
;
15 use wcf\system\bbcode\BBCodeHandler
;
16 use wcf\system\exception\IllegalLinkException
;
17 use wcf\system\exception\PermissionDeniedException
;
18 use wcf\system\message\quote\MessageQuoteManager
;
19 use wcf\system\page\PageLocationManager
;
20 use wcf\system\page\ParentPageLocation
;
21 use wcf\system\request\LinkHandler
;
22 use wcf\system\user\signature\SignatureCache
;
24 use wcf\util\HeaderUtil
;
25 use wcf\util\StringUtil
;
28 * Shows a conversation.
31 * @copyright 2001-2019 WoltLab GmbH
32 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
33 * @package WoltLabSuite\Core\Page
35 * @property ViewableConversationMessageList $objectList
37 class ConversationPage
extends MultipleLinkPage
{
41 public $itemsPerPage = CONVERSATION_MESSAGES_PER_PAGE
;
46 public $sortOrder = 'ASC';
51 public $objectListClassName = ViewableConversationMessageList
::class;
56 public $loginRequired = true;
61 public $neededModules = ['MODULE_CONVERSATION'];
66 public $neededPermissions = ['user.conversation.canUseConversation'];
72 public $conversationID = 0;
75 * viewable conversation object
76 * @var ViewableConversation
81 * conversation label list
82 * @var ConversationLabelList
90 public $messageID = 0;
93 * conversation message object
94 * @var ConversationMessage
99 * modification log list object
100 * @var ConversationLogModificationLogList
102 public $modificationLogList;
105 * list of participants
106 * @var ConversationParticipantList
108 public $participantList;
113 public function readParameters() {
114 parent
::readParameters();
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();
123 $this->conversationID
= $this->message
->conversationID
;
126 $this->conversation
= Conversation
::getUserConversation($this->conversationID
, WCF
::getUser()->userID
);
127 if ($this->conversation
=== null) {
128 throw new IllegalLinkException();
130 if (!$this->conversation
->canRead()) {
131 throw new PermissionDeniedException();
135 $this->labelList
= ConversationLabel
::getLabelsByUser();
136 $this->conversation
= ViewableConversation
::getViewableConversation($this->conversation
, $this->labelList
);
139 /** @noinspection PhpUndefinedFieldInspection */
140 if (WCF
::getUser()->conversationMessagesPerPage
) {
141 /** @noinspection PhpUndefinedFieldInspection */
142 $this->itemsPerPage
= WCF
::getUser()->conversationMessagesPerPage
;
145 $this->canonicalURL
= LinkHandler
::getInstance()->getLink('Conversation', [
146 'object' => $this->conversation
147 ], ($this->pageNo ?
'pageNo=' . $this->pageNo
: ''));
153 protected function initObjectList() {
154 parent
::initObjectList();
156 $this->objectList
->getConditionBuilder()->add('conversation_message.conversationID = ?', [$this->conversation
->conversationID
]);
157 $this->objectList
->setConversation($this->conversation
->getDecoratedObject());
159 // handle visibility filter
160 if ($this->conversation
->joinedAt
> 0) $this->objectList
->getConditionBuilder()->add('conversation_message.time >= ?', [$this->conversation
->joinedAt
]);
161 if ($this->conversation
->leftAt
> 0) $this->objectList
->getConditionBuilder()->add('conversation_message.time <= ?', [$this->conversation
->leftAt
]);
164 if ($this->action
== 'lastPost') $this->goToLastPost();
165 if ($this->action
== 'firstNew') $this->goToFirstNewPost();
166 if ($this->messageID
) $this->goToPost();
172 public function readData() {
176 if ($this->conversation
->isDraft
) {
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'])
183 PageLocationManager
::getInstance()->addParentLocation('com.woltlab.wcf.conversation.ConversationList');
185 // update last visit time count
187 $this->conversation
->isNew()
189 $this->objectList
->getMaxPostTime() > $this->conversation
->lastVisitTime
190 ||
($this->conversation
->joinedAt
&& !count($this->objectList
))
193 $visitTime = $this->objectList
->getMaxPostTime();
194 if ($visitTime == $this->conversation
->lastPostTime
) $visitTime = TIME_NOW
;
195 $conversationAction = new ConversationAction([$this->conversation
->getDecoratedObject()], 'markAsRead', ['visitTime' => $visitTime]);
196 $conversationAction->executeAction();
200 $this->participantList
= new ConversationParticipantList($this->conversationID
, WCF
::getUser()->userID
, $this->conversation
->userID
== WCF
::getUser()->userID
);
201 $this->participantList
->readObjects();
203 // init quote objects
205 foreach ($this->objectList
as $message) {
206 $messageIDs[] = $message->messageID
;
208 MessageQuoteManager
::getInstance()->initObjects('com.woltlab.wcf.conversation.message', $messageIDs);
211 foreach ($this->objectList
as $message) {
212 if ($message->userID
) {
213 $userIDs[] = $message->userID
;
217 // fetch special trophies
219 if (!empty($userIDs)) {
220 UserProfile
::prepareSpecialTrophies(array_unique($userIDs));
224 if (MODULE_USER_SIGNATURE
) {
225 if (!empty($userIDs)) {
226 SignatureCache
::getInstance()->cacheUserSignature($userIDs);
230 // set attachment permissions
231 if ($this->objectList
->getAttachmentList() !== null) {
232 $this->objectList
->getAttachmentList()->setPermissions([
233 'canDownload' => true,
234 'canViewPreview' => true
238 // get timeframe for modifications
239 $this->objectList
->rewind();
240 $startTime = ($this->conversation
->joinedAt ?
: $this->objectList
->current()->time
);
241 $endTime = ($this->conversation
->leftAt ?
: TIME_NOW
);
243 $count = count($this->objectList
);
245 $this->objectList
->seek($count - 1);
246 if ($this->objectList
->current()->time
< $this->conversation
->lastPostTime
) {
248 FROM wcf".WCF_N
."_conversation_message
249 WHERE conversationID = ?
252 $statement = WCF
::getDB()->prepareStatement($sql, 1);
253 $statement->execute([$this->conversationID
, $this->objectList
->current()->time
]);
254 $endTime = $statement->fetchSingleColumn() - 1;
257 $this->objectList
->rewind();
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
;
269 // load modification log entries
270 $this->modificationLogList
= new ConversationLogModificationLogList($this->conversation
->conversationID
);
271 $this->modificationLogList
->getConditionBuilder()->add("modification_log.time BETWEEN ? AND ?", [$startTime, $endTime]);
273 if (!empty($invisibleParticipantIDs)) {
274 $this->modificationLogList
->getConditionBuilder()->add("(modification_log.action <> ? OR modification_log.userID NOT IN (?))", ['leave', $invisibleParticipantIDs]);
277 $this->modificationLogList
->readObjects();
283 public function assignVariables() {
284 parent
::assignVariables();
286 MessageQuoteManager
::getInstance()->assignVariables();
288 $tmpHash = StringUtil
::getRandomID();
289 $attachmentHandler = new AttachmentHandler('com.woltlab.wcf.conversation.message', 0, $tmpHash, 0);
291 WCF
::getTPL()->assign([
292 'attachmentHandler' => $attachmentHandler,
293 'attachmentObjectID' => 0,
294 'attachmentObjectType' => 'com.woltlab.wcf.conversation.message',
295 'attachmentParentObjectID' => 0,
296 'tmpHash' => $tmpHash,
297 'attachmentList' => $this->objectList
->getAttachmentList(),
298 'labelList' => $this->labelList
,
299 'modificationLogList' => $this->modificationLogList
,
300 'sortOrder' => $this->sortOrder
,
301 'conversation' => $this->conversation
,
302 'conversationID' => $this->conversationID
,
303 'participants' => $this->participantList
->getObjects(),
304 'defaultSmilies' => SmileyCache
::getInstance()->getCategorySmilies()
307 BBCodeHandler
::getInstance()->setDisallowedBBCodes(explode(',', WCF
::getSession()->getPermission('user.message.disallowedBBCodes')));
311 * Calculates the position of a specific post in this conversation.
313 protected function goToPost() {
314 $conditionBuilder = clone $this->objectList
->getConditionBuilder();
315 $conditionBuilder->add('time '.($this->sortOrder
== 'ASC' ?
'<=' : '>=').' ?', [$this->message
->time
]);
317 $sql = "SELECT COUNT(*) AS messages
318 FROM wcf".WCF_N
."_conversation_message conversation_message
320 $statement = WCF
::getDB()->prepareStatement($sql);
321 $statement->execute($conditionBuilder->getParameters());
322 $row = $statement->fetchArray();
323 $this->pageNo
= intval(ceil($row['messages'] / $this->itemsPerPage
));
327 * Gets the id of the last post in this conversation and forwards the user to this post.
329 protected function goToLastPost() {
330 $sql = "SELECT conversation_message.messageID
331 FROM wcf".WCF_N
."_conversation_message conversation_message
332 ".$this->objectList
->getConditionBuilder()."
333 ORDER BY time ".($this->sortOrder
== 'ASC' ?
'DESC' : 'ASC');
334 $statement = WCF
::getDB()->prepareStatement($sql, 1);
335 $statement->execute($this->objectList
->getConditionBuilder()->getParameters());
336 $row = $statement->fetchArray();
337 HeaderUtil
::redirect(LinkHandler
::getInstance()->getLink('Conversation', [
338 'encodeTitle' => true,
339 'object' => $this->conversation
,
340 'messageID' => $row['messageID']
341 ]).'#message'.$row['messageID']);
346 * Forwards the user to the first new message in this conversation.
348 protected function goToFirstNewPost() {
349 $conditionBuilder = clone $this->objectList
->getConditionBuilder();
350 $conditionBuilder->add('time > ?', [$this->conversation
->lastVisitTime
]);
352 $sql = "SELECT conversation_message.messageID
353 FROM wcf".WCF_N
."_conversation_message conversation_message
354 ".$conditionBuilder."
356 $statement = WCF
::getDB()->prepareStatement($sql, 1);
357 $statement->execute($conditionBuilder->getParameters());
358 $row = $statement->fetchArray();
359 if ($row !== false) {
360 HeaderUtil
::redirect(LinkHandler
::getInstance()->getLink('Conversation', [
361 'encodeTitle' => true,
362 'object' => $this->conversation
,
363 'messageID' => $row['messageID']
364 ]).'#message'.$row['messageID']);
368 $this->goToLastPost();