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

Make event-triggered actions more aware of application access

Summary:
Fixes T3675.

- Maniphest had a couple of old non-event listeners; move them to events.
- Make most of the similar listeners a little more similar.
- Add checks for access to the application.

Test Plan:
- Viewed profile, project, task, revision.
- Clicked all the actions.
- Blocked access to various applications and verified the actions vanished.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T3675

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

+274 -115
+4 -2
src/__phutil_library_map__.php
··· 297 297 'DefaultDatabaseConfigurationProvider' => 'infrastructure/storage/configuration/DefaultDatabaseConfigurationProvider.php', 298 298 'DifferentialAction' => 'applications/differential/constants/DifferentialAction.php', 299 299 'DifferentialActionHasNoEffectException' => 'applications/differential/exception/DifferentialActionHasNoEffectException.php', 300 - 'DifferentialActionMenuEventListener' => 'applications/differential/events/DifferentialActionMenuEventListener.php', 300 + 'DifferentialActionMenuEventListener' => 'applications/differential/event/DifferentialActionMenuEventListener.php', 301 301 'DifferentialAddCommentView' => 'applications/differential/view/DifferentialAddCommentView.php', 302 302 'DifferentialAffectedPath' => 'applications/differential/storage/DifferentialAffectedPath.php', 303 303 'DifferentialApplyPatchFieldSpecification' => 'applications/differential/field/specification/DifferentialApplyPatchFieldSpecification.php', ··· 368 368 'DifferentialFreeformFieldTestCase' => 'applications/differential/field/specification/__tests__/DifferentialFreeformFieldTestCase.php', 369 369 'DifferentialGitSVNIDFieldSpecification' => 'applications/differential/field/specification/DifferentialGitSVNIDFieldSpecification.php', 370 370 'DifferentialHostFieldSpecification' => 'applications/differential/field/specification/DifferentialHostFieldSpecification.php', 371 - 'DifferentialHovercardEventListener' => 'applications/differential/events/DifferentialHovercardEventListener.php', 371 + 'DifferentialHovercardEventListener' => 'applications/differential/event/DifferentialHovercardEventListener.php', 372 372 'DifferentialHunk' => 'applications/differential/storage/DifferentialHunk.php', 373 373 'DifferentialHunkParser' => 'applications/differential/parser/DifferentialHunkParser.php', 374 374 'DifferentialHunkParserTestCase' => 'applications/differential/parser/__tests__/DifferentialHunkParserTestCase.php', ··· 1876 1876 'PhluxVariableEditor' => 'applications/phlux/editor/PhluxVariableEditor.php', 1877 1877 'PhluxVariableQuery' => 'applications/phlux/query/PhluxVariableQuery.php', 1878 1878 'PhluxViewController' => 'applications/phlux/controller/PhluxViewController.php', 1879 + 'PholioActionMenuEventListener' => 'applications/pholio/event/PholioActionMenuEventListener.php', 1879 1880 'PholioConstants' => 'applications/pholio/constants/PholioConstants.php', 1880 1881 'PholioController' => 'applications/pholio/controller/PholioController.php', 1881 1882 'PholioDAO' => 'applications/pholio/storage/PholioDAO.php', ··· 4122 4123 'PhluxVariableEditor' => 'PhabricatorApplicationTransactionEditor', 4123 4124 'PhluxVariableQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 4124 4125 'PhluxViewController' => 'PhluxController', 4126 + 'PholioActionMenuEventListener' => 'PhabricatorEventListener', 4125 4127 'PholioController' => 'PhabricatorController', 4126 4128 'PholioDAO' => 'PhabricatorLiskDAO', 4127 4129 'PholioImage' =>
+19 -11
src/applications/audit/events/AuditActionMenuEventListener.php
··· 14 14 } 15 15 } 16 16 17 - private function handleActionsEvent($event) { 18 - $person = $event->getValue('object'); 19 - if (!($person instanceof PhabricatorUser)) { 20 - return; 17 + private function handleActionsEvent(PhutilEvent $event) { 18 + $object = $event->getValue('object'); 19 + 20 + $actions = null; 21 + if ($object instanceof PhabricatorUser) { 22 + $actions = $this->renderUserItems($event); 21 23 } 22 24 23 - $actions = $event->getValue('actions'); 25 + $this->addActionMenuItems($event, $actions); 26 + } 24 27 25 - $username = phutil_escape_uri($person->getUsername()); 26 - $href = '/audit/view/author/'.$username.'/'; 28 + private function renderUserItems(PhutilEvent $event) { 29 + if (!$this->canUseApplication($event->getUser())) { 30 + return null; 31 + } 27 32 28 - $actions[] = id(new PhabricatorActionView()) 33 + $user = $event->getValue('object'); 34 + 35 + $username = phutil_escape_uri($user->getUsername()); 36 + $view_uri = '/audit/view/author/'.$username.'/'; 37 + 38 + return id(new PhabricatorActionView()) 29 39 ->setIcon('audit-dark') 30 40 ->setIconSheet(PHUIIconView::SPRITE_APPS) 31 41 ->setName(pht('View Commits')) 32 - ->setHref($href); 33 - 34 - $event->setValue('actions', $actions); 42 + ->setHref($view_uri); 35 43 } 36 44 37 45 }
+16 -9
src/applications/conpherence/events/ConpherenceActionMenuEventListener.php
··· 15 15 } 16 16 } 17 17 18 - private function handleActionsEvent($event) { 19 - $person = $event->getValue('object'); 20 - if (!($person instanceof PhabricatorUser)) { 21 - return; 18 + private function handleActionsEvent(PhutilEvent $event) { 19 + $object = $event->getValue('object'); 20 + 21 + $actions = null; 22 + if ($object instanceof PhabricatorUser) { 23 + $actions = $this->renderUserItems($event); 22 24 } 23 25 24 - $href = '/conpherence/new/?participant='.$person->getPHID(); 26 + $this->addActionMenuItems($event, $actions); 27 + } 28 + 29 + private function renderUserItems(PhutilEvent $event) { 30 + if (!$this->canUseApplication($event->getUser())) { 31 + return null; 32 + } 25 33 26 - $actions = $event->getValue('actions'); 34 + $user = $event->getValue('object'); 35 + $href = '/conpherence/new/?participant='.$user->getPHID(); 27 36 28 - $actions[] = id(new PhabricatorActionView()) 37 + return id(new PhabricatorActionView()) 29 38 ->setIcon('message') 30 39 ->setName(pht('Send Message')) 31 40 ->setWorkflow(true) 32 41 ->setHref($href); 33 - 34 - $event->setValue('actions', $actions); 35 42 } 36 43 37 44 }
+70
src/applications/differential/event/DifferentialActionMenuEventListener.php
··· 1 + <?php 2 + 3 + final class DifferentialActionMenuEventListener 4 + extends PhabricatorEventListener { 5 + 6 + public function register() { 7 + $this->listen(PhabricatorEventType::TYPE_UI_DIDRENDERACTIONS); 8 + } 9 + 10 + public function handleEvent(PhutilEvent $event) { 11 + switch ($event->getType()) { 12 + case PhabricatorEventType::TYPE_UI_DIDRENDERACTIONS: 13 + $this->handleActionsEvent($event); 14 + break; 15 + } 16 + } 17 + 18 + private function handleActionsEvent(PhutilEvent $event) { 19 + $object = $event->getValue('object'); 20 + 21 + $actions = null; 22 + if ($object instanceof PhabricatorUser) { 23 + $actions = $this->renderUserItems($event); 24 + } else if ($object instanceof ManiphestTask) { 25 + $actions = $this->renderTaskItems($event); 26 + } 27 + 28 + $this->addActionMenuItems($event, $actions); 29 + } 30 + 31 + private function renderUserItems(PhutilEvent $event) { 32 + if (!$this->canUseApplication($event->getUser())) { 33 + return null; 34 + } 35 + 36 + $person = $event->getValue('object'); 37 + $href = '/differential/?authorPHIDs[]='.$person->getPHID(); 38 + 39 + return id(new PhabricatorActionView()) 40 + ->setRenderAsForm(true) 41 + ->setIcon('differential-dark') 42 + ->setIconSheet(PHUIIconView::SPRITE_APPS) 43 + ->setName(pht('View Revisions')) 44 + ->setHref($href); 45 + } 46 + 47 + private function renderTaskItems(PhutilEvent $event) { 48 + if (!$this->canUseApplication($event->getUser())) { 49 + return null; 50 + } 51 + 52 + $task = $event->getValue('object'); 53 + $phid = $task->getPHID(); 54 + 55 + $can_edit = PhabricatorPolicyFilter::hasCapability( 56 + $event->getUser(), 57 + $task, 58 + PhabricatorPolicyCapability::CAN_EDIT); 59 + 60 + return id(new PhabricatorActionView()) 61 + ->setName(pht('Edit Differential Revisions')) 62 + ->setHref("/search/attach/{$phid}/DREV/") 63 + ->setWorkflow(true) 64 + ->setIcon('attach') 65 + ->setDisabled(!$can_edit) 66 + ->setWorkflow(true); 67 + } 68 + 69 + } 70 +
-39
src/applications/differential/events/DifferentialActionMenuEventListener.php
··· 1 - <?php 2 - 3 - final class DifferentialActionMenuEventListener 4 - extends PhabricatorEventListener { 5 - 6 - public function register() { 7 - $this->listen(PhabricatorEventType::TYPE_UI_DIDRENDERACTIONS); 8 - } 9 - 10 - public function handleEvent(PhutilEvent $event) { 11 - switch ($event->getType()) { 12 - case PhabricatorEventType::TYPE_UI_DIDRENDERACTIONS: 13 - $this->handleActionsEvent($event); 14 - break; 15 - } 16 - } 17 - 18 - private function handleActionsEvent($event) { 19 - $person = $event->getValue('object'); 20 - if (!($person instanceof PhabricatorUser)) { 21 - return; 22 - } 23 - 24 - $href = '/differential/?authorPHIDs[]='.$person->getPHID(); 25 - 26 - $actions = $event->getValue('actions'); 27 - 28 - $actions[] = id(new PhabricatorActionView()) 29 - ->setRenderAsForm(true) 30 - ->setIcon('differential-dark') 31 - ->setIconSheet(PHUIIconView::SPRITE_APPS) 32 - ->setName(pht('View Revisions')) 33 - ->setHref($href); 34 - 35 - $event->setValue('actions', $actions); 36 - } 37 - 38 - } 39 -
src/applications/differential/events/DifferentialHovercardEventListener.php src/applications/differential/event/DifferentialHovercardEventListener.php
+4
src/applications/flag/events/PhabricatorFlagsUIEventListener.php
··· 31 31 return; 32 32 } 33 33 34 + if (!$this->canUseApplication($event->getUser())) { 35 + return null; 36 + } 37 + 34 38 $flag = PhabricatorFlagQuery::loadUserFlag($user, $object->getPHID()); 35 39 36 40 if ($flag) {
-22
src/applications/maniphest/controller/ManiphestTaskDetailController.php
··· 500 500 ->setDisabled(!$can_edit) 501 501 ->setWorkflow(true)); 502 502 503 - $view->addAction( 504 - id(new PhabricatorActionView()) 505 - ->setName(pht('Edit Differential Revisions')) 506 - ->setHref("/search/attach/{$phid}/DREV/") 507 - ->setWorkflow(true) 508 - ->setIcon('attach') 509 - ->setDisabled(!$can_edit) 510 - ->setWorkflow(true)); 511 - 512 - $pholio_app = 513 - PhabricatorApplication::getByClass('PhabricatorApplicationPholio'); 514 - if ($pholio_app->isInstalled()) { 515 - $view->addAction( 516 - id(new PhabricatorActionView()) 517 - ->setName(pht('Edit Pholio Mocks')) 518 - ->setHref("/search/attach/{$phid}/MOCK/edge/") 519 - ->setWorkflow(true) 520 - ->setIcon('attach') 521 - ->setDisabled(!$can_edit) 522 - ->setWorkflow(true)); 523 - } 524 - 525 503 return $view; 526 504 } 527 505
+45 -16
src/applications/maniphest/event/ManiphestActionMenuEventListener.php
··· 14 14 } 15 15 } 16 16 17 - private function handleActionsEvent($event) { 18 - $actions = $event->getValue('actions'); 17 + private function handleActionsEvent(PhutilEvent $event) { 18 + $object = $event->getValue('object'); 19 + 20 + $actions = null; 21 + if ($object instanceof PhabricatorUser) { 22 + $actions = $this->renderUserItems($event); 23 + } else if ($object instanceof PhabricatorProject) { 24 + $actions = $this->renderProjectItems($event); 25 + } 26 + 27 + $this->addActionMenuItems($event, $actions); 28 + } 29 + 30 + private function renderUserItems(PhutilEvent $event) { 31 + if (!$this->canUseApplication($event->getUser())) { 32 + return null; 33 + } 19 34 20 - $action = id(new PhabricatorActionView()) 35 + $user = $event->getValue('object'); 36 + $phid = $user->getPHID(); 37 + $view_uri = '/maniphest/?statuses[]=0&assigned='.$phid.'#R'; 38 + 39 + return id(new PhabricatorActionView()) 21 40 ->setIcon('maniphest-dark') 22 41 ->setIconSheet(PHUIIconView::SPRITE_APPS) 23 - ->setName(pht('View Tasks')); 42 + ->setName(pht('View Tasks')) 43 + ->setHref($view_uri); 44 + } 45 + 46 + private function renderProjectItems(PhutilEvent $event) { 47 + if (!$this->canUseApplication($event->getUser())) { 48 + return null; 49 + } 24 50 25 - $object = $event->getValue('object'); 26 - if ($object instanceof PhabricatorUser) { 27 - $href = '/maniphest/?statuses[]=0&assigned='.$object->getPHID().'#R'; 28 - $actions[] = $action->setHref($href); 29 - } else if ($object instanceof PhabricatorProject) { 30 - $href = '/maniphest/?statuses[]=0&allProjects[]='.$object->getPHID().'#R'; 31 - $actions[] = $action->setHref($href); 51 + $project = $event->getValue('object'); 32 52 33 - $actions[] = id(new PhabricatorActionView()) 53 + $phid = $project->getPHID(); 54 + $view_uri = '/maniphest/?statuses[]=0&allProjects[]='.$phid.'#R'; 55 + $create_uri = '/maniphest/task/create/?projects='.$phid; 56 + 57 + return array( 58 + id(new PhabricatorActionView()) 59 + ->setIcon('maniphest-dark') 60 + ->setIconSheet(PHUIIconView::SPRITE_APPS) 61 + ->setName(pht('View Tasks')) 62 + ->setHref($view_uri), 63 + id(new PhabricatorActionView()) 34 64 ->setName(pht("Add Task")) 35 65 ->setIcon('create') 36 - ->setHref('/maniphest/task/create/?projects=' . $object->getPHID()); 37 - } 66 + ->setHref($create_uri), 67 + ); 68 + } 38 69 39 - $event->setValue('actions', $actions); 40 - } 41 70 42 71 }
+6
src/applications/pholio/application/PhabricatorApplicationPholio.php
··· 34 34 return true; 35 35 } 36 36 37 + public function getEventListeners() { 38 + return array( 39 + new PholioActionMenuEventListener(), 40 + ); 41 + } 42 + 37 43 public function getRemarkupRules() { 38 44 return array( 39 45 new PholioRemarkupRule(),
+52
src/applications/pholio/event/PholioActionMenuEventListener.php
··· 1 + <?php 2 + 3 + final class PholioActionMenuEventListener 4 + extends PhabricatorEventListener { 5 + 6 + public function register() { 7 + $this->listen(PhabricatorEventType::TYPE_UI_DIDRENDERACTIONS); 8 + } 9 + 10 + public function handleEvent(PhutilEvent $event) { 11 + switch ($event->getType()) { 12 + case PhabricatorEventType::TYPE_UI_DIDRENDERACTIONS: 13 + $this->handleActionsEvent($event); 14 + break; 15 + } 16 + } 17 + 18 + private function handleActionsEvent(PhutilEvent $event) { 19 + $object = $event->getValue('object'); 20 + 21 + $actions = null; 22 + if ($object instanceof ManiphestTask) { 23 + $actions = $this->renderTaskItems($event); 24 + } 25 + 26 + $this->addActionMenuItems($event, $actions); 27 + } 28 + 29 + private function renderTaskItems(PhutilEvent $event) { 30 + if (!$this->canUseApplication($event->getUser())) { 31 + return; 32 + } 33 + 34 + $task = $event->getValue('object'); 35 + $phid = $task->getPHID(); 36 + 37 + $can_edit = PhabricatorPolicyFilter::hasCapability( 38 + $event->getUser(), 39 + $task, 40 + PhabricatorPolicyCapability::CAN_EDIT); 41 + 42 + return id(new PhabricatorActionView()) 43 + ->setName(pht('Edit Pholio Mocks')) 44 + ->setHref("/search/attach/{$phid}/MOCK/edge/") 45 + ->setWorkflow(true) 46 + ->setIcon('attach') 47 + ->setDisabled(!$can_edit) 48 + ->setWorkflow(true); 49 + } 50 + 51 + } 52 +
+9 -3
src/applications/phrequent/event/PhrequentUIEventListener.php
··· 33 33 return; 34 34 } 35 35 36 + if (!$this->canUseApplication($event->getUser())) { 37 + return; 38 + } 39 + 36 40 $tracking = PhrequentUserTimeQuery::isUserTrackingObject( 37 41 $user, 38 42 $object->getPHID()); ··· 56 60 $track_action->setDisabled(true); 57 61 } 58 62 59 - $actions = $event->getValue('actions'); 60 - $actions[] = $track_action; 61 - $event->setValue('actions', $actions); 63 + $this->addActionMenuItems($event, $track_action); 62 64 } 63 65 64 66 private function handlePropertyEvent($ui_event) { ··· 72 74 73 75 if (!($object instanceof PhrequentTrackableInterface)) { 74 76 // This object isn't a time trackable object. 77 + return; 78 + } 79 + 80 + if (!$this->canUseApplication($ui_event->getUser())) { 75 81 return; 76 82 } 77 83
+21 -12
src/applications/phriction/event/PhrictionActionMenuEventListener.php
··· 14 14 } 15 15 } 16 16 17 - private function handleActionsEvent($event) { 18 - $actions = $event->getValue('actions'); 17 + private function handleActionsEvent(PhutilEvent $event) { 18 + $object = $event->getValue('object'); 19 + 20 + $actions = null; 21 + if ($object instanceof PhabricatorProject) { 22 + $actions = $this->buildProjectActions($event); 23 + } 19 24 20 - $action = id(new PhabricatorActionView()) 21 - ->setIcon('phriction-dark') 22 - ->setIconSheet(PHUIIconView::SPRITE_APPS) 23 - ->setName(pht('View Wiki')); 25 + $this->addActionMenuItems($event, $actions); 26 + } 24 27 25 - $object = $event->getValue('object'); 26 - if ($object instanceof PhabricatorProject) { 27 - $slug = PhabricatorSlug::normalize($object->getPhrictionSlug()); 28 - $href = '/w/projects/'.$slug; 29 - $actions[] = $action->setHref($href); 28 + private function buildProjectActions(PhutilEvent $event) { 29 + if (!$this->canUseApplication($event->getUser())) { 30 + return null; 30 31 } 31 32 32 - $event->setValue('actions', $actions); 33 + $project = $event->getValue('object'); 34 + $slug = PhabricatorSlug::normalize($project->getPhrictionSlug()); 35 + $href = '/w/projects/'.$slug; 36 + 37 + return id(new PhabricatorActionView()) 38 + ->setIcon('phriction-dark') 39 + ->setIconSheet(PHUIIconView::SPRITE_APPS) 40 + ->setName(pht('View Wiki')) 41 + ->setHref($href); 33 42 } 34 43 35 44 }
+8
src/applications/tokens/event/PhabricatorTokenUIEventListener.php
··· 33 33 return; 34 34 } 35 35 36 + if (!$this->canUseApplication($event->getUser())) { 37 + return null; 38 + } 39 + 36 40 $current = id(new PhabricatorTokenGivenQuery()) 37 41 ->setViewer($user) 38 42 ->withAuthorPHIDs(array($user->getPHID())) ··· 73 77 if (!($object instanceof PhabricatorTokenReceiverInterface)) { 74 78 // This object isn't a token receiver. 75 79 return; 80 + } 81 + 82 + if (!$this->canUseApplication($event->getUser())) { 83 + return null; 76 84 } 77 85 78 86 $limit = 1;
+20
src/infrastructure/events/PhabricatorEventListener.php
··· 28 28 PhabricatorPolicyCapability::CAN_VIEW); 29 29 } 30 30 31 + protected function addActionMenuItems(PhutilEvent $event, $items) { 32 + if ($event->getType() !== PhabricatorEventType::TYPE_UI_DIDRENDERACTIONS) { 33 + throw new Exception("Not an action menu event!"); 34 + } 35 + 36 + if (!$items) { 37 + return; 38 + } 39 + 40 + if (!is_array($items)) { 41 + $items = array($items); 42 + } 43 + 44 + $event_actions = $event->getValue('actions'); 45 + foreach ($items as $item) { 46 + $event_actions[] = $item; 47 + } 48 + $event->setValue('actions', $event_actions); 49 + } 50 + 31 51 } 32 52 33 53
-1
src/view/layout/PhabricatorActionListView.php
··· 42 42 PhutilEventEngine::dispatchEvent($event); 43 43 44 44 $actions = $event->getValue('actions'); 45 - 46 45 if (!$actions) { 47 46 return null; 48 47 }