Completed
Push — development ( 51e525...bd9e52 )
by Stephen
18s
created

Membergroups.subs.php ➔ createMembergroup()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 19
Code Lines 12

Duplication

Lines 19
Ratio 100 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 12
nc 1
nop 3
dl 19
loc 19
ccs 0
cts 12
cp 0
crap 2
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * This file contains functions regarding manipulation of and information about membergroups.
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 Release Candidate 1
15
 *
16
 */
17
18
/**
19
 * Delete one of more membergroups.
20
 *
21
 * - Requires the manage_membergroups permission.
22
 * - Returns true on success or false on failure.
23
 * - Has protection against deletion of protected membergroups.
24
 * - Deletes the permissions linked to the membergroup.
25
 * - Takes members out of the deleted membergroups.
26
 *
27
 * @package Membergroups
28
 * @param int[]|int $groups
29
 * @return boolean
30
 */
31
function deleteMembergroups($groups)
32
{
33
	global $modSettings;
34
35
	$db = database();
36
37
	// Make sure it's an array.
38 View Code Duplication
	if (!is_array($groups))
39
		$groups = array((int) $groups);
40
	else
41
	{
42
		$groups = array_unique($groups);
43
44
		// Make sure all groups are integer.
45
		foreach ($groups as $key => $value)
46
			$groups[$key] = (int) $value;
47
	}
48
49
	// Some groups are protected (guests, administrators, moderators, newbies).
50
	$protected_groups = array(-1, 0, 1, 3, 4);
51
52
	// There maybe some others as well.
53
	if (!allowedTo('admin_forum'))
54
	{
55
		$request = $db->query('', '
56
			SELECT id_group
57
			FROM {db_prefix}membergroups
58
			WHERE group_type = {int:is_protected}',
59
			array(
60
				'is_protected' => 1,
61
			)
62
		);
63
		while ($row = $db->fetch_assoc($request))
64
			$protected_groups[] = $row['id_group'];
65
		$db->free_result($request);
66
	}
67
68
	// Make sure they don't delete protected groups!
69
	$groups = array_diff($groups, array_unique($protected_groups));
70
	if (empty($groups))
71
		return false;
72
73
	// Log the deletion.
74
	$groups_to_log = membergroupsById($groups, 0);
75
	foreach ($groups_to_log as $key => $row)
76
		logAction('delete_group', array('group' => $row['group_name']), 'admin');
77
78
	call_integration_hook('integrate_delete_membergroups', array($groups));
79
80
	// Remove the membergroups themselves.
81
	$db->query('', '
82
		DELETE FROM {db_prefix}membergroups
83
		WHERE id_group IN ({array_int:group_list})',
84
		array(
85
			'group_list' => $groups,
86
		)
87
	);
88
89
	// Remove the permissions of the membergroups.
90
	$db->query('', '
91
		DELETE FROM {db_prefix}permissions
92
		WHERE id_group IN ({array_int:group_list})',
93
		array(
94
			'group_list' => $groups,
95
		)
96
	);
97
	$db->query('', '
98
		DELETE FROM {db_prefix}board_permissions
99
		WHERE id_group IN ({array_int:group_list})',
100
		array(
101
			'group_list' => $groups,
102
		)
103
	);
104
	$db->query('', '
105
		DELETE FROM {db_prefix}group_moderators
106
		WHERE id_group IN ({array_int:group_list})',
107
		array(
108
			'group_list' => $groups,
109
		)
110
	);
111
112
	// Delete any outstanding requests.
113
	$db->query('', '
114
		DELETE FROM {db_prefix}log_group_requests
115
		WHERE id_group IN ({array_int:group_list})',
116
		array(
117
			'group_list' => $groups,
118
		)
119
	);
120
121
	// Update the primary groups of members.
122
	$db->query('', '
123
		UPDATE {db_prefix}members
124
		SET id_group = {int:regular_group}
125
		WHERE id_group IN ({array_int:group_list})',
126
		array(
127
			'group_list' => $groups,
128
			'regular_group' => 0,
129
		)
130
	);
131
132
	// Update any inherited groups (Lose inheritance).
133
	$db->query('', '
134
		UPDATE {db_prefix}membergroups
135
		SET id_parent = {int:uninherited}
136
		WHERE id_parent IN ({array_int:group_list})',
137
		array(
138
			'group_list' => $groups,
139
			'uninherited' => -2,
140
		)
141
	);
142
143
	// Update the additional groups of members.
144
	$request = $db->query('', '
145
		SELECT id_member, additional_groups
146
		FROM {db_prefix}members
147
		WHERE FIND_IN_SET({raw:additional_groups_explode}, additional_groups) != 0',
148
		array(
149
			'additional_groups_explode' => implode(', additional_groups) != 0 OR FIND_IN_SET(', $groups),
150
		)
151
	);
152
153
	// Update each member information.
154
	$updates = array();
155
	while ($row = $db->fetch_assoc($request))
156
		$updates[$row['additional_groups']][] = $row['id_member'];
157
	$db->free_result($request);
158
159
	require_once(SUBSDIR . '/Members.subs.php');
160
	foreach ($updates as $additional_groups => $memberArray)
161
		updateMemberData($memberArray, array('additional_groups' => implode(',', array_diff(explode(',', $additional_groups), $groups))));
162
163
	// No boards can provide access to these membergroups anymore.
164
	$request = $db->query('', '
165
		SELECT id_board, member_groups
166
		FROM {db_prefix}boards
167
		WHERE FIND_IN_SET({raw:member_groups_explode}, member_groups) != 0',
168
		array(
169
			'member_groups_explode' => implode(', member_groups) != 0 OR FIND_IN_SET(', $groups),
170
		)
171
	);
172
	$updates = array();
173
	while ($row = $db->fetch_assoc($request))
174
		$updates[$row['member_groups']][] = $row['id_board'];
175
	$db->free_result($request);
176
177
	foreach ($updates as $member_groups => $boardArray)
178
		$db->query('', '
179
			UPDATE {db_prefix}boards
180
			SET member_groups = {string:member_groups}
181
			WHERE id_board IN ({array_int:board_lists})',
182
			array(
183
				'board_lists' => $boardArray,
184
				'member_groups' => implode(',', array_diff(explode(',', $member_groups), $groups)),
185
			)
186
		);
187
188
	// Recalculate the post groups, as they likely changed.
189
	updatePostGroupStats();
190
191
	// Make a note of the fact that the cache may be wrong.
192
	$settings_update = array('settings_updated' => time());
193
194
	// Have we deleted the spider group?
195
	// @memo we are lucky that the group 1 and 0 cannot be deleted
196
	// $modSettings['spider_group'] is set to 1 (admin) for regular members (that usually is group 0)
197
	if (isset($modSettings['spider_group']) && in_array($modSettings['spider_group'], $groups))
198
		$settings_update['spider_group'] = 0;
199
200
	updateSettings($settings_update);
201
202
	// It was a success.
203
	return true;
204
}
205
206
/**
207
 * Remove one or more members from one or more membergroups.
208
 *
209
 * - Requires the manage_membergroups permission.
210
 * - Function includes a protection against removing from implicit groups.
211
 * - Non-admins are not able to remove members from the admin group.
212
 *
213
 * @package Membergroups
214
 * @param int[]|int $members
215
 * @param integer|null $groups
216
 * @param bool $permissionCheckDone = false
217
 *
218
 * @return boolean
219
 * @throws Elk_Exception
220
 */
