ManagePosts::action_postSettings_display()   F
last analyzed

Complexity

Conditions 19
Paths 516

Size

Total Lines 98
Code Lines 46

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 114.9262

Importance

Changes 0
Metric Value
cc 19
eloc 46
c 0
b 0
f 0
nc 516
nop 0
dl 0
loc 98
rs 1.0222
ccs 15
cts 42
cp 0.357
crap 114.9262

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
 * Handles all the administration settings for topics and posts.
5
 *
6
 * @package   ElkArte Forum
7
 * @copyright ElkArte Forum contributors
8
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file)
9
 *
10
 * This file contains code covered by:
11
 * copyright: 2011 Simple Machines (http://www.simplemachines.org)
12
 *
13
 * @version 2.0 Beta 1
14
 *
15
 */
16
17
namespace ElkArte\AdminController;
18
19
use ElkArte\AbstractController;
20
use ElkArte\Action;
21
use ElkArte\Exceptions\Exception;
22
use ElkArte\SettingsForm\SettingsForm;
23
24
/**
25
 * ManagePosts controller handles all the administration settings for topics and posts.
26
 *
27
 * @package Posts
28
 */
29
class ManagePosts extends AbstractController
30
{
31
	/**
32
	 * The main entrance point for the 'Posts and topics' screen.
33
	 *
34
	 * What it does:
35
	 *
36
	 * - Like all others, it checks permissions, then forwards to the right function
37
	 * based on the given sub-action.
38
	 * - Defaults to sub-action 'posts'.
39
	 * - Accessed from ?action=admin;area=postsettings.
40
	 * - Requires (and checks for) the admin_forum permission.
41
	 *
42
	 * @event integrate_sa_manage_posts used to add new subactions
43
	 * @see AbstractController::action_index()
44
	 */
45
	public function action_index()
46
	{
47
		global $context, $txt;
48
49
		$subActions = [
50
			'posts' => [
51
				$this, 'action_postSettings_display', 'permission' => 'admin_forum'],
52
			'censor' => [
53
				$this, 'action_censor', 'permission' => 'admin_forum'],
54
			'topics' => [
55
				'function' => 'action_index',
56
				'controller' => ManageTopics::class,
57
				'permission' => 'admin_forum'],
58
		];
59
60
		// Good old action handle
61
		$action = new Action('manage_posts');
62
63
		// Default the sub-action to 'posts'. call integrate_sa_manage_posts
64
		$subAction = $action->initialize($subActions, 'posts');
65
66
		// Just for the template
67
		$context['page_title'] = $txt['manageposts_title'];
68
		$context['sub_action'] = $subAction;
69
70
		// Tabs for browsing the different post-functions.
71
		$context[$context['admin_menu_name']]['object']->prepareTabData([
72
				'title' => 'manageposts_title',
73
				'help' => 'posts_and_topics',
74
				'description' => 'manageposts_description',
75
				'tabs' => [
76
					'posts' => [
77
						'description' => $txt['manageposts_settings_description'],
78
					],
79
					'censor' => [
80
						'description' => $txt['admin_censored_desc'],
81
					],
82
					'topics' => [
83
						'description' => $txt['manageposts_topic_settings_description'],
84
					],
85
				]]
86
		);
87
88
		// Call the right function for this sub-action.
89
		$action->dispatch($subAction);
90
	}
91
92
	/**
93
	 * Shows an interface to set and test censored words.
94
	 *
95
	 * - It uses the censor_vulgar, censor_proper, censorWholeWord, and
96
	 * censorIgnoreCase settings.
97
	 * - Requires the admin_forum permission.
98
	 * - Accessed from ?action=admin;area=postsettings;sa=censor.
99
	 *
100
	 * @event integrate_save_censors
101
	 * @event integrate_censors
102
	 * @uses the Admin template and the edit_censored sub template.
103
	 */
104
	public function action_censor(): void
105
	{
106
		global $txt, $modSettings, $context;
107
108
		if ($this->_req->hasPost('save_censor'))
109
		{
110
			// Make sure censoring is something they can do.
111
			checkSession();
112
			validateToken('admin-censor');
113
114
			$censored_vulgar = [];
115
			$censored_proper = [];
116
117
			// Rip it apart, then split it into two arrays.
118
			if ($this->_req->hasPost('censortext'))
119
			{
120
				$censorText = $this->_req->getPost('censortext', 'trim', '');
121
				$censorText = explode("\n", strtr($censorText, ["\r" => '']));
122
				foreach ($censorText as $c)
123
				{
124
					[$censored_vulgar[], $censored_proper[]] = array_pad(explode('=', trim($c)), 2, '');
125
				}
126
			}
127
			elseif ($this->_req->hasPost('censor_vulgar') && $this->_req->hasPost('censor_proper'))
128
			{
129
				$posted_vulgar = $this->_req->getPost('censor_vulgar', null, []);
130
				if (is_array($posted_vulgar))
131
				{
132
					// Work on local copies to avoid mutating the request
133
					$local_vulgar = (array) $posted_vulgar;
134
					$local_proper = (array) $this->_req->getPost('censor_proper', null, []);
135
136
					foreach ($local_vulgar as $i => $value)
137
					{
138
						if (trim(str_replace('*', ' ', $value)) === '')
139
						{
140
							unset($local_vulgar[$i], $local_proper[$i]);
141
						}
142
					}
143
144
					$censored_vulgar = $local_vulgar;
145
					$censored_proper = $local_proper;
146
				}
147
				else
148
				{
149
					$vulgar_text = (string) $this->_req->getPost('censor_vulgar', null, '');
150
					$proper_text = (string) $this->_req->getPost('censor_proper', null, '');
151
					$censored_vulgar = explode("\n", strtr($vulgar_text, ["\r" => '']));
152
					$censored_proper = explode("\n", strtr($proper_text, ["\r" => '']));
153
				}
154
			}
155
156
			// Set the new arrays and settings in the database.
157
			$updates = [
158
				'censor_vulgar' => implode("\n", $censored_vulgar),
159
				'censor_proper' => implode("\n", $censored_proper),
160
				'censorWholeWord' => empty($this->_req->getPost('censorWholeWord', null, '')) ? '0' : '1',
161
				'censorIgnoreCase' => empty($this->_req->getPost('censorIgnoreCase', null, '')) ? '0' : '1',
162
				'allow_no_censored' => empty($this->_req->getPost('allow_no_censored', null, '')) ? '0' : '1',
163
			];
164
165
			call_integration_hook('integrate_save_censors', [&$updates]);
166
167
			updateSettings($updates);
168
		}
169
170
		// Testing a word to see how it will be censored?
171
		$pre_censor = '';
172
		if ($this->_req->hasPost('censortest'))
173
		{
174
			require_once(SUBSDIR . '/Post.subs.php');
175
			$raw = (string) $this->_req->getPost('censortest', null, '');
176
			$censorText = htmlspecialchars($raw, ENT_QUOTES, 'UTF-8');
177
			preparsecode($censorText);
178
			$pre_censor = $censorText;
179
			$context['censor_test'] = strtr(censor($censorText), ['"' => '&quot;']);
180
		}
181
182
		// Set everything up for the template to do its thang.
183
		$censor_vulgar = explode("\n", $modSettings['censor_vulgar']);
184
		$censor_proper = explode("\n", $modSettings['censor_proper']);
185
186
		$context['censored_words'] = [];
187
		foreach ($censor_vulgar as $i => $censor_vulgar_i)
188
		{
189
			if ($censor_vulgar_i === '' || $censor_vulgar_i === '0')
190
			{
191
				continue;
192
			}
193
194
			// Skip it, it's either spaces or stars only.
195
			if (trim(str_replace('*', ' ', $censor_vulgar_i)) === '')
196
			{
197
				continue;
198
			}
199
200
			$context['censored_words'][htmlspecialchars(trim($censor_vulgar_i))] = isset($censor_proper[$i])
201
				? htmlspecialchars($censor_proper[$i], ENT_COMPAT, 'UTF-8')
202
				: '';
203
		}
204
205
		call_integration_hook('integrate_censors');
206
		createToken('admin-censor');
207
208
		// Using ajax?
209
		if ($this->_req->hasPost('censortest') && $this->getApi() === 'json')
210
		{
211
			// Clear the templates
212
			setJsonTemplate();
213
214
			// Send back a response
215
			$context['json_data'] = [
216
				'result' => true,
217
				'censor' => $pre_censor . ' <i class="icon i-chevron-circle-right"></i> ' . $context['censor_test'],
218
				'token_val' => $context['admin-censor_token_var'],
219
				'token' => $context['admin-censor_token'],
220
			];
221
		}
222
		else
223
		{
224
			$context['sub_template'] = 'edit_censored';
225
			$context['page_title'] = $txt['admin_censored_words'];
226
		}
227
	}
228
229
	/**
230
	 * Modify any setting related to posts and posting.
231
	 *
232
	 * - Requires the admin_forum permission.
233
	 * - Accessed from ?action=admin;area=postsettings;sa=posts.
234
	 *
235
	 * @event integrate_save_post_settings
236
	 * @uses Admin template, edit_post_settings sub-template.
237
	 */
238
	public function action_postSettings_display(): void
239
	{
240
		global $context, $txt, $modSettings;
241
242
		// Initialize the form
243
		$settingsForm = new SettingsForm(SettingsForm::DB_ADAPTER);
244
245
		if (!empty($modSettings['nofollow_allowlist']))
246
		{
247
			$modSettings['nofollow_allowlist'] = implode("\n", (array) json_decode($modSettings['nofollow_allowlist'], true));
248
		}
249
250
		// Initialize it with our settings
251
		$settingsForm->setConfigVars($this->_settings());
252
253
		// Set up the template.
254
		$context['page_title'] = $txt['manageposts_settings'];
255
		$context['sub_template'] = 'show_settings';
256
257
		// Are we saving them - are we??
258
		if ($this->_req->hasQuery('save'))
259
		{
260
			checkSession();
261
			$db = database();
262
263
			// If we're changing the message length (and we are using MySQL), let's check the column is big enough.
264
			$postedMaxLen = $this->_req->getPost('max_messageLength', 'intval');
265
			if ($postedMaxLen !== null && $postedMaxLen !== (int) $modSettings['max_messageLength'] && $db->supportMediumtext())
266
			{
267
				require_once(SUBSDIR . '/Maintenance.subs.php');
268
				$colData = getMessageTableColumns();
269
				foreach ($colData as $column)
270
				{
271
					if ($column['name'] === 'body')
272
					{
273
						$body_type = $column['type'];
274
					}
275
				}
276
277
				if (isset($body_type) && ($postedMaxLen > 65535 || $postedMaxLen === 0) && $body_type === 'text')
278
				{
279
					throw new Exception('convert_to_mediumtext', false, [getUrl('admin', ['action' => 'admin', 'area' => 'maintain', 'sa' => 'database'])]);
280
				}
281
			}
282
283
			// If we're changing the post-preview length, let's check its valid
284
			$preview_chars = $this->_req->getPost('preview_characters', 'intval');
285
			if (!empty($preview_chars))
286
			{
287
				$preview_chars = min(max(0, $preview_chars), 512);
288
			}
289
290
			// Set a min quote length of 3 lines of text (@ default font size)
291
			$heightBefore = $this->_req->getPost('heightBeforeShowMore', 'intval');
292
			if (!empty($heightBefore))
293
			{
294
				$heightBefore = max($heightBefore, 155);
295
			}
296
297
			$allowRaw = $this->_req->getPost('nofollow_allowlist', 'trim');
298
			if ($allowRaw !== null)
299
			{
300
				$allowList = array_unique(explode("\n", $allowRaw));
301
				$allowList = array_filter(array_map('\\ElkArte\\Helper\\Util::htmlspecialchars', array_map('trim', $allowList)));
302
				$allowRaw = json_encode($allowList);
303
			}
304
305
			call_integration_hook('integrate_save_post_settings');
306 4
307
			$config = (array) $this->_req->post;
308 4
			if ($postedMaxLen !== null)
309
			{
310
				$config['max_messageLength'] = $postedMaxLen;
311
			}
312
			if ($preview_chars !== null)
313 4
			{
314
				$config['preview_characters'] = $preview_chars;
315
			}
316
			if ($heightBefore !== null)
317 4
			{
318 4
				$config['heightBeforeShowMore'] = $heightBefore;
319
			}
320 4
			if ($allowRaw !== null)
321 4
			{
322 4
				$config['nofollow_allowlist'] = $allowRaw;
323
			}
324 4
325 4
			$settingsForm->setConfigValues($config);
326 4
			$settingsForm->save();
327 4
			redirectexit('action=admin;area=postsettings;sa=posts');
328
		}
329 4
330 4
		// Final settings...
331
		$context['post_url'] = getUrl('admin', ['action' => 'admin', 'area' => 'postsettings', 'save', 'sa' => 'posts']);
332
		$context['settings_title'] = $txt['manageposts_settings'];
333
334 4
		// Prepare the settings...
335
		$settingsForm->prepare();
336 4
	}
337
338
	/**
339
	 * Return admin configuration settings for posts.
340
	 *
341
	 * @event integrate_modify_post_settings
342 4
	 */
343
	private function _settings()
344 4
	{
345
		global $txt;
346
347
		// Initialize it with our settings
348
		$config_vars = [
349
			// Quote options...
350
			['int', 'removeNestedQuotes', 'postinput' => $txt['zero_for_none']],
351
			['int', 'heightBeforeShowMore', 'postinput' => $txt['zero_to_disable']],
352
			'',
353
			// Video options
354
			['check', 'enableVideoEmbeding'],
355
			['int', 'video_embed_limit', 'postinput' => $txt['video_embed_limit_note']],
356
			'',
357
			// Posting limits...
358
			['int', 'max_messageLength', 'subtext' => $txt['max_messageLength_zero'], 'postinput' => $txt['manageposts_characters']],
359
			['int', 'topicSummaryPosts', 'postinput' => $txt['manageposts_posts']],
360
			'',
361
			// Posting time limits...
362
			['int', 'spamWaitTime', 'postinput' => $txt['manageposts_seconds']],
363
			['int', 'edit_wait_time', 'postinput' => $txt['manageposts_seconds']],
364
			['int', 'edit_disable_time', 'subtext' => $txt['edit_disable_time_zero'], 'postinput' => $txt['manageposts_minutes']],
365
			['check', 'show_modify'],
366
			'',
367
			['check', 'show_user_images'],
368
			['check', 'hide_post_group'],
369
			'',
370
			// First & Last message preview lengths
371
			['select', 'message_index_preview', [$txt['message_index_preview_off'], $txt['message_index_preview_first'], $txt['message_index_preview_last']]],
372
			['int', 'preview_characters', 'subtext' => $txt['preview_characters_zero'], 'postinput' => $txt['preview_characters_units']],
373
			// Misc
374
			['title', 'mods_cat_modifications_misc'],
375
			['check', 'enableCodePrettify'],
376
			['check', 'autoLinkUrls'],
377
			['large_text', 'nofollow_allowlist', 'subtext' => $txt['nofollow_allowlist_desc']],
378
			['check', 'enablePostHTML'],
379
			['check', 'enablePostMarkdown'],
380
		];
381
382
		// Add new settings with a nice hook, makes them available for admin settings search as well
383
		call_integration_hook('integrate_modify_post_settings', [&$config_vars]);
384
385
		return $config_vars;
386
	}
387
388
	/**
389
	 * Return the post-settings for use in admin search
390
	 */
391
	public function settings_search()
392
	{
393
		return $this->_settings();
394
	}
395
}
396