1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* Show a list of members or a selection of members. |
5
|
|
|
* |
6
|
|
|
* Simple Machines Forum (SMF) |
7
|
|
|
* |
8
|
|
|
* @package SMF |
9
|
|
|
* @author Simple Machines https://www.simplemachines.org |
10
|
|
|
* @copyright 2022 Simple Machines and individual contributors |
11
|
|
|
* @license https://www.simplemachines.org/about/smf/license.php BSD |
12
|
|
|
* |
13
|
|
|
* @version 2.1.0 |
14
|
|
|
*/ |
15
|
|
|
|
16
|
|
|
if (!defined('SMF')) |
17
|
|
|
die('No direct access...'); |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* The main entrance point for the Manage Members screen. |
21
|
|
|
* As everyone else, it calls a function based on the given sub-action. |
22
|
|
|
* Called by ?action=admin;area=viewmembers. |
23
|
|
|
* Requires the moderate_forum permission. |
24
|
|
|
* |
25
|
|
|
* Uses ManageMembers template |
26
|
|
|
* Uses ManageMembers language file. |
27
|
|
|
*/ |
28
|
|
|
function ViewMembers() |
29
|
|
|
{ |
30
|
|
|
global $txt, $scripturl, $context, $modSettings, $smcFunc; |
31
|
|
|
|
32
|
|
|
$subActions = array( |
33
|
|
|
'all' => array('ViewMemberlist', 'moderate_forum'), |
34
|
|
|
'approve' => array('AdminApprove', 'moderate_forum'), |
35
|
|
|
'browse' => array('MembersAwaitingActivation', 'moderate_forum'), |
36
|
|
|
'search' => array('SearchMembers', 'moderate_forum'), |
37
|
|
|
'query' => array('ViewMemberlist', 'moderate_forum'), |
38
|
|
|
); |
39
|
|
|
|
40
|
|
|
// Load the essentials. |
41
|
|
|
loadLanguage('ManageMembers'); |
42
|
|
|
loadTemplate('ManageMembers'); |
43
|
|
|
|
44
|
|
|
// Fetch our activation counts. |
45
|
|
|
GetMemberActivationCounts(); |
46
|
|
|
|
47
|
|
|
// For the page header... do we show activation? |
48
|
|
|
$context['show_activate'] = (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 1) || !empty($context['awaiting_activation']); |
49
|
|
|
|
50
|
|
|
// What about approval? |
51
|
|
|
$context['show_approve'] = (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 2) || !empty($context['awaiting_approval']) || !empty($modSettings['approveAccountDeletion']); |
52
|
|
|
|
53
|
|
|
// Setup the admin tabs. |
54
|
|
|
$context[$context['admin_menu_name']]['tab_data'] = array( |
55
|
|
|
'title' => $txt['admin_members'], |
56
|
|
|
'help' => 'view_members', |
57
|
|
|
'description' => $txt['admin_members_list'], |
58
|
|
|
'tabs' => array(), |
59
|
|
|
); |
60
|
|
|
|
61
|
|
|
$context['tabs'] = array( |
62
|
|
|
'viewmembers' => array( |
63
|
|
|
'label' => $txt['view_all_members'], |
64
|
|
|
'description' => $txt['admin_members_list'], |
65
|
|
|
'url' => $scripturl . '?action=admin;area=viewmembers;sa=all', |
66
|
|
|
'selected_actions' => array('all'), |
67
|
|
|
), |
68
|
|
|
'search' => array( |
69
|
|
|
'label' => $txt['mlist_search'], |
70
|
|
|
'description' => $txt['admin_members_list'], |
71
|
|
|
'url' => $scripturl . '?action=admin;area=viewmembers;sa=search', |
72
|
|
|
'selected_actions' => array('search', 'query'), |
73
|
|
|
), |
74
|
|
|
); |
75
|
|
|
$context['last_tab'] = 'search'; |
76
|
|
|
|
77
|
|
|
// Do we have approvals |
78
|
|
|
if ($context['show_approve']) |
79
|
|
|
{ |
80
|
|
|
$context['tabs']['approve'] = array( |
81
|
|
|
'label' => sprintf($txt['admin_browse_awaiting_approval'], $context['awaiting_approval']), |
82
|
|
|
'description' => $txt['admin_browse_approve_desc'], |
83
|
|
|
'url' => $scripturl . '?action=admin;area=viewmembers;sa=browse;type=approve', |
84
|
|
|
); |
85
|
|
|
$context['last_tab'] = 'approve'; |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
// Do we have activations to show? |
89
|
|
|
if ($context['show_activate']) |
90
|
|
|
{ |
91
|
|
|
$context['tabs']['activate'] = array( |
92
|
|
|
'label' => sprintf($txt['admin_browse_awaiting_activate'], $context['awaiting_activation']), |
93
|
|
|
'description' => $txt['admin_browse_activate_desc'], |
94
|
|
|
'url' => $scripturl . '?action=admin;area=viewmembers;sa=browse;type=activate', |
95
|
|
|
); |
96
|
|
|
$context['last_tab'] = 'activate'; |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
// Call our hook now, letting customizations add to the subActions and/or modify $context as needed. |
100
|
|
|
call_integration_hook('integrate_manage_members', array(&$subActions)); |
101
|
|
|
|
102
|
|
|
// Default to sub action 'index' or 'settings' depending on permissions. |
103
|
|
|
$context['current_subaction'] = isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : 'all'; |
104
|
|
|
|
105
|
|
|
// We know the sub action, now we know what you're allowed to do. |
106
|
|
|
isAllowedTo($subActions[$context['current_subaction']][1]); |
107
|
|
|
|
108
|
|
|
// Set the last tab. |
109
|
|
|
$context['tabs'][$context['last_tab']]['is_last'] = true; |
110
|
|
|
|
111
|
|
|
// Find the active tab. |
112
|
|
|
if (isset($context['tabs'][$context['current_subaction']])) |
113
|
|
|
$context['tabs'][$context['current_subaction']]['is_selected'] = true; |
114
|
|
|
elseif (isset($context['current_subaction'])) |
115
|
|
|
foreach ($context['tabs'] as $id_tab => $tab_data) |
116
|
|
|
if (!empty($tab_data['selected_actions']) && in_array($context['current_subaction'], $tab_data['selected_actions'])) |
117
|
|
|
$context['tabs'][$id_tab]['is_selected'] = true; |
118
|
|
|
|
119
|
|
|
call_helper($subActions[$context['current_subaction']][0]); |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* View all members list. It allows sorting on several columns, and deletion of |
124
|
|
|
* selected members. It also handles the search query sent by |
125
|
|
|
* ?action=admin;area=viewmembers;sa=search. |
126
|
|
|
* Called by ?action=admin;area=viewmembers;sa=all or ?action=admin;area=viewmembers;sa=query. |
127
|
|
|
* Requires the moderate_forum permission. |
128
|
|
|
* |
129
|
|
|
* Uses a standard list (@see createList()) |
130
|
|
|
*/ |
131
|
|
|
function ViewMemberlist() |
132
|
|
|
{ |
133
|
|
|
global $txt, $scripturl, $context, $modSettings, $sourcedir, $smcFunc, $user_info; |
134
|
|
|
|
135
|
|
|
// Are we performing a delete? |
136
|
|
|
if (isset($_POST['delete_members']) && !empty($_POST['delete']) && allowedTo('profile_remove_any')) |
137
|
|
|
{ |
138
|
|
|
checkSession(); |
139
|
|
|
|
140
|
|
|
// Clean the input. |
141
|
|
|
foreach ($_POST['delete'] as $key => $value) |
142
|
|
|
{ |
143
|
|
|
// Don't delete yourself, idiot. |
144
|
|
|
if ($value != $user_info['id']) |
145
|
|
|
$delete[$key] = (int) $value; |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
if (!empty($delete)) |
149
|
|
|
{ |
150
|
|
|
// Delete all the selected members. |
151
|
|
|
require_once($sourcedir . '/Subs-Members.php'); |
152
|
|
|
deleteMembers($delete, true); |
153
|
|
|
} |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
// Check input after a member search has been submitted. |
157
|
|
|
if ($context['current_subaction'] == 'query') |
158
|
|
|
{ |
159
|
|
|
// Retrieving the membergroups and postgroups. |
160
|
|
|
$context['membergroups'] = array( |
161
|
|
|
array( |
162
|
|
|
'id' => 0, |
163
|
|
|
'name' => $txt['membergroups_members'], |
164
|
|
|
'can_be_additional' => false |
165
|
|
|
) |
166
|
|
|
); |
167
|
|
|
$context['postgroups'] = array(); |
168
|
|
|
|
169
|
|
|
$request = $smcFunc['db_query']('', ' |
170
|
|
|
SELECT id_group, group_name, min_posts |
171
|
|
|
FROM {db_prefix}membergroups |
172
|
|
|
WHERE id_group != {int:moderator_group} |
173
|
|
|
ORDER BY min_posts, CASE WHEN id_group < {int:newbie_group} THEN id_group ELSE 4 END, group_name', |
174
|
|
|
array( |
175
|
|
|
'moderator_group' => 3, |
176
|
|
|
'newbie_group' => 4, |
177
|
|
|
) |
178
|
|
|
); |
179
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
180
|
|
|
{ |
181
|
|
|
if ($row['min_posts'] == -1) |
182
|
|
|
$context['membergroups'][] = array( |
183
|
|
|
'id' => $row['id_group'], |
184
|
|
|
'name' => $row['group_name'], |
185
|
|
|
'can_be_additional' => true |
186
|
|
|
); |
187
|
|
|
else |
188
|
|
|
$context['postgroups'][] = array( |
189
|
|
|
'id' => $row['id_group'], |
190
|
|
|
'name' => $row['group_name'] |
191
|
|
|
); |
192
|
|
|
} |
193
|
|
|
$smcFunc['db_free_result']($request); |
194
|
|
|
|
195
|
|
|
// Some data about the form fields and how they are linked to the database. |
196
|
|
|
$params = array( |
197
|
|
|
'mem_id' => array( |
198
|
|
|
'db_fields' => array('id_member'), |
199
|
|
|
'type' => 'int', |
200
|
|
|
'range' => true |
201
|
|
|
), |
202
|
|
|
'age' => array( |
203
|
|
|
'db_fields' => array('birthdate'), |
204
|
|
|
'type' => 'age', |
205
|
|
|
'range' => true |
206
|
|
|
), |
207
|
|
|
'posts' => array( |
208
|
|
|
'db_fields' => array('posts'), |
209
|
|
|
'type' => 'int', |
210
|
|
|
'range' => true |
211
|
|
|
), |
212
|
|
|
'reg_date' => array( |
213
|
|
|
'db_fields' => array('date_registered'), |
214
|
|
|
'type' => 'date', |
215
|
|
|
'range' => true |
216
|
|
|
), |
217
|
|
|
'last_online' => array( |
218
|
|
|
'db_fields' => array('last_login'), |
219
|
|
|
'type' => 'date', |
220
|
|
|
'range' => true |
221
|
|
|
), |
222
|
|
|
'activated' => array( |
223
|
|
|
'db_fields' => array('CASE WHEN is_activated IN (1, 11) THEN 1 ELSE 0 END'), |
224
|
|
|
'type' => 'checkbox', |
225
|
|
|
'values' => array('0', '1'), |
226
|
|
|
), |
227
|
|
|
'membername' => array( |
228
|
|
|
'db_fields' => array('member_name', 'real_name'), |
229
|
|
|
'type' => 'string' |
230
|
|
|
), |
231
|
|
|
'email' => array( |
232
|
|
|
'db_fields' => array('email_address'), |
233
|
|
|
'type' => 'string' |
234
|
|
|
), |
235
|
|
|
'website' => array( |
236
|
|
|
'db_fields' => array('website_title', 'website_url'), |
237
|
|
|
'type' => 'string' |
238
|
|
|
), |
239
|
|
|
'ip' => array( |
240
|
|
|
'db_fields' => array('member_ip'), |
241
|
|
|
'type' => 'inet' |
242
|
|
|
), |
243
|
|
|
'membergroups' => array( |
244
|
|
|
'db_fields' => array('id_group'), |
245
|
|
|
'type' => 'groups' |
246
|
|
|
), |
247
|
|
|
'postgroups' => array( |
248
|
|
|
'db_fields' => array('id_group'), |
249
|
|
|
'type' => 'groups' |
250
|
|
|
) |
251
|
|
|
); |
252
|
|
|
$range_trans = array( |
253
|
|
|
'--' => '<', |
254
|
|
|
'-' => '<=', |
255
|
|
|
'=' => '=', |
256
|
|
|
'+' => '>=', |
257
|
|
|
'++' => '>' |
258
|
|
|
); |
259
|
|
|
|
260
|
|
|
call_integration_hook('integrate_view_members_params', array(&$params)); |
261
|
|
|
|
262
|
|
|
$search_params = array(); |
263
|
|
|
if ($context['current_subaction'] == 'query' && !empty($_REQUEST['params']) && empty($_POST['types'])) |
264
|
|
|
$search_params = $smcFunc['json_decode'](base64_decode($_REQUEST['params']), true); |
265
|
|
|
elseif (!empty($_POST)) |
266
|
|
|
{ |
267
|
|
|
$search_params['types'] = $_POST['types']; |
268
|
|
|
foreach ($params as $param_name => $param_info) |
269
|
|
|
if (isset($_POST[$param_name])) |
270
|
|
|
$search_params[$param_name] = $_POST[$param_name]; |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
$search_url_params = isset($search_params) ? base64_encode($smcFunc['json_encode']($search_params)) : null; |
274
|
|
|
|
275
|
|
|
// @todo Validate a little more. |
276
|
|
|
|
277
|
|
|
// Loop through every field of the form. |
278
|
|
|
$query_parts = array(); |
279
|
|
|
$where_params = array(); |
280
|
|
|
foreach ($params as $param_name => $param_info) |
281
|
|
|
{ |
282
|
|
|
// Not filled in? |
283
|
|
|
if (!isset($search_params[$param_name]) || $search_params[$param_name] === '') |
284
|
|
|
continue; |
285
|
|
|
|
286
|
|
|
// Make sure numeric values are really numeric. |
287
|
|
|
if (in_array($param_info['type'], array('int', 'age'))) |
288
|
|
|
$search_params[$param_name] = (int) $search_params[$param_name]; |
289
|
|
|
// Date values have to match a date format that PHP recognizes. |
290
|
|
|
elseif ($param_info['type'] == 'date') |
291
|
|
|
{ |
292
|
|
|
$search_params[$param_name] = strtotime($search_params[$param_name] . ' ' . getUserTimezone()); |
293
|
|
|
if (!is_int($search_params[$param_name])) |
294
|
|
|
continue; |
295
|
|
|
} |
296
|
|
|
elseif ($param_info['type'] == 'inet') |
297
|
|
|
{ |
298
|
|
|
$search_params[$param_name] = ip2range($search_params[$param_name]); |
299
|
|
|
if (empty($search_params[$param_name])) |
300
|
|
|
continue; |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
// Those values that are in some kind of range (<, <=, =, >=, >). |
304
|
|
|
if (!empty($param_info['range'])) |
305
|
|
|
{ |
306
|
|
|
// Default to '=', just in case... |
307
|
|
|
if (empty($range_trans[$search_params['types'][$param_name]])) |
308
|
|
|
$search_params['types'][$param_name] = '='; |
309
|
|
|
|
310
|
|
|
// Handle special case 'age'. |
311
|
|
|
if ($param_info['type'] == 'age') |
312
|
|
|
{ |
313
|
|
|
// All people that were born between $lowerlimit and $upperlimit are currently the specified age. |
314
|
|
|
$datearray = getdate(time()); |
315
|
|
|
$upperlimit = sprintf('%04d-%02d-%02d', $datearray['year'] - $search_params[$param_name], $datearray['mon'], $datearray['mday']); |
316
|
|
|
$lowerlimit = sprintf('%04d-%02d-%02d', $datearray['year'] - $search_params[$param_name] - 1, $datearray['mon'], $datearray['mday']); |
317
|
|
|
if (in_array($search_params['types'][$param_name], array('-', '--', '='))) |
318
|
|
|
{ |
319
|
|
|
$query_parts[] = ($param_info['db_fields'][0]) . ' > {string:' . $param_name . '_minlimit}'; |
320
|
|
|
$where_params[$param_name . '_minlimit'] = ($search_params['types'][$param_name] == '--' ? $upperlimit : $lowerlimit); |
321
|
|
|
} |
322
|
|
|
if (in_array($search_params['types'][$param_name], array('+', '++', '='))) |
323
|
|
|
{ |
324
|
|
|
$query_parts[] = ($param_info['db_fields'][0]) . ' <= {string:' . $param_name . '_pluslimit}'; |
325
|
|
|
$where_params[$param_name . '_pluslimit'] = ($search_params['types'][$param_name] == '++' ? $lowerlimit : $upperlimit); |
326
|
|
|
|
327
|
|
|
// Make sure that members that didn't set their birth year are not queried. |
328
|
|
|
$query_parts[] = ($param_info['db_fields'][0]) . ' > {date:dec_zero_date}'; |
329
|
|
|
$where_params['dec_zero_date'] = '0004-12-31'; |
330
|
|
|
} |
331
|
|
|
} |
332
|
|
|
// Special case - equals a date. |
333
|
|
|
elseif ($param_info['type'] == 'date') |
334
|
|
|
{ |
335
|
|
|
if ($search_params['types'][$param_name] == '=') |
336
|
|
|
{ |
337
|
|
|
$query_parts[] = $param_info['db_fields'][0] . ' >= ' . $search_params[$param_name] . ' AND ' . $param_info['db_fields'][0] . ' < ' . ($search_params[$param_name] + 86400); |
338
|
|
|
} |
339
|
|
|
// Less than or equal to |
340
|
|
|
elseif ($search_params['types'][$param_name] == '-') |
341
|
|
|
{ |
342
|
|
|
$query_parts[] = $param_info['db_fields'][0] . ' < ' . ($search_params[$param_name] + 86400); |
343
|
|
|
} |
344
|
|
|
// Greater than |
345
|
|
|
elseif ($search_params['types'][$param_name] == '++') |
346
|
|
|
{ |
347
|
|
|
$query_parts[] = $param_info['db_fields'][0] . ' >= ' . ($search_params[$param_name] + 86400); |
348
|
|
|
} |
349
|
|
|
else |
350
|
|
|
$query_parts[] = $param_info['db_fields'][0] . ' ' . $range_trans[$search_params['types'][$param_name]] . ' ' . $search_params[$param_name]; |
351
|
|
|
} |
352
|
|
|
else |
353
|
|
|
$query_parts[] = $param_info['db_fields'][0] . ' ' . $range_trans[$search_params['types'][$param_name]] . ' ' . $search_params[$param_name]; |
354
|
|
|
} |
355
|
|
|
// Checkboxes. |
356
|
|
|
elseif ($param_info['type'] == 'checkbox') |
357
|
|
|
{ |
358
|
|
|
// Each checkbox or no checkbox at all is checked -> ignore. |
359
|
|
|
if (!is_array($search_params[$param_name]) || count($search_params[$param_name]) == 0 || count($search_params[$param_name]) == count($param_info['values'])) |
360
|
|
|
continue; |
361
|
|
|
|
362
|
|
|
$query_parts[] = ($param_info['db_fields'][0]) . ' IN ({array_string:' . $param_name . '_check})'; |
363
|
|
|
$where_params[$param_name . '_check'] = $search_params[$param_name]; |
364
|
|
|
} |
365
|
|
|
// INET. |
366
|
|
|
elseif ($param_info['type'] == 'inet') |
367
|
|
|
{ |
368
|
|
|
if (count($search_params[$param_name]) === 1) |
369
|
|
|
{ |
370
|
|
|
$query_parts[] = '(' . $param_info['db_fields'][0] . ' = {inet:' . $param_name . '})'; |
371
|
|
|
$where_params[$param_name] = $search_params[$param_name][0]; |
372
|
|
|
} |
373
|
|
|
elseif (count($search_params[$param_name]) === 2) |
374
|
|
|
{ |
375
|
|
|
$query_parts[] = '(' . $param_info['db_fields'][0] . ' <= {inet:' . $param_name . '_high} and ' . $param_info['db_fields'][0] . ' >= {inet:' . $param_name . '_low})'; |
376
|
|
|
$where_params[$param_name . '_low'] = $search_params[$param_name]['low']; |
377
|
|
|
$where_params[$param_name . '_high'] = $search_params[$param_name]['high']; |
378
|
|
|
} |
379
|
|
|
|
380
|
|
|
} |
381
|
|
|
elseif ($param_info['type'] != 'groups') |
382
|
|
|
{ |
383
|
|
|
// Replace the wildcard characters ('*' and '?') into MySQL ones. |
384
|
|
|
$parameter = strtolower(strtr($smcFunc['htmlspecialchars']($search_params[$param_name], ENT_QUOTES), array('%' => '\%', '_' => '\_', '*' => '%', '?' => '_'))); |
385
|
|
|
|
386
|
|
|
if ($smcFunc['db_case_sensitive']) |
387
|
|
|
$query_parts[] = '(LOWER(' . implode(') LIKE {string:' . $param_name . '_normal} OR LOWER(', $param_info['db_fields']) . ') LIKE {string:' . $param_name . '_normal})'; |
388
|
|
|
else |
389
|
|
|
$query_parts[] = '(' . implode(' LIKE {string:' . $param_name . '_normal} OR ', $param_info['db_fields']) . ' LIKE {string:' . $param_name . '_normal})'; |
390
|
|
|
$where_params[$param_name . '_normal'] = '%' . $parameter . '%'; |
391
|
|
|
} |
392
|
|
|
} |
393
|
|
|
|
394
|
|
|
// Set up the membergroup query part. |
395
|
|
|
$mg_query_parts = array(); |
396
|
|
|
|
397
|
|
|
// Primary membergroups, but only if at least was was not selected. |
398
|
|
|
if (!empty($search_params['membergroups'][1]) && count($context['membergroups']) != count($search_params['membergroups'][1])) |
399
|
|
|
{ |
400
|
|
|
$mg_query_parts[] = 'mem.id_group IN ({array_int:group_check})'; |
401
|
|
|
$where_params['group_check'] = $search_params['membergroups'][1]; |
402
|
|
|
} |
403
|
|
|
|
404
|
|
|
// Additional membergroups (these are only relevant if not all primary groups where selected!). |
405
|
|
|
if (!empty($search_params['membergroups'][2]) && (empty($search_params['membergroups'][1]) || count($context['membergroups']) != count($search_params['membergroups'][1]))) |
406
|
|
|
foreach ($search_params['membergroups'][2] as $mg) |
407
|
|
|
{ |
408
|
|
|
$mg_query_parts[] = 'FIND_IN_SET({int:add_group_' . $mg . '}, mem.additional_groups) != 0'; |
409
|
|
|
$where_params['add_group_' . $mg] = $mg; |
410
|
|
|
} |
411
|
|
|
|
412
|
|
|
// Combine the one or two membergroup parts into one query part linked with an OR. |
413
|
|
|
if (!empty($mg_query_parts)) |
414
|
|
|
$query_parts[] = '(' . implode(' OR ', $mg_query_parts) . ')'; |
415
|
|
|
|
416
|
|
|
// Get all selected post count related membergroups. |
417
|
|
|
if (!empty($search_params['postgroups']) && count($search_params['postgroups']) != count($context['postgroups'])) |
418
|
|
|
{ |
419
|
|
|
$query_parts[] = 'id_post_group IN ({array_int:post_groups})'; |
420
|
|
|
$where_params['post_groups'] = $search_params['postgroups']; |
421
|
|
|
} |
422
|
|
|
|
423
|
|
|
// Construct the where part of the query. |
424
|
|
|
$where = empty($query_parts) ? '1=1' : implode(' |
425
|
|
|
AND ', $query_parts); |
426
|
|
|
} |
427
|
|
|
else |
428
|
|
|
$search_url_params = null; |
429
|
|
|
|
430
|
|
|
// Construct the additional URL part with the query info in it. |
431
|
|
|
$context['params_url'] = $context['current_subaction'] == 'query' ? ';sa=query;params=' . $search_url_params : ''; |
432
|
|
|
|
433
|
|
|
// Get the title and sub template ready.. |
434
|
|
|
$context['page_title'] = $txt['admin_members']; |
435
|
|
|
|
436
|
|
|
$listOptions = array( |
437
|
|
|
'id' => 'member_list', |
438
|
|
|
'title' => $txt['members_list'], |
439
|
|
|
'items_per_page' => $modSettings['defaultMaxMembers'], |
440
|
|
|
'base_href' => $scripturl . '?action=admin;area=viewmembers' . $context['params_url'], |
441
|
|
|
'default_sort_col' => 'user_name', |
442
|
|
|
'get_items' => array( |
443
|
|
|
'file' => $sourcedir . '/Subs-Members.php', |
444
|
|
|
'function' => 'list_getMembers', |
445
|
|
|
'params' => array( |
446
|
|
|
isset($where) ? $where : '1=1', |
447
|
|
|
isset($where_params) ? $where_params : array(), |
448
|
|
|
), |
449
|
|
|
), |
450
|
|
|
'get_count' => array( |
451
|
|
|
'file' => $sourcedir . '/Subs-Members.php', |
452
|
|
|
'function' => 'list_getNumMembers', |
453
|
|
|
'params' => array( |
454
|
|
|
isset($where) ? $where : '1=1', |
455
|
|
|
isset($where_params) ? $where_params : array(), |
456
|
|
|
), |
457
|
|
|
), |
458
|
|
|
'columns' => array( |
459
|
|
|
'id_member' => array( |
460
|
|
|
'header' => array( |
461
|
|
|
'value' => $txt['member_id'], |
462
|
|
|
), |
463
|
|
|
'data' => array( |
464
|
|
|
'db' => 'id_member', |
465
|
|
|
), |
466
|
|
|
'sort' => array( |
467
|
|
|
'default' => 'id_member', |
468
|
|
|
'reverse' => 'id_member DESC', |
469
|
|
|
), |
470
|
|
|
), |
471
|
|
|
'user_name' => array( |
472
|
|
|
'header' => array( |
473
|
|
|
'value' => $txt['username'], |
474
|
|
|
), |
475
|
|
|
'data' => array( |
476
|
|
|
'sprintf' => array( |
477
|
|
|
'format' => '<a href="' . strtr($scripturl, array('%' => '%%')) . '?action=profile;u=%1$d">%2$s</a>', |
478
|
|
|
'params' => array( |
479
|
|
|
'id_member' => false, |
480
|
|
|
'member_name' => false, |
481
|
|
|
), |
482
|
|
|
), |
483
|
|
|
), |
484
|
|
|
'sort' => array( |
485
|
|
|
'default' => 'member_name', |
486
|
|
|
'reverse' => 'member_name DESC', |
487
|
|
|
), |
488
|
|
|
), |
489
|
|
|
'display_name' => array( |
490
|
|
|
'header' => array( |
491
|
|
|
'value' => $txt['display_name'], |
492
|
|
|
), |
493
|
|
|
'data' => array( |
494
|
|
|
'sprintf' => array( |
495
|
|
|
'format' => '<a href="' . strtr($scripturl, array('%' => '%%')) . '?action=profile;u=%1$d">%2$s</a>', |
496
|
|
|
'params' => array( |
497
|
|
|
'id_member' => false, |
498
|
|
|
'real_name' => false, |
499
|
|
|
), |
500
|
|
|
), |
501
|
|
|
), |
502
|
|
|
'sort' => array( |
503
|
|
|
'default' => 'real_name', |
504
|
|
|
'reverse' => 'real_name DESC', |
505
|
|
|
), |
506
|
|
|
), |
507
|
|
|
'email' => array( |
508
|
|
|
'header' => array( |
509
|
|
|
'value' => $txt['email_address'], |
510
|
|
|
), |
511
|
|
|
'data' => array( |
512
|
|
|
'sprintf' => array( |
513
|
|
|
'format' => '<a href="mailto:%1$s">%1$s</a>', |
514
|
|
|
'params' => array( |
515
|
|
|
'email_address' => true, |
516
|
|
|
), |
517
|
|
|
), |
518
|
|
|
), |
519
|
|
|
'sort' => array( |
520
|
|
|
'default' => 'email_address', |
521
|
|
|
'reverse' => 'email_address DESC', |
522
|
|
|
), |
523
|
|
|
), |
524
|
|
|
'ip' => array( |
525
|
|
|
'header' => array( |
526
|
|
|
'value' => $txt['ip_address'], |
527
|
|
|
), |
528
|
|
|
'data' => array( |
529
|
|
|
'sprintf' => array( |
530
|
|
|
'format' => '<a href="' . strtr($scripturl, array('%' => '%%')) . '?action=trackip;searchip=%1$s">%1$s</a>', |
531
|
|
|
'params' => array( |
532
|
|
|
'member_ip' => false, |
533
|
|
|
), |
534
|
|
|
), |
535
|
|
|
), |
536
|
|
|
'sort' => array( |
537
|
|
|
'default' => 'member_ip', |
538
|
|
|
'reverse' => 'member_ip DESC', |
539
|
|
|
), |
540
|
|
|
), |
541
|
|
|
'last_active' => array( |
542
|
|
|
'header' => array( |
543
|
|
|
'value' => $txt['viewmembers_online'], |
544
|
|
|
), |
545
|
|
|
'data' => array( |
546
|
|
|
'function' => function($rowData) use ($txt) |
547
|
|
|
{ |
548
|
|
|
// Calculate number of days since last online. |
549
|
|
|
if (empty($rowData['last_login'])) |
550
|
|
|
$difference = $txt['never']; |
551
|
|
|
else |
552
|
|
|
{ |
553
|
|
|
$num_days_difference = jeffsdatediff($rowData['last_login']); |
554
|
|
|
|
555
|
|
|
// Today. |
556
|
|
|
if (empty($num_days_difference)) |
557
|
|
|
$difference = $txt['viewmembers_today']; |
558
|
|
|
|
559
|
|
|
// Yesterday. |
560
|
|
|
elseif ($num_days_difference == 1) |
561
|
|
|
$difference = sprintf('1 %1$s', $txt['viewmembers_day_ago']); |
562
|
|
|
|
563
|
|
|
// X days ago. |
564
|
|
|
else |
565
|
|
|
$difference = sprintf('%1$d %2$s', $num_days_difference, $txt['viewmembers_days_ago']); |
566
|
|
|
} |
567
|
|
|
|
568
|
|
|
// Show it in italics if they're not activated... |
569
|
|
|
if ($rowData['is_activated'] % 10 != 1) |
570
|
|
|
$difference = sprintf('<em title="%1$s">%2$s</em>', $txt['not_activated'], $difference); |
571
|
|
|
|
572
|
|
|
return $difference; |
573
|
|
|
}, |
574
|
|
|
), |
575
|
|
|
'sort' => array( |
576
|
|
|
'default' => 'last_login DESC', |
577
|
|
|
'reverse' => 'last_login', |
578
|
|
|
), |
579
|
|
|
), |
580
|
|
|
'posts' => array( |
581
|
|
|
'header' => array( |
582
|
|
|
'value' => $txt['member_postcount'], |
583
|
|
|
), |
584
|
|
|
'data' => array( |
585
|
|
|
'db' => 'posts', |
586
|
|
|
), |
587
|
|
|
'sort' => array( |
588
|
|
|
'default' => 'posts', |
589
|
|
|
'reverse' => 'posts DESC', |
590
|
|
|
), |
591
|
|
|
), |
592
|
|
|
'check' => array( |
593
|
|
|
'header' => array( |
594
|
|
|
'value' => '<input type="checkbox" onclick="invertAll(this, this.form);">', |
595
|
|
|
'class' => 'centercol', |
596
|
|
|
), |
597
|
|
|
'data' => array( |
598
|
|
|
'function' => function($rowData) use ($user_info) |
599
|
|
|
{ |
600
|
|
|
return '<input type="checkbox" name="delete[]" value="' . $rowData['id_member'] . '"' . ($rowData['id_member'] == $user_info['id'] || $rowData['id_group'] == 1 || in_array(1, explode(',', $rowData['additional_groups'])) ? ' disabled' : '') . '>'; |
601
|
|
|
}, |
602
|
|
|
'class' => 'centercol', |
603
|
|
|
), |
604
|
|
|
), |
605
|
|
|
), |
606
|
|
|
'form' => array( |
607
|
|
|
'href' => $scripturl . '?action=admin;area=viewmembers' . $context['params_url'], |
608
|
|
|
'include_start' => true, |
609
|
|
|
'include_sort' => true, |
610
|
|
|
), |
611
|
|
|
'additional_rows' => array( |
612
|
|
|
array( |
613
|
|
|
'position' => 'below_table_data', |
614
|
|
|
'value' => '<input type="submit" name="delete_members" value="' . $txt['admin_delete_members'] . '" data-confirm="' . $txt['confirm_delete_members'] . '" class="button you_sure">', |
615
|
|
|
), |
616
|
|
|
), |
617
|
|
|
); |
618
|
|
|
|
619
|
|
|
// Without enough permissions, don't show 'delete members' checkboxes. |
620
|
|
|
if (!allowedTo('profile_remove_any')) |
621
|
|
|
unset($listOptions['cols']['check'], $listOptions['form'], $listOptions['additional_rows']); |
622
|
|
|
|
623
|
|
|
require_once($sourcedir . '/Subs-List.php'); |
624
|
|
|
createList($listOptions); |
625
|
|
|
|
626
|
|
|
$context['sub_template'] = 'show_list'; |
627
|
|
|
$context['default_list'] = 'member_list'; |
628
|
|
|
} |
629
|
|
|
|
630
|
|
|
/** |
631
|
|
|
* Search the member list, using one or more criteria. |
632
|
|
|
* Called by ?action=admin;area=viewmembers;sa=search. |
633
|
|
|
* Requires the moderate_forum permission. |
634
|
|
|
* form is submitted to action=admin;area=viewmembers;sa=query. |
635
|
|
|
* |
636
|
|
|
* @uses template_search_members() |
637
|
|
|
*/ |
638
|
|
|
function SearchMembers() |
639
|
|
|
{ |
640
|
|
|
global $context, $txt, $smcFunc; |
641
|
|
|
|
642
|
|
|
// Get a list of all the membergroups and postgroups that can be selected. |
643
|
|
|
$context['membergroups'] = array( |
644
|
|
|
array( |
645
|
|
|
'id' => 0, |
646
|
|
|
'name' => $txt['membergroups_members'], |
647
|
|
|
'can_be_additional' => false |
648
|
|
|
) |
649
|
|
|
); |
650
|
|
|
$context['postgroups'] = array(); |
651
|
|
|
|
652
|
|
|
$request = $smcFunc['db_query']('', ' |
653
|
|
|
SELECT id_group, group_name, min_posts |
654
|
|
|
FROM {db_prefix}membergroups |
655
|
|
|
WHERE id_group != {int:moderator_group} |
656
|
|
|
ORDER BY min_posts, CASE WHEN id_group < {int:newbie_group} THEN id_group ELSE 4 END, group_name', |
657
|
|
|
array( |
658
|
|
|
'moderator_group' => 3, |
659
|
|
|
'newbie_group' => 4, |
660
|
|
|
) |
661
|
|
|
); |
662
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
663
|
|
|
{ |
664
|
|
|
if ($row['min_posts'] == -1) |
665
|
|
|
$context['membergroups'][] = array( |
666
|
|
|
'id' => $row['id_group'], |
667
|
|
|
'name' => $row['group_name'], |
668
|
|
|
'can_be_additional' => true |
669
|
|
|
); |
670
|
|
|
else |
671
|
|
|
$context['postgroups'][] = array( |
672
|
|
|
'id' => $row['id_group'], |
673
|
|
|
'name' => $row['group_name'] |
674
|
|
|
); |
675
|
|
|
} |
676
|
|
|
$smcFunc['db_free_result']($request); |
677
|
|
|
|
678
|
|
|
$context['page_title'] = $txt['admin_members']; |
679
|
|
|
$context['sub_template'] = 'search_members'; |
680
|
|
|
} |
681
|
|
|
|
682
|
|
|
/** |
683
|
|
|
* List all members who are awaiting approval / activation, sortable on different columns. |
684
|
|
|
* It allows instant approval or activation of (a selection of) members. |
685
|
|
|
* Called by ?action=admin;area=viewmembers;sa=browse;type=approve |
686
|
|
|
* or ?action=admin;area=viewmembers;sa=browse;type=activate. |
687
|
|
|
* The form submits to ?action=admin;area=viewmembers;sa=approve. |
688
|
|
|
* Requires the moderate_forum permission. |
689
|
|
|
* |
690
|
|
|
* @uses template_admin_browse() |
691
|
|
|
*/ |
692
|
|
|
function MembersAwaitingActivation() |
693
|
|
|
{ |
694
|
|
|
global $txt, $context, $scripturl, $modSettings; |
695
|
|
|
global $sourcedir; |
696
|
|
|
|
697
|
|
|
// Not a lot here! |
698
|
|
|
$context['page_title'] = $txt['admin_members']; |
699
|
|
|
$context['sub_template'] = 'admin_browse'; |
700
|
|
|
$context['browse_type'] = isset($_REQUEST['type']) ? $_REQUEST['type'] : (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 1 ? 'activate' : 'approve'); |
701
|
|
|
if (isset($context['tabs'][$context['browse_type']])) |
702
|
|
|
$context['tabs'][$context['browse_type']]['is_selected'] = true; |
703
|
|
|
|
704
|
|
|
// Allowed filters are those we can have, in theory. |
705
|
|
|
$context['allowed_filters'] = $context['browse_type'] == 'approve' ? array(3, 4, 5) : array(0, 2); |
706
|
|
|
$context['current_filter'] = isset($_REQUEST['filter']) && in_array($_REQUEST['filter'], $context['allowed_filters']) && !empty($context['activation_numbers'][$_REQUEST['filter']]) ? (int) $_REQUEST['filter'] : -1; |
707
|
|
|
|
708
|
|
|
// Sort out the different sub areas that we can actually filter by. |
709
|
|
|
$context['available_filters'] = array(); |
710
|
|
|
foreach ($context['activation_numbers'] as $type => $amount) |
711
|
|
|
{ |
712
|
|
|
// We have some of these... |
713
|
|
|
if (in_array($type, $context['allowed_filters']) && $amount > 0) |
714
|
|
|
$context['available_filters'][] = array( |
715
|
|
|
'type' => $type, |
716
|
|
|
'amount' => $amount, |
717
|
|
|
'desc' => isset($txt['admin_browse_filter_type_' . $type]) ? $txt['admin_browse_filter_type_' . $type] : '?', |
718
|
|
|
'selected' => $type == $context['current_filter'] |
719
|
|
|
); |
720
|
|
|
} |
721
|
|
|
|
722
|
|
|
// If the filter was not sent, set it to whatever has people in it! |
723
|
|
|
if ($context['current_filter'] == -1 && !empty($context['available_filters'][0]['amount'])) |
724
|
|
|
$context['current_filter'] = $context['available_filters'][0]['type']; |
725
|
|
|
|
726
|
|
|
// This little variable is used to determine if we should flag where we are looking. |
727
|
|
|
$context['show_filter'] = ($context['current_filter'] != 0 && $context['current_filter'] != 3) || count($context['available_filters']) > 1; |
728
|
|
|
|
729
|
|
|
// The columns that can be sorted. |
730
|
|
|
$context['columns'] = array( |
731
|
|
|
'id_member' => array('label' => $txt['admin_browse_id']), |
732
|
|
|
'member_name' => array('label' => $txt['admin_browse_username']), |
733
|
|
|
'email_address' => array('label' => $txt['admin_browse_email']), |
734
|
|
|
'member_ip' => array('label' => $txt['admin_browse_ip']), |
735
|
|
|
'date_registered' => array('label' => $txt['admin_browse_registered']), |
736
|
|
|
); |
737
|
|
|
|
738
|
|
|
// Are we showing duplicate information? |
739
|
|
|
if (isset($_GET['showdupes'])) |
740
|
|
|
$_SESSION['showdupes'] = (int) $_GET['showdupes']; |
741
|
|
|
$context['show_duplicates'] = !empty($_SESSION['showdupes']); |
742
|
|
|
|
743
|
|
|
// Determine which actions we should allow on this page. |
744
|
|
|
if ($context['browse_type'] == 'approve') |
745
|
|
|
{ |
746
|
|
|
// If we are approving deleted accounts we have a slightly different list... actually a mirror ;) |
747
|
|
|
if ($context['current_filter'] == 4) |
748
|
|
|
$context['allowed_actions'] = array( |
749
|
|
|
'reject' => $txt['admin_browse_w_approve_deletion'], |
750
|
|
|
'ok' => $txt['admin_browse_w_reject'], |
751
|
|
|
); |
752
|
|
|
else |
753
|
|
|
$context['allowed_actions'] = array( |
754
|
|
|
'ok' => $txt['admin_browse_w_approve'] .' '. $txt['admin_browse_no_email'], |
755
|
|
|
'okemail' => $txt['admin_browse_w_approve'] . ' ' . $txt['admin_browse_w_email'], |
756
|
|
|
'require_activation' => $txt['admin_browse_w_approve_require_activate'], |
757
|
|
|
'reject' => $txt['admin_browse_w_reject'], |
758
|
|
|
'rejectemail' => $txt['admin_browse_w_reject'] . ' ' . $txt['admin_browse_w_email'], |
759
|
|
|
); |
760
|
|
|
} |
761
|
|
|
elseif ($context['browse_type'] == 'activate') |
762
|
|
|
$context['allowed_actions'] = array( |
763
|
|
|
'ok' => $txt['admin_browse_w_activate'], |
764
|
|
|
'okemail' => $txt['admin_browse_w_activate'] . ' ' . $txt['admin_browse_w_email'], |
765
|
|
|
'delete' => $txt['admin_browse_w_delete'], |
766
|
|
|
'deleteemail' => $txt['admin_browse_w_delete'] . ' ' . $txt['admin_browse_w_email'], |
767
|
|
|
'remind' => $txt['admin_browse_w_remind'] . ' ' . $txt['admin_browse_w_email'], |
768
|
|
|
); |
769
|
|
|
|
770
|
|
|
// Create an option list for actions allowed to be done with selected members. |
771
|
|
|
$allowed_actions = ' |
772
|
|
|
<option selected value="">' . $txt['admin_browse_with_selected'] . ':</option> |
773
|
|
|
<option value="" disabled>-----------------------------</option>'; |
774
|
|
|
foreach ($context['allowed_actions'] as $key => $desc) |
775
|
|
|
$allowed_actions .= ' |
776
|
|
|
<option value="' . $key . '">' . $desc . '</option>'; |
777
|
|
|
|
778
|
|
|
// Setup the Javascript function for selecting an action for the list. |
779
|
|
|
$javascript = ' |
780
|
|
|
function onSelectChange() |
781
|
|
|
{ |
782
|
|
|
if (document.forms.postForm.todo.value == "") |
783
|
|
|
return; |
784
|
|
|
|
785
|
|
|
var message = "";'; |
786
|
|
|
|
787
|
|
|
// We have special messages for approving deletion of accounts - it's surprisingly logical - honest. |
788
|
|
|
if ($context['current_filter'] == 4) |
789
|
|
|
$javascript .= ' |
790
|
|
|
if (document.forms.postForm.todo.value.indexOf("reject") != -1) |
791
|
|
|
message = "' . $txt['admin_browse_w_delete'] . '"; |
792
|
|
|
else |
793
|
|
|
message = "' . $txt['admin_browse_w_reject'] . '";'; |
794
|
|
|
|
795
|
|
|
// Otherwise a nice standard message. |
796
|
|
|
else |
797
|
|
|
$javascript .= ' |
798
|
|
|
if (document.forms.postForm.todo.value.indexOf("delete") != -1) |
799
|
|
|
message = "' . $txt['admin_browse_w_delete'] . '"; |
800
|
|
|
else if (document.forms.postForm.todo.value.indexOf("reject") != -1) |
801
|
|
|
message = "' . $txt['admin_browse_w_reject'] . '"; |
802
|
|
|
else if (document.forms.postForm.todo.value == "remind") |
803
|
|
|
message = "' . $txt['admin_browse_w_remind'] . '"; |
804
|
|
|
else |
805
|
|
|
message = "' . ($context['browse_type'] == 'approve' ? $txt['admin_browse_w_approve'] : $txt['admin_browse_w_activate']) . '";'; |
806
|
|
|
|
807
|
|
|
$javascript .= ' |
808
|
|
|
if (confirm(message + " ' . $txt['admin_browse_warn'] . '")) |
809
|
|
|
document.forms.postForm.submit(); |
810
|
|
|
}'; |
811
|
|
|
|
812
|
|
|
$listOptions = array( |
813
|
|
|
'id' => 'approve_list', |
814
|
|
|
'items_per_page' => $modSettings['defaultMaxMembers'], |
815
|
|
|
'base_href' => $scripturl . '?action=admin;area=viewmembers;sa=browse;type=' . $context['browse_type'] . (!empty($context['show_filter']) ? ';filter=' . $context['current_filter'] : ''), |
816
|
|
|
'default_sort_col' => 'date_registered', |
817
|
|
|
'get_items' => array( |
818
|
|
|
'file' => $sourcedir . '/Subs-Members.php', |
819
|
|
|
'function' => 'list_getMembers', |
820
|
|
|
'params' => array( |
821
|
|
|
'is_activated = {int:activated_status}', |
822
|
|
|
array('activated_status' => $context['current_filter']), |
823
|
|
|
$context['show_duplicates'], |
824
|
|
|
), |
825
|
|
|
), |
826
|
|
|
'get_count' => array( |
827
|
|
|
'file' => $sourcedir . '/Subs-Members.php', |
828
|
|
|
'function' => 'list_getNumMembers', |
829
|
|
|
'params' => array( |
830
|
|
|
'is_activated = {int:activated_status}', |
831
|
|
|
array('activated_status' => $context['current_filter']), |
832
|
|
|
), |
833
|
|
|
), |
834
|
|
|
'columns' => array( |
835
|
|
|
'id_member' => array( |
836
|
|
|
'header' => array( |
837
|
|
|
'value' => $txt['member_id'], |
838
|
|
|
), |
839
|
|
|
'data' => array( |
840
|
|
|
'db' => 'id_member', |
841
|
|
|
), |
842
|
|
|
'sort' => array( |
843
|
|
|
'default' => 'id_member', |
844
|
|
|
'reverse' => 'id_member DESC', |
845
|
|
|
), |
846
|
|
|
), |
847
|
|
|
'user_name' => array( |
848
|
|
|
'header' => array( |
849
|
|
|
'value' => $txt['username'], |
850
|
|
|
), |
851
|
|
|
'data' => array( |
852
|
|
|
'sprintf' => array( |
853
|
|
|
'format' => '<a href="' . strtr($scripturl, array('%' => '%%')) . '?action=profile;u=%1$d">%2$s</a>', |
854
|
|
|
'params' => array( |
855
|
|
|
'id_member' => false, |
856
|
|
|
'member_name' => false, |
857
|
|
|
), |
858
|
|
|
), |
859
|
|
|
), |
860
|
|
|
'sort' => array( |
861
|
|
|
'default' => 'member_name', |
862
|
|
|
'reverse' => 'member_name DESC', |
863
|
|
|
), |
864
|
|
|
), |
865
|
|
|
'email' => array( |
866
|
|
|
'header' => array( |
867
|
|
|
'value' => $txt['email_address'], |
868
|
|
|
), |
869
|
|
|
'data' => array( |
870
|
|
|
'sprintf' => array( |
871
|
|
|
'format' => '<a href="mailto:%1$s">%1$s</a>', |
872
|
|
|
'params' => array( |
873
|
|
|
'email_address' => true, |
874
|
|
|
), |
875
|
|
|
), |
876
|
|
|
), |
877
|
|
|
'sort' => array( |
878
|
|
|
'default' => 'email_address', |
879
|
|
|
'reverse' => 'email_address DESC', |
880
|
|
|
), |
881
|
|
|
), |
882
|
|
|
'ip' => array( |
883
|
|
|
'header' => array( |
884
|
|
|
'value' => $txt['ip_address'], |
885
|
|
|
), |
886
|
|
|
'data' => array( |
887
|
|
|
'sprintf' => array( |
888
|
|
|
'format' => '<a href="' . strtr($scripturl, array('%' => '%%')) . '?action=trackip;searchip=%1$s">%1$s</a>', |
889
|
|
|
'params' => array( |
890
|
|
|
'member_ip' => false, |
891
|
|
|
), |
892
|
|
|
), |
893
|
|
|
), |
894
|
|
|
'sort' => array( |
895
|
|
|
'default' => 'member_ip', |
896
|
|
|
'reverse' => 'member_ip DESC', |
897
|
|
|
), |
898
|
|
|
), |
899
|
|
|
'hostname' => array( |
900
|
|
|
'header' => array( |
901
|
|
|
'value' => $txt['hostname'], |
902
|
|
|
), |
903
|
|
|
'data' => array( |
904
|
|
|
'function' => function($rowData) |
905
|
|
|
{ |
906
|
|
|
return host_from_ip(inet_dtop($rowData['member_ip'])); |
|
|
|
|
907
|
|
|
}, |
908
|
|
|
'class' => 'smalltext', |
909
|
|
|
), |
910
|
|
|
), |
911
|
|
|
'date_registered' => array( |
912
|
|
|
'header' => array( |
913
|
|
|
'value' => $context['current_filter'] == 4 ? $txt['viewmembers_online'] : $txt['date_registered'], |
914
|
|
|
), |
915
|
|
|
'data' => array( |
916
|
|
|
'function' => function($rowData) use ($context) |
917
|
|
|
{ |
918
|
|
|
return timeformat($rowData['' . ($context['current_filter'] == 4 ? 'last_login' : 'date_registered') . '']); |
919
|
|
|
}, |
920
|
|
|
), |
921
|
|
|
'sort' => array( |
922
|
|
|
'default' => $context['current_filter'] == 4 ? 'mem.last_login DESC' : 'date_registered DESC', |
923
|
|
|
'reverse' => $context['current_filter'] == 4 ? 'mem.last_login' : 'date_registered', |
924
|
|
|
), |
925
|
|
|
), |
926
|
|
|
'duplicates' => array( |
927
|
|
|
'header' => array( |
928
|
|
|
'value' => $txt['duplicates'], |
929
|
|
|
// Make sure it doesn't go too wide. |
930
|
|
|
'style' => 'width: 20%;', |
931
|
|
|
), |
932
|
|
|
'data' => array( |
933
|
|
|
'function' => function($rowData) use ($scripturl, $txt) |
934
|
|
|
{ |
935
|
|
|
$member_links = array(); |
936
|
|
|
foreach ($rowData['duplicate_members'] as $member) |
937
|
|
|
{ |
938
|
|
|
if ($member['id']) |
939
|
|
|
$member_links[] = '<a href="' . $scripturl . '?action=profile;u=' . $member['id'] . '" ' . (!empty($member['is_banned']) ? 'class="red"' : '') . '>' . $member['name'] . '</a>'; |
940
|
|
|
else |
941
|
|
|
$member_links[] = $member['name'] . ' (' . $txt['guest'] . ')'; |
942
|
|
|
} |
943
|
|
|
return implode(', ', $member_links); |
944
|
|
|
}, |
945
|
|
|
'class' => 'smalltext', |
946
|
|
|
), |
947
|
|
|
), |
948
|
|
|
'check' => array( |
949
|
|
|
'header' => array( |
950
|
|
|
'value' => '<input type="checkbox" onclick="invertAll(this, this.form);">', |
951
|
|
|
'class' => 'centercol', |
952
|
|
|
), |
953
|
|
|
'data' => array( |
954
|
|
|
'sprintf' => array( |
955
|
|
|
'format' => '<input type="checkbox" name="todoAction[]" value="%1$d">', |
956
|
|
|
'params' => array( |
957
|
|
|
'id_member' => false, |
958
|
|
|
), |
959
|
|
|
), |
960
|
|
|
'class' => 'centercol', |
961
|
|
|
), |
962
|
|
|
), |
963
|
|
|
), |
964
|
|
|
'javascript' => $javascript, |
965
|
|
|
'form' => array( |
966
|
|
|
'href' => $scripturl . '?action=admin;area=viewmembers;sa=approve;type=' . $context['browse_type'], |
967
|
|
|
'name' => 'postForm', |
968
|
|
|
'include_start' => true, |
969
|
|
|
'include_sort' => true, |
970
|
|
|
'hidden_fields' => array( |
971
|
|
|
'orig_filter' => $context['current_filter'], |
972
|
|
|
), |
973
|
|
|
), |
974
|
|
|
'additional_rows' => array( |
975
|
|
|
array( |
976
|
|
|
'position' => 'below_table_data', |
977
|
|
|
'value' => ' |
978
|
|
|
[<a href="' . $scripturl . '?action=admin;area=viewmembers;sa=browse;showdupes=' . ($context['show_duplicates'] ? 0 : 1) . ';type=' . $context['browse_type'] . (!empty($context['show_filter']) ? ';filter=' . $context['current_filter'] : '') . ';' . $context['session_var'] . '=' . $context['session_id'] . '">' . ($context['show_duplicates'] ? $txt['dont_check_for_duplicate'] : $txt['check_for_duplicate']) . '</a>] |
979
|
|
|
<select name="todo" onchange="onSelectChange();"> |
980
|
|
|
' . $allowed_actions . ' |
981
|
|
|
</select> |
982
|
|
|
<noscript><input type="submit" value="' . $txt['go'] . '" class="button"><br class="clear_right"></noscript> |
983
|
|
|
', |
984
|
|
|
'class' => 'floatright', |
985
|
|
|
), |
986
|
|
|
), |
987
|
|
|
); |
988
|
|
|
|
989
|
|
|
// Pick what column to actually include if we're showing duplicates. |
990
|
|
|
if ($context['show_duplicates']) |
991
|
|
|
unset($listOptions['columns']['email']); |
992
|
|
|
else |
993
|
|
|
unset($listOptions['columns']['duplicates']); |
994
|
|
|
|
995
|
|
|
// Only show hostname on duplicates as it takes a lot of time. |
996
|
|
|
if (!$context['show_duplicates'] || !empty($modSettings['disableHostnameLookup'])) |
997
|
|
|
unset($listOptions['columns']['hostname']); |
998
|
|
|
|
999
|
|
|
// Is there any need to show filters? |
1000
|
|
|
if (isset($context['available_filters']) && count($context['available_filters']) > 1) |
1001
|
|
|
{ |
1002
|
|
|
$filterOptions = ' |
1003
|
|
|
<strong>' . $txt['admin_browse_filter_by'] . ':</strong> |
1004
|
|
|
<select name="filter" onchange="this.form.submit();">'; |
1005
|
|
|
foreach ($context['available_filters'] as $filter) |
1006
|
|
|
$filterOptions .= ' |
1007
|
|
|
<option value="' . $filter['type'] . '"' . ($filter['selected'] ? ' selected' : '') . '>' . $filter['desc'] . ' - ' . $filter['amount'] . ' ' . ($filter['amount'] == 1 ? $txt['user'] : $txt['users']) . '</option>'; |
1008
|
|
|
$filterOptions .= ' |
1009
|
|
|
</select> |
1010
|
|
|
<noscript><input type="submit" value="' . $txt['go'] . '" name="filter" class="button"></noscript>'; |
1011
|
|
|
$listOptions['additional_rows'][] = array( |
1012
|
|
|
'position' => 'top_of_list', |
1013
|
|
|
'value' => $filterOptions, |
1014
|
|
|
'class' => 'righttext', |
1015
|
|
|
); |
1016
|
|
|
} |
1017
|
|
|
|
1018
|
|
|
// What about if we only have one filter, but it's not the "standard" filter - show them what they are looking at. |
1019
|
|
|
if (!empty($context['show_filter']) && !empty($context['available_filters'])) |
1020
|
|
|
$listOptions['additional_rows'][] = array( |
1021
|
|
|
'position' => 'above_column_headers', |
1022
|
|
|
'value' => '<strong>' . $txt['admin_browse_filter_show'] . ':</strong> ' . ((isset($context['current_filter']) && isset($txt['admin_browse_filter_type_' . $context['current_filter']])) ? $txt['admin_browse_filter_type_' . $context['current_filter']] : $context['available_filters'][0]['desc']), |
1023
|
|
|
'class' => 'filter_row generic_list_wrapper smalltext', |
1024
|
|
|
); |
1025
|
|
|
|
1026
|
|
|
// Now that we have all the options, create the list. |
1027
|
|
|
require_once($sourcedir . '/Subs-List.php'); |
1028
|
|
|
createList($listOptions); |
1029
|
|
|
} |
1030
|
|
|
|
1031
|
|
|
/** |
1032
|
|
|
* This function handles the approval, rejection, activation or deletion of members. |
1033
|
|
|
* Called by ?action=admin;area=viewmembers;sa=approve. |
1034
|
|
|
* Requires the moderate_forum permission. |
1035
|
|
|
* Redirects to ?action=admin;area=viewmembers;sa=browse |
1036
|
|
|
* with the same parameters as the calling page. |
1037
|
|
|
*/ |
1038
|
|
|
function AdminApprove() |
1039
|
|
|
{ |
1040
|
|
|
global $scripturl, $modSettings, $sourcedir, $language, $user_info, $smcFunc; |
1041
|
|
|
|
1042
|
|
|
// First, check our session. |
1043
|
|
|
checkSession(); |
1044
|
|
|
|
1045
|
|
|
require_once($sourcedir . '/Subs-Post.php'); |
1046
|
|
|
|
1047
|
|
|
// We also need to the login languages here - for emails. |
1048
|
|
|
loadLanguage('Login'); |
1049
|
|
|
|
1050
|
|
|
// Sort out where we are going... |
1051
|
|
|
$current_filter = (int) $_REQUEST['orig_filter']; |
1052
|
|
|
|
1053
|
|
|
// If we are applying a filter do just that - then redirect. |
1054
|
|
|
if (isset($_REQUEST['filter']) && $_REQUEST['filter'] != $_REQUEST['orig_filter']) |
1055
|
|
|
redirectexit('action=admin;area=viewmembers;sa=browse;type=' . $_REQUEST['type'] . ';sort=' . $_REQUEST['sort'] . ';filter=' . $_REQUEST['filter'] . ';start=' . $_REQUEST['start']); |
1056
|
|
|
|
1057
|
|
|
// Nothing to do? |
1058
|
|
|
if (!isset($_POST['todoAction']) && !isset($_POST['time_passed'])) |
1059
|
|
|
redirectexit('action=admin;area=viewmembers;sa=browse;type=' . $_REQUEST['type'] . ';sort=' . $_REQUEST['sort'] . ';filter=' . $current_filter . ';start=' . $_REQUEST['start']); |
1060
|
|
|
|
1061
|
|
|
// Are we dealing with members who have been waiting for > set amount of time? |
1062
|
|
|
if (isset($_POST['time_passed'])) |
1063
|
|
|
{ |
1064
|
|
|
$timeBefore = time() - 86400 * (int) $_POST['time_passed']; |
1065
|
|
|
$condition = ' |
1066
|
|
|
AND date_registered < {int:time_before}'; |
1067
|
|
|
} |
1068
|
|
|
// Coming from checkboxes - validate the members passed through to us. |
1069
|
|
|
else |
1070
|
|
|
{ |
1071
|
|
|
$members = array(); |
1072
|
|
|
foreach ($_POST['todoAction'] as $id) |
1073
|
|
|
$members[] = (int) $id; |
1074
|
|
|
$condition = ' |
1075
|
|
|
AND id_member IN ({array_int:members})'; |
1076
|
|
|
} |
1077
|
|
|
|
1078
|
|
|
// Get information on each of the members, things that are important to us, like email address... |
1079
|
|
|
$request = $smcFunc['db_query']('', ' |
1080
|
|
|
SELECT id_member, member_name, real_name, email_address, validation_code, lngfile |
1081
|
|
|
FROM {db_prefix}members |
1082
|
|
|
WHERE is_activated = {int:activated_status}' . $condition . ' |
1083
|
|
|
ORDER BY lngfile', |
1084
|
|
|
array( |
1085
|
|
|
'activated_status' => $current_filter, |
1086
|
|
|
'time_before' => empty($timeBefore) ? 0 : $timeBefore, |
1087
|
|
|
'members' => empty($members) ? array() : $members, |
1088
|
|
|
) |
1089
|
|
|
); |
1090
|
|
|
|
1091
|
|
|
$member_count = $smcFunc['db_num_rows']($request); |
1092
|
|
|
|
1093
|
|
|
// If no results then just return! |
1094
|
|
|
if ($member_count == 0) |
1095
|
|
|
redirectexit('action=admin;area=viewmembers;sa=browse;type=' . $_REQUEST['type'] . ';sort=' . $_REQUEST['sort'] . ';filter=' . $current_filter . ';start=' . $_REQUEST['start']); |
1096
|
|
|
|
1097
|
|
|
$member_info = array(); |
1098
|
|
|
$members = array(); |
1099
|
|
|
// Fill the info array. |
1100
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
1101
|
|
|
{ |
1102
|
|
|
$members[] = $row['id_member']; |
1103
|
|
|
$member_info[] = array( |
1104
|
|
|
'id' => $row['id_member'], |
1105
|
|
|
'username' => $row['member_name'], |
1106
|
|
|
'name' => $row['real_name'], |
1107
|
|
|
'email' => $row['email_address'], |
1108
|
|
|
'language' => empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile'], |
1109
|
|
|
'code' => $row['validation_code'] |
1110
|
|
|
); |
1111
|
|
|
} |
1112
|
|
|
$smcFunc['db_free_result']($request); |
1113
|
|
|
|
1114
|
|
|
// Are we activating or approving the members? |
1115
|
|
|
if ($_POST['todo'] == 'ok' || $_POST['todo'] == 'okemail') |
1116
|
|
|
{ |
1117
|
|
|
// Approve/activate this member. |
1118
|
|
|
$smcFunc['db_query']('', ' |
1119
|
|
|
UPDATE {db_prefix}members |
1120
|
|
|
SET validation_code = {string:blank_string}, is_activated = {int:is_activated} |
1121
|
|
|
WHERE is_activated = {int:activated_status}' . $condition, |
1122
|
|
|
array( |
1123
|
|
|
'is_activated' => 1, |
1124
|
|
|
'time_before' => empty($timeBefore) ? 0 : $timeBefore, |
1125
|
|
|
'members' => empty($members) ? array() : $members, |
1126
|
|
|
'activated_status' => $current_filter, |
1127
|
|
|
'blank_string' => '', |
1128
|
|
|
) |
1129
|
|
|
); |
1130
|
|
|
|
1131
|
|
|
// Do we have to let the integration code know about the activations? |
1132
|
|
|
if (!empty($modSettings['integrate_activate'])) |
1133
|
|
|
{ |
1134
|
|
|
foreach ($member_info as $member) |
1135
|
|
|
call_integration_hook('integrate_activate', array($member['username'])); |
1136
|
|
|
} |
1137
|
|
|
|
1138
|
|
|
// Check for email. |
1139
|
|
|
if ($_POST['todo'] == 'okemail') |
1140
|
|
|
{ |
1141
|
|
|
foreach ($member_info as $member) |
1142
|
|
|
{ |
1143
|
|
|
$replacements = array( |
1144
|
|
|
'NAME' => $member['name'], |
1145
|
|
|
'USERNAME' => $member['username'], |
1146
|
|
|
'PROFILELINK' => $scripturl . '?action=profile;u=' . $member['id'], |
1147
|
|
|
'FORGOTPASSWORDLINK' => $scripturl . '?action=reminder', |
1148
|
|
|
); |
1149
|
|
|
|
1150
|
|
|
$emaildata = loadEmailTemplate('admin_approve_accept', $replacements, $member['language']); |
1151
|
|
|
sendmail($member['email'], $emaildata['subject'], $emaildata['body'], null, 'accapp' . $member['id'], $emaildata['is_html'], 0); |
1152
|
|
|
} |
1153
|
|
|
} |
1154
|
|
|
} |
1155
|
|
|
// Maybe we're sending it off for activation? |
1156
|
|
|
elseif ($_POST['todo'] == 'require_activation') |
1157
|
|
|
{ |
1158
|
|
|
require_once($sourcedir . '/Subs-Members.php'); |
1159
|
|
|
|
1160
|
|
|
// We have to do this for each member I'm afraid. |
1161
|
|
|
foreach ($member_info as $member) |
1162
|
|
|
{ |
1163
|
|
|
// Generate a random activation code. |
1164
|
|
|
$validation_code = generateValidationCode(); |
1165
|
|
|
|
1166
|
|
|
// Set these members for activation - I know this includes two id_member checks but it's safer than bodging $condition ;). |
1167
|
|
|
$smcFunc['db_query']('', ' |
1168
|
|
|
UPDATE {db_prefix}members |
1169
|
|
|
SET validation_code = {string:validation_code}, is_activated = {int:not_activated} |
1170
|
|
|
WHERE is_activated = {int:activated_status} |
1171
|
|
|
' . $condition . ' |
1172
|
|
|
AND id_member = {int:selected_member}', |
1173
|
|
|
array( |
1174
|
|
|
'not_activated' => 0, |
1175
|
|
|
'activated_status' => $current_filter, |
1176
|
|
|
'selected_member' => $member['id'], |
1177
|
|
|
'validation_code' => $validation_code, |
1178
|
|
|
'time_before' => empty($timeBefore) ? 0 : $timeBefore, |
1179
|
|
|
'members' => empty($members) ? array() : $members, |
1180
|
|
|
) |
1181
|
|
|
); |
1182
|
|
|
|
1183
|
|
|
$replacements = array( |
1184
|
|
|
'USERNAME' => $member['name'], |
1185
|
|
|
'ACTIVATIONLINK' => $scripturl . '?action=activate;u=' . $member['id'] . ';code=' . $validation_code, |
1186
|
|
|
'ACTIVATIONLINKWITHOUTCODE' => $scripturl . '?action=activate;u=' . $member['id'], |
1187
|
|
|
'ACTIVATIONCODE' => $validation_code, |
1188
|
|
|
); |
1189
|
|
|
|
1190
|
|
|
$emaildata = loadEmailTemplate('admin_approve_activation', $replacements, $member['language']); |
1191
|
|
|
sendmail($member['email'], $emaildata['subject'], $emaildata['body'], null, 'accact' . $member['id'], $emaildata['is_html'], 0); |
1192
|
|
|
} |
1193
|
|
|
} |
1194
|
|
|
// Are we rejecting them? |
1195
|
|
|
elseif ($_POST['todo'] == 'reject' || $_POST['todo'] == 'rejectemail') |
1196
|
|
|
{ |
1197
|
|
|
require_once($sourcedir . '/Subs-Members.php'); |
1198
|
|
|
deleteMembers($members); |
1199
|
|
|
|
1200
|
|
|
// Send email telling them they aren't welcome? |
1201
|
|
|
if ($_POST['todo'] == 'rejectemail') |
1202
|
|
|
{ |
1203
|
|
|
foreach ($member_info as $member) |
1204
|
|
|
{ |
1205
|
|
|
$replacements = array( |
1206
|
|
|
'USERNAME' => $member['name'], |
1207
|
|
|
); |
1208
|
|
|
|
1209
|
|
|
$emaildata = loadEmailTemplate('admin_approve_reject', $replacements, $member['language']); |
1210
|
|
|
sendmail($member['email'], $emaildata['subject'], $emaildata['body'], null, 'accrej', $emaildata['is_html'], 1); |
1211
|
|
|
} |
1212
|
|
|
} |
1213
|
|
|
} |
1214
|
|
|
// A simple delete? |
1215
|
|
|
elseif ($_POST['todo'] == 'delete' || $_POST['todo'] == 'deleteemail') |
1216
|
|
|
{ |
1217
|
|
|
require_once($sourcedir . '/Subs-Members.php'); |
1218
|
|
|
deleteMembers($members); |
1219
|
|
|
|
1220
|
|
|
// Send email telling them they aren't welcome? |
1221
|
|
|
if ($_POST['todo'] == 'deleteemail') |
1222
|
|
|
{ |
1223
|
|
|
foreach ($member_info as $member) |
1224
|
|
|
{ |
1225
|
|
|
$replacements = array( |
1226
|
|
|
'USERNAME' => $member['name'], |
1227
|
|
|
); |
1228
|
|
|
|
1229
|
|
|
$emaildata = loadEmailTemplate('admin_approve_delete', $replacements, $member['language']); |
1230
|
|
|
sendmail($member['email'], $emaildata['subject'], $emaildata['body'], null, 'accdel', $emaildata['is_html'], 1); |
1231
|
|
|
} |
1232
|
|
|
} |
1233
|
|
|
} |
1234
|
|
|
// Remind them to activate their account? |
1235
|
|
|
elseif ($_POST['todo'] == 'remind') |
1236
|
|
|
{ |
1237
|
|
|
foreach ($member_info as $member) |
1238
|
|
|
{ |
1239
|
|
|
$replacements = array( |
1240
|
|
|
'USERNAME' => $member['name'], |
1241
|
|
|
'ACTIVATIONLINK' => $scripturl . '?action=activate;u=' . $member['id'] . ';code=' . $member['code'], |
1242
|
|
|
'ACTIVATIONLINKWITHOUTCODE' => $scripturl . '?action=activate;u=' . $member['id'], |
1243
|
|
|
'ACTIVATIONCODE' => $member['code'], |
1244
|
|
|
); |
1245
|
|
|
|
1246
|
|
|
$emaildata = loadEmailTemplate('admin_approve_remind', $replacements, $member['language']); |
1247
|
|
|
sendmail($member['email'], $emaildata['subject'], $emaildata['body'], null, 'accrem' . $member['id'], $emaildata['is_html'], 1); |
1248
|
|
|
} |
1249
|
|
|
} |
1250
|
|
|
|
1251
|
|
|
// @todo current_language is never set, no idea what this is for. Remove? |
1252
|
|
|
// Back to the user's language! |
1253
|
|
|
if (isset($current_language) && $current_language != $user_info['language']) |
|
|
|
|
1254
|
|
|
{ |
1255
|
|
|
loadLanguage('index'); |
1256
|
|
|
loadLanguage('ManageMembers'); |
1257
|
|
|
} |
1258
|
|
|
|
1259
|
|
|
// Log what we did? |
1260
|
|
|
if (!empty($modSettings['modlog_enabled']) && in_array($_POST['todo'], array('ok', 'okemail', 'require_activation', 'remind'))) |
1261
|
|
|
{ |
1262
|
|
|
$log_action = $_POST['todo'] == 'remind' ? 'remind_member' : 'approve_member'; |
1263
|
|
|
|
1264
|
|
|
require_once($sourcedir . '/Logging.php'); |
1265
|
|
|
foreach ($member_info as $member) |
1266
|
|
|
logAction($log_action, array('member' => $member['id']), 'admin'); |
1267
|
|
|
} |
1268
|
|
|
|
1269
|
|
|
// Although updateStats *may* catch this, best to do it manually just in case (Doesn't always sort out unapprovedMembers). |
1270
|
|
|
if (in_array($current_filter, array(3, 4, 5))) |
1271
|
|
|
updateSettings(array('unapprovedMembers' => ($modSettings['unapprovedMembers'] > $member_count ? $modSettings['unapprovedMembers'] - $member_count : 0))); |
1272
|
|
|
|
1273
|
|
|
// Update the member's stats. (but, we know the member didn't change their name.) |
1274
|
|
|
updateStats('member', false); |
1275
|
|
|
|
1276
|
|
|
// If they haven't been deleted, update the post group statistics on them... |
1277
|
|
|
if (!in_array($_POST['todo'], array('delete', 'deleteemail', 'reject', 'rejectemail', 'remind'))) |
1278
|
|
|
updateStats('postgroups', $members); |
1279
|
|
|
|
1280
|
|
|
redirectexit('action=admin;area=viewmembers;sa=browse;type=' . $_REQUEST['type'] . ';sort=' . $_REQUEST['sort'] . ';filter=' . $current_filter . ';start=' . $_REQUEST['start']); |
1281
|
|
|
} |
1282
|
|
|
|
1283
|
|
|
/** |
1284
|
|
|
* Nifty function to calculate the number of days ago a given date was. |
1285
|
|
|
* Requires a unix timestamp as input, returns an integer. |
1286
|
|
|
* Named in honour of Jeff Lewis, the original creator of...this function. |
1287
|
|
|
* |
1288
|
|
|
* @param int $old The timestamp of the old date |
1289
|
|
|
* @return int The number of days since $old, based on the forum time |
1290
|
|
|
*/ |
1291
|
|
|
function jeffsdatediff($old) |
1292
|
|
|
{ |
1293
|
|
|
// Get the current time as the user would see it... |
1294
|
|
|
$forumTime = time(); |
1295
|
|
|
|
1296
|
|
|
// Calculate the seconds that have passed since midnight. |
1297
|
|
|
$sinceMidnight = date('H', $forumTime) * 60 * 60 + date('i', $forumTime) * 60 + date('s', $forumTime); |
1298
|
|
|
|
1299
|
|
|
// Take the difference between the two times. |
1300
|
|
|
$dis = time() - $old; |
1301
|
|
|
|
1302
|
|
|
// Before midnight? |
1303
|
|
|
if ($dis < $sinceMidnight) |
1304
|
|
|
return 0; |
1305
|
|
|
else |
1306
|
|
|
$dis -= $sinceMidnight; |
1307
|
|
|
|
1308
|
|
|
// Divide out the seconds in a day to get the number of days. |
1309
|
|
|
return ceil($dis / (24 * 60 * 60)); |
1310
|
|
|
} |
1311
|
|
|
|
1312
|
|
|
/** |
1313
|
|
|
* Fetches all the activation counts for ViewMembers. |
1314
|
|
|
* |
1315
|
|
|
*/ |
1316
|
|
|
function GetMemberActivationCounts() |
1317
|
|
|
{ |
1318
|
|
|
global $smcFunc, $context; |
1319
|
|
|
|
1320
|
|
|
// Get counts on every type of activation - for sections and filtering alike. |
1321
|
|
|
$request = $smcFunc['db_query']('', ' |
1322
|
|
|
SELECT COUNT(*) AS total_members, is_activated |
1323
|
|
|
FROM {db_prefix}members |
1324
|
|
|
WHERE is_activated != {int:is_activated} |
1325
|
|
|
GROUP BY is_activated', |
1326
|
|
|
array( |
1327
|
|
|
'is_activated' => 1, |
1328
|
|
|
) |
1329
|
|
|
); |
1330
|
|
|
$context['activation_numbers'] = array(); |
1331
|
|
|
$context['awaiting_activation'] = 0; |
1332
|
|
|
$context['awaiting_approval'] = 0; |
1333
|
|
|
while ($row = $smcFunc['db_fetch_assoc']($request)) |
1334
|
|
|
$context['activation_numbers'][$row['is_activated']] = $row['total_members']; |
1335
|
|
|
$smcFunc['db_free_result']($request); |
1336
|
|
|
|
1337
|
|
|
foreach ($context['activation_numbers'] as $activation_type => $total_members) |
1338
|
|
|
{ |
1339
|
|
|
if (in_array($activation_type, array(0, 2))) |
1340
|
|
|
$context['awaiting_activation'] += $total_members; |
1341
|
|
|
elseif (in_array($activation_type, array(3, 4, 5))) |
1342
|
|
|
$context['awaiting_approval'] += $total_members; |
1343
|
|
|
} |
1344
|
|
|
|
1345
|
|
|
} |
1346
|
|
|
|
1347
|
|
|
?> |