Commit | Line | Data |
---|---|---|
9544b6b4 MW |
1 | <?php |
2 | namespace wcf\data\conversation; | |
5e279c42 | 3 | use wcf\data\conversation\label\ConversationLabel; |
9544b6b4 | 4 | use wcf\data\conversation\message\ConversationMessageAction; |
5d7f0df0 | 5 | use wcf\data\conversation\message\ConversationMessageList; |
a0c1a541 | 6 | use wcf\data\conversation\message\SimplifiedViewableConversationMessageList; |
b475685e | 7 | use wcf\data\AbstractDatabaseObjectAction; |
232cdc4b | 8 | use wcf\data\IClipboardAction; |
d8963ec2 | 9 | use wcf\data\IVisitableObjectAction; |
e8fe47c2 | 10 | use wcf\system\clipboard\ClipboardHandler; |
7f07124d | 11 | use wcf\system\conversation\ConversationHandler; |
5d7f0df0 | 12 | use wcf\system\database\util\PreparedStatementConditionBuilder; |
5e279c42 | 13 | use wcf\system\exception\PermissionDeniedException; |
e8fe47c2 | 14 | use wcf\system\exception\UserInputException; |
65a160b7 | 15 | use wcf\system\log\modification\ConversationModificationLogHandler; |
b2e0a2ad | 16 | use wcf\system\request\LinkHandler; |
87de5988 | 17 | use wcf\system\search\SearchIndexManager; |
8b467fcd MW |
18 | use wcf\system\user\notification\object\ConversationUserNotificationObject; |
19 | use wcf\system\user\notification\UserNotificationHandler; | |
9544b6b4 MW |
20 | use wcf\system\user\storage\UserStorageHandler; |
21 | use wcf\system\WCF; | |
22 | ||
23 | /** | |
24 | * Executes conversation-related actions. | |
25 | * | |
26 | * @author Marcel Werk | |
ca7ac0d3 | 27 | * @copyright 2001-2018 WoltLab GmbH |
9544b6b4 | 28 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> |
c032049e | 29 | * @package WoltLabSuite\Core\Data\Conversation |
5def88a8 MS |
30 | * |
31 | * @method ConversationEditor[] getObjects() | |
32 | * @method ConversationEditor getSingleObject() | |
9544b6b4 | 33 | */ |
d8963ec2 | 34 | class ConversationAction extends AbstractDatabaseObjectAction implements IClipboardAction, IVisitableObjectAction { |
9544b6b4 | 35 | /** |
76f12d13 | 36 | * @inheritDoc |
9544b6b4 | 37 | */ |
76f12d13 | 38 | protected $className = ConversationEditor::class; |
9544b6b4 | 39 | |
65b37bf6 AE |
40 | /** |
41 | * conversation object | |
76f12d13 | 42 | * @var ConversationEditor |
65b37bf6 | 43 | */ |
09ab08af | 44 | protected $conversation; |
65b37bf6 | 45 | |
ecc8c621 AE |
46 | /** |
47 | * list of conversation data modifications | |
03043c3c | 48 | * @var mixed[][] |
ecc8c621 | 49 | */ |
76f12d13 | 50 | protected $conversationData = []; |
ecc8c621 | 51 | |
be03f342 | 52 | /** @noinspection PhpMissingParentCallCommonInspection */ |
9544b6b4 | 53 | /** |
76f12d13 | 54 | * @inheritDoc |
5def88a8 | 55 | * @return Conversation |
9544b6b4 MW |
56 | */ |
57 | public function create() { | |
58 | // create conversation | |
59 | $data = $this->parameters['data']; | |
60 | $data['lastPosterID'] = $data['userID']; | |
61 | $data['lastPoster'] = $data['username']; | |
62 | $data['lastPostTime'] = $data['time']; | |
63 | // count participants | |
64 | if (!empty($this->parameters['participants'])) { | |
65 | $data['participants'] = count($this->parameters['participants']); | |
66 | } | |
67 | // count attachments | |
68 | if (isset($this->parameters['attachmentHandler']) && $this->parameters['attachmentHandler'] !== null) { | |
69 | $data['attachments'] = count($this->parameters['attachmentHandler']); | |
70 | } | |
76f12d13 | 71 | $conversation = call_user_func([$this->className, 'create'], $data); |
f34884b9 | 72 | $conversationEditor = new ConversationEditor($conversation); |
9544b6b4 | 73 | |
f34884b9 | 74 | if (!$conversation->isDraft) { |
11cde7d7 | 75 | // save participants |
219838a1 AE |
76 | $conversationEditor->updateParticipants( |
77 | (!empty($this->parameters['participants']) ? $this->parameters['participants'] : []), | |
78 | (!empty($this->parameters['invisibleParticipants']) ? $this->parameters['invisibleParticipants'] : []), | |
79 | 'all' | |
80 | ); | |
f34884b9 MW |
81 | |
82 | // add author | |
5e10b75b | 83 | if ($data['userID'] !== null) { |
ef4db0fc | 84 | $conversationEditor->updateParticipants([$data['userID']], [], 'all'); |
5e10b75b | 85 | } |
3bbcb27d MW |
86 | |
87 | // update conversation count | |
462d532a | 88 | UserStorageHandler::getInstance()->reset($conversation->getParticipantIDs(), 'conversationCount'); |
db864366 | 89 | |
1920cd3d MW |
90 | // mark conversation as read for the author |
91 | $sql = "UPDATE wcf".WCF_N."_conversation_to_user | |
92 | SET lastVisitTime = ? | |
93 | WHERE participantID = ? | |
94 | AND conversationID = ?"; | |
95 | $statement = WCF::getDB()->prepareStatement($sql); | |
76f12d13 | 96 | $statement->execute([$data['time'], $data['userID'], $conversation->conversationID]); |
3bbcb27d MW |
97 | } |
98 | else { | |
99 | // update conversation count | |
76f12d13 | 100 | UserStorageHandler::getInstance()->reset([$data['userID']], 'conversationCount'); |
9544b6b4 | 101 | } |
9544b6b4 MW |
102 | |
103 | // update participant summary | |
9544b6b4 MW |
104 | $conversationEditor->updateParticipantSummary(); |
105 | ||
106 | // create message | |
1920cd3d MW |
107 | $messageData = $this->parameters['messageData']; |
108 | $messageData['conversationID'] = $conversation->conversationID; | |
109 | $messageData['time'] = $this->parameters['data']['time']; | |
110 | $messageData['userID'] = $this->parameters['data']['userID']; | |
111 | $messageData['username'] = $this->parameters['data']['username']; | |
9544b6b4 | 112 | |
76f12d13 | 113 | $messageAction = new ConversationMessageAction([], 'create', [ |
1920cd3d | 114 | 'data' => $messageData, |
9544b6b4 MW |
115 | 'conversation' => $conversation, |
116 | 'isFirstPost' => true, | |
8a6ee075 MS |
117 | 'attachmentHandler' => isset($this->parameters['attachmentHandler']) ? $this->parameters['attachmentHandler'] : null, |
118 | 'htmlInputProcessor' => isset($this->parameters['htmlInputProcessor']) ? $this->parameters['htmlInputProcessor'] : null | |
76f12d13 | 119 | ]); |
9544b6b4 MW |
120 | $resultValues = $messageAction->executeAction(); |
121 | ||
ba1ab5e5 | 122 | // update first message id |
76f12d13 | 123 | $conversationEditor->update([ |
f34884b9 | 124 | 'firstMessageID' => $resultValues['returnValues']->messageID |
76f12d13 | 125 | ]); |
f34884b9 | 126 | |
11cde7d7 MW |
127 | $conversation->setFirstMessage($resultValues['returnValues']); |
128 | if (!$conversation->isDraft) { | |
129 | // fire notification event | |
76f12d13 | 130 | $notificationRecipients = array_merge((!empty($this->parameters['participants']) ? $this->parameters['participants'] : []), (!empty($this->parameters['invisibleParticipants']) ? $this->parameters['invisibleParticipants'] : [])); |
901d21f2 MS |
131 | UserNotificationHandler::getInstance()->fireEvent( |
132 | 'conversation', | |
133 | 'com.woltlab.wcf.conversation.notification', | |
134 | new ConversationUserNotificationObject($conversation), | |
135 | $notificationRecipients | |
136 | ); | |
11cde7d7 MW |
137 | } |
138 | ||
9544b6b4 MW |
139 | return $conversation; |
140 | } | |
141 | ||
5d7f0df0 | 142 | /** |
76f12d13 | 143 | * @inheritDoc |
5d7f0df0 MW |
144 | */ |
145 | public function delete() { | |
146 | // deletes messages | |
147 | $messageList = new ConversationMessageList(); | |
76f12d13 | 148 | $messageList->getConditionBuilder()->add('conversation_message.conversationID IN (?)', [$this->objectIDs]); |
5d7f0df0 MW |
149 | $messageList->readObjectIDs(); |
150 | $action = new ConversationMessageAction($messageList->getObjectIDs(), 'delete'); | |
151 | $action->executeAction(); | |
152 | ||
054a1c89 AE |
153 | // get the list of participants in order to reset the 'unread conversation'-counter |
154 | $participantIDs = []; | |
155 | if (!empty($this->objectIDs)) { | |
156 | $conditions = new PreparedStatementConditionBuilder(); | |
157 | $conditions->add("conversationID IN (?)", [$this->objectIDs]); | |
158 | $sql = "SELECT DISTINCT participantID | |
159 | FROM wcf" . WCF_N . "_conversation_to_user | |
160 | " . $conditions; | |
161 | $statement = WCF::getDB()->prepareStatement($sql); | |
162 | $statement->execute($conditions->getParameters()); | |
163 | ||
164 | while ($participantID = $statement->fetchColumn()) { | |
165 | $participantIDs[] = $participantID; | |
166 | } | |
167 | } | |
168 | ||
5d7f0df0 MW |
169 | // delete conversations |
170 | parent::delete(); | |
d0cc88e1 | 171 | |
5d7f0df0 MW |
172 | if (!empty($this->objectIDs)) { |
173 | // delete notifications | |
9888e764 | 174 | UserNotificationHandler::getInstance()->removeNotifications('com.woltlab.wcf.conversation.notification', $this->objectIDs); |
3b37e024 AE |
175 | |
176 | // remove modification logs | |
76f12d13 | 177 | ConversationModificationLogHandler::getInstance()->deleteLogs($this->objectIDs); |
054a1c89 AE |
178 | |
179 | // reset the number of unread conversations | |
180 | if (!empty($participantIDs)) { | |
181 | UserStorageHandler::getInstance()->reset($participantIDs, 'unreadConversationCount'); | |
182 | } | |
5d7f0df0 MW |
183 | } |
184 | } | |
185 | ||
f34884b9 | 186 | /** |
76f12d13 | 187 | * @inheritDoc |
f34884b9 MW |
188 | */ |
189 | public function update() { | |
76f12d13 MS |
190 | if (!isset($this->parameters['participants'])) $this->parameters['participants'] = []; |
191 | if (!isset($this->parameters['invisibleParticipants'])) $this->parameters['invisibleParticipants'] = []; | |
f73a10ed | 192 | |
f34884b9 MW |
193 | // count participants |
194 | if (!empty($this->parameters['participants'])) { | |
195 | $this->parameters['data']['participants'] = count($this->parameters['participants']); | |
196 | } | |
197 | ||
198 | parent::update(); | |
199 | ||
c9ee8de8 | 200 | foreach ($this->getObjects() as $conversation) { |
bf720d62 | 201 | // participants |
f34884b9 | 202 | if (!empty($this->parameters['participants']) || !empty($this->parameters['invisibleParticipants'])) { |
f73a10ed AE |
203 | // get current participants |
204 | $participantIDs = $conversation->getParticipantIDs(); | |
205 | ||
219838a1 AE |
206 | $conversation->updateParticipants( |
207 | (!empty($this->parameters['participants']) ? $this->parameters['participants'] : []), | |
208 | (!empty($this->parameters['invisibleParticipants']) ? $this->parameters['invisibleParticipants'] : []), | |
209 | (!empty($this->parameters['visibility']) ? $this->parameters['visibility'] : 'all') | |
210 | ); | |
f34884b9 | 211 | $conversation->updateParticipantSummary(); |
f73a10ed AE |
212 | |
213 | // check if new participants have been added | |
1773c844 MW |
214 | $newParticipantIDs = array_diff(array_merge($this->parameters['participants'], $this->parameters['invisibleParticipants']), $participantIDs); |
215 | if (!empty($newParticipantIDs)) { | |
f73a10ed | 216 | // update conversation count |
1846a5f4 | 217 | UserStorageHandler::getInstance()->reset($newParticipantIDs, 'unreadConversationCount'); |
1773c844 | 218 | UserStorageHandler::getInstance()->reset($newParticipantIDs, 'conversationCount'); |
f73a10ed AE |
219 | |
220 | // fire notification event | |
901d21f2 MS |
221 | UserNotificationHandler::getInstance()->fireEvent( |
222 | 'conversation', | |
223 | 'com.woltlab.wcf.conversation.notification', | |
224 | new ConversationUserNotificationObject($conversation->getDecoratedObject()), | |
225 | $newParticipantIDs | |
226 | ); | |
f73a10ed | 227 | } |
f34884b9 MW |
228 | } |
229 | ||
230 | // draft status | |
231 | if (isset($this->parameters['data']['isDraft'])) { | |
232 | if ($conversation->isDraft && !$this->parameters['data']['isDraft']) { | |
233 | // add author | |
219838a1 | 234 | $conversation->updateParticipants([$conversation->userID], [], 'all'); |
3bbcb27d MW |
235 | |
236 | // update conversation count | |
1846a5f4 | 237 | UserStorageHandler::getInstance()->reset($conversation->getParticipantIDs(), 'unreadConversationCount'); |
462d532a | 238 | UserStorageHandler::getInstance()->reset($conversation->getParticipantIDs(), 'conversationCount'); |
f34884b9 MW |
239 | } |
240 | } | |
241 | } | |
242 | } | |
243 | ||
9544b6b4 | 244 | /** |
76f12d13 | 245 | * @inheritDoc |
9544b6b4 MW |
246 | */ |
247 | public function markAsRead() { | |
248 | if (empty($this->parameters['visitTime'])) { | |
249 | $this->parameters['visitTime'] = TIME_NOW; | |
250 | } | |
799e823e CW |
251 | |
252 | // in case this is a call via PHP and the userID parameter is missing, set it to the userID of the current user | |
253 | if (!isset($this->parameters['userID'])) { | |
254 | $this->parameters['userID'] = WCF::getUser()->userID; | |
255 | } | |
9544b6b4 | 256 | |
ac18582b | 257 | if (empty($this->objects)) { |
9544b6b4 MW |
258 | $this->readObjects(); |
259 | } | |
260 | ||
76f12d13 | 261 | $conversationIDs = []; |
9544b6b4 MW |
262 | $sql = "UPDATE wcf".WCF_N."_conversation_to_user |
263 | SET lastVisitTime = ? | |
264 | WHERE participantID = ? | |
265 | AND conversationID = ?"; | |
266 | $statement = WCF::getDB()->prepareStatement($sql); | |
c2b184f9 | 267 | WCF::getDB()->beginTransaction(); |
c9ee8de8 | 268 | foreach ($this->getObjects() as $conversation) { |
76f12d13 | 269 | $statement->execute([ |
c2b184f9 | 270 | $this->parameters['visitTime'], |
799e823e | 271 | $this->parameters['userID'], |
c2b184f9 | 272 | $conversation->conversationID |
76f12d13 | 273 | ]); |
d0051596 | 274 | $conversationIDs[] = $conversation->conversationID; |
9544b6b4 | 275 | } |
c2b184f9 | 276 | WCF::getDB()->commitTransaction(); |
9544b6b4 MW |
277 | |
278 | // reset storage | |
799e823e | 279 | UserStorageHandler::getInstance()->reset([$this->parameters['userID']], 'unreadConversationCount'); |
d0051596 | 280 | |
c61f0f25 | 281 | // mark notifications as confirmed |
d0051596 MW |
282 | if (!empty($conversationIDs)) { |
283 | // conversation start notification | |
284 | $conditionBuilder = new PreparedStatementConditionBuilder(); | |
76f12d13 | 285 | $conditionBuilder->add('notification.eventID = ?', [UserNotificationHandler::getInstance()->getEvent('com.woltlab.wcf.conversation.notification', 'conversation')->eventID]); |
d0051596 | 286 | $conditionBuilder->add('notification.objectID = conversation.conversationID'); |
799e823e | 287 | $conditionBuilder->add('notification.userID = ?', [$this->parameters['userID']]); |
76f12d13 MS |
288 | $conditionBuilder->add('conversation.conversationID IN (?)', [$conversationIDs]); |
289 | $conditionBuilder->add('conversation.time <= ?', [$this->parameters['visitTime']]); | |
d0051596 MW |
290 | |
291 | $sql = "SELECT conversation.conversationID | |
292 | FROM wcf".WCF_N."_conversation conversation, | |
c61f0f25 | 293 | wcf".WCF_N."_user_notification notification |
d0051596 MW |
294 | ".$conditionBuilder; |
295 | $statement = WCF::getDB()->prepareStatement($sql); | |
296 | $statement->execute($conditionBuilder->getParameters()); | |
c9d69e7c | 297 | $notificationObjectIDs = $statement->fetchAll(\PDO::FETCH_COLUMN); |
d0051596 MW |
298 | |
299 | if (!empty($notificationObjectIDs)) { | |
799e823e | 300 | UserNotificationHandler::getInstance()->markAsConfirmed('conversation', 'com.woltlab.wcf.conversation.notification', [$this->parameters['userID']], $notificationObjectIDs); |
d0051596 MW |
301 | } |
302 | ||
303 | // conversation reply notification | |
304 | $conditionBuilder = new PreparedStatementConditionBuilder(); | |
76f12d13 | 305 | $conditionBuilder->add('notification.eventID = ?', [UserNotificationHandler::getInstance()->getEvent('com.woltlab.wcf.conversation.message.notification', 'conversationMessage')->eventID]); |
d0051596 | 306 | $conditionBuilder->add('notification.objectID = conversation_message.messageID'); |
799e823e | 307 | $conditionBuilder->add('notification.userID = ?', [$this->parameters['userID']]); |
76f12d13 MS |
308 | $conditionBuilder->add('conversation_message.conversationID IN (?)', [$conversationIDs]); |
309 | $conditionBuilder->add('conversation_message.time <= ?', [$this->parameters['visitTime']]); | |
a480521b | 310 | |
d0051596 MW |
311 | $sql = "SELECT conversation_message.messageID |
312 | FROM wcf".WCF_N."_conversation_message conversation_message, | |
c61f0f25 | 313 | wcf".WCF_N."_user_notification notification |
d0051596 MW |
314 | ".$conditionBuilder; |
315 | $statement = WCF::getDB()->prepareStatement($sql); | |
316 | $statement->execute($conditionBuilder->getParameters()); | |
c9d69e7c | 317 | $notificationObjectIDs = $statement->fetchAll(\PDO::FETCH_COLUMN); |
a480521b | 318 | |
d0051596 | 319 | if (!empty($notificationObjectIDs)) { |
799e823e | 320 | UserNotificationHandler::getInstance()->markAsConfirmed('conversationMessage', 'com.woltlab.wcf.conversation.message.notification', [$this->parameters['userID']], $notificationObjectIDs); |
d0051596 MW |
321 | } |
322 | } | |
4ca3137c AE |
323 | |
324 | if (!empty($conversationIDs)) { | |
325 | $this->unmarkItems($conversationIDs); | |
326 | } | |
c61f0f25 | 327 | |
76f12d13 | 328 | $returnValues = [ |
c61f0f25 | 329 | 'totalCount' => ConversationHandler::getInstance()->getUnreadConversationCount(null, true) |
76f12d13 | 330 | ]; |
c61f0f25 AE |
331 | |
332 | if (count($conversationIDs) == 1) { | |
333 | $returnValues['markAsRead'] = reset($conversationIDs); | |
334 | } | |
335 | ||
336 | return $returnValues; | |
9544b6b4 MW |
337 | } |
338 | ||
339 | /** | |
76f12d13 | 340 | * @inheritDoc |
9544b6b4 MW |
341 | */ |
342 | public function validateMarkAsRead() { | |
c2b184f9 AE |
343 | // visitTime might not be in the future |
344 | if (isset($this->parameters['visitTime'])) { | |
345 | $this->parameters['visitTime'] = intval($this->parameters['visitTime']); | |
346 | if ($this->parameters['visitTime'] > TIME_NOW) { | |
347 | $this->parameters['visitTime'] = TIME_NOW; | |
348 | } | |
349 | } | |
799e823e CW |
350 | |
351 | // userID should always be equal to the userID of the current user when called via AJAX | |
352 | $this->parameters['userID'] = WCF::getUser()->userID; | |
c2b184f9 AE |
353 | |
354 | if (empty($this->objects)) { | |
355 | $this->readObjects(); | |
356 | } | |
357 | ||
358 | // check participation | |
76f12d13 | 359 | $conversationIDs = []; |
c9ee8de8 | 360 | foreach ($this->getObjects() as $conversation) { |
c2b184f9 AE |
361 | $conversationIDs[] = $conversation->conversationID; |
362 | } | |
363 | ||
364 | if (empty($conversationIDs)) { | |
365 | throw new UserInputException('objectIDs'); | |
366 | } | |
367 | ||
368 | if (!Conversation::isParticipant($conversationIDs)) { | |
369 | throw new PermissionDeniedException(); | |
370 | } | |
9544b6b4 | 371 | } |
5e279c42 | 372 | |
38cc68ad MW |
373 | /** |
374 | * Marks all conversations as read. | |
375 | */ | |
376 | public function markAllAsRead() { | |
377 | $sql = "UPDATE wcf".WCF_N."_conversation_to_user | |
378 | SET lastVisitTime = ? | |
379 | WHERE participantID = ?"; | |
380 | $statement = WCF::getDB()->prepareStatement($sql); | |
76f12d13 | 381 | $statement->execute([ |
38cc68ad MW |
382 | TIME_NOW, |
383 | WCF::getUser()->userID | |
76f12d13 | 384 | ]); |
38cc68ad MW |
385 | |
386 | // reset storage | |
76f12d13 | 387 | UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'unreadConversationCount'); |
38cc68ad | 388 | |
9888e764 F |
389 | // confirm obsolete notifications |
390 | UserNotificationHandler::getInstance()->markAsConfirmed('conversation', 'com.woltlab.wcf.conversation.notification', [WCF::getUser()->userID]); | |
391 | UserNotificationHandler::getInstance()->markAsConfirmed('conversationMessage', 'com.woltlab.wcf.conversation.message.notification', [WCF::getUser()->userID]); | |
c61f0f25 | 392 | |
76f12d13 | 393 | return [ |
c61f0f25 | 394 | 'markAllAsRead' => true |
76f12d13 | 395 | ]; |
38cc68ad MW |
396 | } |
397 | ||
398 | /** | |
399 | * Validates the markAllAsRead action. | |
400 | */ | |
76f12d13 MS |
401 | public function validateMarkAllAsRead() { |
402 | // does nothing | |
403 | } | |
38cc68ad | 404 | |
5e279c42 AE |
405 | /** |
406 | * Validates user access for label management. | |
6421362c MS |
407 | * |
408 | * @throws PermissionDeniedException | |
5e279c42 | 409 | */ |
bf720d62 | 410 | public function validateGetLabelManagement() { |
5e279c42 AE |
411 | if (!WCF::getSession()->getPermission('user.conversation.canUseConversation')) { |
412 | throw new PermissionDeniedException(); | |
413 | } | |
414 | } | |
415 | ||
416 | /** | |
417 | * Returns the conversation label management. | |
418 | * | |
419 | * @return array | |
420 | */ | |
421 | public function getLabelManagement() { | |
76f12d13 | 422 | WCF::getTPL()->assign([ |
5e279c42 AE |
423 | 'cssClassNames' => ConversationLabel::getLabelCssClassNames(), |
424 | 'labelList' => ConversationLabel::getLabelsByUser() | |
76f12d13 | 425 | ]); |
5e279c42 | 426 | |
76f12d13 | 427 | return [ |
5e279c42 | 428 | 'actionName' => 'getLabelManagement', |
d8c52eb0 MS |
429 | 'template' => WCF::getTPL()->fetch('conversationLabelManagement'), |
430 | 'maxLabels' => WCF::getSession()->getPermission('user.conversation.maxLabels'), | |
431 | 'labelCount' => count(ConversationLabel::getLabelsByUser()) | |
76f12d13 | 432 | ]; |
5e279c42 | 433 | } |
e2196ce0 MW |
434 | |
435 | /** | |
436 | * Validates the get message preview action. | |
6421362c MS |
437 | * |
438 | * @throws PermissionDeniedException | |
e2196ce0 MW |
439 | */ |
440 | public function validateGetMessagePreview() { | |
953b3e7b | 441 | $this->conversation = $this->getSingleObject(); |
76f12d13 | 442 | if (!Conversation::isParticipant([$this->conversation->conversationID])) { |
953b3e7b | 443 | throw new PermissionDeniedException(); |
e2196ce0 | 444 | } |
e2196ce0 MW |
445 | } |
446 | ||
447 | /** | |
a480521b | 448 | * Returns a preview of a message in a specific conversation. |
e2196ce0 | 449 | * |
76f12d13 | 450 | * @return string[] |
e2196ce0 MW |
451 | */ |
452 | public function getMessagePreview() { | |
a0c1a541 | 453 | $messageList = new SimplifiedViewableConversationMessageList(); |
e2196ce0 | 454 | |
76f12d13 | 455 | $messageList->getConditionBuilder()->add("conversation_message.messageID = ?", [$this->conversation->firstMessageID]); |
e2196ce0 MW |
456 | $messageList->readObjects(); |
457 | $messages = $messageList->getObjects(); | |
458 | ||
76f12d13 | 459 | WCF::getTPL()->assign([ |
e2196ce0 | 460 | 'message' => reset($messages) |
76f12d13 MS |
461 | ]); |
462 | return [ | |
e2196ce0 | 463 | 'template' => WCF::getTPL()->fetch('conversationMessagePreview') |
76f12d13 | 464 | ]; |
e2196ce0 | 465 | } |
ecc8c621 AE |
466 | |
467 | /** | |
468 | * Validates parameters to close conversations. | |
6421362c MS |
469 | * |
470 | * @throws PermissionDeniedException | |
471 | * @throws UserInputException | |
ecc8c621 AE |
472 | */ |
473 | public function validateClose() { | |
474 | // read objects | |
475 | if (empty($this->objects)) { | |
476 | $this->readObjects(); | |
eb6d1db7 AE |
477 | |
478 | if (empty($this->objects)) { | |
479 | throw new UserInputException('objectIDs'); | |
480 | } | |
ecc8c621 AE |
481 | } |
482 | ||
483 | // validate ownership | |
c9ee8de8 | 484 | foreach ($this->getObjects() as $conversation) { |
ecc8c621 AE |
485 | if ($conversation->isClosed || ($conversation->userID != WCF::getUser()->userID)) { |
486 | throw new PermissionDeniedException(); | |
487 | } | |
488 | } | |
489 | } | |
490 | ||
491 | /** | |
492 | * Closes conversations. | |
493 | * | |
03043c3c | 494 | * @return mixed[][] |
ecc8c621 AE |
495 | */ |
496 | public function close() { | |
c9ee8de8 | 497 | foreach ($this->getObjects() as $conversation) { |
76f12d13 | 498 | $conversation->update(['isClosed' => 1]); |
2e0bc870 | 499 | $this->addConversationData($conversation->getDecoratedObject(), 'isClosed', 1); |
953b3e7b AE |
500 | |
501 | ConversationModificationLogHandler::getInstance()->close($conversation->getDecoratedObject()); | |
ecc8c621 AE |
502 | } |
503 | ||
e8fe47c2 AE |
504 | $this->unmarkItems(); |
505 | ||
ecc8c621 AE |
506 | return $this->getConversationData(); |
507 | } | |
508 | ||
509 | /** | |
510 | * Validates parameters to open conversations. | |
6421362c MS |
511 | * |
512 | * @throws PermissionDeniedException | |
513 | * @throws UserInputException | |
ecc8c621 AE |
514 | */ |
515 | public function validateOpen() { | |
516 | // read objects | |
517 | if (empty($this->objects)) { | |
518 | $this->readObjects(); | |
eb6d1db7 AE |
519 | |
520 | if (empty($this->objects)) { | |
521 | throw new UserInputException('objectIDs'); | |
522 | } | |
ecc8c621 | 523 | } |
db864366 | 524 | |
ecc8c621 | 525 | // validate ownership |
c9ee8de8 | 526 | foreach ($this->getObjects() as $conversation) { |
ecc8c621 AE |
527 | if (!$conversation->isClosed || ($conversation->userID != WCF::getUser()->userID)) { |
528 | throw new PermissionDeniedException(); | |
529 | } | |
530 | } | |
531 | } | |
532 | ||
533 | /** | |
534 | * Opens conversations. | |
ba1ab5e5 | 535 | * |
03043c3c | 536 | * @return mixed[][] |
ecc8c621 AE |
537 | */ |
538 | public function open() { | |
c9ee8de8 | 539 | foreach ($this->getObjects() as $conversation) { |
76f12d13 | 540 | $conversation->update(['isClosed' => 0]); |
2e0bc870 | 541 | $this->addConversationData($conversation->getDecoratedObject(), 'isClosed', 0); |
953b3e7b | 542 | |
518ad17c | 543 | ConversationModificationLogHandler::getInstance()->open($conversation->getDecoratedObject()); |
ecc8c621 | 544 | } |
e8fe47c2 AE |
545 | |
546 | $this->unmarkItems(); | |
db864366 | 547 | |
ecc8c621 AE |
548 | return $this->getConversationData(); |
549 | } | |
550 | ||
50cd21a1 AE |
551 | /** |
552 | * Validates conversations for leave form. | |
6421362c MS |
553 | * |
554 | * @throws PermissionDeniedException | |
555 | * @throws UserInputException | |
50cd21a1 AE |
556 | */ |
557 | public function validateGetLeaveForm() { | |
2f5b4859 AE |
558 | if (empty($this->objectIDs)) { |
559 | throw new UserInputException('objectIDs'); | |
50cd21a1 AE |
560 | } |
561 | ||
562 | // validate participation | |
2f5b4859 | 563 | if (!Conversation::isParticipant($this->objectIDs)) { |
50cd21a1 AE |
564 | throw new PermissionDeniedException(); |
565 | } | |
566 | } | |
567 | ||
568 | /** | |
569 | * Returns dialog form to leave conversations. | |
570 | * | |
571 | * @return array | |
572 | */ | |
573 | public function getLeaveForm() { | |
574 | // get hidden state from first conversation (all others have the same state) | |
575 | $sql = "SELECT hideConversation | |
576 | FROM wcf".WCF_N."_conversation_to_user | |
577 | WHERE conversationID = ? | |
578 | AND participantID = ?"; | |
579 | $statement = WCF::getDB()->prepareStatement($sql); | |
76f12d13 | 580 | $statement->execute([ |
2f5b4859 | 581 | current($this->objectIDs), |
50cd21a1 | 582 | WCF::getUser()->userID |
76f12d13 | 583 | ]); |
50cd21a1 AE |
584 | $row = $statement->fetchArray(); |
585 | ||
227ecefb | 586 | WCF::getTPL()->assign('hideConversation', ($row !== false ? $row['hideConversation'] : 0)); |
50cd21a1 | 587 | |
76f12d13 | 588 | return [ |
50cd21a1 AE |
589 | 'actionName' => 'getLeaveForm', |
590 | 'template' => WCF::getTPL()->fetch('conversationLeave') | |
76f12d13 | 591 | ]; |
50cd21a1 AE |
592 | } |
593 | ||
594 | /** | |
595 | * Validates parameters to hide conversations. | |
6421362c MS |
596 | * |
597 | * @throws PermissionDeniedException | |
598 | * @throws UserInputException | |
50cd21a1 AE |
599 | */ |
600 | public function validateHideConversation() { | |
8a6ee075 | 601 | $this->parameters['hideConversation'] = isset($this->parameters['hideConversation']) ? intval($this->parameters['hideConversation']) : null; |
76f12d13 | 602 | if ($this->parameters['hideConversation'] === null || !in_array($this->parameters['hideConversation'], [Conversation::STATE_DEFAULT, Conversation::STATE_HIDDEN, Conversation::STATE_LEFT])) { |
50cd21a1 AE |
603 | throw new UserInputException('hideConversation'); |
604 | } | |
605 | ||
2f5b4859 AE |
606 | if (empty($this->objectIDs)) { |
607 | throw new UserInputException('objectIDs'); | |
50cd21a1 AE |
608 | } |
609 | ||
610 | // validate participation | |
2f5b4859 | 611 | if (!Conversation::isParticipant($this->objectIDs)) { |
50cd21a1 AE |
612 | throw new PermissionDeniedException(); |
613 | } | |
614 | } | |
615 | ||
616 | /** | |
617 | * Hides or restores conversations. | |
618 | * | |
76f12d13 | 619 | * @return string[] |
50cd21a1 AE |
620 | */ |
621 | public function hideConversation() { | |
622 | $sql = "UPDATE wcf".WCF_N."_conversation_to_user | |
623 | SET hideConversation = ? | |
624 | WHERE conversationID = ? | |
625 | AND participantID = ?"; | |
626 | $statement = WCF::getDB()->prepareStatement($sql); | |
627 | ||
628 | WCF::getDB()->beginTransaction(); | |
2f5b4859 | 629 | foreach ($this->objectIDs as $conversationID) { |
76f12d13 | 630 | $statement->execute([ |
50cd21a1 AE |
631 | $this->parameters['hideConversation'], |
632 | $conversationID, | |
633 | WCF::getUser()->userID | |
76f12d13 | 634 | ]); |
50cd21a1 AE |
635 | } |
636 | WCF::getDB()->commitTransaction(); | |
637 | ||
c26a69bc MS |
638 | // reset user's conversation counters if user leaves conversation |
639 | // permanently | |
a056f309 | 640 | if ($this->parameters['hideConversation'] == Conversation::STATE_LEFT) { |
76f12d13 MS |
641 | UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'conversationCount'); |
642 | UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'unreadConversationCount'); | |
8bbdb36d MS |
643 | } |
644 | ||
e829b862 MW |
645 | // add modification log entry |
646 | if ($this->parameters['hideConversation'] == Conversation::STATE_LEFT) { | |
647 | if (empty($this->objects)) $this->readObjects(); | |
648 | ||
c9ee8de8 | 649 | foreach ($this->getObjects() as $conversation) { |
e829b862 MW |
650 | ConversationModificationLogHandler::getInstance()->leave($conversation->getDecoratedObject()); |
651 | } | |
652 | } | |
653 | ||
02d63678 | 654 | // unmark items |
e8fe47c2 AE |
655 | $this->unmarkItems(); |
656 | ||
5d7f0df0 | 657 | if ($this->parameters['hideConversation'] == Conversation::STATE_LEFT) { |
0320065e MS |
658 | // update participants count and participant summary |
659 | ConversationEditor::updateParticipantCounts($this->objectIDs); | |
1920cd3d MW |
660 | ConversationEditor::updateParticipantSummaries($this->objectIDs); |
661 | ||
662 | // delete conversation if all users have left it | |
5d7f0df0 | 663 | $conditionBuilder = new PreparedStatementConditionBuilder(); |
76f12d13 | 664 | $conditionBuilder->add('conversation.conversationID IN (?)', [$this->objectIDs]); |
5d7f0df0 | 665 | $conditionBuilder->add('conversation_to_user.conversationID IS NULL'); |
5d7f0df0 MW |
666 | $sql = "SELECT DISTINCT conversation.conversationID |
667 | FROM wcf".WCF_N."_conversation conversation | |
668 | LEFT JOIN wcf".WCF_N."_conversation_to_user conversation_to_user | |
24f6c489 TD |
669 | ON ( conversation_to_user.conversationID = conversation.conversationID |
670 | AND conversation_to_user.hideConversation <> ".Conversation::STATE_LEFT." | |
671 | AND conversation_to_user.participantID IS NOT NULL) | |
5d7f0df0 MW |
672 | ".$conditionBuilder; |
673 | $statement = WCF::getDB()->prepareStatement($sql); | |
674 | $statement->execute($conditionBuilder->getParameters()); | |
c9d69e7c | 675 | $conversationIDs = $statement->fetchAll(\PDO::FETCH_COLUMN); |
0e86a288 | 676 | |
5d7f0df0 MW |
677 | if (!empty($conversationIDs)) { |
678 | $action = new ConversationAction($conversationIDs, 'delete'); | |
679 | $action->executeAction(); | |
680 | } | |
681 | } | |
682 | ||
76f12d13 | 683 | return [ |
b2e0a2ad AE |
684 | 'actionName' => 'hideConversation', |
685 | 'redirectURL' => LinkHandler::getInstance()->getLink('ConversationList') | |
76f12d13 | 686 | ]; |
50cd21a1 AE |
687 | } |
688 | ||
742b8736 | 689 | /** |
b17ff425 | 690 | * Validates parameters to return the mixed conversation list. |
742b8736 | 691 | */ |
b17ff425 | 692 | public function validateGetMixedConversationList() { |
a480521b MS |
693 | // does nothing |
694 | } | |
742b8736 AE |
695 | |
696 | /** | |
582481f3 | 697 | * Returns a mixed conversation list with up to 10 unread conversations. |
742b8736 | 698 | * |
03043c3c | 699 | * @return mixed[][] |
742b8736 | 700 | */ |
b17ff425 | 701 | public function getMixedConversationList() { |
df3404c7 MW |
702 | $sqlSelect = ' , (SELECT participantID FROM wcf'.WCF_N.'_conversation_to_user WHERE conversationID = conversation.conversationID AND participantID <> conversation.userID AND isInvisible = 0 ORDER BY username, participantID LIMIT 1) AS otherParticipantID |
703 | , (SELECT username FROM wcf'.WCF_N.'_conversation_to_user WHERE conversationID = conversation.conversationID AND participantID <> conversation.userID AND isInvisible = 0 ORDER BY username, participantID LIMIT 1) AS otherParticipant'; | |
704 | ||
b17ff425 | 705 | $unreadConversationList = new UserConversationList(WCF::getUser()->userID); |
df3404c7 | 706 | $unreadConversationList->sqlSelects .= $sqlSelect; |
219838a1 | 707 | $unreadConversationList->getConditionBuilder()->add('conversation_to_user.lastVisitTime < lastPostTime'); |
582481f3 | 708 | $unreadConversationList->sqlLimit = 10; |
219838a1 | 709 | $unreadConversationList->sqlOrderBy = 'lastPostTime DESC'; |
b17ff425 AE |
710 | $unreadConversationList->readObjects(); |
711 | ||
76f12d13 | 712 | $conversations = []; |
b17ff425 AE |
713 | $count = 0; |
714 | foreach ($unreadConversationList as $conversation) { | |
715 | $conversations[] = $conversation; | |
716 | $count++; | |
717 | } | |
718 | ||
582481f3 | 719 | if ($count < 10) { |
b17ff425 | 720 | $conversationList = new UserConversationList(WCF::getUser()->userID); |
df3404c7 | 721 | $conversationList->sqlSelects .= $sqlSelect; |
219838a1 | 722 | $conversationList->getConditionBuilder()->add('conversation_to_user.lastVisitTime >= lastPostTime'); |
582481f3 | 723 | $conversationList->sqlLimit = (10 - $count); |
219838a1 | 724 | $conversationList->sqlOrderBy = 'lastPostTime DESC'; |
b17ff425 AE |
725 | $conversationList->readObjects(); |
726 | ||
727 | foreach ($conversationList as $conversation) { | |
728 | $conversations[] = $conversation; | |
729 | } | |
730 | } | |
742b8736 | 731 | |
76f12d13 | 732 | WCF::getTPL()->assign([ |
b17ff425 | 733 | 'conversations' => $conversations |
76f12d13 | 734 | ]); |
742b8736 | 735 | |
acd16520 | 736 | $totalCount = ConversationHandler::getInstance()->getUnreadConversationCount(); |
582481f3 | 737 | if ($count < 10 && $count < $totalCount) { |
76f12d13 | 738 | UserStorageHandler::getInstance()->reset([WCF::getUser()->userID], 'unreadConversationCount'); |
acd16520 AE |
739 | } |
740 | ||
76f12d13 | 741 | return [ |
c61f0f25 | 742 | 'template' => WCF::getTPL()->fetch('conversationListUserPanel'), |
acd16520 | 743 | 'totalCount' => $totalCount |
76f12d13 | 744 | ]; |
742b8736 AE |
745 | } |
746 | ||
0035c8ea | 747 | /** |
a480521b | 748 | * Validates the 'unmarkAll' action. |
0035c8ea | 749 | */ |
a480521b MS |
750 | public function validateUnmarkAll() { |
751 | // does nothing | |
752 | } | |
0035c8ea AE |
753 | |
754 | /** | |
755 | * Unmarks all conversations. | |
756 | */ | |
757 | public function unmarkAll() { | |
758 | ClipboardHandler::getInstance()->removeItems(ClipboardHandler::getInstance()->getObjectTypeID('com.woltlab.wcf.conversation.conversation')); | |
759 | } | |
760 | ||
65b37bf6 AE |
761 | /** |
762 | * Validates parameters to display the 'add participants' form. | |
6421362c MS |
763 | * |
764 | * @throws PermissionDeniedException | |
65b37bf6 AE |
765 | */ |
766 | public function validateGetAddParticipantsForm() { | |
767 | $this->conversation = $this->getSingleObject(); | |
76f12d13 | 768 | if (!Conversation::isParticipant([$this->conversation->conversationID]) || !$this->conversation->canAddParticipants()) { |
65b37bf6 AE |
769 | throw new PermissionDeniedException(); |
770 | } | |
771 | } | |
772 | ||
773 | /** | |
774 | * Shows the 'add participants' form. | |
775 | * | |
776 | * @return array | |
777 | */ | |
778 | public function getAddParticipantsForm() { | |
76f12d13 | 779 | return [ |
368540c1 AE |
780 | 'excludedSearchValues' => $this->conversation->getParticipantNames(), |
781 | 'maxItems' => WCF::getSession()->getPermission('user.conversation.maxParticipants') - $this->conversation->participants, | |
219838a1 | 782 | 'template' => WCF::getTPL()->fetch('conversationAddParticipants', 'wcf', ['conversation' => $this->conversation]) |
76f12d13 | 783 | ]; |
65b37bf6 AE |
784 | } |
785 | ||
786 | /** | |
787 | * Validates parameters to add new participants. | |
788 | */ | |
789 | public function validateAddParticipants() { | |
790 | $this->validateGetAddParticipantsForm(); | |
791 | ||
792 | // validate participants | |
368540c1 | 793 | $this->readStringArray('participants'); |
219838a1 AE |
794 | |
795 | if (!$this->conversation->getDecoratedObject()->isDraft) { | |
796 | $this->readString('visibility'); | |
797 | if (!in_array($this->parameters['visibility'], ['all', 'new'])) { | |
798 | throw new UserInputException('visibility'); | |
799 | } | |
2c9c3c30 AE |
800 | |
801 | if ($this->parameters['visibility'] === 'all' && !$this->conversation->canAddParticipantsUnrestricted()) { | |
802 | throw new UserInputException('visibility'); | |
803 | } | |
219838a1 | 804 | } |
65b37bf6 AE |
805 | } |
806 | ||
807 | /** | |
808 | * Adds new participants. | |
809 | * | |
810 | * @return array | |
811 | */ | |
812 | public function addParticipants() { | |
094ca1e9 | 813 | try { |
b5b88a93 | 814 | $participantIDs = Conversation::validateParticipants($this->parameters['participants'], 'participants', $this->conversation->getParticipantIDs(true)); |
094ca1e9 AE |
815 | } |
816 | catch (UserInputException $e) { | |
817 | $errorMessage = ''; | |
818 | foreach ($e->getType() as $type) { | |
0bca0d8c | 819 | if (!empty($errorMessage)) $errorMessage .= ' '; |
76f12d13 | 820 | $errorMessage .= WCF::getLanguage()->getDynamicVariable('wcf.conversation.participants.error.'.$type['type'], ['errorData' => ['username' => $type['username']]]); |
094ca1e9 AE |
821 | } |
822 | ||
76f12d13 | 823 | return [ |
094ca1e9 AE |
824 | 'actionName' => 'addParticipants', |
825 | 'errorMessage' => $errorMessage | |
76f12d13 | 826 | ]; |
094ca1e9 AE |
827 | } |
828 | ||
ee3847e4 AE |
829 | // validate limit |
830 | $newCount = $this->conversation->participants + count($participantIDs); | |
831 | if ($newCount > WCF::getSession()->getPermission('user.conversation.maxParticipants')) { | |
76f12d13 | 832 | return [ |
ee3847e4 | 833 | 'actionName' => 'addParticipants', |
3846d50e | 834 | 'errorMessage' => WCF::getLanguage()->getDynamicVariable('wcf.conversation.participants.error.tooManyParticipants') |
76f12d13 | 835 | ]; |
ee3847e4 AE |
836 | } |
837 | ||
65b37bf6 AE |
838 | $count = 0; |
839 | $successMessage = ''; | |
65b37bf6 AE |
840 | if (!empty($participantIDs)) { |
841 | // check for already added participants | |
b5b88a93 MW |
842 | if ($this->conversation->isDraft) { |
843 | $draftData = unserialize($this->conversation->draftData); | |
844 | $draftData['participants'] = array_merge($draftData['participants'], $participantIDs); | |
76f12d13 | 845 | $data = ['data' => ['draftData' => serialize($draftData)]]; |
b5b88a93 MW |
846 | } |
847 | else { | |
219838a1 AE |
848 | $data = [ |
849 | 'participants' => $participantIDs, | |
850 | 'visibility' => (isset($this->parameters['visibility'])) ? $this->parameters['visibility'] : 'all' | |
851 | ]; | |
b5b88a93 MW |
852 | } |
853 | ||
76f12d13 | 854 | $conversationAction = new ConversationAction([$this->conversation], 'update', $data); |
b5b88a93 MW |
855 | $conversationAction->executeAction(); |
856 | ||
857 | $count = count($participantIDs); | |
76f12d13 | 858 | $successMessage = WCF::getLanguage()->getDynamicVariable('wcf.conversation.edit.addParticipants.success', ['count' => $count]); |
b5b88a93 MW |
859 | |
860 | ConversationModificationLogHandler::getInstance()->addParticipants($this->conversation->getDecoratedObject(), $participantIDs); | |
861 | ||
862 | if (!$this->conversation->isDraft) { | |
863 | // update participant summary | |
864 | $this->conversation->updateParticipantSummary(); | |
65b37bf6 AE |
865 | } |
866 | } | |
867 | ||
76f12d13 | 868 | return [ |
65b37bf6 AE |
869 | 'count' => $count, |
870 | 'successMessage' => $successMessage | |
76f12d13 | 871 | ]; |
65b37bf6 AE |
872 | } |
873 | ||
a208d1f4 AE |
874 | /** |
875 | * Validates parameters to remove a participant from a conversation. | |
6421362c MS |
876 | * |
877 | * @throws PermissionDeniedException | |
878 | * @throws UserInputException | |
a208d1f4 AE |
879 | */ |
880 | public function validateRemoveParticipant() { | |
881 | $this->readInteger('userID'); | |
882 | ||
883 | // validate conversation | |
884 | $this->conversation = $this->getSingleObject(); | |
885 | if (!$this->conversation->conversationID) { | |
886 | throw new UserInputException('objectIDs'); | |
887 | } | |
888 | ||
889 | // check ownership | |
890 | if ($this->conversation->userID != WCF::getUser()->userID) { | |
891 | throw new PermissionDeniedException(); | |
892 | } | |
893 | ||
894 | // validate participants | |
76f12d13 | 895 | if ($this->parameters['userID'] == WCF::getUser()->userID || !Conversation::isParticipant([$this->conversation->conversationID]) || !Conversation::isParticipant([$this->conversation->conversationID], $this->parameters['userID'])) { |
a208d1f4 AE |
896 | throw new PermissionDeniedException(); |
897 | } | |
898 | ||
899 | } | |
900 | ||
901 | /** | |
902 | * Removes a participant from a conversation. | |
903 | */ | |
904 | public function removeParticipant() { | |
905 | $this->conversation->removeParticipant($this->parameters['userID']); | |
906 | $this->conversation->updateParticipantSummary(); | |
907 | ||
908 | ConversationModificationLogHandler::getInstance()->removeParticipant($this->conversation->getDecoratedObject(), $this->parameters['userID']); | |
909 | ||
92e66692 | 910 | // reset storage |
76f12d13 | 911 | UserStorageHandler::getInstance()->reset([$this->parameters['userID']], 'unreadConversationCount'); |
92e66692 | 912 | |
76f12d13 | 913 | return [ |
a208d1f4 | 914 | 'userID' => $this->parameters['userID'] |
76f12d13 | 915 | ]; |
a208d1f4 AE |
916 | } |
917 | ||
3b34d39f MS |
918 | /** |
919 | * Rebuilds the conversation data of the relevant conversations. | |
920 | */ | |
921 | public function rebuild() { | |
922 | if (empty($this->objects)) { | |
923 | $this->readObjects(); | |
924 | } | |
925 | ||
926 | // collect number of messages for each conversation | |
927 | $conditionBuilder = new PreparedStatementConditionBuilder(); | |
76f12d13 | 928 | $conditionBuilder->add('conversation_message.conversationID IN (?)', [$this->objectIDs]); |
487b839f | 929 | $sql = "SELECT conversationID, COUNT(messageID) AS messages, SUM(attachments) AS attachments |
3b34d39f MS |
930 | FROM wcf".WCF_N."_conversation_message conversation_message |
931 | ".$conditionBuilder." | |
932 | GROUP BY conversationID"; | |
933 | $statement = WCF::getDB()->prepareStatement($sql); | |
934 | $statement->execute($conditionBuilder->getParameters()); | |
935 | ||
76f12d13 | 936 | $objectIDs = []; |
8a6ee075 | 937 | while ($row = $statement->fetchArray()) { |
3b34d39f MS |
938 | if (!$row['messages']) { |
939 | continue; | |
940 | } | |
941 | $objectIDs[] = $row['conversationID']; | |
942 | ||
76f12d13 | 943 | $conversationEditor = new ConversationEditor(new Conversation(null, [ |
3b34d39f | 944 | 'conversationID' => $row['conversationID'] |
76f12d13 MS |
945 | ])); |
946 | $conversationEditor->update([ | |
487b839f | 947 | 'attachments' => $row['attachments'], |
3b34d39f | 948 | 'replies' => $row['messages'] - 1 |
76f12d13 | 949 | ]); |
3b34d39f MS |
950 | $conversationEditor->updateFirstMessage(); |
951 | $conversationEditor->updateLastMessage(); | |
952 | } | |
953 | ||
954 | // delete conversations without messages | |
955 | $deleteConversationIDs = array_diff($this->objectIDs, $objectIDs); | |
956 | if (!empty($deleteConversationIDs)) { | |
957 | $conversationAction = new ConversationAction($deleteConversationIDs, 'delete'); | |
958 | $conversationAction->executeAction(); | |
959 | } | |
960 | } | |
961 | ||
4251df82 AE |
962 | /** |
963 | * Validates the parameters to edit a conversation's subject. | |
964 | * | |
965 | * @throws PermissionDeniedException | |
966 | */ | |
967 | public function validateEditSubject() { | |
968 | $this->readString('subject'); | |
969 | ||
970 | $this->conversation = $this->getSingleObject(); | |
971 | if ($this->conversation->userID != WCF::getUser()->userID) { | |
972 | throw new PermissionDeniedException(); | |
973 | } | |
974 | } | |
975 | ||
976 | /** | |
977 | * Edits a conversation's subject. | |
978 | * | |
979 | * @return string[] | |
980 | */ | |
981 | public function editSubject() { | |
87de5988 TD |
982 | $subject = mb_substr($this->parameters['subject'], 0, 255); |
983 | ||
0f11e888 | 984 | $this->conversation->update([ |
87de5988 | 985 | 'subject' => $subject |
0f11e888 | 986 | ]); |
4251df82 | 987 | |
87de5988 TD |
988 | $message = $this->conversation->getFirstMessage(); |
989 | ||
990 | SearchIndexManager::getInstance()->set( | |
991 | 'com.woltlab.wcf.conversation.message', | |
992 | $message->messageID, | |
993 | $message->message, | |
994 | $subject, | |
995 | $message->time, | |
996 | $message->userID, | |
997 | $message->username | |
998 | ); | |
999 | ||
4251df82 | 1000 | return [ |
87de5988 | 1001 | 'subject' => $subject |
4251df82 AE |
1002 | ]; |
1003 | } | |
1004 | ||
ecc8c621 AE |
1005 | /** |
1006 | * Adds conversation modification data. | |
1007 | * | |
76f12d13 MS |
1008 | * @param Conversation $conversation |
1009 | * @param string $key | |
1010 | * @param mixed $value | |
ecc8c621 AE |
1011 | */ |
1012 | protected function addConversationData(Conversation $conversation, $key, $value) { | |
1013 | if (!isset($this->conversationData[$conversation->conversationID])) { | |
76f12d13 | 1014 | $this->conversationData[$conversation->conversationID] = []; |
ecc8c621 AE |
1015 | } |
1016 | ||
1017 | $this->conversationData[$conversation->conversationID][$key] = $value; | |
1018 | } | |
1019 | ||
1020 | /** | |
db864366 MS |
1021 | * Returns conversation data. |
1022 | * | |
03043c3c | 1023 | * @return mixed[][] |
ecc8c621 AE |
1024 | */ |
1025 | protected function getConversationData() { | |
76f12d13 | 1026 | return [ |
ecc8c621 | 1027 | 'conversationData' => $this->conversationData |
76f12d13 | 1028 | ]; |
ecc8c621 | 1029 | } |
e8fe47c2 AE |
1030 | |
1031 | /** | |
1032 | * Unmarks conversations. | |
1033 | * | |
76f12d13 | 1034 | * @param integer[] $conversationIDs |
e8fe47c2 | 1035 | */ |
76f12d13 | 1036 | protected function unmarkItems(array $conversationIDs = []) { |
e8fe47c2 AE |
1037 | if (empty($conversationIDs)) { |
1038 | $conversationIDs = $this->objectIDs; | |
1039 | } | |
1040 | ||
1041 | ClipboardHandler::getInstance()->unmark($conversationIDs, ClipboardHandler::getInstance()->getObjectTypeID('com.woltlab.wcf.conversation.conversation')); | |
1042 | } | |
9544b6b4 | 1043 | } |