comparison forum/Sources/ManageMembers.php @ 76:e3e11437ecea website

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