Page MenuHomePhorge

No OneTemporary

diff --git a/src/applications/project/controller/PhabricatorProjectController.php b/src/applications/project/controller/PhabricatorProjectController.php
index ac406412ad..2fcb276576 100644
--- a/src/applications/project/controller/PhabricatorProjectController.php
+++ b/src/applications/project/controller/PhabricatorProjectController.php
@@ -1,91 +1,157 @@
<?php
abstract class PhabricatorProjectController extends PhabricatorController {
private $project;
protected function setProject(PhabricatorProject $project) {
$this->project = $project;
return $this;
}
protected function getProject() {
return $this->project;
}
+ protected function loadProject() {
+ $viewer = $this->getViewer();
+ $request = $this->getRequest();
+
+ $id = $request->getURIData('id');
+ $slug = $request->getURIData('slug');
+
+ if ($slug) {
+ $normal_slug = PhabricatorSlug::normalizeProjectSlug($slug);
+ $is_abnormal = ($slug !== $normal_slug);
+ $normal_uri = "/tag/{$normal_slug}/";
+ } else {
+ $is_abnormal = false;
+ }
+
+ $query = id(new PhabricatorProjectQuery())
+ ->setViewer($viewer)
+ ->needMembers(true)
+ ->needWatchers(true)
+ ->needImages(true)
+ ->needSlugs(true);
+
+ if ($slug) {
+ $query->withSlugs(array($slug));
+ } else {
+ $query->withIDs(array($id));
+ }
+
+ $policy_exception = null;
+ try {
+ $project = $query->executeOne();
+ } catch (PhabricatorPolicyException $ex) {
+ $policy_exception = $ex;
+ $project = null;
+ }
+
+ if (!$project) {
+ // This project legitimately does not exist, so just 404 the user.
+ if (!$policy_exception) {
+ return new Aphront404Response();
+ }
+
+ // Here, the project exists but the user can't see it. If they are
+ // using a non-canonical slug to view the project, redirect to the
+ // canonical slug. If they're already using the canonical slug, rethrow
+ // the exception to give them the policy error.
+ if ($is_abnormal) {
+ return id(new AphrontRedirectResponse())->setURI($normal_uri);
+ } else {
+ throw $policy_exception;
+ }
+ }
+
+ // The user can view the project, but is using a noncanonical slug.
+ // Redirect to the canonical slug.
+ $primary_slug = $project->getPrimarySlug();
+ if ($slug && ($slug !== $primary_slug)) {
+ $primary_uri = "/tag/{$primary_slug}/";
+ return id(new AphrontRedirectResponse())->setURI($primary_uri);
+ }
+
+ $this->setProject($project);
+
+ return null;
+ }
+
public function buildApplicationMenu() {
return $this->buildSideNavView(true)->getMenu();
}
public function buildSideNavView($for_app = false) {
$project = $this->getProject();
$nav = new AphrontSideNavFilterView();
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
$viewer = $this->getViewer();
$id = null;
if ($for_app) {
if ($project) {
$id = $project->getID();
$nav->addFilter("profile/{$id}/", pht('Profile'));
$nav->addFilter("board/{$id}/", pht('Workboard'));
$nav->addFilter("members/{$id}/", pht('Members'));
$nav->addFilter("feed/{$id}/", pht('Feed'));
$nav->addFilter("details/{$id}/", pht('Edit Details'));
}
$nav->addFilter('create', pht('Create Project'));
}
if (!$id) {
id(new PhabricatorProjectSearchEngine())
->setViewer($viewer)
->addNavigationItems($nav->getMenu());
}
$nav->selectFilter(null);
return $nav;
}
public function buildIconNavView(PhabricatorProject $project) {
$this->setProject($project);
$viewer = $this->getViewer();
$id = $project->getID();
$picture = $project->getProfileImageURI();
$name = $project->getName();
$columns = id(new PhabricatorProjectColumnQuery())
->setViewer($viewer)
->withProjectPHIDs(array($project->getPHID()))
->execute();
if ($columns) {
$board_icon = 'fa-columns';
} else {
$board_icon = 'fa-columns grey';
}
$nav = new AphrontSideNavFilterView();
$nav->setIconNav(true);
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
$nav->addIcon("profile/{$id}/", $name, null, $picture);
$class = 'PhabricatorManiphestApplication';
if (PhabricatorApplication::isClassInstalledForViewer($class, $viewer)) {
$phid = $project->getPHID();
$nav->addIcon("board/{$id}/", pht('Workboard'), $board_icon);
$query_uri = urisprintf(
'/maniphest/?statuses=open()&projects=%s#R',
$phid);
$nav->addIcon(null, pht('Open Tasks'), 'fa-anchor', null, $query_uri);
}
$nav->addIcon("feed/{$id}/", pht('Feed'), 'fa-newspaper-o');
$nav->addIcon("members/{$id}/", pht('Members'), 'fa-group');
$nav->addIcon("details/{$id}/", pht('Edit Details'), 'fa-pencil');
return $nav;
}
}
diff --git a/src/applications/project/controller/PhabricatorProjectFeedController.php b/src/applications/project/controller/PhabricatorProjectFeedController.php
index efd82d31d0..5cd74094fc 100644
--- a/src/applications/project/controller/PhabricatorProjectFeedController.php
+++ b/src/applications/project/controller/PhabricatorProjectFeedController.php
@@ -1,89 +1,60 @@
<?php
final class PhabricatorProjectFeedController
extends PhabricatorProjectController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
- $user = $request->getUser();
+ $viewer = $request->getUser();
- $query = id(new PhabricatorProjectQuery())
- ->setViewer($user)
- ->needMembers(true)
- ->needWatchers(true)
- ->needImages(true)
- ->needSlugs(true);
- $id = $request->getURIData('id');
- $slug = $request->getURIData('slug');
- if ($slug) {
- $query->withSlugs(array($slug));
- } else {
- $query->withIDs(array($id));
- }
- $project = $query->executeOne();
- if (!$project) {
- return new Aphront404Response();
- }
- if ($slug && $slug != $project->getPrimarySlug()) {
- return id(new AphrontRedirectResponse())
- ->setURI('/tag/'.$project->getPrimarySlug().'/');
+ $response = $this->loadProject();
+ if ($response) {
+ return $response;
}
- $query = new PhabricatorFeedQuery();
- $query->setFilterPHIDs(
- array(
- $project->getPHID(),
- ));
- $query->setLimit(50);
- $query->setViewer($request->getUser());
- $stories = $query->execute();
+ $project = $this->getProject();
+ $id = $project->getID();
+
+ $stories = id(new PhabricatorFeedQuery())
+ ->setViewer($viewer)
+ ->setFilterPHIDs(
+ array(
+ $project->getPHID(),
+ ))
+ ->setLimit(50)
+ ->execute();
+
$feed = $this->renderStories($stories);
$box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Project Activity'))
->appendChild($feed);
$nav = $this->buildIconNavView($project);
$nav->selectFilter("feed/{$id}/");
$nav->appendChild($box);
return $this->buildApplicationPage(
$nav,
array(
'title' => $project->getName(),
));
}
- private function renderFeedPage(PhabricatorProject $project) {
-
- $query = new PhabricatorFeedQuery();
- $query->setFilterPHIDs(array($project->getPHID()));
- $query->setViewer($this->getRequest()->getUser());
- $query->setLimit(100);
- $stories = $query->execute();
-
- if (!$stories) {
- return pht('There are no stories about this project.');
- }
-
- return $this->renderStories($stories);
- }
-
private function renderStories(array $stories) {
assert_instances_of($stories, 'PhabricatorFeedStory');
$builder = new PhabricatorFeedBuilder($stories);
$builder->setUser($this->getRequest()->getUser());
$builder->setShowHovercards(true);
$view = $builder->buildView();
return phutil_tag_div(
'profile-feed',
$view->render());
}
-
}
diff --git a/src/applications/project/controller/PhabricatorProjectMembersEditController.php b/src/applications/project/controller/PhabricatorProjectMembersEditController.php
index c7a9144188..f007650e4a 100644
--- a/src/applications/project/controller/PhabricatorProjectMembersEditController.php
+++ b/src/applications/project/controller/PhabricatorProjectMembersEditController.php
@@ -1,154 +1,150 @@
<?php
final class PhabricatorProjectMembersEditController
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)
->needImages(true)
- ->requireCapabilities(
- array(
- PhabricatorPolicyCapability::CAN_VIEW,
- ))
->executeOne();
if (!$project) {
return new Aphront404Response();
}
$member_phids = $project->getMemberPHIDs();
if ($request->isFormPost()) {
$member_spec = array();
$remove = $request->getStr('remove');
if ($remove) {
$member_spec['-'] = array_fuse(array($remove));
}
$add_members = $request->getArr('phids');
if ($add_members) {
$member_spec['+'] = array_fuse($add_members);
}
$type_member = PhabricatorProjectProjectHasMemberEdgeType::EDGECONST;
$xactions = array();
$xactions[] = id(new PhabricatorProjectTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
->setMetadataValue('edge:type', $type_member)
->setNewValue($member_spec);
$editor = id(new PhabricatorProjectTransactionEditor($project))
->setActor($viewer)
->setContentSourceFromRequest($request)
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true)
->applyTransactions($project, $xactions);
return id(new AphrontRedirectResponse())
->setURI($request->getRequestURI());
}
$member_phids = array_reverse($member_phids);
$handles = $this->loadViewerHandles($member_phids);
$state = array();
foreach ($handles as $handle) {
$state[] = array(
'phid' => $handle->getPHID(),
'name' => $handle->getFullName(),
);
}
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$project,
PhabricatorPolicyCapability::CAN_EDIT);
$form_box = null;
$title = pht('Add Members');
if ($can_edit) {
$header_name = pht('Edit Members');
$view_uri = $this->getApplicationURI('profile/'.$project->getID().'/');
$form = new AphrontFormView();
$form
->setUser($viewer)
->appendControl(
id(new AphrontFormTokenizerControl())
->setName('phids')
->setLabel(pht('Add Members'))
->setDatasource(new PhabricatorPeopleDatasource()))
->appendChild(
id(new AphrontFormSubmitControl())
->addCancelButton($view_uri)
->setValue(pht('Add Members')));
$form_box = id(new PHUIObjectBoxView())
->setHeaderText($title)
->setForm($form);
}
$member_list = $this->renderMemberList($project, $handles);
$nav = $this->buildIconNavView($project);
$nav->selectFilter("members/{$id}/");
$nav->appendChild($form_box);
$nav->appendChild($member_list);
return $this->buildApplicationPage(
$nav,
array(
'title' => $title,
));
}
private function renderMemberList(
PhabricatorProject $project,
array $handles) {
$request = $this->getRequest();
$viewer = $request->getUser();
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$project,
PhabricatorPolicyCapability::CAN_EDIT);
$list = id(new PHUIObjectItemListView())
->setNoDataString(pht('This project does not have any members.'));
foreach ($handles as $handle) {
$remove_uri = $this->getApplicationURI(
'/members/'.$project->getID().'/remove/?phid='.$handle->getPHID());
$item = id(new PHUIObjectItemView())
->setHeader($handle->getFullName())
->setHref($handle->getURI())
->setImageURI($handle->getImageURI());
if ($can_edit) {
$item->addAction(
id(new PHUIListItemView())
->setIcon('fa-times')
->setName(pht('Remove'))
->setHref($remove_uri)
->setWorkflow(true));
}
$list->addItem($item);
}
$box = id(new PHUIObjectBoxView())
->setHeaderText(pht('Members'))
->setObjectList($list);
return $box;
}
}
diff --git a/src/applications/project/controller/PhabricatorProjectProfileController.php b/src/applications/project/controller/PhabricatorProjectProfileController.php
index 89880bdd1a..cc246b5a2d 100644
--- a/src/applications/project/controller/PhabricatorProjectProfileController.php
+++ b/src/applications/project/controller/PhabricatorProjectProfileController.php
@@ -1,223 +1,206 @@
<?php
final class PhabricatorProjectProfileController
extends PhabricatorProjectController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
- $user = $request->getUser();
-
- $query = id(new PhabricatorProjectQuery())
- ->setViewer($user)
- ->needMembers(true)
- ->needWatchers(true)
- ->needImages(true)
- ->needSlugs(true);
- $id = $request->getURIData('id');
- $slug = $request->getURIData('slug');
- if ($slug) {
- $query->withSlugs(array($slug));
- } else {
- $query->withIDs(array($id));
- }
- $project = $query->executeOne();
- if (!$project) {
- return new Aphront404Response();
- }
- if ($slug && $slug != $project->getPrimarySlug()) {
- return id(new AphrontRedirectResponse())
- ->setURI('/tag/'.$project->getPrimarySlug().'/');
+ $viewer = $request->getUser();
+
+ $response = $this->loadProject();
+ if ($response) {
+ return $response;
}
+ $project = $this->getProject();
+ $id = $project->getID();
$picture = $project->getProfileImageURI();
$header = id(new PHUIHeaderView())
->setHeader($project->getName())
- ->setUser($user)
+ ->setUser($viewer)
->setPolicyObject($project)
->setImage($picture);
if ($project->getStatus() == PhabricatorProjectStatus::STATUS_ACTIVE) {
$header->setStatus('fa-check', 'bluegrey', pht('Active'));
} else {
$header->setStatus('fa-ban', 'red', pht('Archived'));
}
$actions = $this->buildActionListView($project);
$properties = $this->buildPropertyListView($project, $actions);
$object_box = id(new PHUIObjectBoxView())
->setHeader($header)
->addPropertyList($properties);
$timeline = $this->buildTransactionTimeline(
$project,
new PhabricatorProjectTransactionQuery());
$timeline->setShouldTerminate(true);
$nav = $this->buildIconNavView($project);
$nav->selectFilter("profile/{$id}/");
- $nav->appendChild($object_box);
- $nav->appendChild($timeline);
-
- return $this->buildApplicationPage(
- $nav,
- array(
- 'title' => $project->getName(),
- 'pageObjects' => array($project->getPHID()),
- ));
+
+ return $this->newPage()
+ ->setNavigation($nav)
+ ->setTitle($project->getName())
+ ->setPageObjectPHIDs(array($project->getPHID()))
+ ->appendChild($object_box)
+ ->appendChild($timeline);
}
private function buildActionListView(PhabricatorProject $project) {
$request = $this->getRequest();
$viewer = $request->getUser();
$id = $project->getID();
$view = id(new PhabricatorActionListView())
->setUser($viewer)
->setObject($project);
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$project,
PhabricatorPolicyCapability::CAN_EDIT);
$view->addAction(
id(new PhabricatorActionView())
->setName(pht('Edit Details'))
->setIcon('fa-pencil')
->setHref($this->getApplicationURI("details/{$id}/"))
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit));
$view->addAction(
id(new PhabricatorActionView())
->setName(pht('Edit Picture'))
->setIcon('fa-picture-o')
->setHref($this->getApplicationURI("picture/{$id}/"))
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit));
if ($project->isArchived()) {
$view->addAction(
id(new PhabricatorActionView())
->setName(pht('Activate Project'))
->setIcon('fa-check')
->setHref($this->getApplicationURI("archive/{$id}/"))
->setDisabled(!$can_edit)
->setWorkflow(true));
} else {
$view->addAction(
id(new PhabricatorActionView())
->setName(pht('Archive Project'))
->setIcon('fa-ban')
->setHref($this->getApplicationURI("archive/{$id}/"))
->setDisabled(!$can_edit)
->setWorkflow(true));
}
$action = null;
if (!$project->isUserMember($viewer->getPHID())) {
$can_join = PhabricatorPolicyFilter::hasCapability(
$viewer,
$project,
PhabricatorPolicyCapability::CAN_JOIN);
$action = id(new PhabricatorActionView())
->setUser($viewer)
->setRenderAsForm(true)
->setHref('/project/update/'.$project->getID().'/join/')
->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);
}
}
return $view;
}
private function buildPropertyListView(
PhabricatorProject $project,
PhabricatorActionListView $actions) {
$request = $this->getRequest();
$viewer = $request->getUser();
$view = id(new PHUIPropertyListView())
->setUser($viewer)
->setObject($project)
->setActionList($actions);
$hashtags = array();
foreach ($project->getSlugs() as $slug) {
$hashtags[] = id(new PHUITagView())
->setType(PHUITagView::TYPE_OBJECT)
->setName('#'.$slug->getSlug());
}
$view->addProperty(pht('Hashtags'), phutil_implode_html(' ', $hashtags));
$view->addProperty(
pht('Members'),
$project->getMemberPHIDs()
? $viewer
->renderHandleList($project->getMemberPHIDs())
->setAsInline(true)
: phutil_tag('em', array(), pht('None')));
$view->addProperty(
pht('Watchers'),
$project->getWatcherPHIDs()
? $viewer
->renderHandleList($project->getWatcherPHIDs())
->setAsInline(true)
: phutil_tag('em', array(), pht('None')));
$descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions(
$viewer,
$project);
$view->addProperty(
pht('Looks Like'),
$viewer->renderHandle($project->getPHID())->setAsTag(true));
$view->addProperty(
pht('Joinable By'),
$descriptions[PhabricatorPolicyCapability::CAN_JOIN]);
$field_list = PhabricatorCustomField::getObjectFields(
$project,
PhabricatorCustomField::ROLE_VIEW);
$field_list->appendFieldsToPropertyList($project, $viewer, $view);
return $view;
}
}
diff --git a/src/applications/project/controller/PhabricatorProjectViewController.php b/src/applications/project/controller/PhabricatorProjectViewController.php
index bfc9827ab5..087971878b 100644
--- a/src/applications/project/controller/PhabricatorProjectViewController.php
+++ b/src/applications/project/controller/PhabricatorProjectViewController.php
@@ -1,90 +1,43 @@
<?php
final class PhabricatorProjectViewController
extends PhabricatorProjectController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$request = $this->getRequest();
$viewer = $request->getViewer();
- $query = id(new PhabricatorProjectQuery())
- ->setViewer($viewer)
- ->needMembers(true)
- ->needWatchers(true)
- ->needImages(true)
- ->needSlugs(true);
- $id = $request->getURIData('id');
- $slug = $request->getURIData('slug');
- if ($slug) {
- $query->withSlugs(array($slug));
- } else {
- $query->withIDs(array($id));
- }
- $project = $query->executeOne();
- if (!$project) {
-
- // If this request corresponds to a project but just doesn't have the
- // slug quite right, redirect to the proper URI.
- $uri = $this->getNormalizedURI($slug);
- if ($uri !== null) {
- return id(new AphrontRedirectResponse())->setURI($uri);
- }
-
- return new Aphront404Response();
+ $response = $this->loadProject();
+ if ($response) {
+ return $response;
}
+ $project = $this->getProject();
$columns = id(new PhabricatorProjectColumnQuery())
->setViewer($viewer)
->withProjectPHIDs(array($project->getPHID()))
->execute();
if ($columns) {
$controller = 'board';
} else {
$controller = 'profile';
}
switch ($controller) {
case 'board':
$controller_object = new PhabricatorProjectBoardViewController();
break;
case 'profile':
default:
$controller_object = new PhabricatorProjectProfileController();
break;
}
return $this->delegateToController($controller_object);
}
- private function getNormalizedURI($slug) {
- if (!strlen($slug)) {
- return null;
- }
-
- $normal = PhabricatorSlug::normalizeProjectSlug($slug);
- if ($normal === $slug) {
- return null;
- }
-
- $viewer = $this->getViewer();
-
- // Do execute() instead of executeOne() here so we canonicalize before
- // raising a policy exception. This is a little more polished than letting
- // the user hit the error on any variant of the slug.
-
- $projects = id(new PhabricatorProjectQuery())
- ->setViewer($viewer)
- ->withSlugs(array($normal))
- ->execute();
- if (!$projects) {
- return null;
- }
-
- return "/tag/{$normal}/";
- }
-
}

File Metadata

Mime Type
text/x-diff
Expires
Sun, Jan 19, 13:55 (3 w, 3 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1125274
Default Alt Text
(23 KB)

Event Timeline