221
function removeMembersFromGroups($members, $groups = null, $permissionCheckDone = false)
222
{
223
	global $modSettings;
224
225
	$db = database();
226
227
	// You're getting nowhere without this permission, unless of course you are the group's moderator.
228
	if (!$permissionCheckDone)
229
		isAllowedTo('manage_membergroups');
230
231
	// Assume something will happen.
232
	updateSettings(array('settings_updated' => time()));
233
234
	// Cleaning the input.
235 View Code Duplication
	if (!is_array($members))
236
		$members = array((int) $members);
237
	else
238
	{
239
		$members = array_unique($members);
240
241
		// Cast the members to integer.
242
		foreach ($members as $key => $value)
243
			$members[$key] = (int) $value;
244
	}
245
246
	// Before we get started, let's check we won't leave the admin group empty!
247
	if ($groups === null || $groups == 1 || (is_array($groups) && in_array(1, $groups)))
248
	{
249
		$admins = array();
250
		listMembergroupMembers_Href($admins, 1);
251
252
		// Remove any admins if there are too many.
253
		$non_changing_admins = array_diff(array_keys($admins), $members);
254
255
		if (empty($non_changing_admins))
256
			$members = array_diff($members, array_keys($admins));
257
	}
258
259
	// Just in case.
260
	if (empty($members))
261
		return false;
262
263
	// Wanna remove all groups from these members? That's easy.
264
	if ($groups === null)
265
	{
266
		$db->query('', '
267
			UPDATE {db_prefix}members
268
			SET
269
				id_group = {int:regular_member},
270
				additional_groups = {string:blank_string}
271
			WHERE id_member IN ({array_int:member_list})' . (allowedTo('admin_forum') ? '' : '
272
				AND id_group != {int:admin_group}
273
				AND FIND_IN_SET({int:admin_group}, additional_groups) = 0'),
274
			array(
275
				'member_list' => $members,
276
				'regular_member' => 0,
277
				'admin_group' => 1,
278
				'blank_string' => '',
279
			)
280
		);
281
282
		updatePostGroupStats($members);
283
284
		// Log what just happened.
285
		foreach ($members as $member)
286
			logAction('removed_all_groups', array('member' => $member), 'admin');
287
288
		return true;
289
	}
290
	elseif (!is_array($groups))
291
		$groups = array((int) $groups);
292
	// Make sure all groups are integer.
293
	else
294
		$groups = array_unique(array_map('intval', $groups));
295
296
	// Fetch a list of groups members cannot be assigned to explicitly, and the group names of the ones we want.
297
	$implicitGroups = array(-1, 0, 3);
298
	$group_names = array();
299
	$group_details = membergroupsById($groups, 0, true);
300
	foreach ($group_details as $key => $row)
301
	{
302 View Code Duplication
		if ($row['min_posts'] != -1)
303
			$implicitGroups[] = $row['id_group'];
304
		else
305
			$group_names[$row['id_group']] = $row['group_name'];
306
	}
307
308
	// Now get rid of those groups.
309
	$groups = array_diff($groups, $implicitGroups);
310
311
	// Don't forget the protected groups.
312 View Code Duplication
	if (!allowedTo('admin_forum'))
313
	{
314
		$request = $db->query('', '
315
			SELECT id_group
316
			FROM {db_prefix}membergroups
317
			WHERE group_type = {int:is_protected}',
318
			array(
319
				'is_protected' => 1,
320
			)
321
		);
322
		$protected_groups = array(1);
323
		while ($row = $db->fetch_assoc($request))
324
			$protected_groups[] = $row['id_group'];
325
		$db->free_result($request);
326
327
		// If you're not an admin yourself, you can't touch protected groups!
328
		$groups = array_diff($groups, array_unique($protected_groups));
329
	}
330
331
	// Only continue if there are still groups and members left.
332
	if (empty($groups) || empty($members))
333
		return false;
334
335
	// First, reset those who have this as their primary group - this is the easy one.
336
	$log_inserts = $db->fetchQueryCallback('
337
		SELECT id_member, id_group
338
		FROM {db_prefix}members AS members
339
		WHERE id_group IN ({array_int:group_list})
340
			AND id_member IN ({array_int:member_list})',
341
		array(
342
			'group_list' => $groups,
343
			'member_list' => $members,
344
		),
345
		function ($row) use ($group_names)
346
		{
347
			return array('group' => $group_names[$row['id_group']], 'member' => $row['id_member']);
348
		}
349
	);
350
351
	$db->query('', '
352
		UPDATE {db_prefix}members
353
		SET id_group = {int:regular_member}
354
		WHERE id_group IN ({array_int:group_list})
355
			AND id_member IN ({array_int:member_list})',
356
		array(
357
			'group_list' => $groups,
358
			'member_list' => $members,
359
			'regular_member' => 0,
360
		)
361
	);
362
363
	// Those who have it as part of their additional group must be updated the long way... sadly.
364
	$request = $db->query('', '
365
		SELECT id_member, additional_groups
366
		FROM {db_prefix}members
367
		WHERE (FIND_IN_SET({raw:additional_groups_implode}, additional_groups) != 0)
368
			AND id_member IN ({array_int:member_list})
369
		LIMIT ' . count($members),
370
		array(
371
			'member_list' => $members,
372
			'additional_groups_implode' => implode(', additional_groups) != 0 OR FIND_IN_SET(', $groups),
373
		)
374
	);
375
	$updates = array();
376
	while ($row = $db->fetch_assoc($request))
377
	{
378
		// What log entries must we make for this one, eh?
379
		foreach (explode(',', $row['additional_groups']) as $group)
380
			if (in_array($group, $groups))
381
				$log_inserts[] = array('group' => $group_names[$group], 'member' => $row['id_member']);
382
383
		$updates[$row['additional_groups']][] = $row['id_member'];
384
	}
385
	$db->free_result($request);
386
387
	require_once(SUBSDIR . '/Members.subs.php');
388
	foreach ($updates as $additional_groups => $memberArray)
389
		updateMemberData($memberArray, array('additional_groups' => implode(',', array_diff(explode(',', $additional_groups), $groups))));
390
391
	// Their post groups may have changed now...
392
	updatePostGroupStats($members);
393
394
	// Do the log.
395
	if (!empty($log_inserts) && !empty($modSettings['modlog_enabled']))
396
		foreach ($log_inserts as $extra)
397
			logAction('removed_from_group', $extra, 'admin');
398
399
	// Mission successful.
400
	return true;
401
}
402
403
/**
404
 * Add one or more members to a membergroup.
405
 *
406
 * - Requires the manage_membergroups permission.
407
 * - Function has protection against adding members to implicit groups.
408
 * - Non-admins cannot add members to the admin group, or protected groups.
409
 *
410
 * @package Membergroups
411
 * @param int|int[] $members
412
 * @param int $group
413
 * @param string $type = 'auto' specifies whether the group is added as primary or as additional group.
414
 * Supported types:
415
 * - only_primary    - Assigns a membergroup as primary membergroup, but only
416
 *                     if a member has not yet a primary membergroup assigned,
417
 *                     unless the member is already part of the membergroup.
418
 * - only_additional - Assigns a membergroup to the additional membergroups,
419
 *                     unless the member is already part of the membergroup.
420
 * - force_primary   - Assigns a membergroup as primary membergroup no matter
421
 *                     what the previous primary membergroup was.
422
 * - auto            - Assigns a membergroup to the primary group if it's still
423
 *                     available. If not, assign it to the additional group.
424
 * @param bool $permissionCheckDone = false if true, it checks permission of the current user to add groups ('manage_membergroups')
425
 * @return boolean success or failure
426
 * @throws Elk_Exception
427
 */
428
function addMembersToGroup($members, $group, $type = 'auto', $permissionCheckDone = false)
429
{
430
	$db = database();
431
432
	// Show your licence, but only if it hasn't been done yet.
433
	if (!$permissionCheckDone)
434
		isAllowedTo('manage_membergroups');
435
436
	// Make sure we don't keep old stuff cached.
437
	updateSettings(array('settings_updated' => time()));
438
439
	if (!is_array($members))
440
		$members = array((int) $members);
441
	// Make sure all members are integer.
442
	else
443
		$members = array_unique(array_map('intval', $members));
444
445
	$group = (int) $group;
446
447
	// Some groups just don't like explicitly having members.
448
	$implicitGroups = array(-1, 0, 3);
449
	$group_names = array();
450
	$group_details = membergroupById($group, true);
451 View Code Duplication
	if ($group_details['min_posts'] != -1)
452
		$implicitGroups[] = $group_details['id_group'];
453
	else
454
		$group_names[$group_details['id_group']] = $group_details['group_name'];
455
456
	// Sorry, you can't join an implicit group.
457
	if (in_array($group, $implicitGroups) || empty($members))
458
		return false;
459
460
	// Only admins can add admins...
461
	if (!allowedTo('admin_forum') && $group == 1)
462
		return false;
463
	// ... and assign protected groups!
464
	elseif (!allowedTo('admin_forum') && $group_details['group_type'] == 1)
465
		return false;
466
467
	// Do the actual updates.
468
	if ($type == 'only_additional')
469
		$db->query('', '
470
			UPDATE {db_prefix}members
471
			SET additional_groups = CASE WHEN additional_groups = {string:blank_string} THEN {string:id_group_string} ELSE CONCAT(additional_groups, {string:id_group_string_extend}) END
472
			WHERE id_member IN ({array_int:member_list})
473
				AND id_group != {int:id_group}
474
				AND FIND_IN_SET({int:id_group}, additional_groups) = 0',
475
			array(
476
				'member_list' => $members,
477
				'id_group' => $group,
478
				'id_group_string' => (string) $group,
479
				'id_group_string_extend' => ',' . $group,
480
				'blank_string' => '',
481
			)
482
		);
483
	elseif ($type == 'only_primary' || $type == 'force_primary')
484
		$db->query('', '
485
			UPDATE {db_prefix}members
486
			SET id_group = {int:id_group}
487
			WHERE id_member IN ({array_int:member_list})' . ($type == 'force_primary' ? '' : '
488
				AND id_group = {int:regular_group}
489
				AND FIND_IN_SET({int:id_group}, additional_groups) = 0'),
490
			array(
491
				'member_list' => $members,
492
				'id_group' => $group,
493
				'regular_group' => 0,
494
			)
495
		);
496
	elseif ($type == 'auto')
497
		$db->query('', '
498
			UPDATE {db_prefix}members
499
			SET
500
				id_group = CASE WHEN id_group = {int:regular_group} THEN {int:id_group} ELSE id_group END,
501
				additional_groups = CASE WHEN id_group = {int:id_group} THEN additional_groups
502
					WHEN additional_groups = {string:blank_string} THEN {string:id_group_string}
503
					ELSE CONCAT(additional_groups, {string:id_group_string_extend}) END
504
			WHERE id_member IN ({array_int:member_list})
505
				AND id_group != {int:id_group}
506
				AND FIND_IN_SET({int:id_group}, additional_groups) = 0',
507
			array(
508
				'member_list' => $members,
509
				'regular_group' => 0,
510
				'id_group' => $group,
511
				'blank_string' => '',
512
				'id_group_string' => (string) $group,
513
				'id_group_string_extend' => ',' . $group,
514
			)
515
		);
516
	// Ack!!?  What happened?
517
	else
518
		trigger_error('addMembersToGroup(): Unknown type \'' . $type . '\'', E_USER_WARNING);
519
520
	call_integration_hook('integrate_add_members_to_group', array($members, $group_details, &$group_names));
521
522
	// Update their postgroup statistics.
523
	updatePostGroupStats($members);
524
525
	require_once(SOURCEDIR . '/Logging.php');
526
	foreach ($members as $member)
527
		logAction('added_to_group', array('group' => $group_names[$group], 'member' => $member), 'admin');
528
529
	return true;
530
}
531
532
/**
533
 * Gets the members of a supplied membergroup.
534
 *
535
 * - Returns them as a link for display.
536
 *
537
 * @package Membergroups
538
 * @param int[] $members
539
 * @param int $membergroup
540
 * @param integer|null $limit = null
541
 * @return boolean
542
 */
