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

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