In-Profile moderation feature for cover photos
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / data / user / UserAction.class.php
1 <?php
2 namespace wcf\data\user;
3 use wcf\data\object\type\ObjectTypeCache;
4 use wcf\data\user\avatar\UserAvatarAction;
5 use wcf\data\user\group\UserGroup;
6 use wcf\data\AbstractDatabaseObjectAction;
7 use wcf\data\IClipboardAction;
8 use wcf\data\ISearchAction;
9 use wcf\system\attachment\AttachmentHandler;
10 use wcf\system\clipboard\ClipboardHandler;
11 use wcf\system\comment\CommentHandler;
12 use wcf\system\database\util\PreparedStatementConditionBuilder;
13 use wcf\system\email\mime\MimePartFacade;
14 use wcf\system\email\mime\RecipientAwareTextMimePart;
15 use wcf\system\email\Email;
16 use wcf\system\email\UserMailbox;
17 use wcf\system\event\EventHandler;
18 use wcf\system\exception\IllegalLinkException;
19 use wcf\system\exception\PermissionDeniedException;
20 use wcf\system\exception\UserInputException;
21 use wcf\system\request\RequestHandler;
22 use wcf\system\WCF;
23 use wcf\util\UserRegistrationUtil;
24
25 /**
26 * Executes user-related actions.
27 *
28 * @author Alexander Ebert
29 * @copyright 2001-2018 WoltLab GmbH
30 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
31 * @package WoltLabSuite\Core\Data\User
32 *
33 * @method UserEditor[] getObjects()
34 * @method UserEditor getSingleObject()
35 */
36 class UserAction extends AbstractDatabaseObjectAction implements IClipboardAction, ISearchAction {
37 /**
38 * @inheritDoc
39 */
40 public $className = UserEditor::class;
41
42 /**
43 * @inheritDoc
44 */
45 protected $allowGuestAccess = ['getSearchResultList'];
46
47 /**
48 * @inheritDoc
49 */
50 protected $permissionsCreate = ['admin.user.canAddUser'];
51
52 /**
53 * @inheritDoc
54 */
55 protected $permissionsDelete = ['admin.user.canDeleteUser'];
56
57 /**
58 * @inheritDoc
59 */
60 protected $permissionsUpdate = ['admin.user.canEditUser'];
61
62 /**
63 * @inheritDoc
64 */
65 protected $requireACP = ['create', 'delete', 'resendActivationMail'];
66
67 /**
68 * Validates permissions and parameters.
69 */
70 public function validateCreate() {
71 $this->readString('password', false, 'data');
72 }
73
74 /**
75 * Validates accessible groups.
76 *
77 * @param boolean $ignoreOwnUser
78 * @throws PermissionDeniedException
79 * @throws UserInputException
80 */
81 protected function __validateAccessibleGroups($ignoreOwnUser = true) {
82 if ($ignoreOwnUser) {
83 if (in_array(WCF::getUser()->userID, $this->objectIDs)) {
84 unset($this->objectIDs[array_search(WCF::getUser()->userID, $this->objectIDs)]);
85 if (isset($this->objects[WCF::getUser()->userID])) {
86 unset($this->objects[WCF::getUser()->userID]);
87 }
88 }
89 }
90
91 // list might be empty because only our own user id was given
92 if (empty($this->objectIDs)) {
93 throw new UserInputException('objectIDs');
94 }
95
96 // validate groups
97 $conditions = new PreparedStatementConditionBuilder();
98 $conditions->add("userID IN (?)", [$this->objectIDs]);
99
100 $sql = "SELECT DISTINCT groupID
101 FROM wcf".WCF_N."_user_to_group
102 ".$conditions;
103 $statement = WCF::getDB()->prepareStatement($sql);
104 $statement->execute($conditions->getParameters());
105 $groupIDs = $statement->fetchAll(\PDO::FETCH_COLUMN);
106
107 if (!UserGroup::isAccessibleGroup($groupIDs)) {
108 throw new PermissionDeniedException();
109 }
110 }
111
112 /**
113 * Validates permissions and parameters.
114 */
115 public function validateDelete() {
116 // read and validate user objects
117 parent::validateDelete();
118
119 $this->__validateAccessibleGroups();
120 }
121
122 /**
123 * @inheritDoc
124 */
125 public function delete() {
126 if (empty($this->objects)) {
127 $this->readObjects();
128 }
129
130 // delete avatars
131 $avatarIDs = [];
132 foreach ($this->getObjects() as $user) {
133 if ($user->avatarID) $avatarIDs[] = $user->avatarID;
134 }
135 if (!empty($avatarIDs)) {
136 $action = new UserAvatarAction($avatarIDs, 'delete');
137 $action->executeAction();
138 }
139
140 // delete profile comments and signature attachments
141 if (!empty($this->objectIDs)) {
142 CommentHandler::getInstance()->deleteObjects('com.woltlab.wcf.user.profileComment', $this->objectIDs);
143 AttachmentHandler::removeAttachments('com.woltlab.wcf.user.signature', $this->objectIDs);
144 }
145
146 return parent::delete();
147 }
148
149 /**
150 * Validates permissions and parameters.
151 */
152 public function validateUpdate() {
153 // read objects
154 if (empty($this->objects)) {
155 $this->readObjects();
156
157 if (empty($this->objects)) {
158 throw new UserInputException('objectIDs');
159 }
160 }
161
162 // disallow updating of anything except for options outside of ACP
163 if (RequestHandler::getInstance()->isACPRequest() && (count($this->parameters) != 1 || !isset($this->parameters['options']))) {
164 throw new PermissionDeniedException();
165 }
166
167 try {
168 WCF::getSession()->checkPermissions($this->permissionsUpdate);
169 }
170 catch (PermissionDeniedException $e) {
171 // check if we're editing ourselves
172 if (count($this->objects) == 1 && ($this->objects[0]->userID == WCF::getUser()->userID)) {
173 $count = count($this->parameters);
174 if ($count > 1 || ($count == 1 && !isset($this->parameters['options']))) {
175 throw new PermissionDeniedException();
176 }
177 }
178 else {
179 throw new PermissionDeniedException();
180 }
181 }
182 }
183
184 /**
185 * Validates the ban action.
186 */
187 public function validateBan() {
188 $this->validateUnban();
189
190 $this->readString('banReason', true);
191 $this->readString('banExpires', true);
192 }
193
194 /**
195 * Validates the unban action.
196 */
197 public function validateUnban() {
198 WCF::getSession()->checkPermissions(['admin.user.canBanUser']);
199
200 $this->__validateAccessibleGroups();
201 }
202
203 /**
204 * Bans users.
205 */
206 public function ban() {
207 $banExpires = $this->parameters['banExpires'];
208 if ($banExpires) {
209 $banExpires = strtotime($banExpires);
210 if ($banExpires > 2147483647) $banExpires = 2147483647;
211 }
212 else {
213 $banExpires = 0;
214 }
215
216 $conditionBuilder = new PreparedStatementConditionBuilder();
217 $conditionBuilder->add('userID IN (?)', [$this->objectIDs]);
218
219 $sql = "UPDATE wcf".WCF_N."_user
220 SET banned = ?,
221 banReason = ?,
222 banExpires = ?
223 ".$conditionBuilder;
224 $statement = WCF::getDB()->prepareStatement($sql);
225 $statement->execute(
226 array_merge([
227 1,
228 $this->parameters['banReason'],
229 $banExpires
230 ], $conditionBuilder->getParameters())
231 );
232
233 $this->unmarkItems();
234
235 $firstUser = new User(reset($this->objectIDs));
236 return WCF::getLanguage()->getDynamicVariable('wcf.user.banned', ['user' => $firstUser]);
237 }
238
239 /**
240 * Unbans users.
241 */
242 public function unban() {
243 $conditionBuilder = new PreparedStatementConditionBuilder();
244 $conditionBuilder->add('userID IN (?)', [$this->objectIDs]);
245
246 $sql = "UPDATE wcf".WCF_N."_user
247 SET banned = ?,
248 banExpires = ?
249 ".$conditionBuilder;
250 $statement = WCF::getDB()->prepareStatement($sql);
251 $statement->execute(
252 array_merge([
253 0,
254 0
255 ], $conditionBuilder->getParameters())
256 );
257 }
258
259 /**
260 * @inheritDoc
261 * @return User
262 */
263 public function create() {
264 /** @var User $user */
265 $user = parent::create();
266 $userEditor = new UserEditor($user);
267
268 // updates user options
269 if (isset($this->parameters['options'])) {
270 $userEditor->updateUserOptions($this->parameters['options']);
271 }
272
273 // insert user groups
274 $addDefaultGroups = isset($this->parameters['addDefaultGroups']) ? $this->parameters['addDefaultGroups'] : true;
275 $groupIDs = isset($this->parameters['groups']) ? $this->parameters['groups'] : [];
276 $userEditor->addToGroups($groupIDs, false, $addDefaultGroups);
277
278 // insert visible languages
279 if (!isset($this->parameters['languageIDs'])) {
280 // using the 'languages' key is deprecated since WCF 2.1, please use 'languageIDs' instead
281 $this->parameters['languageIDs'] = (!empty($this->parameters['languages'])) ? $this->parameters['languages'] : [];
282 }
283 $userEditor->addToLanguages($this->parameters['languageIDs'], false);
284
285 if (PACKAGE_ID) {
286 // set default notifications
287 $sql = "INSERT INTO wcf".WCF_N."_user_notification_event_to_user
288 (userID, eventID, mailNotificationType)
289 SELECT ?, eventID, presetMailNotificationType
290 FROM wcf".WCF_N."_user_notification_event
291 WHERE preset = ?";
292 $statement = WCF::getDB()->prepareStatement($sql);
293 $statement->execute([$user->userID, 1]);
294
295 // update user rank
296 if (MODULE_USER_RANK) {
297 $action = new UserProfileAction([$userEditor], 'updateUserRank');
298 $action->executeAction();
299 }
300 // update user online marking
301 $action = new UserProfileAction([$userEditor], 'updateUserOnlineMarking');
302 $action->executeAction();
303 }
304
305 return $user;
306 }
307
308 /**
309 * @inheritDoc
310 */
311 public function update() {
312 if (isset($this->parameters['data']) || isset($this->parameters['counters'])) {
313 parent::update();
314
315 if (isset($this->parameters['data']['languageID'])) {
316 foreach ($this->getObjects() as $object) {
317 if ($object->userID == WCF::getUser()->userID) {
318 if ($this->parameters['data']['languageID'] != WCF::getUser()->languageID) {
319 WCF::setLanguage($this->parameters['data']['languageID']);
320 }
321
322 break;
323 }
324 }
325 }
326 }
327 else {
328 if (empty($this->objects)) {
329 $this->readObjects();
330 }
331 }
332
333 $groupIDs = isset($this->parameters['groups']) ? $this->parameters['groups'] : [];
334 $languageIDs = isset($this->parameters['languageIDs']) ? $this->parameters['languageIDs'] : [];
335 $removeGroups = isset($this->parameters['removeGroups']) ? $this->parameters['removeGroups'] : [];
336 $userOptions = isset($this->parameters['options']) ? $this->parameters['options'] : [];
337
338 if (!empty($groupIDs)) {
339 $action = new UserAction($this->objects, 'addToGroups', [
340 'groups' => $groupIDs,
341 'addDefaultGroups' => false
342 ]);
343 $action->executeAction();
344 }
345
346 if (!empty($removeGroups)) {
347 $action = new UserAction($this->objects, 'removeFromGroups', [
348 'groups' => $removeGroups
349 ]);
350 $action->executeAction();
351 }
352
353 foreach ($this->getObjects() as $userEditor) {
354 if (!empty($userOptions)) {
355 $userEditor->updateUserOptions($userOptions);
356 }
357
358 if (!empty($languageIDs)) {
359 $userEditor->addToLanguages($languageIDs);
360 }
361 }
362
363 // handle user rename
364 if (count($this->objects) == 1 && !empty($this->parameters['data']['username'])) {
365 if ($this->objects[0]->username != $this->parameters['data']['username']) {
366 $userID = $this->objects[0]->userID;
367 $username = $this->parameters['data']['username'];
368
369 WCF::getDB()->beginTransaction();
370
371 // update article
372 $sql = "UPDATE wcf".WCF_N."_article
373 SET username = ?
374 WHERE userID = ?";
375 $statement = WCF::getDB()->prepareStatement($sql);
376 $statement->execute([$username, $userID]);
377
378 // update comments
379 $sql = "UPDATE wcf".WCF_N."_comment
380 SET username = ?
381 WHERE userID = ?";
382 $statement = WCF::getDB()->prepareStatement($sql);
383 $statement->execute([$username, $userID]);
384
385 // update comment responses
386 $sql = "UPDATE wcf".WCF_N."_comment_response
387 SET username = ?
388 WHERE userID = ?";
389 $statement = WCF::getDB()->prepareStatement($sql);
390 $statement->execute([$username, $userID]);
391
392 // update media
393 $sql = "UPDATE wcf".WCF_N."_media
394 SET username = ?
395 WHERE userID = ?";
396 $statement = WCF::getDB()->prepareStatement($sql);
397 $statement->execute([$username, $userID]);
398
399 // update modification log
400 $sql = "UPDATE wcf".WCF_N."_modification_log
401 SET username = ?
402 WHERE userID = ?";
403 $statement = WCF::getDB()->prepareStatement($sql);
404 $statement->execute([$username, $userID]);
405
406 WCF::getDB()->commitTransaction();
407
408 // fire event to handle other database tables
409 EventHandler::getInstance()->fireAction($this, 'rename');
410 }
411 }
412 }
413
414 /**
415 * Remove users from given groups.
416 */
417 public function removeFromGroups() {
418 if (empty($this->objects)) {
419 $this->readObjects();
420 }
421
422 $groupIDs = $this->parameters['groups'];
423
424 foreach ($this->getObjects() as $userEditor) {
425 $userEditor->removeFromGroups($groupIDs);
426 }
427
428 //reread objects
429 $this->objects = [];
430 UserEditor::resetCache();
431 $this->readObjects();
432
433 if (MODULE_USER_RANK) {
434 $action = new UserProfileAction($this->objects, 'updateUserRank');
435 $action->executeAction();
436 }
437 if (MODULE_USERS_ONLINE) {
438 $action = new UserProfileAction($this->objects, 'updateUserOnlineMarking');
439 $action->executeAction();
440 }
441 }
442
443 /**
444 * Add users to given groups.
445 */
446 public function addToGroups() {
447 if (empty($this->objects)) {
448 $this->readObjects();
449 }
450
451 $groupIDs = $this->parameters['groups'];
452 $deleteOldGroups = $addDefaultGroups = true;
453 if (isset($this->parameters['deleteOldGroups'])) $deleteOldGroups = $this->parameters['deleteOldGroups'];
454 if (isset($this->parameters['addDefaultGroups'])) $addDefaultGroups = $this->parameters['addDefaultGroups'];
455
456 foreach ($this->getObjects() as $userEditor) {
457 $userEditor->addToGroups($groupIDs, $deleteOldGroups, $addDefaultGroups);
458 }
459
460 //reread objects
461 $this->objects = [];
462 UserEditor::resetCache();
463 $this->readObjects();
464
465 if (MODULE_USER_RANK) {
466 $action = new UserProfileAction($this->objects, 'updateUserRank');
467 $action->executeAction();
468 }
469 if (MODULE_USERS_ONLINE) {
470 $action = new UserProfileAction($this->objects, 'updateUserOnlineMarking');
471 $action->executeAction();
472 }
473 }
474
475 /**
476 * @inheritDoc
477 */
478 public function validateGetSearchResultList() {
479 $this->readBoolean('includeUserGroups', false, 'data');
480 $this->readString('searchString', false, 'data');
481
482 if (isset($this->parameters['data']['excludedSearchValues']) && !is_array($this->parameters['data']['excludedSearchValues'])) {
483 throw new UserInputException('excludedSearchValues');
484 }
485 }
486
487 /**
488 * @inheritDoc
489 */
490 public function getSearchResultList() {
491 $searchString = $this->parameters['data']['searchString'];
492 $excludedSearchValues = [];
493 if (isset($this->parameters['data']['excludedSearchValues'])) {
494 $excludedSearchValues = $this->parameters['data']['excludedSearchValues'];
495 }
496 $list = [];
497
498 if ($this->parameters['data']['includeUserGroups']) {
499 $accessibleGroups = UserGroup::getAccessibleGroups();
500 foreach ($accessibleGroups as $group) {
501 $groupName = $group->getName();
502 if (!in_array($groupName, $excludedSearchValues)) {
503 $pos = mb_strripos($groupName, $searchString);
504 if ($pos !== false && $pos == 0) {
505 $list[] = [
506 'label' => $groupName,
507 'objectID' => $group->groupID,
508 'type' => 'group'
509 ];
510 }
511 }
512 }
513 }
514
515 // find users
516 $searchString = addcslashes($searchString, '_%');
517 $parameters = [
518 'searchString' => $searchString
519 ];
520 EventHandler::getInstance()->fireAction($this, 'beforeFindUsers', $parameters);
521 $userProfileList = new UserProfileList();
522 $userProfileList->getConditionBuilder()->add("username LIKE ?", [$parameters['searchString'].'%']);
523 if (!empty($excludedSearchValues)) {
524 $userProfileList->getConditionBuilder()->add("username NOT IN (?)", [$excludedSearchValues]);
525 }
526 $userProfileList->sqlLimit = 10;
527 $userProfileList->readObjects();
528
529 foreach ($userProfileList as $userProfile) {
530 $list[] = [
531 'icon' => $userProfile->getAvatar()->getImageTag(16),
532 'label' => $userProfile->username,
533 'objectID' => $userProfile->userID,
534 'type' => 'user'
535 ];
536 }
537
538 return $list;
539 }
540
541 /**
542 * @inheritDoc
543 */
544 public function validateUnmarkAll() {
545 // does nothing
546 }
547
548 /**
549 * @inheritDoc
550 */
551 public function unmarkAll() {
552 ClipboardHandler::getInstance()->removeItems(ClipboardHandler::getInstance()->getObjectTypeID('com.woltlab.wcf.user'));
553 }
554
555 /**
556 * Unmarks users.
557 *
558 * @param integer[] $userIDs
559 */
560 protected function unmarkItems(array $userIDs = []) {
561 if (empty($userIDs)) {
562 $userIDs = $this->objectIDs;
563 }
564
565 if (!empty($userIDs)) {
566 ClipboardHandler::getInstance()->unmark($userIDs, ClipboardHandler::getInstance()->getObjectTypeID('com.woltlab.wcf.user'));
567 }
568 }
569
570 /**
571 * Validates the enable action.
572 */
573 public function validateEnable() {
574 WCF::getSession()->checkPermissions(['admin.user.canEnableUser']);
575
576 $this->__validateAccessibleGroups();
577 }
578
579 /**
580 * Validates the disable action.
581 */
582 public function validateDisable() {
583 $this->validateEnable();
584 }
585
586 /**
587 * Enables users.
588 */
589 public function enable() {
590 if (empty($this->objects)) $this->readObjects();
591
592 $action = new UserAction($this->objects, 'update', [
593 'data' => [
594 'activationCode' => 0
595 ],
596 'removeGroups' => UserGroup::getGroupIDsByType([UserGroup::GUESTS])
597 ]);
598 $action->executeAction();
599 $action = new UserAction($this->objects, 'addToGroups', [
600 'groups' => UserGroup::getGroupIDsByType([UserGroup::USERS]),
601 'deleteOldGroups' => false,
602 'addDefaultGroups' => false
603 ]);
604 $action->executeAction();
605
606 // send e-mail notification
607 if (empty($this->parameters['skipNotification'])) {
608 foreach ($this->getObjects() as $user) {
609 $email = new Email();
610 $email->addRecipient(new UserMailbox($user->getDecoratedObject()));
611 $email->setSubject($user->getLanguage()->getDynamicVariable('wcf.acp.user.activation.mail.subject'));
612 $email->setBody(new MimePartFacade([
613 new RecipientAwareTextMimePart('text/html', 'email_adminActivation'),
614 new RecipientAwareTextMimePart('text/plain', 'email_adminActivation')
615 ]));
616 $email->send();
617 }
618 }
619
620 $this->unmarkItems();
621 }
622
623 /**
624 * Disables users.
625 */
626 public function disable() {
627 if (empty($this->objects)) $this->readObjects();
628
629 $action = new UserAction($this->objects, 'update', [
630 'data' => [
631 'activationCode' => UserRegistrationUtil::getActivationCode()
632 ],
633 'removeGroups' => UserGroup::getGroupIDsByType([UserGroup::USERS])
634 ]);
635 $action->executeAction();
636 $action = new UserAction($this->objects, 'addToGroups', [
637 'groups' => UserGroup::getGroupIDsByType([UserGroup::GUESTS]),
638 'deleteOldGroups' => false,
639 'addDefaultGroups' => false
640 ]);
641 $action->executeAction();
642
643 $this->unmarkItems();
644 }
645
646 /**
647 * @inheritDoc
648 */
649 protected function readObjects() {
650 if (empty($this->objectIDs)) {
651 return;
652 }
653
654 // get base class
655 $baseClass = call_user_func([$this->className, 'getBaseClass']);
656
657 // get objects
658 $sql = "SELECT user_option_value.*, user_table.*
659 FROM wcf".WCF_N."_user user_table
660 LEFT JOIN wcf".WCF_N."_user_option_value user_option_value
661 ON (user_option_value.userID = user_table.userID)
662 WHERE user_table.userID IN (".str_repeat('?,', count($this->objectIDs) - 1)."?)";
663 $statement = WCF::getDB()->prepareStatement($sql);
664 $statement->execute($this->objectIDs);
665 while ($object = $statement->fetchObject($baseClass)) {
666 $this->objects[] = new $this->className($object);
667 }
668 }
669
670 /**
671 * Validates the 'disableSignature' action.
672 */
673 public function validateDisableSignature() {
674 $this->validateEnableSignature();
675
676 $this->readString('disableSignatureReason', true);
677 $this->readString('disableSignatureExpires', true);
678 }
679
680 /**
681 * Disables the signature of the handled users.
682 */
683 public function disableSignature() {
684 if (empty($this->objects)) {
685 $this->readObjects();
686 }
687
688 $disableSignatureExpires = $this->parameters['disableSignatureExpires'];
689 if ($disableSignatureExpires) {
690 $disableSignatureExpires = strtotime($disableSignatureExpires);
691 }
692 else {
693 $disableSignatureExpires = 0;
694 }
695
696 foreach ($this->getObjects() as $userEditor) {
697 $userEditor->update([
698 'disableSignature' => 1,
699 'disableSignatureReason' => $this->parameters['disableSignatureReason'],
700 'disableSignatureExpires' => $disableSignatureExpires
701 ]);
702 }
703 }
704
705 /**
706 * Validates the 'enableSignature' action.
707 */
708 public function validateEnableSignature() {
709 WCF::getSession()->checkPermissions(['admin.user.canDisableSignature']);
710
711 $this->__validateAccessibleGroups();
712
713 if (empty($this->objects)) {
714 $this->readObjects();
715
716 if (empty($this->objects)) {
717 throw new UserInputException('objectIDs');
718 }
719 }
720 }
721
722 /**
723 * Enables the signature of the handled users.
724 */
725 public function enableSignature() {
726 if (empty($this->objects)) {
727 $this->readObjects();
728 }
729
730 foreach ($this->getObjects() as $userEditor) {
731 $userEditor->update([
732 'disableSignature' => 0
733 ]);
734 }
735 }
736
737 /**
738 * Validates the 'disableAvatar' action.
739 */
740 public function validateDisableAvatar() {
741 $this->validateEnableAvatar();
742
743 $this->readString('disableAvatarReason', true);
744 $this->readString('disableAvatarExpires', true);
745 }
746
747 /**
748 * Disables the avatar of the handled users.
749 */
750 public function disableAvatar() {
751 if (empty($this->objects)) {
752 $this->readObjects();
753 }
754
755 $disableAvatarExpires = $this->parameters['disableAvatarExpires'];
756 if ($disableAvatarExpires) {
757 $disableAvatarExpires = strtotime($disableAvatarExpires);
758 }
759 else {
760 $disableAvatarExpires = 0;
761 }
762
763 foreach ($this->getObjects() as $userEditor) {
764 $userEditor->update([
765 'disableAvatar' => 1,
766 'disableAvatarReason' => $this->parameters['disableAvatarReason'],
767 'disableAvatarExpires' => $disableAvatarExpires
768 ]);
769 }
770 }
771
772 /**
773 * Validates the 'disableCoverPhoto' action.
774 *
775 * @since 3.2
776 */
777 public function validateDisableCoverPhoto() {
778 $this->validateEnableCoverPhoto();
779
780 $this->readString('disableCoverPhotoReason', true);
781 $this->readString('disableCoverPhotoExpires', true);
782 }
783
784 /**
785 * Disables the cover photo of the handled users.
786 *
787 * @since 3.2
788 */
789 public function disableCoverPhoto() {
790 if (empty($this->objects)) {
791 $this->readObjects();
792 }
793
794 $disableCoverPhotoExpires = $this->parameters['disableCoverPhotoExpires'];
795 if ($disableCoverPhotoExpires) {
796 $disableCoverPhotoExpires = strtotime($disableCoverPhotoExpires);
797 }
798 else {
799 $disableCoverPhotoExpires = 0;
800 }
801
802 foreach ($this->getObjects() as $userEditor) {
803 $userEditor->update([
804 'disableCoverPhoto' => 1,
805 'disableCoverPhotoReason' => $this->parameters['disableCoverPhotoReason'],
806 'disableCoverPhotoExpires' => $disableCoverPhotoExpires
807 ]);
808 }
809 }
810
811 /**
812 * Validates the 'enableAvatar' action.
813 */
814 public function validateEnableAvatar() {
815 WCF::getSession()->checkPermissions(['admin.user.canDisableAvatar']);
816
817 $this->__validateAccessibleGroups();
818
819 if (empty($this->objects)) {
820 $this->readObjects();
821
822 if (empty($this->objects)) {
823 throw new UserInputException('objectIDs');
824 }
825 }
826 }
827
828 /**
829 * Enables the avatar of the handled users.
830 */
831 public function enableAvatar() {
832 if (empty($this->objects)) {
833 $this->readObjects();
834 }
835
836 foreach ($this->getObjects() as $userEditor) {
837 $userEditor->update([
838 'disableAvatar' => 0
839 ]);
840 }
841 }
842
843 /**
844 * Validates the 'enableCoverPhoto' action.
845 *
846 * @since 3.2
847 */
848 public function validateEnableCoverPhoto() {
849 WCF::getSession()->checkPermissions(['admin.user.canDisableCoverPhoto']);
850
851 $this->__validateAccessibleGroups();
852
853 if (empty($this->objects)) {
854 $this->readObjects();
855
856 if (empty($this->objects)) {
857 throw new UserInputException('objectIDs');
858 }
859 }
860 }
861
862 /**
863 * Enables the cover photo of the handled users.
864 *
865 * @since 3.2
866 */
867 public function enableCoverPhoto() {
868 if (empty($this->objects)) {
869 $this->readObjects();
870 }
871
872 foreach ($this->getObjects() as $userEditor) {
873 $userEditor->update([
874 'disableCoverPhoto' => 0
875 ]);
876 }
877 }
878
879 /**
880 * Returns the remove content dialog.
881 *
882 * @return String[]
883 * @since 3.2
884 */
885 public function prepareRemoveContent() {
886 $knownContentProvider = array_map(function ($contentProvider) {
887 return $contentProvider->objectType;
888 }, array_filter(ObjectTypeCache::getInstance()->getObjectTypes('com.woltlab.wcf.content.userContentProvider'), function ($contentProvider) {
889 return !$contentProvider->hidden;
890 }));
891
892 return [
893 'template' => WCF::getTPL()->fetch('removeUserContentDialog', 'wcf', [
894 'knownContentProvider' => $knownContentProvider,
895 'userID' => $this->parameters['userID'],
896 'user' => $this->parameters['user']
897 ])
898 ];
899 }
900
901 /**
902 * Validates the prepareRemoveContent method.
903 *
904 * @since 3.2
905 */
906 public function validatePrepareRemoveContent() {
907 if (!isset($this->parameters['userID'])) {
908 throw new \InvalidArgumentException("userID missing");
909 }
910
911 $this->parameters['user'] = new User($this->parameters['userID']);
912
913 if ($this->parameters['user']->userID && !$this->parameters['user']->canEdit()) {
914 throw new PermissionDeniedException();
915 }
916 }
917
918 /**
919 * Validates parameters to retrieve the social network privacy settings.
920 * @deprecated 3.0
921 */
922 public function validateGetSocialNetworkPrivacySettings() {
923 // does nothing
924 }
925
926 /**
927 * Returns the social network privacy settings.
928 * @deprecated 3.0
929 */
930 public function getSocialNetworkPrivacySettings() {
931 // does nothing
932 }
933
934 /**
935 * Validates the 'saveSocialNetworkPrivacySettings' action.
936 * @deprecated 3.0
937 */
938 public function validateSaveSocialNetworkPrivacySettings() {
939 // does nothing
940 }
941
942 /**
943 * Saves the social network privacy settings.
944 * @deprecated 3.0
945 */
946 public function saveSocialNetworkPrivacySettings() {
947 // does nothing
948 }
949
950 /**
951 * Validates the 'resendActivationMail' action.
952 * @throws UserInputException
953 * @since 3.2
954 */
955 public function validateResendActivationMail() {
956 $this->readObjects();
957
958 if (!WCF::getSession()->getPermission('admin.user.canEnableUser')) {
959 throw new PermissionDeniedException();
960 }
961
962 if (REGISTER_ACTIVATION_METHOD != 1) {
963 throw new IllegalLinkException();
964 }
965
966 foreach ($this->objects as $object) {
967 if (!$object->activationCode) {
968 throw new UserInputException('objectIDs');
969 }
970 }
971 }
972
973 /**
974 * Triggers a new activation email.
975 * @since 3.2
976 */
977 public function resendActivationMail() {
978 // update every selected user's activation code
979 foreach ($this->objects as $object) {
980 $action = new UserAction([$object], 'update', [
981 'data' => [
982 'activationCode' => UserRegistrationUtil::getActivationCode()
983 ]
984 ]);
985 $action->executeAction();
986
987 }
988
989 // get fresh user list with updated user objects
990 $newUserList = new UserList();
991 $newUserList->getConditionBuilder()->add('user_table.userID IN (?)', [$this->objectIDs]);
992 $newUserList->readObjects();
993 foreach ($newUserList->getObjects() as $object) {
994 $email = new Email();
995 $email->addRecipient(new UserMailbox($object));
996 $email->setSubject($object->getLanguage()->getDynamicVariable('wcf.user.register.needActivation.mail.subject'));
997 $email->setBody(new MimePartFacade([
998 new RecipientAwareTextMimePart('text/html', 'email_registerNeedActivation'),
999 new RecipientAwareTextMimePart('text/plain', 'email_registerNeedActivation')
1000 ]));
1001 $email->send();
1002 }
1003
1004 $this->unmarkItems($this->objectIDs);
1005 }
1006 }