@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Use keywords instead of ints to update task priority in ManiphestEditEngine

Summary: Fixes T12124. Changes `ManiphestEditEngine` to populate the select using priority keywords instead of the integer value. Marks `maniphest.querystatuses` as frozen. Adds a new Conduit method for fetching potential task statuses.

Test Plan: Created tasks and changed their priorities, observed that transactions in the DB still have the same type (integers as strings). Invoked `maniphest.update` with `priority => '90'` and observed that it still works. Invoked `maniphest.edit` with `priority => 'unbreak'` and observed that it now works.

Reviewers: #blessed_reviewers, epriestley

Reviewed By: #blessed_reviewers, epriestley

Subscribers: Korvin, epriestley

Maniphest Tasks: T12124

Differential Revision: https://secure.phabricator.com/D18111

+198 -48
+4
resources/sql/autopatches/20170614.taskstatus.sql
··· 1 + /* Extend from 12 characters to 64. */ 2 + 3 + ALTER TABLE {$NAMESPACE}_maniphest.maniphest_task 4 + CHANGE status status VARCHAR(64) COLLATE {$COLLATE_TEXT} NOT NULL;
+2
src/__phutil_library_map__.php
··· 1507 1507 'ManiphestSearchConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestSearchConduitAPIMethod.php', 1508 1508 'ManiphestStatusConfigOptionType' => 'applications/maniphest/config/ManiphestStatusConfigOptionType.php', 1509 1509 'ManiphestStatusEmailCommand' => 'applications/maniphest/command/ManiphestStatusEmailCommand.php', 1510 + 'ManiphestStatusSearchConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestStatusSearchConduitAPIMethod.php', 1510 1511 'ManiphestSubpriorityController' => 'applications/maniphest/controller/ManiphestSubpriorityController.php', 1511 1512 'ManiphestSubtypesConfigOptionsType' => 'applications/maniphest/config/ManiphestSubtypesConfigOptionsType.php', 1512 1513 'ManiphestTask' => 'applications/maniphest/storage/ManiphestTask.php', ··· 6607 6608 'ManiphestSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 6608 6609 'ManiphestStatusConfigOptionType' => 'PhabricatorConfigJSONOptionType', 6609 6610 'ManiphestStatusEmailCommand' => 'ManiphestEmailCommand', 6611 + 'ManiphestStatusSearchConduitAPIMethod' => 'ManiphestConduitAPIMethod', 6610 6612 'ManiphestSubpriorityController' => 'ManiphestController', 6611 6613 'ManiphestSubtypesConfigOptionsType' => 'PhabricatorConfigJSONOptionType', 6612 6614 'ManiphestTask' => array(
+8 -2
src/applications/maniphest/__tests__/ManiphestTaskTestCase.php
··· 194 194 $dst, 195 195 $is_after); 196 196 197 + $keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap(); 198 + $keyword = head($keyword_map[$pri]); 199 + 197 200 $xactions = array(); 198 201 199 202 $xactions[] = id(new ManiphestTransaction()) 200 203 ->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE) 201 - ->setNewValue($pri); 204 + ->setNewValue($keyword); 202 205 203 206 $xactions[] = id(new ManiphestTransaction()) 204 207 ->setTransactionType(ManiphestTaskSubpriorityTransaction::TRANSACTIONTYPE) ··· 217 220 $target_priority, 218 221 $is_end); 219 222 223 + $keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap(); 224 + $keyword = head($keyword_map[$pri]); 225 + 220 226 $xactions = array(); 221 227 222 228 $xactions[] = id(new ManiphestTransaction()) 223 229 ->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE) 224 - ->setNewValue($pri); 230 + ->setNewValue($keyword); 225 231 226 232 $xactions[] = id(new ManiphestTransaction()) 227 233 ->setTransactionType(ManiphestTaskSubpriorityTransaction::TRANSACTIONTYPE)
+5
src/applications/maniphest/bulk/ManiphestTaskEditBulkJobType.php
··· 285 285 '=' => array_fuse($value), 286 286 )); 287 287 break; 288 + case ManiphestTaskPriorityTransaction::TRANSACTIONTYPE: 289 + $keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap(); 290 + $keyword = head(idx($keyword_map, $value)); 291 + $xaction->setNewValue($keyword); 292 + break; 288 293 default: 289 294 $xaction->setNewValue($value); 290 295 break;
+3 -13
src/applications/maniphest/command/ManiphestPriorityEmailCommand.php
··· 49 49 array $argv) { 50 50 $xactions = array(); 51 51 52 - $target = phutil_utf8_strtolower(head($argv)); 53 - $priority = null; 54 - 55 - $keywords = ManiphestTaskPriority::getTaskPriorityKeywordsMap(); 56 - foreach ($keywords as $key => $words) { 57 - foreach ($words as $word) { 58 - if ($word == $target) { 59 - $priority = $key; 60 - break; 61 - } 62 - } 63 - } 52 + $keyword = phutil_utf8_strtolower(head($argv)); 53 + $priority = ManiphestTaskPriority::getTaskPriorityFromKeyword($keyword); 64 54 65 55 if ($priority === null) { 66 56 return array(); ··· 72 62 73 63 $xactions[] = $object->getApplicationTransactionTemplate() 74 64 ->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE) 75 - ->setNewValue($priority); 65 + ->setNewValue($keyword); 76 66 77 67 return $xactions; 78 68 }
+3 -1
src/applications/maniphest/conduit/ManiphestConduitAPIMethod.php
··· 99 99 throw id(new ConduitException('ERR-INVALID-PARAMETER')) 100 100 ->setErrorDescription(pht('Priority set to invalid value.')); 101 101 } 102 - $changes[ManiphestTaskPriorityTransaction::TRANSACTIONTYPE] = $priority; 102 + $keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap(); 103 + $keyword = head(idx($keyword_map, $priority)); 104 + $changes[ManiphestTaskPriorityTransaction::TRANSACTIONTYPE] = $keyword; 103 105 } 104 106 105 107 $owner_phid = $request->getValue('ownerPHID');
+10
src/applications/maniphest/conduit/ManiphestQueryStatusesConduitAPIMethod.php
··· 33 33 return $results; 34 34 } 35 35 36 + public function getMethodStatus() { 37 + return self::METHOD_STATUS_FROZEN; 38 + } 39 + 40 + public function getMethodStatusDescription() { 41 + return pht( 42 + 'This method is frozen and will eventually be deprecated. New code '. 43 + 'should use "maniphest.status.search" instead.'); 44 + } 45 + 36 46 }
+52
src/applications/maniphest/conduit/ManiphestStatusSearchConduitAPIMethod.php
··· 1 + <?php 2 + 3 + final class ManiphestStatusSearchConduitAPIMethod 4 + extends ManiphestConduitAPIMethod { 5 + 6 + public function getAPIMethodName() { 7 + return 'maniphest.status.search'; 8 + } 9 + 10 + public function getMethodSummary() { 11 + return pht('Read information about task statuses.'); 12 + } 13 + 14 + public function getMethodDescription() { 15 + return pht( 16 + 'Returns information about the possible statuses for Maniphest '. 17 + 'tasks.'); 18 + } 19 + 20 + protected function defineParamTypes() { 21 + return array(); 22 + } 23 + 24 + protected function defineReturnType() { 25 + return 'map<string, wild>'; 26 + } 27 + 28 + public function getRequiredScope() { 29 + return self::SCOPE_ALWAYS; 30 + } 31 + 32 + protected function execute(ConduitAPIRequest $request) { 33 + $config = PhabricatorEnv::getEnvConfig('maniphest.statuses'); 34 + $results = array(); 35 + foreach ($config as $code => $status) { 36 + $stripped_status = array( 37 + 'name' => $status['name'], 38 + 'value' => $code, 39 + 'closed' => !empty($status['closed']), 40 + ); 41 + 42 + if (isset($status['special'])) { 43 + $stripped_status['special'] = $status['special']; 44 + } 45 + 46 + $results[] = $stripped_status; 47 + } 48 + 49 + return array('data' => $results); 50 + } 51 + 52 + }
+42 -1
src/applications/maniphest/constants/ManiphestTaskPriority.php
··· 2 2 3 3 final class ManiphestTaskPriority extends ManiphestConstants { 4 4 5 + const UNKNOWN_PRIORITY_KEYWORD = '!!unknown!!'; 6 + 5 7 /** 6 8 * Get the priorities and their full descriptions. 7 9 * ··· 105 107 return 'fa-arrow-right'; 106 108 } 107 109 110 + public static function getTaskPriorityFromKeyword($keyword) { 111 + $map = self::getTaskPriorityKeywordsMap(); 112 + 113 + foreach ($map as $priority => $keywords) { 114 + if (in_array($keyword, $keywords)) { 115 + return $priority; 116 + } 117 + } 118 + 119 + return null; 120 + } 121 + 108 122 public static function isDisabledPriority($priority) { 109 123 $config = idx(self::getConfig(), $priority, array()); 110 124 return idx($config, 'disabled', false); ··· 116 130 return $config; 117 131 } 118 132 133 + private static function isValidPriorityKeyword($keyword) { 134 + if (!strlen($keyword) || strlen($keyword) > 64) { 135 + return false; 136 + } 137 + 138 + // Alphanumeric, but not exclusively numeric 139 + if (!preg_match('/^(?![0-9]*$)[a-zA-Z0-9]+$/', $keyword)) { 140 + return false; 141 + } 142 + return true; 143 + } 144 + 119 145 public static function validateConfiguration($config) { 120 146 if (!is_array($config)) { 121 147 throw new Exception( ··· 147 173 'name' => 'string', 148 174 'short' => 'optional string', 149 175 'color' => 'optional string', 150 - 'keywords' => 'optional list<string>', 176 + 'keywords' => 'list<string>', 151 177 'disabled' => 'optional bool', 152 178 )); 179 + 180 + $keywords = $value['keywords']; 181 + foreach ($keywords as $keyword) { 182 + if (!self::isValidPriorityKeyword($keyword)) { 183 + throw new Exception( 184 + pht( 185 + 'Key "%s" is not a valid priority keyword. Priority keywords '. 186 + 'must be 1-64 alphanumeric characters and cannot be '. 187 + 'exclusively digits. For example, "%s" or "%s" are '. 188 + 'reasonable choices.', 189 + $keyword, 190 + 'low', 191 + 'critical')); 192 + } 193 + } 153 194 } 154 195 } 155 196
+7 -7
src/applications/maniphest/constants/ManiphestTaskStatus.php
··· 232 232 * @task validate 233 233 */ 234 234 public static function isValidStatusConstant($constant) { 235 - if (strlen($constant) > 12) { 235 + if (!strlen($constant) || strlen($constant) > 64) { 236 236 return false; 237 237 } 238 - if (!preg_match('/^[a-z0-9]+\z/', $constant)) { 238 + 239 + // Alphanumeric, but not exclusively numeric 240 + if (!preg_match('/^(?![0-9]*$)[a-zA-Z0-9]+$/', $constant)) { 239 241 return false; 240 242 } 241 243 return true; 242 244 } 243 - 244 245 245 246 /** 246 247 * @task validate ··· 250 251 if (!self::isValidStatusConstant($key)) { 251 252 throw new Exception( 252 253 pht( 253 - 'Key "%s" is not a valid status constant. Status constants must '. 254 - 'be 1-12 characters long and contain only lowercase letters (a-z) '. 255 - 'and digits (0-9). For example, "%s" or "%s" are reasonable '. 256 - 'choices.', 254 + 'Key "%s" is not a valid status constant. Status constants '. 255 + 'must be 1-64 alphanumeric characters and cannot be exclusively '. 256 + 'digits. For example, "%s" or "%s" are reasonable choices.', 257 257 $key, 258 258 'open', 259 259 'closed'));
+7 -2
src/applications/maniphest/constants/__tests__/ManiphestTaskStatusTestCase.php
··· 10 10 'duplicate2' => true, 11 11 12 12 '' => false, 13 - 'longlonglonglong' => false, 13 + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' => 14 + false, 14 15 '.' => false, 15 - 'ABCD' => false, 16 + ' ' => false, 17 + 'ABCD' => true, 16 18 'a b c ' => false, 19 + '1' => false, 20 + '111' => false, 21 + '11a' => true, 17 22 ); 18 23 19 24 foreach ($map as $input => $expect) {
+4 -1
src/applications/maniphest/controller/ManiphestSubpriorityController.php
··· 40 40 $is_end = false); 41 41 } 42 42 43 + $keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap(); 44 + $keyword = head(idx($keyword_map, $pri)); 45 + 43 46 $xactions = array(); 44 47 45 48 $xactions[] = id(new ManiphestTransaction()) 46 49 ->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE) 47 - ->setNewValue($pri); 50 + ->setNewValue($keyword); 48 51 49 52 $xactions[] = id(new ManiphestTransaction()) 50 53 ->setTransactionType(ManiphestTaskSubpriorityTransaction::TRANSACTIONTYPE)
+16 -16
src/applications/maniphest/editor/ManiphestEditEngine.php
··· 215 215 ->setConduitTypeDescription(pht('New task priority constant.')) 216 216 ->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE) 217 217 ->setIsCopyable(true) 218 - ->setValue($object->getPriority()) 218 + ->setValue($object->getPriorityKeyword()) 219 219 ->setOptions($priority_map) 220 220 ->setCommentActionLabel(pht('Change Priority')), 221 221 ); ··· 289 289 290 290 private function getTaskPriorityMap(ManiphestTask $task) { 291 291 $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); 292 + $priority_keywords = ManiphestTaskPriority::getTaskPriorityKeywordsMap(); 292 293 $current_priority = $task->getPriority(); 293 - 294 - // If the current value isn't a legitimate one, put it in the dropdown 295 - // anyway so saving the form doesn't cause a side effects. 296 - if (idx($priority_map, $current_priority) === null) { 297 - $priority_map[$current_priority] = pht( 298 - '<Unknown: %s>', 299 - $current_priority); 300 - } 294 + $results = array(); 301 295 302 296 foreach ($priority_map as $priority => $priority_name) { 303 - // Always keep the current priority. 304 - if ($priority == $current_priority) { 297 + $disabled = ManiphestTaskPriority::isDisabledPriority($priority); 298 + if ($disabled && !($priority == $current_priority)) { 305 299 continue; 306 300 } 307 301 308 - if (ManiphestTaskPriority::isDisabledPriority($priority)) { 309 - unset($priority_map[$priority]); 310 - continue; 311 - } 302 + $keyword = head(idx($priority_keywords, $priority)); 303 + $results[$keyword] = $priority_name; 304 + } 305 + 306 + // If the current value isn't a legitimate one, put it in the dropdown 307 + // anyway so saving the form doesn't cause any side effects. 308 + if (idx($priority_map, $current_priority) === null) { 309 + $results[ManiphestTaskPriority::UNKNOWN_PRIORITY_KEYWORD] = pht( 310 + '<Unknown: %s>', 311 + $current_priority); 312 312 } 313 313 314 - return $priority_map; 314 + return $results; 315 315 } 316 316 317 317 protected function newEditResponse(
+5 -2
src/applications/maniphest/herald/ManiphestTaskPriorityHeraldAction.php
··· 39 39 return; 40 40 } 41 41 42 + $keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap(); 43 + $keyword = head(idx($keyword_map, $priority)); 44 + 42 45 $xaction = $adapter->newTransaction() 43 46 ->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE) 44 - ->setNewValue($priority); 47 + ->setNewValue($keyword); 45 48 46 49 $adapter->queueTransaction($xaction); 47 - $this->logEffect(self::DO_PRIORITY, $priority); 50 + $this->logEffect(self::DO_PRIORITY, $keyword); 48 51 } 49 52 50 53 public function getHeraldActionStandardType() {
+4 -1
src/applications/maniphest/lipsum/PhabricatorManiphestTaskTestDataGenerator.php
··· 100 100 } 101 101 102 102 public function generateTaskPriority() { 103 - return array_rand(ManiphestTaskPriority::getTaskPriorityMap()); 103 + $pri = array_rand(ManiphestTaskPriority::getTaskPriorityMap()); 104 + $keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap(); 105 + $keyword = head(idx($keyword_map, $pri)); 106 + return $keyword; 104 107 } 105 108 106 109 public function generateTaskSubPriority() {
+9 -1
src/applications/maniphest/storage/ManiphestTask.php
··· 79 79 ), 80 80 self::CONFIG_COLUMN_SCHEMA => array( 81 81 'ownerPHID' => 'phid?', 82 - 'status' => 'text12', 82 + 'status' => 'text64', 83 83 'priority' => 'uint32', 84 84 'title' => 'sort', 85 85 'originalTitle' => 'text', ··· 243 243 (int)-$this->getID(), 244 244 ), 245 245 ); 246 + } 247 + 248 + public function getPriorityKeyword() { 249 + $priority = $this->getPriority(); 250 + $map = ManiphestTaskPriority::getTaskPriorityKeywordsMap(); 251 + $default = array(ManiphestTaskPriority::UNKNOWN_PRIORITY_KEYWORD); 252 + $keywords = idx($map, $priority, $default); 253 + return head($keywords); 246 254 } 247 255 248 256 private function comparePriorityTo(ManiphestTask $other) {
+13
src/applications/maniphest/xaction/ManiphestTaskPriorityTransaction.php
··· 12 12 return $object->getPriority(); 13 13 } 14 14 15 + public function generateNewValue($object, $value) { 16 + // `$value` is supposed to be a keyword, but if the priority 17 + // assigned to a task has been removed from the config, 18 + // no such keyword will be available. Other edits to the task 19 + // should still be allowed, even if the priority is no longer 20 + // valid, so treat this as a no-op. 21 + if ($value === ManiphestTaskPriority::UNKNOWN_PRIORITY_KEYWORD) { 22 + return $object->getPriority(); 23 + } 24 + 25 + return (string)ManiphestTaskPriority::getTaskPriorityFromKeyword($value); 26 + } 27 + 15 28 public function applyInternalEffects($object, $value) { 16 29 $object->setPriority($value); 17 30 }
+4 -1
src/applications/project/controller/PhabricatorProjectMoveController.php
··· 153 153 break; 154 154 } 155 155 156 + $keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap(); 157 + $keyword = head(idx($keyword_map, $pri)); 158 + 156 159 $xactions = array(); 157 160 if ($pri !== null) { 158 161 $xactions[] = id(new ManiphestTransaction()) 159 162 ->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE) 160 - ->setNewValue($pri); 163 + ->setNewValue($keyword); 161 164 $xactions[] = id(new ManiphestTransaction()) 162 165 ->setTransactionType( 163 166 ManiphestTaskSubpriorityTransaction::TRANSACTIONTYPE)