Skip to content

Commit 0470125

Browse files
author
epriestley
committed
Add skeleton code for webhooks
Summary: Ref T11330. Adds general support for webhooks. This is still rough and missing a lot of pieces -- and not yet useful for anything -- but can make HTTP requests. Test Plan: Used `bin/webhook call ...` to complete requests to a test endpoint. Maniphest Tasks: T11330 Differential Revision: https://secure.phabricator.com/D19045
1 parent 9386e43 commit 0470125

34 files changed

+1896
-14
lines changed

bin/webhook

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../scripts/setup/manage_webhook.php
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CREATE TABLE {$NAMESPACE}_herald.herald_webhook (
2+
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
3+
phid VARBINARY(64) NOT NULL,
4+
name VARCHAR(128) NOT NULL COLLATE {$COLLATE_TEXT},
5+
webhookURI VARCHAR(255) NOT NULL COLLATE {$COLLATE_TEXT},
6+
viewPolicy VARBINARY(64) NOT NULL,
7+
editPolicy VARBINARY(64) NOT NULL,
8+
status VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT},
9+
hmacKey VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT},
10+
dateCreated INT UNSIGNED NOT NULL,
11+
dateModified INT UNSIGNED NOT NULL
12+
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
CREATE TABLE {$NAMESPACE}_herald.herald_webhooktransaction (
2+
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
3+
phid VARBINARY(64) NOT NULL,
4+
authorPHID VARBINARY(64) NOT NULL,
5+
objectPHID VARBINARY(64) NOT NULL,
6+
viewPolicy VARBINARY(64) NOT NULL,
7+
editPolicy VARBINARY(64) NOT NULL,
8+
commentPHID VARBINARY(64) DEFAULT NULL,
9+
commentVersion INT UNSIGNED NOT NULL,
10+
transactionType VARCHAR(32) COLLATE {$COLLATE_TEXT} NOT NULL,
11+
oldValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
12+
newValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
13+
contentSource LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
14+
metadata LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
15+
dateCreated INT UNSIGNED NOT NULL,
16+
dateModified INT UNSIGNED NOT NULL,
17+
UNIQUE KEY `key_phid` (`phid`),
18+
KEY `key_object` (`objectPHID`)
19+
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CREATE TABLE {$NAMESPACE}_herald.herald_webhookrequest (
2+
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
3+
phid VARBINARY(64) NOT NULL,
4+
webhookPHID VARBINARY(64) NOT NULL,
5+
objectPHID VARBINARY(64) NOT NULL,
6+
status VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT},
7+
properties LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
8+
lastRequestResult VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT},
9+
lastRequestEpoch INT UNSIGNED NOT NULL,
10+
dateCreated INT UNSIGNED NOT NULL,
11+
dateModified INT UNSIGNED NOT NULL
12+
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

scripts/setup/manage_webhook.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/usr/bin/env php
2+
<?php
3+
4+
$root = dirname(dirname(dirname(__FILE__)));
5+
require_once $root.'/scripts/init/init-script.php';
6+
7+
$args = new PhutilArgumentParser($argv);
8+
$args->setTagline(pht('manage webhooks'));
9+
$args->setSynopsis(<<<EOSYNOPSIS
10+
**webhook** __command__ [__options__]
11+
Manage webhooks.
12+
13+
EOSYNOPSIS
14+
);
15+
$args->parseStandardArguments();
16+
17+
$workflows = id(new PhutilClassMapQuery())
18+
->setAncestorClass('HeraldWebhookManagementWorkflow')
19+
->execute();
20+
$workflows[] = new PhutilHelpArgumentWorkflow();
21+
$args->parseWorkflows($workflows);

