Differential D5613 Diff 21933 src/applications/subscriptions/events/PhabricatorSubscriptionsUIEventListener.php
Changeset View
Changeset View
Standalone View
Standalone View
src/applications/subscriptions/events/PhabricatorSubscriptionsUIEventListener.php
<?php | <?php | ||||
final class PhabricatorSubscriptionsUIEventListener | final class PhabricatorSubscriptionsUIEventListener | ||||
extends PhabricatorEventListener { | extends PhabricatorEventListener { | ||||
public function register() { | public function register() { | ||||
$this->listen(PhabricatorEventType::TYPE_UI_DIDRENDERACTIONS); | $this->listen(PhabricatorEventType::TYPE_UI_DIDRENDERACTIONS); | ||||
$this->listen(PhabricatorEventType::TYPE_UI_WILLRENDERPROPERTIES); | $this->listen(PhabricatorEventType::TYPE_UI_WILLRENDERPROPERTIES); | ||||
$this->listen(PhabricatorEventType::TYPE_UI_DIDRENDERHOVERCARD); | |||||
} | } | ||||
public function handleEvent(PhutilEvent $event) { | public function handleEvent(PhutilEvent $event) { | ||||
switch ($event->getType()) { | switch ($event->getType()) { | ||||
case PhabricatorEventType::TYPE_UI_DIDRENDERACTIONS: | case PhabricatorEventType::TYPE_UI_DIDRENDERACTIONS: | ||||
$this->handleActionEvent($event); | $this->handleActionEvent($event); | ||||
break; | break; | ||||
case PhabricatorEventType::TYPE_UI_WILLRENDERPROPERTIES: | case PhabricatorEventType::TYPE_UI_WILLRENDERPROPERTIES: | ||||
$this->handlePropertyEvent($event); | $this->handlePropertyEvent($event); | ||||
break; | break; | ||||
case PhabricatorEventType::TYPE_UI_DIDRENDERHOVERCARD: | |||||
$this->handleHovercardEvent($event); | |||||
break; | |||||
} | } | ||||
} | } | ||||
private function handleActionEvent($event) { | private function handleActionEvent($event) { | ||||
$user = $event->getUser(); | $user = $event->getUser(); | ||||
$object = $event->getValue('object'); | $object = $event->getValue('object'); | ||||
if (!$object || !$object->getPHID()) { | if (!$object || !$object->getPHID()) { | ||||
Show All 17 Lines | if ($object->isAutomaticallySubscribed($user->getPHID())) { | ||||
->setDisabled(true) | ->setDisabled(true) | ||||
->setRenderAsForm(true) | ->setRenderAsForm(true) | ||||
->setHref('/subscriptions/add/'.$object->getPHID().'/') | ->setHref('/subscriptions/add/'.$object->getPHID().'/') | ||||
->setName(pht('Automatically Subscribed')) | ->setName(pht('Automatically Subscribed')) | ||||
->setIcon('fa-check-circle lightgreytext'); | ->setIcon('fa-check-circle lightgreytext'); | ||||
} else { | } else { | ||||
$subscribed = false; | $subscribed = false; | ||||
if ($user->isLoggedIn()) { | if ($user->isLoggedIn()) { | ||||
$src_phid = $object->getPHID(); | $subscribed = $this->fetchStatusFromEdge($object, $user); | ||||
$dst_phid = $user->getPHID(); | |||||
$edge_type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_SUBSCRIBER; | |||||
$edges = id(new PhabricatorEdgeQuery()) | |||||
->withSourcePHIDs(array($src_phid)) | |||||
->withEdgeTypes(array($edge_type)) | |||||
->withDestinationPHIDs(array($user->getPHID())) | |||||
->execute(); | |||||
$subscribed = isset($edges[$src_phid][$edge_type][$dst_phid]); | |||||
} | } | ||||
if ($subscribed) { | if ($subscribed) { | ||||
$sub_action = id(new PhabricatorActionView()) | $sub_action = id(new PhabricatorActionView()) | ||||
->setWorkflow(true) | ->setWorkflow(true) | ||||
->setRenderAsForm(true) | ->setRenderAsForm(true) | ||||
->setHref('/subscriptions/delete/'.$object->getPHID().'/') | ->setHref('/subscriptions/delete/'.$object->getPHID().'/') | ||||
->setName(pht('Unsubscribe')) | ->setName(pht('Unsubscribe')) | ||||
Show All 27 Lines | private function handlePropertyEvent($event) { | ||||
} | } | ||||
if (!($object instanceof PhabricatorSubscribableInterface)) { | if (!($object instanceof PhabricatorSubscribableInterface)) { | ||||
// This object isn't subscribable. | // This object isn't subscribable. | ||||
return; | return; | ||||
} | } | ||||
if (!$object->shouldShowSubscribersProperty()) { | if (!$object->shouldShowSubscribersProperty()) { | ||||
// This object doesn't render subscribers in its property list. | // This object doesn't render subscribers in its property list. | ||||
return; | return; | ||||
} | } | ||||
$subscribers = PhabricatorSubscribersQuery::loadSubscribersForPHID( | $subscribers = PhabricatorSubscribersQuery::loadSubscribersForPHID( | ||||
$object->getPHID()); | $object->getPHID()); | ||||
epriestley: I think this one can go either way, but in general we should err on the side of showing (but… | |||||
if ($subscribers) { | if ($subscribers) { | ||||
$handles = id(new PhabricatorHandleQuery()) | $handles = id(new PhabricatorHandleQuery()) | ||||
->setViewer($user) | ->setViewer($user) | ||||
Not Done Inline ActionsWould probably prefer to have this be 'Subscribed' but have the button inactive, like the action list on the object. chad: Would probably prefer to have this be 'Subscribed' but have the button inactive, like the… | |||||
Not Done Inline ActionsOh, thanks for spotting. This wasn't supposed to be here. AnhNhan: Oh, thanks for spotting. This wasn't supposed to be here. | |||||
->withPHIDs($subscribers) | ->withPHIDs($subscribers) | ||||
->execute(); | ->execute(); | ||||
} else { | } else { | ||||
$handles = array(); | $handles = array(); | ||||
} | } | ||||
$sub_view = id(new SubscriptionListStringBuilder()) | $sub_view = id(new SubscriptionListStringBuilder()) | ||||
->setObjectPHID($object->getPHID()) | ->setObjectPHID($object->getPHID()) | ||||
->setHandles($handles) | ->setHandles($handles) | ||||
->buildPropertyString(); | ->buildPropertyString(); | ||||
$view = $event->getValue('view'); | $view = $event->getValue('view'); | ||||
$view->addProperty(pht('Subscribers'), $sub_view); | $view->addProperty(pht('Subscribers'), $sub_view); | ||||
} | } | ||||
private function handleHovercardEvent(PhutilEvent $event) { | |||||
$user = $event->getUser(); | |||||
$object = $event->getValue('object'); | |||||
$hc = $event->getValue('hovercard'); | |||||
if (!$object || !$object->getPHID()) { | |||||
// No object, or the object has no PHID yet. No way to subscribe. | |||||
return; | |||||
} | |||||
if (!($object instanceof PhabricatorSubscribableInterface)) { | |||||
// This object isn't subscribable. | |||||
return; | |||||
} | |||||
if (!$object->shouldAllowSubscription($user->getPHID())) { | |||||
// This object doesn't allow the viewer to subscribe. | |||||
return; | |||||
} | |||||
if ($object->isAutomaticallySubscribed($user->getPHID())) { | |||||
$hc->addAction(pht('Uhh...'), null); | |||||
} else { | |||||
$subscribed = $this->fetchStatusFromEdge($object, $user); | |||||
$hc->setUser($user); | |||||
// Workflow no work? You just get a page reload | |||||
if ($subscribed) { | |||||
$hc->addAction(pht('Unsubscribe'), | |||||
'/subscriptions/delete/'.$object->getPHID().'/', | |||||
true, | |||||
true); | |||||
} else { | |||||
$hc->addAction(pht('Subscribe'), | |||||
'/subscriptions/add/'.$object->getPHID().'/', | |||||
true, | |||||
true); | |||||
} | |||||
} | |||||
$event->setValue('hovercard', $hc); | |||||
} | |||||
private function fetchStatusFromEdge($object, $user) { | |||||
$src_phid = $object->getPHID(); | |||||
$dst_phid = $user->getPHID(); | |||||
$edge_type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_SUBSCRIBER; | |||||
$edges = id(new PhabricatorEdgeQuery()) | |||||
->withSourcePHIDs(array($src_phid)) | |||||
->withEdgeTypes(array($edge_type)) | |||||
->withDestinationPHIDs(array($dst_phid)) | |||||
->execute(); | |||||
return isset($edges[$src_phid][$edge_type][$dst_phid]); | |||||
} | |||||
} | } |
I think this one can go either way, but in general we should err on the side of showing (but disabling/deactivating) options which are possible but not currently permitted -- this lets the user click them to learn why they can't take the action. But just dropping the button in this case seems pretty reasonable.