Passed
Push — development ( 924c99...c29c1d )
by Spuds
01:04 queued 20s
created

ManageScheduledTasks::action_edit()   C

Complexity

Conditions 12
Paths 35

Size

Total Lines 75
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 156

Importance

Changes 0
Metric Value
cc 12
eloc 30
nc 35
nop 0
dl 0
loc 75
ccs 0
cts 42
cp 0
crap 156
rs 6.9666
c 0
b 0
f 0

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 concerns itself with scheduled tasks management.
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\Languages\Txt;
23
24
/**
25
 * ManageScheduledTasks admin Controller: handles the scheduled task pages
26
 * which allow one to see, edit and run the systems scheduled tasks
27
 *
28
 * @package ScheduledTasks
29
 */
30
class ManageScheduledTasks extends AbstractController
31
{
32
	/**
33
	 * Scheduled tasks management dispatcher.
34
	 *
35
	 * - This function checks permissions and delegates to the appropriate function
36
	 * based on the sub-action.
37
	 * - Everything here requires admin_forum permission.
38
	 *
39
	 * @event integrate_sa_manage_scheduled_tasks
40
	 * @uses ManageScheduledTasks template file
41
	 * @uses ManageScheduledTasks language file
42
	 *
43
	 * @see  AbstractController::action_index()
44
	 */
45
	public function action_index(): void
46
	{
47
		global $context, $txt;
48
49
		Txt::load('ManageScheduled');
50
		theme()->getTemplates()->load('ManageScheduledTasks');
51
52
		$subActions = [
53
			'taskedit' => [$this, 'action_edit', 'permission' => 'admin_forum'],
54
			'tasklog' => [$this, 'action_log', 'permission' => 'admin_forum'],
55
			'tasks' => [$this, 'action_tasks', 'permission' => 'admin_forum'],
56
		];
57
58
		// Control those actions
59
		$action = new Action('manage_scheduled_tasks');
60
61
		// We need to find what's the action. Call integrate_sa_manage_scheduled_tasks
62
		$subAction = $action->initialize($subActions, 'tasks');
63
64
		// Page details
65
		$context['page_title'] = $txt['maintain_info'];
66
		$context['sub_action'] = $subAction;
67
68
		// Now for the lovely tabs. That we all love.
69
		$context[$context['admin_menu_name']]['object']->prepareTabData([
70
				'title' => 'scheduled_tasks_title',
71
				'description' => 'maintain_info',
72
				'tabs' => [
73
					'tasks' => [
74
						'description' => $txt['maintain_tasks_desc'],
75
					],
76
					'tasklog' => [
77
						'description' => $txt['scheduled_log_desc'],
78
					],
79
				]]
80
		);
81
82
		// Call the right function for this sub-action.
83
		$action->dispatch($subAction);
84
	}
85
86
	/**
87
	 * List all the scheduled task in place on the forum.
88
	 *
89
	 * @event integrate_autotask_include (depreciated since 1.1)
90
	 * @event integrate_list_scheduled_tasks
91
	 * @uses ManageScheduledTasks template, view_scheduled_tasks sub-template
92
	 */
93
	public function action_tasks(): void
94
	{
95
		global $context, $txt;
96
97
		// We'll need to recalculate dates and stuff like that.
98
		require_once(SUBSDIR . '/ScheduledTasks.subs.php');
99
100
		$context['sub_template'] = 'view_scheduled_tasks';
101
		$context['page_title'] = $txt['maintain_tasks'];
102
103
		// Saving changes?
104
		if (isset($this->_req->post->save, $this->_req->post->enable_task))
105
		{
106
			checkSession();
107
108
			// Enable and disable as required.
109
			$enablers = [0];
110
			$enable = $this->_req->getPost('enable_task', null, []);
111
			if (!is_array($enable))
112
			{
113
				$enable = [$enable];
114
			}
115
			foreach ($enable as $id => $enabled)
116
			{
117
				if ($enabled)
118
				{
119
					$enablers[] = (int) $id;
120
				}
121
			}
122
123
			// Do the update!
124
			updateTaskStatus($enablers);
125
126
			// Pop along...
127
			calculateNextTrigger();
128
		}
129
130
		// Want to run any of the tasks?
131
		if (isset($this->_req->post->run, $this->_req->post->run_task))
132
		{
133
			// Lets figure out which ones they want to run.
134
			$tasks = [];
135
			foreach ($this->_req->post->run_task as $task => $dummy)
136
			{
137
				$tasks[] = (int) $task;
138
			}
139
140
			// Load up the tasks.
141
			$nextTasks = loadTasks($tasks);
142
143
			// Lets get it on!
144
			ignore_user_abort(true);
145
146
			foreach ($nextTasks as $task_id => $taskname)
147
			{
148
				run_this_task($task_id, $taskname);
149
			}
150
151
			// Things go as expected?  If not save the error in session
152
			if (!empty($context['scheduled_errors']))
153
			{
154
				$_SESSION['st_error'] = $context['scheduled_errors'];
155
			}
156
157
			redirectexit('action=admin;area=scheduledtasks;done');
158
		}
159
160
		// Build the list so we can see the tasks
161
		$listOptions = [
162
			'id' => 'scheduled_tasks',
163
			'title' => $txt['maintain_tasks'],
164
			'base_href' => getUrl('admin', ['action' => 'admin', 'area' => 'scheduledtasks']),
165
			'get_items' => [
166
				'function' => fn() => $this->list_getScheduledTasks(),
167
			],
168
			'columns' => [
169
				'name' => [
170
					'header' => [
171
						'value' => $txt['scheduled_tasks_name'],
172
						'style' => 'width: 40%;',
173
					],
174
					'data' => [
175
						'sprintf' => [
176
							'format' => '
177
								<a class="linkbutton w_icon" href="' . getUrl('admin', ['action' => 'admin', 'area' => 'scheduledtasks', 'sa' => 'taskedit', 'tid' => '%1$d']) . '" title="' . $txt['scheduled_task_edit'] . ' %2$s"><i class="icon i-pencil"></i> %2$s</a><br /><span class="smalltext">%3$s</span>',
178
							'params' => [
179
								'id' => false,
180
								'name' => false,
181
								'desc' => false,
182
							],
183
						],
184
					],
185
				],
186
				'next_due' => [
187
					'header' => [
188
						'value' => $txt['scheduled_tasks_next_time'],
189
					],
190
					'data' => [
191
						'db' => 'next_time',
192
						'class' => 'smalltext',
193
					],
194
				],
195
				'regularity' => [
196
					'header' => [
197
						'value' => $txt['scheduled_tasks_regularity'],
198
					],
199
					'data' => [
200
						'db' => 'regularity',
201
						'class' => 'smalltext',
202
					],
203
				],
204
				'enabled' => [
205
					'header' => [
206
						'value' => $txt['scheduled_tasks_enabled'],
207
						'style' => 'width: 6%;text-align: center;',
208
					],
209
					'data' => [
210
						'sprintf' => [
211
							'format' => '
212
								<input type="hidden" name="enable_task[%1$d]" id="task_%1$d" value="0" /><input type="checkbox" name="enable_task[%1$d]" id="task_check_%1$d" %2$s class="input_check" />',
213
							'params' => [
214
								'id' => false,
215
								'checked_state' => false,
216
							],
217
						],
218
						'class' => 'centertext',
219
					],
220
				],
221
				'run_now' => [
222
					'header' => [
223
						'value' => $txt['scheduled_tasks_run_now'],
224
						'style' => 'width: 12%;text-align: center;',
225
					],
226
					'data' => [
227
						'sprintf' => [
228
							'format' => '
229
								<input type="checkbox" name="run_task[%1$d]" id="run_task_%1$d" class="input_check" />',
230
							'params' => [
231
								'id' => false,
232
							],
233
						],
234
						'class' => 'centertext',
235
					],
236
				],
237
			],
238
			'form' => [
239
				'href' => getUrl('admin', ['action' => 'admin', 'area' => 'scheduledtasks']),
240
			],
241
			'additional_rows' => [
242
				[
243
					'class' => 'submitbutton',
244
					'position' => 'below_table_data',
245
					'value' => '
246
						<input type="submit" name="run" value="' . $txt['scheduled_tasks_run_now'] . '" class="right_submit" />
247
						<input type="submit" name="save" value="' . $txt['scheduled_tasks_save_changes'] . '" class="right_submit" />',
248
				],
249
				[
250
					'position' => 'after_title',
251
					'value' => $txt['scheduled_tasks_time_offset'],
252
				],
253
			],
254
		];
255
256
		createList($listOptions);
257
258
		$context['sub_template'] = 'view_scheduled_tasks';
259
		$context['tasks_were_run'] = $this->_req->hasQuery('done');
260
261
		// If we had any errors, place them in context as well
262
		if (isset($_SESSION['st_error']))
263
		{
264
			$context['scheduled_errors'] = $_SESSION['st_error'];
265
			unset($_SESSION['st_error']);
266
		}
267
	}
268
269
	/**
270
	 * Callback function for createList() in action_tasks().
271
	 *
272
	 */
273
	public function list_getScheduledTasks(): array
274
	{
275
		return scheduledTasks();
276
	}
277
278
	/**
279
	 * Function for editing a task.
280
	 *
281
	 * @uses ManageScheduledTasks template, edit_scheduled_tasks sub-template
282
	 */
283
	public function action_edit(): void
284
	{
285
		global $context, $txt;
286
287
		// Just set up some lovely context stuff.
288
		$context[$context['admin_menu_name']]['current_subsection'] = 'tasks';
289
		$context['sub_template'] = 'edit_scheduled_tasks';
290
		$context['page_title'] = $txt['scheduled_task_edit'];
291
		$context['server_time'] = standardTime(time(), false, 'server');
292
293
		// We'll need this to calculate the next event.
294
		require_once(SUBSDIR . '/ScheduledTasks.subs.php');
295
296
		// Cleaning...
297
		if (!$this->_req->hasQuery('tid'))
298
		{
299
			throw new Exception('no_access', false);
300
		}
301
302
		$tid = $this->_req->getQuery('tid', 'intval', 0);
303
		if ($tid === 0)
304
		{
305
			throw new Exception('no_access', false);
306
		}
307
308
		// Saving?
309
		if ($this->_req->hasQuery('save'))
310
		{
311
			checkSession();
312
			validateToken('admin-st');
313
314
			// Do we have a valid offset?
315
			preg_match('~(\d{1,2}):(\d{1,2})~', $this->_req->post->offset, $matches);
316
317
			// If a half is empty then assume zero offset!
318
			if (!isset($matches[2]) || $matches[2] > 59)
319
			{
320
				$matches[2] = 0;
321
			}
322
323
			if (!isset($matches[1]) || $matches[1] > 23)
324
			{
325
				$matches[1] = 0;
326
			}
327
328
			// Now the offset is easy; easy peasy - except we need to offset by a few hours...
329
			$offset = $matches[1] * 3600 + $matches[2] * 60 - date('Z');
330
331
			// The other time bits are simple!
332
			$interval = max((int) $this->_req->post->regularity, 1);
333
			$unit = in_array(substr($this->_req->post->unit, 0, 1), ['m', 'h', 'd', 'w']) ? substr($this->_req->post->unit, 0, 1) : 'd';
334
335
			// Don't allow one minute intervals.
336
			if ($interval === 1 && $unit === 'm')
337
			{
338
				$interval = 2;
339
			}
340
341
			// Is it disabled?
342
			$disabled = isset($this->_req->post->enabled) ? 0 : 1;
343
344
			// Do the update!
345
			updateTask($tid, $disabled, $offset, $interval, $unit);
346
347
			// Check the next event.
348
			calculateNextTrigger($tid, true);
349
350
			// Return to the main list.
351
			redirectexit('action=admin;area=scheduledtasks');
352
		}
353
354
		// Load the task, understand? Que? Que?
355
		$context['task'] = loadTaskDetails($tid);
356
357
		createToken('admin-st');
358
	}
359
360
	/**
361
	 * Show the log of all tasks that have taken place.
362
	 *
363
	 * @uses ManageScheduledTasks language file
364
	 */
365
	public function action_log(): void
366
	{
367
		global $context, $txt;
368
369
		require_once(SUBSDIR . '/ScheduledTasks.subs.php');
370
371
		// Lets load the language just in case we are outside the Scheduled area.
372
		Txt::load('ManageScheduled');
373
374
		// Empty the log?
375
		if (!empty($this->_req->post->removeAll))
376
		{
377
			checkSession();
378
			validateToken('admin-tl');
379
380
			emptyTaskLog();
381
		}
382
383
		// Setup the list.
384
		$listOptions = [
385
			'id' => 'task_log',
386
			'items_per_page' => 30,
387
			'title' => $txt['scheduled_log'],
388
			'no_items_label' => $txt['scheduled_log_empty'],
389
			'base_href' => $context['admin_area'] === 'scheduledtasks' ? getUrl('admin', ['action' => 'admin', 'area' => 'scheduledtasks', 'sa' => 'tasklog']) : getUrl('admin', ['action' => 'admin', 'area' => 'logs', 'sa' => 'tasklog']),
390
			'default_sort_col' => 'date',
391
			'get_items' => [
392
				'function' => fn($start, $items_per_page, $sort) => $this->list_getTaskLogEntries($start, $items_per_page, $sort),
393
			],
394
			'get_count' => [
395
				'function' => fn() => $this->list_getNumTaskLogEntries(),
396
			],
397
			'columns' => [
398
				'name' => [
399
					'header' => [
400
						'value' => $txt['scheduled_tasks_name'],
401
					],
402
					'data' => [
403
						'db' => 'name'
404
					],
405
				],
406
				'date' => [
407
					'header' => [
408
						'value' => $txt['scheduled_log_time_run'],
409
					],
410
					'data' => [
411
						'function' => static fn($rowData) => standardTime($rowData['time_run'], true),
412
					],
413
					'sort' => [
414
						'default' => 'lst.id_log DESC',
415
						'reverse' => 'lst.id_log',
416
					],
417
				],
418
				'time_taken' => [
419
					'header' => [
420
						'value' => $txt['scheduled_log_time_taken'],
421
					],
422
					'data' => [
423
						'sprintf' => [
424
							'format' => $txt['scheduled_log_time_taken_seconds'],
425
							'params' => [
426
								'time_taken' => false,
427
							],
428
						],
429
					],
430
					'sort' => [
431
						'default' => 'lst.time_taken',
432
						'reverse' => 'lst.time_taken DESC',
433
					],
434
				],
435
				'task_completed' => [
436
					'header' => [
437
						'value' => $txt['scheduled_log_completed'],
438
					],
439
					'data' => [
440
						'function' => static function ($rowData) {
441
							global $txt;
442
443
							return '<i class="icon ' . ($rowData['task_completed'] ? 'i-check' : 'i-fail') . '" title="' . sprintf($txt[$rowData['task_completed'] ? 'maintain_done' : 'maintain_fail'], $rowData['name']) . '" />';
444
						},
445
					],
446
				],
447
			],
448
			'form' => [
449
				'href' => $context['admin_area'] === 'scheduledtasks' ? getUrl('admin', ['action' => 'admin', 'area' => 'scheduledtasks', 'sa' => 'tasklog']) : getUrl('admin', ['action' => 'admin', 'area' => 'logs', 'sa' => 'tasklog']),
450
				'token' => 'admin-tl',
451
			],
452
			'additional_rows' => [
453
				[
454
					'position' => 'below_table_data',
455
					'value' => '
456
						<input type="submit" name="removeAll" value="' . $txt['scheduled_log_empty_log'] . '" onclick="return confirm(\'' . $txt['scheduled_log_empty_log_confirm'] . '\');" class="right_submit" />',
457
				],
458
				[
459
					'position' => 'after_title',
460
					'value' => $txt['scheduled_tasks_time_offset'],
461
				],
462
			],
463
		];
464
465
		createToken('admin-tl');
466
		createList($listOptions);
467
468
		$context['sub_template'] = 'show_list';
469
		$context['default_list'] = 'task_log';
470
471
		// Make it all look tify.
472
		$context[$context['admin_menu_name']]['current_subsection'] = 'tasklog';
473
		$context['page_title'] = $txt['scheduled_log'];
474
	}
475
476
	/**
477
	 * Callback function for createList() in action_log().
478
	 *
479
	 * @param int $start The item to start with (for pagination purposes)
480
	 * @param int $items_per_page The number of items to show per page
481
	 * @param string $sort A string indicating how to sort the results
482
	 *
483
	 * @return array
484
	 */
485
	public function list_getTaskLogEntries(int $start, int $items_per_page, string $sort): array
486
	{
487
		return getTaskLogEntries($start, $items_per_page, $sort);
488
	}
489
490
	/**
491
	 * Callback function for createList() in action_log().
492
	 */
493
	public function list_getNumTaskLogEntries(): int
494
	{
495
		return countTaskLogEntries();
496
	}
497
}
498