Commit | Line | Data |
---|---|---|
11ade432 AE |
1 | <?php |
2 | namespace wcf\data\user; | |
a706abdf | 3 | use wcf\data\object\type\ObjectTypeCache; |
0dd6ea0c | 4 | use wcf\data\user\avatar\UserAvatarAction; |
11ade432 | 5 | use wcf\data\user\group\UserGroup; |
931f6597 | 6 | use wcf\data\AbstractDatabaseObjectAction; |
7918ddba | 7 | use wcf\data\IClipboardAction; |
a427a8c8 | 8 | use wcf\data\ISearchAction; |
b0dc9618 | 9 | use wcf\system\attachment\AttachmentHandler; |
7f379ade | 10 | use wcf\system\clipboard\ClipboardHandler; |
97247661 | 11 | use wcf\system\comment\CommentHandler; |
11ade432 | 12 | use wcf\system\database\util\PreparedStatementConditionBuilder; |
bde0e3dc TD |
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; | |
dd900ec4 | 17 | use wcf\system\event\EventHandler; |
6815ac08 | 18 | use wcf\system\exception\IllegalLinkException; |
dd900ec4 AE |
19 | use wcf\system\exception\PermissionDeniedException; |
20 | use wcf\system\exception\UserInputException; | |
bae8dd1e | 21 | use wcf\system\request\RequestHandler; |
2bc9f31d | 22 | use wcf\system\WCF; |
2fe45e04 | 23 | use 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 | 36 | class 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 | } |