3 namespace wcf\acp\page
;
5 use wcf\data\user\group\UserGroup
;
6 use wcf\data\user\option\ViewableUserOption
;
7 use wcf\data\user\User
;
8 use wcf\data\user\UserProfile
;
9 use wcf\page\SortablePage
;
10 use wcf\system\cache\builder\UserOptionCacheBuilder
;
11 use wcf\system\clipboard\ClipboardHandler
;
12 use wcf\system\database\util\PreparedStatementConditionBuilder
;
13 use wcf\system\event\EventHandler
;
14 use wcf\system\exception\IllegalLinkException
;
15 use wcf\system\option\IOptionHandler
;
16 use wcf\system\option\user\IUserOptionOutput
;
17 use wcf\system\request\LinkHandler
;
19 use wcf\util\DateUtil
;
20 use wcf\util\StringUtil
;
23 * Shows the result of a user search.
26 * @copyright 2001-2019 WoltLab GmbH
27 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
28 * @package WoltLabSuite\Core\Acp\Page
30 class UserListPage
extends SortablePage
33 * list of displayed column names
36 public $columnHeads = [];
39 * list of selected columns
42 public $columns = ['registrationDate', 'lastActivityTime'];
45 * applies special CSS classes for selected columns
48 public $columnStyling = [
49 'registrationDate' => 'columnDate',
50 'lastActivityTime' => 'columnDate',
51 'profileHits' => 'columnDigits',
52 'activityPoints' => 'columnDigits',
53 'likesReceived' => 'columnDigits',
57 * list of column values
60 public $columnValues = [];
65 public $defaultSortField = 'username';
70 public $itemsPerPage = 50;
73 * list of marked user ids
76 public $markedUsers = [];
81 public $neededPermissions = ['admin.user.canSearchUser'];
84 * IOptionHandler object
87 protected $optionHandler;
90 * list of available user option names
105 public $userIDs = [];
120 * condition builder for user filtering
121 * @var PreparedStatementConditionBuilder
128 public $validSortFields = [
141 public function readParameters()
143 parent
::readParameters();
145 $this->conditions
= new PreparedStatementConditionBuilder();
147 if (!empty($_REQUEST['id'])) {
148 $this->searchID
= \
intval($_REQUEST['id']);
149 if ($this->searchID
) {
150 $this->readSearchResult();
152 if (empty($this->userIDs
)) {
153 throw new IllegalLinkException();
155 $this->conditions
->add("user_table.userID IN (?)", [$this->userIDs
]);
159 $this->readUserOptions();
165 public function validateSortField()
167 // add options to valid sort fields
168 $this->validSortFields
= \array_merge
($this->validSortFields
, \array_keys
($this->options
));
170 // avoid leaking mail adresses by sorting
171 if (WCF
::getSession()->getPermission('admin.user.canEditMailAddress')) {
172 $this->validSortFields
[] = 'email';
175 parent
::validateSortField();
181 public function readData()
185 // add email column for authorized users
186 if (WCF
::getSession()->getPermission('admin.user.canEditMailAddress')) {
187 \array_unshift
($this->columns
, 'email');
191 $this->markedUsers
= WCF
::getSession()->getVar('markedUsers');
192 if ($this->markedUsers
== null ||
!\
is_array($this->markedUsers
)) {
193 $this->markedUsers
= [];
197 $this->readColumnsHeads();
203 $this->url
= LinkHandler
::getInstance()->getLink(
206 'searchID=' . $this->searchID
. '&action=' . \rawurlencode
($this->action
) . '&pageNo=' . $this->pageNo
. '&sortField=' . $this->sortField
. '&sortOrder=' . $this->sortOrder
213 public function assignVariables()
215 parent
::assignVariables();
217 WCF
::getTPL()->assign([
218 'users' => $this->users
,
219 'searchID' => $this->searchID
,
220 'hasMarkedItems' => ClipboardHandler
::getInstance()->hasMarkedItems(ClipboardHandler
::getInstance()->getObjectTypeID('com.woltlab.wcf.user')),
222 'columnHeads' => $this->columnHeads
,
223 'columnValues' => $this->columnValues
,
224 'columnStyling' => $this->columnStyling
,
231 public function show()
233 $this->activeMenuItem
= 'wcf.acp.menu.link.user.' . ($this->searchID ?
'search' : 'list');
241 public function countItems()
243 // call countItems event
244 EventHandler
::getInstance()->fireAction($this, 'countItems');
246 $sql = "SELECT COUNT(*)
247 FROM wcf" . WCF_N
. "_user user_table
248 " . $this->conditions
;
249 $statement = WCF
::getDB()->prepareStatement($sql);
250 $statement->execute($this->conditions
->getParameters());
252 return $statement->fetchSingleColumn();
256 * Fetches the list of results.
258 protected function readUsers()
261 $sql = "SELECT user_table.userID
262 FROM wcf" . WCF_N
. "_user user_table
263 " . (isset($this->options
[$this->sortField
]) ?
"
264 LEFT JOIN wcf" . WCF_N
. "_user_option_value user_option_value
265 ON user_option_value.userID = user_table.userID
267 " . $this->conditions
. "
268 ORDER BY " . (($this->sortField
!= 'email' && isset($this->options
[$this->sortField
])) ?
'user_option_value.userOption' . $this->options
[$this->sortField
]->optionID
: $this->sortField
) . " " . $this->sortOrder
;
269 $statement = WCF
::getDB()->prepareStatement(
272 ($this->pageNo
- 1) * $this->itemsPerPage
274 $statement->execute($this->conditions
->getParameters());
275 $userIDs = $statement->fetchAll(\PDO
::FETCH_COLUMN
);
278 if (!empty($userIDs)) {
280 $conditions = new PreparedStatementConditionBuilder();
281 $conditions->add("user_table.userID IN (?)", [$userIDs]);
283 $sql = "SELECT userID, groupID
284 FROM wcf" . WCF_N
. "_user_to_group user_table
286 $statement = WCF
::getDB()->prepareStatement($sql);
287 $statement->execute($conditions->getParameters());
288 $userToGroups = $statement->fetchMap('userID', 'groupID', false);
290 $sql = "SELECT user_avatar.*, option_value.*, user_table.*
291 FROM wcf" . WCF_N
. "_user user_table
292 LEFT JOIN wcf" . WCF_N
. "_user_option_value option_value
293 ON option_value.userID = user_table.userID
294 LEFT JOIN wcf" . WCF_N
. "_user_avatar user_avatar
295 ON user_avatar.avatarID = user_table.avatarID
297 ORDER BY " . (($this->sortField
!= 'email' && isset($this->options
[$this->sortField
])) ?
'option_value.userOption' . $this->options
[$this->sortField
]->optionID
: 'user_table.' . $this->sortField
) . " " . $this->sortOrder
;
298 $statement = WCF
::getDB()->prepareStatement($sql);
299 $statement->execute($conditions->getParameters());
300 while ($row = $statement->fetchArray()) {
301 $groupIDs = ($userToGroups[$row['userID']] ??
[]);
303 $row['groupIDs'] = \
implode(',', $groupIDs);
304 $accessible = (!empty($groupIDs) ? UserGroup
::isAccessibleGroup($groupIDs) : true);
305 $row['accessible'] = $accessible;
306 $row['deletable'] = ($accessible && WCF
::getSession()->getPermission('admin.user.canDeleteUser') && $row['userID'] != WCF
::getUser()->userID
) ?
1 : 0;
307 $row['editable'] = ($accessible && WCF
::getSession()->getPermission('admin.user.canEditUser')) ?
1 : 0;
308 $row['bannable'] = ($accessible && WCF
::getSession()->getPermission('admin.user.canBanUser') && $row['userID'] != WCF
::getUser()->userID
) ?
1 : 0;
309 $row['canBeEnabled'] = ($accessible && WCF
::getSession()->getPermission('admin.user.canEnableUser') && $row['userID'] != WCF
::getUser()->userID
) ?
1 : 0;
310 $row['isMarked'] = \
intval(\
in_array($row['userID'], $this->markedUsers
));
312 $this->users
[] = new UserProfile(new User(null, $row));
315 // get special columns
316 foreach ($this->users
as $key => $user) {
317 foreach ($this->columns
as $column) {
320 $this->columnValues
[$user->userID
][$column] = '<a href="mailto:' . StringUtil
::encodeHTML($user->email
) . '">' . StringUtil
::encodeHTML($user->email
) . '</a>';
323 case 'registrationDate':
324 $this->columnValues
[$user->userID
][$column] = DateUtil
::format(
325 DateUtil
::getDateTimeByTimestamp($user->{$column}),
326 DateUtil
::DATE_FORMAT
330 case 'lastActivityTime':
331 if ($user->{$column}) {
332 $this->columnValues
[$user->userID
][$column] = \
str_replace(
335 DateUtil
::getDateTimeByTimestamp($user->{$column}),
336 DateUtil
::TIME_FORMAT
341 DateUtil
::getDateTimeByTimestamp($user->{$column}),
342 DateUtil
::DATE_FORMAT
344 WCF
::getLanguage()->get('wcf.date.dateTimeFormat')
351 case 'activityPoints':
352 case 'likesReceived':
353 $this->columnValues
[$user->userID
][$column] = StringUtil
::formatInteger($user->{$column});
357 if (isset($this->options
[$column])) {
358 if ($this->options
[$column]->outputClass
) {
359 $this->options
[$column]->setOptionValue($user->getDecoratedObject());
361 /** @var IUserOptionOutput $outputObj */
362 $outputObj = $this->options
[$column]->getOutputObject();
363 $this->columnValues
[$user->userID
][$column] = $outputObj->getOutput(
364 $user->getDecoratedObject(),
365 $this->options
[$column]->getDecoratedObject(),
369 $this->columnValues
[$user->userID
][$column] = StringUtil
::encodeHTML($user->{$column});
380 * Fetches the result of the search with the given search id.
382 protected function readSearchResult()
384 // get user search from database
385 $sql = "SELECT searchData
386 FROM wcf" . WCF_N
. "_search
390 $statement = WCF
::getDB()->prepareStatement($sql);
391 $statement->execute([
393 WCF
::getUser()->userID
,
396 $search = $statement->fetchArray();
397 if (!isset($search['searchData'])) {
398 throw new IllegalLinkException();
401 $data = \
unserialize($search['searchData']);
402 $this->userIDs
= $data['matches'];
403 $this->itemsPerPage
= $data['itemsPerPage'];
404 $this->columns
= $data['columns'];
409 * Fetches the user options from cache.
411 protected function readUserOptions()
413 $this->options
= UserOptionCacheBuilder
::getInstance()->getData([], 'options');
415 foreach ($this->options
as &$option) {
416 $option = new ViewableUserOption($option);
422 * Reads the column heads.
424 protected function readColumnsHeads()
426 foreach ($this->columns
as $column) {
427 if ($column == 'likesReceived') {
428 $this->columnHeads
[$column] = 'wcf.like.likesReceived';
431 if ($column == 'activityPoints') {
432 $this->columnHeads
[$column] = 'wcf.user.activityPoint';
436 if (isset($this->options
[$column]) && $column != 'email') {
437 $this->columnHeads
[$column] = 'wcf.user.option.' . $column;
439 $this->columnHeads
[$column] = 'wcf.user.' . $column;
447 protected function initObjectList()
455 protected function readObjects()