Skip to content

Commit f590692

Browse files
committed
Merge branch 'release/1.1.0'
2 parents 78ab252 + 09eb0e2 commit f590692

File tree

13 files changed

+274
-73
lines changed

13 files changed

+274
-73
lines changed

CHANGELOG.md

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

3+
## 1.1.0 - 2018-12-13
4+
5+
### Added
6+
- Added support for webhooks that send GET requests.
7+
- Webhook names and group names can now contain emojis, even if using MySQL.
8+
- Typing `->` or `=>` into a webhook’s Name field now creates a ➡️.
9+
310
## 1.0.1 - 2018-12-13
411

512
### Fixed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<h1 align="center">Webhooks for Craft CMS</h1>
44

5-
This plugin adds the ability to manage “webhooks” in Craft CMS, which will create POST requests when certain events occur.
5+
This plugin adds the ability to manage “webhooks” in Craft CMS, which will send GET or POST requests when certain events occur.
66

77
It can be used to integrate your Craft project with task automation tools like [Zapier](https://zapier.com) and [IFTTT](https://ifttt.com).
88

@@ -55,7 +55,7 @@ See [Integrating with Task Automation Tools](#integrating-with-task-automation-t
5555

5656
![Screenshot of the Edit Webhook page](./screenshot.png)
5757

58-
Webhooks will send a POST request with a JSON body, containing the following keys:
58+
Webhooks can either send a GET request, or a POST request with a JSON body containing the following keys:
5959

6060
- `time` – an ISO-8601-formatted timestamp of the exact moment the event was triggered. (Webhooks are sent via the queue so there will be a slight delay between the time the event was triggered and the webhook was sent.)
6161
- `user` – an object representing the logged-in user at the time the event was triggered.
@@ -67,7 +67,7 @@ Webhooks will send a POST request with a JSON body, containing the following key
6767

6868
#### Sending More Data
6969

70-
If you need more data than what’s in the default payload, you can fill in the “Extra User Attributes”, “Extra Sender Attributes”, and “Extra Event Attributes” fields.
70+
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.
7171

7272
The attributes listed here (separated by newlines) will be passed to the `$extraFields` argument of the user/sender/event-property’s [toArray()](https://www.yiiframework.com/doc/api/2.0/yii-base-arrayabletrait#toArray()-detail) method (if it has one).
7373

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "craftcms/webhooks",
33
"description": "Post webhooks when events are triggered in Craft CMS.",
4-
"version": "1.0.1",
4+
"version": "1.1.0",
55
"type": "craft-plugin",
66
"keywords": [
77
"html",

src/Plugin.php

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ class Plugin extends \craft\base\Plugin
2828
*/
2929
public $hasCpSection = true;
3030

31+
/**
32+
* @inheritdoc
33+
*/
34+
public $schemaVersion = '1.1.0';
35+
3136
// Public Methods
3237
// =========================================================================
3338

@@ -47,25 +52,35 @@ public function init()
4752
$this->set('webhookManager', $manager);
4853

4954
// Register webhook events
50-
foreach ($manager->getEnabledWebhooks() as $webhook) {
55+
try {
56+
$webhooks = $manager->getEnabledWebhooks();
57+
} catch (\Throwable $e) {
58+
Craft::error('Unable to fetch enabled webhooks: ' . $e->getMessage(), __METHOD__);
59+
Craft::$app->getErrorHandler()->logException($e);
60+
$webhooks = [];
61+
}
62+
63+
foreach ($webhooks as $webhook) {
5164
Event::on($webhook->class, $webhook->event, function(Event $e) use ($webhook) {
52-
// Build out the body data
53-
$user = Craft::$app->getUser()->getIdentity();
54-
$data = [
55-
'time' => (new \DateTime())->format(\DateTime::ATOM),
56-
'user' => $user ? $this->toArray($user, $webhook->getUserAttributes()) : null,
57-
'name' => $e->name,
58-
'senderClass' => get_class($e->sender),
59-
'sender' => $this->toArray($e->sender, $webhook->getSenderAttributes()),
60-
'eventClass' => get_class($e),
61-
'event' => [],
62-
];
63-
64-
$eventAttributes = $webhook->getEventAttributes();
65-
foreach ((new \ReflectionObject($e))->getProperties() as $property) {
66-
if ($property->isPublic() && $property->getDeclaringClass()->getName() !== Event::class) {
67-
$name = $property->getName();
68-
$data['event'][$name] = $this->toArray($e->$name, $eventAttributes[$name] ?? []);
65+
if ($webhook->type === 'post') {
66+
// Build out the body data
67+
$user = Craft::$app->getUser()->getIdentity();
68+
$data = [
69+
'time' => (new \DateTime())->format(\DateTime::ATOM),
70+
'user' => $user ? $this->toArray($user, $webhook->getUserAttributes()) : null,
71+
'name' => $e->name,
72+
'senderClass' => get_class($e->sender),
73+
'sender' => $this->toArray($e->sender, $webhook->getSenderAttributes()),
74+
'eventClass' => get_class($e),
75+
'event' => [],
76+
];
77+
78+
$eventAttributes = $webhook->getEventAttributes();
79+
foreach ((new \ReflectionObject($e))->getProperties() as $property) {
80+
if ($property->isPublic() && $property->getDeclaringClass()->getName() !== Event::class) {
81+
$name = $property->getName();
82+
$data['event'][$name] = $this->toArray($e->$name, $eventAttributes[$name] ?? []);
83+
}
6984
}
7085
}
7186

@@ -74,8 +89,9 @@ public function init()
7489
'description' => Craft::t('webhooks', 'Sending webhook “{name}”', [
7590
'name' => $webhook->name,
7691
]),
92+
'type' => $webhook->type,
7793
'url' => $webhook->url,
78-
'data' => $data,
94+
'data' => $data ?? null,
7995
]));
8096
});
8197
}

src/SendWebhookJob.php

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,18 @@
1414
*/
1515
class SendWebhookJob extends BaseJob
1616
{
17+
/**
18+
* @var string The request type ('get' or 'post')
19+
*/
20+
public $type = 'post';
21+
1722
/**
1823
* @var string The URL to send a request to
1924
*/
2025
public $url;
2126

2227
/**
23-
* @var array The data to send in the request
28+
* @var array|null The data to send in the request
2429
*/
2530
public $data;
2631

@@ -37,9 +42,12 @@ public function defaultDescription()
3742
*/
3843
public function execute($queue)
3944
{
45+
$options = [];
46+
if ($this->type === 'post' && $this->data !== null) {
47+
$options[RequestOptions::JSON] = $this->data;
48+
}
49+
4050
$client = Craft::createGuzzleClient();
41-
$client->post($this->url, [
42-
RequestOptions::JSON => $this->data,
43-
]);
51+
$client->request($this->type, $this->url, $options);
4452
}
4553
}

src/Webhook.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ class Webhook extends Model
4646
*/
4747
public $event;
4848

49+
/**
50+
* @var string
51+
*/
52+
public $type = 'post';
53+
4954
/**
5055
* @var string
5156
*/
@@ -80,10 +85,11 @@ public function rules()
8085
return trim($value, ' \\');
8186
}, 'skipOnArray' => true
8287
],
83-
[['name', 'class', 'event', 'url'], 'required'],
88+
[['name', 'class', 'event', 'type', 'url'], 'required'],
8489
[['name'], UniqueValidator::class, 'targetClass' => WebhookRecord::class],
8590
[['groupId'], 'number'],
8691
[['enabled'], 'boolean'],
92+
[['type'], 'in', 'range' => ['get', 'post']],
8793
[['url'], 'url'],
8894
[
8995
['class'],

src/WebhookManager.php

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

55
use Craft;
66
use craft\db\Query;
7+
use craft\helpers\StringHelper;
78
use yii\base\InvalidArgumentException;
89

910
/**
@@ -31,8 +32,13 @@ public function getAllGroups(): array
3132
->all();
3233

3334
$groups = [];
35+
$isMysql = Craft::$app->getDb()->getIsMysql();
3436

3537
foreach ($results as $result) {
38+
if ($isMysql) {
39+
$result['name'] = html_entity_decode($result['name'], ENT_QUOTES | ENT_HTML5);
40+
}
41+
3642
$groups[] = new Group($result);
3743
}
3844

@@ -55,18 +61,24 @@ public function saveGroup(Group $group, bool $runValidation = true): bool
5561

5662
$db = Craft::$app->getDb();
5763

64+
if ($db->getIsMysql()) {
65+
$name = StringHelper::encodeMb4($group->name);
66+
} else {
67+
$name = $group->name;
68+
}
69+
5870
if ($group->id) {
5971
$db->createCommand()
6072
->update('{{%webhookgroups}}', [
61-
'name' => $group->name,
73+
'name' => $name,
6274
], [
6375
'id' => $group->id,
6476
])
6577
->execute();
6678
} else {
6779
$db->createCommand()
6880
->insert('{{%webhookgroups}}', [
69-
'name' => $group->name,
81+
'name' => $name,
7082
])
7183
->execute();
7284

@@ -153,7 +165,7 @@ public function getWebhookById(int $id): Webhook
153165
throw new InvalidArgumentException('Invalid webhook ID: ' . $id);
154166
}
155167

156-
return new Webhook($result);
168+
return $this->_createWebhook($result);
157169
}
158170

159171
/**
@@ -170,20 +182,27 @@ public function saveWebhook(Webhook $webhook, bool $runValidation = true): bool
170182
return false;
171183
}
172184

185+
$db = Craft::$app->getDb();
186+
187+
if ($db->getIsMysql()) {
188+
$name = StringHelper::encodeMb4($webhook->name);
189+
} else {
190+
$name = $webhook->name;
191+
}
192+
173193
$data = [
174194
'groupId' => $webhook->groupId,
175195
'enabled' => (bool)$webhook->enabled,
176-
'name' => $webhook->name,
196+
'name' => $name,
177197
'class' => $webhook->class,
178198
'event' => $webhook->event,
199+
'type' => $webhook->type,
179200
'url' => $webhook->url,
180201
'userAttributes' => $webhook->userAttributes,
181202
'senderAttributes' => $webhook->senderAttributes,
182203
'eventAttributes' => $webhook->eventAttributes,
183204
];
184205

185-
$db = Craft::$app->getDb();
186-
187206
if ($webhook->id) {
188207
$db->createCommand()
189208
->update('{{%webhooks}}', $data, ['id' => $webhook->id])
@@ -216,20 +235,35 @@ public function deleteWebhookById(int $id)
216235
private function _createWebhookQuery(): Query
217236
{
218237
return (new Query())
219-
->select(['id', 'groupId', 'enabled', 'name', 'class', 'event', 'url', 'userAttributes', 'senderAttributes', 'eventAttributes'])
238+
->select(['id', 'groupId', 'enabled', 'name', 'class', 'event', 'type', 'url', 'userAttributes', 'senderAttributes', 'eventAttributes'])
220239
->from(['{{%webhooks}}']);
221240
}
222241

242+
/**
243+
* @param array $result
244+
* @param bool|null $isMysql
245+
* @return Webhook
246+
*/
247+
private function _createWebhook(array $result, bool $isMysql = null): Webhook
248+
{
249+
if ($isMysql ?? Craft::$app->getDb()->getIsMysql()) {
250+
$result['name'] = html_entity_decode($result['name'], ENT_QUOTES | ENT_HTML5);
251+
}
252+
253+
return new Webhook($result);
254+
}
255+
223256
/**
224257
* @param array
225258
* @return Webhook[]
226259
*/
227260
private function _createWebhooks(array $results): array
228261
{
229262
$webhooks = [];
263+
$isMysql = Craft::$app->getDb()->getIsMysql();
230264

231265
foreach ($results as $result) {
232-
$webhooks[] = new Webhook($result);
266+
$webhooks[] = $this->_createWebhook($result, $isMysql);
233267
}
234268

235269
return $webhooks;

src/assets/edit/EditAsset.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
/**
3+
* @link https://craftcms.com/
4+
* @copyright Copyright (c) Pixel & Tonic, Inc.
5+
* @license MIT
6+
*/
7+
8+
namespace craft\webhooks\assets\edit;
9+
10+
use craft\web\AssetBundle;
11+
use craft\web\assets\cp\CpAsset;
12+
use craft\web\View;
13+
14+
/**
15+
* Webhooks index asset bundle
16+
*
17+
* @author Pixel & Tonic, Inc. <[email protected]>
18+
* @since 1.0
19+
*/
20+
class EditAsset extends AssetBundle
21+
{
22+
public $sourcePath = __DIR__ . '/dist';
23+
24+
public $depends = [
25+
CpAsset::class,
26+
];
27+
28+
public $js = [
29+
'js/EditWebhook.js',
30+
];
31+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
(function($) {
2+
/** global: Craft */
3+
/** global: Garnish */
4+
var EditWebhook = Garnish.Base.extend(
5+
{
6+
$nameInput: null,
7+
8+
init: function() {
9+
this.$nameInput = $('#name');
10+
11+
this.addListener(this.$nameInput, 'change, keyup', 'handleTextChange');
12+
},
13+
14+
handleTextChange: function() {
15+
var input = this.$nameInput.get(0);
16+
17+
// does it look like they just typed -> or => ?
18+
if (typeof input.selectionStart !== 'undefined' && input.selectionStart === input.selectionEnd) {
19+
var pos = input.selectionStart;
20+
var last2 = input.value.substring(pos - 2, pos);
21+
if (last2 === '->' || last2 === '=>') {
22+
input.value = input.value.substring(0, pos - 2) + '➡️' + input.value.substring(pos);
23+
input.setSelectionRange(pos, pos);
24+
}
25+
}
26+
}
27+
})
28+
29+
30+
Garnish.$doc.ready(function() {
31+
new EditWebhook();
32+
});
33+
})(jQuery);

src/controllers/WebhooksController.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Craft;
66
use craft\helpers\UrlHelper;
77
use craft\web\Controller as BaseController;
8+
use craft\webhooks\assets\edit\EditAsset;
89
use craft\webhooks\Plugin;
910
use craft\webhooks\Webhook;
1011
use yii\base\InvalidArgumentException;
@@ -91,6 +92,8 @@ public function actionEdit(int $id = null, int $groupId = null, Webhook $webhook
9192
}
9293
}
9394

95+
Craft::$app->getView()->registerAssetBundle(EditAsset::class);
96+
9497
return $this->renderTemplate('webhooks/_edit', compact(
9598
'groupOptions',
9699
'webhook',

0 commit comments

Comments
 (0)