src/__phutil_library_map__.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,6 +1364,7 @@
13641364
'HeraldContentSourceField' => 'applications/herald/field/HeraldContentSourceField.php',
13651365
'HeraldController' => 'applications/herald/controller/HeraldController.php',
13661366
'HeraldCoreStateReasons' => 'applications/herald/state/HeraldCoreStateReasons.php',
1367+
'HeraldCreateWebhooksCapability' => 'applications/herald/capability/HeraldCreateWebhooksCapability.php',
13671368
'HeraldDAO' => 'applications/herald/storage/HeraldDAO.php',
13681369
'HeraldDeprecatedFieldGroup' => 'applications/herald/field/HeraldDeprecatedFieldGroup.php',
13691370
'HeraldDifferentialAdapter' => 'applications/differential/herald/HeraldDifferentialAdapter.php',
@@ -1440,6 +1441,30 @@
14401441
'HeraldTranscriptSearchEngine' => 'applications/herald/query/HeraldTranscriptSearchEngine.php',
14411442
'HeraldTranscriptTestCase' => 'applications/herald/storage/__tests__/HeraldTranscriptTestCase.php',
14421443
'HeraldUtilityActionGroup' => 'applications/herald/action/HeraldUtilityActionGroup.php',
1444+
'HeraldWebhook' => 'applications/herald/storage/HeraldWebhook.php',
1445+
'HeraldWebhookCallManagementWorkflow' => 'applications/herald/management/HeraldWebhookCallManagementWorkflow.php',
1446+
'HeraldWebhookController' => 'applications/herald/controller/HeraldWebhookController.php',
1447+
'HeraldWebhookEditController' => 'applications/herald/controller/HeraldWebhookEditController.php',
1448+
'HeraldWebhookEditEngine' => 'applications/herald/editor/HeraldWebhookEditEngine.php',
1449+
'HeraldWebhookEditor' => 'applications/herald/editor/HeraldWebhookEditor.php',
1450+
'HeraldWebhookListController' => 'applications/herald/controller/HeraldWebhookListController.php',
1451+
'HeraldWebhookManagementWorkflow' => 'applications/herald/management/HeraldWebhookManagementWorkflow.php',
1452+
'HeraldWebhookNameTransaction' => 'applications/herald/xaction/HeraldWebhookNameTransaction.php',
1453+
'HeraldWebhookPHIDType' => 'applications/herald/phid/HeraldWebhookPHIDType.php',
1454+
'HeraldWebhookQuery' => 'applications/herald/query/HeraldWebhookQuery.php',
1455+
'HeraldWebhookRequest' => 'applications/herald/storage/HeraldWebhookRequest.php',
1456+
'HeraldWebhookRequestListView' => 'applications/herald/view/HeraldWebhookRequestListView.php',
1457+
'HeraldWebhookRequestPHIDType' => 'applications/herald/phid/HeraldWebhookRequestPHIDType.php',
1458+
'HeraldWebhookRequestQuery' => 'applications/herald/query/HeraldWebhookRequestQuery.php',
1459+
'HeraldWebhookSearchEngine' => 'applications/herald/query/HeraldWebhookSearchEngine.php',
1460+
'HeraldWebhookStatusTransaction' => 'applications/herald/xaction/HeraldWebhookStatusTransaction.php',
1461+
'HeraldWebhookTestController' => 'applications/herald/controller/HeraldWebhookTestController.php',
1462+
'HeraldWebhookTransaction' => 'applications/herald/storage/HeraldWebhookTransaction.php',
1463+
'HeraldWebhookTransactionQuery' => 'applications/herald/query/HeraldWebhookTransactionQuery.php',
1464+
'HeraldWebhookTransactionType' => 'applications/herald/xaction/HeraldWebhookTransactionType.php',
1465+
'HeraldWebhookURITransaction' => 'applications/herald/xaction/HeraldWebhookURITransaction.php',
1466+
'HeraldWebhookViewController' => 'applications/herald/controller/HeraldWebhookViewController.php',
1467+
'HeraldWebhookWorker' => 'applications/herald/worker/HeraldWebhookWorker.php',
14431468
'Javelin' => 'infrastructure/javelin/Javelin.php',
14441469
'LegalpadController' => 'applications/legalpad/controller/LegalpadController.php',
14451470
'LegalpadCreateDocumentsCapability' => 'applications/legalpad/capability/LegalpadCreateDocumentsCapability.php',
@@ -6614,6 +6639,7 @@
66146639
'HeraldContentSourceField' => 'HeraldField',
66156640
'HeraldController' => 'PhabricatorController',
66166641
'HeraldCoreStateReasons' => 'HeraldStateReasons',
6642+
'HeraldCreateWebhooksCapability' => 'PhabricatorPolicyCapability',
66176643
'HeraldDAO' => 'PhabricatorLiskDAO',
66186644
'HeraldDeprecatedFieldGroup' => 'HeraldFieldGroup',
66196645
'HeraldDifferentialAdapter' => 'HeraldAdapter',
@@ -6704,6 +6730,39 @@
67046730
'HeraldTranscriptSearchEngine' => 'PhabricatorApplicationSearchEngine',
67056731
'HeraldTranscriptTestCase' => 'PhabricatorTestCase',
67066732
'HeraldUtilityActionGroup' => 'HeraldActionGroup',
6733+
'HeraldWebhook' => array(
6734+
'HeraldDAO',
6735+
'PhabricatorPolicyInterface',
6736+
'PhabricatorApplicationTransactionInterface',
6737+
'PhabricatorDestructibleInterface',
6738+
),
6739+
'HeraldWebhookCallManagementWorkflow' => 'HeraldWebhookManagementWorkflow',
6740+
'HeraldWebhookController' => 'HeraldController',
6741+
'HeraldWebhookEditController' => 'HeraldWebhookController',
6742+
'HeraldWebhookEditEngine' => 'PhabricatorEditEngine',
6743+
'HeraldWebhookEditor' => 'PhabricatorApplicationTransactionEditor',
6744+
'HeraldWebhookListController' => 'HeraldWebhookController',
6745+
'HeraldWebhookManagementWorkflow' => 'PhabricatorManagementWorkflow',
6746+
'HeraldWebhookNameTransaction' => 'HeraldWebhookTransactionType',
6747+
'HeraldWebhookPHIDType' => 'PhabricatorPHIDType',
6748+
'HeraldWebhookQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
6749+
'HeraldWebhookRequest' => array(
6750+
'HeraldDAO',
6751+
'PhabricatorPolicyInterface',
6752+
'PhabricatorExtendedPolicyInterface',
6753+
),
6754+
'HeraldWebhookRequestListView' => 'AphrontView',
6755+
'HeraldWebhookRequestPHIDType' => 'PhabricatorPHIDType',
6756+
'HeraldWebhookRequestQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
6757+
'HeraldWebhookSearchEngine' => 'PhabricatorApplicationSearchEngine',
6758+
'HeraldWebhookStatusTransaction' => 'HeraldWebhookTransactionType',
6759+
'HeraldWebhookTestController' => 'HeraldWebhookController',
6760+
'HeraldWebhookTransaction' => 'PhabricatorModularTransaction',
6761+
'HeraldWebhookTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
6762+
'HeraldWebhookTransactionType' => 'PhabricatorModularTransactionType',
6763+
'HeraldWebhookURITransaction' => 'HeraldWebhookTransactionType',
6764+
'HeraldWebhookViewController' => 'HeraldWebhookController',
6765+
'HeraldWebhookWorker' => 'PhabricatorWorker',
67076766
'Javelin' => 'Phobject',
67086767
'LegalpadController' => 'PhabricatorController',
67096768
'LegalpadCreateDocumentsCapability' => 'PhabricatorPolicyCapability',

