2 namespace wcf\data\conversation\message
;
3 use wcf\data\conversation\Conversation
;
4 use wcf\data\conversation\ConversationEditor
;
5 use wcf\data\AbstractDatabaseObjectAction
;
6 use wcf\data\DatabaseObject
;
7 use wcf\data\IExtendedMessageQuickReplyAction
;
8 use wcf\data\IMessageInlineEditorAction
;
9 use wcf\data\IMessageQuoteAction
;
10 use wcf\system\attachment\AttachmentHandler
;
11 use wcf\system\bbcode\BBCodeParser
;
12 use wcf\system\bbcode\PreParser
;
13 use wcf\system\exception\PermissionDeniedException
;
14 use wcf\system\exception\UserInputException
;
15 use wcf\system\message\censorship\Censorship
;
16 use wcf\system\message\quote\MessageQuoteManager
;
17 use wcf\system\message\QuickReplyManager
;
18 use wcf\system\request\LinkHandler
;
19 use wcf\system\search\SearchIndexManager
;
20 use wcf\system\user\notification\
object\ConversationMessageUserNotificationObject
;
21 use wcf\system\user\notification\UserNotificationHandler
;
22 use wcf\system\user\storage\UserStorageHandler
;
24 use wcf\util\StringUtil
;
27 * Executes message-related actions.
30 * @copyright 2001-2012 WoltLab GmbH
31 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
32 * @package com.woltlab.wcf.conversation
33 * @subpackage data.conversation.message
34 * @category Community Framework
36 class ConversationMessageAction
extends AbstractDatabaseObjectAction
implements IExtendedMessageQuickReplyAction
, IMessageInlineEditorAction
, IMessageQuoteAction
{
38 * @see wcf\data\AbstractDatabaseObjectAction::$className
40 protected $className = 'wcf\data\conversation\message\ConversationMessageEditor';
44 * @var wcf\data\conversation\Conversation
46 public $conversation = null;
49 * conversation message object
50 * @var wcf\data\conversation\message\ConversationMessage
52 public $message = null;
55 * @see wcf\data\AbstractDatabaseObjectAction::create()
57 public function create() {
59 if (isset($this->parameters
['attachmentHandler']) && $this->parameters
['attachmentHandler'] !== null) {
60 $this->parameters
['data']['attachments'] = count($this->parameters
['attachmentHandler']);
65 if (!isset($this->parameters
['data']['ipAddress'])) {
66 $this->parameters
['data']['ipAddress'] = WCF
::getSession()->ipAddress
;
70 // do not track ip address
71 if (isset($this->parameters
['data']['ipAddress'])) {
72 unset($this->parameters
['data']['ipAddress']);
77 $message = parent
::create();
80 $conversation = (isset($this->parameters
['converation']) ?
$this->parameters
['converation'] : new Conversation($message->conversationID
));
81 $conversationEditor = new ConversationEditor($conversation);
83 if (empty($this->parameters
['isFirstPost'])) {
84 // update last message
85 $conversationEditor->addMessage($message);
87 // fire notification event
88 if (!$conversation->isDraft
) {
89 $notificationRecipients = array_diff($conversation->getParticipantIDs(true), array($message->userID
)); // don't notify message author
90 if (!empty($notificationRecipients)) {
91 UserNotificationHandler
::getInstance()->fireEvent('conversationMessage', 'com.woltlab.wcf.conversation.message.notification', new ConversationMessageUserNotificationObject($message), $notificationRecipients);
95 // make invisible participant visible
96 $sql = "UPDATE wcf".WCF_N
."_conversation_to_user
98 WHERE participantID = ?
99 AND conversationID = ?";
100 $statement = WCF
::getDB()->prepareStatement($sql);
101 $statement->execute(array($message->userID
, $conversation->conversationID
));
103 // reset visibility if it was hidden but not left
104 $sql = "UPDATE wcf".WCF_N
."_conversation_to_user
105 SET hideConversation = ?
106 WHERE conversationID = ?
107 AND hideConversation = ?";
108 $statement = WCF
::getDB()->prepareStatement($sql);
109 $statement->execute(array(
110 Conversation
::STATE_DEFAULT
,
111 $conversation->conversationID
,
112 Conversation
::STATE_HIDDEN
117 UserStorageHandler
::getInstance()->reset($conversation->getParticipantIDs(), 'unreadConversationCount');
119 // update search index
120 SearchIndexManager
::getInstance()->add('com.woltlab.wcf.conversation.message', $message->messageID
, $message->message
, (!empty($this->parameters
['isFirstPost']) ?
$conversation->subject
: ''), $message->time
, $message->userID
, $message->username
);
122 // update attachments
123 if (isset($this->parameters
['attachmentHandler']) && $this->parameters
['attachmentHandler'] !== null) {
124 $this->parameters
['attachmentHandler']->updateObjectID($message->messageID
);
128 if (isset($this->parameters
['removeQuoteIDs']) && !empty($this->parameters
['removeQuoteIDs'])) {
129 MessageQuoteManager
::getInstance()->markQuotesForRemoval($this->parameters
['removeQuoteIDs']);
131 MessageQuoteManager
::getInstance()->removeMarkedQuotes();
133 // return new message
138 * @see wcf\data\AbstractDatabaseObjectAction::update()
140 public function update() {
142 if (isset($this->parameters
['attachmentHandler']) && $this->parameters
['attachmentHandler'] !== null) {
143 $this->parameters
['data']['attachments'] = count($this->parameters
['attachmentHandler']);
148 // update search index
149 foreach ($this->objects
as $message) {
150 $conversation = $message->getConversation();
151 SearchIndexManager
::getInstance()->update('com.woltlab.wcf.conversation.message', $message->messageID
, $message->message
, ($conversation->firstMessageID
== $message->messageID ?
$conversation->subject
: ''), $message->time
, $message->userID
, $message->username
);
156 * @see wcf\data\AbstractDatabaseObjectAction::delete()
158 public function delete() {
159 $count = parent
::delete();
161 $attachmentMessageIDs = array();
162 foreach ($this->objects
as $message) {
163 if ($message->attachments
) {
164 $attachmentMessageIDs[] = $message->messageID
;
169 // @todo: modification log, reports
171 if (!empty($this->objectIDs
)) {
172 // delete notifications
173 UserNotificationHandler
::getInstance()->deleteNotifications('conversationMessage', 'com.woltlab.wcf.conversation.message.notification', array(), $this->objectIDs
);
175 // update search index
176 SearchIndexManager
::getInstance()->delete('com.woltlab.wcf.conversation.message', $this->objectIDs
);
179 // remove attachments
180 if (!empty($attachmentMessageIDs)) {
181 AttachmentHandler
::removeAttachments('com.woltlab.wcf.conversation.message', $attachmentMessageIDs);
188 * @see wcf\data\IMessageQuickReply::validateQuickReply()
190 public function validateQuickReply() {
191 QuickReplyManager
::getInstance()->setAllowedBBCodes(explode(',', WCF
::getSession()->getPermission('user.message.allowedBBCodes')));
192 QuickReplyManager
::getInstance()->validateParameters($this, $this->parameters
, 'wcf\data\conversation\Conversation');
196 * @see wcf\data\IMessageQuickReply::quickReply()
198 public function quickReply() {
199 return QuickReplyManager
::getInstance()->createMessage(
202 'wcf\data\conversation\ConversationAction',
203 'wcf\data\conversation\message\ViewableConversationMessageList',
204 'conversationMessageList',
205 CONVERSATION_LIST_DEFAULT_SORT_ORDER
210 * @see wcf\data\IExtendedMessageQuickReplyAction::validateJumpToExtended()
212 public function validateJumpToExtended() {
213 $this->readInteger('containerID');
214 $this->readString('message', true);
216 $this->conversation
= new Conversation($this->parameters
['containerID']);
217 if (!$this->conversation
->conversationID
) {
218 throw new UserInputException('containerID');
220 else if ($this->conversation
->isClosed ||
!Conversation
::isParticipant(array($this->conversation
->conversationID
))) {
221 throw new PermissionDeniedException();
224 // editing existing message
225 if (isset($this->parameters
['messageID'])) {
226 $this->message
= new ConversationMessage(intval($this->parameters
['messageID']));
227 if (!$this->message
->messageID ||
($this->message
->conversationID
!= $this->conversation
->conversationID
)) {
228 throw new UserInputException('messageID');
231 if (!$this->message
->canEdit()) {
232 throw new PermissionDeniedException();
238 * @see wcf\data\IExtendedMessageQuickReplyAction::jumpToExtended()
240 public function jumpToExtended() {
242 if ($this->message
=== null) {
243 QuickReplyManager
::getInstance()->setMessage('conversation', $this->conversation
->conversationID
, $this->parameters
['message']);
244 $url = LinkHandler
::getInstance()->getLink('ConversationMessageAdd', array('id' => $this->conversation
->conversationID
));
248 QuickReplyManager
::getInstance()->setMessage('conversationMessage', $this->message
->messageID
, $this->parameters
['message']);
249 $url = LinkHandler
::getInstance()->getLink('ConversationMessageEdit', array('id' => $this->message
->messageID
));
259 * @see wcf\data\IMessageInlineEditorAction::validateBeginEdit()
261 public function validateBeginEdit() {
262 $this->readInteger('containerID');
263 $this->readInteger('objectID');
265 $this->conversation
= new Conversation($this->parameters
['containerID']);
266 if (!$this->conversation
->conversationID
) {
267 throw new UserInputException('containerID');
270 if ($this->conversation
->isClosed ||
!Conversation
::isParticipant(array($this->conversation
->conversationID
))) {
271 throw new PermissionDeniedException();
274 $this->message
= new ConversationMessage($this->parameters
['objectID']);
275 if (!$this->message
->messageID
) {
276 throw new UserInputException('objectID');
279 if (!$this->message
->canEdit()) {
280 throw new PermissionDeniedException();
285 * @see wcf\data\IMessageInlineEditorAction::beginEdit()
287 public function beginEdit() {
288 WCF
::getTPL()->assign(array(
289 'defaultSmilies' => array(), /* TODO: fix this */
290 'message' => $this->message
,
291 'wysiwygSelector' => 'messageEditor'.$this->message
->messageID
295 'actionName' => 'beginEdit',
296 'template' => WCF
::getTPL()->fetch('conversationMessageInlineEditor')
301 * @see wcf\data\IMessageInlineEditorAction::validateSave()
303 public function validateSave() {
304 $this->readString('message', false, 'data');
306 $this->validateBeginEdit();
307 $this->validateMessage($this->conversation
, $this->parameters
['data']['message']);
311 * @see wcf\data\IMessageInlineEditorAction::save()
313 public function save() {
314 $messageEditor = new ConversationMessageEditor($this->message
);
315 $messageEditor->update(array(
316 'message' => PreParser
::getInstance()->parse($this->parameters
['data']['message'], explode(',', WCF
::getSession()->getPermission('user.message.allowedBBCodes')))
320 $this->message
= new ConversationMessage($this->message
->messageID
);
321 $this->message
->getAttachments();
324 'actionName' => 'save',
325 'message' => $this->message
->getFormattedMessage()
330 * @see wcf\data\IMessageQuickReply::validateContainer()
332 public function validateContainer(DatabaseObject
$conversation) {
333 if (!$conversation->conversationID
) {
334 throw new UserInputException('objectID');
336 else if ($conversation->isClosed ||
!Conversation
::isParticipant(array($conversation->conversationID
))) {
337 throw new PermissionDeniedException();
342 * @see wcf\data\IMessageQuickReplyAction::validateMessage()
344 public function validateMessage(DatabaseObject
$container, $message) {
345 if (StringUtil
::length($message) > WCF
::getSession()->getPermission('user.conversation.maxLength')) {
346 throw new UserInputException('message', WCF
::getLanguage()->getDynamicVariable('wcf.message.error.tooLong', array('maxTextLength' => WCF
::getSession()->getPermission('user.conversation.maxLength'))));
349 // search for disallowed bbcodes
350 $disallowedBBCodes = BBCodeParser
::getInstance()->validateBBCodes($message, explode(',', WCF
::getSession()->getPermission('user.message.allowedBBCodes')));
351 if (!empty($disallowedBBCodes)) {
352 throw new UserInputException('text', WCF
::getLanguage()->getDynamicVariable('wcf.message.error.disallowedBBCodes', array('disallowedBBCodes' => $disallowedBBCodes)));
355 // search for censored words
356 if (ENABLE_CENSORSHIP
) {
357 $result = Censorship
::getInstance()->test($message);
359 throw new UserInputException('message', WCF
::getLanguage()->getDynamicVariable('wcf.message.error.censoredWordsFound', array('censoredWords' => $result)));
365 * @see wcf\data\IMessageQuickReply::getPageNo()
367 public function getPageNo(DatabaseObject
$conversation) {
368 $sql = "SELECT COUNT(*) AS count
369 FROM wcf".WCF_N
."_conversation_message
370 WHERE conversationID = ?";
371 $statement = WCF
::getDB()->prepareStatement($sql);
372 $statement->execute(array($conversation->conversationID
));
373 $count = $statement->fetchArray();
375 return array(intval(ceil($count['count'] / CONVERSATION_MESSAGES_PER_PAGE
)), $count['count']);
379 * @see wcf\data\IMessageQuickReply::getRedirectUrl()
381 public function getRedirectUrl(DatabaseObject
$conversation, DatabaseObject
$message) {
382 return LinkHandler
::getInstance()->getLink('Conversation', array(
383 'object' => $conversation,
384 'messageID' => $message->messageID
385 )).'#message'.$message->messageID
;
389 * @see wcf\data\IMessageQuoteAction::validateSaveFullQuote()
391 public function validateSaveFullQuote() {
392 $this->message
= $this->getSingleObject();
394 if (!Conversation
::isParticipant(array($this->message
->conversationID
))) {
395 throw new PermissionDeniedException();
400 * @see wcf\data\IMessageQuoteAction::saveFullQuote()
402 public function saveFullQuote() {
403 if (!MessageQuoteManager
::getInstance()->addQuote('com.woltlab.wcf.conversation.message', $this->message
->messageID
, $this->message
->getExcerpt(), $this->message
->getMessage())) {
404 $quoteID = MessageQuoteManager
::getInstance()->getQuoteID('com.woltlab.wcf.conversation.message', $this->message
->conversationID
, $this->message
->messageID
, $this->message
->getExcerpt(), $this->message
->getMessage());
405 MessageQuoteManager
::getInstance()->removeQuote($quoteID);
409 'count' => MessageQuoteManager
::getInstance()->countQuotes(),
410 'fullQuoteMessageIDs' => MessageQuoteManager
::getInstance()->getFullQuoteObjectIDs(array('com.woltlab.wcf.conversation.message'))
415 * @see wcf\data\IMessageQuoteAction::validateSaveQuote()
417 public function validateSaveQuote() {
418 $this->readString('message');
419 $this->message
= $this->getSingleObject();
421 if (!Conversation
::isParticipant(array($this->message
->conversationID
))) {
422 throw new PermissionDeniedException();
427 * @see wcf\data\IMessageQuoteAction::saveQuote()
429 public function saveQuote() {
430 MessageQuoteManager
::getInstance()->addQuote('com.woltlab.wcf.conversation.message', $this->message
->conversationID
, $this->message
->messageID
, $this->parameters
['message']);
433 'count' => MessageQuoteManager
::getInstance()->countQuotes(),
434 'fullQuoteMessageIDs' => MessageQuoteManager
::getInstance()->getFullQuoteObjectIDs(array('com.woltlab.wcf.conversation.message'))