2 namespace wcf\data\conversation\message
;
3 use wcf\data\conversation\Conversation
;
4 use wcf\data\conversation\ConversationEditor
;
5 use wcf\data\smiley\SmileyCache
;
6 use wcf\data\AbstractDatabaseObjectAction
;
7 use wcf\data\DatabaseObject
;
8 use wcf\data\IExtendedMessageQuickReplyAction
;
9 use wcf\data\IMessageInlineEditorAction
;
10 use wcf\data\IMessageQuoteAction
;
11 use wcf\system\attachment\AttachmentHandler
;
12 use wcf\system\bbcode\BBCodeParser
;
13 use wcf\system\bbcode\PreParser
;
14 use wcf\system\exception\PermissionDeniedException
;
15 use wcf\system\exception\UserInputException
;
16 use wcf\system\message\censorship\Censorship
;
17 use wcf\system\message\quote\MessageQuoteManager
;
18 use wcf\system\message\QuickReplyManager
;
19 use wcf\system\request\LinkHandler
;
20 use wcf\system\search\SearchIndexManager
;
21 use wcf\system\user\notification\
object\ConversationMessageUserNotificationObject
;
22 use wcf\system\user\notification\UserNotificationHandler
;
23 use wcf\system\user\storage\UserStorageHandler
;
25 use wcf\util\StringUtil
;
28 * Executes message-related actions.
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
35 * @category Community Framework
37 class ConversationMessageAction
extends AbstractDatabaseObjectAction
implements IExtendedMessageQuickReplyAction
, IMessageInlineEditorAction
, IMessageQuoteAction
{
39 * @see wcf\data\AbstractDatabaseObjectAction::$className
41 protected $className = 'wcf\data\conversation\message\ConversationMessageEditor';
45 * @var wcf\data\conversation\Conversation
47 public $conversation = null;
50 * conversation message object
51 * @var wcf\data\conversation\message\ConversationMessage
53 public $message = null;
56 * @see wcf\data\AbstractDatabaseObjectAction::create()
58 public function create() {
60 if (isset($this->parameters
['attachmentHandler']) && $this->parameters
['attachmentHandler'] !== null) {
61 $this->parameters
['data']['attachments'] = count($this->parameters
['attachmentHandler']);
66 if (!isset($this->parameters
['data']['ipAddress'])) {
67 $this->parameters
['data']['ipAddress'] = WCF
::getSession()->ipAddress
;
71 // do not track ip address
72 if (isset($this->parameters
['data']['ipAddress'])) {
73 unset($this->parameters
['data']['ipAddress']);
78 $message = parent
::create();
81 $conversation = (isset($this->parameters
['converation']) ?
$this->parameters
['converation'] : new Conversation($message->conversationID
));
82 $conversationEditor = new ConversationEditor($conversation);
84 if (empty($this->parameters
['isFirstPost'])) {
85 // update last message
86 $conversationEditor->addMessage($message);
88 // fire notification event
89 if (!$conversation->isDraft
) {
90 $notificationRecipients = array_diff($conversation->getParticipantIDs(true), array($message->userID
)); // don't notify message author
91 if (!empty($notificationRecipients)) {
92 UserNotificationHandler
::getInstance()->fireEvent('conversationMessage', 'com.woltlab.wcf.conversation.message.notification', new ConversationMessageUserNotificationObject($message), $notificationRecipients);
96 // make invisible participant visible
97 $sql = "UPDATE wcf".WCF_N
."_conversation_to_user
99 WHERE participantID = ?
100 AND conversationID = ?";
101 $statement = WCF
::getDB()->prepareStatement($sql);
102 $statement->execute(array($message->userID
, $conversation->conversationID
));
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(
111 Conversation
::STATE_DEFAULT
,
112 $conversation->conversationID
,
113 Conversation
::STATE_HIDDEN
118 UserStorageHandler
::getInstance()->reset($conversation->getParticipantIDs(), 'unreadConversationCount');
120 // update search index
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
);
123 // update attachments
124 if (isset($this->parameters
['attachmentHandler']) && $this->parameters
['attachmentHandler'] !== null) {
125 $this->parameters
['attachmentHandler']->updateObjectID($message->messageID
);
129 if (isset($this->parameters
['removeQuoteIDs']) && !empty($this->parameters
['removeQuoteIDs'])) {
130 MessageQuoteManager
::getInstance()->markQuotesForRemoval($this->parameters
['removeQuoteIDs']);
132 MessageQuoteManager
::getInstance()->removeMarkedQuotes();
134 // return new message
139 * @see wcf\data\AbstractDatabaseObjectAction::update()
141 public function update() {
143 if (isset($this->parameters
['attachmentHandler']) && $this->parameters
['attachmentHandler'] !== null) {
144 $this->parameters
['data']['attachments'] = count($this->parameters
['attachmentHandler']);
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
);
157 * @see wcf\data\AbstractDatabaseObjectAction::delete()
159 public function delete() {
160 $count = parent
::delete();
162 $attachmentMessageIDs = array();
163 foreach ($this->objects
as $message) {
164 if ($message->attachments
) {
165 $attachmentMessageIDs[] = $message->messageID
;
170 // @todo: modification log, reports
172 if (!empty($this->objectIDs
)) {
173 // delete notifications
174 UserNotificationHandler
::getInstance()->deleteNotifications('conversationMessage', 'com.woltlab.wcf.conversation.message.notification', array(), $this->objectIDs
);
176 // update search index
177 SearchIndexManager
::getInstance()->delete('com.woltlab.wcf.conversation.message', $this->objectIDs
);
180 // remove attachments
181 if (!empty($attachmentMessageIDs)) {
182 AttachmentHandler
::removeAttachments('com.woltlab.wcf.conversation.message', $attachmentMessageIDs);
189 * @see wcf\data\IMessageQuickReply::validateQuickReply()
191 public function validateQuickReply() {
192 QuickReplyManager
::getInstance()->setAllowedBBCodes(explode(',', WCF
::getSession()->getPermission('user.message.allowedBBCodes')));
193 QuickReplyManager
::getInstance()->validateParameters($this, $this->parameters
, 'wcf\data\conversation\Conversation');
197 * @see wcf\data\IMessageQuickReply::quickReply()
199 public function quickReply() {
200 return QuickReplyManager
::getInstance()->createMessage(
203 'wcf\data\conversation\ConversationAction',
204 'wcf\data\conversation\message\ViewableConversationMessageList',
205 'conversationMessageList',
206 CONVERSATION_LIST_DEFAULT_SORT_ORDER
211 * @see wcf\data\IExtendedMessageQuickReplyAction::validateJumpToExtended()
213 public function validateJumpToExtended() {
214 $this->readInteger('containerID');
215 $this->readString('message', true);
217 $this->conversation
= new Conversation($this->parameters
['containerID']);
218 if (!$this->conversation
->conversationID
) {
219 throw new UserInputException('containerID');
221 else if ($this->conversation
->isClosed ||
!Conversation
::isParticipant(array($this->conversation
->conversationID
))) {
222 throw new PermissionDeniedException();
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');
232 if (!$this->message
->canEdit()) {
233 throw new PermissionDeniedException();
239 * @see wcf\data\IExtendedMessageQuickReplyAction::jumpToExtended()
241 public function jumpToExtended() {
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
));
249 QuickReplyManager
::getInstance()->setMessage('conversationMessage', $this->message
->messageID
, $this->parameters
['message']);
250 $url = LinkHandler
::getInstance()->getLink('ConversationMessageEdit', array('id' => $this->message
->messageID
));
260 * @see wcf\data\IMessageInlineEditorAction::validateBeginEdit()
262 public function validateBeginEdit() {
263 $this->readInteger('containerID');
264 $this->readInteger('objectID');
266 $this->conversation
= new Conversation($this->parameters
['containerID']);
267 if (!$this->conversation
->conversationID
) {
268 throw new UserInputException('containerID');
271 if ($this->conversation
->isClosed ||
!Conversation
::isParticipant(array($this->conversation
->conversationID
))) {
272 throw new PermissionDeniedException();
275 $this->message
= new ConversationMessage($this->parameters
['objectID']);
276 if (!$this->message
->messageID
) {
277 throw new UserInputException('objectID');
280 if (!$this->message
->canEdit()) {
281 throw new PermissionDeniedException();
286 * @see wcf\data\IMessageInlineEditorAction::beginEdit()
288 public function beginEdit() {
289 WCF
::getTPL()->assign(array(
290 'defaultSmilies' => SmileyCache
::getInstance()->getCategorySmilies(),
291 'message' => $this->message
,
292 'wysiwygSelector' => 'messageEditor'.$this->message
->messageID
296 'actionName' => 'beginEdit',
297 'template' => WCF
::getTPL()->fetch('conversationMessageInlineEditor')
302 * @see wcf\data\IMessageInlineEditorAction::validateSave()
304 public function validateSave() {
305 $this->readString('message', false, 'data');
307 $this->validateBeginEdit();
308 $this->validateMessage($this->conversation
, $this->parameters
['data']['message']);
312 * @see wcf\data\IMessageInlineEditorAction::save()
314 public function save() {
315 $messageEditor = new ConversationMessageEditor($this->message
);
316 $messageEditor->update(array(
317 'message' => PreParser
::getInstance()->parse($this->parameters
['data']['message'], explode(',', WCF
::getSession()->getPermission('user.message.allowedBBCodes')))
321 $this->message
= new ConversationMessage($this->message
->messageID
);
322 $this->message
->getAttachments();
325 'actionName' => 'save',
326 'message' => $this->message
->getFormattedMessage()
331 * @see wcf\data\IMessageQuickReply::validateContainer()
333 public function validateContainer(DatabaseObject
$conversation) {
334 if (!$conversation->conversationID
) {
335 throw new UserInputException('objectID');
337 else if ($conversation->isClosed ||
!Conversation
::isParticipant(array($conversation->conversationID
))) {
338 throw new PermissionDeniedException();
343 * @see wcf\data\IMessageQuickReplyAction::validateMessage()
345 public function validateMessage(DatabaseObject
$container, $message) {
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'))));
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)));
356 // search for censored words
357 if (ENABLE_CENSORSHIP
) {
358 $result = Censorship
::getInstance()->test($message);
360 throw new UserInputException('message', WCF
::getLanguage()->getDynamicVariable('wcf.message.error.censoredWordsFound', array('censoredWords' => $result)));
366 * @see wcf\data\IMessageQuickReply::getPageNo()
368 public function getPageNo(DatabaseObject
$conversation) {
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();
376 return array(intval(ceil($count['count'] / CONVERSATION_MESSAGES_PER_PAGE
)), $count['count']);
380 * @see wcf\data\IMessageQuickReply::getRedirectUrl()
382 public function getRedirectUrl(DatabaseObject
$conversation, DatabaseObject
$message) {
383 return LinkHandler
::getInstance()->getLink('Conversation', array(
384 'object' => $conversation,
385 'messageID' => $message->messageID
386 )).'#message'.$message->messageID
;
390 * @see wcf\data\IMessageQuoteAction::validateSaveFullQuote()
392 public function validateSaveFullQuote() {
393 $this->message
= $this->getSingleObject();
395 if (!Conversation
::isParticipant(array($this->message
->conversationID
))) {
396 throw new PermissionDeniedException();
401 * @see wcf\data\IMessageQuoteAction::saveFullQuote()
403 public function saveFullQuote() {
404 if (!MessageQuoteManager
::getInstance()->addQuote('com.woltlab.wcf.conversation.message', $this->message
->messageID
, $this->message
->getExcerpt(), $this->message
->getMessage())) {
405 $quoteID = MessageQuoteManager
::getInstance()->getQuoteID('com.woltlab.wcf.conversation.message', $this->message
->conversationID
, $this->message
->messageID
, $this->message
->getExcerpt(), $this->message
->getMessage());
406 MessageQuoteManager
::getInstance()->removeQuote($quoteID);
410 'count' => MessageQuoteManager
::getInstance()->countQuotes(),
411 'fullQuoteMessageIDs' => MessageQuoteManager
::getInstance()->getFullQuoteObjectIDs(array('com.woltlab.wcf.conversation.message'))
416 * @see wcf\data\IMessageQuoteAction::validateSaveQuote()
418 public function validateSaveQuote() {
419 $this->readString('message');
420 $this->message
= $this->getSingleObject();
422 if (!Conversation
::isParticipant(array($this->message
->conversationID
))) {
423 throw new PermissionDeniedException();
428 * @see wcf\data\IMessageQuoteAction::saveQuote()
430 public function saveQuote() {
431 MessageQuoteManager
::getInstance()->addQuote('com.woltlab.wcf.conversation.message', $this->message
->conversationID
, $this->message
->messageID
, $this->parameters
['message']);
434 'count' => MessageQuoteManager
::getInstance()->countQuotes(),
435 'fullQuoteMessageIDs' => MessageQuoteManager
::getInstance()->getFullQuoteObjectIDs(array('com.woltlab.wcf.conversation.message'))
440 * @see wcf\data\IMessageQuoteAction::validateGetRenderedQuotes()
442 public function validateGetRenderedQuotes() {
443 $this->readInteger('parentObjectID');
445 $this->conversation
= new Conversation($this->parameters
['parentObjectID']);
446 if (!$this->conversation
->conversationID
) {
447 throw new UserInputException('parentObjectID');
452 * @see wcf\data\IMessageQuoteAction::getRenderedQuotes()
454 public function getRenderedQuotes() {
455 $quotes = MessageQuoteManager
::getInstance()->getQuotesByParentObjectID('com.woltlab.wbb.conversation.message', $this->conversation
->conversationID
);
458 'template' => implode("\n\n", $quotes)