src/applications/herald/application/PhabricatorHeraldApplication.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,17 @@ public function getRoutes() {
6262
'(?P<id>[1-9]\d*)/'
6363
=> 'HeraldTranscriptController',
6464
),
65+
'webhook/' => array(
66+
$this->getQueryRoutePattern() => 'HeraldWebhookListController',
67+
'view/(?P<id>\d+)/(?:request/(?P<requestID>[^/]+)/)?' =>
68+
'HeraldWebhookViewController',
69+
$this->getEditRoutePattern('edit/') => 'HeraldWebhookEditController',
70+
'test/(?P<id>\d+)/' => 'HeraldWebhookTestController',
71+
'key/' => array(
72+
'view/(?P<id>\d+)/' => 'HeraldWebhookViewKeyController',
73+
'cycle/(?P<id>\d+)/' => 'HeraldWebhookCycleKeyController',
74+
),
75+
),
6576
),
6677
);
6778
}
@@ -72,6 +83,9 @@ protected function getCustomCapabilities() {
7283
'caption' => pht('Global rules can bypass access controls.'),
7384
'default' => PhabricatorPolicies::POLICY_ADMIN,
7485
),
86+
HeraldCreateWebhooksCapability::CAPABILITY => array(
87+
'default' => PhabricatorPolicies::POLICY_ADMIN,
88+
),
7589
);
7690
}
7791

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
final class HeraldCreateWebhooksCapability
4+
extends PhabricatorPolicyCapability {
5+
6+
const CAPABILITY = 'herald.webhooks';
7+
8+
public function getCapabilityName() {
9+
return pht('Can Create Webhooks');
10+
}
11+
12+
public function describeCapabilityRejection() {
13+
return pht('You do not have permission to create webhooks.');
14+
}
15+
16+
}

src/applications/herald/controller/HeraldController.php

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,6 @@ public function buildApplicationMenu() {
66
return $this->buildSideNavView()->getMenu();
77
}
88

