2 namespace wcf\acp\page
;
3 use wcf\data\user\group\UserGroup
;
4 use wcf\data\user\option\ViewableUserOption
;
5 use wcf\data\user\User
;
6 use wcf\data\user\UserProfile
;
7 use wcf\page\SortablePage
;
8 use wcf\system\cache\builder\UserOptionCacheBuilder
;
9 use wcf\system\clipboard\ClipboardHandler
;
10 use wcf\system\database\util\PreparedStatementConditionBuilder
;
11 use wcf\system\event\EventHandler
;
12 use wcf\system\exception\IllegalLinkException
;
13 use wcf\system\option\user\IUserOptionOutput
;
14 use wcf\system\option\IOptionHandler
;
15 use wcf\system\request\LinkHandler
;
17 use wcf\util\DateUtil
;
18 use wcf\util\StringUtil
;
21 * Shows the result of a user search.
24 * @copyright 2001-2019 WoltLab GmbH
25 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
26 * @package WoltLabSuite\Core\Acp\Page
28 class UserListPage
extends SortablePage
{
30 * list of displayed column names
33 public $columnHeads = [];
36 * list of selected columns
39 public $columns = ['registrationDate', 'lastActivityTime'];
42 * applies special CSS classes for selected columns
45 public $columnStyling = [
46 'registrationDate' => 'columnDate',
47 'lastActivityTime' => 'columnDate',
48 'profileHits' => 'columnDigits',
49 'activityPoints' => 'columnDigits',
50 'likesReceived' => 'columnDigits'
54 * list of column values
57 public $columnValues = [];
62 public $defaultSortField = 'username';
67 public $itemsPerPage = 50;
70 * list of marked user ids
73 public $markedUsers = [];
78 public $neededPermissions = ['admin.user.canSearchUser'];
81 * IOptionHandler object
84 protected $optionHandler = null;
87 * list of available user option names
102 public $userIDs = [];
117 * condition builder for user filtering
118 * @var PreparedStatementConditionBuilder
120 public $conditions = null;
125 public $validSortFields = ['userID', 'registrationDate', 'username', 'lastActivityTime', 'profileHits', 'activityPoints', 'likesReceived'];
130 public function readParameters() {
131 parent
::readParameters();
133 $this->conditions
= new PreparedStatementConditionBuilder();
135 if (!empty($_REQUEST['id'])) {
136 $this->searchID
= intval($_REQUEST['id']);
137 if ($this->searchID
) $this->readSearchResult();
138 if (empty($this->userIDs
)) {
139 throw new IllegalLinkException();
141 $this->conditions
->add("user_table.userID IN (?)", [$this->userIDs
]);
145 $this->readUserOptions();
151 public function validateSortField() {
152 // add options to valid sort fields
153 $this->validSortFields
= array_merge($this->validSortFields
, array_keys($this->options
));
155 // avoid leaking mail adresses by sorting
156 if (WCF
::getSession()->getPermission('admin.user.canEditMailAddress')) {
157 $this->validSortFields
[] = 'email';
160 parent
::validateSortField();
166 public function readData() {
169 // add email column for authorized users
170 if (WCF
::getSession()->getPermission('admin.user.canEditMailAddress')) {
171 array_unshift($this->columns
, 'email');
175 $this->markedUsers
= WCF
::getSession()->getVar('markedUsers');
176 if ($this->markedUsers
== null ||
!is_array($this->markedUsers
)) $this->markedUsers
= [];
179 $this->readColumnsHeads();
185 $this->url
= LinkHandler
::getInstance()->getLink('UserList', [], 'searchID='.$this->searchID
.'&action='.rawurlencode($this->action
).'&pageNo='.$this->pageNo
.'&sortField='.$this->sortField
.'&sortOrder='.$this->sortOrder
);
191 public function assignVariables() {
192 parent
::assignVariables();
194 WCF
::getTPL()->assign([
195 'users' => $this->users
,
196 'searchID' => $this->searchID
,
197 'hasMarkedItems' => ClipboardHandler
::getInstance()->hasMarkedItems(ClipboardHandler
::getInstance()->getObjectTypeID('com.woltlab.wcf.user')),
199 'columnHeads' => $this->columnHeads
,
200 'columnValues' => $this->columnValues
,
201 'columnStyling' => $this->columnStyling
208 public function show() {
209 $this->activeMenuItem
= 'wcf.acp.menu.link.user.'.($this->searchID ?
'search' : 'list');
217 public function countItems() {
218 // call countItems event
219 EventHandler
::getInstance()->fireAction($this, 'countItems');
221 $sql = "SELECT COUNT(*)
222 FROM wcf".WCF_N
."_user user_table
224 $statement = WCF
::getDB()->prepareStatement($sql);
225 $statement->execute($this->conditions
->getParameters());
227 return $statement->fetchSingleColumn();
231 * Fetches the list of results.
233 protected function readUsers() {
235 $sql = "SELECT user_table.userID
236 FROM wcf".WCF_N
."_user user_table
237 ".(isset($this->options
[$this->sortField
]) ?
"LEFT JOIN wcf".WCF_N
."_user_option_value user_option_value ON (user_option_value.userID = user_table.userID)" : '')."
238 ".$this->conditions
."
239 ORDER BY ".(($this->sortField
!= 'email' && isset($this->options
[$this->sortField
])) ?
'user_option_value.userOption'.$this->options
[$this->sortField
]->optionID
: $this->sortField
)." ".$this->sortOrder
;
240 $statement = WCF
::getDB()->prepareStatement($sql, $this->itemsPerPage
, ($this->pageNo
- 1) * $this->itemsPerPage
);
241 $statement->execute($this->conditions
->getParameters());
242 $userIDs = $statement->fetchAll(\PDO
::FETCH_COLUMN
);
245 if (!empty($userIDs)) {
247 $conditions = new PreparedStatementConditionBuilder();
248 $conditions->add("user_table.userID IN (?)", [$userIDs]);
250 $sql = "SELECT userID, groupID
251 FROM wcf".WCF_N
."_user_to_group user_table
253 $statement = WCF
::getDB()->prepareStatement($sql);
254 $statement->execute($conditions->getParameters());
255 $userToGroups = $statement->fetchMap('userID', 'groupID', false);
257 $sql = "SELECT user_avatar.*, option_value.*, user_table.*
258 FROM wcf".WCF_N
."_user user_table
259 LEFT JOIN wcf".WCF_N
."_user_option_value option_value
260 ON (option_value.userID = user_table.userID)
261 LEFT JOIN wcf".WCF_N
."_user_avatar user_avatar
262 ON (user_avatar.avatarID = user_table.avatarID)
264 ORDER BY ".(($this->sortField
!= 'email' && isset($this->options
[$this->sortField
])) ?
'option_value.userOption'.$this->options
[$this->sortField
]->optionID
: 'user_table.'.$this->sortField
)." ".$this->sortOrder
;
265 $statement = WCF
::getDB()->prepareStatement($sql);
266 $statement->execute($conditions->getParameters());
267 while ($row = $statement->fetchArray()) {
268 $groupIDs = (isset($userToGroups[$row['userID']]) ?
$userToGroups[$row['userID']] : []);
270 $row['groupIDs'] = implode(',', $groupIDs);
271 $accessible = (!empty($groupIDs) ? UserGroup
::isAccessibleGroup($groupIDs) : true);
272 $row['accessible'] = $accessible;
273 $row['deletable'] = ($accessible && WCF
::getSession()->getPermission('admin.user.canDeleteUser') && $row['userID'] != WCF
::getUser()->userID
) ?
1 : 0;
274 $row['editable'] = ($accessible && WCF
::getSession()->getPermission('admin.user.canEditUser')) ?
1 : 0;
275 $row['bannable'] = ($accessible && WCF
::getSession()->getPermission('admin.user.canBanUser') && $row['userID'] != WCF
::getUser()->userID
) ?
1 : 0;
276 $row['canBeEnabled'] = ($accessible && WCF
::getSession()->getPermission('admin.user.canEnableUser') && $row['userID'] != WCF
::getUser()->userID
) ?
1 : 0;
277 $row['isMarked'] = intval(in_array($row['userID'], $this->markedUsers
));
279 $this->users
[] = new UserProfile(new User(null, $row));
282 // get special columns
283 foreach ($this->users
as $key => $user) {
284 foreach ($this->columns
as $column) {
287 $this->columnValues
[$user->userID
][$column] = '<a href="mailto:'.StringUtil
::encodeHTML($user->email
).'">'.StringUtil
::encodeHTML($user->email
).'</a>';
290 case 'registrationDate':
291 $this->columnValues
[$user->userID
][$column] = DateUtil
::format(DateUtil
::getDateTimeByTimestamp($user->{$column}), DateUtil
::DATE_FORMAT
);
294 case 'lastActivityTime':
295 if ($user->{$column}) {
296 $this->columnValues
[$user->userID
][$column] = str_replace('%time%', DateUtil
::format(DateUtil
::getDateTimeByTimestamp($user->{$column}), DateUtil
::TIME_FORMAT
), str_replace('%date%', DateUtil
::format(DateUtil
::getDateTimeByTimestamp($user->{$column}), DateUtil
::DATE_FORMAT
), WCF
::getLanguage()->get('wcf.date.dateTimeFormat')));
301 case 'activityPoints':
302 case 'likesReceived':
303 $this->columnValues
[$user->userID
][$column] = StringUtil
::formatInteger($user->{$column});
307 if (isset($this->options
[$column])) {
308 if ($this->options
[$column]->outputClass
) {
309 $this->options
[$column]->setOptionValue($user->getDecoratedObject());
311 /** @var IUserOptionOutput $outputObj */
312 $outputObj = $this->options
[$column]->getOutputObject();
313 $this->columnValues
[$user->userID
][$column] = $outputObj->getOutput($user->getDecoratedObject(), $this->options
[$column]->getDecoratedObject(), $user->{$column});
316 $this->columnValues
[$user->userID
][$column] = StringUtil
::encodeHTML($user->{$column});
327 * Fetches the result of the search with the given search id.
329 protected function readSearchResult() {
330 // get user search from database
331 $sql = "SELECT searchData
332 FROM wcf".WCF_N
."_search
336 $statement = WCF
::getDB()->prepareStatement($sql);
337 $statement->execute([
339 WCF
::getUser()->userID
,
342 $search = $statement->fetchArray();
343 if (!isset($search['searchData'])) {
344 throw new IllegalLinkException();
347 $data = unserialize($search['searchData']);
348 $this->userIDs
= $data['matches'];
349 $this->itemsPerPage
= $data['itemsPerPage'];
350 $this->columns
= $data['columns'];
355 * Fetches the user options from cache.
357 protected function readUserOptions() {
358 $this->options
= UserOptionCacheBuilder
::getInstance()->getData([], 'options');
360 foreach ($this->options
as &$option) {
361 $option = new ViewableUserOption($option);
367 * Reads the column heads.
369 protected function readColumnsHeads() {
370 foreach ($this->columns
as $column) {
371 if ($column == 'likesReceived') {
372 $this->columnHeads
[$column] = 'wcf.like.likesReceived';
375 if ($column == 'activityPoints') {
376 $this->columnHeads
[$column] = 'wcf.user.activityPoint';
380 if (isset($this->options
[$column]) && $column != 'email') {
381 $this->columnHeads
[$column] = 'wcf.user.option.'.$column;
384 $this->columnHeads
[$column] = 'wcf.user.'.$column;
392 protected function initObjectList() {
399 protected function readObjects() {