diff --git a/UPGRADE.md b/UPGRADE.md index cd16285f7..bf7d903c5 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,8 @@ # NEXT +- The Admin API no longer exposes `swag_migration_connection.credentialFields`. Use `GET /api/_action/migration/get-connection-credentials?connectionId=` with `swag_migration.editor` permission to retrieve credentials. +- Supplying replacement `credentialFields` to `POST /api/_action/migration/check-connection` now requires `swag_migration.editor`. Checking stored credentials still requires only `swag_migration.viewer`. + - [BREAKING] [#202](https://github.com/shopware/SwagMigrationAssistant/pull/202) - fix!: replace native time reads with an injected clock - [BREAKING] Added required constructor parameter `Psr\Clock\ClockInterface $clock` to `\SwagMigrationAssistant\Profile\Shopware\Converter\ShippingMethodConverter` - [BREAKING] [#190](https://github.com/shopware/SwagMigrationAssistant/pull/190) - fix!: update product.sales during migration diff --git a/src/Controller/StatusController.php b/src/Controller/StatusController.php index c1a867118..24b2c4055 100644 --- a/src/Controller/StatusController.php +++ b/src/Controller/StatusController.php @@ -7,6 +7,7 @@ namespace SwagMigrationAssistant\Controller; +use Shopware\Core\Framework\Api\ApiException; use Shopware\Core\Framework\Context; use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository; use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria; @@ -179,6 +180,29 @@ public function getGateways(Request $request): JsonResponse return new JsonResponse($gatewayNames); } + #[Route( + path: '/api/_action/migration/get-connection-credentials', + name: 'api.admin.migration.get-connection-credentials', + defaults: [PlatformRequest::ATTRIBUTE_ACL => ['swag_migration.editor']], + methods: [Request::METHOD_GET] + )] + public function getConnectionCredentials(Request $request, Context $context): JsonResponse + { + $connectionId = $request->query->getAlnum('connectionId'); + + if ($connectionId === '') { + throw RoutingException::missingRequestParameter('connectionId'); + } + + $connection = $this->migrationConnectionRepo->search(new Criteria([$connectionId]), $context)->getEntities()->first(); + + if ($connection === null) { + throw MigrationException::noConnectionFound(); + } + + return new JsonResponse($connection->getCredentialFields() ?? [], Response::HTTP_OK, ['Cache-Control' => 'no-store']); + } + #[Route( path: '/api/_action/migration/update-connection-credentials', name: 'api.admin.migration.update-connection-credentials', @@ -303,6 +327,10 @@ public function checkConnection(Request $request, Context $context): JsonRespons $credentialFields = $request->request->all('credentialFields'); if ($credentialFields !== []) { + if (!$context->isAllowed('swag_migration.editor')) { + throw ApiException::missingPrivileges(['swag_migration.editor']); + } + $connection->setCredentialFields($credentialFields); } diff --git a/src/Migration/Connection/SwagMigrationConnectionDefinition.php b/src/Migration/Connection/SwagMigrationConnectionDefinition.php index 41d8e9431..fb95189ba 100644 --- a/src/Migration/Connection/SwagMigrationConnectionDefinition.php +++ b/src/Migration/Connection/SwagMigrationConnectionDefinition.php @@ -9,6 +9,7 @@ use Shopware\Core\Framework\DataAbstractionLayer\EntityDefinition; use Shopware\Core\Framework\DataAbstractionLayer\Field\CreatedAtField; +use Shopware\Core\Framework\DataAbstractionLayer\Field\Flag\ApiAware; use Shopware\Core\Framework\DataAbstractionLayer\Field\Flag\PrimaryKey; use Shopware\Core\Framework\DataAbstractionLayer\Field\Flag\Required; use Shopware\Core\Framework\DataAbstractionLayer\Field\Flag\WriteProtected; @@ -50,7 +51,7 @@ protected function defineFields(): FieldCollection return new FieldCollection([ (new IdField('id', 'id'))->addFlags(new PrimaryKey(), new Required()), (new StringField('name', 'name'))->addFlags(new Required()), - (new JsonField('credential_fields', 'credentialFields'))->addFlags(new WriteProtected(MigrationContext::SOURCE_CONTEXT)), + (new JsonField('credential_fields', 'credentialFields'))->removeFlag(ApiAware::class)->addFlags(new WriteProtected(MigrationContext::SOURCE_CONTEXT)), new PremappingField('premapping', 'premapping'), (new StringField('profile_name', 'profileName'))->addFlags(new Required()), (new StringField('gateway_name', 'gatewayName'))->addFlags(new Required()), diff --git a/src/Resources/app/administration/src/core/service/api/swag-migration.api.service.ts b/src/Resources/app/administration/src/core/service/api/swag-migration.api.service.ts index 4c4833f2b..c646e255c 100644 --- a/src/Resources/app/administration/src/core/service/api/swag-migration.api.service.ts +++ b/src/Resources/app/administration/src/core/service/api/swag-migration.api.service.ts @@ -144,6 +144,21 @@ export default class MigrationApiService extends ApiService { return this.handleResponse(response) as MigrationEnvironmentInformation; } + async getConnectionCredentials( + connectionId: string, + additionalHeaders: AdditionalHeaders = {}, + ): Promise { + const response = await this.apiService.httpClient.get( + this.getActionPath('get-connection-credentials'), + { + params: { connectionId }, + headers: this.getHeaders(additionalHeaders), + }, + ); + + return this.handleResponse(response) as MigrationCredentials; + } + async updateConnectionCredentials( connectionId: string, credentialFields: MigrationCredentials, diff --git a/src/Resources/app/administration/src/module/swag-migration/page/wizard/swag-migration-wizard/index.ts b/src/Resources/app/administration/src/module/swag-migration/page/wizard/swag-migration-wizard/index.ts index b05d399dd..821a88e8e 100644 --- a/src/Resources/app/administration/src/module/swag-migration/page/wizard/swag-migration-wizard/index.ts +++ b/src/Resources/app/administration/src/module/swag-migration/page/wizard/swag-migration-wizard/index.ts @@ -536,24 +536,26 @@ export default Shopware.Component.wrapComponentConfig({ await this.fetchConnection(items.first().selectedConnectionId); }, - fetchConnection(connectionId: string) { - return new Promise((resolve) => { - const criteria = new Criteria(1, 1); - criteria.addFilter(Criteria.equals('id', connectionId)); + async fetchConnection(connectionId: string) { + const criteria = new Criteria(1, 1); + criteria.addFilter(Criteria.equals('id', connectionId)); - this.migrationConnectionRepository.search(criteria, this.context).then((connectionResponse) => { - if (connectionResponse.length === 0 || connectionResponse.first().id === null) { - this.isLoading = false; - this.onNoConnectionSelected(); - resolve(null); - return; - } + try { + const connectionResponse = await this.migrationConnectionRepository.search(criteria, this.context); - this.connection = connectionResponse.first(); - this.isLoading = false; - resolve(null); - }); - }); + if (connectionResponse.length === 0 || connectionResponse.first().id === null) { + this.onNoConnectionSelected(); + return; + } + + const connection = connectionResponse.first(); + connection.credentialFields = await this.migrationApiService.getConnectionCredentials(connection.id); + this.connection = connection; + } catch (error) { + this.onResponseError(error.response.data.errors[0].code); + } finally { + this.isLoading = false; + } }, onNoConnectionSelected() { @@ -625,14 +627,17 @@ export default Shopware.Component.wrapComponentConfig({ setting.selectedConnectionId = connection.id; this.migrationGeneralSettingRepository .save(setting, this.context) - .then(() => { + .then(async () => { + connection.credentialFields = await this.migrationApiService.getConnectionCredentials( + connection.id, + ); this.connection = connection; this.isLoading = false; resolve(null); }) - .catch(() => { + .catch((error) => { this.isLoading = false; - reject(); + reject(error); }); }) .catch(() => { diff --git a/src/Resources/app/administration/src/type/types.d.ts b/src/Resources/app/administration/src/type/types.d.ts index a30fa1476..41fff38bd 100644 --- a/src/Resources/app/administration/src/type/types.d.ts +++ b/src/Resources/app/administration/src/type/types.d.ts @@ -108,7 +108,7 @@ type MigrationConnection = { id: string; profile?: MigrationProfile; gateway?: MigrationGateway; - credentialsFields?: MigrationCredentials; + credentialFields?: MigrationCredentials; }; type MigrationError = { diff --git a/tests/Jest/src/module/swag-migration/page/wizard/swag-migration-wizard.spec.js b/tests/Jest/src/module/swag-migration/page/wizard/swag-migration-wizard.spec.js index d6ef3c183..040dd3586 100644 --- a/tests/Jest/src/module/swag-migration/page/wizard/swag-migration-wizard.spec.js +++ b/tests/Jest/src/module/swag-migration/page/wizard/swag-migration-wizard.spec.js @@ -75,6 +75,7 @@ const migrationApiServiceMock = { getProfiles: jest.fn(() => Promise.resolve([])), getGateways: jest.fn(() => Promise.resolve([])), getEnvironmentInformation: jest.fn(() => Promise.resolve(environementInformationSuccessMock)), + getConnectionCredentials: jest.fn(() => Promise.resolve({ apiKey, apiUser, endpoint })), createNewConnection: jest.fn(() => Promise.resolve(environementInformationSuccessMock)), };