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\user\UserEditor
;
7 use wcf\data\AbstractDatabaseObjectAction
;
8 use wcf\data\IClipboardAction
;
9 use wcf\data\ISearchAction
;
10 use wcf\system\clipboard\ClipboardHandler
;
11 use wcf\system\database\util\PreparedStatementConditionBuilder
;
12 use wcf\system\exception\PermissionDeniedException
;
13 use wcf\system\exception\UserInputException
;
14 use wcf\system\request\RequestHandler
;
16 use wcf\util\UserRegistrationUtil
;
19 * Executes user-related actions.
21 * @author Alexander Ebert
22 * @copyright 2001-2014 WoltLab GmbH
23 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
24 * @package com.woltlab.wcf
25 * @subpackage data.user
26 * @category Community Framework
28 class UserAction
extends AbstractDatabaseObjectAction
implements IClipboardAction
, ISearchAction
{
30 * @see \wcf\data\AbstractDatabaseObjectAction::$className
32 public $className = 'wcf\data\user\UserEditor';
35 * @see \wcf\data\AbstractDatabaseObjectAction::$allowGuestAccess
37 protected $allowGuestAccess = array('getSearchResultList');
40 * @see \wcf\data\AbstractDatabaseObjectAction::$permissionsCreate
42 protected $permissionsCreate = array('admin.user.canAddUser');
45 * @see \wcf\data\AbstractDatabaseObjectAction::$permissionsDelete
47 protected $permissionsDelete = array('admin.user.canDeleteUser');
50 * @see \wcf\data\AbstractDatabaseObjectAction::$permissionsUpdate
52 protected $permissionsUpdate = array('admin.user.canEditUser');
55 * @see \wcf\data\AbstractDatabaseObjectAction::$requireACP
57 protected $requireACP = array('create', 'ban', 'delete', 'disable', 'enable', 'unban');
60 * Validates permissions and parameters.
62 public function validateCreate() {
63 $this->readString('password', false, 'data');
67 * Validates accessible groups.
69 * @param boolean $ignoreOwnUser
71 protected function __validateAccessibleGroups($ignoreOwnUser = true) {
73 if (in_array(WCF
::getUser()->userID
, $this->objectIDs
)) {
74 unset($this->objectIDs
[array_search(WCF
::getUser()->userID
, $this->objectIDs
)]);
75 if (isset($this->objects
[WCF
::getUser()->userID
])) {
76 unset($this->objects
[WCF
::getUser()->userID
]);
81 // list might be empty because only our own user id was given
82 if (empty($this->objectIDs
)) {
83 throw new UserInputException('objectIDs');
87 $conditions = new PreparedStatementConditionBuilder();
88 $conditions->add("userID IN (?)", array($this->objectIDs
));
90 $sql = "SELECT DISTINCT groupID
91 FROM wcf".WCF_N
."_user_to_group
93 $statement = WCF
::getDB()->prepareStatement($sql);
94 $statement->execute($conditions->getParameters());
97 while ($row = $statement->fetchArray()) {
98 $groupIDs[] = $row['groupID'];
101 if (!UserGroup
::isAccessibleGroup($groupIDs)) {
102 throw new PermissionDeniedException();
107 * Validates permissions and parameters.
109 public function validateDelete() {
110 // read and validate user objects
111 parent
::validateDelete();
113 $this->__validateAccessibleGroups();
117 * @see \wcf\data\IDeleteAction::delete()
119 public function delete() {
120 if (empty($this->objects
)) {
121 $this->readObjects();
125 $avatarIDs = array();
126 foreach ($this->objects
as $user) {
127 if ($user->avatarID
) $avatarIDs[] = $user->avatarID
;
129 if (!empty($avatarIDs)) {
130 $action = new UserAvatarAction($avatarIDs, 'delete');
131 $action->executeAction();
134 // delete profile comments
135 if (!empty($this->objectIDs
)) {
136 $objectType = ObjectTypeCache
::getInstance()->getObjectTypeByName('com.woltlab.wcf.comment.commentableContent', 'com.woltlab.wcf.user.profileComment');
137 $conditionBuilder = new PreparedStatementConditionBuilder();
138 $conditionBuilder->add('objectTypeID = ?', array($objectType->objectTypeID
));
139 $conditionBuilder->add('objectID IN (?)', array($this->objectIDs
));
141 $sql = "DELETE FROM wcf".WCF_N
."_comment
143 $statement = WCF
::getDB()->prepareStatement($sql);
144 $statement->execute($conditionBuilder->getParameters());
147 $returnValue = parent
::delete();
153 * Validates permissions and parameters.
155 public function validateUpdate() {
157 if (empty($this->objects
)) {
158 $this->readObjects();
160 if (empty($this->objects
)) {
161 throw new UserInputException('objectIDs');
165 // disallow updating of anything except for options outside of ACP
166 if (RequestHandler
::getInstance()->isACPRequest() && (count($this->parameters
) != 1 ||
!isset($this->parameters
['options']))) {
167 throw new PermissionDeniedException();
171 WCF
::getSession()->checkPermissions($this->permissionsUpdate
);
173 catch (PermissionDeniedException
$e) {
174 // check if we're editing ourselves
175 if (count($this->objects
) == 1 && ($this->objects
[0]->userID
== WCF
::getUser()->userID
)) {
176 $count = count($this->parameters
);
177 if ($count > 1 ||
($count == 1 && !isset($this->parameters
['options']))) {
178 throw new PermissionDeniedException();
182 throw new PermissionDeniedException();
187 * Validates the ban action.
189 public function validateBan() {
190 WCF
::getSession()->checkPermissions(array('admin.user.canBanUser'));
192 $this->__validateAccessibleGroups();
196 * Validates the unban action.
198 public function validateUnban() {
199 $this->validateBan();
205 public function ban() {
206 $conditionBuilder = new PreparedStatementConditionBuilder();
207 $conditionBuilder->add('userID IN (?)', array($this->objectIDs
));
208 $sql = "UPDATE wcf".WCF_N
."_user
212 $statement = WCF
::getDB()->prepareStatement($sql);
214 array_merge(array(1, $this->parameters
['banReason']), $conditionBuilder->getParameters())
217 $this->unmarkItems();
223 public function unban() {
224 $conditionBuilder = new PreparedStatementConditionBuilder();
225 $conditionBuilder->add('userID IN (?)', array($this->objectIDs
));
226 $sql = "UPDATE wcf".WCF_N
."_user
229 $statement = WCF
::getDB()->prepareStatement($sql);
230 $statement->execute($conditionBuilder->getParameters());
234 * Creates a new user.
238 public function create() {
239 $user = parent
::create();
240 $userEditor = new UserEditor($user);
242 // updates user options
243 if (isset($this->parameters
['options'])) {
244 $userEditor->updateUserOptions($this->parameters
['options']);
247 // insert user groups
248 $addDefaultGroups = (isset($this->parameters
['addDefaultGroups'])) ?
$this->parameters
['addDefaultGroups'] : true;
249 $groupIDs = (isset($this->parameters
['groups'])) ?
$this->parameters
['groups'] : array();
250 $userEditor->addToGroups($groupIDs, false, $addDefaultGroups);
252 // insert visible languages
253 $languageIDs = (isset($this->parameters
['languages'])) ?
$this->parameters
['languages'] : array();
254 $userEditor->addToLanguages($languageIDs, false);
257 // set default notifications
258 $sql = "INSERT INTO wcf".WCF_N
."_user_notification_event_to_user
261 FROM wcf".WCF_N
."_user_notification_event
263 $statement = WCF
::getDB()->prepareStatement($sql);
264 $statement->execute(array($user->userID
, 1));
267 if (MODULE_USER_RANK
) {
268 $action = new UserProfileAction(array($userEditor), 'updateUserRank');
269 $action->executeAction();
271 // update user online marking
272 $action = new UserProfileAction(array($userEditor), 'updateUserOnlineMarking');
273 $action->executeAction();
280 * @see \wcf\data\AbstractDatabaseObjectAction::update()
282 public function update() {
283 if (isset($this->parameters
['data'])) {
286 if (isset($this->parameters
['data']['languageID'])) {
287 foreach ($this->objects
as $object) {
288 if ($object->userID
== WCF
::getUser()->userID
) {
289 if ($this->parameters
['data']['languageID'] != WCF
::getUser()->languageID
) {
290 WCF
::setLanguage($this->parameters
['data']['languageID']);
299 if (empty($this->objects
)) {
300 $this->readObjects();
304 $groupIDs = (isset($this->parameters
['groups'])) ?
$this->parameters
['groups'] : array();
305 $languageIDs = (isset($this->parameters
['languageIDs'])) ?
$this->parameters
['languageIDs'] : array();
306 $removeGroups = (isset($this->parameters
['removeGroups'])) ?
$this->parameters
['removeGroups'] : array();
307 $userOptions = (isset($this->parameters
['options'])) ?
$this->parameters
['options'] : array();
309 if (!empty($groupIDs)) {
310 $action = new UserAction($this->objects
, 'addToGroups', array(
311 'groups' => $groupIDs,
312 'addDefaultGroups' => false
314 $action->executeAction();
317 foreach ($this->objects
as $userEditor) {
318 if (!empty($removeGroups)) {
319 $userEditor->removeFromGroups($removeGroups);
322 if (!empty($userOptions)) {
323 $userEditor->updateUserOptions($userOptions);
326 if (!empty($languageIDs)) {
327 $userEditor->addToLanguages($languageIDs);
333 * Add users to given groups.
335 public function addToGroups() {
336 if (empty($this->objects
)) {
337 $this->readObjects();
340 $groupIDs = $this->parameters
['groups'];
341 $deleteOldGroups = $addDefaultGroups = true;
342 if (isset($this->parameters
['deleteOldGroups'])) $deleteOldGroups = $this->parameters
['deleteOldGroups'];
343 if (isset($this->parameters
['addDefaultGroups'])) $addDefaultGroups = $this->parameters
['addDefaultGroups'];
345 foreach ($this->objects
as $userEditor) {
346 $userEditor->addToGroups($groupIDs, $deleteOldGroups, $addDefaultGroups);
350 $this->objects
= array();
351 UserEditor
::resetCache();
352 $this->readObjects();
354 if (MODULE_USER_RANK
) {
355 $action = new UserProfileAction($this->objects
, 'updateUserRank');
356 $action->executeAction();
358 if (MODULE_USERS_ONLINE
) {
359 $action = new UserProfileAction($this->objects
, 'updateUserOnlineMarking');
360 $action->executeAction();
365 * @see \wcf\data\ISearchAction::validateGetSearchResultList()
367 public function validateGetSearchResultList() {
368 $this->readBoolean('includeUserGroups', false, 'data');
369 $this->readString('searchString', false, 'data');
371 if (isset($this->parameters
['data']['excludedSearchValues']) && !is_array($this->parameters
['data']['excludedSearchValues'])) {
372 throw new UserInputException('excludedSearchValues');
377 * @see \wcf\data\ISearchAction::getSearchResultList()
379 public function getSearchResultList() {
380 $searchString = $this->parameters
['data']['searchString'];
381 $excludedSearchValues = array();
382 if (isset($this->parameters
['data']['excludedSearchValues'])) {
383 $excludedSearchValues = $this->parameters
['data']['excludedSearchValues'];
387 if ($this->parameters
['data']['includeUserGroups']) {
388 $accessibleGroups = UserGroup
::getAccessibleGroups();
389 foreach ($accessibleGroups as $group) {
390 $groupName = $group->getName();
391 if (!in_array($groupName, $excludedSearchValues)) {
392 $pos = mb_strripos($groupName, $searchString);
393 if ($pos !== false && $pos == 0) {
395 'label' => $groupName,
396 'objectID' => $group->groupID
,
405 $userProfileList = new UserProfileList();
406 $userProfileList->getConditionBuilder()->add("username LIKE ?", array($searchString.'%'));
407 if (!empty($excludedSearchValues)) {
408 $userProfileList->getConditionBuilder()->add("username NOT IN (?)", array($excludedSearchValues));
410 $userProfileList->sqlLimit
= 10;
411 $userProfileList->readObjects();
413 foreach ($userProfileList as $userProfile) {
415 'icon' => $userProfile->getAvatar()->getImageTag(16),
416 'label' => $userProfile->username
,
417 'objectID' => $userProfile->userID
,
426 * @see \wcf\data\IClipboardAction::validateUnmarkAll()
428 public function validateUnmarkAll() {
433 * @see \wcf\data\IClipboardAction::unmarkAll()
435 public function unmarkAll() {
436 ClipboardHandler
::getInstance()->removeItems(ClipboardHandler
::getInstance()->getObjectTypeID('com.woltlab.wcf.user'));
442 * @param array<integer> $userIDs
444 protected function unmarkItems(array $userIDs = array()) {
445 if (empty($userIDs)) {
446 $userIDs = $this->objectIDs
;
449 if (!empty($userIDs)) {
450 ClipboardHandler
::getInstance()->unmark($userIDs, ClipboardHandler
::getInstance()->getObjectTypeID('com.woltlab.wcf.user'));
455 * Validates the enable action.
457 public function validateEnable() {
458 WCF
::getSession()->checkPermissions(array('admin.user.canEnableUser'));
460 $this->__validateAccessibleGroups();
464 * Validates the disable action.
466 public function validateDisable() {
467 $this->validateEnable();
473 public function enable() {
474 if (empty($this->objects
)) $this->readObjects();
476 $action = new UserAction($this->objects
, 'update', array(
478 'activationCode' => 0
480 'removeGroups' => UserGroup
::getGroupIDsByType(array(UserGroup
::GUESTS
))
482 $action->executeAction();
483 $action = new UserAction($this->objects
, 'addToGroups', array(
484 'groups' => UserGroup
::getGroupIDsByType(array(UserGroup
::USERS
)),
485 'deleteOldGroups' => false,
486 'addDefaultGroups' => false
488 $action->executeAction();
490 $this->unmarkItems();
496 public function disable() {
497 if (empty($this->objects
)) $this->readObjects();
499 $action = new UserAction($this->objects
, 'update', array(
501 'activationCode' => UserRegistrationUtil
::getActivationCode()
503 'removeGroups' => UserGroup
::getGroupIDsByType(array(UserGroup
::USERS
)),
505 $action->executeAction();
506 $action = new UserAction($this->objects
, 'addToGroups', array(
507 'groups' => UserGroup
::getGroupIDsByType(array(UserGroup
::GUESTS
)),
508 'deleteOldGroups' => false,
509 'addDefaultGroups' => false
511 $action->executeAction();
513 $this->unmarkItems();
517 * @see \wcf\data\AbstractDatabaseObjectAction::readObjects()
519 protected function readObjects() {
520 if (empty($this->objectIDs
)) {
525 $baseClass = call_user_func(array($this->className
, 'getBaseClass'));
528 $sql = "SELECT user_option_value.*, user_table.*
529 FROM wcf".WCF_N
."_user user_table
530 LEFT JOIN wcf".WCF_N
."_user_option_value user_option_value
531 ON (user_option_value.userID = user_table.userID)
532 WHERE user_table.userID IN (".str_repeat('?,', count($this->objectIDs
) - 1)."?)";
533 $statement = WCF
::getDB()->prepareStatement($sql);
534 $statement->execute($this->objectIDs
);
535 while ($object = $statement->fetchObject($baseClass)) {
536 $this->objects
[] = new $this->className($object);