1 | <?php |
||
2 | |||
3 | /** |
||
4 | * This file is mainly concerned with the Who's Online list. |
||
5 | * Although, it also handles credits. :P |
||
6 | * |
||
7 | * Simple Machines Forum (SMF) |
||
8 | * |
||
9 | * @package SMF |
||
10 | * @author Simple Machines https://www.simplemachines.org |
||
11 | * @copyright 2022 Simple Machines and individual contributors |
||
12 | * @license https://www.simplemachines.org/about/smf/license.php BSD |
||
13 | * |
||
14 | * @version 2.1.2 |
||
15 | */ |
||
16 | |||
17 | if (!defined('SMF')) |
||
18 | die('No direct access...'); |
||
19 | |||
20 | /** |
||
21 | * Who's online, and what are they doing? |
||
22 | * This function prepares the who's online data for the Who template. |
||
23 | * It requires the who_view permission. |
||
24 | * It is enabled with the who_enabled setting. |
||
25 | * It is accessed via ?action=who. |
||
26 | * |
||
27 | * Uses Who template, main sub-template |
||
28 | * Uses Who language file. |
||
29 | */ |
||
30 | function Who() |
||
31 | { |
||
32 | global $context, $scripturl, $txt, $modSettings, $memberContext, $smcFunc; |
||
33 | |||
34 | // Permissions, permissions, permissions. |
||
35 | isAllowedTo('who_view'); |
||
36 | |||
37 | // You can't do anything if this is off. |
||
38 | if (empty($modSettings['who_enabled'])) |
||
39 | fatal_lang_error('who_off', false); |
||
40 | |||
41 | // Discourage robots from indexing this page. |
||
42 | $context['robot_no_index'] = true; |
||
43 | |||
44 | // Load the 'Who' template. |
||
45 | loadTemplate('Who'); |
||
46 | loadLanguage('Who'); |
||
47 | |||
48 | // Sort out... the column sorting. |
||
49 | $sort_methods = array( |
||
50 | 'user' => 'mem.real_name', |
||
51 | 'time' => 'lo.log_time' |
||
52 | ); |
||
53 | |||
54 | $show_methods = array( |
||
55 | 'members' => '(lo.id_member != 0)', |
||
56 | 'guests' => '(lo.id_member = 0)', |
||
57 | 'all' => '1=1', |
||
58 | ); |
||
59 | |||
60 | // Store the sort methods and the show types for use in the template. |
||
61 | $context['sort_methods'] = array( |
||
62 | 'user' => $txt['who_user'], |
||
63 | 'time' => $txt['who_time'], |
||
64 | ); |
||
65 | $context['show_methods'] = array( |
||
66 | 'all' => $txt['who_show_all'], |
||
67 | 'members' => $txt['who_show_members_only'], |
||
68 | 'guests' => $txt['who_show_guests_only'], |
||
69 | ); |
||
70 | |||
71 | // Can they see spiders too? |
||
72 | if (!empty($modSettings['show_spider_online']) && ($modSettings['show_spider_online'] == 2 || allowedTo('admin_forum')) && !empty($modSettings['spider_name_cache'])) |
||
73 | { |
||
74 | $show_methods['spiders'] = '(lo.id_member = 0 AND lo.id_spider > 0)'; |
||
75 | $show_methods['guests'] = '(lo.id_member = 0 AND lo.id_spider = 0)'; |
||
76 | $context['show_methods']['spiders'] = $txt['who_show_spiders_only']; |
||
77 | } |
||
78 | elseif (empty($modSettings['show_spider_online']) && isset($_SESSION['who_online_filter']) && $_SESSION['who_online_filter'] == 'spiders') |
||
79 | unset($_SESSION['who_online_filter']); |
||
80 | |||
81 | // Does the user prefer a different sort direction? |
||
82 | if (isset($_REQUEST['sort']) && isset($sort_methods[$_REQUEST['sort']])) |
||
83 | { |
||
84 | $context['sort_by'] = $_SESSION['who_online_sort_by'] = $_REQUEST['sort']; |
||
85 | $sort_method = $sort_methods[$_REQUEST['sort']]; |
||
86 | } |
||
87 | // Did we set a preferred sort order earlier in the session? |
||
88 | elseif (isset($_SESSION['who_online_sort_by'])) |
||
89 | { |
||
90 | $context['sort_by'] = $_SESSION['who_online_sort_by']; |
||
91 | $sort_method = $sort_methods[$_SESSION['who_online_sort_by']]; |
||
92 | } |
||
93 | // Default to last time online. |
||
94 | else |
||
95 | { |
||
96 | $context['sort_by'] = $_SESSION['who_online_sort_by'] = 'time'; |
||
97 | $sort_method = 'lo.log_time'; |
||
98 | } |
||
99 | |||
100 | $context['sort_direction'] = isset($_REQUEST['asc']) || (isset($_REQUEST['sort_dir']) && $_REQUEST['sort_dir'] == 'asc') ? 'up' : 'down'; |
||
101 | |||
102 | $conditions = array(); |
||
103 | if (!allowedTo('moderate_forum')) |
||
104 | $conditions[] = '(COALESCE(mem.show_online, 1) = 1)'; |
||
105 | |||
106 | // Fallback to top filter? |
||
107 | if (isset($_REQUEST['submit_top']) && isset($_REQUEST['show_top'])) |
||
108 | $_REQUEST['show'] = $_REQUEST['show_top']; |
||
109 | // Does the user wish to apply a filter? |
||
110 | if (isset($_REQUEST['show']) && isset($show_methods[$_REQUEST['show']])) |
||
111 | $context['show_by'] = $_SESSION['who_online_filter'] = $_REQUEST['show']; |
||
112 | // Perhaps we saved a filter earlier in the session? |
||
113 | elseif (isset($_SESSION['who_online_filter'])) |
||
114 | $context['show_by'] = $_SESSION['who_online_filter']; |
||
115 | else |
||
116 | $context['show_by'] = 'members'; |
||
117 | |||
118 | $conditions[] = $show_methods[$context['show_by']]; |
||
119 | |||
120 | // Get the total amount of members online. |
||
121 | $request = $smcFunc['db_query']('', ' |
||
122 | SELECT COUNT(*) |
||
123 | FROM {db_prefix}log_online AS lo |
||
124 | LEFT JOIN {db_prefix}members AS mem ON (lo.id_member = mem.id_member)' . (!empty($conditions) ? ' |
||
125 | WHERE ' . implode(' AND ', $conditions) : ''), |
||
126 | array( |
||
127 | ) |
||
128 | ); |
||
129 | list ($totalMembers) = $smcFunc['db_fetch_row']($request); |
||
130 | $smcFunc['db_free_result']($request); |
||
131 | |||
132 | // Prepare some page index variables. |
||
133 | $context['page_index'] = constructPageIndex($scripturl . '?action=who;sort=' . $context['sort_by'] . ($context['sort_direction'] == 'up' ? ';asc' : '') . ';show=' . $context['show_by'], $_REQUEST['start'], $totalMembers, $modSettings['defaultMaxMembers']); |
||
134 | $context['start'] = $_REQUEST['start']; |
||
135 | |||
136 | // Look for people online, provided they don't mind if you see they are. |
||
137 | $request = $smcFunc['db_query']('', ' |
||
138 | SELECT |
||
139 | lo.log_time, lo.id_member, lo.url, lo.ip AS ip, mem.real_name, |
||
140 | lo.session, mg.online_color, COALESCE(mem.show_online, 1) AS show_online, |
||
141 | lo.id_spider |
||
142 | FROM {db_prefix}log_online AS lo |
||
143 | LEFT JOIN {db_prefix}members AS mem ON (lo.id_member = mem.id_member) |
||
144 | LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = CASE WHEN mem.id_group = {int:regular_member} THEN mem.id_post_group ELSE mem.id_group END)' . (!empty($conditions) ? ' |
||
145 | WHERE ' . implode(' AND ', $conditions) : '') . ' |
||
146 | ORDER BY {raw:sort_method} {raw:sort_direction} |
||
147 | LIMIT {int:offset}, {int:limit}', |
||
148 | array( |
||
149 | 'regular_member' => 0, |
||
150 | 'sort_method' => $sort_method, |
||
151 | 'sort_direction' => $context['sort_direction'] == 'up' ? 'ASC' : 'DESC', |
||
152 | 'offset' => $context['start'], |
||
153 | 'limit' => $modSettings['defaultMaxMembers'], |
||
154 | ) |
||
155 | ); |
||
156 | $context['members'] = array(); |
||
157 | $member_ids = array(); |
||
158 | $url_data = array(); |
||
159 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
160 | { |
||
161 | $actions = $smcFunc['json_decode']($row['url'], true); |
||
162 | if ($actions === array()) |
||
163 | continue; |
||
164 | |||
165 | // Send the information to the template. |
||
166 | $context['members'][$row['session']] = array( |
||
167 | 'id' => $row['id_member'], |
||
168 | 'ip' => allowedTo('moderate_forum') ? inet_dtop($row['ip']) : '', |
||
169 | // It is *going* to be today or yesterday, so why keep that information in there? |
||
170 | 'time' => strtr(timeformat($row['log_time']), array($txt['today'] => '', $txt['yesterday'] => '')), |
||
171 | 'timestamp' => $row['log_time'], |
||
172 | 'query' => $actions, |
||
173 | 'is_hidden' => $row['show_online'] == 0, |
||
174 | 'id_spider' => $row['id_spider'], |
||
175 | 'color' => empty($row['online_color']) ? '' : $row['online_color'] |
||
176 | ); |
||
177 | |||
178 | $url_data[$row['session']] = array($row['url'], $row['id_member']); |
||
179 | $member_ids[] = $row['id_member']; |
||
180 | } |
||
181 | $smcFunc['db_free_result']($request); |
||
182 | |||
183 | // Load the user data for these members. |
||
184 | loadMemberData($member_ids); |
||
185 | |||
186 | // Load up the guest user. |
||
187 | $memberContext[0] = array( |
||
188 | 'id' => 0, |
||
189 | 'name' => $txt['guest_title'], |
||
190 | 'group' => $txt['guest_title'], |
||
191 | 'href' => '', |
||
192 | 'link' => $txt['guest_title'], |
||
193 | 'email' => $txt['guest_title'], |
||
194 | 'is_guest' => true |
||
195 | ); |
||
196 | |||
197 | // Are we showing spiders? |
||
198 | $spiderContext = array(); |
||
199 | if (!empty($modSettings['show_spider_online']) && ($modSettings['show_spider_online'] == 2 || allowedTo('admin_forum')) && !empty($modSettings['spider_name_cache'])) |
||
200 | { |
||
201 | foreach ($smcFunc['json_decode']($modSettings['spider_name_cache'], true) as $id => $name) |
||
202 | $spiderContext[$id] = array( |
||
203 | 'id' => 0, |
||
204 | 'name' => $name, |
||
205 | 'group' => $txt['spiders'], |
||
206 | 'href' => '', |
||
207 | 'link' => $name, |
||
208 | 'email' => $name, |
||
209 | 'is_guest' => true |
||
210 | ); |
||
211 | } |
||
212 | |||
213 | $url_data = determineActions($url_data); |
||
214 | |||
215 | // Setup the linktree and page title (do it down here because the language files are now loaded..) |
||
216 | $context['page_title'] = $txt['who_title']; |
||
217 | $context['linktree'][] = array( |
||
218 | 'url' => $scripturl . '?action=who', |
||
219 | 'name' => $txt['who_title'] |
||
220 | ); |
||
221 | |||
222 | // Put it in the context variables. |
||
223 | foreach ($context['members'] as $i => $member) |
||
224 | { |
||
225 | if ($member['id'] != 0) |
||
226 | $member['id'] = loadMemberContext($member['id']) ? $member['id'] : 0; |
||
227 | |||
228 | // Keep the IP that came from the database. |
||
229 | $memberContext[$member['id']]['ip'] = $member['ip']; |
||
230 | $context['members'][$i]['action'] = isset($url_data[$i]) ? $url_data[$i] : array('label' => 'who_hidden', 'class' => 'em'); |
||
231 | if ($member['id'] == 0 && isset($spiderContext[$member['id_spider']])) |
||
232 | $context['members'][$i] += $spiderContext[$member['id_spider']]; |
||
233 | else |
||
234 | $context['members'][$i] += $memberContext[$member['id']]; |
||
235 | } |
||
236 | |||
237 | // Some people can't send personal messages... |
||
238 | $context['can_send_pm'] = allowedTo('pm_send'); |
||
239 | $context['can_send_email'] = allowedTo('send_email_to_members'); |
||
240 | |||
241 | // any profile fields disabled? |
||
242 | $context['disabled_fields'] = isset($modSettings['disabled_profile_fields']) ? array_flip(explode(',', $modSettings['disabled_profile_fields'])) : array(); |
||
243 | |||
244 | } |
||
245 | |||
246 | /** |
||
247 | * This function determines the actions of the members passed in urls. |
||
248 | * |
||
249 | * Adding actions to the Who's Online list: |
||
250 | * Adding actions to this list is actually relatively easy... |
||
251 | * - for actions anyone should be able to see, just add a string named whoall_ACTION. |
||
252 | * (where ACTION is the action used in index.php.) |
||
253 | * - for actions that have a subaction which should be represented differently, use whoall_ACTION_SUBACTION. |
||
254 | * - for actions that include a topic, and should be restricted, use whotopic_ACTION. |
||
255 | * - for actions that use a message, by msg or quote, use whopost_ACTION. |
||
256 | * - for administrator-only actions, use whoadmin_ACTION. |
||
257 | * - for actions that should be viewable only with certain permissions, |
||
258 | * use whoallow_ACTION and add a list of possible permissions to the |
||
259 | * $allowedActions array, using ACTION as the key. |
||
260 | * |
||
261 | * @param mixed $urls a single url (string) or an array of arrays, each inner array being (JSON-encoded request data, id_member) |
||
262 | * @param string|bool $preferred_prefix = false |
||
263 | * @return array an array of descriptions if you passed an array, otherwise the string describing their current location. |
||
264 | */ |
||
265 | function determineActions($urls, $preferred_prefix = false) |
||
266 | { |
||
267 | global $txt, $user_info, $modSettings, $smcFunc, $scripturl, $context; |
||
268 | |||
269 | if (!allowedTo('who_view')) |
||
270 | return array(); |
||
271 | loadLanguage('Who'); |
||
272 | |||
273 | // Actions that require a specific permission level. |
||
274 | $allowedActions = array( |
||
275 | 'admin' => array('moderate_forum', 'manage_membergroups', 'manage_bans', 'admin_forum', 'manage_permissions', 'send_mail', 'manage_attachments', 'manage_smileys', 'manage_boards', 'edit_news'), |
||
276 | 'ban' => array('manage_bans'), |
||
277 | 'boardrecount' => array('admin_forum'), |
||
278 | 'calendar' => array('calendar_view'), |
||
279 | 'corefeatures' => array('admin_forum'), |
||
280 | 'editnews' => array('edit_news'), |
||
281 | 'featuresettings' => array('admin_forum'), |
||
282 | 'languages' => array('admin_forum'), |
||
283 | 'logs' => array('admin_forum'), |
||
284 | 'mailing' => array('send_mail'), |
||
285 | 'mailqueue' => array('admin_forum'), |
||
286 | 'maintain' => array('admin_forum'), |
||
287 | 'manageattachments' => array('manage_attachments'), |
||
288 | 'manageboards' => array('manage_boards'), |
||
289 | 'managecalendar' => array('admin_forum'), |
||
290 | 'managesearch' => array('admin_forum'), |
||
291 | 'managesmileys' => array('manage_smileys'), |
||
292 | 'membergroups' => array('manage_membergroups'), |
||
293 | 'mlist' => array('view_mlist'), |
||
294 | 'moderate' => array('access_mod_center', 'moderate_forum', 'manage_membergroups'), |
||
295 | 'modsettings' => array('admin_forum'), |
||
296 | 'news' => array('edit_news', 'send_mail', 'admin_forum'), |
||
297 | 'optimizetables' => array('admin_forum'), |
||
298 | 'packages' => array('admin_forum'), |
||
299 | 'paidsubscribe' => array('admin_forum'), |
||
300 | 'permissions' => array('manage_permissions'), |
||
301 | 'postsettings' => array('admin_forum'), |
||
302 | 'regcenter' => array('admin_forum', 'moderate_forum'), |
||
303 | 'repairboards' => array('admin_forum'), |
||
304 | 'reports' => array('admin_forum'), |
||
305 | 'scheduledtasks' => array('admin_forum'), |
||
306 | 'search' => array('search_posts'), |
||
307 | 'search2' => array('search_posts'), |
||
308 | 'securitysettings' => array('admin_forum'), |
||
309 | 'sengines' => array('admin_forum'), |
||
310 | 'serversettings' => array('admin_forum'), |
||
311 | 'setcensor' => array('moderate_forum'), |
||
312 | 'setreserve' => array('moderate_forum'), |
||
313 | 'stats' => array('view_stats'), |
||
314 | 'theme' => array('admin_forum'), |
||
315 | 'viewerrorlog' => array('admin_forum'), |
||
316 | 'viewmembers' => array('moderate_forum'), |
||
317 | ); |
||
318 | call_integration_hook('who_allowed', array(&$allowedActions)); |
||
319 | |||
320 | if (!is_array($urls)) |
||
321 | $url_list = array(array($urls, $user_info['id'])); |
||
322 | else |
||
323 | $url_list = $urls; |
||
324 | |||
325 | // These are done to later query these in large chunks. (instead of one by one.) |
||
326 | $topic_ids = array(); |
||
327 | $profile_ids = array(); |
||
328 | $board_ids = array(); |
||
329 | |||
330 | $data = array(); |
||
331 | foreach ($url_list as $k => $url) |
||
332 | { |
||
333 | // Get the request parameters.. |
||
334 | $actions = $smcFunc['json_decode']($url[0], true); |
||
335 | if ($actions === array()) |
||
336 | continue; |
||
337 | |||
338 | // If it's the admin or moderation center, and there is an area set, use that instead. |
||
339 | if (isset($actions['action']) && ($actions['action'] == 'admin' || $actions['action'] == 'moderate') && isset($actions['area'])) |
||
340 | $actions['action'] = $actions['area']; |
||
341 | |||
342 | // Check if there was no action or the action is display. |
||
343 | if (!isset($actions['action']) || $actions['action'] == 'display') |
||
344 | { |
||
345 | // It's a topic! Must be! |
||
346 | if (isset($actions['topic'])) |
||
347 | { |
||
348 | // Assume they can't view it, and queue it up for later. |
||
349 | $data[$k] = array('label' => 'who_hidden', 'class' => 'em'); |
||
350 | $topic_ids[(int) $actions['topic']][$k] = $txt['who_topic']; |
||
351 | } |
||
352 | // It's a board! |
||
353 | elseif (isset($actions['board'])) |
||
354 | { |
||
355 | // Hide first, show later. |
||
356 | $data[$k] = array('label' => 'who_hidden', 'class' => 'em'); |
||
357 | $board_ids[$actions['board']][$k] = $txt['who_board']; |
||
358 | } |
||
359 | // It's the board index!! It must be! |
||
360 | else |
||
361 | $data[$k] = sprintf($txt['who_index'], $scripturl, $context['forum_name_html_safe']); |
||
362 | } |
||
363 | // Probably an error or some goon? |
||
364 | elseif ($actions['action'] == '') |
||
365 | $data[$k] = sprintf($txt['who_index'], $scripturl, $context['forum_name_html_safe']); |
||
366 | // Some other normal action...? |
||
367 | else |
||
368 | { |
||
369 | // Viewing/editing a profile. |
||
370 | if ($actions['action'] == 'profile') |
||
371 | { |
||
372 | // Whose? Their own? |
||
373 | if (empty($actions['u'])) |
||
374 | $actions['u'] = $url[1]; |
||
375 | |||
376 | $data[$k] = array('label' => 'who_hidden', 'class' => 'em'); |
||
377 | $profile_ids[(int) $actions['u']][$k] = $actions['u'] == $url[1] ? $txt['who_viewownprofile'] : $txt['who_viewprofile']; |
||
378 | } |
||
379 | elseif (($actions['action'] == 'post' || $actions['action'] == 'post2') && empty($actions['topic']) && isset($actions['board'])) |
||
380 | { |
||
381 | $data[$k] = array('label' => 'who_hidden', 'class' => 'em'); |
||
382 | $board_ids[(int) $actions['board']][$k] = isset($actions['poll']) ? $txt['who_poll'] : $txt['who_post']; |
||
383 | } |
||
384 | // A subaction anyone can view... if the language string is there, show it. |
||
385 | elseif (isset($actions['sa']) && isset($txt['whoall_' . $actions['action'] . '_' . $actions['sa']])) |
||
386 | $data[$k] = $preferred_prefix && isset($txt[$preferred_prefix . $actions['action'] . '_' . $actions['sa']]) ? $txt[$preferred_prefix . $actions['action'] . '_' . $actions['sa']] : sprintf($txt['whoall_' . $actions['action'] . '_' . $actions['sa']], $scripturl); |
||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||
387 | // An action any old fellow can look at. (if ['whoall_' . $action] exists, we know everyone can see it.) |
||
388 | elseif (isset($txt['whoall_' . $actions['action']])) |
||
389 | $data[$k] = $preferred_prefix && isset($txt[$preferred_prefix . $actions['action']]) ? $txt[$preferred_prefix . $actions['action']] : sprintf($txt['whoall_' . $actions['action']], $scripturl); |
||
390 | // Viewable if and only if they can see the board... |
||
391 | elseif (isset($txt['whotopic_' . $actions['action']])) |
||
392 | { |
||
393 | // Find out what topic they are accessing. |
||
394 | $topic = (int) (isset($actions['topic']) ? $actions['topic'] : (isset($actions['from']) ? $actions['from'] : 0)); |
||
395 | |||
396 | $data[$k] = array('label' => 'who_hidden', 'class' => 'em'); |
||
397 | $topic_ids[$topic][$k] = $txt['whotopic_' . $actions['action']]; |
||
398 | } |
||
399 | elseif (isset($txt['whopost_' . $actions['action']])) |
||
400 | { |
||
401 | // Find out what message they are accessing. |
||
402 | $msgid = (int) (isset($actions['msg']) ? $actions['msg'] : (isset($actions['quote']) ? $actions['quote'] : 0)); |
||
403 | |||
404 | $result = $smcFunc['db_query']('', ' |
||
405 | SELECT m.id_topic, m.subject |
||
406 | FROM {db_prefix}messages AS m |
||
407 | ' . ($modSettings['postmod_active'] ? 'INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic AND t.approved = {int:is_approved})' : '') . ' |
||
408 | WHERE m.id_msg = {int:id_msg} |
||
409 | AND {query_see_message_board}' . ($modSettings['postmod_active'] ? ' |
||
410 | AND m.approved = {int:is_approved}' : '') . ' |
||
411 | LIMIT 1', |
||
412 | array( |
||
413 | 'is_approved' => 1, |
||
414 | 'id_msg' => $msgid, |
||
415 | ) |
||
416 | ); |
||
417 | list ($id_topic, $subject) = $smcFunc['db_fetch_row']($result); |
||
418 | $data[$k] = sprintf($txt['whopost_' . $actions['action']], $id_topic, $subject, $scripturl); |
||
419 | $smcFunc['db_free_result']($result); |
||
420 | |||
421 | if (empty($id_topic)) |
||
422 | $data[$k] = array('label' => 'who_hidden', 'class' => 'em'); |
||
423 | } |
||
424 | // Viewable only by administrators.. (if it starts with whoadmin, it's admin only!) |
||
425 | elseif (allowedTo('moderate_forum') && isset($txt['whoadmin_' . $actions['action']])) |
||
426 | $data[$k] = sprintf($txt['whoadmin_' . $actions['action']], $scripturl); |
||
427 | // Viewable by permission level. |
||
428 | elseif (isset($allowedActions[$actions['action']])) |
||
429 | { |
||
430 | if (allowedTo($allowedActions[$actions['action']]) && !empty($txt['whoallow_' . $actions['action']])) |
||
431 | $data[$k] = sprintf($txt['whoallow_' . $actions['action']], $scripturl); |
||
432 | elseif (in_array('moderate_forum', $allowedActions[$actions['action']])) |
||
433 | $data[$k] = $txt['who_moderate']; |
||
434 | elseif (in_array('admin_forum', $allowedActions[$actions['action']])) |
||
435 | $data[$k] = $txt['who_admin']; |
||
436 | else |
||
437 | $data[$k] = array('label' => 'who_hidden', 'class' => 'em'); |
||
438 | } |
||
439 | elseif (!empty($actions['action'])) |
||
440 | $data[$k] = $txt['who_generic'] . ' ' . $actions['action']; |
||
441 | else |
||
442 | $data[$k] = array('label' => 'who_unknown', 'class' => 'em'); |
||
443 | } |
||
444 | |||
445 | if (isset($actions['error'])) |
||
446 | { |
||
447 | loadLanguage('Errors'); |
||
448 | |||
449 | if (isset($txt[$actions['error']])) |
||
450 | $error_message = str_replace('"', '"', empty($actions['error_params']) ? $txt[$actions['error']] : vsprintf($txt[$actions['error']], (array) $actions['error_params'])); |
||
451 | elseif ($actions['error'] == 'guest_login') |
||
452 | $error_message = str_replace('"', '"', $txt['who_guest_login']); |
||
453 | else |
||
454 | $error_message = str_replace('"', '"', $actions['error']); |
||
455 | |||
456 | if (!empty($error_message)) |
||
457 | { |
||
458 | $error_message = ' <span class="main_icons error" title="' . $error_message . '"></span>'; |
||
459 | |||
460 | if (is_array($data[$k])) |
||
461 | $data[$k]['error_message'] = $error_message; |
||
462 | else |
||
463 | $data[$k] .= $error_message; |
||
464 | } |
||
465 | } |
||
466 | |||
467 | // Maybe the action is integrated into another system? |
||
468 | if (count($integrate_actions = call_integration_hook('integrate_whos_online', array($actions))) > 0) |
||
469 | { |
||
470 | foreach ($integrate_actions as $integrate_action) |
||
471 | { |
||
472 | if (!empty($integrate_action)) |
||
473 | { |
||
474 | $data[$k] = $integrate_action; |
||
475 | if (isset($actions['topic']) && isset($topic_ids[(int) $actions['topic']][$k])) |
||
476 | $topic_ids[(int) $actions['topic']][$k] = $integrate_action; |
||
477 | if (isset($actions['board']) && isset($board_ids[(int) $actions['board']][$k])) |
||
478 | $board_ids[(int) $actions['board']][$k] = $integrate_action; |
||
479 | if (isset($actions['u']) && isset($profile_ids[(int) $actions['u']][$k])) |
||
480 | $profile_ids[(int) $actions['u']][$k] = $integrate_action; |
||
481 | break; |
||
482 | } |
||
483 | } |
||
484 | } |
||
485 | } |
||
486 | |||
487 | // Load topic names. |
||
488 | if (!empty($topic_ids)) |
||
489 | { |
||
490 | $result = $smcFunc['db_query']('', ' |
||
491 | SELECT t.id_topic, m.subject |
||
492 | FROM {db_prefix}topics AS t |
||
493 | INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg) |
||
494 | WHERE {query_see_topic_board} |
||
495 | AND t.id_topic IN ({array_int:topic_list})' . ($modSettings['postmod_active'] ? ' |
||
496 | AND t.approved = {int:is_approved}' : '') . ' |
||
497 | LIMIT {int:limit}', |
||
498 | array( |
||
499 | 'topic_list' => array_keys($topic_ids), |
||
500 | 'is_approved' => 1, |
||
501 | 'limit' => count($topic_ids), |
||
502 | ) |
||
503 | ); |
||
504 | while ($row = $smcFunc['db_fetch_assoc']($result)) |
||
505 | { |
||
506 | // Show the topic's subject for each of the actions. |
||
507 | foreach ($topic_ids[$row['id_topic']] as $k => $session_text) |
||
508 | $data[$k] = sprintf($session_text, $row['id_topic'], censorText($row['subject']), $scripturl); |
||
509 | } |
||
510 | $smcFunc['db_free_result']($result); |
||
511 | } |
||
512 | |||
513 | // Load board names. |
||
514 | if (!empty($board_ids)) |
||
515 | { |
||
516 | $result = $smcFunc['db_query']('', ' |
||
517 | SELECT b.id_board, b.name |
||
518 | FROM {db_prefix}boards AS b |
||
519 | WHERE {query_see_board} |
||
520 | AND b.id_board IN ({array_int:board_list}) |
||
521 | LIMIT {int:limit}', |
||
522 | array( |
||
523 | 'board_list' => array_keys($board_ids), |
||
524 | 'limit' => count($board_ids), |
||
525 | ) |
||
526 | ); |
||
527 | while ($row = $smcFunc['db_fetch_assoc']($result)) |
||
528 | { |
||
529 | // Put the board name into the string for each member... |
||
530 | foreach ($board_ids[$row['id_board']] as $k => $session_text) |
||
531 | $data[$k] = sprintf($session_text, $row['id_board'], $row['name'], $scripturl); |
||
532 | } |
||
533 | $smcFunc['db_free_result']($result); |
||
534 | } |
||
535 | |||
536 | // Load member names for the profile. (is_not_guest permission for viewing their own profile) |
||
537 | $allow_view_own = allowedTo('is_not_guest'); |
||
538 | $allow_view_any = allowedTo('profile_view'); |
||
539 | if (!empty($profile_ids) && ($allow_view_any || $allow_view_own)) |
||
540 | { |
||
541 | $result = $smcFunc['db_query']('', ' |
||
542 | SELECT id_member, real_name |
||
543 | FROM {db_prefix}members |
||
544 | WHERE id_member IN ({array_int:member_list}) |
||
545 | LIMIT ' . count($profile_ids), |
||
546 | array( |
||
547 | 'member_list' => array_keys($profile_ids), |
||
548 | ) |
||
549 | ); |
||
550 | while ($row = $smcFunc['db_fetch_assoc']($result)) |
||
551 | { |
||
552 | // If they aren't allowed to view this person's profile, skip it. |
||
553 | if (!$allow_view_any && ($user_info['id'] != $row['id_member'])) |
||
554 | continue; |
||
555 | |||
556 | // Set their action on each - session/text to sprintf. |
||
557 | foreach ($profile_ids[$row['id_member']] as $k => $session_text) |
||
558 | $data[$k] = sprintf($session_text, $row['id_member'], $row['real_name'], $scripturl); |
||
559 | } |
||
560 | $smcFunc['db_free_result']($result); |
||
561 | } |
||
562 | |||
563 | call_integration_hook('whos_online_after', array(&$urls, &$data)); |
||
564 | |||
565 | if (!is_array($urls)) |
||
566 | return isset($data[0]) ? $data[0] : false; |
||
567 | else |
||
568 | return $data; |
||
569 | } |
||
570 | |||
571 | /** |
||
572 | * It prepares credit and copyright information for the credits page or the admin page |
||
573 | * |
||
574 | * @param bool $in_admin = false, if parameter is true the it will not load the sub-template nor the template file |
||
575 | */ |
||
576 | function Credits($in_admin = false) |
||
577 | { |
||
578 | global $context, $smcFunc, $forum_copyright, $txt, $user_info, $scripturl; |
||
579 | |||
580 | // Don't blink. Don't even blink. Blink and you're dead. |
||
581 | loadLanguage('Who'); |
||
582 | |||
583 | // Discourage robots from indexing this page. |
||
584 | $context['robot_no_index'] = true; |
||
585 | |||
586 | if ($in_admin) |
||
587 | { |
||
588 | $context[$context['admin_menu_name']]['tab_data'] = array( |
||
589 | 'title' => $txt['support_credits_title'], |
||
590 | 'help' => '', |
||
591 | 'description' => '', |
||
592 | ); |
||
593 | } |
||
594 | |||
595 | $context['credits'] = array( |
||
596 | array( |
||
597 | 'pretext' => $txt['credits_intro'], |
||
598 | 'title' => $txt['credits_team'], |
||
599 | 'groups' => array( |
||
600 | array( |
||
601 | 'title' => $txt['credits_groups_pm'], |
||
602 | 'members' => array( |
||
603 | 'Aleksi "Lex" Kilpinen', |
||
604 | // Former Project Managers |
||
605 | 'Michele "Illori" Davis', |
||
606 | 'Jessica "Suki" González', |
||
607 | 'Will "Kindred" Wagner', |
||
608 | ), |
||
609 | ), |
||
610 | array( |
||
611 | 'title' => $txt['credits_groups_dev'], |
||
612 | 'members' => array( |
||
613 | // Lead Developer |
||
614 | 'Jon "Sesquipedalian" Stovell', |
||
615 | // Developers |
||
616 | 'Jessica "Suki" González', |
||
617 | 'John "live627" Rayes', |
||
618 | 'Oscar "Ozp" Rydhé', |
||
619 | 'Shawn Bulen', |
||
620 | |||
621 | // Former Developers |
||
622 | 'Aaron van Geffen', |
||
623 | 'Antechinus', |
||
624 | 'Bjoern "Bloc" Kristiansen', |
||
625 | 'Brad "IchBin™" Grow', |
||
626 | 'Colin Schoen', |
||
627 | 'emanuele', |
||
628 | 'Hendrik Jan "Compuart" Visser', |
||
629 | 'Juan "JayBachatero" Hernandez', |
||
630 | 'Karl "RegularExpression" Benson', |
||
631 | 'Matthew "Labradoodle-360" Kerle', |
||
632 | $user_info['is_admin'] ? 'Matt "Grudge" Wolf' : 'Grudge', |
||
633 | 'Michael "Oldiesmann" Eshom', |
||
634 | 'Michael "Thantos" Miller', |
||
635 | 'Norv', |
||
636 | 'Peter "Arantor" Spicer', |
||
637 | 'Selman "[SiNaN]" Eser', |
||
638 | 'Shitiz "Dragooon" Garg', |
||
639 | // 'Spuds', // Doesn't want to be listed here |
||
640 | // 'Steven "Fustrate" Hoffman', |
||
641 | 'Theodore "Orstio" Hildebrandt', |
||
642 | 'Thorsten "TE" Eurich', |
||
643 | 'winrules', |
||
644 | ), |
||
645 | ), |
||
646 | array( |
||
647 | 'title' => $txt['credits_groups_support'], |
||
648 | 'members' => array( |
||
649 | // Lead Support Specialist |
||
650 | 'Will "Kindred" Wagner', |
||
651 | // Support Specialists |
||
652 | 'Doug Heffernan', |
||
653 | 'lurkalot', |
||
654 | 'shadav', |
||
655 | 'Steve', |
||
656 | |||
657 | // Former Support Specialists |
||
658 | 'Aleksi "Lex" Kilpinen', |
||
659 | 'br360', |
||
660 | 'GigaWatt', |
||
661 | 'ziycon', |
||
662 | 'Adam Tallon', |
||
663 | 'Bigguy', |
||
664 | 'Bruno "margarett" Alves', |
||
665 | 'CapadY', |
||
666 | 'ChalkCat', |
||
667 | 'Chas Large', |
||
668 | 'Duncan85', |
||
669 | 'gbsothere', |
||
670 | 'JimM', |
||
671 | 'Justyne', |
||
672 | 'Kat', |
||
673 | 'Kevin "greyknight17" Hou', |
||
674 | 'Krash', |
||
675 | 'Mashby', |
||
676 | 'Michael Colin Blaber', |
||
677 | 'Old Fossil', |
||
678 | 'S-Ace', |
||
679 | 'Storman™', |
||
680 | 'Wade "sησω" Poulsen', |
||
681 | 'xenovanis', |
||
682 | ), |
||
683 | ), |
||
684 | array( |
||
685 | 'title' => $txt['credits_groups_customize'], |
||
686 | 'members' => array( |
||
687 | // Lead Customizer |
||
688 | 'Gary M. Gadsdon', |
||
689 | // Customizers |
||
690 | 'Diego Andrés', |
||
691 | 'Jonathan "vbgamer45" Valentin', |
||
692 | 'Michael "Mick." Gomez', |
||
693 | |||
694 | // Former Customizers |
||
695 | 'Sami "SychO" Mazouz', |
||
696 | 'Brannon "B" Hall', |
||
697 | 'Jack "akabugeyes" Thorsen', |
||
698 | 'Jason "JBlaze" Clemons', |
||
699 | 'Joey "Tyrsson" Smith', |
||
700 | 'Kays', |
||
701 | 'NanoSector', |
||
702 | 'Ricky.', |
||
703 | 'Russell "NEND" Najar', |
||
704 | 'SA™', |
||
705 | ), |
||
706 | ), |
||
707 | array( |
||
708 | 'title' => $txt['credits_groups_docs'], |
||
709 | 'members' => array( |
||
710 | // Doc Coordinator |
||
711 | 'Michele "Illori" Davis', |
||
712 | // Doc Writers |
||
713 | 'Irisado', |
||
714 | |||
715 | // Former Doc Writers |
||
716 | 'AngelinaBelle', |
||
717 | 'Chainy', |
||
718 | 'Graeme Spence', |
||
719 | 'Joshua "groundup" Dickerson', |
||
720 | ), |
||
721 | ), |
||
722 | array( |
||
723 | 'title' => $txt['credits_groups_internationalizers'], |
||
724 | 'members' => array( |
||
725 | // Lead Localizer |
||
726 | 'Nikola "Dzonny" Novaković', |
||
727 | // Localizers |
||
728 | 'm4z', |
||
729 | // Former Localizers |
||
730 | 'Francisco "d3vcho" Domínguez', |
||
731 | 'Robert Monden', |
||
732 | 'Relyana', |
||
733 | ), |
||
734 | ), |
||
735 | array( |
||
736 | 'title' => $txt['credits_groups_marketing'], |
||
737 | 'members' => array( |
||
738 | // Marketing Coordinator |
||
739 | |||
740 | // Marketing |
||
741 | |||
742 | // Former Marketing |
||
743 | 'Adish "(F.L.A.M.E.R)" Patel', |
||
744 | 'Bryan "Runic" Deakin', |
||
745 | 'Marcus "cσσкιє мσηѕтєя" Forsberg', |
||
746 | 'Ralph "[n3rve]" Otowo', |
||
747 | ), |
||
748 | ), |
||
749 | array( |
||
750 | 'title' => $txt['credits_groups_site'], |
||
751 | 'members' => array( |
||
752 | 'Jeremy "SleePy" Darwood', |
||
753 | ), |
||
754 | ), |
||
755 | array( |
||
756 | 'title' => $txt['credits_groups_servers'], |
||
757 | 'members' => array( |
||
758 | 'Derek Schwab', |
||
759 | 'Michael Johnson', |
||
760 | 'Liroy van Hoewijk', |
||
761 | ), |
||
762 | ), |
||
763 | ), |
||
764 | ), |
||
765 | ); |
||
766 | |||
767 | // Give the translators some credit for their hard work. |
||
768 | if (!is_array($txt['translation_credits'])) |
||
769 | $txt['translation_credits'] = array_filter(array_map('trim', explode(',', $txt['translation_credits']))); |
||
770 | |||
771 | if (!empty($txt['translation_credits'])) |
||
772 | $context['credits'][] = array( |
||
773 | 'title' => $txt['credits_groups_translation'], |
||
774 | 'groups' => array( |
||
775 | array( |
||
776 | 'title' => $txt['credits_groups_translation'], |
||
777 | 'members' => $txt['translation_credits'], |
||
778 | ), |
||
779 | ), |
||
780 | ); |
||
781 | |||
782 | $context['credits'][] = array( |
||
783 | 'title' => $txt['credits_special'], |
||
784 | 'posttext' => $txt['credits_anyone'], |
||
785 | 'groups' => array( |
||
786 | array( |
||
787 | 'title' => $txt['credits_groups_consultants'], |
||
788 | 'members' => array( |
||
789 | 'albertlast', |
||
790 | 'Brett Flannigan', |
||
791 | 'Mark Rose', |
||
792 | 'René-Gilles "Nao 尚" Deberdt', |
||
793 | 'tinoest', |
||
794 | $txt['credits_code_contributors'], |
||
795 | ), |
||
796 | ), |
||
797 | array( |
||
798 | 'title' => $txt['credits_groups_beta'], |
||
799 | 'members' => array( |
||
800 | $txt['credits_beta_message'], |
||
801 | ), |
||
802 | ), |
||
803 | array( |
||
804 | 'title' => $txt['credits_groups_translators'], |
||
805 | 'members' => array( |
||
806 | $txt['credits_translators_message'], |
||
807 | ), |
||
808 | ), |
||
809 | array( |
||
810 | 'title' => $txt['credits_groups_founder'], |
||
811 | 'members' => array( |
||
812 | 'Unknown W. "[Unknown]" Brackets', |
||
813 | ), |
||
814 | ), |
||
815 | array( |
||
816 | 'title' => $txt['credits_groups_orignal_pm'], |
||
817 | 'members' => array( |
||
818 | 'Jeff Lewis', |
||
819 | 'Joseph Fung', |
||
820 | 'David Recordon', |
||
821 | ), |
||
822 | ), |
||
823 | array( |
||
824 | 'title' => $txt['credits_in_memoriam'], |
||
825 | 'members' => array( |
||
826 | 'Crip', |
||
827 | 'K@', |
||
828 | 'metallica48423', |
||
829 | 'Paul_Pauline', |
||
830 | ), |
||
831 | ), |
||
832 | ), |
||
833 | ); |
||
834 | |||
835 | // Give credit to any graphic library's, software library's, plugins etc |
||
836 | $context['credits_software_graphics'] = array( |
||
837 | 'graphics' => array( |
||
838 | '<a href="http://p.yusukekamiyamane.com/">Fugue Icons</a> | © 2012 Yusuke Kamiyamane | These icons are licensed under a Creative Commons Attribution 3.0 License', |
||
839 | '<a href="https://techbase.kde.org/Projects/Oxygen/Licensing#Use_on_Websites">Oxygen Icons</a> | These icons are licensed under <a href="http://www.gnu.org/copyleft/lesser.html">GNU LGPLv3</a>', |
||
840 | ), |
||
841 | 'software' => array( |
||
842 | '<a href="https://jquery.org/">JQuery</a> | © John Resig | Licensed under <a href="https://github.com/jquery/jquery/blob/master/LICENSE.txt">The MIT License (MIT)</a>', |
||
843 | '<a href="https://briancherne.github.io/jquery-hoverIntent/">hoverIntent</a> | © Brian Cherne | Licensed under <a href="https://en.wikipedia.org/wiki/MIT_License">The MIT License (MIT)</a>', |
||
844 | '<a href="https://www.sceditor.com/">SCEditor</a> | © Sam Clarke | Licensed under <a href="https://en.wikipedia.org/wiki/MIT_License">The MIT License (MIT)</a>', |
||
845 | '<a href="http://wayfarerweb.com/jquery/plugins/animadrag/">animaDrag</a> | © Abel Mohler | Licensed under <a href="https://en.wikipedia.org/wiki/MIT_License">The MIT License (MIT)</a>', |
||
846 | '<a href="https://github.com/mzubala/jquery-custom-scrollbar">jQuery Custom Scrollbar</a> | © Maciej Zubala | Licensed under <a href="http://en.wikipedia.org/wiki/MIT_License">The MIT License (MIT)</a>', |
||
847 | '<a href="http://slippry.com/">jQuery Responsive Slider</a> | © booncon ROCKETS | Licensed under <a href="http://en.wikipedia.org/wiki/MIT_License">The MIT License (MIT)</a>', |
||
848 | '<a href="https://github.com/ichord/At.js">At.js</a> | © [email protected] | Licensed under <a href="https://github.com/ichord/At.js/blob/master/LICENSE-MIT">The MIT License (MIT)</a>', |
||
849 | '<a href="https://github.com/ttsvetko/HTML5-Desktop-Notifications">HTML5 Desktop Notifications</a> | © Tsvetan Tsvetkov | Licensed under <a href="https://github.com/ttsvetko/HTML5-Desktop-Notifications/blob/master/License.txt">The Apache License Version 2.0</a>', |
||
850 | '<a href="https://github.com/enygma/gauth">GAuth Code Generator/Validator</a> | © Chris Cornutt | Licensed under <a href="https://github.com/enygma/gauth/blob/master/LICENSE">The MIT License (MIT)</a>', |
||
851 | '<a href="https://github.com/enyo/dropzone">Dropzone.js</a> | © Matias Meno | Licensed under <a href="http://en.wikipedia.org/wiki/MIT_License">The MIT License (MIT)</a>', |
||
852 | '<a href="https://github.com/matthiasmullie/minify">Minify</a> | © Matthias Mullie | Licensed under <a href="http://en.wikipedia.org/wiki/MIT_License">The MIT License (MIT)</a>', |
||
853 | '<a href="https://github.com/true/php-punycode">PHP-Punycode</a> | © True B.V. | Licensed under <a href="http://en.wikipedia.org/wiki/MIT_License">The MIT License (MIT)</a>', |
||
854 | ), |
||
855 | 'fonts' => array( |
||
856 | '<a href="https://fontlibrary.org/en/font/anonymous-pro"> Anonymous Pro</a> | © 2009 | This font is licensed under the SIL Open Font License, Version 1.1', |
||
857 | '<a href="https://fontlibrary.org/en/font/consolamono"> ConsolaMono</a> | © 2012 | This font is licensed under the SIL Open Font License, Version 1.1', |
||
858 | '<a href="https://fontlibrary.org/en/font/phennig"> Phennig</a> | © 2009-2012 | This font is licensed under the SIL Open Font License, Version 1.1', |
||
859 | ), |
||
860 | ); |
||
861 | |||
862 | // Support for mods that use the <credits> tag via the package manager |
||
863 | $context['credits_modifications'] = array(); |
||
864 | if (($mods = cache_get_data('mods_credits', 86400)) === null) |
||
865 | { |
||
866 | $mods = array(); |
||
867 | $request = $smcFunc['db_query']('substring', ' |
||
868 | SELECT version, name, credits |
||
869 | FROM {db_prefix}log_packages |
||
870 | WHERE install_state = {int:installed_mods} |
||
871 | AND credits != {string:empty} |
||
872 | AND SUBSTRING(filename, 1, 9) != {string:patch_name}', |
||
873 | array( |
||
874 | 'installed_mods' => 1, |
||
875 | 'patch_name' => 'smf_patch', |
||
876 | 'empty' => '', |
||
877 | ) |
||
878 | ); |
||
879 | |||
880 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
881 | { |
||
882 | $credit_info = $smcFunc['json_decode']($row['credits'], true); |
||
883 | |||
884 | $copyright = empty($credit_info['copyright']) ? '' : $txt['credits_copyright'] . ' © ' . $smcFunc['htmlspecialchars']($credit_info['copyright']); |
||
885 | $license = empty($credit_info['license']) ? '' : $txt['credits_license'] . ': ' . (!empty($credit_info['licenseurl']) ? '<a href="' . $smcFunc['htmlspecialchars']($credit_info['licenseurl']) . '">' . $smcFunc['htmlspecialchars']($credit_info['license']) . '</a>' : $smcFunc['htmlspecialchars']($credit_info['license'])); |
||
886 | $version = $txt['credits_version'] . ' ' . $row['version']; |
||
887 | $title = (empty($credit_info['title']) ? $row['name'] : $smcFunc['htmlspecialchars']($credit_info['title'])) . ': ' . $version; |
||
888 | |||
889 | // build this one out and stash it away |
||
890 | $mod_name = empty($credit_info['url']) ? $title : '<a href="' . $credit_info['url'] . '">' . $title . '</a>'; |
||
891 | $mods[] = $mod_name . (!empty($license) ? ' | ' . $license : '') . (!empty($copyright) ? ' | ' . $copyright : ''); |
||
892 | } |
||
893 | cache_put_data('mods_credits', $mods, 86400); |
||
894 | } |
||
895 | $context['credits_modifications'] = $mods; |
||
896 | |||
897 | $context['copyrights'] = array( |
||
898 | 'smf' => sprintf($forum_copyright, SMF_FULL_VERSION, SMF_SOFTWARE_YEAR, $scripturl), |
||
899 | /* Modification Authors: You may add a copyright statement to this array for your mods. |
||
900 | Copyright statements should be in the form of a value only without a array key. I.E.: |
||
901 | 'Some Mod by Thantos © 2010', |
||
902 | $txt['some_mod_copyright'], |
||
903 | */ |
||
904 | 'mods' => array( |
||
905 | ), |
||
906 | ); |
||
907 | |||
908 | // Support for those that want to use a hook as well |
||
909 | call_integration_hook('integrate_credits'); |
||
910 | |||
911 | if (!$in_admin) |
||
912 | { |
||
913 | loadTemplate('Who'); |
||
914 | $context['sub_template'] = 'credits'; |
||
915 | $context['robot_no_index'] = true; |
||
916 | $context['page_title'] = $txt['credits']; |
||
917 | } |
||
918 | } |
||
919 | |||
920 | ?> |