1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* webtrees-lib: MyArtJaub library for webtrees |
4
|
|
|
* |
5
|
|
|
* @package MyArtJaub\Webtrees |
6
|
|
|
* @subpackage AdminTasks |
7
|
|
|
* @author Jonathan Jaubart <[email protected]> |
8
|
|
|
* @copyright Copyright (c) 2012-2016, Jonathan Jaubart |
9
|
|
|
* @license http://www.gnu.org/licenses/gpl.html GNU General Public License, version 3 |
10
|
|
|
*/ |
11
|
|
|
namespace MyArtJaub\Webtrees\Module\AdminTasks; |
12
|
|
|
|
13
|
|
|
use Fisharebest\Webtrees\Auth; |
14
|
|
|
use Fisharebest\Webtrees\Controller\AjaxController; |
15
|
|
|
use Fisharebest\Webtrees\Controller\PageController; |
16
|
|
|
use Fisharebest\Webtrees\Filter; |
17
|
|
|
use Fisharebest\Webtrees\I18N; |
18
|
|
|
use Fisharebest\Webtrees\Log; |
19
|
|
|
use Fisharebest\Webtrees\Module; |
20
|
|
|
use Fisharebest\Webtrees\Module\AbstractModule; |
21
|
|
|
use Fisharebest\Webtrees\Theme; |
22
|
|
|
use Fisharebest\Webtrees\Theme\AdministrationTheme; |
23
|
|
|
use MyArtJaub\Webtrees\Controller\JsonController; |
24
|
|
|
use MyArtJaub\Webtrees\Functions\Functions; |
25
|
|
|
use MyArtJaub\Webtrees\Module\AdminTasks\Model\AbstractTask; |
26
|
|
|
use MyArtJaub\Webtrees\Module\AdminTasks\Model\TaskProviderInterface; |
27
|
|
|
use MyArtJaub\Webtrees\Mvc\Controller\MvcController; |
28
|
|
|
use MyArtJaub\Webtrees\Mvc\View\ViewBag; |
29
|
|
|
use MyArtJaub\Webtrees\Mvc\View\ViewFactory; |
30
|
|
|
use Rhumsaa\Uuid\Uuid; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* Controller for AdminTasks AdminConfig |
34
|
|
|
*/ |
35
|
|
|
class AdminConfigController extends MvcController |
36
|
|
|
{ |
37
|
|
|
/** |
38
|
|
|
* Tasks Provider |
39
|
|
|
* @var TaskProviderInterface $provider |
40
|
|
|
*/ |
41
|
|
|
protected $provider; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* Constructor for Admin Config controller |
45
|
|
|
* @param \Fisharebest\Webtrees\Module\AbstractModule $module |
46
|
|
|
*/ |
47
|
|
|
public function __construct(AbstractModule $module) { |
48
|
|
|
parent::__construct($module); |
49
|
|
|
|
50
|
|
|
$this->provider = $this->module->getProvider(); |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* Pages |
55
|
|
|
*/ |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* AdminConfig@index |
59
|
|
|
*/ |
60
|
|
|
public function index() { |
61
|
|
|
global $WT_TREE; |
62
|
|
|
|
63
|
|
|
Theme::theme(new AdministrationTheme)->init($WT_TREE); |
64
|
|
|
$controller = new PageController(); |
65
|
|
|
$controller |
66
|
|
|
->restrictAccess(Auth::isAdmin()) |
67
|
|
|
->setPageTitle($this->module->getTitle()); |
68
|
|
|
|
69
|
|
|
$token = $this->module->getSetting('MAJ_AT_FORCE_EXEC_TOKEN'); |
70
|
|
|
if(is_null($token)) { |
71
|
|
|
$token = Functions::generateRandomToken(); |
72
|
|
|
$this->module->setSetting('PAT_FORCE_EXEC_TOKEN', $token); |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
$data = new ViewBag(); |
76
|
|
|
$data->set('title', $controller->getPageTitle()); |
77
|
|
|
|
78
|
|
|
$table_id = 'table-admintasks-' . Uuid::uuid4(); |
79
|
|
|
$data->set('table_id', $table_id); |
80
|
|
|
|
81
|
|
|
$data->set('trigger_url_root', WT_BASE_URL.'module.php?mod='.$this->module->getName().'&mod_action=Task@trigger'); |
82
|
|
|
$token = $this->module->getSetting('MAJ_AT_FORCE_EXEC_TOKEN'); |
83
|
|
|
if(is_null($token)) { |
84
|
|
|
$token = Functions::generateRandomToken(); |
85
|
|
|
$this->module->setSetting('MAJ_AT_FORCE_EXEC_TOKEN', $token); |
86
|
|
|
} |
87
|
|
|
$data->set('trigger_token', $token); |
88
|
|
|
|
89
|
|
|
$this->provider->getInstalledTasks(); |
90
|
|
|
|
91
|
|
|
$controller |
92
|
|
|
->addExternalJavascript(WT_JQUERY_DATATABLES_JS_URL) |
93
|
|
|
->addExternalJavascript(WT_DATATABLES_BOOTSTRAP_JS_URL) |
94
|
|
|
->addInlineJavascript(' |
95
|
|
|
//Datatable initialisation |
96
|
|
|
jQuery.fn.dataTableExt.oSort["unicode-asc" ]=function(a,b) {return a.replace(/<[^<]*>/, "").localeCompare(b.replace(/<[^<]*>/, ""))}; |
97
|
|
|
jQuery.fn.dataTableExt.oSort["unicode-desc" ]=function(a,b) {return b.replace(/<[^<]*>/, "").localeCompare(a.replace(/<[^<]*>/, ""))}; |
98
|
|
|
jQuery.fn.dataTableExt.oSort["num-html-asc" ]=function(a,b) {a=parseFloat(a.replace(/<[^<]*>/, "")); b=parseFloat(b.replace(/<[^<]*>/, "")); return (a<b) ? -1 : (a>b ? 1 : 0);}; |
99
|
|
|
jQuery.fn.dataTableExt.oSort["num-html-desc"]=function(a,b) {a=parseFloat(a.replace(/<[^<]*>/, "")); b=parseFloat(b.replace(/<[^<]*>/, "")); return (a>b) ? -1 : (a<b ? 1 : 0);}; |
100
|
|
|
|
101
|
|
|
var adminTasksTable = jQuery("#'.$table_id.'").DataTable({ |
102
|
|
|
'.I18N::datatablesI18N().', |
103
|
|
|
sorting: [[3, "asc"]], |
104
|
|
|
pageLength: 10, |
105
|
|
|
processing: true, |
106
|
|
|
serverSide : true, |
107
|
|
|
ajax : { |
108
|
|
|
url : "module.php?mod='.$this->module->getName().'&mod_action=AdminConfig@jsonTasksList&ged='. $WT_TREE->getNameUrl().'", |
109
|
|
|
type : "POST" |
110
|
|
|
}, |
111
|
|
|
columns: [ |
112
|
|
|
/* 0 Edit */ { sortable: false, className: "text-center"}, |
113
|
|
|
/* 1 task_name */ { visible: false }, |
114
|
|
|
/* 2 Enabled */ { sortable: false, className: "text-center" }, |
115
|
|
|
/* 3 Task Title */ null, |
116
|
|
|
/* 4 Last Run */ null, |
117
|
|
|
/* 5 Last status */ { className: "text-center" }, |
118
|
|
|
/* 6 Frequency */ { sortable: false, className: "text-center" }, |
119
|
|
|
/* 7 Nb Occcurrences*/ { sortable: false, className: "text-center" }, |
120
|
|
|
/* 8 Is Running */ { sortable: false, className: "text-center" }, |
121
|
|
|
/* 9 Run task */ { sortable: false, className: "text-center" } |
122
|
|
|
], |
123
|
|
|
}); |
124
|
|
|
|
125
|
|
|
') |
126
|
|
|
->addInlineJavascript(' |
127
|
|
|
function generate_force_token() { |
128
|
|
|
jQuery("#bt_genforcetoken").attr("disabled", "disabled"); |
129
|
|
|
jQuery("#bt_tokentext").empty().html("<i class=\"fa fa-spinner fa-pulse fa-fw\"></i>"); |
130
|
|
|
jQuery("#token_url").load( |
131
|
|
|
"module.php?mod='.$this->module->getName().'&mod_action=AdminConfig@generateToken", |
132
|
|
|
function() { |
133
|
|
|
jQuery("#bt_genforcetoken").removeAttr("disabled"); |
134
|
|
|
jQuery("#bt_tokentext").empty().html("'.I18N::translate('Regenerate token').'"); |
135
|
|
|
adminTasksTable.ajax.reload(); |
136
|
|
|
} |
137
|
|
|
); |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
function set_admintask_status(task, status) { |
141
|
|
|
jQuery.ajax({ |
142
|
|
|
url: "module.php", |
143
|
|
|
type: "GET", |
144
|
|
|
data: { |
145
|
|
|
mod: "' . $this->module->getName() .'", |
146
|
|
|
mod_action: "Task@setStatus", |
147
|
|
|
task: task, |
148
|
|
|
status: status |
149
|
|
|
}, |
150
|
|
|
error: function(result, stat, error) { |
151
|
|
|
var err = typeof result.responseJSON === "undefined" ? error : result.responseJSON.error; |
152
|
|
|
alert("' . I18N::translate('An error occured while editing this task:') . '" + err); |
153
|
|
|
}, |
154
|
|
|
complete: function(result, stat) { |
155
|
|
|
adminTasksTable.ajax.reload(null, false); |
156
|
|
|
} |
157
|
|
|
}); |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
function run_admintask(taskname) { |
161
|
|
|
jQuery("#bt_runtask_" + taskname).attr("disabled", "disabled"); |
162
|
|
|
jQuery("#bt_runtasktext_" + taskname).empty().html("<i class=\"fa fa-cog fa-spin fa-fw\"></i><span class=\"sr-only\">'.I18N::translate('Running').'</span>"); |
163
|
|
|
jQuery("#bt_runtasktext_" + taskname).load( |
164
|
|
|
"module.php?mod='.$this->module->getName().'&mod_action=Task@trigger&force='.$token.'&task=" + taskname, |
165
|
|
|
function() { |
166
|
|
|
jQuery("#bt_runtasktext_" + taskname).empty().html("<i class=\"fa fa-check\"></i>'.I18N::translate('Done').'"); |
167
|
|
|
adminTasksTable.ajax.reload(); |
168
|
|
|
} |
169
|
|
|
); |
170
|
|
|
|
171
|
|
|
} |
172
|
|
|
'); |
173
|
|
|
|
174
|
|
|
ViewFactory::make('AdminConfig', $this, $controller, $data)->render(); |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
/** |
178
|
|
|
* AdminConfig@jsonTasksList |
179
|
|
|
*/ |
180
|
|
|
public function jsonTasksList() { |
181
|
|
|
global $WT_TREE; |
182
|
|
|
|
183
|
|
|
$controller = new JsonController(); |
184
|
|
|
$controller |
185
|
|
|
->restrictAccess(Auth::isAdmin()); |
186
|
|
|
|
187
|
|
|
// Generate an AJAX/JSON response for datatables to load a block of rows |
188
|
|
|
$search = Filter::postArray('search'); |
189
|
|
|
if($search) $search = $search['value']; |
|
|
|
|
190
|
|
|
$start = Filter::postInteger('start'); |
191
|
|
|
$length = Filter::postInteger('length'); |
192
|
|
|
$order = Filter::postArray('order'); |
193
|
|
|
|
194
|
|
|
$order_by_name = false; |
195
|
|
|
foreach($order as $key => &$value) { |
196
|
|
|
switch($value['column']) { |
197
|
|
|
case 3: |
198
|
|
|
$order_by_name = true; |
199
|
|
|
unset($order[$key]); |
200
|
|
|
break; |
201
|
|
|
case 4; |
202
|
|
|
$value['column'] = 'majat_last_run'; |
203
|
|
|
break; |
204
|
|
|
case 4; |
205
|
|
|
$value['column'] = 'majat_last_result'; |
206
|
|
|
break; |
207
|
|
|
default: |
208
|
|
|
unset($order[$key]); |
209
|
|
|
} |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
$list = $this->provider->getFilteredTasksList($search, $order, $start, $length); |
|
|
|
|
213
|
|
|
if($order_by_name) { |
214
|
|
|
usort($list, function(AbstractTask $a, AbstractTask $b) { return I18N::strcasecmp($a->getTitle(), $b->getTitle()); }); |
215
|
|
|
} |
216
|
|
|
$recordsFiltered = count($list); |
217
|
|
|
$recordsTotal = $this->provider->getTasksCount(); |
218
|
|
|
|
219
|
|
|
$data = array(); |
220
|
|
|
foreach($list as $task) { |
221
|
|
|
$datum = array(); |
222
|
|
|
|
223
|
|
|
$datum[0] = ' |
224
|
|
|
<div class="btn-group"> |
225
|
|
|
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-expanded="false"> |
226
|
|
|
<i class="fa fa-pencil"></i><span class="caret"></span> |
227
|
|
|
</button> |
228
|
|
|
<ul class="dropdown-menu" role="menu"> |
229
|
|
|
<li> |
230
|
|
|
<a href="#" onclick="return set_admintask_status(\''. $task->getName().'\', '.($task->isEnabled() ? 'false' : 'true').');"> |
231
|
|
|
<i class="fa fa-fw '.($task->isEnabled() ? 'fa-times' : 'fa-check').'"></i> ' . ($task->isEnabled() ? I18N::translate('Disable') : I18N::translate('Enable')) . ' |
232
|
|
|
</a> |
233
|
|
|
</li> |
234
|
|
|
<li> |
235
|
|
|
<a href="module.php?mod='.$this->module->getName().'&mod_action=Task@edit&task='. $task->getName().'"> |
236
|
|
|
<i class="fa fa-fw fa-pencil"></i> ' . I18N::translate('Edit') . ' |
237
|
|
|
</a> |
238
|
|
|
</li> |
239
|
|
|
</ul> |
240
|
|
|
</div>'; |
241
|
|
|
$datum[1] = $task->getName(); |
242
|
|
|
$datum[2] = $task->isEnabled() ? |
243
|
|
|
'<i class="fa fa-check"></i><span class="sr-only">'.I18N::translate('Enabled').'</span>' : |
244
|
|
|
'<i class="fa fa-times"></i><span class="sr-only">'.I18N::translate('Disabled').'</span>'; |
245
|
|
|
$datum[3] = $task->getTitle(); |
246
|
|
|
$date_format = str_replace('%', '', I18N::dateFormat()) . ' H:i:s'; |
247
|
|
|
$datum[4] = $task->getLastUpdated()->format($date_format); |
248
|
|
|
$datum[5] = $task->isLastRunSuccess() ? |
249
|
|
|
'<i class="fa fa-check"></i><span class="sr-only">'.I18N::translate('Yes').'</span>' : |
250
|
|
|
'<i class="fa fa-times"></i><span class="sr-only">'.I18N::translate('No').'</span>'; |
251
|
|
|
$dtF = new \DateTime('@0'); |
252
|
|
|
$dtT = new \DateTime('@' . ($task->getFrequency() * 60)); |
253
|
|
|
$datum[6] = $dtF->diff($dtT)->format(I18N::translate('%a d %h h %i m')); |
254
|
|
|
$datum[7] = $task->getRemainingOccurrences() > 0 ? I18N::number($task->getRemainingOccurrences()) : I18N::translate('Unlimited'); |
255
|
|
|
$datum[8] = $task->isRunning() ? |
256
|
|
|
'<i class="fa fa-cog fa-spin fa-fw"></i><span class="sr-only">'.I18N::translate('Running').'</span>' : |
257
|
|
|
'<i class="fa fa-times"></i><span class="sr-only">'.I18N::translate('Not running').'</span>'; |
258
|
|
|
if($task->isEnabled() && !$task->isRunning()) { |
259
|
|
|
$datum[9] = ' |
260
|
|
|
<button id="bt_runtask_'. $task->getName() .'" class="btn btn-primary" href="#" onclick="return run_admintask(\''. $task->getName() .'\')"> |
261
|
|
|
<div id="bt_runtasktext_'. $task->getName() .'"><i class="fa fa-cog fa-fw" ></i>' . I18N::translate('Run') . '</div> |
262
|
|
|
</button>'; |
263
|
|
|
} |
264
|
|
|
else { |
265
|
|
|
$datum[9] = ''; |
266
|
|
|
} |
267
|
|
|
|
268
|
|
|
$data[] = $datum; |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
$controller->pageHeader(); |
272
|
|
|
|
273
|
|
|
$controller->encode(array( |
274
|
|
|
'draw' => Filter::getInteger('draw'), |
275
|
|
|
'recordsTotal' => $recordsTotal, |
276
|
|
|
'recordsFiltered' => $recordsFiltered, |
277
|
|
|
'data' => $data |
278
|
|
|
)); |
279
|
|
|
|
280
|
|
|
} |
281
|
|
|
|
282
|
|
|
/** |
283
|
|
|
* AdminConfig@generateToken |
284
|
|
|
* |
285
|
|
|
* Ajax call to generate a new token. Display the token, if generated. |
286
|
|
|
* Tokens call only be generated by a site administrator. |
287
|
|
|
* |
288
|
|
|
*/ |
289
|
|
|
public function generateToken() |
290
|
|
|
{ |
291
|
|
|
$controller = new AjaxController(); |
292
|
|
|
$controller->restrictAccess(Auth::isAdmin()); |
293
|
|
|
|
294
|
|
|
$token = Functions::generateRandomToken(); |
295
|
|
|
$this->module->setSetting('MAJ_AT_FORCE_EXEC_TOKEN', $token); |
296
|
|
|
Log::addConfigurationLog($this->module->getTitle().' : New token generated.'); |
297
|
|
|
|
298
|
|
|
$controller->pageHeader(); |
299
|
|
|
echo $token; |
300
|
|
|
} |
301
|
|
|
|
302
|
|
|
|
303
|
|
|
|
304
|
|
|
|
305
|
|
|
} |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.