Split additional joins into multiple lines
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / data / user / online / UsersOnlineList.class.php
CommitLineData
320f4a6d 1<?php
a9229942 2
320f4a6d 3namespace wcf\data\user\online;
a9229942 4
11e9145a 5use wcf\data\option\OptionAction;
320f4a6d
MW
6use wcf\data\session\SessionList;
7use wcf\data\user\group\UserGroup;
8use wcf\data\user\User;
f990a9cc 9use wcf\data\user\UserProfile;
55bf83d4 10use wcf\system\event\EventHandler;
320f4a6d
MW
11use wcf\system\WCF;
12use wcf\util\StringUtil;
13
14/**
15 * Represents a list of currently online users.
e82bf444 16 *
a9229942
TD
17 * @author Marcel Werk
18 * @copyright 2001-2019 WoltLab GmbH
19 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
20 * @package WoltLabSuite\Core\Data\User\Online
21 *
22 * @method UserOnline current()
23 * @method UserOnline[] getObjects()
24 * @method UserOnline|null search($objectID)
25 * @property UserOnline[] $objects
320f4a6d 26 */
a9229942
TD
27class UsersOnlineList extends SessionList
28{
29 /**
30 * @inheritDoc
31 */
32 public $sqlOrderBy = 'user_table.username';
33
34 /**
35 * users online stats
36 * @var array
37 */
38 public $stats = [
39 'total' => 0,
40 'invisible' => 0,
41 'members' => 0,
42 'guests' => 0,
43 ];
44
45 /**
46 * users online markings
47 * @var array
48 */
49 public $usersOnlineMarkings;
50
51 /**
52 * @inheritDoc
53 */
54 public function __construct()
55 {
56 parent::__construct();
57
58 $this->sqlSelects .= "user_avatar.*, user_option_value.*, user_group.userOnlineMarking, user_table.*";
59
d3bd0a85
MS
60 $this->sqlConditionJoins .= "
61 LEFT JOIN wcf" . WCF_N . "_user user_table
62 ON user_table.userID = session.userID";
63 $this->sqlJoins .= "
64 LEFT JOIN wcf" . WCF_N . "_user user_table
65 ON user_table.userID = session.userID
66 LEFT JOIN wcf" . WCF_N . "_user_option_value user_option_value
67 ON user_option_value.userID = user_table.userID
68 LEFT JOIN wcf" . WCF_N . "_user_avatar user_avatar
69 ON user_avatar.avatarID = user_table.avatarID
70 LEFT JOIN wcf" . WCF_N . "_user_group user_group
71 ON user_group.groupID = user_table.userOnlineGroupID";
a9229942
TD
72
73 $this->getConditionBuilder()->add('session.lastActivityTime > ?', [TIME_NOW - USER_ONLINE_TIMEOUT]);
74 }
75
76 /**
77 * @inheritDoc
78 */
79 public function readObjects()
80 {
81 parent::readObjects();
82
83 $objects = $this->objects;
84 $this->indexToObject = $this->objects = [];
85
86 foreach ($objects as $object) {
87 $object = new UserOnline(new User(null, null, $object));
88 if (!$object->userID || self::isVisibleUser($object)) {
89 $this->objects[$object->sessionID] = $object;
90 $this->indexToObject[] = $object->sessionID;
91 }
92 }
93 $this->objectIDs = $this->indexToObject;
94 $this->rewind();
95 }
96
97 /**
98 * Fetches users online stats.
99 */
100 public function readStats()
101 {
102 $conditionBuilder = clone $this->getConditionBuilder();
103 $conditionBuilder->add('session.spiderID IS NULL');
104
105 $sql = "SELECT user_option_value.userOption" . User::getUserOptionID('canViewOnlineStatus') . " AS canViewOnlineStatus, session.userID
106 FROM wcf" . WCF_N . "_session session
107 LEFT JOIN wcf" . WCF_N . "_user_option_value user_option_value
c240c98a 108 ON user_option_value.userID = session.userID
a9229942
TD
109 " . $conditionBuilder;
110 $statement = WCF::getDB()->prepareStatement($sql);
111 $statement->execute($conditionBuilder->getParameters());
112
113 $users = $userIDs = [];
114 while ($row = $statement->fetchArray()) {
115 $this->stats['total']++;
116
117 $user = new UserOnline(new User(null, $row));
118 if ($user->userID) {
119 $this->stats['members']++;
120 $users[] = $user;
121 $userIDs[] = $user->userID;
122 } else {
123 $this->stats['guests']++;
124 }
125 }
126
127 foreach ($users as $user) {
128 if ($user->canViewOnlineStatus && !self::isVisibleUser($user)) {
129 $this->stats['invisible']++;
130 }
131 }
132 }
133
134 /**
135 * Returns a list of the users online markings.
136 *
137 * @return array
138 */
139 public function getUsersOnlineMarkings()
140 {
141 if ($this->usersOnlineMarkings === null) {
142 $this->usersOnlineMarkings = $priorities = [];
143
144 // get groups
145 foreach (UserGroup::getGroupsByType() as $group) {
146 if ($group->userOnlineMarking != '%s') {
147 $priorities[] = $group->priority;
148 $this->usersOnlineMarkings[] = \str_replace(
149 '%s',
150 StringUtil::encodeHTML(WCF::getLanguage()->get($group->groupName)),
151 $group->userOnlineMarking
152 );
153 }
154 }
155
156 // sort list
157 \array_multisort($priorities, \SORT_DESC, $this->usersOnlineMarkings);
158 }
159
160 return $this->usersOnlineMarkings;
161 }
162
163 /**
164 * Checks the users online record.
165 */
166 public function checkRecord()
167 {
168 $usersOnlineTotal = (USERS_ONLINE_RECORD_NO_GUESTS ? $this->stats['members'] : $this->stats['total']);
169 if ($usersOnlineTotal > USERS_ONLINE_RECORD) {
170 // save new record
171 $optionAction = new OptionAction([], 'import', [
172 'data' => [
173 'users_online_record' => $usersOnlineTotal,
174 'users_online_record_time' => TIME_NOW,
175 ],
176 ]);
177 $optionAction->executeAction();
178 }
179 }
180
181 /**
182 * Checks the 'canViewOnlineStatus' setting.
183 *
184 * @param int $userID
185 * @param int $canViewOnlineStatus
186 * @return bool
187 * @deprecated 5.3 Use `isVisibleUser` instead
188 */
189 public static function isVisible($userID, $canViewOnlineStatus)
190 {
191 if (WCF::getSession()->getPermission('admin.user.canViewInvisible') || $userID == WCF::getUser()->userID) {
192 return true;
193 }
194
195 $data = [
196 'result' => false,
197 'userID' => $userID,
198 'canViewOnlineStatus' => $canViewOnlineStatus,
199 ];
200
201 switch ($canViewOnlineStatus) {
202 case UserProfile::ACCESS_EVERYONE:
203 $data['result'] = true;
204 break;
205
206 case UserProfile::ACCESS_REGISTERED:
207 if (WCF::getUser()->userID) {
208 $data['result'] = true;
209 }
210 break;
211
212 case UserProfile::ACCESS_FOLLOWING:
213 /** @noinspection PhpUndefinedMethodInspection */
214 if (WCF::getUserProfileHandler()->isFollower($userID)) {
215 $data['result'] = true;
216 }
217 break;
218 }
219
220 EventHandler::getInstance()->fireAction(\get_called_class(), 'isVisible', $data);
221
222 return $data['result'];
223 }
224
225 /**
226 * Checks the 'canViewOnlineStatus' setting for the given user.
227 *
228 * @param UserOnline $userOnline
229 * @return bool
230 * @since 5.3
231 */
232 public static function isVisibleUser(UserOnline $userOnline)
233 {
234 if (WCF::getSession()->getPermission('admin.user.canViewInvisible') || $userOnline->userID == WCF::getUser()->userID) {
235 return true;
236 }
237
238 $data = [
239 'result' => false,
240 'userOnline' => $userOnline,
241 ];
242
243 switch ($userOnline->canViewOnlineStatus) {
244 case UserProfile::ACCESS_EVERYONE:
245 $data['result'] = true;
246 break;
247
248 case UserProfile::ACCESS_REGISTERED:
249 if (WCF::getUser()->userID) {
250 $data['result'] = true;
251 }
252 break;
253
254 case UserProfile::ACCESS_FOLLOWING:
255 /** @noinspection PhpUndefinedMethodInspection */
256 if (WCF::getUserProfileHandler()->isFollower($userOnline->userID)) {
257 $data['result'] = true;
258 }
259 break;
260 }
261
262 EventHandler::getInstance()->fireAction(\get_called_class(), 'isVisibleUser', $data);
263
264 return $data['result'];
265 }
320f4a6d 266}