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

Modularize "add projects" and "remove projects" Herald actions

Summary: Ref T8726. Convert these to be modular.

Test Plan:
- Created rules using these actions.
- Upgraded them.
- Verified they still work.

{F659266}

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: joshuaspence, epriestley

Maniphest Tasks: T8726

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

+273 -58
+11
resources/sql/autopatches/20150724.herald.3.sql
··· 1 + UPDATE {$NAMESPACE}_herald.herald_actionrecord a 2 + JOIN {$NAMESPACE}_herald.herald_rule r 3 + ON a.ruleID = r.id 4 + SET a.action = 'projects.add' 5 + WHERE a.action = 'addprojects'; 6 + 7 + UPDATE {$NAMESPACE}_herald.herald_actionrecord a 8 + JOIN {$NAMESPACE}_herald.herald_rule r 9 + ON a.ruleID = r.id 10 + SET a.action = 'projects.remove' 11 + WHERE a.action = 'removeprojects';
+6
src/__phutil_library_map__.php
··· 2540 2540 'PhabricatorPolicyType' => 'applications/policy/constants/PhabricatorPolicyType.php', 2541 2541 'PhabricatorPonderApplication' => 'applications/ponder/application/PhabricatorPonderApplication.php', 2542 2542 'PhabricatorProject' => 'applications/project/storage/PhabricatorProject.php', 2543 + 'PhabricatorProjectAddHeraldAction' => 'applications/project/herald/PhabricatorProjectAddHeraldAction.php', 2543 2544 'PhabricatorProjectApplication' => 'applications/project/application/PhabricatorProjectApplication.php', 2544 2545 'PhabricatorProjectArchiveController' => 'applications/project/controller/PhabricatorProjectArchiveController.php', 2545 2546 'PhabricatorProjectBoardController' => 'applications/project/controller/PhabricatorProjectBoardController.php', ··· 2572 2573 'PhabricatorProjectEditPictureController' => 'applications/project/controller/PhabricatorProjectEditPictureController.php', 2573 2574 'PhabricatorProjectEditorTestCase' => 'applications/project/editor/__tests__/PhabricatorProjectEditorTestCase.php', 2574 2575 'PhabricatorProjectFeedController' => 'applications/project/controller/PhabricatorProjectFeedController.php', 2576 + 'PhabricatorProjectHeraldAction' => 'applications/project/herald/PhabricatorProjectHeraldAction.php', 2575 2577 'PhabricatorProjectIcon' => 'applications/project/icon/PhabricatorProjectIcon.php', 2576 2578 'PhabricatorProjectInterface' => 'applications/project/interface/PhabricatorProjectInterface.php', 2577 2579 'PhabricatorProjectListController' => 'applications/project/controller/PhabricatorProjectListController.php', ··· 2593 2595 'PhabricatorProjectProjectHasObjectEdgeType' => 'applications/project/edge/PhabricatorProjectProjectHasObjectEdgeType.php', 2594 2596 'PhabricatorProjectProjectPHIDType' => 'applications/project/phid/PhabricatorProjectProjectPHIDType.php', 2595 2597 'PhabricatorProjectQuery' => 'applications/project/query/PhabricatorProjectQuery.php', 2598 + 'PhabricatorProjectRemoveHeraldAction' => 'applications/project/herald/PhabricatorProjectRemoveHeraldAction.php', 2596 2599 'PhabricatorProjectSchemaSpec' => 'applications/project/storage/PhabricatorProjectSchemaSpec.php', 2597 2600 'PhabricatorProjectSearchEngine' => 'applications/project/query/PhabricatorProjectSearchEngine.php', 2598 2601 'PhabricatorProjectSearchField' => 'applications/project/searchfield/PhabricatorProjectSearchField.php', ··· 6496 6499 'PhabricatorCustomFieldInterface', 6497 6500 'PhabricatorDestructibleInterface', 6498 6501 ), 6502 + 'PhabricatorProjectAddHeraldAction' => 'PhabricatorProjectHeraldAction', 6499 6503 'PhabricatorProjectApplication' => 'PhabricatorApplication', 6500 6504 'PhabricatorProjectArchiveController' => 'PhabricatorProjectController', 6501 6505 'PhabricatorProjectBoardController' => 'PhabricatorProjectController', ··· 6539 6543 'PhabricatorProjectEditPictureController' => 'PhabricatorProjectController', 6540 6544 'PhabricatorProjectEditorTestCase' => 'PhabricatorTestCase', 6541 6545 'PhabricatorProjectFeedController' => 'PhabricatorProjectController', 6546 + 'PhabricatorProjectHeraldAction' => 'HeraldAction', 6542 6547 'PhabricatorProjectIcon' => 'Phobject', 6543 6548 'PhabricatorProjectListController' => 'PhabricatorProjectController', 6544 6549 'PhabricatorProjectLogicalAndDatasource' => 'PhabricatorTypeaheadCompositeDatasource', ··· 6559 6564 'PhabricatorProjectProjectHasObjectEdgeType' => 'PhabricatorEdgeType', 6560 6565 'PhabricatorProjectProjectPHIDType' => 'PhabricatorPHIDType', 6561 6566 'PhabricatorProjectQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 6567 + 'PhabricatorProjectRemoveHeraldAction' => 'PhabricatorProjectHeraldAction', 6562 6568 'PhabricatorProjectSchemaSpec' => 'PhabricatorConfigSchemaSpec', 6563 6569 'PhabricatorProjectSearchEngine' => 'PhabricatorApplicationSearchEngine', 6564 6570 'PhabricatorProjectSearchField' => 'PhabricatorSearchTokenizerField',
-58
src/applications/herald/adapter/HeraldAdapter.php
··· 28 28 29 29 const ACTION_AUDIT = 'audit'; 30 30 const ACTION_ASSIGN_TASK = 'assigntask'; 31 - const ACTION_ADD_PROJECTS = 'addprojects'; 32 - const ACTION_REMOVE_PROJECTS = 'removeprojects'; 33 31 const ACTION_ADD_REVIEWERS = 'addreviewers'; 34 32 const ACTION_ADD_BLOCKING_REVIEWERS = 'addblockingreviewers'; 35 33 const ACTION_APPLY_BUILD_PLANS = 'applybuildplans'; ··· 707 705 708 706 $actions = $custom_actions; 709 707 710 - $object = $this->newObject(); 711 - 712 - if (($object instanceof PhabricatorProjectInterface)) { 713 - if ($rule_type == HeraldRuleTypeConfig::RULE_TYPE_GLOBAL) { 714 - $actions[] = self::ACTION_ADD_PROJECTS; 715 - $actions[] = self::ACTION_REMOVE_PROJECTS; 716 - } 717 - } 718 - 719 708 foreach ($this->getActionsForRuleType($rule_type) as $key => $action) { 720 709 $actions[] = $key; 721 710 } ··· 730 719 $standard = array( 731 720 self::ACTION_AUDIT => pht('Trigger an Audit by'), 732 721 self::ACTION_ASSIGN_TASK => pht('Assign task to'), 733 - self::ACTION_ADD_PROJECTS => pht('Add projects'), 734 - self::ACTION_REMOVE_PROJECTS => pht('Remove projects'), 735 722 self::ACTION_ADD_REVIEWERS => pht('Add reviewers'), 736 723 self::ACTION_ADD_BLOCKING_REVIEWERS => pht('Add blocking reviewers'), 737 724 self::ACTION_APPLY_BUILD_PLANS => pht('Run build plans'), ··· 829 816 case self::ACTION_ADD_REVIEWERS: 830 817 case self::ACTION_ADD_BLOCKING_REVIEWERS: 831 818 return new HeraldEmptyFieldValue(); 832 - case self::ACTION_ADD_PROJECTS: 833 - case self::ACTION_REMOVE_PROJECTS: 834 - return $this->buildTokenizerFieldValue( 835 - new PhabricatorProjectDatasource()); 836 819 } 837 820 } else { 838 821 switch ($action) { 839 - case self::ACTION_ADD_PROJECTS: 840 - case self::ACTION_REMOVE_PROJECTS: 841 - return $this->buildTokenizerFieldValue( 842 - new PhabricatorProjectDatasource()); 843 822 case self::ACTION_ASSIGN_TASK: 844 823 return $this->buildTokenizerFieldValue( 845 824 new PhabricatorPeopleDatasource()); ··· 1200 1179 $rule_type)); 1201 1180 } 1202 1181 1203 - switch ($action) { 1204 - case self::ACTION_ADD_PROJECTS: 1205 - case self::ACTION_REMOVE_PROJECTS: 1206 - return $this->applyProjectsEffect($effect); 1207 - default: 1208 - break; 1209 - } 1210 - 1211 1182 $result = $this->handleCustomHeraldEffect($effect); 1212 1183 1213 1184 if (!$result) { ··· 1220 1191 } 1221 1192 1222 1193 return $result; 1223 - } 1224 - 1225 - /** 1226 - * @task apply 1227 - */ 1228 - private function applyProjectsEffect(HeraldEffect $effect) { 1229 - 1230 - if ($effect->getAction() == self::ACTION_ADD_PROJECTS) { 1231 - $kind = '+'; 1232 - } else { 1233 - $kind = '-'; 1234 - } 1235 - 1236 - $project_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; 1237 - $project_phids = $effect->getTarget(); 1238 - $xaction = $this->newTransaction() 1239 - ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) 1240 - ->setMetadataValue('edge:type', $project_type) 1241 - ->setNewValue( 1242 - array( 1243 - $kind => array_fuse($project_phids), 1244 - )); 1245 - 1246 - $this->queueTransaction($xaction); 1247 - 1248 - return new HeraldApplyTranscript( 1249 - $effect, 1250 - true, 1251 - pht('Added projects.')); 1252 1194 } 1253 1195 1254 1196 public function loadEdgePHIDs($type) {
+28
src/applications/project/herald/PhabricatorProjectAddHeraldAction.php
··· 1 + <?php 2 + 3 + final class PhabricatorProjectAddHeraldAction 4 + extends PhabricatorProjectHeraldAction { 5 + 6 + const ACTIONCONST = 'projects.add'; 7 + 8 + public function getHeraldActionName() { 9 + return pht('Add projects'); 10 + } 11 + 12 + public function applyEffect($object, HeraldEffect $effect) { 13 + return $this->applyProjects($effect->getTarget(), $is_add = true); 14 + } 15 + 16 + public function getHeraldActionStandardType() { 17 + return self::STANDARD_PHID_LIST; 18 + } 19 + 20 + protected function getDatasource() { 21 + return new PhabricatorProjectDatasource(); 22 + } 23 + 24 + public function renderActionDescription($value) { 25 + return pht('Add projects: %s.', $this->renderHandleList($value)); 26 + } 27 + 28 + }
+180
src/applications/project/herald/PhabricatorProjectHeraldAction.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorProjectHeraldAction 4 + extends HeraldAction { 5 + 6 + const DO_NO_TARGETS = 'do.no-targets'; 7 + const DO_INVALID = 'do.invalid'; 8 + const DO_ALREADY_ASSOCIATED = 'do.already-associated'; 9 + const DO_ALREADY_UNASSOCIATED = 'do.already-unassociated'; 10 + const DO_ADD_PROJECTS = 'do.add-projects'; 11 + const DO_REMOVE_PROJECTS = 'do.remove-projects'; 12 + 13 + public function getActionGroupKey() { 14 + return HeraldSupportActionGroup::ACTIONGROUPKEY; 15 + } 16 + 17 + public function supportsObject($object) { 18 + return ($object instanceof PhabricatorProjectInterface); 19 + } 20 + 21 + public function supportsRuleType($rule_type) { 22 + return ($rule_type == HeraldRuleTypeConfig::RULE_TYPE_GLOBAL); 23 + } 24 + 25 + protected function applyProjects(array $phids, $is_add) { 26 + $phids = array_fuse($phids); 27 + $adapter = $this->getAdapter(); 28 + 29 + if (!$phids) { 30 + $this->logEffect(self::DO_NO_TARGETS); 31 + return; 32 + } 33 + 34 + $projects = id(new PhabricatorProjectQuery()) 35 + ->setViewer(PhabricatorUser::getOmnipotentUser()) 36 + ->withPHIDs($phids) 37 + ->execute(); 38 + $projects = mpull($projects, null, 'getPHID'); 39 + 40 + $invalid = array(); 41 + foreach ($phids as $phid) { 42 + if (empty($projects[$phid])) { 43 + $invalid[] = $phid; 44 + unset($phids[$phid]); 45 + } 46 + } 47 + 48 + if ($invalid) { 49 + $this->logEffect(self::DO_INVALID, $invalid); 50 + } 51 + 52 + if (!$phids) { 53 + return; 54 + } 55 + 56 + $project_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; 57 + 58 + $current = $adapter->loadEdgePHIDs($project_type); 59 + 60 + if ($is_add) { 61 + $already = array(); 62 + foreach ($phids as $phid) { 63 + if (isset($current[$phid])) { 64 + $already[$phid] = $phid; 65 + unset($phids[$phid]); 66 + } 67 + } 68 + 69 + if ($already) { 70 + $this->logEffect(self::DO_ALREADY_ASSOCIATED, $already); 71 + } 72 + } else { 73 + $already = array(); 74 + foreach ($phids as $phid) { 75 + if (empty($current[$phid])) { 76 + $already[$phid] = $phid; 77 + unset($phids[$phid]); 78 + } 79 + } 80 + 81 + if ($already) { 82 + $this->logEffect(self::DO_ALREADY_UNASSOCIATED, $already); 83 + } 84 + } 85 + 86 + if (!$phids) { 87 + return; 88 + } 89 + 90 + if ($is_add) { 91 + $kind = '+'; 92 + } else { 93 + $kind = '-'; 94 + } 95 + 96 + $xaction = $adapter->newTransaction() 97 + ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) 98 + ->setMetadataValue('edge:type', $project_type) 99 + ->setNewValue( 100 + array( 101 + $kind => $phids, 102 + )); 103 + 104 + $adapter->queueTransaction($xaction); 105 + 106 + if ($is_add) { 107 + $this->logEffect(self::DO_ADD_PROJECTS, $phids); 108 + } else { 109 + $this->logEffect(self::DO_REMOVE_PROJECTS, $phids); 110 + } 111 + } 112 + 113 + protected function getActionEffectMap() { 114 + return array( 115 + self::DO_NO_TARGETS => array( 116 + 'icon' => 'fa-ban', 117 + 'color' => 'grey', 118 + 'name' => pht('No Targets'), 119 + ), 120 + self::DO_INVALID => array( 121 + 'icon' => 'fa-ban', 122 + 'color' => 'red', 123 + 'name' => pht('Invalid Targets'), 124 + ), 125 + self::DO_ALREADY_ASSOCIATED => array( 126 + 'icon' => 'fa-chevron-right', 127 + 'color' => 'grey', 128 + 'name' => pht('Already Associated'), 129 + ), 130 + self::DO_ALREADY_UNASSOCIATED => array( 131 + 'icon' => 'fa-chevron-right', 132 + 'color' => 'grey', 133 + 'name' => pht('Already Unassociated'), 134 + ), 135 + self::DO_ADD_PROJECTS => array( 136 + 'icon' => 'fa-briefcase', 137 + 'color' => 'green', 138 + 'name' => pht('Added Projects'), 139 + ), 140 + self::DO_REMOVE_PROJECTS => array( 141 + 'icon' => 'fa-minus-circle', 142 + 'color' => 'green', 143 + 'name' => pht('Removed Projects'), 144 + ), 145 + ); 146 + } 147 + 148 + public function renderActionEffectDescription($type, $data) { 149 + switch ($type) { 150 + case self::DO_NO_TARGETS: 151 + return pht('Rule lists no projects.'); 152 + case self::DO_INVALID: 153 + return pht( 154 + 'Declined to act on %s invalid project(s): %s.', 155 + new PhutilNumber(count($data)), 156 + $this->renderHandleList($data)); 157 + case self::DO_ALREADY_ASSOCIATED: 158 + return pht( 159 + '%s project(s) are already associated: %s.', 160 + new PhutilNumber(count($data)), 161 + $this->renderHandleList($data)); 162 + case self::DO_ALREADY_UNASSOCIATED: 163 + return pht( 164 + '%s project(s) are not associated: %s.', 165 + new PhutilNumber(count($data)), 166 + $this->renderHandleList($data)); 167 + case self::DO_ADD_PROJECTS: 168 + return pht( 169 + 'Added %s project(s): %s.', 170 + new PhutilNumber(count($data)), 171 + $this->renderHandleList($data)); 172 + case self::DO_REMOVE_PROJECTS: 173 + return pht( 174 + 'Removed %s project(s): %s.', 175 + new PhutilNumber(count($data)), 176 + $this->renderHandleList($data)); 177 + } 178 + } 179 + 180 + }
+28
src/applications/project/herald/PhabricatorProjectRemoveHeraldAction.php
··· 1 + <?php 2 + 3 + final class PhabricatorProjectRemoveHeraldAction 4 + extends PhabricatorProjectHeraldAction { 5 + 6 + const ACTIONCONST = 'projects.remove'; 7 + 8 + public function getHeraldActionName() { 9 + return pht('Remove projects'); 10 + } 11 + 12 + public function applyEffect($object, HeraldEffect $effect) { 13 + return $this->applyProjects($effect->getTarget(), $is_add = false); 14 + } 15 + 16 + public function getHeraldActionStandardType() { 17 + return self::STANDARD_PHID_LIST; 18 + } 19 + 20 + protected function getDatasource() { 21 + return new PhabricatorProjectDatasource(); 22 + } 23 + 24 + public function renderActionDescription($value) { 25 + return pht('Remove projects: %s.', $this->renderHandleList($value)); 26 + } 27 + 28 + }
+20
src/infrastructure/internationalization/translation/PhabricatorUSEnglishTranslation.php
··· 1303 1303 'preferences: %2$s.', 1304 1304 ), 1305 1305 1306 + '%s project(s) are not associated: %s.' => array( 1307 + 'A project is not associated: %2$s.', 1308 + 'Projects are not associated: %2$s.', 1309 + ), 1310 + 1311 + '%s project(s) are already associated: %s.' => array( 1312 + 'A project is already associated: %2$s.', 1313 + 'Projects are already associated: %2$s.', 1314 + ), 1315 + 1316 + 'Added %s project(s): %s.' => array( 1317 + 'Added a project: %2$s.', 1318 + 'Added projects: %2$s.', 1319 + ), 1320 + 1321 + 'Removed %s project(s): %s.' => array( 1322 + 'Removed a project: %2$s.', 1323 + 'Removed projects: %2$s.', 1324 + ), 1325 + 1306 1326 ); 1307 1327 } 1308 1328