9-
protected function buildApplicationCrumbs() {
10-
$crumbs = parent::buildApplicationCrumbs();
11-
12-
$crumbs->addAction(
13-
id(new PHUIListItemView())
14-
->setName(pht('Create Herald Rule'))
15-
->setHref($this->getApplicationURI('create/'))
16-
->setIcon('fa-plus-square'));
17-
18-
return $crumbs;
19-
}
20-
219
public function buildSideNavView() {
2210
$viewer = $this->getViewer();
2311

@@ -29,8 +17,11 @@ public function buildSideNavView() {
2917
->addNavigationItems($nav->getMenu());
3018

3119
$nav->addLabel(pht('Utilities'))
32-
->addFilter('test', pht('Test Console'))
33-
->addFilter('transcript', pht('Transcripts'));
20+
->addFilter('test', pht('Test Console'))
21+
->addFilter('transcript', pht('Transcripts'));
22+
23+
$nav->addLabel(pht('Webhooks'))
24+
->addFilter('webhook', pht('Webhooks'));
3425

3526
$nav->selectFilter(null);
3627

src/applications/herald/controller/HeraldRuleListController.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,16 @@ public function handleRequest(AphrontRequest $request) {
1717
return $this->delegateToController($controller);
1818
}
1919

20+
protected function buildApplicationCrumbs() {
21+
$crumbs = parent::buildApplicationCrumbs();
22+
23+
$crumbs->addAction(
24+
id(new PHUIListItemView())
25+
->setName(pht('Create Herald Rule'))
26+
->setHref($this->getApplicationURI('create/'))
27+
->setIcon('fa-plus-square'));
28+
29+
return $crumbs;
30+
}
2031

2132
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
abstract class HeraldWebhookController extends HeraldController {
4+
5+
protected function buildApplicationCrumbs() {
6+
$crumbs = parent::buildApplicationCrumbs();
7+
8+
$crumbs->addTextCrumb(
9+
pht('Webhooks'),
10+
$this->getApplicationURI('webhook/'));
11+
12+
return $crumbs;
13+
}
14+
15+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
final class HeraldWebhookEditController
4+
extends HeraldWebhookController {
5+
6+
public function handleRequest(AphrontRequest $request) {
7+
return id(new HeraldWebhookEditEngine())
8+
->setController($this)
9+
->buildResponse();
10+
}
11+
12+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
final class HeraldWebhookListController
4+
extends HeraldWebhookController {
5+
6+
public function shouldAllowPublic() {
7+
return true;
8+
}
9+
10+
public function handleRequest(AphrontRequest $request) {
11+
return id(new HeraldWebhookSearchEngine())
12+
->setController($this)
13+
->buildResponse();
14+
}
15+
16+
protected function buildApplicationCrumbs() {
17+
$crumbs = parent::buildApplicationCrumbs();
18+
19+
id(new HeraldWebhookEditEngine())
20+
->setViewer($this->getViewer())
21+
->addActionToCrumbs($crumbs);
22+
23+
return $crumbs;
24+
}
25+
26+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
final class HeraldWebhookTestController
4+
extends HeraldWebhookController {
5+
6+
public function handleRequest(AphrontRequest $request) {
7+
$viewer = $this->getViewer();
8+
9+
$hook = id(new HeraldWebhookQuery())
10+
->setViewer($viewer)
11+
->withIDs(array($request->getURIData('id')))
12+
->requireCapabilities(
13+
array(
14+
PhabricatorPolicyCapability::CAN_VIEW,
15+
PhabricatorPolicyCapability::CAN_EDIT,
16+
))
17+
->executeOne();
18+
if (!$hook) {
19+
return new Aphront404Response();
20+
}
21+
22+
if ($request->isFormPost()) {
23+
$object = $hook;
24+
25+
$request = HeraldWebhookRequest::initializeNewWebhookRequest($hook)
26+
->setObjectPHID($object->getPHID())
27+
->save();
28+
29+
$request->queueCall();
30+
31+
$next_uri = $hook->getURI().'request/'.$request->getID().'/';
32+
33+
return id(new AphrontRedirectResponse())->setURI($next_uri);
34+
}
35+
36+
return $this->newDialog()
37+
->setTitle(pht('New Test Request'))
38+
->appendParagraph(
39+
pht('This will make a new test request to the configured URI.'))
40+
->addCancelButton($hook->getURI())
41+
->addSubmitButton(pht('Make Request'));
42+
}
43+
44+
45+
}

0 commit comments

Comments
 (0)