MessageIndex::prepareQuickTopic()   A
last analyzed

Complexity

Conditions 6
Paths 7

Size

Total Lines 25
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 6
eloc 14
c 2
b 0
f 1
nc 7
nop 0
dl 0
loc 25
ccs 0
cts 0
cp 0
crap 42
rs 9.2222
1
<?php
2
3
/**
4
 * This file is what shows the listing of topics in a board.
5
 * It's just one or two functions, but don't underestimate it ;).
6
 *
7
 * @package   ElkArte Forum
8
 * @copyright ElkArte Forum contributors
9
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
10
 *
11
 * This file contains code covered by:
12
 * copyright: 2011 Simple Machines (http://www.simplemachines.org)
13
 *
14
 * @version 2.0 Beta 1
15
 *
16
 */
17
18
namespace ElkArte\Controller;
19
20
use BBC\ParserWrapper;
21
use ElkArte\AbstractController;
22
use ElkArte\BoardsList;
23
use ElkArte\EventManager;
24
use ElkArte\FrontpageInterface;
25
use ElkArte\Helper\DataValidator;
26
use ElkArte\MembersList;
27
use ElkArte\TopicUtil;
28
use ElkArte\User;
29
30
/**
31
 * The all powerful messageindex, shows all the topics on a given board
32
 */
