Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2890663
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
23 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Jan 19, 13:55 (3 w, 2 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1125274
Default Alt Text
(23 KB)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment