2016-01-20 01:27:36 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
final class PhabricatorProjectMembersViewController
|
|
|
|
extends PhabricatorProjectController {
|
|
|
|
|
|
|
|
public function handleRequest(AphrontRequest $request) {
|
|
|
|
$viewer = $request->getViewer();
|
|
|
|
$id = $request->getURIData('id');
|
|
|
|
|
|
|
|
$project = id(new PhabricatorProjectQuery())
|
|
|
|
->setViewer($viewer)
|
|
|
|
->withIDs(array($id))
|
|
|
|
->needMembers(true)
|
|
|
|
->needWatchers(true)
|
|
|
|
->needImages(true)
|
|
|
|
->executeOne();
|
|
|
|
if (!$project) {
|
|
|
|
return new Aphront404Response();
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->setProject($project);
|
|
|
|
$title = pht('Members and Watchers');
|
|
|
|
|
|
|
|
$properties = $this->buildProperties($project);
|
2016-04-14 20:26:43 +02:00
|
|
|
$curtain = $this->buildCurtainView($project);
|
2016-01-20 01:27:36 +01:00
|
|
|
|
|
|
|
$object_box = id(new PHUIObjectBoxView())
|
2016-04-14 20:26:43 +02:00
|
|
|
->setHeaderText(pht('Details'))
|
|
|
|
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
2016-01-20 01:27:36 +01:00
|
|
|
->addPropertyList($properties);
|
|
|
|
|
|
|
|
$member_list = id(new PhabricatorProjectMemberListView())
|
|
|
|
->setUser($viewer)
|
|
|
|
->setProject($project)
|
2016-04-14 20:26:43 +02:00
|
|
|
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
2016-01-20 01:27:36 +01:00
|
|
|
->setUserPHIDs($project->getMemberPHIDs());
|
|
|
|
|
|
|
|
$watcher_list = id(new PhabricatorProjectWatcherListView())
|
|
|
|
->setUser($viewer)
|
|
|
|
->setProject($project)
|
2016-04-14 20:26:43 +02:00
|
|
|
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
2016-01-20 01:27:36 +01:00
|
|
|
->setUserPHIDs($project->getWatcherPHIDs());
|
|
|
|
|
|
|
|
$nav = $this->getProfileMenu();
|
|
|
|
$nav->selectFilter(PhabricatorProject::PANEL_MEMBERS);
|
|
|
|
|
|
|
|
$crumbs = $this->buildApplicationCrumbs();
|
|
|
|
$crumbs->addTextCrumb(pht('Members'));
|
2016-04-14 20:26:43 +02:00
|
|
|
$crumbs->setBorder(true);
|
|
|
|
|
|
|
|
$header = id(new PHUIHeaderView())
|
|
|
|
->setHeader($title)
|
|
|
|
->setHeaderIcon('fa-group');
|
|
|
|
|
|
|
|
$view = id(new PHUITwoColumnView())
|
|
|
|
->setHeader($header)
|
|
|
|
->setCurtain($curtain)
|
|
|
|
->setMainColumn(array(
|
|
|
|
$object_box,
|
|
|
|
$member_list,
|
|
|
|
$watcher_list,
|
|
|
|
));
|
|
|
|
|
2016-01-20 01:27:36 +01:00
|
|
|
|
|
|
|
return $this->newPage()
|
|
|
|
->setNavigation($nav)
|
|
|
|
->setCrumbs($crumbs)
|
2016-04-14 20:26:43 +02:00
|
|
|
->setTitle(array($project->getName(), $title))
|
|
|
|
->appendChild($view);
|
2016-01-20 01:27:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private function buildProperties(PhabricatorProject $project) {
|
|
|
|
$viewer = $this->getViewer();
|
|
|
|
|
|
|
|
$view = id(new PHUIPropertyListView())
|
|
|
|
->setUser($viewer)
|
|
|
|
->setObject($project);
|
|
|
|
|
|
|
|
if ($project->isMilestone()) {
|
|
|
|
$icon_key = PhabricatorProjectIconSet::getMilestoneIconKey();
|
|
|
|
$icon = PhabricatorProjectIconSet::getIconIcon($icon_key);
|
|
|
|
$target = PhabricatorProjectIconSet::getIconName($icon_key);
|
|
|
|
$note = pht(
|
|
|
|
'Members of the parent project are members of this project.');
|
|
|
|
$show_join = false;
|
|
|
|
} else if ($project->getHasSubprojects()) {
|
|
|
|
$icon = 'fa-sitemap';
|
|
|
|
$target = pht('Parent Project');
|
|
|
|
$note = pht(
|
|
|
|
'Members of all subprojects are members of this project.');
|
|
|
|
$show_join = false;
|
|
|
|
} else if ($project->getIsMembershipLocked()) {
|
|
|
|
$icon = 'fa-lock';
|
|
|
|
$target = pht('Locked Project');
|
|
|
|
$note = pht(
|
|
|
|
'Users with access may join this project, but may not leave.');
|
|
|
|
$show_join = true;
|
|
|
|
} else {
|
|
|
|
$icon = 'fa-briefcase';
|
|
|
|
$target = pht('Normal Project');
|
|
|
|
$note = pht('Users with access may join and leave this project.');
|
|
|
|
$show_join = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
$item = id(new PHUIStatusItemView())
|
|
|
|
->setIcon($icon)
|
|
|
|
->setTarget(phutil_tag('strong', array(), $target))
|
|
|
|
->setNote($note);
|
|
|
|
|
|
|
|
$status = id(new PHUIStatusListView())
|
|
|
|
->addItem($item);
|
|
|
|
|
|
|
|
$view->addProperty(pht('Membership'), $status);
|
|
|
|
|
|
|
|
if ($show_join) {
|
|
|
|
$descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions(
|
|
|
|
$viewer,
|
|
|
|
$project);
|
|
|
|
|
|
|
|
$view->addProperty(
|
|
|
|
pht('Joinable By'),
|
|
|
|
$descriptions[PhabricatorPolicyCapability::CAN_JOIN]);
|
|
|
|
}
|
|
|
|
|
Replace subscribe/unsubscribe for projects with explicit mail setting
Summary:
Ref T10054. Ref T6113. Users can currently subscribe to projects, which causes them to receive:
# mail about project membership changes, description changes, etc; and
# mail to the project, e.g. when the project is added as a subscriber on a task, or a reviewer on a revision.
Almost no one cares about (1), and after D15061 you can use Herald to get this stuff if you really want it. (It will get progressively more annoying in the future with external membership sources causing automated project membership updates.)
A lot of users are confused about (2) and how it relates to membership, watching, etc, and most users who want (2) don't want (1).
Instead, add an explicit option for this and explain what it does.
This is fairly verbose but I've hidden it on the member/watch screen, which is now the "explain how projects work" screen, I guess.
Test Plan:
{F1064929}
{F1064930}
{F1064931}
- Disabled/enabled mail for a project.
- Sent mail to a project with mail disabled, verified I didn't get a copy.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T6113, T10054
Differential Revision: https://secure.phabricator.com/D15065
2016-01-20 03:56:15 +01:00
|
|
|
$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);
|
|
|
|
}
|
|
|
|
|
2016-01-20 01:27:36 +01:00
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
2016-04-14 20:26:43 +02:00
|
|
|
private function buildCurtainView(PhabricatorProject $project) {
|
2016-01-20 01:27:36 +01:00
|
|
|
$viewer = $this->getViewer();
|
|
|
|
$id = $project->getID();
|
|
|
|
|
2016-04-14 20:26:43 +02:00
|
|
|
$curtain = $this->newCurtainView($project);
|
2016-01-20 01:27:36 +01:00
|
|
|
|
|
|
|
$is_locked = $project->getIsMembershipLocked();
|
|
|
|
|
|
|
|
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
|
|
|
$viewer,
|
|
|
|
$project,
|
|
|
|
PhabricatorPolicyCapability::CAN_EDIT);
|
|
|
|
|
|
|
|
$supports_edit = $project->supportsEditMembers();
|
|
|
|
|
|
|
|
$can_join = $supports_edit && PhabricatorPolicyFilter::hasCapability(
|
|
|
|
$viewer,
|
|
|
|
$project,
|
|
|
|
PhabricatorPolicyCapability::CAN_JOIN);
|
|
|
|
|
|
|
|
$can_leave = $supports_edit && (!$is_locked || $can_edit);
|
|
|
|
|
Replace subscribe/unsubscribe for projects with explicit mail setting
Summary:
Ref T10054. Ref T6113. Users can currently subscribe to projects, which causes them to receive:
# mail about project membership changes, description changes, etc; and
# mail to the project, e.g. when the project is added as a subscriber on a task, or a reviewer on a revision.
Almost no one cares about (1), and after D15061 you can use Herald to get this stuff if you really want it. (It will get progressively more annoying in the future with external membership sources causing automated project membership updates.)
A lot of users are confused about (2) and how it relates to membership, watching, etc, and most users who want (2) don't want (1).
Instead, add an explicit option for this and explain what it does.
This is fairly verbose but I've hidden it on the member/watch screen, which is now the "explain how projects work" screen, I guess.
Test Plan:
{F1064929}
{F1064930}
{F1064931}
- Disabled/enabled mail for a project.
- Sent mail to a project with mail disabled, verified I didn't get a copy.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T6113, T10054
Differential Revision: https://secure.phabricator.com/D15065
2016-01-20 03:56:15 +01:00
|
|
|
$viewer_phid = $viewer->getPHID();
|
|
|
|
|
|
|
|
if (!$project->isUserMember($viewer_phid)) {
|
2016-04-14 20:26:43 +02:00
|
|
|
$curtain->addAction(
|
2016-01-20 01:27:36 +01:00
|
|
|
id(new PhabricatorActionView())
|
|
|
|
->setHref('/project/update/'.$project->getID().'/join/')
|
|
|
|
->setIcon('fa-plus')
|
|
|
|
->setDisabled(!$can_join)
|
|
|
|
->setWorkflow(true)
|
|
|
|
->setName(pht('Join Project')));
|
|
|
|
} else {
|
2016-04-14 20:26:43 +02:00
|
|
|
$curtain->addAction(
|
2016-01-20 01:27:36 +01:00
|
|
|
id(new PhabricatorActionView())
|
|
|
|
->setHref('/project/update/'.$project->getID().'/leave/')
|
|
|
|
->setIcon('fa-times')
|
|
|
|
->setDisabled(!$can_leave)
|
|
|
|
->setWorkflow(true)
|
|
|
|
->setName(pht('Leave Project')));
|
2016-01-20 02:43:14 +01:00
|
|
|
}
|
2016-01-20 01:27:36 +01:00
|
|
|
|
2016-01-20 02:43:14 +01:00
|
|
|
if (!$project->isUserWatcher($viewer->getPHID())) {
|
2016-04-14 20:26:43 +02:00
|
|
|
$curtain->addAction(
|
2016-01-20 02:43:14 +01:00
|
|
|
id(new PhabricatorActionView())
|
|
|
|
->setWorkflow(true)
|
|
|
|
->setHref('/project/watch/'.$project->getID().'/')
|
|
|
|
->setIcon('fa-eye')
|
|
|
|
->setName(pht('Watch Project')));
|
|
|
|
} else {
|
2016-04-14 20:26:43 +02:00
|
|
|
$curtain->addAction(
|
2016-01-20 02:43:14 +01:00
|
|
|
id(new PhabricatorActionView())
|
|
|
|
->setWorkflow(true)
|
|
|
|
->setHref('/project/unwatch/'.$project->getID().'/')
|
|
|
|
->setIcon('fa-eye-slash')
|
|
|
|
->setName(pht('Unwatch Project')));
|
2016-01-20 01:27:36 +01:00
|
|
|
}
|
|
|
|
|
Replace subscribe/unsubscribe for projects with explicit mail setting
Summary:
Ref T10054. Ref T6113. Users can currently subscribe to projects, which causes them to receive:
# mail about project membership changes, description changes, etc; and
# mail to the project, e.g. when the project is added as a subscriber on a task, or a reviewer on a revision.
Almost no one cares about (1), and after D15061 you can use Herald to get this stuff if you really want it. (It will get progressively more annoying in the future with external membership sources causing automated project membership updates.)
A lot of users are confused about (2) and how it relates to membership, watching, etc, and most users who want (2) don't want (1).
Instead, add an explicit option for this and explain what it does.
This is fairly verbose but I've hidden it on the member/watch screen, which is now the "explain how projects work" screen, I guess.
Test Plan:
{F1064929}
{F1064930}
{F1064931}
- Disabled/enabled mail for a project.
- Sent mail to a project with mail disabled, verified I didn't get a copy.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T6113, T10054
Differential Revision: https://secure.phabricator.com/D15065
2016-01-20 03:56:15 +01:00
|
|
|
$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');
|
|
|
|
}
|
|
|
|
|
2016-04-14 20:26:43 +02:00
|
|
|
$curtain->addAction(
|
Replace subscribe/unsubscribe for projects with explicit mail setting
Summary:
Ref T10054. Ref T6113. Users can currently subscribe to projects, which causes them to receive:
# mail about project membership changes, description changes, etc; and
# mail to the project, e.g. when the project is added as a subscriber on a task, or a reviewer on a revision.
Almost no one cares about (1), and after D15061 you can use Herald to get this stuff if you really want it. (It will get progressively more annoying in the future with external membership sources causing automated project membership updates.)
A lot of users are confused about (2) and how it relates to membership, watching, etc, and most users who want (2) don't want (1).
Instead, add an explicit option for this and explain what it does.
This is fairly verbose but I've hidden it on the member/watch screen, which is now the "explain how projects work" screen, I guess.
Test Plan:
{F1064929}
{F1064930}
{F1064931}
- Disabled/enabled mail for a project.
- Sent mail to a project with mail disabled, verified I didn't get a copy.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T6113, T10054
Differential Revision: https://secure.phabricator.com/D15065
2016-01-20 03:56:15 +01:00
|
|
|
id(new PhabricatorActionView())
|
|
|
|
->setName($silence_text)
|
|
|
|
->setIcon('fa-envelope-o')
|
|
|
|
->setHref("/project/silence/{$id}/")
|
|
|
|
->setWorkflow(true)
|
|
|
|
->setDisabled(!$can_silence));
|
|
|
|
|
2016-01-20 01:27:36 +01:00
|
|
|
$can_add = $can_edit && $supports_edit;
|
|
|
|
|
2016-04-14 20:26:43 +02:00
|
|
|
$curtain->addAction(
|
2016-01-20 01:27:36 +01:00
|
|
|
id(new PhabricatorActionView())
|
|
|
|
->setName(pht('Add Members'))
|
|
|
|
->setIcon('fa-user-plus')
|
|
|
|
->setHref("/project/members/{$id}/add/")
|
|
|
|
->setWorkflow(true)
|
|
|
|
->setDisabled(!$can_add));
|
|
|
|
|
|
|
|
$can_lock = $can_edit && $supports_edit && $this->hasApplicationCapability(
|
|
|
|
ProjectCanLockProjectsCapability::CAPABILITY);
|
|
|
|
|
|
|
|
if ($is_locked) {
|
|
|
|
$lock_name = pht('Unlock Project');
|
|
|
|
$lock_icon = 'fa-unlock';
|
|
|
|
} else {
|
|
|
|
$lock_name = pht('Lock Project');
|
|
|
|
$lock_icon = 'fa-lock';
|
|
|
|
}
|
|
|
|
|
2016-04-14 20:26:43 +02:00
|
|
|
$curtain->addAction(
|
2016-01-20 01:27:36 +01:00
|
|
|
id(new PhabricatorActionView())
|
|
|
|
->setName($lock_name)
|
|
|
|
->setIcon($lock_icon)
|
|
|
|
->setHref($this->getApplicationURI("lock/{$id}/"))
|
|
|
|
->setDisabled(!$can_lock)
|
|
|
|
->setWorkflow(true));
|
|
|
|
|
2016-04-14 20:26:43 +02:00
|
|
|
return $curtain;
|
2016-01-20 01:27:36 +01:00
|
|
|
}
|
|
|
|
|
Replace subscribe/unsubscribe for projects with explicit mail setting
Summary:
Ref T10054. Ref T6113. Users can currently subscribe to projects, which causes them to receive:
# mail about project membership changes, description changes, etc; and
# mail to the project, e.g. when the project is added as a subscriber on a task, or a reviewer on a revision.
Almost no one cares about (1), and after D15061 you can use Herald to get this stuff if you really want it. (It will get progressively more annoying in the future with external membership sources causing automated project membership updates.)
A lot of users are confused about (2) and how it relates to membership, watching, etc, and most users who want (2) don't want (1).
Instead, add an explicit option for this and explain what it does.
This is fairly verbose but I've hidden it on the member/watch screen, which is now the "explain how projects work" screen, I guess.
Test Plan:
{F1064929}
{F1064930}
{F1064931}
- Disabled/enabled mail for a project.
- Sent mail to a project with mail disabled, verified I didn't get a copy.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T6113, T10054
Differential Revision: https://secure.phabricator.com/D15065
2016-01-20 03:56:15 +01:00
|
|
|
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]);
|
|
|
|
}
|
|
|
|
|
2016-01-20 01:27:36 +01:00
|
|
|
}
|