33
class MessageIndex extends AbstractController implements FrontpageInterface
34
{
35
	/** @var string The db column wer are going to sort */
36
	public $sort_column = '';
37
38
	/** @var array Know sort methods to db column */
39
	public $sort_methods = [];
40
41
	/** @var bool Sort direction asc or desc */
42
	public $ascending = '';
43
44
	/** @var bool if we are marking as read */
45
	public $is_marked_notify;
46
47
	/** @var string Chosen sort method from the request */
48
	public $sort_by;
49
50
	/** @var int Basically the page start */
51
	public $sort_start;
52
53
	/**
54
	 * {@inheritDoc}
55
	 */
56
	public static function frontPageHook(&$default_action)
57
	{
58
		add_integration_function('integrate_menu_buttons', '\\ElkArte\\Controller\\MessageIndex::addForumButton', '', false);
59
		add_integration_function('integrate_current_action', '\\ElkArte\\Controller\\MessageIndex::fixCurrentAction', '', false);
60
61
		$default_action = [
62
			'controller' => MessageIndex::class,
63
			'function' => 'action_messageindex_fp'
64
		];
65
	}
66
67
	/**
68
	 * {@inheritDoc}
69
	 */
70
	public static function frontPageOptions()
71
	{
72
		parent::frontPageOptions();
73
74
		theme()->addInlineJavascript('
75
			document.getElementById("front_page").addEventListener("change", function() {
76
			    let base = document.getElementById("message_index_frontpage").parentNode;
77
			
78
			    if (this.value.endsWith("MessageIndex")) 
79
			    {
80
			        base.fadeIn();
81
			        base.previousElementSibling.fadeIn();
82
			    }
83
			    else 
84
			    {
85
			        base.fadeOut();
86
			        base.previousElementSibling.fadeOut();
87
			    }
88
			});
89
			
90
			// Trigger change event
91
			let event = new Event("change");
92
			document.getElementById("front_page").dispatchEvent(event);', true);
93
94
		return [['select', 'message_index_frontpage', self::_getBoardsList()]];
95
	}
96
97
	/**
98
	 * Return the board listing for use in this class
99
	 *
100
	 * @return string[] list of boards with key = id and value = cat + name
101
	 * @uses getBoardList()
102
	 */
103
	protected static function _getBoardsList(): array
104
	{
105
		// Load the boards list.
106
		require_once(SUBSDIR . '/Boards.subs.php');
107
		$boards_list = getBoardList(['override_permissions' => true, 'not_redirection' => true], true);
108
109
		$boards = [];
110
		foreach ($boards_list as $board)
111
		{
112
			$boards[$board['id_board']] = $board['cat_name'] . ' - ' . $board['board_name'];
113
		}
114
115 2
		return $boards;
116
	}
117
118 2
	/**
119 2
	 * {@inheritDoc}
120
	 */
121
	public static function validateFrontPageOptions($post)
122
	{
123
		parent::validateFrontPageOptions($post);
124
		$boards = self::_getBoardsList();
125
126 2
		if (empty($post->message_index_frontpage) || !isset($boards[$post->message_index_frontpage]))
127
		{
128 2
			$post->front_page = null;
129 2
130
			return false;
131
		}
132 2
133
		return true;
134
	}
135 2
136
	/**
137
	 * Dispatches forward to message index handler.
138
	 *
139
	 * @see AbstractController::action_index
140
	 */
141 2
	public function action_index()
142 2
	{
143
		// Forward to the message index, it's not like we know much more :P
144 2
		$this->action_messageindex();
145
	}
146 2
147 2
	/**
148 2
	 * Show the list of topics in this board, along with any sub-boards.
149 2
	 *
150
	 * @uses template_topic_listing() sub template of the MessageIndex template
151
	 */
152 2
	public function action_messageindex(): void
153
	{
154
		global $txt, $context, $board_info;
155 2
156 2
		// Check for the redirection board, and if found, head off
157 2
		if ($board_info['redirect'])
158
		{
159
			$this->handleRedirectBoard();
160 2
		}
161 2
162
		// Load any necessary resources
163
		$this->loadSupportingResources();
164 2
165
		// Initialize $context
166 2
		$this->initializeContext();
167
168
		// Build a list of unapproved posts, if applicable
169
		if ($this->currentUserCanApprovePosts() && $this->hasUnapprovedPosts())
170 2
		{
171
			$context['unapproved_posts_message'] = $this->buildUnapprovedPostsMessage();
172
		}
173
174
		// Make sure the starting place makes sense and construct the page index
175
		$this->setPageNavigation();
176 2
177
		// Prepare profile links to those who can moderate on this board
178
		$this->setBoardModeratorLinks();
179
180
		// Mark current and parent boards as seen.
181
		$this->markCurrentAndParentBoardsAsSeen();
182
183
		// Load basic information about the boards children, aka sub boards
184 2
		$this->prepareSubBoardsForDisplay();
185
186
		// Who else is taking a look?
187 2
		$this->prepareWhoViewing();
188 2
189
		// Setup topic sort icons/options for template use
190
		$this->setSortIcons();
191 2
192
		// Load the topic listing, accounting for sort, start page, etc.
193
		$this->loadBoardTopics();
194
195
		// What quick moderation options are available?
196 2
		$this->quickModeration();
197
198 2
		// Set template details/layers
199
		$template_layers = theme()->getLayers();
200
		if (!empty($context['boards']) && $this->sort_start === 0)
201
		{
202
			$template_layers->add('display_child_boards');
203
		}
204
205
		// If there are children, but no topics and no ability to post topics...
206
		$context['no_topic_listing'] = !empty($context['boards']) && empty($context['topics']) && !$context['can_post_new'];
207 2
208 2
		$template_layers->add('topic_listing');
209
210
		theme()->addJavascriptVar(['notification_board_notice' => $this->is_marked_notify ? $txt['notification_disable_board'] : $txt['notification_enable_board']], true);
211 2
212
		// Is Quick Topic available?
213
		$this->quickTopic();
214 2
215 2
		// Finally, action buttons like start a new topic, notify, mark read ...
216
		$this->buildBoardButtons();
217
	}
218 2
219 2
	/**
220 2
	 * Handles redirection for a board. Increments the number of posts in the board
221
	 * and redirects to the specified board URL.
222
	 */
223 2
	private function handleRedirectBoard(): void
224
	{
225
		global $board, $board_info;
226
227
		// If this is a redirection board, head off.
228
		require_once(SUBSDIR . '/Boards.subs.php');
229
230 2
		incrementBoard($board, 'num_posts');
231 2
		redirectexit($board_info['redirect']);
232 2
	}
233
234
	/**
235
	 * Initializes the context by setting various variables for the template.
236
	 */
237
	private function initializeContext(): void
238
	{
239
		global $txt, $context, $board_info, $modSettings;
240
241 2
		$description = ParserWrapper::instance()->parseBoard($board_info['description']);
242
243
		$context += [
244 2
			'name' => $board_info['name'],
245
			'sub_template' => 'topic_listing',
246
			'description' => $description,
247 2
			'robot_no_index' => $this->setRobotNoIndex(),
248
			// 'Print' the header and board info.
249
			'page_title' => strip_tags($board_info['name']),
250
			'page_description' => strip_tags($description),
251
			// Set the variables up for the template.
252
			'can_mark_notify' => $this->currentUserCanMarkNotify(),
253
			'can_post_new' => $this->currentUserCanPostNew(),
254 2
			'can_post_poll' => $this->currentUserCanPostPoll(),
255
			'can_moderate_forum' => $this->currentUserCanModerate(),
256
			'can_approve_posts' => $this->currentUserCanApprovePosts(),
257
			'jump_to' => [
258 2
				'label' => addslashes(un_htmlspecialchars($txt['jump_to'])),
259
				'board_name' => htmlspecialchars(strtr(strip_tags($board_info['name']), ['&amp;' => '&']), ENT_COMPAT, 'UTF-8'),
260
				'child_level' => $board_info['child_level'],
261 2
			],
262
			'message_index_preview' => !empty($modSettings['message_index_preview'])
263
		];
264
	}
265
266
	/**
267
	 * Sets if this is a page that we do, or do not, want bots to index
268
	 *
269
	 * @return bool
270
	 */
271
	public function setRobotNoIndex(): bool
272
	{
273 2
		global $modSettings;
274
275
		foreach ($this->_req->query as $k => $v)
276
		{
277
			// Don't index a sort result etc.
278
			if (!in_array($k, ['board', 'start', session_name()], true))
279 2
			{
280
				return true;
281
			}
282
		}
283
284
		$start = $this->_req->getQuery('start', 'intval', 0);
285
		return $start !== 0 && ($start % $modSettings['defaultMaxMessages'] !== 0);
286
	}
287 2
288
	/**
289
	 * Checks whether the current user has permission to mark notifications
290 2
	 *
291 2
	 * @return bool True if the current user can mark notifications, false otherwise
292 2
	 */
293 2
	private function currentUserCanMarkNotify(): bool
294 2
	{
295
		return allowedTo('mark_notify') && $this->user->is_guest === false;
0 ignored issues
show
Bug Best Practice introduced by
The property is_guest does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
296
	}
297
298 2
	/**
299 2
	 * Checks if the current user is allowed to post new topics
300 2
	 *
301
	 * @return bool Returns true if the current user is allowed to post new topics, otherwise false.
302 2
	 */
303
	private function currentUserCanPostNew(): bool
304 2
	{
305 2
		global $modSettings;
306
307
		return allowedTo('post_new') || ($modSettings['postmod_active'] && allowedTo('post_unapproved_topics'));
308 2
	}
309
310
	/**
311
	 * Checks if the current user can post a poll
312
	 *
313
	 * @return bool Returns true if the current user can post a poll, false otherwise
314
	 */
315 2
	private function currentUserCanPostPoll(): bool
316
	{
317 2
		global $modSettings;
318 2
319
		return !empty($modSettings['pollMode']) && allowedTo('poll_post') && $this->currentUserCanPostNew();
320
	}
321
322
	/**
323
	 * Checks if the current user is allowed to moderate the forum
324
	 *
325
	 * @return bool Returns true if the current user is allowed to moderate the forum, false otherwise
326
	 */
327 2
	private function currentUserCanModerate(): bool
328
	{
329 2
		return allowedTo('moderate_forum');
330 2
	}
331
332
	/**
333 2
	 * Checks if the current user has the permission to approve posts
334
	 *
335
	 * @return bool True if the current user can approve posts, false otherwise
336 2
	 */
337
	private function currentUserCanApprovePosts(): bool
338 1
	{
339
		return allowedTo('approve_posts');
340 2
	}
341 2
342 2
	/**
343 2
	 * Check if the current user can restore a topic
344 2
	 *
345
	 * @return bool True if they can restore a topic
346 2
	 */
347
	private function currentUserCanRestore(): bool
348
	{
349 2
		global $modSettings, $board;
350 2
351 2
		return allowedTo('move_any') && !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] == $board;
352
	}
353
354
	/**
355
	 * Loads supporting resources for the MessageIndex page.
356 2
	 */
357 2
	private function loadSupportingResources(): void
358
	{
359
		global $modSettings, $txt;
360
361
		// Fairly often, we'll work with boards. Current board, sub-boards.
362
		require_once(SUBSDIR . '/Boards.subs.php');
363
		require_once(SUBSDIR . '/MessageIndex.subs.php');
364
365
		theme()->getTemplates()->load('MessageIndex');
366 2
		loadJavascriptFile('topic.js');
367
368
		if (!empty($modSettings['message_index_preview']))
369 2
		{
370
			loadJavascriptFile('elk_toolTips.js', ['defer' => true]);
371
		}
372
373 2
		theme()->addJavascriptVar([
374 2
			'txt_mark_as_read_confirm' => $txt['mark_these_as_read_confirm']
375 2
		], true);
376 2
	}
377 2
378
	/**
379
	 * Checks if the current board has unapproved posts or topics.
380
	 *
381 2
	 * @return bool Returns true if the board has unapproved posts or topics, otherwise false.
382
	 */
383 2
	private function hasUnapprovedPosts(): bool
384
	{
385 2
		global $board_info;
386
387
		return $board_info['unapproved_topics'] || $board_info['unapproved_posts'];
388 2
	}
389
390
	/**
391 2
	 * Builds the message/links for the number of unapproved posts and topics in the current board.
392
	 *
393
	 * @return string The message containing the number of unapproved topics and posts.
394
	 */
395
	private function buildUnapprovedPostsMessage(): string
396 2
	{
397
		global $txt, $board_info, $board;
398 2
399
		$unApprovedTopics = $board_info['unapproved_topics'] ? '<a href="' . getUrl('action', ['action' => 'moderate', 'area' => 'postmod', 'sa' => 'topics', 'brd' => $board]) . '">' . $board_info['unapproved_topics'] . '</a>' : 0;
400 2
		$unApprovedPosts = $board_info['unapproved_posts'] ? '<a href="' . getUrl('action', ['action' => 'moderate', 'area' => 'postmod', 'sa' => 'posts', 'brd' => $board]) . '">' . ($board_info['unapproved_posts'] - $board_info['unapproved_topics']) . '</a>' : 0;
401 2
402
		return sprintf($txt['there_are_unapproved_topics'], $unApprovedTopics, $unApprovedPosts, getUrl('action', ['action' => 'moderate', 'area' => 'postmod', 'sa' => ($board_info['unapproved_topics'] ? 'topics' : 'posts'), 'brd' => $board]));
403
	}
404
405
	/**
406
	 * Sets up the page navigation for the board view.
407
	 */
408 2
	private function setPageNavigation(): void
409 2
	{
410 2
		global $board, $modSettings, $context, $options, $board_info, $url_format;
411 2
412
		// How many topics do we have in total?
413
		$board_info['total_topics'] = $this->currentUserCanApprovePosts()
414
			? $board_info['num_topics'] + $board_info['unapproved_topics']
415 2
			: $board_info['num_topics'] + $board_info['unapproved_user_topics'];
416
417
		$all = $this->_req->isSet('all');
418
		$start = $this->_req->getQuery('start', 'intval', 0);
419
420
		// View all the topics, or just a few?
421
		$context['topics_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['topics_per_page']) ? $options['topics_per_page'] : $modSettings['defaultMaxTopics'];
422
		$context['messages_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['messages_per_page']) ? $options['messages_per_page'] : $modSettings['defaultMaxMessages'];
423
		$per_page = $all && !empty($modSettings['enableAllMessages']) ? $board_info['total_topics'] : $context['topics_per_page'];
424
425
		// Make sure the starting place makes sense based on the chosen URL style and construct the page index.
426
		if ($url_format === 'queryless')
427
		{
428
			$context['page_index'] = constructPageIndex('{scripturl}?board,' . $board . '.%1$d.html' . $this->buildSortingString(), $start, $board_info['total_topics'], $per_page, true);
429
		}
430
		else
431
		{
432
			$base_url = getUrl('board', ['board' => $board_info['id'], 'name' => $board_info['name']]);
433
			$base_url = str_replace('%', '%%', $base_url);
434
			$context['page_index'] = constructPageIndex($base_url . '.%1$d' . $this->buildSortingString(), $start, $board_info['total_topics'], $per_page, true);
435
		}
436
437
		// Set a canonical URL for this page.
438
		$context['canonical_url'] = getUrl('board', ['board' => $board, 'start' => $start, 'name' => $board_info['name']]);
439
440
		$context['links'] += [
441
			'prev' => $start >= $context['topics_per_page'] ? getUrl('board', ['board' => $board, 'start' => $start - $context['topics_per_page'], 'name' => $board_info['name']]) : '',
442
			'next' => $start + $context['topics_per_page'] < $board_info['total_topics'] ? getUrl('board', ['board' => $board, 'start' => $start + $context['topics_per_page'], 'name' => $board_info['name']]) : '',
443
		];
444
445
		if ($all && !empty($modSettings['enableAllMessages']) && $per_page > $modSettings['enableAllMessages'])
446
		{
447
			$per_page = $modSettings['enableAllMessages'];
448
			$start = 0;
449
		}
450
451
		$this->sort_start = $start;
452
		$context['start'] = $start;
453
		$context['per_page'] = $per_page;
454
	}
455
456
	/**
457
	 * Builds the sorting string for the message index page.
458
	 *
459 2
	 * @return string The sorting string with the chosen sort method and direction
460
	 */
461
	private function buildSortingString(): string
462
	{
463
		global $context, $txt;
464
465 2
		// Known sort methods.
466
		$this->sort_methods = messageIndexSort();
467
		$default_sort_method = 'last_post';
468
469
		// Requested a sorting method?
470
		$chosen_sort = $this->_req->getQuery('sort', 'trim', $default_sort_method);
471 2
472 2
		// We only know these.
473
		if (!isset($this->sort_methods[$chosen_sort]))
474 2
		{
475
			$chosen_sort = $default_sort_method;
476
		}
477 2
478 2
		$sort_string = ';sort=' . $chosen_sort . ($this->_req->isSet('desc') ? ';desc' : '');
479 2
		$this->sort_by = $chosen_sort;
480
		$this->ascending = $this->_req->isSet('asc');
481
		$this->sort_column = $this->sort_methods[$this->sort_by];
482 2
483 2
		$context['sort_by'] = $this->sort_by;
484 2
		$context['sort_direction'] = $this->ascending ? 'up' : 'down';
485
		$context['sort_title'] = $this->ascending ? $txt['sort_desc'] : $txt['sort_asc'];
486
487 2
		return $sort_string;
488
	}
489 2
490 2
	/**
491 2
	 * Load board moderator links into context for displaying on the template.
492
	 */
493 2
	private function setBoardModeratorLinks(): void
494 2
	{
495
		global $board_info, $context, $txt;
496
497
		// Build a list of the board's moderators.
498
		$context['moderators'] = &$board_info['moderators'];
499 2
		$context['link_moderators'] = [];
500 2
501
		if (!empty($board_info['moderators']))
502
		{
503
			foreach ($board_info['moderators'] as $mod)
504
			{
505
				$context['link_moderators'][] = '<a href="' . getUrl('profile', ['action' => 'profile', 'u' => $mod['id'], 'name' => $mod['name']]) . '" title="' . $txt['board_moderator'] . '">' . $mod['name'] . '</a>';
506
			}
507
		}
508
	}
509
510
	/**
511
	 * Mark the current board and its parent boards as seen for the current user
512
	 */
513
	public function markCurrentAndParentBoardsAsSeen(): void
514
	{
515
		global $board_info, $board;
516
517
		if ($this->user->is_guest)
0 ignored issues
show
Bug Best Practice introduced by
The property is_guest does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
518
		{
519
			$this->is_marked_notify = false;
520
			return;
521
		}
522
523
		// We can't know they read it if we allow prefetches.
524
		stop_prefetching();
525
526
		// Mark the board as read, and its parents.
527
		if (!empty($board_info['parent_boards']))
528
		{
529
			$board_list = array_keys($board_info['parent_boards']);
530
			$board_list[] = $board;
531
		}
532
		else
533
		{
534
			$board_list = [$board];
535
		}
536
537
		// Mark boards as read. Boards alone, no need for topics.
538
		markBoardsRead($board_list);
539
540
		// Clear topicseen cache
541
		if (!empty($board_info['parent_boards']))
542
		{
543
			// We've seen all these boards now!
544
			foreach ($board_info['parent_boards'] as $k => $dummy)
545
			{
546
				if (isset($_SESSION['topicseen_cache'][$k]))
547
				{
548
					unset($_SESSION['topicseen_cache'][$k]);
549
				}
550
			}
551
		}
552
553
		if (isset($_SESSION['topicseen_cache'][$board]))
554
		{
555
			unset($_SESSION['topicseen_cache'][$board]);
556
		}
557
558
		// From now on, they've seen it. So we reset notifications.
559
		$this->is_marked_notify = resetSentBoardNotification($this->user->id, $board);
560
	}
561
562
	/**
563
	 * Prepare and load sub-boards for display.
564
	 */
565
	private function prepareSubBoardsForDisplay(): void
566
	{
567
		global $board_info, $modSettings, $context;
568
569
		// Prepare sub-boards for display.
570
		$boardIndexOptions = [
571
			'include_categories' => false,
572
			'base_level' => $board_info['child_level'] + 1,
573
			'parent_id' => $board_info['id'],
574
			'set_latest_post' => false,
575
			'countChildPosts' => !empty($modSettings['countChildPosts']),
576
		];
577
578
		$boardList = new BoardsList($boardIndexOptions);
579
		$context['boards'] = $boardList->getBoards();
580
	}
581
582
	/**
583
	 * Prepares and loads into context the information about who is currently viewing the board
584
	 */
585
	private function prepareWhoViewing(): void
586
	{
587
		global $settings, $board;
588
589
		// Nosey, nosey - who's viewing this board?
590
		if (!empty($settings['display_who_viewing']))
591
		{
592
			require_once(SUBSDIR . '/Who.subs.php');
593
			formatViewers($board, 'board');
594
		}
595
	}
596
597
	/**
598
	 * Sets the sort icons for the topics headers in the context.
599
	 */
600
	private function setSortIcons(): void
601
	{
602
		global $context, $board, $board_info, $txt;
603
604
		// Trick
605
		$txt['starter'] = $txt['started_by'];
606
607
		// todo: Need to move this to theme.
608
		foreach ($this->sort_methods as $key => $val)
609
		{
610
			$sortIcon = match ($key)
611
			{
612
				'subject', 'starter', 'last_poster' => 'alpha',
613
				default => 'numeric',
614
			};
615
616
			$context['topics_headers'][$key] = [
617
				'url' => getUrl('board', ['board' => $board, 'start' => $this->sort_start, 'sort' => $key, 'name' => $board_info['name'], $this->sort_by === $key && $this->ascending ? 'desc' : 'asc']),
618
				'sort_dir_img' => $this->sort_by === $key ? '<i class="icon icon-small i-sort-' . $sortIcon . '-' . $context['sort_direction'] . '" title="' . $context['sort_title'] . '"><s>' . $context['sort_title'] . '</s></i>' : '',
619
			];
620
		}
621
	}
622
623
	/**
624
	 * Loads board topics into the context
625
	 */
626
	private function loadBoardTopics(): void
627
	{
628
		global $board, $modSettings, $context, $settings, $board_info;
629
630
		// Calculate the fastest way to get the topics.
631
		$start = $this->_req->getQuery('start', 'intval', 0);
632
		$per_page = $context['per_page'];
633
		$fake_ascending = false;
634
		if ($start > ($board_info['total_topics'] - 1) / 2)
635
		{
636
			// Rolled off the end?
637
			$start = ($start >= $board_info['total_topics']) ? $board_info['total_topics'] - $per_page : $start;
638
			$this->ascending = !$this->ascending;
639
			$fake_ascending = true;
640
			$per_page = $board_info['total_topics'] < $start + $per_page + 1 ? $board_info['total_topics'] - $start : $per_page;
641
			$start = $board_info['total_topics'] < $start + $per_page + 1 ? 0 : $board_info['total_topics'] - $start - $per_page;
642
		}
643
644
		$context['topics'] = [];
645
646
		// Set up the query options
647
		$indexOptions = [
648
			'only_approved' => $modSettings['postmod_active'] && !allowedTo('approve_posts'),
649
			'previews' => empty($modSettings['message_index_preview']) ? 0 : (empty($modSettings['preview_characters']) ? -1 : $modSettings['preview_characters']),
650
			'include_avatars' => $settings['avatars_on_indexes'],
651
			'ascending' => $this->ascending,
652
			'fake_ascending' => $fake_ascending
653
		];
654
655
		// Allow integration to modify / add to the $indexOptions
656
		call_integration_hook('integrate_messageindex_topics', [&$this->sort_column, &$indexOptions]);
657
658
		$topics_info = messageIndexTopics($board, $this->user->id, $start, $per_page, $this->sort_by, $this->sort_column, $indexOptions);
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
659
660
		$context['topics'] = TopicUtil::prepareContext($topics_info, false, empty($modSettings['preview_characters']) ? 128 : $modSettings['preview_characters']);
661
662
		// Allow addons to add to the $context['topics']
663
		call_integration_hook('integrate_messageindex_listing', [$topics_info]);
664
665
		// Fix the sequence of topics if they were retrieved in the wrong order. (for speed reasons...)
666
		if ($fake_ascending)
667
		{
668
			$context['topics'] = array_reverse($context['topics'], true);
669
		}
670
671
		$topic_ids = array_keys($context['topics']);
672
673
		if (!empty($modSettings['enableParticipation']) && $this->user->is_guest === false && !empty($topic_ids))
0 ignored issues
show
Bug Best Practice introduced by
The property is_guest does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
674
		{
675
			$topics_participated_in = topicsParticipation($this->user->id, $topic_ids);
676
			foreach ($topics_participated_in as $participated)
677
			{
678
				$context['topics'][$participated['id_topic']]['is_posted_in'] = true;
679
				$context['topics'][$participated['id_topic']]['class'] = 'my_' . $context['topics'][$participated['id_topic']]['class'];
680
			}
681
		}
682
683
		// Trigger a topic loaded event
684
		$this->_events->trigger('topicinfo', ['callbacks' => &$context['topics']]);
685
	}
686
687
	/**
688
	 * Determines which quick moderation actions are available for this user.
689
	 * Loads which actions are available, on a per-topic basis, into $context.
690
	 */
691
	private function quickModeration(): void
692
	{
693
		global $modSettings, $context, $options, $board_info;
694
695
		// Is Quick Moderation active/needed?
696
		if (!empty($options['display_quick_mod']) && !empty($context['topics']))
697
		{
698
			$context += [
699
				'can_markread' => $context['user']['is_logged'],
700
				'can_lock' => allowedTo('lock_any'),
701
				'can_sticky' => allowedTo('make_sticky'),
702
				'can_move' => allowedTo('move_any'),
703
				'can_remove' => allowedTo('remove_any'),
704
				'can_merge' => allowedTo('merge_any'),
705
			];
706
707
			// Ignore approving own topics as it's unlikely to come up...
708
			$context['can_approve'] = $modSettings['postmod_active'] && allowedTo('approve_posts') && !empty($board_info['unapproved_topics']);
709
710
			// Can we restore topics?
711
			$context['can_restore'] = $this->currentUserCanRestore();
712
713
			// Set permissions for all the topics.
714
			foreach ($context['topics'] as $t => $topic)
715
			{
716
				$started = (int) $topic['first_post']['member']['id'] === $this->user->id;
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
717
				$context['topics'][$t]['quick_mod'] = [
718
					'lock' => allowedTo('lock_any') || ($started && allowedTo('lock_own')),
719
					'sticky' => allowedTo('make_sticky'),
720
					'move' => allowedTo('move_any') || ($started && allowedTo('move_own')),
721
					'modify' => allowedTo('modify_any') || ($started && allowedTo('modify_own')),
722
					'remove' => allowedTo('remove_any') || ($started && allowedTo('remove_own')),
723
					'approve' => $context['can_approve'] && $topic['unapproved_posts']
724
				];
725
				$context['can_lock'] |= ($started && allowedTo('lock_own'));
726
				$context['can_move'] |= ($started && allowedTo('move_own'));
727
				$context['can_remove'] |= ($started && allowedTo('remove_own'));
728
			}
729
730
			// Can we even use quick moderation on this batch?
731
			$context['can_quick_mod'] = $context['user']['is_logged'] || $context['can_approve'] || $context['can_remove'] || $context['can_lock'] || $context['can_sticky'] || $context['can_move'] || $context['can_merge'] || $context['can_restore'];
732
			if (!empty($context['can_quick_mod']))
733
			{
734
				$this->buildQuickModerationButtons();
735
				$context['qmod_actions'] = ['approve', 'remove', 'lock', 'sticky', 'move', 'merge', 'restore', 'markread'];
736
				call_integration_hook('integrate_quick_mod_actions');
737
			}
738
		}
739
	}
740
741
	/**
742
	 * Loads into $context the moderation button array for template use.
743
	 * Call integrate_message_index_mod_buttons hook
744
	 */
745
	public function buildQuickModerationButtons(): void
746
	{
747
		global $context;
748
749
		$context['can_show'] = false;
750
		$quickMod = array_column($context['topics'], 'quick_mod', 'id');
751
		$context['show_qm_message_checkbox'] = array_column($context['topics'], 'id');
752
753
		// Build valid topic id's by action
754
		$keys = array_keys($quickMod);
755
		foreach (['move', 'lock', 'remove', 'approve'] as $area)
756
		{
757
			// e.g., get topic ids where this quick_mod action xxx value is valid
758
			$temp = array_combine($keys, array_column($quickMod, $area));
759
			$context['allow_qm']['can_' . $area] = array_keys($temp, true);
760
			${'show_' . $area} = !empty($context['allow_qm']['can_' . $area]);
761
		}
762
763
		// Build the mod button array with buttons that are valid for, at least some, of the messages
764
		$context['mod_buttons'] = [
765
			'move' => [
766
				'test' => $show_move ? 'can_move' : 'can_show',
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $show_move seems to be never defined.
Loading history...
767
				'text' => 'move_topic',
768
				'id' => 'move',
769
				'lang' => true,
770
				'url' => 'javascript:void(0);',
771
			],
772
			'remove' => [
773
				'test' => $show_remove ? 'can_remove' : 'can_show',
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $show_remove seems to be never defined.
Loading history...
774
				'text' => 'remove_topic',
775
				'id' => 'remove',
776
				'lang' => true,
777
				'url' => 'javascript:void(0);',
778
			],
779
			'lock' => [
780
				'test' => $show_lock ? 'can_lock' : 'can_show',
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $show_lock seems to be never defined.
Loading history...
781
				'text' => 'set_lock',
782
				'id' => 'lock',
783
				'lang' => true,
784
				'url' => 'javascript:void(0);',
785
			],
786
			'approve' => [
787
				'test' => $show_approve ? 'can_approve' : 'can_show',
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $show_approve seems to be never defined.
Loading history...
788
				'text' => 'approve',
789
				'id' => 'approve',
790
				'lang' => true,
791
				'url' => 'javascript:void(0);',
792
			],
793
			'sticky' => [
794
				'test' => 'can_sticky',
795
				'text' => 'set_sticky',
796
				'id' => 'sticky',
797
				'lang' => true,
798
				'url' => 'javascript:void(0);',
799
			],
800
			'merge' => [
801
				'test' => 'can_merge',
802
				'text' => 'merge',
803
				'id' => 'merge',
804
				'lang' => true,
805
				'url' => 'javascript:void(0);',
806
			],
807
			'markread' => [
808
				'test' => 'can_markread',
809
				'text' => 'mark_read_short',
810
				'id' => 'markread',
811
				'lang' => true,
812
				'url' => 'javascript:void(0);',
813
			],
814
		];
815
816
		// Restore a topic, maybe even some doxing!
817
		if ($context['can_restore'])
818
		{
819
			$context['mod_buttons']['restore'] = [
820
				'text' => 'restore_topic',
821
				'lang' => true,
822
				'url' => 'javascript:void(0);',
823
			];
824
		}
825
826
		// Allow adding new buttons easily.
827
		call_integration_hook('integrate_message_index_quickmod_buttons');
828
829
		$context['mod_buttons'] = array_reverse($context['mod_buttons']);
830
	}
831
832
	/**
833
	 * Similar to Quick Reply, this is Quick Topic.
834
	 * Allows a way to start a new topic from the boards message index.
835
	 */
836
	private function quickTopic(): void
837
	{
838
		global $txt, $modSettings, $context, $options;
839
840
		// Quick topic enabled?
841
		if ($context['can_post_new'] && !empty($options['display_quick_reply']))
842
		{
843
			$this->prepareQuickTopic();
844
845
			checkSubmitOnce('register');
846
847
			$context['becomes_approved'] = true;
848
			if ($modSettings['postmod_active'] && !allowedTo('post_new') && allowedTo('post_unapproved_topics'))
849
			{
850
				$context['becomes_approved'] = false;
851
			}
852
			else
853
			{
854
				isAllowedTo('post_new');
855
			}
856
857
			require_once(SUBSDIR . '/Editor.subs.php');
858
			// Create the editor for the QT area
859
			$editorOptions = [
860
				'id' => 'message',
861
				'value' => '',
862
				'labels' => [
863
					'post_button' => $txt['post'],
864
				],
865
				'height' => '200px',
866
				'width' => '100%',
867
				'smiley_container' => 'smileyBox_message',
868
				'bbc_container' => 'bbcBox_message',
869
				// We submit/switch to the full post page for the preview
870
				'preview_type' => 1,
871
				'buttons' => [
872
					'more' => [
873
						'type' => 'submit',
874
						'name' => 'more_options',
875
						'value' => $txt['post_options'],
876
						'options' => ''
877
					]
878
				],
879
			];
880
881
			// Trigger the prepare_context event for modules that have tied in to it
882
			$this->_events->trigger('prepare_context', ['editorOptions' => &$editorOptions, 'use_quick_reply' => !empty($options['display_quick_reply'])]);
883
884
			create_control_richedit($editorOptions);
885
886
			theme()->getTemplates()->load('GenericMessages');
887
		}
888
	}
889
890
	/**
891
	 * If Quick Topic is on, we need to load user information into $context so the poster sidebar renders
892
	 */
893
	private function prepareQuickTopic(): void
894
	{
895
		global $options, $context, $modSettings;
896
897
		if (empty($options['hide_poster_area']) && $options['display_quick_reply'])
898
		{
899
			if ($this->user->is_guest)
0 ignored issues
show
Bug Best Practice introduced by
The property is_guest does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
900
			{
901
				MembersList::loadGuest();
902
			}
903
			else
904
			{
905
				MembersList::load(User::$info->id);
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
906
			}
907
908
			$thisUser = MembersList::get(User::$info->id);
909
			$thisUser->loadContext();
910
911
			$context['thisMember'] = [
912
				'id' => 'new',
913
				'is_message_author' => true,
914
				'member' => $thisUser->toArray()['data']
915
			];
916
			$context['can_issue_warning'] = allowedTo('issue_warning') && featureEnabled('w') && !empty($modSettings['warning_enable']);
917
			$context['can_send_pm'] = allowedTo('pm_send');
918
		}
919
	}
920
921
	/**
922
	 * Build the board buttons for the message index page.
923
	 */
924
	private function buildBoardButtons(): void
925
	{
926
		global $context, $settings, $board;
927
928
		// Build the message index button array.
929
		$context['normal_buttons'] = [
930
			'new_topic' => [
931
				'test' => 'can_post_new',
932
				'text' => 'new_topic',
933
				'lang' => true,
934
				'url' => getUrl('action', ['action' => 'post', 'board' => $board . '.0']),
935
				'active' => true],
936
			'notify' => [
937
				'test' => 'can_mark_notify',
938
				'text' => $this->is_marked_notify ? 'unnotify' : 'notify',
939
				'lang' => true, 'custom' => 'onclick="return notifyboardButton(this);"',
940
				'url' => getUrl('action', ['action' => 'notifyboard', 'sa' => ($this->is_marked_notify ? 'off' : 'on'), 'board' => $board . '.' . $this->sort_start, '{session_data}'])],
941
		];
942
943
		// They can only mark read if they are logged in, and it's enabled!
944
		if ($this->user->is_guest === false && $settings['show_mark_read'])
0 ignored issues
show
Bug Best Practice introduced by
The property is_guest does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
945
		{
946
			$context['normal_buttons']['markread'] = [
947
				'text' => 'mark_read_short',
948
				'lang' => true,
949
				'url' => getUrl('action', ['action' => 'markasread', 'sa' => 'board', 'board' => $board . '.0', '{session_data}']),
950
				'custom' => 'onclick="return markboardreadButton(this);"'
951
			];
952
		}
953
954
		// Allow adding new buttons easily.
955
		call_integration_hook('integrate_messageindex_buttons');
956
957
		// Trigger a post load event with quick access to normal buttons
958
		$this->_events->trigger('post_load', ['callbacks' => &$context['normal_buttons']]);
959
	}
960
961
	/**
962
	 * Show the list of topics in this board, along with any sub-boards.
963
	 *
964
	 * @uses template_topic_listing() sub template of the MessageIndex template
965
	 */
966
	public function action_messageindex_fp(): void
967
	{
968
		global $modSettings, $board;
969
970
		$board = $modSettings['message_index_frontpage'];
971
		loadBoard();
972
973
		$this->action_messageindex();
974
	}
975
976
	/**
977
	 * Allows for moderation from the message index.
978
	 *
979
	 * @todo refactor this...
980
	 */
981
	public function action_quickmod(): ?bool
982
	{
983
		global $board, $modSettings, $context;
984
985
		// Check the session = get or post.
986
		checkSession('request');
987
988
		// Cleanup
989
		$validator = new DataValidator();
990
		$validator->sanitation_rules([
991
			'topics' => 'intval',
992
			'qaction' => 'trim',
993
			'move_to' => 'intval',
994
			'redirect_topic' => 'intval',
995
			'redirect_expires' => 'intval',
996
		]);
997
		$validator->input_processing(['topics' => 'array']);
998
		$validator->validate($this->_req->post);
999
1000
		$selected_topics = $validator->topics;
1001
		$selected_qaction = $validator->qaction;
1002
1003
		// Let's go straight to the restore area.
1004
		if ($selected_qaction === 'restore' && !empty($selected_topics))
1005
		{
1006
			redirectexit('action=restoretopic;topics=' . implode(',', $selected_topics) . ';' . $context['session_var'] . '=' . $context['session_id']);
1007
		}
1008
1009
		if (isset($_SESSION['topicseen_cache']))
1010
		{
1011
			$_SESSION['topicseen_cache'] = [];
1012
		}
1013
1014
		// Remember the last board they moved things to.
1015
		if (!empty($validator->move_to))
1016
		{
1017
			$_SESSION['move_to_topic'] = [
1018
				'move_to' => $validator->move_to,
1019
				// And remember the last expiry period too.
1020
				'redirect_topic' => $validator->redirect_topic,
1021
				'redirect_expires' => $validator->redirect_expires,
1022
			];
1023
		}
1024
1025
		// This is going to be needed to send off the notifications and for updateLastMessages().
1026
		require_once(SUBSDIR . '/Post.subs.php');
1027
		require_once(SUBSDIR . '/Notification.subs.php');
1028
		require_once(SUBSDIR . '/Topic.subs.php');
1029
1030
		// Only a few possible actions.
1031
		$actions = [];
1032
1033
		// Permissions on this board
1034
		if (!empty($board))
1035
		{
1036
			$boards_can = [
1037
				'make_sticky' => allowedTo('make_sticky') ? [$board] : [],
1038
				'move_any' => allowedTo('move_any') ? [$board] : [],
1039
				'move_own' => allowedTo('move_own') ? [$board] : [],
1040
				'remove_any' => allowedTo('remove_any') ? [$board] : [],
1041
				'remove_own' => allowedTo('remove_own') ? [$board] : [],
1042
				'lock_any' => allowedTo('lock_any') ? [$board] : [],
1043
				'lock_own' => allowedTo('lock_own') ? [$board] : [],
1044
				'merge_any' => allowedTo('merge_any') ? [$board] : [],
1045
				'approve_posts' => allowedTo('approve_posts') ? [$board] : [],
1046
			];
1047
1048
			$start = $this->_req->getQuery('start', 'intval', 0);
1049
			$redirect_url = 'board=' . $board . '.' . $start;
1050
		}
1051
		else
1052
		{
1053
			$boards_can = boardsAllowedTo(['make_sticky', 'move_any', 'move_own', 'remove_any', 'remove_own', 'lock_any', 'lock_own', 'merge_any', 'approve_posts'], true, false);
1054
			$redirect_url = $this->_req->getPost('redirect_url', 'trim|strval', $_SESSION['old_url'] ?? getUrlQuery('action', $modSettings['default_forum_action']));
1055
		}
1056
1057
		// Just what actions can they do?, approve, move, remove, lock, sticky, lock, merge, mark read?
1058
		$possibleActions = $this->setPossibleQmActions($boards_can);
1059
1060
		// Two methods:
1061
		// $_REQUEST['actions'] (id_topic => action), and
1062
		// $_REQUEST['topics'] and $this->_req->post->qaction.
1063
		// (if action is 'move', $_REQUEST['move_to'] or $_REQUEST['move_tos'][$topic] is used.)
1064
		if (!empty($selected_topics))
1065
		{
1066
			// If the action isn't valid, just quit now.
1067
			if (empty($selected_qaction) || !in_array($selected_qaction, $possibleActions, true))
1068
			{
1069
				redirectexit($redirect_url);
1070
			}
1071
1072
			// Merge requires all topics as one parameter and can be done at once.
1073
			if ($selected_qaction === 'merge')
1074
			{
1075
				// Merge requires at least two topics.
1076
				if (count($selected_topics) < 2)
1077
				{
1078
					redirectexit($redirect_url);
1079
				}
1080
1081
				$controller = new MergeTopics(new EventManager());
1082
				$controller->setUser(User::$info);
1083
				$controller->pre_dispatch();
1084
1085
				return $controller->action_mergeExecute($selected_topics);
1086
			}
1087
1088
			// Just convert to the other method to make it easier.
1089
			foreach ($selected_topics as $topic)
1090
			{
1091
				$actions[$topic] = $selected_qaction;
1092
			}
1093
		}
1094
		else
1095
		{
1096
			$actions = $this->_req->getRequest('actions');
1097
		}
1098
1099
		// Weird... how'd you get here?
1100
		if (empty($actions))
1101
		{
1102
			redirectexit($redirect_url);
1103
		}
1104
1105
		// Validate each action.
1106
		$all_actions = [];
1107
		$action = '';
1108
		foreach ($actions as $topic => $action)
1109
		{
1110
			if (in_array($action, $possibleActions, true))
1111
			{
1112
				$all_actions[(int) $topic] = $action;
1113
			}
1114
		}
1115
1116
		$stickyCache = [];
1117
		$moveCache = [0 => [], 1 => []];
1118
		$removeCache = [];
1119
		$lockCache = [];
1120
		$markCache = [];
1121
		$approveCache = [];
1122
1123
		if (!empty($all_actions))
1124
		{
1125
			// Find all topics...
1126
			$topics_info = topicsDetails(array_keys($all_actions));
1127
1128
			foreach ($topics_info as $row)
1129
			{
1130
				if (!empty($board) && ($row['id_board'] != $board || ($modSettings['postmod_active'] && !$row['approved'] && !allowedTo('approve_posts'))))
1131
				{
1132
					continue;
1133
				}
1134
1135
				// Don't allow them to act on unapproved posts they can't see...
1136
				if ($modSettings['postmod_active'] && !$row['approved'] && !in_array(0, $boards_can['approve_posts']) && !in_array($row['id_board'], $boards_can['approve_posts']))
1137
				{
1138
					continue;
1139
				}
1140
1141
				// Goodness, this is fun.  We need to validate the action.
1142
				if ($all_actions[$row['id_topic']] === 'sticky' && !$this->canMakeSticky($boards_can, $row))
1143
				{
1144
					continue;
1145
				}
1146
1147
				if ($all_actions[$row['id_topic']] === 'move' && !$this->canMove($boards_can, $row))
1148
				{
1149
					continue;
1150
				}
1151
1152
				if ($all_actions[$row['id_topic']] === 'remove' && !$this->canRemove($boards_can, $row))
1153
				{
1154
					continue;
1155
				}
1156
1157
				if ($all_actions[$row['id_topic']] === 'lock' && !$this->canLock($boards_can, $row))
1158
				{
1159
					continue;
1160
				}
1161
1162
				// Separate the actions.
1163
				switch ($action)
1164
				{
1165
					case 'markread':
1166
						$markCache[] = $row['id_topic'];
1167
						break;
1168
					case 'sticky':
1169
						$stickyCache[] = $row['id_topic'];
1170
						break;
1171
					case 'move':
1172
						if (isset($this->_req->query->current_board))
1173
						{
1174
							moveTopicConcurrence((int) $this->_req->query->current_board, $board, $row['id_topic']);
1175
						}
1176
1177
						// $moveCache[0] is the topic, $moveCache[1] is the board to move to.
1178
						$moveCache[1][$row['id_topic']] = (int) ($this->_req->post->move_tos[$row['id_topic']] ?? $this->_req->post->move_to);
1179
1180
						if (!empty($moveCache[1][$row['id_topic']]))
1181
						{
1182
							$moveCache[0][] = $row['id_topic'];
1183
						}
1184
1185
						break;
1186
					case 'remove':
1187
						$removeCache[] = $row['id_topic'];
1188
						break;
1189
					case 'lock':
1190
						$lockCache[] = $row['id_topic'];
1191
						break;
1192
					case 'approve':
1193
						$approveCache[] = $row['id_topic'];
1194
						break;
1195
				}
1196
			}
1197
		}
1198
1199
		$affectedBoards = empty($board) ? [] : [$board => [0, 0]];
1200
1201
		// Do all the stickies...
1202
		if (!empty($stickyCache))
1203
		{
1204
			toggleTopicSticky($stickyCache, true);
1205
		}
1206
1207
		// Move sucka! (this is, by the by, probably the most complicated part....)
1208
		if (!empty($moveCache[0]))
1209
		{
1210
			moveTopicsPermissions($moveCache);
1211
		}
1212
1213
		// Now delete the topics...
1214
		if (!empty($removeCache))
1215
		{
1216
			removeTopicsPermissions($removeCache);
1217
		}
1218
1219
		// Approve the topics...
1220
		if (!empty($approveCache))
1221
		{
1222
			approveTopics($approveCache, true, true);
1223
		}
1224
1225
		// And (almost) lastly, lock the topics...
1226
		if (!empty($lockCache))
1227
		{
1228
			toggleTopicsLock($lockCache, true);
1229
		}
1230
1231
		if (!empty($markCache))
1232
		{
1233
			$logged_topics = getLoggedTopics($this->user->id, $markCache);
1234
1235
			$markArray = [];
1236
			foreach ($markCache as $topic)
1237
			{
1238
				$markArray[] = [$this->user->id, $topic, $modSettings['maxMsgID'], (int) !empty($logged_topics[$topic])];
1239
			}
1240
1241
			markTopicsRead($markArray, true);
1242
		}
1243
1244
		updateTopicStats();
1245
		require_once(SUBSDIR . '/Messages.subs.php');
1246
		updateMessageStats();
1247
		updateSettings(['calendar_updated' => time(),]);
1248
1249
		if (!empty($affectedBoards))
1250
		{
1251
			updateLastMessages(array_keys($affectedBoards));
1252
		}
1253
1254
		redirectexit($redirect_url);
1255
	}
1256
1257
	/**
1258
	 * Just what actions can they perform on this board?
1259
	 *
1260
	 * Checks if they can markread, sticky, move, remove, lock, or merge
1261
	 *
1262
	 * @param array $boards_can
1263
	 * @return array
1264
	 */
1265
	public function setPossibleQmActions($boards_can): array
1266
	{
1267
		$possibleActions = [];
1268
1269
		if ($this->user->is_guest === false)
0 ignored issues
show
Bug Best Practice introduced by
The property is_guest does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
1270
		{
1271
			$possibleActions[] = 'markread';
1272
		}
1273
1274
		if (!empty($boards_can['make_sticky']))
1275
		{
1276
			$possibleActions[] = 'sticky';
1277
		}
1278
1279
		if (!empty($boards_can['move_any']) || !empty($boards_can['move_own']))
1280
		{
1281
			$possibleActions[] = 'move';
1282
		}
1283
1284
		if (!empty($boards_can['remove_any']) || !empty($boards_can['remove_own']))
1285
		{
1286
			$possibleActions[] = 'remove';
1287
		}
1288
1289
		if (!empty($boards_can['lock_any']) || !empty($boards_can['lock_own']))
1290
		{
1291
			$possibleActions[] = 'lock';
1292
		}
1293
1294
		if (!empty($boards_can['merge_any']))
1295
		{
1296
			$possibleActions[] = 'merge';
1297
		}
1298
1299
		if (!empty($boards_can['approve_posts']))
1300
		{
1301
			$possibleActions[] = 'approve';
1302
		}
1303
1304
		return $possibleActions;
1305
	}
1306
1307
	/**
1308
	 * Can they sticky a topic?
1309
	 *
1310
	 * @param array $boards_can
1311
	 * @param array $row
1312
	 * @return bool
1313
	 */
1314
	public function canMakeSticky($boards_can, $row): bool
1315
	{
1316
		return in_array(0, $boards_can['make_sticky'])
1317
			|| in_array($row['id_board'], $boards_can['make_sticky']);
1318
	}
1319
1320
	/**
1321
	 * Can they move a topic?
1322
	 *
1323
	 * @param array $boards_can
1324
	 * @param array $row
1325
	 * @return bool
1326
	 */
1327
	public function canMove($boards_can, $row): bool
1328
	{
1329
		return in_array(0, $boards_can['move_any'])
1330
			|| in_array($row['id_board'], $boards_can['move_any'])
1331
			|| ($row['id_member_started'] == $this->user->id
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
1332
				&& (in_array(0, $boards_can['move_own']) || in_array($row['id_board'], $boards_can['move_own'])));
1333
	}
1334
1335
	/**
1336
	 * Can they remove a topic?
1337
	 *
1338
	 * @param array $boards_can
1339
	 * @param array $row
1340
	 * @return bool
1341
	 */
1342
	public function canRemove($boards_can, $row): bool
1343
	{
1344
		return in_array(0, $boards_can['remove_any'])
1345
			|| in_array($row['id_board'], $boards_can['remove_any'])
1346
			|| ($row['id_member_started'] == $this->user->id
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
1347
				&& (in_array(0, $boards_can['remove_own']) || in_array($row['id_board'], $boards_can['remove_own'])));
1348
1349
	}
1350
1351
	/**
1352
	 * Can they lock a topic?
1353
	 *
1354
	 * @param array $boards_can
1355
	 * @param array $row
1356
	 * @return bool
1357
	 */
1358
	public function canLock($boards_can, $row): bool
1359
	{
1360
		return in_array(0, $boards_can['lock_any'])
1361
			|| in_array($row['id_board'], $boards_can['lock_any'])
1362
			|| ($row['id_member_started'] == $this->user->id
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on ElkArte\Helper\ValuesContainer. Since you implemented __get, consider adding a @property annotation.
Loading history...
1363
				&& $row['locked'] != 1
1364
				&& (in_array(0, $boards_can['lock_own']) || in_array($row['id_board'], $boards_can['lock_own'])));
1365
	}
1366
}
1367