Allow projects to be "watched", sort of a super-subscribe

Summary:
Ref T4967. Adds a "Watch" relationship to projects, which is stronger than member/subscribed.

Specifically, when a task is tagged with a project, we'll include all project watchers in the email/notifications. Normally we don't include projects unless they're explicitly CC'd, or have some other active role in the object (like being a reviewer or auditor).

This allows you to closely follow a project without needing to write a Herald rule for every project you care about.

Test Plan:
  - Watched/unwatched a project.
  - Tested the watch/subscribe/member relationships:
    - Watching implies subscribe.
    - Joining implies subscribe.
    - Leaving implies unsubscribe + unwatch.
    - You can't unsubscribe until you unwatch (slightly better would be unsubscribe implies unwatch, but this is a bit tricky).
  - Watched a project, then recevied email about a tagged task without otherwise being involved.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T4967

Differential Revision: https://secure.phabricator.com/D9185
This commit is contained in:
epriestley
2014-05-19 12:40:57 -07:00
parent af0edf883d
commit 3a31554268
10 changed files with 312 additions and 23 deletions

View File

@@ -21,6 +21,7 @@ final class PhabricatorProjectProfileController
->setViewer($user)
->withIDs(array($this->id))
->needMembers(true)
->needWatchers(true)
->needImages(true)
->executeOne();
if (!$project) {
@@ -222,14 +223,32 @@ final class PhabricatorProjectProfileController
->setIcon('fa-plus')
->setDisabled(!$can_join)
->setName(pht('Join Project'));
$view->addAction($action);
} else {
$action = id(new PhabricatorActionView())
->setWorkflow(true)
->setHref('/project/update/'.$project->getID().'/leave/')
->setIcon('fa-times')
->setName(pht('Leave Project...'));
$view->addAction($action);
if (!$project->isUserWatcher($viewer->getPHID())) {
$action = id(new PhabricatorActionView())
->setWorkflow(true)
->setHref('/project/watch/'.$project->getID().'/')
->setIcon('fa-eye')
->setName(pht('Watch Project'));
$view->addAction($action);
} else {
$action = id(new PhabricatorActionView())
->setWorkflow(true)
->setHref('/project/unwatch/'.$project->getID().'/')
->setIcon('fa-eye-slash')
->setName(pht('Unwatch Project'));
$view->addAction($action);
}
}
$view->addAction($action);
return $view;
}
@@ -240,7 +259,10 @@ final class PhabricatorProjectProfileController
$request = $this->getRequest();
$viewer = $request->getUser();
$this->loadHandles($project->getMemberPHIDs());
$this->loadHandles(
array_merge(
$project->getMemberPHIDs(),
$project->getWatcherPHIDs()));
$view = id(new PHUIPropertyListView())
->setUser($viewer)
@@ -250,8 +272,14 @@ final class PhabricatorProjectProfileController
$view->addProperty(
pht('Members'),
$project->getMemberPHIDs()
? $this->renderHandlesForPHIDs($project->getMemberPHIDs(), ',')
: phutil_tag('em', array(), pht('None')));
? $this->renderHandlesForPHIDs($project->getMemberPHIDs(), ',')
: phutil_tag('em', array(), pht('None')));
$view->addProperty(
pht('Watchers'),
$project->getWatcherPHIDs()
? $this->renderHandlesForPHIDs($project->getWatcherPHIDs(), ',')
: phutil_tag('em', array(), pht('None')));
$field_list = PhabricatorCustomField::getObjectFields(
$project,