Skip to content

Commit a7650e4

Browse files
committed
Custom header support
Resolves #12
1 parent 50f61a1 commit a7650e4

File tree

10 files changed

+120
-3
lines changed

10 files changed

+120
-3
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Release Notes for Webhooks for Craft CMS
22

3+
## Unreleased
4+
5+
### Added
6+
- Webhooks can now specify custom request headers. ([#12](https://github.com/craftcms/webhooks/issues/12))
7+
38
## 2.1.0 - 2019-07-26
49

510
### Added

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,18 @@ class ArticleFilter implements FilterInterface
132132
}
133133
```
134134

135+
#### Sending Custom Headers
136+
137+
You can send custom headers along with webhook requests using the Custom Headers setting.
138+
139+
<img src="./images/custom-headers.png" width="696" height="292" alt="Screenshot of the Custom Headers setting">
140+
141+
Header values can be set to an environment variable using the `$VARIABLE_NAME` syntax, or a Twig template.
142+
143+
An `event` variable will be available to the Twig template, set to the event that triggered the webhook.
144+
145+
You can have multiple headers that have the same name, and if a header value takes up multiple lines (after any empty lines have been discarded), each line will be sent as its own header, all using the same header name.
146+
135147
#### Sending More Data
136148

137149
If you need more data than what’s in the default POST request payload, you can fill in the “Extra User Attributes”, “Extra Sender Attributes”, and “Extra Event Attributes” fields.

images/custom-headers.png

17.4 KB
Loading

src/Plugin.php

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ class Plugin extends \craft\base\Plugin
7979
/**
8080
* @inheritdoc
8181
*/
82-
public $schemaVersion = '2.1.0';
82+
public $schemaVersion = '2.2.0';
8383

8484
// Public Methods
8585
// =========================================================================
@@ -118,10 +118,12 @@ public function init()
118118
}
119119
}
120120

121+
$view = Craft::$app->getView();
122+
121123
if ($webhook->method === 'post') {
122124
// Build out the body data
123125
if ($webhook->payloadTemplate) {
124-
$json = Craft::$app->getView()->renderString($webhook->payloadTemplate, [
126+
$json = $view->renderString($webhook->payloadTemplate, [
125127
'event' => $e,
126128
]);
127129
$data = Json::decodeIfJson($json);
@@ -147,15 +149,39 @@ public function init()
147149
}
148150
}
149151

150-
// Queue the send request up
152+
// Set the headers and body
151153
$headers = [];
154+
155+
foreach ($webhook->headers as $header) {
156+
$header['value'] = Craft::parseEnv($header['value']);
157+
if (strpos($header['value'], '{') !== false) {
158+
$header['value'] = $view->renderString($header['value'], [
159+
'event' => $e,
160+
]);
161+
}
162+
// Get the trimmed lines
163+
$lines = array_filter(array_map('trim', preg_split('/[\r\n]+/', $header['value'])));
164+
// Add to the header array one-by-one, ensuring that we don't overwrite existing values
165+
foreach ($lines as $line) {
166+
if (!isset($headers[$header['name']])) {
167+
$headers[$header['name']] = $line;
168+
} else {
169+
if (!is_array($headers[$header['name']])) {
170+
$headers[$header['name']] = [$headers[$header['name']]];
171+
}
172+
$headers[$header['name']][] = $line;
173+
}
174+
}
175+
}
176+
152177
if (isset($data) && is_array($data)) {
153178
$body = Json::encode($data);
154179
$headers['Content-Type'] = 'application/json';
155180
} else {
156181
$body = $data ?? null;
157182
}
158183

184+
// Queue the send request up
159185
$this->request($webhook->method, $webhook->url, $headers, $body, $webhook->id);
160186
});
161187
}

src/Webhook.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ class Webhook extends Model
6262
*/
6363
public $url;
6464

65+
/**
66+
* @var array
67+
*/
68+
public $headers = [];
69+
6570
/**
6671
* @var string|null
6772
*/
@@ -162,6 +167,12 @@ function() {
162167
}
163168
}
164169
],
170+
[
171+
['headers'],
172+
function() {
173+
$this->headers = $this->headers ? array_values($this->headers) : [];
174+
}
175+
],
165176
[['userAttributes', 'senderAttributes'], 'validateAttributeList'],
166177
[['eventAttributes'], 'validateAttributeList', 'params' => ['regex' => '/^[a-z]\w*\.[a-z]\w*(?:\.[a-z]\w*)*$/i']],
167178
[['payloadTemplate'], 'validatePayloadTemplate'],

src/WebhookManager.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ public function saveWebhook(Webhook $webhook, bool $runValidation = true): bool
200200
'filters' => $webhook->filters ? Json::encode($webhook->filters) : null,
201201
'method' => $webhook->method,
202202
'url' => $webhook->url,
203+
'headers' => $webhook->headers ? Json::encode($webhook->headers) : null,
203204
'userAttributes' => $webhook->userAttributes,
204205
'senderAttributes' => $webhook->senderAttributes,
205206
'eventAttributes' => $webhook->eventAttributes,
@@ -248,6 +249,7 @@ private function _createWebhookQuery(): Query
248249
'filters',
249250
'method',
250251
'url',
252+
'headers',
251253
'userAttributes',
252254
'senderAttributes',
253255
'eventAttributes',
@@ -273,6 +275,12 @@ private function _createWebhook(array $result, bool $isMysql = null): Webhook
273275
$result['filters'] = [];
274276
}
275277

278+
if ($result['headers']) {
279+
$result['headers'] = Json::decode($result['headers']);
280+
} else {
281+
$result['headers'] = [];
282+
}
283+
276284
return new Webhook($result);
277285
}
278286

src/migrations/Install.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public function safeUp()
3636
'filters' => $this->text(),
3737
'method' => $this->string(10)->notNull(),
3838
'url' => $this->string()->notNull(),
39+
'headers' => $this->text(),
3940
'userAttributes' => $this->text(),
4041
'senderAttributes' => $this->text(),
4142
'eventAttributes' => $this->text(),
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
namespace craft\webhooks\migrations;
4+
5+
use Craft;
6+
use craft\db\Migration;
7+
8+
/**
9+
* m190724_202705_custom_headers migration.
10+
*/
11+
class m190724_202705_custom_headers extends Migration
12+
{
13+
/**
14+
* @inheritdoc
15+
*/
16+
public function safeUp()
17+
{
18+
$this->addColumn('{{%webhooks}}', 'headers', $this->text()->after('url'));
19+
}
20+
21+
/**
22+
* @inheritdoc
23+
*/
24+
public function safeDown()
25+
{
26+
echo "m190724_202705_custom_headers cannot be reverted.\n";
27+
return false;
28+
}
29+
}

src/records/Webhook.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* @property string|null $filters
1515
* @property string $event
1616
* @property string $url
17+
* @property string|null $headers
1718
* @property string|null $userAttributes
1819
* @property string|null $senderAttributes
1920
* @property string|null $eventAttributes

src/templates/_manage/edit.html

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,30 @@
131131
errors: webhook.getErrors('url')
132132
}, urlInput) }}
133133

134+
{{ forms.editableTableField({
135+
id: 'headers',
136+
name: 'headers',
137+
label: 'Custom Headers'|t('webhooks'),
138+
instructions: 'Any custom headers that should be sent.'|t('webhooks'),
139+
cols: {
140+
name: {
141+
heading: 'Name'|t('webhooks'),
142+
type: 'singleline',
143+
code: true,
144+
placeholder: 'X-Foo-Bar',
145+
},
146+
value: {
147+
heading: 'Value'|t('webhooks'),
148+
info: 'Can be set to an environment variable (`$VARIABLE_NAME`) or Twig code.'|t('webhooks'),
149+
type: 'multiline',
150+
code: true,
151+
placeholder: '{{ event.sender.fooBar }}',
152+
}
153+
},
154+
rows: webhook.headers,
155+
addRowLabel: 'Add a header'|t('webhooks'),
156+
}) }}
157+
134158
<div id="method-settings--post" {% if webhook.method == 'get' %}class="hidden"{% endif %}>
135159

136160
<hr>

0 commit comments

Comments
 (0)