Skip to content

Commit 5e715c1

Browse files
author
epriestley
committed
Simplify some logic in project controllers
Summary: Ref T10010. Several controlers currently have similar logic for handling tags and slugs, loading projects, and canonicalizing URIs. Clean it up a bit. Test Plan: - Visited profile, boards, feed. - Visited by ID and by tag. - Visited by non-normal tag (redircted). - Visited by alternate tag (redirected). - Visited non-policy project by non-normal tag (redirected into policy error). Reviewers: chad Reviewed By: chad Maniphest Tasks: T10010 Differential Revision: https://secure.phabricator.com/D14890
1 parent d1f1d3e commit 5e715c1

File tree

5 files changed

+101
-132
lines changed

5 files changed

+101
-132
lines changed

src/applications/project/controller/PhabricatorProjectController.php

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,72 @@ protected function getProject() {
1313
return $this->project;
1414
}
1515

16+
protected function loadProject() {
17+
$viewer = $this->getViewer();
18+
$request = $this->getRequest();
19+
20+
$id = $request->getURIData('id');
21+
$slug = $request->getURIData('slug');
22+
23+
if ($slug) {
24+
$normal_slug = PhabricatorSlug::normalizeProjectSlug($slug);
25+
$is_abnormal = ($slug !== $normal_slug);
26+
$normal_uri = "/tag/{$normal_slug}/";
27+
} else {
28+
$is_abnormal = false;
29+
}
30+
31+
$query = id(new PhabricatorProjectQuery())
32+
->setViewer($viewer)
33+
->needMembers(true)
34+
->needWatchers(true)
35+
->needImages(true)
36+
->needSlugs(true);
37+
38+
if ($slug) {
39+
$query->withSlugs(array($slug));
40+
} else {
41+
$query->withIDs(array($id));
42+
}
43+
44+
$policy_exception = null;
45+
try {
46+
$project = $query->executeOne();
47+
} catch (PhabricatorPolicyException $ex) {
48+
$policy_exception = $ex;
49+
$project = null;
50+
}
51+
52+
if (!$project) {
53+
// This project legitimately does not exist, so just 404 the user.
54+
if (!$policy_exception) {
55+
return new Aphront404Response();
56+
}
57+
58+
// Here, the project exists but the user can't see it. If they are
59+
// using a non-canonical slug to view the project, redirect to the
60+
// canonical slug. If they're already using the canonical slug, rethrow
61+
// the exception to give them the policy error.
62+
if ($is_abnormal) {
63+
return id(new AphrontRedirectResponse())->setURI($normal_uri);
64+
} else {
65+
throw $policy_exception;
66+
}
67+
}
68+
69+
// The user can view the project, but is using a noncanonical slug.
70+
// Redirect to the canonical slug.
71+
$primary_slug = $project->getPrimarySlug();
72+
if ($slug && ($slug !== $primary_slug)) {
73+
$primary_uri = "/tag/{$primary_slug}/";
74+
return id(new AphrontRedirectResponse())->setURI($primary_uri);
75+
}
76+
77+
$this->setProject($project);
78+
79+
return null;
80+
}
81+
1682
public function buildApplicationMenu() {
1783
return $this->buildSideNavView(true)->getMenu();
1884
}

src/applications/project/controller/PhabricatorProjectFeedController.php

Lines changed: 16 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -8,38 +8,25 @@ public function shouldAllowPublic() {
88
}
99

1010
public function handleRequest(AphrontRequest $request) {
11-
$user = $request->getUser();
11+
$viewer = $request->getUser();
1212

13-
$query = id(new PhabricatorProjectQuery())
14-
->setViewer($user)
15-
->needMembers(true)
16-
->needWatchers(true)
17-
->needImages(true)
18-
->needSlugs(true);
19-
$id = $request->getURIData('id');
20-
$slug = $request->getURIData('slug');
21-
if ($slug) {
22-
$query->withSlugs(array($slug));
23-
} else {
24-
$query->withIDs(array($id));
25-
}
26-
$project = $query->executeOne();
27-
if (!$project) {
28-
return new Aphront404Response();
29-
}
30-
if ($slug && $slug != $project->getPrimarySlug()) {
31-
return id(new AphrontRedirectResponse())
32-
->setURI('/tag/'.$project->getPrimarySlug().'/');
13+
$response = $this->loadProject();
14+
if ($response) {
15+
return $response;
3316
}
3417

35-
$query = new PhabricatorFeedQuery();
36-
$query->setFilterPHIDs(
37-
array(
38-
$project->getPHID(),
39-
));
40-
$query->setLimit(50);
41-
$query->setViewer($request->getUser());
42-
$stories = $query->execute();
18+
$project = $this->getProject();
19+
$id = $project->getID();
20+
21+
$stories = id(new PhabricatorFeedQuery())
22+
->setViewer($viewer)
23+
->setFilterPHIDs(
24+
array(
25+
$project->getPHID(),
26+
))
27+
->setLimit(50)
28+
->execute();
29+
4330
$feed = $this->renderStories($stories);
4431

4532
$box = id(new PHUIObjectBoxView())
@@ -57,21 +44,6 @@ public function handleRequest(AphrontRequest $request) {
5744
));
5845
}
5946

