From d4d26987e56ab4135646fd152f1566781473239e Mon Sep 17 00:00:00 2001 From: rxu Date: Sat, 18 Dec 2021 12:18:24 +0700 Subject: [PATCH 1/5] [ticket/16688] Fix PHP fatal errors on installing extensions via catalog PHPBB3-16688 --- phpBB/phpbb/composer/installer.php | 4 ++++ tests/functional/extension_acp_test.php | 18 +++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/phpBB/phpbb/composer/installer.php b/phpBB/phpbb/composer/installer.php index 9910cb5a08..f436587fb5 100644 --- a/phpBB/phpbb/composer/installer.php +++ b/phpBB/phpbb/composer/installer.php @@ -152,7 +152,9 @@ class installer { if (!$io) { + $this->restore_cwd(); $io = new null_io(); + $this->move_to_root(); } $this->generate_ext_json_file($packages); @@ -183,6 +185,7 @@ class installer } catch (\Exception $e) { + $this->restore_cwd(); $this->restore_ext_json_file(); throw new runtime_exception('COMPOSER_CANNOT_INSTALL', [], $e); @@ -190,6 +193,7 @@ class installer if ($result !== 0) { + $this->restore_cwd(); $this->restore_ext_json_file(); throw new runtime_exception($io->get_composer_error(), []); diff --git a/tests/functional/extension_acp_test.php b/tests/functional/extension_acp_test.php index ab02831209..ee5d82ff0e 100644 --- a/tests/functional/extension_acp_test.php +++ b/tests/functional/extension_acp_test.php @@ -76,7 +76,7 @@ class phpbb_functional_extension_acp_test extends phpbb_functional_test_case $this->login(); $this->admin_login(); - $this->add_lang('acp/extensions'); + $this->add_lang(['acp/common', 'acp/extensions']); } public function test_list() @@ -264,4 +264,20 @@ class phpbb_functional_extension_acp_test extends phpbb_functional_test_case // Ensure catalog has any records in extensions list $this->assertGreaterThan(0, $crawler->filter('tbody > tr > td > strong')->count()); } + + public function test_extensions_catalog_installing_extension() + { + $crawler = self::request('GET', 'adm/index.php?i=acp_extensions&mode=catalog&sid=' . $this->sid); + $this->assertContainsLang('ACP_EXTENSIONS_CATALOG', $this->get_content()); + + // Ensure catalog has any records in extensions list + $this->assertGreaterThan(0, $crawler->filter('tbody > tr > td > strong')->count()); + + // Attempt to install any extension which is 1st in the list + $extension_install_link = $crawler->filter('tbody')->selectLink($this->lang('INSTALL'))->link(); + $crawler = self::$client->click($extension_install_link); + + // Assert any action result is presented regardless of success + $this->assertTrue(strlen($crawler->filter('.console-output > pre')->text()) > 0, $this->get_content()); + } } From 6404ed2502ee4a9db634b942842d334f042de62a Mon Sep 17 00:00:00 2001 From: rxu Date: Sun, 19 Dec 2021 16:57:40 +0700 Subject: [PATCH 2/5] [ticket/16688] Do not restore current working dir before json file restoring PHPBB3-16688 --- phpBB/phpbb/composer/installer.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpBB/phpbb/composer/installer.php b/phpBB/phpbb/composer/installer.php index f436587fb5..9244644788 100644 --- a/phpBB/phpbb/composer/installer.php +++ b/phpBB/phpbb/composer/installer.php @@ -185,16 +185,16 @@ class installer } catch (\Exception $e) { - $this->restore_cwd(); $this->restore_ext_json_file(); + $this->restore_cwd(); throw new runtime_exception('COMPOSER_CANNOT_INSTALL', [], $e); } if ($result !== 0) { - $this->restore_cwd(); $this->restore_ext_json_file(); + $this->restore_cwd(); throw new runtime_exception($io->get_composer_error(), []); } From 4d9e33aa3246efa835c58382dd36a0a542af0915 Mon Sep 17 00:00:00 2001 From: rxu Date: Sun, 19 Dec 2021 17:28:25 +0700 Subject: [PATCH 3/5] [ticket/16688] Fix Composer error on installing extensions via catalog Do not pass packages update list on installing extension. PHPBB3-16943 --- phpBB/phpbb/composer/manager.php | 2 +- tests/functional/extension_acp_test.php | 24 ++++++++++++++++++------ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/phpBB/phpbb/composer/manager.php b/phpBB/phpbb/composer/manager.php index d5fe8935cf..e36a32d1e9 100644 --- a/phpBB/phpbb/composer/manager.php +++ b/phpBB/phpbb/composer/manager.php @@ -89,7 +89,7 @@ class manager implements manager_interface $managed_packages = array_merge($this->get_all_managed_packages(), $packages); ksort($managed_packages); - $this->installer->install($managed_packages, array_keys($packages), $io); + $this->installer->install($managed_packages, [], $io); $this->post_install($packages, $io); diff --git a/tests/functional/extension_acp_test.php b/tests/functional/extension_acp_test.php index ee5d82ff0e..3764abe9de 100644 --- a/tests/functional/extension_acp_test.php +++ b/tests/functional/extension_acp_test.php @@ -267,17 +267,29 @@ class phpbb_functional_extension_acp_test extends phpbb_functional_test_case public function test_extensions_catalog_installing_extension() { - $crawler = self::request('GET', 'adm/index.php?i=acp_extensions&mode=catalog&sid=' . $this->sid); + // Lets check page 6 where 'Scroll Page' should be listed + $crawler = self::request('GET', 'adm/index.php?i=acp_extensions&mode=catalog&start=100&sid=' . $this->sid); $this->assertContainsLang('ACP_EXTENSIONS_CATALOG', $this->get_content()); // Ensure catalog has any records in extensions list $this->assertGreaterThan(0, $crawler->filter('tbody > tr > td > strong')->count()); - // Attempt to install any extension which is 1st in the list - $extension_install_link = $crawler->filter('tbody')->selectLink($this->lang('INSTALL'))->link(); - $crawler = self::$client->click($extension_install_link); + // Attempt to install vse/scrollpage extension + $extension_install_link = $crawler->filter('tr')->reduce( + function ($node, $i) + { + return (bool) (strpos($node->text(), 'Scroll Page') !== false); + } + )->selectLink($this->lang('INSTALL'))->link(); - // Assert any action result is presented regardless of success - $this->assertTrue(strlen($crawler->filter('.console-output > pre')->text()) > 0, $this->get_content()); + $crawler = self::$client->click($extension_install_link); + $this->assertContainsLang('EXTENSIONS_INSTALLED', $crawler->filter('.successbox > p')->text()); + + // Assert there's console log output + $this->assertStringContainsString('Installing vse/scrollpage', $crawler->filter('.console-output > pre')->text()); + + // Ensure installed extension appears in available extensions list + $crawler = self::request('GET', 'adm/index.php?i=acp_extensions&mode=main&sid=' . $this->sid); + $this->assertStringContainsString('Scroll Page', $crawler->filter('strong[title="vse/scrollpage"]')->text()); } } From 85f23474d760d25f6095732bde709d8f742a38e5 Mon Sep 17 00:00:00 2001 From: rxu Date: Sun, 19 Dec 2021 19:30:47 +0700 Subject: [PATCH 4/5] [ticket/16688] Fix 'Remove' link for Extension manager 'Remove' link is broken and rendered as 'Array'. PHPBB3-16943 --- phpBB/adm/style/acp_ext_list.html | 4 +- phpBB/includes/acp/acp_extensions.php | 18 ++--- tests/functional/extension_acp_test.php | 98 +++++++++++++++++++++++-- 3 files changed, 99 insertions(+), 21 deletions(-) diff --git a/phpBB/adm/style/acp_ext_list.html b/phpBB/adm/style/acp_ext_list.html index c5527c14bc..0b63302eed 100644 --- a/phpBB/adm/style/acp_ext_list.html +++ b/phpBB/adm/style/acp_ext_list.html @@ -60,7 +60,7 @@ {L_DETAILS} - title="{enabled.actions.L_ACTION_EXPLAIN}">{enabled.actions.L_ACTION} + style="color: #bc2a4d;" title="{enabled.actions.L_ACTION_EXPLAIN}">{enabled.actions.L_ACTION}  |  @@ -88,7 +88,7 @@ - title="{disabled.actions.L_ACTION_EXPLAIN}">{disabled.actions.L_ACTION} + style="color: #bc2a4d;" title="{disabled.actions.L_ACTION_EXPLAIN}">{disabled.actions.L_ACTION}  |  diff --git a/phpBB/includes/acp/acp_extensions.php b/phpBB/includes/acp/acp_extensions.php index 5bdb381d1b..de98bfadb1 100644 --- a/phpBB/includes/acp/acp_extensions.php +++ b/phpBB/includes/acp/acp_extensions.php @@ -838,10 +838,7 @@ class acp_extensions { $this->output_actions('enabled', [ 'UPDATE' => $this->u_catalog_action . '&action=update&extension=' . urlencode($block_vars['META_NAME']), - 'REMOVE' => [ - 'url' => $this->u_catalog_action . '&action=remove&extension=' . urlencode($block_vars['META_NAME']), - 'color' => '#BC2A4D;', - ] + 'REMOVE' => $this->u_catalog_action . '&action=remove&extension=' . urlencode($block_vars['META_NAME']), ]); } } @@ -922,10 +919,7 @@ class acp_extensions { $this->output_actions('disabled', [ 'UPDATE' => $this->u_catalog_action . '&action=update&extension=' . urlencode($block_vars['META_NAME']), - 'REMOVE' => [ - 'url' => $this->u_catalog_action . '&action=remove&extension=' . urlencode($block_vars['META_NAME']), - 'color' => '#BC2A4D;', - ] + 'REMOVE' => $this->u_catalog_action . '&action=remove&extension=' . urlencode($block_vars['META_NAME']), ]); } } @@ -997,6 +991,7 @@ class acp_extensions $this->output_actions('disabled', array( 'ENABLE' => $this->u_action . '&action=enable_pre&ext_name=' . urlencode($name), + 'REMOVE' => $this->u_catalog_action . '&action=remove&extension=' . urlencode($block_vars['META_NAME']), )); } } @@ -1009,11 +1004,12 @@ class acp_extensions */ private function output_actions($block, $actions) { - foreach ($actions as $lang => $url) + foreach ($actions as $action => $url) { $this->template->assign_block_vars($block . '.actions', [ - 'L_ACTION' => $this->user->lang('EXTENSION_' . $lang), - 'L_ACTION_EXPLAIN' => (isset($this->user->lang['EXTENSION_' . $lang . '_EXPLAIN'])) ? $this->user->lang('EXTENSION_' . $lang . '_EXPLAIN') : '', + 'ACTION' => $action, + 'L_ACTION' => $this->user->lang('EXTENSION_' . $action), + 'L_ACTION_EXPLAIN' => (isset($this->user->lang['EXTENSION_' . $action . '_EXPLAIN'])) ? $this->user->lang('EXTENSION_' . $action . '_EXPLAIN') : '', 'U_ACTION' => $url, ]); } diff --git a/tests/functional/extension_acp_test.php b/tests/functional/extension_acp_test.php index 3764abe9de..f36df243f3 100644 --- a/tests/functional/extension_acp_test.php +++ b/tests/functional/extension_acp_test.php @@ -267,29 +267,111 @@ class phpbb_functional_extension_acp_test extends phpbb_functional_test_case public function test_extensions_catalog_installing_extension() { - // Lets check page 6 where 'Scroll Page' should be listed + // Lets check page 6 where 'Scroll Page' and 'Scroll To Top' should be listed $crawler = self::request('GET', 'adm/index.php?i=acp_extensions&mode=catalog&start=100&sid=' . $this->sid); $this->assertContainsLang('ACP_EXTENSIONS_CATALOG', $this->get_content()); - // Ensure catalog has any records in extensions list - $this->assertGreaterThan(0, $crawler->filter('tbody > tr > td > strong')->count()); - - // Attempt to install vse/scrollpage extension - $extension_install_link = $crawler->filter('tr')->reduce( + // Get Install links for both extensions + $scrollpage_install_link = $crawler->filter('tr')->reduce( function ($node, $i) { return (bool) (strpos($node->text(), 'Scroll Page') !== false); } )->selectLink($this->lang('INSTALL'))->link(); - $crawler = self::$client->click($extension_install_link); - $this->assertContainsLang('EXTENSIONS_INSTALLED', $crawler->filter('.successbox > p')->text()); + $scrolltotop_install_link = $crawler->filter('tr')->reduce( + function ($node, $i) + { + return (bool) (strpos($node->text(), 'Scroll To Top') !== false); + } + )->selectLink($this->lang('INSTALL'))->link(); + // Attempt to install vse/scrollpage extension + $crawler = self::$client->click($scrollpage_install_link); + $this->assertContainsLang('EXTENSIONS_INSTALLED', $crawler->filter('.successbox > p')->text()); // Assert there's console log output $this->assertStringContainsString('Installing vse/scrollpage', $crawler->filter('.console-output > pre')->text()); + // Attempt to install vse/scrolltotop extension + $crawler = self::$client->click($scrolltotop_install_link); + $this->assertContainsLang('EXTENSIONS_INSTALLED', $crawler->filter('.successbox > p')->text()); + // Assert there's console log output + $this->assertStringContainsString('Installing vse/scrolltotop', $crawler->filter('.console-output > pre')->text()); + // Ensure installed extension appears in available extensions list $crawler = self::request('GET', 'adm/index.php?i=acp_extensions&mode=main&sid=' . $this->sid); + $this->assertStringContainsString('Scroll To Top', $crawler->filter('strong[title="vse/scrolltotop"]')->text()); + $this->assertStringContainsString('Scroll Page', $crawler->filter('strong[title="vse/scrollpage"]')->text()); + } + + public function test_extensions_catalog_updating_extension() + { + // Enable 'Scroll Page' extension installed earlier + $crawler = self::request('GET', 'adm/index.php?i=acp_extensions&mode=main&sid=' . $this->sid); + $extension_enable_link = $crawler->filter('tr')->reduce( + function ($node, $i) + { + return (bool) (strpos($node->text(), 'Scroll Page') !== false); + } + )->selectLink($this->lang('EXTENSION_ENABLE'))->link(); + $crawler = self::$client->click($extension_enable_link); + $form = $crawler->selectButton($this->lang('EXTENSION_ENABLE'))->form(); + $crawler = self::submit($form); + $this->assertContainsLang('EXTENSION_ENABLE_SUCCESS', $crawler->filter('.successbox')->text()); + + // Update 'Scroll Page' enabled extension + $crawler = self::request('GET', 'adm/index.php?i=acp_extensions&mode=main&sid=' . $this->sid); + $scrollpage_update_link = $crawler->filter('tr')->reduce( + function ($node, $i) + { + return (bool) (strpos($node->text(), 'Scroll Page') !== false); + } + )->selectLink($this->lang('EXTENSION_UPDATE'))->link(); + $crawler = self::$client->click($scrollpage_update_link); + $this->assertContainsLang('EXTENSIONS_UPDATED', $crawler->filter('.successbox > p')->text()); + // Assert there's console log output + $this->assertStringContainsString('Updating packages', $crawler->filter('.console-output > pre')->text()); + + // Ensure installed extension still appears in available extensions list + $crawler = self::request('GET', 'adm/index.php?i=acp_extensions&mode=main&sid=' . $this->sid); $this->assertStringContainsString('Scroll Page', $crawler->filter('strong[title="vse/scrollpage"]')->text()); } + + public function test_extensions_catalog_removing_extension() + { + $crawler = self::request('GET', 'adm/index.php?i=acp_extensions&mode=main&sid=' . $this->sid); + + // Check if both enabled and disabled extensions have 'Remove' action available + $scrollpage_remove_link = $crawler->filter('tr')->reduce( + function ($node, $i) + { + return (bool) (strpos($node->text(), 'Scroll Page') !== false); + } + )->selectLink($this->lang('EXTENSION_REMOVE'))->link(); + + $scrolltotop_remove_link = $crawler->filter('tr')->reduce( + function ($node, $i) + { + return (bool) (strpos($node->text(), 'Scroll To Top') !== false); + } + )->selectLink($this->lang('EXTENSION_REMOVE'))->link(); + + // Test extensions removal + // Remove 'Scroll Page' enabled extension + $crawler = self::$client->click($scrollpage_remove_link); + $this->assertContainsLang('EXTENSIONS_REMOVED', $crawler->filter('.successbox > p')->text()); + // Assert there's console log output + $this->assertStringContainsString('Deleting ext/vse/scrollpage', $crawler->filter('.console-output > pre')->text()); + + // Remove 'Scroll To Top' disabled extension + $crawler = self::$client->click($scrolltotop_remove_link); + $this->assertContainsLang('EXTENSIONS_REMOVED', $crawler->filter('.successbox > p')->text()); + // Assert there's console log output + $this->assertStringContainsString('Deleting ext/vse/scrolltotop', $crawler->filter('.console-output > pre')->text()); + + // Ensure removed extensions do not appear in available extensions list + $crawler = self::request('GET', 'adm/index.php?i=acp_extensions&mode=main&sid=' . $this->sid); + $this->assertStringNotContainsString('Scroll Page', $this->get_content()); + $this->assertStringNotContainsString('Scroll To Top', $this->get_content()); + } } From afe97fb57312f2ce5452d12be9362fbfe9153c24 Mon Sep 17 00:00:00 2001 From: rxu Date: Mon, 20 Dec 2021 23:39:19 +0700 Subject: [PATCH 5/5] [ticket/16688] Fix issues with custom repositories Make any custom repo non-canonical to give repo.packagist.org (if enabled) higher repository priority in case custom repo contains outdated/incorrect packages/dependencies. PHPBB3-16688 --- phpBB/phpbb/composer/installer.php | 1 + tests/functional/extension_acp_test.php | 1 + 2 files changed, 2 insertions(+) diff --git a/phpBB/phpbb/composer/installer.php b/phpBB/phpbb/composer/installer.php index 9244644788..3e6d87d46f 100644 --- a/phpBB/phpbb/composer/installer.php +++ b/phpBB/phpbb/composer/installer.php @@ -591,6 +591,7 @@ class installer $repositories[] = [ 'type' => 'composer', 'url' => $repository, + 'canonical' => $this->packagist ? false : true, ]; } } diff --git a/tests/functional/extension_acp_test.php b/tests/functional/extension_acp_test.php index f36df243f3..a4d45506f4 100644 --- a/tests/functional/extension_acp_test.php +++ b/tests/functional/extension_acp_test.php @@ -254,6 +254,7 @@ class phpbb_functional_extension_acp_test extends phpbb_functional_test_case $form = $crawler->selectButton('Submit')->form(); $form['minimum_stability']->select('dev'); + $form['repositories'] = 'https://satis.phpbb.com/'; $crawler = self::submit($form); $this->assertContainsLang('CONFIG_UPDATED', $crawler->filter('div[class="successbox"] > p')->text());