Skip to content

Commit

Permalink
Merge pull request #10 from craftcms/bugfix/webhook-instructions
Browse files Browse the repository at this point in the history
Webhook Configuration
  • Loading branch information
i-just authored Jun 14, 2024
2 parents dc6aeb6 + f8e29d2 commit d14de28
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 31 deletions.
2 changes: 1 addition & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
src/web/assets/stripecp/dist
composer.lock
README.md
README.md
22 changes: 18 additions & 4 deletions src/Plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -563,15 +563,29 @@ private function handleUserElementChanges(): void
Event::on(User::class, User::EVENT_AFTER_SAVE, function(ModelEvent $event) {
/** @var User|StripeCustomerBehavior $user */
$user = $event->sender;
if (!empty($user->email) && $user->getStripeCustomers()->isEmpty()) {
// search for customer in Stripe by their email address

// Do they have an email at all?
if (empty($user->email)) {
return;
}

// Do we have any existing Stripe customer records for them?
if (!$user->getStripeCustomers()->isEmpty()) {
return;
}

// Search for customer in Stripe by their email address:
try {
// If the plugin isn't configured yet, this may fail:
$stripe = $this->getApi()->getClient();
$stripeCustomers = $stripe->customers->search(['query' => "email:'{$user->email}'"]);
// if we found Stripe customers with that email address - kick off the queue job to sync data

// If we found Stripe customers with that email address, kick off the queue job to sync data:
if (!$stripeCustomers->isEmpty()) {
// sync data via the queue
Queue::push(new SyncData());
}
} catch (\Stripe\Exception\ExceptionInterface $e) {
Craft::error("Tried to synchronize user data, but the plugin was not fully configured: {$e->getMessage()}", 'stripe');
}
});
}
Expand Down
26 changes: 18 additions & 8 deletions src/controllers/WebhooksController.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use Stripe\WebhookEndpoint;
use yii\base\InvalidConfigException;
use yii\web\Response as YiiResponse;
use yii\web\ServerErrorHttpException;

/**
* The WebhooksController handles Stripe webhook event.
Expand All @@ -28,9 +29,20 @@
class WebhooksController extends Controller
{
public $defaultAction = 'handle';
public $enableCsrfValidation = false;
public array|bool|int $allowAnonymous = ['handle'];

/**
* @inheritdoc
*/
public function beforeAction($action): bool
{
// Disable CSRF only for incoming webhooks (to agree with `allowAnonymous`, above):
if ($action->id === 'handle') {
$this->enableCsrfValidation = false;
}

return parent::beforeAction($action);
}
/**
* Handle incoming Stripe webhook event
*
Expand Down Expand Up @@ -82,7 +94,7 @@ public function actionEdit(): YiiResponse
$pluginSettings = $plugin->getSettings();

if (!$pluginSettings->secretKey) {
throw new InvalidConfigException('No Stripe API key found, check credentials in settings.');
throw new ServerErrorHttpException('No Stripe API key found. Make sure you have added one in the plugin’s settings screen.');
}

$webhookInfo = [];
Expand Down Expand Up @@ -125,7 +137,7 @@ public function actionCreate()
$pluginSettings = $plugin->getSettings();

if (!$pluginSettings->secretKey) {
throw new InvalidConfigException('No Stripe API key found, check credentials in settings.');
throw new ServerErrorHttpException('No Stripe API key found, check credentials in settings.');
}

$stripe = $plugin->getApi()->getClient();
Expand Down Expand Up @@ -218,7 +230,7 @@ private function saveWebhookData(Plugin $plugin, Settings $settings, WebhookEndp
$configService->setDotEnvVar('STRIPE_WH_KEY', $response->secret ?? '');
} catch (\Throwable $e) {
$success = false;
Craft::error('Couldn\'t save you Stripe Webhook Signing Secret in the .env file. ' . $e->getMessage());
Craft::error('Couldn\'t save the Stripe Webhook Signing Secret in the .env file. ' . $e->getMessage());
}
$success ? $settings->webhookSigningSecret = '$STRIPE_WH_KEY' : $response->secret;

Expand All @@ -227,15 +239,14 @@ private function saveWebhookData(Plugin $plugin, Settings $settings, WebhookEndp
$configService->setDotEnvVar('STRIPE_WH_ID', $response->id ?? '');
} catch (\Throwable $e) {
$success = false;
Craft::error('Couldn\'t save you Stripe Webhook Id in the .env file. ' . $e->getMessage());
Craft::error('Couldn\'t save the Stripe Webhook ID in the .env file. ' . $e->getMessage());
}
$success ? $settings->webhookId = '$STRIPE_WH_ID' : $response->id;

if (!Craft::$app->getPlugins()->savePluginSettings($plugin, $settings->toArray())) {
Craft::$app->getSession()->setNotice(Craft::t(
'stripe',
'Webhook registered successfully, but we had trouble saving the Webhook Signing Secret.
Please go to your Stripe Dashboard, get the webhook signing secret and add it to your plugin’s settings.')
'Webhook registered successfully, but we had trouble saving the Webhook Signing Secret. Please go to your Stripe Dashboard, get the webhook signing secret and add it to your plugin’s settings.')
);
} else {
$this->setSuccessFlash(Craft::t(
Expand All @@ -251,7 +262,6 @@ private function saveWebhookData(Plugin $plugin, Settings $settings, WebhookEndp
* @param Plugin $plugin
* @param string $webhookId
* @return WebhookEndpoint
* @throws InvalidConfigException
* @throws \Stripe\Exception\ApiErrorException
*/
private function getWebhookInfo(Plugin $plugin, string $webhookId): WebhookEndpoint
Expand Down
40 changes: 22 additions & 18 deletions src/templates/webhooks/_index.twig
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,29 @@

