In-Profile moderation feature for cover photos
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / data / user / UserAction.class.php
CommitLineData
11ade432
AE
1<?php
2namespace wcf\data\user;
a706abdf 3use wcf\data\object\type\ObjectTypeCache;
0dd6ea0c 4use wcf\data\user\avatar\UserAvatarAction;
11ade432 5use wcf\data\user\group\UserGroup;
931f6597 6use wcf\data\AbstractDatabaseObjectAction;
7918ddba 7use wcf\data\IClipboardAction;
a427a8c8 8use wcf\data\ISearchAction;
b0dc9618 9use wcf\system\attachment\AttachmentHandler;
7f379ade 10use wcf\system\clipboard\ClipboardHandler;
97247661 11use wcf\system\comment\CommentHandler;
11ade432 12use wcf\system\database\util\PreparedStatementConditionBuilder;
bde0e3dc
TD
13use wcf\system\email\mime\MimePartFacade;
14use wcf\system\email\mime\RecipientAwareTextMimePart;
15use wcf\system\email\Email;
16use wcf\system\email\UserMailbox;
dd900ec4 17use wcf\system\event\EventHandler;
6815ac08 18use wcf\system\exception\IllegalLinkException;
dd900ec4
AE
19use wcf\system\exception\PermissionDeniedException;
20use wcf\system\exception\UserInputException;
bae8dd1e 21use wcf\system\request\RequestHandler;
2bc9f31d 22use wcf\system\WCF;
2fe45e04 23use wcf\util\UserRegistrationUtil;
11ade432
AE
24
25/**
26 * Executes user-related actions.
27 *
28 * @author Alexander Ebert
c839bd49 29 * @copyright 2001-2018 WoltLab GmbH
11ade432 30 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
e71525e4 31 * @package WoltLabSuite\Core\Data\User
0e8867ac
MS
32 *
33 * @method UserEditor[] getObjects()
34 * @method UserEditor getSingleObject()
11ade432 35 */
7918ddba 36class UserAction extends AbstractDatabaseObjectAction implements IClipboardAction, ISearchAction {
11ade432 37 /**
b35f63d6 38 * @inheritDoc
11ade432 39 */
b35f63d6 40 public $className = UserEditor::class;
11ade432 41
8eb8876b 42 /**
b35f63d6 43 * @inheritDoc
8eb8876b 44 */
b35f63d6 45 protected $allowGuestAccess = ['getSearchResultList'];
8eb8876b 46
11ade432 47 /**
b35f63d6 48 * @inheritDoc
11ade432 49 */
b35f63d6 50 protected $permissionsCreate = ['admin.user.canAddUser'];
11ade432
AE
51
52 /**
b35f63d6 53 * @inheritDoc
11ade432 54 */
b35f63d6 55 protected $permissionsDelete = ['admin.user.canDeleteUser'];
11ade432
AE
56
57 /**
b35f63d6 58 * @inheritDoc
11ade432 59 */
b35f63d6 60 protected $permissionsUpdate = ['admin.user.canEditUser'];
11ade432 61
bae8dd1e 62 /**
b35f63d6 63 * @inheritDoc
bae8dd1e 64 */
fe1743f0 65 protected $requireACP = ['create', 'delete', 'resendActivationMail'];
bae8dd1e 66
11ade432
AE
67 /**
68 * Validates permissions and parameters.
69 */
70 public function validateCreate() {
a54f8d8f 71 $this->readString('password', false, 'data');
11ade432
AE
72 }
73
74 /**
11cf19be
MW
75 * Validates accessible groups.
76 *
77 * @param boolean $ignoreOwnUser
2b770bdd
MS
78 * @throws PermissionDeniedException
79 * @throws UserInputException
11ade432 80 */
11cf19be
MW
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 }
a7fd745e 88 }
48f9369a 89 }
11ade432 90
a7fd745e 91 // list might be empty because only our own user id was given
11cf19be 92 if (empty($this->objectIDs)) {
3631f7bd 93 throw new UserInputException('objectIDs');
a7fd745e
AE
94 }
95
11ade432
AE
96 // validate groups
97 $conditions = new PreparedStatementConditionBuilder();
b35f63d6 98 $conditions->add("userID IN (?)", [$this->objectIDs]);
11ade432
AE
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());
cd975610 105 $groupIDs = $statement->fetchAll(\PDO::FETCH_COLUMN);
11ade432
AE
106
107 if (!UserGroup::isAccessibleGroup($groupIDs)) {
3631f7bd 108 throw new PermissionDeniedException();
11ade432
AE
109 }
110 }
111
11cf19be
MW
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
0dd6ea0c 122 /**
b35f63d6 123 * @inheritDoc
0dd6ea0c
MW
124 */
125 public function delete() {
126 if (empty($this->objects)) {
127 $this->readObjects();
128 }
129
130 // delete avatars
b35f63d6 131 $avatarIDs = [];
4a130a51 132 foreach ($this->getObjects() as $user) {
0dd6ea0c
MW
133 if ($user->avatarID) $avatarIDs[] = $user->avatarID;
134 }
135 if (!empty($avatarIDs)) {
136 $action = new UserAvatarAction($avatarIDs, 'delete');
137 $action->executeAction();
138 }
139
b0dc9618 140 // delete profile comments and signature attachments
0dd6ea0c 141 if (!empty($this->objectIDs)) {
97247661 142 CommentHandler::getInstance()->deleteObjects('com.woltlab.wcf.user.profileComment', $this->objectIDs);
b0dc9618 143 AttachmentHandler::removeAttachments('com.woltlab.wcf.user.signature', $this->objectIDs);
0dd6ea0c
MW
144 }
145
241627da 146 return parent::delete();
0dd6ea0c
MW
147 }
148
11ade432
AE
149 /**
150 * Validates permissions and parameters.
11ade432
AE
151 */
152 public function validateUpdate() {
a79cfb56 153 // read objects
15fa2802 154 if (empty($this->objects)) {
a79cfb56 155 $this->readObjects();
15fa2802
MS
156
157 if (empty($this->objects)) {
3631f7bd 158 throw new UserInputException('objectIDs');
15fa2802 159 }
a79cfb56 160 }
11ade432 161
bae8dd1e
AE
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
a79cfb56
AE
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)) {
67ca3261
AE
173 $count = count($this->parameters);
174 if ($count > 1 || ($count == 1 && !isset($this->parameters['options']))) {
3631f7bd 175 throw new PermissionDeniedException();
a79cfb56
AE
176 }
177 }
85f591f6
AE
178 else {
179 throw new PermissionDeniedException();
180 }
a79cfb56 181 }
11ade432
AE
182 }
183
11cf19be
MW
184 /**
185 * Validates the ban action.
186 */
187 public function validateBan() {
f034d0ec 188 $this->validateUnban();
11cf19be 189
f034d0ec
MS
190 $this->readString('banReason', true);
191 $this->readString('banExpires', true);
11cf19be
MW
192 }
193
194 /**
195 * Validates the unban action.
196 */
197 public function validateUnban() {
b35f63d6 198 WCF::getSession()->checkPermissions(['admin.user.canBanUser']);
f034d0ec
MS
199
200 $this->__validateAccessibleGroups();
11cf19be
MW
201 }
202
203 /**
204 * Bans users.
205 */
206 public function ban() {
f034d0ec
MS
207 $banExpires = $this->parameters['banExpires'];
208 if ($banExpires) {
209 $banExpires = strtotime($banExpires);
a5888364 210 if ($banExpires > 2147483647) $banExpires = 2147483647;
f034d0ec
MS
211 }
212 else {
213 $banExpires = 0;
214 }
215
11cf19be 216 $conditionBuilder = new PreparedStatementConditionBuilder();
b35f63d6 217 $conditionBuilder->add('userID IN (?)', [$this->objectIDs]);
f034d0ec 218
11cf19be
MW
219 $sql = "UPDATE wcf".WCF_N."_user
220 SET banned = ?,
f034d0ec
MS
221 banReason = ?,
222 banExpires = ?
11cf19be
MW
223 ".$conditionBuilder;
224 $statement = WCF::getDB()->prepareStatement($sql);
225 $statement->execute(
b35f63d6 226 array_merge([
f034d0ec
MS
227 1,
228 $this->parameters['banReason'],
229 $banExpires
b35f63d6 230 ], $conditionBuilder->getParameters())
11cf19be 231 );
bbef7ed8
MW
232
233 $this->unmarkItems();
17bf3ee5
MW
234
235 $firstUser = new User(reset($this->objectIDs));
236 return WCF::getLanguage()->getDynamicVariable('wcf.user.banned', ['user' => $firstUser]);
11cf19be
MW
237 }
238
239 /**
240 * Unbans users.
241 */
242 public function unban() {
243 $conditionBuilder = new PreparedStatementConditionBuilder();
b35f63d6 244 $conditionBuilder->add('userID IN (?)', [$this->objectIDs]);
f034d0ec 245
11cf19be 246 $sql = "UPDATE wcf".WCF_N."_user
f034d0ec
MS
247 SET banned = ?,
248 banExpires = ?
11cf19be
MW
249 ".$conditionBuilder;
250 $statement = WCF::getDB()->prepareStatement($sql);
f034d0ec 251 $statement->execute(
b35f63d6 252 array_merge([
f034d0ec
MS
253 0,
254 0
b35f63d6 255 ], $conditionBuilder->getParameters())
f034d0ec 256 );
11cf19be
MW
257 }
258
11ade432 259 /**
0e8867ac 260 * @inheritDoc
11ade432
AE
261 * @return User
262 */
263 public function create() {
0e8867ac 264 /** @var User $user */
11ade432
AE
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
63b9817b
MS
274 $addDefaultGroups = isset($this->parameters['addDefaultGroups']) ? $this->parameters['addDefaultGroups'] : true;
275 $groupIDs = isset($this->parameters['groups']) ? $this->parameters['groups'] : [];
2bb10466 276 $userEditor->addToGroups($groupIDs, false, $addDefaultGroups);
11ade432
AE
277
278 // insert visible languages
7623b12f
AE
279 if (!isset($this->parameters['languageIDs'])) {
280 // using the 'languages' key is deprecated since WCF 2.1, please use 'languageIDs' instead
b35f63d6 281 $this->parameters['languageIDs'] = (!empty($this->parameters['languages'])) ? $this->parameters['languages'] : [];
7623b12f
AE
282 }
283 $userEditor->addToLanguages($this->parameters['languageIDs'], false);
11ade432 284
320f4a6d
MW
285 if (PACKAGE_ID) {
286 // set default notifications
287 $sql = "INSERT INTO wcf".WCF_N."_user_notification_event_to_user
0ceb9e95
MW
288 (userID, eventID, mailNotificationType)
289 SELECT ?, eventID, presetMailNotificationType
695780d7
MW
290 FROM wcf".WCF_N."_user_notification_event
291 WHERE preset = ?";
320f4a6d 292 $statement = WCF::getDB()->prepareStatement($sql);
b35f63d6 293 $statement->execute([$user->userID, 1]);
c9d91afc
MW
294
295 // update user rank
296 if (MODULE_USER_RANK) {
b35f63d6 297 $action = new UserProfileAction([$userEditor], 'updateUserRank');
c9d91afc
MW
298 $action->executeAction();
299 }
300 // update user online marking
b35f63d6 301 $action = new UserProfileAction([$userEditor], 'updateUserOnlineMarking');
c9d91afc 302 $action->executeAction();
320f4a6d
MW
303 }
304
11ade432
AE
305 return $user;
306 }
835fa8c2
AE
307
308 /**
b35f63d6 309 * @inheritDoc
835fa8c2
AE
310 */
311 public function update() {
de7f211d 312 if (isset($this->parameters['data']) || isset($this->parameters['counters'])) {
881246d6 313 parent::update();
8a3258f5
MS
314
315 if (isset($this->parameters['data']['languageID'])) {
4a130a51 316 foreach ($this->getObjects() as $object) {
8a3258f5
MS
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 }
881246d6
AE
326 }
327 else {
15fa2802 328 if (empty($this->objects)) {
881246d6
AE
329 $this->readObjects();
330 }
331 }
835fa8c2 332
63b9817b
MS
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'] : [];
835fa8c2 337
c2000c5d 338 if (!empty($groupIDs)) {
b35f63d6 339 $action = new UserAction($this->objects, 'addToGroups', [
12f80a9d
MW
340 'groups' => $groupIDs,
341 'addDefaultGroups' => false
b35f63d6 342 ]);
c2000c5d
MW
343 $action->executeAction();
344 }
345
cc27b414 346 if (!empty($removeGroups)) {
b35f63d6 347 $action = new UserAction($this->objects, 'removeFromGroups', [
3ffea5e3 348 'groups' => $removeGroups
b35f63d6 349 ]);
cc27b414
JR
350 $action->executeAction();
351 }
352
4a130a51 353 foreach ($this->getObjects() as $userEditor) {
f277d540
AE
354 if (!empty($userOptions)) {
355 $userEditor->updateUserOptions($userOptions);
356 }
44adccf6
AE
357
358 if (!empty($languageIDs)) {
359 $userEditor->addToLanguages($languageIDs);
360 }
835fa8c2 361 }
83f2404b
AE
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
e06bab73
MW
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
83f2404b
AE
378 // update comments
379 $sql = "UPDATE wcf".WCF_N."_comment
380 SET username = ?
381 WHERE userID = ?";
382 $statement = WCF::getDB()->prepareStatement($sql);
b35f63d6 383 $statement->execute([$username, $userID]);
83f2404b 384
b35f63d6 385 // update comment responses
83f2404b
AE
386 $sql = "UPDATE wcf".WCF_N."_comment_response
387 SET username = ?
388 WHERE userID = ?";
389 $statement = WCF::getDB()->prepareStatement($sql);
b35f63d6 390 $statement->execute([$username, $userID]);
83f2404b 391
b35f63d6
MS
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
83f2404b
AE
400 $sql = "UPDATE wcf".WCF_N."_modification_log
401 SET username = ?
402 WHERE userID = ?";
403 $statement = WCF::getDB()->prepareStatement($sql);
b35f63d6 404 $statement->execute([$username, $userID]);
83f2404b
AE
405
406 WCF::getDB()->commitTransaction();
407
408 // fire event to handle other database tables
409 EventHandler::getInstance()->fireAction($this, 'rename');
410 }
411 }
835fa8c2 412 }
d5cab442 413
fe6d199c 414 /**
cc27b414 415 * Remove users from given groups.
fe6d199c
JR
416 */
417 public function removeFromGroups() {
418 if (empty($this->objects)) {
419 $this->readObjects();
420 }
421
422 $groupIDs = $this->parameters['groups'];
423
4a130a51 424 foreach ($this->getObjects() as $userEditor) {
fe6d199c
JR
425 $userEditor->removeFromGroups($groupIDs);
426 }
427
428 //reread objects
b35f63d6 429 $this->objects = [];
fe6d199c
JR
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
0dd6ea0c
MW
443 /**
444 * Add users to given groups.
445 */
c2000c5d
MW
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
4a130a51 456 foreach ($this->getObjects() as $userEditor) {
c2000c5d
MW
457 $userEditor->addToGroups($groupIDs, $deleteOldGroups, $addDefaultGroups);
458 }
320f4a6d 459
6374f974 460 //reread objects
b35f63d6 461 $this->objects = [];
6374f974
JR
462 UserEditor::resetCache();
463 $this->readObjects();
464
320f4a6d
MW
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 }
c2000c5d
MW
473 }
474
a7fd745e 475 /**
b35f63d6 476 * @inheritDoc
a7fd745e 477 */
a427a8c8 478 public function validateGetSearchResultList() {
a54f8d8f
AE
479 $this->readBoolean('includeUserGroups', false, 'data');
480 $this->readString('searchString', false, 'data');
a7fd745e
AE
481
482 if (isset($this->parameters['data']['excludedSearchValues']) && !is_array($this->parameters['data']['excludedSearchValues'])) {
3631f7bd 483 throw new UserInputException('excludedSearchValues');
a7fd745e 484 }
d5cab442
AE
485 }
486
a7fd745e 487 /**
b35f63d6 488 * @inheritDoc
a7fd745e 489 */
a427a8c8 490 public function getSearchResultList() {
d5cab442 491 $searchString = $this->parameters['data']['searchString'];
b35f63d6 492 $excludedSearchValues = [];
c000b08a
MS
493 if (isset($this->parameters['data']['excludedSearchValues'])) {
494 $excludedSearchValues = $this->parameters['data']['excludedSearchValues'];
495 }
b35f63d6 496 $list = [];
9f959ced 497
d5cab442
AE
498 if ($this->parameters['data']['includeUserGroups']) {
499 $accessibleGroups = UserGroup::getAccessibleGroups();
500 foreach ($accessibleGroups as $group) {
18c05238 501 $groupName = $group->getName();
c000b08a 502 if (!in_array($groupName, $excludedSearchValues)) {
838e315b 503 $pos = mb_strripos($groupName, $searchString);
c000b08a 504 if ($pos !== false && $pos == 0) {
b35f63d6 505 $list[] = [
c000b08a
MS
506 'label' => $groupName,
507 'objectID' => $group->groupID,
508 'type' => 'group'
b35f63d6 509 ];
c000b08a 510 }
d5cab442
AE
511 }
512 }
513 }
c000b08a 514
c2d0b2d6 515 // find users
1f92bb4a
MW
516 $searchString = addcslashes($searchString, '_%');
517 $parameters = [
518 'searchString' => $searchString
519 ];
520 EventHandler::getInstance()->fireAction($this, 'beforeFindUsers', $parameters);
c2d0b2d6 521 $userProfileList = new UserProfileList();
1f92bb4a 522 $userProfileList->getConditionBuilder()->add("username LIKE ?", [$parameters['searchString'].'%']);
15fa2802 523 if (!empty($excludedSearchValues)) {
b35f63d6 524 $userProfileList->getConditionBuilder()->add("username NOT IN (?)", [$excludedSearchValues]);
c000b08a 525 }
c2d0b2d6
MS
526 $userProfileList->sqlLimit = 10;
527 $userProfileList->readObjects();
9f959ced 528
c2d0b2d6 529 foreach ($userProfileList as $userProfile) {
b35f63d6 530 $list[] = [
c2d0b2d6
MS
531 'icon' => $userProfile->getAvatar()->getImageTag(16),
532 'label' => $userProfile->username,
533 'objectID' => $userProfile->userID,
d5cab442 534 'type' => 'user'
b35f63d6 535 ];
d5cab442 536 }
9f959ced 537
d5cab442
AE
538 return $list;
539 }
49c164a8
AE
540
541 /**
b35f63d6 542 * @inheritDoc
49c164a8 543 */
fbb077d4
MS
544 public function validateUnmarkAll() {
545 // does nothing
546 }
49c164a8
AE
547
548 /**
b35f63d6 549 * @inheritDoc
49c164a8
AE
550 */
551 public function unmarkAll() {
552 ClipboardHandler::getInstance()->removeItems(ClipboardHandler::getInstance()->getObjectTypeID('com.woltlab.wcf.user'));
553 }
bbef7ed8
MW
554
555 /**
556 * Unmarks users.
59dc0db6 557 *
b35f63d6 558 * @param integer[] $userIDs
bbef7ed8 559 */
b35f63d6 560 protected function unmarkItems(array $userIDs = []) {
bbef7ed8
MW
561 if (empty($userIDs)) {
562 $userIDs = $this->objectIDs;
563 }
e3369fd2 564
bbef7ed8
MW
565 if (!empty($userIDs)) {
566 ClipboardHandler::getInstance()->unmark($userIDs, ClipboardHandler::getInstance()->getObjectTypeID('com.woltlab.wcf.user'));
567 }
568 }
2fe45e04
MW
569
570 /**
571 * Validates the enable action.
572 */
573 public function validateEnable() {
b35f63d6 574 WCF::getSession()->checkPermissions(['admin.user.canEnableUser']);
9927f711
MS
575
576 $this->__validateAccessibleGroups();
2fe45e04
MW
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();
9927f711 591
b35f63d6
MS
592 $action = new UserAction($this->objects, 'update', [
593 'data' => [
2fe45e04 594 'activationCode' => 0
b35f63d6
MS
595 ],
596 'removeGroups' => UserGroup::getGroupIDsByType([UserGroup::GUESTS])
597 ]);
2fe45e04 598 $action->executeAction();
b35f63d6
MS
599 $action = new UserAction($this->objects, 'addToGroups', [
600 'groups' => UserGroup::getGroupIDsByType([UserGroup::USERS]),
2818981f 601 'deleteOldGroups' => false,
9927f711 602 'addDefaultGroups' => false
b35f63d6 603 ]);
2fe45e04 604 $action->executeAction();
00ce5cf8 605
11dccf1c 606 // send e-mail notification
723b4553 607 if (empty($this->parameters['skipNotification'])) {
4a130a51 608 foreach ($this->getObjects() as $user) {
bde0e3dc
TD
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')
b35f63d6 615 ]));
bde0e3dc 616 $email->send();
11dccf1c
MW
617 }
618 }
619
00ce5cf8 620 $this->unmarkItems();
2fe45e04
MW
621 }
622
623 /**
624 * Disables users.
625 */
626 public function disable() {
627 if (empty($this->objects)) $this->readObjects();
9927f711 628
b35f63d6
MS
629 $action = new UserAction($this->objects, 'update', [
630 'data' => [
2fe45e04 631 'activationCode' => UserRegistrationUtil::getActivationCode()
b35f63d6 632 ],
3728a6bd 633 'removeGroups' => UserGroup::getGroupIDsByType([UserGroup::USERS])
b35f63d6 634 ]);
2fe45e04 635 $action->executeAction();
b35f63d6
MS
636 $action = new UserAction($this->objects, 'addToGroups', [
637 'groups' => UserGroup::getGroupIDsByType([UserGroup::GUESTS]),
2818981f
MW
638 'deleteOldGroups' => false,
639 'addDefaultGroups' => false
b35f63d6 640 ]);
2fe45e04 641 $action->executeAction();
00ce5cf8
AE
642
643 $this->unmarkItems();
2fe45e04 644 }
2ce24640
MW
645
646 /**
b35f63d6 647 * @inheritDoc
2ce24640
MW
648 */
649 protected function readObjects() {
650 if (empty($this->objectIDs)) {
651 return;
652 }
57f097e8 653
2ce24640 654 // get base class
b35f63d6 655 $baseClass = call_user_func([$this->className, 'getBaseClass']);
57f097e8 656
2ce24640
MW
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 }
57f097e8
MS
669
670 /**
671 * Validates the 'disableSignature' action.
672 */
673 public function validateDisableSignature() {
3696fe93 674 $this->validateEnableSignature();
57f097e8
MS
675
676 $this->readString('disableSignatureReason', true);
f034d0ec 677 $this->readString('disableSignatureExpires', true);
57f097e8
MS
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
f034d0ec
MS
688 $disableSignatureExpires = $this->parameters['disableSignatureExpires'];
689 if ($disableSignatureExpires) {
690 $disableSignatureExpires = strtotime($disableSignatureExpires);
691 }
692 else {
693 $disableSignatureExpires = 0;
694 }
695
4a130a51 696 foreach ($this->getObjects() as $userEditor) {
b35f63d6 697 $userEditor->update([
57f097e8 698 'disableSignature' => 1,
f034d0ec
MS
699 'disableSignatureReason' => $this->parameters['disableSignatureReason'],
700 'disableSignatureExpires' => $disableSignatureExpires
b35f63d6 701 ]);
57f097e8
MS
702 }
703 }
704
705 /**
706 * Validates the 'enableSignature' action.
707 */
708 public function validateEnableSignature() {
b35f63d6 709 WCF::getSession()->checkPermissions(['admin.user.canDisableSignature']);
57f097e8
MS
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
4a130a51 730 foreach ($this->getObjects() as $userEditor) {
b35f63d6 731 $userEditor->update([
57f097e8 732 'disableSignature' => 0
b35f63d6 733 ]);
57f097e8
MS
734 }
735 }
736
737 /**
738 * Validates the 'disableAvatar' action.
739 */
740 public function validateDisableAvatar() {
3696fe93 741 $this->validateEnableAvatar();
57f097e8
MS
742
743 $this->readString('disableAvatarReason', true);
f034d0ec 744 $this->readString('disableAvatarExpires', true);
57f097e8
MS
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 }
1a6e8c52 754
f034d0ec
MS
755 $disableAvatarExpires = $this->parameters['disableAvatarExpires'];
756 if ($disableAvatarExpires) {
757 $disableAvatarExpires = strtotime($disableAvatarExpires);
758 }
759 else {
760 $disableAvatarExpires = 0;
761 }
57f097e8 762
4a130a51 763 foreach ($this->getObjects() as $userEditor) {
b35f63d6 764 $userEditor->update([
57f097e8 765 'disableAvatar' => 1,
f034d0ec
MS
766 'disableAvatarReason' => $this->parameters['disableAvatarReason'],
767 'disableAvatarExpires' => $disableAvatarExpires
b35f63d6 768 ]);
57f097e8
MS
769 }
770 }
771
42ef9c72
AE
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
57f097e8
MS
811 /**
812 * Validates the 'enableAvatar' action.
813 */
814 public function validateEnableAvatar() {
b35f63d6 815 WCF::getSession()->checkPermissions(['admin.user.canDisableAvatar']);
57f097e8
MS
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
4a130a51 836 foreach ($this->getObjects() as $userEditor) {
b35f63d6 837 $userEditor->update([
57f097e8 838 'disableAvatar' => 0
b35f63d6 839 ]);
57f097e8
MS
840 }
841 }
9ed42d00 842
42ef9c72
AE
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
a706abdf
JR
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;
d05c7d03
JR
888 }, array_filter(ObjectTypeCache::getInstance()->getObjectTypes('com.woltlab.wcf.content.userContentProvider'), function ($contentProvider) {
889 return !$contentProvider->hidden;
890 }));
a706abdf
JR
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
9ed42d00
AE
918 /**
919 * Validates parameters to retrieve the social network privacy settings.
527a8fc6 920 * @deprecated 3.0
9ed42d00 921 */
b35f63d6
MS
922 public function validateGetSocialNetworkPrivacySettings() {
923 // does nothing
924 }
9ed42d00
AE
925
926 /**
927 * Returns the social network privacy settings.
527a8fc6 928 * @deprecated 3.0
9ed42d00
AE
929 */
930 public function getSocialNetworkPrivacySettings() {
527a8fc6 931 // does nothing
9ed42d00
AE
932 }
933
b35f63d6
MS
934 /**
935 * Validates the 'saveSocialNetworkPrivacySettings' action.
527a8fc6 936 * @deprecated 3.0
b35f63d6 937 */
9ed42d00 938 public function validateSaveSocialNetworkPrivacySettings() {
527a8fc6 939 // does nothing
9ed42d00
AE
940 }
941
b35f63d6
MS
942 /**
943 * Saves the social network privacy settings.
527a8fc6 944 * @deprecated 3.0
b35f63d6 945 */
9ed42d00 946 public function saveSocialNetworkPrivacySettings() {
527a8fc6 947 // does nothing
9ed42d00 948 }
fe1743f0 949
950 /**
951 * Validates the 'resendActivationMail' action.
952 * @throws UserInputException
953 * @since 3.2
954 */
955 public function validateResendActivationMail() {
956 $this->readObjects();
957
6815ac08
JR
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
fe1743f0 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) {
5f7d8f2e 980 $action = new UserAction([$object], 'update', [
fe1743f0 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();
966f2f62 991 $newUserList->getConditionBuilder()->add('user_table.userID IN (?)', [$this->objectIDs]);
fe1743f0 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 }
11ade432 1006}