543
function listMembergroupMembers_Href(&$members, $membergroup, $limit = null)
544
{
545
	global $scripturl;
546
547
	$db = database();
548
549
	$request = $db->query('', '
550
		SELECT id_member, real_name
551
		FROM {db_prefix}members
552
		WHERE id_group = {int:id_group} OR FIND_IN_SET({int:id_group}, additional_groups) != 0' . ($limit === null ? '' : '
553
		LIMIT ' . ($limit + 1)),
554
		array(
555
			'id_group' => $membergroup,
556
		)
557
	);
558
	$members = array();
559 View Code Duplication
	while ($row = $db->fetch_assoc($request))
560
		$members[$row['id_member']] = '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>';
561
	$db->free_result($request);
562
563
	// If there are more than $limit members, add a 'more' link.
564
	if ($limit !== null && count($members) > $limit)
565
	{
566
		array_pop($members);
567
		return true;
568
	}
569
	else
570
		return false;
571
}
572
573
/**
574
 * Retrieve a list of (visible) membergroups used by the cache.
575
 *
576
 * @package Membergroups
577
 */
578
function cache_getMembergroupList()
579
{
580
	global $scripturl;
581
582
	$db = database();
583
584
	$groupCache = $db->fetchQueryCallback('
585
		SELECT id_group, group_name, online_color
586
		FROM {db_prefix}membergroups
587
		WHERE min_posts = {int:min_posts}
588
			AND hidden = {int:not_hidden}
589
			AND id_group != {int:mod_group}
590
			AND online_color != {string:blank_string}
591
		ORDER BY group_name',
592
		array(
593
			'min_posts' => -1,
594
			'not_hidden' => 0,
595
			'mod_group' => 3,
596
			'blank_string' => '',
597
		),
598
		function ($row) use ($scripturl)
599
		{
600
			return '<a href="' . $scripturl . '?action=groups;sa=members;group=' . $row['id_group'] . '" ' . ($row['online_color'] ? 'style="color: ' . $row['online_color'] . '"' : '') . '>' . $row['group_name'] . '</a>';
601
		}
602
	);
603
604
	return array(
605
		'data' => $groupCache,
606
		'expires' => time() + 3600,
607
		'refresh_eval' => 'return $GLOBALS[\'modSettings\'][\'settings_updated\'] > ' . time() . ';',
608
	);
609
}
610
611
/**
612
 * Helper function to generate a list of membergroups for display.
613
 *
614
 * @package Membergroups
615
 * @param int $start not used
616
 * @param int $items_per_page not used
617
 * @param string $sort An SQL query indicating how to sort the results
618
 * @param string $membergroup_type Should be 'post_count' for post groups or 'regular' for other groups
619
 * @param int $user_id id of the member making the request
620
 * @param bool $include_hidden If true includes hidden groups if the user has permission
621
 * @param bool $include_all If true includes all groups the user can see
622
 * @param bool $aggregate
623
 * @param bool $count_permissions
624
 * @param int|null $pid - profile id
625
 */
626
function list_getMembergroups($start, $items_per_page, $sort, $membergroup_type, $user_id, $include_hidden, $include_all = false, $aggregate = false, $count_permissions = false, $pid = null)
0 ignored issues
show
Unused Code introduced by
The parameter $start is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $items_per_page is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
627
{
628
	global $scripturl, $txt, $context;
629
630
	$db = database();
631
	loadLanguage('Admin');
632
633
	$request = $db->query('', '
634
		SELECT mg.id_group, mg.group_name, mg.min_posts, mg.description, mg.group_type, mg.online_color,
635
			mg.hidden, mg.id_parent, mg.icons, COALESCE(gm.id_member, 0) AS can_moderate, 0 AS num_members
636
		FROM {db_prefix}membergroups AS mg
637
			LEFT JOIN {db_prefix}group_moderators AS gm ON (gm.id_group = mg.id_group AND gm.id_member = {int:current_member})
638
		WHERE mg.min_posts {raw:min_posts}' . ($include_all ? '' : '
639
			AND mg.id_group != {int:mod_group}
640
			AND mg.group_type != {int:is_protected}') . '
641
		ORDER BY {raw:sort}',
642
		array(
643
			'current_member' => $user_id,
644
			'min_posts' => ($membergroup_type === 'post_count' ? '!= -1' : '= -1'),
645
			'mod_group' => 3,
646
			'is_protected' => 1,
647
			'sort' => $sort,
648
		)
649
	);
650
651
	// Start collecting the data.
652
	$groups = array();
653
	$group_ids = array();
654
	$parent_groups = array();
655
656
	if ($membergroup_type === 'all')
657
	{
658
		// Determine the number of ungrouped members.
659
		$num_members = countMembersInGroup(0);
660
661
		// Fill the context variable with 'Guests' and 'Regular Members'.
662
		$groups = array(
663
			-1 => array(
664
				'id_group' => -1,
665
				'group_name' => $txt['membergroups_guests'],
666
				'group_name_color' => $txt['membergroups_guests'],
667
				'min_posts' => 0,
668
				'desc' => '',
669
				'num_members' => $txt['membergroups_guests_na'],
670
				'icons' => '',
671
				'can_search' => false,
672
				'id_parent' => -2,
673
				'num_permissions' => array(
674
					'allowed' => 0,
675
					'denied' => 0,
676
				)
677
			),
678
			0 => array(
679
				'id_group' => 0,
680
				'group_name' => $txt['membergroups_members'],
681
				'group_name_color' => $txt['membergroups_members'],
682
				'min_posts' => 0,
683
				'desc' => '',
684
				'num_members' => $num_members,
685
				'icons' => '',
686
				'can_search' => true,
687
				'id_parent' => -2,
688
				'num_permissions' => array(
689
					'allowed' => 0,
690
					'denied' => 0,
691
				)
692
			),
693
		);
694
	}
695
696
	while ($row = $db->fetch_assoc($request))
697
	{
698
		// We only list the groups they can see.
699
		if ($row['hidden'] && !$row['can_moderate'] && !$include_hidden)
700
			continue;
701
702
		if ($row['id_parent'] != -2)
703
			$parent_groups[] = $row['id_parent'];
704
705
		// If it's inherited, just add it as a child.
706
		if ($aggregate && $row['id_parent'] != -2)
707
		{
708 View Code Duplication
			if (isset($groups[$row['id_parent']]))
709
				$groups[$row['id_parent']]['children'][$row['id_group']] = $row['group_name'];
710
			continue;
711
		}
712
713
		$row['icons'] = explode('#', $row['icons']);
714
715
		$groups[$row['id_group']] = array(
716
			'id_group' => $row['id_group'],
717
			'group_name' => $row['group_name'],
718
			'group_name_color' => empty($row['online_color']) ? $row['group_name'] : '<span style="color: ' . $row['online_color'] . '">' . $row['group_name'] . '</span>',
719
			'min_posts' => $row['min_posts'],
720
			'desc' => $row['description'],
721
			'online_color' => $row['online_color'],
722
			'type' => $row['group_type'],
723
			'num_members' => $row['num_members'],
724
			'moderators' => array(),
725
			'icons' => $row['icons'],
726
			'can_search' => $row['id_group'] != 3,
727
			'id_parent' => $row['id_parent'],
728
		);
729
730
		if ($count_permissions)
731
			$groups[$row['id_group']]['num_permissions'] = array(
732
				'allowed' => $row['id_group'] == 1 ? '(' . $txt['permissions_all'] . ')' : 0,
733
				'denied' => $row['id_group'] == 1 ? '(' . $txt['permissions_none'] . ')' : 0,
734
			);
735
736
		$include_hidden |= $row['can_moderate'];
737
		$group_ids[] = $row['id_group'];
738
	}
739
	$db->free_result($request);
740
741
	// If we found any membergroups, get the amount of members in them.
742
	if (!empty($group_ids))
743
	{
744
		if ($membergroup_type === 'post_count')
745
			$groups_count = membersInGroups($group_ids);
746
		else
747
			$groups_count = membersInGroups(array(), $group_ids, $include_hidden);
748
749
		// @todo not sure why += wouldn't = be enough?
750
		foreach ($groups_count as $group_id => $num_members)
751
			$groups[$group_id]['num_members'] += $num_members;
752
753
		$query = $db->query('', '
754
			SELECT mods.id_group, mods.id_member, mem.member_name, mem.real_name
755
			FROM {db_prefix}group_moderators AS mods
756
				INNER JOIN {db_prefix}members AS mem ON (mem.id_member = mods.id_member)
757
			WHERE mods.id_group IN ({array_int:group_list})',
758
			array(
759
				'group_list' => $group_ids,
760
			)
761
		);
762
		while ($row = $db->fetch_assoc($query))
763
			$groups[$row['id_group']]['moderators'][] = '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>';
764
		$db->free_result($query);
765
	}
766
767
	if (!empty($parent_groups))
768
	{
769
		$all_group_names = array(
770
			-1 => $txt['membergroups_guests'],
771
			0 => $txt['membergroups_members']
772
		);
773
		$request = $db->query('', '
774
			SELECT id_group, group_name
775
			FROM {db_prefix}membergroups
776
			WHERE id_group IN ({array_int:groups})',
777
			array(
778
				'groups' => $parent_groups,
779
			)
780
		);
781
		while ($row = $db->fetch_assoc($request))
782
			$all_group_names[$row['id_group']] = $row['group_name'];
783
	}
784
	foreach ($groups as $key => $group)
785
	{
786
		if ($group['id_parent'] != -2)
787
		{
788
			$groups[$key]['parent_name'] = $all_group_names[$group['id_parent']];
0 ignored issues
show
Bug introduced by
The variable $all_group_names does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
789
		}
790
	}
791
792
	// Apply manual sorting if the 'number of members' column is selected.
793
	if (substr($sort, 0, 1) == '1' || strpos($sort, ', 1') !== false)
794
	{
795
		$sort_ascending = strpos($sort, 'DESC') === false;
796
		$sort_array = array();
797
798
		foreach ($groups as $group)
799
			$sort_array[] = $group['id_group'] != 3 ? (int) $group['num_members'] : -1;
800
801
		array_multisort($sort_array, $sort_ascending ? SORT_ASC : SORT_DESC, SORT_REGULAR, $groups);
802
	}
803
804
	if ($count_permissions)
805
	{
806
		// pid = profile id
807
		if (empty($pid))
808
		{
809
			$groups = countPermissions($groups, $context['hidden_permissions']);
810
811
			// Get the "default" profile permissions too.
812
			$groups = countBoardPermissions($groups, $context['hidden_permissions'], 1);
813
		}
814
		else
815
		{
816
			$groups = countBoardPermissions($groups, null, $pid);
817
		}
818
	}
819
820
	return $groups;
821
}
822
823
/**
824
 * Count the number of members in specific groups
825
 *
826
 * @package Membergroups
827
 * @param int[] $postGroups an array of post-based groups id.
828
 * @param int[] $normalGroups = array() an array of normal groups id.
829
 * @param bool $include_hidden if true, includes hidden groups in the count (default false).
830
 * @param bool $include_moderators if true, includes board moderators too (default false).
831
 * @param bool $include_non_active if true, includes non active members (default false).
832
 * @return array
833
 */
