Skip to content

Commit

Permalink
feat: [MINT-2723] integration onboarding steps (#146)
Browse files Browse the repository at this point in the history
* feat: [MINT-2723] integration onboarding steps

* [MINT-2723] update tests

* auto-changelog

---------

Co-authored-by: magento-bot <magento-bot@extend.com>
  • Loading branch information
jomarsantos and magento-bot authored Oct 16, 2024
1 parent 53e9cac commit 7e7fabc
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 18 deletions.
70 changes: 69 additions & 1 deletion Block/Adminhtml/Integration/Edit/Tab/HowToActivate.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,17 @@ class HowToActivate extends Field
* @var string
*/
protected $_template = 'Extend_Integration::system/config/how-to-activate.phtml';
// TODO: MINT-2855 Switch to the following template instead of the one above
// protected $_template = 'Extend_Integration::system/config/integration-status.phtml';
private Environment $environment;
private IntegrationServiceInterface $integrationService;
private Context $context;
private AccessTokenBuilder $accessTokenBuilder;
private $stepMap = [
0 => 'activation_required',
1 => 'identity_link_required',
2 => 'complete'
];

/**
* Intro constructor
Expand Down Expand Up @@ -75,14 +82,40 @@ protected function _getElementHtml(AbstractElement $element): string
*/
public function getIntegrations()
{
$urlBuilder = $this->context->getUrlBuilder();
$integrationsStatuses = [];
$environmentOptions = $this->environment->toOptionArray();
if ($environmentOptions) {
foreach ($environmentOptions as $environmentOption) {
$integration = $this->integrationService->get($environmentOption['value']);

$identityLinkUrl = $integration->getIdentityLinkUrl() . '?oauth_consumer_key=' . $integration->getConsumerKey() . '&success_call_back=' . $urlBuilder->getCurrentUrl();;
$isAuthHandshakeComplete = $this->isAuthHandshakeComplete($integration);
$isIdentityLinkConfirmed = $this->isIdentityLinkConfirmed($integration);
$isIntegrationComplete = $isAuthHandshakeComplete && $isIdentityLinkConfirmed;

$integrationCreatedAt = $integration->getCreatedAt();
$integrationUpdatedAt = $integration->getUpdatedAt();

$oauthActivatedAt = $isAuthHandshakeComplete && $integrationUpdatedAt > $integrationCreatedAt ? $integrationUpdatedAt : null;

$prevActivationFailed = !$isAuthHandshakeComplete && $integrationUpdatedAt > $integrationCreatedAt;

$currentStep = $this->stepMap[0];
if ($isIntegrationComplete) {
$currentStep = $this->stepMap[2];
} elseif ($isAuthHandshakeComplete) {
$currentStep = $this->stepMap[1];
}

$integrationsStatuses[] = [
'activation_status' => $this->getStatus($integration), // TODO: MINT-2855 Remove the activation status as this was only used by old template
'current_step' => $currentStep,
'identity_link_url' => $identityLinkUrl,
'integration_id' => $integration->getId(),
'activation_status' => $this->getStatus($integration)
'integration_name' => $environmentOption['label'],
'oauth_activated_at' => $oauthActivatedAt,
'prev_activation_failed' => $prevActivationFailed
];
}
}
Expand Down Expand Up @@ -114,4 +147,39 @@ private function getStatus($integration)
}

}

/**
* Determines whether the integration has successfully performed the oauth handshake with Extend.
* This is performed after the merchant clicks on Activate on the Magento Integrations page for
* the Extend integration.
*
* @param \Magento\Integration\Model\Integration $integration
* @return bool
*/
private function isAuthHandshakeComplete($integration): bool
{
$integrationStatus = $integration->getStatus();

return $integrationStatus === 1;
}

