1
0
Fork 0
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:
epriestley 2018-02-09 17:16:18 -08:00
commit 88faa980c6
178 changed files with 6904 additions and 791 deletions

1
bin/conduit Symbolic link
View file

@ -0,0 +1 @@
../scripts/setup/manage_conduit.php

1
bin/webhook Symbolic link
View file

@ -0,0 +1 @@
../scripts/setup/manage_webhook.php

View file

@ -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',

View file

@ -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"
} }

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_maniphest.maniphest_task
DROP originalTitle;

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_differential.differential_revision
DROP originalTitle;

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_pholio.pholio_mock
DROP originalName;

View file

@ -0,0 +1,5 @@
ALTER TABLE {$NAMESPACE}_maniphest.maniphest_task
ADD closedEpoch INT UNSIGNED;
ALTER TABLE {$NAMESPACE}_maniphest.maniphest_task
ADD closerPHID VARBINARY(64);

View 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;
}
}

View 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};

View 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};

View 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};

View 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);

View 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);

View file

@ -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',

View file

@ -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'),

View file

@ -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'),

View file

@ -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());
}
} }

View file

@ -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

View file

@ -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) {

View file

@ -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(

View file

@ -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;
}
}

View file

@ -0,0 +1,4 @@
<?php
abstract class PhabricatorConduitManagementWorkflow
extends PhabricatorManagementWorkflow {}

View file

@ -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) {

View file

@ -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,8 +37,20 @@ 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 ($is_stdin) {
if (count($argv) > 1) {
throw new PhutilArgumentUsageException(
pht(
'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) { if (count($argv) == 1) {
throw new PhutilArgumentUsageException( throw new PhutilArgumentUsageException(
pht( pht(
@ -40,14 +58,16 @@ final class PhabricatorConfigManagementSetWorkflow
$key)); $key));
} }
$value = $argv[1];
if (count($argv) > 2) { if (count($argv) > 2) {
throw new PhutilArgumentUsageException( throw new PhutilArgumentUsageException(
pht( pht(
'Too many arguments: expected one key and one value.')); 'Too many arguments: expected one key and one value.'));
} }
$value = $argv[1];
}
$options = PhabricatorApplicationConfigOptions::loadAllOptions(); $options = PhabricatorApplicationConfigOptions::loadAllOptions();
if (empty($options[$key])) { if (empty($options[$key])) {
throw new PhutilArgumentUsageException( throw new PhutilArgumentUsageException(

View file

@ -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',

View file

@ -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) {

View file

@ -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(

View file

@ -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());
}
} }

View file

@ -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());
}
}

View file

@ -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 )----------------------------------------- */

View file

@ -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;

View file

@ -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;

View file

@ -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,

View file

@ -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();

View file

@ -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',

View file

@ -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');

View file

@ -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;

View file

@ -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(

View file

@ -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(

View 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();
}
}

View file

@ -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;
}
} }

View file

@ -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,
),
); );
} }

View file

@ -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.');
}
}

View file

@ -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();
@ -32,6 +20,9 @@ abstract class HeraldController extends PhabricatorController {
->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);
return $nav; return $nav;

View file

@ -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;
}
} }

View file

@ -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())

View file

@ -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;
}
}

View file

@ -0,0 +1,12 @@
<?php
final class HeraldWebhookEditController
extends HeraldWebhookController {
public function handleRequest(AphrontRequest $request) {
return id(new HeraldWebhookEditEngine())
->setController($this)
->buildResponse();
}
}

View file

@ -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'));
}
}

View file

@ -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;
}
}

View file

@ -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'));
}
}

View file

@ -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);
}
}

View 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()),
);
}
}

View 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;
}
}

View 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;
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -0,0 +1,4 @@
<?php
abstract class HeraldWebhookManagementWorkflow
extends PhabricatorManagementWorkflow {}

View 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);
}
}
}
}

View file

@ -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()));
}
}
}

View 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';
}
}

View 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';
}
}

View 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.'));
}
}

View file

@ -0,0 +1,10 @@
<?php
final class HeraldWebhookTransactionQuery
extends PhabricatorApplicationTransactionQuery {
public function getTemplateApplicationTransaction() {
return new HeraldWebhookTransaction();
}
}

View 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();
}
}

View 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),
);
}
}

View 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';
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View 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();
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -0,0 +1,4 @@
<?php
abstract class HeraldWebhookTransactionType
extends PhabricatorModularTransactionType {}

View file

@ -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;
}
}

View file

@ -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) {

View file

@ -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();

View file

@ -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) {

View file

@ -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);
} }

View file

@ -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)) {
// This says "emoji", but the actual rule we implement is "all other
// unicode characters are also fine".
$errors[] = $this->newInvalidError( $errors[] = $this->newInvalidError(
pht('Macro name "%s" be at least three characters long and contain '. pht(
'only lowercase letters, digits, hyphens, colons and '. 'Macro name "%s" be: at least three characters long; and contain '.
'underscores.', 'only lowercase letters, digits, hyphens, colons, underscores, '.
$new_value)); '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;
}
} }

View file

@ -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));
}
}
}

View file

@ -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,

View file

@ -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());
}
}

View file

@ -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,
@ -723,6 +758,10 @@ final class ManiphestTaskQuery extends PhabricatorCursorPagedPolicyAwareQuery {
'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) {

View file

@ -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,
); );
} }

View file

@ -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,
); );
} }

View file

@ -86,9 +86,24 @@ final class ManiphestTaskListView extends ManiphestView {
$item->setStatusIcon($icon.' '.$color, $tooltip); $item->setStatusIcon($icon.' '.$color, $tooltip);
if ($task->isClosed()) {
$closed_epoch = $task->getClosedEpoch();
// 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( $item->addIcon(
'none', 'none',
phabricator_datetime($task->getDateModified(), $this->getUser())); phabricator_datetime($task->getDateModified(), $this->getUser()));
}
if ($this->showSubpriorityControls) { if ($this->showSubpriorityControls) {
$item->setGrippable(true); $item->setGrippable(true);

View file

@ -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() {

View file

@ -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() {

View file

@ -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);
}
}
} }

View file

@ -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;
}
}
} }

View file

@ -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);

View file

@ -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'];

View file

@ -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;

View file

@ -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;
} }

View file

@ -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;
}
}

View file

@ -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(

View file

@ -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;
} }

View file

@ -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',
), ),
); );
} }

View file

@ -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