834
function membersInGroups($postGroups, $normalGroups = array(), $include_hidden = false, $include_moderators = false, $include_non_active = false)
835
{
836
	$db = database();
837
838
	$groups = array();
839
840
	// If we have post groups, let's count the number of members...
841
	if (!empty($postGroups))
842
	{
843
		$query = $db->query('', '
844
			SELECT id_post_group AS id_group, COUNT(*) AS member_count
845
			FROM {db_prefix}members
846
			WHERE id_post_group IN ({array_int:post_group_list})' . ($include_non_active ? '' : '
847
				AND is_activated = {int:active_members}') . '
848
			GROUP BY id_post_group',
849
			array(
850
				'post_group_list' => $postGroups,
851
				'active_members' => 1,
852
			)
853
		);
854
		while ($row = $db->fetch_assoc($query))
855
			$groups[$row['id_group']] = $row['member_count'];
856
		$db->free_result($query);
857
	}
858
859
	if (!empty($normalGroups))
860
	{
861
		// Find people who are members of this group...
862
		$query = $db->query('', '
863
			SELECT id_group, COUNT(*) AS member_count
864
			FROM {db_prefix}members
865
			WHERE id_group IN ({array_int:normal_group_list})' . ($include_non_active ? '' : '
866
				AND is_activated = {int:active_members}') . '
867
			GROUP BY id_group',
868
			array(
869
				'normal_group_list' => $normalGroups,
870
				'active_members' => 1,
871
			)
872
		);
873
		while ($row = $db->fetch_assoc($query))
874
			$groups[$row['id_group']] = $row['member_count'];
875
		$db->free_result($query);
876
877
		// Only do additional groups if we can moderate...
878
		if ($include_hidden)
879
		{
880
			// Also do those who have it as an additional membergroup - this ones more yucky...
881
			$query = $db->query('', '
882
				SELECT mg.id_group, COUNT(*) AS member_count
883
				FROM {db_prefix}membergroups AS mg
884
					INNER JOIN {db_prefix}members AS mem ON (mem.additional_groups != {string:blank_string}
885
						AND mem.id_group != mg.id_group
886
						AND FIND_IN_SET(mg.id_group, mem.additional_groups) != 0)
887
				WHERE mg.id_group IN ({array_int:normal_group_list})' . ($include_non_active ? '' : '
888
					AND mem.is_activated = {int:active_members}') . '
889
				GROUP BY mg.id_group',
890
				array(
891
					'normal_group_list' => $normalGroups,
892
					'active_members' => 1,
893
					'blank_string' => '',
894
				)
895
			);
896
			while ($row = $db->fetch_assoc($query))
897
			{
898 View Code Duplication
				if (isset($groups[$row['id_group']]))
899
					$groups[$row['id_group']] += $row['member_count'];
900
				else
901
					$groups[$row['id_group']] = $row['member_count'];
902
			}
903
			$db->free_result($query);
904
		}
905
	}
906
907
	if ($include_moderators)
908
	{
909
		// Any moderators?
910
		$request = $db->query('', '
911
			SELECT COUNT(DISTINCT id_member) AS num_distinct_mods
912
			FROM {db_prefix}moderators
913
			LIMIT 1',
914
			array(
915
			)
916
		);
917
		list ($groups[3]) = $db->fetch_row($request);
918
		$db->free_result($request);
919
	}
920
921
	return $groups;
922
}
923
924
/**
925
 * Returns details of membergroups based on the id
926
 *
927
 * @package Membergroups
928
 * @param int[]|int $group_ids the IDs of the groups.
929
 * @param integer $limit = 1 the number of results returned (default 1, if null/false/0 returns all).
930
 * @param bool $detailed = false if true then it returns more fields (default false).
931
 *     false returns: id_group, group_name, group_type.
932
 *     true adds to above: description, min_posts, online_color, max_messages, icons, hidden, id_parent.
933
 * @param bool $assignable = false determine if the group is assignable or not and return that information.
934
 * @return array|false
935
 */
936
function membergroupsById($group_ids, $limit = 1, $detailed = false, $assignable = false)
937
{
938
	$db = database();
939
940
	if (empty($group_ids))
941
		return false;
942
943
	$group_ids = !is_array($group_ids) ? array($group_ids) : $group_ids;
944
945
	$groups = array();
946
	$group_ids = array_map('intval', $group_ids);
947
948
	$request = $db->query('', '
949
		SELECT id_group, group_name, group_type' . (!$detailed ? '' : ',
950
			description, min_posts, online_color, max_messages, icons, hidden, id_parent') . (!$assignable ? '' : ',
951
			CASE WHEN min_posts = {int:min_posts} THEN 1 ELSE 0 END AS assignable,
952
			CASE WHEN min_posts != {int:min_posts} THEN 1 ELSE 0 END AS is_post_group') . '
953
		FROM {db_prefix}membergroups
954
		WHERE id_group IN ({array_int:group_ids})' . (empty($limit) ? '' : '
955
		LIMIT {int:limit}'),
956
		array(
957
			'min_posts' => -1,
958
			'group_ids' => $group_ids,
959
			'limit' => $limit,
960
		)
961
	);
962
963
	while ($row = $db->fetch_assoc($request))
964
		$groups[$row['id_group']] = $row;
965
	$db->free_result($request);
966
967
	return $groups;
968
}
969
970
/**
971
 * Uses membergroupsById to return the group information of a single group
972
 *
973
 * @package Membergroups
974
 * @param int $group_id
975
 * @param bool $detailed
976
 * @param bool $assignable
977
 */
978
function membergroupById($group_id, $detailed = false, $assignable = false)
979
{
980
	$groups = membergroupsById(array($group_id), 1, $detailed, $assignable);
981
982
	if (isset($groups[$group_id]))
983
		return $groups[$group_id];
984
	else
985
		return false;
986
}
987
988
/**
989
 * Gets basic membergroup data
990
 *
991
 * - the $includes and $excludes array is used for granular filtering the output.
992
 * - We need to exclude groups sometimes because they are special ones.
993
 * Example: getBasicMembergroupData(array('admin', 'mod', 'globalmod'));
994
 * $includes parameters:
995
 * - 'admin' includes the admin: id_group = 1
996
 * - 'mod' includes the local moderator: id_group = 3
997
 * - 'globalmod' includes the global moderators: id_group = 2
998
 * - 'member' includes the ungrouped users from id_group = 0
999
 * - 'postgroups' includes the post based membergroups
1000
 * - 'protected' includes protected groups
1001
 * - 'all' lists all groups
1002
 * $excludes parameters:
1003
 * - 'newbie' excludes the newbie group id_group 4
1004
 * - 'custom' lists only the system based groups (id 0, 1, 2, 3)
1005
 * - 'membergroups' excludes permission groups, lists the post based membergroups
1006
 * - 'hidden' excludes hidden groups
1007
 *
1008
 * @package Membergroups
1009
 * @param string[]|string $includes
1010
 * @param string[] $excludes
1011
 * @param string|null $sort_order
1012
 * @param bool|null $split splits postgroups and membergroups
1013
 * @return array
1014
 */