{% block content %}

<h3>{{ "Webhook Management"|t('stripe') }}</h3>
<h2>{{ "Webhook Management"|t('stripe') }}</h2>

<div class="{{ hasWebhook ? 'hidden' : '' }}">
<p>{{ "Create the webhook for the current environment."|t('stripe') }}</p>
{% if not hasWebhook %}
<p>{{ "Create the webhook for the current environment."|t('stripe') }} <a class="go" href="https://github.com/craftcms/stripe#webhooks">{{ 'Learn more'|t('app') }}</a></p>
{% endif %}

{# Divs needed for the Admin Table js below #}
<div class="pane tablepane hairline">
<div id="webhooks-container">
</div>
</div>

{% if not hasWebhook %}
<form method="POST">
{{ actionInput('stripe/webhooks/create') }}
{{ redirectInput('stripe/webhooks') }}
{{ csrfInput() }}
<button class="btn primary" type="submit">{{ "Create"|t('stripe') }}</button>
</form>
</div>
{% endif %}

{# Divs needed for the Admin Table js below #}
<div class="field">
<div id="webhooks-container">
</div>
</div>
{% set tableData = [] %}

{% set tableData = [] %}
{% if webhookInfo is not empty %}
{% set tableData = [{
id: webhookInfo.id,
Expand All @@ -40,11 +44,11 @@

{% js %}
var columns = [
{ name: '__slot:title', title: '{{ 'Topic'|t('stripe') }}' },
{ name: 'apiVersion', title: '{{ 'API Version'|t('stripe') }}' },
{ name: 'livemode', title: '{{ 'Live Mode'|t('stripe') }}' },
{ name: 'whStatus', title: '{{ 'Status'|t('stripe') }}' },
{ name: 'address', title: '{{ 'URL'|t('stripe') }}' },
{ name: '__slot:title', title: '{{ 'Topic'|t('stripe') }}' },
{ name: 'apiVersion', title: '{{ 'API Version'|t('stripe') }}' },
{ name: 'livemode', title: '{{ 'Live Mode'|t('stripe') }}' },
{ name: 'whStatus', title: '{{ 'Status'|t('stripe') }}' },
{ name: 'address', title: '{{ 'URL'|t('stripe') }}' },
];

new Craft.VueAdminTable({
Expand All @@ -57,9 +61,9 @@
deleteSuccessMessage: Craft.t('stripe', "Webhook deleted"),
emptyMessage: Craft.t('stripe', 'No webhooks exist yet.'),
tableData: {{ tableData|json_encode|raw }},
deleteCallback: function(){
window.location.reload(); // We need to reload to get the create button showing again
}
deleteCallback: function() {
window.location.reload(); // We need to reload to get the create button showing again
},
});
{% endjs %}
{% endblock %}
Expand Down

0 comments on commit d14de28

Please sign in to comment.