Completed
Push — development ( ac22bd...5236fa )
by Stephen
14:46
created

MoveTopic_Controller::_check_access_2()   C

Complexity

Conditions 9
Paths 15

Size

Total Lines 47
Code Lines 21

Duplication

Lines 4
Ratio 8.51 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 0
Metric Value
cc 9
eloc 21
nc 15
nop 0
dl 4
loc 47
ccs 0
cts 23
cp 0
crap 90
rs 5.2941
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Handles the moving of topics from board to board
5
 *
6
 * @name      ElkArte Forum
7
 * @copyright ElkArte Forum contributors
8
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause
9
 *
10
 * This file contains code covered by:
11
 * copyright:	2011 Simple Machines (http://www.simplemachines.org)
12
 * license:		BSD, See included LICENSE.TXT for terms and conditions.
13
 *
14
 * @version 1.1
15
 *
16
 */
17
18
/**
19
 * Move Topic Controller
20
 */
21
class MoveTopic_Controller extends Action_Controller
22
{
23
	/**
24
	 * The id of the topic being manipulated
25
	 * @var int
26
	 */
27
	private $_topic;
28
29
	/**
30
	 * Information about the topic being moved
31
	 * @var array
32
	 */
33
	private $_topic_info;
34
35
	/**
36
	 * Information about the board where the topic resides
37
	 * @var array
38
	 */
39
	private $_board_info;
40
41
	/**
42
	 * Board that will receive the topic
43
	 * @var int
44
	 */
45
	private $_toboard;
46
47
	/**
48
	 * Pre Dispatch, called before other methods.
49
	 */
50
	public function pre_dispatch()
51
	{
52
		global $topic;
53
54
		// Set the topic from the global, yes yes
55
		$this->_topic = $topic;
56
	}
57
58
	/**
59
	 * Forwards to the action method to handle the action.
60
	 *
61
	 * @see Action_Controller::action_index()
62
	 */
63
	public function action_index()
64
	{
65
		// move a topic, what else?!
66
		// $this->action_movetopic();
67
	}
68
69
	/**
70
	 * This function allows to move a topic
71
	 *
72
	 * What it does:
73
	 *
74
	 * - It must be called with a topic specified. (that is, global $topic must
75
	 * be set... @todo fix this thing.)
76
	 * - Validates access
77
	 * - Accessed via ?action=movetopic.
78
	 *
79
	 * @uses template_move_topic() sub-template in MoveTopic.template.php
80
	 */
81
	public function action_movetopic()
82
	{
83
		global $context;
84
85
		// Lets make sure they can access the topic being moved and have permissions to move it
86
		$this->_check_access();
87
88
		// Get a list of boards this moderator can move to.
89
		require_once(SUBSDIR . '/Boards.subs.php');
90
		$context += getBoardList(array('not_redirection' => true));
91
92
		// No boards?
93
		if (empty($context['categories']) || $context['num_boards'] == 1)
94
			throw new Elk_Exception('moveto_noboards', false);
95
96
		// Already used the function, let's set the selected board back to the last
97
		$last_moved_to = isset($_SESSION['move_to_topic']['move_to']) && $_SESSION['move_to_topic']['move_to'] != $context['current_board'] ? (int) $_SESSION['move_to_topic']['move_to'] : 0;
98
		if (!empty($last_moved_to))
99
		{
100
			foreach ($context['categories'] as $id => $values)
101
			{
102
				if (isset($values['boards'][$last_moved_to]))
103
				{
104
					$context['categories'][$id]['boards'][$last_moved_to]['selected'] = true;
105
					break;
106
				}
107
			}
108
		}
109
110
		// Set up for the template
111
		theme()->getTemplates()->load('MoveTopic');
112
		$this->_prep_template();
113
	}
114
115
	/**
116
	 * Executes the actual move of a topic.
117
	 *
118
	 * What it does:
119
	 *
120
	 * - It is called on the submit of action_movetopic.
121
	 * - This function logs that topics have been moved in the moderation log.
122
	 * - Upon successful completion redirects to message index.
123
	 * - Accessed via ?action=movetopic2.
124
	 *
125
	 * @uses subs/Post.subs.php.
126
	 */
127
	public function action_movetopic2()
128
	{
129
		global $board, $user_info;
130
131
		$this->_check_access_2();
132
133
		checkSession();
134
		require_once(SUBSDIR . '/Post.subs.php');
135
		require_once(SUBSDIR . '/Boards.subs.php');
136
137
		// The destination board must be numeric.
138
		$this->_toboard = (int) $this->_req->post->toboard;
139
140
		// Make sure they can see the board they are trying to move to (and get whether posts count in the target board).
141
		$this->_board_info = boardInfo($this->_toboard, $this->_topic);
142
		if (empty($this->_board_info))
143
			throw new Elk_Exception('no_board');
144
145
		// Remember this for later.
146
		$_SESSION['move_to_topic'] = array(
147
			'move_to' => $this->_toboard
148
		);
149
150
		// Rename the topic if needed
151
		$this->_rename_topic();
152
153
		// Create a link to this in the old board.
154
		$this->_post_redirect();
155
156
		// Account for boards that count posts and those that don't
157
		$this->_count_update();
158
159
		// Do the move (includes statistics update needed for the redirect topic).
160
		moveTopics($this->_topic, $this->_toboard);
161
162
		// Log that they moved this topic.
163
		if (!allowedTo('move_own') || $this->_topic_info['id_member_started'] != $user_info['id'])
164
			logAction('move', array('topic' => $this->_topic, 'board_from' => $board, 'board_to' => $this->_toboard));
165
166
		// Notify people that this topic has been moved?
167
		require_once(SUBSDIR . '/Notification.subs.php');
168
		sendNotifications($this->_topic, 'move');
169
170
		// Why not go back to the original board in case they want to keep moving?
171
		if (!isset($this->_req->post->goback))
172
			redirectexit('board=' . $board . '.0');
173
		else
174
			redirectexit('topic=' . $this->_topic . '.0');
175
	}
176
177
	/**
178
	 * Prepares the content for use in the move topic template
179
	 */
180
	private function _prep_template()
181
	{
182
		global $context, $txt, $scripturl, $user_info, $language, $board;
183
184
		$context['is_approved'] = $this->_topic_info['approved'];
185
		$context['subject'] = $this->_topic_info['subject'];
186
		$context['redirect_topic'] = isset($_SESSION['move_to_topic']['redirect_topic']) ? (int) $_SESSION['move_to_topic']['redirect_topic'] : 0;
187
		$context['redirect_expires'] = isset($_SESSION['move_to_topic']['redirect_expires']) ? (int) $_SESSION['move_to_topic']['redirect_expires'] : 0;
188
		$context['page_title'] = $txt['move_topic'];
189
		$context['sub_template'] = 'move_topic';
190
191
		// Breadcrumbs
192
		$context['linktree'][] = array(
193
			'url' => $scripturl . '?topic=' . $this->_topic . '.0',
194
			'name' => $context['subject'],
195
		);
196
		$context['linktree'][] = array(
197
			'url' => '#',
198
			'name' => $txt['move_topic'],
199
		);
200
201
		$context['back_to_topic'] = isset($this->_req->post->goback);
202
203
		// Ugly !
204 View Code Duplication
		if ($user_info['language'] != $language)
205
		{
206
			theme()->getTemplates()->loadLanguageFile('index', $language);
207
			$temp = $txt['movetopic_default'];
208
			theme()->getTemplates()->loadLanguageFile('index');
209
			$txt['movetopic_default'] = $temp;
210
		}
211
212
		// We will need this
213 View Code Duplication
		if (isset($this->_req->query->current_board))
214
		{
215
			moveTopicConcurrence((int) $this->_req->query->current_board, $board, $this->_topic);
216
		}
217
218
		// Register this form and get a sequence number in $context.
219
		checkSubmitOnce('register');
220
	}
221
222
	/**
223
	 * Validates that the member can access the topic
224
	 *
225
	 * What it does:
226
	 *
227
	 * - Checks that a topic is supplied
228
	 * - Validates the topic information can be loaded
229
	 * - If the topic is not approved yet, must have approve permissions to move it
230
	 * - If the member is the topic starter requires the move_own permission, otherwise the move_any permission.
231
	 */
232
	private function _check_access()
233
	{
234
		global $modSettings, $user_info;
235
236
		if (empty($this->_topic))
237
			throw new Elk_Exception('no_access', false);
238
239
		// Retrieve the basic topic information for whats being moved
240
		require_once(SUBSDIR . '/Topic.subs.php');
241
		$this->_topic_info = getTopicInfo($this->_topic, 'message');
242
243
		if (empty($this->_topic_info))
244
			throw new Elk_Exception('topic_gone', false);
245
246
		// Can they see it - if not approved?
247
		if ($modSettings['postmod_active'] && !$this->_topic_info['approved'])
248
			isAllowedTo('approve_posts');
249
250
		// Are they allowed to actually move any topics or even their own?
251
		if (!allowedTo('move_any') && ($this->_topic_info['id_member_started'] == $user_info['id'] && !allowedTo('move_own')))
252
			throw new Elk_Exception('cannot_move_any', false);
253
	}
254
255
	/**
256
	 * Checks access and input validation before committing the move
257
	 *
258
	 * What it does:
259
	 *
260
	 * - Checks that a topic is supplied
261
	 * - Validates the move location
262
	 * - Checks redirection details if its a redirection is to be posted
263
	 * - If the member is the topic starter requires the move_own permission, otherwise the move_any permission.
264
	 *
265
	 * @return bool
266
	 * @throws Elk_Exception no_access
267
	 */
268
	private function _check_access_2()
269
	{
270
		global $user_info, $board;
271
272
		if (empty($this->_topic))
273
			throw new Elk_Exception('no_access', false);
274
275
		// You can't choose to have a redirection topic and not provide a reason.
276
		if (isset($this->_req->post->postRedirect) && $this->_req->getPost('reason', 'trim', '') === '')
277
			throw new Elk_Exception('movetopic_no_reason', false);
278
279
		// You have to tell us were you are moving to
280
		if (!isset($this->_req->post->toboard))
281
			throw new Elk_Exception('movetopic_no_board', false);
282
283
		// We will need this
284
		require_once(SUBSDIR . '/Topic.subs.php');
285 View Code Duplication
		if (isset($this->_req->query->current_board))
286
		{
287
			moveTopicConcurrence((int) $this->_req->query->current_board, $board, $this->_topic);
288
		}
289
290
		// Make sure this form hasn't been submitted before.
291
		checkSubmitOnce('check');
292
293
		// Get the basic details on this topic (again)
294
		$this->_topic_info = getTopicInfo($this->_topic);
295
296
		// Not approved then you need approval permissions to move it as well
297
		if (!$this->_topic_info['approved'])
298
			isAllowedTo('approve_posts');
299
300
		// Can they move topics on this board?
301
		if (!allowedTo('move_any'))
302
		{
303
			if ($this->_topic_info['id_member_started'] == $user_info['id'])
304
			{
305
				isAllowedTo('move_own');
306
			}
307
			else
308
			{
309
				isAllowedTo('move_any');
310
			}
311
		}
312
313
		return true;
314
	}
315
316
	/**
317
	 * Renames the topic during the move if requested
318
	 *
319
	 * What it does:
320
	 *
321
	 * - Renames the moved topic with a new topic subject
322
	 * - If enforce_subject is set, renames all posts withing the moved topic posts with a new subject
323
	 */
324
	private function _rename_topic()
325
	{
326
		global $context;
327
328
		// Rename the topic...
329
		if (isset($this->_req->post->reset_subject, $this->_req->post->custom_subject) && $this->_req->post->custom_subject != '')
330
		{
331
			$custom_subject = strtr(Util::htmltrim(Util::htmlspecialchars($this->_req->post->custom_subject)), array("\r" => '', "\n" => '', "\t" => ''));
332
333
			// Keep checking the length.
334
			if (Util::strlen($custom_subject) > 100)
335
				$custom_subject = Util::substr($custom_subject, 0, 100);
336
337
			// If it's still valid move onwards and upwards.
338
			if ($custom_subject != '')
339
			{
340
				$all_messages = isset($this->_req->post->enforce_subject);
341
				if ($all_messages)
342
				{
343
					// Get a response prefix, but in the forum's default language.
344
					$context['response_prefix'] = response_prefix();
345
346
					topicSubject($this->_topic_info, $custom_subject, $context['response_prefix'], $all_messages);
347
				}
348
				else
349
					topicSubject($this->_topic_info, $custom_subject);
350
351
				// Fix the subject cache.
352
				require_once(SUBSDIR . '/Messages.subs.php');
353
				updateSubjectStats($this->_topic, $custom_subject);
354
			}
355
		}
356
	}
357
358
	/**
359
	 * Posts a redirection topic in the original location of the moved topic
360
	 *
361
	 * What it does:
362
	 *
363
	 * - If leaving a moved "where did it go" topic, validates the needed inputs
364
	 * - Posts a new topic in the originating board of the topic to be moved.
365
	 */
366
	private function _post_redirect()
367
	{
368
		global $txt, $board, $scripturl, $language, $user_info;
369
370
		// @todo Does this make sense if the topic was unapproved before? I'd just about say so.
371
		if (isset($this->_req->post->postRedirect))
372
		{
373
			// Should be in the boardwide language.
374
			if ($user_info['language'] != $language)
375
				theme()->getTemplates()->loadLanguageFile('index', $language);
376
377
			$reason = Util::htmlspecialchars($this->_req->post->reason, ENT_QUOTES);
378
			preparsecode($reason);
379
380
			// Add a URL onto the message.
381
			$reason = strtr($reason, array(
382
				$txt['movetopic_auto_board'] => '[url=' . $scripturl . '?board=' . $this->_toboard . '.0]' . $this->_board_info['name'] . '[/url]',
383
				$txt['movetopic_auto_topic'] => '[iurl]' . $scripturl . '?topic=' . $this->_topic . '.0[/iurl]'
384
			));
385
386
			// Auto remove this MOVED redirection topic in the future?
387
			$redirect_expires = !empty($this->_req->post->redirect_expires) ? (int) $this->_req->post->redirect_expires : 0;
388
389
			// Redirect to the MOVED topic from topic list?
390
			$redirect_topic = isset($this->_req->post->redirect_topic) ? $this->_topic : 0;
391
392
			// And remember the last expiry period too.
393
			$_SESSION['move_to_topic']['redirect_topic'] = $redirect_topic;
394
			$_SESSION['move_to_topic']['redirect_expires'] = $redirect_expires;
395
396
			$msgOptions = array(
397
				'subject' => $txt['moved'] . ': ' . $this->_board_info['subject'],
398
				'body' => $reason,
399
				'icon' => 'moved',
400
				'smileys_enabled' => 1,
401
			);
402
403
			$topicOptions = array(
404
				'board' => $board,
405
				'lock_mode' => 1,
406
				'mark_as_read' => true,
407
				'redirect_expires' => empty($redirect_expires) ? 0 : ($redirect_expires * 60) + time(),
408
				'redirect_topic' => $redirect_topic,
409
			);
410
411
			$posterOptions = array(
412
				'id' => $user_info['id'],
413
				'update_post_count' => empty($this->_board_info['count_posts']),
414
			);
415
			createPost($msgOptions, $topicOptions, $posterOptions);
416
		}
417
	}
418
419
	/**
420
	 * Accounts for board / user post counts when a topic is moved.
421
	 *
422
	 * What it does:
423
	 *
424
	 * - Checks if a topic is being moved to/from a board that does/does'nt count posts.
425
	 */
426
	private function _count_update()
427
	{
428
		global $board;
429
430
		$board_from = boardInfo($board);
431
		if ($board_from['count_posts'] != $this->_board_info['count_posts'])
432
		{
433
			require_once(SUBSDIR . '/Members.subs.php');
434
			$posters = postersCount($this->_topic);
435
436 View Code Duplication
			foreach ($posters as $id_member => $posts)
437
			{
438
				// The board we're moving from counted posts, but not to.
439
				if (empty($board_from['count_posts']))
440
					updateMemberData($id_member, array('posts' => 'posts - ' . $posts));
441
				// The reverse: from didn't, to did.
442
				else
443
					updateMemberData($id_member, array('posts' => 'posts + ' . $posts));
444
			}
445
		}
446
	}
447
}
448