1015
function getBasicMembergroupData($includes = array(), $excludes = array(), $sort_order = null, $split = null)
1016
{
1017 1
	global $txt, $modSettings;
1018
1019 1
	$db = database();
1020
1021
	// No $includes parameters given? Let's set some default values
1022 1
	if (empty($includes))
1023 1
		$includes = array('globalmod', 'member', 'postgroups');
1024 1
	elseif (!is_array($includes))
1025
		$includes = array($includes);
1026
1027 1
	$groups = array();
1028
1029 1
	$where = '';
1030 1
	$sort_order = isset($sort_order) ? $sort_order : 'min_posts, CASE WHEN id_group < {int:newbie_group} THEN id_group ELSE 4 END, group_name';
1031
1032
	// Do we need the post based membergroups?
1033 1
	$where .= !empty($modSettings['permission_enable_postgroups']) || in_array('postgroups', $includes) ? '' : 'AND min_posts = {int:min_posts}';
1034
	// Include protected groups?
1035 1
	$where .= allowedTo('admin_forum') || in_array('protected', $includes) ? '' : ' AND group_type != {int:is_protected}';
1036
	// Include the global moderators?
1037 1
	$where .= in_array('globalmod', $includes) ? '' : ' AND id_group != {int:global_mod_group}';
1038
	// Include the admins?
1039 1
	$where .= in_array('admin', $includes) ? '' : ' AND id_group != {int:admin_group}';
1040
	// Local Moderators?
1041 1
	$where .= in_array('mod', $includes) ? '' : ' AND id_group != {int:moderator_group}';
1042
	// Ignore the first post based group?
1043 1
	$where .= !in_array('newbie', $excludes) ? '' : ' AND id_group != {int:newbie_group}';
1044
	// Exclude custom groups?
1045 1
	$where .= !in_array('custom', $excludes) ? '' : ' AND id_group < {int:newbie_group}';
1046
	// Exclude hidden?
1047 1
	$where .= !in_array('hidden', $excludes) ? '' : ' AND hidden != {int:hidden_group}';
1048
1049
	// Only the post based membergroups? We can safely overwrite the $where.
1050 1
	if (in_array('membergroups', $excludes))
1051 1
		$where = ' AND min_posts != {int:min_posts}';
1052
1053
	// Simply all of them?
1054 1
	if (in_array('all', $includes))
1055 1
		$where = '';
1056
1057 1
	$request = $db->query('', '
1058
		SELECT id_group, group_name, min_posts, online_color
1059
		FROM {db_prefix}membergroups
1060
		WHERE 1 = 1
1061 1
			' . $where . '
1062 1
		ORDER BY ' . $sort_order,
1063
		array(
1064 1
			'admin_group' => 1,
1065 1
			'moderator_group' => 3,
1066 1
			'global_mod_group' => 2,
1067 1
			'min_posts' => -1,
1068 1
			'is_protected' => 1,
1069 1
			'newbie_group' => 4,
1070 1
			'hidden_group' => 2,
1071
		)
1072 1
	);
1073
1074
	// Include the default membergroup? the ones with id_member = 0
1075 1
	if (in_array('member', $includes) && !isset($split))
1076 1
	{
1077 1
		$groups[] = array(
1078 1
			'id' => 0,
1079 1
			'name' => $txt['membergroups_members']
1080 1
		);
1081 1
	}
1082
1083 1
	if (!empty($split))
1084 1
	{
1085
		if (empty($modSettings['permission_enable_postgroups']))
1086
		{
1087
			$groups['groups'][0] = array(
1088
				'id' => 0,
1089
				'name' => $txt['membergroups_members'],
1090
				'can_be_additional' => false,
1091
				'member_count' => 0,
1092
			);
1093
			$groups['membergroups'][0] = array(
1094
				'id' => 0,
1095
				'name' => $txt['membergroups_members'],
1096
				'can_be_additional' => false,
1097
				'member_count' => 0,
1098
			);
1099
		}
1100
		while ($row = $db->fetch_assoc($request))
1101
		{
1102
			$groups['groups'][$row['id_group']] = array(
1103
				'id' => $row['id_group'],
1104
				'name' => $row['group_name'],
1105
				'member_count' => 0,
1106
			);
1107
1108
			if ($row['min_posts'] == -1)
1109
				$groups['membergroups'][] = array(
1110
					'id' => $row['id_group'],
1111
					'name' => $row['group_name'],
1112
					'can_be_additional' => true,
1113
				);
1114
			else
1115
				$groups['postgroups'][] = array(
1116
					'id' => $row['id_group'],
1117
					'name' => $row['group_name'],
1118
				);
1119
		}
1120
	}
1121
	else
1122 1
		while ($row = $db->fetch_assoc($request))
1123
		{
1124 1
			$groups[] = array(
1125 1
				'id' => $row['id_group'],
1126 1
				'name' => $row['group_name'],
1127 1
				'online_color' => $row['online_color'],
1128
			);
1129 1
		}
1130
1131 1
	$db->free_result($request);
1132
1133 1
	return $groups;
1134
}
1135
1136
/**
1137
 * Retrieve groups and their number of members.
1138
 *
1139
 * @package Membergroups
1140
 * @param int[] $groupList
1141
 * @return array with ('id', 'name', 'member_count')
1142
 */
1143
function getGroups($groupList)
1144
{
1145
	global $txt;
1146
1147
	$db = database();
1148
1149
	$groups = array();
1150
	if (in_array(0, $groupList))
1151
	{
1152
		$groups[0] = array(
1153
			'id' => 0,
1154
			'name' => $txt['announce_regular_members'],
1155
			'member_count' => 'n/a',
1156
		);
1157
	}
1158
1159
	// Get all membergroups that have access to the board the announcement was made on.
1160
	$request = $db->query('', '
1161
		SELECT mg.id_group, mg.group_name, COUNT(mem.id_member) AS num_members
1162
		FROM {db_prefix}membergroups AS mg
1163
			LEFT JOIN {db_prefix}members AS mem ON (mem.id_group = mg.id_group OR FIND_IN_SET(mg.id_group, mem.additional_groups) != 0 OR mg.id_group = mem.id_post_group)
1164
		WHERE mg.id_group IN ({array_int:group_list})
1165
		GROUP BY mg.id_group',
1166
		array(
1167
			'group_list' => $groupList,
1168
		)
1169
	);
1170
	while ($row = $db->fetch_assoc($request))
1171
	{
1172
		$groups[$row['id_group']] = array(
1173
			'id' => $row['id_group'],
1174
			'name' => $row['group_name'],
1175
			'member_count' => $row['num_members'],
1176
		);
1177
	}
1178
	$db->free_result($request);
1179
1180
	return $groups;
1181
}
1182
1183
/**
1184
 * Gets the last assigned group id.
1185
 *
1186
 * @package Membergroups
1187
 * @return int $id_group
1188
 */
1189
function getMaxGroupID()
1190
{
1191
	$db = database();
1192
1193
	$request = $db->query('', '
1194
		SELECT MAX(id_group)
1195
		FROM {db_prefix}membergroups',
1196
		array(
1197
		)
1198
	);
1199
	list ($id_group) = $db->fetch_row($request);
1200
1201
	return $id_group;
1202
}
1203
1204
/**
1205
 * Adds a new group to the membergroups table.
1206
 *
1207
 * @deprecated since 1.1 RC2 - use createMembergroup instead
1208
 *
1209
 * @package Membergroups
1210
 * @param int $id_group
1211
 * @param string $groupname
1212
 * @param int $minposts
1213
 * @param string $type
1214
 */
1215 View Code Duplication
function addMembergroup($id_group, $groupname, $minposts, $type)
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1216
{
1217
	$db = database();
1218
1219
	$db->insert('',
1220
		'{db_prefix}membergroups',
1221
		array(
1222
			'id_group' => 'int', 'description' => 'string', 'group_name' => 'string-80', 'min_posts' => 'int',
1223
			'icons' => 'string', 'online_color' => 'string', 'group_type' => 'int',
1224
		),
1225
		array(
1226
			$id_group, '', Util::htmlspecialchars($groupname, ENT_QUOTES), $minposts,
1227
			'1#icon.png', '', $type,
1228
		),
1229
		array('id_group')
1230
	);
1231
}
1232
1233
/**
1234
 * Adds a new group to the membergroups table.
1235
 *
1236
 * @package Membergroups
1237
 * @param string $groupname
1238
 * @param int $minposts
1239
 * @param string $type
1240
 */
1241 View Code Duplication
function createMembergroup($groupname, $minposts, $type)
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1242
{
1243
	$db = database();
1244
1245
	$db->insert('',
1246
		'{db_prefix}membergroups',
1247
		array(
1248
			'description' => 'string', 'group_name' => 'string-80', 'min_posts' => 'int',
1249
			'icons' => 'string', 'online_color' => 'string', 'group_type' => 'int',
1250
		),
1251
		array(
1252
			'', Util::htmlspecialchars($groupname, ENT_QUOTES), $minposts,
1253
			'1#icon.png', '', $type,
1254
		),
1255
		array('id_group')
1256
	);
1257
1258
	return $db->insert_id('{db_prefix}membergroups');
1259
}
1260
1261
/**
1262
 * Copies permissions from a given membergroup.
1263
 *
1264
 * @package Membergroups
1265
 * @param int $id_group
1266
 * @param int $copy_from
1267
 * @param string[]|null $illegal_permissions
1268
 * @todo another function with the same name in ManagePermissions.subs.php
1269
 */
1270
function copyPermissions($id_group, $copy_from, $illegal_permissions)
1271
{
1272
	$db = database();
1273
1274
	$inserts = array();
1275
1276
	$request = $db->query('', '
1277
		SELECT permission, add_deny
1278
		FROM {db_prefix}permissions
1279
		WHERE id_group = {int:copy_from}',
1280
		array(
1281
			'copy_from' => $copy_from,
1282
		)
1283
	);
1284
1285
	while ($row = $db->fetch_assoc($request))
1286
	{
1287
		if (empty($illegal_permissions) || !in_array($row['permission'], $illegal_permissions))
1288
			$inserts[] = array($id_group, $row['permission'], $row['add_deny']);
1289
	}
1290
	$db->free_result($request);
1291
1292
	if (!empty($inserts))
1293
		$db->insert('insert',
1294
			'{db_prefix}permissions',
1295
			array('id_group' => 'int', 'permission' => 'string', 'add_deny' => 'int'),
1296
			$inserts,
1297
			array('id_group', 'permission')
1298
		);
1299
}
1300
1301
/**
1302
 * Copies the board permissions from a given membergroup.
1303
 *
1304
 * @package Membergroups
1305
 * @param int $id_group
1306
 * @param int $copy_from
1307
 */
1308
function copyBoardPermissions($id_group, $copy_from)
1309
{
1310
	$db = database();
1311
1312
	$inserts = $db->fetchQueryCallback('
1313
		SELECT id_profile, permission, add_deny
1314
		FROM {db_prefix}board_permissions
1315
		WHERE id_group = {int:copy_from}',
1316
		array(
1317
			'copy_from' => $copy_from,
1318
		),
1319
		function ($row) use ($id_group)
1320
		{
1321
			return array($id_group, $row['id_profile'], $row['permission'], $row['add_deny']);
1322
		}
1323
	);
1324
1325 View Code Duplication
	if (!empty($inserts))
1326
	{
1327
		$db->insert('insert',
1328
			'{db_prefix}board_permissions',
1329
			array('id_group' => 'int', 'id_profile' => 'int', 'permission' => 'string', 'add_deny' => 'int'),
1330
			$inserts,
1331
			array('id_group', 'id_profile', 'permission')
1332
		);
1333
	}
1334
}
1335
1336
/**
1337
 * Updates the properties of a copied membergroup.
1338
 *
1339
 * @package Membergroups
1340
 * @param int $id_group
1341
 * @param int $copy_from
1342
 */
