diff --git a/.github/workflows/action.yml b/.github/workflows/action.yml index d4f0d0d07f7..e00bb9863d5 100644 --- a/.github/workflows/action.yml +++ b/.github/workflows/action.yml @@ -21,7 +21,7 @@ jobs: strategy: fail-fast: false matrix: - operating-system: [ ubuntu-20.04 ] + operating-system: [ ubuntu-22.04 ] php: [ 7.4 ] db: [ mysql, pgsql, sqlite3 ] include: @@ -112,7 +112,7 @@ jobs: strategy: fail-fast: false matrix: - operating-system: [ ubuntu-20.04 ] + operating-system: [ ubuntu-22.04 ] php: [ 7.4 ] db: [ pgsql ] group: [ admin01, admin02, admin03, front, installer ] @@ -186,6 +186,9 @@ jobs: - name: setup-chromedriver uses: nanasess/setup-chromedriver@master + - name: Install fonts + run: sudo apt install fonts-ipafont fonts-ipaexfont + - name: Run chromedriver run: | export DISPLAY=:99 @@ -235,7 +238,7 @@ jobs: strategy: fail-fast: false matrix: - operating-system: [ ubuntu-20.04 ] + operating-system: [ ubuntu-22.04 ] php: [ 7.4 ] db: [ pgsql, mysql ] method: @@ -381,7 +384,7 @@ jobs: strategy: fail-fast: false matrix: - operating-system: [ ubuntu-20.04 ] + operating-system: [ ubuntu-22.04 ] php: [ 7.4 ] db: [ pgsql, mysql ] method: @@ -525,7 +528,7 @@ jobs: strategy: fail-fast: false matrix: - operating-system: [ ubuntu-20.04 ] + operating-system: [ ubuntu-22.04 ] php: [ 7.4 ] db: [ pgsql, mysql ] method: @@ -669,7 +672,7 @@ jobs: strategy: fail-fast: false matrix: - operating-system: [ ubuntu-20.04 ] + operating-system: [ ubuntu-22.04 ] php: [ 7.4 ] db: [ pgsql, mysql ] method: @@ -812,7 +815,7 @@ jobs: deploy: name: Deploy - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: Checkout if: github.event_name == 'release' && (github.event.action == 'published' || github.event.action == 'prereleased' ) diff --git a/codeception/_envs/github_action.yml b/codeception/_envs/github_action.yml index 04907352348..a009f2de6ee 100644 --- a/codeception/_envs/github_action.yml +++ b/codeception/_envs/github_action.yml @@ -8,6 +8,7 @@ modules: chromeOptions: prefs: download.default_directory: '%GITHUB_WORKSPACE%/codeception/_support/_downloads' + wait: 30 MailCatcher: url: 'localhost' port: 1080 diff --git a/codeception/acceptance/EF03OrderCest.php b/codeception/acceptance/EF03OrderCest.php index 174c7bf3077..bf8337dab8f 100644 --- a/codeception/acceptance/EF03OrderCest.php +++ b/codeception/acceptance/EF03OrderCest.php @@ -123,9 +123,13 @@ public function order_カート数量減らす(\AcceptanceTester $I) ProductDetailPage::go($I, 2) ->カートに入れる(2) ->カートへ進む(); + + $I->wait(1); $cartPage = CartPage::go($I) ->商品数量減らす(1); + + $I->wait(1); // 確認 $I->assertEquals('1', $cartPage->商品数量(1)); diff --git a/package-lock.json b/package-lock.json index a585b51a048..e33d65a823a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "eccube", - "version": "4.0.6-p4", + "version": "4.0.6-p5", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 1af3bf261a8..6ad97f26d86 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eccube", - "version": "4.0.6-p4", + "version": "4.0.6-p5", "description": "EC-CUBE EC open platform.", "main": "index.js", "directories": { diff --git a/src/Eccube/Common/Constant.php b/src/Eccube/Common/Constant.php index c8cd428abf3..c9c8892a7aa 100644 --- a/src/Eccube/Common/Constant.php +++ b/src/Eccube/Common/Constant.php @@ -18,7 +18,7 @@ class Constant /** * EC-CUBE VERSION. */ - const VERSION = '4.0.6-p4'; + const VERSION = '4.0.6-p5'; /** * Enable value. diff --git a/src/Eccube/Controller/Admin/Store/OwnerStoreController.php b/src/Eccube/Controller/Admin/Store/OwnerStoreController.php index 6b703140698..fbfaad578c5 100644 --- a/src/Eccube/Controller/Admin/Store/OwnerStoreController.php +++ b/src/Eccube/Controller/Admin/Store/OwnerStoreController.php @@ -32,6 +32,8 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Validator\Constraints as Assert; +use Symfony\Component\Validator\Validator\ValidatorInterface; /** * @Route("/%eccube_admin_route%/store/plugin/api") @@ -63,6 +65,11 @@ class OwnerStoreController extends AbstractController */ protected $pluginApiService; + /** + * @var ValidatorInterface + */ + protected $validator; + private static $vendorName = 'ec-cube'; /** @var BaseInfo */ @@ -81,6 +88,7 @@ class OwnerStoreController extends AbstractController * @param PluginApiService $pluginApiService * @param BaseInfoRepository $baseInfoRepository * @param CacheUtil $cacheUtil + * @param ValidatorInterface $validatorInterface * * @throws \Doctrine\ORM\NoResultException * @throws \Doctrine\ORM\NonUniqueResultException @@ -92,7 +100,8 @@ public function __construct( SystemService $systemService, PluginApiService $pluginApiService, BaseInfoRepository $baseInfoRepository, - CacheUtil $cacheUtil + CacheUtil $cacheUtil, + ValidatorInterface $validatorInterface ) { $this->pluginRepository = $pluginRepository; $this->pluginService = $pluginService; @@ -100,6 +109,7 @@ public function __construct( $this->pluginApiService = $pluginApiService; $this->BaseInfo = $baseInfoRepository->get(); $this->cacheUtil = $cacheUtil; + $this->validator = $validatorInterface; // TODO: Check the flow of the composer service below $this->composerService = $composerService; @@ -266,14 +276,32 @@ public function apiInstall(Request $request) $pluginCode = $request->get('pluginCode'); - $log = null; - try { - $log = $this->composerService->execRequire('ec-cube/'.$pluginCode); - - return $this->json(['success' => true, 'log' => $log]); - } catch (\Exception $e) { - $log = $e->getMessage(); - log_error($e); + $errors = $this->validator->validate( + $pluginCode, + [ + new Assert\NotBlank(), + new Assert\Regex( + [ + 'pattern' => '/^[a-zA-Z0-9_]+$/', + ] + ), + ] + ); + + if ($errors->count() != 0) { + $log = []; + foreach ($errors as $error) { + $log[] = $error->getMessage(); + } + } else { + try { + $log = $this->composerService->execRequire('ec-cube/'.$pluginCode); + + return $this->json(['success' => true, 'log' => $log]); + } catch (\Exception $e) { + $log = $e->getMessage(); + log_error($e); + } } return $this->json(['success' => false, 'log' => $log], 500); @@ -350,14 +378,53 @@ public function apiUpgrade(Request $request) $pluginCode = $request->get('pluginCode'); $version = $request->get('version'); - $log = null; - try { - $log = $this->composerService->execRequire('ec-cube/'.$pluginCode.':'.$version); + $log = []; + + $errors = $this->validator->validate( + $pluginCode, + [ + new Assert\NotBlank(), + new Assert\Regex( + [ + 'pattern' => '/^[a-zA-Z0-9_]+$/', + ] + ), + ] + ); + + if ($errors->count() != 0) { + foreach ($errors as $error) { + $log[] = $error->getMessage(); + } + } - return $this->json(['success' => true, 'log' => $log]); - } catch (\Exception $e) { - $log = $e->getMessage(); - log_error($e); + $errors = $this->validator->validate( + $version, + [ + new Assert\NotBlank(), + new Assert\Regex( + [ + 'pattern' => '/^[0-9.]+$/', + ] + ), + ] + ); + + if ($errors->count() != 0) { + foreach ($errors as $error) { + $log[] = $error->getMessage(); + } + } + + if (empty($log)) { + try { + $log = $this->composerService->execRequire('ec-cube/'.$pluginCode.':'.$version); + + return $this->json(['success' => true, 'log' => $log]); + } catch (\Exception $e) { + $log = $e->getMessage(); + log_error($e); + } } return $this->json(['success' => false, 'log' => $log], 500); diff --git a/tests/Eccube/Tests/Service/CsvImportServiceTest.php b/tests/Eccube/Tests/Service/CsvImportServiceTest.php index 36b5e625437..c137733b6d3 100644 --- a/tests/Eccube/Tests/Service/CsvImportServiceTest.php +++ b/tests/Eccube/Tests/Service/CsvImportServiceTest.php @@ -94,6 +94,10 @@ public function testReadCsvFileWithTrailingBlankLines() $CsvImportService->setColumnHeaders(['id', 'number', 'description']); foreach ($CsvImportService as $row) { + if (empty(array_filter($row))) { + continue; + } + $this->assertNotNull($row['id']); $this->assertNotNull($row['number']); $this->assertNotNull($row['description']); diff --git a/tests/Eccube/Tests/Web/Admin/Store/PluginControllerTest.php b/tests/Eccube/Tests/Web/Admin/Store/PluginControllerTest.php index d12df535949..2ffca3625c3 100644 --- a/tests/Eccube/Tests/Web/Admin/Store/PluginControllerTest.php +++ b/tests/Eccube/Tests/Web/Admin/Store/PluginControllerTest.php @@ -50,4 +50,85 @@ public function testSubmit() $this->actual = $this->container->get(BaseInfoRepository::class)->get()->getPhpPath(); $this->verify(); } + + /** + * 異常系を確認。正常系のインストールはE2Eテストの方で実施 + * + * @dataProvider OwnerStoreInstallParam + * + */ + public function testFailureInstall($param1, $param2, $message) + { + $form = [ + 'pluginCode' => $param1, + 'version' => $param2, + ]; + + $crawler = $this->client->request('POST', + $this->generateUrl('admin_store_plugin_api_install', $form), + [], + [], + [ + 'HTTP_X-Requested-With' => 'XMLHttpRequest', + 'CONTENT_TYPE' => 'application/json', + ] + ); + // ダウンロードできないことを確認 + $this->assertEquals(500, $this->client->getResponse()->getStatusCode()); + // ログを確認 + $this->assertContains($message, json_decode($this->client->getResponse()->getContent())->log); + } + + /** + * 異常系を確認。正常系のアップデートはE2Eテストの方で実施 + * + * @dataProvider OwnerStoreUpgradeParam + * + */ + public function testFailureUpgrade($param1, $param2, $message) + { + $form = [ + 'pluginCode' => $param1, + 'version' => $param2, + ]; + + $crawler = $this->client->request('POST', + $this->generateUrl('admin_store_plugin_api_upgrade', $form), + [], + [], + [ + 'HTTP_X-Requested-With' => 'XMLHttpRequest', + 'CONTENT_TYPE' => 'application/json', + ] + ); + // ダウンロードできないことを確認 + $this->assertEquals(500, $this->client->getResponse()->getStatusCode()); + + // ログを確認 + $this->assertTrue(strpos(implode(',', json_decode($this->client->getResponse()->getContent())->log), $message) !== false); + } + + /** + * 異常系のテストケース + */ + public function OwnerStoreInstallParam() + { + return [ + ['api+symfony/yaml:5.3', '2.1.3', '有効な値ではありません。'], + ['', '2.1.3','入力されていません。'], + ]; + } + + /** + * 異常系のテストケース + */ + public function OwnerStoreUpgradeParam() + { + return [ + ['api+symfony/yaml:5.3', '2.1.3', '有効な値ではありません。'], + ['api', '2.1.3+symfony/yaml:5.3', '有効な値ではありません。'], + ['', '2.1.3','入力されていません。'], + ['api', '','入力されていません。'], + ]; + } }