ManageBoards::action_cat()   C
last analyzed

Complexity

Conditions 11
Paths 72

Size

Total Lines 94
Code Lines 53

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 132

Importance

Changes 0
Metric Value
cc 11
eloc 53
nc 72
nop 0
dl 0
loc 94
ccs 0
cts 38
cp 0
crap 132
rs 6.8787
c 0
b 0
f 0

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
 * Manage and maintain the boards and categories of the forum.
5
 *
6
 * @package   ElkArte Forum
7
 * @copyright ElkArte Forum contributors
8
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
9
 *
10
 * This file contains code covered by:
11
 * copyright: 2011 Simple Machines (http://www.simplemachines.org)
12
 *
13
 * @version 2.0 Beta 1
14
 *
15
 */
16
17
namespace ElkArte\AdminController;
18
19
use BBC\ParserWrapper;
20
use ElkArte\AbstractController;
21
use ElkArte\Action;
22
use ElkArte\BoardsTree;
23
use ElkArte\Converters\Html2BBC;
24
use ElkArte\Exceptions\Exception;
25
use ElkArte\Helper\Util;
26
use ElkArte\Languages\Txt;
27
use ElkArte\SettingsForm\SettingsForm;
28
29
/**
30
 * This class controls execution for actions in the manage boards area
31
 * of the admin panel.
32
 *
33
 * @package Boards
34
 */
35
class ManageBoards extends AbstractController
36
{
37
	/** @var int Category being worked on */
38
	public int $cat;
39
40
	/** @var int Current board id being modified */
41
	public int $boardid;
42
43
	/**
44
	 * The main dispatcher; delegates.
45
	 *
46
	 * What it does:
47
	 *
48
	 * - This is the main entry point for all the manageboards admin screens.
49
	 * - Called by ?action=admin;area=manageboards.
50
	 * - It checks the permissions, based on the sub-action, and calls a function based on the sub-action.
51
	 *
52
	 * @uses ManageBoards language file.
53
	 */
54
	public function action_index()
55
	{
56
		global $context;
57
58
		// Everything's gonna need this.
59
		Txt::load('ManageBoards');
60
61
		// Format: 'sub-action' => array('controller', 'function', 'permission'=>'need')
62
		$subActions = [
63
			'board' => [$this, 'action_board',  'permission' => 'manage_boards'],
64
			'board2' => [$this, 'action_board2', 'permission' => 'manage_boards'],
65
			'cat' => [$this, 'action_cat', 'permission' => 'manage_boards'],
66
			'cat2' => [$this, 'action_cat2', 'permission' => 'manage_boards'],
67
			'main' => [$this, 'action_main', 'permission' => 'manage_boards'],
68
			'move' => [$this, 'action_main', 'permission' => 'manage_boards'],
69
			'newcat' => [$this, 'action_cat', 'permission' => 'manage_boards'],
70
			'newboard' => [$this, 'action_board', 'permission' => 'manage_boards'],
71
			'settings' => [$this, 'action_boardSettings_display', 'permission' => 'admin_forum'],
72
		];
73
74
		// Your way will end here if you don't have permission.
75
		$action = new Action('manage_boards');
76
77
		// Default to sub-action 'main' or 'settings' depending on permissions.
78
		$subAction = $action->initialize($subActions, allowedTo('manage_boards') ? 'main' : 'settings');
79
		$context['sub_action'] = $subAction;
80
81
		// Create the tabs for the template.
82
		$context[$context['admin_menu_name']]['object']->prepareTabData([
83
			'title' => 'boards_and_cats',
84
			'help' => 'manage_boards',
85
			'description' => 'boards_and_cats_desc',
86
			'prefix' => 'mboards',
87
		]);
88
89
		$action->dispatch($subAction);
90
	}
91
92
	/**
93
	 * The main control panel thing, the screen showing all boards and categories.
94
	 *
95
	 * What it does:
96
	 *
97
	 * - Called by ?action=admin;area=manageboards or ?action=admin;area=manageboards;sa=move.
98
	 * - Requires manage_boards permission.
99
	 * - It also handles the interface for moving boards.
100
	 *
101
	 * @event integrate_boards_main Used to access global board arrays before the template
102
	 * @uses ManageBoards template, main sub-template.
103
	 */
104
	public function action_main(): void
105
	{
106
		global $txt, $context;
107
108
		theme()->getTemplates()->load('ManageBoards');
109
110
		require_once(SUBSDIR . '/Boards.subs.php');
111
112
		// Moving a board, child of, before, after, top
113
		$move_to = $this->_req->getQuery('move_to', 'trim|strval', '');
114
		if ($this->_req->compareQuery('sa', 'move', 'trim|strval')
115
			&& in_array($move_to, ['child', 'before', 'after', 'top']))
116
		{
117
			checkSession('get');
118
			$src_board = $this->_req->getQuery('src_board', 'intval', 0);
119
			validateToken('admin-bm-' . (int) $src_board, 'request');
120
121
			// Top is special, it is the top!
122
			if ($move_to === 'top')
123
			{
124
				$boardOptions = [
125
					'move_to' => $move_to,
126
					'target_category' => $this->_req->getQuery('target_cat', 'intval', 0),
127
					'move_first_child' => true,
128
				];
129
			}
130
			// Moving it after another board
131
			else
132
			{
133
				$boardOptions = [
134
					'move_to' => $move_to,
135
					'target_board' => $this->_req->getQuery('target_board', 'intval', 0),
136
					'move_first_child' => true,
137
				];
138
			}
139
140
			// Use modifyBoard to perform the action
141
			modifyBoard((int) $src_board, $boardOptions);
142
			redirectexit('action=admin;area=manageboards');
143
		}
144
145
		$boardTree = new BoardsTree(database());
146
		$boards = $boardTree->getBoards();
147
		$boardList = $boardTree->getBoardList();
148
149
		createToken('admin-sort');
150
		$move_board = $this->_req->getQuery('move', 'intval', 0);
151
		$context['move_board'] = isset($boards[$move_board]) ? $move_board : 0;
152
153
		$bbc_parser = ParserWrapper::instance();
154
		$cat_tree = $boardTree->getCategories();
155
156
		$context['categories'] = [];
157
		foreach ($cat_tree as $catid => $tree)
158
		{
159
			$context['categories'][$catid] = [
160
				'name' => $tree['node']['name'],
161
				'id' => $tree['node']['id'],
162
				'boards' => []
163
			];
164
			$move_cat = !empty($context['move_board']) && $boards[$context['move_board']]['category'] === $catid;
165
			foreach ($boardList[$catid] as $boardid)
166
			{
167
				$boards[$boardid]['description'] = $bbc_parser->parseBoard($boards[$boardid]['description']);
168
				$context['categories'][$catid]['boards'][$boardid] = [
169
					'id' => $boards[$boardid]['id'],
170
					'name' => $boards[$boardid]['name'],
171
					'description' => $boards[$boardid]['description'],
172
					'child_level' => $boards[$boardid]['level'],
173
					'move' => $move_cat && ($boardid === $context['move_board'] || $boardTree->isChildOf($boardid, (int) $context['move_board'])),
174
					'permission_profile' => $boards[$boardid]['profile'],
175
				];
176
			}
177
		}
178
179
		if (!empty($context['move_board']))
180
		{
181
			createToken('admin-bm-' . $context['move_board'], 'request');
182
183
			$context['move_title'] = sprintf($txt['mboards_select_destination'], htmlspecialchars($boards[$context['move_board']]['name'], ENT_COMPAT, 'UTF-8'));
184
			foreach ($cat_tree as $catid => $tree)
185
			{
186
				$prev_child_level = 0;
187
				$prev_board = 0;
188
				$stack = [];
189
190
				// Just a shortcut, this is the same for all the urls
191
				$security_token = $context['admin-bm-' . $context['move_board'] . '_token_var'] . '=' . $context['admin-bm-' . $context['move_board'] . '_token'];
192
				foreach ($boardList[$catid] as $boardid)
193
				{
194
					if (!isset($context['categories'][$catid]['move_link']))
195
					{
196
						$context['categories'][$catid]['move_link'] = [
197
							'child_level' => 0,
198
							'label' => $txt['mboards_order_before'] . " '" . htmlspecialchars($boards[$boardid]['name'], ENT_COMPAT, 'UTF-8') . "'",
199
							'href' => getUrl('admin', ['action' => 'admin', 'area' => 'manageboards', 'sa' => 'move', 'src_board' => $context['move_board'], 'target_board' => $boardid, 'move_to' => 'before', '{session_data}', $security_token]),
200
						];
201
					}
202
203
					if (!$context['categories'][$catid]['boards'][$boardid]['move'])
204
					{
205
						$context['categories'][$catid]['boards'][$boardid]['move_links'] = [
206
							[
207
								'child_level' => $boards[$boardid]['level'],
208
								'label' => $txt['mboards_order_after'] . "'" . htmlspecialchars($boards[$boardid]['name'], ENT_COMPAT, 'UTF-8') . "'",
209
								'href' => getUrl('admin', ['action' => 'admin', 'area' => 'manageboards', 'sa' => 'move', 'src_board' => $context['move_board'], 'target_board' => $boardid, 'move_to' => 'after', '{session_data}', $security_token]),
210
							],
211
							[
212
								'child_level' => $boards[$boardid]['level'] + 1,
213
								'label' => $txt['mboards_order_child_of'] . " '" . htmlspecialchars($boards[$boardid]['name'], ENT_COMPAT, 'UTF-8') . "'",
214
								'href' => getUrl('admin', ['action' => 'admin', 'area' => 'manageboards', 'sa' => 'move', 'src_board' => $context['move_board'], 'target_board' => $boardid, 'move_to' => 'child', '{session_data}', $security_token]),
215
							],
216
						];
217
					}
218
219
					$difference = $boards[$boardid]['level'] - $prev_child_level;
220
					if ($difference === 1)
221
					{
222
						$stack[] = empty($context['categories'][$catid]['boards'][$prev_board]['move_links']) ? null : array_shift($context['categories'][$catid]['boards'][$prev_board]['move_links']);
223
					}
224
					elseif ($difference < 0)
225
					{
226
						if (empty($context['categories'][$catid]['boards'][$prev_board]['move_links']))
227
						{
228
							$context['categories'][$catid]['boards'][$prev_board]['move_links'] = [];
229
						}
230
231
						for ($i = 0; $i < -$difference; $i++)
232
						{
233
							if (($temp = array_pop($stack)) !== null)
234
							{
235
								array_unshift($context['categories'][$catid]['boards'][$prev_board]['move_links'], $temp);
236
							}
237
						}
238
					}
239
240
					$prev_board = $boardid;
241
					$prev_child_level = $boards[$boardid]['level'];
242
				}
243
244
				if (!empty($stack) && !empty($context['categories'][$catid]['boards'][$prev_board]['move_links']))
245
				{
246
					$context['categories'][$catid]['boards'][$prev_board]['move_links'] = array_merge($stack, $context['categories'][$catid]['boards'][$prev_board]['move_links']);
247
				}
248
				elseif (!empty($stack))
249
				{
250
					$context['categories'][$catid]['boards'][$prev_board]['move_links'] = $stack;
251
				}
252
253
				if (empty($boardList[$catid]))
254
				{
255
					$context['categories'][$catid]['move_link'] = [
256
						'child_level' => 0,
257
						'label' => $txt['mboards_order_before'] . " '" . htmlspecialchars($tree['node']['name'], ENT_COMPAT, 'UTF-8') . "'",
258
						'href' => getUrl('admin', ['action' => 'admin', 'area' => 'manageboards', 'sa' => 'move', 'src_board' => $context['move_board'], 'target_cat' => $catid, 'move_to' => 'top', '{session_data}', $security_token]),
259
					];
260
				}
261
			}
262
		}
263
264
		call_integration_hook('integrate_boards_main');
265
266
		$context['page_title'] = $txt['boards_and_cats'];
267
		$context['sub_template'] = 'manage_boards';
268
		$context['can_manage_permissions'] = allowedTo('manage_permissions');
269
	}
270
271
	/**
272
	 * Function for handling a submitted form saving the category.
273
	 *
274
	 * What it does:
275
	 *
276
	 * - Complete the modifications to a specific category.
277
	 * - It also handles deletion of a category.
278
	 * - It requires manage_boards permission.
279
	 * - Called by ?action=admin;area=manageboards;sa=cat2
280
	 * - Redirects to ?action=admin;area=manageboards.
281
	 */
282
	public function action_cat2(): void
283
	{
284
		checkSession();
285
		validateToken('admin-bc-' . $this->_req->post->cat);
286
287
		require_once(SUBSDIR . '/Categories.subs.php');
288
289
		$this->cat = $this->_req->getPost('cat', 'intval');
290
291
		// Add a new category or modify an existing one...
292
		if (isset($this->_req->post->edit) || isset($this->_req->post->add))
293
		{
294
			$catOptions = [];
295
296
			if (isset($this->_req->post->cat_order))
297
			{
298
				$catOptions['move_after'] = (int) $this->_req->post->cat_order;
299
			}
300
301
			// Change "This & That" to "This &amp; That" but don't change "&cent" to "&amp;cent;"...
302
			$catOptions['cat_name'] = preg_replace('~[&]([^;]{8}|[^;]{0,8}$)~', '&amp;$1', $this->_req->post->cat_name);
303
			$catOptions['is_collapsible'] = isset($this->_req->post->collapse);
304
305
			if (isset($this->_req->post->add))
306
			{
307
				createCategory($catOptions);
308
			}
309
			else
310
			{
311
				modifyCategory($this->cat, $catOptions);
312
			}
313
		}
314
		// If they want to delete - first give them confirmation.
315
		elseif (isset($this->_req->post->delete) && !isset($this->_req->post->confirmation) && !isset($this->_req->post->empty))
316
		{
317
			$this->action_cat();
318
319
			return;
320
		}
321
		// Delete the category!
322
		elseif (isset($this->_req->post->delete))
323
		{
324
			// First off - check if we are moving all the current boards first - before we start deleting!
325
			if ($this->_req->comparePost('delete_action', 1, 'intval'))
326
			{
327
				if (empty($this->_req->post->cat_to))
328
				{
329
					throw new Exception('mboards_delete_error');
330
				}
331
332
				deleteCategories([$this->cat], $this->_req->getPost('cat_to', 'intval'));
333
			}
334
			else
335
			{
336
				deleteCategories([$this->cat]);
337
			}
338
		}
339
340
		redirectexit('action=admin;area=manageboards');
341
	}
342
343
	/**
344
	 * Modify a specific category.
345
	 *
346
	 * What it does:
347
	 *
348
	 * - Screen for editing and repositioning a category.
349
	 * - Also used to show the confirmation deletion of category screen
350
	 * - Called by ?action=admin;area=manageboards;sa=cat
351
	 * - Requires manage_boards permission.
352
	 *
353
	 * @event integrate_edit_category access category globals before the template
354
	 * @uses ManageBoards template, modify_category sub-template.
355
	 */
356
	public function action_cat(): void
357
	{
358
		global $txt, $context;
359
360
		theme()->getTemplates()->load('ManageBoards');
361
		require_once(SUBSDIR . '/Boards.subs.php');
362
		$boardTree = new BoardsTree(database());
363
		$cat_tree = $boardTree->getCategories();
364
365
		// id_cat must be a number... if it exists.
366
		$this->cat = $this->_req->getQuery('cat', 'intval', 0);
367
368
		// Start with one - "In the first place".
369
		$context['category_order'] = [
370
			[
371
				'id' => 0,
372
				'name' => $txt['mboards_order_first'],
373
				'selected' => !empty($this->cat) && !empty($cat_tree[$this->cat]['is_first']),
374
				'true_name' => ''
375
			]
376
		];
377
378
		// If this is a new category, set up some defaults.
379
		if ($this->_req->compareQuery('sa', 'newcat', 'trim'))
380
		{
381
			$context['category'] = [
382
				'id' => 0,
383
				'name' => $txt['mboards_new_cat_name'],
384
				'editable_name' => htmlspecialchars($txt['mboards_new_cat_name'], ENT_COMPAT, 'UTF-8'),
385
				'can_collapse' => true,
386
				'is_new' => true,
387
				'is_empty' => true
388
			];
389
		}
390
		// Category doesn't exist, man... sorry.
391
		elseif ($boardTree->categoryExists($this->cat) === false)
392
		{
393
			redirectexit('action=admin;area=manageboards');
394
		}
395
		else
396
		{
397
			$context['category'] = [
398
				'id' => $this->cat,
399
				'name' => $cat_tree[$this->cat]['node']['name'],
400
				'editable_name' => htmlspecialchars($cat_tree[$this->cat]['node']['name'], ENT_COMPAT, 'UTF-8'),
401
				'can_collapse' => !empty($cat_tree[$this->cat]['node']['can_collapse']),
402
				'children' => [],
403
				'is_empty' => empty($cat_tree[$this->cat]['children'])
404
			];
405
406
			$boardCat = $boardTree->getBoardsInCat($this->cat);
407
			$boards = $boardTree->getBoards();
408
			foreach ($boardCat as $child_board)
409
			{
410
				$context['category']['children'][] = str_repeat('-', $boards[$child_board]['level']) . ' ' . $boards[$child_board]['name'];
411
			}
412
		}
413
414
		$prevCat = 0;
415
		foreach ($cat_tree as $catid => $tree)
416
		{
417
			if ($catid === $this->cat && $prevCat > 0)
418
			{
419
				$context['category_order'][$prevCat]['selected'] = true;
420
			}
421
			elseif ($catid !== $this->cat)
422
			{
423
				$context['category_order'][$catid] = [
424
					'id' => $catid,
425
					'name' => $txt['mboards_order_after'] . $tree['node']['name'],
426
					'selected' => false,
427
					'true_name' => $tree['node']['name']
428
				];
429
			}
430
431
			$prevCat = $catid;
432
		}
433
434
		if (!isset($this->_req->query->delete))
435
		{
436
			$context['sub_template'] = 'modify_category';
437
			$context['page_title'] = $this->_req->compareQuery('sa', 'newcat') ? $txt['mboards_new_cat_name'] : $txt['catEdit'];
438
		}
439
		else
440
		{
441
			$context['sub_template'] = 'confirm_category_delete';
442
			$context['page_title'] = $txt['mboards_delete_cat'];
443
		}
444
445
		// Create a special token.
446
		$context['token_check'] = 'admin-bc-' . $this->cat;
447
		createToken($context['token_check']);
448
449
		call_integration_hook('integrate_edit_category');
450
	}
451
452
	/**
453
	 * Make changes to/delete a board.
454
	 *
455
	 * What it does:
456
	 *
457
	 * - Function for handling a submitted form saving the board.
458
	 * - It also handles deletion of a board.
459
	 * - Called by ?action=admin;area=manageboards;sa=board2
460
	 * - Redirects to ?action=admin;area=manageboards.
461
	 * - It requires manage_boards permission.
462
	 *
463
	 * @event integrate_save_board
464
	 */
465
	public function action_board2(): void
466
	{
467
		global $context;
468
469
		$board_id = $this->_req->getPost('boardid', 'intval', 0);
470
		checkSession();
471
		validateToken('admin-be-' . $this->_req->post->boardid);
472
473
		require_once(SUBSDIR . '/Boards.subs.php');
474
		require_once(SUBSDIR . '/Post.subs.php');
475
476
		$posts = getBoardProperties($this->_req->post->boardid)['numPosts'];
477
478
		// Mode: modify aka. don't delete.
479
		if (isset($this->_req->post->edit) || isset($this->_req->post->add))
480
		{
481
			$boardOptions = [];
482
483
			// Move this board to a new category?
484
			if (!empty($this->_req->post->new_cat))
485
			{
486
				$boardOptions['move_to'] = 'bottom';
487
				$boardOptions['target_category'] = (int) $this->_req->post->new_cat;
488
			}
489
			// Change the boardorder of this board?
490
			elseif (!empty($this->_req->post->placement) && !empty($this->_req->post->board_order))
491
			{
492
				if (!in_array($this->_req->post->placement, ['before', 'after', 'child']))
493
				{
494
					throw new Exception('mangled_post', false);
495
				}
496
497
				$boardOptions['move_to'] = $this->_req->post->placement;
498
				$boardOptions['target_board'] = (int) $this->_req->post->board_order;
499
			}
500
501
			// Checkboxes....
502
			$boardOptions['posts_count'] = isset($this->_req->post->count);
503
			$boardOptions['old_posts'] = isset($this->_req->post->old_posts);
504
			$boardOptions['override_theme'] = isset($this->_req->post->override_theme);
505
			$boardOptions['board_theme'] = (int) $this->_req->post->boardtheme;
506
			$boardOptions['access_groups'] = [];
507
			$boardOptions['deny_groups'] = [];
508
509
			if (!empty($this->_req->post->groups))
510
			{
511
				foreach ($this->_req->post->groups as $group => $action)
512
				{
513
					if ($action === 'allow')
514
					{
515
						$boardOptions['access_groups'][] = (int) $group;
516
					}
517
					elseif ($action === 'deny')
518
					{
519
						$boardOptions['deny_groups'][] = (int) $group;
520
					}
521
				}
522
			}
523
524
			if (strlen(implode(',', $boardOptions['access_groups'])) > 255 || strlen(implode(',', $boardOptions['deny_groups'])) > 255)
525
			{
526
				throw new Exception('too_many_groups', false);
527
			}
528
529
			// Change '1 & 2' to '1 &amp; 2', but not '&amp;' to '&amp;amp;'...
530
			$boardOptions['board_name'] = preg_replace('~[&]([^;]{8}|[^;]{0,8}$)~', '&amp;$1', $this->_req->post->board_name);
531
532
			// Convert any HTML to bbc
533
			$parser = new Html2BBC($this->_req->post->desc);
534
			$boardOptions['board_description'] = Util::htmlspecialchars($parser->get_bbc());
535
			preparsecode($boardOptions['board_description']);
536
537
			$boardOptions['moderator_string'] = $this->_req->post->moderators;
538
539
			if (isset($this->_req->post->moderator_list) && is_array($this->_req->post->moderator_list))
540
			{
541
				$moderators = [];
542
				foreach ($this->_req->post->moderator_list as $moderator)
543
				{
544
					$moderators[(int) $moderator] = (int) $moderator;
545
				}
546
547
				$boardOptions['moderators'] = $moderators;
548
			}
549
550
			// Are they doing redirection?
551
			$boardOptions['redirect'] = $this->_req->comparePost('redirect_address', '', 'trim') ? '' : $this->_req->get('redirect_address');
552
553
			// Profiles...
554
			$boardOptions['profile'] = $this->_req->post->profile;
555
			$boardOptions['inherit_permissions'] = (int) $this->_req->post->profile === -1;
556
557
			// We need to know what used to be the case in terms of redirection.
558
			if (!empty($board_id))
559
			{
560
				$properties = getBoardProperties($board_id);
561
562
				// If we're turning redirection on, check the board doesn't have posts in it - if it does, don't make it a redirection board.
563
				if ($boardOptions['redirect'] && empty($properties['oldRedirect']) && $properties['numPosts'])
564
				{
565
					unset($boardOptions['redirect']);
566
				}
567
				// Reset the redirection count when switching on/off.
568
				elseif (empty($boardOptions['redirect']) !== empty($properties['oldRedirect']))
569
				{
570
					$boardOptions['num_posts'] = 0;
571
				}
572
				// Resetting the count?
573
				elseif ($boardOptions['redirect'] && !empty($this->_req->post->reset_redirect))
574
				{
575
					$boardOptions['num_posts'] = 0;
576
				}
577
			}
578
579
			call_integration_hook('integrate_save_board', [$board_id, &$boardOptions]);
580
581
			// Create a new board...
582
			if (isset($this->_req->post->add))
583
			{
584
				// New boards by default go to the bottom of the category.
585
				if (empty($this->_req->post->new_cat))
586
				{
587
					$boardOptions['target_category'] = $this->_req->getPost('cur_cat', 'intval', 0);
588
				}
589
590
				if (!isset($boardOptions['move_to']))
591
				{
592
					$boardOptions['move_to'] = 'bottom';
593
				}
594
595
				createBoard($boardOptions);
596
			}
597
			// ...or update an existing board.
598
			else
599
			{
600
				modifyBoard($board_id, $boardOptions);
601
			}
602
		}
603
		elseif (isset($this->_req->post->delete) && !isset($this->_req->post->confirmation) && !isset($this->_req->post->no_children))
604
		{
605
			if ($posts)
606
			{
607
				throw new Exception('mboards_delete_board_has_posts');
608
			}
609
			$this->action_board();
610
611
			return;
612
		}
613
		elseif (isset($this->_req->post->delete))
614
		{
615
			$boardTree = new BoardsTree(database());
616
			// First, check if our board still has posts or topics.
617
			if ($posts)
618
			{
619
				throw new Exception('mboards_delete_board_has_posts');
620
			}
621
622
			if ($this->_req->comparePost('delete_action', 1, 'intval'))
623
			{
624
				// Check if we are moving all the current sub-boards first - before we start deleting!
625
				if (empty($this->_req->post->board_to))
626
				{
627
					throw new Exception('mboards_delete_board_error');
628
				}
629
				$boardTree->deleteBoards([$board_id], $this->_req->getPost('board_to', 'intval'));
630
			}
631
			else
632
			{
633
				$boardTree->deleteBoards([$board_id], 0);
634
			}
635
		}
636
637
		if ($this->_req->compareQuery('rid', 'permissions', 'trim'))
638
		{
639
			redirectexit('action=admin;area=permissions;sa=board;' . $context['session_var'] . '=' . $context['session_id']);
640
		}
641
		else
642
		{
643
			redirectexit('action=admin;area=manageboards');
644
		}
645
	}
646
647
	/**
648
	 * Modify a specific board...
649
	 *
650
	 * What it does
651
	 * - Screen for editing and repositioning a board.
652
	 * - Called by ?action=admin;area=manageboards;sa=board
653
	 * - Used to show the confirmation deletion of category screen (sub-template confirm_board_delete).
654
	 * - Requires manage_boards permission.
655
	 *
656
	 * @event integrate_edit_board
657
	 * @uses the modify_board sub-template of the ManageBoards template.
658
	 * @uses ManagePermissions language
659
	 */
660
	public function action_board(): void
661
	{
662
		global $txt, $context, $modSettings;
663
664
		theme()->getTemplates()->load('ManageBoards');
665
		require_once(SUBSDIR . '/Boards.subs.php');
666
		require_once(SUBSDIR . '/Post.subs.php');
667
		$boardTree = new BoardsTree(database());
668
669
		// For editing the profile, we'll need this.
670
		Txt::load('ManagePermissions');
671
		require_once(SUBSDIR . '/ManagePermissions.subs.php');
672
		loadPermissionProfiles();
673
674
		// id_board must be a number...
675
		$this->boardid = $this->_req->getQuery('boardid', 'intval', 0);
676
		if ($boardTree->boardExists($this->boardid) === false)
677
		{
678
			$this->boardid = 0;
679
			$this->_req->query->sa = 'newboard';
680
		}
681
682
		if ($this->_req->compareQuery('sa', 'newboard', 'trim'))
683
		{
684
			$this->cat = $this->_req->getQuery('cat', 'intval', 0);
685
686
			// Category doesn't exist, man... sorry.
687
			if (empty($this->cat))
688
			{
689
				redirectexit('action=admin;area=manageboards');
690
			}
691
692
			// Some things that need to be set up for a new board.
693
			$curBoard = [
694
				'member_groups' => [0, -1],
695
				'deny_groups' => [],
696
				'category' => $this->cat
697
			];
698
			$context['board_order'] = [];
699
			$context['board'] = [
700
				'is_new' => true,
701
				'id' => 0,
702
				'name' => $txt['mboards_new_board_name'],
703
				'description' => '',
704
				'count_posts' => 1,
705
				'old_posts' => 1,
706
				'posts' => 0,
707
				'topics' => 0,
708
				'theme' => 0,
709
				'profile' => 1,
710
				'override_theme' => 0,
711
				'redirect' => '',
712
				'category' => $this->cat,
713
				'no_children' => true,
714
			];
715
		}
716
		else
717
		{
718
			// Just some easy shortcuts.
719
			$curBoard = $boardTree->getBoardById($this->boardid);
720
			$context['board'] = $curBoard;
721
			$context['board']['name'] = htmlspecialchars(strtr($context['board']['name'], ['&amp;' => '&']), ENT_COMPAT, 'UTF-8');
722
			$context['board']['description'] = un_preparsecode($context['board']['description']);
723
			$context['board']['no_children'] = empty($curBoard['tree']['children']);
724
			$context['board']['is_recycle'] = !empty($modSettings['recycle_enable']) && !empty($modSettings['recycle_board']) && $modSettings['recycle_board'] == $context['board']['id'];
725
		}
726
727
		// As we may have come from the permissions screen, keep track of where we should go on save.
728
		$context['redirect_location'] = $this->_req->compareQuery('rid', 'permissions', 'trim') ? 'permissions' : 'boards';
729
730
		// We might need this to hide links to certain areas.
731
		$context['can_manage_permissions'] = allowedTo('manage_permissions');
732
733
		// Default membergroups.
734
		$context['groups'] = [
735
			-1 => [
736
				'id' => '-1',
737
				'name' => $txt['parent_guests_only'],
738
				'allow' => in_array('-1', $curBoard['member_groups']),
739
				'deny' => in_array('-1', $curBoard['deny_groups']),
740
				'is_post_group' => false,
741
			],
742
			0 => [
743
				'id' => '0',
744
				'name' => $txt['parent_members_only'],
745
				'allow' => in_array('0', $curBoard['member_groups']),
746
				'deny' => in_array('0', $curBoard['deny_groups']),
747
				'is_post_group' => false,
748
			]
749
		];
750
751
		$context['groups'] += getOtherGroups($curBoard, $this->_req->compareQuery('sa', 'newboard'));
752
753
		// Category doesn't exist, man... sorry.
754
		if ($boardTree->categoryExists($curBoard['category']) === false)
755
		{
756
			redirectexit('action=admin;area=manageboards');
757
		}
758
759
		$catBoards = $boardTree->getBoardsInCat($curBoard['category']);
760
		foreach ($catBoards as $boardid)
761
		{
762
			$thisBoard = $boardTree->getBoardById($boardid);
763
			if ($boardid === $this->boardid)
764
			{
765
				$context['board_order'][] = [
766
					'id' => $boardid,
767
					'name' => str_repeat('-', $thisBoard['level']) . ' (' . $txt['mboards_current_position'] . ')',
768
					'children' => $thisBoard['tree']['children'],
769
					'no_children' => empty($thisBoard['tree']['children']),
770
					'is_child' => false,
771
					'selected' => true
772
				];
773
			}
774
			else
775
			{
776
				$context['board_order'][] = [
777
					'id' => $boardid,
778
					'name' => str_repeat('-', $thisBoard['level']) . ' ' . $thisBoard['name'],
779
					'is_child' => !empty($this->boardid) && $boardTree->isChildOf($boardid, $this->boardid),
780
					'selected' => false
781
				];
782
			}
783
		}
784
785
		// Are there any places to move sub-boards to in the case where we are confirming delete?
786
		if (!empty($this->boardid))
787
		{
788
			$context['can_move_children'] = false;
789
			$context['children'] = $curBoard['tree']['children'];
790
			foreach ($context['board_order'] as $board)
791
			{
792
				if ($board['is_child'] !== false)
793
				{
794
					continue;
795
				}
796
797
				if ($board['selected'] !== false)
798
				{
799
					continue;
800
				}
801
802
				$context['can_move_children'] = true;
803
			}
804
		}
805
806
		// Get other available categories.
807
		$context['categories'] = [];
808
		$cat_tree = $boardTree->getCategories();
809
		foreach ($cat_tree as $catID => $tree)
810
		{
811
			$context['categories'][] = [
812
				'id' => $catID === $curBoard['category'] ? 0 : $catID,
813
				'name' => $tree['node']['name'],
814
				'selected' => $catID === $curBoard['category']
815
			];
816
		}
817
818
		$context['board']['moderators'] = getBoardModerators($this->boardid);
819
		$context['board']['moderator_list'] = empty($context['board']['moderators']) ? '' : '&quot;' . implode('&quot;, &quot;', $context['board']['moderators']) . '&quot;';
820
821
		if (!empty($context['board']['moderators']))
822
		{
823
			[$context['board']['last_moderator_id']] = array_slice(array_keys($context['board']['moderators']), -1);
824
		}
825
826
		$context['themes'] = getAllThemes();
827
828
		if (!isset($this->_req->query->delete))
829
		{
830
			$context['sub_template'] = 'modify_board';
831
			$context['page_title'] = $txt['boardsEdit'];
832
			loadJavascriptFile('suggest.js', ['defer' => true]);
833
		}
834
		else
835
		{
836
			$context['sub_template'] = 'confirm_board_delete';
837
			$context['page_title'] = $txt['mboards_delete_board'];
838
		}
839
840
		// Create a special token.
841
		createToken('admin-be-' . $this->boardid);
842
843
		call_integration_hook('integrate_edit_board');
844
	}
845
846
	/**
847
	 * A screen to display and allow setting a few general board and category settings.
848
	 *
849
	 * @event integrate_save_board_settings called during manage board settings
850
	 * @uses modify_general_settings sub-template.
851
	 */
852
	public function action_boardSettings_display(): void
853
	{
854
		global $context, $txt;
855
856
		// Initialize the form
857
		$settingsForm = new SettingsForm(SettingsForm::DB_ADAPTER);
858
859
		// Initialize it with our settings
860
		$settingsForm->setConfigVars($this->_settings());
861
862
		// Add some JavaScript stuff for the recycle box.
863
		theme()->addInlineJavascript('
864
				document.getElementById("recycle_board").disabled = !document.getElementById("recycle_enable").checked;', true);
865
866
		// Get the necessary template bits
867
		theme()->getTemplates()->load('ManageBoards');
868
		$context['page_title'] = $txt['boards_and_cats'] . ' - ' . $txt['settings'];
869
		$context['sub_template'] = 'show_settings';
870
		$context['post_url'] = getUrl('admin', ['action' => 'admin', 'area' => 'manageboards', 'sa' => 'settings', 'save']);
871
872
		// Warn the admin against selecting the recycle topic without selecting a board.
873
		$context['force_form_onsubmit'] = "if(document.getElementById('recycle_enable').checked && document.getElementById('recycle_board').value == 0) { return confirm('" . $txt['recycle_board_unselected_notice'] . "');} return true;";
874
875
		// Doing a save?
876
		if ($this->_req->hasQuery('save'))
877
		{
878
			checkSession();
879
880
			call_integration_hook('integrate_save_board_settings');
881
882
			$settingsForm->setConfigValues((array) $this->_req->post);
883
			$settingsForm->save();
884
			redirectexit('action=admin;area=manageboards;sa=settings');
885
		}
886
887
		// Prepare the settings...
888
		$settingsForm->prepare();
889
	}
890
891
	/**
892
	 * Retrieve and return all admin settings for boards management.
893
	 *
894
	 * @event integrate_modify_board_settings add config settings to boards management
895
	 */
896
	private function _settings()
897
	{
898
		global $txt;
899
900
		// We need to borrow a string from here
901
		Txt::load('ManagePermissions');
902
903
		// Load the boards list - for the recycle bin!
904
		require_once(SUBSDIR . '/Boards.subs.php');
905
		$boards = getBoardList(['override_permissions' => true, 'not_redirection' => true], true);
906
		$recycle_boards = [''];
907
		foreach ($boards as $board)
908
		{
909
			$recycle_boards[$board['id_board']] = $board['cat_name'] . ' - ' . $board['board_name'];
910
		}
911
912
		// Here and the board settings...
913
		$config_vars = [
914
			['title', 'settings'],
915
			// Inline permissions.
916
			['permissions', 'manage_boards', 'helptext' => $txt['permissionhelp_manage_boards'], 'collapsed' => true],
917
			'',
918
			// Other board settings.
919
			['check', 'countChildPosts'],
920
			['check', 'recycle_enable', 'onclick' => "document.getElementById('recycle_board').disabled = !this.checked;"],
921
			['select', 'recycle_board', $recycle_boards],
922
			['check', 'allow_ignore_boards'],
923
			['check', 'deny_boards_access'],
924
		];
925 4
926
		// Add new settings with a nice hook, makes them available for admin settings search as well
927 4
		call_integration_hook('integrate_modify_board_settings', [&$config_vars]);
928
929
		return $config_vars;
930 4
	}
931
932
	/**
933 4
	 * Return the form settings for use in admin search
934 4
	 */
935 4
	public function settings_search()
936 4
	{
937
		return $this->_settings();
938 4
	}
939
}
940