1343
function updateCopiedGroup($id_group, $copy_from)
1344
{
1345
	$db = database();
1346
1347
	require_once(SUBSDIR . '/Membergroups.subs.php');
1348
	$group_info = membergroupById($copy_from, true);
1349
1350
	// update the new membergroup
1351
	$db->query('', '
1352
		UPDATE {db_prefix}membergroups
1353
		SET
1354
			online_color = {string:online_color},
1355
			max_messages = {int:max_messages},
1356
			icons = {string:icons}
1357
			WHERE id_group = {int:current_group}',
1358
			array(
1359
				'max_messages' => $group_info['max_messages'],
1360
				'current_group' => $id_group,
1361
				'online_color' => $group_info['online_color'],
1362
				'icons' => $group_info['icons'],
1363
			)
1364
	);
1365
}
1366
1367
/**
1368
 * Updates the properties of a inherited membergroup.
1369
 *
1370
 * @package Membergroups
1371
 * @param int $id_group
1372
 * @param int $copy_id
1373
 */
1374
function updateInheritedGroup($id_group, $copy_id)
1375
{
1376
	$db = database();
1377
1378
	$db->query('', '
1379
		UPDATE {db_prefix}membergroups
1380
		SET id_parent = {int:copy_from}
1381
		WHERE id_group = {int:current_group}',
1382
		array(
1383
			'copy_from' => $copy_id,
1384
			'current_group' => $id_group,
1385
		)
1386
	);
1387
}
1388
1389
/**
1390
 * This function updates the membergroup with the given information.
1391
 *
1392
 * - It's passed an associative array $properties, with 'current_group' holding
1393
 * the group to update. The rest of the keys are details to update it with.
1394
 *
1395
 * @package Membergroups
1396
 * @param mixed[] $properties
1397
 */
1398
function updateMembergroupProperties($properties)
1399
{
1400
	$db = database();
1401
1402
	$known_properties = array(
1403
		'max_messages' => array('type' => 'int'),
1404
		'min_posts' => array('type' => 'int'),
1405
		'group_type' => array('type' => 'int'),
1406
		'hidden' => array('type' => 'int'),
1407
		'id_parent' => array('type' => 'int'),
1408
		'group_name' => array('type' => 'string'),
1409
		'online_color' => array('type' => 'string'),
1410
		'icons' => array('type' => 'string'),
1411
		'description' => array('type' => 'string'),
1412
	);
1413
1414
	$values = array('current_group' => $properties['current_group']);
1415
	$updates = array();
1416
	foreach ($properties as $name => $value)
1417
	{
1418
		if (isset($known_properties[$name]))
1419
		{
1420
			$updates[] = $name . '={' . $known_properties[$name]['type'] . ':subs_' . $name . '}';
1421
			switch ($known_properties[$name]['type'])
1422
			{
1423
				case 'string':
1424
					$values['subs_' . $name] = Util::htmlspecialchars((string) $value);
1425
					break;
1426
				default:
1427
					$values['subs_' . $name] = (int) $value;
1428
			}
1429
		}
1430
	}
1431
1432
	if (empty($values))
1433
		return;
1434
1435
	$db->query('', '
1436
		UPDATE {db_prefix}membergroups
1437
		SET ' . implode(', ', $updates) . '
1438
		WHERE id_group = {int:current_group}',
1439
		$values
1440
	);
1441
}
1442
1443
/**
1444
 * Detaches a membergroup from the boards listed in $boards.
1445
 *
1446
 * @package Membergroups
1447
 * @param int $id_group
1448
 * @param mixed[] $boards
1449
 * @param string $access_list ('allow', 'deny')
1450
 */
1451
function detachGroupFromBoards($id_group, $boards, $access_list)
1452
{
1453
	$db = database();
1454
1455
	// Find all boards in whose access list this group is in, but shouldn't be.
1456
	$db->fetchQueryCallback('
1457
		SELECT id_board, {raw:column}
1458
		FROM {db_prefix}boards
1459
		WHERE FIND_IN_SET({string:current_group}, {raw:column}) != 0' . (empty($boards[$access_list]) ? '' : '
1460
			AND id_board NOT IN ({array_int:board_access_list})'),
1461
		array(
1462
			'current_group' => $id_group,
1463
			'board_access_list' => $boards[$access_list],
1464
			'column' => $access_list == 'allow' ? 'member_groups' : 'deny_member_groups',
1465
		),
1466
		function ($row) use ($id_group, $access_list, $db)
1467
		{
1468
			$db->query('', '
1469
				UPDATE {db_prefix}boards
1470
				SET {raw:column} = {string:member_group_access}
1471
				WHERE id_board = {int:current_board}',
1472
				array(
1473
					'current_board' => $row['id_board'],
1474
					'member_group_access' => implode(',', array_diff(explode(',', $row['member_groups']), array($id_group))),
1475
					'column' => $access_list == 'allow' ? 'member_groups' : 'deny_member_groups',
1476
				)
1477
			);
1478
		}
1479
	);
1480
}
1481
1482
/**
1483
 * Assigns the given group $id_group to the boards specified, for
1484
 * the 'allow' or 'deny' list.
1485
 *
1486
 * @package Membergroups
1487
 * @param int $id_group
1488
 * @param mixed[] $boards
1489
 * @param string $access_list ('allow', 'deny')
1490
 */
1491
function assignGroupToBoards($id_group, $boards, $access_list)
1492
{
1493
	$db = database();
1494
1495
	$db->query('', '
1496
		UPDATE {db_prefix}boards
1497
		SET {raw:column} = CASE WHEN {raw:column} = {string:blank_string} THEN {string:group_id_string} ELSE CONCAT({raw:column}, {string:comma_group}) END
1498
		WHERE id_board IN ({array_int:board_list})
1499
			AND FIND_IN_SET({int:current_group}, {raw:column}) = 0',
1500
		array(
1501
			'board_list' => $boards[$access_list],
1502
			'blank_string' => '',
1503
			'current_group' => $id_group,
1504
			'group_id_string' => (string) $id_group,
1505
			'comma_group' => ',' . $id_group,
1506
			'column' => $access_list == 'allow' ? 'member_groups' : 'deny_member_groups',
1507
		)
1508
	);
1509
}
1510
1511
/**
1512
 * Membergroup was deleted? We need to detach that group from our members, too...
1513
 *
1514
 * @package Membergroups
1515
 * @param int $id_group
1516
 */
1517 View Code Duplication
function detachDeletedGroupFromMembers($id_group)
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1518
{
1519
	$db = database();
1520
1521
	$updates = array();
1522
1523
	$db->query('', '
1524
		UPDATE {db_prefix}members
1525
		SET id_group = {int:regular_member}
1526
		WHERE id_group = {int:current_group}',
1527
		array(
1528
			'regular_member' => 0,
1529
			'current_group' => $id_group,
1530
		)
1531
	);
1532
1533
	$request = $db->query('', '
1534
		SELECT id_member, additional_groups
1535
		FROM {db_prefix}members
1536
		WHERE FIND_IN_SET({string:current_group}, additional_groups) != 0',
1537
		array(
1538
			'current_group' => $id_group,
1539
		)
1540
	);
1541
1542
	while ($row = $db->fetch_assoc($request))
1543
		$updates[$row['additional_groups']][] = $row['id_member'];
1544
	$db->free_result($request);
1545
1546
	require_once(SUBSDIR . '/Members.subs.php');
1547
	foreach ($updates as $additional_groups => $memberArray)
1548
		updateMemberData($memberArray, array('additional_groups' => implode(',', array_diff(explode(',', $additional_groups), array($id_group)))));
1549
1550
}
1551
1552
/**
1553
 * Make the given group hidden. Hidden groups are stored in the additional_groups.
1554
 *
1555
 * @package Membergroups
1556
 * @param int $id_group
1557
 */
1558 View Code Duplication
function setGroupToHidden($id_group)
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1559
{
1560
	$db = database();
1561
1562
	$updates = array();
1563
1564
	$request = $db->query('', '
1565
		SELECT id_member, additional_groups
1566
		FROM {db_prefix}members
1567
		WHERE id_group = {int:current_group}
1568
			AND FIND_IN_SET({int:current_group}, additional_groups) = 0',
1569
		array(
1570
			'current_group' => $id_group,
1571
		)
1572
	);
1573
1574
	while ($row = $db->fetch_assoc($request))
1575
		$updates[$row['additional_groups']][] = $row['id_member'];
1576
	$db->free_result($request);
1577
1578
	require_once(SUBSDIR . '/Members.subs.php');
1579
	foreach ($updates as $additional_groups => $memberArray)
1580
		updateMemberData($memberArray, array('additional_groups' => implode(',', array_merge(explode(',', $additional_groups), array($id_group)))));
1581
1582
	$db->query('', '
1583
		UPDATE {db_prefix}members
1584
		SET id_group = {int:regular_member}
1585
		WHERE id_group = {int:current_group}',
1586
		array(
1587
			'regular_member' => 0,
1588
			'current_group' => $id_group,
1589
		)
1590
	);
1591
}
1592
1593
/**
1594
 * Make sure the setting to display membergroup key on the board index is valid.
1595
 * It updates the setting if necessary.
1596
 *
1597
 * @package Membergroups
1598
 */
