AJAX error handling overhaul
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / data / user / UserAction.class.php
1 <?php
2 namespace wcf\data\user;
3 use wcf\data\user\group\UserGroup;
4 use wcf\data\AbstractDatabaseObjectAction;
5 use wcf\data\IClipboardAction;
6 use wcf\data\ISearchAction;
7 use wcf\system\clipboard\ClipboardHandler;
8 use wcf\system\database\util\PreparedStatementConditionBuilder;
9 use wcf\system\exception\PermissionDeniedException;
10 use wcf\system\exception\UserInputException;
11 use wcf\system\WCF;
12 use wcf\util\StringUtil;
13
14 /**
15 * Executes user-related actions.
16 *
17 * @author Alexander Ebert
18 * @copyright 2001-2012 WoltLab GmbH
19 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
20 * @package com.woltlab.wcf
21 * @subpackage data.user
22 * @category Community Framework
23 */
24 class UserAction extends AbstractDatabaseObjectAction implements IClipboardAction, ISearchAction {
25 /**
26 * @see wcf\data\AbstractDatabaseObjectAction::$className
27 */
28 public $className = 'wcf\data\user\UserEditor';
29
30 /**
31 * @see wcf\data\AbstractDatabaseObjectAction::$permissionsCreate
32 */
33 protected $permissionsCreate = array('admin.user.canAddUser');
34
35 /**
36 * @see wcf\data\AbstractDatabaseObjectAction::$permissionsDelete
37 */
38 protected $permissionsDelete = array('admin.user.canDeleteUser');
39
40 /**
41 * @see wcf\data\AbstractDatabaseObjectAction::$permissionsUpdate
42 */
43 protected $permissionsUpdate = array('admin.user.canEditUser');
44
45 /**
46 * Validates permissions and parameters.
47 */
48 public function validateCreate() {
49 if (!isset($this->parameters['data']['password'])) {
50 throw new UserInputException('password');
51 }
52 }
53
54 /**
55 * Validates permissions and parameters.
56 */
57 public function validateDelete() {
58 // read and validate user objects
59 parent::validateDelete();
60
61 $userIDs = array();
62 foreach ($this->objects as $user) {
63 // you cannot delete yourself
64 if ($user->userID == WCF::getUser()->userID) {
65 continue;
66 }
67
68 $userIDs[] = $user->userID;
69 }
70
71 // list might be empty because only our own user id was given
72 if (empty($userIDs)) {
73 throw new UserInputException('objectIDs');
74 }
75
76 // validate groups
77 $conditions = new PreparedStatementConditionBuilder();
78 $conditions->add("userID IN (?)", array($userIDs));
79
80 $sql = "SELECT DISTINCT groupID
81 FROM wcf".WCF_N."_user_to_group
82 ".$conditions;
83 $statement = WCF::getDB()->prepareStatement($sql);
84 $statement->execute($conditions->getParameters());
85
86 $groupIDs = array();
87 while ($row = $statement->fetchArray()) {
88 $groupIDs[] = $row['groupID'];
89 }
90
91 if (!UserGroup::isAccessibleGroup($groupIDs)) {
92 throw new PermissionDeniedException();
93 }
94 }
95
96 /**
97 * Validates permissions and parameters.
98 */
99 public function validateUpdate() {
100 // read objects
101 if (empty($this->objects)) {
102 $this->readObjects();
103
104 if (empty($this->objects)) {
105 throw new UserInputException('objectIDs');
106 }
107 }
108
109 try {
110 WCF::getSession()->checkPermissions($this->permissionsUpdate);
111 }
112 catch (PermissionDeniedException $e) {
113 // check if we're editing ourselves
114 if (count($this->objects) == 1 && ($this->objects[0]->userID == WCF::getUser()->userID)) {
115 $count = count($this->parameters);
116 if ($count > 1 || ($count == 1 && !isset($this->parameters['options']))) {
117 throw new PermissionDeniedException();
118 }
119 }
120
121 throw new PermissionDeniedException();
122 }
123 }
124
125 /**
126 * Creates a new user.
127 *
128 * @return User
129 */
130 public function create() {
131 $user = parent::create();
132 $userEditor = new UserEditor($user);
133
134 // updates user options
135 if (isset($this->parameters['options'])) {
136 $userEditor->updateUserOptions($this->parameters['options']);
137 }
138
139 // insert user groups
140 $addDefaultGroups = (isset($this->parameters['addDefaultGroups'])) ? $this->parameters['addDefaultGroups'] : true;
141 $groupIDs = (isset($this->parameters['groups'])) ? $this->parameters['groups'] : array();
142 $userEditor->addToGroups($groupIDs, false, $addDefaultGroups);
143
144 // insert visible languages
145 $languageIDs = (isset($this->parameters['languages'])) ? $this->parameters['languages'] : array();
146 $userEditor->addToLanguages($languageIDs);
147
148 return $user;
149 }
150
151 /**
152 * @see wcf\data\AbstractDatabaseObjectAction::update()
153 */
154 public function update() {
155 if (isset($this->parameters['data'])) {
156 parent::update();
157
158 if (isset($this->parameters['data']['languageID'])) {
159 foreach ($this->objects as $object) {
160 if ($object->userID == WCF::getUser()->userID) {
161 if ($this->parameters['data']['languageID'] != WCF::getUser()->languageID) {
162 WCF::setLanguage($this->parameters['data']['languageID']);
163 }
164
165 break;
166 }
167 }
168 }
169 }
170 else {
171 if (empty($this->objects)) {
172 $this->readObjects();
173 }
174 }
175
176 $groupIDs = (isset($this->parameters['groups'])) ? $this->parameters['groups'] : array();
177 $languageIDs = (isset($this->parameters['languageIDs'])) ? $this->parameters['languageIDs'] : array();
178 $removeGroups = (isset($this->parameters['removeGroups'])) ? $this->parameters['removeGroups'] : array();
179 $userOptions = (isset($this->parameters['options'])) ? $this->parameters['options'] : array();
180
181 foreach ($this->objects as $userEditor) {
182 if (!empty($groupIDs)) {
183 $userEditor->addToGroups($groupIDs);
184 }
185
186 if (!empty($removeGroups)) {
187 $userEditor->removeFromGroups($removeGroups);
188 }
189
190 if (!empty($userOptions)) {
191 $userEditor->updateUserOptions($userOptions);
192 }
193
194 if (!empty($languageIDs)) {
195 $userEditor->addToLanguages($languageIDs);
196 }
197 }
198 }
199
200 /**
201 * @see wcf\data\ISearchAction::validateGetSearchResultList()
202 */
203 public function validateGetSearchResultList() {
204 if (!isset($this->parameters['data']['searchString'])) {
205 throw new UserInputException('searchString');
206 }
207
208 if (!isset($this->parameters['data']['includeUserGroups'])) {
209 throw new UserInputException('includeUserGroups');
210 }
211
212 if (isset($this->parameters['data']['excludedSearchValues']) && !is_array($this->parameters['data']['excludedSearchValues'])) {
213 throw new UserInputException('excludedSearchValues');
214 }
215 }
216
217 /**
218 * @see wcf\data\ISearchAction::getSearchResultList()
219 */
220 public function getSearchResultList() {
221 $searchString = $this->parameters['data']['searchString'];
222 $excludedSearchValues = array();
223 if (isset($this->parameters['data']['excludedSearchValues'])) {
224 $excludedSearchValues = $this->parameters['data']['excludedSearchValues'];
225 }
226 $list = array();
227
228 if ($this->parameters['data']['includeUserGroups']) {
229 $accessibleGroups = UserGroup::getAccessibleGroups();
230 foreach ($accessibleGroups as $group) {
231 $groupName = $group->getName();
232 if (!in_array($groupName, $excludedSearchValues)) {
233 $pos = StringUtil::indexOfIgnoreCase($groupName, $searchString);
234 if ($pos !== false && $pos == 0) {
235 $list[] = array(
236 'label' => $groupName,
237 'objectID' => $group->groupID,
238 'type' => 'group'
239 );
240 }
241 }
242 }
243 }
244
245 $conditionBuilder = new PreparedStatementConditionBuilder();
246 $conditionBuilder->add("username LIKE ?", array($searchString.'%'));
247 if (!empty($excludedSearchValues)) {
248 $conditionBuilder->add("username NOT IN (?)", array($excludedSearchValues));
249 }
250
251 // find users
252 $sql = "SELECT userID, username
253 FROM wcf".WCF_N."_user
254 ".$conditionBuilder;
255 $statement = WCF::getDB()->prepareStatement($sql, 10); /* TODO: add limit parameter */
256 $statement->execute($conditionBuilder->getParameters());
257 while ($row = $statement->fetchArray()) {
258 $list[] = array(
259 'label' => $row['username'],
260 'objectID' => $row['userID'],
261 'type' => 'user'
262 );
263 }
264
265 return $list;
266 }
267
268 /**
269 * @see wcf\data\IClipboardAction::validateUnmarkAll()
270 */
271 public function validateUnmarkAll() {
272 // does nothing
273 }
274
275 /**
276 * @see wcf\data\IClipboardAction::unmarkAll()
277 */
278 public function unmarkAll() {
279 ClipboardHandler::getInstance()->removeItems(ClipboardHandler::getInstance()->getObjectTypeID('com.woltlab.wcf.user'));
280 }
281 }