Completed
Pull Request — master (#3325)
by Emanuele
11:19
created

ManageMembers_Controller::action_approve()   F

Complexity

Conditions 23
Paths 1728

Size

Total Lines 98
Code Lines 53

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 552

Importance

Changes 0
Metric Value
cc 23
eloc 53
dl 0
loc 98
rs 0
c 0
b 0
f 0
nc 1728
nop 0
ccs 0
cts 63
cp 0
crap 552

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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