1599
function validateShowGroupMembership()
1600
{
1601
	global $modSettings;
1602
1603
	$db = database();
1604
1605
	$request = $db->query('', '
1606
		SELECT COUNT(*)
1607
		FROM {db_prefix}membergroups
1608
		WHERE group_type > {int:non_joinable}',
1609
		array(
1610
			'non_joinable' => 1,
1611
		)
1612
	);
1613
	list ($have_joinable) = $db->fetch_row($request);
1614
	$db->free_result($request);
1615
1616
	// Do we need to update the setting?
1617
	if ((empty($modSettings['show_group_membership']) && $have_joinable) || (!empty($modSettings['show_group_membership']) && !$have_joinable))
1618
		updateSettings(array('show_group_membership' => $have_joinable ? 1 : 0));
1619
}
1620
1621
/**
1622
 * Detaches group moderators from a deleted group.
1623
 *
1624
 * @package Membergroups
1625
 * @param int $id_group
1626
 */
1627
function detachGroupModerators($id_group)
1628
{
1629
	$db = database();
1630
1631
	$db->query('', '
1632
		DELETE FROM {db_prefix}group_moderators
1633
		WHERE id_group = {int:current_group}',
1634
		array(
1635
			'current_group' => $id_group,
1636
		)
1637
	);
1638
}
1639
1640
/**
1641
 * Get the id_member from the membergroup moderators.
1642
 *
1643
 * @package Membergroups
1644
 * @param string[] $moderators
1645
 *
1646
 * @return int[]
1647
 */
1648
function getIDMemberFromGroupModerators($moderators)
1649
{
1650
	$db = database();
1651
1652
	return $db->fetchQueryCallback('
1653
		SELECT id_member
1654
		FROM {db_prefix}members
1655
		WHERE member_name IN ({array_string:moderators}) OR real_name IN ({array_string:moderators})
1656
		LIMIT ' . count($moderators),
1657
		array(
1658
			'moderators' => $moderators,
1659
		),
1660
		function ($row)
1661
		{
1662
			return $row['id_member'];
1663
		}
1664
	);
1665
}
1666
1667
/**
1668
 * Assign members to the membergroup moderators.
1669
 *
1670
 * @package Membergroups
1671
 * @param int $id_group
1672
 * @param int[] $group_moderators
1673
 */
1674
function assignGroupModerators($id_group, $group_moderators)
1675
{
1676
	$db = database();
1677
1678
	$mod_insert = array();
1679
		foreach ($group_moderators as $moderator)
1680
			$mod_insert[] = array($id_group, $moderator);
1681
1682
		$db->insert('insert',
1683
			'{db_prefix}group_moderators',
1684
			array('id_group' => 'int', 'id_member' => 'int'),
1685
			$mod_insert,
1686
			array('id_group', 'id_member')
1687
		);
1688
}
1689
1690
/**
1691
 * List moderators from a given membergroup.
1692
 *
1693
 * @package Membergroups
1694
 * @param int $id_group
1695
 * @return array moderators as array(id => name)
1696
 */
1697
function getGroupModerators($id_group)
1698
{
1699
	$db = database();
1700
1701
	$moderators = array();
1702
1703
	$request = $db->query('', '
1704
		SELECT mem.id_member, mem.real_name
1705
		FROM {db_prefix}group_moderators AS mods
1706
			INNER JOIN {db_prefix}members AS mem ON (mem.id_member = mods.id_member)
1707
		WHERE mods.id_group = {int:current_group}',
1708
		array(
1709
			'current_group' => $id_group,
1710
		)
1711
	);
1712
	while ($row = $db->fetch_assoc($request))
1713
		$moderators[$row['id_member']] = $row['real_name'];
1714
	$db->free_result($request);
1715
1716
	return $moderators;
1717
}
1718
1719
/**
1720
 * Lists all groups which inherit permission profiles from the given group.
1721
 *
1722
 * - If no group is specified it will list any group that can be used
1723
 *
1724
 * @package Membergroups
1725
 * @param int|bool $id_group
1726
 * @return array
1727
 */
