mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-15 01:50:55 +01:00
(stable) Promote 2018 Week 6
This commit is contained in:
commit
88faa980c6
178 changed files with 6904 additions and 791 deletions
1
bin/conduit
Symbolic link
1
bin/conduit
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../scripts/setup/manage_conduit.php
|
1
bin/webhook
Symbolic link
1
bin/webhook
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../scripts/setup/manage_webhook.php
|
|
@ -9,11 +9,11 @@ return array(
|
||||||
'names' => array(
|
'names' => array(
|
||||||
'conpherence.pkg.css' => 'e68cf1fa',
|
'conpherence.pkg.css' => 'e68cf1fa',
|
||||||
'conpherence.pkg.js' => '15191c65',
|
'conpherence.pkg.js' => '15191c65',
|
||||||
'core.pkg.css' => '51debec3',
|
'core.pkg.css' => 'e4f098a5',
|
||||||
'core.pkg.js' => '4c79d74f',
|
'core.pkg.js' => '3ac6e174',
|
||||||
'darkconsole.pkg.js' => '1f9a31bc',
|
'darkconsole.pkg.js' => '1f9a31bc',
|
||||||
'differential.pkg.css' => '45951e9e',
|
'differential.pkg.css' => '113e692c',
|
||||||
'differential.pkg.js' => '19ee9979',
|
'differential.pkg.js' => '5d53d5ce',
|
||||||
'diffusion.pkg.css' => 'a2d17c7d',
|
'diffusion.pkg.css' => 'a2d17c7d',
|
||||||
'diffusion.pkg.js' => '6134c5a1',
|
'diffusion.pkg.js' => '6134c5a1',
|
||||||
'favicon.ico' => '30672e08',
|
'favicon.ico' => '30672e08',
|
||||||
|
@ -31,7 +31,7 @@ return array(
|
||||||
'rsrc/css/aphront/multi-column.css' => '84cc6640',
|
'rsrc/css/aphront/multi-column.css' => '84cc6640',
|
||||||
'rsrc/css/aphront/notification.css' => '457861ec',
|
'rsrc/css/aphront/notification.css' => '457861ec',
|
||||||
'rsrc/css/aphront/panel-view.css' => '8427b78d',
|
'rsrc/css/aphront/panel-view.css' => '8427b78d',
|
||||||
'rsrc/css/aphront/phabricator-nav-view.css' => 'faf6a6fc',
|
'rsrc/css/aphront/phabricator-nav-view.css' => '028126f6',
|
||||||
'rsrc/css/aphront/table-view.css' => '8c9bbafe',
|
'rsrc/css/aphront/table-view.css' => '8c9bbafe',
|
||||||
'rsrc/css/aphront/tokenizer.css' => '15d5ff71',
|
'rsrc/css/aphront/tokenizer.css' => '15d5ff71',
|
||||||
'rsrc/css/aphront/tooltip.css' => '173b9431',
|
'rsrc/css/aphront/tooltip.css' => '173b9431',
|
||||||
|
@ -121,7 +121,7 @@ return array(
|
||||||
'rsrc/css/font/font-awesome.css' => 'e838e088',
|
'rsrc/css/font/font-awesome.css' => 'e838e088',
|
||||||
'rsrc/css/font/font-lato.css' => 'c7ccd872',
|
'rsrc/css/font/font-lato.css' => 'c7ccd872',
|
||||||
'rsrc/css/font/phui-font-icon-base.css' => '870a7360',
|
'rsrc/css/font/phui-font-icon-base.css' => '870a7360',
|
||||||
'rsrc/css/layout/phabricator-filetree-view.css' => 'fccf9f82',
|
'rsrc/css/layout/phabricator-filetree-view.css' => 'b912ad97',
|
||||||
'rsrc/css/layout/phabricator-source-code-view.css' => 'aea41829',
|
'rsrc/css/layout/phabricator-source-code-view.css' => 'aea41829',
|
||||||
'rsrc/css/phui/button/phui-button-bar.css' => 'f1ff5494',
|
'rsrc/css/phui/button/phui-button-bar.css' => 'f1ff5494',
|
||||||
'rsrc/css/phui/button/phui-button-simple.css' => '8e1baf68',
|
'rsrc/css/phui/button/phui-button-simple.css' => '8e1baf68',
|
||||||
|
@ -136,7 +136,7 @@ return array(
|
||||||
'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '9d9685d6',
|
'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '9d9685d6',
|
||||||
'rsrc/css/phui/object-item/phui-oi-list-view.css' => '6ae18df0',
|
'rsrc/css/phui/object-item/phui-oi-list-view.css' => '6ae18df0',
|
||||||
'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => 'a8beebea',
|
'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => 'a8beebea',
|
||||||
'rsrc/css/phui/phui-action-list.css' => 'f7f61a34',
|
'rsrc/css/phui/phui-action-list.css' => '0bcd9a45',
|
||||||
'rsrc/css/phui/phui-action-panel.css' => 'b4798122',
|
'rsrc/css/phui/phui-action-panel.css' => 'b4798122',
|
||||||
'rsrc/css/phui/phui-badge.css' => '22c0cf4f',
|
'rsrc/css/phui/phui-badge.css' => '22c0cf4f',
|
||||||
'rsrc/css/phui/phui-basic-nav-view.css' => '98c11ab3',
|
'rsrc/css/phui/phui-basic-nav-view.css' => '98c11ab3',
|
||||||
|
@ -395,8 +395,8 @@ return array(
|
||||||
'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => '408bf173',
|
'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => '408bf173',
|
||||||
'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '453c5375',
|
'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '453c5375',
|
||||||
'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63',
|
'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63',
|
||||||
'rsrc/js/application/diff/DiffChangeset.js' => '99abf4cd',
|
'rsrc/js/application/diff/DiffChangeset.js' => 'b49b59d6',
|
||||||
'rsrc/js/application/diff/DiffChangesetList.js' => '3b77efdd',
|
'rsrc/js/application/diff/DiffChangesetList.js' => '1f2e5265',
|
||||||
'rsrc/js/application/diff/DiffInline.js' => 'e83d28f3',
|
'rsrc/js/application/diff/DiffInline.js' => 'e83d28f3',
|
||||||
'rsrc/js/application/diff/behavior-preview-link.js' => '051c7832',
|
'rsrc/js/application/diff/behavior-preview-link.js' => '051c7832',
|
||||||
'rsrc/js/application/differential/behavior-comment-preview.js' => '51c5ad07',
|
'rsrc/js/application/differential/behavior-comment-preview.js' => '51c5ad07',
|
||||||
|
@ -498,7 +498,7 @@ return array(
|
||||||
'rsrc/js/core/behavior-more.js' => 'a80d0378',
|
'rsrc/js/core/behavior-more.js' => 'a80d0378',
|
||||||
'rsrc/js/core/behavior-object-selector.js' => '77c1f0b0',
|
'rsrc/js/core/behavior-object-selector.js' => '77c1f0b0',
|
||||||
'rsrc/js/core/behavior-oncopy.js' => '2926fff2',
|
'rsrc/js/core/behavior-oncopy.js' => '2926fff2',
|
||||||
'rsrc/js/core/behavior-phabricator-nav.js' => '947753e0',
|
'rsrc/js/core/behavior-phabricator-nav.js' => '81144dfa',
|
||||||
'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => 'acd29eee',
|
'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => 'acd29eee',
|
||||||
'rsrc/js/core/behavior-read-only-warning.js' => 'ba158207',
|
'rsrc/js/core/behavior-read-only-warning.js' => 'ba158207',
|
||||||
'rsrc/js/core/behavior-refresh-csrf.js' => 'ab2f381b',
|
'rsrc/js/core/behavior-refresh-csrf.js' => 'ab2f381b',
|
||||||
|
@ -657,7 +657,7 @@ return array(
|
||||||
'javelin-behavior-phabricator-keyboard-pager' => 'a8da01f0',
|
'javelin-behavior-phabricator-keyboard-pager' => 'a8da01f0',
|
||||||
'javelin-behavior-phabricator-keyboard-shortcuts' => '01fca1f0',
|
'javelin-behavior-phabricator-keyboard-shortcuts' => '01fca1f0',
|
||||||
'javelin-behavior-phabricator-line-linker' => '1499a8cb',
|
'javelin-behavior-phabricator-line-linker' => '1499a8cb',
|
||||||
'javelin-behavior-phabricator-nav' => '947753e0',
|
'javelin-behavior-phabricator-nav' => '81144dfa',
|
||||||
'javelin-behavior-phabricator-notification-example' => '8ce821c5',
|
'javelin-behavior-phabricator-notification-example' => '8ce821c5',
|
||||||
'javelin-behavior-phabricator-object-selector' => '77c1f0b0',
|
'javelin-behavior-phabricator-object-selector' => '77c1f0b0',
|
||||||
'javelin-behavior-phabricator-oncopy' => '2926fff2',
|
'javelin-behavior-phabricator-oncopy' => '2926fff2',
|
||||||
|
@ -766,7 +766,7 @@ return array(
|
||||||
'path-typeahead' => 'f7fc67ec',
|
'path-typeahead' => 'f7fc67ec',
|
||||||
'people-picture-menu-item-css' => 'a06f7f34',
|
'people-picture-menu-item-css' => 'a06f7f34',
|
||||||
'people-profile-css' => '4df76faf',
|
'people-profile-css' => '4df76faf',
|
||||||
'phabricator-action-list-view-css' => 'f7f61a34',
|
'phabricator-action-list-view-css' => '0bcd9a45',
|
||||||
'phabricator-busy' => '59a7976a',
|
'phabricator-busy' => '59a7976a',
|
||||||
'phabricator-chatlog-css' => 'd295b020',
|
'phabricator-chatlog-css' => 'd295b020',
|
||||||
'phabricator-content-source-view-css' => '4b8b05d4',
|
'phabricator-content-source-view-css' => '4b8b05d4',
|
||||||
|
@ -775,8 +775,8 @@ return array(
|
||||||
'phabricator-darklog' => 'c8e1ffe3',
|
'phabricator-darklog' => 'c8e1ffe3',
|
||||||
'phabricator-darkmessage' => 'c48cccdd',
|
'phabricator-darkmessage' => 'c48cccdd',
|
||||||
'phabricator-dashboard-css' => 'fe5b1869',
|
'phabricator-dashboard-css' => 'fe5b1869',
|
||||||
'phabricator-diff-changeset' => '99abf4cd',
|
'phabricator-diff-changeset' => 'b49b59d6',
|
||||||
'phabricator-diff-changeset-list' => '3b77efdd',
|
'phabricator-diff-changeset-list' => '1f2e5265',
|
||||||
'phabricator-diff-inline' => 'e83d28f3',
|
'phabricator-diff-inline' => 'e83d28f3',
|
||||||
'phabricator-drag-and-drop-file-upload' => '58dea2fa',
|
'phabricator-drag-and-drop-file-upload' => '58dea2fa',
|
||||||
'phabricator-draggable-list' => 'bea6e7f4',
|
'phabricator-draggable-list' => 'bea6e7f4',
|
||||||
|
@ -784,12 +784,12 @@ return array(
|
||||||
'phabricator-favicon' => '1fe2510c',
|
'phabricator-favicon' => '1fe2510c',
|
||||||
'phabricator-feed-css' => 'ecd4ec57',
|
'phabricator-feed-css' => 'ecd4ec57',
|
||||||
'phabricator-file-upload' => '680ea2c8',
|
'phabricator-file-upload' => '680ea2c8',
|
||||||
'phabricator-filetree-view-css' => 'fccf9f82',
|
'phabricator-filetree-view-css' => 'b912ad97',
|
||||||
'phabricator-flag-css' => 'bba8f811',
|
'phabricator-flag-css' => 'bba8f811',
|
||||||
'phabricator-keyboard-shortcut' => '1ae869f2',
|
'phabricator-keyboard-shortcut' => '1ae869f2',
|
||||||
'phabricator-keyboard-shortcut-manager' => 'c19dd9b9',
|
'phabricator-keyboard-shortcut-manager' => 'c19dd9b9',
|
||||||
'phabricator-main-menu-view' => '1802a242',
|
'phabricator-main-menu-view' => '1802a242',
|
||||||
'phabricator-nav-view-css' => 'faf6a6fc',
|
'phabricator-nav-view-css' => '028126f6',
|
||||||
'phabricator-notification' => '008faf9c',
|
'phabricator-notification' => '008faf9c',
|
||||||
'phabricator-notification-css' => '457861ec',
|
'phabricator-notification-css' => '457861ec',
|
||||||
'phabricator-notification-menu-css' => '10685bd4',
|
'phabricator-notification-menu-css' => '10685bd4',
|
||||||
|
@ -1044,6 +1044,10 @@ return array(
|
||||||
'javelin-uri',
|
'javelin-uri',
|
||||||
'javelin-routable',
|
'javelin-routable',
|
||||||
),
|
),
|
||||||
|
'1f2e5265' => array(
|
||||||
|
'javelin-install',
|
||||||
|
'phuix-button-view',
|
||||||
|
),
|
||||||
'1f6794f6' => array(
|
'1f6794f6' => array(
|
||||||
'javelin-behavior',
|
'javelin-behavior',
|
||||||
'javelin-stratcom',
|
'javelin-stratcom',
|
||||||
|
@ -1143,10 +1147,6 @@ return array(
|
||||||
'javelin-dom',
|
'javelin-dom',
|
||||||
'javelin-magical-init',
|
'javelin-magical-init',
|
||||||
),
|
),
|
||||||
'3b77efdd' => array(
|
|
||||||
'javelin-install',
|
|
||||||
'phuix-button-view',
|
|
||||||
),
|
|
||||||
'3cb0b2fc' => array(
|
'3cb0b2fc' => array(
|
||||||
'javelin-behavior',
|
'javelin-behavior',
|
||||||
'javelin-dom',
|
'javelin-dom',
|
||||||
|
@ -1561,6 +1561,16 @@ return array(
|
||||||
'7f243deb' => array(
|
'7f243deb' => array(
|
||||||
'javelin-install',
|
'javelin-install',
|
||||||
),
|
),
|
||||||
|
'81144dfa' => array(
|
||||||
|
'javelin-behavior',
|
||||||
|
'javelin-behavior-device',
|
||||||
|
'javelin-stratcom',
|
||||||
|
'javelin-dom',
|
||||||
|
'javelin-magical-init',
|
||||||
|
'javelin-vector',
|
||||||
|
'javelin-request',
|
||||||
|
'javelin-util',
|
||||||
|
),
|
||||||
'834a1173' => array(
|
'834a1173' => array(
|
||||||
'javelin-behavior',
|
'javelin-behavior',
|
||||||
'javelin-scrollbar',
|
'javelin-scrollbar',
|
||||||
|
@ -1648,16 +1658,6 @@ return array(
|
||||||
'javelin-workflow',
|
'javelin-workflow',
|
||||||
'javelin-dom',
|
'javelin-dom',
|
||||||
),
|
),
|
||||||
'947753e0' => array(
|
|
||||||
'javelin-behavior',
|
|
||||||
'javelin-behavior-device',
|
|
||||||
'javelin-stratcom',
|
|
||||||
'javelin-dom',
|
|
||||||
'javelin-magical-init',
|
|
||||||
'javelin-vector',
|
|
||||||
'javelin-request',
|
|
||||||
'javelin-util',
|
|
||||||
),
|
|
||||||
'949c0fe5' => array(
|
'949c0fe5' => array(
|
||||||
'javelin-install',
|
'javelin-install',
|
||||||
),
|
),
|
||||||
|
@ -1678,17 +1678,6 @@ return array(
|
||||||
'javelin-mask',
|
'javelin-mask',
|
||||||
'phabricator-drag-and-drop-file-upload',
|
'phabricator-drag-and-drop-file-upload',
|
||||||
),
|
),
|
||||||
'99abf4cd' => array(
|
|
||||||
'javelin-dom',
|
|
||||||
'javelin-util',
|
|
||||||
'javelin-stratcom',
|
|
||||||
'javelin-install',
|
|
||||||
'javelin-workflow',
|
|
||||||
'javelin-router',
|
|
||||||
'javelin-behavior-device',
|
|
||||||
'javelin-vector',
|
|
||||||
'phabricator-diff-inline',
|
|
||||||
),
|
|
||||||
'9a6dd75c' => array(
|
'9a6dd75c' => array(
|
||||||
'javelin-behavior',
|
'javelin-behavior',
|
||||||
'javelin-stratcom',
|
'javelin-stratcom',
|
||||||
|
@ -1837,6 +1826,17 @@ return array(
|
||||||
'b3e7d692' => array(
|
'b3e7d692' => array(
|
||||||
'javelin-install',
|
'javelin-install',
|
||||||
),
|
),
|
||||||
|
'b49b59d6' => array(
|
||||||
|
'javelin-dom',
|
||||||
|
'javelin-util',
|
||||||
|
'javelin-stratcom',
|
||||||
|
'javelin-install',
|
||||||
|
'javelin-workflow',
|
||||||
|
'javelin-router',
|
||||||
|
'javelin-behavior-device',
|
||||||
|
'javelin-vector',
|
||||||
|
'phabricator-diff-inline',
|
||||||
|
),
|
||||||
'b59e1e96' => array(
|
'b59e1e96' => array(
|
||||||
'javelin-behavior',
|
'javelin-behavior',
|
||||||
'javelin-stratcom',
|
'javelin-stratcom',
|
||||||
|
|
|
@ -1622,5 +1622,9 @@
|
||||||
"zipper_mouth": "\ud83e\udd10",
|
"zipper_mouth": "\ud83e\udd10",
|
||||||
"zzz": "\ud83d\udca4",
|
"zzz": "\ud83d\udca4",
|
||||||
"100": "\ud83d\udcaf",
|
"100": "\ud83d\udcaf",
|
||||||
"1234": "\ud83d\udd22"
|
"1234": "\ud83d\udd22",
|
||||||
|
|
||||||
|
"party": "\ud83c\udf89",
|
||||||
|
"celebration": "\ud83c\udf89",
|
||||||
|
"confetti": "\ud83c\udf89"
|
||||||
}
|
}
|
||||||
|
|
2
resources/sql/autopatches/20180207.mail.01.task.sql
Normal file
2
resources/sql/autopatches/20180207.mail.01.task.sql
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_maniphest.maniphest_task
|
||||||
|
DROP originalTitle;
|
2
resources/sql/autopatches/20180207.mail.02.revision.sql
Normal file
2
resources/sql/autopatches/20180207.mail.02.revision.sql
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_differential.differential_revision
|
||||||
|
DROP originalTitle;
|
2
resources/sql/autopatches/20180207.mail.03.mock.sql
Normal file
2
resources/sql/autopatches/20180207.mail.03.mock.sql
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_pholio.pholio_mock
|
||||||
|
DROP originalName;
|
|
@ -0,0 +1,5 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_maniphest.maniphest_task
|
||||||
|
ADD closedEpoch INT UNSIGNED;
|
||||||
|
|
||||||
|
ALTER TABLE {$NAMESPACE}_maniphest.maniphest_task
|
||||||
|
ADD closerPHID VARBINARY(64);
|
65
resources/sql/autopatches/20180208.maniphest.02.populate.php
Normal file
65
resources/sql/autopatches/20180208.maniphest.02.populate.php
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$table = new ManiphestTask();
|
||||||
|
$conn = $table->establishConnection('w');
|
||||||
|
$viewer = PhabricatorUser::getOmnipotentUser();
|
||||||
|
|
||||||
|
foreach (new LiskMigrationIterator($table) as $task) {
|
||||||
|
if ($task->getClosedEpoch()) {
|
||||||
|
// Task already has a closed date.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$status = $task->getStatus();
|
||||||
|
if (!ManiphestTaskStatus::isClosedStatus($status)) {
|
||||||
|
// Task isn't closed.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look through the transactions from newest to oldest until we find one
|
||||||
|
// where the task was closed. A merge also counts as a close, even though
|
||||||
|
// it doesn't currently produce a separate transaction.
|
||||||
|
|
||||||
|
$type_merge = ManiphestTaskStatusTransaction::TRANSACTIONTYPE;
|
||||||
|
$type_status = ManiphestTaskMergedIntoTransaction::TRANSACTIONTYPE;
|
||||||
|
|
||||||
|
$xactions = id(new ManiphestTransactionQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withObjectPHIDs(array($task->getPHID()))
|
||||||
|
->withTransactionTypes(
|
||||||
|
array(
|
||||||
|
$type_merge,
|
||||||
|
$type_status,
|
||||||
|
))
|
||||||
|
->execute();
|
||||||
|
foreach ($xactions as $xaction) {
|
||||||
|
$old = $xaction->getOldValue();
|
||||||
|
$new = $xaction->getNewValue();
|
||||||
|
|
||||||
|
$type = $xaction->getTransactionType();
|
||||||
|
|
||||||
|
// If this is a status change, but is not a close, don't use it.
|
||||||
|
// (We always use merges, even though it's possible to merge a task which
|
||||||
|
// was previously closed: we can't tell when this happens very easily.)
|
||||||
|
if ($type === $type_status) {
|
||||||
|
if (!ManiphestTaskStatus::isClosedStatus($new)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($old && ManiphestTaskStatus::isClosedStatus($old)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
queryfx(
|
||||||
|
$conn,
|
||||||
|
'UPDATE %T SET closedEpoch = %d, closerPHID = %ns
|
||||||
|
WHERE id = %d',
|
||||||
|
$table->getTableName(),
|
||||||
|
$xaction->getDateCreated(),
|
||||||
|
$xaction->getAuthorPHID(),
|
||||||
|
$task->getID());
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
12
resources/sql/autopatches/20180209.hook.01.hook.sql
Normal file
12
resources/sql/autopatches/20180209.hook.01.hook.sql
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
CREATE TABLE {$NAMESPACE}_herald.herald_webhook (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
phid VARBINARY(64) NOT NULL,
|
||||||
|
name VARCHAR(128) NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
webhookURI VARCHAR(255) NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
viewPolicy VARBINARY(64) NOT NULL,
|
||||||
|
editPolicy VARBINARY(64) NOT NULL,
|
||||||
|
status VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
hmacKey VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
dateCreated INT UNSIGNED NOT NULL,
|
||||||
|
dateModified INT UNSIGNED NOT NULL
|
||||||
|
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
19
resources/sql/autopatches/20180209.hook.02.hookxaction.sql
Normal file
19
resources/sql/autopatches/20180209.hook.02.hookxaction.sql
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
CREATE TABLE {$NAMESPACE}_herald.herald_webhooktransaction (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
phid VARBINARY(64) NOT NULL,
|
||||||
|
authorPHID VARBINARY(64) NOT NULL,
|
||||||
|
objectPHID VARBINARY(64) NOT NULL,
|
||||||
|
viewPolicy VARBINARY(64) NOT NULL,
|
||||||
|
editPolicy VARBINARY(64) NOT NULL,
|
||||||
|
commentPHID VARBINARY(64) DEFAULT NULL,
|
||||||
|
commentVersion INT UNSIGNED NOT NULL,
|
||||||
|
transactionType VARCHAR(32) COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
oldValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
newValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
contentSource LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
metadata LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
dateCreated INT UNSIGNED NOT NULL,
|
||||||
|
dateModified INT UNSIGNED NOT NULL,
|
||||||
|
UNIQUE KEY `key_phid` (`phid`),
|
||||||
|
KEY `key_object` (`objectPHID`)
|
||||||
|
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
12
resources/sql/autopatches/20180209.hook.03.hookrequest.sql
Normal file
12
resources/sql/autopatches/20180209.hook.03.hookrequest.sql
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
CREATE TABLE {$NAMESPACE}_herald.herald_webhookrequest (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
phid VARBINARY(64) NOT NULL,
|
||||||
|
webhookPHID VARBINARY(64) NOT NULL,
|
||||||
|
objectPHID VARBINARY(64) NOT NULL,
|
||||||
|
status VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
properties LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
lastRequestResult VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
lastRequestEpoch INT UNSIGNED NOT NULL,
|
||||||
|
dateCreated INT UNSIGNED NOT NULL,
|
||||||
|
dateModified INT UNSIGNED NOT NULL
|
||||||
|
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
21
scripts/setup/manage_conduit.php
Executable file
21
scripts/setup/manage_conduit.php
Executable file
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$root = dirname(dirname(dirname(__FILE__)));
|
||||||
|
require_once $root.'/scripts/init/init-script.php';
|
||||||
|
|
||||||
|
$args = new PhutilArgumentParser($argv);
|
||||||
|
$args->setTagline(pht('manage Conduit'));
|
||||||
|
$args->setSynopsis(<<<EOSYNOPSIS
|
||||||
|
**conduit** __command__ [__options__]
|
||||||
|
Manage Conduit.
|
||||||
|
|
||||||
|
EOSYNOPSIS
|
||||||
|
);
|
||||||
|
$args->parseStandardArguments();
|
||||||
|
|
||||||
|
$workflows = id(new PhutilClassMapQuery())
|
||||||
|
->setAncestorClass('PhabricatorConduitManagementWorkflow')
|
||||||
|
->execute();
|
||||||
|
$workflows[] = new PhutilHelpArgumentWorkflow();
|
||||||
|
$args->parseWorkflows($workflows);
|
21
scripts/setup/manage_webhook.php
Executable file
21
scripts/setup/manage_webhook.php
Executable file
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$root = dirname(dirname(dirname(__FILE__)));
|
||||||
|
require_once $root.'/scripts/init/init-script.php';
|
||||||
|
|
||||||
|
$args = new PhutilArgumentParser($argv);
|
||||||
|
$args->setTagline(pht('manage webhooks'));
|
||||||
|
$args->setSynopsis(<<<EOSYNOPSIS
|
||||||
|
**webhook** __command__ [__options__]
|
||||||
|
Manage webhooks.
|
||||||
|
|
||||||
|
EOSYNOPSIS
|
||||||
|
);
|
||||||
|
$args->parseStandardArguments();
|
||||||
|
|
||||||
|
$workflows = id(new PhutilClassMapQuery())
|
||||||
|
->setAncestorClass('HeraldWebhookManagementWorkflow')
|
||||||
|
->execute();
|
||||||
|
$workflows[] = new PhutilHelpArgumentWorkflow();
|
||||||
|
$args->parseWorkflows($workflows);
|
|
@ -487,6 +487,7 @@ phutil_register_library_map(array(
|
||||||
'DifferentialLintField' => 'applications/differential/customfield/DifferentialLintField.php',
|
'DifferentialLintField' => 'applications/differential/customfield/DifferentialLintField.php',
|
||||||
'DifferentialLintStatus' => 'applications/differential/constants/DifferentialLintStatus.php',
|
'DifferentialLintStatus' => 'applications/differential/constants/DifferentialLintStatus.php',
|
||||||
'DifferentialLocalCommitsView' => 'applications/differential/view/DifferentialLocalCommitsView.php',
|
'DifferentialLocalCommitsView' => 'applications/differential/view/DifferentialLocalCommitsView.php',
|
||||||
|
'DifferentialMailEngineExtension' => 'applications/differential/engineextension/DifferentialMailEngineExtension.php',
|
||||||
'DifferentialMailView' => 'applications/differential/mail/DifferentialMailView.php',
|
'DifferentialMailView' => 'applications/differential/mail/DifferentialMailView.php',
|
||||||
'DifferentialManiphestTasksField' => 'applications/differential/customfield/DifferentialManiphestTasksField.php',
|
'DifferentialManiphestTasksField' => 'applications/differential/customfield/DifferentialManiphestTasksField.php',
|
||||||
'DifferentialModernHunk' => 'applications/differential/storage/DifferentialModernHunk.php',
|
'DifferentialModernHunk' => 'applications/differential/storage/DifferentialModernHunk.php',
|
||||||
|
@ -1345,6 +1346,7 @@ phutil_register_library_map(array(
|
||||||
'HarbormasterWaitForPreviousBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterWaitForPreviousBuildStepImplementation.php',
|
'HarbormasterWaitForPreviousBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterWaitForPreviousBuildStepImplementation.php',
|
||||||
'HarbormasterWorker' => 'applications/harbormaster/worker/HarbormasterWorker.php',
|
'HarbormasterWorker' => 'applications/harbormaster/worker/HarbormasterWorker.php',
|
||||||
'HarbormasterWorkingCopyArtifact' => 'applications/harbormaster/artifact/HarbormasterWorkingCopyArtifact.php',
|
'HarbormasterWorkingCopyArtifact' => 'applications/harbormaster/artifact/HarbormasterWorkingCopyArtifact.php',
|
||||||
|
'HeraldActingUserField' => 'applications/herald/field/HeraldActingUserField.php',
|
||||||
'HeraldAction' => 'applications/herald/action/HeraldAction.php',
|
'HeraldAction' => 'applications/herald/action/HeraldAction.php',
|
||||||
'HeraldActionGroup' => 'applications/herald/action/HeraldActionGroup.php',
|
'HeraldActionGroup' => 'applications/herald/action/HeraldActionGroup.php',
|
||||||
'HeraldActionRecord' => 'applications/herald/storage/HeraldActionRecord.php',
|
'HeraldActionRecord' => 'applications/herald/storage/HeraldActionRecord.php',
|
||||||
|
@ -1355,6 +1357,7 @@ phutil_register_library_map(array(
|
||||||
'HeraldApplyTranscript' => 'applications/herald/storage/transcript/HeraldApplyTranscript.php',
|
'HeraldApplyTranscript' => 'applications/herald/storage/transcript/HeraldApplyTranscript.php',
|
||||||
'HeraldBasicFieldGroup' => 'applications/herald/field/HeraldBasicFieldGroup.php',
|
'HeraldBasicFieldGroup' => 'applications/herald/field/HeraldBasicFieldGroup.php',
|
||||||
'HeraldBuildableState' => 'applications/herald/state/HeraldBuildableState.php',
|
'HeraldBuildableState' => 'applications/herald/state/HeraldBuildableState.php',
|
||||||
|
'HeraldCallWebhookAction' => 'applications/herald/action/HeraldCallWebhookAction.php',
|
||||||
'HeraldCommentAction' => 'applications/herald/action/HeraldCommentAction.php',
|
'HeraldCommentAction' => 'applications/herald/action/HeraldCommentAction.php',
|
||||||
'HeraldCommitAdapter' => 'applications/diffusion/herald/HeraldCommitAdapter.php',
|
'HeraldCommitAdapter' => 'applications/diffusion/herald/HeraldCommitAdapter.php',
|
||||||
'HeraldCondition' => 'applications/herald/storage/HeraldCondition.php',
|
'HeraldCondition' => 'applications/herald/storage/HeraldCondition.php',
|
||||||
|
@ -1362,6 +1365,7 @@ phutil_register_library_map(array(
|
||||||
'HeraldContentSourceField' => 'applications/herald/field/HeraldContentSourceField.php',
|
'HeraldContentSourceField' => 'applications/herald/field/HeraldContentSourceField.php',
|
||||||
'HeraldController' => 'applications/herald/controller/HeraldController.php',
|
'HeraldController' => 'applications/herald/controller/HeraldController.php',
|
||||||
'HeraldCoreStateReasons' => 'applications/herald/state/HeraldCoreStateReasons.php',
|
'HeraldCoreStateReasons' => 'applications/herald/state/HeraldCoreStateReasons.php',
|
||||||
|
'HeraldCreateWebhooksCapability' => 'applications/herald/capability/HeraldCreateWebhooksCapability.php',
|
||||||
'HeraldDAO' => 'applications/herald/storage/HeraldDAO.php',
|
'HeraldDAO' => 'applications/herald/storage/HeraldDAO.php',
|
||||||
'HeraldDeprecatedFieldGroup' => 'applications/herald/field/HeraldDeprecatedFieldGroup.php',
|
'HeraldDeprecatedFieldGroup' => 'applications/herald/field/HeraldDeprecatedFieldGroup.php',
|
||||||
'HeraldDifferentialAdapter' => 'applications/differential/herald/HeraldDifferentialAdapter.php',
|
'HeraldDifferentialAdapter' => 'applications/differential/herald/HeraldDifferentialAdapter.php',
|
||||||
|
@ -1438,6 +1442,33 @@ phutil_register_library_map(array(
|
||||||
'HeraldTranscriptSearchEngine' => 'applications/herald/query/HeraldTranscriptSearchEngine.php',
|
'HeraldTranscriptSearchEngine' => 'applications/herald/query/HeraldTranscriptSearchEngine.php',
|
||||||
'HeraldTranscriptTestCase' => 'applications/herald/storage/__tests__/HeraldTranscriptTestCase.php',
|
'HeraldTranscriptTestCase' => 'applications/herald/storage/__tests__/HeraldTranscriptTestCase.php',
|
||||||
'HeraldUtilityActionGroup' => 'applications/herald/action/HeraldUtilityActionGroup.php',
|
'HeraldUtilityActionGroup' => 'applications/herald/action/HeraldUtilityActionGroup.php',
|
||||||
|
'HeraldWebhook' => 'applications/herald/storage/HeraldWebhook.php',
|
||||||
|
'HeraldWebhookCallManagementWorkflow' => 'applications/herald/management/HeraldWebhookCallManagementWorkflow.php',
|
||||||
|
'HeraldWebhookController' => 'applications/herald/controller/HeraldWebhookController.php',
|
||||||
|
'HeraldWebhookDatasource' => 'applications/herald/typeahead/HeraldWebhookDatasource.php',
|
||||||
|
'HeraldWebhookEditController' => 'applications/herald/controller/HeraldWebhookEditController.php',
|
||||||
|
'HeraldWebhookEditEngine' => 'applications/herald/editor/HeraldWebhookEditEngine.php',
|
||||||
|
'HeraldWebhookEditor' => 'applications/herald/editor/HeraldWebhookEditor.php',
|
||||||
|
'HeraldWebhookKeyController' => 'applications/herald/controller/HeraldWebhookKeyController.php',
|
||||||
|
'HeraldWebhookListController' => 'applications/herald/controller/HeraldWebhookListController.php',
|
||||||
|
'HeraldWebhookManagementWorkflow' => 'applications/herald/management/HeraldWebhookManagementWorkflow.php',
|
||||||
|
'HeraldWebhookNameTransaction' => 'applications/herald/xaction/HeraldWebhookNameTransaction.php',
|
||||||
|
'HeraldWebhookPHIDType' => 'applications/herald/phid/HeraldWebhookPHIDType.php',
|
||||||
|
'HeraldWebhookQuery' => 'applications/herald/query/HeraldWebhookQuery.php',
|
||||||
|
'HeraldWebhookRequest' => 'applications/herald/storage/HeraldWebhookRequest.php',
|
||||||
|
'HeraldWebhookRequestGarbageCollector' => 'applications/herald/garbagecollector/HeraldWebhookRequestGarbageCollector.php',
|
||||||
|
'HeraldWebhookRequestListView' => 'applications/herald/view/HeraldWebhookRequestListView.php',
|
||||||
|
'HeraldWebhookRequestPHIDType' => 'applications/herald/phid/HeraldWebhookRequestPHIDType.php',
|
||||||
|
'HeraldWebhookRequestQuery' => 'applications/herald/query/HeraldWebhookRequestQuery.php',
|
||||||
|
'HeraldWebhookSearchEngine' => 'applications/herald/query/HeraldWebhookSearchEngine.php',
|
||||||
|
'HeraldWebhookStatusTransaction' => 'applications/herald/xaction/HeraldWebhookStatusTransaction.php',
|
||||||
|
'HeraldWebhookTestController' => 'applications/herald/controller/HeraldWebhookTestController.php',
|
||||||
|
'HeraldWebhookTransaction' => 'applications/herald/storage/HeraldWebhookTransaction.php',
|
||||||
|
'HeraldWebhookTransactionQuery' => 'applications/herald/query/HeraldWebhookTransactionQuery.php',
|
||||||
|
'HeraldWebhookTransactionType' => 'applications/herald/xaction/HeraldWebhookTransactionType.php',
|
||||||
|
'HeraldWebhookURITransaction' => 'applications/herald/xaction/HeraldWebhookURITransaction.php',
|
||||||
|
'HeraldWebhookViewController' => 'applications/herald/controller/HeraldWebhookViewController.php',
|
||||||
|
'HeraldWebhookWorker' => 'applications/herald/worker/HeraldWebhookWorker.php',
|
||||||
'Javelin' => 'infrastructure/javelin/Javelin.php',
|
'Javelin' => 'infrastructure/javelin/Javelin.php',
|
||||||
'LegalpadController' => 'applications/legalpad/controller/LegalpadController.php',
|
'LegalpadController' => 'applications/legalpad/controller/LegalpadController.php',
|
||||||
'LegalpadCreateDocumentsCapability' => 'applications/legalpad/capability/LegalpadCreateDocumentsCapability.php',
|
'LegalpadCreateDocumentsCapability' => 'applications/legalpad/capability/LegalpadCreateDocumentsCapability.php',
|
||||||
|
@ -1528,6 +1559,7 @@ phutil_register_library_map(array(
|
||||||
'ManiphestGetTaskTransactionsConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestGetTaskTransactionsConduitAPIMethod.php',
|
'ManiphestGetTaskTransactionsConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestGetTaskTransactionsConduitAPIMethod.php',
|
||||||
'ManiphestHovercardEngineExtension' => 'applications/maniphest/engineextension/ManiphestHovercardEngineExtension.php',
|
'ManiphestHovercardEngineExtension' => 'applications/maniphest/engineextension/ManiphestHovercardEngineExtension.php',
|
||||||
'ManiphestInfoConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestInfoConduitAPIMethod.php',
|
'ManiphestInfoConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestInfoConduitAPIMethod.php',
|
||||||
|
'ManiphestMailEngineExtension' => 'applications/maniphest/engineextension/ManiphestMailEngineExtension.php',
|
||||||
'ManiphestNameIndex' => 'applications/maniphest/storage/ManiphestNameIndex.php',
|
'ManiphestNameIndex' => 'applications/maniphest/storage/ManiphestNameIndex.php',
|
||||||
'ManiphestPointsConfigType' => 'applications/maniphest/config/ManiphestPointsConfigType.php',
|
'ManiphestPointsConfigType' => 'applications/maniphest/config/ManiphestPointsConfigType.php',
|
||||||
'ManiphestPrioritiesConfigType' => 'applications/maniphest/config/ManiphestPrioritiesConfigType.php',
|
'ManiphestPrioritiesConfigType' => 'applications/maniphest/config/ManiphestPrioritiesConfigType.php',
|
||||||
|
@ -1958,6 +1990,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorApplicationEditHTTPParameterHelpView' => 'applications/transactions/view/PhabricatorApplicationEditHTTPParameterHelpView.php',
|
'PhabricatorApplicationEditHTTPParameterHelpView' => 'applications/transactions/view/PhabricatorApplicationEditHTTPParameterHelpView.php',
|
||||||
'PhabricatorApplicationEditor' => 'applications/meta/editor/PhabricatorApplicationEditor.php',
|
'PhabricatorApplicationEditor' => 'applications/meta/editor/PhabricatorApplicationEditor.php',
|
||||||
'PhabricatorApplicationEmailCommandsController' => 'applications/meta/controller/PhabricatorApplicationEmailCommandsController.php',
|
'PhabricatorApplicationEmailCommandsController' => 'applications/meta/controller/PhabricatorApplicationEmailCommandsController.php',
|
||||||
|
'PhabricatorApplicationObjectMailEngineExtension' => 'applications/transactions/engineextension/PhabricatorApplicationObjectMailEngineExtension.php',
|
||||||
'PhabricatorApplicationPanelController' => 'applications/meta/controller/PhabricatorApplicationPanelController.php',
|
'PhabricatorApplicationPanelController' => 'applications/meta/controller/PhabricatorApplicationPanelController.php',
|
||||||
'PhabricatorApplicationPolicyChangeTransaction' => 'applications/meta/xactions/PhabricatorApplicationPolicyChangeTransaction.php',
|
'PhabricatorApplicationPolicyChangeTransaction' => 'applications/meta/xactions/PhabricatorApplicationPolicyChangeTransaction.php',
|
||||||
'PhabricatorApplicationProfileMenuItem' => 'applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php',
|
'PhabricatorApplicationProfileMenuItem' => 'applications/search/menuitem/PhabricatorApplicationProfileMenuItem.php',
|
||||||
|
@ -2219,6 +2252,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorBoardResponseEngine' => 'applications/project/engine/PhabricatorBoardResponseEngine.php',
|
'PhabricatorBoardResponseEngine' => 'applications/project/engine/PhabricatorBoardResponseEngine.php',
|
||||||
'PhabricatorBoolConfigType' => 'applications/config/type/PhabricatorBoolConfigType.php',
|
'PhabricatorBoolConfigType' => 'applications/config/type/PhabricatorBoolConfigType.php',
|
||||||
'PhabricatorBoolEditField' => 'applications/transactions/editfield/PhabricatorBoolEditField.php',
|
'PhabricatorBoolEditField' => 'applications/transactions/editfield/PhabricatorBoolEditField.php',
|
||||||
|
'PhabricatorBoolMailStamp' => 'applications/metamta/stamp/PhabricatorBoolMailStamp.php',
|
||||||
'PhabricatorBritishEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorBritishEnglishTranslation.php',
|
'PhabricatorBritishEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorBritishEnglishTranslation.php',
|
||||||
'PhabricatorBuiltinDraftEngine' => 'applications/transactions/draft/PhabricatorBuiltinDraftEngine.php',
|
'PhabricatorBuiltinDraftEngine' => 'applications/transactions/draft/PhabricatorBuiltinDraftEngine.php',
|
||||||
'PhabricatorBuiltinFileCachePurger' => 'applications/cache/purger/PhabricatorBuiltinFileCachePurger.php',
|
'PhabricatorBuiltinFileCachePurger' => 'applications/cache/purger/PhabricatorBuiltinFileCachePurger.php',
|
||||||
|
@ -2407,6 +2441,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorClusterExceptionHandler' => 'infrastructure/cluster/exception/PhabricatorClusterExceptionHandler.php',
|
'PhabricatorClusterExceptionHandler' => 'infrastructure/cluster/exception/PhabricatorClusterExceptionHandler.php',
|
||||||
'PhabricatorClusterImpossibleWriteException' => 'infrastructure/cluster/exception/PhabricatorClusterImpossibleWriteException.php',
|
'PhabricatorClusterImpossibleWriteException' => 'infrastructure/cluster/exception/PhabricatorClusterImpossibleWriteException.php',
|
||||||
'PhabricatorClusterImproperWriteException' => 'infrastructure/cluster/exception/PhabricatorClusterImproperWriteException.php',
|
'PhabricatorClusterImproperWriteException' => 'infrastructure/cluster/exception/PhabricatorClusterImproperWriteException.php',
|
||||||
|
'PhabricatorClusterMailersConfigType' => 'infrastructure/cluster/config/PhabricatorClusterMailersConfigType.php',
|
||||||
'PhabricatorClusterNoHostForRoleException' => 'infrastructure/cluster/exception/PhabricatorClusterNoHostForRoleException.php',
|
'PhabricatorClusterNoHostForRoleException' => 'infrastructure/cluster/exception/PhabricatorClusterNoHostForRoleException.php',
|
||||||
'PhabricatorClusterSearchConfigType' => 'infrastructure/cluster/config/PhabricatorClusterSearchConfigType.php',
|
'PhabricatorClusterSearchConfigType' => 'infrastructure/cluster/config/PhabricatorClusterSearchConfigType.php',
|
||||||
'PhabricatorClusterServiceHealthRecord' => 'infrastructure/cluster/PhabricatorClusterServiceHealthRecord.php',
|
'PhabricatorClusterServiceHealthRecord' => 'infrastructure/cluster/PhabricatorClusterServiceHealthRecord.php',
|
||||||
|
@ -2425,6 +2460,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCommonPasswords' => 'applications/auth/constants/PhabricatorCommonPasswords.php',
|
'PhabricatorCommonPasswords' => 'applications/auth/constants/PhabricatorCommonPasswords.php',
|
||||||
'PhabricatorConduitAPIController' => 'applications/conduit/controller/PhabricatorConduitAPIController.php',
|
'PhabricatorConduitAPIController' => 'applications/conduit/controller/PhabricatorConduitAPIController.php',
|
||||||
'PhabricatorConduitApplication' => 'applications/conduit/application/PhabricatorConduitApplication.php',
|
'PhabricatorConduitApplication' => 'applications/conduit/application/PhabricatorConduitApplication.php',
|
||||||
|
'PhabricatorConduitCallManagementWorkflow' => 'applications/conduit/management/PhabricatorConduitCallManagementWorkflow.php',
|
||||||
'PhabricatorConduitCertificateToken' => 'applications/conduit/storage/PhabricatorConduitCertificateToken.php',
|
'PhabricatorConduitCertificateToken' => 'applications/conduit/storage/PhabricatorConduitCertificateToken.php',
|
||||||
'PhabricatorConduitConsoleController' => 'applications/conduit/controller/PhabricatorConduitConsoleController.php',
|
'PhabricatorConduitConsoleController' => 'applications/conduit/controller/PhabricatorConduitConsoleController.php',
|
||||||
'PhabricatorConduitContentSource' => 'infrastructure/contentsource/PhabricatorConduitContentSource.php',
|
'PhabricatorConduitContentSource' => 'infrastructure/contentsource/PhabricatorConduitContentSource.php',
|
||||||
|
@ -2435,6 +2471,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorConduitLogController' => 'applications/conduit/controller/PhabricatorConduitLogController.php',
|
'PhabricatorConduitLogController' => 'applications/conduit/controller/PhabricatorConduitLogController.php',
|
||||||
'PhabricatorConduitLogQuery' => 'applications/conduit/query/PhabricatorConduitLogQuery.php',
|
'PhabricatorConduitLogQuery' => 'applications/conduit/query/PhabricatorConduitLogQuery.php',
|
||||||
'PhabricatorConduitLogSearchEngine' => 'applications/conduit/query/PhabricatorConduitLogSearchEngine.php',
|
'PhabricatorConduitLogSearchEngine' => 'applications/conduit/query/PhabricatorConduitLogSearchEngine.php',
|
||||||
|
'PhabricatorConduitManagementWorkflow' => 'applications/conduit/management/PhabricatorConduitManagementWorkflow.php',
|
||||||
'PhabricatorConduitMethodCallLog' => 'applications/conduit/storage/PhabricatorConduitMethodCallLog.php',
|
'PhabricatorConduitMethodCallLog' => 'applications/conduit/storage/PhabricatorConduitMethodCallLog.php',
|
||||||
'PhabricatorConduitMethodQuery' => 'applications/conduit/query/PhabricatorConduitMethodQuery.php',
|
'PhabricatorConduitMethodQuery' => 'applications/conduit/query/PhabricatorConduitMethodQuery.php',
|
||||||
'PhabricatorConduitRequestExceptionHandler' => 'aphront/handler/PhabricatorConduitRequestExceptionHandler.php',
|
'PhabricatorConduitRequestExceptionHandler' => 'aphront/handler/PhabricatorConduitRequestExceptionHandler.php',
|
||||||
|
@ -2810,6 +2847,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorEditPage' => 'applications/transactions/editengine/PhabricatorEditPage.php',
|
'PhabricatorEditPage' => 'applications/transactions/editengine/PhabricatorEditPage.php',
|
||||||
'PhabricatorEditType' => 'applications/transactions/edittype/PhabricatorEditType.php',
|
'PhabricatorEditType' => 'applications/transactions/edittype/PhabricatorEditType.php',
|
||||||
'PhabricatorEditor' => 'infrastructure/PhabricatorEditor.php',
|
'PhabricatorEditor' => 'infrastructure/PhabricatorEditor.php',
|
||||||
|
'PhabricatorEditorMailEngineExtension' => 'applications/transactions/engineextension/PhabricatorEditorMailEngineExtension.php',
|
||||||
'PhabricatorEditorMultipleSetting' => 'applications/settings/setting/PhabricatorEditorMultipleSetting.php',
|
'PhabricatorEditorMultipleSetting' => 'applications/settings/setting/PhabricatorEditorMultipleSetting.php',
|
||||||
'PhabricatorEditorSetting' => 'applications/settings/setting/PhabricatorEditorSetting.php',
|
'PhabricatorEditorSetting' => 'applications/settings/setting/PhabricatorEditorSetting.php',
|
||||||
'PhabricatorElasticFulltextStorageEngine' => 'applications/search/fulltextstorage/PhabricatorElasticFulltextStorageEngine.php',
|
'PhabricatorElasticFulltextStorageEngine' => 'applications/search/fulltextstorage/PhabricatorElasticFulltextStorageEngine.php',
|
||||||
|
@ -2826,6 +2864,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorEmailPreferencesSettingsPanel' => 'applications/settings/panel/PhabricatorEmailPreferencesSettingsPanel.php',
|
'PhabricatorEmailPreferencesSettingsPanel' => 'applications/settings/panel/PhabricatorEmailPreferencesSettingsPanel.php',
|
||||||
'PhabricatorEmailRePrefixSetting' => 'applications/settings/setting/PhabricatorEmailRePrefixSetting.php',
|
'PhabricatorEmailRePrefixSetting' => 'applications/settings/setting/PhabricatorEmailRePrefixSetting.php',
|
||||||
'PhabricatorEmailSelfActionsSetting' => 'applications/settings/setting/PhabricatorEmailSelfActionsSetting.php',
|
'PhabricatorEmailSelfActionsSetting' => 'applications/settings/setting/PhabricatorEmailSelfActionsSetting.php',
|
||||||
|
'PhabricatorEmailStampsSetting' => 'applications/settings/setting/PhabricatorEmailStampsSetting.php',
|
||||||
'PhabricatorEmailTagsSetting' => 'applications/settings/setting/PhabricatorEmailTagsSetting.php',
|
'PhabricatorEmailTagsSetting' => 'applications/settings/setting/PhabricatorEmailTagsSetting.php',
|
||||||
'PhabricatorEmailVarySubjectsSetting' => 'applications/settings/setting/PhabricatorEmailVarySubjectsSetting.php',
|
'PhabricatorEmailVarySubjectsSetting' => 'applications/settings/setting/PhabricatorEmailVarySubjectsSetting.php',
|
||||||
'PhabricatorEmailVerificationController' => 'applications/auth/controller/PhabricatorEmailVerificationController.php',
|
'PhabricatorEmailVerificationController' => 'applications/auth/controller/PhabricatorEmailVerificationController.php',
|
||||||
|
@ -3164,19 +3203,23 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorMacroQuery' => 'applications/macro/query/PhabricatorMacroQuery.php',
|
'PhabricatorMacroQuery' => 'applications/macro/query/PhabricatorMacroQuery.php',
|
||||||
'PhabricatorMacroReplyHandler' => 'applications/macro/mail/PhabricatorMacroReplyHandler.php',
|
'PhabricatorMacroReplyHandler' => 'applications/macro/mail/PhabricatorMacroReplyHandler.php',
|
||||||
'PhabricatorMacroSearchEngine' => 'applications/macro/query/PhabricatorMacroSearchEngine.php',
|
'PhabricatorMacroSearchEngine' => 'applications/macro/query/PhabricatorMacroSearchEngine.php',
|
||||||
|
'PhabricatorMacroTestCase' => 'applications/macro/xaction/__tests__/PhabricatorMacroTestCase.php',
|
||||||
'PhabricatorMacroTransaction' => 'applications/macro/storage/PhabricatorMacroTransaction.php',
|
'PhabricatorMacroTransaction' => 'applications/macro/storage/PhabricatorMacroTransaction.php',
|
||||||
'PhabricatorMacroTransactionComment' => 'applications/macro/storage/PhabricatorMacroTransactionComment.php',
|
'PhabricatorMacroTransactionComment' => 'applications/macro/storage/PhabricatorMacroTransactionComment.php',
|
||||||
'PhabricatorMacroTransactionQuery' => 'applications/macro/query/PhabricatorMacroTransactionQuery.php',
|
'PhabricatorMacroTransactionQuery' => 'applications/macro/query/PhabricatorMacroTransactionQuery.php',
|
||||||
'PhabricatorMacroTransactionType' => 'applications/macro/xaction/PhabricatorMacroTransactionType.php',
|
'PhabricatorMacroTransactionType' => 'applications/macro/xaction/PhabricatorMacroTransactionType.php',
|
||||||
'PhabricatorMacroViewController' => 'applications/macro/controller/PhabricatorMacroViewController.php',
|
'PhabricatorMacroViewController' => 'applications/macro/controller/PhabricatorMacroViewController.php',
|
||||||
|
'PhabricatorMailConfigTestCase' => 'applications/metamta/storage/__tests__/PhabricatorMailConfigTestCase.php',
|
||||||
'PhabricatorMailEmailHeraldField' => 'applications/metamta/herald/PhabricatorMailEmailHeraldField.php',
|
'PhabricatorMailEmailHeraldField' => 'applications/metamta/herald/PhabricatorMailEmailHeraldField.php',
|
||||||
'PhabricatorMailEmailHeraldFieldGroup' => 'applications/metamta/herald/PhabricatorMailEmailHeraldFieldGroup.php',
|
'PhabricatorMailEmailHeraldFieldGroup' => 'applications/metamta/herald/PhabricatorMailEmailHeraldFieldGroup.php',
|
||||||
'PhabricatorMailEmailSubjectHeraldField' => 'applications/metamta/herald/PhabricatorMailEmailSubjectHeraldField.php',
|
'PhabricatorMailEmailSubjectHeraldField' => 'applications/metamta/herald/PhabricatorMailEmailSubjectHeraldField.php',
|
||||||
|
'PhabricatorMailEngineExtension' => 'applications/metamta/engine/PhabricatorMailEngineExtension.php',
|
||||||
'PhabricatorMailImplementationAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationAdapter.php',
|
'PhabricatorMailImplementationAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationAdapter.php',
|
||||||
'PhabricatorMailImplementationAmazonSESAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationAmazonSESAdapter.php',
|
'PhabricatorMailImplementationAmazonSESAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationAmazonSESAdapter.php',
|
||||||
'PhabricatorMailImplementationMailgunAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationMailgunAdapter.php',
|
'PhabricatorMailImplementationMailgunAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationMailgunAdapter.php',
|
||||||
'PhabricatorMailImplementationPHPMailerAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationPHPMailerAdapter.php',
|
'PhabricatorMailImplementationPHPMailerAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationPHPMailerAdapter.php',
|
||||||
'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationPHPMailerLiteAdapter.php',
|
'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationPHPMailerLiteAdapter.php',
|
||||||
|
'PhabricatorMailImplementationPostmarkAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationPostmarkAdapter.php',
|
||||||
'PhabricatorMailImplementationSendGridAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationSendGridAdapter.php',
|
'PhabricatorMailImplementationSendGridAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationSendGridAdapter.php',
|
||||||
'PhabricatorMailImplementationTestAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationTestAdapter.php',
|
'PhabricatorMailImplementationTestAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationTestAdapter.php',
|
||||||
'PhabricatorMailManagementListInboundWorkflow' => 'applications/metamta/management/PhabricatorMailManagementListInboundWorkflow.php',
|
'PhabricatorMailManagementListInboundWorkflow' => 'applications/metamta/management/PhabricatorMailManagementListInboundWorkflow.php',
|
||||||
|
@ -3189,6 +3232,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorMailManagementUnverifyWorkflow' => 'applications/metamta/management/PhabricatorMailManagementUnverifyWorkflow.php',
|
'PhabricatorMailManagementUnverifyWorkflow' => 'applications/metamta/management/PhabricatorMailManagementUnverifyWorkflow.php',
|
||||||
'PhabricatorMailManagementVolumeWorkflow' => 'applications/metamta/management/PhabricatorMailManagementVolumeWorkflow.php',
|
'PhabricatorMailManagementVolumeWorkflow' => 'applications/metamta/management/PhabricatorMailManagementVolumeWorkflow.php',
|
||||||
'PhabricatorMailManagementWorkflow' => 'applications/metamta/management/PhabricatorMailManagementWorkflow.php',
|
'PhabricatorMailManagementWorkflow' => 'applications/metamta/management/PhabricatorMailManagementWorkflow.php',
|
||||||
|
'PhabricatorMailMustEncryptHeraldAction' => 'applications/metamta/herald/PhabricatorMailMustEncryptHeraldAction.php',
|
||||||
'PhabricatorMailOutboundMailHeraldAdapter' => 'applications/metamta/herald/PhabricatorMailOutboundMailHeraldAdapter.php',
|
'PhabricatorMailOutboundMailHeraldAdapter' => 'applications/metamta/herald/PhabricatorMailOutboundMailHeraldAdapter.php',
|
||||||
'PhabricatorMailOutboundRoutingHeraldAction' => 'applications/metamta/herald/PhabricatorMailOutboundRoutingHeraldAction.php',
|
'PhabricatorMailOutboundRoutingHeraldAction' => 'applications/metamta/herald/PhabricatorMailOutboundRoutingHeraldAction.php',
|
||||||
'PhabricatorMailOutboundRoutingSelfEmailHeraldAction' => 'applications/metamta/herald/PhabricatorMailOutboundRoutingSelfEmailHeraldAction.php',
|
'PhabricatorMailOutboundRoutingSelfEmailHeraldAction' => 'applications/metamta/herald/PhabricatorMailOutboundRoutingSelfEmailHeraldAction.php',
|
||||||
|
@ -3199,6 +3243,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorMailReplyHandler' => 'applications/metamta/replyhandler/PhabricatorMailReplyHandler.php',
|
'PhabricatorMailReplyHandler' => 'applications/metamta/replyhandler/PhabricatorMailReplyHandler.php',
|
||||||
'PhabricatorMailRoutingRule' => 'applications/metamta/constants/PhabricatorMailRoutingRule.php',
|
'PhabricatorMailRoutingRule' => 'applications/metamta/constants/PhabricatorMailRoutingRule.php',
|
||||||
'PhabricatorMailSetupCheck' => 'applications/config/check/PhabricatorMailSetupCheck.php',
|
'PhabricatorMailSetupCheck' => 'applications/config/check/PhabricatorMailSetupCheck.php',
|
||||||
|
'PhabricatorMailStamp' => 'applications/metamta/stamp/PhabricatorMailStamp.php',
|
||||||
'PhabricatorMailTarget' => 'applications/metamta/replyhandler/PhabricatorMailTarget.php',
|
'PhabricatorMailTarget' => 'applications/metamta/replyhandler/PhabricatorMailTarget.php',
|
||||||
'PhabricatorMailgunConfigOptions' => 'applications/config/option/PhabricatorMailgunConfigOptions.php',
|
'PhabricatorMailgunConfigOptions' => 'applications/config/option/PhabricatorMailgunConfigOptions.php',
|
||||||
'PhabricatorMainMenuBarExtension' => 'view/page/menu/PhabricatorMainMenuBarExtension.php',
|
'PhabricatorMainMenuBarExtension' => 'view/page/menu/PhabricatorMainMenuBarExtension.php',
|
||||||
|
@ -3258,6 +3303,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorMetaMTAMailgunReceiveController' => 'applications/metamta/controller/PhabricatorMetaMTAMailgunReceiveController.php',
|
'PhabricatorMetaMTAMailgunReceiveController' => 'applications/metamta/controller/PhabricatorMetaMTAMailgunReceiveController.php',
|
||||||
'PhabricatorMetaMTAMemberQuery' => 'applications/metamta/query/PhabricatorMetaMTAMemberQuery.php',
|
'PhabricatorMetaMTAMemberQuery' => 'applications/metamta/query/PhabricatorMetaMTAMemberQuery.php',
|
||||||
'PhabricatorMetaMTAPermanentFailureException' => 'applications/metamta/exception/PhabricatorMetaMTAPermanentFailureException.php',
|
'PhabricatorMetaMTAPermanentFailureException' => 'applications/metamta/exception/PhabricatorMetaMTAPermanentFailureException.php',
|
||||||
|
'PhabricatorMetaMTAPostmarkReceiveController' => 'applications/metamta/controller/PhabricatorMetaMTAPostmarkReceiveController.php',
|
||||||
'PhabricatorMetaMTAReceivedMail' => 'applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php',
|
'PhabricatorMetaMTAReceivedMail' => 'applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php',
|
||||||
'PhabricatorMetaMTAReceivedMailProcessingException' => 'applications/metamta/exception/PhabricatorMetaMTAReceivedMailProcessingException.php',
|
'PhabricatorMetaMTAReceivedMailProcessingException' => 'applications/metamta/exception/PhabricatorMetaMTAReceivedMailProcessingException.php',
|
||||||
'PhabricatorMetaMTAReceivedMailTestCase' => 'applications/metamta/storage/__tests__/PhabricatorMetaMTAReceivedMailTestCase.php',
|
'PhabricatorMetaMTAReceivedMailTestCase' => 'applications/metamta/storage/__tests__/PhabricatorMetaMTAReceivedMailTestCase.php',
|
||||||
|
@ -3275,6 +3321,8 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorMultiFactorSettingsPanel' => 'applications/settings/panel/PhabricatorMultiFactorSettingsPanel.php',
|
'PhabricatorMultiFactorSettingsPanel' => 'applications/settings/panel/PhabricatorMultiFactorSettingsPanel.php',
|
||||||
'PhabricatorMultimeterApplication' => 'applications/multimeter/application/PhabricatorMultimeterApplication.php',
|
'PhabricatorMultimeterApplication' => 'applications/multimeter/application/PhabricatorMultimeterApplication.php',
|
||||||
'PhabricatorMustVerifyEmailController' => 'applications/auth/controller/PhabricatorMustVerifyEmailController.php',
|
'PhabricatorMustVerifyEmailController' => 'applications/auth/controller/PhabricatorMustVerifyEmailController.php',
|
||||||
|
'PhabricatorMutedByEdgeType' => 'applications/transactions/edges/PhabricatorMutedByEdgeType.php',
|
||||||
|
'PhabricatorMutedEdgeType' => 'applications/transactions/edges/PhabricatorMutedEdgeType.php',
|
||||||
'PhabricatorMySQLConfigOptions' => 'applications/config/option/PhabricatorMySQLConfigOptions.php',
|
'PhabricatorMySQLConfigOptions' => 'applications/config/option/PhabricatorMySQLConfigOptions.php',
|
||||||
'PhabricatorMySQLFileStorageEngine' => 'applications/files/engine/PhabricatorMySQLFileStorageEngine.php',
|
'PhabricatorMySQLFileStorageEngine' => 'applications/files/engine/PhabricatorMySQLFileStorageEngine.php',
|
||||||
'PhabricatorMySQLSearchHost' => 'infrastructure/cluster/search/PhabricatorMySQLSearchHost.php',
|
'PhabricatorMySQLSearchHost' => 'infrastructure/cluster/search/PhabricatorMySQLSearchHost.php',
|
||||||
|
@ -3433,6 +3481,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorPHIDListEditField' => 'applications/transactions/editfield/PhabricatorPHIDListEditField.php',
|
'PhabricatorPHIDListEditField' => 'applications/transactions/editfield/PhabricatorPHIDListEditField.php',
|
||||||
'PhabricatorPHIDListEditType' => 'applications/transactions/edittype/PhabricatorPHIDListEditType.php',
|
'PhabricatorPHIDListEditType' => 'applications/transactions/edittype/PhabricatorPHIDListEditType.php',
|
||||||
'PhabricatorPHIDListExportField' => 'infrastructure/export/field/PhabricatorPHIDListExportField.php',
|
'PhabricatorPHIDListExportField' => 'infrastructure/export/field/PhabricatorPHIDListExportField.php',
|
||||||
|
'PhabricatorPHIDMailStamp' => 'applications/metamta/stamp/PhabricatorPHIDMailStamp.php',
|
||||||
'PhabricatorPHIDResolver' => 'applications/phid/resolver/PhabricatorPHIDResolver.php',
|
'PhabricatorPHIDResolver' => 'applications/phid/resolver/PhabricatorPHIDResolver.php',
|
||||||
'PhabricatorPHIDType' => 'applications/phid/type/PhabricatorPHIDType.php',
|
'PhabricatorPHIDType' => 'applications/phid/type/PhabricatorPHIDType.php',
|
||||||
'PhabricatorPHIDTypeTestCase' => 'applications/phid/type/__tests__/PhabricatorPHIDTypeTestCase.php',
|
'PhabricatorPHIDTypeTestCase' => 'applications/phid/type/__tests__/PhabricatorPHIDTypeTestCase.php',
|
||||||
|
@ -3843,6 +3892,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorProjectsEditField' => 'applications/transactions/editfield/PhabricatorProjectsEditField.php',
|
'PhabricatorProjectsEditField' => 'applications/transactions/editfield/PhabricatorProjectsEditField.php',
|
||||||
'PhabricatorProjectsExportEngineExtension' => 'infrastructure/export/engine/PhabricatorProjectsExportEngineExtension.php',
|
'PhabricatorProjectsExportEngineExtension' => 'infrastructure/export/engine/PhabricatorProjectsExportEngineExtension.php',
|
||||||
'PhabricatorProjectsFulltextEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsFulltextEngineExtension.php',
|
'PhabricatorProjectsFulltextEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsFulltextEngineExtension.php',
|
||||||
|
'PhabricatorProjectsMailEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsMailEngineExtension.php',
|
||||||
'PhabricatorProjectsMembersSearchEngineAttachment' => 'applications/project/engineextension/PhabricatorProjectsMembersSearchEngineAttachment.php',
|
'PhabricatorProjectsMembersSearchEngineAttachment' => 'applications/project/engineextension/PhabricatorProjectsMembersSearchEngineAttachment.php',
|
||||||
'PhabricatorProjectsMembershipIndexEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsMembershipIndexEngineExtension.php',
|
'PhabricatorProjectsMembershipIndexEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsMembershipIndexEngineExtension.php',
|
||||||
'PhabricatorProjectsPolicyRule' => 'applications/project/policyrule/PhabricatorProjectsPolicyRule.php',
|
'PhabricatorProjectsPolicyRule' => 'applications/project/policyrule/PhabricatorProjectsPolicyRule.php',
|
||||||
|
@ -4136,6 +4186,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSpacesExportEngineExtension' => 'infrastructure/export/engine/PhabricatorSpacesExportEngineExtension.php',
|
'PhabricatorSpacesExportEngineExtension' => 'infrastructure/export/engine/PhabricatorSpacesExportEngineExtension.php',
|
||||||
'PhabricatorSpacesInterface' => 'applications/spaces/interface/PhabricatorSpacesInterface.php',
|
'PhabricatorSpacesInterface' => 'applications/spaces/interface/PhabricatorSpacesInterface.php',
|
||||||
'PhabricatorSpacesListController' => 'applications/spaces/controller/PhabricatorSpacesListController.php',
|
'PhabricatorSpacesListController' => 'applications/spaces/controller/PhabricatorSpacesListController.php',
|
||||||
|
'PhabricatorSpacesMailEngineExtension' => 'applications/spaces/engineextension/PhabricatorSpacesMailEngineExtension.php',
|
||||||
'PhabricatorSpacesNamespace' => 'applications/spaces/storage/PhabricatorSpacesNamespace.php',
|
'PhabricatorSpacesNamespace' => 'applications/spaces/storage/PhabricatorSpacesNamespace.php',
|
||||||
'PhabricatorSpacesNamespaceArchiveTransaction' => 'applications/spaces/xaction/PhabricatorSpacesNamespaceArchiveTransaction.php',
|
'PhabricatorSpacesNamespaceArchiveTransaction' => 'applications/spaces/xaction/PhabricatorSpacesNamespaceArchiveTransaction.php',
|
||||||
'PhabricatorSpacesNamespaceDatasource' => 'applications/spaces/typeahead/PhabricatorSpacesNamespaceDatasource.php',
|
'PhabricatorSpacesNamespaceDatasource' => 'applications/spaces/typeahead/PhabricatorSpacesNamespaceDatasource.php',
|
||||||
|
@ -4201,6 +4252,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorStringListConfigType' => 'applications/config/type/PhabricatorStringListConfigType.php',
|
'PhabricatorStringListConfigType' => 'applications/config/type/PhabricatorStringListConfigType.php',
|
||||||
'PhabricatorStringListEditField' => 'applications/transactions/editfield/PhabricatorStringListEditField.php',
|
'PhabricatorStringListEditField' => 'applications/transactions/editfield/PhabricatorStringListEditField.php',
|
||||||
'PhabricatorStringListExportField' => 'infrastructure/export/field/PhabricatorStringListExportField.php',
|
'PhabricatorStringListExportField' => 'infrastructure/export/field/PhabricatorStringListExportField.php',
|
||||||
|
'PhabricatorStringMailStamp' => 'applications/metamta/stamp/PhabricatorStringMailStamp.php',
|
||||||
'PhabricatorStringSetting' => 'applications/settings/setting/PhabricatorStringSetting.php',
|
'PhabricatorStringSetting' => 'applications/settings/setting/PhabricatorStringSetting.php',
|
||||||
'PhabricatorSubmitEditField' => 'applications/transactions/editfield/PhabricatorSubmitEditField.php',
|
'PhabricatorSubmitEditField' => 'applications/transactions/editfield/PhabricatorSubmitEditField.php',
|
||||||
'PhabricatorSubscribableInterface' => 'applications/subscriptions/interface/PhabricatorSubscribableInterface.php',
|
'PhabricatorSubscribableInterface' => 'applications/subscriptions/interface/PhabricatorSubscribableInterface.php',
|
||||||
|
@ -4219,6 +4271,8 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSubscriptionsFulltextEngineExtension' => 'applications/subscriptions/engineextension/PhabricatorSubscriptionsFulltextEngineExtension.php',
|
'PhabricatorSubscriptionsFulltextEngineExtension' => 'applications/subscriptions/engineextension/PhabricatorSubscriptionsFulltextEngineExtension.php',
|
||||||
'PhabricatorSubscriptionsHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsHeraldAction.php',
|
'PhabricatorSubscriptionsHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsHeraldAction.php',
|
||||||
'PhabricatorSubscriptionsListController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsListController.php',
|
'PhabricatorSubscriptionsListController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsListController.php',
|
||||||
|
'PhabricatorSubscriptionsMailEngineExtension' => 'applications/subscriptions/engineextension/PhabricatorSubscriptionsMailEngineExtension.php',
|
||||||
|
'PhabricatorSubscriptionsMuteController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsMuteController.php',
|
||||||
'PhabricatorSubscriptionsRemoveSelfHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsRemoveSelfHeraldAction.php',
|
'PhabricatorSubscriptionsRemoveSelfHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsRemoveSelfHeraldAction.php',
|
||||||
'PhabricatorSubscriptionsRemoveSubscribersHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsRemoveSubscribersHeraldAction.php',
|
'PhabricatorSubscriptionsRemoveSubscribersHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsRemoveSubscribersHeraldAction.php',
|
||||||
'PhabricatorSubscriptionsSearchEngineAttachment' => 'applications/subscriptions/engineextension/PhabricatorSubscriptionsSearchEngineAttachment.php',
|
'PhabricatorSubscriptionsSearchEngineAttachment' => 'applications/subscriptions/engineextension/PhabricatorSubscriptionsSearchEngineAttachment.php',
|
||||||
|
@ -5596,6 +5650,7 @@ phutil_register_library_map(array(
|
||||||
'DifferentialLintField' => 'DifferentialHarbormasterField',
|
'DifferentialLintField' => 'DifferentialHarbormasterField',
|
||||||
'DifferentialLintStatus' => 'Phobject',
|
'DifferentialLintStatus' => 'Phobject',
|
||||||
'DifferentialLocalCommitsView' => 'AphrontView',
|
'DifferentialLocalCommitsView' => 'AphrontView',
|
||||||
|
'DifferentialMailEngineExtension' => 'PhabricatorMailEngineExtension',
|
||||||
'DifferentialMailView' => 'Phobject',
|
'DifferentialMailView' => 'Phobject',
|
||||||
'DifferentialManiphestTasksField' => 'DifferentialCoreCustomField',
|
'DifferentialManiphestTasksField' => 'DifferentialCoreCustomField',
|
||||||
'DifferentialModernHunk' => 'DifferentialHunk',
|
'DifferentialModernHunk' => 'DifferentialHunk',
|
||||||
|
@ -6568,6 +6623,7 @@ phutil_register_library_map(array(
|
||||||
'HarbormasterWaitForPreviousBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
|
'HarbormasterWaitForPreviousBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
|
||||||
'HarbormasterWorker' => 'PhabricatorWorker',
|
'HarbormasterWorker' => 'PhabricatorWorker',
|
||||||
'HarbormasterWorkingCopyArtifact' => 'HarbormasterDrydockLeaseArtifact',
|
'HarbormasterWorkingCopyArtifact' => 'HarbormasterDrydockLeaseArtifact',
|
||||||
|
'HeraldActingUserField' => 'HeraldField',
|
||||||
'HeraldAction' => 'Phobject',
|
'HeraldAction' => 'Phobject',
|
||||||
'HeraldActionGroup' => 'HeraldGroup',
|
'HeraldActionGroup' => 'HeraldGroup',
|
||||||
'HeraldActionRecord' => 'HeraldDAO',
|
'HeraldActionRecord' => 'HeraldDAO',
|
||||||
|
@ -6578,6 +6634,7 @@ phutil_register_library_map(array(
|
||||||
'HeraldApplyTranscript' => 'Phobject',
|
'HeraldApplyTranscript' => 'Phobject',
|
||||||
'HeraldBasicFieldGroup' => 'HeraldFieldGroup',
|
'HeraldBasicFieldGroup' => 'HeraldFieldGroup',
|
||||||
'HeraldBuildableState' => 'HeraldState',
|
'HeraldBuildableState' => 'HeraldState',
|
||||||
|
'HeraldCallWebhookAction' => 'HeraldAction',
|
||||||
'HeraldCommentAction' => 'HeraldAction',
|
'HeraldCommentAction' => 'HeraldAction',
|
||||||
'HeraldCommitAdapter' => array(
|
'HeraldCommitAdapter' => array(
|
||||||
'HeraldAdapter',
|
'HeraldAdapter',
|
||||||
|
@ -6588,6 +6645,7 @@ phutil_register_library_map(array(
|
||||||
'HeraldContentSourceField' => 'HeraldField',
|
'HeraldContentSourceField' => 'HeraldField',
|
||||||
'HeraldController' => 'PhabricatorController',
|
'HeraldController' => 'PhabricatorController',
|
||||||
'HeraldCoreStateReasons' => 'HeraldStateReasons',
|
'HeraldCoreStateReasons' => 'HeraldStateReasons',
|
||||||
|
'HeraldCreateWebhooksCapability' => 'PhabricatorPolicyCapability',
|
||||||
'HeraldDAO' => 'PhabricatorLiskDAO',
|
'HeraldDAO' => 'PhabricatorLiskDAO',
|
||||||
'HeraldDeprecatedFieldGroup' => 'HeraldFieldGroup',
|
'HeraldDeprecatedFieldGroup' => 'HeraldFieldGroup',
|
||||||
'HeraldDifferentialAdapter' => 'HeraldAdapter',
|
'HeraldDifferentialAdapter' => 'HeraldAdapter',
|
||||||
|
@ -6678,6 +6736,43 @@ phutil_register_library_map(array(
|
||||||
'HeraldTranscriptSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
'HeraldTranscriptSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||||
'HeraldTranscriptTestCase' => 'PhabricatorTestCase',
|
'HeraldTranscriptTestCase' => 'PhabricatorTestCase',
|
||||||
'HeraldUtilityActionGroup' => 'HeraldActionGroup',
|
'HeraldUtilityActionGroup' => 'HeraldActionGroup',
|
||||||
|
'HeraldWebhook' => array(
|
||||||
|
'HeraldDAO',
|
||||||
|
'PhabricatorPolicyInterface',
|
||||||
|
'PhabricatorApplicationTransactionInterface',
|
||||||
|
'PhabricatorDestructibleInterface',
|
||||||
|
'PhabricatorProjectInterface',
|
||||||
|
),
|
||||||
|
'HeraldWebhookCallManagementWorkflow' => 'HeraldWebhookManagementWorkflow',
|
||||||
|
'HeraldWebhookController' => 'HeraldController',
|
||||||
|
'HeraldWebhookDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||||
|
'HeraldWebhookEditController' => 'HeraldWebhookController',
|
||||||
|
'HeraldWebhookEditEngine' => 'PhabricatorEditEngine',
|
||||||
|
'HeraldWebhookEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||||
|
'HeraldWebhookKeyController' => 'HeraldWebhookController',
|
||||||
|
'HeraldWebhookListController' => 'HeraldWebhookController',
|
||||||
|
'HeraldWebhookManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||||
|
'HeraldWebhookNameTransaction' => 'HeraldWebhookTransactionType',
|
||||||
|
'HeraldWebhookPHIDType' => 'PhabricatorPHIDType',
|
||||||
|
'HeraldWebhookQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
|
'HeraldWebhookRequest' => array(
|
||||||
|
'HeraldDAO',
|
||||||
|
'PhabricatorPolicyInterface',
|
||||||
|
'PhabricatorExtendedPolicyInterface',
|
||||||
|
),
|
||||||
|
'HeraldWebhookRequestGarbageCollector' => 'PhabricatorGarbageCollector',
|
||||||
|
'HeraldWebhookRequestListView' => 'AphrontView',
|
||||||
|
'HeraldWebhookRequestPHIDType' => 'PhabricatorPHIDType',
|
||||||
|
'HeraldWebhookRequestQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
|
'HeraldWebhookSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||||
|
'HeraldWebhookStatusTransaction' => 'HeraldWebhookTransactionType',
|
||||||
|
'HeraldWebhookTestController' => 'HeraldWebhookController',
|
||||||
|
'HeraldWebhookTransaction' => 'PhabricatorModularTransaction',
|
||||||
|
'HeraldWebhookTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||||
|
'HeraldWebhookTransactionType' => 'PhabricatorModularTransactionType',
|
||||||
|
'HeraldWebhookURITransaction' => 'HeraldWebhookTransactionType',
|
||||||
|
'HeraldWebhookViewController' => 'HeraldWebhookController',
|
||||||
|
'HeraldWebhookWorker' => 'PhabricatorWorker',
|
||||||
'Javelin' => 'Phobject',
|
'Javelin' => 'Phobject',
|
||||||
'LegalpadController' => 'PhabricatorController',
|
'LegalpadController' => 'PhabricatorController',
|
||||||
'LegalpadCreateDocumentsCapability' => 'PhabricatorPolicyCapability',
|
'LegalpadCreateDocumentsCapability' => 'PhabricatorPolicyCapability',
|
||||||
|
@ -6783,6 +6878,7 @@ phutil_register_library_map(array(
|
||||||
'ManiphestGetTaskTransactionsConduitAPIMethod' => 'ManiphestConduitAPIMethod',
|
'ManiphestGetTaskTransactionsConduitAPIMethod' => 'ManiphestConduitAPIMethod',
|
||||||
'ManiphestHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension',
|
'ManiphestHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension',
|
||||||
'ManiphestInfoConduitAPIMethod' => 'ManiphestConduitAPIMethod',
|
'ManiphestInfoConduitAPIMethod' => 'ManiphestConduitAPIMethod',
|
||||||
|
'ManiphestMailEngineExtension' => 'PhabricatorMailEngineExtension',
|
||||||
'ManiphestNameIndex' => 'ManiphestDAO',
|
'ManiphestNameIndex' => 'ManiphestDAO',
|
||||||
'ManiphestPointsConfigType' => 'PhabricatorJSONConfigType',
|
'ManiphestPointsConfigType' => 'PhabricatorJSONConfigType',
|
||||||
'ManiphestPrioritiesConfigType' => 'PhabricatorJSONConfigType',
|
'ManiphestPrioritiesConfigType' => 'PhabricatorJSONConfigType',
|
||||||
|
@ -7266,6 +7362,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorApplicationEditHTTPParameterHelpView' => 'AphrontView',
|
'PhabricatorApplicationEditHTTPParameterHelpView' => 'AphrontView',
|
||||||
'PhabricatorApplicationEditor' => 'PhabricatorApplicationTransactionEditor',
|
'PhabricatorApplicationEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||||
'PhabricatorApplicationEmailCommandsController' => 'PhabricatorApplicationsController',
|
'PhabricatorApplicationEmailCommandsController' => 'PhabricatorApplicationsController',
|
||||||
|
'PhabricatorApplicationObjectMailEngineExtension' => 'PhabricatorMailEngineExtension',
|
||||||
'PhabricatorApplicationPanelController' => 'PhabricatorApplicationsController',
|
'PhabricatorApplicationPanelController' => 'PhabricatorApplicationsController',
|
||||||
'PhabricatorApplicationPolicyChangeTransaction' => 'PhabricatorApplicationTransactionType',
|
'PhabricatorApplicationPolicyChangeTransaction' => 'PhabricatorApplicationTransactionType',
|
||||||
'PhabricatorApplicationProfileMenuItem' => 'PhabricatorProfileMenuItem',
|
'PhabricatorApplicationProfileMenuItem' => 'PhabricatorProfileMenuItem',
|
||||||
|
@ -7573,6 +7670,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorBoardResponseEngine' => 'Phobject',
|
'PhabricatorBoardResponseEngine' => 'Phobject',
|
||||||
'PhabricatorBoolConfigType' => 'PhabricatorTextConfigType',
|
'PhabricatorBoolConfigType' => 'PhabricatorTextConfigType',
|
||||||
'PhabricatorBoolEditField' => 'PhabricatorEditField',
|
'PhabricatorBoolEditField' => 'PhabricatorEditField',
|
||||||
|
'PhabricatorBoolMailStamp' => 'PhabricatorMailStamp',
|
||||||
'PhabricatorBritishEnglishTranslation' => 'PhutilTranslation',
|
'PhabricatorBritishEnglishTranslation' => 'PhutilTranslation',
|
||||||
'PhabricatorBuiltinDraftEngine' => 'PhabricatorDraftEngine',
|
'PhabricatorBuiltinDraftEngine' => 'PhabricatorDraftEngine',
|
||||||
'PhabricatorBuiltinFileCachePurger' => 'PhabricatorCachePurger',
|
'PhabricatorBuiltinFileCachePurger' => 'PhabricatorCachePurger',
|
||||||
|
@ -7804,6 +7902,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorClusterExceptionHandler' => 'PhabricatorRequestExceptionHandler',
|
'PhabricatorClusterExceptionHandler' => 'PhabricatorRequestExceptionHandler',
|
||||||
'PhabricatorClusterImpossibleWriteException' => 'PhabricatorClusterException',
|
'PhabricatorClusterImpossibleWriteException' => 'PhabricatorClusterException',
|
||||||
'PhabricatorClusterImproperWriteException' => 'PhabricatorClusterException',
|
'PhabricatorClusterImproperWriteException' => 'PhabricatorClusterException',
|
||||||
|
'PhabricatorClusterMailersConfigType' => 'PhabricatorJSONConfigType',
|
||||||
'PhabricatorClusterNoHostForRoleException' => 'Exception',
|
'PhabricatorClusterNoHostForRoleException' => 'Exception',
|
||||||
'PhabricatorClusterSearchConfigType' => 'PhabricatorJSONConfigType',
|
'PhabricatorClusterSearchConfigType' => 'PhabricatorJSONConfigType',
|
||||||
'PhabricatorClusterServiceHealthRecord' => 'Phobject',
|
'PhabricatorClusterServiceHealthRecord' => 'Phobject',
|
||||||
|
@ -7821,6 +7920,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCommonPasswords' => 'Phobject',
|
'PhabricatorCommonPasswords' => 'Phobject',
|
||||||
'PhabricatorConduitAPIController' => 'PhabricatorConduitController',
|
'PhabricatorConduitAPIController' => 'PhabricatorConduitController',
|
||||||
'PhabricatorConduitApplication' => 'PhabricatorApplication',
|
'PhabricatorConduitApplication' => 'PhabricatorApplication',
|
||||||
|
'PhabricatorConduitCallManagementWorkflow' => 'PhabricatorConduitManagementWorkflow',
|
||||||
'PhabricatorConduitCertificateToken' => 'PhabricatorConduitDAO',
|
'PhabricatorConduitCertificateToken' => 'PhabricatorConduitDAO',
|
||||||
'PhabricatorConduitConsoleController' => 'PhabricatorConduitController',
|
'PhabricatorConduitConsoleController' => 'PhabricatorConduitController',
|
||||||
'PhabricatorConduitContentSource' => 'PhabricatorContentSource',
|
'PhabricatorConduitContentSource' => 'PhabricatorContentSource',
|
||||||
|
@ -7831,6 +7931,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorConduitLogController' => 'PhabricatorConduitController',
|
'PhabricatorConduitLogController' => 'PhabricatorConduitController',
|
||||||
'PhabricatorConduitLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'PhabricatorConduitLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
'PhabricatorConduitLogSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
'PhabricatorConduitLogSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||||
|
'PhabricatorConduitManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||||
'PhabricatorConduitMethodCallLog' => array(
|
'PhabricatorConduitMethodCallLog' => array(
|
||||||
'PhabricatorConduitDAO',
|
'PhabricatorConduitDAO',
|
||||||
'PhabricatorPolicyInterface',
|
'PhabricatorPolicyInterface',
|
||||||
|
@ -8256,6 +8357,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorEditPage' => 'Phobject',
|
'PhabricatorEditPage' => 'Phobject',
|
||||||
'PhabricatorEditType' => 'Phobject',
|
'PhabricatorEditType' => 'Phobject',
|
||||||
'PhabricatorEditor' => 'Phobject',
|
'PhabricatorEditor' => 'Phobject',
|
||||||
|
'PhabricatorEditorMailEngineExtension' => 'PhabricatorMailEngineExtension',
|
||||||
'PhabricatorEditorMultipleSetting' => 'PhabricatorSelectSetting',
|
'PhabricatorEditorMultipleSetting' => 'PhabricatorSelectSetting',
|
||||||
'PhabricatorEditorSetting' => 'PhabricatorStringSetting',
|
'PhabricatorEditorSetting' => 'PhabricatorStringSetting',
|
||||||
'PhabricatorElasticFulltextStorageEngine' => 'PhabricatorFulltextStorageEngine',
|
'PhabricatorElasticFulltextStorageEngine' => 'PhabricatorFulltextStorageEngine',
|
||||||
|
@ -8271,6 +8373,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorEmailPreferencesSettingsPanel' => 'PhabricatorSettingsPanel',
|
'PhabricatorEmailPreferencesSettingsPanel' => 'PhabricatorSettingsPanel',
|
||||||
'PhabricatorEmailRePrefixSetting' => 'PhabricatorSelectSetting',
|
'PhabricatorEmailRePrefixSetting' => 'PhabricatorSelectSetting',
|
||||||
'PhabricatorEmailSelfActionsSetting' => 'PhabricatorSelectSetting',
|
'PhabricatorEmailSelfActionsSetting' => 'PhabricatorSelectSetting',
|
||||||
|
'PhabricatorEmailStampsSetting' => 'PhabricatorSelectSetting',
|
||||||
'PhabricatorEmailTagsSetting' => 'PhabricatorInternalSetting',
|
'PhabricatorEmailTagsSetting' => 'PhabricatorInternalSetting',
|
||||||
'PhabricatorEmailVarySubjectsSetting' => 'PhabricatorSelectSetting',
|
'PhabricatorEmailVarySubjectsSetting' => 'PhabricatorSelectSetting',
|
||||||
'PhabricatorEmailVerificationController' => 'PhabricatorAuthController',
|
'PhabricatorEmailVerificationController' => 'PhabricatorAuthController',
|
||||||
|
@ -8649,19 +8752,23 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorMacroQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'PhabricatorMacroQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
'PhabricatorMacroReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler',
|
'PhabricatorMacroReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler',
|
||||||
'PhabricatorMacroSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
'PhabricatorMacroSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||||
|
'PhabricatorMacroTestCase' => 'PhabricatorTestCase',
|
||||||
'PhabricatorMacroTransaction' => 'PhabricatorModularTransaction',
|
'PhabricatorMacroTransaction' => 'PhabricatorModularTransaction',
|
||||||
'PhabricatorMacroTransactionComment' => 'PhabricatorApplicationTransactionComment',
|
'PhabricatorMacroTransactionComment' => 'PhabricatorApplicationTransactionComment',
|
||||||
'PhabricatorMacroTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
'PhabricatorMacroTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||||
'PhabricatorMacroTransactionType' => 'PhabricatorModularTransactionType',
|
'PhabricatorMacroTransactionType' => 'PhabricatorModularTransactionType',
|
||||||
'PhabricatorMacroViewController' => 'PhabricatorMacroController',
|
'PhabricatorMacroViewController' => 'PhabricatorMacroController',
|
||||||
|
'PhabricatorMailConfigTestCase' => 'PhabricatorTestCase',
|
||||||
'PhabricatorMailEmailHeraldField' => 'HeraldField',
|
'PhabricatorMailEmailHeraldField' => 'HeraldField',
|
||||||
'PhabricatorMailEmailHeraldFieldGroup' => 'HeraldFieldGroup',
|
'PhabricatorMailEmailHeraldFieldGroup' => 'HeraldFieldGroup',
|
||||||
'PhabricatorMailEmailSubjectHeraldField' => 'PhabricatorMailEmailHeraldField',
|
'PhabricatorMailEmailSubjectHeraldField' => 'PhabricatorMailEmailHeraldField',
|
||||||
|
'PhabricatorMailEngineExtension' => 'Phobject',
|
||||||
'PhabricatorMailImplementationAdapter' => 'Phobject',
|
'PhabricatorMailImplementationAdapter' => 'Phobject',
|
||||||
'PhabricatorMailImplementationAmazonSESAdapter' => 'PhabricatorMailImplementationPHPMailerLiteAdapter',
|
'PhabricatorMailImplementationAmazonSESAdapter' => 'PhabricatorMailImplementationPHPMailerLiteAdapter',
|
||||||
'PhabricatorMailImplementationMailgunAdapter' => 'PhabricatorMailImplementationAdapter',
|
'PhabricatorMailImplementationMailgunAdapter' => 'PhabricatorMailImplementationAdapter',
|
||||||
'PhabricatorMailImplementationPHPMailerAdapter' => 'PhabricatorMailImplementationAdapter',
|
'PhabricatorMailImplementationPHPMailerAdapter' => 'PhabricatorMailImplementationAdapter',
|
||||||
'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'PhabricatorMailImplementationAdapter',
|
'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'PhabricatorMailImplementationAdapter',
|
||||||
|
'PhabricatorMailImplementationPostmarkAdapter' => 'PhabricatorMailImplementationAdapter',
|
||||||
'PhabricatorMailImplementationSendGridAdapter' => 'PhabricatorMailImplementationAdapter',
|
'PhabricatorMailImplementationSendGridAdapter' => 'PhabricatorMailImplementationAdapter',
|
||||||
'PhabricatorMailImplementationTestAdapter' => 'PhabricatorMailImplementationAdapter',
|
'PhabricatorMailImplementationTestAdapter' => 'PhabricatorMailImplementationAdapter',
|
||||||
'PhabricatorMailManagementListInboundWorkflow' => 'PhabricatorMailManagementWorkflow',
|
'PhabricatorMailManagementListInboundWorkflow' => 'PhabricatorMailManagementWorkflow',
|
||||||
|
@ -8674,6 +8781,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorMailManagementUnverifyWorkflow' => 'PhabricatorMailManagementWorkflow',
|
'PhabricatorMailManagementUnverifyWorkflow' => 'PhabricatorMailManagementWorkflow',
|
||||||
'PhabricatorMailManagementVolumeWorkflow' => 'PhabricatorMailManagementWorkflow',
|
'PhabricatorMailManagementVolumeWorkflow' => 'PhabricatorMailManagementWorkflow',
|
||||||
'PhabricatorMailManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
'PhabricatorMailManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||||
|
'PhabricatorMailMustEncryptHeraldAction' => 'HeraldAction',
|
||||||
'PhabricatorMailOutboundMailHeraldAdapter' => 'HeraldAdapter',
|
'PhabricatorMailOutboundMailHeraldAdapter' => 'HeraldAdapter',
|
||||||
'PhabricatorMailOutboundRoutingHeraldAction' => 'HeraldAction',
|
'PhabricatorMailOutboundRoutingHeraldAction' => 'HeraldAction',
|
||||||
'PhabricatorMailOutboundRoutingSelfEmailHeraldAction' => 'PhabricatorMailOutboundRoutingHeraldAction',
|
'PhabricatorMailOutboundRoutingSelfEmailHeraldAction' => 'PhabricatorMailOutboundRoutingHeraldAction',
|
||||||
|
@ -8684,6 +8792,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorMailReplyHandler' => 'Phobject',
|
'PhabricatorMailReplyHandler' => 'Phobject',
|
||||||
'PhabricatorMailRoutingRule' => 'Phobject',
|
'PhabricatorMailRoutingRule' => 'Phobject',
|
||||||
'PhabricatorMailSetupCheck' => 'PhabricatorSetupCheck',
|
'PhabricatorMailSetupCheck' => 'PhabricatorSetupCheck',
|
||||||
|
'PhabricatorMailStamp' => 'Phobject',
|
||||||
'PhabricatorMailTarget' => 'Phobject',
|
'PhabricatorMailTarget' => 'Phobject',
|
||||||
'PhabricatorMailgunConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
'PhabricatorMailgunConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||||
'PhabricatorMainMenuBarExtension' => 'Phobject',
|
'PhabricatorMainMenuBarExtension' => 'Phobject',
|
||||||
|
@ -8737,6 +8846,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorMetaMTAMail' => array(
|
'PhabricatorMetaMTAMail' => array(
|
||||||
'PhabricatorMetaMTADAO',
|
'PhabricatorMetaMTADAO',
|
||||||
'PhabricatorPolicyInterface',
|
'PhabricatorPolicyInterface',
|
||||||
|
'PhabricatorDestructibleInterface',
|
||||||
),
|
),
|
||||||
'PhabricatorMetaMTAMailBody' => 'Phobject',
|
'PhabricatorMetaMTAMailBody' => 'Phobject',
|
||||||
'PhabricatorMetaMTAMailBodyTestCase' => 'PhabricatorTestCase',
|
'PhabricatorMetaMTAMailBodyTestCase' => 'PhabricatorTestCase',
|
||||||
|
@ -8753,6 +8863,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorMetaMTAMailgunReceiveController' => 'PhabricatorMetaMTAController',
|
'PhabricatorMetaMTAMailgunReceiveController' => 'PhabricatorMetaMTAController',
|
||||||
'PhabricatorMetaMTAMemberQuery' => 'PhabricatorQuery',
|
'PhabricatorMetaMTAMemberQuery' => 'PhabricatorQuery',
|
||||||
'PhabricatorMetaMTAPermanentFailureException' => 'Exception',
|
'PhabricatorMetaMTAPermanentFailureException' => 'Exception',
|
||||||
|
'PhabricatorMetaMTAPostmarkReceiveController' => 'PhabricatorMetaMTAController',
|
||||||
'PhabricatorMetaMTAReceivedMail' => 'PhabricatorMetaMTADAO',
|
'PhabricatorMetaMTAReceivedMail' => 'PhabricatorMetaMTADAO',
|
||||||
'PhabricatorMetaMTAReceivedMailProcessingException' => 'Exception',
|
'PhabricatorMetaMTAReceivedMailProcessingException' => 'Exception',
|
||||||
'PhabricatorMetaMTAReceivedMailTestCase' => 'PhabricatorTestCase',
|
'PhabricatorMetaMTAReceivedMailTestCase' => 'PhabricatorTestCase',
|
||||||
|
@ -8770,6 +8881,8 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorMultiFactorSettingsPanel' => 'PhabricatorSettingsPanel',
|
'PhabricatorMultiFactorSettingsPanel' => 'PhabricatorSettingsPanel',
|
||||||
'PhabricatorMultimeterApplication' => 'PhabricatorApplication',
|
'PhabricatorMultimeterApplication' => 'PhabricatorApplication',
|
||||||
'PhabricatorMustVerifyEmailController' => 'PhabricatorAuthController',
|
'PhabricatorMustVerifyEmailController' => 'PhabricatorAuthController',
|
||||||
|
'PhabricatorMutedByEdgeType' => 'PhabricatorEdgeType',
|
||||||
|
'PhabricatorMutedEdgeType' => 'PhabricatorEdgeType',
|
||||||
'PhabricatorMySQLConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
'PhabricatorMySQLConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||||
'PhabricatorMySQLFileStorageEngine' => 'PhabricatorFileStorageEngine',
|
'PhabricatorMySQLFileStorageEngine' => 'PhabricatorFileStorageEngine',
|
||||||
'PhabricatorMySQLSearchHost' => 'PhabricatorSearchHost',
|
'PhabricatorMySQLSearchHost' => 'PhabricatorSearchHost',
|
||||||
|
@ -8957,6 +9070,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorPHIDListEditField' => 'PhabricatorEditField',
|
'PhabricatorPHIDListEditField' => 'PhabricatorEditField',
|
||||||
'PhabricatorPHIDListEditType' => 'PhabricatorEditType',
|
'PhabricatorPHIDListEditType' => 'PhabricatorEditType',
|
||||||
'PhabricatorPHIDListExportField' => 'PhabricatorListExportField',
|
'PhabricatorPHIDListExportField' => 'PhabricatorListExportField',
|
||||||
|
'PhabricatorPHIDMailStamp' => 'PhabricatorMailStamp',
|
||||||
'PhabricatorPHIDResolver' => 'Phobject',
|
'PhabricatorPHIDResolver' => 'Phobject',
|
||||||
'PhabricatorPHIDType' => 'Phobject',
|
'PhabricatorPHIDType' => 'Phobject',
|
||||||
'PhabricatorPHIDTypeTestCase' => 'PhutilTestCase',
|
'PhabricatorPHIDTypeTestCase' => 'PhutilTestCase',
|
||||||
|
@ -9459,6 +9573,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorProjectsEditField' => 'PhabricatorTokenizerEditField',
|
'PhabricatorProjectsEditField' => 'PhabricatorTokenizerEditField',
|
||||||
'PhabricatorProjectsExportEngineExtension' => 'PhabricatorExportEngineExtension',
|
'PhabricatorProjectsExportEngineExtension' => 'PhabricatorExportEngineExtension',
|
||||||
'PhabricatorProjectsFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension',
|
'PhabricatorProjectsFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension',
|
||||||
|
'PhabricatorProjectsMailEngineExtension' => 'PhabricatorMailEngineExtension',
|
||||||
'PhabricatorProjectsMembersSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
'PhabricatorProjectsMembersSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
||||||
'PhabricatorProjectsMembershipIndexEngineExtension' => 'PhabricatorIndexEngineExtension',
|
'PhabricatorProjectsMembershipIndexEngineExtension' => 'PhabricatorIndexEngineExtension',
|
||||||
'PhabricatorProjectsPolicyRule' => 'PhabricatorPolicyRule',
|
'PhabricatorProjectsPolicyRule' => 'PhabricatorPolicyRule',
|
||||||
|
@ -9828,6 +9943,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSpacesExportEngineExtension' => 'PhabricatorExportEngineExtension',
|
'PhabricatorSpacesExportEngineExtension' => 'PhabricatorExportEngineExtension',
|
||||||
'PhabricatorSpacesInterface' => 'PhabricatorPHIDInterface',
|
'PhabricatorSpacesInterface' => 'PhabricatorPHIDInterface',
|
||||||
'PhabricatorSpacesListController' => 'PhabricatorSpacesController',
|
'PhabricatorSpacesListController' => 'PhabricatorSpacesController',
|
||||||
|
'PhabricatorSpacesMailEngineExtension' => 'PhabricatorMailEngineExtension',
|
||||||
'PhabricatorSpacesNamespace' => array(
|
'PhabricatorSpacesNamespace' => array(
|
||||||
'PhabricatorSpacesDAO',
|
'PhabricatorSpacesDAO',
|
||||||
'PhabricatorPolicyInterface',
|
'PhabricatorPolicyInterface',
|
||||||
|
@ -9900,6 +10016,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorStringListConfigType' => 'PhabricatorTextListConfigType',
|
'PhabricatorStringListConfigType' => 'PhabricatorTextListConfigType',
|
||||||
'PhabricatorStringListEditField' => 'PhabricatorEditField',
|
'PhabricatorStringListEditField' => 'PhabricatorEditField',
|
||||||
'PhabricatorStringListExportField' => 'PhabricatorListExportField',
|
'PhabricatorStringListExportField' => 'PhabricatorListExportField',
|
||||||
|
'PhabricatorStringMailStamp' => 'PhabricatorMailStamp',
|
||||||
'PhabricatorStringSetting' => 'PhabricatorSetting',
|
'PhabricatorStringSetting' => 'PhabricatorSetting',
|
||||||
'PhabricatorSubmitEditField' => 'PhabricatorEditField',
|
'PhabricatorSubmitEditField' => 'PhabricatorEditField',
|
||||||
'PhabricatorSubscribedToObjectEdgeType' => 'PhabricatorEdgeType',
|
'PhabricatorSubscribedToObjectEdgeType' => 'PhabricatorEdgeType',
|
||||||
|
@ -9917,6 +10034,8 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSubscriptionsFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension',
|
'PhabricatorSubscriptionsFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension',
|
||||||
'PhabricatorSubscriptionsHeraldAction' => 'HeraldAction',
|
'PhabricatorSubscriptionsHeraldAction' => 'HeraldAction',
|
||||||
'PhabricatorSubscriptionsListController' => 'PhabricatorController',
|
'PhabricatorSubscriptionsListController' => 'PhabricatorController',
|
||||||
|
'PhabricatorSubscriptionsMailEngineExtension' => 'PhabricatorMailEngineExtension',
|
||||||
|
'PhabricatorSubscriptionsMuteController' => 'PhabricatorController',
|
||||||
'PhabricatorSubscriptionsRemoveSelfHeraldAction' => 'PhabricatorSubscriptionsHeraldAction',
|
'PhabricatorSubscriptionsRemoveSelfHeraldAction' => 'PhabricatorSubscriptionsHeraldAction',
|
||||||
'PhabricatorSubscriptionsRemoveSubscribersHeraldAction' => 'PhabricatorSubscriptionsHeraldAction',
|
'PhabricatorSubscriptionsRemoveSubscribersHeraldAction' => 'PhabricatorSubscriptionsHeraldAction',
|
||||||
'PhabricatorSubscriptionsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
'PhabricatorSubscriptionsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
||||||
|
|
|
@ -81,6 +81,8 @@ final class AlmanacManagementTrustKeyWorkflow
|
||||||
$key->setIsTrusted(1);
|
$key->setIsTrusted(1);
|
||||||
$key->save();
|
$key->save();
|
||||||
|
|
||||||
|
PhabricatorAuthSSHKeyQuery::deleteSSHKeyCache();
|
||||||
|
|
||||||
$console->writeOut(
|
$console->writeOut(
|
||||||
"**<bg:green> %s </bg>** %s\n",
|
"**<bg:green> %s </bg>** %s\n",
|
||||||
pht('TRUSTED'),
|
pht('TRUSTED'),
|
||||||
|
|
|
@ -43,6 +43,8 @@ final class AlmanacManagementUntrustKeyWorkflow
|
||||||
$key->setIsTrusted(0);
|
$key->setIsTrusted(0);
|
||||||
$key->save();
|
$key->save();
|
||||||
|
|
||||||
|
PhabricatorAuthSSHKeyQuery::deleteSSHKeyCache();
|
||||||
|
|
||||||
$console->writeOut(
|
$console->writeOut(
|
||||||
"**<bg:green> %s </bg>** %s\n",
|
"**<bg:green> %s </bg>** %s\n",
|
||||||
pht('TRUST REVOKED'),
|
pht('TRUST REVOKED'),
|
||||||
|
|
|
@ -473,17 +473,14 @@ final class PhabricatorAuditEditor
|
||||||
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
|
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
|
||||||
$identifier = $object->getCommitIdentifier();
|
$identifier = $object->getCommitIdentifier();
|
||||||
$repository = $object->getRepository();
|
$repository = $object->getRepository();
|
||||||
$monogram = $repository->getMonogram();
|
|
||||||
|
|
||||||
$summary = $object->getSummary();
|
$summary = $object->getSummary();
|
||||||
$name = $repository->formatCommitName($identifier);
|
$name = $repository->formatCommitName($identifier);
|
||||||
|
|
||||||
$subject = "{$name}: {$summary}";
|
$subject = "{$name}: {$summary}";
|
||||||
$thread_topic = "Commit {$monogram}{$identifier}";
|
|
||||||
|
|
||||||
$template = id(new PhabricatorMetaMTAMail())
|
$template = id(new PhabricatorMetaMTAMail())
|
||||||
->setSubject($subject)
|
->setSubject($subject);
|
||||||
->addHeader('Thread-Topic', $thread_topic);
|
|
||||||
|
|
||||||
$this->attachPatch(
|
$this->attachPatch(
|
||||||
$template,
|
$template,
|
||||||
|
@ -493,13 +490,14 @@ final class PhabricatorAuditEditor
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getMailTo(PhabricatorLiskDAO $object) {
|
protected function getMailTo(PhabricatorLiskDAO $object) {
|
||||||
|
$this->requireAuditors($object);
|
||||||
|
|
||||||
$phids = array();
|
$phids = array();
|
||||||
|
|
||||||
if ($object->getAuthorPHID()) {
|
if ($object->getAuthorPHID()) {
|
||||||
$phids[] = $object->getAuthorPHID();
|
$phids[] = $object->getAuthorPHID();
|
||||||
}
|
}
|
||||||
|
|
||||||
$status_resigned = PhabricatorAuditStatusConstants::RESIGNED;
|
|
||||||
foreach ($object->getAudits() as $audit) {
|
foreach ($object->getAudits() as $audit) {
|
||||||
if (!$audit->isInteresting()) {
|
if (!$audit->isInteresting()) {
|
||||||
// Don't send mail to uninteresting auditors, like packages which
|
// Don't send mail to uninteresting auditors, like packages which
|
||||||
|
@ -507,7 +505,7 @@ final class PhabricatorAuditEditor
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($audit->getAuditStatus() != $status_resigned) {
|
if (!$audit->isResigned()) {
|
||||||
$phids[] = $audit->getAuditorPHID();
|
$phids[] = $audit->getAuditorPHID();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -517,6 +515,20 @@ final class PhabricatorAuditEditor
|
||||||
return $phids;
|
return $phids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function newMailUnexpandablePHIDs(PhabricatorLiskDAO $object) {
|
||||||
|
$this->requireAuditors($object);
|
||||||
|
|
||||||
|
$phids = array();
|
||||||
|
|
||||||
|
foreach ($object->getAudits() as $auditor) {
|
||||||
|
if ($auditor->isResigned()) {
|
||||||
|
$phids[] = $auditor->getAuditorPHID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $phids;
|
||||||
|
}
|
||||||
|
|
||||||
protected function buildMailBody(
|
protected function buildMailBody(
|
||||||
PhabricatorLiskDAO $object,
|
PhabricatorLiskDAO $object,
|
||||||
array $xactions) {
|
array $xactions) {
|
||||||
|
@ -848,4 +860,24 @@ final class PhabricatorAuditEditor
|
||||||
->executeOne();
|
->executeOne();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function requireAuditors(PhabricatorRepositoryCommit $commit) {
|
||||||
|
if ($commit->hasAttachedAudits()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$with_auditors = id(new DiffusionCommitQuery())
|
||||||
|
->setViewer($this->getActor())
|
||||||
|
->needAuditRequests(true)
|
||||||
|
->withPHIDs(array($commit->getPHID()))
|
||||||
|
->executeOne();
|
||||||
|
if (!$with_auditors) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Failed to reload commit ("%s").',
|
||||||
|
$commit->getPHID()));
|
||||||
|
}
|
||||||
|
|
||||||
|
$commit->attachAudits($with_auditors->getAudits());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -255,11 +255,9 @@ final class PhabricatorAuthSSHKeyEditor
|
||||||
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
|
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
|
||||||
$id = $object->getID();
|
$id = $object->getID();
|
||||||
$name = $object->getName();
|
$name = $object->getName();
|
||||||
$phid = $object->getPHID();
|
|
||||||
|
|
||||||
$mail = id(new PhabricatorMetaMTAMail())
|
$mail = id(new PhabricatorMetaMTAMail())
|
||||||
->setSubject(pht('SSH Key %d: %s', $id, $name))
|
->setSubject(pht('SSH Key %d: %s', $id, $name));
|
||||||
->addHeader('Thread-Topic', $phid);
|
|
||||||
|
|
||||||
// The primary value of this mail is alerting users to account compromises,
|
// The primary value of this mail is alerting users to account compromises,
|
||||||
// so force delivery. In particular, this mail should still be delivered
|
// so force delivery. In particular, this mail should still be delivered
|
||||||
|
|
|
@ -87,12 +87,10 @@ final class PhabricatorBadgesEditor
|
||||||
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
|
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
|
||||||
$name = $object->getName();
|
$name = $object->getName();
|
||||||
$id = $object->getID();
|
$id = $object->getID();
|
||||||
$topic = pht('Badge %d', $id);
|
|
||||||
$subject = pht('Badge %d: %s', $id, $name);
|
$subject = pht('Badge %d: %s', $id, $name);
|
||||||
|
|
||||||
return id(new PhabricatorMetaMTAMail())
|
return id(new PhabricatorMetaMTAMail())
|
||||||
->setSubject($subject)
|
->setSubject($subject);
|
||||||
->addHeader('Thread-Topic', $topic);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getMailTo(PhabricatorLiskDAO $object) {
|
protected function getMailTo(PhabricatorLiskDAO $object) {
|
||||||
|
|
|
@ -309,13 +309,11 @@ final class PhabricatorCalendarEventEditor
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
|
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
|
||||||
$id = $object->getID();
|
|
||||||
$name = $object->getName();
|
$name = $object->getName();
|
||||||
$monogram = $object->getMonogram();
|
$monogram = $object->getMonogram();
|
||||||
|
|
||||||
return id(new PhabricatorMetaMTAMail())
|
return id(new PhabricatorMetaMTAMail())
|
||||||
->setSubject("{$monogram}: {$name}")
|
->setSubject("{$monogram}: {$name}");
|
||||||
->addHeader('Thread-Topic', $monogram);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildMailBody(
|
protected function buildMailBody(
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorConduitCallManagementWorkflow
|
||||||
|
extends PhabricatorConduitManagementWorkflow {
|
||||||
|
|
||||||
|
protected function didConstruct() {
|
||||||
|
$this
|
||||||
|
->setName('call')
|
||||||
|
->setSynopsis(pht('Call a Conduit method..'))
|
||||||
|
->setArguments(
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
'name' => 'method',
|
||||||
|
'param' => 'method',
|
||||||
|
'help' => pht('Method to call.'),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'input',
|
||||||
|
'param' => 'input',
|
||||||
|
'help' => pht(
|
||||||
|
'File to read parameters from, or "-" to read from '.
|
||||||
|
'stdin.'),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(PhutilArgumentParser $args) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$method = $args->getArg('method');
|
||||||
|
if (!strlen($method)) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht('Specify a method to call with "--method".'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$input = $args->getArg('input');
|
||||||
|
if (!strlen($input)) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht('Specify a file to read parameters from with "--input".'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($input === '-') {
|
||||||
|
fprintf(STDERR, tsprintf("%s\n", pht('Reading input from stdin...')));
|
||||||
|
$input_json = file_get_contents('php://stdin');
|
||||||
|
} else {
|
||||||
|
$input_json = Filesystem::readFile($input);
|
||||||
|
}
|
||||||
|
|
||||||
|
$params = phutil_json_decode($input_json);
|
||||||
|
|
||||||
|
$result = id(new ConduitCall($method, $params))
|
||||||
|
->setUser($viewer)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$output = array(
|
||||||
|
'result' => $result,
|
||||||
|
);
|
||||||
|
|
||||||
|
echo tsprintf(
|
||||||
|
"%B\n",
|
||||||
|
id(new PhutilJSON())->encodeFormatted($output));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class PhabricatorConduitManagementWorkflow
|
||||||
|
extends PhabricatorManagementWorkflow {}
|
|
@ -7,6 +7,10 @@ final class PhabricatorMailSetupCheck extends PhabricatorSetupCheck {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function executeChecks() {
|
protected function executeChecks() {
|
||||||
|
if (PhabricatorEnv::getEnvConfig('cluster.mailers')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$adapter = PhabricatorEnv::getEnvConfig('metamta.mail-adapter');
|
$adapter = PhabricatorEnv::getEnvConfig('metamta.mail-adapter');
|
||||||
|
|
||||||
switch ($adapter) {
|
switch ($adapter) {
|
||||||
|
|
|
@ -6,7 +6,9 @@ final class PhabricatorConfigManagementSetWorkflow
|
||||||
protected function didConstruct() {
|
protected function didConstruct() {
|
||||||
$this
|
$this
|
||||||
->setName('set')
|
->setName('set')
|
||||||
->setExamples('**set** __key__ __value__')
|
->setExamples(
|
||||||
|
"**set** __key__ __value__\n".
|
||||||
|
"**set** __key__ --stdin < value.json")
|
||||||
->setSynopsis(pht('Set a local configuration value.'))
|
->setSynopsis(pht('Set a local configuration value.'))
|
||||||
->setArguments(
|
->setArguments(
|
||||||
array(
|
array(
|
||||||
|
@ -16,6 +18,10 @@ final class PhabricatorConfigManagementSetWorkflow
|
||||||
'Update configuration in the database instead of '.
|
'Update configuration in the database instead of '.
|
||||||
'in local configuration.'),
|
'in local configuration.'),
|
||||||
),
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'stdin',
|
||||||
|
'help' => pht('Read option value from stdin.'),
|
||||||
|
),
|
||||||
array(
|
array(
|
||||||
'name' => 'args',
|
'name' => 'args',
|
||||||
'wildcard' => true,
|
'wildcard' => true,
|
||||||
|
@ -31,22 +37,36 @@ final class PhabricatorConfigManagementSetWorkflow
|
||||||
pht('Specify a configuration key and a value to set it to.'));
|
pht('Specify a configuration key and a value to set it to.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$is_stdin = $args->getArg('stdin');
|
||||||
|
|
||||||
$key = $argv[0];
|
$key = $argv[0];
|
||||||
|
|
||||||
if (count($argv) == 1) {
|
if ($is_stdin) {
|
||||||
throw new PhutilArgumentUsageException(
|
if (count($argv) > 1) {
|
||||||
pht(
|
throw new PhutilArgumentUsageException(
|
||||||
"Specify a value to set the key '%s' to.",
|
pht(
|
||||||
$key));
|
'Too many arguments: expected only a key when using "--stdin".'));
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(STDERR, tsprintf("%s\n", pht('Reading value from stdin...')));
|
||||||
|
$value = file_get_contents('php://stdin');
|
||||||
|
} else {
|
||||||
|
if (count($argv) == 1) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
"Specify a value to set the key '%s' to.",
|
||||||
|
$key));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($argv) > 2) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'Too many arguments: expected one key and one value.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = $argv[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
$value = $argv[1];
|
|
||||||
|
|
||||||
if (count($argv) > 2) {
|
|
||||||
throw new PhutilArgumentUsageException(
|
|
||||||
pht(
|
|
||||||
'Too many arguments: expected one key and one value.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$options = PhabricatorApplicationConfigOptions::loadAllOptions();
|
$options = PhabricatorApplicationConfigOptions::loadAllOptions();
|
||||||
if (empty($options[$key])) {
|
if (empty($options[$key])) {
|
||||||
|
|
|
@ -66,7 +66,9 @@ of each approach are:
|
||||||
received a similar message, but can not prevent all stray email arising
|
received a similar message, but can not prevent all stray email arising
|
||||||
from "Reply All".
|
from "Reply All".
|
||||||
- Not supported with a private reply-to address.
|
- Not supported with a private reply-to address.
|
||||||
- Mails are sent in the server default translation.
|
- Mail messages are sent in the server default translation.
|
||||||
|
- Mail that must be delivered over secure channels will leak the recipient
|
||||||
|
list in the "To" and "Cc" headers.
|
||||||
- One mail to each user:
|
- One mail to each user:
|
||||||
- Policy controls work correctly and are enforced per-user.
|
- Policy controls work correctly and are enforced per-user.
|
||||||
- Recipients need to look in the mail body to see To/Cc.
|
- Recipients need to look in the mail body to see To/Cc.
|
||||||
|
@ -77,7 +79,7 @@ of each approach are:
|
||||||
- "Reply All" will never send extra mail to other users involved in the
|
- "Reply All" will never send extra mail to other users involved in the
|
||||||
thread.
|
thread.
|
||||||
- Required if private reply-to addresses are configured.
|
- Required if private reply-to addresses are configured.
|
||||||
- Mails are sent in the language of user preference.
|
- Mail messages are sent in the language of user preference.
|
||||||
|
|
||||||
EODOC
|
EODOC
|
||||||
));
|
));
|
||||||
|
@ -138,24 +140,19 @@ EODOC
|
||||||
,
|
,
|
||||||
'metamta.public-replies'));
|
'metamta.public-replies'));
|
||||||
|
|
||||||
$adapter_doc_href = PhabricatorEnv::getDoclink(
|
|
||||||
'Configuring Outbound Email');
|
|
||||||
$adapter_doc_name = pht('Configuring Outbound Email');
|
|
||||||
$adapter_description = $this->deformat(pht(<<<EODOC
|
$adapter_description = $this->deformat(pht(<<<EODOC
|
||||||
Adapter class to use to transmit mail to the MTA. The default uses
|
Adapter class to use to transmit mail to the MTA. The default uses
|
||||||
PHPMailerLite, which will invoke "sendmail". This is appropriate if sendmail
|
PHPMailerLite, which will invoke "sendmail". This is appropriate if sendmail
|
||||||
actually works on your host, but if you haven't configured mail it may not be so
|
actually works on your host, but if you haven't configured mail it may not be so
|
||||||
great. A number of other mailers are available (e.g., SES, SendGrid, SMTP,
|
great. A number of other mailers are available (e.g., SES, SendGrid, SMTP,
|
||||||
custom mailers) - consult [[ %s | %s ]] for details.
|
custom mailers). This option is deprecated in favor of 'cluster.mailers'.
|
||||||
EODOC
|
EODOC
|
||||||
,
|
));
|
||||||
$adapter_doc_href,
|
|
||||||
$adapter_doc_name));
|
|
||||||
|
|
||||||
$placeholder_description = $this->deformat(pht(<<<EODOC
|
$placeholder_description = $this->deformat(pht(<<<EODOC
|
||||||
When sending a message that has no To recipient (i.e. all recipients are CC'd,
|
When sending a message that has no To recipient (i.e. all recipients are CC'd),
|
||||||
for example when multiplexing mail), set the To field to the following value. If
|
set the To field to the following value. If no value is set, messages with no
|
||||||
no value is set, messages with no To will have their CCs upgraded to To.
|
To will have their CCs upgraded to To.
|
||||||
EODOC
|
EODOC
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -197,7 +194,18 @@ The default is `full`.
|
||||||
EODOC
|
EODOC
|
||||||
));
|
));
|
||||||
|
|
||||||
|
$mailers_description = $this->deformat(pht(<<<EODOC
|
||||||
|
Define one or more mail transmission services. For help with configuring
|
||||||
|
mailers, see **[[ %s | %s ]]** in the documentation.
|
||||||
|
EODOC
|
||||||
|
,
|
||||||
|
PhabricatorEnv::getDoclink('Configuring Outbound Email'),
|
||||||
|
pht('Configuring Outbound Email')));
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
|
$this->newOption('cluster.mailers', 'cluster.mailers', null)
|
||||||
|
->setHidden(true)
|
||||||
|
->setDescription($mailers_description),
|
||||||
$this->newOption(
|
$this->newOption(
|
||||||
'metamta.default-address',
|
'metamta.default-address',
|
||||||
'string',
|
'string',
|
||||||
|
|
|
@ -227,11 +227,9 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
||||||
'%s sent you a message.',
|
'%s sent you a message.',
|
||||||
$this->getActor()->getUserName());
|
$this->getActor()->getUserName());
|
||||||
}
|
}
|
||||||
$phid = $object->getPHID();
|
|
||||||
|
|
||||||
return id(new PhabricatorMetaMTAMail())
|
return id(new PhabricatorMetaMTAMail())
|
||||||
->setSubject("Z{$id}: {$title}")
|
->setSubject("Z{$id}: {$title}");
|
||||||
->addHeader('Thread-Topic', "Z{$id}: {$phid}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getMailTo(PhabricatorLiskDAO $object) {
|
protected function getMailTo(PhabricatorLiskDAO $object) {
|
||||||
|
|
|
@ -45,8 +45,7 @@ final class PhabricatorCountdownEditor
|
||||||
$name = $object->getTitle();
|
$name = $object->getTitle();
|
||||||
|
|
||||||
return id(new PhabricatorMetaMTAMail())
|
return id(new PhabricatorMetaMTAMail())
|
||||||
->setSubject("{$monogram}: {$name}")
|
->setSubject("{$monogram}: {$name}");
|
||||||
->addHeader('Thread-Topic', $monogram);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildMailBody(
|
protected function buildMailBody(
|
||||||
|
|
|
@ -632,6 +632,8 @@ final class DifferentialTransactionEditor
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getMailTo(PhabricatorLiskDAO $object) {
|
protected function getMailTo(PhabricatorLiskDAO $object) {
|
||||||
|
$this->requireReviewers($object);
|
||||||
|
|
||||||
$phids = array();
|
$phids = array();
|
||||||
$phids[] = $object->getAuthorPHID();
|
$phids[] = $object->getAuthorPHID();
|
||||||
foreach ($object->getReviewers() as $reviewer) {
|
foreach ($object->getReviewers() as $reviewer) {
|
||||||
|
@ -644,6 +646,20 @@ final class DifferentialTransactionEditor
|
||||||
return $phids;
|
return $phids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function newMailUnexpandablePHIDs(PhabricatorLiskDAO $object) {
|
||||||
|
$this->requireReviewers($object);
|
||||||
|
|
||||||
|
$phids = array();
|
||||||
|
|
||||||
|
foreach ($object->getReviewers() as $reviewer) {
|
||||||
|
if ($reviewer->isResigned()) {
|
||||||
|
$phids[] = $reviewer->getReviewerPHID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $phids;
|
||||||
|
}
|
||||||
|
|
||||||
protected function getMailAction(
|
protected function getMailAction(
|
||||||
PhabricatorLiskDAO $object,
|
PhabricatorLiskDAO $object,
|
||||||
array $xactions) {
|
array $xactions) {
|
||||||
|
@ -689,15 +705,10 @@ final class DifferentialTransactionEditor
|
||||||
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
|
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
|
||||||
$id = $object->getID();
|
$id = $object->getID();
|
||||||
$title = $object->getTitle();
|
$title = $object->getTitle();
|
||||||
|
|
||||||
$original_title = $object->getOriginalTitle();
|
|
||||||
|
|
||||||
$subject = "D{$id}: {$title}";
|
$subject = "D{$id}: {$title}";
|
||||||
$thread_topic = "D{$id}: {$original_title}";
|
|
||||||
|
|
||||||
return id(new PhabricatorMetaMTAMail())
|
return id(new PhabricatorMetaMTAMail())
|
||||||
->setSubject($subject)
|
->setSubject($subject);
|
||||||
->addHeader('Thread-Topic', $thread_topic);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getTransactionsForMail(
|
protected function getTransactionsForMail(
|
||||||
|
@ -1730,4 +1741,25 @@ final class DifferentialTransactionEditor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function requireReviewers(DifferentialRevision $revision) {
|
||||||
|
if ($revision->hasAttachedReviewers()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$with_reviewers = id(new DifferentialRevisionQuery())
|
||||||
|
->setViewer($this->getActor())
|
||||||
|
->needReviewers(true)
|
||||||
|
->withPHIDs(array($revision->getPHID()))
|
||||||
|
->executeOne();
|
||||||
|
if (!$with_reviewers) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Failed to reload revision ("%s").',
|
||||||
|
$revision->getPHID()));
|
||||||
|
}
|
||||||
|
|
||||||
|
$revision->attachReviewers($with_reviewers->getReviewers());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class DifferentialMailEngineExtension
|
||||||
|
extends PhabricatorMailEngineExtension {
|
||||||
|
|
||||||
|
const EXTENSIONKEY = 'differential';
|
||||||
|
|
||||||
|
public function supportsObject($object) {
|
||||||
|
return ($object instanceof DifferentialRevision);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newMailStampTemplates($object) {
|
||||||
|
return array(
|
||||||
|
id(new PhabricatorPHIDMailStamp())
|
||||||
|
->setKey('author')
|
||||||
|
->setLabel(pht('Author')),
|
||||||
|
id(new PhabricatorPHIDMailStamp())
|
||||||
|
->setKey('reviewer')
|
||||||
|
->setLabel(pht('Reviewer')),
|
||||||
|
id(new PhabricatorPHIDMailStamp())
|
||||||
|
->setKey('blocking-reviewer')
|
||||||
|
->setLabel(pht('Reviewer')),
|
||||||
|
id(new PhabricatorPHIDMailStamp())
|
||||||
|
->setKey('resigned-reviewer')
|
||||||
|
->setLabel(pht('Reviewer')),
|
||||||
|
id(new PhabricatorPHIDMailStamp())
|
||||||
|
->setKey('revision-repository')
|
||||||
|
->setLabel(pht('Revision Repository')),
|
||||||
|
id(new PhabricatorPHIDMailStamp())
|
||||||
|
->setKey('revision-status')
|
||||||
|
->setLabel(pht('Revision Status')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newMailStamps($object, array $xactions) {
|
||||||
|
$editor = $this->getEditor();
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$revision = id(new DifferentialRevisionQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->needReviewers(true)
|
||||||
|
->withPHIDs(array($object->getPHID()))
|
||||||
|
->executeOne();
|
||||||
|
|
||||||
|
$reviewers = array();
|
||||||
|
$blocking = array();
|
||||||
|
$resigned = array();
|
||||||
|
foreach ($revision->getReviewers() as $reviewer) {
|
||||||
|
$reviewer_phid = $reviewer->getReviewerPHID();
|
||||||
|
|
||||||
|
if ($reviewer->isResigned()) {
|
||||||
|
$resigned[] = $reviewer_phid;
|
||||||
|
} else {
|
||||||
|
$reviewers[] = $reviewer_phid;
|
||||||
|
if ($reviewer->isBlocking()) {
|
||||||
|
$reviewers[] = $blocking;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->getMailStamp('author')
|
||||||
|
->setValue($revision->getAuthorPHID());
|
||||||
|
|
||||||
|
$this->getMailStamp('reviewer')
|
||||||
|
->setValue($reviewers);
|
||||||
|
|
||||||
|
$this->getMailStamp('blocking-reviewer')
|
||||||
|
->setValue($blocking);
|
||||||
|
|
||||||
|
$this->getMailStamp('resigned-reviewer')
|
||||||
|
->setValue($resigned);
|
||||||
|
|
||||||
|
$this->getMailStamp('revision-repository')
|
||||||
|
->setValue($revision->getRepositoryPHID());
|
||||||
|
|
||||||
|
$this->getMailStamp('revision-status')
|
||||||
|
->setValue($revision->getModernRevisionStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -221,6 +221,51 @@ final class DifferentialChangeset
|
||||||
return $this->assertAttached($this->diff);
|
return $this->assertAttached($this->diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function newFileTreeIcon() {
|
||||||
|
$file_type = $this->getFileType();
|
||||||
|
$change_type = $this->getChangeType();
|
||||||
|
|
||||||
|
$change_icons = array(
|
||||||
|
DifferentialChangeType::TYPE_DELETE => 'fa-file-o',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isset($change_icons[$change_type])) {
|
||||||
|
$icon = $change_icons[$change_type];
|
||||||
|
} else {
|
||||||
|
$icon = DifferentialChangeType::getIconForFileType($file_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
$change_colors = array(
|
||||||
|
DifferentialChangeType::TYPE_ADD => 'green',
|
||||||
|
DifferentialChangeType::TYPE_DELETE => 'red',
|
||||||
|
DifferentialChangeType::TYPE_MOVE_AWAY => 'orange',
|
||||||
|
DifferentialChangeType::TYPE_MOVE_HERE => 'orange',
|
||||||
|
DifferentialChangeType::TYPE_COPY_HERE => 'orange',
|
||||||
|
DifferentialChangeType::TYPE_MULTICOPY => 'orange',
|
||||||
|
);
|
||||||
|
|
||||||
|
$color = idx($change_colors, $change_type, 'bluetext');
|
||||||
|
|
||||||
|
return id(new PHUIIconView())
|
||||||
|
->setIcon($icon.' '.$color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFileTreeClass() {
|
||||||
|
switch ($this->getChangeType()) {
|
||||||
|
case DifferentialChangeType::TYPE_ADD:
|
||||||
|
return 'filetree-added';
|
||||||
|
case DifferentialChangeType::TYPE_DELETE:
|
||||||
|
return 'filetree-deleted';
|
||||||
|
case DifferentialChangeType::TYPE_MOVE_AWAY:
|
||||||
|
case DifferentialChangeType::TYPE_MOVE_HERE:
|
||||||
|
case DifferentialChangeType::TYPE_COPY_HERE:
|
||||||
|
case DifferentialChangeType::TYPE_MULTICOPY:
|
||||||
|
return 'filetree-movecopy';
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,11 @@ final class DifferentialReviewer
|
||||||
return ($this->getReviewerStatus() == $status_resigned);
|
return ($this->getReviewerStatus() == $status_resigned);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isBlocking() {
|
||||||
|
$status_blocking = DifferentialReviewerStatus::STATUS_BLOCKING;
|
||||||
|
return ($this->getReviewerStatus() == $status_blocking);
|
||||||
|
}
|
||||||
|
|
||||||
public function isRejected($diff_phid) {
|
public function isRejected($diff_phid) {
|
||||||
$status_rejected = DifferentialReviewerStatus::STATUS_REJECTED;
|
$status_rejected = DifferentialReviewerStatus::STATUS_REJECTED;
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@ final class DifferentialRevision extends DifferentialDAO
|
||||||
PhabricatorDraftInterface {
|
PhabricatorDraftInterface {
|
||||||
|
|
||||||
protected $title = '';
|
protected $title = '';
|
||||||
protected $originalTitle;
|
|
||||||
protected $status;
|
protected $status;
|
||||||
|
|
||||||
protected $summary = '';
|
protected $summary = '';
|
||||||
|
@ -98,7 +97,6 @@ final class DifferentialRevision extends DifferentialDAO
|
||||||
),
|
),
|
||||||
self::CONFIG_COLUMN_SCHEMA => array(
|
self::CONFIG_COLUMN_SCHEMA => array(
|
||||||
'title' => 'text255',
|
'title' => 'text255',
|
||||||
'originalTitle' => 'text255',
|
|
||||||
'status' => 'text32',
|
'status' => 'text32',
|
||||||
'summary' => 'text',
|
'summary' => 'text',
|
||||||
'testPlan' => 'text',
|
'testPlan' => 'text',
|
||||||
|
@ -155,14 +153,6 @@ final class DifferentialRevision extends DifferentialDAO
|
||||||
return '/'.$this->getMonogram();
|
return '/'.$this->getMonogram();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setTitle($title) {
|
|
||||||
$this->title = $title;
|
|
||||||
if (!$this->getID()) {
|
|
||||||
$this->originalTitle = $title;
|
|
||||||
}
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function loadIDsByCommitPHIDs($phids) {
|
public function loadIDsByCommitPHIDs($phids) {
|
||||||
if (!$phids) {
|
if (!$phids) {
|
||||||
return array();
|
return array();
|
||||||
|
@ -593,6 +583,10 @@ final class DifferentialRevision extends DifferentialDAO
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function hasAttachedReviewers() {
|
||||||
|
return ($this->reviewerStatus !== self::ATTACHABLE);
|
||||||
|
}
|
||||||
|
|
||||||
public function getReviewerPHIDs() {
|
public function getReviewerPHIDs() {
|
||||||
$reviewers = $this->getReviewers();
|
$reviewers = $this->getReviewers();
|
||||||
return mpull($reviewers, 'getReviewerPHID');
|
return mpull($reviewers, 'getReviewerPHID');
|
||||||
|
@ -830,9 +824,15 @@ final class DifferentialRevision extends DifferentialDAO
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($reviewers as $reviewer) {
|
foreach ($reviewers as $reviewer) {
|
||||||
if ($reviewer->getReviewerPHID() == $phid) {
|
if ($reviewer->getReviewerPHID() !== $phid) {
|
||||||
return true;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($reviewer->isResigned()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -206,6 +206,7 @@ final class DifferentialChangesetDetailView extends AphrontView {
|
||||||
'displayPath' => hsprintf('%s', $display_parts),
|
'displayPath' => hsprintf('%s', $display_parts),
|
||||||
'path' => $display_filename,
|
'path' => $display_filename,
|
||||||
'icon' => $display_icon,
|
'icon' => $display_icon,
|
||||||
|
'treeNodeID' => 'tree-node-'.$changeset->getAnchorName(),
|
||||||
),
|
),
|
||||||
'class' => $class,
|
'class' => $class,
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
|
|
|
@ -83,6 +83,9 @@ final class DifferentialChangesetFileTreeSideNavBuilder extends Phobject {
|
||||||
while (($path = $path->getNextNode())) {
|
while (($path = $path->getNextNode())) {
|
||||||
$data = $path->getData();
|
$data = $path->getData();
|
||||||
|
|
||||||
|
$classes = array();
|
||||||
|
$classes[] = 'phabricator-filetree-item';
|
||||||
|
|
||||||
$name = $path->getName();
|
$name = $path->getName();
|
||||||
$style = 'padding-left: '.(2 + (3 * $path->getDepth())).'px';
|
$style = 'padding-left: '.(2 + (3 * $path->getDepth())).'px';
|
||||||
|
|
||||||
|
@ -90,13 +93,23 @@ final class DifferentialChangesetFileTreeSideNavBuilder extends Phobject {
|
||||||
if ($data) {
|
if ($data) {
|
||||||
$href = '#'.$data->getAnchorName();
|
$href = '#'.$data->getAnchorName();
|
||||||
$title = $name;
|
$title = $name;
|
||||||
$icon = id(new PHUIIconView())
|
|
||||||
->setIcon('fa-file-text-o bluetext');
|
$icon = $data->newFileTreeIcon();
|
||||||
|
$classes[] = $data->getFileTreeClass();
|
||||||
|
|
||||||
|
$count = phutil_tag(
|
||||||
|
'span',
|
||||||
|
array(
|
||||||
|
'class' => 'filetree-progress-hint',
|
||||||
|
'id' => 'tree-node-'.$data->getAnchorName(),
|
||||||
|
));
|
||||||
} else {
|
} else {
|
||||||
$name .= '/';
|
$name .= '/';
|
||||||
$title = $path->getFullPath().'/';
|
$title = $path->getFullPath().'/';
|
||||||
$icon = id(new PHUIIconView())
|
$icon = id(new PHUIIconView())
|
||||||
->setIcon('fa-folder-open blue');
|
->setIcon('fa-folder-open blue');
|
||||||
|
|
||||||
|
$count = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$name_element = phutil_tag(
|
$name_element = phutil_tag(
|
||||||
|
@ -106,15 +119,16 @@ final class DifferentialChangesetFileTreeSideNavBuilder extends Phobject {
|
||||||
),
|
),
|
||||||
$name);
|
$name);
|
||||||
|
|
||||||
|
|
||||||
$filetree[] = javelin_tag(
|
$filetree[] = javelin_tag(
|
||||||
$href ? 'a' : 'span',
|
$href ? 'a' : 'span',
|
||||||
array(
|
array(
|
||||||
'href' => $href,
|
'href' => $href,
|
||||||
'style' => $style,
|
'style' => $style,
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
'class' => 'phabricator-filetree-item',
|
'class' => implode(' ', $classes),
|
||||||
),
|
),
|
||||||
array($icon, $name_element));
|
array($count, $icon, $name_element));
|
||||||
}
|
}
|
||||||
$tree->destroy();
|
$tree->destroy();
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,11 @@ final class DiffusionQueryPathsConduitAPIMethod
|
||||||
$commit = $request->getValue('commit');
|
$commit = $request->getValue('commit');
|
||||||
$repository = $drequest->getRepository();
|
$repository = $drequest->getRepository();
|
||||||
|
|
||||||
// http://comments.gmane.org/gmane.comp.version-control.git/197735
|
// Recent versions of Git don't work if you pass the empty string, and
|
||||||
|
// require "." to list everything.
|
||||||
|
if (!strlen($path)) {
|
||||||
|
$path = '.';
|
||||||
|
}
|
||||||
|
|
||||||
$future = $repository->getLocalCommandFuture(
|
$future = $repository->getLocalCommandFuture(
|
||||||
'ls-tree --name-only -r -z %s -- %s',
|
'ls-tree --name-only -r -z %s -- %s',
|
||||||
|
|
|
@ -23,14 +23,10 @@ final class DiffusionRepositoryURIViewController
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
// For display, reload the URI by loading it through the repository. This
|
// For display, access the URI by loading it through the repository. This
|
||||||
// may adjust builtin URIs for repository configuration, so we may end up
|
// may adjust builtin URIs for repository configuration, so we may end up
|
||||||
// with a different view of builtin URIs than we'd see if we loaded them
|
// with a different view of builtin URIs than we'd see if we loaded them
|
||||||
// directly from the database. See T12884.
|
// directly from the database. See T12884.
|
||||||
$repository_with_uris = id(new PhabricatorRepositoryQuery())
|
|
||||||
->setViewer($viewer)
|
|
||||||
->needURIs(true)
|
|
||||||
->execute();
|
|
||||||
|
|
||||||
$repository_uris = $repository->getURIs();
|
$repository_uris = $repository->getURIs();
|
||||||
$repository_uris = mpull($repository_uris, null, 'getID');
|
$repository_uris = mpull($repository_uris, null, 'getID');
|
||||||
|
|
|
@ -297,7 +297,11 @@ final class DiffusionCommitHookEngine extends Phobject {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$adapter_template->setHookEngine($this);
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$adapter_template
|
||||||
|
->setHookEngine($this)
|
||||||
|
->setActingAsPHID($viewer->getPHID());
|
||||||
|
|
||||||
$engine = new HeraldEngine();
|
$engine = new HeraldEngine();
|
||||||
$rules = null;
|
$rules = null;
|
||||||
|
|
|
@ -47,8 +47,7 @@ final class PhabricatorFileEditor
|
||||||
$name = $object->getName();
|
$name = $object->getName();
|
||||||
|
|
||||||
return id(new PhabricatorMetaMTAMail())
|
return id(new PhabricatorMetaMTAMail())
|
||||||
->setSubject("F{$id}: {$name}")
|
->setSubject("F{$id}: {$name}");
|
||||||
->addHeader('Thread-Topic', "F{$id}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildMailBody(
|
protected function buildMailBody(
|
||||||
|
|
|
@ -50,8 +50,7 @@ final class FundInitiativeEditor
|
||||||
$name = $object->getName();
|
$name = $object->getName();
|
||||||
|
|
||||||
return id(new PhabricatorMetaMTAMail())
|
return id(new PhabricatorMetaMTAMail())
|
||||||
->setSubject("{$monogram}: {$name}")
|
->setSubject("{$monogram}: {$name}");
|
||||||
->addHeader('Thread-Topic', $monogram);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildMailBody(
|
protected function buildMailBody(
|
||||||
|
|
62
src/applications/herald/action/HeraldCallWebhookAction.php
Normal file
62
src/applications/herald/action/HeraldCallWebhookAction.php
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldCallWebhookAction extends HeraldAction {
|
||||||
|
|
||||||
|
const ACTIONCONST = 'webhook';
|
||||||
|
const DO_WEBHOOK = 'do.call-webhook';
|
||||||
|
|
||||||
|
public function getHeraldActionName() {
|
||||||
|
return pht('Call webhooks');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getActionGroupKey() {
|
||||||
|
return HeraldUtilityActionGroup::ACTIONGROUPKEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsObject($object) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsRuleType($rule_type) {
|
||||||
|
return ($rule_type !== HeraldRuleTypeConfig::RULE_TYPE_PERSONAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyEffect($object, HeraldEffect $effect) {
|
||||||
|
$adapter = $this->getAdapter();
|
||||||
|
$rule = $effect->getRule();
|
||||||
|
$target = $effect->getTarget();
|
||||||
|
|
||||||
|
foreach ($target as $webhook_phid) {
|
||||||
|
$adapter->queueWebhook($webhook_phid, $rule->getPHID());
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->logEffect(self::DO_WEBHOOK, $target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHeraldActionStandardType() {
|
||||||
|
return self::STANDARD_PHID_LIST;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getActionEffectMap() {
|
||||||
|
return array(
|
||||||
|
self::DO_WEBHOOK => array(
|
||||||
|
'icon' => 'fa-cloud-upload',
|
||||||
|
'color' => 'green',
|
||||||
|
'name' => pht('Called Webhooks'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderActionDescription($value) {
|
||||||
|
return pht('Call webhooks: %s.', $this->renderHandleList($value));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function renderActionEffectDescription($type, $data) {
|
||||||
|
return pht('Called webhooks: %s.', $this->renderHandleList($data));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getDatasource() {
|
||||||
|
return new HeraldWebhookDatasource();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -39,6 +39,9 @@ abstract class HeraldAdapter extends Phobject {
|
||||||
private $edgeCache = array();
|
private $edgeCache = array();
|
||||||
private $forbiddenActions = array();
|
private $forbiddenActions = array();
|
||||||
private $viewer;
|
private $viewer;
|
||||||
|
private $mustEncryptReasons = array();
|
||||||
|
private $actingAsPHID;
|
||||||
|
private $webhookMap = array();
|
||||||
|
|
||||||
public function getEmailPHIDs() {
|
public function getEmailPHIDs() {
|
||||||
return array_values($this->emailPHIDs);
|
return array_values($this->emailPHIDs);
|
||||||
|
@ -48,6 +51,15 @@ abstract class HeraldAdapter extends Phobject {
|
||||||
return array_values($this->forcedEmailPHIDs);
|
return array_values($this->forcedEmailPHIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final public function setActingAsPHID($acting_as_phid) {
|
||||||
|
$this->actingAsPHID = $acting_as_phid;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getActingAsPHID() {
|
||||||
|
return $this->actingAsPHID;
|
||||||
|
}
|
||||||
|
|
||||||
public function addEmailPHID($phid, $force) {
|
public function addEmailPHID($phid, $force) {
|
||||||
$this->emailPHIDs[$phid] = $phid;
|
$this->emailPHIDs[$phid] = $phid;
|
||||||
if ($force) {
|
if ($force) {
|
||||||
|
@ -1182,4 +1194,30 @@ abstract class HeraldAdapter extends Phobject {
|
||||||
return $this->forbiddenActions[$action];
|
return $this->forbiddenActions[$action];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( Must Encrypt )------------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
final public function addMustEncryptReason($reason) {
|
||||||
|
$this->mustEncryptReasons[] = $reason;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getMustEncryptReasons() {
|
||||||
|
return $this->mustEncryptReasons;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( Webhooks )----------------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
final public function queueWebhook($webhook_phid, $rule_phid) {
|
||||||
|
$this->webhookMap[$webhook_phid][] = $rule_phid;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getWebhookMap() {
|
||||||
|
return $this->webhookMap;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,10 @@ final class PhabricatorHeraldApplication extends PhabricatorApplication {
|
||||||
'name' => pht('Herald User Guide'),
|
'name' => pht('Herald User Guide'),
|
||||||
'href' => PhabricatorEnv::getDoclink('Herald User Guide'),
|
'href' => PhabricatorEnv::getDoclink('Herald User Guide'),
|
||||||
),
|
),
|
||||||
|
array(
|
||||||
|
'name' => pht('User Guide: Webhooks'),
|
||||||
|
'href' => PhabricatorEnv::getDoclink('User Guide: Webhooks'),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,6 +66,15 @@ final class PhabricatorHeraldApplication extends PhabricatorApplication {
|
||||||
'(?P<id>[1-9]\d*)/'
|
'(?P<id>[1-9]\d*)/'
|
||||||
=> 'HeraldTranscriptController',
|
=> 'HeraldTranscriptController',
|
||||||
),
|
),
|
||||||
|
'webhook/' => array(
|
||||||
|
$this->getQueryRoutePattern() => 'HeraldWebhookListController',
|
||||||
|
'view/(?P<id>\d+)/(?:request/(?P<requestID>[^/]+)/)?' =>
|
||||||
|
'HeraldWebhookViewController',
|
||||||
|
$this->getEditRoutePattern('edit/') => 'HeraldWebhookEditController',
|
||||||
|
'test/(?P<id>\d+)/' => 'HeraldWebhookTestController',
|
||||||
|
'key/(?P<action>view|cycle)/(?P<id>\d+)/' =>
|
||||||
|
'HeraldWebhookKeyController',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -72,6 +85,9 @@ final class PhabricatorHeraldApplication extends PhabricatorApplication {
|
||||||
'caption' => pht('Global rules can bypass access controls.'),
|
'caption' => pht('Global rules can bypass access controls.'),
|
||||||
'default' => PhabricatorPolicies::POLICY_ADMIN,
|
'default' => PhabricatorPolicies::POLICY_ADMIN,
|
||||||
),
|
),
|
||||||
|
HeraldCreateWebhooksCapability::CAPABILITY => array(
|
||||||
|
'default' => PhabricatorPolicies::POLICY_ADMIN,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldCreateWebhooksCapability
|
||||||
|
extends PhabricatorPolicyCapability {
|
||||||
|
|
||||||
|
const CAPABILITY = 'herald.webhooks';
|
||||||
|
|
||||||
|
public function getCapabilityName() {
|
||||||
|
return pht('Can Create Webhooks');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function describeCapabilityRejection() {
|
||||||
|
return pht('You do not have permission to create webhooks.');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -6,18 +6,6 @@ abstract class HeraldController extends PhabricatorController {
|
||||||
return $this->buildSideNavView()->getMenu();
|
return $this->buildSideNavView()->getMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildApplicationCrumbs() {
|
|
||||||
$crumbs = parent::buildApplicationCrumbs();
|
|
||||||
|
|
||||||
$crumbs->addAction(
|
|
||||||
id(new PHUIListItemView())
|
|
||||||
->setName(pht('Create Herald Rule'))
|
|
||||||
->setHref($this->getApplicationURI('create/'))
|
|
||||||
->setIcon('fa-plus-square'));
|
|
||||||
|
|
||||||
return $crumbs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function buildSideNavView() {
|
public function buildSideNavView() {
|
||||||
$viewer = $this->getViewer();
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
@ -29,8 +17,11 @@ abstract class HeraldController extends PhabricatorController {
|
||||||
->addNavigationItems($nav->getMenu());
|
->addNavigationItems($nav->getMenu());
|
||||||
|
|
||||||
$nav->addLabel(pht('Utilities'))
|
$nav->addLabel(pht('Utilities'))
|
||||||
->addFilter('test', pht('Test Console'))
|
->addFilter('test', pht('Test Console'))
|
||||||
->addFilter('transcript', pht('Transcripts'));
|
->addFilter('transcript', pht('Transcripts'));
|
||||||
|
|
||||||
|
$nav->addLabel(pht('Webhooks'))
|
||||||
|
->addFilter('webhook', pht('Webhooks'));
|
||||||
|
|
||||||
$nav->selectFilter(null);
|
$nav->selectFilter(null);
|
||||||
|
|
||||||
|
|
|
@ -17,5 +17,16 @@ final class HeraldRuleListController extends HeraldController {
|
||||||
return $this->delegateToController($controller);
|
return $this->delegateToController($controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function buildApplicationCrumbs() {
|
||||||
|
$crumbs = parent::buildApplicationCrumbs();
|
||||||
|
|
||||||
|
$crumbs->addAction(
|
||||||
|
id(new PHUIListItemView())
|
||||||
|
->setName(pht('Create Herald Rule'))
|
||||||
|
->setHref($this->getApplicationURI('create/'))
|
||||||
|
->setIcon('fa-plus-square'));
|
||||||
|
|
||||||
|
return $crumbs;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ final class HeraldTestConsoleController extends HeraldController {
|
||||||
|
|
||||||
$adapter
|
$adapter
|
||||||
->setIsNewObject(false)
|
->setIsNewObject(false)
|
||||||
|
->setActingAsPHID($viewer->getPHID())
|
||||||
->setViewer($viewer);
|
->setViewer($viewer);
|
||||||
|
|
||||||
$rules = id(new HeraldRuleQuery())
|
$rules = id(new HeraldRuleQuery())
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class HeraldWebhookController extends HeraldController {
|
||||||
|
|
||||||
|
protected function buildApplicationCrumbs() {
|
||||||
|
$crumbs = parent::buildApplicationCrumbs();
|
||||||
|
|
||||||
|
$crumbs->addTextCrumb(
|
||||||
|
pht('Webhooks'),
|
||||||
|
$this->getApplicationURI('webhook/'));
|
||||||
|
|
||||||
|
return $crumbs;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldWebhookEditController
|
||||||
|
extends HeraldWebhookController {
|
||||||
|
|
||||||
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
return id(new HeraldWebhookEditEngine())
|
||||||
|
->setController($this)
|
||||||
|
->buildResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldWebhookKeyController
|
||||||
|
extends HeraldWebhookController {
|
||||||
|
|
||||||
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$hook = id(new HeraldWebhookQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withIDs(array($request->getURIData('id')))
|
||||||
|
->requireCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
))
|
||||||
|
->executeOne();
|
||||||
|
if (!$hook) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$action = $request->getURIData('action');
|
||||||
|
if ($action === 'cycle') {
|
||||||
|
if (!$request->isFormPost()) {
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Regenerate HMAC Key'))
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'Regenerate the HMAC key used to sign requests made by this '.
|
||||||
|
'webhook?'))
|
||||||
|
->appendParagraph(
|
||||||
|
pht(
|
||||||
|
'Requests which are currently authenticated with the old key '.
|
||||||
|
'may fail.'))
|
||||||
|
->addCancelButton($hook->getURI())
|
||||||
|
->addSubmitButton(pht('Regnerate Key'));
|
||||||
|
} else {
|
||||||
|
$hook->regenerateHMACKey()->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$form = id(new AphrontFormView())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->appendControl(
|
||||||
|
id(new AphrontFormTextControl())
|
||||||
|
->setLabel(pht('HMAC Key'))
|
||||||
|
->setValue($hook->getHMACKey()));
|
||||||
|
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Webhook HMAC Key'))
|
||||||
|
->appendForm($form)
|
||||||
|
->addCancelButton($hook->getURI(), pht('Done'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldWebhookListController
|
||||||
|
extends HeraldWebhookController {
|
||||||
|
|
||||||
|
public function shouldAllowPublic() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
return id(new HeraldWebhookSearchEngine())
|
||||||
|
->setController($this)
|
||||||
|
->buildResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildApplicationCrumbs() {
|
||||||
|
$crumbs = parent::buildApplicationCrumbs();
|
||||||
|
|
||||||
|
id(new HeraldWebhookEditEngine())
|
||||||
|
->setViewer($this->getViewer())
|
||||||
|
->addActionToCrumbs($crumbs);
|
||||||
|
|
||||||
|
return $crumbs;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldWebhookTestController
|
||||||
|
extends HeraldWebhookController {
|
||||||
|
|
||||||
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$hook = id(new HeraldWebhookQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withIDs(array($request->getURIData('id')))
|
||||||
|
->requireCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
))
|
||||||
|
->executeOne();
|
||||||
|
if (!$hook) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$v_object = null;
|
||||||
|
$e_object = null;
|
||||||
|
$errors = array();
|
||||||
|
if ($request->isFormPost()) {
|
||||||
|
|
||||||
|
$v_object = $request->getStr('object');
|
||||||
|
if (!strlen($v_object)) {
|
||||||
|
$object = $hook;
|
||||||
|
} else {
|
||||||
|
$objects = id(new PhabricatorObjectQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withNames(array($v_object))
|
||||||
|
->execute();
|
||||||
|
if ($objects) {
|
||||||
|
$object = head($objects);
|
||||||
|
} else {
|
||||||
|
$e_object = pht('Invalid');
|
||||||
|
$errors[] = pht('Specified object could not be loaded.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$errors) {
|
||||||
|
$xaction_query =
|
||||||
|
PhabricatorApplicationTransactionQuery::newQueryForObject($object);
|
||||||
|
|
||||||
|
$xactions = $xaction_query
|
||||||
|
->withObjectPHIDs(array($object->getPHID()))
|
||||||
|
->setViewer($viewer)
|
||||||
|
->setLimit(10)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$request = HeraldWebhookRequest::initializeNewWebhookRequest($hook)
|
||||||
|
->setObjectPHID($object->getPHID())
|
||||||
|
->setTriggerPHIDs(array($viewer->getPHID()))
|
||||||
|
->setIsTestAction(true)
|
||||||
|
->setTransactionPHIDs(mpull($xactions, 'getPHID'))
|
||||||
|
->save();
|
||||||
|
|
||||||
|
$request->queueCall();
|
||||||
|
|
||||||
|
$next_uri = $hook->getURI().'request/'.$request->getID().'/';
|
||||||
|
|
||||||
|
return id(new AphrontRedirectResponse())->setURI($next_uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$instructions = <<<EOREMARKUP
|
||||||
|
Optionally, choose an object to generate test data for (like `D123` or `T234`).
|
||||||
|
|
||||||
|
The 10 most recent transactions for the object will be submitted to the webhook.
|
||||||
|
EOREMARKUP;
|
||||||
|
|
||||||
|
$form = id(new AphrontFormView())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->appendControl(
|
||||||
|
id(new AphrontFormTextControl())
|
||||||
|
->setLabel(pht('Object'))
|
||||||
|
->setName('object')
|
||||||
|
->setError($e_object)
|
||||||
|
->setValue($v_object));
|
||||||
|
|
||||||
|
return $this->newDialog()
|
||||||
|
->setErrors($errors)
|
||||||
|
->setWidth(AphrontDialogView::WIDTH_FORM)
|
||||||
|
->setTitle(pht('New Test Request'))
|
||||||
|
->appendParagraph(new PHUIRemarkupView($viewer, $instructions))
|
||||||
|
->appendForm($form)
|
||||||
|
->addCancelButton($hook->getURI())
|
||||||
|
->addSubmitButton(pht('Test Webhook'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,184 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldWebhookViewController
|
||||||
|
extends HeraldWebhookController {
|
||||||
|
|
||||||
|
public function shouldAllowPublic() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$hook = id(new HeraldWebhookQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withIDs(array($request->getURIData('id')))
|
||||||
|
->executeOne();
|
||||||
|
if (!$hook) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$header = $this->buildHeaderView($hook);
|
||||||
|
|
||||||
|
$warnings = null;
|
||||||
|
if ($hook->isInErrorBackoff($viewer)) {
|
||||||
|
$message = pht(
|
||||||
|
'Many requests to this webhook have failed recently (at least %s '.
|
||||||
|
'errors in the last %s seconds). New requests are temporarily paused.',
|
||||||
|
$hook->getErrorBackoffThreshold(),
|
||||||
|
$hook->getErrorBackoffWindow());
|
||||||
|
|
||||||
|
$warnings = id(new PHUIInfoView())
|
||||||
|
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
|
||||||
|
->setErrors(
|
||||||
|
array(
|
||||||
|
$message,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
$curtain = $this->buildCurtain($hook);
|
||||||
|
$properties_view = $this->buildPropertiesView($hook);
|
||||||
|
|
||||||
|
$timeline = $this->buildTransactionTimeline(
|
||||||
|
$hook,
|
||||||
|
new HeraldWebhookTransactionQuery());
|
||||||
|
$timeline->setShouldTerminate(true);
|
||||||
|
|
||||||
|
$requests = id(new HeraldWebhookRequestQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withWebhookPHIDs(array($hook->getPHID()))
|
||||||
|
->setLimit(20)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$requests_table = id(new HeraldWebhookRequestListView())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->setRequests($requests)
|
||||||
|
->setHighlightID($request->getURIData('requestID'));
|
||||||
|
|
||||||
|
$requests_view = id(new PHUIObjectBoxView())
|
||||||
|
->setHeaderText(pht('Recent Requests'))
|
||||||
|
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||||
|
->setTable($requests_table);
|
||||||
|
|
||||||
|
$hook_view = id(new PHUITwoColumnView())
|
||||||
|
->setHeader($header)
|
||||||
|
->setMainColumn(
|
||||||
|
array(
|
||||||
|
$warnings,
|
||||||
|
$properties_view,
|
||||||
|
$requests_view,
|
||||||
|
$timeline,
|
||||||
|
))
|
||||||
|
->setCurtain($curtain);
|
||||||
|
|
||||||
|
$crumbs = $this->buildApplicationCrumbs()
|
||||||
|
->addTextCrumb(pht('Webhook %d', $hook->getID()))
|
||||||
|
->setBorder(true);
|
||||||
|
|
||||||
|
return $this->newPage()
|
||||||
|
->setTitle(
|
||||||
|
array(
|
||||||
|
pht('Webhook %d', $hook->getID()),
|
||||||
|
$hook->getName(),
|
||||||
|
))
|
||||||
|
->setCrumbs($crumbs)
|
||||||
|
->setPageObjectPHIDs(
|
||||||
|
array(
|
||||||
|
$hook->getPHID(),
|
||||||
|
))
|
||||||
|
->appendChild($hook_view);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildHeaderView(HeraldWebhook $hook) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$title = $hook->getName();
|
||||||
|
|
||||||
|
$status_icon = $hook->getStatusIcon();
|
||||||
|
$status_color = $hook->getStatusColor();
|
||||||
|
$status_name = $hook->getStatusDisplayName();
|
||||||
|
|
||||||
|
$header = id(new PHUIHeaderView())
|
||||||
|
->setHeader($title)
|
||||||
|
->setViewer($viewer)
|
||||||
|
->setPolicyObject($hook)
|
||||||
|
->setStatus($status_icon, $status_color, $status_name)
|
||||||
|
->setHeaderIcon('fa-cloud-upload');
|
||||||
|
|
||||||
|
return $header;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function buildCurtain(HeraldWebhook $hook) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$curtain = $this->newCurtainView($hook);
|
||||||
|
|
||||||
|
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||||
|
$viewer,
|
||||||
|
$hook,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
|
|
||||||
|
$id = $hook->getID();
|
||||||
|
$edit_uri = $this->getApplicationURI("webhook/edit/{$id}/");
|
||||||
|
$test_uri = $this->getApplicationURI("webhook/test/{$id}/");
|
||||||
|
|
||||||
|
$key_view_uri = $this->getApplicationURI("webhook/key/view/{$id}/");
|
||||||
|
$key_cycle_uri = $this->getApplicationURI("webhook/key/cycle/{$id}/");
|
||||||
|
|
||||||
|
$curtain->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName(pht('Edit Webhook'))
|
||||||
|
->setIcon('fa-pencil')
|
||||||
|
->setDisabled(!$can_edit)
|
||||||
|
->setWorkflow(!$can_edit)
|
||||||
|
->setHref($edit_uri));
|
||||||
|
|
||||||
|
$curtain->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName(pht('New Test Request'))
|
||||||
|
->setIcon('fa-cloud-upload')
|
||||||
|
->setDisabled(!$can_edit)
|
||||||
|
->setWorkflow(true)
|
||||||
|
->setHref($test_uri));
|
||||||
|
|
||||||
|
$curtain->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName(pht('View HMAC Key'))
|
||||||
|
->setIcon('fa-key')
|
||||||
|
->setDisabled(!$can_edit)
|
||||||
|
->setWorkflow(true)
|
||||||
|
->setHref($key_view_uri));
|
||||||
|
|
||||||
|
$curtain->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName(pht('Regenerate HMAC Key'))
|
||||||
|
->setIcon('fa-refresh')
|
||||||
|
->setDisabled(!$can_edit)
|
||||||
|
->setWorkflow(true)
|
||||||
|
->setHref($key_cycle_uri));
|
||||||
|
|
||||||
|
return $curtain;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function buildPropertiesView(HeraldWebhook $hook) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$properties = id(new PHUIPropertyListView())
|
||||||
|
->setViewer($viewer);
|
||||||
|
|
||||||
|
$properties->addProperty(
|
||||||
|
pht('URI'),
|
||||||
|
$hook->getWebhookURI());
|
||||||
|
|
||||||
|
$properties->addProperty(
|
||||||
|
pht('Status'),
|
||||||
|
$hook->getStatusDisplayName());
|
||||||
|
|
||||||
|
return id(new PHUIObjectBoxView())
|
||||||
|
->setHeaderText(pht('Details'))
|
||||||
|
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||||
|
->appendChild($properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
105
src/applications/herald/editor/HeraldWebhookEditEngine.php
Normal file
105
src/applications/herald/editor/HeraldWebhookEditEngine.php
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldWebhookEditEngine
|
||||||
|
extends PhabricatorEditEngine {
|
||||||
|
|
||||||
|
const ENGINECONST = 'herald.webhook';
|
||||||
|
|
||||||
|
public function isEngineConfigurable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEngineName() {
|
||||||
|
return pht('Webhooks');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSummaryHeader() {
|
||||||
|
return pht('Edit Webhook Configurations');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSummaryText() {
|
||||||
|
return pht('This engine is used to edit webhooks.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEngineApplicationClass() {
|
||||||
|
return 'PhabricatorHeraldApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newEditableObject() {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
return HeraldWebhook::initializeNewWebhook($viewer);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function newObjectQuery() {
|
||||||
|
return new HeraldWebhookQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getObjectCreateTitleText($object) {
|
||||||
|
return pht('Create Webhook');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getObjectCreateButtonText($object) {
|
||||||
|
return pht('Create Webhook');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getObjectEditTitleText($object) {
|
||||||
|
return pht('Edit Webhook: %s', $object->getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getObjectEditShortText($object) {
|
||||||
|
return pht('Edit Webhook');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getObjectCreateShortText() {
|
||||||
|
return pht('Create Webhook');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getObjectName() {
|
||||||
|
return pht('Webhook');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getEditorURI() {
|
||||||
|
return '/herald/webhook/edit/';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getObjectCreateCancelURI($object) {
|
||||||
|
return '/herald/webhook/';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getObjectViewURI($object) {
|
||||||
|
return $object->getURI();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getCreateNewObjectPolicy() {
|
||||||
|
return $this->getApplication()->getPolicy(
|
||||||
|
HeraldCreateWebhooksCapability::CAPABILITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildCustomEditFields($object) {
|
||||||
|
return array(
|
||||||
|
id(new PhabricatorTextEditField())
|
||||||
|
->setKey('name')
|
||||||
|
->setLabel(pht('Name'))
|
||||||
|
->setDescription(pht('Name of the webhook.'))
|
||||||
|
->setTransactionType(HeraldWebhookNameTransaction::TRANSACTIONTYPE)
|
||||||
|
->setIsRequired(true)
|
||||||
|
->setValue($object->getName()),
|
||||||
|
id(new PhabricatorTextEditField())
|
||||||
|
->setKey('uri')
|
||||||
|
->setLabel(pht('URI'))
|
||||||
|
->setDescription(pht('URI for the webhook.'))
|
||||||
|
->setTransactionType(HeraldWebhookURITransaction::TRANSACTIONTYPE)
|
||||||
|
->setIsRequired(true)
|
||||||
|
->setValue($object->getWebhookURI()),
|
||||||
|
id(new PhabricatorSelectEditField())
|
||||||
|
->setKey('status')
|
||||||
|
->setLabel(pht('Status'))
|
||||||
|
->setDescription(pht('Status mode for the webhook.'))
|
||||||
|
->setTransactionType(HeraldWebhookStatusTransaction::TRANSACTIONTYPE)
|
||||||
|
->setOptions(HeraldWebhook::getStatusDisplayNameMap())
|
||||||
|
->setValue($object->getStatus()),
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
31
src/applications/herald/editor/HeraldWebhookEditor.php
Normal file
31
src/applications/herald/editor/HeraldWebhookEditor.php
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldWebhookEditor
|
||||||
|
extends PhabricatorApplicationTransactionEditor {
|
||||||
|
|
||||||
|
public function getEditorApplicationClass() {
|
||||||
|
return 'PhabricatorHeraldApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEditorObjectsDescription() {
|
||||||
|
return pht('Webhooks');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCreateObjectTitle($author, $object) {
|
||||||
|
return pht('%s created this webhook.', $author);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCreateObjectTitleForFeed($author, $object) {
|
||||||
|
return pht('%s created %s.', $author, $object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTransactionTypes() {
|
||||||
|
$types = parent::getTransactionTypes();
|
||||||
|
|
||||||
|
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
||||||
|
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
|
||||||
|
|
||||||
|
return $types;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
32
src/applications/herald/field/HeraldActingUserField.php
Normal file
32
src/applications/herald/field/HeraldActingUserField.php
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldActingUserField
|
||||||
|
extends HeraldField {
|
||||||
|
|
||||||
|
const FIELDCONST = 'herald.acting-user';
|
||||||
|
|
||||||
|
public function getHeraldFieldName() {
|
||||||
|
return pht('Acting user');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHeraldFieldValue($object) {
|
||||||
|
return $this->getAdapter()->getActingAsPHID();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getHeraldFieldStandardType() {
|
||||||
|
return self::STANDARD_PHID;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getDatasource() {
|
||||||
|
return new PhabricatorPeopleDatasource();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsObject($object) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFieldGroupKey() {
|
||||||
|
return HeraldEditFieldGroup::FIELDGROUPKEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldWebhookRequestGarbageCollector
|
||||||
|
extends PhabricatorGarbageCollector {
|
||||||
|
|
||||||
|
const COLLECTORCONST = 'herald.webhooks';
|
||||||
|
|
||||||
|
public function getCollectorName() {
|
||||||
|
return pht('Herald Webhooks');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDefaultRetentionPolicy() {
|
||||||
|
return phutil_units('7 days in seconds');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function collectGarbage() {
|
||||||
|
$table = new HeraldWebhookRequest();
|
||||||
|
$conn_w = $table->establishConnection('w');
|
||||||
|
|
||||||
|
queryfx(
|
||||||
|
$conn_w,
|
||||||
|
'DELETE FROM %T WHERE dateCreated < %d LIMIT 100',
|
||||||
|
$table->getTableName(),
|
||||||
|
$this->getGarbageEpoch());
|
||||||
|
|
||||||
|
return ($conn_w->getAffectedRows() == 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldWebhookCallManagementWorkflow
|
||||||
|
extends HeraldWebhookManagementWorkflow {
|
||||||
|
|
||||||
|
protected function didConstruct() {
|
||||||
|
$this
|
||||||
|
->setName('call')
|
||||||
|
->setExamples('**call** --id __id__ [--object __object__]')
|
||||||
|
->setSynopsis(pht('Call a webhook.'))
|
||||||
|
->setArguments(
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
'name' => 'id',
|
||||||
|
'param' => 'id',
|
||||||
|
'help' => pht('Webhook ID to call'),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'object',
|
||||||
|
'param' => 'object',
|
||||||
|
'help' => pht('Submit transactions for a particular object.'),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'silent',
|
||||||
|
'help' => pht('Set the "silent" flag on the request.'),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'secure',
|
||||||
|
'help' => pht('Set the "secure" flag on the request.'),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(PhutilArgumentParser $args) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$id = $args->getArg('id');
|
||||||
|
if (!$id) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'Specify a webhook to call with "--id".'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$hook = id(new HeraldWebhookQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withIDs(array($id))
|
||||||
|
->executeOne();
|
||||||
|
if (!$hook) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'Unable to load specified webhook ("%s").',
|
||||||
|
$id));
|
||||||
|
}
|
||||||
|
|
||||||
|
$object_name = $args->getArg('object');
|
||||||
|
if ($object_name === null) {
|
||||||
|
$object = $hook;
|
||||||
|
} else {
|
||||||
|
$objects = id(new PhabricatorObjectQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withNames(array($object_name))
|
||||||
|
->execute();
|
||||||
|
if (!$objects) {
|
||||||
|
throw new PhutilArgumentUsageException(
|
||||||
|
pht(
|
||||||
|
'Unable to load specified object ("%s").',
|
||||||
|
$object_name));
|
||||||
|
}
|
||||||
|
$object = head($objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
$xaction_query =
|
||||||
|
PhabricatorApplicationTransactionQuery::newQueryForObject($object);
|
||||||
|
|
||||||
|
$xactions = $xaction_query
|
||||||
|
->withObjectPHIDs(array($object->getPHID()))
|
||||||
|
->setViewer($viewer)
|
||||||
|
->setLimit(10)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$application_phid = id(new PhabricatorHeraldApplication())->getPHID();
|
||||||
|
|
||||||
|
$request = HeraldWebhookRequest::initializeNewWebhookRequest($hook)
|
||||||
|
->setObjectPHID($object->getPHID())
|
||||||
|
->setIsTestAction(true)
|
||||||
|
->setIsSilentAction((bool)$args->getArg('silent'))
|
||||||
|
->setIsSecureAction((bool)$args->getArg('secure'))
|
||||||
|
->setTriggerPHIDs(array($application_phid))
|
||||||
|
->setTransactionPHIDs(mpull($xactions, 'getPHID'))
|
||||||
|
->save();
|
||||||
|
|
||||||
|
PhabricatorWorker::setRunAllTasksInProcess(true);
|
||||||
|
$request->queueCall();
|
||||||
|
|
||||||
|
$request->reload();
|
||||||
|
|
||||||
|
echo tsprintf(
|
||||||
|
"%s\n",
|
||||||
|
pht(
|
||||||
|
'Success, got HTTP %s from webhook.',
|
||||||
|
$request->getErrorCode()));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class HeraldWebhookManagementWorkflow
|
||||||
|
extends PhabricatorManagementWorkflow {}
|
49
src/applications/herald/phid/HeraldWebhookPHIDType.php
Normal file
49
src/applications/herald/phid/HeraldWebhookPHIDType.php
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldWebhookPHIDType extends PhabricatorPHIDType {
|
||||||
|
|
||||||
|
const TYPECONST = 'HWBH';
|
||||||
|
|
||||||
|
public function getTypeName() {
|
||||||
|
return pht('Webhook');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newObject() {
|
||||||
|
return new HeraldWebhook();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPHIDTypeApplicationClass() {
|
||||||
|
return 'PhabricatorHeraldApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildQueryForObjects(
|
||||||
|
PhabricatorObjectQuery $query,
|
||||||
|
array $phids) {
|
||||||
|
|
||||||
|
return id(new HeraldWebhookQuery())
|
||||||
|
->withPHIDs($phids);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadHandles(
|
||||||
|
PhabricatorHandleQuery $query,
|
||||||
|
array $handles,
|
||||||
|
array $objects) {
|
||||||
|
|
||||||
|
foreach ($handles as $phid => $handle) {
|
||||||
|
$hook = $objects[$phid];
|
||||||
|
|
||||||
|
$name = $hook->getName();
|
||||||
|
$id = $hook->getID();
|
||||||
|
|
||||||
|
$handle
|
||||||
|
->setName($name)
|
||||||
|
->setURI($hook->getURI())
|
||||||
|
->setFullName(pht('Webhook %d %s', $id, $name));
|
||||||
|
|
||||||
|
if ($hook->isDisabled()) {
|
||||||
|
$handle->setStatus(PhabricatorObjectHandle::STATUS_CLOSED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldWebhookRequestPHIDType extends PhabricatorPHIDType {
|
||||||
|
|
||||||
|
const TYPECONST = 'HWBR';
|
||||||
|
|
||||||
|
public function getTypeName() {
|
||||||
|
return pht('Webhook Request');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newObject() {
|
||||||
|
return new HeraldWebhook();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPHIDTypeApplicationClass() {
|
||||||
|
return 'PhabricatorHeraldApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildQueryForObjects(
|
||||||
|
PhabricatorObjectQuery $query,
|
||||||
|
array $phids) {
|
||||||
|
|
||||||
|
return id(new HeraldWebhookRequestQuery())
|
||||||
|
->withPHIDs($phids);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadHandles(
|
||||||
|
PhabricatorHandleQuery $query,
|
||||||
|
array $handles,
|
||||||
|
array $objects) {
|
||||||
|
|
||||||
|
foreach ($handles as $phid => $handle) {
|
||||||
|
$request = $objects[$phid];
|
||||||
|
$handle->setName(pht('Webhook Request %d', $request->getID()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
64
src/applications/herald/query/HeraldWebhookQuery.php
Normal file
64
src/applications/herald/query/HeraldWebhookQuery.php
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldWebhookQuery
|
||||||
|
extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||||
|
|
||||||
|
private $ids;
|
||||||
|
private $phids;
|
||||||
|
private $statuses;
|
||||||
|
|
||||||
|
public function withIDs(array $ids) {
|
||||||
|
$this->ids = $ids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withPHIDs(array $phids) {
|
||||||
|
$this->phids = $phids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withStatuses(array $statuses) {
|
||||||
|
$this->statuses = $statuses;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newResultObject() {
|
||||||
|
return new HeraldWebhook();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadPage() {
|
||||||
|
return $this->loadStandardPage($this->newResultObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
||||||
|
$where = parent::buildWhereClauseParts($conn);
|
||||||
|
|
||||||
|
if ($this->ids !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'id IN (%Ld)',
|
||||||
|
$this->ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->phids !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'phid IN (%Ls)',
|
||||||
|
$this->phids);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->statuses !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'status IN (%Ls)',
|
||||||
|
$this->statuses);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $where;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQueryApplicationClass() {
|
||||||
|
return 'PhabricatorHeraldApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
126
src/applications/herald/query/HeraldWebhookRequestQuery.php
Normal file
126
src/applications/herald/query/HeraldWebhookRequestQuery.php
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldWebhookRequestQuery
|
||||||
|
extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||||
|
|
||||||
|
private $ids;
|
||||||
|
private $phids;
|
||||||
|
private $webhookPHIDs;
|
||||||
|
private $lastRequestEpochMin;
|
||||||
|
private $lastRequestEpochMax;
|
||||||
|
private $lastRequestResults;
|
||||||
|
|
||||||
|
public function withIDs(array $ids) {
|
||||||
|
$this->ids = $ids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withPHIDs(array $phids) {
|
||||||
|
$this->phids = $phids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withWebhookPHIDs(array $phids) {
|
||||||
|
$this->webhookPHIDs = $phids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newResultObject() {
|
||||||
|
return new HeraldWebhookRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadPage() {
|
||||||
|
return $this->loadStandardPage($this->newResultObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withLastRequestEpochBetween($epoch_min, $epoch_max) {
|
||||||
|
$this->lastRequestEpochMin = $epoch_min;
|
||||||
|
$this->lastRequestEpochMax = $epoch_max;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withLastRequestResults(array $results) {
|
||||||
|
$this->lastRequestResults = $results;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
|
||||||
|
$where = parent::buildWhereClauseParts($conn);
|
||||||
|
|
||||||
|
if ($this->ids !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'id IN (%Ld)',
|
||||||
|
$this->ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->phids !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'phid IN (%Ls)',
|
||||||
|
$this->phids);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->webhookPHIDs !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'webhookPHID IN (%Ls)',
|
||||||
|
$this->webhookPHIDs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->lastRequestEpochMin !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'lastRequestEpoch >= %d',
|
||||||
|
$this->lastRequestEpochMin);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->lastRequestEpochMax !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'lastRequestEpoch <= %d',
|
||||||
|
$this->lastRequestEpochMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->lastRequestResults !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'lastRequestResult IN (%Ls)',
|
||||||
|
$this->lastRequestResults);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $where;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function willFilterPage(array $requests) {
|
||||||
|
$hook_phids = mpull($requests, 'getWebhookPHID');
|
||||||
|
|
||||||
|
$hooks = id(new HeraldWebhookQuery())
|
||||||
|
->setViewer($this->getViewer())
|
||||||
|
->setParentQuery($this)
|
||||||
|
->withPHIDs($hook_phids)
|
||||||
|
->execute();
|
||||||
|
$hooks = mpull($hooks, null, 'getPHID');
|
||||||
|
|
||||||
|
foreach ($requests as $key => $request) {
|
||||||
|
$hook_phid = $request->getWebhookPHID();
|
||||||
|
$hook = idx($hooks, $hook_phid);
|
||||||
|
|
||||||
|
if (!$hook) {
|
||||||
|
unset($requests[$key]);
|
||||||
|
$this->didRejectResult($request);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$request->attachWebhook($hook);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $requests;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getQueryApplicationClass() {
|
||||||
|
return 'PhabricatorHeraldApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
102
src/applications/herald/query/HeraldWebhookSearchEngine.php
Normal file
102
src/applications/herald/query/HeraldWebhookSearchEngine.php
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldWebhookSearchEngine
|
||||||
|
extends PhabricatorApplicationSearchEngine {
|
||||||
|
|
||||||
|
public function getResultTypeDescription() {
|
||||||
|
return pht('Webhooks');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationClassName() {
|
||||||
|
return 'PhabricatorHeraldApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newQuery() {
|
||||||
|
return new HeraldWebhookQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildQueryFromParameters(array $map) {
|
||||||
|
$query = $this->newQuery();
|
||||||
|
|
||||||
|
if ($map['statuses']) {
|
||||||
|
$query->withStatuses($map['statuses']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildCustomSearchFields() {
|
||||||
|
return array(
|
||||||
|
id(new PhabricatorSearchCheckboxesField())
|
||||||
|
->setKey('statuses')
|
||||||
|
->setLabel(pht('Status'))
|
||||||
|
->setDescription(
|
||||||
|
pht('Search for archived or active pastes.'))
|
||||||
|
->setOptions(HeraldWebhook::getStatusDisplayNameMap()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getURI($path) {
|
||||||
|
return '/herald/webhook/'.$path;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getBuiltinQueryNames() {
|
||||||
|
$names = array();
|
||||||
|
|
||||||
|
$names['active'] = pht('Active');
|
||||||
|
$names['all'] = pht('All');
|
||||||
|
|
||||||
|
return $names;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildSavedQueryFromBuiltin($query_key) {
|
||||||
|
$query = $this->newSavedQuery();
|
||||||
|
$query->setQueryKey($query_key);
|
||||||
|
|
||||||
|
switch ($query_key) {
|
||||||
|
case 'all':
|
||||||
|
return $query;
|
||||||
|
case 'active':
|
||||||
|
return $query->setParameter(
|
||||||
|
'statuses',
|
||||||
|
array(
|
||||||
|
HeraldWebhook::HOOKSTATUS_FIREHOSE,
|
||||||
|
HeraldWebhook::HOOKSTATUS_ENABLED,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::buildSavedQueryFromBuiltin($query_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function renderResultList(
|
||||||
|
array $hooks,
|
||||||
|
PhabricatorSavedQuery $query,
|
||||||
|
array $handles) {
|
||||||
|
assert_instances_of($hooks, 'HeraldWebhook');
|
||||||
|
|
||||||
|
$viewer = $this->requireViewer();
|
||||||
|
|
||||||
|
$list = id(new PHUIObjectItemListView())
|
||||||
|
->setViewer($viewer);
|
||||||
|
foreach ($hooks as $hook) {
|
||||||
|
$item = id(new PHUIObjectItemView())
|
||||||
|
->setObjectName(pht('Webhook %d', $hook->getID()))
|
||||||
|
->setHeader($hook->getName())
|
||||||
|
->setHref($hook->getURI())
|
||||||
|
->addAttribute($hook->getWebhookURI());
|
||||||
|
|
||||||
|
$item->addIcon($hook->getStatusIcon(), $hook->getStatusDisplayName());
|
||||||
|
|
||||||
|
if ($hook->isDisabled()) {
|
||||||
|
$item->setDisabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$list->addItem($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return id(new PhabricatorApplicationSearchResultView())
|
||||||
|
->setObjectList($list)
|
||||||
|
->setNoDataString(pht('No webhooks found.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldWebhookTransactionQuery
|
||||||
|
extends PhabricatorApplicationTransactionQuery {
|
||||||
|
|
||||||
|
public function getTemplateApplicationTransaction() {
|
||||||
|
return new HeraldWebhookTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
244
src/applications/herald/storage/HeraldWebhook.php
Normal file
244
src/applications/herald/storage/HeraldWebhook.php
Normal file
|
@ -0,0 +1,244 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldWebhook
|
||||||
|
extends HeraldDAO
|
||||||
|
implements
|
||||||
|
PhabricatorPolicyInterface,
|
||||||
|
PhabricatorApplicationTransactionInterface,
|
||||||
|
PhabricatorDestructibleInterface,
|
||||||
|
PhabricatorProjectInterface {
|
||||||
|
|
||||||
|
protected $name;
|
||||||
|
protected $webhookURI;
|
||||||
|
protected $viewPolicy;
|
||||||
|
protected $editPolicy;
|
||||||
|
protected $status;
|
||||||
|
protected $hmacKey;
|
||||||
|
|
||||||
|
const HOOKSTATUS_FIREHOSE = 'firehose';
|
||||||
|
const HOOKSTATUS_ENABLED = 'enabled';
|
||||||
|
const HOOKSTATUS_DISABLED = 'disabled';
|
||||||
|
|
||||||
|
protected function getConfiguration() {
|
||||||
|
return array(
|
||||||
|
self::CONFIG_AUX_PHID => true,
|
||||||
|
self::CONFIG_COLUMN_SCHEMA => array(
|
||||||
|
'name' => 'text128',
|
||||||
|
'webhookURI' => 'text255',
|
||||||
|
'status' => 'text32',
|
||||||
|
'hmacKey' => 'text32',
|
||||||
|
),
|
||||||
|
self::CONFIG_KEY_SCHEMA => array(
|
||||||
|
'key_status' => array(
|
||||||
|
'columns' => array('status'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
) + parent::getConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPHIDType() {
|
||||||
|
return HeraldWebhookPHIDType::TYPECONST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function initializeNewWebhook(PhabricatorUser $viewer) {
|
||||||
|
return id(new self())
|
||||||
|
->setStatus(self::HOOKSTATUS_ENABLED)
|
||||||
|
->setViewPolicy(PhabricatorPolicies::getMostOpenPolicy())
|
||||||
|
->setEditPolicy($viewer->getPHID())
|
||||||
|
->regenerateHMACKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getURI() {
|
||||||
|
return '/herald/webhook/view/'.$this->getID().'/';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isDisabled() {
|
||||||
|
return ($this->getStatus() === self::HOOKSTATUS_DISABLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getStatusDisplayNameMap() {
|
||||||
|
$specs = self::getStatusSpecifications();
|
||||||
|
return ipull($specs, 'name', 'key');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getStatusSpecifications() {
|
||||||
|
$specs = array(
|
||||||
|
array(
|
||||||
|
'key' => self::HOOKSTATUS_FIREHOSE,
|
||||||
|
'name' => pht('Firehose'),
|
||||||
|
'color' => 'orange',
|
||||||
|
'icon' => 'fa-star-o',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'key' => self::HOOKSTATUS_ENABLED,
|
||||||
|
'name' => pht('Enabled'),
|
||||||
|
'color' => 'bluegrey',
|
||||||
|
'icon' => 'fa-check',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'key' => self::HOOKSTATUS_DISABLED,
|
||||||
|
'name' => pht('Disabled'),
|
||||||
|
'color' => 'dark',
|
||||||
|
'icon' => 'fa-ban',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return ipull($specs, null, 'key');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static function getSpecificationForStatus($status) {
|
||||||
|
$specs = self::getStatusSpecifications();
|
||||||
|
|
||||||
|
if (isset($specs[$status])) {
|
||||||
|
return $specs[$status];
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'key' => $status,
|
||||||
|
'name' => pht('Unknown ("%s")', $status),
|
||||||
|
'icon' => 'fa-question',
|
||||||
|
'color' => 'indigo',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getDisplayNameForStatus($status) {
|
||||||
|
$spec = self::getSpecificationForStatus($status);
|
||||||
|
return $spec['name'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getIconForStatus($status) {
|
||||||
|
$spec = self::getSpecificationForStatus($status);
|
||||||
|
return $spec['icon'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getColorForStatus($status) {
|
||||||
|
$spec = self::getSpecificationForStatus($status);
|
||||||
|
return $spec['color'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStatusDisplayName() {
|
||||||
|
$status = $this->getStatus();
|
||||||
|
return self::getDisplayNameForStatus($status);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStatusIcon() {
|
||||||
|
$status = $this->getStatus();
|
||||||
|
return self::getIconForStatus($status);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStatusColor() {
|
||||||
|
$status = $this->getStatus();
|
||||||
|
return self::getColorForStatus($status);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getErrorBackoffWindow() {
|
||||||
|
return phutil_units('5 minutes in seconds');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getErrorBackoffThreshold() {
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isInErrorBackoff(PhabricatorUser $viewer) {
|
||||||
|
$backoff_window = $this->getErrorBackoffWindow();
|
||||||
|
$backoff_threshold = $this->getErrorBackoffThreshold();
|
||||||
|
|
||||||
|
$now = PhabricatorTime::getNow();
|
||||||
|
|
||||||
|
$window_start = ($now - $backoff_window);
|
||||||
|
|
||||||
|
$requests = id(new HeraldWebhookRequestQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withWebhookPHIDs(array($this->getPHID()))
|
||||||
|
->withLastRequestEpochBetween($window_start, null)
|
||||||
|
->withLastRequestResults(
|
||||||
|
array(
|
||||||
|
HeraldWebhookRequest::RESULT_FAIL,
|
||||||
|
))
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
if (count($requests) >= $backoff_threshold) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function regenerateHMACKey() {
|
||||||
|
return $this->setHMACKey(Filesystem::readRandomCharacters(32));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function getCapabilities() {
|
||||||
|
return array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPolicy($capability) {
|
||||||
|
switch ($capability) {
|
||||||
|
case PhabricatorPolicyCapability::CAN_VIEW:
|
||||||
|
return $this->getViewPolicy();
|
||||||
|
case PhabricatorPolicyCapability::CAN_EDIT:
|
||||||
|
return $this->getEditPolicy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function getApplicationTransactionEditor() {
|
||||||
|
return new HeraldWebhookEditor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionObject() {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionTemplate() {
|
||||||
|
return new HeraldWebhookTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function willRenderTimeline(
|
||||||
|
PhabricatorApplicationTransactionView $timeline,
|
||||||
|
AphrontRequest $request) {
|
||||||
|
return $timeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorDestructibleInterface )----------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function destroyObjectPermanently(
|
||||||
|
PhabricatorDestructionEngine $engine) {
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
$requests = id(new HeraldWebhookRequestQuery())
|
||||||
|
->setViewer($engine->getViewer())
|
||||||
|
->withWebhookPHIDs(array($this->getPHID()))
|
||||||
|
->setLimit(100)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
if (!$requests) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($requests as $request) {
|
||||||
|
$request->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
223
src/applications/herald/storage/HeraldWebhookRequest.php
Normal file
223
src/applications/herald/storage/HeraldWebhookRequest.php
Normal file
|
@ -0,0 +1,223 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldWebhookRequest
|
||||||
|
extends HeraldDAO
|
||||||
|
implements
|
||||||
|
PhabricatorPolicyInterface,
|
||||||
|
PhabricatorExtendedPolicyInterface {
|
||||||
|
|
||||||
|
protected $webhookPHID;
|
||||||
|
protected $objectPHID;
|
||||||
|
protected $status;
|
||||||
|
protected $properties = array();
|
||||||
|
protected $lastRequestResult;
|
||||||
|
protected $lastRequestEpoch;
|
||||||
|
|
||||||
|
private $webhook = self::ATTACHABLE;
|
||||||
|
|
||||||
|
const RETRY_NEVER = 'never';
|
||||||
|
const RETRY_FOREVER = 'forever';
|
||||||
|
|
||||||
|
const STATUS_QUEUED = 'queued';
|
||||||
|
const STATUS_FAILED = 'failed';
|
||||||
|
const STATUS_SENT = 'sent';
|
||||||
|
|
||||||
|
const RESULT_NONE = 'none';
|
||||||
|
const RESULT_OKAY = 'okay';
|
||||||
|
const RESULT_FAIL = 'fail';
|
||||||
|
|
||||||
|
protected function getConfiguration() {
|
||||||
|
return array(
|
||||||
|
self::CONFIG_AUX_PHID => true,
|
||||||
|
self::CONFIG_SERIALIZATION => array(
|
||||||
|
'properties' => self::SERIALIZATION_JSON,
|
||||||
|
),
|
||||||
|
self::CONFIG_COLUMN_SCHEMA => array(
|
||||||
|
'status' => 'text32',
|
||||||
|
'lastRequestResult' => 'text32',
|
||||||
|
'lastRequestEpoch' => 'epoch',
|
||||||
|
),
|
||||||
|
self::CONFIG_KEY_SCHEMA => array(
|
||||||
|
'key_ratelimit' => array(
|
||||||
|
'columns' => array(
|
||||||
|
'webhookPHID',
|
||||||
|
'lastRequestResult',
|
||||||
|
'lastRequestEpoch',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'key_collect' => array(
|
||||||
|
'columns' => array('dateCreated'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
) + parent::getConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPHIDType() {
|
||||||
|
return HeraldWebhookRequestPHIDType::TYPECONST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function initializeNewWebhookRequest(HeraldWebhook $hook) {
|
||||||
|
return id(new self())
|
||||||
|
->setWebhookPHID($hook->getPHID())
|
||||||
|
->attachWebhook($hook)
|
||||||
|
->setStatus(self::STATUS_QUEUED)
|
||||||
|
->setRetryMode(self::RETRY_NEVER)
|
||||||
|
->setLastRequestResult(self::RESULT_NONE)
|
||||||
|
->setLastRequestEpoch(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getWebhook() {
|
||||||
|
return $this->assertAttached($this->webhook);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attachWebhook(HeraldWebhook $hook) {
|
||||||
|
$this->webhook = $hook;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setProperty($key, $value) {
|
||||||
|
$this->properties[$key] = $value;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getProperty($key, $default = null) {
|
||||||
|
return idx($this->properties, $key, $default);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setRetryMode($mode) {
|
||||||
|
return $this->setProperty('retry', $mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRetryMode() {
|
||||||
|
return $this->getProperty('retry');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setErrorType($error_type) {
|
||||||
|
return $this->setProperty('errorType', $error_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getErrorType() {
|
||||||
|
return $this->getProperty('errorType');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setErrorCode($error_code) {
|
||||||
|
return $this->setProperty('errorCode', $error_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getErrorCode() {
|
||||||
|
return $this->getProperty('errorCode');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTransactionPHIDs(array $phids) {
|
||||||
|
return $this->setProperty('transactionPHIDs', $phids);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTransactionPHIDs() {
|
||||||
|
return $this->getProperty('transactionPHIDs', array());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTriggerPHIDs(array $phids) {
|
||||||
|
return $this->setProperty('triggerPHIDs', $phids);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTriggerPHIDs() {
|
||||||
|
return $this->getProperty('triggerPHIDs', array());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setIsSilentAction($bool) {
|
||||||
|
return $this->setProperty('silent', $bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIsSilentAction() {
|
||||||
|
return $this->getProperty('silent', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setIsTestAction($bool) {
|
||||||
|
return $this->setProperty('test', $bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIsTestAction() {
|
||||||
|
return $this->getProperty('test', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setIsSecureAction($bool) {
|
||||||
|
return $this->setProperty('secure', $bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIsSecureAction() {
|
||||||
|
return $this->getProperty('secure', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function queueCall() {
|
||||||
|
PhabricatorWorker::scheduleTask(
|
||||||
|
'HeraldWebhookWorker',
|
||||||
|
array(
|
||||||
|
'webhookRequestPHID' => $this->getPHID(),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'objectPHID' => $this->getPHID(),
|
||||||
|
));
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newStatusIcon() {
|
||||||
|
switch ($this->getStatus()) {
|
||||||
|
case self::STATUS_QUEUED:
|
||||||
|
$icon = 'fa-refresh';
|
||||||
|
$color = 'blue';
|
||||||
|
$tooltip = pht('Queued');
|
||||||
|
break;
|
||||||
|
case self::STATUS_SENT:
|
||||||
|
$icon = 'fa-check';
|
||||||
|
$color = 'green';
|
||||||
|
$tooltip = pht('Sent');
|
||||||
|
break;
|
||||||
|
case self::STATUS_FAILED:
|
||||||
|
default:
|
||||||
|
$icon = 'fa-times';
|
||||||
|
$color = 'red';
|
||||||
|
$tooltip = pht('Failed');
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return id(new PHUIIconView())
|
||||||
|
->setIcon($icon, $color)
|
||||||
|
->setTooltip($tooltip);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function getCapabilities() {
|
||||||
|
return array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPolicy($capability) {
|
||||||
|
switch ($capability) {
|
||||||
|
case PhabricatorPolicyCapability::CAN_VIEW:
|
||||||
|
return PhabricatorPolicies::getMostOpenPolicy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( PhabricatorExtendedPolicyInterface )--------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function getExtendedPolicy($capability, PhabricatorUser $viewer) {
|
||||||
|
return array(
|
||||||
|
array($this->getWebhook(), PhabricatorPolicyCapability::CAN_VIEW),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
22
src/applications/herald/storage/HeraldWebhookTransaction.php
Normal file
22
src/applications/herald/storage/HeraldWebhookTransaction.php
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldWebhookTransaction
|
||||||
|
extends PhabricatorModularTransaction {
|
||||||
|
|
||||||
|
public function getApplicationName() {
|
||||||
|
return 'herald';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionType() {
|
||||||
|
return HeraldWebhookPHIDType::TYPECONST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionCommentObject() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBaseTransactionClass() {
|
||||||
|
return 'HeraldWebhookTransactionType';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldWebhookDatasource
|
||||||
|
extends PhabricatorTypeaheadDatasource {
|
||||||
|
|
||||||
|
public function getPlaceholderText() {
|
||||||
|
return pht('Type a webhook name...');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBrowseTitle() {
|
||||||
|
return pht('Browse Webhooks');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDatasourceApplicationClass() {
|
||||||
|
return 'PhabricatorHeraldApplication';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadResults() {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$raw_query = $this->getRawQuery();
|
||||||
|
|
||||||
|
$hooks = id(new HeraldWebhookQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$handles = id(new PhabricatorHandleQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withPHIDs(mpull($hooks, 'getPHID'))
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$results = array();
|
||||||
|
foreach ($hooks as $hook) {
|
||||||
|
$handle = $handles[$hook->getPHID()];
|
||||||
|
|
||||||
|
$result = id(new PhabricatorTypeaheadResult())
|
||||||
|
->setName($handle->getFullName())
|
||||||
|
->setPHID($handle->getPHID());
|
||||||
|
|
||||||
|
if ($hook->isDisabled()) {
|
||||||
|
$result->setClosed(pht('Disabled'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$results[] = $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldWebhookRequestListView
|
||||||
|
extends AphrontView {
|
||||||
|
|
||||||
|
private $requests;
|
||||||
|
private $highlightID;
|
||||||
|
|
||||||
|
public function setRequests(array $requests) {
|
||||||
|
assert_instances_of($requests, 'HeraldWebhookRequest');
|
||||||
|
$this->requests = $requests;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setHighlightID($highlight_id) {
|
||||||
|
$this->highlightID = $highlight_id;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHighlightID() {
|
||||||
|
return $this->highlightID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render() {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$requests = $this->requests;
|
||||||
|
|
||||||
|
$handle_phids = array();
|
||||||
|
foreach ($requests as $request) {
|
||||||
|
$handle_phids[] = $request->getObjectPHID();
|
||||||
|
}
|
||||||
|
$handles = $viewer->loadHandles($handle_phids);
|
||||||
|
|
||||||
|
$highlight_id = $this->getHighlightID();
|
||||||
|
|
||||||
|
$rows = array();
|
||||||
|
$rowc = array();
|
||||||
|
foreach ($requests as $request) {
|
||||||
|
$icon = $request->newStatusIcon();
|
||||||
|
|
||||||
|
if ($highlight_id == $request->getID()) {
|
||||||
|
$rowc[] = 'highlighted';
|
||||||
|
} else {
|
||||||
|
$rowc[] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$last_epoch = $request->getLastRequestEpoch();
|
||||||
|
if ($request->getLastRequestEpoch()) {
|
||||||
|
$last_request = phabricator_datetime($last_epoch, $viewer);
|
||||||
|
} else {
|
||||||
|
$last_request = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$rows[] = array(
|
||||||
|
$request->getID(),
|
||||||
|
$icon,
|
||||||
|
$handles[$request->getObjectPHID()]->renderLink(),
|
||||||
|
$request->getErrorType(),
|
||||||
|
$request->getErrorCode(),
|
||||||
|
$last_request,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$table = id(new AphrontTableView($rows))
|
||||||
|
->setRowClasses($rowc)
|
||||||
|
->setHeaders(
|
||||||
|
array(
|
||||||
|
pht('ID'),
|
||||||
|
'',
|
||||||
|
pht('Object'),
|
||||||
|
pht('Type'),
|
||||||
|
pht('Code'),
|
||||||
|
pht('Requested At'),
|
||||||
|
))
|
||||||
|
->setColumnClasses(
|
||||||
|
array(
|
||||||
|
'n',
|
||||||
|
'',
|
||||||
|
'wide',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
));
|
||||||
|
|
||||||
|
return $table;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
243
src/applications/herald/worker/HeraldWebhookWorker.php
Normal file
243
src/applications/herald/worker/HeraldWebhookWorker.php
Normal file
|
@ -0,0 +1,243 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldWebhookWorker
|
||||||
|
extends PhabricatorWorker {
|
||||||
|
|
||||||
|
protected function doWork() {
|
||||||
|
$viewer = PhabricatorUser::getOmnipotentUser();
|
||||||
|
|
||||||
|
$data = $this->getTaskData();
|
||||||
|
$request_phid = idx($data, 'webhookRequestPHID');
|
||||||
|
|
||||||
|
$request = id(new HeraldWebhookRequestQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withPHIDs(array($request_phid))
|
||||||
|
->executeOne();
|
||||||
|
if (!$request) {
|
||||||
|
throw new PhabricatorWorkerPermanentFailureException(
|
||||||
|
pht(
|
||||||
|
'Unable to load webhook request ("%s"). It may have been '.
|
||||||
|
'garbage collected.',
|
||||||
|
$request_phid));
|
||||||
|
}
|
||||||
|
|
||||||
|
$status = $request->getStatus();
|
||||||
|
if ($status !== HeraldWebhookRequest::STATUS_QUEUED) {
|
||||||
|
throw new PhabricatorWorkerPermanentFailureException(
|
||||||
|
pht(
|
||||||
|
'Webhook request ("%s") is not in "%s" status (actual '.
|
||||||
|
'status is "%s"). Declining call to hook.',
|
||||||
|
$request_phid,
|
||||||
|
HeraldWebhookRequest::STATUS_QUEUED,
|
||||||
|
$status));
|
||||||
|
}
|
||||||
|
|
||||||
|
$hook = $request->getWebhook();
|
||||||
|
|
||||||
|
if ($hook->isDisabled()) {
|
||||||
|
$this->failRequest($request, 'hook', 'disabled');
|
||||||
|
throw new PhabricatorWorkerPermanentFailureException(
|
||||||
|
pht(
|
||||||
|
'Associated hook ("%s") for webhook request ("%s") is disabled.',
|
||||||
|
$hook->getPHID(),
|
||||||
|
$request_phid));
|
||||||
|
}
|
||||||
|
|
||||||
|
$uri = $hook->getWebhookURI();
|
||||||
|
try {
|
||||||
|
PhabricatorEnv::requireValidRemoteURIForFetch(
|
||||||
|
$uri,
|
||||||
|
array(
|
||||||
|
'http',
|
||||||
|
'https',
|
||||||
|
));
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
$this->failRequest($request, 'hook', 'uri');
|
||||||
|
throw new PhabricatorWorkerPermanentFailureException(
|
||||||
|
pht(
|
||||||
|
'Associated hook ("%s") for webhook request ("%s") has invalid '.
|
||||||
|
'fetch URI: %s',
|
||||||
|
$hook->getPHID(),
|
||||||
|
$request_phid,
|
||||||
|
$ex->getMessage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
$object_phid = $request->getObjectPHID();
|
||||||
|
|
||||||
|
$object = id(new PhabricatorObjectQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withPHIDs(array($object_phid))
|
||||||
|
->executeOne();
|
||||||
|
if (!$object) {
|
||||||
|
$this->failRequest($request, 'hook', 'object');
|
||||||
|
throw new PhabricatorWorkerPermanentFailureException(
|
||||||
|
pht(
|
||||||
|
'Unable to load object ("%s") for webhook request ("%s").',
|
||||||
|
$object_phid,
|
||||||
|
$request_phid));
|
||||||
|
}
|
||||||
|
|
||||||
|
$xaction_query = PhabricatorApplicationTransactionQuery::newQueryForObject(
|
||||||
|
$object);
|
||||||
|
$xaction_phids = $request->getTransactionPHIDs();
|
||||||
|
if ($xaction_phids) {
|
||||||
|
$xactions = $xaction_query
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withObjectPHIDs(array($object_phid))
|
||||||
|
->withPHIDs($xaction_phids)
|
||||||
|
->execute();
|
||||||
|
$xactions = mpull($xactions, null, 'getPHID');
|
||||||
|
} else {
|
||||||
|
$xactions = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
// To prevent thundering herd issues for high volume webhooks (where
|
||||||
|
// a large number of workers might try to work through a request backlog
|
||||||
|
// simultaneously, before the error backoff can catch up), we never
|
||||||
|
// parallelize requests to a particular webhook.
|
||||||
|
|
||||||
|
$lock_key = 'webhook('.$hook->getPHID().')';
|
||||||
|
$lock = PhabricatorGlobalLock::newLock($lock_key);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$lock->lock();
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
phlog($ex);
|
||||||
|
throw new PhabricatorWorkerYieldException(15);
|
||||||
|
}
|
||||||
|
|
||||||
|
$caught = null;
|
||||||
|
try {
|
||||||
|
$this->callWebhookWithLock($hook, $request, $object, $xactions);
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
$caught = $ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
$lock->unlock();
|
||||||
|
|
||||||
|
if ($caught) {
|
||||||
|
throw $caught;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function callWebhookWithLock(
|
||||||
|
HeraldWebhook $hook,
|
||||||
|
HeraldWebhookRequest $request,
|
||||||
|
$object,
|
||||||
|
array $xactions) {
|
||||||
|
$viewer = PhabricatorUser::getOmnipotentUser();
|
||||||
|
|
||||||
|
if ($hook->isInErrorBackoff($viewer)) {
|
||||||
|
throw new PhabricatorWorkerYieldException($hook->getErrorBackoffWindow());
|
||||||
|
}
|
||||||
|
|
||||||
|
$xaction_data = array();
|
||||||
|
foreach ($xactions as $xaction) {
|
||||||
|
$xaction_data[] = array(
|
||||||
|
'phid' => $xaction->getPHID(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$trigger_data = array();
|
||||||
|
foreach ($request->getTriggerPHIDs() as $trigger_phid) {
|
||||||
|
$trigger_data[] = array(
|
||||||
|
'phid' => $trigger_phid,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$payload = array(
|
||||||
|
'object' => array(
|
||||||
|
'type' => phid_get_type($object->getPHID()),
|
||||||
|
'phid' => $object->getPHID(),
|
||||||
|
),
|
||||||
|
'triggers' => $trigger_data,
|
||||||
|
'action' => array(
|
||||||
|
'test' => $request->getIsTestAction(),
|
||||||
|
'silent' => $request->getIsSilentAction(),
|
||||||
|
'secure' => $request->getIsSecureAction(),
|
||||||
|
'epoch' => (int)$request->getDateCreated(),
|
||||||
|
),
|
||||||
|
'transactions' => $xaction_data,
|
||||||
|
);
|
||||||
|
|
||||||
|
$payload = id(new PhutilJSON())->encodeFormatted($payload);
|
||||||
|
$key = $hook->getHmacKey();
|
||||||
|
$signature = PhabricatorHash::digestHMACSHA256($payload, $key);
|
||||||
|
$uri = $hook->getWebhookURI();
|
||||||
|
|
||||||
|
$future = id(new HTTPSFuture($uri))
|
||||||
|
->setMethod('POST')
|
||||||
|
->addHeader('Content-Type', 'application/json')
|
||||||
|
->addHeader('X-Phabricator-Webhook-Signature', $signature)
|
||||||
|
->setTimeout(15)
|
||||||
|
->setData($payload);
|
||||||
|
|
||||||
|
list($status) = $future->resolve();
|
||||||
|
|
||||||
|
if ($status->isTimeout()) {
|
||||||
|
$error_type = 'timeout';
|
||||||
|
} else {
|
||||||
|
$error_type = 'http';
|
||||||
|
}
|
||||||
|
$error_code = $status->getStatusCode();
|
||||||
|
|
||||||
|
$request
|
||||||
|
->setErrorType($error_type)
|
||||||
|
->setErrorCode($error_code)
|
||||||
|
->setLastRequestEpoch(PhabricatorTime::getNow());
|
||||||
|
|
||||||
|
$retry_forever = HeraldWebhookRequest::RETRY_FOREVER;
|
||||||
|
if ($status->isTimeout() || $status->isError()) {
|
||||||
|
$should_retry = ($request->getRetryMode() === $retry_forever);
|
||||||
|
|
||||||
|
$request
|
||||||
|
->setLastRequestResult(HeraldWebhookRequest::RESULT_FAIL);
|
||||||
|
|
||||||
|
if ($should_retry) {
|
||||||
|
$request->save();
|
||||||
|
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Webhook request ("%s", to "%s") failed (%s / %s). The request '.
|
||||||
|
'will be retried.',
|
||||||
|
$request->getPHID(),
|
||||||
|
$uri,
|
||||||
|
$error_type,
|
||||||
|
$error_code));
|
||||||
|
} else {
|
||||||
|
$request
|
||||||
|
->setStatus(HeraldWebhookRequest::STATUS_FAILED)
|
||||||
|
->save();
|
||||||
|
|
||||||
|
throw new PhabricatorWorkerPermanentFailureException(
|
||||||
|
pht(
|
||||||
|
'Webhook request ("%s", to "%s") failed (%s / %s). The request '.
|
||||||
|
'will not be retried.',
|
||||||
|
$request->getPHID(),
|
||||||
|
$uri,
|
||||||
|
$error_type,
|
||||||
|
$error_code));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$request
|
||||||
|
->setLastRequestResult(HeraldWebhookRequest::RESULT_OKAY)
|
||||||
|
->setStatus(HeraldWebhookRequest::STATUS_SENT)
|
||||||
|
->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function failRequest(
|
||||||
|
HeraldWebhookRequest $request,
|
||||||
|
$error_type,
|
||||||
|
$error_code) {
|
||||||
|
|
||||||
|
$request
|
||||||
|
->setStatus(HeraldWebhookRequest::STATUS_FAILED)
|
||||||
|
->setErrorType($error_type)
|
||||||
|
->setErrorCode($error_code)
|
||||||
|
->setLastRequestResult(HeraldWebhookRequest::RESULT_NONE)
|
||||||
|
->setLastRequestEpoch(0)
|
||||||
|
->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldWebhookNameTransaction
|
||||||
|
extends HeraldWebhookTransactionType {
|
||||||
|
|
||||||
|
const TRANSACTIONTYPE = 'name';
|
||||||
|
|
||||||
|
public function generateOldValue($object) {
|
||||||
|
return $object->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyInternalEffects($object, $value) {
|
||||||
|
$object->setName($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle() {
|
||||||
|
return pht(
|
||||||
|
'%s renamed this webhook from %s to %s.',
|
||||||
|
$this->renderAuthor(),
|
||||||
|
$this->renderOldValue(),
|
||||||
|
$this->renderNewValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitleForFeed() {
|
||||||
|
return pht(
|
||||||
|
'%s renamed %s from %s to %s.',
|
||||||
|
$this->renderAuthor(),
|
||||||
|
$this->renderObject(),
|
||||||
|
$this->renderOldValue(),
|
||||||
|
$this->renderNewValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateTransactions($object, array $xactions) {
|
||||||
|
$errors = array();
|
||||||
|
$viewer = $this->getActor();
|
||||||
|
|
||||||
|
if ($this->isEmptyTextTransaction($object->getName(), $xactions)) {
|
||||||
|
$errors[] = $this->newRequiredError(
|
||||||
|
pht('Webhooks must have a name.'));
|
||||||
|
return $errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
$max_length = $object->getColumnMaximumByteLength('name');
|
||||||
|
foreach ($xactions as $xaction) {
|
||||||
|
$old_value = $this->generateOldValue($object);
|
||||||
|
$new_value = $xaction->getNewValue();
|
||||||
|
|
||||||
|
$new_length = strlen($new_value);
|
||||||
|
if ($new_length > $max_length) {
|
||||||
|
$errors[] = $this->newInvalidError(
|
||||||
|
pht(
|
||||||
|
'Webhook names can be no longer than %s characters.',
|
||||||
|
new PhutilNumber($max_length)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldWebhookStatusTransaction
|
||||||
|
extends HeraldWebhookTransactionType {
|
||||||
|
|
||||||
|
const TRANSACTIONTYPE = 'status';
|
||||||
|
|
||||||
|
public function generateOldValue($object) {
|
||||||
|
return $object->getStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyInternalEffects($object, $value) {
|
||||||
|
$object->setStatus($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle() {
|
||||||
|
$old_value = $this->getOldValue();
|
||||||
|
$new_value = $this->getNewValue();
|
||||||
|
|
||||||
|
$old_status = HeraldWebhook::getDisplayNameForStatus($old_value);
|
||||||
|
$new_status = HeraldWebhook::getDisplayNameForStatus($new_value);
|
||||||
|
|
||||||
|
return pht(
|
||||||
|
'%s changed hook status from %s to %s.',
|
||||||
|
$this->renderAuthor(),
|
||||||
|
$this->renderValue($old_status),
|
||||||
|
$this->renderValue($new_status));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitleForFeed() {
|
||||||
|
$old_value = $this->getOldValue();
|
||||||
|
$new_value = $this->getNewValue();
|
||||||
|
|
||||||
|
$old_status = HeraldWebhook::getDisplayNameForStatus($old_value);
|
||||||
|
$new_status = HeraldWebhook::getDisplayNameForStatus($new_value);
|
||||||
|
|
||||||
|
return pht(
|
||||||
|
'%s changed %s from %s to %s.',
|
||||||
|
$this->renderAuthor(),
|
||||||
|
$this->renderObject(),
|
||||||
|
$this->renderValue($old_status),
|
||||||
|
$this->renderValue($new_status));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateTransactions($object, array $xactions) {
|
||||||
|
$errors = array();
|
||||||
|
$viewer = $this->getActor();
|
||||||
|
|
||||||
|
$options = HeraldWebhook::getStatusDisplayNameMap();
|
||||||
|
|
||||||
|
foreach ($xactions as $xaction) {
|
||||||
|
$new_value = $xaction->getNewValue();
|
||||||
|
|
||||||
|
if (!isset($options[$new_value])) {
|
||||||
|
$errors[] = $this->newInvalidError(
|
||||||
|
pht(
|
||||||
|
'Webhook status "%s" is not valid. Valid statuses are: %s.',
|
||||||
|
$new_value,
|
||||||
|
implode(', ', array_keys($options))),
|
||||||
|
$xaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class HeraldWebhookTransactionType
|
||||||
|
extends PhabricatorModularTransactionType {}
|
|
@ -0,0 +1,74 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class HeraldWebhookURITransaction
|
||||||
|
extends HeraldWebhookTransactionType {
|
||||||
|
|
||||||
|
const TRANSACTIONTYPE = 'uri';
|
||||||
|
|
||||||
|
public function generateOldValue($object) {
|
||||||
|
return $object->getWebhookURI();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyInternalEffects($object, $value) {
|
||||||
|
$object->setWebhookURI($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle() {
|
||||||
|
return pht(
|
||||||
|
'%s changed the URI for this webhook from %s to %s.',
|
||||||
|
$this->renderAuthor(),
|
||||||
|
$this->renderOldValue(),
|
||||||
|
$this->renderNewValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitleForFeed() {
|
||||||
|
return pht(
|
||||||
|
'%s changed the URI for %s from %s to %s.',
|
||||||
|
$this->renderAuthor(),
|
||||||
|
$this->renderObject(),
|
||||||
|
$this->renderOldValue(),
|
||||||
|
$this->renderNewValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validateTransactions($object, array $xactions) {
|
||||||
|
$errors = array();
|
||||||
|
$viewer = $this->getActor();
|
||||||
|
|
||||||
|
if ($this->isEmptyTextTransaction($object->getName(), $xactions)) {
|
||||||
|
$errors[] = $this->newRequiredError(
|
||||||
|
pht('Webhooks must have a URI.'));
|
||||||
|
return $errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
$max_length = $object->getColumnMaximumByteLength('webhookURI');
|
||||||
|
foreach ($xactions as $xaction) {
|
||||||
|
$old_value = $this->generateOldValue($object);
|
||||||
|
$new_value = $xaction->getNewValue();
|
||||||
|
|
||||||
|
$new_length = strlen($new_value);
|
||||||
|
if ($new_length > $max_length) {
|
||||||
|
$errors[] = $this->newInvalidError(
|
||||||
|
pht(
|
||||||
|
'Webhook URIs can be no longer than %s characters.',
|
||||||
|
new PhutilNumber($max_length)),
|
||||||
|
$xaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
PhabricatorEnv::requireValidRemoteURIForFetch(
|
||||||
|
$new_value,
|
||||||
|
array(
|
||||||
|
'http',
|
||||||
|
'https',
|
||||||
|
));
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
$errors[] = $this->newInvalidError(
|
||||||
|
$ex->getMessage(),
|
||||||
|
$xaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -124,12 +124,10 @@ final class LegalpadDocumentEditor
|
||||||
|
|
||||||
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
|
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
|
||||||
$id = $object->getID();
|
$id = $object->getID();
|
||||||
$phid = $object->getPHID();
|
|
||||||
$title = $object->getDocumentBody()->getTitle();
|
$title = $object->getDocumentBody()->getTitle();
|
||||||
|
|
||||||
return id(new PhabricatorMetaMTAMail())
|
return id(new PhabricatorMetaMTAMail())
|
||||||
->setSubject("L{$id}: {$title}")
|
->setSubject("L{$id}: {$title}");
|
||||||
->addHeader('Thread-Topic', "L{$id}: {$phid}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getMailTo(PhabricatorLiskDAO $object) {
|
protected function getMailTo(PhabricatorLiskDAO $object) {
|
||||||
|
|
|
@ -176,7 +176,7 @@ final class LegalpadDocumentSearchEngine
|
||||||
$create_button = id(new PHUIButtonView())
|
$create_button = id(new PHUIButtonView())
|
||||||
->setTag('a')
|
->setTag('a')
|
||||||
->setText(pht('Create a Document'))
|
->setText(pht('Create a Document'))
|
||||||
->setHref('/legalpad/create/')
|
->setHref('/legalpad/edit/')
|
||||||
->setColor(PHUIButtonView::GREEN);
|
->setColor(PHUIButtonView::GREEN);
|
||||||
|
|
||||||
$icon = $this->getApplication()->getIcon();
|
$icon = $this->getApplication()->getIcon();
|
||||||
|
|
|
@ -35,8 +35,7 @@ final class PhabricatorMacroEditor
|
||||||
$name = 'Image Macro "'.$name.'"';
|
$name = 'Image Macro "'.$name.'"';
|
||||||
|
|
||||||
return id(new PhabricatorMetaMTAMail())
|
return id(new PhabricatorMetaMTAMail())
|
||||||
->setSubject($name)
|
->setSubject($name);
|
||||||
->addHeader('Thread-Topic', $name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getMailTo(PhabricatorLiskDAO $object) {
|
protected function getMailTo(PhabricatorLiskDAO $object) {
|
||||||
|
|
|
@ -8,7 +8,7 @@ final class PhabricatorImageMacroRemarkupRule extends PhutilRemarkupRule {
|
||||||
|
|
||||||
public function apply($text) {
|
public function apply($text) {
|
||||||
return preg_replace_callback(
|
return preg_replace_callback(
|
||||||
'@^\s*([a-zA-Z0-9:_\-]+)$@m',
|
'@^\s*([a-zA-Z0-9:_\x7f-\xff-]+)$@m',
|
||||||
array($this, 'markupImageMacro'),
|
array($this, 'markupImageMacro'),
|
||||||
$text);
|
$text);
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,12 +52,16 @@ final class PhabricatorMacroNameTransaction
|
||||||
new PhutilNumber($max_length)));
|
new PhutilNumber($max_length)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!preg_match('/^[a-z0-9:_-]{3,}\z/', $new_value)) {
|
if (!self::isValidMacroName($new_value)) {
|
||||||
$errors[] = $this->newInvalidError(
|
// This says "emoji", but the actual rule we implement is "all other
|
||||||
pht('Macro name "%s" be at least three characters long and contain '.
|
// unicode characters are also fine".
|
||||||
'only lowercase letters, digits, hyphens, colons and '.
|
$errors[] = $this->newInvalidError(
|
||||||
'underscores.',
|
pht(
|
||||||
$new_value));
|
'Macro name "%s" be: at least three characters long; and contain '.
|
||||||
|
'only lowercase letters, digits, hyphens, colons, underscores, '.
|
||||||
|
'and emoji; and not be composed entirely of latin symbols.',
|
||||||
|
$new_value),
|
||||||
|
$xaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check name is unique when updating / creating
|
// Check name is unique when updating / creating
|
||||||
|
@ -78,4 +82,35 @@ final class PhabricatorMacroNameTransaction
|
||||||
return $errors;
|
return $errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function isValidMacroName($name) {
|
||||||
|
if (preg_match('/^[:_-]+\z/', $name)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accept trivial macro names.
|
||||||
|
if (preg_match('/^[a-z0-9:_-]{3,}\z/', $name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reject names with fewer than 3 glyphs.
|
||||||
|
$length = phutil_utf8v_combined($name);
|
||||||
|
if (count($length) < 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check character-by-character for any symbols that we don't want.
|
||||||
|
$characters = phutil_utf8v($name);
|
||||||
|
foreach ($characters as $character) {
|
||||||
|
if (ord($character[0]) > 0x7F) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('/^[^a-z0-9:_-]/', $character)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorMacroTestCase
|
||||||
|
extends PhabricatorTestCase {
|
||||||
|
|
||||||
|
public function testMacroNames() {
|
||||||
|
$lit = "\xF0\x9F\x94\xA5";
|
||||||
|
$combining_diaeresis = "\xCC\x88";
|
||||||
|
|
||||||
|
$cases = array(
|
||||||
|
// Only 2 glyphs long.
|
||||||
|
"u{$combining_diaeresis}n" => false,
|
||||||
|
"{$lit}{$lit}" => false,
|
||||||
|
|
||||||
|
// Too short.
|
||||||
|
'a' => false,
|
||||||
|
'' => false,
|
||||||
|
|
||||||
|
// Bad characters.
|
||||||
|
'yes!' => false,
|
||||||
|
"{$lit} {$lit} {$lit}" => false,
|
||||||
|
"aaa\nbbb" => false,
|
||||||
|
'aaa~' => false,
|
||||||
|
'aaa`' => false,
|
||||||
|
|
||||||
|
// Special rejections for only latin symbols.
|
||||||
|
'---' => false,
|
||||||
|
'___' => false,
|
||||||
|
'-_-' => false,
|
||||||
|
':::' => false,
|
||||||
|
'-_:' => false,
|
||||||
|
|
||||||
|
"{$lit}{$lit}{$lit}" => true,
|
||||||
|
'bwahahaha' => true,
|
||||||
|
"u{$combining_diaeresis}nt" => true,
|
||||||
|
'a-a-a-a' => true,
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($cases as $input => $expect) {
|
||||||
|
$this->assertEqual(
|
||||||
|
$expect,
|
||||||
|
PhabricatorMacroNameTransaction::isValidMacroName($input),
|
||||||
|
pht('Validity of macro "%s"', $input));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -206,8 +206,7 @@ final class ManiphestTransactionEditor
|
||||||
$title = $object->getTitle();
|
$title = $object->getTitle();
|
||||||
|
|
||||||
return id(new PhabricatorMetaMTAMail())
|
return id(new PhabricatorMetaMTAMail())
|
||||||
->setSubject("T{$id}: {$title}")
|
->setSubject("T{$id}: {$title}");
|
||||||
->addHeader('Thread-Topic', "T{$id}: ".$object->getOriginalTitle());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildMailBody(
|
protected function buildMailBody(
|
||||||
|
@ -523,7 +522,6 @@ final class ManiphestTransactionEditor
|
||||||
'status' => '""',
|
'status' => '""',
|
||||||
'priority' => 0,
|
'priority' => 0,
|
||||||
'title' => '""',
|
'title' => '""',
|
||||||
'originalTitle' => '""',
|
|
||||||
'description' => '""',
|
'description' => '""',
|
||||||
'dateCreated' => 0,
|
'dateCreated' => 0,
|
||||||
'dateModified' => 0,
|
'dateModified' => 0,
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ManiphestMailEngineExtension
|
||||||
|
extends PhabricatorMailEngineExtension {
|
||||||
|
|
||||||
|
const EXTENSIONKEY = 'maniphest';
|
||||||
|
|
||||||
|
public function supportsObject($object) {
|
||||||
|
return ($object instanceof ManiphestTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newMailStampTemplates($object) {
|
||||||
|
return array(
|
||||||
|
id(new PhabricatorPHIDMailStamp())
|
||||||
|
->setKey('author')
|
||||||
|
->setLabel(pht('Author')),
|
||||||
|
id(new PhabricatorPHIDMailStamp())
|
||||||
|
->setKey('task-owner')
|
||||||
|
->setLabel(pht('Task Owner')),
|
||||||
|
id(new PhabricatorBoolMailStamp())
|
||||||
|
->setKey('task-unassigned')
|
||||||
|
->setLabel(pht('Task Unassigned')),
|
||||||
|
id(new PhabricatorStringMailStamp())
|
||||||
|
->setKey('task-priority')
|
||||||
|
->setLabel(pht('Task Priority')),
|
||||||
|
id(new PhabricatorStringMailStamp())
|
||||||
|
->setKey('task-status')
|
||||||
|
->setLabel(pht('Task Status')),
|
||||||
|
id(new PhabricatorStringMailStamp())
|
||||||
|
->setKey('subtype')
|
||||||
|
->setLabel(pht('Subtype')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newMailStamps($object, array $xactions) {
|
||||||
|
$editor = $this->getEditor();
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$this->getMailStamp('author')
|
||||||
|
->setValue($object->getAuthorPHID());
|
||||||
|
|
||||||
|
$this->getMailStamp('task-owner')
|
||||||
|
->setValue($object->getOwnerPHID());
|
||||||
|
|
||||||
|
$this->getMailStamp('task-unassigned')
|
||||||
|
->setValue(!$object->getOwnerPHID());
|
||||||
|
|
||||||
|
$this->getMailStamp('task-priority')
|
||||||
|
->setValue($object->getPriority());
|
||||||
|
|
||||||
|
$this->getMailStamp('task-status')
|
||||||
|
->setValue($object->getStatus());
|
||||||
|
|
||||||
|
$this->getMailStamp('subtype')
|
||||||
|
->setValue($object->getSubtype());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -23,6 +23,9 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||||
private $parentTaskIDs;
|
private $parentTaskIDs;
|
||||||
private $subtaskIDs;
|
private $subtaskIDs;
|
||||||
private $subtypes;
|
private $subtypes;
|
||||||
|
private $closedEpochMin;
|
||||||
|
private $closedEpochMax;
|
||||||
|
private $closerPHIDs;
|
||||||
|
|
||||||
private $status = 'status-any';
|
private $status = 'status-any';
|
||||||
const STATUS_ANY = 'status-any';
|
const STATUS_ANY = 'status-any';
|
||||||
|
@ -179,6 +182,17 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function withClosedEpochBetween($min, $max) {
|
||||||
|
$this->closedEpochMin = $min;
|
||||||
|
$this->closedEpochMax = $max;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withCloserPHIDs(array $phids) {
|
||||||
|
$this->closerPHIDs = $phids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function needSubscriberPHIDs($bool) {
|
public function needSubscriberPHIDs($bool) {
|
||||||
$this->needSubscriberPHIDs = $bool;
|
$this->needSubscriberPHIDs = $bool;
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -379,6 +393,27 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||||
$this->dateModifiedBefore);
|
$this->dateModifiedBefore);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->closedEpochMin !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'task.closedEpoch >= %d',
|
||||||
|
$this->closedEpochMin);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->closedEpochMax !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'task.closedEpoch <= %d',
|
||||||
|
$this->closedEpochMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->closerPHIDs !== null) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'task.closerPHID IN (%Ls)',
|
||||||
|
$this->closerPHIDs);
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->priorities !== null) {
|
if ($this->priorities !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn,
|
$conn,
|
||||||
|
@ -722,7 +757,11 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||||
'outdated' => array(
|
'outdated' => array(
|
||||||
'vector' => array('-updated', '-id'),
|
'vector' => array('-updated', '-id'),
|
||||||
'name' => pht('Date Updated (Oldest First)'),
|
'name' => pht('Date Updated (Oldest First)'),
|
||||||
),
|
),
|
||||||
|
'closed' => array(
|
||||||
|
'vector' => array('closed', 'id'),
|
||||||
|
'name' => pht('Date Closed (Latest First)'),
|
||||||
|
),
|
||||||
'title' => array(
|
'title' => array(
|
||||||
'vector' => array('title', 'id'),
|
'vector' => array('title', 'id'),
|
||||||
'name' => pht('Title'),
|
'name' => pht('Title'),
|
||||||
|
@ -741,6 +780,7 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||||
'outdated',
|
'outdated',
|
||||||
'newest',
|
'newest',
|
||||||
'oldest',
|
'oldest',
|
||||||
|
'closed',
|
||||||
'title',
|
'title',
|
||||||
)) + $orders;
|
)) + $orders;
|
||||||
|
|
||||||
|
@ -790,6 +830,12 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||||
'column' => 'dateModified',
|
'column' => 'dateModified',
|
||||||
'type' => 'int',
|
'type' => 'int',
|
||||||
),
|
),
|
||||||
|
'closed' => array(
|
||||||
|
'table' => 'task',
|
||||||
|
'column' => 'closedEpoch',
|
||||||
|
'type' => 'int',
|
||||||
|
'null' => 'tail',
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -808,6 +854,7 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||||
'status' => $task->getStatus(),
|
'status' => $task->getStatus(),
|
||||||
'title' => $task->getTitle(),
|
'title' => $task->getTitle(),
|
||||||
'updated' => $task->getDateModified(),
|
'updated' => $task->getDateModified(),
|
||||||
|
'closed' => $task->getClosedEpoch(),
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach ($keys as $key) {
|
foreach ($keys as $key) {
|
||||||
|
|
|
@ -126,6 +126,17 @@ final class ManiphestTaskSearchEngine
|
||||||
id(new PhabricatorSearchDateField())
|
id(new PhabricatorSearchDateField())
|
||||||
->setLabel(pht('Updated Before'))
|
->setLabel(pht('Updated Before'))
|
||||||
->setKey('modifiedEnd'),
|
->setKey('modifiedEnd'),
|
||||||
|
id(new PhabricatorSearchDateField())
|
||||||
|
->setLabel(pht('Closed After'))
|
||||||
|
->setKey('closedStart'),
|
||||||
|
id(new PhabricatorSearchDateField())
|
||||||
|
->setLabel(pht('Closed Before'))
|
||||||
|
->setKey('closedEnd'),
|
||||||
|
id(new PhabricatorUsersSearchField())
|
||||||
|
->setLabel(pht('Closed By'))
|
||||||
|
->setKey('closerPHIDs')
|
||||||
|
->setAliases(array('closer', 'closerPHID', 'closers'))
|
||||||
|
->setDescription(pht('Search for tasks closed by certain users.')),
|
||||||
id(new PhabricatorSearchTextField())
|
id(new PhabricatorSearchTextField())
|
||||||
->setLabel(pht('Page Size'))
|
->setLabel(pht('Page Size'))
|
||||||
->setKey('limit'),
|
->setKey('limit'),
|
||||||
|
@ -153,6 +164,9 @@ final class ManiphestTaskSearchEngine
|
||||||
'createdEnd',
|
'createdEnd',
|
||||||
'modifiedStart',
|
'modifiedStart',
|
||||||
'modifiedEnd',
|
'modifiedEnd',
|
||||||
|
'closedStart',
|
||||||
|
'closedEnd',
|
||||||
|
'closerPHIDs',
|
||||||
'limit',
|
'limit',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -208,6 +222,14 @@ final class ManiphestTaskSearchEngine
|
||||||
$query->withDateModifiedBefore($map['modifiedEnd']);
|
$query->withDateModifiedBefore($map['modifiedEnd']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($map['closedStart'] || $map['closedEnd']) {
|
||||||
|
$query->withClosedEpochBetween($map['closedStart'], $map['closedEnd']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($map['closerPHIDs']) {
|
||||||
|
$query->withCloserPHIDs($map['closerPHIDs']);
|
||||||
|
}
|
||||||
|
|
||||||
if ($map['hasParents'] !== null) {
|
if ($map['hasParents'] !== null) {
|
||||||
$query->withOpenParents($map['hasParents']);
|
$query->withOpenParents($map['hasParents']);
|
||||||
}
|
}
|
||||||
|
@ -456,6 +478,15 @@ final class ManiphestTaskSearchEngine
|
||||||
id(new PhabricatorStringExportField())
|
id(new PhabricatorStringExportField())
|
||||||
->setKey('statusName')
|
->setKey('statusName')
|
||||||
->setLabel(pht('Status Name')),
|
->setLabel(pht('Status Name')),
|
||||||
|
id(new PhabricatorEpochExportField())
|
||||||
|
->setKey('dateClosed')
|
||||||
|
->setLabel(pht('Date Closed')),
|
||||||
|
id(new PhabricatorPHIDExportField())
|
||||||
|
->setKey('closerPHID')
|
||||||
|
->setLabel(pht('Closer PHID')),
|
||||||
|
id(new PhabricatorStringExportField())
|
||||||
|
->setKey('closer')
|
||||||
|
->setLabel(pht('Closer')),
|
||||||
id(new PhabricatorStringExportField())
|
id(new PhabricatorStringExportField())
|
||||||
->setKey('priority')
|
->setKey('priority')
|
||||||
->setLabel(pht('Priority')),
|
->setLabel(pht('Priority')),
|
||||||
|
@ -492,6 +523,7 @@ final class ManiphestTaskSearchEngine
|
||||||
foreach ($tasks as $task) {
|
foreach ($tasks as $task) {
|
||||||
$phids[] = $task->getAuthorPHID();
|
$phids[] = $task->getAuthorPHID();
|
||||||
$phids[] = $task->getOwnerPHID();
|
$phids[] = $task->getOwnerPHID();
|
||||||
|
$phids[] = $task->getCloserPHID();
|
||||||
}
|
}
|
||||||
$handles = $viewer->loadHandles($phids);
|
$handles = $viewer->loadHandles($phids);
|
||||||
|
|
||||||
|
@ -512,6 +544,13 @@ final class ManiphestTaskSearchEngine
|
||||||
$owner_name = null;
|
$owner_name = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$closer_phid = $task->getCloserPHID();
|
||||||
|
if ($closer_phid) {
|
||||||
|
$closer_name = $handles[$closer_phid]->getName();
|
||||||
|
} else {
|
||||||
|
$closer_name = null;
|
||||||
|
}
|
||||||
|
|
||||||
$status_value = $task->getStatus();
|
$status_value = $task->getStatus();
|
||||||
$status_name = ManiphestTaskStatus::getTaskStatusName($status_value);
|
$status_name = ManiphestTaskStatus::getTaskStatusName($status_value);
|
||||||
|
|
||||||
|
@ -534,6 +573,9 @@ final class ManiphestTaskSearchEngine
|
||||||
'title' => $task->getTitle(),
|
'title' => $task->getTitle(),
|
||||||
'uri' => PhabricatorEnv::getProductionURI($task->getURI()),
|
'uri' => PhabricatorEnv::getProductionURI($task->getURI()),
|
||||||
'description' => $task->getDescription(),
|
'description' => $task->getDescription(),
|
||||||
|
'dateClosed' => $task->getClosedEpoch(),
|
||||||
|
'closerPHID' => $closer_phid,
|
||||||
|
'closer' => $closer_name,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,6 @@ final class ManiphestTask extends ManiphestDAO
|
||||||
protected $subpriority = 0;
|
protected $subpriority = 0;
|
||||||
|
|
||||||
protected $title = '';
|
protected $title = '';
|
||||||
protected $originalTitle = '';
|
|
||||||
protected $description = '';
|
protected $description = '';
|
||||||
protected $originalEmailSource;
|
protected $originalEmailSource;
|
||||||
protected $mailKey;
|
protected $mailKey;
|
||||||
|
@ -45,6 +44,9 @@ final class ManiphestTask extends ManiphestDAO
|
||||||
protected $points;
|
protected $points;
|
||||||
protected $subtype;
|
protected $subtype;
|
||||||
|
|
||||||
|
protected $closedEpoch;
|
||||||
|
protected $closerPHID;
|
||||||
|
|
||||||
private $subscriberPHIDs = self::ATTACHABLE;
|
private $subscriberPHIDs = self::ATTACHABLE;
|
||||||
private $groupByProjectPHID = self::ATTACHABLE;
|
private $groupByProjectPHID = self::ATTACHABLE;
|
||||||
private $customFields = self::ATTACHABLE;
|
private $customFields = self::ATTACHABLE;
|
||||||
|
@ -83,7 +85,6 @@ final class ManiphestTask extends ManiphestDAO
|
||||||
'status' => 'text64',
|
'status' => 'text64',
|
||||||
'priority' => 'uint32',
|
'priority' => 'uint32',
|
||||||
'title' => 'sort',
|
'title' => 'sort',
|
||||||
'originalTitle' => 'text',
|
|
||||||
'description' => 'text',
|
'description' => 'text',
|
||||||
'mailKey' => 'bytes20',
|
'mailKey' => 'bytes20',
|
||||||
'ownerOrdering' => 'text64?',
|
'ownerOrdering' => 'text64?',
|
||||||
|
@ -92,6 +93,8 @@ final class ManiphestTask extends ManiphestDAO
|
||||||
'points' => 'double?',
|
'points' => 'double?',
|
||||||
'bridgedObjectPHID' => 'phid?',
|
'bridgedObjectPHID' => 'phid?',
|
||||||
'subtype' => 'text64',
|
'subtype' => 'text64',
|
||||||
|
'closedEpoch' => 'epoch?',
|
||||||
|
'closerPHID' => 'phid?',
|
||||||
),
|
),
|
||||||
self::CONFIG_KEY_SCHEMA => array(
|
self::CONFIG_KEY_SCHEMA => array(
|
||||||
'key_phid' => null,
|
'key_phid' => null,
|
||||||
|
@ -133,6 +136,12 @@ final class ManiphestTask extends ManiphestDAO
|
||||||
'key_subtype' => array(
|
'key_subtype' => array(
|
||||||
'columns' => array('subtype'),
|
'columns' => array('subtype'),
|
||||||
),
|
),
|
||||||
|
'key_closed' => array(
|
||||||
|
'columns' => array('closedEpoch'),
|
||||||
|
),
|
||||||
|
'key_closer' => array(
|
||||||
|
'columns' => array('closerPHID', 'closedEpoch'),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
) + parent::getConfiguration();
|
) + parent::getConfiguration();
|
||||||
}
|
}
|
||||||
|
@ -176,14 +185,6 @@ final class ManiphestTask extends ManiphestDAO
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setTitle($title) {
|
|
||||||
$this->title = $title;
|
|
||||||
if (!$this->getID()) {
|
|
||||||
$this->originalTitle = $title;
|
|
||||||
}
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getMonogram() {
|
public function getMonogram() {
|
||||||
return 'T'.$this->getID();
|
return 'T'.$this->getID();
|
||||||
}
|
}
|
||||||
|
@ -512,6 +513,16 @@ final class ManiphestTask extends ManiphestDAO
|
||||||
->setKey('subtype')
|
->setKey('subtype')
|
||||||
->setType('string')
|
->setType('string')
|
||||||
->setDescription(pht('Subtype of the task.')),
|
->setDescription(pht('Subtype of the task.')),
|
||||||
|
id(new PhabricatorConduitSearchFieldSpecification())
|
||||||
|
->setKey('closerPHID')
|
||||||
|
->setType('phid?')
|
||||||
|
->setDescription(
|
||||||
|
pht('User who closed the task, if the task is closed.')),
|
||||||
|
id(new PhabricatorConduitSearchFieldSpecification())
|
||||||
|
->setKey('dateClosed')
|
||||||
|
->setType('int?')
|
||||||
|
->setDescription(
|
||||||
|
pht('Epoch timestamp when the task was closed.')),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,6 +542,11 @@ final class ManiphestTask extends ManiphestDAO
|
||||||
'color' => ManiphestTaskPriority::getTaskPriorityColor($priority_value),
|
'color' => ManiphestTaskPriority::getTaskPriorityColor($priority_value),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$closed_epoch = $this->getClosedEpoch();
|
||||||
|
if ($closed_epoch !== null) {
|
||||||
|
$closed_epoch = (int)$closed_epoch;
|
||||||
|
}
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'name' => $this->getTitle(),
|
'name' => $this->getTitle(),
|
||||||
'description' => array(
|
'description' => array(
|
||||||
|
@ -542,6 +558,8 @@ final class ManiphestTask extends ManiphestDAO
|
||||||
'priority' => $priority_info,
|
'priority' => $priority_info,
|
||||||
'points' => $this->getPoints(),
|
'points' => $this->getPoints(),
|
||||||
'subtype' => $this->getSubtype(),
|
'subtype' => $this->getSubtype(),
|
||||||
|
'closerPHID' => $this->getCloserPHID(),
|
||||||
|
'dateClosed' => $closed_epoch,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,9 +86,24 @@ final class ManiphestTaskListView extends ManiphestView {
|
||||||
|
|
||||||
$item->setStatusIcon($icon.' '.$color, $tooltip);
|
$item->setStatusIcon($icon.' '.$color, $tooltip);
|
||||||
|
|
||||||
$item->addIcon(
|
if ($task->isClosed()) {
|
||||||
'none',
|
$closed_epoch = $task->getClosedEpoch();
|
||||||
phabricator_datetime($task->getDateModified(), $this->getUser()));
|
|
||||||
|
// We don't expect a task to be closed without a closed epoch, but
|
||||||
|
// recover if we find one. This can happen with older objects or with
|
||||||
|
// lipsum test data.
|
||||||
|
if (!$closed_epoch) {
|
||||||
|
$closed_epoch = $task->getDateModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
$item->addIcon(
|
||||||
|
'fa-check-square-o grey',
|
||||||
|
phabricator_datetime($closed_epoch, $this->getUser()));
|
||||||
|
} else {
|
||||||
|
$item->addIcon(
|
||||||
|
'none',
|
||||||
|
phabricator_datetime($task->getDateModified(), $this->getUser()));
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->showSubpriorityControls) {
|
if ($this->showSubpriorityControls) {
|
||||||
$item->setGrippable(true);
|
$item->setGrippable(true);
|
||||||
|
|
|
@ -10,7 +10,7 @@ final class ManiphestTaskMergedIntoTransaction
|
||||||
}
|
}
|
||||||
|
|
||||||
public function applyInternalEffects($object, $value) {
|
public function applyInternalEffects($object, $value) {
|
||||||
$object->setStatus(ManiphestTaskStatus::getDuplicateStatus());
|
$this->updateStatus($object, ManiphestTaskStatus::getDuplicateStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getActionName() {
|
public function getActionName() {
|
||||||
|
|
|
@ -10,7 +10,7 @@ final class ManiphestTaskStatusTransaction
|
||||||
}
|
}
|
||||||
|
|
||||||
public function applyInternalEffects($object, $value) {
|
public function applyInternalEffects($object, $value) {
|
||||||
$object->setStatus($value);
|
$this->updateStatus($object, $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function shouldHide() {
|
public function shouldHide() {
|
||||||
|
|
|
@ -3,4 +3,27 @@
|
||||||
abstract class ManiphestTaskTransactionType
|
abstract class ManiphestTaskTransactionType
|
||||||
extends PhabricatorModularTransactionType {
|
extends PhabricatorModularTransactionType {
|
||||||
|
|
||||||
|
protected function updateStatus($object, $new_value) {
|
||||||
|
$old_value = $object->getStatus();
|
||||||
|
$object->setStatus($new_value);
|
||||||
|
|
||||||
|
// If this status change closes or opens the task, update the closed
|
||||||
|
// date and actor PHID.
|
||||||
|
$old_closed = ManiphestTaskStatus::isClosedStatus($old_value);
|
||||||
|
$new_closed = ManiphestTaskStatus::isClosedStatus($new_value);
|
||||||
|
|
||||||
|
$is_close = ($new_closed && !$old_closed);
|
||||||
|
$is_open = (!$new_closed && $old_closed);
|
||||||
|
|
||||||
|
if ($is_close) {
|
||||||
|
$object
|
||||||
|
->setClosedEpoch(PhabricatorTime::getNow())
|
||||||
|
->setCloserPHID($this->getActingAsPHID());
|
||||||
|
} else if ($is_open) {
|
||||||
|
$object
|
||||||
|
->setClosedEpoch(null)
|
||||||
|
->setCloserPHID(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,22 @@
|
||||||
|
|
||||||
abstract class PhabricatorMailImplementationAdapter extends Phobject {
|
abstract class PhabricatorMailImplementationAdapter extends Phobject {
|
||||||
|
|
||||||
|
private $key;
|
||||||
|
private $priority;
|
||||||
|
private $options = array();
|
||||||
|
|
||||||
|
final public function getAdapterType() {
|
||||||
|
return $this->getPhobjectClassConstant('ADAPTERTYPE');
|
||||||
|
}
|
||||||
|
|
||||||
|
final public static function getAllAdapters() {
|
||||||
|
return id(new PhutilClassMapQuery())
|
||||||
|
->setAncestorClass(__CLASS__)
|
||||||
|
->setUniqueMethod('getAdapterType')
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
abstract public function setFrom($email, $name = '');
|
abstract public function setFrom($email, $name = '');
|
||||||
abstract public function addReplyTo($email, $name = '');
|
abstract public function addReplyTo($email, $name = '');
|
||||||
abstract public function addTos(array $emails);
|
abstract public function addTos(array $emails);
|
||||||
|
@ -12,6 +28,7 @@ abstract class PhabricatorMailImplementationAdapter extends Phobject {
|
||||||
abstract public function setHTMLBody($html_body);
|
abstract public function setHTMLBody($html_body);
|
||||||
abstract public function setSubject($subject);
|
abstract public function setSubject($subject);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Some mailers, notably Amazon SES, do not support us setting a specific
|
* Some mailers, notably Amazon SES, do not support us setting a specific
|
||||||
* Message-ID header.
|
* Message-ID header.
|
||||||
|
@ -32,4 +49,59 @@ abstract class PhabricatorMailImplementationAdapter extends Phobject {
|
||||||
*/
|
*/
|
||||||
abstract public function send();
|
abstract public function send();
|
||||||
|
|
||||||
|
final public function setKey($key) {
|
||||||
|
$this->key = $key;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getKey() {
|
||||||
|
return $this->key;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function setPriority($priority) {
|
||||||
|
$this->priority = $priority;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getPriority() {
|
||||||
|
return $this->priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getOption($key) {
|
||||||
|
if (!array_key_exists($key, $this->options)) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Mailer ("%s") is attempting to access unknown option ("%s").',
|
||||||
|
get_class($this),
|
||||||
|
$key));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->options[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function setOptions(array $options) {
|
||||||
|
$this->validateOptions($options);
|
||||||
|
$this->options = $options;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract protected function validateOptions(array $options);
|
||||||
|
|
||||||
|
abstract public function newDefaultOptions();
|
||||||
|
abstract public function newLegacyOptions();
|
||||||
|
|
||||||
|
public function prepareForSend() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function renderAddress($email, $name = null) {
|
||||||
|
if (strlen($name)) {
|
||||||
|
return (string)id(new PhutilEmailAddress())
|
||||||
|
->setDisplayName($name)
|
||||||
|
->setAddress($email);
|
||||||
|
} else {
|
||||||
|
return $email;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,13 @@
|
||||||
final class PhabricatorMailImplementationAmazonSESAdapter
|
final class PhabricatorMailImplementationAmazonSESAdapter
|
||||||
extends PhabricatorMailImplementationPHPMailerLiteAdapter {
|
extends PhabricatorMailImplementationPHPMailerLiteAdapter {
|
||||||
|
|
||||||
|
const ADAPTERTYPE = 'ses';
|
||||||
|
|
||||||
private $message;
|
private $message;
|
||||||
private $isHTML;
|
private $isHTML;
|
||||||
|
|
||||||
public function __construct() {
|
public function prepareForSend() {
|
||||||
parent::__construct();
|
parent::prepareForSend();
|
||||||
$this->mailer->Mailer = 'amazon-ses';
|
$this->mailer->Mailer = 'amazon-ses';
|
||||||
$this->mailer->customMailer = $this;
|
$this->mailer->customMailer = $this;
|
||||||
}
|
}
|
||||||
|
@ -17,13 +19,39 @@ final class PhabricatorMailImplementationAmazonSESAdapter
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function validateOptions(array $options) {
|
||||||
|
PhutilTypeSpec::checkMap(
|
||||||
|
$options,
|
||||||
|
array(
|
||||||
|
'access-key' => 'string',
|
||||||
|
'secret-key' => 'string',
|
||||||
|
'endpoint' => 'string',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newDefaultOptions() {
|
||||||
|
return array(
|
||||||
|
'access-key' => null,
|
||||||
|
'secret-key' => null,
|
||||||
|
'endpoint' => null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newLegacyOptions() {
|
||||||
|
return array(
|
||||||
|
'access-key' => PhabricatorEnv::getEnvConfig('amazon-ses.access-key'),
|
||||||
|
'secret-key' => PhabricatorEnv::getEnvConfig('amazon-ses.secret-key'),
|
||||||
|
'endpoint' => PhabricatorEnv::getEnvConfig('amazon-ses.endpoint'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @phutil-external-symbol class SimpleEmailService
|
* @phutil-external-symbol class SimpleEmailService
|
||||||
*/
|
*/
|
||||||
public function executeSend($body) {
|
public function executeSend($body) {
|
||||||
$key = PhabricatorEnv::getEnvConfig('amazon-ses.access-key');
|
$key = $this->getOption('access-key');
|
||||||
$secret = PhabricatorEnv::getEnvConfig('amazon-ses.secret-key');
|
$secret = $this->getOption('secret-key');
|
||||||
$endpoint = PhabricatorEnv::getEnvConfig('amazon-ses.endpoint');
|
$endpoint = $this->getOption('endpoint');
|
||||||
|
|
||||||
$root = phutil_get_library_root('phabricator');
|
$root = phutil_get_library_root('phabricator');
|
||||||
$root = dirname($root);
|
$root = dirname($root);
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
final class PhabricatorMailImplementationMailgunAdapter
|
final class PhabricatorMailImplementationMailgunAdapter
|
||||||
extends PhabricatorMailImplementationAdapter {
|
extends PhabricatorMailImplementationAdapter {
|
||||||
|
|
||||||
|
const ADAPTERTYPE = 'mailgun';
|
||||||
|
|
||||||
private $params = array();
|
private $params = array();
|
||||||
private $attachments = array();
|
private $attachments = array();
|
||||||
|
|
||||||
|
@ -19,7 +21,7 @@ final class PhabricatorMailImplementationMailgunAdapter
|
||||||
if (empty($this->params['reply-to'])) {
|
if (empty($this->params['reply-to'])) {
|
||||||
$this->params['reply-to'] = array();
|
$this->params['reply-to'] = array();
|
||||||
}
|
}
|
||||||
$this->params['reply-to'][] = "{$name} <{$email}>";
|
$this->params['reply-to'][] = $this->renderAddress($email, $name);
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,9 +73,32 @@ final class PhabricatorMailImplementationMailgunAdapter
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function validateOptions(array $options) {
|
||||||
|
PhutilTypeSpec::checkMap(
|
||||||
|
$options,
|
||||||
|
array(
|
||||||
|
'api-key' => 'string',
|
||||||
|
'domain' => 'string',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newDefaultOptions() {
|
||||||
|
return array(
|
||||||
|
'api-key' => null,
|
||||||
|
'domain' => null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newLegacyOptions() {
|
||||||
|
return array(
|
||||||
|
'api-key' => PhabricatorEnv::getEnvConfig('mailgun.api-key'),
|
||||||
|
'domain' => PhabricatorEnv::getEnvConfig('mailgun.domain'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function send() {
|
public function send() {
|
||||||
$key = PhabricatorEnv::getEnvConfig('mailgun.api-key');
|
$key = $this->getOption('api-key');
|
||||||
$domain = PhabricatorEnv::getEnvConfig('mailgun.domain');
|
$domain = $this->getOption('domain');
|
||||||
$params = array();
|
$params = array();
|
||||||
|
|
||||||
$params['to'] = implode(', ', idx($this->params, 'tos', array()));
|
$params['to'] = implode(', ', idx($this->params, 'tos', array()));
|
||||||
|
@ -85,11 +110,8 @@ final class PhabricatorMailImplementationMailgunAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
$from = idx($this->params, 'from');
|
$from = idx($this->params, 'from');
|
||||||
if (idx($this->params, 'from-name')) {
|
$from_name = idx($this->params, 'from-name');
|
||||||
$params['from'] = "\"{$this->params['from-name']}\" <{$from}>";
|
$params['from'] = $this->renderAddress($from, $from_name);
|
||||||
} else {
|
|
||||||
$params['from'] = $from;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (idx($this->params, 'reply-to')) {
|
if (idx($this->params, 'reply-to')) {
|
||||||
$replyto = $this->params['reply-to'];
|
$replyto = $this->params['reply-to'];
|
||||||
|
|
|
@ -3,40 +3,79 @@
|
||||||
final class PhabricatorMailImplementationPHPMailerAdapter
|
final class PhabricatorMailImplementationPHPMailerAdapter
|
||||||
extends PhabricatorMailImplementationAdapter {
|
extends PhabricatorMailImplementationAdapter {
|
||||||
|
|
||||||
|
const ADAPTERTYPE = 'smtp';
|
||||||
|
|
||||||
private $mailer;
|
private $mailer;
|
||||||
|
|
||||||
|
protected function validateOptions(array $options) {
|
||||||
|
PhutilTypeSpec::checkMap(
|
||||||
|
$options,
|
||||||
|
array(
|
||||||
|
'host' => 'string|null',
|
||||||
|
'port' => 'int',
|
||||||
|
'user' => 'string|null',
|
||||||
|
'password' => 'string|null',
|
||||||
|
'protocol' => 'string|null',
|
||||||
|
'encoding' => 'string',
|
||||||
|
'mailer' => 'string',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newDefaultOptions() {
|
||||||
|
return array(
|
||||||
|
'host' => null,
|
||||||
|
'port' => 25,
|
||||||
|
'user' => null,
|
||||||
|
'password' => null,
|
||||||
|
'protocol' => null,
|
||||||
|
'encoding' => 'base64',
|
||||||
|
'mailer' => 'smtp',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newLegacyOptions() {
|
||||||
|
return array(
|
||||||
|
'host' => PhabricatorEnv::getEnvConfig('phpmailer.smtp-host'),
|
||||||
|
'port' => PhabricatorEnv::getEnvConfig('phpmailer.smtp-port'),
|
||||||
|
'user' => PhabricatorEnv::getEnvConfig('phpmailer.smtp-user'),
|
||||||
|
'password' => PhabricatorEnv::getEnvConfig('phpmailer.smtp-passsword'),
|
||||||
|
'protocol' => PhabricatorEnv::getEnvConfig('phpmailer.smtp-protocol'),
|
||||||
|
'encoding' => PhabricatorEnv::getEnvConfig('phpmailer.smtp-encoding'),
|
||||||
|
'mailer' => PhabricatorEnv::getEnvConfig('phpmailer.mailer'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @phutil-external-symbol class PHPMailer
|
* @phutil-external-symbol class PHPMailer
|
||||||
*/
|
*/
|
||||||
public function __construct() {
|
public function prepareForSend() {
|
||||||
$root = phutil_get_library_root('phabricator');
|
$root = phutil_get_library_root('phabricator');
|
||||||
$root = dirname($root);
|
$root = dirname($root);
|
||||||
require_once $root.'/externals/phpmailer/class.phpmailer.php';
|
require_once $root.'/externals/phpmailer/class.phpmailer.php';
|
||||||
$this->mailer = new PHPMailer($use_exceptions = true);
|
$this->mailer = new PHPMailer($use_exceptions = true);
|
||||||
$this->mailer->CharSet = 'utf-8';
|
$this->mailer->CharSet = 'utf-8';
|
||||||
|
|
||||||
$encoding = PhabricatorEnv::getEnvConfig('phpmailer.smtp-encoding');
|
$encoding = $this->getOption('encoding');
|
||||||
$this->mailer->Encoding = $encoding;
|
$this->mailer->Encoding = $encoding;
|
||||||
|
|
||||||
// By default, PHPMailer sends one mail per recipient. We handle
|
// By default, PHPMailer sends one mail per recipient. We handle
|
||||||
// multiplexing higher in the stack, so tell it to send mail exactly
|
// combining or separating To and Cc higher in the stack, so tell it to
|
||||||
// like we ask.
|
// send mail exactly like we ask.
|
||||||
$this->mailer->SingleTo = false;
|
$this->mailer->SingleTo = false;
|
||||||
|
|
||||||
$mailer = PhabricatorEnv::getEnvConfig('phpmailer.mailer');
|
$mailer = $this->getOption('mailer');
|
||||||
if ($mailer == 'smtp') {
|
if ($mailer == 'smtp') {
|
||||||
$this->mailer->IsSMTP();
|
$this->mailer->IsSMTP();
|
||||||
$this->mailer->Host = PhabricatorEnv::getEnvConfig('phpmailer.smtp-host');
|
$this->mailer->Host = $this->getOption('host');
|
||||||
$this->mailer->Port = PhabricatorEnv::getEnvConfig('phpmailer.smtp-port');
|
$this->mailer->Port = $this->getOption('port');
|
||||||
$user = PhabricatorEnv::getEnvConfig('phpmailer.smtp-user');
|
$user = $this->getOption('user');
|
||||||
if ($user) {
|
if ($user) {
|
||||||
$this->mailer->SMTPAuth = true;
|
$this->mailer->SMTPAuth = true;
|
||||||
$this->mailer->Username = $user;
|
$this->mailer->Username = $user;
|
||||||
$this->mailer->Password =
|
$this->mailer->Password = $this->getOption('password');
|
||||||
PhabricatorEnv::getEnvConfig('phpmailer.smtp-password');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$protocol = PhabricatorEnv::getEnvConfig('phpmailer.smtp-protocol');
|
$protocol = $this->getOption('protocol');
|
||||||
if ($protocol) {
|
if ($protocol) {
|
||||||
$protocol = phutil_utf8_strtolower($protocol);
|
$protocol = phutil_utf8_strtolower($protocol);
|
||||||
$this->mailer->SMTPSecure = $protocol;
|
$this->mailer->SMTPSecure = $protocol;
|
||||||
|
|
|
@ -6,24 +6,46 @@
|
||||||
class PhabricatorMailImplementationPHPMailerLiteAdapter
|
class PhabricatorMailImplementationPHPMailerLiteAdapter
|
||||||
extends PhabricatorMailImplementationAdapter {
|
extends PhabricatorMailImplementationAdapter {
|
||||||
|
|
||||||
|
const ADAPTERTYPE = 'sendmail';
|
||||||
|
|
||||||
protected $mailer;
|
protected $mailer;
|
||||||
|
|
||||||
|
protected function validateOptions(array $options) {
|
||||||
|
PhutilTypeSpec::checkMap(
|
||||||
|
$options,
|
||||||
|
array(
|
||||||
|
'encoding' => 'string',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newDefaultOptions() {
|
||||||
|
return array(
|
||||||
|
'encoding' => 'base64',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newLegacyOptions() {
|
||||||
|
return array(
|
||||||
|
'encoding' => PhabricatorEnv::getEnvConfig('phpmailer.smtp-encoding'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @phutil-external-symbol class PHPMailerLite
|
* @phutil-external-symbol class PHPMailerLite
|
||||||
*/
|
*/
|
||||||
public function __construct() {
|
public function prepareForSend() {
|
||||||
$root = phutil_get_library_root('phabricator');
|
$root = phutil_get_library_root('phabricator');
|
||||||
$root = dirname($root);
|
$root = dirname($root);
|
||||||
require_once $root.'/externals/phpmailer/class.phpmailer-lite.php';
|
require_once $root.'/externals/phpmailer/class.phpmailer-lite.php';
|
||||||
$this->mailer = new PHPMailerLite($use_exceptions = true);
|
$this->mailer = new PHPMailerLite($use_exceptions = true);
|
||||||
$this->mailer->CharSet = 'utf-8';
|
$this->mailer->CharSet = 'utf-8';
|
||||||
|
|
||||||
$encoding = PhabricatorEnv::getEnvConfig('phpmailer.smtp-encoding');
|
$encoding = $this->getOption('encoding');
|
||||||
$this->mailer->Encoding = $encoding;
|
$this->mailer->Encoding = $encoding;
|
||||||
|
|
||||||
// By default, PHPMailerLite sends one mail per recipient. We handle
|
// By default, PHPMailerLite sends one mail per recipient. We handle
|
||||||
// multiplexing higher in the stack, so tell it to send mail exactly
|
// combining or separating To and Cc higher in the stack, so tell it to
|
||||||
// like we ask.
|
// send mail exactly like we ask.
|
||||||
$this->mailer->SingleTo = false;
|
$this->mailer->SingleTo = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorMailImplementationPostmarkAdapter
|
||||||
|
extends PhabricatorMailImplementationAdapter {
|
||||||
|
|
||||||
|
const ADAPTERTYPE = 'postmark';
|
||||||
|
|
||||||
|
private $parameters = array();
|
||||||
|
|
||||||
|
public function setFrom($email, $name = '') {
|
||||||
|
$this->parameters['From'] = $this->renderAddress($email, $name);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addReplyTo($email, $name = '') {
|
||||||
|
$this->parameters['ReplyTo'] = $this->renderAddress($email, $name);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addTos(array $emails) {
|
||||||
|
foreach ($emails as $email) {
|
||||||
|
$this->parameters['To'][] = $email;
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addCCs(array $emails) {
|
||||||
|
foreach ($emails as $email) {
|
||||||
|
$this->parameters['Cc'][] = $email;
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addAttachment($data, $filename, $mimetype) {
|
||||||
|
$this->parameters['Attachments'][] = array(
|
||||||
|
'Name' => $filename,
|
||||||
|
'ContentType' => $mimetype,
|
||||||
|
'Content' => base64_encode($data),
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addHeader($header_name, $header_value) {
|
||||||
|
$this->parameters['Headers'][] = array(
|
||||||
|
'Name' => $header_name,
|
||||||
|
'Value' => $header_value,
|
||||||
|
);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setBody($body) {
|
||||||
|
$this->parameters['TextBody'] = $body;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setHTMLBody($html_body) {
|
||||||
|
$this->parameters['HtmlBody'] = $html_body;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setSubject($subject) {
|
||||||
|
$this->parameters['Subject'] = $subject;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsMessageIDHeader() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function validateOptions(array $options) {
|
||||||
|
PhutilTypeSpec::checkMap(
|
||||||
|
$options,
|
||||||
|
array(
|
||||||
|
'access-token' => 'string',
|
||||||
|
'inbound-addresses' => 'list<string>',
|
||||||
|
));
|
||||||
|
|
||||||
|
// Make sure this is properly formatted.
|
||||||
|
PhutilCIDRList::newList($options['inbound-addresses']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newDefaultOptions() {
|
||||||
|
return array(
|
||||||
|
'access-token' => null,
|
||||||
|
'inbound-addresses' => array(
|
||||||
|
// Via Postmark support circa February 2018, see:
|
||||||
|
//
|
||||||
|
// https://postmarkapp.com/support/article/800-ips-for-firewalls
|
||||||
|
//
|
||||||
|
// "Configuring Outbound Email" should be updated if this changes.
|
||||||
|
'50.31.156.6/32',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newLegacyOptions() {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function send() {
|
||||||
|
$access_token = $this->getOption('access-token');
|
||||||
|
|
||||||
|
$parameters = $this->parameters;
|
||||||
|
$flatten = array(
|
||||||
|
'To',
|
||||||
|
'Cc',
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($flatten as $key) {
|
||||||
|
if (isset($parameters[$key])) {
|
||||||
|
$parameters[$key] = implode(', ', $parameters[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
id(new PhutilPostmarkFuture())
|
||||||
|
->setAccessToken($access_token)
|
||||||
|
->setMethod('email', $parameters)
|
||||||
|
->resolve();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -6,8 +6,33 @@
|
||||||
final class PhabricatorMailImplementationSendGridAdapter
|
final class PhabricatorMailImplementationSendGridAdapter
|
||||||
extends PhabricatorMailImplementationAdapter {
|
extends PhabricatorMailImplementationAdapter {
|
||||||
|
|
||||||
|
const ADAPTERTYPE = 'sendgrid';
|
||||||
|
|
||||||
private $params = array();
|
private $params = array();
|
||||||
|
|
||||||
|
protected function validateOptions(array $options) {
|
||||||
|
PhutilTypeSpec::checkMap(
|
||||||
|
$options,
|
||||||
|
array(
|
||||||
|
'api-user' => 'string',
|
||||||
|
'api-key' => 'string',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newDefaultOptions() {
|
||||||
|
return array(
|
||||||
|
'api-user' => null,
|
||||||
|
'api-key' => null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newLegacyOptions() {
|
||||||
|
return array(
|
||||||
|
'api-user' => PhabricatorEnv::getEnvConfig('sendgrid.api-user'),
|
||||||
|
'api-key' => PhabricatorEnv::getEnvConfig('sendgrid.api-key'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function setFrom($email, $name = '') {
|
public function setFrom($email, $name = '') {
|
||||||
$this->params['from'] = $email;
|
$this->params['from'] = $email;
|
||||||
$this->params['from-name'] = $name;
|
$this->params['from-name'] = $name;
|
||||||
|
@ -73,8 +98,8 @@ final class PhabricatorMailImplementationSendGridAdapter
|
||||||
|
|
||||||
public function send() {
|
public function send() {
|
||||||
|
|
||||||
$user = PhabricatorEnv::getEnvConfig('sendgrid.api-user');
|
$user = $this->getOption('api-user');
|
||||||
$key = PhabricatorEnv::getEnvConfig('sendgrid.api-key');
|
$key = $this->getOption('api-key');
|
||||||
|
|
||||||
if (!$user || !$key) {
|
if (!$user || !$key) {
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
|
|
|
@ -7,10 +7,26 @@
|
||||||
final class PhabricatorMailImplementationTestAdapter
|
final class PhabricatorMailImplementationTestAdapter
|
||||||
extends PhabricatorMailImplementationAdapter {
|
extends PhabricatorMailImplementationAdapter {
|
||||||
|
|
||||||
private $guts = array();
|
const ADAPTERTYPE = 'test';
|
||||||
private $config;
|
|
||||||
|
|
||||||
public function __construct(array $config = array()) {
|
private $guts = array();
|
||||||
|
private $config = array();
|
||||||
|
|
||||||
|
protected function validateOptions(array $options) {
|
||||||
|
PhutilTypeSpec::checkMap(
|
||||||
|
$options,
|
||||||
|
array());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newDefaultOptions() {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newLegacyOptions() {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function prepareForSend(array $config = array()) {
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ final class PhabricatorMetaMTAApplication extends PhabricatorApplication {
|
||||||
'detail/(?P<id>[1-9]\d*)/' => 'PhabricatorMetaMTAMailViewController',
|
'detail/(?P<id>[1-9]\d*)/' => 'PhabricatorMetaMTAMailViewController',
|
||||||
'sendgrid/' => 'PhabricatorMetaMTASendGridReceiveController',
|
'sendgrid/' => 'PhabricatorMetaMTASendGridReceiveController',
|
||||||
'mailgun/' => 'PhabricatorMetaMTAMailgunReceiveController',
|
'mailgun/' => 'PhabricatorMetaMTAMailgunReceiveController',
|
||||||
|
'postmark/' => 'PhabricatorMetaMTAPostmarkReceiveController',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,23 @@ final class PhabricatorMetaMTAMailViewController
|
||||||
$color = PhabricatorMailOutboundStatus::getStatusColor($status);
|
$color = PhabricatorMailOutboundStatus::getStatusColor($status);
|
||||||
$header->setStatus($icon, $color, $name);
|
$header->setStatus($icon, $color, $name);
|
||||||
|
|
||||||
|
if ($mail->getMustEncrypt()) {
|
||||||
|
Javelin::initBehavior('phabricator-tooltips');
|
||||||
|
$header->addTag(
|
||||||
|
id(new PHUITagView())
|
||||||
|
->setType(PHUITagView::TYPE_SHADE)
|
||||||
|
->setColor('blue')
|
||||||
|
->setName(pht('Must Encrypt'))
|
||||||
|
->setIcon('fa-shield blue')
|
||||||
|
->addSigil('has-tooltip')
|
||||||
|
->setMetadata(
|
||||||
|
array(
|
||||||
|
'tip' => pht(
|
||||||
|
'Message content can only be transmitted over secure '.
|
||||||
|
'channels.'),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
$crumbs = $this->buildApplicationCrumbs()
|
$crumbs = $this->buildApplicationCrumbs()
|
||||||
->addTextCrumb(pht('Mail %d', $mail->getID()))
|
->addTextCrumb(pht('Mail %d', $mail->getID()))
|
||||||
->setBorder(true);
|
->setBorder(true);
|
||||||
|
@ -58,8 +75,26 @@ final class PhabricatorMetaMTAMailViewController
|
||||||
->setKey('metadata')
|
->setKey('metadata')
|
||||||
->appendChild($this->buildMetadataProperties($mail)));
|
->appendChild($this->buildMetadataProperties($mail)));
|
||||||
|
|
||||||
|
$header_view = id(new PHUIHeaderView())
|
||||||
|
->setHeader(pht('Mail'));
|
||||||
|
|
||||||
|
$object_phid = $mail->getRelatedPHID();
|
||||||
|
if ($object_phid) {
|
||||||
|
$handles = $viewer->loadHandles(array($object_phid));
|
||||||
|
$handle = $handles[$object_phid];
|
||||||
|
if ($handle->isComplete() && $handle->getURI()) {
|
||||||
|
$view_button = id(new PHUIButtonView())
|
||||||
|
->setTag('a')
|
||||||
|
->setText(pht('View Object'))
|
||||||
|
->setIcon('fa-chevron-right')
|
||||||
|
->setHref($handle->getURI());
|
||||||
|
|
||||||
|
$header_view->addActionLink($view_button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$object_box = id(new PHUIObjectBoxView())
|
$object_box = id(new PHUIObjectBoxView())
|
||||||
->setHeaderText(pht('Mail'))
|
->setHeader($header_view)
|
||||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||||
->addTabGroup($tab_group);
|
->addTabGroup($tab_group);
|
||||||
|
|
||||||
|
@ -134,6 +169,12 @@ final class PhabricatorMetaMTAMailViewController
|
||||||
|
|
||||||
$properties->addTextContent($body);
|
$properties->addTextContent($body);
|
||||||
|
|
||||||
|
$file_phids = $mail->getAttachmentFilePHIDs();
|
||||||
|
if ($file_phids) {
|
||||||
|
$properties->addProperty(
|
||||||
|
pht('Attached Files'),
|
||||||
|
$viewer->loadHandles($file_phids)->renderList());
|
||||||
|
}
|
||||||
|
|
||||||
return $properties;
|
return $properties;
|
||||||
}
|
}
|
||||||
|
@ -158,6 +199,15 @@ final class PhabricatorMetaMTAMailViewController
|
||||||
$properties->addProperty($key, $value);
|
$properties->addProperty($key, $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$encrypt_phids = $mail->getMustEncryptReasons();
|
||||||
|
if ($encrypt_phids) {
|
||||||
|
$properties->addProperty(
|
||||||
|
pht('Must Encrypt'),
|
||||||
|
$viewer->loadHandles($encrypt_phids)
|
||||||
|
->renderList());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return $properties;
|
return $properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue