Enforce new canReply permission
[GitHub/WoltLab/com.woltlab.wcf.conversation.git] / files / lib / data / conversation / message / ConversationMessageAction.class.php
CommitLineData
9544b6b4
MW
1<?php
2namespace wcf\data\conversation\message;
3use wcf\data\conversation\Conversation;
3b34d39f 4use wcf\data\conversation\ConversationAction;
9544b6b4 5use wcf\data\conversation\ConversationEditor;
b2de9161 6use wcf\data\smiley\SmileyCache;
9544b6b4 7use wcf\data\AbstractDatabaseObjectAction;
52971287 8use wcf\data\DatabaseObject;
e77f4283 9use wcf\data\IAttachmentMessageQuickReplyAction;
4a2ee5bb 10use wcf\data\IMessageInlineEditorAction;
5fa9d104 11use wcf\data\IMessageQuoteAction;
5d7f0df0 12use wcf\system\attachment\AttachmentHandler;
a21c8732 13use wcf\system\bbcode\BBCodeHandler;
5e52978f
AE
14use wcf\system\exception\PermissionDeniedException;
15use wcf\system\exception\UserInputException;
5ff95003 16use wcf\system\html\input\HtmlInputProcessor;
d8671029 17use wcf\system\message\censorship\Censorship;
a0c1a541 18use wcf\system\message\embedded\object\MessageEmbeddedObjectManager;
5fa9d104 19use wcf\system\message\quote\MessageQuoteManager;
5e52978f 20use wcf\system\message\QuickReplyManager;
3b37e024 21use wcf\system\moderation\queue\ModerationQueueManager;
5e52978f 22use wcf\system\request\LinkHandler;
80a0761e 23use wcf\system\search\SearchIndexManager;
b5ffaf76
AE
24use wcf\system\user\notification\object\ConversationMessageUserNotificationObject;
25use wcf\system\user\notification\UserNotificationHandler;
df8f8628 26use wcf\system\user\storage\UserStorageHandler;
9544b6b4 27use wcf\system\WCF;
5e00d333 28use wcf\util\StringUtil;
9544b6b4
MW
29
30/**
3b37e024 31 * Executes conversation message-related actions.
9544b6b4
MW
32 *
33 * @author Marcel Werk
4ddaa70e 34 * @copyright 2001-2019 WoltLab GmbH
9544b6b4 35 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
c032049e 36 * @package WoltLabSuite\Core\Data\Conversation\Message
5def88a8
MS
37 *
38 * @method ConversationMessageEditor[] getObjects()
39 * @method ConversationMessageEditor getSingleObject()
9544b6b4 40 */
e77f4283 41class ConversationMessageAction extends AbstractDatabaseObjectAction implements IAttachmentMessageQuickReplyAction, IMessageInlineEditorAction, IMessageQuoteAction {
9544b6b4 42 /**
9c3943b0 43 * @inheritDoc
9544b6b4 44 */
f586b354 45 protected $className = ConversationMessageEditor::class;
9544b6b4 46
5e52978f
AE
47 /**
48 * conversation object
1217c56d 49 * @var Conversation
5e52978f 50 */
1217c56d
AE
51 public $conversation;
52
53 /**
54 * @var HtmlInputProcessor
55 */
56 public $htmlInputProcessor;
5e52978f 57
a5bacc02
AE
58 /**
59 * conversation message object
1217c56d 60 * @var ConversationMessage
a5bacc02 61 */
1217c56d 62 public $message;
a5bacc02 63
9544b6b4 64 /**
9c3943b0 65 * @inheritDoc
5def88a8 66 * @return ConversationMessage
9544b6b4
MW
67 */
68 public function create() {
2a341b9b
AE
69 if (!isset($this->parameters['data']['enableHtml'])) $this->parameters['data']['enableHtml'] = 1;
70
9544b6b4
MW
71 // count attachments
72 if (isset($this->parameters['attachmentHandler']) && $this->parameters['attachmentHandler'] !== null) {
73 $this->parameters['data']['attachments'] = count($this->parameters['attachmentHandler']);
74 }
75
76 if (LOG_IP_ADDRESS) {
77 // add ip address
78 if (!isset($this->parameters['data']['ipAddress'])) {
79 $this->parameters['data']['ipAddress'] = WCF::getSession()->ipAddress;
80 }
81 }
82 else {
83 // do not track ip address
84 if (isset($this->parameters['data']['ipAddress'])) {
85 unset($this->parameters['data']['ipAddress']);
86 }
87 }
88
5ff95003 89 if (!empty($this->parameters['htmlInputProcessor'])) {
5887729d
AE
90 /** @noinspection PhpUndefinedMethodInspection */
91 $this->parameters['data']['message'] = $this->parameters['htmlInputProcessor']->getHtml();
5ff95003
AE
92 }
93
9544b6b4 94 // create message
c9ee8de8 95 /** @var ConversationMessage $message */
9544b6b4 96 $message = parent::create();
a0c1a541 97 $messageEditor = new ConversationMessageEditor($message);
9544b6b4 98
fcf27f27 99 // get conversation
7eafd933 100 $conversation = (isset($this->parameters['conversation']) ? $this->parameters['conversation'] : new Conversation($message->conversationID));
6f1cd040 101 $conversationEditor = new ConversationEditor($conversation);
61f754e0 102
4b541146 103 if (empty($this->parameters['isFirstPost'])) {
9544b6b4
MW
104 // update last message
105 $conversationEditor->addMessage($message);
64ac54a1
MW
106
107 // fire notification event
6f1cd040 108 if (!$conversation->isDraft) {
eaf1c8eb 109 $notificationRecipients = array_diff($conversation->getParticipantIDs(true), [$message->userID]); // don't notify message author
566eb43f 110 if (!empty($notificationRecipients)) {
901d21f2
MS
111 UserNotificationHandler::getInstance()->fireEvent(
112 'conversationMessage',
113 'com.woltlab.wcf.conversation.message.notification',
114 new ConversationMessageUserNotificationObject($message),
115 $notificationRecipients
116 );
566eb43f 117 }
5fa9d104 118 }
fcf27f27 119
ad478273
MW
120 $userConversation = Conversation::getUserConversation($conversation->conversationID, $message->userID);
121 if ($userConversation !== null && $userConversation->isInvisible) {
122 // make invisible participant visible
123 $sql = "UPDATE wcf".WCF_N."_conversation_to_user
124 SET isInvisible = 0
125 WHERE participantID = ?
126 AND conversationID = ?";
127 $statement = WCF::getDB()->prepareStatement($sql);
eaf1c8eb 128 $statement->execute([$message->userID, $conversation->conversationID]);
ad478273
MW
129
130 $conversationEditor->updateParticipantSummary();
131 $conversationEditor->updateParticipantCount();
132 }
0ff992a3
AE
133
134 // reset visibility if it was hidden but not left
135 $sql = "UPDATE wcf".WCF_N."_conversation_to_user
136 SET hideConversation = ?
137 WHERE conversationID = ?
138 AND hideConversation = ?";
139 $statement = WCF::getDB()->prepareStatement($sql);
eaf1c8eb 140 $statement->execute([
06695793 141 Conversation::STATE_DEFAULT,
0ff992a3 142 $conversation->conversationID,
06695793 143 Conversation::STATE_HIDDEN
eaf1c8eb 144 ]);
9544b6b4
MW
145 }
146
df8f8628 147 // reset storage
462d532a 148 UserStorageHandler::getInstance()->reset($conversation->getParticipantIDs(), 'unreadConversationCount');
9544b6b4 149
80a0761e 150 // update search index
901d21f2
MS
151 SearchIndexManager::getInstance()->set(
152 'com.woltlab.wcf.conversation.message',
153 $message->messageID,
154 $message->message,
155 !empty($this->parameters['isFirstPost']) ? $conversation->subject : '',
156 $message->time,
157 $message->userID,
158 $message->username
159 );
9544b6b4 160
e3f7a050
MW
161 // update attachments
162 if (isset($this->parameters['attachmentHandler']) && $this->parameters['attachmentHandler'] !== null) {
b41c9fd6 163 /** @noinspection PhpUndefinedMethodInspection */
e3f7a050
MW
164 $this->parameters['attachmentHandler']->updateObjectID($message->messageID);
165 }
166
a0c1a541 167 // save embedded objects
5887729d 168 if (!empty($this->parameters['htmlInputProcessor'])) {
2a341b9b
AE
169 /** @noinspection PhpUndefinedMethodInspection */
170 $this->parameters['htmlInputProcessor']->setObjectID($message->messageID);
171
a94cad7f 172 if (MessageEmbeddedObjectManager::getInstance()->registerObjects($this->parameters['htmlInputProcessor'])) {
5887729d
AE
173 $messageEditor->update(['hasEmbeddedObjects' => 1]);
174 }
a0c1a541
MW
175 }
176
5fa9d104 177 // clear quotes
f1781bd0
AE
178 if (isset($this->parameters['removeQuoteIDs']) && !empty($this->parameters['removeQuoteIDs'])) {
179 MessageQuoteManager::getInstance()->markQuotesForRemoval($this->parameters['removeQuoteIDs']);
180 }
5fa9d104
AE
181 MessageQuoteManager::getInstance()->removeMarkedQuotes();
182
9544b6b4
MW
183 // return new message
184 return $message;
185 }
c764783c
MW
186
187 /**
9c3943b0 188 * @inheritDoc
c764783c
MW
189 */
190 public function update() {
191 // count attachments
192 if (isset($this->parameters['attachmentHandler']) && $this->parameters['attachmentHandler'] !== null) {
193 $this->parameters['data']['attachments'] = count($this->parameters['attachmentHandler']);
194 }
195
5887729d
AE
196 if (!empty($this->parameters['htmlInputProcessor'])) {
197 /** @noinspection PhpUndefinedMethodInspection */
198 $this->parameters['data']['message'] = $this->parameters['htmlInputProcessor']->getHtml();
199 }
200
c764783c 201 parent::update();
80a0761e 202
a0c1a541 203 // update search index / embedded objects
28bd6cbd 204 if (isset($this->parameters['data']) && isset($this->parameters['data']['message'])) {
c9ee8de8 205 foreach ($this->getObjects() as $message) {
28bd6cbd 206 $conversation = $message->getConversation();
901d21f2
MS
207 SearchIndexManager::getInstance()->set(
208 'com.woltlab.wcf.conversation.message',
209 $message->messageID,
210 $this->parameters['data']['message'],
211 $conversation->firstMessageID == $message->messageID ? $conversation->subject : '',
212 $message->time,
213 $message->userID,
214 $message->username
215 );
28bd6cbd 216
5887729d 217 if (!empty($this->parameters['htmlInputProcessor'])) {
2a341b9b
AE
218 /** @noinspection PhpUndefinedMethodInspection */
219 $this->parameters['htmlInputProcessor']->setObjectID($message->messageID);
220
a94cad7f 221 if ($message->hasEmbeddedObjects != MessageEmbeddedObjectManager::getInstance()->registerObjects($this->parameters['htmlInputProcessor'])) {
8a6ee075 222 $message->update(['hasEmbeddedObjects' => $message->hasEmbeddedObjects ? 0 : 1]);
5887729d 223 }
28bd6cbd 224 }
a0c1a541 225 }
fcf27f27 226 }
c764783c 227 }
5e52978f 228
db07cb2d 229 /**
9c3943b0 230 * @inheritDoc
db07cb2d
AE
231 */
232 public function delete() {
233 $count = parent::delete();
234
eaf1c8eb 235 $attachmentMessageIDs = $conversationIDs = [];
c9ee8de8 236 foreach ($this->getObjects() as $message) {
3b34d39f
MS
237 if (!in_array($message->conversationID, $conversationIDs)) {
238 $conversationIDs[] = $message->conversationID;
239 }
240
5d7f0df0
MW
241 if ($message->attachments) {
242 $attachmentMessageIDs[] = $message->messageID;
db07cb2d
AE
243 }
244 }
245
3b34d39f
MS
246 // rebuild conversations
247 if (!empty($conversationIDs)) {
248 $conversationAction = new ConversationAction($conversationIDs, 'rebuild');
249 $conversationAction->executeAction();
250 }
251
5d7f0df0
MW
252 if (!empty($this->objectIDs)) {
253 // delete notifications
9888e764 254 UserNotificationHandler::getInstance()->removeNotifications('com.woltlab.wcf.conversation.message.notification', $this->objectIDs);
3b34d39f 255
5d7f0df0
MW
256 // update search index
257 SearchIndexManager::getInstance()->delete('com.woltlab.wcf.conversation.message', $this->objectIDs);
3b37e024 258
a0c1a541
MW
259 // update embedded objects
260 MessageEmbeddedObjectManager::getInstance()->removeObjects('com.woltlab.wcf.conversation.message', $this->objectIDs);
261
3b37e024
AE
262 // remove moderation queues
263 ModerationQueueManager::getInstance()->removeQueues('com.woltlab.wcf.conversation.message', $this->objectIDs);
5d7f0df0
MW
264 }
265
266 // remove attachments
267 if (!empty($attachmentMessageIDs)) {
268 AttachmentHandler::removeAttachments('com.woltlab.wcf.conversation.message', $attachmentMessageIDs);
269 }
270
db07cb2d
AE
271 return $count;
272 }
273
5e52978f 274 /**
9c3943b0 275 * @inheritDoc
5e52978f
AE
276 */
277 public function validateQuickReply() {
c2514e3d 278 QuickReplyManager::getInstance()->setDisallowedBBCodes(explode(',', WCF::getSession()->getPermission('user.message.disallowedBBCodes')));
f586b354 279 QuickReplyManager::getInstance()->validateParameters($this, $this->parameters, Conversation::class);
5e52978f
AE
280 }
281
282 /**
9c3943b0 283 * @inheritDoc
5e52978f
AE
284 */
285 public function quickReply() {
286 return QuickReplyManager::getInstance()->createMessage(
287 $this,
288 $this->parameters,
f586b354 289 ConversationAction::class,
9353cd87
AE
290 CONVERSATION_LIST_DEFAULT_SORT_ORDER,
291 'conversationMessageList'
5e52978f
AE
292 );
293 }
294
a5bacc02 295 /**
9c3943b0 296 * @inheritDoc
a5bacc02
AE
297 */
298 public function validateJumpToExtended() {
c2b8907c
AE
299 $this->readInteger('containerID');
300 $this->readString('message', true);
a7dd6eef 301 $this->readString('tmpHash', true);
a5bacc02 302
c2b8907c
AE
303 $this->conversation = new Conversation($this->parameters['containerID']);
304 if (!$this->conversation->conversationID) {
86a5431b 305 throw new UserInputException('containerID');
a5bacc02 306 }
eaf1c8eb 307 else if ($this->conversation->isClosed || !Conversation::isParticipant([$this->conversation->conversationID])) {
c2b8907c 308 throw new PermissionDeniedException();
a5bacc02
AE
309 }
310
311 // editing existing message
312 if (isset($this->parameters['messageID'])) {
313 $this->message = new ConversationMessage(intval($this->parameters['messageID']));
314 if (!$this->message->messageID || ($this->message->conversationID != $this->conversation->conversationID)) {
315 throw new UserInputException('messageID');
316 }
61f754e0 317
a5bacc02
AE
318 if (!$this->message->canEdit()) {
319 throw new PermissionDeniedException();
320 }
321 }
322 }
323
324 /**
9c3943b0 325 * @inheritDoc
a5bacc02
AE
326 */
327 public function jumpToExtended() {
328 // quick reply
329 if ($this->message === null) {
330 QuickReplyManager::getInstance()->setMessage('conversation', $this->conversation->conversationID, $this->parameters['message']);
eaf1c8eb 331 $url = LinkHandler::getInstance()->getLink('ConversationMessageAdd', ['id' => $this->conversation->conversationID]);
a5bacc02
AE
332 }
333 else {
334 // editing message
335 QuickReplyManager::getInstance()->setMessage('conversationMessage', $this->message->messageID, $this->parameters['message']);
eaf1c8eb 336 $url = LinkHandler::getInstance()->getLink('ConversationMessageEdit', ['id' => $this->message->messageID]);
a5bacc02
AE
337 }
338
a7dd6eef
AE
339 if (!empty($this->parameters['tmpHash'])) {
340 QuickReplyManager::getInstance()->setTmpHash($this->parameters['tmpHash']);
341 }
342
a5bacc02 343 // redirect
eaf1c8eb 344 return [
a5bacc02 345 'url' => $url
eaf1c8eb 346 ];
a5bacc02
AE
347 }
348
b5ffaf76 349 /**
9c3943b0 350 * @inheritDoc
b5ffaf76
AE
351 */
352 public function validateBeginEdit() {
c2b8907c
AE
353 $this->readInteger('containerID');
354 $this->readInteger('objectID');
355
356 $this->conversation = new Conversation($this->parameters['containerID']);
357 if (!$this->conversation->conversationID) {
b5ffaf76
AE
358 throw new UserInputException('containerID');
359 }
c2b8907c 360
eaf1c8eb 361 if ($this->conversation->isClosed || !Conversation::isParticipant([$this->conversation->conversationID])) {
c2b8907c 362 throw new PermissionDeniedException();
b5ffaf76
AE
363 }
364
c2b8907c
AE
365 $this->message = new ConversationMessage($this->parameters['objectID']);
366 if (!$this->message->messageID) {
b5ffaf76
AE
367 throw new UserInputException('objectID');
368 }
c2b8907c
AE
369
370 if (!$this->message->canEdit()) {
371 throw new PermissionDeniedException();
b5ffaf76 372 }
c2514e3d
AE
373
374 BBCodeHandler::getInstance()->setDisallowedBBCodes(explode(',', WCF::getSession()->getPermission('user.message.disallowedBBCodes')));
b5ffaf76
AE
375 }
376
377 /**
9c3943b0 378 * @inheritDoc
b5ffaf76
AE
379 */
380 public function beginEdit() {
eaf1c8eb 381 WCF::getTPL()->assign([
b2de9161 382 'defaultSmilies' => SmileyCache::getInstance()->getCategorySmilies(),
b5ffaf76 383 'message' => $this->message,
a21c8732 384 'permissionCanUseSmilies' => 'user.message.canUseSmilies',
71d51a10 385 'wysiwygSelector' => 'messageEditor'.$this->message->messageID,
eaf1c8eb 386 ]);
b5ffaf76 387
71d51a10
MS
388 $tmpHash = StringUtil::getRandomID();
389 $attachmentHandler = new AttachmentHandler('com.woltlab.wcf.conversation.message', $this->message->messageID, $tmpHash);
390 $attachmentList = $attachmentHandler->getAttachmentList();
391
392 WCF::getTPL()->assign([
393 'attachmentHandler' => $attachmentHandler,
394 'attachmentList' => $attachmentList->getObjects(),
395 'attachmentObjectID' => $this->message->messageID,
396 'attachmentObjectType' => 'com.woltlab.wcf.conversation.message',
397 'attachmentParentObjectID' => 0,
398 'tmpHash' => $tmpHash,
399 ]);
5e00d333 400
eaf1c8eb 401 return [
b5ffaf76 402 'actionName' => 'beginEdit',
71d51a10 403 'template' => WCF::getTPL()->fetch('conversationMessageInlineEditor'),
eaf1c8eb 404 ];
b5ffaf76
AE
405 }
406
407 /**
9c3943b0 408 * @inheritDoc
b5ffaf76
AE
409 */
410 public function validateSave() {
9101781c
MS
411 $this->readString('message', true, 'data');
412
413 if (empty($this->parameters['data']['message'])) {
a943eb00 414 throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('wcf.global.form.error.empty'));
9101781c 415 }
b5ffaf76
AE
416
417 $this->validateBeginEdit();
5ff95003 418
2cccc1b6 419 $this->validateMessage($this->conversation, $this->getHtmlInputProcessor($this->parameters['data']['message'], $this->message->messageID));
b5ffaf76
AE
420 }
421
422 /**
9c3943b0 423 * @inheritDoc
b5ffaf76
AE
424 */
425 public function save() {
5887729d 426 $data = [];
5ff95003 427
e7ed68e5
MW
428 if (!$this->message->getConversation()->isDraft) {
429 $data['lastEditTime'] = TIME_NOW;
430 $data['editCount'] = $this->message->editCount + 1;
431 }
28bd6cbd 432 // execute update action
5887729d
AE
433 $action = new ConversationMessageAction([$this->message], 'update', [
434 'data' => $data,
435 'htmlInputProcessor' => $this->getHtmlInputProcessor()
436 ]);
28bd6cbd 437 $action->executeAction();
b5ffaf76
AE
438
439 // load new message
440 $this->message = new ConversationMessage($this->message->messageID);
f7b9b1f3 441 $this->message->getAttachments();
b5ffaf76 442
71d51a10
MS
443 $attachmentList = $this->message->getAttachments(true);
444 $count = 0;
445 if ($attachmentList !== null) {
446 // set permissions
447 $attachmentList->setPermissions([
448 'canDownload' => true,
449 'canViewPreview' => true,
450 ]);
a91ea2de 451
71d51a10
MS
452 $count = count($attachmentList);
453 }
454
455 // update count to reflect number of attachments after edit
456 if ($count != $this->message->attachments) {
457 $messageEditor = new ConversationMessageEditor($this->message);
458 $messageEditor->update(['attachments' => $count]);
5e00d333
MW
459 }
460
461 // load embedded objects
eaf1c8eb 462 MessageEmbeddedObjectManager::getInstance()->loadObjects('com.woltlab.wcf.conversation.message', [$this->message->messageID]);
5e00d333 463
eaf1c8eb 464 $data = [
b5ffaf76
AE
465 'actionName' => 'save',
466 'message' => $this->message->getFormattedMessage()
eaf1c8eb 467 ];
5e00d333 468
71d51a10
MS
469 WCF::getTPL()->assign([
470 'attachmentList' => $attachmentList,
471 'objectID' => $this->message->messageID
472 ]);
473 $data['attachmentList'] = WCF::getTPL()->fetch('attachments');
5e00d333
MW
474
475 return $data;
b5ffaf76
AE
476 }
477
5e52978f 478 /**
9c3943b0 479 * @inheritDoc
5e52978f 480 */
52971287 481 public function validateContainer(DatabaseObject $conversation) {
b41c9fd6
MS
482 /** @var Conversation $conversation */
483
5e52978f
AE
484 if (!$conversation->conversationID) {
485 throw new UserInputException('objectID');
486 }
962207b7
MW
487 if ($conversation->isClosed) {
488 throw new PermissionDeniedException();
489 }
490 $conversation->loadUserParticipation();
0e2a5b3e 491 if (!$conversation->canRead() || !$conversation->canReply()) {
5e52978f
AE
492 throw new PermissionDeniedException();
493 }
494 }
495
b6c2b36c 496 /**
9c3943b0 497 * @inheritDoc
b6c2b36c 498 */
5ff95003 499 public function validateMessage(DatabaseObject $container, HtmlInputProcessor $htmlInputProcessor) {
c2514e3d
AE
500 $message = $htmlInputProcessor->getTextContent();
501 if (mb_strlen($message) > WCF::getSession()->getPermission('user.conversation.maxLength')) {
eaf1c8eb 502 throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('wcf.message.error.tooLong', ['maxTextLength' => WCF::getSession()->getPermission('user.conversation.maxLength')]));
84cebd68
MW
503 }
504
027c57f4 505 // search for disallowed bbcodes
c2514e3d 506 $disallowedBBCodes = $htmlInputProcessor->validate();
027c57f4 507 if (!empty($disallowedBBCodes)) {
eaf1c8eb 508 throw new UserInputException('text', WCF::getLanguage()->getDynamicVariable('wcf.message.error.disallowedBBCodes', ['disallowedBBCodes' => $disallowedBBCodes]));
027c57f4
MS
509 }
510
d8671029
MW
511 // search for censored words
512 if (ENABLE_CENSORSHIP) {
513 $result = Censorship::getInstance()->test($message);
514 if ($result) {
eaf1c8eb 515 throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('wcf.message.error.censoredWordsFound', ['censoredWords' => $result]));
d8671029 516 }
c2514e3d 517 }
d8671029 518 }
b6c2b36c 519
9353cd87 520 /**
9c3943b0 521 * @inheritDoc
9353cd87
AE
522 */
523 public function getMessageList(DatabaseObject $conversation, $lastMessageTime) {
5acf7f80
MS
524 /** @var Conversation $conversation */
525
648456e0 526 $messageList = new ViewableConversationMessageList();
a0c1a541 527 $messageList->setConversation($conversation);
eaf1c8eb
MS
528 $messageList->getConditionBuilder()->add("conversation_message.conversationID = ?", [$conversation->conversationID]);
529 $messageList->getConditionBuilder()->add("conversation_message.time > ?", [$lastMessageTime]);
9353cd87
AE
530 $messageList->sqlOrderBy = "conversation_message.time ".CONVERSATION_LIST_DEFAULT_SORT_ORDER;
531 $messageList->readObjects();
a480521b 532
9353cd87
AE
533 return $messageList;
534 }
535
5e52978f 536 /**
9c3943b0 537 * @inheritDoc
5e52978f 538 */
52971287 539 public function getPageNo(DatabaseObject $conversation) {
b41c9fd6
MS
540 /** @var Conversation $conversation */
541
5e52978f
AE
542 $sql = "SELECT COUNT(*) AS count
543 FROM wcf".WCF_N."_conversation_message
544 WHERE conversationID = ?";
545 $statement = WCF::getDB()->prepareStatement($sql);
eaf1c8eb 546 $statement->execute([$conversation->conversationID]);
5e52978f
AE
547 $count = $statement->fetchArray();
548
eaf1c8eb 549 return [intval(ceil($count['count'] / CONVERSATION_MESSAGES_PER_PAGE)), $count['count']];
5e52978f
AE
550 }
551
552 /**
9c3943b0 553 * @inheritDoc
5e52978f 554 */
52971287 555 public function getRedirectUrl(DatabaseObject $conversation, DatabaseObject $message) {
b41c9fd6 556 /** @var ConversationMessage $message */
1743db5a 557 return $message->getLink();
5e52978f 558 }
5fa9d104 559
42335f61 560 /**
9c3943b0 561 * @inheritDoc
42335f61 562 */
09f53f03 563 public function validateSaveFullQuote() {
c2b8907c 564 $this->message = $this->getSingleObject();
61f754e0 565
eaf1c8eb 566 if (!Conversation::isParticipant([$this->message->conversationID])) {
42335f61
AE
567 throw new PermissionDeniedException();
568 }
569 }
570
571 /**
9c3943b0 572 * @inheritDoc
42335f61
AE
573 */
574 public function saveFullQuote() {
2aa7b942
AE
575 $quoteID = MessageQuoteManager::getInstance()->addQuote(
576 'com.woltlab.wcf.conversation.message',
577 $this->message->conversationID,
578 $this->message->messageID,
579 $this->message->getExcerpt(),
580 $this->message->getMessage()
581 );
582
583 if ($quoteID === false) {
901d21f2
MS
584 $removeQuoteID = MessageQuoteManager::getInstance()->getQuoteID(
585 'com.woltlab.wcf.conversation.message',
586 $this->message->messageID,
587 $this->message->getExcerpt(),
588 $this->message->getMessage()
589 );
2aa7b942 590 MessageQuoteManager::getInstance()->removeQuote($removeQuoteID);
42335f61 591 }
db864366 592
eaf1c8eb 593 $returnValues = [
ce6fa919 594 'count' => MessageQuoteManager::getInstance()->countQuotes(),
eaf1c8eb
MS
595 'fullQuoteMessageIDs' => MessageQuoteManager::getInstance()->getFullQuoteObjectIDs(['com.woltlab.wcf.conversation.message'])
596 ];
2aa7b942
AE
597
598 if ($quoteID) {
599 $returnValues['renderedQuote'] = MessageQuoteManager::getInstance()->getQuoteComponents($quoteID);
600 }
601
602 return $returnValues;
42335f61
AE
603 }
604
5fa9d104 605 /**
9c3943b0 606 * @inheritDoc
5fa9d104
AE
607 */
608 public function validateSaveQuote() {
c2b8907c 609 $this->readString('message');
97266c6a 610 $this->readBoolean('renderQuote', true);
c2b8907c 611 $this->message = $this->getSingleObject();
5fa9d104 612
eaf1c8eb 613 if (!Conversation::isParticipant([$this->message->conversationID])) {
5fa9d104
AE
614 throw new PermissionDeniedException();
615 }
616 }
617
618 /**
9c3943b0 619 * @inheritDoc
5fa9d104
AE
620 */
621 public function saveQuote() {
901d21f2
MS
622 $quoteID = MessageQuoteManager::getInstance()->addQuote(
623 'com.woltlab.wcf.conversation.message',
624 $this->message->conversationID,
625 $this->message->messageID,
626 $this->parameters['message'],
627 false
628 );
5fa9d104 629
eaf1c8eb 630 $returnValues = [
ce6fa919 631 'count' => MessageQuoteManager::getInstance()->countQuotes(),
eaf1c8eb
MS
632 'fullQuoteMessageIDs' => MessageQuoteManager::getInstance()->getFullQuoteObjectIDs(['com.woltlab.wcf.conversation.message'])
633 ];
9ac36595
AE
634
635 if ($this->parameters['renderQuote']) {
5d9e720d 636 $returnValues['renderedQuote'] = MessageQuoteManager::getInstance()->getQuoteComponents($quoteID);
9ac36595
AE
637 }
638
639 return $returnValues;
5fa9d104 640 }
1ffd7648
AE
641
642 /**
9c3943b0 643 * @inheritDoc
1ffd7648
AE
644 */
645 public function validateGetRenderedQuotes() {
646 $this->readInteger('parentObjectID');
647
648 $this->conversation = new Conversation($this->parameters['parentObjectID']);
649 if (!$this->conversation->conversationID) {
650 throw new UserInputException('parentObjectID');
651 }
652 }
653
654 /**
9c3943b0 655 * @inheritDoc
1ffd7648
AE
656 */
657 public function getRenderedQuotes() {
3c427544 658 $quotes = MessageQuoteManager::getInstance()->getQuotesByParentObjectID('com.woltlab.wcf.conversation.message', $this->conversation->conversationID);
ba1ab5e5 659
eaf1c8eb 660 return [
1ffd7648 661 'template' => implode("\n\n", $quotes)
eaf1c8eb 662 ];
1ffd7648 663 }
e77f4283
AE
664
665 /**
9c3943b0 666 * @inheritDoc
e77f4283
AE
667 */
668 public function getAttachmentHandler(DatabaseObject $conversation) {
669 return new AttachmentHandler('com.woltlab.wcf.conversation.message', 0, $this->parameters['tmpHash']);
670 }
5ff95003
AE
671
672 /**
673 * @inheritDoc
674 */
2cccc1b6 675 public function getHtmlInputProcessor($message = null, $objectID = 0) {
5ff95003
AE
676 if ($message === null) {
677 return $this->htmlInputProcessor;
678 }
679
680 $this->htmlInputProcessor = new HtmlInputProcessor();
2cccc1b6 681 $this->htmlInputProcessor->process($message, 'com.woltlab.wcf.conversation.message', $objectID);
5ff95003
AE
682
683 return $this->htmlInputProcessor;
684 }
9544b6b4 685}