Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 530 |
|
0.00% |
0 / 11 |
CRAP | |
0.00% |
0 / 1 |
acp_extensions | |
0.00% |
0 / 528 |
|
0.00% |
0 / 11 |
13340 | |
0.00% |
0 / 1 |
main | |
0.00% |
0 / 18 |
|
0.00% |
0 / 1 |
12 | |||
main_mode | |
0.00% |
0 / 176 |
|
0.00% |
0 / 1 |
1640 | |||
catalog_mode | |
0.00% |
0 / 170 |
|
0.00% |
0 / 1 |
702 | |||
display_composer_exception | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
12 | |||
list_enabled_exts | |
0.00% |
0 / 38 |
|
0.00% |
0 / 1 |
72 | |||
list_disabled_exts | |
0.00% |
0 / 40 |
|
0.00% |
0 / 1 |
72 | |||
list_available_exts | |
0.00% |
0 / 34 |
|
0.00% |
0 / 1 |
42 | |||
output_actions | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
12 | |||
sort_extension_meta_data_table | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
output_metadata_to_template | |
0.00% |
0 / 21 |
|
0.00% |
0 / 1 |
182 | |||
check_is_enableable | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
20 |
1 | <?php |
2 | /** |
3 | * |
4 | * This file is part of the phpBB Forum Software package. |
5 | * |
6 | * @copyright (c) phpBB Limited <https://www.phpbb.com> |
7 | * @license GNU General Public License, version 2 (GPL-2.0) |
8 | * |
9 | * For full copyright and license information, please see |
10 | * the docs/CREDITS.txt file. |
11 | * |
12 | */ |
13 | |
14 | use phpbb\exception\exception_interface; |
15 | use phpbb\exception\version_check_exception; |
16 | |
17 | /** |
18 | * @ignore |
19 | */ |
20 | if (!defined('IN_PHPBB')) |
21 | { |
22 | exit; |
23 | } |
24 | |
25 | class acp_extensions |
26 | { |
27 | public $u_action; |
28 | |
29 | private $db; |
30 | |
31 | /** @var phpbb\config\config */ |
32 | private $config; |
33 | |
34 | /** @var \phpbb\template\twig\twig */ |
35 | private $template; |
36 | private $user; |
37 | private $log; |
38 | |
39 | /** @var \phpbb\request\request */ |
40 | private $request; |
41 | private $phpbb_dispatcher; |
42 | |
43 | /** @var \phpbb\extension\manager */ |
44 | private $ext_manager; |
45 | |
46 | private $phpbb_container; |
47 | private $php_ini; |
48 | private $u_catalog_action; |
49 | |
50 | /** @var string */ |
51 | private $phpbb_root_path; |
52 | |
53 | function main($id, $mode) |
54 | { |
55 | // Start the page |
56 | global $config, $user, $template, $request, $phpbb_extension_manager, $db, $phpbb_log, $phpbb_dispatcher, $phpbb_container, $phpbb_root_path; |
57 | |
58 | $this->db = $db; |
59 | $this->config = $config; |
60 | $this->template = $template; |
61 | $this->user = $user; |
62 | $this->request = $request; |
63 | $this->log = $phpbb_log; |
64 | $this->phpbb_dispatcher = $phpbb_dispatcher; |
65 | $this->ext_manager = $phpbb_extension_manager; |
66 | $this->phpbb_container = $phpbb_container; |
67 | $this->php_ini = $this->phpbb_container->get('php_ini'); |
68 | $this->phpbb_root_path = $phpbb_root_path; |
69 | |
70 | $this->user->add_lang(['install', 'acp/extensions', 'acp/modules', 'migrator']); |
71 | |
72 | switch ($mode) |
73 | { |
74 | case 'catalog': |
75 | $this->catalog_mode($id, $mode); |
76 | break; |
77 | default: |
78 | $this->main_mode($id, $mode); |
79 | break; |
80 | } |
81 | } |
82 | |
83 | public function main_mode($id, $mode) |
84 | { |
85 | global $phpbb_extension_manager, $phpbb_container, $phpbb_admin_path, $phpEx; |
86 | |
87 | $this->page_title = 'ACP_EXTENSIONS'; |
88 | |
89 | $action = $this->request->variable('action', 'list'); |
90 | $ext_name = $this->request->variable('ext_name', ''); |
91 | |
92 | // What is a safe limit of execution time? Half the max execution time should be safe. |
93 | $safe_time_limit = ($this->php_ini->getNumeric('max_execution_time') / 2); |
94 | $start_time = time(); |
95 | |
96 | // Cancel action |
97 | if ($this->request->is_set_post('cancel')) |
98 | { |
99 | $action = 'list'; |
100 | $ext_name = ''; |
101 | } |
102 | |
103 | if (in_array($action, array('enable', 'disable', 'delete_data')) && !check_link_hash($this->request->variable('hash', ''), $action . '.' . $ext_name)) |
104 | { |
105 | trigger_error('FORM_INVALID', E_USER_WARNING); |
106 | } |
107 | |
108 | /** |
109 | * Event to run a specific action on extension |
110 | * |
111 | * @event core.acp_extensions_run_action_before |
112 | * @var string action Action to run; if the event completes execution of the action, should be set to 'none' |
113 | * @var string u_action Url we are at |
114 | * @var string ext_name Extension name from request |
115 | * @var int safe_time_limit Safe limit of execution time |
116 | * @var int start_time Start time |
117 | * @var string tpl_name Template file to load |
118 | * @since 3.1.11-RC1 |
119 | * @changed 3.2.1-RC1 Renamed to core.acp_extensions_run_action_before, added tpl_name, added action 'none' |
120 | */ |
121 | $u_action = $this->u_action; |
122 | $tpl_name = ''; |
123 | $vars = array('action', 'u_action', 'ext_name', 'safe_time_limit', 'start_time', 'tpl_name'); |
124 | extract($this->phpbb_dispatcher->trigger_event('core.acp_extensions_run_action_before', compact($vars))); |
125 | |
126 | // In case they have been updated by the event |
127 | $this->u_action = $u_action; |
128 | $this->tpl_name = $tpl_name; |
129 | |
130 | // If they've specified an extension, let's load the metadata manager and validate it. |
131 | if ($ext_name) |
132 | { |
133 | $md_manager = $this->ext_manager->create_extension_metadata_manager($ext_name); |
134 | |
135 | try |
136 | { |
137 | $md_manager->get_metadata('all'); |
138 | } |
139 | catch (exception_interface $e) |
140 | { |
141 | $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters())); |
142 | trigger_error($message . adm_back_link($this->u_action), E_USER_WARNING); |
143 | } |
144 | } |
145 | |
146 | $this->u_catalog_action = append_sid("{$phpbb_admin_path}index.$phpEx", "i=$id&mode=catalog"); |
147 | |
148 | // What are we doing? |
149 | switch ($action) |
150 | { |
151 | case 'none': |
152 | // Intentionally empty, used by extensions that execute additional actions in the prior event |
153 | break; |
154 | |
155 | case 'set_config_version_check_force_unstable': |
156 | $force_unstable = $this->request->variable('force_unstable', false); |
157 | |
158 | if ($force_unstable) |
159 | { |
160 | $s_hidden_fields = build_hidden_fields(array( |
161 | 'force_unstable' => $force_unstable, |
162 | )); |
163 | |
164 | confirm_box(false, $this->user->lang('EXTENSION_FORCE_UNSTABLE_CONFIRM'), $s_hidden_fields); |
165 | } |
166 | else |
167 | { |
168 | $this->config->set('extension_force_unstable', false); |
169 | trigger_error($this->user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action)); |
170 | } |
171 | break; |
172 | |
173 | case 'list': |
174 | default: |
175 | if (confirm_box(true)) |
176 | { |
177 | $this->config->set('extension_force_unstable', true); |
178 | trigger_error($this->user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action)); |
179 | } |
180 | |
181 | /** @var \phpbb\composer\manager $composer_manager */ |
182 | $composer_manager = $phpbb_container->get('ext.composer.manager'); |
183 | |
184 | $managed_packages = []; |
185 | if ($composer_manager->check_requirements()) |
186 | { |
187 | $managed_packages = $composer_manager->get_managed_packages(); |
188 | } |
189 | |
190 | $this->list_enabled_exts($phpbb_extension_manager, $managed_packages); |
191 | $this->list_disabled_exts($phpbb_extension_manager, $managed_packages); |
192 | $this->list_available_exts($managed_packages); |
193 | |
194 | $this->tpl_name = 'acp_ext_list'; |
195 | |
196 | $this->template->assign_vars(array( |
197 | 'U_VERSIONCHECK_FORCE' => $this->u_action . '&action=list&versioncheck_force=1', |
198 | 'FORCE_UNSTABLE' => $this->config['extension_force_unstable'], |
199 | 'U_ACTION' => $this->u_action, |
200 | 'MANAGED_EXTENSIONS' => $managed_packages, |
201 | 'U_CATALOG_ACTION' => $this->u_catalog_action, |
202 | )); |
203 | |
204 | $this->request->disable_super_globals(); |
205 | break; |
206 | |
207 | case 'enable_pre': |
208 | try |
209 | { |
210 | $md_manager->validate_enable(); |
211 | } |
212 | catch (exception_interface $e) |
213 | { |
214 | $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters())); |
215 | trigger_error($message . adm_back_link($this->u_action), E_USER_WARNING); |
216 | } |
217 | |
218 | $extension = $this->ext_manager->get_extension($ext_name); |
219 | |
220 | $this->check_is_enableable($extension); |
221 | |
222 | if ($this->ext_manager->is_enabled($ext_name)) |
223 | { |
224 | redirect($this->u_action); |
225 | } |
226 | |
227 | $this->tpl_name = 'acp_ext_enable'; |
228 | |
229 | $this->template->assign_vars([ |
230 | 'S_PRE_STEP' => true, |
231 | 'CONFIRM_MESSAGE' => $this->user->lang('EXTENSION_ENABLE_CONFIRM', $md_manager->get_metadata('display-name')), |
232 | 'U_ENABLE' => $this->u_action . '&action=enable&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('enable.' . $ext_name), |
233 | ]); |
234 | break; |
235 | |
236 | case 'enable': |
237 | try |
238 | { |
239 | $md_manager->validate_enable(); |
240 | } |
241 | catch (exception_interface $e) |
242 | { |
243 | $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters())); |
244 | trigger_error($message . adm_back_link($this->u_action), E_USER_WARNING); |
245 | } |
246 | |
247 | $extension = $this->ext_manager->get_extension($ext_name); |
248 | |
249 | $this->check_is_enableable($extension); |
250 | |
251 | try |
252 | { |
253 | while ($this->ext_manager->enable_step($ext_name)) |
254 | { |
255 | // Are we approaching the time limit? If so we want to pause the update and continue after refreshing |
256 | if ((time() - $start_time) >= $safe_time_limit) |
257 | { |
258 | $this->template->assign_var('S_NEXT_STEP', true); |
259 | |
260 | meta_refresh(0, $this->u_action . '&action=enable&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('enable.' . $ext_name)); |
261 | } |
262 | } |
263 | |
264 | // Update custom style for admin area |
265 | $this->template->set_custom_style(array( |
266 | array( |
267 | 'name' => 'adm', |
268 | 'ext_path' => 'adm/style/', |
269 | ), |
270 | ), array($this->phpbb_root_path . 'adm/style')); |
271 | |
272 | $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_EXT_ENABLE', time(), array($ext_name)); |
273 | } |
274 | catch (\phpbb\db\migration\exception $e) |
275 | { |
276 | $this->template->assign_var('MIGRATOR_ERROR', $e->getLocalisedMessage($this->user)); |
277 | } |
278 | |
279 | $this->tpl_name = 'acp_ext_enable'; |
280 | |
281 | $this->template->assign_vars([ |
282 | 'U_RETURN' => $this->u_action . '&action=list', |
283 | ]); |
284 | break; |
285 | |
286 | case 'disable_pre': |
287 | if (!$this->ext_manager->is_enabled($ext_name)) |
288 | { |
289 | redirect($this->u_action); |
290 | } |
291 | |
292 | $this->tpl_name = 'acp_ext_disable'; |
293 | |
294 | $this->template->assign_vars([ |
295 | 'S_PRE_STEP' => true, |
296 | 'CONFIRM_MESSAGE' => $this->user->lang('EXTENSION_DISABLE_CONFIRM', $md_manager->get_metadata('display-name')), |
297 | 'U_DISABLE' => $this->u_action . '&action=disable&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('disable.' . $ext_name), |
298 | ]); |
299 | break; |
300 | |
301 | case 'disable': |
302 | if (!$this->ext_manager->is_enabled($ext_name)) |
303 | { |
304 | redirect($this->u_action); |
305 | } |
306 | |
307 | while ($this->ext_manager->disable_step($ext_name)) |
308 | { |
309 | // Are we approaching the time limit? If so we want to pause the update and continue after refreshing |
310 | if ((time() - $start_time) >= $safe_time_limit) |
311 | { |
312 | $this->template->assign_var('S_NEXT_STEP', true); |
313 | |
314 | meta_refresh(0, $this->u_action . '&action=disable&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('disable.' . $ext_name)); |
315 | } |
316 | } |
317 | $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_EXT_DISABLE', time(), array($ext_name)); |
318 | |
319 | $this->tpl_name = 'acp_ext_disable'; |
320 | |
321 | $this->template->assign_vars([ |
322 | 'U_RETURN' => $this->u_action . '&action=list', |
323 | ]); |
324 | break; |
325 | |
326 | case 'delete_data_pre': |
327 | if ($this->ext_manager->is_enabled($ext_name)) |
328 | { |
329 | redirect($this->u_action); |
330 | } |
331 | |
332 | $this->tpl_name = 'acp_ext_delete_data'; |
333 | |
334 | $this->template->assign_vars([ |
335 | 'S_PRE_STEP' => true, |
336 | 'CONFIRM_MESSAGE' => $this->user->lang('EXTENSION_DELETE_DATA_CONFIRM', $md_manager->get_metadata('display-name')), |
337 | 'U_PURGE' => $this->u_action . '&action=delete_data&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('delete_data.' . $ext_name), |
338 | ]); |
339 | break; |
340 | |
341 | case 'delete_data': |
342 | if ($this->ext_manager->is_enabled($ext_name)) |
343 | { |
344 | redirect($this->u_action); |
345 | } |
346 | |
347 | try |
348 | { |
349 | while ($this->ext_manager->purge_step($ext_name)) |
350 | { |
351 | // Are we approaching the time limit? If so we want to pause the update and continue after refreshing |
352 | if ((time() - $start_time) >= $safe_time_limit) |
353 | { |
354 | $this->template->assign_var('S_NEXT_STEP', true); |
355 | |
356 | meta_refresh(0, $this->u_action . '&action=delete_data&ext_name=' . urlencode($ext_name) . '&hash=' . generate_link_hash('delete_data.' . $ext_name)); |
357 | } |
358 | } |
359 | $this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_EXT_PURGE', time(), array($ext_name)); |
360 | } |
361 | catch (\phpbb\db\migration\exception $e) |
362 | { |
363 | $this->template->assign_var('MIGRATOR_ERROR', $e->getLocalisedMessage($this->user)); |
364 | } |
365 | |
366 | $this->tpl_name = 'acp_ext_delete_data'; |
367 | |
368 | $this->template->assign_vars([ |
369 | 'U_RETURN' => $this->u_action . '&action=list', |
370 | ]); |
371 | break; |
372 | |
373 | case 'details': |
374 | // Output it to the template |
375 | $meta = $md_manager->get_metadata('all'); |
376 | $this->output_metadata_to_template($meta); |
377 | |
378 | if (isset($meta['extra']['version-check'])) |
379 | { |
380 | try |
381 | { |
382 | $updates_available = $this->ext_manager->version_check($md_manager, $this->request->variable('versioncheck_force', false), false, $this->config['extension_force_unstable'] ? 'unstable' : null); |
383 | |
384 | $this->template->assign_vars(array( |
385 | 'S_UP_TO_DATE' => empty($updates_available), |
386 | 'UP_TO_DATE_MSG' => $this->user->lang(empty($updates_available) ? 'UP_TO_DATE' : 'NOT_UP_TO_DATE', $md_manager->get_metadata('display-name')), |
387 | )); |
388 | |
389 | $this->template->assign_block_vars('updates_available', $updates_available); |
390 | } |
391 | catch (exception_interface $e) |
392 | { |
393 | $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters())); |
394 | |
395 | $this->template->assign_vars(array( |
396 | 'S_VERSIONCHECK_FAIL' => true, |
397 | 'VERSIONCHECK_FAIL_REASON' => ($e->getMessage() !== 'VERSIONCHECK_FAIL') ? $message : '', |
398 | )); |
399 | } |
400 | $this->template->assign_var('S_VERSIONCHECK', true); |
401 | } |
402 | else |
403 | { |
404 | $this->template->assign_var('S_VERSIONCHECK', false); |
405 | } |
406 | |
407 | $this->template->assign_vars(array( |
408 | 'U_BACK' => $this->u_action . '&action=list', |
409 | 'U_VERSIONCHECK_FORCE' => $this->u_action . '&action=details&versioncheck_force=1&ext_name=' . urlencode($md_manager->get_metadata('name')), |
410 | )); |
411 | |
412 | $this->tpl_name = 'acp_ext_details'; |
413 | break; |
414 | } |
415 | |
416 | /** |
417 | * Event to run after a specific action on extension has completed |
418 | * |
419 | * @event core.acp_extensions_run_action_after |
420 | * @var string action Action that has run |
421 | * @var string u_action Url we are at |
422 | * @var string ext_name Extension name from request |
423 | * @var int safe_time_limit Safe limit of execution time |
424 | * @var int start_time Start time |
425 | * @var string tpl_name Template file to load |
426 | * @since 3.1.11-RC1 |
427 | */ |
428 | $u_action = $this->u_action; |
429 | $tpl_name = $this->tpl_name; |
430 | $vars = array('action', 'u_action', 'ext_name', 'safe_time_limit', 'start_time', 'tpl_name'); |
431 | extract($this->phpbb_dispatcher->trigger_event('core.acp_extensions_run_action_after', compact($vars))); |
432 | |
433 | // In case they have been updated by the event |
434 | $this->u_action = $u_action; |
435 | $this->tpl_name = $tpl_name; |
436 | } |
437 | |
438 | /** |
439 | * Handles the catalog mode of the extensions list |
440 | * |
441 | * @param string $id |
442 | * @param string $mode |
443 | */ |
444 | public function catalog_mode($id, $mode) |
445 | { |
446 | global $phpbb_container; |
447 | |
448 | $action = $this->request->variable('action', 'list'); |
449 | |
450 | /** @var \phpbb\language\language $language */ |
451 | $language = $phpbb_container->get('language'); |
452 | |
453 | /** @var \phpbb\composer\manager $composer_manager */ |
454 | $composer_manager = $phpbb_container->get('ext.composer.manager'); |
455 | |
456 | /** @var \phpbb\extension\manager $extensions_manager */ |
457 | $extensions_manager = $phpbb_container->get('ext.manager'); |
458 | |
459 | if (!$composer_manager->check_requirements()) |
460 | { |
461 | $this->page_title = 'ACP_EXTENSIONS_CATALOG'; |
462 | $this->tpl_name = 'message_body'; |
463 | |
464 | $this->template->assign_vars([ |
465 | 'MESSAGE_TITLE' => $language->lang('EXTENSIONS_CATALOG_NOT_AVAILABLE'), |
466 | 'MESSAGE_TEXT' => $language->lang('EXTENSIONS_COMPOSER_NOT_WRITABLE'), |
467 | ]); |
468 | |
469 | return; |
470 | } |
471 | |
472 | switch ($action) |
473 | { |
474 | case 'install': |
475 | $this->page_title = 'ACP_EXTENSIONS_INSTALL'; |
476 | |
477 | $extension = $this->request->variable('extension', ''); |
478 | |
479 | if (empty($extension)) |
480 | { |
481 | redirect($this->u_action); |
482 | } |
483 | |
484 | $formatter = new \phpbb\composer\io\html_output_formatter([ |
485 | 'warning' => new \Symfony\Component\Console\Formatter\OutputFormatterStyle('black', 'yellow') |
486 | ]); |
487 | |
488 | $composer_io = new \phpbb\composer\io\web_io($language, '', $phpbb_container->getParameter('extensions.composer.output'), $formatter); |
489 | |
490 | try |
491 | { |
492 | $composer_manager->install((array) $extension, $composer_io); |
493 | } |
494 | catch (\phpbb\exception\runtime_exception $e) |
495 | { |
496 | $this->display_composer_exception($language, $e, $composer_io); |
497 | return; |
498 | } |
499 | $this->tpl_name = 'detailed_message_body'; |
500 | |
501 | $this->template->assign_vars(array( |
502 | 'MESSAGE_TITLE' => $language->lang('ACP_EXTENSIONS_INSTALL'), |
503 | 'MESSAGE_TEXT' => $language->lang('EXTENSIONS_INSTALLED') . adm_back_link($this->u_action), |
504 | 'MESSAGE_DETAIL' => $composer_io->getOutput(), |
505 | 'MESSAGE_DETAIL_LEGEND' => $language->lang('COMPOSER_OUTPUT'), |
506 | 'S_USER_NOTICE' => true, |
507 | ) |
508 | ); |
509 | |
510 | break; |
511 | case 'remove': |
512 | $this->page_title = 'ACP_EXTENSIONS_REMOVE'; |
513 | |
514 | $extension = $this->request->variable('extension', ''); |
515 | |
516 | if (empty($extension)) |
517 | { |
518 | redirect($this->u_action); |
519 | } |
520 | |
521 | $formatter = new \phpbb\composer\io\html_output_formatter([ |
522 | 'warning' => new \Symfony\Component\Console\Formatter\OutputFormatterStyle('black', 'yellow') |
523 | ]); |
524 | |
525 | $composer_io = new \phpbb\composer\io\web_io($language, '', $phpbb_container->getParameter('extensions.composer.output'), $formatter); |
526 | |
527 | try |
528 | { |
529 | $composer_manager->remove((array) $extension, $composer_io); |
530 | } |
531 | catch (\phpbb\exception\runtime_exception $e) |
532 | { |
533 | $this->display_composer_exception($language, $e, $composer_io); |
534 | return; |
535 | } |
536 | $this->tpl_name = 'detailed_message_body'; |
537 | |
538 | $this->template->assign_vars(array( |
539 | 'MESSAGE_TITLE' => $language->lang('ACP_EXTENSIONS_REMOVE'), |
540 | 'MESSAGE_TEXT' => $language->lang('EXTENSIONS_REMOVED') . adm_back_link($this->u_action), |
541 | 'MESSAGE_DETAIL' => $composer_io->getOutput(), |
542 | 'MESSAGE_DETAIL_LEGEND' => $language->lang('COMPOSER_OUTPUT'), |
543 | 'S_USER_NOTICE' => true, |
544 | ) |
545 | ); |
546 | |
547 | break; |
548 | case 'update': |
549 | $this->page_title = 'ACP_EXTENSIONS_UPDATE'; |
550 | |
551 | $extension = $this->request->variable('extension', ''); |
552 | |
553 | if (empty($extension)) |
554 | { |
555 | redirect($this->u_action); |
556 | } |
557 | |
558 | $formatter = new \phpbb\composer\io\html_output_formatter([ |
559 | 'warning' => new \Symfony\Component\Console\Formatter\OutputFormatterStyle('black', 'yellow') |
560 | ]); |
561 | |
562 | $composer_io = new \phpbb\composer\io\web_io($language, '', $phpbb_container->getParameter('extensions.composer.output'), $formatter); |
563 | |
564 | try |
565 | { |
566 | $composer_manager->update((array) $extension, $composer_io); |
567 | } |
568 | catch (\phpbb\exception\runtime_exception $e) |
569 | { |
570 | $this->display_composer_exception($language, $e, $composer_io); |
571 | return; |
572 | } |
573 | $this->tpl_name = 'detailed_message_body'; |
574 | |
575 | $this->template->assign_vars(array( |
576 | 'MESSAGE_TITLE' => $language->lang('ACP_EXTENSIONS_UPDATE'), |
577 | 'MESSAGE_TEXT' => $language->lang('EXTENSIONS_UPDATED') . adm_back_link($this->u_action), |
578 | 'MESSAGE_DETAIL' => $composer_io->getOutput(), |
579 | 'MESSAGE_DETAIL_LEGEND' => $language->lang('COMPOSER_OUTPUT'), |
580 | 'S_USER_NOTICE' => true, |
581 | ) |
582 | ); |
583 | |
584 | break; |
585 | case 'manage': |
586 | $this->page_title = 'ACP_EXTENSIONS_MANAGE'; |
587 | |
588 | $extension = $this->request->variable('extension', ''); |
589 | |
590 | if (empty($extension)) |
591 | { |
592 | redirect($this->u_action); |
593 | } |
594 | |
595 | $formatter = new \phpbb\composer\io\html_output_formatter([ |
596 | 'warning' => new \Symfony\Component\Console\Formatter\OutputFormatterStyle('black', 'yellow') |
597 | ]); |
598 | |
599 | $composer_io = new \phpbb\composer\io\web_io($language, '', $phpbb_container->getParameter('extensions.composer.output'), $formatter); |
600 | |
601 | try |
602 | { |
603 | $composer_manager->start_managing($extension, $composer_io); |
604 | } |
605 | catch (\phpbb\exception\runtime_exception $e) |
606 | { |
607 | $this->display_composer_exception($language, $e, $composer_io); |
608 | return; |
609 | } |
610 | $this->tpl_name = 'detailed_message_body'; |
611 | |
612 | $this->template->assign_vars(array( |
613 | 'MESSAGE_TITLE' => $language->lang('ACP_EXTENSIONS_MANAGE'), |
614 | 'MESSAGE_TEXT' => $language->lang('EXTENSION_MANAGED_SUCCESS', $extension) . adm_back_link($this->u_action), |
615 | 'MESSAGE_DETAIL' => $composer_io->getOutput(), |
616 | 'MESSAGE_DETAIL_LEGEND' => $language->lang('COMPOSER_OUTPUT'), |
617 | 'S_USER_NOTICE' => true, |
618 | ) |
619 | ); |
620 | |
621 | break; |
622 | case 'list': |
623 | default: |
624 | if (!$this->config['exts_composer_packagist'] && $this->request->is_set('enable_packagist') && confirm_box(true)) |
625 | { |
626 | $this->config->set('exts_composer_packagist', true); |
627 | $composer_manager->reset_cache(); |
628 | |
629 | trigger_error($language->lang('CONFIG_UPDATED') . adm_back_link($this->u_action)); |
630 | } |
631 | |
632 | $submit = $this->request->is_set('update'); |
633 | if ($submit) |
634 | { |
635 | if (!check_form_key('catalog_settings')) |
636 | { |
637 | trigger_error($language->lang('FORM_INVALID') . adm_back_link($this->u_action), E_USER_WARNING); |
638 | } |
639 | |
640 | $enable_packagist = $this->request->variable('enable_packagist', false); |
641 | $enable_on_install = $this->request->variable('enable_on_install', false); |
642 | $purge_on_remove = $this->request->variable('purge_on_remove', false); |
643 | $minimum_stability = $this->request->variable('minimum_stability', 'stable'); |
644 | $repositories = array_unique( |
645 | array_filter( |
646 | array_map( |
647 | 'trim', |
648 | explode("\n", $this->request->variable('repositories', '')) |
649 | ) |
650 | ) |
651 | ); |
652 | |
653 | $previous_minimum_stability = $this->config['exts_composer_minimum_stability']; |
654 | $previous_repositories = $this->config['exts_composer_repositories']; |
655 | $previous_enable_packagist = $this->config['exts_composer_packagist']; |
656 | |
657 | $this->config->set('exts_composer_enable_on_install', $enable_on_install); |
658 | $this->config->set('exts_composer_purge_on_remove', $purge_on_remove); |
659 | $this->config->set('exts_composer_minimum_stability', $minimum_stability); |
660 | $this->config->set('exts_composer_repositories', json_encode($repositories, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); |
661 | |
662 | if ($minimum_stability != $previous_minimum_stability |
663 | || $repositories != $previous_repositories |
664 | || $enable_packagist != $previous_enable_packagist) |
665 | { |
666 | $composer_manager->reset_cache(); |
667 | } |
668 | |
669 | if (!$this->config['exts_composer_packagist'] && $enable_packagist) |
670 | { |
671 | $s_hidden_fields = build_hidden_fields(array( |
672 | 'enable_packagist' => $enable_packagist |
673 | )); |
674 | |
675 | confirm_box(false, $language->lang('ENABLE_PACKAGIST_CONFIRM'), $s_hidden_fields); |
676 | } |
677 | else |
678 | { |
679 | $this->config->set('exts_composer_packagist', $enable_packagist); |
680 | trigger_error($language->lang('CONFIG_UPDATED') . adm_back_link($this->u_action)); |
681 | } |
682 | } |
683 | |
684 | /** @var \phpbb\composer\extension_manager $manager */ |
685 | $manager = $phpbb_container->get('ext.composer.manager'); |
686 | |
687 | /** @var \phpbb\pagination $pagination */ |
688 | $pagination = $phpbb_container->get('pagination'); |
689 | |
690 | $start = $this->request->variable('start', 0); |
691 | $base_url = $this->u_action; |
692 | |
693 | $available_extensions = $manager->get_available_packages(); |
694 | $managed_packages = $manager->get_managed_packages(); |
695 | |
696 | $extensions = array_slice($available_extensions, $start, 20); |
697 | |
698 | $pagination->generate_template_pagination($base_url, 'pagination', 'start', count($available_extensions), 20, $start); |
699 | |
700 | $this->page_title = 'ACP_EXTENSIONS_CATALOG'; |
701 | $this->tpl_name = 'acp_ext_catalog'; |
702 | |
703 | $this->template->assign_vars([ |
704 | 'extensions' => $extensions, |
705 | 'managed_extensions' => array_keys($managed_packages), |
706 | 'installed_extensions' => array_keys($extensions_manager->all_available()), |
707 | 'U_ACTION' => $this->u_action, |
708 | 'settings' => [ |
709 | 'enable_packagist' => $this->config['exts_composer_packagist'], |
710 | 'enable_on_install' => $this->config['exts_composer_enable_on_install'], |
711 | 'purge_on_remove' => $this->config['exts_composer_purge_on_remove'], |
712 | 'minimum_stability' => $this->config['exts_composer_minimum_stability'], |
713 | 'stabilities' => array_keys(\Composer\Package\BasePackage::$stabilities), |
714 | 'repositories' => json_decode($this->config['exts_composer_repositories'], true), |
715 | ], |
716 | ]); |
717 | |
718 | add_form_key('catalog_settings'); |
719 | |
720 | break; |
721 | } |
722 | } |
723 | |
724 | /** |
725 | * Display an exception raised by the composer manager |
726 | * |
727 | * @param \phpbb\language\language $language |
728 | * @param \phpbb\exception\runtime_exception $e |
729 | * @param \phpbb\composer\io\web_io $composer_io |
730 | */ |
731 | private function display_composer_exception(\phpbb\language\language $language, \phpbb\exception\runtime_exception $e, \phpbb\composer\io\web_io $composer_io) |
732 | { |
733 | $this->tpl_name = 'detailed_message_body'; |
734 | |
735 | if ($e->getPrevious()) |
736 | { |
737 | $message_title = $language->lang_array($e->getMessage(), $e->get_parameters()); |
738 | |
739 | if ($e->getPrevious() instanceof \phpbb\exception\exception_interface) |
740 | { |
741 | $message_text = $language->lang_array($e->getPrevious()->getMessage(), $e->getPrevious()->get_parameters()) . adm_back_link($this->u_action); |
742 | } |
743 | else |
744 | { |
745 | $message_text = $e->getPrevious()->getMessage() . adm_back_link($this->u_action); |
746 | } |
747 | } |
748 | else |
749 | { |
750 | $message_title = $language->lang('INFORMATION'); |
751 | $message_text = $language->lang_array($e->getMessage(), $e->get_parameters()) . adm_back_link($this->u_action); |
752 | } |
753 | |
754 | $this->template->assign_vars(array( |
755 | 'MESSAGE_TITLE' => $message_title, |
756 | 'MESSAGE_TEXT' => $message_text, |
757 | 'MESSAGE_DETAIL' => $composer_io->getOutput(), |
758 | 'MESSAGE_DETAIL_LEGEND' => $language->lang('COMPOSER_OUTPUT'), |
759 | 'S_USER_ERROR' => true, |
760 | ) |
761 | ); |
762 | } |
763 | |
764 | /** |
765 | * Lists all the enabled extensions and dumps to the template |
766 | * |
767 | * @param \phpbb\extension\manager $phpbb_extension_manager An instance of the extension manager |
768 | * @param array $managed_packages List of managed packages |
769 | * |
770 | * @return void |
771 | */ |
772 | public function list_enabled_exts(\phpbb\extension\manager $phpbb_extension_manager, array $managed_packages) |
773 | { |
774 | $enabled_extension_meta_data = array(); |
775 | |
776 | foreach ($this->ext_manager->all_enabled() as $name => $location) |
777 | { |
778 | $md_manager = $this->ext_manager->create_extension_metadata_manager($name); |
779 | |
780 | try |
781 | { |
782 | $meta = $md_manager->get_metadata('all'); |
783 | $enabled_extension_meta_data[$name] = array( |
784 | 'META_DISPLAY_NAME' => $md_manager->get_metadata('display-name'), |
785 | 'META_VERSION' => $meta['version'], |
786 | 'META_NAME' => $md_manager->get_metadata('name'), |
787 | ); |
788 | |
789 | if (isset($meta['extra']['version-check'])) |
790 | { |
791 | try |
792 | { |
793 | $force_update = $this->request->variable('versioncheck_force', false); |
794 | $updates = $this->ext_manager->version_check($md_manager, $force_update, !$force_update); |
795 | |
796 | $enabled_extension_meta_data[$name]['S_UP_TO_DATE'] = empty($updates); |
797 | $enabled_extension_meta_data[$name]['S_VERSIONCHECK'] = true; |
798 | $enabled_extension_meta_data[$name]['U_VERSIONCHECK_FORCE'] = $this->u_action . '&action=details&versioncheck_force=1&ext_name=' . urlencode($md_manager->get_metadata('name')); |
799 | } |
800 | catch (exception_interface $e) |
801 | { |
802 | // Ignore exceptions due to the version check |
803 | } |
804 | } |
805 | else |
806 | { |
807 | $enabled_extension_meta_data[$name]['S_VERSIONCHECK'] = false; |
808 | } |
809 | } |
810 | catch (exception_interface $e) |
811 | { |
812 | $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters())); |
813 | $this->template->assign_block_vars('disabled', array( |
814 | 'META_DISPLAY_NAME' => $this->user->lang('EXTENSION_INVALID_LIST', $name, $message), |
815 | 'S_VERSIONCHECK' => false, |
816 | )); |
817 | } |
818 | catch (\RuntimeException $e) |
819 | { |
820 | $enabled_extension_meta_data[$name]['S_VERSIONCHECK'] = false; |
821 | } |
822 | } |
823 | |
824 | uasort($enabled_extension_meta_data, array($this, 'sort_extension_meta_data_table')); |
825 | |
826 | foreach ($enabled_extension_meta_data as $name => $block_vars) |
827 | { |
828 | $block_vars['NAME'] = $name; |
829 | $block_vars['U_DETAILS'] = $this->u_action . '&action=details&ext_name=' . urlencode($name); |
830 | |
831 | $this->template->assign_block_vars('enabled', $block_vars); |
832 | |
833 | $this->output_actions('enabled', array( |
834 | 'DISABLE' => $this->u_action . '&action=disable_pre&ext_name=' . urlencode($name), |
835 | )); |
836 | |
837 | if (isset($managed_packages[$block_vars['META_NAME']])) |
838 | { |
839 | $this->output_actions('enabled', [ |
840 | 'UPDATE' => $this->u_catalog_action . '&action=update&extension=' . urlencode($block_vars['META_NAME']), |
841 | 'REMOVE' => $this->u_catalog_action . '&action=remove&extension=' . urlencode($block_vars['META_NAME']), |
842 | ]); |
843 | } |
844 | } |
845 | } |
846 | |
847 | /** |
848 | * Lists all the disabled extensions and dumps to the template |
849 | * |
850 | * @param \phpbb\extension\manager $phpbb_extension_manager An instance of the extension manager |
851 | * @param array $managed_packages List of managed packages |
852 | * |
853 | * @return void |
854 | */ |
855 | public function list_disabled_exts(\phpbb\extension\manager $phpbb_extension_manager, array $managed_packages) |
856 | { |
857 | $disabled_extension_meta_data = array(); |
858 | |
859 | foreach ($this->ext_manager->all_disabled() as $name => $location) |
860 | { |
861 | $md_manager = $this->ext_manager->create_extension_metadata_manager($name); |
862 | |
863 | try |
864 | { |
865 | $meta = $md_manager->get_metadata('all'); |
866 | $disabled_extension_meta_data[$name] = array( |
867 | 'META_DISPLAY_NAME' => $md_manager->get_metadata('display-name'), |
868 | 'META_VERSION' => $meta['version'], |
869 | 'META_NAME' => $md_manager->get_metadata('name'), |
870 | ); |
871 | |
872 | if (isset($meta['extra']['version-check'])) |
873 | { |
874 | $force_update = $this->request->variable('versioncheck_force', false); |
875 | $updates = $this->ext_manager->version_check($md_manager, $force_update, !$force_update); |
876 | |
877 | $disabled_extension_meta_data[$name]['S_UP_TO_DATE'] = empty($updates); |
878 | $disabled_extension_meta_data[$name]['S_VERSIONCHECK'] = true; |
879 | $disabled_extension_meta_data[$name]['U_VERSIONCHECK_FORCE'] = $this->u_action . '&action=details&versioncheck_force=1&ext_name=' . urlencode($md_manager->get_metadata('name')); |
880 | } |
881 | else |
882 | { |
883 | $disabled_extension_meta_data[$name]['S_VERSIONCHECK'] = false; |
884 | } |
885 | } |
886 | catch (version_check_exception $e) |
887 | { |
888 | $disabled_extension_meta_data[$name]['S_VERSIONCHECK'] = false; |
889 | } |
890 | catch (exception_interface $e) |
891 | { |
892 | $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters())); |
893 | $this->template->assign_block_vars('disabled', array( |
894 | 'META_DISPLAY_NAME' => $this->user->lang('EXTENSION_INVALID_LIST', $name, $message), |
895 | 'S_VERSIONCHECK' => false, |
896 | )); |
897 | } |
898 | catch (\RuntimeException $e) |
899 | { |
900 | $disabled_extension_meta_data[$name]['S_VERSIONCHECK'] = false; |
901 | } |
902 | } |
903 | |
904 | uasort($disabled_extension_meta_data, array($this, 'sort_extension_meta_data_table')); |
905 | |
906 | foreach ($disabled_extension_meta_data as $name => $block_vars) |
907 | { |
908 | $block_vars['NAME'] = $name; |
909 | $block_vars['U_DETAILS'] = $this->u_action . '&action=details&ext_name=' . urlencode($name); |
910 | |
911 | $this->template->assign_block_vars('disabled', $block_vars); |
912 | |
913 | $this->output_actions('disabled', array( |
914 | 'ENABLE' => $this->u_action . '&action=enable_pre&ext_name=' . urlencode($name), |
915 | 'DELETE_DATA' => $this->u_action . '&action=delete_data_pre&ext_name=' . urlencode($name), |
916 | )); |
917 | |
918 | if (isset($managed_packages[$block_vars['META_NAME']])) |
919 | { |
920 | $this->output_actions('disabled', [ |
921 | 'UPDATE' => $this->u_catalog_action . '&action=update&extension=' . urlencode($block_vars['META_NAME']), |
922 | 'REMOVE' => $this->u_catalog_action . '&action=remove&extension=' . urlencode($block_vars['META_NAME']), |
923 | ]); |
924 | } |
925 | } |
926 | } |
927 | |
928 | /** |
929 | * Lists all the available extensions and dumps to the template |
930 | * |
931 | * @param array $managed_packages List of managed packages |
932 | * |
933 | * @return void |
934 | */ |
935 | public function list_available_exts(array $managed_packages) |
936 | { |
937 | $uninstalled = array_diff_key($this->ext_manager->all_available(), $this->ext_manager->all_configured()); |
938 | |
939 | $available_extension_meta_data = array(); |
940 | |
941 | foreach ($uninstalled as $name => $location) |
942 | { |
943 | $md_manager = $this->ext_manager->create_extension_metadata_manager($name); |
944 | |
945 | try |
946 | { |
947 | $meta = $md_manager->get_metadata('all'); |
948 | $available_extension_meta_data[$name] = array( |
949 | 'META_DISPLAY_NAME' => $md_manager->get_metadata('display-name'), |
950 | 'META_VERSION' => $meta['version'], |
951 | 'META_NAME' => $md_manager->get_metadata('name'), |
952 | ); |
953 | |
954 | if (isset($meta['extra']['version-check'])) |
955 | { |
956 | $force_update = $this->request->variable('versioncheck_force', false); |
957 | $updates = $this->ext_manager->version_check($md_manager, $force_update, !$force_update); |
958 | |
959 | $available_extension_meta_data[$name]['S_UP_TO_DATE'] = empty($updates); |
960 | $available_extension_meta_data[$name]['S_VERSIONCHECK'] = true; |
961 | $available_extension_meta_data[$name]['U_VERSIONCHECK_FORCE'] = $this->u_action . '&action=details&versioncheck_force=1&ext_name=' . urlencode($md_manager->get_metadata('name')); |
962 | } |
963 | else |
964 | { |
965 | $available_extension_meta_data[$name]['S_VERSIONCHECK'] = false; |
966 | } |
967 | } |
968 | catch (version_check_exception $e) |
969 | { |
970 | $available_extension_meta_data[$name]['S_VERSIONCHECK'] = false; |
971 | } |
972 | catch (exception_interface $e) |
973 | { |
974 | $message = call_user_func_array(array($this->user, 'lang'), array_merge(array($e->getMessage()), $e->get_parameters())); |
975 | $this->template->assign_block_vars('not_installed', array( |
976 | 'META_DISPLAY_NAME' => $this->user->lang('EXTENSION_INVALID_LIST', $name, $message), |
977 | 'S_VERSIONCHECK' => false, |
978 | )); |
979 | } |
980 | } |
981 | |
982 | uasort($available_extension_meta_data, array($this, 'sort_extension_meta_data_table')); |
983 | |
984 | foreach ($available_extension_meta_data as $name => $block_vars) |
985 | { |
986 | $block_vars['NAME'] = $name; |
987 | $block_vars['U_DETAILS'] = $this->u_action . '&action=details&ext_name=' . urlencode($name); |
988 | |
989 | $this->template->assign_block_vars('not_installed', $block_vars); |
990 | |
991 | $this->output_actions('not_installed', array( |
992 | 'ENABLE' => $this->u_action . '&action=enable_pre&ext_name=' . urlencode($name), |
993 | 'REMOVE' => $this->u_catalog_action . '&action=remove&extension=' . urlencode($block_vars['META_NAME']), |
994 | )); |
995 | } |
996 | } |
997 | |
998 | /** |
999 | * Output actions to a block |
1000 | * |
1001 | * @param string $block |
1002 | * @param array $actions |
1003 | */ |
1004 | private function output_actions($block, $actions) |
1005 | { |
1006 | foreach ($actions as $action => $url) |
1007 | { |
1008 | $this->template->assign_block_vars($block . '.actions', [ |
1009 | 'ACTION' => $action, |
1010 | 'L_ACTION' => $this->user->lang('EXTENSION_' . $action), |
1011 | 'L_ACTION_EXPLAIN' => (isset($this->user->lang['EXTENSION_' . $action . '_EXPLAIN'])) ? $this->user->lang('EXTENSION_' . $action . '_EXPLAIN') : '', |
1012 | 'U_ACTION' => $url, |
1013 | ]); |
1014 | } |
1015 | } |
1016 | |
1017 | /** |
1018 | * Sort helper for the table containing the metadata about the extensions. |
1019 | */ |
1020 | protected function sort_extension_meta_data_table($val1, $val2) |
1021 | { |
1022 | return strnatcasecmp($val1['META_DISPLAY_NAME'], $val2['META_DISPLAY_NAME']); |
1023 | } |
1024 | |
1025 | /** |
1026 | * Outputs extension metadata into the template |
1027 | * |
1028 | * @param array $metadata Array with all metadata for the extension |
1029 | * @return void |
1030 | */ |
1031 | public function output_metadata_to_template($metadata) |
1032 | { |
1033 | $this->template->assign_vars(array( |
1034 | 'META_NAME' => $metadata['name'], |
1035 | 'META_TYPE' => $metadata['type'], |
1036 | 'META_DESCRIPTION' => (isset($metadata['description'])) ? $metadata['description'] : '', |
1037 | 'META_HOMEPAGE' => (isset($metadata['homepage'])) ? $metadata['homepage'] : '', |
1038 | 'META_VERSION' => $metadata['version'], |
1039 | 'META_TIME' => (isset($metadata['time'])) ? $metadata['time'] : '', |
1040 | 'META_LICENSE' => $metadata['license'], |
1041 | |
1042 | 'META_REQUIRE_PHP' => (isset($metadata['require']['php'])) ? $metadata['require']['php'] : '', |
1043 | 'META_REQUIRE_PHP_FAIL' => (isset($metadata['require']['php'])) ? false : true, |
1044 | |
1045 | 'META_REQUIRE_PHPBB' => (isset($metadata['extra']['soft-require']['phpbb/phpbb'])) ? $metadata['extra']['soft-require']['phpbb/phpbb'] : '', |
1046 | 'META_REQUIRE_PHPBB_FAIL' => (isset($metadata['extra']['soft-require']['phpbb/phpbb'])) ? false : true, |
1047 | |
1048 | 'META_DISPLAY_NAME' => (isset($metadata['extra']['display-name'])) ? $metadata['extra']['display-name'] : '', |
1049 | )); |
1050 | |
1051 | foreach ($metadata['authors'] as $author) |
1052 | { |
1053 | $this->template->assign_block_vars('meta_authors', array( |
1054 | 'AUTHOR_NAME' => $author['name'], |
1055 | 'AUTHOR_EMAIL' => (isset($author['email'])) ? $author['email'] : '', |
1056 | 'AUTHOR_HOMEPAGE' => (isset($author['homepage'])) ? $author['homepage'] : '', |
1057 | 'AUTHOR_ROLE' => (isset($author['role'])) ? $author['role'] : '', |
1058 | )); |
1059 | } |
1060 | } |
1061 | |
1062 | /** |
1063 | * Checks whether the extension can be enabled. Triggers error if not. |
1064 | * Error message can be set by the extension. |
1065 | * |
1066 | * @param \phpbb\extension\extension_interface $extension Extension to check |
1067 | */ |
1068 | protected function check_is_enableable(\phpbb\extension\extension_interface $extension) |
1069 | { |
1070 | $message = $extension->is_enableable(); |
1071 | if ($message !== true) |
1072 | { |
1073 | if (empty($message)) |
1074 | { |
1075 | $message = $this->user->lang('EXTENSION_NOT_ENABLEABLE'); |
1076 | } |
1077 | else if (is_array($message)) |
1078 | { |
1079 | $message = implode('<br>', $message); |
1080 | } |
1081 | |
1082 | trigger_error($message . adm_back_link($this->u_action), E_USER_WARNING); |
1083 | } |
1084 | } |
1085 | } |