Completed
Push — development ( ac22bd...5236fa )
by Stephen
14:46
created

Membergroups.subs.php ➔ addMembergroup()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
Code Lines 11

Duplication

Lines 17
Ratio 100 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 11
nc 1
nop 4
dl 17
loc 17
ccs 0
cts 8
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
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
	theme()->getTemplates()->loadLanguageFile('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 6
	global $txt, $modSettings;
1018
1019 6
	$db = database();
1020
1021
	// No $includes parameters given? Let's set some default values
1022 6
	if (empty($includes))
1023 4
		$includes = array('globalmod', 'member', 'postgroups');
1024 6
	elseif (!is_array($includes))
1025
		$includes = array($includes);
1026
1027 6
	$groups = array();
1028
1029 6
	$where = '';
1030 6
	$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 6
	$where .= !empty($modSettings['permission_enable_postgroups']) || in_array('postgroups', $includes) ? '' : 'AND min_posts = {int:min_posts}';
1034
	// Include protected groups?
1035 6
	$where .= allowedTo('admin_forum') || in_array('protected', $includes) ? '' : ' AND group_type != {int:is_protected}';
1036
	// Include the global moderators?
1037 6
	$where .= in_array('globalmod', $includes) ? '' : ' AND id_group != {int:global_mod_group}';
1038
	// Include the admins?
1039 6
	$where .= in_array('admin', $includes) ? '' : ' AND id_group != {int:admin_group}';
1040
	// Local Moderators?
1041 6
	$where .= in_array('mod', $includes) ? '' : ' AND id_group != {int:moderator_group}';
1042
	// Ignore the first post based group?
1043 6
	$where .= !in_array('newbie', $excludes) ? '' : ' AND id_group != {int:newbie_group}';
1044
	// Exclude custom groups?
1045 6
	$where .= !in_array('custom', $excludes) ? '' : ' AND id_group < {int:newbie_group}';
1046
	// Exclude hidden?
1047 6
	$where .= !in_array('hidden', $excludes) ? '' : ' AND hidden != {int:hidden_group}';
1048
1049
	// Only the post based membergroups? We can safely overwrite the $where.
1050 6
	if (in_array('membergroups', $excludes))
1051 4
		$where = ' AND min_posts != {int:min_posts}';
1052
1053
	// Simply all of them?
1054 6
	if (in_array('all', $includes))
1055 4
		$where = '';
1056
1057 6
	$request = $db->query('', '
1058
		SELECT id_group, group_name, min_posts, online_color
1059
		FROM {db_prefix}membergroups
1060
		WHERE 1 = 1
1061 6
			' . $where . '
1062 6
		ORDER BY ' . $sort_order,
1063
		array(
1064 6
			'admin_group' => 1,
1065 4
			'moderator_group' => 3,
1066 4
			'global_mod_group' => 2,
1067 4
			'min_posts' => -1,
1068 4
			'is_protected' => 1,
1069 4
			'newbie_group' => 4,
1070 4
			'hidden_group' => 2,
1071
		)
1072 4
	);
1073
1074
	// Include the default membergroup? the ones with id_member = 0
1075 6
	if (in_array('member', $includes) && !isset($split))
1076 4
	{
1077 6
		$groups[] = array(
1078 6
			'id' => 0,
1079 6
			'name' => $txt['membergroups_members']
1080 4
		);
1081 4
	}
1082
1083 6
	if (!empty($split))
1084 4
	{
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 6
		while ($row = $db->fetch_assoc($request))
1123
		{
1124 6
			$groups[] = array(
1125 6
				'id' => $row['id_group'],
1126 6
				'name' => $row['group_name'],
1127 6
				'online_color' => $row['online_color'],
1128
			);
1129 4
		}
1130
1131 6
	$db->free_result($request);
1132
1133 6
	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
 * @package Membergroups
1208
 * @param string $groupname
1209
 * @param int $minposts
1210
 * @param string $type
1211
 */
1212
function createMembergroup($groupname, $minposts, $type)
1213
{
1214
	$db = database();
1215
1216
	$db->insert('',
1217
		'{db_prefix}membergroups',
1218
		array(
1219
			'description' => 'string', 'group_name' => 'string-80', 'min_posts' => 'int',
1220
			'icons' => 'string', 'online_color' => 'string', 'group_type' => 'int',
1221
		),
1222
		array(
1223
			'', Util::htmlspecialchars($groupname, ENT_QUOTES), $minposts,
1224
			'1#icon.png', '', $type,
1225
		),
1226
		array('id_group')
1227
	);
1228
1229
	return $db->insert_id('{db_prefix}membergroups');
1230
}
1231
1232
/**
1233
 * Copies permissions from a given membergroup.
1234
 *
1235
 * @package Membergroups
1236
 * @param int $id_group
1237
 * @param int $copy_from
1238
 * @param string[]|null $illegal_permissions
1239
 * @todo another function with the same name in ManagePermissions.subs.php
1240
 */
1241
function copyPermissions($id_group, $copy_from, $illegal_permissions)
1242
{
1243
	$db = database();
1244
1245
	$inserts = array();
1246
1247
	$request = $db->query('', '
1248
		SELECT permission, add_deny
1249
		FROM {db_prefix}permissions
1250
		WHERE id_group = {int:copy_from}',
1251
		array(
1252
			'copy_from' => $copy_from,
1253
		)
1254
	);
1255
1256
	while ($row = $db->fetch_assoc($request))
1257
	{
1258
		if (empty($illegal_permissions) || !in_array($row['permission'], $illegal_permissions))
1259
			$inserts[] = array($id_group, $row['permission'], $row['add_deny']);
1260
	}
1261
	$db->free_result($request);
1262
1263
	if (!empty($inserts))
1264
		$db->insert('insert',
1265
			'{db_prefix}permissions',
1266
			array('id_group' => 'int', 'permission' => 'string', 'add_deny' => 'int'),
1267
			$inserts,
1268
			array('id_group', 'permission')
1269
		);
1270
}
1271
1272
/**
1273
 * Copies the board permissions from a given membergroup.
1274
 *
1275
 * @package Membergroups
1276
 * @param int $id_group
1277
 * @param int $copy_from
1278
 */
1279
function copyBoardPermissions($id_group, $copy_from)
1280
{
1281
	$db = database();
1282
1283
	$inserts = $db->fetchQueryCallback('
1284
		SELECT id_profile, permission, add_deny
1285
		FROM {db_prefix}board_permissions
1286
		WHERE id_group = {int:copy_from}',
1287
		array(
1288
			'copy_from' => $copy_from,
1289
		),
1290
		function ($row) use ($id_group)
1291
		{
1292
			return array($id_group, $row['id_profile'], $row['permission'], $row['add_deny']);
1293
		}
1294
	);
1295
1296 View Code Duplication
	if (!empty($inserts))
1297
	{
1298
		$db->insert('insert',
1299
			'{db_prefix}board_permissions',
1300
			array('id_group' => 'int', 'id_profile' => 'int', 'permission' => 'string', 'add_deny' => 'int'),
1301
			$inserts,
1302
			array('id_group', 'id_profile', 'permission')
1303
		);
1304
	}
1305
}
1306
1307
/**
1308
 * Updates the properties of a copied membergroup.
1309
 *
1310
 * @package Membergroups
1311
 * @param int $id_group
1312
 * @param int $copy_from
1313
 */
1314
function updateCopiedGroup($id_group, $copy_from)
1315
{
1316
	$db = database();
1317
1318
	require_once(SUBSDIR . '/Membergroups.subs.php');
1319
	$group_info = membergroupById($copy_from, true);
1320
1321
	// update the new membergroup
1322
	$db->query('', '
1323
		UPDATE {db_prefix}membergroups
1324
		SET
1325
			online_color = {string:online_color},
1326
			max_messages = {int:max_messages},
1327
			icons = {string:icons}
1328
			WHERE id_group = {int:current_group}',
1329
			array(
1330
				'max_messages' => $group_info['max_messages'],
1331
				'current_group' => $id_group,
1332
				'online_color' => $group_info['online_color'],
1333
				'icons' => $group_info['icons'],
1334
			)
1335
	);
1336
}
1337
1338
/**
1339
 * Updates the properties of a inherited membergroup.
1340
 *
1341
 * @package Membergroups
1342
 * @param int $id_group
1343
 * @param int $copy_id
1344
 */
1345
function updateInheritedGroup($id_group, $copy_id)
1346
{
1347
	$db = database();
1348
1349
	$db->query('', '
1350
		UPDATE {db_prefix}membergroups
1351
		SET id_parent = {int:copy_from}
1352
		WHERE id_group = {int:current_group}',
1353
		array(
1354
			'copy_from' => $copy_id,
1355
			'current_group' => $id_group,
1356
		)
1357
	);
1358
}
1359
1360
/**
1361
 * This function updates the membergroup with the given information.
1362
 *
1363
 * - It's passed an associative array $properties, with 'current_group' holding
1364
 * the group to update. The rest of the keys are details to update it with.
1365
 *
1366
 * @package Membergroups
1367
 * @param mixed[] $properties
1368
 */
1369
function updateMembergroupProperties($properties)
1370
{
1371
	$db = database();
1372
1373
	$known_properties = array(
1374
		'max_messages' => array('type' => 'int'),
1375
		'min_posts' => array('type' => 'int'),
1376
		'group_type' => array('type' => 'int'),
1377
		'hidden' => array('type' => 'int'),
1378
		'id_parent' => array('type' => 'int'),
1379
		'group_name' => array('type' => 'string'),
1380
		'online_color' => array('type' => 'string'),
1381
		'icons' => array('type' => 'string'),
1382
		'description' => array('type' => 'string'),
1383
	);
1384
1385
	$values = array('current_group' => $properties['current_group']);
1386
	$updates = array();
1387
	foreach ($properties as $name => $value)
1388
	{
1389
		if (isset($known_properties[$name]))
1390
		{
1391
			$updates[] = $name . '={' . $known_properties[$name]['type'] . ':subs_' . $name . '}';
1392
			switch ($known_properties[$name]['type'])
1393
			{
1394
				case 'string':
1395
					$values['subs_' . $name] = Util::htmlspecialchars((string) $value);
1396
					break;
1397
				default:
1398
					$values['subs_' . $name] = (int) $value;
1399
			}
1400
		}
1401
	}
1402
1403
	if (empty($values))
1404
		return;
1405
1406
	$db->query('', '
1407
		UPDATE {db_prefix}membergroups
1408
		SET ' . implode(', ', $updates) . '
1409
		WHERE id_group = {int:current_group}',
1410
		$values
1411
	);
1412
}
1413
1414
/**
1415
 * Detaches a membergroup from the boards listed in $boards.
1416
 *
1417
 * @package Membergroups
1418
 * @param int $id_group
1419
 * @param mixed[] $boards
1420
 * @param string $access_list ('allow', 'deny')
1421
 */
1422
function detachGroupFromBoards($id_group, $boards, $access_list)
1423
{
1424
	$db = database();
1425
1426
	// Find all boards in whose access list this group is in, but shouldn't be.
1427
	$db->fetchQueryCallback('
1428
		SELECT id_board, {raw:column}
1429
		FROM {db_prefix}boards
1430
		WHERE FIND_IN_SET({string:current_group}, {raw:column}) != 0' . (empty($boards[$access_list]) ? '' : '
1431
			AND id_board NOT IN ({array_int:board_access_list})'),
1432
		array(
1433
			'current_group' => $id_group,
1434
			'board_access_list' => $boards[$access_list],
1435
			'column' => $access_list == 'allow' ? 'member_groups' : 'deny_member_groups',
1436
		),
1437
		function ($row) use ($id_group, $access_list, $db)
1438
		{
1439
			$db->query('', '
1440
				UPDATE {db_prefix}boards
1441
				SET {raw:column} = {string:member_group_access}
1442
				WHERE id_board = {int:current_board}',
1443
				array(
1444
					'current_board' => $row['id_board'],
1445
					'member_group_access' => implode(',', array_diff(explode(',', $row['member_groups']), array($id_group))),
1446
					'column' => $access_list == 'allow' ? 'member_groups' : 'deny_member_groups',
1447
				)
1448
			);
1449
		}
1450
	);
1451
}
1452
1453
/**
1454
 * Assigns the given group $id_group to the boards specified, for
1455
 * the 'allow' or 'deny' list.
1456
 *
1457
 * @package Membergroups
1458
 * @param int $id_group
1459
 * @param mixed[] $boards
1460
 * @param string $access_list ('allow', 'deny')
1461
 */
1462
function assignGroupToBoards($id_group, $boards, $access_list)
1463
{
1464
	$db = database();
1465
1466
	$db->query('', '
1467
		UPDATE {db_prefix}boards
1468
		SET {raw:column} = CASE WHEN {raw:column} = {string:blank_string} THEN {string:group_id_string} ELSE CONCAT({raw:column}, {string:comma_group}) END
1469
		WHERE id_board IN ({array_int:board_list})
1470
			AND FIND_IN_SET({int:current_group}, {raw:column}) = 0',
1471
		array(
1472
			'board_list' => $boards[$access_list],
1473
			'blank_string' => '',
1474
			'current_group' => $id_group,
1475
			'group_id_string' => (string) $id_group,
1476
			'comma_group' => ',' . $id_group,
1477
			'column' => $access_list == 'allow' ? 'member_groups' : 'deny_member_groups',
1478
		)
1479
	);
1480
}
1481
1482
/**
1483
 * Membergroup was deleted? We need to detach that group from our members, too...
1484
 *
1485
 * @package Membergroups
1486
 * @param int $id_group
1487
 */
1488 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...
1489
{
1490
	$db = database();
1491
1492
	$updates = array();
1493
1494
	$db->query('', '
1495
		UPDATE {db_prefix}members
1496
		SET id_group = {int:regular_member}
1497
		WHERE id_group = {int:current_group}',
1498
		array(
1499
			'regular_member' => 0,
1500
			'current_group' => $id_group,
1501
		)
1502
	);
1503
1504
	$request = $db->query('', '
1505
		SELECT id_member, additional_groups
1506
		FROM {db_prefix}members
1507
		WHERE FIND_IN_SET({string:current_group}, additional_groups) != 0',
1508
		array(
1509
			'current_group' => $id_group,
1510
		)
1511
	);
1512
1513
	while ($row = $db->fetch_assoc($request))
1514
		$updates[$row['additional_groups']][] = $row['id_member'];
1515
	$db->free_result($request);
1516
1517
	require_once(SUBSDIR . '/Members.subs.php');
1518
	foreach ($updates as $additional_groups => $memberArray)
1519
		updateMemberData($memberArray, array('additional_groups' => implode(',', array_diff(explode(',', $additional_groups), array($id_group)))));
1520
1521
}
1522
1523
/**
1524
 * Make the given group hidden. Hidden groups are stored in the additional_groups.
1525
 *
1526
 * @package Membergroups
1527
 * @param int $id_group
1528
 */
1529 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...
1530
{
1531
	$db = database();
1532
1533
	$updates = array();
1534
1535
	$request = $db->query('', '
1536
		SELECT id_member, additional_groups
1537
		FROM {db_prefix}members
1538
		WHERE id_group = {int:current_group}
1539
			AND FIND_IN_SET({int:current_group}, additional_groups) = 0',
1540
		array(
1541
			'current_group' => $id_group,
1542
		)
1543
	);
1544
1545
	while ($row = $db->fetch_assoc($request))
1546
		$updates[$row['additional_groups']][] = $row['id_member'];
1547
	$db->free_result($request);
1548
1549
	require_once(SUBSDIR . '/Members.subs.php');
1550
	foreach ($updates as $additional_groups => $memberArray)
1551
		updateMemberData($memberArray, array('additional_groups' => implode(',', array_merge(explode(',', $additional_groups), array($id_group)))));
1552
1553
	$db->query('', '
1554
		UPDATE {db_prefix}members
1555
		SET id_group = {int:regular_member}
1556
		WHERE id_group = {int:current_group}',
1557
		array(
1558
			'regular_member' => 0,
1559
			'current_group' => $id_group,
1560
		)
1561
	);
1562
}
1563
1564
/**
1565
 * Make sure the setting to display membergroup key on the board index is valid.
1566
 * It updates the setting if necessary.
1567
 *
1568
 * @package Membergroups
1569
 */
1570
function validateShowGroupMembership()
1571
{
1572
	global $modSettings;
1573
1574
	$db = database();
1575
1576
	$request = $db->query('', '
1577
		SELECT COUNT(*)
1578
		FROM {db_prefix}membergroups
1579
		WHERE group_type > {int:non_joinable}',
1580
		array(
1581
			'non_joinable' => 1,
1582
		)
1583
	);
1584
	list ($have_joinable) = $db->fetch_row($request);
1585
	$db->free_result($request);
1586
1587
	// Do we need to update the setting?
1588
	if ((empty($modSettings['show_group_membership']) && $have_joinable) || (!empty($modSettings['show_group_membership']) && !$have_joinable))
1589
		updateSettings(array('show_group_membership' => $have_joinable ? 1 : 0));
1590
}
1591
1592
/**
1593
 * Detaches group moderators from a deleted group.
1594
 *
1595
 * @package Membergroups
1596
 * @param int $id_group
1597
 */
1598
function detachGroupModerators($id_group)
1599
{
1600
	$db = database();
1601
1602
	$db->query('', '
1603
		DELETE FROM {db_prefix}group_moderators
1604
		WHERE id_group = {int:current_group}',
1605
		array(
1606
			'current_group' => $id_group,
1607
		)
1608
	);
1609
}
1610
1611
/**
1612
 * Get the id_member from the membergroup moderators.
1613
 *
1614
 * @package Membergroups
1615
 * @param string[] $moderators
1616
 *
1617
 * @return int[]
1618
 */
1619
function getIDMemberFromGroupModerators($moderators)
1620
{
1621
	$db = database();
1622
1623
	return $db->fetchQueryCallback('
1624
		SELECT id_member
1625
		FROM {db_prefix}members
1626
		WHERE member_name IN ({array_string:moderators}) OR real_name IN ({array_string:moderators})
1627
		LIMIT ' . count($moderators),
1628
		array(
1629
			'moderators' => $moderators,
1630
		),
1631
		function ($row)
1632
		{
1633
			return $row['id_member'];
1634
		}
1635
	);
1636
}
1637
1638
/**
1639
 * Assign members to the membergroup moderators.
1640
 *
1641
 * @package Membergroups
1642
 * @param int $id_group
1643
 * @param int[] $group_moderators
1644
 */
1645
function assignGroupModerators($id_group, $group_moderators)
1646
{
1647
	$db = database();
1648
1649
	$mod_insert = array();
1650
		foreach ($group_moderators as $moderator)
1651
			$mod_insert[] = array($id_group, $moderator);
1652
1653
		$db->insert('insert',
1654
			'{db_prefix}group_moderators',
1655
			array('id_group' => 'int', 'id_member' => 'int'),
1656
			$mod_insert,
1657
			array('id_group', 'id_member')
1658
		);
1659
}
1660
1661
/**
1662
 * List moderators from a given membergroup.
1663
 *
1664
 * @package Membergroups
1665
 * @param int $id_group
1666
 * @return array moderators as array(id => name)
1667
 */
1668
function getGroupModerators($id_group)
1669
{
1670
	$db = database();
1671
1672
	$moderators = array();
1673
1674
	$request = $db->query('', '
1675
		SELECT mem.id_member, mem.real_name
1676
		FROM {db_prefix}group_moderators AS mods
1677
			INNER JOIN {db_prefix}members AS mem ON (mem.id_member = mods.id_member)
1678
		WHERE mods.id_group = {int:current_group}',
1679
		array(
1680
			'current_group' => $id_group,
1681
		)
1682
	);
1683
	while ($row = $db->fetch_assoc($request))
1684
		$moderators[$row['id_member']] = $row['real_name'];
1685
	$db->free_result($request);
1686
1687
	return $moderators;
1688
}
1689
1690
/**
1691
 * Lists all groups which inherit permission profiles from the given group.
1692
 *
1693
 * - If no group is specified it will list any group that can be used
1694
 *
1695
 * @package Membergroups
1696
 * @param int|bool $id_group
1697
 * @return array
1698
 */
1699
function getInheritableGroups($id_group = false)
1700
{
1701
	global $modSettings;
1702
1703
	$db = database();
1704
1705
	$inheritable_groups = array();
1706
1707
	$request = $db->query('', '
1708
		SELECT id_group, group_name
1709
		FROM {db_prefix}membergroups
1710
		WHERE id_parent = {int:not_inherited}' . ($id_group === false ? '' : '
1711
			AND id_group != {int:current_group}') .
1712
			(empty($modSettings['permission_enable_postgroups']) ? '
1713
			AND min_posts = {int:min_posts}' : '') . (allowedTo('admin_forum') ? '' : '
1714
			AND group_type != {int:is_protected}') . '
1715
			AND id_group NOT IN (1, 3)',
1716
		array(
1717
			'current_group' => $id_group,
1718
			'min_posts' => -1,
1719
			'not_inherited' => -2,
1720
			'is_protected' => 1,
1721
		)
1722
	);
1723
1724
	while ($row = $db->fetch_assoc($request))
1725
		$inheritable_groups[$row['id_group']] = $row['group_name'];
1726
	$db->free_result($request);
1727
1728
	return $inheritable_groups;
1729
}
1730
1731
/**
1732
 * List all membergroups and prepares them to assign permissions to..
1733
 *
1734
 * @package Membergroups
1735
 * @return array
1736
 */
1737
function prepareMembergroupPermissions()
1738
{
1739
	global $modSettings, $txt;
1740
1741
	$db = database();
1742
1743
	// Start this with the guests/members.
1744
	$profile_groups = array(
1745
		-1 => array(
1746
			'id' => -1,
1747
			'name' => $txt['membergroups_guests'],
1748
			'color' => '',
1749
			'new_topic' => 'disallow',
1750
			'replies_own' => 'disallow',
1751
			'replies_any' => 'disallow',
1752
			'attachment' => 'disallow',
1753
			'children' => array(),
1754
		),
1755
		0 => array(
1756
			'id' => 0,
1757
			'name' => $txt['membergroups_members'],
1758
			'color' => '',
1759
			'new_topic' => 'disallow',
1760
			'replies_own' => 'disallow',
1761
			'replies_any' => 'disallow',
1762
			'attachment' => 'disallow',
1763
			'children' => array(),
1764
		),
1765
	);
1766
1767
	$request = $db->query('', '
1768
		SELECT id_group, group_name, online_color, id_parent
1769
		FROM {db_prefix}membergroups
1770
		WHERE id_group != {int:admin_group}
1771
			' . (empty($modSettings['permission_enable_postgroups']) ? ' AND min_posts = {int:min_posts}' : '') . '
1772
		ORDER BY id_parent ASC',
1773
		array(
1774
			'admin_group' => 1,
1775
			'min_posts' => -1,
1776
		)
1777
	);
1778
	while ($row = $db->fetch_assoc($request))
1779
	{
1780
		if ($row['id_parent'] == -2)
1781
		{
1782
			$profile_groups[$row['id_group']] = array(
1783
				'id' => $row['id_group'],
1784
				'name' => $row['group_name'],
1785
				'color' => $row['online_color'],
1786
				'new_topic' => 'disallow',
1787
				'replies_own' => 'disallow',
1788
				'replies_any' => 'disallow',
1789
				'attachment' => 'disallow',
1790
				'children' => array(),
1791
			);
1792
		}
1793
		elseif (isset($profile_groups[$row['id_parent']]))
1794
			$profile_groups[$row['id_parent']]['children'][] = $row['group_name'];
1795
	}
1796
	$db->free_result($request);
1797
1798
	return $profile_groups;
1799
}
1800
1801
/**
1802
 * Returns the groups that a user could see.
1803
 *
1804
 * - Ask and it will give you.
1805
 *
1806
 * @package Membergroups
1807
 * @param int $id_member the id of a member
1808
 * @param bool $show_hidden true if hidden groups (that the user can moderate) should be loaded (default false)
1809
 * @param int $min_posts minimum number of posts for the group (-1 for non-post based groups)
1810
 *
1811
 * @return array
1812
 */
1813
function loadGroups($id_member, $show_hidden = false, $min_posts = -1)
1814
{
1815
	$db = database();
1816
1817
	$request = $db->query('', '
1818
		SELECT mg.id_group, mg.group_name, COALESCE(gm.id_member, 0) AS can_moderate, mg.hidden
1819
		FROM {db_prefix}membergroups AS mg
1820
			LEFT JOIN {db_prefix}group_moderators AS gm ON (gm.id_group = mg.id_group AND gm.id_member = {int:current_member})
1821
		WHERE mg.min_posts = {int:min_posts}
1822
			AND mg.id_group != {int:moderator_group}' . ($show_hidden ? '' : '
1823
			AND mg.hidden = {int:not_hidden}') . '
1824
		ORDER BY mg.group_name',
1825
		array(
1826
			'current_member' => $id_member,
1827
			'min_posts' => $min_posts,
1828
			'moderator_group' => 3,
1829
			'not_hidden' => 0,
1830
		)
1831
	);
1832
	$groups = array();
1833 View Code Duplication
	while ($row = $db->fetch_assoc($request))
1834
	{
1835
		// Hide hidden groups!
1836
		if ($show_hidden && $row['hidden'] && !$row['can_moderate'])
1837
			continue;
1838
1839
		$groups[$row['id_group']] = $row['group_name'];
1840
	}
1841
1842
	$db->free_result($request);
1843
1844
	return $groups;
1845
}
1846
1847
/**
1848
 * Returns the groups that the current user can see.
1849
 *
1850
 * - uses $user_info and allowedTo().
1851
 * - does not include post count based groups
1852
 *
1853
 * @package Membergroups
1854
 * @return array
1855
 */
1856
function accessibleGroups()
1857
{
1858
	global $user_info;
1859
1860
	$db = database();
1861
1862
	$request = $db->query('', '
1863
		SELECT mg.id_group, mg.group_name, COALESCE(gm.id_member, 0) AS can_moderate, mg.hidden
1864
		FROM {db_prefix}membergroups AS mg
1865
			LEFT JOIN {db_prefix}group_moderators AS gm ON (gm.id_group = mg.id_group AND gm.id_member = {int:current_member})
1866
		WHERE mg.min_posts = {int:min_posts}
1867
			AND mg.id_group != {int:moderator_group}',
1868
		array(
1869
			'current_member' => $user_info['id'],
1870
			'min_posts' => -1,
1871
			'moderator_group' => 3,
1872
		)
1873
	);
1874
	$groups = array();
1875 View Code Duplication
	while ($row = $db->fetch_assoc($request))
1876
	{
1877
		// Hide hidden groups!
1878
		if ($row['hidden'] && !$row['can_moderate'] && !allowedTo('manage_membergroups'))
1879
			continue;
1880
1881
		$groups[$row['id_group']] = $row['group_name'];
1882
	}
1883
1884
	$db->free_result($request);
1885
	asort($groups);
1886
1887
	return $groups;
1888
}
1889
1890
/**
1891
 * Finds the number of group requests in the system
1892
 *
1893
 * - Callback function for createList().
1894
 *
1895
 * @package Membergroups
1896
 * @param string $where
1897
 * @param string $where_parameters
1898
 * @return int the count of group requests
1899
 */
1900
function list_getGroupRequestCount($where, $where_parameters)
1901
{
1902
	$db = database();
1903
1904
	$request = $db->query('', '
1905
		SELECT COUNT(*)
1906
		FROM {db_prefix}log_group_requests AS lgr
1907
		WHERE ' . $where,
1908
		array_merge($where_parameters, array(
1909
		))
1910
	);
1911
	list ($totalRequests) = $db->fetch_row($request);
1912
	$db->free_result($request);
1913
1914
	return $totalRequests;
1915
}
1916
1917
/**
1918
 * Find the details of pending group requests
1919
 *
1920
 * - Callback function for createList()
1921
 *
1922
 * @package Membergroups
1923
 * @param int $start The item to start with (for pagination purposes)
1924
 * @param int $items_per_page  The number of items to show per page
1925
 * @param string $sort A string indicating how to sort the results
1926
 * @param string $where
1927
 * @param string[] $where_parameters
1928
 * @return mixed[] an array of group requests
1929
 * Each group request has:
1930
 *   'id'
1931
 *   'member_link'
1932
 *   'group_link'
1933
 *   'reason'
1934
 *   'time_submitted'
1935
 */
1936
function list_getGroupRequests($start, $items_per_page, $sort, $where, $where_parameters)
1937
{
1938
	global $scripturl;
1939
1940
	$db = database();
1941
1942
	return $db->fetchQueryCallback('
1943
		SELECT lgr.id_request, lgr.id_member, lgr.id_group, lgr.time_applied, lgr.reason,
1944
			mem.member_name, mg.group_name, mg.online_color, mem.real_name
1945
		FROM {db_prefix}log_group_requests AS lgr
1946
			INNER JOIN {db_prefix}members AS mem ON (mem.id_member = lgr.id_member)
1947
			INNER JOIN {db_prefix}membergroups AS mg ON (mg.id_group = lgr.id_group)
1948
		WHERE ' . $where . '
1949
		ORDER BY {raw:sort}
1950
		LIMIT ' . $start . ', ' . $items_per_page,
1951
		array_merge($where_parameters, array(
1952
			'sort' => $sort,
1953
		)),
1954
		function ($row) use ($scripturl)
1955
		{
1956
			return array(
1957
				'id' => $row['id_request'],
1958
				'member_link' => '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>',
1959
				'group_link' => '<span style="color: ' . $row['online_color'] . '">' . $row['group_name'] . '</span>',
1960
				'reason' => censor($row['reason']),
1961
				'time_submitted' => standardTime($row['time_applied']),
1962
			);
1963
		}
1964
	);
1965
}
1966
1967
/**
1968
 * Deletes old group requests.
1969
 *
1970
 * @package Membergroups
1971
 * @param int[] $groups
1972
 */
1973
function deleteGroupRequests($groups)
1974
{
1975
	$db = database();
1976
1977
	// Remove the evidence...
1978
	$db->query('', '
1979
		DELETE FROM {db_prefix}log_group_requests
1980
		WHERE id_request IN ({array_int:request_list})',
1981
		array(
1982
			'request_list' => $groups,
1983
		)
1984
	);
1985
}
1986
1987
/**
1988
 * This function updates those members who match post-based
1989
 * membergroups in the database (restricted by parameter $members).
1990
 *
1991
 * @package Membergroups
1992
 * @param int[]|null $members = null The members to update, null if all
1993
 * @param string[]|null $parameter2 = null
1994
 */
1995
function updatePostGroupStats($members = null, $parameter2 = null)
1996
{
1997
	$db = database();
1998 54
1999
	// Parameter two is the updated columns: we should check to see if we base groups off any of these.
2000
	if ($parameter2 !== null && !in_array('posts', $parameter2))
2001 54
		return;
2002 44
2003
	$postgroups = Cache::instance()->get('updatePostGroupStats', 360);
2004 36
	if ($postgroups === null || $members === null)
2005 36
	{
2006 24
		// Fetch the postgroups!
2007
		$request = $db->query('', '
2008 36
			SELECT id_group, min_posts
2009
			FROM {db_prefix}membergroups
2010
			WHERE min_posts != {int:min_posts}',
2011 24
			array(
2012
				'min_posts' => -1,
2013 36
			)
2014
		);
2015 24
		$postgroups = array();
2016 36
		while ($row = $db->fetch_assoc($request))
2017 36
			$postgroups[$row['id_group']] = $row['min_posts'];
2018 36
		$db->free_result($request);
2019 36
2020
		// Sort them this way because if it's done with MySQL it causes a filesort :(.
2021
		arsort($postgroups);
2022 36
2023
		Cache::instance()->put('updatePostGroupStats', $postgroups, 360);
2024 36
	}
2025 24
2026
	// Oh great, they've screwed their post groups.
2027
	if (empty($postgroups))
2028 36
		return;
2029 24
2030
	// Set all membergroups from most posts to least posts.
2031
	$conditions = '';
2032 36
	$lastMin = 0;
2033 36
	foreach ($postgroups as $id => $min_posts)
2034 36
	{
2035
		$conditions .= '
2036
				WHEN posts >= ' . $min_posts . (!empty($lastMin) ? ' AND posts <= ' . $lastMin : '') . ' THEN ' . $id;
2037 36
		$lastMin = $min_posts;
2038 36
	}
2039 24
2040
	// A big fat CASE WHEN... END is faster than a zillion UPDATE's ;).
2041
	$db->query('', '
2042 36
		UPDATE {db_prefix}members
2043
		SET id_post_group = CASE ' . $conditions . '
2044 36
				ELSE 0
2045
			END' . ($members !== null ? '
2046 36
		WHERE id_member IN ({array_int:members})' : ''),
2047 36
		array(
2048
			'members' => is_array($members) ? $members : array($members),
2049 36
		)
2050
	);
2051 24
}
2052 36
2053
/**
2054
 * Get the ids of the groups that are unassignable
2055
 *
2056
 * @param boolean $ignore_protected To ignore protected groups
2057
 * @return int[]
2058
 */
2059
function getUnassignableGroups($ignore_protected)
2060
{
2061
	$db = database();
2062 7
2063
	return $db->fetchQueryCallback('
2064 7
		SELECT id_group
2065
		FROM {db_prefix}membergroups
2066
		WHERE min_posts != {int:min_posts}' . ($ignore_protected ? '' : '
2067 7
			OR group_type = {int:is_protected}'),
2068 5
		array(
2069
			'min_posts' => -1,
2070 7
			'is_protected' => 1,
2071 5
		),
2072 5
		function ($row)
2073
		{
2074
			return $row['id_group'];
2075 7
		},
2076 7
		array(-1, 3)
2077 7
	);
2078 5
}
2079
2080
/**
2081
 * Returns a list of groups that a member can be assigned to
2082
 *
2083
 * @return array
2084
 */
2085
function getGroupsList()
2086
{
2087
	global $txt;
2088
2089
	theme()->getTemplates()->loadLanguageFile('Profile');
2090
2091
	$db = database();
2092
	$member_groups = array(
2093
		0 => array(
2094
			'id' => 0,
2095
			'name' => $txt['no_primary_membergroup'],
2096
			'is_primary' => false,
2097
			'can_be_additional' => false,
2098
			'can_be_primary' => true,
2099
		)
2100
	);
2101
2102
	// Load membergroups, but only those groups the user can assign.
2103
	$request = $db->query('', '
2104
		SELECT group_name, id_group, hidden
2105
		FROM {db_prefix}membergroups
2106
		WHERE id_group != {int:moderator_group}
2107
			AND min_posts = {int:min_posts}' . (allowedTo('admin_forum') ? '' : '
2108
			AND group_type != {int:is_protected}') . '
2109
		ORDER BY min_posts, CASE WHEN id_group < {int:newbie_group} THEN id_group ELSE 4 END, group_name',
2110
		array(
2111
			'moderator_group' => 3,
2112
			'min_posts' => -1,
2113
			'is_protected' => 1,
2114
			'newbie_group' => 4,
2115
		)
2116
	);
2117
	while ($row = $db->fetch_assoc($request))
2118
	{
2119
		// We should skip the administrator group if they don't have the admin_forum permission!
2120
		if ($row['id_group'] == 1 && !allowedTo('admin_forum'))
2121
			continue;
2122
2123
		$member_groups[$row['id_group']] = array(
2124
			'id' => $row['id_group'],
2125
			'name' => $row['group_name'],
2126
			'hidden' => $row['hidden'],
2127
			'is_primary' => false,
2128
			'can_be_primary' => $row['hidden'] != 2,
2129
		);
2130
	}
2131
	$db->free_result($request);
2132
2133
	return $member_groups;
2134
}
2135