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\bbcode\BBCodeParser
;
11 use wcf\system\bbcode\PreParser
;
12 use wcf\system\exception\PermissionDeniedException
;
13 use wcf\system\exception\UserInputException
;
14 use wcf\system\message\censorship\Censorship
;
15 use wcf\system\message\quote\MessageQuoteManager
;
16 use wcf\system\message\QuickReplyManager
;
17 use wcf\system\request\LinkHandler
;
18 use wcf\system\search\SearchIndexManager
;
19 use wcf\system\user\notification\
object\ConversationMessageUserNotificationObject
;
20 use wcf\system\user\notification\UserNotificationHandler
;
21 use wcf\system\user\storage\UserStorageHandler
;
23 use wcf\util\StringUtil
;
26 * Executes message-related actions.
29 * @copyright 2001-2012 WoltLab GmbH
30 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
31 * @package com.woltlab.wcf.conversation
32 * @subpackage data.conversation.message
33 * @category Community Framework
35 class ConversationMessageAction
extends AbstractDatabaseObjectAction
implements IExtendedMessageQuickReplyAction
, IMessageInlineEditorAction
, IMessageQuoteAction
{
37 * @see wcf\data\AbstractDatabaseObjectAction::$className
39 protected $className = 'wcf\data\conversation\message\ConversationMessageEditor';
43 * @var wcf\data\conversation\Conversation
45 public $conversation = null;
48 * conversation message object
49 * @var wcf\data\conversation\message\ConversationMessage
51 public $message = null;
54 * @see wcf\data\AbstractDatabaseObjectAction::create()
56 public function create() {
58 if (isset($this->parameters
['attachmentHandler']) && $this->parameters
['attachmentHandler'] !== null) {
59 $this->parameters
['data']['attachments'] = count($this->parameters
['attachmentHandler']);
64 if (!isset($this->parameters
['data']['ipAddress'])) {
65 $this->parameters
['data']['ipAddress'] = WCF
::getSession()->ipAddress
;
69 // do not track ip address
70 if (isset($this->parameters
['data']['ipAddress'])) {
71 unset($this->parameters
['data']['ipAddress']);
76 $message = parent
::create();
79 $conversation = (isset($this->parameters
['converation']) ?
$this->parameters
['converation'] : new Conversation($message->conversationID
));
80 $conversationEditor = new ConversationEditor($conversation);
82 if (empty($this->parameters
['isFirstPost'])) {
83 // update last message
84 $conversationEditor->addMessage($message);
86 // fire notification event
87 if (!$conversation->isDraft
) {
88 $notificationRecipients = array_diff($conversation->getParticipantIDs(true), array($message->userID
)); // don't notify message author
89 if (!empty($notificationRecipients)) {
90 UserNotificationHandler
::getInstance()->fireEvent('conversationMessage', 'com.woltlab.wcf.conversation.message.notification', new ConversationMessageUserNotificationObject($message), $notificationRecipients);
94 // make invisible participant visible
95 $sql = "UPDATE wcf".WCF_N
."_conversation_to_user
97 WHERE participantID = ?
98 AND conversationID = ?";
99 $statement = WCF
::getDB()->prepareStatement($sql);
100 $statement->execute(array($message->userID
, $conversation->conversationID
));
102 // reset visibility if it was hidden but not left
103 $sql = "UPDATE wcf".WCF_N
."_conversation_to_user
104 SET hideConversation = ?
105 WHERE conversationID = ?
106 AND hideConversation = ?";
107 $statement = WCF
::getDB()->prepareStatement($sql);
108 $statement->execute(array(
109 Conversation
::STATE_DEFAULT
,
110 $conversation->conversationID
,
111 Conversation
::STATE_HIDDEN
116 UserStorageHandler
::getInstance()->reset($conversation->getParticipantIDs(), 'unreadConversationCount');
118 // update search index
119 SearchIndexManager
::getInstance()->add('com.woltlab.wcf.conversation.message', $message->messageID
, $message->message
, (!empty($this->parameters
['isFirstPost']) ?
$conversation->subject
: ''), $message->time
, $message->userID
, $message->username
);
121 // update attachments
122 if (isset($this->parameters
['attachmentHandler']) && $this->parameters
['attachmentHandler'] !== null) {
123 $this->parameters
['attachmentHandler']->updateObjectID($message->messageID
);
127 if (isset($this->parameters
['removeQuoteIDs']) && !empty($this->parameters
['removeQuoteIDs'])) {
128 MessageQuoteManager
::getInstance()->markQuotesForRemoval($this->parameters
['removeQuoteIDs']);
130 MessageQuoteManager
::getInstance()->removeMarkedQuotes();
132 // return new message
137 * @see wcf\data\AbstractDatabaseObjectAction::update()
139 public function update() {
141 if (isset($this->parameters
['attachmentHandler']) && $this->parameters
['attachmentHandler'] !== null) {
142 $this->parameters
['data']['attachments'] = count($this->parameters
['attachmentHandler']);
147 // update search index
148 foreach ($this->objects
as $message) {
149 $conversation = $message->getConversation();
150 SearchIndexManager
::getInstance()->update('com.woltlab.wcf.conversation.message', $message->messageID
, $message->message
, ($conversation->firstMessageID
== $message->messageID ?
$conversation->subject
: ''), $message->time
, $message->userID
, $message->username
);
155 * @see wcf\data\AbstractDatabaseObjectAction::delete()
157 public function delete() {
158 $count = parent
::delete();
161 $message = reset($this->objects
);
162 $conversationEditor = new ConversationEditor(new Conversation($message->conversationID
));
164 // reset user storage
165 UserStorageHandler
::getInstance()->reset($conversationEditor->getParticipantIDs(), 'unreadConversationCount');
167 // check if last message was deleted
168 if (($conversationEditor->replies
- $count) == -1) {
169 // remove conversation
170 $conversationEditor->delete();
173 // check if first message was deleted
174 $sql = "SELECT messageID
175 FROM wcf".WCF_N
."_conversation_message
176 WHERE conversationID = ?
178 $statement = WCF
::getDB()->prepareStatement($sql);
179 $statement->execute(array($conversationEditor->conversationID
));
180 $row = $statement->fetchArray();
182 $data = array('replies' => ($conversationEditor->replies
- $count));
183 if ($conversationEditor->firstMessageID
!= $row['messageID']) {
184 $data['firstMessageID'] = $row['messageID'];
187 // update conversation data
188 $conversationEditor->update($data);
196 * @see wcf\data\IMessageQuickReply::validateQuickReply()
198 public function validateQuickReply() {
199 QuickReplyManager
::getInstance()->setAllowedBBCodes(explode(',', WCF
::getSession()->getPermission('user.message.allowedBBCodes')));
200 QuickReplyManager
::getInstance()->validateParameters($this, $this->parameters
, 'wcf\data\conversation\Conversation');
204 * @see wcf\data\IMessageQuickReply::quickReply()
206 public function quickReply() {
207 return QuickReplyManager
::getInstance()->createMessage(
210 'wcf\data\conversation\ConversationAction',
211 'wcf\data\conversation\message\ViewableConversationMessageList',
212 'conversationMessageList',
213 CONVERSATION_LIST_DEFAULT_SORT_ORDER
218 * @see wcf\data\IExtendedMessageQuickReplyAction::validateJumpToExtended()
220 public function validateJumpToExtended() {
221 $this->readInteger('containerID');
222 $this->readString('message', true);
224 $this->conversation
= new Conversation($this->parameters
['containerID']);
225 if (!$this->conversation
->conversationID
) {
226 throw new UserInputException('containerID');
228 else if ($this->conversation
->isClosed ||
!Conversation
::isParticipant(array($this->conversation
->conversationID
))) {
229 throw new PermissionDeniedException();
232 // editing existing message
233 if (isset($this->parameters
['messageID'])) {
234 $this->message
= new ConversationMessage(intval($this->parameters
['messageID']));
235 if (!$this->message
->messageID ||
($this->message
->conversationID
!= $this->conversation
->conversationID
)) {
236 throw new UserInputException('messageID');
239 if (!$this->message
->canEdit()) {
240 throw new PermissionDeniedException();
246 * @see wcf\data\IExtendedMessageQuickReplyAction::jumpToExtended()
248 public function jumpToExtended() {
250 if ($this->message
=== null) {
251 QuickReplyManager
::getInstance()->setMessage('conversation', $this->conversation
->conversationID
, $this->parameters
['message']);
252 $url = LinkHandler
::getInstance()->getLink('ConversationMessageAdd', array('id' => $this->conversation
->conversationID
));
256 QuickReplyManager
::getInstance()->setMessage('conversationMessage', $this->message
->messageID
, $this->parameters
['message']);
257 $url = LinkHandler
::getInstance()->getLink('ConversationMessageEdit', array('id' => $this->message
->messageID
));
267 * @see wcf\data\IMessageInlineEditorAction::validateBeginEdit()
269 public function validateBeginEdit() {
270 $this->readInteger('containerID');
271 $this->readInteger('objectID');
273 $this->conversation
= new Conversation($this->parameters
['containerID']);
274 if (!$this->conversation
->conversationID
) {
275 throw new UserInputException('containerID');
278 if ($this->conversation
->isClosed ||
!Conversation
::isParticipant(array($this->conversation
->conversationID
))) {
279 throw new PermissionDeniedException();
282 $this->message
= new ConversationMessage($this->parameters
['objectID']);
283 if (!$this->message
->messageID
) {
284 throw new UserInputException('objectID');
287 if (!$this->message
->canEdit()) {
288 throw new PermissionDeniedException();
293 * @see wcf\data\IMessageInlineEditorAction::beginEdit()
295 public function beginEdit() {
296 WCF
::getTPL()->assign(array(
297 'defaultSmilies' => array(), /* TODO: fix this */
298 'message' => $this->message
,
299 'wysiwygSelector' => 'messageEditor'.$this->message
->messageID
303 'actionName' => 'beginEdit',
304 'template' => WCF
::getTPL()->fetch('conversationMessageInlineEditor')
309 * @see wcf\data\IMessageInlineEditorAction::validateSave()
311 public function validateSave() {
312 $this->readString('message', false, 'data');
314 $this->validateBeginEdit();
315 $this->validateMessage($this->conversation
, $this->parameters
['data']['message']);
319 * @see wcf\data\IMessageInlineEditorAction::save()
321 public function save() {
322 $messageEditor = new ConversationMessageEditor($this->message
);
323 $messageEditor->update(array(
324 'message' => PreParser
::getInstance()->parse($this->parameters
['data']['message'], explode(',', WCF
::getSession()->getPermission('user.message.allowedBBCodes')))
328 $this->message
= new ConversationMessage($this->message
->messageID
);
329 $this->message
->getAttachments();
332 'actionName' => 'save',
333 'message' => $this->message
->getFormattedMessage()
338 * @see wcf\data\IMessageQuickReply::validateContainer()
340 public function validateContainer(DatabaseObject
$conversation) {
341 if (!$conversation->conversationID
) {
342 throw new UserInputException('objectID');
344 else if ($conversation->isClosed ||
!Conversation
::isParticipant(array($conversation->conversationID
))) {
345 throw new PermissionDeniedException();
350 * @see wcf\data\IMessageQuickReplyAction::validateMessage()
352 public function validateMessage(DatabaseObject
$container, $message) {
353 if (StringUtil
::length($message) > WCF
::getSession()->getPermission('user.conversation.maxLength')) {
354 throw new UserInputException('message', WCF
::getLanguage()->getDynamicVariable('wcf.message.error.tooLong', array('maxTextLength' => WCF
::getSession()->getPermission('user.conversation.maxLength'))));
357 // search for disallowed bbcodes
358 $disallowedBBCodes = BBCodeParser
::getInstance()->validateBBCodes($message, explode(',', WCF
::getSession()->getPermission('user.message.allowedBBCodes')));
359 if (!empty($disallowedBBCodes)) {
360 throw new UserInputException('text', WCF
::getLanguage()->getDynamicVariable('wcf.message.error.disallowedBBCodes', array('disallowedBBCodes' => $disallowedBBCodes)));
363 // search for censored words
364 if (ENABLE_CENSORSHIP
) {
365 $result = Censorship
::getInstance()->test($message);
367 throw new UserInputException('message', WCF
::getLanguage()->getDynamicVariable('wcf.message.error.censoredWordsFound', array('censoredWords' => $result)));
373 * @see wcf\data\IMessageQuickReply::getPageNo()
375 public function getPageNo(DatabaseObject
$conversation) {
376 $sql = "SELECT COUNT(*) AS count
377 FROM wcf".WCF_N
."_conversation_message
378 WHERE conversationID = ?";
379 $statement = WCF
::getDB()->prepareStatement($sql);
380 $statement->execute(array($conversation->conversationID
));
381 $count = $statement->fetchArray();
383 return array(intval(ceil($count['count'] / CONVERSATION_MESSAGES_PER_PAGE
)), $count['count']);
387 * @see wcf\data\IMessageQuickReply::getRedirectUrl()
389 public function getRedirectUrl(DatabaseObject
$conversation, DatabaseObject
$message) {
390 return LinkHandler
::getInstance()->getLink('Conversation', array(
391 'object' => $conversation,
392 'messageID' => $message->messageID
393 )).'#message'.$message->messageID
;
397 * @see wcf\data\IMessageQuoteAction::validateSaveFullQuote()
399 public function validateSaveFullQuote() {
400 $this->message
= $this->getSingleObject();
402 if (!Conversation
::isParticipant(array($this->message
->conversationID
))) {
403 throw new PermissionDeniedException();
408 * @see wcf\data\IMessageQuoteAction::saveFullQuote()
410 public function saveFullQuote() {
411 if (!MessageQuoteManager
::getInstance()->addQuote('com.woltlab.wcf.conversation.message', $this->message
->messageID
, $this->message
->getExcerpt(), $this->message
->getMessage())) {
412 $quoteID = MessageQuoteManager
::getInstance()->getQuoteID('com.woltlab.wcf.conversation.message', $this->message
->messageID
, $this->message
->getExcerpt(), $this->message
->getMessage());
413 MessageQuoteManager
::getInstance()->removeQuote($quoteID);
417 'count' => MessageQuoteManager
::getInstance()->countQuotes(),
418 'fullQuoteMessageIDs' => MessageQuoteManager
::getInstance()->getFullQuoteObjectIDs(array('com.woltlab.wcf.conversation.message'))
423 * @see wcf\data\IMessageQuoteAction::validateSaveQuote()
425 public function validateSaveQuote() {
426 $this->readString('message');
427 $this->message
= $this->getSingleObject();
429 if (!Conversation
::isParticipant(array($this->message
->conversationID
))) {
430 throw new PermissionDeniedException();
435 * @see wcf\data\IMessageQuoteAction::saveQuote()
437 public function saveQuote() {
438 MessageQuoteManager
::getInstance()->addQuote('com.woltlab.wcf.conversation.message', $this->message
->messageID
, $this->parameters
['message']);
441 'count' => MessageQuoteManager
::getInstance()->countQuotes(),
442 'fullQuoteMessageIDs' => MessageQuoteManager
::getInstance()->getFullQuoteObjectIDs(array('com.woltlab.wcf.conversation.message'))