1728
function getInheritableGroups($id_group = false)
1729
{
1730
	global $modSettings;
1731
1732
	$db = database();
1733
1734
	$inheritable_groups = array();
1735
1736
	$request = $db->query('', '
1737
		SELECT id_group, group_name
1738
		FROM {db_prefix}membergroups
1739
		WHERE id_parent = {int:not_inherited}' . ($id_group === false ? '' : '
1740
			AND id_group != {int:current_group}') .
1741
			(empty($modSettings['permission_enable_postgroups']) ? '
1742
			AND min_posts = {int:min_posts}' : '') . (allowedTo('admin_forum') ? '' : '
1743
			AND group_type != {int:is_protected}') . '
1744
			AND id_group NOT IN (1, 3)',
1745
		array(
1746
			'current_group' => $id_group,
1747
			'min_posts' => -1,
1748
			'not_inherited' => -2,
1749
			'is_protected' => 1,
1750
		)
1751
	);
1752
1753
	while ($row = $db->fetch_assoc($request))
1754
		$inheritable_groups[$row['id_group']] = $row['group_name'];
1755
	$db->free_result($request);
1756
1757
	return $inheritable_groups;
1758
}
1759
1760
/**
1761
 * List all membergroups and prepares them to assign permissions to..
1762
 *
1763
 * @package Membergroups
1764
 * @return array
1765
 */
1766
function prepareMembergroupPermissions()
1767
{
1768
	global $modSettings, $txt;
1769
1770
	$db = database();
1771
1772
	// Start this with the guests/members.
1773
	$profile_groups = array(
1774
		-1 => array(
1775
			'id' => -1,
1776
			'name' => $txt['membergroups_guests'],
1777
			'color' => '',
1778
			'new_topic' => 'disallow',
1779
			'replies_own' => 'disallow',
1780
			'replies_any' => 'disallow',
1781
			'attachment' => 'disallow',
1782
			'children' => array(),
1783
		),
1784
		0 => array(
1785
			'id' => 0,
1786
			'name' => $txt['membergroups_members'],
1787
			'color' => '',
1788
			'new_topic' => 'disallow',
1789
			'replies_own' => 'disallow',
1790
			'replies_any' => 'disallow',
1791
			'attachment' => 'disallow',
1792
			'children' => array(),
1793
		),
1794
	);
1795
1796
	$request = $db->query('', '
1797
		SELECT id_group, group_name, online_color, id_parent
1798
		FROM {db_prefix}membergroups
1799
		WHERE id_group != {int:admin_group}
1800
			' . (empty($modSettings['permission_enable_postgroups']) ? ' AND min_posts = {int:min_posts}' : '') . '
1801
		ORDER BY id_parent ASC',
1802
		array(
1803
			'admin_group' => 1,
1804
			'min_posts' => -1,
1805
		)
1806
	);
1807
	while ($row = $db->fetch_assoc($request))
1808
	{
1809
		if ($row['id_parent'] == -2)
1810
		{
1811
			$profile_groups[$row['id_group']] = array(
1812
				'id' => $row['id_group'],
1813
				'name' => $row['group_name'],
1814
				'color' => $row['online_color'],
1815
				'new_topic' => 'disallow',
1816
				'replies_own' => 'disallow',
1817
				'replies_any' => 'disallow',
1818
				'attachment' => 'disallow',
1819
				'children' => array(),
1820
			);
1821
		}
1822
		elseif (isset($profile_groups[$row['id_parent']]))
1823
			$profile_groups[$row['id_parent']]['children'][] = $row['group_name'];
1824
	}
1825
	$db->free_result($request);
1826
1827
	return $profile_groups;
1828
}
1829
1830
/**
1831
 * Returns the groups that a user could see.
1832
 *
1833
 * - Ask and it will give you.
1834
 *
1835
 * @package Membergroups
1836
 * @param int $id_member the id of a member
1837
 * @param bool $show_hidden true if hidden groups (that the user can moderate) should be loaded (default false)
1838
 * @param int $min_posts minimum number of posts for the group (-1 for non-post based groups)
1839
 *
1840
 * @return array
1841
 */
1842
function loadGroups($id_member, $show_hidden = false, $min_posts = -1)
1843
{
1844
	$db = database();
1845
1846
	$request = $db->query('', '
1847
		SELECT mg.id_group, mg.group_name, COALESCE(gm.id_member, 0) AS can_moderate, mg.hidden
1848
		FROM {db_prefix}membergroups AS mg
1849
			LEFT JOIN {db_prefix}group_moderators AS gm ON (gm.id_group = mg.id_group AND gm.id_member = {int:current_member})
1850
		WHERE mg.min_posts = {int:min_posts}
1851
			AND mg.id_group != {int:moderator_group}' . ($show_hidden ? '' : '
1852
			AND mg.hidden = {int:not_hidden}') . '
1853
		ORDER BY mg.group_name',
1854
		array(
1855
			'current_member' => $id_member,
1856
			'min_posts' => $min_posts,
1857
			'moderator_group' => 3,
1858
			'not_hidden' => 0,
1859
		)
1860
	);
1861
	$groups = array();
1862 View Code Duplication
	while ($row = $db->fetch_assoc($request))
1863
	{
1864
		// Hide hidden groups!
1865
		if ($show_hidden && $row['hidden'] && !$row['can_moderate'])
1866
			continue;
1867
1868
		$groups[$row['id_group']] = $row['group_name'];
1869
	}
1870
1871
	$db->free_result($request);
1872
1873
	return $groups;
1874
}
1875
1876
/**
1877
 * Returns the groups that the current user can see.
1878
 *
1879
 * - uses $user_info and allowedTo().
1880
 * - does not include post count based groups
1881
 *
1882
 * @package Membergroups
1883
 * @return array
1884
 */
1885
function accessibleGroups()
1886
{
1887
	global $user_info;
1888
1889
	$db = database();
1890
1891
	$request = $db->query('', '
1892
		SELECT mg.id_group, mg.group_name, COALESCE(gm.id_member, 0) AS can_moderate, mg.hidden
1893
		FROM {db_prefix}membergroups AS mg
1894
			LEFT JOIN {db_prefix}group_moderators AS gm ON (gm.id_group = mg.id_group AND gm.id_member = {int:current_member})
1895
		WHERE mg.min_posts = {int:min_posts}
1896
			AND mg.id_group != {int:moderator_group}',
1897
		array(
1898
			'current_member' => $user_info['id'],
1899
			'min_posts' => -1,
1900
			'moderator_group' => 3,
1901
		)
1902
	);
1903
	$groups = array();
1904 View Code Duplication
	while ($row = $db->fetch_assoc($request))
1905
	{
1906
		// Hide hidden groups!
1907
		if ($row['hidden'] && !$row['can_moderate'] && !allowedTo('manage_membergroups'))
1908
			continue;
1909
1910
		$groups[$row['id_group']] = $row['group_name'];
1911
	}
1912
1913
	$db->free_result($request);
1914
	asort($groups);
1915
1916
	return $groups;
1917
}
1918
1919
/**
1920
 * Finds the number of group requests in the system
1921
 *
1922
 * - Callback function for createList().
1923
 *
1924
 * @package Membergroups
1925
 * @param string $where
1926
 * @param string $where_parameters
1927
 * @return int the count of group requests
1928
 */
1929
function list_getGroupRequestCount($where, $where_parameters)
1930
{
1931
	$db = database();
1932
1933
	$request = $db->query('', '
1934
		SELECT COUNT(*)
1935
		FROM {db_prefix}log_group_requests AS lgr
1936
		WHERE ' . $where,
1937
		array_merge($where_parameters, array(
1938
		))
1939
	);
1940
	list ($totalRequests) = $db->fetch_row($request);
1941
	$db->free_result($request);
1942
1943
	return $totalRequests;
1944
}
1945
1946
/**
1947
 * Find the details of pending group requests
1948
 *
1949
 * - Callback function for createList()
1950
 *
1951
 * @package Membergroups
1952
 * @param int $start The item to start with (for pagination purposes)
1953
 * @param int $items_per_page  The number of items to show per page
1954
 * @param string $sort A string indicating how to sort the results
1955
 * @param string $where
1956
 * @param string[] $where_parameters
1957
 * @return mixed[] an array of group requests
1958
 * Each group request has:
1959
 *   'id'
1960
 *   'member_link'
1961
 *   'group_link'
1962
 *   'reason'
1963
 *   'time_submitted'
1964
 */
1965
function list_getGroupRequests($start, $items_per_page, $sort, $where, $where_parameters)
1966
{
1967
	global $scripturl;
1968
1969
	$db = database();
1970
1971
	return $db->fetchQueryCallback('
1972
		SELECT lgr.id_request, lgr.id_member, lgr.id_group, lgr.time_applied, lgr.reason,
1973
			mem.member_name, mg.group_name, mg.online_color, mem.real_name
1974
		FROM {db_prefix}log_group_requests AS lgr
1975
			INNER JOIN {db_prefix}members AS mem ON (mem.id_member = lgr.id_member)
1976
			INNER JOIN {db_prefix}membergroups AS mg ON (mg.id_group = lgr.id_group)
1977
		WHERE ' . $where . '
1978
		ORDER BY {raw:sort}
1979
		LIMIT ' . $start . ', ' . $items_per_page,
1980
		array_merge($where_parameters, array(
1981
			'sort' => $sort,
1982
		)),
1983
		function ($row) use ($scripturl)
1984
		{
1985
			return array(
1986
				'id' => $row['id_request'],
1987
				'member_link' => '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>',
1988
				'group_link' => '<span style="color: ' . $row['online_color'] . '">' . $row['group_name'] . '</span>',
1989
				'reason' => censor($row['reason']),
1990
				'time_submitted' => standardTime($row['time_applied']),
1991
			);
1992
		}
1993
	);
1994
}
1995
1996
/**
1997
 * Deletes old group requests.
1998
 *
1999
 * @package Membergroups
2000
 * @param int[] $groups
2001
 */
2002
function deleteGroupRequests($groups)
2003
{
2004
	$db = database();
2005
2006
	// Remove the evidence...
2007
	$db->query('', '
2008
		DELETE FROM {db_prefix}log_group_requests
2009
		WHERE id_request IN ({array_int:request_list})',
2010
		array(
2011
			'request_list' => $groups,
2012
		)
2013
	);
2014
}
2015
2016
/**
2017
 * This function updates those members who match post-based
2018
 * membergroups in the database (restricted by parameter $members).
2019
 *
2020
 * - Used by updateStats('postgroups').
2021
 *
2022
 * @package Membergroups
2023
 * @param int[]|null $members = null The members to update, null if all
2024
 * @param string[]|null $parameter2 = null
2025
 */
2026
function updatePostGroupStats($members = null, $parameter2 = null)
2027
{
2028 9
	$db = database();
2029
2030
	// Parameter two is the updated columns: we should check to see if we base groups off any of these.
2031 9
	if ($parameter2 !== null && !in_array('posts', $parameter2))
2032 9
		return;
2033
2034 6
	$postgroups = Cache::instance()->get('updatePostGroupStats', 360);
2035 6
	if ($postgroups === null || $members === null)
2036 6
	{
2037
		// Fetch the postgroups!
2038 6
		$request = $db->query('', '
2039
			SELECT id_group, min_posts
2040
			FROM {db_prefix}membergroups
2041 6
			WHERE min_posts != {int:min_posts}',
2042
			array(
2043 6
				'min_posts' => -1,
2044
			)
2045 6
		);
2046 6
		$postgroups = array();
2047 6
		while ($row = $db->fetch_assoc($request))
2048 6
			$postgroups[$row['id_group']] = $row['min_posts'];
2049 6
		$db->free_result($request);
2050
2051
		// Sort them this way because if it's done with MySQL it causes a filesort :(.
2052 6
		arsort($postgroups);
2053
2054 6
		Cache::instance()->put('updatePostGroupStats', $postgroups, 360);
2055 6
	}
2056
2057
	// Oh great, they've screwed their post groups.
2058 6
	if (empty($postgroups))
2059 6
		return;
2060
2061
	// Set all membergroups from most posts to least posts.
2062 6
	$conditions = '';
2063 6
	$lastMin = 0;
2064 6
	foreach ($postgroups as $id => $min_posts)
2065
	{
2066
		$conditions .= '
2067 6
				WHEN posts >= ' . $min_posts . (!empty($lastMin) ? ' AND posts <= ' . $lastMin : '') . ' THEN ' . $id;
2068 6
		$lastMin = $min_posts;
2069 6
	}
2070
2071
	// A big fat CASE WHEN... END is faster than a zillion UPDATE's ;).
2072 6
	$db->query('', '
2073
		UPDATE {db_prefix}members
2074 6
		SET id_post_group = CASE ' . $conditions . '
2075
				ELSE 0
2076 6
			END' . ($members !== null ? '
2077 6
		WHERE id_member IN ({array_int:members})' : ''),
2078
		array(
2079 6
			'members' => is_array($members) ? $members : array($members),
2080
		)
2081 6
	);
2082 6
}
2083
2084
/**
2085
 * Get the ids of the groups that are unassignable
2086
 *
2087
 * @param boolean $ignore_protected To ignore protected groups
2088
 * @return int[]
2089
 */
2090
function getUnassignableGroups($ignore_protected)
2091
{
2092 1
	$db = database();
2093
2094 1
	return $db->fetchQueryCallback('
2095
		SELECT id_group
2096
		FROM {db_prefix}membergroups
2097 1
		WHERE min_posts != {int:min_posts}' . ($ignore_protected ? '' : '
2098 1
			OR group_type = {int:is_protected}'),
2099
		array(
2100 1
			'min_posts' => -1,
2101 1
			'is_protected' => 1,
2102 1
		),
2103
		function ($row)
2104
		{
2105 1
			return $row['id_group'];
2106 1
		},
2107 1
		array(-1, 3)
2108 1
	);
2109
}
2110
2111
/**
2112
 * Returns a list of groups that a member can be assigned to
2113
 *
2114
 * @return array
2115
 */
2116
function getGroupsList()
2117
{
2118
	global $txt;
2119
2120
	loadLanguage('Profile');
2121
2122
	$db = database();
2123
	$member_groups = array(
2124
		0 => array(
2125
			'id' => 0,
2126
			'name' => $txt['no_primary_membergroup'],
2127
			'is_primary' => false,
2128
			'can_be_additional' => false,
2129
			'can_be_primary' => true,
2130
		)
2131
	);
2132
2133
	// Load membergroups, but only those groups the user can assign.
2134
	$request = $db->query('', '
2135
		SELECT group_name, id_group, hidden
2136
		FROM {db_prefix}membergroups
2137
		WHERE id_group != {int:moderator_group}
2138
			AND min_posts = {int:min_posts}' . (allowedTo('admin_forum') ? '' : '
2139
			AND group_type != {int:is_protected}') . '
2140
		ORDER BY min_posts, CASE WHEN id_group < {int:newbie_group} THEN id_group ELSE 4 END, group_name',
2141
		array(
2142
			'moderator_group' => 3,
2143
			'min_posts' => -1,
2144
			'is_protected' => 1,
2145
			'newbie_group' => 4,
2146
		)
2147
	);
2148
	while ($row = $db->fetch_assoc($request))
2149
	{
2150
		// We should skip the administrator group if they don't have the admin_forum permission!
2151
		if ($row['id_group'] == 1 && !allowedTo('admin_forum'))
2152
			continue;
2153
2154
		$member_groups[$row['id_group']] = array(
2155
			'id' => $row['id_group'],
2156
			'name' => $row['group_name'],
2157
			'hidden' => $row['hidden'],
2158
			'is_primary' => false,
2159
			'can_be_primary' => $row['hidden'] != 2,
2160
		);
2161
	}
2162
	$db->free_result($request);
2163
2164
	return $member_groups;
2165
}
2166