From 52eab8760870e7c24828f753721bf5796504ed2c Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 1 Apr 2015 10:09:47 -0700 Subject: [PATCH] Implement the "!priority" and "!status" mail commands Summary: Ref T7199. Adds "!priority" and "!status". Test Plan: - Used `!priority` and `!status` to adjust tasks. - Changed config and provided keywords. {F355976} Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T7199 Differential Revision: https://secure.phabricator.com/D12248 --- src/__phutil_library_map__.php | 4 + .../command/ManiphestPriorityEmailCommand.php | 73 +++++++++++++++++++ .../command/ManiphestStatusEmailCommand.php | 72 ++++++++++++++++++ .../PhabricatorManiphestConfigOptions.php | 13 ++++ .../constants/ManiphestTaskPriority.php | 26 +++++++ .../constants/ManiphestTaskStatus.php | 32 ++++++++ 6 files changed, 220 insertions(+) create mode 100644 src/applications/maniphest/command/ManiphestPriorityEmailCommand.php create mode 100644 src/applications/maniphest/command/ManiphestStatusEmailCommand.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 4a3f7ef95d..9256c9f196 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1034,6 +1034,7 @@ phutil_register_library_map(array( 'ManiphestInfoConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestInfoConduitAPIMethod.php', 'ManiphestNameIndex' => 'applications/maniphest/storage/ManiphestNameIndex.php', 'ManiphestNameIndexEventListener' => 'applications/maniphest/event/ManiphestNameIndexEventListener.php', + 'ManiphestPriorityEmailCommand' => 'applications/maniphest/command/ManiphestPriorityEmailCommand.php', 'ManiphestQueryConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestQueryConduitAPIMethod.php', 'ManiphestQueryStatusesConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestQueryStatusesConduitAPIMethod.php', 'ManiphestRemarkupRule' => 'applications/maniphest/remarkup/ManiphestRemarkupRule.php', @@ -1042,6 +1043,7 @@ phutil_register_library_map(array( 'ManiphestSchemaSpec' => 'applications/maniphest/storage/ManiphestSchemaSpec.php', 'ManiphestSearchIndexer' => 'applications/maniphest/search/ManiphestSearchIndexer.php', 'ManiphestStatusConfigOptionType' => 'applications/maniphest/config/ManiphestStatusConfigOptionType.php', + 'ManiphestStatusEmailCommand' => 'applications/maniphest/command/ManiphestStatusEmailCommand.php', 'ManiphestSubpriorityController' => 'applications/maniphest/controller/ManiphestSubpriorityController.php', 'ManiphestTask' => 'applications/maniphest/storage/ManiphestTask.php', 'ManiphestTaskDependedOnByTaskEdgeType' => 'applications/maniphest/edge/ManiphestTaskDependedOnByTaskEdgeType.php', @@ -4284,6 +4286,7 @@ phutil_register_library_map(array( 'ManiphestInfoConduitAPIMethod' => 'ManiphestConduitAPIMethod', 'ManiphestNameIndex' => 'ManiphestDAO', 'ManiphestNameIndexEventListener' => 'PhabricatorEventListener', + 'ManiphestPriorityEmailCommand' => 'ManiphestEmailCommand', 'ManiphestQueryConduitAPIMethod' => 'ManiphestConduitAPIMethod', 'ManiphestQueryStatusesConduitAPIMethod' => 'ManiphestConduitAPIMethod', 'ManiphestRemarkupRule' => 'PhabricatorObjectRemarkupRule', @@ -4292,6 +4295,7 @@ phutil_register_library_map(array( 'ManiphestSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'ManiphestSearchIndexer' => 'PhabricatorSearchDocumentIndexer', 'ManiphestStatusConfigOptionType' => 'PhabricatorConfigJSONOptionType', + 'ManiphestStatusEmailCommand' => 'ManiphestEmailCommand', 'ManiphestSubpriorityController' => 'ManiphestController', 'ManiphestTask' => array( 'ManiphestDAO', diff --git a/src/applications/maniphest/command/ManiphestPriorityEmailCommand.php b/src/applications/maniphest/command/ManiphestPriorityEmailCommand.php new file mode 100644 index 0000000000..04fdc7399f --- /dev/null +++ b/src/applications/maniphest/command/ManiphestPriorityEmailCommand.php @@ -0,0 +1,73 @@ + $words) { + $words = implode(', ', $words); + $table[] = '| '.$names[$priority].' | '.$words; + } + $table = implode("\n", $table); + + return pht( + 'To change the priority of a task, specify the desired priority, like '. + '`!priority high`. This table shows the configured names for priority '. + 'levels.'. + "\n\n%s\n\n". + 'If you specify an invalid priority, the command is ignored. This '. + 'command has no effect if you do not specify a priority.', + $table); + } + + public function buildTransactions( + PhabricatorUser $viewer, + PhabricatorApplicationTransactionInterface $object, + PhabricatorMetaMTAReceivedMail $mail, + $command, + array $argv) { + $xactions = array(); + + $target = phutil_utf8_strtolower(head($argv)); + $priority = null; + + $keywords = ManiphestTaskPriority::getTaskPriorityKeywordsMap(); + foreach ($keywords as $key => $words) { + foreach ($words as $word) { + if ($word == $target) { + $priority = $key; + break; + } + } + } + + if ($priority === null) { + return array(); + } + + $xactions[] = $object->getApplicationTransactionTemplate() + ->setTransactionType(ManiphestTransaction::TYPE_PRIORITY) + ->setNewValue($priority); + + return $xactions; + } + +} diff --git a/src/applications/maniphest/command/ManiphestStatusEmailCommand.php b/src/applications/maniphest/command/ManiphestStatusEmailCommand.php new file mode 100644 index 0000000000..0e2ebbba76 --- /dev/null +++ b/src/applications/maniphest/command/ManiphestStatusEmailCommand.php @@ -0,0 +1,72 @@ + $words) { + $words = implode(', ', $words); + $table[] = '| '.$names[$status].' | '.$words; + } + $table = implode("\n", $table); + + return pht( + 'To change the status of a task, specify the desired status, like '. + '`!status invalid`. This table shows the configured names for statuses.'. + "\n\n%s\n\n". + 'If you specify an invalid status, the command is ignored. This '. + 'command has no effect if you do not specify a status.', + $table); + } + + public function buildTransactions( + PhabricatorUser $viewer, + PhabricatorApplicationTransactionInterface $object, + PhabricatorMetaMTAReceivedMail $mail, + $command, + array $argv) { + $xactions = array(); + + $target = phutil_utf8_strtolower(head($argv)); + $status = null; + + $keywords = ManiphestTaskStatus::getTaskStatusKeywordsMap(); + foreach ($keywords as $key => $words) { + foreach ($words as $word) { + if ($word == $target) { + $status = $key; + break; + } + } + } + + if ($status === null) { + return array(); + } + + $xactions[] = $object->getApplicationTransactionTemplate() + ->setTransactionType(ManiphestTransaction::TYPE_STATUS) + ->setNewValue($status); + + return $xactions; + } + +} diff --git a/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php b/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php index 9f7245e515..18ddf47c6c 100644 --- a/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php +++ b/src/applications/maniphest/config/PhabricatorManiphestConfigOptions.php @@ -26,31 +26,37 @@ final class PhabricatorManiphestConfigOptions 'name' => pht('Unbreak Now!'), 'short' => pht('Unbreak!'), 'color' => 'indigo', + 'keywords' => array('unbreak'), ), 90 => array( 'name' => pht('Needs Triage'), 'short' => pht('Triage'), 'color' => 'violet', + 'keywords' => array('triage'), ), 80 => array( 'name' => pht('High'), 'short' => pht('High'), 'color' => 'red', + 'keywords' => array('high'), ), 50 => array( 'name' => pht('Normal'), 'short' => pht('Normal'), 'color' => 'orange', + 'keywords' => array('normal'), ), 25 => array( 'name' => pht('Low'), 'short' => pht('Low'), 'color' => 'yellow', + 'keywords' => array('low'), ), 0 => array( 'name' => pht('Wishlist'), 'short' => pht('Wish'), 'color' => 'sky', + 'keywords' => array('wish', 'wishlist'), ), ); @@ -80,6 +86,7 @@ final class PhabricatorManiphestConfigOptions 'as resolved', 'as fixed', ), + 'keywords' => array('closed', 'fixed', 'resolved'), ), 'wontfix' => array( 'name' => pht('Wontfix'), @@ -182,6 +189,9 @@ The keys you can provide in a specification are: providing "as invalid" here will allow users to move tasks to this status by writing `Closes T123 as invalid`, even if another status is selected by the "Closes" prefix. + - `keywords` //Optional list.// Allows you to specify a list + of keywords which can be used with `!status` commands in email to select + this status. Statuses will appear in the UI in the order specified. Note the status marked `special` as `duplicate` is not settable directly and will not appear in UI @@ -257,6 +267,9 @@ EOTEXT ' - `short` Alternate shorter name, used in UIs where there is '. ' not much space available.'."\n". ' - `color` A color for this priority, like "red" or "blue".'. + ' - `keywords` An optional list of keywords which can '. + ' be used to select this priority when using `!priority` '. + ' commands in email.'. "\n\n". 'You can choose which priority is the default for newly created '. 'tasks with `maniphest.default-priority`.')), diff --git a/src/applications/maniphest/constants/ManiphestTaskPriority.php b/src/applications/maniphest/constants/ManiphestTaskPriority.php index ec2663f6ee..4ec7643683 100644 --- a/src/applications/maniphest/constants/ManiphestTaskPriority.php +++ b/src/applications/maniphest/constants/ManiphestTaskPriority.php @@ -16,6 +16,32 @@ final class ManiphestTaskPriority extends ManiphestConstants { } + /** + * Get the priorities and their command keywords. + * + * @return map Priorities to lists of command keywords. + */ + public static function getTaskPriorityKeywordsMap() { + $map = self::getConfig(); + foreach ($map as $key => $spec) { + $words = idx($spec, 'keywords', array()); + if (!is_array($words)) { + $words = array($words); + } + + foreach ($words as $word_key => $word) { + $words[$word_key] = phutil_utf8_strtolower($word); + } + + $words = array_unique($words); + + $map[$key] = $words; + } + + return $map; + } + + /** * Get the priorities and their related short (one-word) descriptions. * diff --git a/src/applications/maniphest/constants/ManiphestTaskStatus.php b/src/applications/maniphest/constants/ManiphestTaskStatus.php index d3a75050ac..abbb1b1d18 100644 --- a/src/applications/maniphest/constants/ManiphestTaskStatus.php +++ b/src/applications/maniphest/constants/ManiphestTaskStatus.php @@ -38,6 +38,37 @@ final class ManiphestTaskStatus extends ManiphestConstants { return ipull(self::getEnabledStatusMap(), 'name'); } + + /** + * Get the statuses and their command keywords. + * + * @return map Statuses to lists of command keywords. + */ + public static function getTaskStatusKeywordsMap() { + $map = self::getEnabledStatusMap(); + foreach ($map as $key => $spec) { + $words = idx($spec, 'keywords', array()); + if (!is_array($words)) { + $words = array($words); + } + + // For statuses, we include the status name because it's usually + // at least somewhat meaningful. + $words[] = $key; + + foreach ($words as $word_key => $word) { + $words[$word_key] = phutil_utf8_strtolower($word); + } + + $words = array_unique($words); + + $map[$key] = $words; + } + + return $map; + } + + public static function getTaskStatusName($status) { return self::getStatusAttribute($status, 'name', pht('Unknown Status')); } @@ -231,6 +262,7 @@ final class ManiphestTaskStatus extends ManiphestConstants { 'silly' => 'optional bool', 'prefixes' => 'optional list', 'suffixes' => 'optional list', + 'keywords' => 'optional list', )); }