MessageIndex::hasUnapprovedPosts()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

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