1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-24 06:20:56 +01:00

Allow users to set notifications to "Email", "Notification", or "Ignore"

Summary:
Ref T5861. Ref T5769. If users don't care at all about something, allow them to ignore it.

We have some higher-volume notifications either built now (column changes) or coming (mentions) which users might reasonably want to ignore completely.

Test Plan:
Ignored some notifications, then took appropraite actions. Saw my user culled from the notification subscriber list.

{F189531}

Reviewers: chad, btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T5769, T5861

Differential Revision: https://secure.phabricator.com/D10240
This commit is contained in:
epriestley 2014-08-12 12:29:03 -07:00
parent f6f9d78f3a
commit c443913c0b
5 changed files with 123 additions and 43 deletions

View file

@ -11,7 +11,16 @@ final class PhabricatorFeedStoryPublisher {
private $subscribedPHIDs = array(); private $subscribedPHIDs = array();
private $mailRecipientPHIDs = array(); private $mailRecipientPHIDs = array();
private $notifyAuthor; private $notifyAuthor;
private $mailTags = array();
public function setMailTags(array $mail_tags) {
$this->mailTags = $mail_tags;
return $this;
}
public function getMailTags() {
return $this->mailTags;
}
public function setNotifyAuthor($notify_author) { public function setNotifyAuthor($notify_author) {
$this->notifyAuthor = $notify_author; $this->notifyAuthor = $notify_author;
@ -111,8 +120,12 @@ final class PhabricatorFeedStoryPublisher {
implode(', ', $sql)); implode(', ', $sql));
} }
$this->insertNotifications($chrono_key); $subscribed_phids = $this->subscribedPHIDs;
$this->sendNotification($chrono_key); $subscribed_phids = $this->filterSubscribedPHIDs($subscribed_phids);
if ($subscribed_phids) {
$this->insertNotifications($chrono_key, $subscribed_phids);
$this->sendNotification($chrono_key, $subscribed_phids);
}
PhabricatorWorker::scheduleTask( PhabricatorWorker::scheduleTask(
'FeedPublisherWorker', 'FeedPublisherWorker',
@ -123,19 +136,7 @@ final class PhabricatorFeedStoryPublisher {
return $story; return $story;
} }
private function insertNotifications($chrono_key) { private function insertNotifications($chrono_key, array $subscribed_phids) {
$subscribed_phids = $this->subscribedPHIDs;
if (!$this->notifyAuthor) {
$subscribed_phids = array_diff(
$subscribed_phids,
array($this->storyAuthorPHID));
}
if (!$subscribed_phids) {
return;
}
if (!$this->primaryObjectPHID) { if (!$this->primaryObjectPHID) {
throw new Exception( throw new Exception(
'You must call setPrimaryObjectPHID() if you setSubscribedPHIDs()!'); 'You must call setPrimaryObjectPHID() if you setSubscribedPHIDs()!');
@ -165,23 +166,71 @@ final class PhabricatorFeedStoryPublisher {
queryfx( queryfx(
$conn, $conn,
'INSERT INTO %T 'INSERT INTO %T (primaryObjectPHID, userPHID, chronologicalKey, hasViewed)
(primaryObjectPHID, userPHID, chronologicalKey, hasViewed) VALUES %Q',
VALUES %Q',
$notif->getTableName(), $notif->getTableName(),
implode(', ', $sql)); implode(', ', $sql));
} }
private function sendNotification($chrono_key) { private function sendNotification($chrono_key, array $subscribed_phids) {
$data = array( $data = array(
'key' => (string)$chrono_key, 'key' => (string)$chrono_key,
'type' => 'notification', 'type' => 'notification',
'subscribers' => array_values($this->subscribedPHIDs), 'subscribers' => $subscribed_phids,
); );
PhabricatorNotificationClient::tryToPostMessage($data); PhabricatorNotificationClient::tryToPostMessage($data);
} }
/**
* Remove PHIDs who should not receive notifications from a subscriber list.
*
* @param list<phid> List of potential subscribers.
* @return list<phid> List of actual subscribers.
*/
private function filterSubscribedPHIDs(array $phids) {
$tags = $this->getMailTags();
if ($tags) {
$all_prefs = id(new PhabricatorUserPreferences())->loadAllWhere(
'userPHID in (%Ls)',
$phids);
$all_prefs = mpull($all_prefs, null, 'getUserPHID');
}
$pref_default = PhabricatorUserPreferences::MAILTAG_PREFERENCE_EMAIL;
$pref_ignore = PhabricatorUserPreferences::MAILTAG_PREFERENCE_IGNORE;
$keep = array();
foreach ($phids as $phid) {
if (($phid == $this->storyAuthorPHID) && !$this->getNotifyAuthor()) {
continue;
}
if ($tags && isset($all_prefs[$phid])) {
$mailtags = $all_prefs[$phid]->getPreference(
PhabricatorUserPreferences::PREFERENCE_MAILTAGS,
array());
$notify = false;
foreach ($tags as $tag) {
// If this is set to "email" or "notify", notify the user.
if ((int)idx($mailtags, $tag, $pref_default) != $pref_ignore) {
$notify = true;
break;
}
}
if (!$notify) {
continue;
}
}
$keep[] = $phid;
}
return array_values(array_unique($keep));
}
/** /**
* We generate a unique chronological key for each story type because we want * We generate a unique chronological key for each story type because we want
* to be able to page through the stream with a cursor (i.e., select stories * to be able to page through the stream with a cursor (i.e., select stories

View file

@ -876,6 +876,8 @@ final class PhabricatorMetaMTAMail extends PhabricatorMetaMTADAO {
} }
} }
$value_email = PhabricatorUserPreferences::MAILTAG_PREFERENCE_EMAIL;
// Exclude all recipients who have set preferences to not receive this type // Exclude all recipients who have set preferences to not receive this type
// of email (for example, a user who says they don't want emails about task // of email (for example, a user who says they don't want emails about task
// CC changes). // CC changes).
@ -890,7 +892,7 @@ final class PhabricatorMetaMTAMail extends PhabricatorMetaMTADAO {
// of the mailtags. // of the mailtags.
$send = false; $send = false;
foreach ($tags as $tag) { foreach ($tags as $tag) {
if (idx($user_mailtags, $tag, true)) { if (((int)idx($user_mailtags, $tag, $value_email)) == $value_email) {
$send = true; $send = true;
break; break;
} }

View file

@ -23,6 +23,8 @@ final class PhabricatorSettingsPanelEmailPreferences
$pref_no_mail = PhabricatorUserPreferences::PREFERENCE_NO_MAIL; $pref_no_mail = PhabricatorUserPreferences::PREFERENCE_NO_MAIL;
$pref_no_self_mail = PhabricatorUserPreferences::PREFERENCE_NO_SELF_MAIL; $pref_no_self_mail = PhabricatorUserPreferences::PREFERENCE_NO_SELF_MAIL;
$value_email = PhabricatorUserPreferences::MAILTAG_PREFERENCE_EMAIL;
$errors = array(); $errors = array();
if ($request->isFormPost()) { if ($request->isFormPost()) {
$preferences->setPreference( $preferences->setPreference(
@ -38,7 +40,7 @@ final class PhabricatorSettingsPanelEmailPreferences
$all_tags = $this->getAllTags($user); $all_tags = $this->getAllTags($user);
foreach ($all_tags as $key => $label) { foreach ($all_tags as $key => $label) {
$mailtags[$key] = (bool)idx($new_tags, $key, false); $mailtags[$key] = (int)idx($new_tags, $key, $value_email);
} }
$preferences->setPreference('mailtags', $mailtags); $preferences->setPreference('mailtags', $mailtags);
@ -96,26 +98,24 @@ final class PhabricatorSettingsPanelEmailPreferences
$form->appendRemarkupInstructions( $form->appendRemarkupInstructions(
pht( pht(
'You can customize which kinds of events you receive email for '. 'You can adjust **Application Settings** here to customize when '.
'here. If you turn off email for a certain type of event, you '. 'you are emailed and notified.'.
'will receive an unread notification in Phabricator instead.'.
"\n\n". "\n\n".
'Phabricator notifications (shown in the menu bar) which you receive '. "| Setting | Effect\n".
'an email for are marked read by default in Phabricator. If you turn '. "| ------- | -------\n".
'off email for a certain type of event, the corresponding '. "| Email | You will receive an email and a notification, but the ".
'notification will not be marked read.'. "notification will be marked \"read\".\n".
"| Notify | You will receive an unread notification only.\n".
"| Ignore | You will receive nothing.\n".
"\n\n". "\n\n".
'Note that if an update makes several changes (like adding CCs to a '. 'If an update makes several changes (like adding CCs to a task, '.
'task, closing it, and adding a comment) you will still receive '. 'closing it, and adding a comment) you will receive the strongest '.
'an email as long as at least one of the changes is set to notify '. 'notification any of the changes is configured to deliver.'.
'you.'.
"\n\n". "\n\n".
'These preferences **only** apply to objects you are connected to '. 'These preferences **only** apply to objects you are connected to '.
'(for example, Revisions where you are a reviewer or tasks you are '. '(for example, Revisions where you are a reviewer or tasks you are '.
'CC\'d on). To receive email alerts when other objects are created, '. 'CC\'d on). To receive email alerts when other objects are created, '.
'configure [[ /herald/ | Herald Rules ]].'. 'configure [[ /herald/ | Herald Rules ]].'));
"\n\n".
'Phabricator will send an email to your primary account when:'));
$editors = $this->getAllEditorsWithTags($user); $editors = $this->getAllEditorsWithTags($user);
@ -216,16 +216,39 @@ final class PhabricatorSettingsPanelEmailPreferences
array $tags, array $tags,
array $prefs) { array $prefs) {
$control = new AphrontFormCheckboxControl(); $value_email = PhabricatorUserPreferences::MAILTAG_PREFERENCE_EMAIL;
$control->setLabel($control_label); $value_notify = PhabricatorUserPreferences::MAILTAG_PREFERENCE_NOTIFY;
$value_ignore = PhabricatorUserPreferences::MAILTAG_PREFERENCE_IGNORE;
$content = array();
foreach ($tags as $key => $label) { foreach ($tags as $key => $label) {
$control->addCheckbox( $select = AphrontFormSelectControl::renderSelectTag(
'mailtags['.$key.']', (int)idx($prefs, $key, $value_email),
1, array(
$label, $value_email => pht("\xE2\x9A\xAB Email"),
idx($prefs, $key, 1)); $value_notify => pht("\xE2\x97\x90 Notify"),
$value_ignore => pht("\xE2\x9A\xAA Ignore"),
),
array(
'name' => 'mailtags['.$key.']',
));
$content[] = phutil_tag(
'div',
array(
'class' => 'psb',
),
array(
$select,
' ',
$label,
));
} }
$control = new AphrontFormStaticControl();
$control->setLabel($control_label);
$control->setValue($content);
return $control; return $control;
} }

View file

@ -31,6 +31,11 @@ final class PhabricatorUserPreferences extends PhabricatorUserDAO {
const PREFERENCE_CONPH_NOTIFICATIONS = 'conph-notifications'; const PREFERENCE_CONPH_NOTIFICATIONS = 'conph-notifications';
// These are in an unusual order for historic reasons.
const MAILTAG_PREFERENCE_NOTIFY = 0;
const MAILTAG_PREFERENCE_EMAIL = 1;
const MAILTAG_PREFERENCE_IGNORE = 2;
protected $userPHID; protected $userPHID;
protected $preferences = array(); protected $preferences = array();

View file

@ -2203,6 +2203,7 @@ abstract class PhabricatorApplicationTransactionEditor
->setPrimaryObjectPHID($object->getPHID()) ->setPrimaryObjectPHID($object->getPHID())
->setSubscribedPHIDs($subscribed_phids) ->setSubscribedPHIDs($subscribed_phids)
->setMailRecipientPHIDs($mailed_phids) ->setMailRecipientPHIDs($mailed_phids)
->setMailTags($this->getMailTags($object, $xactions))
->publish(); ->publish();
} }