Adds code formatting fixes missing in previous commit
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / data / user / UserAction.class.php
CommitLineData
11ade432
AE
1<?php
2namespace wcf\data\user;
0dd6ea0c
MW
3use wcf\data\object\type\ObjectTypeCache;
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;
320f4a6d 9use wcf\system\cache\builder\UserNotificationEventCacheBuilder;
7f379ade 10use wcf\system\clipboard\ClipboardHandler;
11ade432 11use wcf\system\database\util\PreparedStatementConditionBuilder;
a79cfb56 12use wcf\system\exception\PermissionDeniedException;
3631f7bd 13use wcf\system\exception\UserInputException;
bae8dd1e 14use wcf\system\request\RequestHandler;
2bc9f31d 15use wcf\system\WCF;
d5cab442 16use wcf\util\StringUtil;
2fe45e04 17use wcf\util\UserRegistrationUtil;
11ade432
AE
18
19/**
20 * Executes user-related actions.
21 *
22 * @author Alexander Ebert
fd1dc2fb 23 * @copyright 2001-2013 WoltLab GmbH
11ade432
AE
24 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
25 * @package com.woltlab.wcf
26 * @subpackage data.user
9f959ced 27 * @category Community Framework
11ade432 28 */
7918ddba 29class UserAction extends AbstractDatabaseObjectAction implements IClipboardAction, ISearchAction {
11ade432 30 /**
73df94ae 31 * @see wcf\data\AbstractDatabaseObjectAction::$className
11ade432
AE
32 */
33 public $className = 'wcf\data\user\UserEditor';
34
8eb8876b
MW
35 /**
36 * @see wcf\data\AbstractDatabaseObjectAction::$allowGuestAccess
37 */
38 protected $allowGuestAccess = array('getSearchResultList');
39
11ade432 40 /**
73df94ae 41 * @see wcf\data\AbstractDatabaseObjectAction::$permissionsCreate
11ade432
AE
42 */
43 protected $permissionsCreate = array('admin.user.canAddUser');
44
45 /**
73df94ae 46 * @see wcf\data\AbstractDatabaseObjectAction::$permissionsDelete
11ade432
AE
47 */
48 protected $permissionsDelete = array('admin.user.canDeleteUser');
49
50 /**
73df94ae 51 * @see wcf\data\AbstractDatabaseObjectAction::$permissionsUpdate
11ade432
AE
52 */
53 protected $permissionsUpdate = array('admin.user.canEditUser');
54
bae8dd1e
AE
55 /**
56 * @see wcf\data\AbstractDatabaseObjectAction::$requireACP
57 */
58 protected $requireACP = array('create', 'ban', 'delete', 'disable', 'enable', 'unban');
59
11ade432
AE
60 /**
61 * Validates permissions and parameters.
62 */
63 public function validateCreate() {
a54f8d8f 64 $this->readString('password', false, 'data');
11ade432
AE
65 }
66
67 /**
11cf19be
MW
68 * Validates accessible groups.
69 *
70 * @param boolean $ignoreOwnUser
11ade432 71 */
11cf19be
MW
72 protected function __validateAccessibleGroups($ignoreOwnUser = true) {
73 if ($ignoreOwnUser) {
74 if (in_array(WCF::getUser()->userID, $this->objectIDs)) {
75 unset($this->objectIDs[array_search(WCF::getUser()->userID, $this->objectIDs)]);
76 if (isset($this->objects[WCF::getUser()->userID])) {
77 unset($this->objects[WCF::getUser()->userID]);
78 }
a7fd745e 79 }
48f9369a 80 }
11ade432 81
a7fd745e 82 // list might be empty because only our own user id was given
11cf19be 83 if (empty($this->objectIDs)) {
3631f7bd 84 throw new UserInputException('objectIDs');
a7fd745e
AE
85 }
86
11ade432
AE
87 // validate groups
88 $conditions = new PreparedStatementConditionBuilder();
11cf19be 89 $conditions->add("userID IN (?)", array($this->objectIDs));
11ade432
AE
90
91 $sql = "SELECT DISTINCT groupID
92 FROM wcf".WCF_N."_user_to_group
93 ".$conditions;
94 $statement = WCF::getDB()->prepareStatement($sql);
95 $statement->execute($conditions->getParameters());
96
97 $groupIDs = array();
98 while ($row = $statement->fetchArray()) {
99 $groupIDs[] = $row['groupID'];
100 }
101
102 if (!UserGroup::isAccessibleGroup($groupIDs)) {
3631f7bd 103 throw new PermissionDeniedException();
11ade432
AE
104 }
105 }
106
11cf19be
MW
107 /**
108 * Validates permissions and parameters.
109 */
110 public function validateDelete() {
111 // read and validate user objects
112 parent::validateDelete();
113
114 $this->__validateAccessibleGroups();
115 }
116
0dd6ea0c
MW
117 /**
118 * @see wcf\data\IDeleteAction::delete()
119 */
120 public function delete() {
121 if (empty($this->objects)) {
122 $this->readObjects();
123 }
124
125 // delete avatars
126 $avatarIDs = array();
127 foreach ($this->objects as $user) {
128 if ($user->avatarID) $avatarIDs[] = $user->avatarID;
129 }
130 if (!empty($avatarIDs)) {
131 $action = new UserAvatarAction($avatarIDs, 'delete');
132 $action->executeAction();
133 }
134
135 // delete profile comments
136 if (!empty($this->objectIDs)) {
137 $objectType = ObjectTypeCache::getInstance()->getObjectTypeByName('com.woltlab.wcf.comment.commentableContent', 'com.woltlab.wcf.user.profileComment');
138 $conditionBuilder = new PreparedStatementConditionBuilder();
139 $conditionBuilder->add('objectTypeID = ?', array($objectType->objectTypeID));
140 $conditionBuilder->add('objectID IN (?)', array($this->objectIDs));
141
142 $sql = "DELETE FROM wcf".WCF_N."_comment
143 ".$conditionBuilder;
144 $statement = WCF::getDB()->prepareStatement($sql);
145 $statement->execute($conditionBuilder->getParameters());
146 }
147
148 $returnValue = parent::delete();
149
150 return $returnValue;
151 }
152
11ade432
AE
153 /**
154 * Validates permissions and parameters.
11ade432
AE
155 */
156 public function validateUpdate() {
a79cfb56 157 // read objects
15fa2802 158 if (empty($this->objects)) {
a79cfb56 159 $this->readObjects();
15fa2802
MS
160
161 if (empty($this->objects)) {
3631f7bd 162 throw new UserInputException('objectIDs');
15fa2802 163 }
a79cfb56 164 }
11ade432 165
bae8dd1e
AE
166 // disallow updating of anything except for options outside of ACP
167 if (RequestHandler::getInstance()->isACPRequest() && (count($this->parameters) != 1 || !isset($this->parameters['options']))) {
168 throw new PermissionDeniedException();
169 }
170
a79cfb56
AE
171 try {
172 WCF::getSession()->checkPermissions($this->permissionsUpdate);
173 }
174 catch (PermissionDeniedException $e) {
175 // check if we're editing ourselves
176 if (count($this->objects) == 1 && ($this->objects[0]->userID == WCF::getUser()->userID)) {
67ca3261
AE
177 $count = count($this->parameters);
178 if ($count > 1 || ($count == 1 && !isset($this->parameters['options']))) {
3631f7bd 179 throw new PermissionDeniedException();
a79cfb56
AE
180 }
181 }
182
3631f7bd 183 throw new PermissionDeniedException();
a79cfb56 184 }
11ade432
AE
185 }
186
11cf19be
MW
187 /**
188 * Validates the ban action.
189 */
190 public function validateBan() {
191 WCF::getSession()->checkPermissions(array('admin.user.canBanUser'));
192
193 $this->__validateAccessibleGroups();
194 }
195
196 /**
197 * Validates the unban action.
198 */
199 public function validateUnban() {
200 $this->validateBan();
201 }
202
203 /**
204 * Bans users.
205 */
206 public function ban() {
207 $conditionBuilder = new PreparedStatementConditionBuilder();
208 $conditionBuilder->add('userID IN (?)', array($this->objectIDs));
209 $sql = "UPDATE wcf".WCF_N."_user
210 SET banned = ?,
211 banReason = ?
212 ".$conditionBuilder;
213 $statement = WCF::getDB()->prepareStatement($sql);
214 $statement->execute(
215 array_merge(array(1, $this->parameters['banReason']), $conditionBuilder->getParameters())
216 );
bbef7ed8
MW
217
218 $this->unmarkItems();
11cf19be
MW
219 }
220
221 /**
222 * Unbans users.
223 */
224 public function unban() {
225 $conditionBuilder = new PreparedStatementConditionBuilder();
226 $conditionBuilder->add('userID IN (?)', array($this->objectIDs));
227 $sql = "UPDATE wcf".WCF_N."_user
228 SET banned = 0
229 ".$conditionBuilder;
230 $statement = WCF::getDB()->prepareStatement($sql);
231 $statement->execute($conditionBuilder->getParameters());
232 }
233
11ade432
AE
234 /**
235 * Creates a new user.
236 *
237 * @return User
238 */
239 public function create() {
240 $user = parent::create();
241 $userEditor = new UserEditor($user);
242
243 // updates user options
244 if (isset($this->parameters['options'])) {
245 $userEditor->updateUserOptions($this->parameters['options']);
246 }
247
248 // insert user groups
2bb10466 249 $addDefaultGroups = (isset($this->parameters['addDefaultGroups'])) ? $this->parameters['addDefaultGroups'] : true;
11ade432 250 $groupIDs = (isset($this->parameters['groups'])) ? $this->parameters['groups'] : array();
2bb10466 251 $userEditor->addToGroups($groupIDs, false, $addDefaultGroups);
11ade432
AE
252
253 // insert visible languages
254 $languageIDs = (isset($this->parameters['languages'])) ? $this->parameters['languages'] : array();
695780d7 255 $userEditor->addToLanguages($languageIDs, false);
11ade432 256
320f4a6d
MW
257 if (PACKAGE_ID) {
258 // set default notifications
259 $sql = "INSERT INTO wcf".WCF_N."_user_notification_event_to_user
260 (userID, eventID)
695780d7
MW
261 SELECT ?, eventID
262 FROM wcf".WCF_N."_user_notification_event
263 WHERE preset = ?";
320f4a6d 264 $statement = WCF::getDB()->prepareStatement($sql);
695780d7 265 $statement->execute(array($user->userID, 1));
320f4a6d
MW
266 }
267
11ade432
AE
268 return $user;
269 }
835fa8c2
AE
270
271 /**
272 * @see wcf\data\AbstractDatabaseObjectAction::update()
273 */
274 public function update() {
881246d6
AE
275 if (isset($this->parameters['data'])) {
276 parent::update();
8a3258f5
MS
277
278 if (isset($this->parameters['data']['languageID'])) {
279 foreach ($this->objects as $object) {
280 if ($object->userID == WCF::getUser()->userID) {
281 if ($this->parameters['data']['languageID'] != WCF::getUser()->languageID) {
282 WCF::setLanguage($this->parameters['data']['languageID']);
283 }
284
285 break;
286 }
287 }
288 }
881246d6
AE
289 }
290 else {
15fa2802 291 if (empty($this->objects)) {
881246d6
AE
292 $this->readObjects();
293 }
294 }
835fa8c2
AE
295
296 $groupIDs = (isset($this->parameters['groups'])) ? $this->parameters['groups'] : array();
44adccf6 297 $languageIDs = (isset($this->parameters['languageIDs'])) ? $this->parameters['languageIDs'] : array();
835fa8c2 298 $removeGroups = (isset($this->parameters['removeGroups'])) ? $this->parameters['removeGroups'] : array();
f277d540 299 $userOptions = (isset($this->parameters['options'])) ? $this->parameters['options'] : array();
835fa8c2 300
c2000c5d 301 if (!empty($groupIDs)) {
12f80a9d
MW
302 $action = new UserAction($this->objects, 'addToGroups', array(
303 'groups' => $groupIDs,
304 'addDefaultGroups' => false
305 ));
c2000c5d
MW
306 $action->executeAction();
307 }
308
835fa8c2 309 foreach ($this->objects as $userEditor) {
f277d540 310 if (!empty($removeGroups)) {
835fa8c2
AE
311 $userEditor->removeFromGroups($removeGroups);
312 }
f277d540
AE
313
314 if (!empty($userOptions)) {
315 $userEditor->updateUserOptions($userOptions);
316 }
44adccf6
AE
317
318 if (!empty($languageIDs)) {
319 $userEditor->addToLanguages($languageIDs);
320 }
835fa8c2
AE
321 }
322 }
d5cab442 323
0dd6ea0c
MW
324 /**
325 * Add users to given groups.
326 */
c2000c5d
MW
327 public function addToGroups() {
328 if (empty($this->objects)) {
329 $this->readObjects();
330 }
331
332 $groupIDs = $this->parameters['groups'];
333 $deleteOldGroups = $addDefaultGroups = true;
334 if (isset($this->parameters['deleteOldGroups'])) $deleteOldGroups = $this->parameters['deleteOldGroups'];
335 if (isset($this->parameters['addDefaultGroups'])) $addDefaultGroups = $this->parameters['addDefaultGroups'];
336
337 foreach ($this->objects as $userEditor) {
338 $userEditor->addToGroups($groupIDs, $deleteOldGroups, $addDefaultGroups);
339 }
320f4a6d
MW
340
341 if (MODULE_USER_RANK) {
342 $action = new UserProfileAction($this->objects, 'updateUserRank');
343 $action->executeAction();
344 }
345 if (MODULE_USERS_ONLINE) {
346 $action = new UserProfileAction($this->objects, 'updateUserOnlineMarking');
347 $action->executeAction();
348 }
c2000c5d
MW
349 }
350
a7fd745e 351 /**
a427a8c8 352 * @see wcf\data\ISearchAction::validateGetSearchResultList()
a7fd745e 353 */
a427a8c8 354 public function validateGetSearchResultList() {
a54f8d8f
AE
355 $this->readBoolean('includeUserGroups', false, 'data');
356 $this->readString('searchString', false, 'data');
a7fd745e
AE
357
358 if (isset($this->parameters['data']['excludedSearchValues']) && !is_array($this->parameters['data']['excludedSearchValues'])) {
3631f7bd 359 throw new UserInputException('excludedSearchValues');
a7fd745e 360 }
d5cab442
AE
361 }
362
a7fd745e 363 /**
a427a8c8 364 * @see wcf\data\ISearchAction::getSearchResultList()
a7fd745e 365 */
a427a8c8 366 public function getSearchResultList() {
d5cab442 367 $searchString = $this->parameters['data']['searchString'];
c000b08a
MS
368 $excludedSearchValues = array();
369 if (isset($this->parameters['data']['excludedSearchValues'])) {
370 $excludedSearchValues = $this->parameters['data']['excludedSearchValues'];
371 }
d5cab442 372 $list = array();
9f959ced 373
d5cab442
AE
374 if ($this->parameters['data']['includeUserGroups']) {
375 $accessibleGroups = UserGroup::getAccessibleGroups();
376 foreach ($accessibleGroups as $group) {
18c05238 377 $groupName = $group->getName();
c000b08a 378 if (!in_array($groupName, $excludedSearchValues)) {
838e315b 379 $pos = mb_strripos($groupName, $searchString);
c000b08a
MS
380 if ($pos !== false && $pos == 0) {
381 $list[] = array(
382 'label' => $groupName,
383 'objectID' => $group->groupID,
384 'type' => 'group'
385 );
386 }
d5cab442
AE
387 }
388 }
389 }
c000b08a 390
c2d0b2d6
MS
391 // find users
392 $userProfileList = new UserProfileList();
393 $userProfileList->getConditionBuilder()->add("username LIKE ?", array($searchString.'%'));
15fa2802 394 if (!empty($excludedSearchValues)) {
c2d0b2d6 395 $userProfileList->getConditionBuilder()->add("username NOT IN (?)", array($excludedSearchValues));
c000b08a 396 }
c2d0b2d6
MS
397 $userProfileList->sqlLimit = 10;
398 $userProfileList->readObjects();
9f959ced 399
c2d0b2d6 400 foreach ($userProfileList as $userProfile) {
d5cab442 401 $list[] = array(
c2d0b2d6
MS
402 'icon' => $userProfile->getAvatar()->getImageTag(16),
403 'label' => $userProfile->username,
404 'objectID' => $userProfile->userID,
d5cab442
AE
405 'type' => 'user'
406 );
407 }
9f959ced 408
d5cab442
AE
409 return $list;
410 }
49c164a8
AE
411
412 /**
7918ddba 413 * @see wcf\data\IClipboardAction::validateUnmarkAll()
49c164a8 414 */
fbb077d4
MS
415 public function validateUnmarkAll() {
416 // does nothing
417 }
49c164a8
AE
418
419 /**
7918ddba 420 * @see wcf\data\IClipboardAction::unmarkAll()
49c164a8
AE
421 */
422 public function unmarkAll() {
423 ClipboardHandler::getInstance()->removeItems(ClipboardHandler::getInstance()->getObjectTypeID('com.woltlab.wcf.user'));
424 }
bbef7ed8
MW
425
426 /**
427 * Unmarks users.
428 *
429 * @param array<integer> $userIDs
430 */
431 protected function unmarkItems(array $userIDs = array()) {
432 if (empty($userIDs)) {
433 $userIDs = $this->objectIDs;
434 }
e3369fd2 435
bbef7ed8
MW
436 if (!empty($userIDs)) {
437 ClipboardHandler::getInstance()->unmark($userIDs, ClipboardHandler::getInstance()->getObjectTypeID('com.woltlab.wcf.user'));
438 }
439 }
2fe45e04
MW
440
441 /**
442 * Validates the enable action.
443 */
444 public function validateEnable() {
445 WCF::getSession()->checkPermissions(array('admin.user.canEnableUser'));
9927f711
MS
446
447 $this->__validateAccessibleGroups();
2fe45e04
MW
448 }
449
450 /**
451 * Validates the disable action.
452 */
453 public function validateDisable() {
454 $this->validateEnable();
455 }
456
457 /**
458 * Enables users.
459 */
460 public function enable() {
461 if (empty($this->objects)) $this->readObjects();
9927f711 462
2fe45e04
MW
463 $action = new UserAction($this->objects, 'update', array(
464 'data' => array(
465 'activationCode' => 0
466 ),
2818981f 467 'removeGroups' => UserGroup::getGroupIDsByType(array(UserGroup::GUESTS))
2fe45e04
MW
468 ));
469 $action->executeAction();
2818981f
MW
470 $action = new UserAction($this->objects, 'addToGroups', array(
471 'groups' => UserGroup::getGroupIDsByType(array(UserGroup::USERS)),
472 'deleteOldGroups' => false,
9927f711 473 'addDefaultGroups' => false
2818981f 474 ));
2fe45e04
MW
475 $action->executeAction();
476 }
477
478 /**
479 * Disables users.
480 */
481 public function disable() {
482 if (empty($this->objects)) $this->readObjects();
9927f711 483
2fe45e04
MW
484 $action = new UserAction($this->objects, 'update', array(
485 'data' => array(
486 'activationCode' => UserRegistrationUtil::getActivationCode()
487 ),
2818981f 488 'removeGroups' => UserGroup::getGroupIDsByType(array(UserGroup::USERS)),
2fe45e04
MW
489 ));
490 $action->executeAction();
2818981f
MW
491 $action = new UserAction($this->objects, 'addToGroups', array(
492 'groups' => UserGroup::getGroupIDsByType(array(UserGroup::GUESTS)),
493 'deleteOldGroups' => false,
494 'addDefaultGroups' => false
495 ));
2fe45e04
MW
496 $action->executeAction();
497 }
11ade432 498}