/**
* Determines whether the merchant has completed the identity link handshake with Extend.
* This is performed when the identity link pops up to the Merchant Portal and the merchant
* successfully connects their Extend account to their Magento instance.
*
* @param \Magento\Integration\Model\Integration $integration
* @return bool
*/
private function isIdentityLinkConfirmed($integration): bool
{
$clientData = $this->accessTokenBuilder->getExtendOAuthClientData($integration->getId());

if (isset($clientData['clientId']) && isset($clientData['clientSecret'])
) {
return true;
} else {
return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ class HowToActivateTest extends TestCase
*/
private HowToActivate $howToActivate;

/**
* @var \Magento\Framework\Url&\PHPUnit\Framework\MockObject\Stub
*/
private $urlBuilder;

/**
* @var \Magento\Backend\Block\Template\Context|\PHPUnit\Framework\MockObject\Stub
*/
Expand Down Expand Up @@ -63,9 +68,24 @@ class HowToActivateTest extends TestCase
*/
private $accessTokenBuilder;

private $callbackUrl = 'https://magento-instance.com/admin';

private $integration1OauthClientData = [
'clientId' => '89rjh89tyrhug3897y',
'clientSecret' => 'fbhn39ry34rhfsdfi98',
];

private $integration2OauthClientData = [
'clientId' => null,
'clientSecret' => null,
];

public function setUp(): void
{
$this->urlBuilder = $this->createMock(\Magento\Framework\Url::class);
$this->urlBuilder->method('getCurrentUrl')->willReturn($this->callbackUrl);
$this->context = $this->createStub(\Magento\Backend\Block\Template\Context::class);
$this->context->method('getUrlBuilder')->willReturn($this->urlBuilder);
$this->environment = $this->createMock(Environment::class);
$this->integrationService = $this->createMock(IntegrationServiceInterface::class);
$this->accessTokenBuilder = $this->createMock(AccessTokenBuilder::class);
Expand All @@ -83,20 +103,50 @@ public function setUp(): void
['value' => 1, 'label' => 'Extend Integration - Prod'],
['value' => 2, 'label' => 'Extend Integration - Demo'],
];

$this->integrationModel1 = $this->createConfiguredMock(\Magento\Integration\Model\Integration::class, [
'getId' => 1,
'getStatus' => 1
]);

$this->integrationModel2 = $this->createConfiguredMock(\Magento\Integration\Model\Integration::class, [
'getId' => 2,
'getStatus' => 0
]);
$this->integrationModel1 = $this->getMockBuilder(\Magento\Integration\Model\Integration::class)
->addMethods(
['getIdentityLinkUrl', 'getConsumerKey']
)
->onlyMethods(['getId', 'getStatus'])
->disableOriginalConstructor()
->getMock();
$this->integrationModel1->method('getId')->willReturn(1);
$this->integrationModel1->method('getStatus')->willReturn(1);
$this->integrationModel1->method('getIdentityLinkUrl')->willReturn('https://merchants.extend.com/magento');
$this->integrationModel1->method('getConsumerKey')->willReturn('prodConsumerKey');

$this->integrationModel2 = $this->getMockBuilder(\Magento\Integration\Model\Integration::class)
->addMethods(
['getIdentityLinkUrl', 'getConsumerKey']
)
->onlyMethods(['getId', 'getStatus'])
->disableOriginalConstructor()
->getMock();
$this->integrationModel2->method('getId')->willReturn(2);
$this->integrationModel2->method('getStatus')->willReturn(0);
$this->integrationModel2->method('getIdentityLinkUrl')->willReturn('https://merchants.demo.extend.com/magento');
$this->integrationModel2->method('getConsumerKey')->willReturn('demoConsumerKey');

$this->activationStatusData = [
['integration_id' => 1, 'activation_status' => 1],
['integration_id' => 2, 'activation_status' => 0]
[
'integration_id' => 1,
'activation_status' => 1,
'current_step' => 'complete',
'identity_link_url' => 'https://merchants.extend.com/magento?oauth_consumer_key=prodConsumerKey&success_call_back='.$this->callbackUrl,
'integration_name' => 'Extend Integration - Prod',
'oauth_activated_at' => null,
'prev_activation_failed' => false,
],
[
'integration_id' => 2,
'activation_status' => 0,
'current_step' => 'activation_required',
'identity_link_url' => 'https://merchants.demo.extend.com/magento?oauth_consumer_key=demoConsumerKey&success_call_back='.$this->callbackUrl,
'integration_name' => 'Extend Integration - Demo',
'oauth_activated_at' => null,
'prev_activation_failed' => false,
],
];
}

Expand All @@ -113,10 +163,15 @@ public function testGetIntegrations()
$this->integrationService->expects($this->exactly(2))->method('get')
->willReturnOnConsecutiveCalls($this->integrationModel1, $this->integrationModel2);

$this->accessTokenBuilder->expects(($this->exactly(2)))
->method('getExtendOAuthClientData')
->willReturnOnConsecutiveCalls(['clientId' => '89rjh89tyrhug3897y', 'clientSecret' => 'fbhn39ry34rhfsdfi98'], ['clientId' => null, 'clientSecret' => null]);
$this->accessTokenBuilder->expects(($this->exactly(4)))
->method('getExtendOAuthClientData')
->willReturnOnConsecutiveCalls(
$this->integration1OauthClientData,
$this->integration1OauthClientData,
$this->integration2OauthClientData,
$this->integration2OauthClientData,
);

$this->assertEquals($this->howToActivate->getIntegrations(), $this->activationStatusData);
}
}
}
6 changes: 4 additions & 2 deletions view/adminhtml/web/js/config/activation-status.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ define([], function () {
if (found) return new Date(found)

// If there is no localStorage, we can leverage the the date of when the integration was activated
if (integration.oauthActivatedAt)
return new Date(integration.oauthActivatedAt)
// Since this is set by the server, it will be coming through as UTC
if (integration.oauthActivatedAt) {
return new Date(`${integration.oauthActivatedAt}Z`)
}

return null
}
Expand Down

0 comments on commit 7e7fabc

Please sign in to comment.