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