Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15394148
D19033.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
19 KB
Referenced Files
None
Subscribers
None
D19033.diff
View Options
diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -9,7 +9,7 @@
'names' => array(
'conpherence.pkg.css' => 'e68cf1fa',
'conpherence.pkg.js' => '15191c65',
- 'core.pkg.css' => '51debec3',
+ 'core.pkg.css' => 'ce8c2a58',
'core.pkg.js' => '4c79d74f',
'darkconsole.pkg.js' => '1f9a31bc',
'differential.pkg.css' => '45951e9e',
@@ -136,7 +136,7 @@
'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '9d9685d6',
'rsrc/css/phui/object-item/phui-oi-list-view.css' => '6ae18df0',
'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => 'a8beebea',
- 'rsrc/css/phui/phui-action-list.css' => 'f7f61a34',
+ 'rsrc/css/phui/phui-action-list.css' => '0bcd9a45',
'rsrc/css/phui/phui-action-panel.css' => 'b4798122',
'rsrc/css/phui/phui-badge.css' => '22c0cf4f',
'rsrc/css/phui/phui-basic-nav-view.css' => '98c11ab3',
@@ -766,7 +766,7 @@
'path-typeahead' => 'f7fc67ec',
'people-picture-menu-item-css' => 'a06f7f34',
'people-profile-css' => '4df76faf',
- 'phabricator-action-list-view-css' => 'f7f61a34',
+ 'phabricator-action-list-view-css' => '0bcd9a45',
'phabricator-busy' => '59a7976a',
'phabricator-chatlog-css' => 'd295b020',
'phabricator-content-source-view-css' => '4b8b05d4',
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -3291,6 +3291,8 @@
'PhabricatorMultiFactorSettingsPanel' => 'applications/settings/panel/PhabricatorMultiFactorSettingsPanel.php',
'PhabricatorMultimeterApplication' => 'applications/multimeter/application/PhabricatorMultimeterApplication.php',
'PhabricatorMustVerifyEmailController' => 'applications/auth/controller/PhabricatorMustVerifyEmailController.php',
+ 'PhabricatorMutedByEdgeType' => 'applications/transactions/edges/PhabricatorMutedByEdgeType.php',
+ 'PhabricatorMutedEdgeType' => 'applications/transactions/edges/PhabricatorMutedEdgeType.php',
'PhabricatorMySQLConfigOptions' => 'applications/config/option/PhabricatorMySQLConfigOptions.php',
'PhabricatorMySQLFileStorageEngine' => 'applications/files/engine/PhabricatorMySQLFileStorageEngine.php',
'PhabricatorMySQLSearchHost' => 'infrastructure/cluster/search/PhabricatorMySQLSearchHost.php',
@@ -4240,6 +4242,7 @@
'PhabricatorSubscriptionsHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsHeraldAction.php',
'PhabricatorSubscriptionsListController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsListController.php',
'PhabricatorSubscriptionsMailEngineExtension' => 'applications/subscriptions/engineextension/PhabricatorSubscriptionsMailEngineExtension.php',
+ 'PhabricatorSubscriptionsMuteController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsMuteController.php',
'PhabricatorSubscriptionsRemoveSelfHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsRemoveSelfHeraldAction.php',
'PhabricatorSubscriptionsRemoveSubscribersHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsRemoveSubscribersHeraldAction.php',
'PhabricatorSubscriptionsSearchEngineAttachment' => 'applications/subscriptions/engineextension/PhabricatorSubscriptionsSearchEngineAttachment.php',
@@ -8808,6 +8811,8 @@
'PhabricatorMultiFactorSettingsPanel' => 'PhabricatorSettingsPanel',
'PhabricatorMultimeterApplication' => 'PhabricatorApplication',
'PhabricatorMustVerifyEmailController' => 'PhabricatorAuthController',
+ 'PhabricatorMutedByEdgeType' => 'PhabricatorEdgeType',
+ 'PhabricatorMutedEdgeType' => 'PhabricatorEdgeType',
'PhabricatorMySQLConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorMySQLFileStorageEngine' => 'PhabricatorFileStorageEngine',
'PhabricatorMySQLSearchHost' => 'PhabricatorSearchHost',
@@ -9960,6 +9965,7 @@
'PhabricatorSubscriptionsHeraldAction' => 'HeraldAction',
'PhabricatorSubscriptionsListController' => 'PhabricatorController',
'PhabricatorSubscriptionsMailEngineExtension' => 'PhabricatorMailEngineExtension',
+ 'PhabricatorSubscriptionsMuteController' => 'PhabricatorController',
'PhabricatorSubscriptionsRemoveSelfHeraldAction' => 'PhabricatorSubscriptionsHeraldAction',
'PhabricatorSubscriptionsRemoveSubscribersHeraldAction' => 'PhabricatorSubscriptionsHeraldAction',
'PhabricatorSubscriptionsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
diff --git a/src/applications/metamta/query/PhabricatorMetaMTAActor.php b/src/applications/metamta/query/PhabricatorMetaMTAActor.php
--- a/src/applications/metamta/query/PhabricatorMetaMTAActor.php
+++ b/src/applications/metamta/query/PhabricatorMetaMTAActor.php
@@ -21,6 +21,7 @@
const REASON_ROUTE_AS_NOTIFICATION = 'route-as-notification';
const REASON_ROUTE_AS_MAIL = 'route-as-mail';
const REASON_UNVERIFIED = 'unverified';
+ const REASON_MUTED = 'muted';
private $phid;
private $emailAddress;
@@ -116,6 +117,7 @@
self::REASON_ROUTE_AS_NOTIFICATION => pht('Route as Notification'),
self::REASON_ROUTE_AS_MAIL => pht('Route as Mail'),
self::REASON_UNVERIFIED => pht('Address Not Verified'),
+ self::REASON_MUTED => pht('Muted'),
);
return idx($names, $reason, pht('Unknown ("%s")', $reason));
@@ -172,6 +174,8 @@
'in Herald.'),
self::REASON_UNVERIFIED => pht(
'This recipient does not have a verified primary email address.'),
+ self::REASON_MUTED => pht(
+ 'This recipient has muted notifications for this object.'),
);
return idx($descriptions, $reason, pht('Unknown Reason ("%s")', $reason));
diff --git a/src/applications/metamta/storage/PhabricatorMetaMTAMail.php b/src/applications/metamta/storage/PhabricatorMetaMTAMail.php
--- a/src/applications/metamta/storage/PhabricatorMetaMTAMail.php
+++ b/src/applications/metamta/storage/PhabricatorMetaMTAMail.php
@@ -160,6 +160,15 @@
return $this->getParam('exclude', array());
}
+ public function setMutedPHIDs(array $muted) {
+ $this->setParam('muted', $muted);
+ return $this;
+ }
+
+ private function getMutedPHIDs() {
+ return $this->getParam('muted', array());
+ }
+
public function setForceHeraldMailRecipientPHIDs(array $force) {
$this->setParam('herald-force-recipients', $force);
return $this;
@@ -1113,6 +1122,18 @@
}
}
+ // Exclude muted recipients. We're doing this after saving deliverability
+ // so that Herald "Send me an email" actions can still punch through a
+ // mute.
+
+ foreach ($this->getMutedPHIDs() as $muted_phid) {
+ $muted_actor = idx($actors, $muted_phid);
+ if (!$muted_actor) {
+ continue;
+ }
+ $muted_actor->setUndeliverable(PhabricatorMetaMTAActor::REASON_MUTED);
+ }
+
// For the rest of the rules, order matters. We're going to run all the
// possible rules in order from weakest to strongest, and let the strongest
// matching rule win. The weaker rules leave annotations behind which help
diff --git a/src/applications/subscriptions/application/PhabricatorSubscriptionsApplication.php b/src/applications/subscriptions/application/PhabricatorSubscriptionsApplication.php
--- a/src/applications/subscriptions/application/PhabricatorSubscriptionsApplication.php
+++ b/src/applications/subscriptions/application/PhabricatorSubscriptionsApplication.php
@@ -24,7 +24,10 @@
return array(
'/subscriptions/' => array(
'(?P<action>add|delete)/'.
- '(?P<phid>[^/]+)/' => 'PhabricatorSubscriptionsEditController',
+ '(?P<phid>[^/]+)/' => 'PhabricatorSubscriptionsEditController',
+ 'mute/' => array(
+ '(?P<phid>[^/]+)/' => 'PhabricatorSubscriptionsMuteController',
+ ),
'list/(?P<phid>[^/]+)/' => 'PhabricatorSubscriptionsListController',
'transaction/(?P<type>add|rem)/(?<phid>[^/]+)/'
=> 'PhabricatorSubscriptionsTransactionController',
diff --git a/src/applications/subscriptions/controller/PhabricatorSubscriptionsMuteController.php b/src/applications/subscriptions/controller/PhabricatorSubscriptionsMuteController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/subscriptions/controller/PhabricatorSubscriptionsMuteController.php
@@ -0,0 +1,92 @@
+<?php
+
+final class PhabricatorSubscriptionsMuteController
+ extends PhabricatorController {
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $request->getViewer();
+ $phid = $request->getURIData('phid');
+
+ $handle = id(new PhabricatorHandleQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($phid))
+ ->executeOne();
+
+ $object = id(new PhabricatorObjectQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($phid))
+ ->executeOne();
+
+ if (!($object instanceof PhabricatorSubscribableInterface)) {
+ return new Aphront400Response();
+ }
+
+ $muted_type = PhabricatorMutedByEdgeType::EDGECONST;
+
+ $edge_query = id(new PhabricatorEdgeQuery())
+ ->withSourcePHIDs(array($object->getPHID()))
+ ->withEdgeTypes(array($muted_type))
+ ->withDestinationPHIDs(array($viewer->getPHID()));
+
+ $edge_query->execute();
+
+ $is_mute = !$edge_query->getDestinationPHIDs();
+ $object_uri = $handle->getURI();
+
+ if ($request->isFormPost()) {
+ if ($is_mute) {
+ $xaction_value = array(
+ '+' => array_fuse(array($viewer->getPHID())),
+ );
+ } else {
+ $xaction_value = array(
+ '-' => array_fuse(array($viewer->getPHID())),
+ );
+ }
+
+ $muted_type = PhabricatorMutedByEdgeType::EDGECONST;
+
+ $xaction = id($object->getApplicationTransactionTemplate())
+ ->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
+ ->setMetadataValue('edge:type', $muted_type)
+ ->setNewValue($xaction_value);
+
+ $editor = id($object->getApplicationTransactionEditor())
+ ->setActor($viewer)
+ ->setContinueOnNoEffect(true)
+ ->setContinueOnMissingFields(true)
+ ->setContentSourceFromRequest($request);
+
+ $editor->applyTransactions(
+ $object->getApplicationTransactionObject(),
+ array($xaction));
+
+ return id(new AphrontReloadResponse())->setURI($object_uri);
+ }
+
+ $dialog = $this->newDialog()
+ ->addCancelButton($object_uri);
+
+ if ($is_mute) {
+ $dialog
+ ->setTitle(pht('Mute Notifications'))
+ ->appendParagraph(
+ pht(
+ 'Mute this object? You will no longer receive notifications or '.
+ 'email about it.'))
+ ->addSubmitButton(pht('Mute'));
+ } else {
+ $dialog
+ ->setTitle(pht('Unmute Notifications'))
+ ->appendParagraph(
+ pht(
+ 'Unmute this object? You will receive notifications and email '.
+ 'again.'))
+ ->addSubmitButton(pht('Unmute'));
+ }
+
+ return $dialog;
+ }
+
+
+}
diff --git a/src/applications/subscriptions/events/PhabricatorSubscriptionsUIEventListener.php b/src/applications/subscriptions/events/PhabricatorSubscriptionsUIEventListener.php
--- a/src/applications/subscriptions/events/PhabricatorSubscriptionsUIEventListener.php
+++ b/src/applications/subscriptions/events/PhabricatorSubscriptionsUIEventListener.php
@@ -42,6 +42,28 @@
return;
}
+ $src_phid = $object->getPHID();
+ $subscribed_type = PhabricatorObjectHasSubscriberEdgeType::EDGECONST;
+ $muted_type = PhabricatorMutedByEdgeType::EDGECONST;
+
+ $edges = id(new PhabricatorEdgeQuery())
+ ->withSourcePHIDs(array($src_phid))
+ ->withEdgeTypes(
+ array(
+ $subscribed_type,
+ $muted_type,
+ ))
+ ->withDestinationPHIDs(array($user_phid))
+ ->execute();
+
+ if ($user_phid) {
+ $is_subscribed = isset($edges[$src_phid][$subscribed_type][$user_phid]);
+ $is_muted = isset($edges[$src_phid][$muted_type][$user_phid]);
+ } else {
+ $is_subscribed = false;
+ $is_muted = false;
+ }
+
if ($user_phid && $object->isAutomaticallySubscribed($user_phid)) {
$sub_action = id(new PhabricatorActionView())
->setWorkflow(true)
@@ -51,22 +73,9 @@
->setName(pht('Automatically Subscribed'))
->setIcon('fa-check-circle lightgreytext');
} else {
- $subscribed = false;
- if ($user->isLoggedIn()) {
- $src_phid = $object->getPHID();
- $edge_type = PhabricatorObjectHasSubscriberEdgeType::EDGECONST;
-
- $edges = id(new PhabricatorEdgeQuery())
- ->withSourcePHIDs(array($src_phid))
- ->withEdgeTypes(array($edge_type))
- ->withDestinationPHIDs(array($user_phid))
- ->execute();
- $subscribed = isset($edges[$src_phid][$edge_type][$user_phid]);
- }
-
$can_interact = PhabricatorPolicyFilter::canInteract($user, $object);
- if ($subscribed) {
+ if ($is_subscribed) {
$sub_action = id(new PhabricatorActionView())
->setWorkflow(true)
->setRenderAsForm(true)
@@ -89,8 +98,26 @@
}
}
+ $mute_action = id(new PhabricatorActionView())
+ ->setWorkflow(true)
+ ->setHref('/subscriptions/mute/'.$object->getPHID().'/')
+ ->setDisabled(!$user_phid);
+
+ if (!$is_muted) {
+ $mute_action
+ ->setName(pht('Mute Notifications'))
+ ->setIcon('fa-volume-up');
+ } else {
+ $mute_action
+ ->setName(pht('Unmute Notifications'))
+ ->setIcon('fa-volume-off')
+ ->setColor(PhabricatorActionView::RED);
+ }
+
+
$actions = $event->getValue('actions');
$actions[] = $sub_action;
+ $actions[] = $mute_action;
$event->setValue('actions', $actions);
}
diff --git a/src/applications/transactions/edges/PhabricatorMutedByEdgeType.php b/src/applications/transactions/edges/PhabricatorMutedByEdgeType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/edges/PhabricatorMutedByEdgeType.php
@@ -0,0 +1,16 @@
+<?php
+
+final class PhabricatorMutedByEdgeType
+ extends PhabricatorEdgeType {
+
+ const EDGECONST = 68;
+
+ public function getInverseEdgeConstant() {
+ return PhabricatorMutedEdgeType::EDGECONST;
+ }
+
+ public function shouldWriteInverseTransactions() {
+ return true;
+ }
+
+}
diff --git a/src/applications/transactions/edges/PhabricatorMutedEdgeType.php b/src/applications/transactions/edges/PhabricatorMutedEdgeType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/transactions/edges/PhabricatorMutedEdgeType.php
@@ -0,0 +1,16 @@
+<?php
+
+final class PhabricatorMutedEdgeType
+ extends PhabricatorEdgeType {
+
+ const EDGECONST = 67;
+
+ public function getInverseEdgeConstant() {
+ return PhabricatorMutedByEdgeType::EDGECONST;
+ }
+
+ public function shouldWriteInverseTransactions() {
+ return true;
+ }
+
+}
diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
--- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
+++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
@@ -78,6 +78,7 @@
private $oldCC = array();
private $mailRemovedPHIDs = array();
private $mailUnexpandablePHIDs = array();
+ private $mailMutedPHIDs = array();
private $transactionQueue = array();
@@ -1211,6 +1212,14 @@
// but were removed by this change.
$this->applyOldRecipientLists();
+ if ($object instanceof PhabricatorSubscribableInterface) {
+ $this->mailMutedPHIDs = PhabricatorEdgeQuery::loadDestinationPHIDs(
+ $object->getPHID(),
+ PhabricatorMutedByEdgeType::EDGECONST);
+ } else {
+ $this->mailMutedPHIDs = array();
+ }
+
$mail_xactions = $this->getTransactionsForMail($object, $xactions);
$stamps = $this->newMailStamps($object, $xactions);
foreach ($stamps as $stamp) {
@@ -2662,6 +2671,11 @@
$mail_xactions);
}
+ $muted_phids = $this->mailMutedPHIDs;
+ if (!is_array($muted_phids)) {
+ $muted_phids = array();
+ }
+
$mail
->setSensitiveContent(false)
->setFrom($this->getActingAsPHID())
@@ -2670,6 +2684,7 @@
->setThreadID($this->getMailThreadID($object), $this->getIsNewObject())
->setRelatedPHID($object->getPHID())
->setExcludeMailRecipientPHIDs($this->getExcludeMailRecipientPHIDs())
+ ->setMutedPHIDs($muted_phids)
->setForceHeraldMailRecipientPHIDs($this->heraldForcedEmailPHIDs)
->setMailTags($mail_tags)
->setIsBulk(true)
@@ -3186,6 +3201,18 @@
$related_phids = $this->feedRelatedPHIDs;
$subscribed_phids = $this->feedNotifyPHIDs;
+ // Remove muted users from the subscription list so they don't get
+ // notifications, either.
+ $muted_phids = $this->mailMutedPHIDs;
+ if (!is_array($muted_phids)) {
+ $muted_phids = array();
+ }
+ $subscribed_phids = array_fuse($subscribed_phids);
+ foreach ($muted_phids as $muted_phid) {
+ unset($subscribed_phids[$muted_phid]);
+ }
+ $subscribed_phids = array_values($subscribed_phids);
+
$story_type = $this->getFeedStoryType();
$story_data = $this->getFeedStoryData($object, $xactions);
@@ -3632,6 +3659,7 @@
'mustEncrypt',
'mailStamps',
'mailUnexpandablePHIDs',
+ 'mailMutedPHIDs',
);
}
diff --git a/src/applications/transactions/storage/PhabricatorApplicationTransaction.php b/src/applications/transactions/storage/PhabricatorApplicationTransaction.php
--- a/src/applications/transactions/storage/PhabricatorApplicationTransaction.php
+++ b/src/applications/transactions/storage/PhabricatorApplicationTransaction.php
@@ -643,6 +643,8 @@
case PhabricatorObjectMentionsObjectEdgeType::EDGECONST:
case ManiphestTaskHasDuplicateTaskEdgeType::EDGECONST:
case ManiphestTaskIsDuplicateOfTaskEdgeType::EDGECONST:
+ case PhabricatorMutedEdgeType::EDGECONST:
+ case PhabricatorMutedByEdgeType::EDGECONST:
return true;
break;
case PhabricatorObjectMentionedByObjectEdgeType::EDGECONST:
diff --git a/src/view/layout/PhabricatorActionView.php b/src/view/layout/PhabricatorActionView.php
--- a/src/view/layout/PhabricatorActionView.php
+++ b/src/view/layout/PhabricatorActionView.php
@@ -21,6 +21,7 @@
private $order;
private $color;
private $type;
+ private $highlight;
const TYPE_DIVIDER = 'type-divider';
const TYPE_LABEL = 'label';
@@ -72,6 +73,15 @@
return $this->href;
}
+ public function setHighlight($highlight) {
+ $this->highlight = $highlight;
+ return $this;
+ }
+
+ public function getHighlight() {
+ return $this->highlight;
+ }
+
public function setIcon($icon) {
$this->icon = $icon;
return $this;
diff --git a/webroot/rsrc/css/phui/phui-action-list.css b/webroot/rsrc/css/phui/phui-action-list.css
--- a/webroot/rsrc/css/phui/phui-action-list.css
+++ b/webroot/rsrc/css/phui/phui-action-list.css
@@ -95,15 +95,20 @@
color: {$sky};
}
-.device-desktop .phabricator-action-view-href.action-item-red:hover
- .phabricator-action-view-item {
- background-color: {$sh-redbackground};
- color: {$sh-redtext};
+.phabricator-action-view.action-item-red {
+ background-color: {$sh-redbackground};
+}
+
+.phabricator-action-view.action-item-red .phabricator-action-view-item,
+.phabricator-action-view.action-item-red .phabricator-action-view-icon {
+ color: {$sh-redtext};
}
-.device-desktop .phabricator-action-view-href.action-item-red:hover
+.device-desktop .phabricator-action-view.action-item-red:hover
+ .phabricator-action-view-item,
+.device-desktop .phabricator-action-view.action-item-red:hover
.phabricator-action-view-icon {
- color: {$red};
+ color: {$red};
}
.phabricator-action-view-label .phabricator-action-view-item,
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Mar 16, 11:20 PM (1 w, 2 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7616377
Default Alt Text
D19033.diff (19 KB)
Attached To
Mode
D19033: Add "Mute/Unmute" for subscribable objects
Attached
Detach File
Event Timeline
Log In to Comment