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

RemoveTopic_Controller   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 299
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
eloc 94
dl 0
loc 299
rs 8.72
c 0
b 0
f 0
wmc 46
ccs 0
cts 137
cp 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A action_index() 0 2 1
B action_restoretopic() 0 52 9
A pre_dispatch() 0 4 1
A _redirectBack() 0 23 4
B action_removetopic2() 0 53 9
A _checkApproval() 0 11 5
C _verifyDeletePermissions() 0 33 13
A action_deletemsg() 0 45 4

How to fix   Complexity   

Complex Class

Complex classes like RemoveTopic_Controller often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use RemoveTopic_Controller, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * The contents of this file handle the deletion of topics, posts, and related
5
 * paraphernalia.
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
16
 *
17
 */
18
19
/**
20
 * RemoveTopic_Controller Class
21
 * Handles the deletion of topics, posts
22
 */
23
class RemoveTopic_Controller extends Action_Controller
24
{
25
	/**
26
	 * Hold topic information for supplied message
27
	 * @var array
28
	 */
29
	private $_topic_info;
30
31
	/**
32
	 * Pre Dispatch, called before other methods.
33
	 */
34
	public function pre_dispatch()
35
	{
36
		// This has some handy functions for topics
37
		require_once(SUBSDIR . '/Topic.subs.php');
38
	}
39
40
	/**
41
	 * Intended entry point for this class.
42
	 *
43
	 * All actions are directly called from other points, so there
44
	 * is currently nothing to action in this method.
45
	 *
46
	 * @see Action_Controller::action_index()
47
	 */
48
	public function action_index()
49
	{
50
		// call the right method
51
	}
52
53
	/**
54
	 * Completely remove an entire topic.
55
	 *
56
	 * What it does:
57
	 *
58
	 * - Redirects to the board when completed.
59
	 * - Accessed by ?action=removetopic2
60
	 * - Removes a topic if it has not already been removed.
61
	 */
62
	public function action_removetopic2()
63
	{
64
		global $user_info, $topic, $board, $modSettings;
65
66
		// Make sure they aren't being lead around by someone. (:@)
67
		checkSession('get');
68
69
		// Trying to fool us around, are we?
70
		if (empty($topic))
71
		{
72
			redirectexit();
73
		}
74
75
		// This file needs to be included for sendNotifications().
76
		require_once(SUBSDIR . '/Notification.subs.php');
77
78
		// Check if its been recycled
79
		removeDeleteConcurrence();
80
81
		$this->_topic_info = getTopicInfo($topic, 'message');
82
83
		// Can you remove your own or any topic
84
		if ($this->_topic_info['id_member_started'] == $user_info['id'] && !allowedTo('remove_any'))
85
		{
86
			isAllowedTo('remove_own');
87
		}
88
		else
89
		{
90
			isAllowedTo('remove_any');
91
		}
92
93
		// Can they see the topic to remove it?
94
		$this->_checkApproval();
95
96
		// Notify people that this topic has been removed.
97
		sendNotifications($topic, 'remove');
98
99
		// Remove the topic
100
		removeTopics($topic);
101
102
		// Note, only log topic ID in native form if it's not gone forever.
103
		if (allowedTo('remove_any') || (allowedTo('remove_own') && $this->_topic_info['id_member_started'] == $user_info['id']))
104
		{
105
			logAction('remove', array(
106
				(empty($modSettings['recycle_enable']) || $modSettings['recycle_board'] != $board ? 'topic' : 'old_topic_id') => $topic,
107
				'subject' => $this->_topic_info['subject'],
108
				'member' => $this->_topic_info['id_member_started'],
109
				'board' => $board)
110
			);
111
		}
112
113
		// Back to the board where the topic was removed from
114
		redirectexit('board=' . $board . '.0');
115
	}
116
117
	/**
118
	 * Remove just a single post.
119
	 *
120
	 * What it does:
121
	 *  - On completion redirect to the topic or to the board.
122
	 *  - Accessed by ?action=deletemsg
123
	 *  - Verifies the message exists and that they can see the message
124
	 */
125
	public function action_deletemsg()
126
	{
127
		global $topic, $modSettings;
128
129
		checkSession('get');
130
131
		// This has some handy functions for topics
132
		require_once(SUBSDIR . '/Messages.subs.php');
133
134
		// Need a message to remove
135
		$_msg = $this->_req->getQuery('msg', 'intval', null);
136
137
		// Is $topic set?
138
		if (empty($topic) && isset($this->_req->query->topic))
139
		{
140
			$topic = (int) $this->_req->query->topic;
141
		}
142
143
		// Trying to mess around are we?
144
		if (empty($_msg))
145
		{
146
			redirectexit();
147
		}
148
149
		// Permanently removing from the recycle bin?
150
		removeDeleteConcurrence();
151
152
		// Load the message details
153
		$this->_topic_info = loadMessageDetails(
154
			array('t.id_member_started'),
155
			array('LEFT JOIN {db_prefix}topics AS t ON (m.id_topic = t.id_topic)'),
156
			array('message_list' => $_msg)
157
		);
158
159
		// Can they see the message to remove it?
160
		$this->_checkApproval();
161
162
		// Ensure they can do this
163
		$this->_verifyDeletePermissions();
164
165
		// Do the removal, track if we removed the entire topic so we redirect back to the board.
166
		$remover = new MessagesDelete($modSettings['recycle_enable'], $modSettings['recycle_board']);
167
		$full_topic = $remover->removeMessage($_msg);
168
169
		$this->_redirectBack($full_topic);
170
	}
171
172
	/**
173
	 * Move back a topic or post from the recycle board to its original board.
174
	 *
175
	 * What it does:
176
	 *
177
	 * - Merges back the posts to the original as necessary.
178
	 * - Accessed by ?action=restoretopic
179
	 */
180
	public function action_restoretopic()
181
	{
182
		global $modSettings;
183
184
		// Check session.
185
		checkSession('get');
186
187
		// Is recycled board enabled?
188
		if (empty($modSettings['recycle_enable']))
189
		{
190
			throw new Elk_Exception('restored_disabled', 'critical');
191
		}
192
193
		// Can we be in here?
194
		isAllowedTo('move_any', $modSettings['recycle_board']);
195
196
		$restorer = new MessagesDelete($modSettings['recycle_enable'], $modSettings['recycle_board']);
197
198
		// Restoring messages?
199
		if (!empty($this->_req->query->msgs))
200
		{
201
			$actioned_messages = $restorer->restoreMessages(array_map('intval', explode(',', $this->_req->query->msgs)));
202
		}
203
204
		// Now any topics?
205
		if (!empty($this->_req->query->topics))
206
		{
207
			$topics_to_restore = array_map('intval', explode(',', $this->_req->query->topics));
208
			$restorer->restoreTopics($topics_to_restore);
209
		}
210
211
		$restorer->doRestore();
212
213
		// Didn't find some things?
214
		if ($restorer->unfoundRestoreMessages())
215
		{
216
			throw new Elk_Exception('restore_not_found', false, array('<ul><li>' . implode('</li><li>', $restorer->unfoundRestoreMessages(true)) . '</li></ul>'));
217
		}
218
219
		// Lets send them back somewhere that may make sense
220
		if (isset($actioned_messages) && count($actioned_messages) == 1 && empty($topics_to_restore))
221
		{
222
			reset($actioned_messages);
223
			redirectexit('topic=' . key($actioned_messages));
224
		}
225
		elseif (count($topics_to_restore) == 1)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $topics_to_restore does not seem to be defined for all execution paths leading up to this point.
Loading history...
226
		{
227
			redirectexit('topic=' . $topics_to_restore[0]);
228
		}
229
		else
230
		{
231
			redirectexit();
232
		}
233
	}
234
235
	/**
236
	 * Verifies the user has the permissions needed to remove a message
237
	 *
238
	 * - @uses isAllowedTo() which will end processing if user lacks proper permissions.
239
	 */
240
	private function _verifyDeletePermissions()
241
	{
242
		global $user_info, $modSettings;
243
244
		if ($this->_topic_info['id_member'] == $user_info['id'])
245
		{
246
			// Are you allowed to delete it
247
			if (!allowedTo('delete_own'))
248
			{
249
				if ($this->_topic_info['id_member_started'] == $user_info['id'] && !allowedTo('delete_any'))
250
				{
251
					isAllowedTo('delete_replies');
252
				}
253
				elseif (!allowedTo('delete_any'))
254
				{
255
					isAllowedTo('delete_own');
256
				}
257
			}
258
			elseif (!allowedTo('delete_any')
259
				&& ($this->_topic_info['id_member_started'] != $user_info['id'] || !allowedTo('delete_replies'))
260
				&& !empty($modSettings['edit_disable_time'])
261
				&& $this->_topic_info['poster_time'] + $modSettings['edit_disable_time'] * 60 < time())
262
			{
263
				throw new Elk_Exception('modify_post_time_passed', false);
264
			}
265
		}
266
		elseif ($this->_topic_info['id_member_started'] == $user_info['id'] && !allowedTo('delete_any'))
267
		{
268
			isAllowedTo('delete_replies');
269
		}
270
		else
271
		{
272
			isAllowedTo('delete_any');
273
		}
274
	}
275
276
	/**
277
	 * After deleting a message(s) returns the user to the best possible location
278
	 *
279
	 * @param bool $full_topic if the entire topic was removed
280
	 * @throws Elk_Exception
281
	 */
282
	private function _redirectBack($full_topic)
283
	{
284
		global $topic, $board;
285
286
		// We want to redirect back to recent action.
287
		if (isset($this->_req->query->recent))
288
		{
289
			redirectexit('action=recent');
290
		}
291
		// Back to profile
292
		elseif (isset($this->_req->query->profile, $this->_req->query->start, $this->_req->query->u))
293
		{
294
			redirectexit('action=profile;u=' . $this->_req->query->u . ';area=showposts;start=' . $this->_req->query->start);
295
		}
296
		// Back to the board if the topic was removed
297
		elseif ($full_topic)
298
		{
299
			redirectexit('board=' . $board . '.0');
300
		}
301
		// Back to the topic where the message was removed
302
		else
303
		{
304
			redirectexit('topic=' . $topic . '.' . $this->_req->query->start);
305
		}
306
	}
307
308
	/**
309
	 * Verifies the user has permissions to remove an unapproved message/topic
310
	 */
311
	private function _checkApproval()
312
	{
313
		global $modSettings, $user_info;
314
315
		// Verify they can see this!
316
		if ($modSettings['postmod_active']
317
			&& !$this->_topic_info['approved']
318
			&& !empty($this->_topic_info['id_member'])
319
			&& $this->_topic_info['id_member'] != $user_info['id'])
320
		{
321
			isAllowedTo('approve_posts');
322
		}
323
	}
324
}
325