Skip to content

Commit 53048f4

Browse files
authored
feat: implement core functionality (#8)
* chore: add and use config.factory as a service dependency * feat: basic functionality with all entity types and primary events * feat: allow the selection of the entities and events to fire the webhook - renaming of event constants - valid events as a constant inside OutgoingWebhook service class - avoid instantiating config objects multiple times, cache once the config object inside OutgoingWebhook constructor - reorder secret field inside OutgoingWebhookConfigForm - serialize selected events as a array in the configuration
1 parent 26d9a1f commit 53048f4

File tree

5 files changed

+122
-8
lines changed

5 files changed

+122
-8
lines changed

config/install/http_webhooks.outgoing_config.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ http_webhooks:
22
outgoing:
33
secret: ''
44
url: ''
5+
events: []

http_webhooks.module

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
*/
77

88
use Drupal\Core\Routing\RouteMatchInterface;
9+
use Drupal\Core\Entity\EntityInterface;
10+
use Drupal\http_webhooks\OutgoingWebhook;
911

1012
/**
1113
* Implements hook_help().
@@ -33,3 +35,15 @@ function http_webhooks_theme() {
3335
],
3436
];
3537
}
38+
39+
function http_webhooks_entity_update(EntityInterface $entity) {
40+
\Drupal::service('http_webhooks.outgoing_webhook')->handle_event($entity, OutgoingWebhook::EVENT_UPDATE);
41+
}
42+
43+
function http_webhooks_entity_create(EntityInterface $entity) {
44+
\Drupal::service('http_webhooks.outgoing_webhook')->handle_event($entity, OutgoingWebhook::EVENT_CREATE);
45+
}
46+
47+
function http_webhooks_entity_delete(EntityInterface $entity) {
48+
\Drupal::service('http_webhooks.outgoing_webhook')->handle_event($entity, OutgoingWebhook::EVENT_DELETE);
49+
}

http_webhooks.services.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ services:
44
arguments: ['http_webhooks']
55
http_webhooks.outgoing_webhook:
66
class: Drupal\http_webhooks\OutgoingWebhook
7-
arguments: ['@http_client', '@serialization.json']
7+
arguments: ['@http_client', '@serialization.json', '@config.factory']

src/Form/OutgoingWebhookConfigForm.php

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Drupal\Core\Form\ConfigFormBase;
66
use Drupal\Core\Form\FormStateInterface;
7+
use Drupal\http_webhooks\OutgoingWebhook;
78

89
/**
910
* Class OutgoingWebhookConfigForm.
@@ -26,11 +27,21 @@ public function getFormId() {
2627
return 'outgoing_webhook_config_form';
2728
}
2829

30+
protected function getEventOptions() {
31+
return OutgoingWebhook::VALID_EVENTS;
32+
}
33+
2934
/**
3035
* {@inheritdoc}
3136
*/
3237
public function buildForm(array $form, FormStateInterface $form_state) {
3338
$config = $this->config('http_webhooks.outgoing_config');
39+
$form['url'] = [
40+
'#type' => 'url',
41+
'#title' => $this->t('URL of the webhook'),
42+
'#description' => $this->t('The URL to make the POST request'),
43+
'#default_value' => $config->get('http_webhooks.outgoing.url'),
44+
];
3445
$form['secret'] = [
3546
'#type' => 'password',
3647
'#title' => $this->t('Secret'),
@@ -39,24 +50,49 @@ public function buildForm(array $form, FormStateInterface $form_state) {
3950
'#size' => 64,
4051
'#default_value' => $config->get('http_webhooks.outgoing.secret'),
4152
];
42-
$form['url'] = [
43-
'#type' => 'url',
44-
'#title' => $this->t('URL of the webhook'),
45-
'#description' => $this->t('The URL to make the POST request'),
46-
'#default_value' => $config->get('http_webhooks.outgoing.url'),
53+
$form['events'] = [
54+
'#type' => 'tableselect',
55+
'#header' => array('type' => 'Entity Type' , 'event' => 'Event'),
56+
'#description' => $this->t("The events that will trigger this webhook."),
57+
'#options' => $this->getEventOptions(),
4758
];
59+
$form['events']['#default_value'] = ($config->isNew()
60+
? []
61+
: $this->deSerializeEvents($config->get('http_webhooks.outgoing.events'))
62+
);
4863
return parent::buildForm($form, $form_state);
4964
}
5065

66+
protected function serializeEvents($events) {
67+
return array_filter(array_values($events));
68+
}
69+
70+
protected function deSerializeEvents($events) {
71+
$options = $this->getEventOptions();
72+
$result = \array_reduce(array_keys($options), function($carry, $key) use($events) {
73+
if (in_array($key, $events)) {
74+
$carry[$key] = $key;
75+
} else {
76+
$carry[$key] = 0;
77+
}
78+
return $carry;
79+
}, []);
80+
$result = (object) $result;
81+
return $result;
82+
}
83+
5184
/**
5285
* {@inheritdoc}
5386
*/
5487
public function submitForm(array &$form, FormStateInterface $form_state) {
5588
parent::submitForm($form, $form_state);
5689

90+
$serializedEvents = $this->serializeEvents($form_state->getValue('events'));
91+
5792
$this->config('http_webhooks.outgoing_config')
5893
->set('http_webhooks.outgoing.secret', $form_state->getValue('secret'))
5994
->set('http_webhooks.outgoing.url', $form_state->getValue('url'))
95+
->set('http_webhooks.outgoing.events', $serializedEvents)
6096
->save();
6197
}
6298

src/OutgoingWebhook.php

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,34 @@
11
<?php
22

33
namespace Drupal\http_webhooks;
4-
use GuzzleHttp\ClientInterface;
4+
55
use Drupal\Component\Serialization\SerializationInterface;
6+
use Drupal\Core\Config\ConfigFactoryInterface;
7+
use Drupal\Core\Entity\EntityInterface;
8+
use GuzzleHttp\ClientInterface;
9+
use GuzzleHttp\Exception\RequestException;
10+
use GuzzleHttp\Psr7;
11+
use GuzzleHttp\Psr7\Request;
612

713
/**
814
* Class OutgoingWebhook.
915
*/
1016
class OutgoingWebhook {
17+
const EVENT_CREATE = "create";
18+
const EVENT_UPDATE = "update";
19+
const EVENT_DELETE = "delete";
20+
21+
const VALID_EVENTS = [
22+
'entity:user:create' => ['type' => 'user' , 'event' => 'create'],
23+
'entity:user:update' => ['type' => 'user' , 'event' => 'update'],
24+
'entity:user:delete' => ['type' => 'user' , 'event' => 'delete'],
25+
'entity:node:create' => ['type' => 'node' , 'event' => 'create'],
26+
'entity:node:update' => ['type' => 'node' , 'event' => 'update'],
27+
'entity:node:delete' => ['type' => 'node' , 'event' => 'delete'],
28+
'entity:comment:create' => ['type' => 'node' , 'event' => 'create'],
29+
'entity:node:update' => ['type' => 'node' , 'event' => 'update'],
30+
'entity:node:delete' => ['type' => 'node' , 'event' => 'delete'],
31+
];
1132

1233
/**
1334
* GuzzleHttp\ClientInterface definition.
@@ -23,12 +44,54 @@ class OutgoingWebhook {
2344
*/
2445
protected $serializationJson;
2546

47+
/**
48+
* @var \Drupal\Core\Config\ImmutableConfig
49+
*/
50+
protected $config;
51+
2652
/**
2753
* Constructs a new OutgoingWebhook object.
2854
*/
29-
public function __construct(ClientInterface $http_client, SerializationInterface $serialization_json) {
55+
public function __construct(
56+
ClientInterface $http_client,
57+
SerializationInterface $serialization_json,
58+
ConfigFactoryInterface $config_factory
59+
) {
3060
$this->httpClient = $http_client;
3161
$this->serializationJson = $serialization_json;
62+
$this->config = $config_factory->get('http_webhooks.outgoing_config');
63+
}
64+
65+
public function handle_event(EntityInterface $entity, $event) {
66+
$type = $entity->getEntityTypeId();
67+
$eventString = "entity:$type:$event";
68+
$allowed_events = $this->config->get("http_webhooks.outgoing.events");
69+
70+
// only post for entities and events allowed in the configuration
71+
if (in_array($eventString, $allowed_events)) {
72+
$this->post();
73+
};
74+
}
75+
76+
public function post() {
77+
$secret = $this->config->get('http_webhooks.outgoing.secret');
78+
$url = $this->config->get('http_webhooks.outgoing.url');
79+
if (empty($secret) || empty($url)) {
80+
// TODO: log a error message: these configuration are necessary,
81+
return;
82+
}
83+
84+
try {
85+
$response = $this->httpClient->request('POST', $url, [
86+
'json' => ['secret'=> $secret]
87+
]);
88+
} catch(RequestException $e) {
89+
// TODO: log a error message: the request failed
90+
return;
91+
}
92+
$body = $response->getBody();
93+
// TODO: log a success message with the response payload
94+
3295
}
3396

3497
}

0 commit comments

Comments
 (0)