Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F13984716
D15065.id36383.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
17 KB
Referenced Files
None
Subscribers
None
D15065.id36383.diff
View Options
diff --git a/resources/sql/autopatches/20160119.project.1.silence.sql b/resources/sql/autopatches/20160119.project.1.silence.sql
new file mode 100644
--- /dev/null
+++ b/resources/sql/autopatches/20160119.project.1.silence.sql
@@ -0,0 +1,8 @@
+/* PhabricatorObjectHasUnsubscriberEdgeType::EDGECONST = 23 */
+/* PhabricatorProjectSilencedEdgeType::EDGECONST = 61 */
+
+/* This is converting existing unsubscribes into disabled mail. */
+
+INSERT IGNORE INTO {$NAMESPACE}_project.edge (src, type, dst, dateCreated)
+ SELECT src, 61, dst, dateCreated FROM {$NAMESPACE}_project.edge
+ WHERE type = 23;
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
@@ -2925,6 +2925,8 @@
'PhabricatorProjectSchemaSpec' => 'applications/project/storage/PhabricatorProjectSchemaSpec.php',
'PhabricatorProjectSearchEngine' => 'applications/project/query/PhabricatorProjectSearchEngine.php',
'PhabricatorProjectSearchField' => 'applications/project/searchfield/PhabricatorProjectSearchField.php',
+ 'PhabricatorProjectSilenceController' => 'applications/project/controller/PhabricatorProjectSilenceController.php',
+ 'PhabricatorProjectSilencedEdgeType' => 'applications/project/edge/PhabricatorProjectSilencedEdgeType.php',
'PhabricatorProjectSlug' => 'applications/project/storage/PhabricatorProjectSlug.php',
'PhabricatorProjectStandardCustomField' => 'applications/project/customfield/PhabricatorProjectStandardCustomField.php',
'PhabricatorProjectStatus' => 'applications/project/constants/PhabricatorProjectStatus.php',
@@ -7237,7 +7239,6 @@
'PhabricatorFlaggableInterface',
'PhabricatorPolicyInterface',
'PhabricatorExtendedPolicyInterface',
- 'PhabricatorSubscribableInterface',
'PhabricatorCustomFieldInterface',
'PhabricatorDestructibleInterface',
'PhabricatorFulltextInterface',
@@ -7329,6 +7330,8 @@
'PhabricatorProjectSchemaSpec' => 'PhabricatorConfigSchemaSpec',
'PhabricatorProjectSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorProjectSearchField' => 'PhabricatorSearchTokenizerField',
+ 'PhabricatorProjectSilenceController' => 'PhabricatorProjectController',
+ 'PhabricatorProjectSilencedEdgeType' => 'PhabricatorEdgeType',
'PhabricatorProjectSlug' => 'PhabricatorProjectDAO',
'PhabricatorProjectStandardCustomField' => array(
'PhabricatorProjectCustomField',
diff --git a/src/applications/metamta/query/PhabricatorMetaMTAMemberQuery.php b/src/applications/metamta/query/PhabricatorMetaMTAMemberQuery.php
--- a/src/applications/metamta/query/PhabricatorMetaMTAMemberQuery.php
+++ b/src/applications/metamta/query/PhabricatorMetaMTAMemberQuery.php
@@ -42,20 +42,48 @@
$projects = id(new PhabricatorProjectQuery())
->setViewer($this->getViewer())
->withPHIDs($phids)
+ ->needMembers(true)
+ ->needWatchers(true)
->execute();
- $subscribers = id(new PhabricatorSubscribersQuery())
- ->withObjectPHIDs($phids)
- ->execute();
+ $edge_type = PhabricatorProjectSilencedEdgeType::EDGECONST;
+
+ $edge_query = id(new PhabricatorEdgeQuery())
+ ->withSourcePHIDs($phids)
+ ->withEdgeTypes(
+ array(
+ $edge_type,
+ ));
+
+ $edge_query->execute();
$projects = mpull($projects, null, 'getPHID');
foreach ($phids as $phid) {
$project = idx($projects, $phid);
+
if (!$project) {
$results[$phid] = array();
- } else {
- $results[$phid] = idx($subscribers, $phid, array());
+ continue;
}
+
+ // Recipients are members who haven't silenced the project, plus
+ // watchers.
+
+ $members = $project->getMemberPHIDs();
+ $members = array_fuse($members);
+
+ $watchers = $project->getWatcherPHIDs();
+ $watchers = array_fuse($watchers);
+
+ $silenced = $edge_query->getDestinationPHIDs(
+ array($phid),
+ array($edge_type));
+ $silenced = array_fuse($silenced);
+
+ $result_map = array_diff_key($members, $silenced);
+ $result_map = $result_map + $watchers;
+
+ $results[$phid] = array_values($result_map);
}
break;
default:
diff --git a/src/applications/project/application/PhabricatorProjectApplication.php b/src/applications/project/application/PhabricatorProjectApplication.php
--- a/src/applications/project/application/PhabricatorProjectApplication.php
+++ b/src/applications/project/application/PhabricatorProjectApplication.php
@@ -89,6 +89,8 @@
'history/(?P<id>[1-9]\d*)/' => 'PhabricatorProjectHistoryController',
'(?P<action>watch|unwatch)/(?P<id>[1-9]\d*)/'
=> 'PhabricatorProjectWatchController',
+ 'silence/(?P<id>[1-9]\d*)/'
+ => 'PhabricatorProjectSilenceController',
),
'/tag/' => array(
'(?P<slug>[^/]+)/' => 'PhabricatorProjectViewController',
diff --git a/src/applications/project/controller/PhabricatorProjectMembersViewController.php b/src/applications/project/controller/PhabricatorProjectMembersViewController.php
--- a/src/applications/project/controller/PhabricatorProjectMembersViewController.php
+++ b/src/applications/project/controller/PhabricatorProjectMembersViewController.php
@@ -110,6 +110,49 @@
$descriptions[PhabricatorPolicyCapability::CAN_JOIN]);
}
+ $viewer_phid = $viewer->getPHID();
+
+ if ($project->isUserWatcher($viewer_phid)) {
+ $watch_item = id(new PHUIStatusItemView())
+ ->setIcon('fa-eye green')
+ ->setTarget(phutil_tag('strong', array(), pht('Watching')))
+ ->setNote(
+ pht(
+ 'You will receive mail about changes made to any related '.
+ 'object.'));
+
+ $watch_status = id(new PHUIStatusListView())
+ ->addItem($watch_item);
+
+ $view->addProperty(pht('Watching'), $watch_status);
+ }
+
+ if ($project->isUserMember($viewer_phid)) {
+ $is_silenced = $this->isProjectSilenced($project);
+ if ($is_silenced) {
+ $mail_icon = 'fa-envelope-o grey';
+ $mail_target = pht('Disabled');
+ $mail_note = pht(
+ 'When mail is sent to project members, you will not receive '.
+ 'a copy.');
+ } else {
+ $mail_icon = 'fa-envelope-o green';
+ $mail_target = pht('Enabled');
+ $mail_note = pht(
+ 'You will receive mail that is sent to project members.');
+ }
+
+ $mail_item = id(new PHUIStatusItemView())
+ ->setIcon($mail_icon)
+ ->setTarget(phutil_tag('strong', array(), $mail_target))
+ ->setNote($mail_note);
+
+ $mail_status = id(new PHUIStatusListView())
+ ->addItem($mail_item);
+
+ $view->addProperty(pht('Mail to Members'), $mail_status);
+ }
+
return $view;
}
@@ -136,7 +179,9 @@
$can_leave = $supports_edit && (!$is_locked || $can_edit);
- if (!$project->isUserMember($viewer->getPHID())) {
+ $viewer_phid = $viewer->getPHID();
+
+ if (!$project->isUserMember($viewer_phid)) {
$view->addAction(
id(new PhabricatorActionView())
->setHref('/project/update/'.$project->getID().'/join/')
@@ -170,6 +215,23 @@
->setName(pht('Unwatch Project')));
}
+ $can_silence = $project->isUserMember($viewer_phid);
+ $is_silenced = $this->isProjectSilenced($project);
+
+ if ($is_silenced) {
+ $silence_text = pht('Enable Mail');
+ } else {
+ $silence_text = pht('Disable Mail');
+ }
+
+ $view->addAction(
+ id(new PhabricatorActionView())
+ ->setName($silence_text)
+ ->setIcon('fa-envelope-o')
+ ->setHref("/project/silence/{$id}/")
+ ->setWorkflow(true)
+ ->setDisabled(!$can_silence));
+
$can_add = $can_edit && $supports_edit;
$view->addAction(
@@ -202,4 +264,20 @@
return $view;
}
+ private function isProjectSilenced(PhabricatorProject $project) {
+ $viewer = $this->getViewer();
+
+ $viewer_phid = $viewer->getPHID();
+ if (!$viewer_phid) {
+ return false;
+ }
+
+ $edge_type = PhabricatorProjectSilencedEdgeType::EDGECONST;
+ $silenced = PhabricatorEdgeQuery::loadDestinationPHIDs(
+ $project->getPHID(),
+ $edge_type);
+ $silenced = array_fuse($silenced);
+ return isset($silenced[$viewer_phid]);
+ }
+
}
diff --git a/src/applications/project/controller/PhabricatorProjectSilenceController.php b/src/applications/project/controller/PhabricatorProjectSilenceController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/controller/PhabricatorProjectSilenceController.php
@@ -0,0 +1,87 @@
+<?php
+
+final class PhabricatorProjectSilenceController
+ extends PhabricatorProjectController {
+
+ public function handleRequest(AphrontRequest $request) {
+ $viewer = $request->getViewer();
+ $id = $request->getURIData('id');
+ $action = $request->getURIData('action');
+
+ $project = id(new PhabricatorProjectQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($id))
+ ->needMembers(true)
+ ->executeOne();
+ if (!$project) {
+ return new Aphront404Response();
+ }
+
+ $edge_type = PhabricatorProjectSilencedEdgeType::EDGECONST;
+ $done_uri = "/project/members/{$id}/";
+ $viewer_phid = $viewer->getPHID();
+
+ if (!$project->isUserMember($viewer_phid)) {
+ return $this->newDialog()
+ ->setTitle(pht('Not a Member'))
+ ->appendParagraph(
+ pht(
+ 'You are not a project member, so you do not receive mail sent '.
+ 'to members of this project.'))
+ ->addCancelButton($done_uri);
+ }
+
+ $silenced = PhabricatorEdgeQuery::loadDestinationPHIDs(
+ $project->getPHID(),
+ $edge_type);
+ $silenced = array_fuse($silenced);
+ $is_silenced = isset($silenced[$viewer_phid]);
+
+ if ($request->isDialogFormPost()) {
+ if ($is_silenced) {
+ $edge_action = '-';
+ } else {
+ $edge_action = '+';
+ }
+
+ $xactions = array();
+ $xactions[] = id(new PhabricatorProjectTransaction())
+ ->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
+ ->setMetadataValue('edge:type', $edge_type)
+ ->setNewValue(
+ array(
+ $edge_action => array($viewer_phid => $viewer_phid),
+ ));
+
+ $editor = id(new PhabricatorProjectTransactionEditor($project))
+ ->setActor($viewer)
+ ->setContentSourceFromRequest($request)
+ ->setContinueOnNoEffect(true)
+ ->setContinueOnMissingFields(true)
+ ->applyTransactions($project, $xactions);
+
+ return id(new AphrontRedirectResponse())->setURI($done_uri);
+ }
+
+ if ($is_silenced) {
+ $title = pht('Enable Mail');
+ $body = pht(
+ 'When mail is sent to members of this project, you will receive a '.
+ 'copy.');
+ $button = pht('Enable Project Mail');
+ } else {
+ $title = pht('Disable Mail');
+ $body = pht(
+ 'When mail is sent to members of this project, you will no longer '.
+ 'receive a copy.');
+ $button = pht('Disable Project Mail');
+ }
+
+ return $this->newDialog()
+ ->setTitle($title)
+ ->appendParagraph($body)
+ ->addCancelButton($done_uri)
+ ->addSubmitButton($button);
+ }
+
+}
diff --git a/src/applications/project/controller/PhabricatorProjectWatchController.php b/src/applications/project/controller/PhabricatorProjectWatchController.php
--- a/src/applications/project/controller/PhabricatorProjectWatchController.php
+++ b/src/applications/project/controller/PhabricatorProjectWatchController.php
@@ -30,11 +30,9 @@
switch ($action) {
case 'watch':
$edge_action = '+';
- $force_subscribe = true;
break;
case 'unwatch':
$edge_action = '-';
- $force_subscribe = false;
break;
}
diff --git a/src/applications/project/edge/PhabricatorProjectSilencedEdgeType.php b/src/applications/project/edge/PhabricatorProjectSilencedEdgeType.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/edge/PhabricatorProjectSilencedEdgeType.php
@@ -0,0 +1,8 @@
+<?php
+
+final class PhabricatorProjectSilencedEdgeType
+ extends PhabricatorEdgeType {
+
+ const EDGECONST = 61;
+
+}
diff --git a/src/applications/project/editor/PhabricatorProjectTransactionEditor.php b/src/applications/project/editor/PhabricatorProjectTransactionEditor.php
--- a/src/applications/project/editor/PhabricatorProjectTransactionEditor.php
+++ b/src/applications/project/editor/PhabricatorProjectTransactionEditor.php
@@ -178,51 +178,6 @@
return parent::applyCustomExternalTransaction($object, $xaction);
}
- protected function applyBuiltinExternalTransaction(
- PhabricatorLiskDAO $object,
- PhabricatorApplicationTransaction $xaction) {
-
- switch ($xaction->getTransactionType()) {
- case PhabricatorTransactions::TYPE_EDGE:
- $edge_type = $xaction->getMetadataValue('edge:type');
- switch ($edge_type) {
- case PhabricatorProjectProjectHasMemberEdgeType::EDGECONST:
- case PhabricatorObjectHasWatcherEdgeType::EDGECONST:
- $edge_const = PhabricatorProjectProjectHasMemberEdgeType::EDGECONST;
- if ($edge_type != $edge_const) {
- break;
- }
-
- $old = $xaction->getOldValue();
- $new = $xaction->getNewValue();
-
- // When adding members, we add subscriptions. When removing
- // members, we remove subscriptions.
- $add = array_keys(array_diff_key($new, $old));
- $rem = array_keys(array_diff_key($old, $new));
-
- // NOTE: The subscribe is "explicit" because there's no implicit
- // unsubscribe, so Join -> Leave -> Join doesn't resubscribe you
- // if we use an implicit subscribe, even though you never willfully
- // unsubscribed. Not sure if adding implicit unsubscribe (which
- // would not write the unsubscribe row) is justified to deal with
- // this, which is a fairly weird edge case and pretty arguable both
- // ways.
-
- id(new PhabricatorSubscriptionsEditor())
- ->setActor($this->requireActor())
- ->setObject($object)
- ->subscribeExplicit($add)
- ->unsubscribe($rem)
- ->save();
- break;
- }
- break;
- }
-
- return parent::applyBuiltinExternalTransaction($object, $xaction);
- }
-
protected function validateAllTransactions(
PhabricatorLiskDAO $object,
array $xactions) {
@@ -584,6 +539,10 @@
);
}
+ protected function getMailCc(PhabricatorLiskDAO $object) {
+ return array();
+ }
+
public function getMailTagsMap() {
return array(
PhabricatorProjectTransaction::MAILTAG_METADATA =>
@@ -592,8 +551,6 @@
pht('Project membership changes.'),
PhabricatorProjectTransaction::MAILTAG_WATCHERS =>
pht('Project watcher list changes.'),
- PhabricatorProjectTransaction::MAILTAG_SUBSCRIBERS =>
- pht('Project subscribers change.'),
PhabricatorProjectTransaction::MAILTAG_OTHER =>
pht('Other project activity not listed above occurs.'),
);
diff --git a/src/applications/project/engine/PhabricatorProjectEditEngine.php b/src/applications/project/engine/PhabricatorProjectEditEngine.php
--- a/src/applications/project/engine/PhabricatorProjectEditEngine.php
+++ b/src/applications/project/engine/PhabricatorProjectEditEngine.php
@@ -148,7 +148,6 @@
'icon',
'color',
'slugs',
- 'subscriberPHIDs',
));
return array(
diff --git a/src/applications/project/storage/PhabricatorProject.php b/src/applications/project/storage/PhabricatorProject.php
--- a/src/applications/project/storage/PhabricatorProject.php
+++ b/src/applications/project/storage/PhabricatorProject.php
@@ -6,7 +6,6 @@
PhabricatorFlaggableInterface,
PhabricatorPolicyInterface,
PhabricatorExtendedPolicyInterface,
- PhabricatorSubscribableInterface,
PhabricatorCustomFieldInterface,
PhabricatorDestructibleInterface,
PhabricatorFulltextInterface,
@@ -179,7 +178,6 @@
return $extended;
}
-
public function isUserMember($user_phid) {
if ($this->memberPHIDs !== self::ATTACHABLE) {
return in_array($user_phid, $this->memberPHIDs);
@@ -536,19 +534,6 @@
}
-
-/* -( PhabricatorSubscribableInterface )----------------------------------- */
-
-
- public function isAutomaticallySubscribed($phid) {
- return false;
- }
-
- public function shouldShowSubscribersProperty() {
- return false;
- }
-
-
/* -( PhabricatorCustomFieldInterface )------------------------------------ */
diff --git a/src/applications/project/storage/PhabricatorProjectTransaction.php b/src/applications/project/storage/PhabricatorProjectTransaction.php
--- a/src/applications/project/storage/PhabricatorProjectTransaction.php
+++ b/src/applications/project/storage/PhabricatorProjectTransaction.php
@@ -18,7 +18,6 @@
const MAILTAG_METADATA = 'project-metadata';
const MAILTAG_MEMBERS = 'project-members';
- const MAILTAG_SUBSCRIBERS = 'project-subscribers';
const MAILTAG_WATCHERS = 'project-watchers';
const MAILTAG_OTHER = 'project-other';
@@ -382,9 +381,6 @@
case self::TYPE_COLOR:
$tags[] = self::MAILTAG_METADATA;
break;
- case PhabricatorTransactions::TYPE_SUBSCRIBERS:
- $tags[] = self::MAILTAG_SUBSCRIBERS;
- break;
case PhabricatorTransactions::TYPE_EDGE:
$type = $this->getMetadata('edge:type');
$type = head($type);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Oct 21, 3:25 PM (3 w, 6 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6739594
Default Alt Text
D15065.id36383.diff (17 KB)
Attached To
Mode
D15065: Replace subscribe/unsubscribe for projects with explicit mail setting
Attached
Detach File
Event Timeline
Log In to Comment