60-
private function renderFeedPage(PhabricatorProject $project) {
61-
62-
$query = new PhabricatorFeedQuery();
63-
$query->setFilterPHIDs(array($project->getPHID()));
64-
$query->setViewer($this->getRequest()->getUser());
65-
$query->setLimit(100);
66-
$stories = $query->execute();
67-
68-
if (!$stories) {
69-
return pht('There are no stories about this project.');
70-
}
71-
72-
return $this->renderStories($stories);
73-
}
74-
7547
private function renderStories(array $stories) {
7648
assert_instances_of($stories, 'PhabricatorFeedStory');
7749

@@ -85,5 +57,4 @@ private function renderStories(array $stories) {
8557
$view->render());
8658
}
8759

88-
8960
}

src/applications/project/controller/PhabricatorProjectMembersEditController.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,6 @@ public function handleRequest(AphrontRequest $request) {
1212
->withIDs(array($id))
1313
->needMembers(true)
1414
->needImages(true)
15-
->requireCapabilities(
16-
array(
17-
PhabricatorPolicyCapability::CAN_VIEW,
18-
))
1915
->executeOne();
2016
if (!$project) {
2117
return new Aphront404Response();

src/applications/project/controller/PhabricatorProjectProfileController.php

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,35 +8,20 @@ public function shouldAllowPublic() {
88
}
99

1010
public function handleRequest(AphrontRequest $request) {
11-
$user = $request->getUser();
12-
13-
$query = id(new PhabricatorProjectQuery())
14-
->setViewer($user)
15-
->needMembers(true)
16-
->needWatchers(true)
17-
->needImages(true)
18-
->needSlugs(true);
19-
$id = $request->getURIData('id');
20-
$slug = $request->getURIData('slug');
21-
if ($slug) {
22-
$query->withSlugs(array($slug));
23-
} else {
24-
$query->withIDs(array($id));
25-
}
26-
$project = $query->executeOne();
27-
if (!$project) {
28-
return new Aphront404Response();
29-
}
30-
if ($slug && $slug != $project->getPrimarySlug()) {
31-
return id(new AphrontRedirectResponse())
32-
->setURI('/tag/'.$project->getPrimarySlug().'/');
11+
$viewer = $request->getUser();
12+
13+
$response = $this->loadProject();
14+
if ($response) {
15+
return $response;
3316
}
3417

18+
$project = $this->getProject();
19+
$id = $project->getID();
3520
$picture = $project->getProfileImageURI();
3621

3722
$header = id(new PHUIHeaderView())
3823
->setHeader($project->getName())
39-
->setUser($user)
24+
->setUser($viewer)
4025
->setPolicyObject($project)
4126
->setImage($picture);
4227

@@ -60,15 +45,13 @@ public function handleRequest(AphrontRequest $request) {
6045

6146
$nav = $this->buildIconNavView($project);
6247
$nav->selectFilter("profile/{$id}/");
63-
$nav->appendChild($object_box);
64-
$nav->appendChild($timeline);
65-
66-
return $this->buildApplicationPage(
67-
$nav,
68-
array(
69-
'title' => $project->getName(),
70-
'pageObjects' => array($project->getPHID()),
71-
));
48+
49+
return $this->newPage()
50+
->setNavigation($nav)
51+
->setTitle($project->getName())
52+
->setPageObjectPHIDs(array($project->getPHID()))
53+
->appendChild($object_box)
54+
->appendChild($timeline);
7255
}
7356

7457
private function buildActionListView(PhabricatorProject $project) {

src/applications/project/controller/PhabricatorProjectViewController.php

Lines changed: 4 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,11 @@ public function handleRequest(AphrontRequest $request) {
1111
$request = $this->getRequest();
1212
$viewer = $request->getViewer();
1313

14-
$query = id(new PhabricatorProjectQuery())
15-
->setViewer($viewer)
16-
->needMembers(true)
17-
->needWatchers(true)
18-
->needImages(true)
19-
->needSlugs(true);
20-
$id = $request->getURIData('id');
21-
$slug = $request->getURIData('slug');
22-
if ($slug) {
23-
$query->withSlugs(array($slug));
24-
} else {
25-
$query->withIDs(array($id));
26-
}
27-
$project = $query->executeOne();
28-
if (!$project) {
29-
30-
// If this request corresponds to a project but just doesn't have the
31-
// slug quite right, redirect to the proper URI.
32-
$uri = $this->getNormalizedURI($slug);
33-
if ($uri !== null) {
34-
return id(new AphrontRedirectResponse())->setURI($uri);
35-
}
36-
37-
return new Aphront404Response();
14+
$response = $this->loadProject();
15+
if ($response) {
16+
return $response;
3817
}
18+
$project = $this->getProject();
3919

4020
$columns = id(new PhabricatorProjectColumnQuery())
4121
->setViewer($viewer)
@@ -60,31 +40,4 @@ public function handleRequest(AphrontRequest $request) {
6040
return $this->delegateToController($controller_object);
6141
}
6242

63-
private function getNormalizedURI($slug) {
64-
if (!strlen($slug)) {
65-
return null;
66-
}
67-
68-
$normal = PhabricatorSlug::normalizeProjectSlug($slug);
69-
if ($normal === $slug) {
70-
return null;
71-
}
72-
73-
$viewer = $this->getViewer();
74-
75-
// Do execute() instead of executeOne() here so we canonicalize before
76-
// raising a policy exception. This is a little more polished than letting
77-
// the user hit the error on any variant of the slug.
78-
79-
$projects = id(new PhabricatorProjectQuery())
80-
->setViewer($viewer)
81-
->withSlugs(array($normal))
82-
->execute();
83-
if (!$projects) {
84-
return null;
85-
}
86-
87-
return "/tag/{$normal}/";
88-
}
89-
9043
}

0 commit comments

Comments
 (0)