Fixed smiley detection in inline editing
[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;
4use wcf\data\conversation\ConversationEditor;
b2de9161 5use wcf\data\smiley\SmileyCache;
9544b6b4 6use wcf\data\AbstractDatabaseObjectAction;
52971287 7use wcf\data\DatabaseObject;
4a2ee5bb
AE
8use wcf\data\IExtendedMessageQuickReplyAction;
9use wcf\data\IMessageInlineEditorAction;
5fa9d104 10use wcf\data\IMessageQuoteAction;
5d7f0df0 11use wcf\system\attachment\AttachmentHandler;
027c57f4 12use wcf\system\bbcode\BBCodeParser;
0a0e61bb 13use wcf\system\bbcode\PreParser;
5e52978f
AE
14use wcf\system\exception\PermissionDeniedException;
15use wcf\system\exception\UserInputException;
d8671029 16use wcf\system\message\censorship\Censorship;
5fa9d104 17use wcf\system\message\quote\MessageQuoteManager;
5e52978f 18use wcf\system\message\QuickReplyManager;
5e52978f 19use wcf\system\request\LinkHandler;
80a0761e 20use wcf\system\search\SearchIndexManager;
b5ffaf76
AE
21use wcf\system\user\notification\object\ConversationMessageUserNotificationObject;
22use wcf\system\user\notification\UserNotificationHandler;
df8f8628 23use wcf\system\user\storage\UserStorageHandler;
9544b6b4 24use wcf\system\WCF;
8a2fa588 25use wcf\util\StringUtil;
9544b6b4
MW
26
27/**
28 * Executes message-related actions.
29 *
30 * @author Marcel Werk
31 * @copyright 2001-2012 WoltLab GmbH
32 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
33 * @package com.woltlab.wcf.conversation
34 * @subpackage data.conversation.message
61f754e0 35 * @category Community Framework
9544b6b4 36 */
5fa9d104 37class ConversationMessageAction extends AbstractDatabaseObjectAction implements IExtendedMessageQuickReplyAction, IMessageInlineEditorAction, IMessageQuoteAction {
9544b6b4 38 /**
61f754e0 39 * @see wcf\data\AbstractDatabaseObjectAction::$className
9544b6b4
MW
40 */
41 protected $className = 'wcf\data\conversation\message\ConversationMessageEditor';
42
5e52978f
AE
43 /**
44 * conversation object
45 * @var wcf\data\conversation\Conversation
46 */
47 public $conversation = null;
48
a5bacc02
AE
49 /**
50 * conversation message object
51 * @var wcf\data\conversation\message\ConversationMessage
52 */
53 public $message = null;
54
9544b6b4 55 /**
61f754e0 56 * @see wcf\data\AbstractDatabaseObjectAction::create()
9544b6b4
MW
57 */
58 public function create() {
59 // count attachments
60 if (isset($this->parameters['attachmentHandler']) && $this->parameters['attachmentHandler'] !== null) {
61 $this->parameters['data']['attachments'] = count($this->parameters['attachmentHandler']);
62 }
63
64 if (LOG_IP_ADDRESS) {
65 // add ip address
66 if (!isset($this->parameters['data']['ipAddress'])) {
67 $this->parameters['data']['ipAddress'] = WCF::getSession()->ipAddress;
68 }
69 }
70 else {
71 // do not track ip address
72 if (isset($this->parameters['data']['ipAddress'])) {
73 unset($this->parameters['data']['ipAddress']);
74 }
75 }
76
77 // create message
78 $message = parent::create();
79
fcf27f27 80 // get conversation
6f1cd040
MW
81 $conversation = (isset($this->parameters['converation']) ? $this->parameters['converation'] : new Conversation($message->conversationID));
82 $conversationEditor = new ConversationEditor($conversation);
61f754e0 83
4b541146 84 if (empty($this->parameters['isFirstPost'])) {
9544b6b4
MW
85 // update last message
86 $conversationEditor->addMessage($message);
64ac54a1
MW
87
88 // fire notification event
6f1cd040 89 if (!$conversation->isDraft) {
0ff992a3 90 $notificationRecipients = array_diff($conversation->getParticipantIDs(true), array($message->userID)); // don't notify message author
566eb43f
MW
91 if (!empty($notificationRecipients)) {
92 UserNotificationHandler::getInstance()->fireEvent('conversationMessage', 'com.woltlab.wcf.conversation.message.notification', new ConversationMessageUserNotificationObject($message), $notificationRecipients);
93 }
5fa9d104 94 }
fcf27f27
MW
95
96 // make invisible participant visible
97 $sql = "UPDATE wcf".WCF_N."_conversation_to_user
98 SET isInvisible = 0
99 WHERE participantID = ?
100 AND conversationID = ?";
101 $statement = WCF::getDB()->prepareStatement($sql);
102 $statement->execute(array($message->userID, $conversation->conversationID));
0ff992a3
AE
103
104 // reset visibility if it was hidden but not left
105 $sql = "UPDATE wcf".WCF_N."_conversation_to_user
106 SET hideConversation = ?
107 WHERE conversationID = ?
108 AND hideConversation = ?";
109 $statement = WCF::getDB()->prepareStatement($sql);
110 $statement->execute(array(
06695793 111 Conversation::STATE_DEFAULT,
0ff992a3 112 $conversation->conversationID,
06695793 113 Conversation::STATE_HIDDEN
0ff992a3 114 ));
9544b6b4
MW
115 }
116
df8f8628 117 // reset storage
462d532a 118 UserStorageHandler::getInstance()->reset($conversation->getParticipantIDs(), 'unreadConversationCount');
9544b6b4 119
80a0761e 120 // update search index
6f1cd040 121 SearchIndexManager::getInstance()->add('com.woltlab.wcf.conversation.message', $message->messageID, $message->message, (!empty($this->parameters['isFirstPost']) ? $conversation->subject : ''), $message->time, $message->userID, $message->username);
9544b6b4
MW
122
123 // update attachments
124 if (isset($this->parameters['attachmentHandler']) && $this->parameters['attachmentHandler'] !== null) {
125 $this->parameters['attachmentHandler']->updateObjectID($message->messageID);
126 }
127
5fa9d104 128 // clear quotes
f1781bd0
AE
129 if (isset($this->parameters['removeQuoteIDs']) && !empty($this->parameters['removeQuoteIDs'])) {
130 MessageQuoteManager::getInstance()->markQuotesForRemoval($this->parameters['removeQuoteIDs']);
131 }
5fa9d104
AE
132 MessageQuoteManager::getInstance()->removeMarkedQuotes();
133
9544b6b4
MW
134 // return new message
135 return $message;
136 }
c764783c
MW
137
138 /**
61f754e0 139 * @see wcf\data\AbstractDatabaseObjectAction::update()
c764783c
MW
140 */
141 public function update() {
142 // count attachments
143 if (isset($this->parameters['attachmentHandler']) && $this->parameters['attachmentHandler'] !== null) {
144 $this->parameters['data']['attachments'] = count($this->parameters['attachmentHandler']);
145 }
146
147 parent::update();
80a0761e 148
fcf27f27
MW
149 // update search index
150 foreach ($this->objects as $message) {
151 $conversation = $message->getConversation();
152 SearchIndexManager::getInstance()->update('com.woltlab.wcf.conversation.message', $message->messageID, $message->message, ($conversation->firstMessageID == $message->messageID ? $conversation->subject : ''), $message->time, $message->userID, $message->username);
153 }
c764783c 154 }
5e52978f 155
db07cb2d
AE
156 /**
157 * @see wcf\data\AbstractDatabaseObjectAction::delete()
158 */
159 public function delete() {
160 $count = parent::delete();
161
5d7f0df0
MW
162 $attachmentMessageIDs = array();
163 foreach ($this->objects as $message) {
164 if ($message->attachments) {
165 $attachmentMessageIDs[] = $message->messageID;
db07cb2d 166
db07cb2d
AE
167 }
168 }
169
5d7f0df0
MW
170 // @todo: modification log, reports
171
172 if (!empty($this->objectIDs)) {
173 // delete notifications
174 UserNotificationHandler::getInstance()->deleteNotifications('conversationMessage', 'com.woltlab.wcf.conversation.message.notification', array(), $this->objectIDs);
175
176 // update search index
177 SearchIndexManager::getInstance()->delete('com.woltlab.wcf.conversation.message', $this->objectIDs);
178 }
179
180 // remove attachments
181 if (!empty($attachmentMessageIDs)) {
182 AttachmentHandler::removeAttachments('com.woltlab.wcf.conversation.message', $attachmentMessageIDs);
183 }
184
db07cb2d
AE
185 return $count;
186 }
187
5e52978f 188 /**
4a2ee5bb 189 * @see wcf\data\IMessageQuickReply::validateQuickReply()
5e52978f
AE
190 */
191 public function validateQuickReply() {
0a0e61bb 192 QuickReplyManager::getInstance()->setAllowedBBCodes(explode(',', WCF::getSession()->getPermission('user.message.allowedBBCodes')));
5e52978f
AE
193 QuickReplyManager::getInstance()->validateParameters($this, $this->parameters, 'wcf\data\conversation\Conversation');
194 }
195
196 /**
4a2ee5bb 197 * @see wcf\data\IMessageQuickReply::quickReply()
5e52978f
AE
198 */
199 public function quickReply() {
200 return QuickReplyManager::getInstance()->createMessage(
201 $this,
202 $this->parameters,
203 'wcf\data\conversation\ConversationAction',
204 'wcf\data\conversation\message\ViewableConversationMessageList',
205 'conversationMessageList',
206 CONVERSATION_LIST_DEFAULT_SORT_ORDER
207 );
208 }
209
a5bacc02 210 /**
4a2ee5bb 211 * @see wcf\data\IExtendedMessageQuickReplyAction::validateJumpToExtended()
a5bacc02
AE
212 */
213 public function validateJumpToExtended() {
c2b8907c
AE
214 $this->readInteger('containerID');
215 $this->readString('message', true);
a5bacc02 216
c2b8907c
AE
217 $this->conversation = new Conversation($this->parameters['containerID']);
218 if (!$this->conversation->conversationID) {
86a5431b 219 throw new UserInputException('containerID');
a5bacc02 220 }
c2b8907c
AE
221 else if ($this->conversation->isClosed || !Conversation::isParticipant(array($this->conversation->conversationID))) {
222 throw new PermissionDeniedException();
a5bacc02
AE
223 }
224
225 // editing existing message
226 if (isset($this->parameters['messageID'])) {
227 $this->message = new ConversationMessage(intval($this->parameters['messageID']));
228 if (!$this->message->messageID || ($this->message->conversationID != $this->conversation->conversationID)) {
229 throw new UserInputException('messageID');
230 }
61f754e0 231
a5bacc02
AE
232 if (!$this->message->canEdit()) {
233 throw new PermissionDeniedException();
234 }
235 }
236 }
237
238 /**
4a2ee5bb 239 * @see wcf\data\IExtendedMessageQuickReplyAction::jumpToExtended()
a5bacc02
AE
240 */
241 public function jumpToExtended() {
242 // quick reply
243 if ($this->message === null) {
244 QuickReplyManager::getInstance()->setMessage('conversation', $this->conversation->conversationID, $this->parameters['message']);
245 $url = LinkHandler::getInstance()->getLink('ConversationMessageAdd', array('id' => $this->conversation->conversationID));
246 }
247 else {
248 // editing message
249 QuickReplyManager::getInstance()->setMessage('conversationMessage', $this->message->messageID, $this->parameters['message']);
250 $url = LinkHandler::getInstance()->getLink('ConversationMessageEdit', array('id' => $this->message->messageID));
251 }
252
253 // redirect
254 return array(
255 'url' => $url
256 );
257 }
258
b5ffaf76 259 /**
4a2ee5bb 260 * @see wcf\data\IMessageInlineEditorAction::validateBeginEdit()
b5ffaf76
AE
261 */
262 public function validateBeginEdit() {
c2b8907c
AE
263 $this->readInteger('containerID');
264 $this->readInteger('objectID');
265
266 $this->conversation = new Conversation($this->parameters['containerID']);
267 if (!$this->conversation->conversationID) {
b5ffaf76
AE
268 throw new UserInputException('containerID');
269 }
c2b8907c
AE
270
271 if ($this->conversation->isClosed || !Conversation::isParticipant(array($this->conversation->conversationID))) {
272 throw new PermissionDeniedException();
b5ffaf76
AE
273 }
274
c2b8907c
AE
275 $this->message = new ConversationMessage($this->parameters['objectID']);
276 if (!$this->message->messageID) {
b5ffaf76
AE
277 throw new UserInputException('objectID');
278 }
c2b8907c
AE
279
280 if (!$this->message->canEdit()) {
281 throw new PermissionDeniedException();
b5ffaf76
AE
282 }
283 }
284
285 /**
4a2ee5bb 286 * @see wcf\data\IMessageInlineEditorAction::beginEdit()
b5ffaf76
AE
287 */
288 public function beginEdit() {
289 WCF::getTPL()->assign(array(
b2de9161 290 'defaultSmilies' => SmileyCache::getInstance()->getCategorySmilies(),
b5ffaf76
AE
291 'message' => $this->message,
292 'wysiwygSelector' => 'messageEditor'.$this->message->messageID
293 ));
294
295 return array(
296 'actionName' => 'beginEdit',
297 'template' => WCF::getTPL()->fetch('conversationMessageInlineEditor')
298 );
299 }
300
301 /**
4a2ee5bb 302 * @see wcf\data\IMessageInlineEditorAction::validateSave()
b5ffaf76
AE
303 */
304 public function validateSave() {
c2b8907c 305 $this->readString('message', false, 'data');
b5ffaf76
AE
306
307 $this->validateBeginEdit();
271c06ce 308 $this->validateMessage($this->conversation, $this->parameters['data']['message']);
b5ffaf76
AE
309 }
310
311 /**
4a2ee5bb 312 * @see wcf\data\IMessageInlineEditorAction::save()
b5ffaf76
AE
313 */
314 public function save() {
315 $messageEditor = new ConversationMessageEditor($this->message);
316 $messageEditor->update(array(
0a0e61bb 317 'message' => PreParser::getInstance()->parse($this->parameters['data']['message'], explode(',', WCF::getSession()->getPermission('user.message.allowedBBCodes')))
b5ffaf76
AE
318 ));
319
320 // load new message
321 $this->message = new ConversationMessage($this->message->messageID);
f7b9b1f3 322 $this->message->getAttachments();
b5ffaf76
AE
323
324 return array(
325 'actionName' => 'save',
326 'message' => $this->message->getFormattedMessage()
327 );
328 }
329
5e52978f 330 /**
4a2ee5bb 331 * @see wcf\data\IMessageQuickReply::validateContainer()
5e52978f 332 */
52971287 333 public function validateContainer(DatabaseObject $conversation) {
5e52978f
AE
334 if (!$conversation->conversationID) {
335 throw new UserInputException('objectID');
336 }
337 else if ($conversation->isClosed || !Conversation::isParticipant(array($conversation->conversationID))) {
338 throw new PermissionDeniedException();
339 }
340 }
341
b6c2b36c
AE
342 /**
343 * @see wcf\data\IMessageQuickReplyAction::validateMessage()
344 */
d8671029 345 public function validateMessage(DatabaseObject $container, $message) {
84cebd68
MW
346 if (StringUtil::length($message) > WCF::getSession()->getPermission('user.conversation.maxLength')) {
347 throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('wcf.message.error.tooLong', array('maxTextLength' => WCF::getSession()->getPermission('user.conversation.maxLength'))));
348 }
349
027c57f4
MS
350 // search for disallowed bbcodes
351 $disallowedBBCodes = BBCodeParser::getInstance()->validateBBCodes($message, explode(',', WCF::getSession()->getPermission('user.message.allowedBBCodes')));
352 if (!empty($disallowedBBCodes)) {
353 throw new UserInputException('text', WCF::getLanguage()->getDynamicVariable('wcf.message.error.disallowedBBCodes', array('disallowedBBCodes' => $disallowedBBCodes)));
354 }
355
d8671029
MW
356 // search for censored words
357 if (ENABLE_CENSORSHIP) {
358 $result = Censorship::getInstance()->test($message);
359 if ($result) {
e86562df 360 throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('wcf.message.error.censoredWordsFound', array('censoredWords' => $result)));
d8671029
MW
361 }
362 }
363 }
b6c2b36c 364
5e52978f 365 /**
4a2ee5bb 366 * @see wcf\data\IMessageQuickReply::getPageNo()
5e52978f 367 */
52971287 368 public function getPageNo(DatabaseObject $conversation) {
5e52978f
AE
369 $sql = "SELECT COUNT(*) AS count
370 FROM wcf".WCF_N."_conversation_message
371 WHERE conversationID = ?";
372 $statement = WCF::getDB()->prepareStatement($sql);
373 $statement->execute(array($conversation->conversationID));
374 $count = $statement->fetchArray();
375
a3157f71 376 return array(intval(ceil($count['count'] / CONVERSATION_MESSAGES_PER_PAGE)), $count['count']);
5e52978f
AE
377 }
378
379 /**
4a2ee5bb 380 * @see wcf\data\IMessageQuickReply::getRedirectUrl()
5e52978f 381 */
52971287 382 public function getRedirectUrl(DatabaseObject $conversation, DatabaseObject $message) {
5e52978f
AE
383 return LinkHandler::getInstance()->getLink('Conversation', array(
384 'object' => $conversation,
385 'messageID' => $message->messageID
386 )).'#message'.$message->messageID;
387 }
5fa9d104 388
42335f61 389 /**
09f53f03 390 * @see wcf\data\IMessageQuoteAction::validateSaveFullQuote()
42335f61 391 */
09f53f03 392 public function validateSaveFullQuote() {
c2b8907c 393 $this->message = $this->getSingleObject();
61f754e0 394
42335f61
AE
395 if (!Conversation::isParticipant(array($this->message->conversationID))) {
396 throw new PermissionDeniedException();
397 }
398 }
399
400 /**
401 * @see wcf\data\IMessageQuoteAction::saveFullQuote()
402 */
403 public function saveFullQuote() {
404 if (!MessageQuoteManager::getInstance()->addQuote('com.woltlab.wcf.conversation.message', $this->message->messageID, $this->message->getExcerpt(), $this->message->getMessage())) {
626fa1ff 405 $quoteID = MessageQuoteManager::getInstance()->getQuoteID('com.woltlab.wcf.conversation.message', $this->message->conversationID, $this->message->messageID, $this->message->getExcerpt(), $this->message->getMessage());
42335f61
AE
406 MessageQuoteManager::getInstance()->removeQuote($quoteID);
407 }
db864366 408
42335f61 409 return array(
ce6fa919
AE
410 'count' => MessageQuoteManager::getInstance()->countQuotes(),
411 'fullQuoteMessageIDs' => MessageQuoteManager::getInstance()->getFullQuoteObjectIDs(array('com.woltlab.wcf.conversation.message'))
42335f61
AE
412 );
413 }
414
5fa9d104
AE
415 /**
416 * @see wcf\data\IMessageQuoteAction::validateSaveQuote()
417 */
418 public function validateSaveQuote() {
c2b8907c
AE
419 $this->readString('message');
420 $this->message = $this->getSingleObject();
5fa9d104 421
5fa9d104
AE
422 if (!Conversation::isParticipant(array($this->message->conversationID))) {
423 throw new PermissionDeniedException();
424 }
425 }
426
427 /**
428 * @see wcf\data\IMessageQuoteAction::saveQuote()
429 */
430 public function saveQuote() {
626fa1ff 431 MessageQuoteManager::getInstance()->addQuote('com.woltlab.wcf.conversation.message', $this->message->conversationID, $this->message->messageID, $this->parameters['message']);
5fa9d104
AE
432
433 return array(
ce6fa919
AE
434 'count' => MessageQuoteManager::getInstance()->countQuotes(),
435 'fullQuoteMessageIDs' => MessageQuoteManager::getInstance()->getFullQuoteObjectIDs(array('com.woltlab.wcf.conversation.message'))
5fa9d104
AE
436 );
437 }
1ffd7648
AE
438
439 /**
440 * @see wcf\data\IMessageQuoteAction::validateGetRenderedQuotes()
441 */
442 public function validateGetRenderedQuotes() {
443 $this->readInteger('parentObjectID');
444
445 $this->conversation = new Conversation($this->parameters['parentObjectID']);
446 if (!$this->conversation->conversationID) {
447 throw new UserInputException('parentObjectID');
448 }
449 }
450
451 /**
452 * @see wcf\data\IMessageQuoteAction::getRenderedQuotes()
453 */
454 public function getRenderedQuotes() {
455 $quotes = MessageQuoteManager::getInstance()->getQuotesByParentObjectID('com.woltlab.wbb.conversation.message', $this->conversation->conversationID);
456
457 return array(
458 'template' => implode("\n\n", $quotes)
459 );
460 }
9544b6b4 461}