Completed
Push — release-2.1 ( 5876a2...f30e04 )
by Mert
06:50
created

ManagePermissions.php ➔ SetQuickGroups()   F

Complexity

Conditions 60
Paths 2752

Size

Total Lines 257
Code Lines 134

Duplication

Lines 16
Ratio 6.23 %
Metric Value
cc 60
eloc 134
nc 2752
nop 0
dl 16
loc 257
rs 2

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * ManagePermissions handles all possible permission stuff.
5
 *
6
 * Simple Machines Forum (SMF)
7
 *
8
 * @package SMF
9
 * @author Simple Machines http://www.simplemachines.org
10
 * @copyright 2016 Simple Machines and individual contributors
11
 * @license http://www.simplemachines.org/about/smf/license.php BSD
12
 *
13
 * @version 2.1 Beta 3
14
 */
15
16
if (!defined('SMF'))
17
	die('No direct access...');
18
19
/**
20
 * Dispatches to the right function based on the given subaction.
21
 * Checks the permissions, based on the sub-action.
22
 * Called by ?action=managepermissions.
23
 *
24
 * @uses ManagePermissions language file.
25
 */
26
27
function ModifyPermissions()
28
{
29
	global $txt, $context;
30
31
	loadLanguage('ManagePermissions+ManageMembers');
32
	loadTemplate('ManagePermissions');
33
34
	// Format: 'sub-action' => array('function_to_call', 'permission_needed'),
35
	$subActions = array(
36
		'board' => array('PermissionByBoard', 'manage_permissions'),
37
		'index' => array('PermissionIndex', 'manage_permissions'),
38
		'modify' => array('ModifyMembergroup', 'manage_permissions'),
39
		'modify2' => array('ModifyMembergroup2', 'manage_permissions'),
40
		'quick' => array('SetQuickGroups', 'manage_permissions'),
41
		'quickboard' => array('SetQuickBoards', 'manage_permissions'),
42
		'postmod' => array('ModifyPostModeration', 'manage_permissions'),
43
		'profiles' => array('EditPermissionProfiles', 'manage_permissions'),
44
		'settings' => array('GeneralPermissionSettings', 'admin_forum'),
45
	);
46
47
	$_REQUEST['sa'] = isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) && empty($subActions[$_REQUEST['sa']]['disabled']) ? $_REQUEST['sa'] : (allowedTo('manage_permissions') ? 'index' : 'settings');
48
	isAllowedTo($subActions[$_REQUEST['sa']][1]);
49
50
	// Create the tabs for the template.
51
	$context[$context['admin_menu_name']]['tab_data'] = array(
52
		'title' => $txt['permissions_title'],
53
		'help' => 'permissions',
54
		'description' => '',
55
		'tabs' => array(
56
			'index' => array(
57
				'description' => $txt['permissions_groups'],
58
			),
59
			'board' => array(
60
				'description' => $txt['permission_by_board_desc'],
61
			),
62
			'profiles' => array(
63
				'description' => $txt['permissions_profiles_desc'],
64
			),
65
			'postmod' => array(
66
				'description' => $txt['permissions_post_moderation_desc'],
67
			),
68
			'settings' => array(
69
				'description' => $txt['permission_settings_desc'],
70
			),
71
		),
72
	);
73
74
	call_integration_hook('integrate_manage_permissions', array(&$subActions));
75
76
	call_helper($subActions[$_REQUEST['sa']][0]);
77
}
78
79
/**
80
 * Sets up the permissions by membergroup index page.
81
 * Called by ?action=managepermissions
82
 * Creates an array of all the groups with the number of members and permissions.
83
 *
84
 * @uses ManagePermissions language file.
85
 * @uses ManagePermissions template file.
86
 * @uses ManageBoards template, permission_index sub-template.
87
 */
