mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-26 08:42:41 +01:00
Add "Mute/Unmute" for subscribable objects
Summary: Ref T13053. See PHI126. Add an explicit "Mute" action to kill mail and notifications for a particular object. Test Plan: Muted and umuted an object while interacting with it. Saw mail route appropriately. Maniphest Tasks: T13053 Differential Revision: https://secure.phabricator.com/D19033
This commit is contained in:
parent
0402a79e0e
commit
ab04d2179b
13 changed files with 254 additions and 24 deletions
|
@ -9,7 +9,7 @@ return array(
|
||||||
'names' => array(
|
'names' => array(
|
||||||
'conpherence.pkg.css' => 'e68cf1fa',
|
'conpherence.pkg.css' => 'e68cf1fa',
|
||||||
'conpherence.pkg.js' => '15191c65',
|
'conpherence.pkg.js' => '15191c65',
|
||||||
'core.pkg.css' => '51debec3',
|
'core.pkg.css' => 'ce8c2a58',
|
||||||
'core.pkg.js' => '4c79d74f',
|
'core.pkg.js' => '4c79d74f',
|
||||||
'darkconsole.pkg.js' => '1f9a31bc',
|
'darkconsole.pkg.js' => '1f9a31bc',
|
||||||
'differential.pkg.css' => '45951e9e',
|
'differential.pkg.css' => '45951e9e',
|
||||||
|
@ -136,7 +136,7 @@ return array(
|
||||||
'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '9d9685d6',
|
'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-list-view.css' => '6ae18df0',
|
||||||
'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => 'a8beebea',
|
'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-action-panel.css' => 'b4798122',
|
||||||
'rsrc/css/phui/phui-badge.css' => '22c0cf4f',
|
'rsrc/css/phui/phui-badge.css' => '22c0cf4f',
|
||||||
'rsrc/css/phui/phui-basic-nav-view.css' => '98c11ab3',
|
'rsrc/css/phui/phui-basic-nav-view.css' => '98c11ab3',
|
||||||
|
@ -766,7 +766,7 @@ return array(
|
||||||
'path-typeahead' => 'f7fc67ec',
|
'path-typeahead' => 'f7fc67ec',
|
||||||
'people-picture-menu-item-css' => 'a06f7f34',
|
'people-picture-menu-item-css' => 'a06f7f34',
|
||||||
'people-profile-css' => '4df76faf',
|
'people-profile-css' => '4df76faf',
|
||||||
'phabricator-action-list-view-css' => 'f7f61a34',
|
'phabricator-action-list-view-css' => '0bcd9a45',
|
||||||
'phabricator-busy' => '59a7976a',
|
'phabricator-busy' => '59a7976a',
|
||||||
'phabricator-chatlog-css' => 'd295b020',
|
'phabricator-chatlog-css' => 'd295b020',
|
||||||
'phabricator-content-source-view-css' => '4b8b05d4',
|
'phabricator-content-source-view-css' => '4b8b05d4',
|
||||||
|
|
|
@ -3291,6 +3291,8 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorMultiFactorSettingsPanel' => 'applications/settings/panel/PhabricatorMultiFactorSettingsPanel.php',
|
'PhabricatorMultiFactorSettingsPanel' => 'applications/settings/panel/PhabricatorMultiFactorSettingsPanel.php',
|
||||||
'PhabricatorMultimeterApplication' => 'applications/multimeter/application/PhabricatorMultimeterApplication.php',
|
'PhabricatorMultimeterApplication' => 'applications/multimeter/application/PhabricatorMultimeterApplication.php',
|
||||||
'PhabricatorMustVerifyEmailController' => 'applications/auth/controller/PhabricatorMustVerifyEmailController.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',
|
'PhabricatorMySQLConfigOptions' => 'applications/config/option/PhabricatorMySQLConfigOptions.php',
|
||||||
'PhabricatorMySQLFileStorageEngine' => 'applications/files/engine/PhabricatorMySQLFileStorageEngine.php',
|
'PhabricatorMySQLFileStorageEngine' => 'applications/files/engine/PhabricatorMySQLFileStorageEngine.php',
|
||||||
'PhabricatorMySQLSearchHost' => 'infrastructure/cluster/search/PhabricatorMySQLSearchHost.php',
|
'PhabricatorMySQLSearchHost' => 'infrastructure/cluster/search/PhabricatorMySQLSearchHost.php',
|
||||||
|
@ -4240,6 +4242,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSubscriptionsHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsHeraldAction.php',
|
'PhabricatorSubscriptionsHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsHeraldAction.php',
|
||||||
'PhabricatorSubscriptionsListController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsListController.php',
|
'PhabricatorSubscriptionsListController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsListController.php',
|
||||||
'PhabricatorSubscriptionsMailEngineExtension' => 'applications/subscriptions/engineextension/PhabricatorSubscriptionsMailEngineExtension.php',
|
'PhabricatorSubscriptionsMailEngineExtension' => 'applications/subscriptions/engineextension/PhabricatorSubscriptionsMailEngineExtension.php',
|
||||||
|
'PhabricatorSubscriptionsMuteController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsMuteController.php',
|
||||||
'PhabricatorSubscriptionsRemoveSelfHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsRemoveSelfHeraldAction.php',
|
'PhabricatorSubscriptionsRemoveSelfHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsRemoveSelfHeraldAction.php',
|
||||||
'PhabricatorSubscriptionsRemoveSubscribersHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsRemoveSubscribersHeraldAction.php',
|
'PhabricatorSubscriptionsRemoveSubscribersHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsRemoveSubscribersHeraldAction.php',
|
||||||
'PhabricatorSubscriptionsSearchEngineAttachment' => 'applications/subscriptions/engineextension/PhabricatorSubscriptionsSearchEngineAttachment.php',
|
'PhabricatorSubscriptionsSearchEngineAttachment' => 'applications/subscriptions/engineextension/PhabricatorSubscriptionsSearchEngineAttachment.php',
|
||||||
|
@ -8808,6 +8811,8 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorMultiFactorSettingsPanel' => 'PhabricatorSettingsPanel',
|
'PhabricatorMultiFactorSettingsPanel' => 'PhabricatorSettingsPanel',
|
||||||
'PhabricatorMultimeterApplication' => 'PhabricatorApplication',
|
'PhabricatorMultimeterApplication' => 'PhabricatorApplication',
|
||||||
'PhabricatorMustVerifyEmailController' => 'PhabricatorAuthController',
|
'PhabricatorMustVerifyEmailController' => 'PhabricatorAuthController',
|
||||||
|
'PhabricatorMutedByEdgeType' => 'PhabricatorEdgeType',
|
||||||
|
'PhabricatorMutedEdgeType' => 'PhabricatorEdgeType',
|
||||||
'PhabricatorMySQLConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
'PhabricatorMySQLConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||||
'PhabricatorMySQLFileStorageEngine' => 'PhabricatorFileStorageEngine',
|
'PhabricatorMySQLFileStorageEngine' => 'PhabricatorFileStorageEngine',
|
||||||
'PhabricatorMySQLSearchHost' => 'PhabricatorSearchHost',
|
'PhabricatorMySQLSearchHost' => 'PhabricatorSearchHost',
|
||||||
|
@ -9960,6 +9965,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSubscriptionsHeraldAction' => 'HeraldAction',
|
'PhabricatorSubscriptionsHeraldAction' => 'HeraldAction',
|
||||||
'PhabricatorSubscriptionsListController' => 'PhabricatorController',
|
'PhabricatorSubscriptionsListController' => 'PhabricatorController',
|
||||||
'PhabricatorSubscriptionsMailEngineExtension' => 'PhabricatorMailEngineExtension',
|
'PhabricatorSubscriptionsMailEngineExtension' => 'PhabricatorMailEngineExtension',
|
||||||
|
'PhabricatorSubscriptionsMuteController' => 'PhabricatorController',
|
||||||
'PhabricatorSubscriptionsRemoveSelfHeraldAction' => 'PhabricatorSubscriptionsHeraldAction',
|
'PhabricatorSubscriptionsRemoveSelfHeraldAction' => 'PhabricatorSubscriptionsHeraldAction',
|
||||||
'PhabricatorSubscriptionsRemoveSubscribersHeraldAction' => 'PhabricatorSubscriptionsHeraldAction',
|
'PhabricatorSubscriptionsRemoveSubscribersHeraldAction' => 'PhabricatorSubscriptionsHeraldAction',
|
||||||
'PhabricatorSubscriptionsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
'PhabricatorSubscriptionsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
|
||||||
|
|
|
@ -21,6 +21,7 @@ final class PhabricatorMetaMTAActor extends Phobject {
|
||||||
const REASON_ROUTE_AS_NOTIFICATION = 'route-as-notification';
|
const REASON_ROUTE_AS_NOTIFICATION = 'route-as-notification';
|
||||||
const REASON_ROUTE_AS_MAIL = 'route-as-mail';
|
const REASON_ROUTE_AS_MAIL = 'route-as-mail';
|
||||||
const REASON_UNVERIFIED = 'unverified';
|
const REASON_UNVERIFIED = 'unverified';
|
||||||
|
const REASON_MUTED = 'muted';
|
||||||
|
|
||||||
private $phid;
|
private $phid;
|
||||||
private $emailAddress;
|
private $emailAddress;
|
||||||
|
@ -116,6 +117,7 @@ final class PhabricatorMetaMTAActor extends Phobject {
|
||||||
self::REASON_ROUTE_AS_NOTIFICATION => pht('Route as Notification'),
|
self::REASON_ROUTE_AS_NOTIFICATION => pht('Route as Notification'),
|
||||||
self::REASON_ROUTE_AS_MAIL => pht('Route as Mail'),
|
self::REASON_ROUTE_AS_MAIL => pht('Route as Mail'),
|
||||||
self::REASON_UNVERIFIED => pht('Address Not Verified'),
|
self::REASON_UNVERIFIED => pht('Address Not Verified'),
|
||||||
|
self::REASON_MUTED => pht('Muted'),
|
||||||
);
|
);
|
||||||
|
|
||||||
return idx($names, $reason, pht('Unknown ("%s")', $reason));
|
return idx($names, $reason, pht('Unknown ("%s")', $reason));
|
||||||
|
@ -172,6 +174,8 @@ final class PhabricatorMetaMTAActor extends Phobject {
|
||||||
'in Herald.'),
|
'in Herald.'),
|
||||||
self::REASON_UNVERIFIED => pht(
|
self::REASON_UNVERIFIED => pht(
|
||||||
'This recipient does not have a verified primary email address.'),
|
'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));
|
return idx($descriptions, $reason, pht('Unknown Reason ("%s")', $reason));
|
||||||
|
|
|
@ -160,6 +160,15 @@ final class PhabricatorMetaMTAMail
|
||||||
return $this->getParam('exclude', array());
|
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) {
|
public function setForceHeraldMailRecipientPHIDs(array $force) {
|
||||||
$this->setParam('herald-force-recipients', $force);
|
$this->setParam('herald-force-recipients', $force);
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -1113,6 +1122,18 @@ final class PhabricatorMetaMTAMail
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
// 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
|
// possible rules in order from weakest to strongest, and let the strongest
|
||||||
// matching rule win. The weaker rules leave annotations behind which help
|
// matching rule win. The weaker rules leave annotations behind which help
|
||||||
|
|
|
@ -25,6 +25,9 @@ final class PhabricatorSubscriptionsApplication extends PhabricatorApplication {
|
||||||
'/subscriptions/' => array(
|
'/subscriptions/' => array(
|
||||||
'(?P<action>add|delete)/'.
|
'(?P<action>add|delete)/'.
|
||||||
'(?P<phid>[^/]+)/' => 'PhabricatorSubscriptionsEditController',
|
'(?P<phid>[^/]+)/' => 'PhabricatorSubscriptionsEditController',
|
||||||
|
'mute/' => array(
|
||||||
|
'(?P<phid>[^/]+)/' => 'PhabricatorSubscriptionsMuteController',
|
||||||
|
),
|
||||||
'list/(?P<phid>[^/]+)/' => 'PhabricatorSubscriptionsListController',
|
'list/(?P<phid>[^/]+)/' => 'PhabricatorSubscriptionsListController',
|
||||||
'transaction/(?P<type>add|rem)/(?<phid>[^/]+)/'
|
'transaction/(?P<type>add|rem)/(?<phid>[^/]+)/'
|
||||||
=> 'PhabricatorSubscriptionsTransactionController',
|
=> 'PhabricatorSubscriptionsTransactionController',
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -42,6 +42,28 @@ final class PhabricatorSubscriptionsUIEventListener
|
||||||
return;
|
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)) {
|
if ($user_phid && $object->isAutomaticallySubscribed($user_phid)) {
|
||||||
$sub_action = id(new PhabricatorActionView())
|
$sub_action = id(new PhabricatorActionView())
|
||||||
->setWorkflow(true)
|
->setWorkflow(true)
|
||||||
|
@ -51,22 +73,9 @@ final class PhabricatorSubscriptionsUIEventListener
|
||||||
->setName(pht('Automatically Subscribed'))
|
->setName(pht('Automatically Subscribed'))
|
||||||
->setIcon('fa-check-circle lightgreytext');
|
->setIcon('fa-check-circle lightgreytext');
|
||||||
} else {
|
} 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);
|
$can_interact = PhabricatorPolicyFilter::canInteract($user, $object);
|
||||||
|
|
||||||
if ($subscribed) {
|
if ($is_subscribed) {
|
||||||
$sub_action = id(new PhabricatorActionView())
|
$sub_action = id(new PhabricatorActionView())
|
||||||
->setWorkflow(true)
|
->setWorkflow(true)
|
||||||
->setRenderAsForm(true)
|
->setRenderAsForm(true)
|
||||||
|
@ -89,8 +98,26 @@ final class PhabricatorSubscriptionsUIEventListener
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$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 = $event->getValue('actions');
|
||||||
$actions[] = $sub_action;
|
$actions[] = $sub_action;
|
||||||
|
$actions[] = $mute_action;
|
||||||
$event->setValue('actions', $actions);
|
$event->setValue('actions', $actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorMutedByEdgeType
|
||||||
|
extends PhabricatorEdgeType {
|
||||||
|
|
||||||
|
const EDGECONST = 68;
|
||||||
|
|
||||||
|
public function getInverseEdgeConstant() {
|
||||||
|
return PhabricatorMutedEdgeType::EDGECONST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shouldWriteInverseTransactions() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorMutedEdgeType
|
||||||
|
extends PhabricatorEdgeType {
|
||||||
|
|
||||||
|
const EDGECONST = 67;
|
||||||
|
|
||||||
|
public function getInverseEdgeConstant() {
|
||||||
|
return PhabricatorMutedByEdgeType::EDGECONST;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shouldWriteInverseTransactions() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -78,6 +78,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
private $oldCC = array();
|
private $oldCC = array();
|
||||||
private $mailRemovedPHIDs = array();
|
private $mailRemovedPHIDs = array();
|
||||||
private $mailUnexpandablePHIDs = array();
|
private $mailUnexpandablePHIDs = array();
|
||||||
|
private $mailMutedPHIDs = array();
|
||||||
|
|
||||||
private $transactionQueue = array();
|
private $transactionQueue = array();
|
||||||
|
|
||||||
|
@ -1211,6 +1212,14 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
// but were removed by this change.
|
// but were removed by this change.
|
||||||
$this->applyOldRecipientLists();
|
$this->applyOldRecipientLists();
|
||||||
|
|
||||||
|
if ($object instanceof PhabricatorSubscribableInterface) {
|
||||||
|
$this->mailMutedPHIDs = PhabricatorEdgeQuery::loadDestinationPHIDs(
|
||||||
|
$object->getPHID(),
|
||||||
|
PhabricatorMutedByEdgeType::EDGECONST);
|
||||||
|
} else {
|
||||||
|
$this->mailMutedPHIDs = array();
|
||||||
|
}
|
||||||
|
|
||||||
$mail_xactions = $this->getTransactionsForMail($object, $xactions);
|
$mail_xactions = $this->getTransactionsForMail($object, $xactions);
|
||||||
$stamps = $this->newMailStamps($object, $xactions);
|
$stamps = $this->newMailStamps($object, $xactions);
|
||||||
foreach ($stamps as $stamp) {
|
foreach ($stamps as $stamp) {
|
||||||
|
@ -2662,6 +2671,11 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
$mail_xactions);
|
$mail_xactions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$muted_phids = $this->mailMutedPHIDs;
|
||||||
|
if (!is_array($muted_phids)) {
|
||||||
|
$muted_phids = array();
|
||||||
|
}
|
||||||
|
|
||||||
$mail
|
$mail
|
||||||
->setSensitiveContent(false)
|
->setSensitiveContent(false)
|
||||||
->setFrom($this->getActingAsPHID())
|
->setFrom($this->getActingAsPHID())
|
||||||
|
@ -2670,6 +2684,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
->setThreadID($this->getMailThreadID($object), $this->getIsNewObject())
|
->setThreadID($this->getMailThreadID($object), $this->getIsNewObject())
|
||||||
->setRelatedPHID($object->getPHID())
|
->setRelatedPHID($object->getPHID())
|
||||||
->setExcludeMailRecipientPHIDs($this->getExcludeMailRecipientPHIDs())
|
->setExcludeMailRecipientPHIDs($this->getExcludeMailRecipientPHIDs())
|
||||||
|
->setMutedPHIDs($muted_phids)
|
||||||
->setForceHeraldMailRecipientPHIDs($this->heraldForcedEmailPHIDs)
|
->setForceHeraldMailRecipientPHIDs($this->heraldForcedEmailPHIDs)
|
||||||
->setMailTags($mail_tags)
|
->setMailTags($mail_tags)
|
||||||
->setIsBulk(true)
|
->setIsBulk(true)
|
||||||
|
@ -3186,6 +3201,18 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
$related_phids = $this->feedRelatedPHIDs;
|
$related_phids = $this->feedRelatedPHIDs;
|
||||||
$subscribed_phids = $this->feedNotifyPHIDs;
|
$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_type = $this->getFeedStoryType();
|
||||||
$story_data = $this->getFeedStoryData($object, $xactions);
|
$story_data = $this->getFeedStoryData($object, $xactions);
|
||||||
|
|
||||||
|
@ -3632,6 +3659,7 @@ abstract class PhabricatorApplicationTransactionEditor
|
||||||
'mustEncrypt',
|
'mustEncrypt',
|
||||||
'mailStamps',
|
'mailStamps',
|
||||||
'mailUnexpandablePHIDs',
|
'mailUnexpandablePHIDs',
|
||||||
|
'mailMutedPHIDs',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -643,6 +643,8 @@ abstract class PhabricatorApplicationTransaction
|
||||||
case PhabricatorObjectMentionsObjectEdgeType::EDGECONST:
|
case PhabricatorObjectMentionsObjectEdgeType::EDGECONST:
|
||||||
case ManiphestTaskHasDuplicateTaskEdgeType::EDGECONST:
|
case ManiphestTaskHasDuplicateTaskEdgeType::EDGECONST:
|
||||||
case ManiphestTaskIsDuplicateOfTaskEdgeType::EDGECONST:
|
case ManiphestTaskIsDuplicateOfTaskEdgeType::EDGECONST:
|
||||||
|
case PhabricatorMutedEdgeType::EDGECONST:
|
||||||
|
case PhabricatorMutedByEdgeType::EDGECONST:
|
||||||
return true;
|
return true;
|
||||||
break;
|
break;
|
||||||
case PhabricatorObjectMentionedByObjectEdgeType::EDGECONST:
|
case PhabricatorObjectMentionedByObjectEdgeType::EDGECONST:
|
||||||
|
|
|
@ -21,6 +21,7 @@ final class PhabricatorActionView extends AphrontView {
|
||||||
private $order;
|
private $order;
|
||||||
private $color;
|
private $color;
|
||||||
private $type;
|
private $type;
|
||||||
|
private $highlight;
|
||||||
|
|
||||||
const TYPE_DIVIDER = 'type-divider';
|
const TYPE_DIVIDER = 'type-divider';
|
||||||
const TYPE_LABEL = 'label';
|
const TYPE_LABEL = 'label';
|
||||||
|
@ -72,6 +73,15 @@ final class PhabricatorActionView extends AphrontView {
|
||||||
return $this->href;
|
return $this->href;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setHighlight($highlight) {
|
||||||
|
$this->highlight = $highlight;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHighlight() {
|
||||||
|
return $this->highlight;
|
||||||
|
}
|
||||||
|
|
||||||
public function setIcon($icon) {
|
public function setIcon($icon) {
|
||||||
$this->icon = $icon;
|
$this->icon = $icon;
|
||||||
return $this;
|
return $this;
|
||||||
|
|
|
@ -95,13 +95,18 @@
|
||||||
color: {$sky};
|
color: {$sky};
|
||||||
}
|
}
|
||||||
|
|
||||||
.device-desktop .phabricator-action-view-href.action-item-red:hover
|
.phabricator-action-view.action-item-red {
|
||||||
.phabricator-action-view-item {
|
|
||||||
background-color: {$sh-redbackground};
|
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};
|
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 {
|
.phabricator-action-view-icon {
|
||||||
color: {$red};
|
color: {$red};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue