Completed
Pull Request — master (#3325)
by Emanuele
11:19
created

MessageIndex_Controller::action_quickmod()   F

Complexity

Conditions 85

Size

Total Lines 245
Code Lines 143

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 7310

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 85
eloc 143
dl 0
loc 245
rs 3.3333
c 2
b 0
f 0
nop 0
ccs 0
cts 161
cp 0
crap 7310

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * 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
 * @name      ElkArte Forum
8
 * @copyright ElkArte Forum contributors
9
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause
10
 *
11
 * This file contains code covered by:
12
 * copyright:	2011 Simple Machines (http://www.simplemachines.org)
13
 * license:		BSD, See included LICENSE.TXT for terms and conditions.
14
 *
15
 * @version 1.1.6
16
 *
17
 */
18
19
use ElkArte\sources\Frontpage_Interface;
20
21
/**
22
 * MessageIndex_Controller class
23
 */
24
class MessageIndex_Controller extends Action_Controller implements Frontpage_Interface
25
{
26
	/**
27
	 * {@inheritdoc}
28
	 */
29
	public static function frontPageHook(&$default_action)
30
	{
31
		add_integration_function('integrate_menu_buttons', 'MessageIndex_Controller::addForumButton', '', false);
32
		add_integration_function('integrate_current_action', 'MessageIndex_Controller::fixCurrentAction', '', false);
33
34
		$default_action = array(
35
			'controller' => 'MessageIndex_Controller',
36
			'function' => 'action_messageindex_fp'
37
		);
38
	}
39
40
	/**
41
	 * {@inheritdoc}
42
	 */
43 1
	public static function frontPageOptions()
44
	{
45 1
		parent::frontPageOptions();
46
47 1
		addInlineJavascript('
48
			$(\'#front_page\').on(\'change\', function() {
49
				var $base = $(\'#message_index_frontpage\').parent();
50 1
				if ($(this).val() == \'MessageIndex_Controller\')
51
				{
52
					$base.fadeIn();
53
					$base.prev().fadeIn();
54
				}
55
				else
56
				{
57
					$base.fadeOut();
58
					$base.prev().fadeOut();
59
				}
60 1
			}).change();', true);
61
62 1
		return array(array('select', 'message_index_frontpage', self::_getBoardsList()));
63
	}
64
65
	/**
66
	 * {@inheritdoc}
67
	 */
68
	public static function validateFrontPageOptions($post)
69
	{
70
		parent::validateFrontPageOptions($post);
71
		$boards = self::_getBoardsList();
72
73
		if (empty($post->message_index_frontpage) || !isset($boards[$post->message_index_frontpage]))
74
		{
75
			$post->front_page = null;
76
77
			return false;
78
		}
79
80
		return true;
81
	}
82
83
	/**
84
	 * Return the board listing for use in this class
85
	 *
86
	 * @uses getBoardList()
87
	 * @return string[] list of boards with key = id and value = cat + name
88
	 */
89 1
	protected static function _getBoardsList()
90
	{
91
		// Load the boards list.
92 1
		require_once(SUBSDIR . '/Boards.subs.php');
93 1
		$boards_list = getBoardList(array('override_permissions' => true, 'not_redirection' => true), true);
94
95 1
		$boards = array();
96 1
		foreach ($boards_list as $board)
97
		{
98 1
			$boards[$board['id_board']] = $board['cat_name'] . ' - ' . $board['board_name'];
99 1
		}
100
101 1
		return $boards;
102
	}
103
104
	/**
105
	 * Dispatches forward to message index handler.
106
	 *
107
	 * @see Action_Controller::action_index()
108
	 */
109 1
	public function action_index()
110
	{
111
		// Forward to message index, it's not like we know much more :P
112 1
		$this->action_messageindex();
113 1
	}
114
115
	/**
116
	 * Show the list of topics in this board, along with any sub-boards.
117
	 *
118
	 * @uses template_topic_listing() sub template of the MessageIndex template
119
	 */
120
	public function action_messageindex_fp()
121
	{
122
		global $modSettings, $board;
123
124
		$board = $modSettings['message_index_frontpage'];
125
		loadBoard();
126
127
		$this->action_messageindex();
128
	}
129
130
	/**
131
	 * Show the list of topics in this board, along with any sub-boards.
132
	 *
133
	 * @uses template_topic_listing() sub template of the MessageIndex template
134
	 */
135 1
	public function action_messageindex()
136
	{
137 1
		global $txt, $scripturl, $board, $modSettings, $context;
138 1
		global $options, $settings, $board_info, $user_info;
139
140
		// Fairly often, we'll work with boards. Current board, sub-boards.
141 1
		require_once(SUBSDIR . '/Boards.subs.php');
142
143
		// If this is a redirection board head off.
144 1
		if ($board_info['redirect'])
145 1
		{
146
			incrementBoard($board, 'num_posts');
147
			redirectexit($board_info['redirect']);
148
		}
149
150 1
		loadTemplate('MessageIndex');
151 1
		loadJavascriptFile('topic.js');
152
153 1
		$bbc = \BBC\ParserWrapper::instance();
154
155 1
		$context['name'] = $board_info['name'];
156 1
		$context['sub_template'] = 'topic_listing';
157 1
		$context['description'] = $bbc->parseBoard($board_info['description']);
158 1
		$template_layers = Template_Layers::instance();
159
160
		// How many topics do we have in total?
161 1
		$board_info['total_topics'] = allowedTo('approve_posts') ? $board_info['num_topics'] + $board_info['unapproved_topics'] : $board_info['num_topics'] + $board_info['unapproved_user_topics'];
162
163
		// View all the topics, or just a few?
164 1
		$context['topics_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['topics_per_page']) ? $options['topics_per_page'] : $modSettings['defaultMaxTopics'];
165 1
		$context['messages_per_page'] = empty($modSettings['disableCustomPerPage']) && !empty($options['messages_per_page']) ? $options['messages_per_page'] : $modSettings['defaultMaxMessages'];
166 1
		$maxindex = isset($this->_req->query->all) && !empty($modSettings['enableAllMessages']) ? $board_info['total_topics'] : $context['topics_per_page'];
167
168
		// Right, let's only index normal stuff!
169 1
		$session_name = session_name();
170 1
		foreach ($this->_req->query as $k => $v)
171
		{
172
			// Don't index a sort result etc.
173 1
			if (!in_array($k, array('board', 'start', $session_name)))
174 1
				$context['robot_no_index'] = true;
175 1
		}
176
177 1
		if (!empty($this->_req->query->start) && (!is_numeric($this->_req->query->start) || $this->_req->query->start % $context['messages_per_page'] != 0))
178 1
		{
179
			$context['robot_no_index'] = true;
180
		}
181
182
		// If we can view unapproved messages and there are some build up a list.
183 1
		if (allowedTo('approve_posts') && ($board_info['unapproved_topics'] || $board_info['unapproved_posts']))
184 1
		{
185
			$untopics = $board_info['unapproved_topics'] ? '<a href="' . $scripturl . '?action=moderate;area=postmod;sa=topics;brd=' . $board . '">' . $board_info['unapproved_topics'] . '</a>' : 0;
186
			$unposts = $board_info['unapproved_posts'] ? '<a href="' . $scripturl . '?action=moderate;area=postmod;sa=posts;brd=' . $board . '">' . ($board_info['unapproved_posts'] - $board_info['unapproved_topics']) . '</a>' : 0;
187
			$context['unapproved_posts_message'] = sprintf($txt['there_are_unapproved_topics'], $untopics, $unposts, $scripturl . '?action=moderate;area=postmod;sa=' . ($board_info['unapproved_topics'] ? 'topics' : 'posts') . ';brd=' . $board);
188
		}
189
190
		// And now, what we're here for: topics!
191 1
		require_once(SUBSDIR . '/MessageIndex.subs.php');
192
193
		// Known sort methods.
194 1
		$sort_methods = messageIndexSort();
195 1
		$default_sort_method = 'last_post';
196
197
		// We only know these.
198 1
		if (isset($this->_req->query->sort) && !isset($sort_methods[$this->_req->query->sort]))
199 1
		{
200
			$this->_req->query->sort = $default_sort_method;
201
		}
202
203
		// Make sure the starting place makes sense and construct the page index.
204 1
		if (isset($this->_req->query->sort))
205 1
			$sort_string = ';sort=' . $this->_req->query->sort . (isset($this->_req->query->desc) ? ';desc' : '');
206
		else
207 1
			$sort_string = '';
208
209 1
		$context['page_index'] = constructPageIndex($scripturl . '?board=' . $board . '.%1$d' . $sort_string, $this->_req->query->start, $board_info['total_topics'], $maxindex, true);
210 1
		$context['start'] = &$this->_req->query->start;
211
212
		// Set a canonical URL for this page.
213 1
		$context['canonical_url'] = $scripturl . '?board=' . $board . '.' . $context['start'];
214
215
		$context['links'] += array(
216 1
			'prev' => $this->_req->query->start >= $context['topics_per_page'] ? $scripturl . '?board=' . $board . '.' . ($this->_req->query->start - $context['topics_per_page']) : '',
217 1
			'next' => $this->_req->query->start + $context['topics_per_page'] < $board_info['total_topics'] ? $scripturl . '?board=' . $board . '.' . ($this->_req->query->start + $context['topics_per_page']) : '',
218
		);
219
220 1
		$context['page_info'] = array(
221 1
			'current_page' => $this->_req->query->start / $context['topics_per_page'] + 1,
222 1
			'num_pages' => floor(($board_info['total_topics'] - 1) / $context['topics_per_page']) + 1
223 1
		);
224
225 1
		if (isset($this->_req->query->all) && !empty($modSettings['enableAllMessages']) && $maxindex > $modSettings['enableAllMessages'])
226 1
		{
227
			$maxindex = $modSettings['enableAllMessages'];
228
			$this->_req->query->start = 0;
229
		}
230
231
		// Build a list of the board's moderators.
232 1
		$context['moderators'] = &$board_info['moderators'];
233 1
		$context['link_moderators'] = array();
234 1
		if (!empty($board_info['moderators']))
235 1
		{
236
			foreach ($board_info['moderators'] as $mod)
237
				$context['link_moderators'][] = '<a href="' . $scripturl . '?action=profile;u=' . $mod['id'] . '" title="' . $txt['board_moderator'] . '">' . $mod['name'] . '</a>';
238
		}
239
240
		// Mark current and parent boards as seen.
241 1
		if (!$user_info['is_guest'])
242 1
		{
243
			// We can't know they read it if we allow prefetches.
244 1
			stop_prefetching();
245
246
			// Mark the board as read, and its parents.
247 1
			if (!empty($board_info['parent_boards']))
248 1
			{
249
				$board_list = array_keys($board_info['parent_boards']);
250
				$board_list[] = $board;
251
			}
252
			else
253 1
				$board_list = array($board);
254
255
			// Mark boards as read. Boards alone, no need for topics.
256 1
			markBoardsRead($board_list, false, false);
257
258
			// Clear topicseen cache
259 1
			if (!empty($board_info['parent_boards']))
260 1
			{
261
				// We've seen all these boards now!
262
				foreach ($board_info['parent_boards'] as $k => $dummy)
263
				{
264
					if (isset($_SESSION['topicseen_cache'][$k]))
265
					{
266
						unset($_SESSION['topicseen_cache'][$k]);
267
					}
268
				}
269
			}
270
271 1
			if (isset($_SESSION['topicseen_cache'][$board]))
272 1
			{
273
				unset($_SESSION['topicseen_cache'][$board]);
274
			}
275
276
			// From now on, they've seen it. So we reset notifications.
277 1
			$context['is_marked_notify'] = resetSentBoardNotification($user_info['id'], $board);
278 1
		}
279
		else
280
			$context['is_marked_notify'] = false;
281
282
		// 'Print' the header and board info.
283 1
		$context['page_title'] = strip_tags($board_info['name']);
284
285
		// Set the variables up for the template.
286 1
		$context['can_mark_notify'] = allowedTo('mark_notify') && !$user_info['is_guest'];
287 1
		$context['can_post_new'] = allowedTo('post_new') || ($modSettings['postmod_active'] && allowedTo('post_unapproved_topics'));
288 1
		$context['can_post_poll'] = !empty($modSettings['pollMode']) && allowedTo('poll_post') && $context['can_post_new'];
289 1
		$context['can_moderate_forum'] = allowedTo('moderate_forum');
290 1
		$context['can_approve_posts'] = allowedTo('approve_posts');
291
292
		// Prepare sub-boards for display.
293
		$boardIndexOptions = array(
294 1
			'include_categories' => false,
295 1
			'base_level' => $board_info['child_level'] + 1,
296 1
			'parent_id' => $board_info['id'],
297 1
			'set_latest_post' => false,
298 1
			'countChildPosts' => !empty($modSettings['countChildPosts']),
299 1
		);
300 1
		$boardlist = new Boards_List($boardIndexOptions);
301 1
		$context['boards'] = $boardlist->getBoards();
302
303
		// Nosey, nosey - who's viewing this board?
304 1
		if (!empty($settings['display_who_viewing']))
305 1
		{
306
			require_once(SUBSDIR . '/Who.subs.php');
307
			formatViewers($board, 'board');
308
		}
309
310
		// They didn't pick one, default to by last post descending.
311 1
		if (!isset($this->_req->query->sort) || !isset($sort_methods[$this->_req->query->sort]))
312 1
		{
313 1
			$context['sort_by'] = $default_sort_method;
314 1
			$ascending = isset($this->_req->query->asc);
315 1
		}
316
		// Otherwise sort by user selection and default to ascending.
317
		else
318
		{
319
			$context['sort_by'] = $this->_req->query->sort;
320
			$ascending = !isset($this->_req->query->desc);
321
		}
322
323 1
		$sort_column = $sort_methods[$context['sort_by']];
324
325 1
		$context['sort_direction'] = $ascending ? 'up' : 'down';
326 1
		$context['sort_title'] = $ascending ? $txt['sort_desc'] : $txt['sort_asc'];
327
328
		// Trick
329 1
		$txt['starter'] = $txt['started_by'];
330
331
		// todo: Need to move this to theme.
332 1
		foreach ($sort_methods as $key => $val)
333
		{
334
			switch ($key)
335
			{
336 1
				case 'subject':
337 1
				case 'starter':
338 1
				case 'last_poster':
339 1
					$sorticon = 'alpha';
340 1
					break;
341 1
				default:
342 1
					$sorticon = 'numeric';
343 1
			}
344
345 1
			$context['topics_headers'][$key] = array(
346 1
				'url' => $scripturl . '?board=' . $context['current_board'] . '.' . $context['start'] . ';sort=' . $key . ($context['sort_by'] == $key && $context['sort_direction'] === 'up' ? ';desc' : ''),
347 1
				'sort_dir_img' => $context['sort_by'] == $key ? '<i class="icon icon-small i-sort-' . $sorticon . '-' . $context['sort_direction'] . '" title="' . $context['sort_title'] . '"><s>' . $context['sort_title'] . '</s></i>' : '',
348
			);
349 1
		}
350
351
		// Calculate the fastest way to get the topics.
352 1
		$start = (int) $this->_req->query->start;
353 1
		if ($start > ($board_info['total_topics'] - 1) / 2)
354 1
		{
355
			$ascending = !$ascending;
356
			$fake_ascending = true;
357
			$maxindex = $board_info['total_topics'] < $start + $maxindex + 1 ? $board_info['total_topics'] - $start : $maxindex;
358
			$start = $board_info['total_topics'] < $start + $maxindex + 1 ? 0 : $board_info['total_topics'] - $start - $maxindex;
359
		}
360
		else
361 1
			$fake_ascending = false;
362
363 1
		$context['topics'] = array();
364
365
		// Set up the query options
366
		$indexOptions = array(
367 1
			'only_approved' => $modSettings['postmod_active'] && !allowedTo('approve_posts'),
368 1
			'previews' => !empty($modSettings['message_index_preview']) ? (empty($modSettings['preview_characters']) ? -1 : $modSettings['preview_characters']) : 0,
369 1
			'include_avatars' => $settings['avatars_on_indexes'],
370 1
			'ascending' => $ascending,
371
			'fake_ascending' => $fake_ascending
372 1
		);
373
374
		// Allow integration to modify / add to the $indexOptions
375 1
		call_integration_hook('integrate_messageindex_topics', array(&$sort_column, &$indexOptions));
376
377 1
		$topics_info = messageIndexTopics($board, $user_info['id'], $start, $maxindex, $context['sort_by'], $sort_column, $indexOptions);
378
379 1
		$context['topics'] = Topic_Util::prepareContext($topics_info, false, !empty($modSettings['preview_characters']) ? $modSettings['preview_characters'] : 128);
380
381
		// Allow addons to add to the $context['topics']
382 1
		call_integration_hook('integrate_messageindex_listing', array($topics_info));
383
384
		// Fix the sequence of topics if they were retrieved in the wrong order. (for speed reasons...)
385
		if ($fake_ascending)
386 1
			$context['topics'] = array_reverse($context['topics'], true);
387
388 1
		$topic_ids = array_keys($context['topics']);
389
390 1
		if (!empty($modSettings['enableParticipation']) && !$user_info['is_guest'] && !empty($topic_ids))
391 1
		{
392 1
			$topics_participated_in = topicsParticipation($user_info['id'], $topic_ids);
393 1
			foreach ($topics_participated_in as $participated)
394
			{
395
				$context['topics'][$participated['id_topic']]['is_posted_in'] = true;
396
				$context['topics'][$participated['id_topic']]['class'] = 'my_' . $context['topics'][$participated['id_topic']]['class'];
397 1
			}
398 1
		}
399
400 1
		$context['jump_to'] = array(
401 1
			'label' => addslashes(un_htmlspecialchars($txt['jump_to'])),
402 1
			'board_name' => htmlspecialchars(strtr(strip_tags($board_info['name']), array('&amp;' => '&')), ENT_COMPAT, 'UTF-8'),
403 1
			'child_level' => $board_info['child_level'],
404
		);
405
406
		// Is Quick Moderation active/needed?
407 1
		if (!empty($options['display_quick_mod']) && !empty($context['topics']))
408 1
		{
409
			$context['can_markread'] = $context['user']['is_logged'];
410
			$context['can_lock'] = allowedTo('lock_any');
411
			$context['can_sticky'] = allowedTo('make_sticky');
412
			$context['can_move'] = allowedTo('move_any');
413
			$context['can_remove'] = allowedTo('remove_any');
414
			$context['can_merge'] = allowedTo('merge_any');
415
416
			// Ignore approving own topics as it's unlikely to come up...
417
			$context['can_approve'] = $modSettings['postmod_active'] && allowedTo('approve_posts') && !empty($board_info['unapproved_topics']);
418
419
			// Can we restore topics?
420
			$context['can_restore'] = allowedTo('move_any') && !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] == $board;
421
422
			// Set permissions for all the topics.
423
			foreach ($context['topics'] as $t => $topic)
424
			{
425
				$started = $topic['first_post']['member']['id'] == $user_info['id'];
426
				$context['topics'][$t]['quick_mod'] = array(
427
					'lock' => allowedTo('lock_any') || ($started && allowedTo('lock_own')),
428
					'sticky' => allowedTo('make_sticky'),
429
					'move' => allowedTo('move_any') || ($started && allowedTo('move_own')),
430
					'modify' => allowedTo('modify_any') || ($started && allowedTo('modify_own')),
431
					'remove' => allowedTo('remove_any') || ($started && allowedTo('remove_own')),
432
					'approve' => $context['can_approve'] && $topic['unapproved_posts']
433
				);
434
				$context['can_lock'] |= ($started && allowedTo('lock_own'));
435
				$context['can_move'] |= ($started && allowedTo('move_own'));
436
				$context['can_remove'] |= ($started && allowedTo('remove_own'));
437
			}
438
439
			// Can we use quick moderation checkboxes?
440
			if ($options['display_quick_mod'] == 1)
441
				$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'];
442
			// Or the icons?
443
			else
444
				$context['can_quick_mod'] = $context['can_remove'] || $context['can_lock'] || $context['can_sticky'] || $context['can_move'];
445
		}
446
447 1
		if (!empty($context['can_quick_mod']) && $options['display_quick_mod'] == 1)
448 1
		{
449
			$context['qmod_actions'] = array('approve', 'remove', 'lock', 'sticky', 'move', 'merge', 'restore', 'markread');
450
			call_integration_hook('integrate_quick_mod_actions');
451
		}
452
453 1
		if (!empty($context['boards']) && $context['start'] == 0)
454 1
			$template_layers->add('display_child_boards');
455
456
		// If there are children, but no topics and no ability to post topics...
457 1
		$context['no_topic_listing'] = !empty($context['boards']) && empty($context['topics']) && !$context['can_post_new'];
458 1
		$template_layers->add('topic_listing');
459
460 1
		addJavascriptVar(array('notification_board_notice' => $context['is_marked_notify'] ? $txt['notification_disable_board'] : $txt['notification_enable_board']), true);
461
462
		// Build the message index button array.
463 1
		$context['normal_buttons'] = array(
464 1
			'new_topic' => array('test' => 'can_post_new', 'text' => 'new_topic', 'image' => 'new_topic.png', 'lang' => true, 'url' => $scripturl . '?action=post;board=' . $context['current_board'] . '.0', 'active' => true),
465 1
			'notify' => array('test' => 'can_mark_notify', 'text' => $context['is_marked_notify'] ? 'unnotify' : 'notify', 'image' => ($context['is_marked_notify'] ? 'un' : '') . 'notify.png', 'lang' => true, 'custom' => 'onclick="return notifyboardButton(this);"', 'url' => $scripturl . '?action=notifyboard;sa=' . ($context['is_marked_notify'] ? 'off' : 'on') . ';board=' . $context['current_board'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']),
466
		);
467
468 1
		addJavascriptVar(array(
469 1
			'txt_mark_as_read_confirm' => $txt['mark_these_as_read_confirm']
470 1
		), true);
471
472
		// They can only mark read if they are logged in and it's enabled!
473 1
		if (!$user_info['is_guest'] && $settings['show_mark_read'])
474 1
			$context['normal_buttons']['markread'] = array(
475 1
				'text' => 'mark_read_short',
476 1
				'image' => 'markread.png',
477 1
				'lang' => true,
478 1
				'url' => $scripturl . '?action=markasread;sa=board;board=' . $context['current_board'] . '.0;' . $context['session_var'] . '=' . $context['session_id'],
479
				'custom' => 'onclick="return markboardreadButton(this);"'
480 1
			);
481
482
		// Allow adding new buttons easily.
483 1
		call_integration_hook('integrate_messageindex_buttons');
484 1
	}
485
486
	/**
487
	 * Allows for moderation from the message index.
488
	 *
489
	 * @todo refactor this...
490
	 */
491
	public function action_quickmod()
492
	{
493
		global $board, $user_info, $modSettings, $context;
494
495
		// Check the session = get or post.
496
		checkSession('request');
497
498
		// Lets go straight to the restore area.
499
		if ($this->_req->getPost('qaction') === 'restore' && !empty($this->_req->post->topics))
500
			redirectexit('action=restoretopic;topics=' . implode(',', $this->_req->post->topics) . ';' . $context['session_var'] . '=' . $context['session_id']);
501
502
		if (isset($_SESSION['topicseen_cache']))
503
			$_SESSION['topicseen_cache'] = array();
504
505
		// This is going to be needed to send off the notifications and for updateLastMessages().
506
		require_once(SUBSDIR . '/Post.subs.php');
507
		require_once(SUBSDIR . '/Notification.subs.php');
508
509
		// Process process process data.
510
		require_once(SUBSDIR . '/Topic.subs.php');
511
512
		// Remember the last board they moved things to.
513
		if (isset($this->_req->post->move_to))
514
		{
515
			$_SESSION['move_to_topic'] = array(
516
				'move_to' => $this->_req->post->move_to,
517
				// And remember the last expiry period too.
518
				'redirect_topic' => $this->_req->getPost('redirect_topic', 'intval', 0),
519
				'redirect_expires' => $this->_req->getPost('redirect_expires', 'intval', 0),
520
			);
521
		}
522
523
		// Only a few possible actions.
524
		$possibleActions = array();
525
		$actions = array();
526
527
		if (!empty($board))
528
		{
529
			$boards_can = array(
530
				'make_sticky' => allowedTo('make_sticky') ? array($board) : array(),
531
				'move_any' => allowedTo('move_any') ? array($board) : array(),
532
				'move_own' => allowedTo('move_own') ? array($board) : array(),
533
				'remove_any' => allowedTo('remove_any') ? array($board) : array(),
534
				'remove_own' => allowedTo('remove_own') ? array($board) : array(),
535
				'lock_any' => allowedTo('lock_any') ? array($board) : array(),
536
				'lock_own' => allowedTo('lock_own') ? array($board) : array(),
537
				'merge_any' => allowedTo('merge_any') ? array($board) : array(),
538
				'approve_posts' => allowedTo('approve_posts') ? array($board) : array(),
539
			);
540
541
			$redirect_url = 'board=' . $board . '.' . $this->_req->query->start;
542
		}
543
		else
544
		{
545
			$boards_can = boardsAllowedTo(array('make_sticky', 'move_any', 'move_own', 'remove_any', 'remove_own', 'lock_any', 'lock_own', 'merge_any', 'approve_posts'), true, false);
546
			$redirect_url = isset($this->_req->post->redirect_url) ? $this->_req->post->redirect_url : (isset($_SESSION['old_url']) ? $_SESSION['old_url'] : substr($modSettings['default_forum_action'], 1));
547
		}
548
549
		if (!$user_info['is_guest'])
550
			$possibleActions[] = 'markread';
551
		if (!empty($boards_can['make_sticky']))
552
			$possibleActions[] = 'sticky';
553
		if (!empty($boards_can['move_any']) || !empty($boards_can['move_own']))
554
			$possibleActions[] = 'move';
555
		if (!empty($boards_can['remove_any']) || !empty($boards_can['remove_own']))
556
			$possibleActions[] = 'remove';
557
		if (!empty($boards_can['lock_any']) || !empty($boards_can['lock_own']))
558
			$possibleActions[] = 'lock';
559
		if (!empty($boards_can['merge_any']))
560
			$possibleActions[] = 'merge';
561
562
		// Two methods: $_REQUEST['actions'] (id_topic => action), and $_REQUEST['topics'] and $this->_req->post->qaction.
563
		// (if action is 'move', $_REQUEST['move_to'] or $_REQUEST['move_tos'][$topic] is used.)
564
		if (!empty($this->_req->post->topics))
565
		{
566
			// If the action isn't valid, just quit now.
567
			if (empty($this->_req->post->qaction) || !in_array($this->_req->post->qaction, $possibleActions))
568
				redirectexit($redirect_url);
569
570
			// Merge requires all topics as one parameter and can be done at once.
571
			if ($this->_req->post->qaction === 'merge')
572
			{
573
				// Merge requires at least two topics.
574
				if (empty($this->_req->post->topics) || count($this->_req->post->topics) < 2)
575
					redirectexit($redirect_url);
576
577
				$controller = new MergeTopics_Controller(new Event_Manager());
578
				$controller->pre_dispatch();
579
				return $controller->action_mergeExecute($this->_req->post->topics);
580
			}
581
582
			// Just convert to the other method, to make it easier.
583
			foreach ($this->_req->post->topics as $topic)
584
				$actions[(int) $topic] = $this->_req->post->qaction;
585
		}
586
		else
587
		{
588
			$actions = $this->_req->actions;
589
		}
590
591
		// Weird... how'd you get here?
592
		if (empty($actions))
593
			redirectexit($redirect_url);
594
595
		// Validate each action.
596
		$all_actions = array();
597
		$action = '';
598
		foreach ($actions as $topic => $action)
599
		{
600
			if (in_array($action, $possibleActions))
601
				$all_actions[(int) $topic] = $action;
602
		}
603
604
		$stickyCache = array();
605
		$moveCache = array(0 => array(), 1 => array());
606
		$removeCache = array();
607
		$lockCache = array();
608
		$markCache = array();
609
610
		if (!empty($all_actions))
611
		{
612
			// Find all topics...
613
			$topics_info = topicsDetails(array_keys($all_actions));
614
615
			foreach ($topics_info as $row)
616
			{
617
				if (!empty($board))
618
				{
619
					if ($row['id_board'] != $board || ($modSettings['postmod_active'] && !$row['approved'] && !allowedTo('approve_posts')))
620
						continue;
621
				}
622
				else
623
				{
624
					// Don't allow them to act on unapproved posts they can't see...
625
					if ($modSettings['postmod_active'] && !$row['approved'] && !in_array(0, $boards_can['approve_posts']) && !in_array($row['id_board'], $boards_can['approve_posts']))
626
					{
627
						continue;
628
					}
629
					// Goodness, this is fun.  We need to validate the action.
630
					elseif ($all_actions[$row['id_topic']] === 'sticky'
631
						&& !in_array(0, $boards_can['make_sticky'])
632
						&& !in_array($row['id_board'], $boards_can['make_sticky']))
633
					{
634
						continue;
635
					}
636
					elseif ($all_actions[$row['id_topic']] === 'move'
637
						&& !in_array(0, $boards_can['move_any'])
638
						&& !in_array($row['id_board'], $boards_can['move_any'])
639
						&& ($row['id_member_started'] != $user_info['id']
640
							|| (!in_array(0, $boards_can['move_own']) && !in_array($row['id_board'], $boards_can['move_own']))))
641
					{
642
						continue;
643
					}
644
					elseif ($all_actions[$row['id_topic']] === 'remove'
645
						&& !in_array(0, $boards_can['remove_any'])
646
						&& !in_array($row['id_board'], $boards_can['remove_any'])
647
						&& ($row['id_member_started'] != $user_info['id']
648
							|| (!in_array(0, $boards_can['remove_own']) && !in_array($row['id_board'], $boards_can['remove_own']))))
649
					{
650
						continue;
651
					}
652
					elseif ($all_actions[$row['id_topic']] === 'lock'
653
						&& !in_array(0, $boards_can['lock_any'])
654
						&& !in_array($row['id_board'], $boards_can['lock_any'])
655
						&& ($row['id_member_started'] != $user_info['id']
656
							|| $row['locked'] == 1
657
							|| (!in_array(0, $boards_can['lock_own']) && !in_array($row['id_board'], $boards_can['lock_own']))))
658
					{
659
						continue;
660
					}
661
				}
662
663
				// Separate the actions.
664
				switch ($action)
665
				{
666
					case 'markread':
667
						$markCache[] = $row['id_topic'];
668
						break;
669
					case 'sticky':
670
						$stickyCache[] = $row['id_topic'];
671
						break;
672
					case 'move':
673
						if (isset($this->_req->query->current_board))
674
						{
675
							moveTopicConcurrence((int) $this->_req->query->current_board);
676
						}
677
678
						// $moveCache[0] is the topic, $moveCache[1] is the board to move to.
679
						$moveCache[1][$row['id_topic']] = (int) (isset($this->_req->post->move_tos[$row['id_topic']]) ? $this->_req->post->move_tos[$row['id_topic']] : $this->_req->post->move_to);
680
681
						if (!empty($moveCache[1][$row['id_topic']]))
682
						{
683
							$moveCache[0][] = $row['id_topic'];
684
						}
685
						break;
686
					case 'remove':
687
						$removeCache[] = $row['id_topic'];
688
						break;
689
					case 'lock':
690
						$lockCache[] = $row['id_topic'];
691
						break;
692
				}
693
			}
694
		}
695
696
		$affectedBoards = empty($board) ? array() : array((int) $board => array(0, 0));
697
698
		// Do all the stickies...
699
		if (!empty($stickyCache))
700
			toggleTopicSticky($stickyCache, true);
701
702
		// Move sucka! (this is, by the by, probably the most complicated part....)
703
		if (!empty($moveCache[0]))
704
			moveTopicsPermissions($moveCache);
705
706
		// Now delete the topics...
707
		if (!empty($removeCache))
708
			removeTopicsPermissions($removeCache);
709
710
		// And (almost) lastly, lock the topics...
711
		if (!empty($lockCache))
712
			toggleTopicsLock($lockCache, true);
713
714
		if (!empty($markCache))
715
		{
716
			$logged_topics = getLoggedTopics($user_info['id'], $markCache);
717
718
			$markArray = array();
719
			foreach ($markCache as $topic)
720
				$markArray[] = array($user_info['id'], $topic, $modSettings['maxMsgID'], (int) !empty($logged_topics[$topic]));
721
722
			markTopicsRead($markArray, true);
723
		}
724
725
		updateTopicStats();
726
		require_once(SUBSDIR . '/Messages.subs.php');
727
			updateMessageStats();
728
		updateSettings(array(
729
			'calendar_updated' => time(),
730
		));
731
732
		if (!empty($affectedBoards))
733
			updateLastMessages(array_keys($affectedBoards));
734
735
		redirectexit($redirect_url);
736
	}
737
}
738