88
function PermissionIndex()
89
{
90
	global $txt, $scripturl, $context, $settings, $modSettings, $smcFunc;
91
92
	$context['page_title'] = $txt['permissions_title'];
93
94
	// Load all the permissions. We'll need them in the template.
95
	loadAllPermissions();
96
97
	// Also load profiles, we may want to reset.
98
	loadPermissionProfiles();
99
100
	// Are we going to show the advanced options?
101
	$context['show_advanced_options'] = empty($context['admin_preferences']['app']);
102
103
	// Determine the number of ungrouped members.
104
	$request = $smcFunc['db_query']('', '
105
		SELECT COUNT(*)
106
		FROM {db_prefix}members
107
		WHERE id_group = {int:regular_group}',
108
		array(
109
			'regular_group' => 0,
110
		)
111
	);
112
	list ($num_members) = $smcFunc['db_fetch_row']($request);
113
	$smcFunc['db_free_result']($request);
114
115
	// Fill the context variable with 'Guests' and 'Regular Members'.
116
	$context['groups'] = array(
117
		-1 => array(
118
			'id' => -1,
119
			'name' => $txt['membergroups_guests'],
120
			'num_members' => $txt['membergroups_guests_na'],
121
			'allow_delete' => false,
122
			'allow_modify' => true,
123
			'can_search' => false,
124
			'href' => '',
125
			'link' => '',
126
			'help' => 'membergroup_guests',
127
			'is_post_group' => false,
128
			'color' => '',
129
			'icons' => '',
130
			'children' => array(),
131
			'num_permissions' => array(
132
				'allowed' => 0,
133
				// Can't deny guest permissions!
134
				'denied' => '(' . $txt['permissions_none'] . ')'
135
			),
136
			'access' => false
137
		),
138
		0 => array(
139
			'id' => 0,
140
			'name' => $txt['membergroups_members'],
141
			'num_members' => $num_members,
142
			'allow_delete' => false,
143
			'allow_modify' => true,
144
			'can_search' => false,
145
			'href' => $scripturl . '?action=moderate;area=viewgroups;sa=members;group=0',
146
			'help' => 'membergroup_regular_members',
147
			'is_post_group' => false,
148
			'color' => '',
149
			'icons' => '',
150
			'children' => array(),
151
			'num_permissions' => array(
152
				'allowed' => 0,
153
				'denied' => 0
154
			),
155
			'access' => false
156
		),
157
	);
158
159
	$postGroups = array();
160
	$normalGroups = array();
161
162
	// Query the database defined membergroups.
163
	$query = $smcFunc['db_query']('', '
164
		SELECT id_group, id_parent, group_name, min_posts, online_color, icons
165
		FROM {db_prefix}membergroups' . (empty($modSettings['permission_enable_postgroups']) ? '
166
		WHERE min_posts = {int:min_posts}' : '') . '
167
		ORDER BY id_parent = {int:not_inherited} DESC, min_posts, CASE WHEN id_group < {int:newbie_group} THEN id_group ELSE 4 END, group_name',
168
		array(
169
			'min_posts' => -1,
170
			'not_inherited' => -2,
171
			'newbie_group' => 4,
172
		)
173
	);
174
	while ($row = $smcFunc['db_fetch_assoc']($query))
175
	{
176
		// If it's inherited, just add it as a child.
177
		if ($row['id_parent'] != -2)
178
		{
179 View Code Duplication
			if (isset($context['groups'][$row['id_parent']]))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
180
				$context['groups'][$row['id_parent']]['children'][$row['id_group']] = $row['group_name'];
181
			continue;
182
		}
183
184
		$row['icons'] = explode('#', $row['icons']);
185
		$context['groups'][$row['id_group']] = array(
186
			'id' => $row['id_group'],
187
			'name' => $row['group_name'],
188
			'num_members' => $row['id_group'] != 3 ? 0 : $txt['membergroups_guests_na'],
189
			'allow_delete' => $row['id_group'] > 4,
190
			'allow_modify' => $row['id_group'] > 1,
191
			'can_search' => $row['id_group'] != 3,
192
			'href' => $scripturl . '?action=moderate;area=viewgroups;sa=members;group=' . $row['id_group'],
193
			'help' => $row['id_group'] == 1 ? 'membergroup_administrator' : ($row['id_group'] == 3 ? 'membergroup_moderator' : ''),
194
			'is_post_group' => $row['min_posts'] != -1,
195
			'color' => empty($row['online_color']) ? '' : $row['online_color'],
196
			'icons' => !empty($row['icons'][0]) && !empty($row['icons'][1]) ? str_repeat('<img src="' . $settings['images_url'] . '/' . $row['icons'][1] . '" alt="*">', $row['icons'][0]) : '',
197
			'children' => array(),
198
			'num_permissions' => array(
199
				'allowed' => $row['id_group'] == 1 ? '(' . $txt['permissions_all'] . ')' : 0,
200
				'denied' => $row['id_group'] == 1 ? '(' . $txt['permissions_none'] . ')' : 0
201
			),
202
			'access' => false,
203
		);
204
205 View Code Duplication
		if ($row['min_posts'] == -1)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
206
			$normalGroups[$row['id_group']] = $row['id_group'];
207
		else
208
			$postGroups[$row['id_group']] = $row['id_group'];
209
	}
210
	$smcFunc['db_free_result']($query);
211
212
	// Get the number of members in this post group.
213
	if (!empty($postGroups))
214
	{
215
		$query = $smcFunc['db_query']('', '
216
			SELECT id_post_group AS id_group, COUNT(*) AS num_members
217
			FROM {db_prefix}members
218
			WHERE id_post_group IN ({array_int:post_group_list})
219
			GROUP BY id_post_group',
220
			array(
221
				'post_group_list' => $postGroups,
222
			)
223
		);
224
		while ($row = $smcFunc['db_fetch_assoc']($query))
225
			$context['groups'][$row['id_group']]['num_members'] += $row['num_members'];
226
		$smcFunc['db_free_result']($query);
227
	}
228
229 View Code Duplication
	if (!empty($normalGroups))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
230
	{
231
		// First, the easy one!
232
		$query = $smcFunc['db_query']('', '
233
			SELECT id_group, COUNT(*) AS num_members
234
			FROM {db_prefix}members
235
			WHERE id_group IN ({array_int:normal_group_list})
236
			GROUP BY id_group',
237
			array(
238
				'normal_group_list' => $normalGroups,
239
			)
240
		);
241
		while ($row = $smcFunc['db_fetch_assoc']($query))
242
			$context['groups'][$row['id_group']]['num_members'] += $row['num_members'];
243
		$smcFunc['db_free_result']($query);
244
245
		// This one is slower, but it's okay... careful not to count twice!
246
		$query = $smcFunc['db_query']('', '
247
			SELECT mg.id_group, COUNT(*) AS num_members
248
			FROM {db_prefix}membergroups AS mg
249
				INNER JOIN {db_prefix}members AS mem ON (mem.additional_groups != {string:blank_string}
250
					AND mem.id_group != mg.id_group
251
					AND FIND_IN_SET(mg.id_group, mem.additional_groups) != 0)
252
			WHERE mg.id_group IN ({array_int:normal_group_list})
253
			GROUP BY mg.id_group',
254
			array(
255
				'normal_group_list' => $normalGroups,
256
				'blank_string' => '',
257
			)
258
		);
259
		while ($row = $smcFunc['db_fetch_assoc']($query))
260
			$context['groups'][$row['id_group']]['num_members'] += $row['num_members'];
261
		$smcFunc['db_free_result']($query);
262
	}
263
264
	foreach ($context['groups'] as $id => $data)
265
	{
266
		if ($data['href'] != '')
267
			$context['groups'][$id]['link'] = '<a href="' . $data['href'] . '">' . $data['num_members'] . '</a>';
268
	}
269
270
	if (empty($_REQUEST['pid']))
271
	{
272
		$request = $smcFunc['db_query']('', '
273
			SELECT id_group, COUNT(*) AS num_permissions, add_deny
274
			FROM {db_prefix}permissions
275
			' . (empty($context['hidden_permissions']) ? '' : ' WHERE permission NOT IN ({array_string:hidden_permissions})') . '
276
			GROUP BY id_group, add_deny',
277
			array(
278
				'hidden_permissions' => !empty($context['hidden_permissions']) ? $context['hidden_permissions'] : array(),
279
			)
280
		);
281 View Code Duplication
		while ($row = $smcFunc['db_fetch_assoc']($request))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
282
			if (isset($context['groups'][(int) $row['id_group']]) && (!empty($row['add_deny']) || $row['id_group'] != -1))
283
				$context['groups'][(int) $row['id_group']]['num_permissions'][empty($row['add_deny']) ? 'denied' : 'allowed'] = $row['num_permissions'];
284
		$smcFunc['db_free_result']($request);
285
286
		// Get the "default" profile permissions too.
287
		$request = $smcFunc['db_query']('', '
288
			SELECT id_profile, id_group, COUNT(*) AS num_permissions, add_deny
289
			FROM {db_prefix}board_permissions
290
			WHERE id_profile = {int:default_profile}
291
			' . (empty($context['hidden_permissions']) ? '' : ' AND permission NOT IN ({array_string:hidden_permissions})') . '
292
			GROUP BY id_profile, id_group, add_deny',
293
			array(
294
				'default_profile' => 1,
295
				'hidden_permissions' => !empty($context['hidden_permissions']) ? $context['hidden_permissions'] : array(),
296
			)
297
		);
298 View Code Duplication
		while ($row = $smcFunc['db_fetch_assoc']($request))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
299
		{
300
			if (isset($context['groups'][(int) $row['id_group']]) && (!empty($row['add_deny']) || $row['id_group'] != -1))
301
				$context['groups'][(int) $row['id_group']]['num_permissions'][empty($row['add_deny']) ? 'denied' : 'allowed'] += $row['num_permissions'];
302
		}
303
		$smcFunc['db_free_result']($request);
304
	}
305
	else
306
	{
307
		$_REQUEST['pid'] = (int) $_REQUEST['pid'];
308
309
		if (!isset($context['profiles'][$_REQUEST['pid']]))
310
			fatal_lang_error('no_access', false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
311
312
		// Change the selected tab to better reflect that this really is a board profile.
313
		$context[$context['admin_menu_name']]['current_subsection'] = 'profiles';
314
315
		$request = $smcFunc['db_query']('', '
316
			SELECT id_profile, id_group, COUNT(*) AS num_permissions, add_deny
317
			FROM {db_prefix}board_permissions
318
			WHERE id_profile = {int:current_profile}
319
			GROUP BY id_profile, id_group, add_deny',
320
			array(
321
				'current_profile' => $_REQUEST['pid'],
322
			)
323
		);
324 View Code Duplication
		while ($row = $smcFunc['db_fetch_assoc']($request))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
325
		{
326
			if (isset($context['groups'][(int) $row['id_group']]) && (!empty($row['add_deny']) || $row['id_group'] != -1))
327
				$context['groups'][(int) $row['id_group']]['num_permissions'][empty($row['add_deny']) ? 'denied' : 'allowed'] += $row['num_permissions'];
328
		}
329
		$smcFunc['db_free_result']($request);
330
331
		$context['profile'] = array(
332
			'id' => $_REQUEST['pid'],
333
			'name' => $context['profiles'][$_REQUEST['pid']]['name'],
334
		);
335
	}
336
337
	// We can modify any permission set apart from the read only, reply only and no polls ones as they are redefined.
338
	$context['can_modify'] = empty($_REQUEST['pid']) || $_REQUEST['pid'] == 1 || $_REQUEST['pid'] > 4;
339
340
	// Load the proper template.
341
	$context['sub_template'] = 'permission_index';
342
	createToken('admin-mpq');
343
}
344
345
/**
346
 * Handle permissions by board... more or less. :P
347
 */
348
function PermissionByBoard()
349
{
350
	global $context, $txt, $smcFunc, $sourcedir, $cat_tree, $boardList, $boards;
351
352
	$context['page_title'] = $txt['permissions_boards'];
353
	$context['edit_all'] = isset($_GET['edit']);
354
355
	// Saving?
356
	if (!empty($_POST['save_changes']) && !empty($_POST['boardprofile']))
357
	{
358
		checkSession('request');
359
		validateToken('admin-mpb');
360
361
		$changes = array();
362
		foreach ($_POST['boardprofile'] as $pBoard => $profile)
363
		{
364
			$changes[(int) $profile][] = (int) $pBoard;
365
		}
366
367
		if (!empty($changes))
368
		{
369
			foreach ($changes as $profile => $boards)
370
				$smcFunc['db_query']('', '
371
					UPDATE {db_prefix}boards
372
					SET id_profile = {int:current_profile}
373
					WHERE id_board IN ({array_int:board_list})',
374
					array(
375
						'board_list' => $boards,
376
						'current_profile' => $profile,
377
					)
378
				);
379
		}
380
381
		$context['edit_all'] = false;
382
	}
383
384
	// Load all permission profiles.
385
	loadPermissionProfiles();
386
387
	// Get the board tree.
388
	require_once($sourcedir . '/Subs-Boards.php');
389
390
	getBoardTree();
391
392
	// Build the list of the boards.
393
	$context['categories'] = array();
394
	foreach ($cat_tree as $catid => $tree)
395
	{
396
		$context['categories'][$catid] = array(
397
			'name' => &$tree['node']['name'],
398
			'id' => &$tree['node']['id'],
399
			'boards' => array()
400
		);
401
		foreach ($boardList[$catid] as $boardid)
402
		{
403
			if (!isset($context['profiles'][$boards[$boardid]['profile']]))
404
				$boards[$boardid]['profile'] = 1;
405
406
			$context['categories'][$catid]['boards'][$boardid] = array(
407
				'id' => &$boards[$boardid]['id'],
408
				'name' => &$boards[$boardid]['name'],
409
				'description' => &$boards[$boardid]['description'],
410
				'child_level' => &$boards[$boardid]['level'],
411
				'profile' => &$boards[$boardid]['profile'],
412
				'profile_name' => $context['profiles'][$boards[$boardid]['profile']]['name'],
413
			);
414
		}
415
	}
416
417
	$context['sub_template'] = 'by_board';
418
	createToken('admin-mpb');
419
}
420
421
/**
422
 * Handles permission modification actions from the upper part of the
423
 * permission manager index.
424
 */
425
function SetQuickGroups()
426
{
427
	global $context, $smcFunc;
428
429
	checkSession();
430
	validateToken('admin-mpq', 'quick');
431
432
	loadIllegalPermissions();
433
	loadIllegalGuestPermissions();
434
435
	// Make sure only one of the quick options was selected.
436
	if ((!empty($_POST['predefined']) && ((isset($_POST['copy_from']) && $_POST['copy_from'] != 'empty') || !empty($_POST['permissions']))) || (!empty($_POST['copy_from']) && $_POST['copy_from'] != 'empty' && !empty($_POST['permissions'])))
437
		fatal_lang_error('permissions_only_one_option', false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
438
439
	if (empty($_POST['group']) || !is_array($_POST['group']))
440
		$_POST['group'] = array();
441
442
	// Only accept numeric values for selected membergroups.
443
	foreach ($_POST['group'] as $id => $group_id)
444
		$_POST['group'][$id] = (int) $group_id;
445
	$_POST['group'] = array_unique($_POST['group']);
446
447
	if (empty($_REQUEST['pid']))
448
		$_REQUEST['pid'] = 0;
449
	else
450
		$_REQUEST['pid'] = (int) $_REQUEST['pid'];
451
452
	// Fix up the old global to the new default!
453
	$bid = max(1, $_REQUEST['pid']);
454
455
	// No modifying the predefined profiles.
456 View Code Duplication
	if ($_REQUEST['pid'] > 1 && $_REQUEST['pid'] < 5)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
457
		fatal_lang_error('no_access', false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
458
459
	// Clear out any cached authority.
460
	updateSettings(array('settings_updated' => time()));
461
462
	// No groups where selected.
463
	if (empty($_POST['group']))
464
		redirectexit('action=admin;area=permissions;pid=' . $_REQUEST['pid']);
465
466
	// Set a predefined permission profile.
467
	if (!empty($_POST['predefined']))
468
	{
469
		// Make sure it's a predefined permission set we expect.
470
		if (!in_array($_POST['predefined'], array('restrict', 'standard', 'moderator', 'maintenance')))
471
			redirectexit('action=admin;area=permissions;pid=' . $_REQUEST['pid']);
472
473
		foreach ($_POST['group'] as $group_id)
474
		{
475
			if (!empty($_REQUEST['pid']))
476
				setPermissionLevel($_POST['predefined'], $group_id, $_REQUEST['pid']);
0 ignored issues
show
Documentation introduced by
$_POST['predefined'] is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
477
			else
478
				setPermissionLevel($_POST['predefined'], $group_id);
0 ignored issues
show
Documentation introduced by
$_POST['predefined'] is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
479
		}
480
	}
481
	// Set a permission profile based on the permissions of a selected group.
482
	elseif ($_POST['copy_from'] != 'empty')
483
	{
484
		// Just checking the input.
485
		if (!is_numeric($_POST['copy_from']))
486
			redirectexit('action=admin;area=permissions;pid=' . $_REQUEST['pid']);
487
488
		// Make sure the group we're copying to is never included.
489
		$_POST['group'] = array_diff($_POST['group'], array($_POST['copy_from']));
490
491
		// No groups left? Too bad.
492
		if (empty($_POST['group']))
493
			redirectexit('action=admin;area=permissions;pid=' . $_REQUEST['pid']);
494
495
		if (empty($_REQUEST['pid']))
496
		{
497
			// Retrieve current permissions of group.
498
			$request = $smcFunc['db_query']('', '
499
				SELECT permission, add_deny
500
				FROM {db_prefix}permissions
501
				WHERE id_group = {int:copy_from}',
502
				array(
503
					'copy_from' => $_POST['copy_from'],
504
				)
505
			);
506
			$target_perm = array();
507 View Code Duplication
			while ($row = $smcFunc['db_fetch_assoc']($request))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
508
				$target_perm[$row['permission']] = $row['add_deny'];
509
			$smcFunc['db_free_result']($request);
510
511
			$inserts = array();
512
			foreach ($_POST['group'] as $group_id)
513
				foreach ($target_perm as $perm => $add_deny)
514
				{
515
					// No dodgy permissions please!
516
					if (!empty($context['illegal_permissions']) && in_array($perm, $context['illegal_permissions']))
517
						continue;
518
					if ($group_id == -1 && in_array($perm, $context['non_guest_permissions']))
519
						continue;
520
521
					if ($group_id != 1 && $group_id != 3)
522
						$inserts[] = array($perm, $group_id, $add_deny);
523
				}
524
525
			// Delete the previous permissions...
526
			$smcFunc['db_query']('', '
527
				DELETE FROM {db_prefix}permissions
528
				WHERE id_group IN ({array_int:group_list})
529
					' . (empty($context['illegal_permissions']) ? '' : ' AND permission NOT IN ({array_string:illegal_permissions})'),
530
				array(
531
					'group_list' => $_POST['group'],
532
					'illegal_permissions' => !empty($context['illegal_permissions']) ? $context['illegal_permissions'] : array(),
533
				)
534
			);
535
536
			if (!empty($inserts))
537
			{
538
				// ..and insert the new ones.
539
				$smcFunc['db_insert']('',
540
					'{db_prefix}permissions',
541
					array(
542
						'permission' => 'string', 'id_group' => 'int', 'add_deny' => 'int',
543
					),
544
					$inserts,
545
					array('permission', 'id_group')
546
				);
547
			}
548
		}
549
550
		// Now do the same for the board permissions.
551
		$request = $smcFunc['db_query']('', '
552
			SELECT permission, add_deny
553
			FROM {db_prefix}board_permissions
554
			WHERE id_group = {int:copy_from}
555
				AND id_profile = {int:current_profile}',
556
			array(
557
				'copy_from' => $_POST['copy_from'],
558
				'current_profile' => $bid,
559
			)
560
		);
561
		$target_perm = array();
562 View Code Duplication
		while ($row = $smcFunc['db_fetch_assoc']($request))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
563
			$target_perm[$row['permission']] = $row['add_deny'];
564
		$smcFunc['db_free_result']($request);
565
566
		$inserts = array();
567
		foreach ($_POST['group'] as $group_id)
568
			foreach ($target_perm as $perm => $add_deny)
569
			{
570
				// Are these for guests?
571
				if ($group_id == -1 && in_array($perm, $context['non_guest_permissions']))
572
					continue;
573
574
				$inserts[] = array($perm, $group_id, $bid, $add_deny);
575
			}
576
577
		// Delete the previous global board permissions...
578
		$smcFunc['db_query']('', '
579
			DELETE FROM {db_prefix}board_permissions
580
			WHERE id_group IN ({array_int:current_group_list})
581
				AND id_profile = {int:current_profile}',
582
			array(
583
				'current_group_list' => $_POST['group'],
584
				'current_profile' => $bid,
585
			)
586
		);
587
588
		// And insert the copied permissions.
589 View Code Duplication
		if (!empty($inserts))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
590
		{
591
			// ..and insert the new ones.
592
			$smcFunc['db_insert']('',
593
				'{db_prefix}board_permissions',
594
				array('permission' => 'string', 'id_group' => 'int', 'id_profile' => 'int', 'add_deny' => 'int'),
595
				$inserts,
596
				array('permission', 'id_group', 'id_profile')
597
			);
598
		}
599
600
		// Update any children out there!
601
		updateChildPermissions($_POST['group'], $_REQUEST['pid']);
602
	}
603
	// Set or unset a certain permission for the selected groups.
604
	elseif (!empty($_POST['permissions']))
605
	{
606
		// Unpack two variables that were transported.
607
		list ($permissionType, $permission) = explode('/', $_POST['permissions']);
608
609
		// Check whether our input is within expected range.
610
		if (!in_array($_POST['add_remove'], array('add', 'clear', 'deny')) || !in_array($permissionType, array('membergroup', 'board')))
611
			redirectexit('action=admin;area=permissions;pid=' . $_REQUEST['pid']);
612
613
		if ($_POST['add_remove'] == 'clear')
614
		{
615
			if ($permissionType == 'membergroup')
616
				$smcFunc['db_query']('', '
617
					DELETE FROM {db_prefix}permissions
618
					WHERE id_group IN ({array_int:current_group_list})
619
						AND permission = {string:current_permission}
620
						' . (empty($context['illegal_permissions']) ? '' : ' AND permission NOT IN ({array_string:illegal_permissions})'),
621
					array(
622
						'current_group_list' => $_POST['group'],
623
						'current_permission' => $permission,
624
						'illegal_permissions' => !empty($context['illegal_permissions']) ? $context['illegal_permissions'] : array(),
625
					)
626
				);
627
			else
628
				$smcFunc['db_query']('', '
629
					DELETE FROM {db_prefix}board_permissions
630
					WHERE id_group IN ({array_int:current_group_list})
631
						AND id_profile = {int:current_profile}
632
						AND permission = {string:current_permission}',
633
					array(
634
						'current_group_list' => $_POST['group'],
635
						'current_profile' => $bid,
636
						'current_permission' => $permission,
637
					)
638
				);
639
		}
640
		// Add a permission (either 'set' or 'deny').
641
		else
642
		{
643
			$add_deny = $_POST['add_remove'] == 'add' ? '1' : '0';
644
			$permChange = array();
645
			foreach ($_POST['group'] as $groupID)
646
			{
647
				if ($groupID == -1 && in_array($permission, $context['non_guest_permissions']))
648
					continue;
649
650
				if ($permissionType == 'membergroup' && $groupID != 1 && $groupID != 3 && (empty($context['illegal_permissions']) || !in_array($permission, $context['illegal_permissions'])))
651
					$permChange[] = array($permission, $groupID, $add_deny);
652
				elseif ($permissionType != 'membergroup')
653
					$permChange[] = array($permission, $groupID, $bid, $add_deny);
654
			}
655
656
			if (!empty($permChange))
657
			{
658
				if ($permissionType == 'membergroup')
659
					$smcFunc['db_insert']('replace',
660
						'{db_prefix}permissions',
661
						array('permission' => 'string', 'id_group' => 'int', 'add_deny' => 'int'),
662
						$permChange,
663
						array('permission', 'id_group')
664
					);
665
				// Board permissions go into the other table.
666
				else
667
					$smcFunc['db_insert']('replace',
668
						'{db_prefix}board_permissions',
669
						array('permission' => 'string', 'id_group' => 'int', 'id_profile' => 'int', 'add_deny' => 'int'),
670
						$permChange,
671
						array('permission', 'id_group', 'id_profile')
672
					);
673
			}
674
		}
675
676
		// Another child update!
677
		updateChildPermissions($_POST['group'], $_REQUEST['pid']);
678
	}
679
680
	redirectexit('action=admin;area=permissions;pid=' . $_REQUEST['pid']);
681
}
682
683
/**
684
 * Initializes the necessary to modify a membergroup's permissions.
685
 */
686
function ModifyMembergroup()
687
{
688
	global $context, $txt, $smcFunc, $modSettings;
689
690
	if (!isset($_GET['group']))
691
		fatal_lang_error('no_access', false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
692
693
	$context['group']['id'] = (int) $_GET['group'];
694
695
	// It's not likely you'd end up here with this setting disabled.
696
	if ($_GET['group'] == 1)
697
		redirectexit('action=admin;area=permissions');
698
699
	loadAllPermissions();
700
	loadPermissionProfiles();
701
	$context['hidden_perms'] = array();
702
703
	if ($context['group']['id'] > 0)
704
	{
705
		$result = $smcFunc['db_query']('', '
706
			SELECT group_name, id_parent
707
			FROM {db_prefix}membergroups
708
			WHERE id_group = {int:current_group}
709
			LIMIT 1',
710
			array(
711
				'current_group' => $context['group']['id'],
712
			)
713
		);
714
		list ($context['group']['name'], $parent) = $smcFunc['db_fetch_row']($result);
715
		$smcFunc['db_free_result']($result);
716
717
		// Cannot edit an inherited group!
718
		if ($parent != -2)
719
			fatal_lang_error('cannot_edit_permissions_inherited');
720
	}
721
	elseif ($context['group']['id'] == -1)
722
		$context['group']['name'] = $txt['membergroups_guests'];
723
	else
724
		$context['group']['name'] = $txt['membergroups_members'];
725
726
	$context['profile']['id'] = empty($_GET['pid']) ? 0 : (int) $_GET['pid'];
727
728
	// If this is a moderator and they are editing "no profile" then we only do boards.
729
	if ($context['group']['id'] == 3 && empty($context['profile']['id']))
730
	{
731
		// For sanity just check they have no general permissions.
732
		$smcFunc['db_query']('', '
733
			DELETE FROM {db_prefix}permissions
734
			WHERE id_group = {int:moderator_group}',
735
			array(
736
				'moderator_group' => 3,
737
			)
738
		);
739
740
		$context['profile']['id'] = 1;
741
	}
742
743
	$context['permission_type'] = empty($context['profile']['id']) ? 'membergroup' : 'board';
744
	$context['profile']['can_modify'] = !$context['profile']['id'] || $context['profiles'][$context['profile']['id']]['can_modify'];
745
746
	// Set up things a little nicer for board related stuff...
747
	if ($context['permission_type'] == 'board')
748
	{
749
		$context['profile']['name'] = $context['profiles'][$context['profile']['id']]['name'];
750
		$context[$context['admin_menu_name']]['current_subsection'] = 'profiles';
751
	}
752
753
	// Fetch the current permissions.
754
	$permissions = array(
755
		'membergroup' => array('allowed' => array(), 'denied' => array()),
756
		'board' => array('allowed' => array(), 'denied' => array())
757
	);
758
759
	// General permissions?
760
	if ($context['permission_type'] == 'membergroup')
761
	{
762
		$result = $smcFunc['db_query']('', '
763
			SELECT permission, add_deny
764
			FROM {db_prefix}permissions
765
			WHERE id_group = {int:current_group}',
766
			array(
767
				'current_group' => $_GET['group'],
768
			)
769
		);
770 View Code Duplication
		while ($row = $smcFunc['db_fetch_assoc']($result))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
771
			$permissions['membergroup'][empty($row['add_deny']) ? 'denied' : 'allowed'][] = $row['permission'];
772
		$smcFunc['db_free_result']($result);
773
	}
774
775
	// Fetch current board permissions...
776
	$result = $smcFunc['db_query']('', '
777
		SELECT permission, add_deny
778
		FROM {db_prefix}board_permissions
779
		WHERE id_group = {int:current_group}
780
			AND id_profile = {int:current_profile}',
781
		array(
782
			'current_group' => $context['group']['id'],
783
			'current_profile' => $context['permission_type'] == 'membergroup' ? 1 : $context['profile']['id'],
784
		)
785
	);
786 View Code Duplication
	while ($row = $smcFunc['db_fetch_assoc']($result))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
787
		$permissions['board'][empty($row['add_deny']) ? 'denied' : 'allowed'][] = $row['permission'];
788
	$smcFunc['db_free_result']($result);
789
790
	// Loop through each permission and set whether it's checked.
791
	foreach ($context['permissions'] as $permissionType => $tmp)
792
	{
793
		foreach ($tmp['columns'] as $position => $permissionGroups)
794
		{
795
			foreach ($permissionGroups as $permissionGroup => $permissionArray)
796
			{
797
				foreach ($permissionArray['permissions'] as $perm)
798
				{
799
					// Create a shortcut for the current permission.
800
					$curPerm = &$context['permissions'][$permissionType]['columns'][$position][$permissionGroup]['permissions'][$perm['id']];
801
802
					if ($perm['has_own_any'])
803
					{
804
						$curPerm['any']['select'] = in_array($perm['id'] . '_any', $permissions[$permissionType]['allowed']) ? 'on' : (in_array($perm['id'] . '_any', $permissions[$permissionType]['denied']) ? 'deny' : 'off');
805
						$curPerm['own']['select'] = in_array($perm['id'] . '_own', $permissions[$permissionType]['allowed']) ? 'on' : (in_array($perm['id'] . '_own', $permissions[$permissionType]['denied']) ? 'deny' : 'off');
806
					}
807
					else
808
						$curPerm['select'] = in_array($perm['id'], $permissions[$permissionType]['denied']) ? 'deny' : (in_array($perm['id'], $permissions[$permissionType]['allowed']) ? 'on' : 'off');
809
810
						// Keep the last value if it's hidden.
811
						if ($perm['hidden'] || $permissionArray['hidden'])
812
						{
813
							if ($perm['has_own_any'])
814
							{
815
								$context['hidden_perms'][] = array(
816
									$permissionType,
817
									$perm['own']['id'],
818
									$curPerm['own']['select'] == 'deny' && !empty($modSettings['permission_enable_deny']) ? 'deny' : $curPerm['own']['select'],
819
								);
820
								$context['hidden_perms'][] = array(
821
									$permissionType,
822
									$perm['any']['id'],
823
									$curPerm['any']['select'] == 'deny' && !empty($modSettings['permission_enable_deny']) ? 'deny' : $curPerm['any']['select'],
824
								);
825
							}
826
							else
827
								$context['hidden_perms'][] = array(
828
									$permissionType,
829
									$perm['id'],
830
									$curPerm['select'] == 'deny' && !empty($modSettings['permission_enable_deny']) ? 'deny' : $curPerm['select'],
831
								);
832
						}
833
				}
834
			}
835
		}
836
	}
837
	$context['sub_template'] = 'modify_group';
838
	$context['page_title'] = $txt['permissions_modify_group'];
839
840
	createToken('admin-mp');
841
}
842
843
/**
844
 * This function actually saves modifications to a membergroup's board permissions.
845
 */
846
function ModifyMembergroup2()
847
{
848
	global $smcFunc, $context;
849
850
	checkSession();
851
	validateToken('admin-mp');
852
853
	loadIllegalPermissions();
854
855
	$_GET['group'] = (int) $_GET['group'];
856
	$_GET['pid'] = (int) $_GET['pid'];
857
858
	// Cannot modify predefined profiles.
859 View Code Duplication
	if ($_GET['pid'] > 1 && $_GET['pid'] < 5)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
860
		fatal_lang_error('no_access', false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
861
862
	// Verify this isn't inherited.
863
	if ($_GET['group'] == -1 || $_GET['group'] == 0)
864
		$parent = -2;
865
	else
866
	{
867
		$result = $smcFunc['db_query']('', '
868
			SELECT id_parent
869
			FROM {db_prefix}membergroups
870
			WHERE id_group = {int:current_group}
871
			LIMIT 1',
872
			array(
873
				'current_group' => $_GET['group'],
874
			)
875
		);
876
		list ($parent) = $smcFunc['db_fetch_row']($result);
877
		$smcFunc['db_free_result']($result);
878
	}
879
880
	if ($parent != -2)
881
		fatal_lang_error('cannot_edit_permissions_inherited');
882
883
	$givePerms = array('membergroup' => array(), 'board' => array());
884
885
	// Guest group, we need illegal, guest permissions.
886
	if ($_GET['group'] == -1)
887
	{
888
		loadIllegalGuestPermissions();
889
		$context['illegal_permissions'] = array_merge($context['illegal_permissions'], $context['non_guest_permissions']);
890
	}
891
892
	// Prepare all permissions that were set or denied for addition to the DB.
893
	if (isset($_POST['perm']) && is_array($_POST['perm']))
894
	{
895
		foreach ($_POST['perm'] as $perm_type => $perm_array)
896
		{
897
			if (is_array($perm_array))
898
			{
899
				foreach ($perm_array as $permission => $value)
900
					if ($value == 'on' || $value == 'deny')
901
					{
902
						// Don't allow people to escalate themselves!
903
						if (!empty($context['illegal_permissions']) && in_array($permission, $context['illegal_permissions']))
904
							continue;
905
906
						$givePerms[$perm_type][] = array($_GET['group'], $permission, $value == 'deny' ? 0 : 1);
907
					}
908
			}
909
		}
910
	}
911
912
	// Insert the general permissions.
913
	if ($_GET['group'] != 3 && empty($_GET['pid']))
914
	{
915
		$smcFunc['db_query']('', '
916
			DELETE FROM {db_prefix}permissions
917
			WHERE id_group = {int:current_group}
918
			' . (empty($context['illegal_permissions']) ? '' : ' AND permission NOT IN ({array_string:illegal_permissions})'),
919
			array(
920
				'current_group' => $_GET['group'],
921
				'illegal_permissions' => !empty($context['illegal_permissions']) ? $context['illegal_permissions'] : array(),
922
			)
923
		);
924
925
		if (!empty($givePerms['membergroup']))
926
		{
927
			$smcFunc['db_insert']('replace',
928
				'{db_prefix}permissions',
929
				array('id_group' => 'int', 'permission' => 'string', 'add_deny' => 'int'),
930
				$givePerms['membergroup'],
931
				array('id_group', 'permission')
932
			);
933
		}
934
	}
935
936
	// Insert the boardpermissions.
937
	$profileid = max(1, $_GET['pid']);
938
	$smcFunc['db_query']('', '
939
		DELETE FROM {db_prefix}board_permissions
940
		WHERE id_group = {int:current_group}
941
			AND id_profile = {int:current_profile}',
942
		array(
943
			'current_group' => $_GET['group'],
944
			'current_profile' => $profileid,
945
		)
946
	);
947
	if (!empty($givePerms['board']))
948
	{
949
		foreach ($givePerms['board'] as $k => $v)
950
			$givePerms['board'][$k][] = $profileid;
951
		$smcFunc['db_insert']('replace',
952
			'{db_prefix}board_permissions',
953
			array('id_group' => 'int', 'permission' => 'string', 'add_deny' => 'int', 'id_profile' => 'int'),
954
			$givePerms['board'],
955
			array('id_group', 'permission', 'id_profile')
956
		);
957
	}
958
959
	// Update any inherited permissions as required.
960
	updateChildPermissions($_GET['group'], $_GET['pid']);
0 ignored issues
show
Documentation introduced by
$_GET['group'] is of type integer, but the function expects a null|array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
961
962
	// Clear cached privs.
963
	updateSettings(array('settings_updated' => time()));
964
965
	redirectexit('action=admin;area=permissions;pid=' . $_GET['pid']);
966
}
967
968
/**
969
 * A screen to set some general settings for permissions.
970
 *
971
 * @param bool $return_config Whether to return the $config_vars array (used for admin search)
972
 * @return void|array Returns nothing or returns the config_vars array if $return_config is true
973
 */
974
function GeneralPermissionSettings($return_config = false)
975
{
976
	global $context, $modSettings, $sourcedir, $txt, $scripturl, $smcFunc;
977
978
	// All the setting variables
979
	$config_vars = array(
980
		array('title', 'settings'),
981
			// Inline permissions.
982
			array('permissions', 'manage_permissions'),
983
		'',
984
			// A few useful settings
985
			array('check', 'permission_enable_deny', 0, $txt['permission_settings_enable_deny'], 'help' => 'permissions_deny'),
986
			array('check', 'permission_enable_postgroups', 0, $txt['permission_settings_enable_postgroups'], 'help' => 'permissions_postgroups'),
987
	);
988
989
	call_integration_hook('integrate_modify_permission_settings', array(&$config_vars));
990
991
	if ($return_config)
992
		return $config_vars;
993
994
	$context['page_title'] = $txt['permission_settings_title'];
995
	$context['sub_template'] = 'show_settings';
996
997
	// Needed for the inline permission functions, and the settings template.
998
	require_once($sourcedir . '/ManageServer.php');
999
1000
	// Don't let guests have these permissions.
1001
	$context['post_url'] = $scripturl . '?action=admin;area=permissions;save;sa=settings';
1002
	$context['permissions_excluded'] = array(-1);
1003
1004
	// Saving the settings?
1005
	if (isset($_GET['save']))
1006
	{
1007
		checkSession();
1008
		call_integration_hook('integrate_save_permission_settings');
1009
		saveDBSettings($config_vars);
1010
1011
		// Clear all deny permissions...if we want that.
1012
		if (empty($modSettings['permission_enable_deny']))
1013
		{
1014
			$smcFunc['db_query']('', '
1015
				DELETE FROM {db_prefix}permissions
1016
				WHERE add_deny = {int:denied}',
1017
				array(
1018
					'denied' => 0,
1019
				)
1020
			);
1021
			$smcFunc['db_query']('', '
1022
				DELETE FROM {db_prefix}board_permissions
1023
				WHERE add_deny = {int:denied}',
1024
				array(
1025
					'denied' => 0,
1026
				)
1027
			);
1028
		}
1029
1030
		// Make sure there are no postgroup based permissions left.
1031
		if (empty($modSettings['permission_enable_postgroups']))
1032
		{
1033
			// Get a list of postgroups.
1034
			$post_groups = array();
1035
			$request = $smcFunc['db_query']('', '
1036
				SELECT id_group
1037
				FROM {db_prefix}membergroups
1038
				WHERE min_posts != {int:min_posts}',
1039
				array(
1040
					'min_posts' => -1,
1041
				)
1042
			);
1043
			while ($row = $smcFunc['db_fetch_assoc']($request))
1044
				$post_groups[] = $row['id_group'];
1045
			$smcFunc['db_free_result']($request);
1046
1047
			// Remove'em.
1048
			$smcFunc['db_query']('', '
1049
				DELETE FROM {db_prefix}permissions
1050
				WHERE id_group IN ({array_int:post_group_list})',
1051
				array(
1052
					'post_group_list' => $post_groups,
1053
				)
1054
			);
1055
			$smcFunc['db_query']('', '
1056
				DELETE FROM {db_prefix}board_permissions
1057
				WHERE id_group IN ({array_int:post_group_list})',
1058
				array(
1059
					'post_group_list' => $post_groups,
1060
				)
1061
			);
1062
			$smcFunc['db_query']('', '
1063
				UPDATE {db_prefix}membergroups
1064
				SET id_parent = {int:not_inherited}
1065
				WHERE id_parent IN ({array_int:post_group_list})',
1066
				array(
1067
					'post_group_list' => $post_groups,
1068
					'not_inherited' => -2,
1069
				)
1070
			);
1071
		}
1072
1073
		$_SESSION['adm-save'] = true;
1074
		redirectexit('action=admin;area=permissions;sa=settings');
1075
	}
1076
1077
	// We need this for the in-line permissions
1078
	createToken('admin-mp');
1079
1080
	prepareDBSettingContext($config_vars);
1081
}
1082
1083
/**
1084
 * Set the permission level for a specific profile, group, or group for a profile.
1085
 * @internal
1086
 *
1087
 * @param string $level The level ('restrict', 'standard', etc.)
1088
 * @param int $group The group to set the permission for
1089
 * @param string|int $profile The ID of the permissions profile or 'null' if we're setting it for a group
1090
 */
1091
function setPermissionLevel($level, $group, $profile = 'null')
1092
{
1093
	global $smcFunc, $context;
1094
1095
	loadIllegalPermissions();
1096
	loadIllegalGuestPermissions();
1097
1098
	// Levels by group... restrict, standard, moderator, maintenance.
1099
	$groupLevels = array(
1100
		'board' => array('inherit' => array()),
1101
		'group' => array('inherit' => array())
1102
	);
1103
	// Levels by board... standard, publish, free.
1104
	$boardLevels = array('inherit' => array());
1105
1106
	// Restrictive - ie. guests.
1107
	$groupLevels['global']['restrict'] = array(
1108
		'search_posts',
1109
		'calendar_view',
1110
		'view_stats',
1111
		'who_view',
1112
		'profile_identity_own',
1113
	);
1114
	$groupLevels['board']['restrict'] = array(
1115
		'poll_view',
1116
		'post_new',
1117
		'post_reply_own',
1118
		'post_reply_any',
1119
		'delete_own',
1120
		'modify_own',
1121
		'report_any',
1122
	);
1123
1124
	// Standard - ie. members.  They can do anything Restrictive can.
1125
	$groupLevels['global']['standard'] = array_merge($groupLevels['global']['restrict'], array(
1126
		'view_mlist',
1127
		'likes_view',
1128
		'likes_like',
1129
		'mention',
1130
		'pm_read',
1131
		'pm_send',
1132
		'profile_view',
1133
		'profile_extra_own',
1134
		'profile_signature_own',
1135
		'profile_forum_own',
1136
		'profile_other_own',
1137
		'profile_password_own',
1138
		'profile_server_avatar',
1139
		'profile_displayed_name',
1140
		'profile_upload_avatar',
1141
		'profile_remote_avatar',
1142
		'profile_remove_own',
1143
		'report_user',
1144
	));
1145
	$groupLevels['board']['standard'] = array_merge($groupLevels['board']['restrict'], array(
1146
		'poll_vote',
1147
		'poll_edit_own',
1148
		'poll_post',
1149
		'poll_add_own',
1150
		'post_attachment',
1151
		'lock_own',
1152
		'remove_own',
1153
		'view_attachments',
1154
	));
1155
1156
	// Moderator - ie. moderators :P.  They can do what standard can, and more.
1157
	$groupLevels['global']['moderator'] = array_merge($groupLevels['global']['standard'], array(
1158
		'calendar_post',
1159
		'calendar_edit_own',
1160
		'access_mod_center',
1161
		'issue_warning',
1162
	));
1163
	$groupLevels['board']['moderator'] = array_merge($groupLevels['board']['standard'], array(
1164
		'make_sticky',
1165
		'poll_edit_any',
1166
		'delete_any',
1167
		'modify_any',
1168
		'lock_any',
1169
		'remove_any',
1170
		'move_any',
1171
		'merge_any',
1172
		'split_any',
1173
		'poll_lock_any',
1174
		'poll_remove_any',
1175
		'poll_add_any',
1176
		'approve_posts',
1177
	));
1178
1179
	// Maintenance - wannabe admins.  They can do almost everything.
1180
	$groupLevels['global']['maintenance'] = array_merge($groupLevels['global']['moderator'], array(
1181
		'manage_attachments',
1182
		'manage_smileys',
1183
		'manage_boards',
1184
		'moderate_forum',
1185
		'manage_membergroups',
1186
		'manage_bans',
1187
		'admin_forum',
1188
		'manage_permissions',
1189
		'edit_news',
1190
		'calendar_edit_any',
1191
		'profile_identity_any',
1192
		'profile_extra_any',
1193
		'profile_signature_any',
1194
		'profile_other_any',
1195
		'profile_displayed_name_any',
1196
		'profile_password_any',
1197
		'profile_title_any',
1198
	));
1199
	$groupLevels['board']['maintenance'] = array_merge($groupLevels['board']['moderator'], array(
1200
	));
1201
1202
	// Standard - nothing above the group permissions. (this SHOULD be empty.)
1203
	$boardLevels['standard'] = array(
1204
	);
1205
1206
	// Locked - just that, you can't post here.
1207
	$boardLevels['locked'] = array(
1208
		'poll_view',
1209
		'report_any',
1210
		'view_attachments',
1211
	);
1212
1213
	// Publisher - just a little more...
1214
	$boardLevels['publish'] = array_merge($boardLevels['locked'], array(
1215
		'post_new',
1216
		'post_reply_own',
1217
		'post_reply_any',
1218
		'delete_own',
1219
		'modify_own',
1220
		'delete_replies',
1221
		'modify_replies',
1222
		'poll_vote',
1223
		'poll_edit_own',
1224
		'poll_post',
1225
		'poll_add_own',
1226
		'poll_remove_own',
1227
		'post_attachment',
1228
		'lock_own',
1229
		'remove_own',
1230
	));
1231
1232
	// Free for All - Scary.  Just scary.
1233
	$boardLevels['free'] = array_merge($boardLevels['publish'], array(
1234
		'poll_lock_any',
1235
		'poll_edit_any',
1236
		'poll_add_any',
1237
		'poll_remove_any',
1238
		'make_sticky',
1239
		'lock_any',
1240
		'remove_any',
1241
		'delete_any',
1242
		'split_any',
1243
		'merge_any',
1244
		'modify_any',
1245
		'approve_posts',
1246
	));
1247
1248
	call_integration_hook('integrate_load_permission_levels', array(&$groupLevels, &$boardLevels));
1249
1250
	// Make sure we're not granting someone too many permissions!
1251
	foreach ($groupLevels['global'][$level] as $k => $permission)
1252
	{
1253
		if (!empty($context['illegal_permissions']) && in_array($permission, $context['illegal_permissions']))
1254
			unset($groupLevels['global'][$level][$k]);
1255
1256
		if ($group == -1 && in_array($permission, $context['non_guest_permissions']))
1257
			unset($groupLevels['global'][$level][$k]);
1258
	}
1259
	if ($group == -1)
1260
		foreach ($groupLevels['board'][$level] as $k => $permission)
1261
			if (in_array($permission, $context['non_guest_permissions']))
1262
				unset($groupLevels['board'][$level][$k]);
1263
1264
	// Reset all cached permissions.
1265
	updateSettings(array('settings_updated' => time()));
1266
1267
	// Setting group permissions.
1268
	if ($profile === 'null' && $group !== 'null')
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison !== seems to always evaluate to true as the types of $group (integer) and 'null' (string) can never be identical. Maybe you want to use a loose comparison != instead?
Loading history...
1269
	{
1270
		$group = (int) $group;
1271
1272
		if (empty($groupLevels['global'][$level]))
1273
			return;
1274
1275
		$smcFunc['db_query']('', '
1276
			DELETE FROM {db_prefix}permissions
1277
			WHERE id_group = {int:current_group}
1278
			' . (empty($context['illegal_permissions']) ? '' : ' AND permission NOT IN ({array_string:illegal_permissions})'),
1279
			array(
1280
				'current_group' => $group,
1281
				'illegal_permissions' => !empty($context['illegal_permissions']) ? $context['illegal_permissions'] : array(),
1282
			)
1283
		);
1284
		$smcFunc['db_query']('', '
1285
			DELETE FROM {db_prefix}board_permissions
1286
			WHERE id_group = {int:current_group}
1287
				AND id_profile = {int:default_profile}',
1288
			array(
1289
				'current_group' => $group,
1290
				'default_profile' => 1,
1291
			)
1292
		);
1293
1294
		$groupInserts = array();
1295
		foreach ($groupLevels['global'][$level] as $permission)
1296
			$groupInserts[] = array($group, $permission);
1297
1298
		$smcFunc['db_insert']('insert',
1299
			'{db_prefix}permissions',
1300
			array('id_group' => 'int', 'permission' => 'string'),
1301
			$groupInserts,
1302
			array('id_group')
1303
		);
1304
1305
		$boardInserts = array();
1306 View Code Duplication
		foreach ($groupLevels['board'][$level] as $permission)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1307
			$boardInserts[] = array(1, $group, $permission);
1308
1309
		$smcFunc['db_insert']('insert',
1310
			'{db_prefix}board_permissions',
1311
			array('id_profile' => 'int', 'id_group' => 'int', 'permission' => 'string'),
1312
			$boardInserts,
1313
			array('id_profile', 'id_group')
1314
		);
1315
	}
1316
	// Setting profile permissions for a specific group.
1317
	elseif ($profile !== 'null' && $group !== 'null' && ($profile == 1 || $profile > 4))
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison !== seems to always evaluate to true as the types of $group (integer) and 'null' (string) can never be identical. Maybe you want to use a loose comparison != instead?
Loading history...
1318
	{
1319
		$group = (int) $group;
1320
		$profile = (int) $profile;
1321
1322
		if (!empty($groupLevels['global'][$level]))
1323
		{
1324
			$smcFunc['db_query']('', '
1325
				DELETE FROM {db_prefix}board_permissions
1326
				WHERE id_group = {int:current_group}
1327
					AND id_profile = {int:current_profile}',
1328
				array(
1329
					'current_group' => $group,
1330
					'current_profile' => $profile,
1331
				)
1332
			);
1333
		}
1334
1335
		if (!empty($groupLevels['board'][$level]))
1336
		{
1337
			$boardInserts = array();
1338 View Code Duplication
			foreach ($groupLevels['board'][$level] as $permission)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1339
				$boardInserts[] = array($profile, $group, $permission);
1340
1341
			$smcFunc['db_insert']('insert',
1342
				'{db_prefix}board_permissions',
1343
				array('id_profile' => 'int', 'id_group' => 'int', 'permission' => 'string'),
1344
				$boardInserts,
1345
				array('id_profile', 'id_group')
1346
			);
1347
		}
1348
	}
1349
	// Setting profile permissions for all groups.
1350
	elseif ($profile !== 'null' && $group === 'null' && ($profile == 1 || $profile > 4))
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $group (integer) and 'null' (string) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
1351
	{
1352
		$profile = (int) $profile;
1353
1354
		$smcFunc['db_query']('', '
1355
			DELETE FROM {db_prefix}board_permissions
1356
			WHERE id_profile = {int:current_profile}',
1357
			array(
1358
				'current_profile' => $profile,
1359
			)
1360
		);
1361
1362
		if (empty($boardLevels[$level]))
1363
			return;
1364
1365
		// Get all the groups...
1366
		$query = $smcFunc['db_query']('', '
1367
			SELECT id_group
1368
			FROM {db_prefix}membergroups
1369
			WHERE id_group > {int:moderator_group}
1370
			ORDER BY min_posts, CASE WHEN id_group < {int:newbie_group} THEN id_group ELSE 4 END, group_name',
1371
			array(
1372
				'moderator_group' => 3,
1373
				'newbie_group' => 4,
1374
			)
1375
		);
1376
		while ($row = $smcFunc['db_fetch_row']($query))
1377
		{
1378
			$group = $row[0];
1379
1380
			$boardInserts = array();
1381
			foreach ($boardLevels[$level] as $permission)
1382
				$boardInserts[] = array($profile, $group, $permission);
1383
1384
			$smcFunc['db_insert']('insert',
1385
				'{db_prefix}board_permissions',
1386
				array('id_profile' => 'int', 'id_group' => 'int', 'permission' => 'string'),
1387
				$boardInserts,
1388
				array('id_profile', 'id_group')
1389
			);
1390
		}
1391
		$smcFunc['db_free_result']($query);
1392
1393
		// Add permissions for ungrouped members.
1394
		$boardInserts = array();
1395
		foreach ($boardLevels[$level] as $permission)
1396
			$boardInserts[] = array($profile, 0, $permission);
1397
1398
		$smcFunc['db_insert']('insert',
1399
				'{db_prefix}board_permissions',
1400
				array('id_profile' => 'int', 'id_group' => 'int', 'permission' => 'string'),
1401
				$boardInserts,
1402
				array('id_profile', 'id_group')
1403
			);
1404
	}
1405
	// $profile and $group are both null!
1406
	else
1407
		fatal_lang_error('no_access', false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1408
}
1409
1410
/**
1411
 * Load permissions into $context['permissions'].
1412
 * @internal
1413
 */
1414
function loadAllPermissions()
1415
{
1416
	global $context, $txt, $modSettings;
1417
1418
	// List of all the groups dependant on the currently selected view - for the order so it looks pretty, yea?
1419
	// Note to Mod authors - you don't need to stick your permission group here if you don't mind SMF sticking it the last group of the page.
1420
	$permissionGroups = array(
1421
		'membergroup' => array(
1422
			'general',
1423
			'pm',
1424
			'calendar',
1425
			'maintenance',
1426
			'member_admin',
1427
			'profile',
1428
			'likes',
1429
			'mentions',
1430
		),
1431
		'board' => array(
1432
			'general_board',
1433
			'topic',
1434
			'post',
1435
			'poll',
1436
			'notification',
1437
			'attachment',
1438
		),
1439
	);
1440
1441
	/*   The format of this list is as follows:
1442
		'membergroup' => array(
1443
			'permissions_inside' => array(has_multiple_options, view_group),
1444
		),
1445
		'board' => array(
1446
			'permissions_inside' => array(has_multiple_options, view_group),
1447
		);
1448
	*/
1449
	$permissionList = array(
1450
		'membergroup' => array(
1451
			'view_stats' => array(false, 'general'),
1452
			'view_mlist' => array(false, 'general'),
1453
			'who_view' => array(false, 'general'),
1454
			'search_posts' => array(false, 'general'),
1455
			'pm_read' => array(false, 'pm'),
1456
			'pm_send' => array(false, 'pm'),
1457
			'pm_draft' => array(false, 'pm'),
1458
			'calendar_view' => array(false, 'calendar'),
1459
			'calendar_post' => array(false, 'calendar'),
1460
			'calendar_edit' => array(true, 'calendar'),
1461
			'admin_forum' => array(false, 'maintenance'),
1462
			'manage_boards' => array(false, 'maintenance'),
1463
			'manage_attachments' => array(false, 'maintenance'),
1464
			'manage_smileys' => array(false, 'maintenance'),
1465
			'edit_news' => array(false, 'maintenance'),
1466
			'access_mod_center' => array(false, 'maintenance'),
1467
			'moderate_forum' => array(false, 'member_admin'),
1468
			'manage_membergroups' => array(false, 'member_admin'),
1469
			'manage_permissions' => array(false, 'member_admin'),
1470
			'manage_bans' => array(false, 'member_admin'),
1471
			'send_mail' => array(false, 'member_admin'),
1472
			'issue_warning' => array(false, 'member_admin'),
1473
			'profile_view' => array(false, 'profile'),
1474
			'profile_forum' => array(true, 'profile'),
1475
			'profile_extra' => array(true, 'profile'),
1476
			'profile_signature' => array(true, 'profile'),
1477
			'profile_other' => array(true, 'profile'),
1478
			'profile_title' => array(true, 'profile'),
1479
			'profile_blurb' => array(true, 'profile'),
1480
			'profile_server_avatar' => array(false, 'profile'),
1481
			'profile_upload_avatar' => array(false, 'profile'),
1482
			'profile_remote_avatar' => array(false, 'profile'),
1483
			'report_user' => array(false, 'profile'),
1484
			'profile_identity' => array(true, 'profile_account'),
1485
			'profile_displayed_name' => array(true, 'profile_account'),
1486
			'profile_password' => array(true, 'profile_account'),
1487
			'profile_remove' => array(true, 'profile_account'),
1488
			'view_warning' => array(true, 'profile_account'),
1489
			'likes_view' => array(false, 'likes'),
1490
			'likes_like' => array(false, 'likes'),
1491
			'mention' => array(false, 'mentions'),
1492
		),
1493
		'board' => array(
1494
			'moderate_board' => array(false, 'general_board'),
1495
			'approve_posts' => array(false, 'general_board'),
1496
			'post_new' => array(false, 'topic'),
1497
			'post_unapproved_topics' => array(false, 'topic'),
1498
			'post_unapproved_replies' => array(true, 'topic'),
1499
			'post_reply' => array(true, 'topic'),
1500
			'post_draft' => array(false, 'topic'),
1501
			'merge_any' => array(false, 'topic'),
1502
			'split_any' => array(false, 'topic'),
1503
			'make_sticky' => array(false, 'topic'),
1504
			'move' => array(true, 'topic', 'moderate'),
1505
			'lock' => array(true, 'topic', 'moderate'),
1506
			'remove' => array(true, 'topic', 'modify'),
1507
			'modify_replies' => array(false, 'topic'),
1508
			'delete_replies' => array(false, 'topic'),
1509
			'announce_topic' => array(false, 'topic'),
1510
			'delete' => array(true, 'post'),
1511
			'modify' => array(true, 'post'),
1512
			'report_any' => array(false, 'post'),
1513
			'poll_view' => array(false, 'poll'),
1514
			'poll_vote' => array(false, 'poll'),
1515
			'poll_post' => array(false, 'poll'),
1516
			'poll_add' => array(true, 'poll'),
1517
			'poll_edit' => array(true, 'poll'),
1518
			'poll_lock' => array(true, 'poll'),
1519
			'poll_remove' => array(true, 'poll'),
1520
			'view_attachments' => array(false, 'attachment'),
1521
			'post_unapproved_attachments' => array(false, 'attachment'),
1522
			'post_attachment' => array(false, 'attachment'),
1523
		),
1524
	);
1525
1526
	// All permission groups that will be shown in the left column on classic view.
1527
	$leftPermissionGroups = array(
1528
		'general',
1529
		'calendar',
1530
		'maintenance',
1531
		'member_admin',
1532
		'topic',
1533
		'post',
1534
	);
1535
1536
	// We need to know what permissions we can't give to guests.
1537
	loadIllegalGuestPermissions();
1538
1539
	// Some permissions are hidden if features are off.
1540
	$hiddenPermissions = array();
1541
	$relabelPermissions = array(); // Permissions to apply a different label to.
1542
	$relabelGroups = array(); // As above but for groups.
0 ignored issues
show
Unused Code introduced by
$relabelGroups is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1543
	if (empty($modSettings['cal_enabled']))
1544
	{
1545
		$hiddenPermissions[] = 'calendar_view';
1546
		$hiddenPermissions[] = 'calendar_post';
1547
		$hiddenPermissions[] = 'calendar_edit';
1548
	}
1549
	if ($modSettings['warning_settings'][0] == 0)
1550
	{
1551
		$hiddenPermissions[] = 'issue_warning';
1552
		$hiddenPermissions[] = 'view_warning';
1553
	}
1554
1555
	// Post moderation?
1556
	if (!$modSettings['postmod_active'])
1557
	{
1558
		$hiddenPermissions[] = 'approve_posts';
1559
		$hiddenPermissions[] = 'post_unapproved_topics';
1560
		$hiddenPermissions[] = 'post_unapproved_replies';
1561
		$hiddenPermissions[] = 'post_unapproved_attachments';
1562
	}
1563
	// If post moderation is enabled, these are named differently...
1564
	else
1565
	{
1566
		// Relabel the topics permissions
1567
		$relabelPermissions['post_new'] = 'auto_approve_topics';
1568
1569
		// Relabel the reply permissions
1570
		$relabelPermissions['post_reply'] = 'auto_approve_replies';
1571
1572
		// Relabel the attachment permissions
1573
		$relabelPermissions['post_attachment'] = 'auto_approve_attachments';
1574
	}
1575
1576
	// Are attachments enabled?
1577
	if (empty($modSettings['attachmentEnable']))
1578
	{
1579
		$hiddenPermissions[] = 'manage_attachments';
1580
		$hiddenPermissions[] = 'view_attachments';
1581
		$hiddenPermissions[] = 'post_unapproved_attachments';
1582
		$hiddenPermissions[] = 'post_attachment';
1583
	}
1584
1585
	// Hide Likes/Mentions permissions...
1586
	if (empty($modSettings['enable_likes']))
1587
	{
1588
		$hiddenPermissions[] = 'likes_view';
1589
		$hiddenPermissions[] = 'likes_like';
1590
	}
1591
	if (empty($modSettings['enable_mentions']))
1592
	{
1593
		$hiddenPermissions[] = 'mention';
1594
	}
1595
1596
	// Provide a practical way to modify permissions.
1597
	call_integration_hook('integrate_load_permissions', array(&$permissionGroups, &$permissionList, &$leftPermissionGroups, &$hiddenPermissions, &$relabelPermissions));
1598
1599
	$context['permissions'] = array();
1600
	$context['hidden_permissions'] = array();
1601
	foreach ($permissionList as $permissionType => $permissionList)
1602
	{
1603
		$context['permissions'][$permissionType] = array(
1604
			'id' => $permissionType,
1605
			'columns' => array()
1606
		);
1607
		foreach ($permissionList as $permission => $permissionArray)
1608
		{
1609
			// If this is a guest permission we don't do it if it's the guest group.
1610
			if (isset($context['group']['id']) && $context['group']['id'] == -1 && in_array($permission, $context['non_guest_permissions']))
1611
				continue;
1612
1613
			// What groups will this permission be in?
1614
			$own_group = $permissionArray[1];
1615
1616
			// First, Do these groups actually exist - if not add them.
1617
			if (!isset($permissionGroups[$permissionType][$own_group]))
1618
				$permissionGroups[$permissionType][$own_group] = true;
1619
1620
			// What column should this be located into?
1621
			$position = !in_array($own_group, $leftPermissionGroups) ? 1 : 0;
1622
1623
			// If the groups have not yet been created be sure to create them.
1624
			$bothGroups = array('own' => $own_group);
1625
1626
			foreach ($bothGroups as $group)
1627
				if (!isset($context['permissions'][$permissionType]['columns'][$position][$group]))
1628
					$context['permissions'][$permissionType]['columns'][$position][$group] = array(
1629
						'type' => $permissionType,
1630
						'id' => $group,
1631
						'name' => $txt['permissiongroup_' . $group],
1632
						'icon' => isset($txt['permissionicon_' . $group]) ? $txt['permissionicon_' . $group] : $txt['permissionicon'],
1633
						'help' => isset($txt['permissionhelp_' . $group]) ? $txt['permissionhelp_' . $group] : '',
1634
						'hidden' => false,
1635
						'permissions' => array()
1636
					);
1637
1638
			$context['permissions'][$permissionType]['columns'][$position][$own_group]['permissions'][$permission] = array(
1639
				'id' => $permission,
1640
				'name' => !isset($relabelPermissions[$permission]) ? $txt['permissionname_' . $permission] : $txt[$relabelPermissions[$permission]],
1641
				'show_help' => isset($txt['permissionhelp_' . $permission]),
1642
				'note' => isset($txt['permissionnote_' . $permission]) ? $txt['permissionnote_' . $permission] : '',
1643
				'has_own_any' => $permissionArray[0],
1644
				'own' => array(
1645
					'id' => $permission . '_own',
1646
					'name' => $permissionArray[0] ? $txt['permissionname_' . $permission . '_own'] : ''
1647
				),
1648
				'any' => array(
1649
					'id' => $permission . '_any',
1650
					'name' => $permissionArray[0] ? $txt['permissionname_' . $permission . '_any'] : ''
1651
				),
1652
				'hidden' => in_array($permission, $hiddenPermissions),
1653
			);
1654
1655
			if (in_array($permission, $hiddenPermissions))
1656
			{
1657
				if ($permissionArray[0])
1658
				{
1659
					$context['hidden_permissions'][] = $permission . '_own';
1660
					$context['hidden_permissions'][] = $permission . '_any';
1661
				}
1662
				else
1663
					$context['hidden_permissions'][] = $permission;
1664
			}
1665
		}
1666
		ksort($context['permissions'][$permissionType]['columns']);
1667
1668
		// Check we don't leave any empty groups - and mark hidden ones as such.
1669
		foreach ($context['permissions'][$permissionType]['columns'] as $column => $groups)
1670
			foreach ($groups as $id => $group)
1671
			{
1672
				if (empty($group['permissions']))
1673
					unset($context['permissions'][$permissionType]['columns'][$column][$id]);
1674
				else
1675
				{
1676
					$foundNonHidden = false;
1677
					foreach ($group['permissions'] as $permission)
1678
						if (empty($permission['hidden']))
1679
							$foundNonHidden = true;
1680
					if (!$foundNonHidden)
1681
						$context['permissions'][$permissionType]['columns'][$column][$id]['hidden'] = true;
1682
				}
1683
			}
1684
	}
1685
}
1686
1687
/**
1688
 * Initialize a form with inline permissions settings.
1689
 * It loads a context variables for each permission.
1690
 * This function is used by several settings screens to set specific permissions.
1691
 * @internal
1692
 *
1693
 * @param array $permissions The permissions to display inline
1694
 * @param array $excluded_groups The IDs of one or more groups to exclude
1695
 *
1696
 * @uses ManagePermissions language
1697
 * @uses ManagePermissions template.
1698
 */
1699
function init_inline_permissions($permissions, $excluded_groups = array())
1700
{
1701
	global $context, $txt, $modSettings, $smcFunc;
1702
1703
	loadLanguage('ManagePermissions');
1704
	loadTemplate('ManagePermissions');
1705
	$context['can_change_permissions'] = allowedTo('manage_permissions');
1706
1707
	// Nothing to initialize here.
1708
	if (!$context['can_change_permissions'])
1709
		return;
1710
1711
	// Load the permission settings for guests
1712
	foreach ($permissions as $permission)
1713
		$context[$permission] = array(
1714
			-1 => array(
1715
				'id' => -1,
1716
				'name' => $txt['membergroups_guests'],
1717
				'is_postgroup' => false,
1718
				'status' => 'off',
1719
			),
1720
			0 => array(
1721
				'id' => 0,
1722
				'name' => $txt['membergroups_members'],
1723
				'is_postgroup' => false,
1724
				'status' => 'off',
1725
			),
1726
		);
1727
1728
	$request = $smcFunc['db_query']('', '
1729
		SELECT id_group, CASE WHEN add_deny = {int:denied} THEN {string:deny} ELSE {string:on} END AS status, permission
1730
		FROM {db_prefix}permissions
1731
		WHERE id_group IN (-1, 0)
1732
			AND permission IN ({array_string:permissions})',
1733
		array(
1734
			'denied' => 0,
1735
			'permissions' => $permissions,
1736
			'deny' => 'deny',
1737
			'on' => 'on',
1738
		)
1739
	);
1740
	while ($row = $smcFunc['db_fetch_assoc']($request))
1741
		$context[$row['permission']][$row['id_group']]['status'] = $row['status'];
1742
	$smcFunc['db_free_result']($request);
1743
1744
	$request = $smcFunc['db_query']('', '
1745
		SELECT mg.id_group, mg.group_name, mg.min_posts, COALESCE(p.add_deny, -1) AS status, p.permission
1746
		FROM {db_prefix}membergroups AS mg
1747
			LEFT JOIN {db_prefix}permissions AS p ON (p.id_group = mg.id_group AND p.permission IN ({array_string:permissions}))
1748
		WHERE mg.id_group NOT IN (1, 3)
1749
			AND mg.id_parent = {int:not_inherited}' . (empty($modSettings['permission_enable_postgroups']) ? '
1750
			AND mg.min_posts = {int:min_posts}' : '') . '
1751
		ORDER BY mg.min_posts, CASE WHEN mg.id_group < {int:newbie_group} THEN mg.id_group ELSE 4 END, mg.group_name',
1752
		array(
1753
			'not_inherited' => -2,
1754
			'min_posts' => -1,
1755
			'newbie_group' => 4,
1756
			'permissions' => $permissions,
1757
		)
1758
	);
1759
	while ($row = $smcFunc['db_fetch_assoc']($request))
1760
	{
1761
		// Initialize each permission as being 'off' until proven otherwise.
1762
		foreach ($permissions as $permission)
1763 View Code Duplication
			if (!isset($context[$permission][$row['id_group']]))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1764
				$context[$permission][$row['id_group']] = array(
1765
					'id' => $row['id_group'],
1766
					'name' => $row['group_name'],
1767
					'is_postgroup' => $row['min_posts'] != -1,
1768
					'status' => 'off',
1769
				);
1770
1771
		$context[$row['permission']][$row['id_group']]['status'] = empty($row['status']) ? 'deny' : ($row['status'] == 1 ? 'on' : 'off');
1772
	}
1773
	$smcFunc['db_free_result']($request);
1774
1775
	// Make sure we honor the "illegal guest permissions"
1776
	loadIllegalGuestPermissions();
1777
1778
	// Some permissions cannot be given to certain groups. Remove the groups.
1779
	foreach ($excluded_groups as $group)
1780
	{
1781
		foreach ($permissions as $permission)
1782
		{
1783
			if (isset($context[$permission][$group]))
1784
				unset($context[$permission][$group]);
1785
		}
1786
	}
1787
1788
	// Are any of these permissions that guests can't have?
1789
	$non_guest_perms = array_intersect(str_replace(array('_any', '_own'), '', $permissions), $context['non_guest_permissions']);
1790
	foreach ($non_guest_perms as $permission)
1791
	{
1792
		if (isset($context[$permission][-1]))
1793
			unset($context[$permission][-1]);
1794
	}
1795
1796
	// Create the token for the separate inline permission verification.
1797
	createToken('admin-mp');
1798
}
1799
1800
/**
1801
 * Show a collapsible box to set a specific permission.
1802
 * The function is called by templates to show a list of permissions settings.
1803
 * Calls the template function template_inline_permissions().
1804
 *
1805
 * @param string $permission The permission to display inline
1806
 */
1807
function theme_inline_permissions($permission)
1808
{
1809
	global $context;
1810
1811
	$context['current_permission'] = $permission;
1812
	$context['member_groups'] = $context[$permission];
1813
1814
	template_inline_permissions();
1815
}
1816
1817
/**
1818
 * Save the permissions of a form containing inline permissions.
1819
 * @internal
1820
 *
1821
 * @param array $permissions The permissions to save
1822
 */
1823
function save_inline_permissions($permissions)
1824
{
1825
	global $context, $smcFunc;
1826
1827
	// No permissions? Not a great deal to do here.
1828
	if (!allowedTo('manage_permissions'))
1829
		return;
1830
1831
	// Almighty session check, verify our ways.
1832
	checkSession();
1833
	validateToken('admin-mp');
1834
1835
	// Check they can't do certain things.
1836
	loadIllegalPermissions();
1837
1838
	$insertRows = array();
1839
	foreach ($permissions as $permission)
1840
	{
1841
		if (!isset($_POST[$permission]))
1842
			continue;
1843
1844
		foreach ($_POST[$permission] as $id_group => $value)
1845
		{
1846
			if (in_array($value, array('on', 'deny')) && (empty($context['illegal_permissions']) || !in_array($permission, $context['illegal_permissions'])))
1847
				$insertRows[] = array((int) $id_group, $permission, $value == 'on' ? 1 : 0);
1848
		}
1849
	}
1850
1851
	// Remove the old permissions...
1852
	$smcFunc['db_query']('', '
1853
		DELETE FROM {db_prefix}permissions
1854
		WHERE permission IN ({array_string:permissions})
1855
		' . (empty($context['illegal_permissions']) ? '' : ' AND permission NOT IN ({array_string:illegal_permissions})'),
1856
		array(
1857
			'illegal_permissions' => !empty($context['illegal_permissions']) ? $context['illegal_permissions'] : array(),
1858
			'permissions' => $permissions,
1859
		)
1860
	);
1861
1862
	// ...and replace them with new ones.
1863
	if (!empty($insertRows))
1864
		$smcFunc['db_insert']('insert',
1865
			'{db_prefix}permissions',
1866
			array('id_group' => 'int', 'permission' => 'string', 'add_deny' => 'int'),
1867
			$insertRows,
1868
			array('id_group', 'permission')
1869
		);
1870
1871
	// Do a full child update.
1872
	updateChildPermissions(array(), -1);
1873
1874
	// Just in case we cached this.
1875
	updateSettings(array('settings_updated' => time()));
1876
}
1877
1878
/**
1879
 * Load permissions profiles.
1880
 */
1881
function loadPermissionProfiles()
1882
{
1883
	global $context, $txt, $smcFunc;
1884
1885
	$request = $smcFunc['db_query']('', '
1886
		SELECT id_profile, profile_name
1887
		FROM {db_prefix}permission_profiles
1888
		ORDER BY id_profile',
1889
		array(
1890
		)
1891
	);
1892
	$context['profiles'] = array();
1893
	while ($row = $smcFunc['db_fetch_assoc']($request))
1894
	{
1895
		// Format the label nicely.
1896
		if (isset($txt['permissions_profile_' . $row['profile_name']]))
1897
			$name = $txt['permissions_profile_' . $row['profile_name']];
1898
		else
1899
			$name = $row['profile_name'];
1900
1901
		$context['profiles'][$row['id_profile']] = array(
1902
			'id' => $row['id_profile'],
1903
			'name' => $name,
1904
			'can_modify' => $row['id_profile'] == 1 || $row['id_profile'] > 4,
1905
			'unformatted_name' => $row['profile_name'],
1906
		);
1907
	}
1908
	$smcFunc['db_free_result']($request);
1909
}
1910
1911
/**
1912
 * Add/Edit/Delete profiles.
1913
 */
1914
function EditPermissionProfiles()
1915
{
1916
	global $context, $txt, $smcFunc;
1917
1918
	// Setup the template, first for fun.
1919
	$context['page_title'] = $txt['permissions_profile_edit'];
1920
	$context['sub_template'] = 'edit_profiles';
1921
1922
	// If we're creating a new one do it first.
1923
	if (isset($_POST['create']) && trim($_POST['profile_name']) != '')
1924
	{
1925
		checkSession();
1926
		validateToken('admin-mpp');
1927
1928
		$_POST['copy_from'] = (int) $_POST['copy_from'];
1929
		$_POST['profile_name'] = $smcFunc['htmlspecialchars']($_POST['profile_name']);
1930
1931
		// Insert the profile itself.
1932
		$smcFunc['db_insert']('',
1933
			'{db_prefix}permission_profiles',
1934
			array(
1935
				'profile_name' => 'string',
1936
			),
1937
			array(
1938
				$_POST['profile_name'],
1939
			),
1940
			array('id_profile')
1941
		);
1942
		$profile_id = $smcFunc['db_insert_id']('{db_prefix}permission_profiles', 'id_profile');
1943
1944
		// Load the permissions from the one it's being copied from.
1945
		$request = $smcFunc['db_query']('', '
1946
			SELECT id_group, permission, add_deny
1947
			FROM {db_prefix}board_permissions
1948
			WHERE id_profile = {int:copy_from}',
1949
			array(
1950
				'copy_from' => $_POST['copy_from'],
1951
			)
1952
		);
1953
		$inserts = array();
1954
		while ($row = $smcFunc['db_fetch_assoc']($request))
1955
			$inserts[] = array($profile_id, $row['id_group'], $row['permission'], $row['add_deny']);
1956
		$smcFunc['db_free_result']($request);
1957
1958 View Code Duplication
		if (!empty($inserts))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1959
			$smcFunc['db_insert']('insert',
1960
				'{db_prefix}board_permissions',
1961
				array('id_profile' => 'int', 'id_group' => 'int', 'permission' => 'string', 'add_deny' => 'int'),
1962
				$inserts,
1963
				array('id_profile', 'id_group', 'permission')
1964
			);
1965
	}
1966
	// Renaming?
1967
	elseif (isset($_POST['rename']))
1968
	{
1969
		checkSession();
1970
		validateToken('admin-mpp');
1971
1972
		// Just showing the boxes?
1973
		if (!isset($_POST['rename_profile']))
1974
			$context['show_rename_boxes'] = true;
1975
		else
1976
		{
1977
			foreach ($_POST['rename_profile'] as $id => $value)
1978
			{
1979
				$value = $smcFunc['htmlspecialchars']($value);
1980
1981
				if (trim($value) != '' && $id > 4)
1982
					$smcFunc['db_query']('', '
1983
						UPDATE {db_prefix}permission_profiles
1984
						SET profile_name = {string:profile_name}
1985
						WHERE id_profile = {int:current_profile}',
1986
						array(
1987
							'current_profile' => (int) $id,
1988
							'profile_name' => $value,
1989
						)
1990
					);
1991
			}
1992
		}
1993
	}
1994
	// Deleting?
1995
	elseif (isset($_POST['delete']) && !empty($_POST['delete_profile']))
1996
	{
1997
		checkSession();
1998
		validateToken('admin-mpp');
1999
2000
		$profiles = array();
2001
		foreach ($_POST['delete_profile'] as $profile)
2002
			if ($profile > 4)
2003
				$profiles[] = (int) $profile;
2004
2005
		// Verify it's not in use...
2006
		$request = $smcFunc['db_query']('', '
2007
			SELECT id_board
2008
			FROM {db_prefix}boards
2009
			WHERE id_profile IN ({array_int:profile_list})
2010
			LIMIT 1',
2011
			array(
2012
				'profile_list' => $profiles,
2013
			)
2014
		);
2015
		if ($smcFunc['db_num_rows']($request) != 0)
2016
			fatal_lang_error('no_access', false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
2017
		$smcFunc['db_free_result']($request);
2018
2019
		// Oh well, delete.
2020
		$smcFunc['db_query']('', '
2021
			DELETE FROM {db_prefix}permission_profiles
2022
			WHERE id_profile IN ({array_int:profile_list})',
2023
			array(
2024
				'profile_list' => $profiles,
2025
			)
2026
		);
2027
	}
2028
2029
	// Clearly, we'll need this!
2030
	loadPermissionProfiles();
2031
2032
	// Work out what ones are in use.
2033
	$request = $smcFunc['db_query']('', '
2034
		SELECT id_profile, COUNT(id_board) AS board_count
2035
		FROM {db_prefix}boards
2036
		GROUP BY id_profile',
2037
		array(
2038
		)
2039
	);
2040
	while ($row = $smcFunc['db_fetch_assoc']($request))
2041
		if (isset($context['profiles'][$row['id_profile']]))
2042
		{
2043
			$context['profiles'][$row['id_profile']]['in_use'] = true;
2044
			$context['profiles'][$row['id_profile']]['boards'] = $row['board_count'];
2045
			$context['profiles'][$row['id_profile']]['boards_text'] = $row['board_count'] > 1 ? sprintf($txt['permissions_profile_used_by_many'], $row['board_count']) : $txt['permissions_profile_used_by_' . ($row['board_count'] ? 'one' : 'none')];
2046
		}
2047
	$smcFunc['db_free_result']($request);
2048
2049
	// What can we do with these?
2050
	$context['can_edit_something'] = false;
2051
	foreach ($context['profiles'] as $id => $profile)
2052
	{
2053
		// Can't delete special ones.
2054
		$context['profiles'][$id]['can_edit'] = isset($txt['permissions_profile_' . $profile['unformatted_name']]) ? false : true;
2055
		if ($context['profiles'][$id]['can_edit'])
2056
			$context['can_edit_something'] = true;
2057
2058
		// You can only delete it if you can edit it AND it's not in use.
2059
		$context['profiles'][$id]['can_delete'] = $context['profiles'][$id]['can_edit'] && empty($profile['in_use']) ? true : false;
2060
	}
2061
2062
	createToken('admin-mpp');
2063
}
2064
2065
/**
2066
 * This function updates the permissions of any groups based off this group.
2067
 *
2068
 * @param null|array $parents The parent groups
2069
 * @param null|int $profile the ID of a permissions profile to update
2070
 * @return void|false Returns nothing if successful or false if there are no child groups to update
2071
 */
2072
function updateChildPermissions($parents, $profile = null)
2073
{
2074
	global $smcFunc;
2075
2076
	// All the parent groups to sort out.
2077
	if (!is_array($parents))
2078
		$parents = array($parents);
2079
2080
	// Find all the children of this group.
2081
	$request = $smcFunc['db_query']('', '
2082
		SELECT id_parent, id_group
2083
		FROM {db_prefix}membergroups
2084
		WHERE id_parent != {int:not_inherited}
2085
			' . (empty($parents) ? '' : 'AND id_parent IN ({array_int:parent_list})'),
2086
		array(
2087
			'parent_list' => $parents,
2088
			'not_inherited' => -2,
2089
		)
2090
	);
2091
	$children = array();
2092
	$parents = array();
2093
	$child_groups = array();
2094
	while ($row = $smcFunc['db_fetch_assoc']($request))
2095
	{
2096
		$children[$row['id_parent']][] = $row['id_group'];
2097
		$child_groups[] = $row['id_group'];
2098
		$parents[] = $row['id_parent'];
2099
	}
2100
	$smcFunc['db_free_result']($request);
2101
2102
	$parents = array_unique($parents);
2103
2104
	// Not a sausage, or a child?
2105
	if (empty($children))
2106
		return false;
2107
2108
	// First off, are we doing general permissions?
2109
	if ($profile < 1 || $profile === null)
2110
	{
2111
		// Fetch all the parent permissions.
2112
		$request = $smcFunc['db_query']('', '
2113
			SELECT id_group, permission, add_deny
2114
			FROM {db_prefix}permissions
2115
			WHERE id_group IN ({array_int:parent_list})',
2116
			array(
2117
				'parent_list' => $parents,
2118
			)
2119
		);
2120
		$permissions = array();
2121 View Code Duplication
		while ($row = $smcFunc['db_fetch_assoc']($request))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
2122
			foreach ($children[$row['id_group']] as $child)
2123
				$permissions[] = array($child, $row['permission'], $row['add_deny']);
2124
		$smcFunc['db_free_result']($request);
2125
2126
		$smcFunc['db_query']('', '
2127
			DELETE FROM {db_prefix}permissions
2128
			WHERE id_group IN ({array_int:child_groups})',
2129
			array(
2130
				'child_groups' => $child_groups,
2131
			)
2132
		);
2133
2134
		// Finally insert.
2135
		if (!empty($permissions))
2136
		{
2137
			$smcFunc['db_insert']('insert',
2138
				'{db_prefix}permissions',
2139
				array('id_group' => 'int', 'permission' => 'string', 'add_deny' => 'int'),
2140
				$permissions,
2141
				array('id_group', 'permission')
2142
			);
2143
		}
2144
	}
2145
2146
	// Then, what about board profiles?
2147
	if ($profile != -1)
2148
	{
2149
		$profileQuery = $profile === null ? '' : ' AND id_profile = {int:current_profile}';
2150
2151
		// Again, get all the parent permissions.
2152
		$request = $smcFunc['db_query']('', '
2153
			SELECT id_profile, id_group, permission, add_deny
2154
			FROM {db_prefix}board_permissions
2155
			WHERE id_group IN ({array_int:parent_groups})
2156
				' . $profileQuery,
2157
			array(
2158
				'parent_groups' => $parents,
2159
				'current_profile' => $profile !== null && $profile ? $profile : 1,
2160
			)
2161
		);
2162
		$permissions = array();
2163 View Code Duplication
		while ($row = $smcFunc['db_fetch_assoc']($request))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
2164
			foreach ($children[$row['id_group']] as $child)
2165
				$permissions[] = array($child, $row['id_profile'], $row['permission'], $row['add_deny']);
2166
		$smcFunc['db_free_result']($request);
2167
2168
		$smcFunc['db_query']('', '
2169
			DELETE FROM {db_prefix}board_permissions
2170
			WHERE id_group IN ({array_int:child_groups})
2171
				' . $profileQuery,
2172
			array(
2173
				'child_groups' => $child_groups,
2174
				'current_profile' => $profile !== null && $profile ? $profile : 1,
2175
			)
2176
		);
2177
2178
		// Do the insert.
2179 View Code Duplication
		if (!empty($permissions))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
2180
		{
2181
			$smcFunc['db_insert']('insert',
2182
				'{db_prefix}board_permissions',
2183
				array('id_group' => 'int', 'id_profile' => 'int', 'permission' => 'string', 'add_deny' => 'int'),
2184
				$permissions,
2185
				array('id_group', 'id_profile', 'permission')
2186
			);
2187
		}
2188
	}
2189
}
2190
2191
/**
2192
 * Load permissions someone cannot grant.
2193
 */
2194
function loadIllegalPermissions()
2195
{
2196
	global $context;
2197
2198
	$context['illegal_permissions'] = array();
2199
	if (!allowedTo('admin_forum'))
2200
		$context['illegal_permissions'][] = 'admin_forum';
2201
	if (!allowedTo('manage_membergroups'))
2202
		$context['illegal_permissions'][] = 'manage_membergroups';
2203
	if (!allowedTo('manage_permissions'))
2204
		$context['illegal_permissions'][] = 'manage_permissions';
2205
2206
	call_integration_hook('integrate_load_illegal_permissions');
2207
}
2208
2209
/**
2210
 * Loads the permissions that can not be given to guests.
2211
 * Stores the permissions in $context['non_guest_permissions'].
2212
*/
2213
function loadIllegalGuestPermissions()
2214
{
2215
	global $context;
2216
2217
	$context['non_guest_permissions'] = array(
2218
		'access_mod_center',
2219
		'admin_forum',
2220
		'announce_topic',
2221
		'approve_posts',
2222
		'calendar_edit',
2223
		'delete',
2224
		'delete_replies',
2225
		'edit_news',
2226
		'issue_warning',
2227
		'likes_like',
2228
		'lock',
2229
		'make_sticky',
2230
		'manage_attachments',
2231
		'manage_bans',
2232
		'manage_boards',
2233
		'manage_membergroups',
2234
		'manage_permissions',
2235
		'manage_smileys',
2236
		'merge_any',
2237
		'moderate_board',
2238
		'moderate_forum',
2239
		'modify',
2240
		'modify_replies',
2241
		'move',
2242
		'pm_autosave_draft',
2243
		'pm_draft',
2244
		'pm_read',
2245
		'pm_send',
2246
		'poll_add',
2247
		'poll_edit',
2248
		'poll_lock',
2249
		'poll_remove',
2250
		'post_autosave_draft',
2251
		'post_draft',
2252
		'profile_blurb',
2253
		'profile_displayed_name',
2254
		'profile_extra',
2255
		'profile_forum',
2256
		'profile_identity',
2257
		'profile_other',
2258
		'profile_password',
2259
		'profile_remove',
2260
		'profile_remote_avatar',
2261
		'profile_server_avatar',
2262
		'profile_signature',
2263
		'profile_title',
2264
		'profile_upload_avatar',
2265
		'profile_warning',
2266
		'remove',
2267
		'report_any',
2268
		'report_user',
2269
		'send_mail',
2270
		'split_any',
2271
	);
2272
2273
	call_integration_hook('integrate_load_illegal_guest_permissions');
2274
}
2275
2276
/**
2277
 * Present a nice way of applying post moderation.
2278
 */
2279
function ModifyPostModeration()
2280
{
2281
	global $context, $txt, $smcFunc, $modSettings, $sourcedir;
2282
2283
	// Just in case.
2284
	checkSession('get');
2285
2286
	$context['page_title'] = $txt['permissions_post_moderation'];
2287
	$context['sub_template'] = 'postmod_permissions';
2288
	$context['current_profile'] = isset($_REQUEST['pid']) ? (int) $_REQUEST['pid'] : 1;
2289
2290
	// Load all the permission profiles.
2291
	loadPermissionProfiles();
2292
2293
	// Mappings, our key => array(can_do_moderated, can_do_all)
2294
	$mappings = array(
2295
		'new_topic' => array('post_new', 'post_unapproved_topics'),
2296
		'replies_own' => array('post_reply_own', 'post_unapproved_replies_own'),
2297
		'replies_any' => array('post_reply_any', 'post_unapproved_replies_any'),
2298
		'attachment' => array('post_attachment', 'post_unapproved_attachments'),
2299
	);
2300
2301
	call_integration_hook('integrate_post_moderation_mapping', array(&$mappings));
2302
2303
	// Start this with the guests/members.
2304
	$context['profile_groups'] = array(
2305
		-1 => array(
2306
			'id' => -1,
2307
			'name' => $txt['membergroups_guests'],
2308
			'color' => '',
2309
			'new_topic' => 'disallow',
2310
			'replies_own' => 'disallow',
2311
			'replies_any' => 'disallow',
2312
			'attachment' => 'disallow',
2313
			'children' => array(),
2314
		),
2315
		0 => array(
2316
			'id' => 0,
2317
			'name' => $txt['membergroups_members'],
2318
			'color' => '',
2319
			'new_topic' => 'disallow',
2320
			'replies_own' => 'disallow',
2321
			'replies_any' => 'disallow',
2322
			'attachment' => 'disallow',
2323
			'children' => array(),
2324
		),
2325
	);
2326
2327
	// Load the groups.
2328
	$request = $smcFunc['db_query']('', '
2329
		SELECT id_group, group_name, online_color, id_parent
2330
		FROM {db_prefix}membergroups
2331
		WHERE id_group != {int:admin_group}
2332
			' . (empty($modSettings['permission_enable_postgroups']) ? ' AND min_posts = {int:min_posts}' : '') . '
2333
		ORDER BY id_parent ASC',
2334
		array(
2335
			'admin_group' => 1,
2336
			'min_posts' => -1,
2337
		)
2338
	);
2339
	while ($row = $smcFunc['db_fetch_assoc']($request))
2340
	{
2341
		if ($row['id_parent'] == -2)
2342
		{
2343
			$context['profile_groups'][$row['id_group']] = array(
2344
				'id' => $row['id_group'],
2345
				'name' => $row['group_name'],
2346
				'color' => $row['online_color'],
2347
				'new_topic' => 'disallow',
2348
				'replies_own' => 'disallow',
2349
				'replies_any' => 'disallow',
2350
				'attachment' => 'disallow',
2351
				'children' => array(),
2352
			);
2353
		}
2354 View Code Duplication
		elseif (isset($context['profile_groups'][$row['id_parent']]))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
2355
			$context['profile_groups'][$row['id_parent']]['children'][] = $row['group_name'];
2356
	}
2357
	$smcFunc['db_free_result']($request);
2358
2359
	// What are the permissions we are querying?
2360
	$all_permissions = array();
2361
	foreach ($mappings as $perm_set)
2362
		$all_permissions = array_merge($all_permissions, $perm_set);
2363
2364
	// If we're saving the changes then do just that - save them.
2365
	if (!empty($_POST['save_changes']) && ($context['current_profile'] == 1 || $context['current_profile'] > 4))
2366
	{
2367
		validateToken('admin-mppm');
2368
2369
		// First, are we saving a new value for enabled post moderation?
2370
		$new_setting = !empty($_POST['postmod_active']);
2371
		if ($new_setting != $modSettings['postmod_active'])
2372
		{
2373
			if ($new_setting)
2374
			{
2375
				// Turning it on. This seems easy enough.
2376
				updateSettings(array('postmod_active' => 1));
2377
			}
2378
			else
2379
			{
2380
				// Turning it off. Not so straightforward. We have to turn off warnings to moderation level, and make everything approved.
2381
				updateSettings(array(
2382
					'postmod_active' => 0,
2383
					'warning_moderate' => 0,
2384
				));
2385
2386
				require_once($sourcedir . '/PostModeration.php');
2387
				approveAllData();
2388
			}
2389
		}
2390
		elseif ($modSettings['postmod_active'])
2391
		{
2392
			// We're not saving a new setting - and if it's still enabled we have more work to do.
2393
2394
			// Start by deleting all the permissions relevant.
2395
			$smcFunc['db_query']('', '
2396
				DELETE FROM {db_prefix}board_permissions
2397
				WHERE id_profile = {int:current_profile}
2398
					AND permission IN ({array_string:permissions})
2399
					AND id_group IN ({array_int:profile_group_list})',
2400
				array(
2401
					'profile_group_list' => array_keys($context['profile_groups']),
2402
					'current_profile' => $context['current_profile'],
2403
					'permissions' => $all_permissions,
2404
				)
2405
			);
2406
2407
			// Do it group by group.
2408
			$new_permissions = array();
2409
			foreach ($context['profile_groups'] as $id => $group)
2410
			{
2411
				foreach ($mappings as $index => $data)
2412
				{
2413
					if (isset($_POST[$index][$group['id']]))
2414
					{
2415
						if ($_POST[$index][$group['id']] == 'allow')
2416
						{
2417
							// Give them both sets for fun.
2418
							$new_permissions[] = array($context['current_profile'], $group['id'], $data[0], 1);
2419
							$new_permissions[] = array($context['current_profile'], $group['id'], $data[1], 1);
2420
						}
2421
						elseif ($_POST[$index][$group['id']] == 'moderate')
2422
							$new_permissions[] = array($context['current_profile'], $group['id'], $data[1], 1);
2423
					}
2424
				}
2425
			}
2426
2427
			// Insert new permissions.
2428 View Code Duplication
			if (!empty($new_permissions))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
2429
				$smcFunc['db_insert']('',
2430
					'{db_prefix}board_permissions',
2431
					array('id_profile' => 'int', 'id_group' => 'int', 'permission' => 'string', 'add_deny' => 'int'),
2432
					$new_permissions,
2433
					array('id_profile', 'id_group', 'permission')
2434
				);
2435
		}
2436
	}
2437
2438
	// Now get all the permissions!
2439
	$request = $smcFunc['db_query']('', '
2440
		SELECT id_group, permission, add_deny
2441
		FROM {db_prefix}board_permissions
2442
		WHERE id_profile = {int:current_profile}
2443
			AND permission IN ({array_string:permissions})
2444
			AND id_group IN ({array_int:profile_group_list})',
2445
		array(
2446
			'profile_group_list' => array_keys($context['profile_groups']),
2447
			'current_profile' => $context['current_profile'],
2448
			'permissions' => $all_permissions,
2449
		)
2450
	);
2451
	while ($row = $smcFunc['db_fetch_assoc']($request))
2452
	{
2453
		foreach ($mappings as $key => $data)
2454
		{
2455
			foreach ($data as $index => $perm)
2456
			{
2457
				if ($perm == $row['permission'])
2458
				{
2459
					// Only bother if it's not denied.
2460
					if ($row['add_deny'])
2461
					{
2462
						// Full allowance?
2463
						if ($index == 0)
2464
							$context['profile_groups'][$row['id_group']][$key] = 'allow';
2465
						// Otherwise only bother with moderate if not on allow.
2466
						elseif ($context['profile_groups'][$row['id_group']][$key] != 'allow')
2467
							$context['profile_groups'][$row['id_group']][$key] = 'moderate';
2468
					}
2469
				}
2470
			}
2471
		}
2472
	}
2473
	$smcFunc['db_free_result']($request);
2474
2475
	createToken('admin-mppm');
2476
}
2477
2478
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...