
Refactoring: added IsAllowed annotation
@f964efdb043a04735a73ef4fe450a593d6f971c9
+++ app/actions/IsAllowedAction.java
... | ... | @@ -0,0 +1,80 @@ |
1 | +/** | |
2 | + * Yobi, Project Hosting SW | |
3 | + * | |
4 | + * Copyright 2013 NAVER Corp. | |
5 | + * http://yobi.io | |
6 | + * | |
7 | + * @Author Keesun Baik | |
8 | + * | |
9 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
10 | + * you may not use this file except in compliance with the License. | |
11 | + * You may obtain a copy of the License at | |
12 | + * | |
13 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
14 | + * | |
15 | + * Unless required by applicable law or agreed to in writing, software | |
16 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
17 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
18 | + * See the License for the specific language governing permissions and | |
19 | + * limitations under the License. | |
20 | + */ | |
21 | +package actions; | |
22 | + | |
23 | +import actions.support.PathParser; | |
24 | +import controllers.UserApp; | |
25 | +import controllers.annotation.IsAllowed; | |
26 | +import models.Project; | |
27 | +import models.enumeration.Operation; | |
28 | +import models.enumeration.ResourceType; | |
29 | +import models.resource.Resource; | |
30 | +import models.resource.ResourceConvertible; | |
31 | +import play.mvc.Action; | |
32 | +import play.mvc.Http; | |
33 | +import play.mvc.Result; | |
34 | +import utils.AccessControl; | |
35 | +import utils.AccessLogger; | |
36 | +import utils.ErrorViews; | |
37 | + | |
38 | +/** | |
39 | + * 1. 프로젝트가 존재하는지 확인한다. | |
40 | + * 2. 특정 타입의 리소스가 존재하는지 확인한다. | |
41 | + * 3. 특정 타입의 리소스에 권한이 있는지 확인한다. | |
42 | + * | |
43 | + * 자세한 설명은 {@link controllers.annotation.IsAllowed} 애노테이션 참고. | |
44 | + * | |
45 | + * @author Keesun Baik | |
46 | + * @see {@link controllers.annotation.IsAllowed} | |
47 | + */ | |
48 | +public class IsAllowedAction extends Action<IsAllowed> { | |
49 | + | |
50 | + @Override | |
51 | + public Result call(Http.Context context) throws Throwable { | |
52 | + PathParser parser = new PathParser(context); | |
53 | + String ownerLoginId = parser.getOwnerLoginId(); | |
54 | + String projectName = parser.getProjectName(); | |
55 | + | |
56 | + Project project = Project.findByOwnerAndProjectName(ownerLoginId, projectName); | |
57 | + | |
58 | + if (project == null) { | |
59 | + return AccessLogger.log(context.request(), | |
60 | + notFound(ErrorViews.NotFound.render("error.notfound.project")), null); | |
61 | + } | |
62 | + | |
63 | + ResourceType resourceType = this.configuration.resourceType(); | |
64 | + ResourceConvertible resourceObject = Resource.getResourceObject(parser, project, resourceType); | |
65 | + Operation operation = this.configuration.value(); | |
66 | + | |
67 | + if(resourceObject == null) { | |
68 | + return AccessLogger.log(context.request(), | |
69 | + notFound(ErrorViews.NotFound.render("error.notfound", project, resourceType.resource())) , null); | |
70 | + } | |
71 | + | |
72 | + if(!AccessControl.isAllowed(UserApp.currentUser(), resourceObject.asResource(), operation)) { | |
73 | + return AccessLogger.log(context.request(), | |
74 | + forbidden(ErrorViews.Forbidden.render("error.forbidden", project)), null); | |
75 | + } | |
76 | + | |
77 | + return this.delegate.call(context); | |
78 | + } | |
79 | + | |
80 | +} |
--- app/actions/IsCreatableAction.java
+++ app/actions/IsCreatableAction.java
... | ... | @@ -33,30 +33,24 @@ |
33 | 33 |
import controllers.annotation.IsCreatable; |
34 | 34 |
|
35 | 35 |
/** |
36 |
- * 해당 프로젝트가 존재하는지 체크하고 사용자가 resource type별 생성권한이 있는지 체크한다. |
|
36 |
+ * 1. 프로젝트가 존재하는지 확인한다. |
|
37 |
+ * 2. 프로젝트에 특정 타입의 리소스를 생성할 수 있는지 확인한다. |
|
37 | 38 |
* |
38 |
- * @author Wansoon Park, Keesun Beak |
|
39 |
- * |
|
39 |
+ * @author Wansoon Park, Keesun Baik |
|
40 |
+ * @see {@link controllers.annotation.IsCreatable} |
|
40 | 41 |
*/ |
41 | 42 |
public class IsCreatableAction extends Action<IsCreatable> { |
42 | 43 |
|
43 | 44 |
@Override |
44 | 45 |
public Result call(Context context) throws Throwable { |
45 |
- String path = context._requestHeader().path(); |
|
46 |
- |
|
47 |
- play.Configuration config = play.Configuration.root(); |
|
48 |
- String contextPath = config.getString("application.context"); |
|
49 |
- |
|
50 |
- PathParser parser = new PathParser(contextPath, path); |
|
51 |
- |
|
46 |
+ PathParser parser = new PathParser(context); |
|
52 | 47 |
String ownerLoginId = parser.getOwnerLoginId(); |
53 | 48 |
String projectName = parser.getProjectName(); |
54 | 49 |
|
55 | 50 |
Project project = Project.findByOwnerAndProjectName(ownerLoginId, projectName); |
56 | 51 |
|
57 | 52 |
if (project == null) { |
58 |
- return AccessLogger.log(context.request() |
|
59 |
- , notFound(ErrorViews.NotFound.render("No project matches given parameters '" + ownerLoginId + "' and project_name '" + projectName + "'")) |
|
53 |
+ return AccessLogger.log(context.request(), notFound(ErrorViews.NotFound.render("error.notfound.project")) |
|
60 | 54 |
, null); |
61 | 55 |
} |
62 | 56 |
|
--- app/actions/ProjectCheckAction.java
+++ app/actions/IsOnlyGitAvailableAction.java
... | ... | @@ -4,7 +4,7 @@ |
4 | 4 |
* Copyright 2013 NAVER Corp. |
5 | 5 |
* http://yobi.io |
6 | 6 |
* |
7 |
- * @Author Wansoon Park, Keesun Baek |
|
7 |
+ * @Author Keesun Baik |
|
8 | 8 |
* |
9 | 9 |
* Licensed under the Apache License, Version 2.0 (the "License"); |
10 | 10 |
* you may not use this file except in compliance with the License. |
... | ... | @@ -20,27 +20,25 @@ |
20 | 20 |
*/ |
21 | 21 |
package actions; |
22 | 22 |
|
23 |
+import actions.support.PathParser; |
|
24 |
+import controllers.annotation.IsOnlyGitAvailable; |
|
23 | 25 |
import models.Project; |
24 | 26 |
import play.mvc.Action; |
25 |
-import play.mvc.Http.Context; |
|
27 |
+import play.mvc.Http; |
|
26 | 28 |
import play.mvc.Result; |
27 |
-import utils.AccessControl; |
|
28 | 29 |
import utils.AccessLogger; |
29 | 30 |
import utils.ErrorViews; |
30 |
-import actions.support.PathParser; |
|
31 |
-import controllers.UserApp; |
|
32 |
-import controllers.annotation.ProjectAccess; |
|
33 | 31 |
|
34 | 32 |
/** |
35 |
- * 해당 프로젝트가 존재하는지 체크하고 사용자가 resource에 대한 operation 권한이 있는지 확인한다. |
|
33 |
+ * 1. 프로젝트가 존재하는지 확인한다. |
|
34 |
+ * 2. 프로젝트가 Git 프로젝트인지 확인한다. |
|
36 | 35 |
* |
37 |
- * @author Wansoon Park, Keesun Beak |
|
38 |
- * |
|
36 |
+ * @author Keesun Baik |
|
39 | 37 |
*/ |
40 |
-public class ProjectCheckAction extends Action<ProjectAccess> { |
|
38 |
+public class IsOnlyGitAvailableAction extends Action<IsOnlyGitAvailable> { |
|
41 | 39 |
|
42 | 40 |
@Override |
43 |
- public Result call(Context context) throws Throwable { |
|
41 |
+ public Result call(Http.Context context) throws Throwable { |
|
44 | 42 |
PathParser parser = new PathParser(context); |
45 | 43 |
String ownerLoginId = parser.getOwnerLoginId(); |
46 | 44 |
String projectName = parser.getProjectName(); |
... | ... | @@ -52,17 +50,11 @@ |
52 | 50 |
, null); |
53 | 51 |
} |
54 | 52 |
|
55 |
- if (!AccessControl.isAllowed(UserApp.currentUser(), project.asResource(), this.configuration.value())) { |
|
56 |
- return AccessLogger.log(context.request() |
|
57 |
- , forbidden(ErrorViews.Forbidden.render("error.forbidden", project)) |
|
58 |
- , null); |
|
59 |
- } |
|
60 |
- |
|
61 |
- boolean isGitOnly = this.configuration.isGitOnly(); |
|
62 |
- if(isGitOnly && !project.isGit()) { |
|
63 |
- return AccessLogger.log(context.request(), badRequest(ErrorViews.BadRequest.render()), null); |
|
53 |
+ if(!project.isGit()) { |
|
54 |
+ return AccessLogger.log(context.request(), badRequest(ErrorViews.BadRequest.render("error.badrequest.only.available.for.git")), null); |
|
64 | 55 |
} |
65 | 56 |
|
66 | 57 |
return this.delegate.call(context); |
67 | 58 |
} |
59 |
+ |
|
68 | 60 |
} |
--- app/actions/PullRequestCheckAction.java
... | ... | @@ -1,74 +0,0 @@ |
1 | -/** | |
2 | - * Yobi, Project Hosting SW | |
3 | - * | |
4 | - * Copyright 2013 NAVER Corp. | |
5 | - * http://yobi.io | |
6 | - * | |
7 | - * @Author Wansoon Park, Keesun Baek | |
8 | - * | |
9 | - * Licensed under the Apache License, Version 2.0 (the "License"); | |
10 | - * you may not use this file except in compliance with the License. | |
11 | - * You may obtain a copy of the License at | |
12 | - * | |
13 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
14 | - * | |
15 | - * Unless required by applicable law or agreed to in writing, software | |
16 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
17 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
18 | - * See the License for the specific language governing permissions and | |
19 | - * limitations under the License. | |
20 | - */ | |
21 | -package actions; | |
22 | - | |
23 | -import models.Project; | |
24 | -import models.PullRequest; | |
25 | -import play.mvc.Action; | |
26 | -import play.mvc.Http.Context; | |
27 | -import play.mvc.Result; | |
28 | -import utils.AccessControl; | |
29 | -import utils.AccessLogger; | |
30 | -import utils.ErrorViews; | |
31 | -import actions.support.PathParser; | |
32 | -import controllers.UserApp; | |
33 | -import controllers.annotation.PullRequestAccess; | |
34 | - | |
35 | -/** | |
36 | - * 해당 pullrequest가 존재하는지 체크하고 사용자가 pullrequest resource에 대한 operation 권한이 있는지 확인한다. | |
37 | - * | |
38 | - * @author Wansoon Park, Keesun Beak | |
39 | - * | |
40 | - */ | |
41 | -public class PullRequestCheckAction extends Action<PullRequestAccess> { | |
42 | - | |
43 | - @Override | |
44 | - public Result call(Context context) throws Throwable { | |
45 | - String path = context._requestHeader().path(); | |
46 | - | |
47 | - play.Configuration config = play.Configuration.root(); | |
48 | - String contextPath = config.getString("application.context"); | |
49 | - | |
50 | - PathParser parser = new PathParser(contextPath, path); | |
51 | - | |
52 | - String ownerLoginId = parser.getOwnerLoginId(); | |
53 | - String projectName = parser.getProjectName(); | |
54 | - int pullRequestNumber = parser.getPullRequestNumber(); | |
55 | - | |
56 | - Project project = Project.findByOwnerAndProjectName(ownerLoginId, projectName); | |
57 | - PullRequest pullRequest = PullRequest.findOne(project, pullRequestNumber); | |
58 | - | |
59 | - if (pullRequest == null) { | |
60 | - return AccessLogger.log(context.request() | |
61 | - , notFound(ErrorViews.NotFound.render("No pullrequest matches given parameter '" + pullRequestNumber + "'", project)) | |
62 | - , null); | |
63 | - } | |
64 | - | |
65 | - if (!AccessControl.isAllowed(UserApp.currentUser(), pullRequest.asResource(), this.configuration.value())) { | |
66 | - return AccessLogger.log(context.request() | |
67 | - , forbidden(ErrorViews.Forbidden.render("error.forbidden", project)) | |
68 | - , null); | |
69 | - } | |
70 | - | |
71 | - return this.delegate.call(context); | |
72 | - } | |
73 | - | |
74 | -} |
--- app/actions/support/PathParser.java
+++ app/actions/support/PathParser.java
... | ... | @@ -25,20 +25,21 @@ |
25 | 25 |
|
26 | 26 |
/** |
27 | 27 |
* 프로젝트 관련 URL을 파싱한다. |
28 |
- * /{user.loginId}/{project.name}/** 패턴에 해당하는 URL에서 프로젝트 owner와 name 정보를 축출한다. |
|
28 |
+ * /{user.loginId}/{project.name}/** 패턴에 해당하는 URL에서 필요한 정보를 축출한다. |
|
29 |
+ * |
|
30 |
+ * @author Wansoon Park, Keesun Baik |
|
29 | 31 |
*/ |
30 | 32 |
public class PathParser { |
31 |
- private static final String DELIMETER = "/"; |
|
32 |
- private String[] paths; |
|
33 |
+ private static final String DELIM = "/"; |
|
34 |
+ private String[] pathSegments; |
|
33 | 35 |
|
34 | 36 |
public PathParser(String path) { |
35 |
- this.paths = StringUtils.split(path, DELIMETER); |
|
37 |
+ this.pathSegments = StringUtils.split(path, DELIM); |
|
36 | 38 |
} |
37 | 39 |
|
38 | 40 |
public PathParser(String contextPath, String path) { |
39 |
- String delimRemovedPath = StringUtils.removeEnd(contextPath, DELIMETER); |
|
40 |
- String contextRemovedPath = StringUtils.removeStart(path, delimRemovedPath); |
|
41 |
- this.paths = StringUtils.split(contextRemovedPath, DELIMETER); |
|
41 |
+ String contextRemovedPath = StringUtils.removeStart(path, contextPath); |
|
42 |
+ this.pathSegments = StringUtils.split(contextRemovedPath, DELIM); |
|
42 | 43 |
} |
43 | 44 |
|
44 | 45 |
public PathParser(Http.Context context) { |
... | ... | @@ -46,17 +47,19 @@ |
46 | 47 |
} |
47 | 48 |
|
48 | 49 |
public String getOwnerLoginId() { |
49 |
- return this.paths[0]; |
|
50 |
+ return this.pathSegments[0]; |
|
50 | 51 |
} |
51 | 52 |
|
52 | 53 |
public String getProjectName() { |
53 |
- return this.paths[1]; |
|
54 |
+ return this.pathSegments[1]; |
|
54 | 55 |
} |
55 | 56 |
|
56 |
- public int getPullRequestNumber() { |
|
57 |
- return Integer.parseInt(this.paths[3]); |
|
57 |
+ public String getPathSegment(int index) { |
|
58 |
+ return pathSegments[index]; |
|
58 | 59 |
} |
60 |
+ |
|
59 | 61 |
public String toString() { |
60 |
- return DELIMETER + StringUtils.join(this.paths, DELIMETER); |
|
62 |
+ return DELIM + StringUtils.join(this.pathSegments, DELIM); |
|
61 | 63 |
} |
64 |
+ |
|
62 | 65 |
} |
--- app/controllers/AbstractPostingApp.java
+++ app/controllers/AbstractPostingApp.java
... | ... | @@ -288,21 +288,4 @@ |
288 | 288 |
return redirect(redirectTo); |
289 | 289 |
} |
290 | 290 |
|
291 |
- /** |
|
292 |
- * 새 게시물 또는 이슈 생성 권한이 있는지 확인하고 {@code content}를 보여준다. |
|
293 |
- * |
|
294 |
- * when: 게시물이나 이슈 생성할 때 사용한다. |
|
295 |
- * |
|
296 |
- * @param project |
|
297 |
- * @param resourceType |
|
298 |
- * @param content |
|
299 |
- * @return |
|
300 |
- */ |
|
301 |
- public static Result newPostingForm(Project project, ResourceType resourceType, Content content) { |
|
302 |
- if (!AccessControl.isProjectResourceCreatable(UserApp.currentUser(), project, resourceType)) { |
|
303 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
304 |
- } |
|
305 |
- |
|
306 |
- return ok(content); |
|
307 |
- } |
|
308 | 291 |
} |
--- app/controllers/BoardApp.java
+++ app/controllers/BoardApp.java
... | ... | @@ -4,6 +4,8 @@ |
4 | 4 |
import actions.NullProjectCheckAction; |
5 | 5 |
import com.avaje.ebean.ExpressionList; |
6 | 6 |
import com.avaje.ebean.Page; |
7 |
+import controllers.annotation.IsAllowed; |
|
8 |
+import controllers.annotation.IsCreatable; |
|
7 | 9 |
import models.*; |
8 | 10 |
import models.enumeration.Operation; |
9 | 11 |
import models.enumeration.ResourceType; |
... | ... | @@ -57,13 +59,9 @@ |
57 | 59 |
* @param pageNum 페이지 번호 |
58 | 60 |
* @return |
59 | 61 |
*/ |
60 |
- @With(NullProjectCheckAction.class) |
|
62 |
+ @IsAllowed(value = Operation.READ, resourceType = ResourceType.PROJECT) |
|
61 | 63 |
public static Result posts(String userName, String projectName, int pageNum) { |
62 | 64 |
Project project = ProjectApp.getProject(userName, projectName); |
63 |
- |
|
64 |
- if (!AccessControl.isAllowed(UserApp.currentUser(), project.asResource(), Operation.READ)) { |
|
65 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
66 |
- } |
|
67 | 65 |
|
68 | 66 |
Form<SearchCondition> postParamForm = new Form<>(SearchCondition.class); |
69 | 67 |
SearchCondition searchCondition = postParamForm.bindFromRequest().get(); |
... | ... | @@ -90,14 +88,14 @@ |
90 | 88 |
* @param projectName 프로젝트 이름 |
91 | 89 |
* @return |
92 | 90 |
*/ |
93 |
- @With(NullProjectCheckAction.class) |
|
91 |
+ @IsCreatable(ResourceType.BOARD_POST) |
|
94 | 92 |
public static Result newPostForm(String userName, String projectName) { |
95 | 93 |
Project project = ProjectApp.getProject(userName, projectName); |
96 | 94 |
|
97 |
- boolean isAllowedToNotice = ProjectUser.isAllowedToNotice(UserApp.currentUser(), project); |
|
95 |
+ boolean isAllowedToNotice = |
|
96 |
+ AccessControl.isProjectResourceCreatable(UserApp.currentUser(), project, ResourceType.BOARD_NOTICE); |
|
98 | 97 |
|
99 |
- return newPostingForm(project, ResourceType.BOARD_POST, |
|
100 |
- create.render("post.new", new Form<>(Posting.class), project, isAllowedToNotice)); |
|
98 |
+ return ok(create.render("post.new", new Form<>(Posting.class), project, isAllowedToNotice)); |
|
101 | 99 |
} |
102 | 100 |
|
103 | 101 |
/** |
... | ... | @@ -112,17 +110,14 @@ |
112 | 110 |
* @return |
113 | 111 |
*/ |
114 | 112 |
@Transactional |
115 |
- @With(NullProjectCheckAction.class) |
|
113 |
+ @IsCreatable(ResourceType.BOARD_POST) |
|
116 | 114 |
public static Result newPost(String userName, String projectName) { |
117 | 115 |
Form<Posting> postForm = new Form<>(Posting.class).bindFromRequest(); |
118 | 116 |
Project project = ProjectApp.getProject(userName, projectName); |
119 | 117 |
|
120 |
- if (!AccessControl.isProjectResourceCreatable(UserApp.currentUser(), project, ResourceType.BOARD_POST)) { |
|
121 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
122 |
- } |
|
123 |
- |
|
124 | 118 |
if (postForm.hasErrors()) { |
125 |
- boolean isAllowedToNotice = ProjectUser.isAllowedToNotice(UserApp.currentUser(), project); |
|
119 |
+ boolean isAllowedToNotice = |
|
120 |
+ AccessControl.isProjectResourceCreatable(UserApp.currentUser(), project, ResourceType.BOARD_NOTICE); |
|
126 | 121 |
return badRequest(create.render("error.validation", postForm, project, isAllowedToNotice)); |
127 | 122 |
} |
128 | 123 |
|
... | ... | @@ -162,18 +157,10 @@ |
162 | 157 |
* @param number 게시물number |
163 | 158 |
* @return |
164 | 159 |
*/ |
165 |
- @With(NullProjectCheckAction.class) |
|
160 |
+ @IsAllowed(value = Operation.READ, resourceType = ResourceType.BOARD_POST) |
|
166 | 161 |
public static Result post(String userName, String projectName, Long number) { |
167 | 162 |
Project project = Project.findByOwnerAndProjectName(userName, projectName); |
168 |
- |
|
169 | 163 |
Posting post = Posting.findByNumber(project, number); |
170 |
- if (post == null) { |
|
171 |
- return notFound(ErrorViews.NotFound.render("error.notfound", project, "post")); |
|
172 |
- } |
|
173 |
- |
|
174 |
- if (!AccessControl.isAllowed(UserApp.currentUser(), post.asResource(), Operation.READ)) { |
|
175 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
176 |
- } |
|
177 | 164 |
|
178 | 165 |
if(request().getHeader("Accept").contains("application/json")) { |
179 | 166 |
ObjectNode json = Json.newObject(); |
... | ... | @@ -200,18 +187,10 @@ |
200 | 187 |
* @param number 게시물number |
201 | 188 |
* @return |
202 | 189 |
*/ |
203 |
- @With(NullProjectCheckAction.class) |
|
190 |
+ @IsAllowed(value = Operation.UPDATE, resourceType = ResourceType.BOARD_POST) |
|
204 | 191 |
public static Result editPostForm(String owner, String projectName, Long number) { |
205 | 192 |
Project project = Project.findByOwnerAndProjectName(owner, projectName); |
206 |
- |
|
207 | 193 |
Posting posting = Posting.findByNumber(project, number); |
208 |
- if (posting == null) { |
|
209 |
- return notFound(ErrorViews.NotFound.render("error.notfound", project, "post")); |
|
210 |
- } |
|
211 |
- |
|
212 |
- if (!AccessControl.isAllowed(UserApp.currentUser(), posting.asResource(), Operation.UPDATE)) { |
|
213 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
214 |
- } |
|
215 | 194 |
|
216 | 195 |
Form<Posting> editForm = new Form<>(Posting.class).fill(posting); |
217 | 196 |
boolean isAllowedToNotice = ProjectUser.isAllowedToNotice(UserApp.currentUser(), project); |
... | ... | @@ -239,7 +218,8 @@ |
239 | 218 |
Project project = ProjectApp.getProject(userName, projectName); |
240 | 219 |
|
241 | 220 |
if (postForm.hasErrors()) { |
242 |
- boolean isAllowedToNotice = ProjectUser.isAllowedToNotice(UserApp.currentUser(), project); |
|
221 |
+ boolean isAllowedToNotice = |
|
222 |
+ AccessControl.isProjectResourceCreatable(UserApp.currentUser(), project, ResourceType.BOARD_NOTICE); |
|
243 | 223 |
return badRequest(edit.render("error.validation", postForm, Posting.findByNumber(project, number), number, project, isAllowedToNotice)); |
244 | 224 |
} |
245 | 225 |
|
... | ... | @@ -270,7 +250,7 @@ |
270 | 250 |
* @see controllers.AbstractPostingApp#delete(play.db.ebean.Model, models.resource.Resource, play.mvc.Call) |
271 | 251 |
*/ |
272 | 252 |
@Transactional |
273 |
- @With(NullProjectCheckAction.class) |
|
253 |
+ @IsAllowed(value = Operation.DELETE, resourceType = ResourceType.BOARD_POST) |
|
274 | 254 |
public static Result deletePost(String owner, String projectName, Long number) { |
275 | 255 |
Project project = Project.findByOwnerAndProjectName(owner, projectName); |
276 | 256 |
Posting posting = Posting.findByNumber(project, number); |
... | ... | @@ -295,24 +275,17 @@ |
295 | 275 |
* @see controllers.AbstractPostingApp#newComment(models.Comment, play.data.Form, play.mvc.Call, Runnable) |
296 | 276 |
*/ |
297 | 277 |
@Transactional |
298 |
- @With(NullProjectCheckAction.class) |
|
278 |
+ @IsAllowed(value = Operation.READ, resourceType = ResourceType.BOARD_POST) |
|
279 |
+ @IsCreatable(ResourceType.NONISSUE_COMMENT) |
|
299 | 280 |
public static Result newComment(String owner, String projectName, Long number) throws IOException { |
300 | 281 |
Project project = Project.findByOwnerAndProjectName(owner, projectName); |
301 | 282 |
final Posting posting = Posting.findByNumber(project, number); |
302 |
- if (posting == null) { |
|
303 |
- return notFound(ErrorViews.NotFound.render("error.notfound")); |
|
304 |
- } |
|
305 | 283 |
Call redirectTo = routes.BoardApp.post(project.owner, project.name, number); |
306 | 284 |
Form<PostingComment> commentForm = new Form<>(PostingComment.class) |
307 | 285 |
.bindFromRequest(); |
308 | 286 |
|
309 | 287 |
if (commentForm.hasErrors()) { |
310 | 288 |
return badRequest(views.html.error.badrequest.render("error.validation", project)); |
311 |
- } |
|
312 |
- |
|
313 |
- if (!AccessControl.isProjectResourceCreatable( |
|
314 |
- UserApp.currentUser(), project, ResourceType.NONISSUE_COMMENT)) { |
|
315 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
316 | 289 |
} |
317 | 290 |
|
318 | 291 |
final PostingComment comment = commentForm.get(); |
... | ... | @@ -344,8 +317,7 @@ |
344 | 317 |
public static Result deleteComment(String userName, String projectName, Long number, Long commentId) { |
345 | 318 |
Comment comment = PostingComment.find.byId(commentId); |
346 | 319 |
Project project = comment.asResource().getProject(); |
347 |
- Call redirectTo = |
|
348 |
- routes.BoardApp.post(project.owner, project.name, number); |
|
320 |
+ Call redirectTo = routes.BoardApp.post(project.owner, project.name, number); |
|
349 | 321 |
|
350 | 322 |
return delete(comment, comment.asResource(), redirectTo); |
351 | 323 |
} |
--- app/controllers/BranchApp.java
+++ app/controllers/BranchApp.java
... | ... | @@ -20,7 +20,8 @@ |
20 | 20 |
*/ |
21 | 21 |
package controllers; |
22 | 22 |
|
23 |
-import controllers.annotation.ProjectAccess; |
|
23 |
+import controllers.annotation.IsAllowed; |
|
24 |
+import controllers.annotation.IsOnlyGitAvailable; |
|
24 | 25 |
import models.Project; |
25 | 26 |
import models.enumeration.Operation; |
26 | 27 |
import org.apache.commons.collections.CollectionUtils; |
... | ... | @@ -39,6 +40,7 @@ |
39 | 40 |
/** |
40 | 41 |
* @author Keesun Baik |
41 | 42 |
*/ |
43 |
+@IsOnlyGitAvailable |
|
42 | 44 |
public class BranchApp extends Controller { |
43 | 45 |
|
44 | 46 |
/** |
... | ... | @@ -50,7 +52,7 @@ |
50 | 52 |
* @throws IOException |
51 | 53 |
* @throws GitAPIException |
52 | 54 |
*/ |
53 |
- @ProjectAccess(value = Operation.READ, isGitOnly = true) |
|
55 |
+ @IsAllowed(Operation.READ) |
|
54 | 56 |
public static Result branches(String loginId, String projectName) throws IOException, GitAPIException { |
55 | 57 |
Project project = Project.findByOwnerAndProjectName(loginId, projectName); |
56 | 58 |
GitRepository gitRepository = new GitRepository(project); |
... | ... | @@ -80,7 +82,7 @@ |
80 | 82 |
* @throws IOException |
81 | 83 |
* @throws GitAPIException |
82 | 84 |
*/ |
83 |
- @ProjectAccess(value = Operation.DELETE, isGitOnly = true) |
|
85 |
+ @IsAllowed(Operation.DELETE) |
|
84 | 86 |
public static Result deleteBranch(String loginId, String projectName, String branchName) throws GitAPIException { |
85 | 87 |
Project project = Project.findByOwnerAndProjectName(loginId, projectName); |
86 | 88 |
Repository repository = GitRepository.buildGitRepository(project); |
... | ... | @@ -96,7 +98,7 @@ |
96 | 98 |
* @param branchName |
97 | 99 |
* @return |
98 | 100 |
*/ |
99 |
- @ProjectAccess(value = Operation.UPDATE, isGitOnly = true) |
|
101 |
+ @IsAllowed(Operation.UPDATE) |
|
100 | 102 |
public static Result setAsDefault(String loginId, String projectName, String branchName) throws IOException, GitAPIException { |
101 | 103 |
Project project = Project.findByOwnerAndProjectName(loginId, projectName); |
102 | 104 |
GitRepository gitRepository = new GitRepository(project); |
--- app/controllers/CodeApp.java
+++ app/controllers/CodeApp.java
... | ... | @@ -1,6 +1,7 @@ |
1 | 1 |
package controllers; |
2 | 2 |
|
3 | 3 |
import actions.NullProjectCheckAction; |
4 |
+import controllers.annotation.IsAllowed; |
|
4 | 5 |
import models.Project; |
5 | 6 |
import models.enumeration.Operation; |
6 | 7 |
import org.apache.tika.Tika; |
... | ... | @@ -13,7 +14,6 @@ |
13 | 14 |
import play.mvc.With; |
14 | 15 |
import playRepository.PlayRepository; |
15 | 16 |
import playRepository.RepositoryService; |
16 |
-import utils.AccessControl; |
|
17 | 17 |
import utils.ErrorViews; |
18 | 18 |
import views.html.code.nohead; |
19 | 19 |
import views.html.code.nohead_svn; |
... | ... | @@ -35,14 +35,10 @@ |
35 | 35 |
* @param userName 프로젝트 소유자 이름 |
36 | 36 |
* @param projectName 프로젝트 이름 |
37 | 37 |
*/ |
38 |
- @With(NullProjectCheckAction.class) |
|
38 |
+ @IsAllowed(Operation.READ) |
|
39 | 39 |
public static Result codeBrowser(String userName, String projectName) |
40 | 40 |
throws IOException, UnsupportedOperationException, ServletException { |
41 | 41 |
Project project = ProjectApp.getProject(userName, projectName); |
42 |
- |
|
43 |
- if (!AccessControl.isAllowed(UserApp.currentUser(), project.asResource(), Operation.READ)) { |
|
44 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
45 |
- } |
|
46 | 42 |
|
47 | 43 |
if (!RepositoryService.VCS_GIT.equals(project.vcs) && !RepositoryService.VCS_SUBVERSION.equals(project.vcs)) { |
48 | 44 |
return status(Http.Status.NOT_IMPLEMENTED, project.vcs + " is not supported!"); |
--- app/controllers/CodeHistoryApp.java
+++ app/controllers/CodeHistoryApp.java
... | ... | @@ -1,6 +1,8 @@ |
1 | 1 |
package controllers; |
2 | 2 |
|
3 | 3 |
import actions.NullProjectCheckAction; |
4 |
+import controllers.annotation.IsAllowed; |
|
5 |
+import controllers.annotation.IsCreatable; |
|
4 | 6 |
import models.Attachment; |
5 | 7 |
import models.CommitComment; |
6 | 8 |
import models.NotificationEvent; |
... | ... | @@ -20,7 +22,6 @@ |
20 | 22 |
import playRepository.FileDiff; |
21 | 23 |
import playRepository.PlayRepository; |
22 | 24 |
import playRepository.RepositoryService; |
23 |
-import utils.AccessControl; |
|
24 | 25 |
import utils.ErrorViews; |
25 | 26 |
import utils.HttpUtil; |
26 | 27 |
import utils.PullRequestCommit; |
... | ... | @@ -28,9 +29,7 @@ |
28 | 29 |
import views.html.code.history; |
29 | 30 |
import views.html.code.nohead; |
30 | 31 |
import views.html.code.svnDiff; |
31 |
-import views.html.error.forbidden; |
|
32 | 32 |
import views.html.error.notfound; |
33 |
-import views.html.error.notfound_default; |
|
34 | 33 |
|
35 | 34 |
import javax.servlet.ServletException; |
36 | 35 |
import java.io.IOException; |
... | ... | @@ -87,17 +86,12 @@ |
87 | 86 |
* @throws GitAPIException |
88 | 87 |
* @throws SVNException |
89 | 88 |
*/ |
90 |
- @With(NullProjectCheckAction.class) |
|
89 |
+ @IsAllowed(Operation.READ) |
|
91 | 90 |
public static Result history(String ownerName, String projectName, String branch, String path) throws IOException, |
92 | 91 |
UnsupportedOperationException, ServletException, GitAPIException, |
93 | 92 |
SVNException { |
94 | 93 |
Project project = Project.findByOwnerAndProjectName(ownerName, projectName); |
95 |
- |
|
96 | 94 |
PlayRepository repository = RepositoryService.getRepository(project); |
97 |
- |
|
98 |
- if (!AccessControl.isAllowed(UserApp.currentUser(), project.asResource(), Operation.READ)) { |
|
99 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
100 |
- } |
|
101 | 95 |
|
102 | 96 |
String pageStr = HttpUtil.getFirstValueFromQuery(request().queryString(), "page"); |
103 | 97 |
int page = 0; |
... | ... | @@ -136,16 +130,11 @@ |
136 | 130 |
* @throws GitAPIException |
137 | 131 |
* @throws SVNException |
138 | 132 |
*/ |
139 |
- @With(NullProjectCheckAction.class) |
|
133 |
+ @IsAllowed(Operation.READ) |
|
140 | 134 |
public static Result show(String ownerName, String projectName, String commitId) |
141 | 135 |
throws IOException, UnsupportedOperationException, ServletException, GitAPIException, |
142 | 136 |
SVNException { |
143 | 137 |
Project project = Project.findByOwnerAndProjectName(ownerName, projectName); |
144 |
- |
|
145 |
- if (!AccessControl.isAllowed(UserApp.currentUser(), project.asResource(), Operation.READ)) { |
|
146 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
147 |
- } |
|
148 |
- |
|
149 | 138 |
PlayRepository repository = RepositoryService.getRepository(project); |
150 | 139 |
Commit commit = repository.getCommit(commitId); |
151 | 140 |
|
... | ... | @@ -179,7 +168,7 @@ |
179 | 168 |
} |
180 | 169 |
} |
181 | 170 |
|
182 |
- @With(NullProjectCheckAction.class) |
|
171 |
+ @IsCreatable(ResourceType.COMMIT_COMMENT) |
|
183 | 172 |
public static Result newComment(String ownerName, String projectName, String commitId) |
184 | 173 |
throws IOException, ServletException, SVNException { |
185 | 174 |
Form<CommitComment> codeCommentForm = new Form<>(CommitComment.class) |
... | ... | @@ -193,11 +182,6 @@ |
193 | 182 |
|
194 | 183 |
if (RepositoryService.getRepository(project).getCommit(commitId) == null) { |
195 | 184 |
return notFound(notfound.render("error.notfound", project, request().path())); |
196 |
- } |
|
197 |
- |
|
198 |
- if (!AccessControl.isProjectResourceCreatable(UserApp.currentUser(), project, |
|
199 |
- ResourceType.COMMIT_COMMENT)) { |
|
200 |
- return forbidden(forbidden.render("error.forbidden", project)); |
|
201 | 185 |
} |
202 | 186 |
|
203 | 187 |
CommitComment codeComment = codeCommentForm.get(); |
... | ... | @@ -227,19 +211,10 @@ |
227 | 211 |
} |
228 | 212 |
|
229 | 213 |
@With(NullProjectCheckAction.class) |
214 |
+ @IsAllowed(value = Operation.DELETE, resourceType = ResourceType.COMMIT_COMMENT) |
|
230 | 215 |
public static Result deleteComment(String ownerName, String projectName, String commitId, |
231 | 216 |
Long id) { |
232 | 217 |
CommitComment codeComment = CommitComment.find.byId(id); |
233 |
- |
|
234 |
- if (codeComment == null) { |
|
235 |
- return notFound(notfound_default.render(request().path())); |
|
236 |
- } |
|
237 |
- |
|
238 |
- if (!AccessControl.isAllowed(UserApp.currentUser(), codeComment.asResource(), |
|
239 |
- Operation.DELETE)) { |
|
240 |
- return forbidden(forbidden.render("error.forbidden", codeComment.project)); |
|
241 |
- } |
|
242 |
- |
|
243 | 218 |
codeComment.delete(); |
244 | 219 |
|
245 | 220 |
Call toView = routes.CodeHistoryApp.show(ownerName, projectName, commitId); |
--- app/controllers/EnrollProjectApp.java
+++ app/controllers/EnrollProjectApp.java
... | ... | @@ -1,5 +1,7 @@ |
1 | 1 |
package controllers; |
2 | 2 |
|
3 |
+import actions.AnonymousCheckAction; |
|
4 |
+import actions.NullProjectCheckAction; |
|
3 | 5 |
import models.NotificationEvent; |
4 | 6 |
import models.Project; |
5 | 7 |
import models.ProjectUser; |
... | ... | @@ -8,10 +10,12 @@ |
8 | 10 |
import play.db.ebean.Transactional; |
9 | 11 |
import play.mvc.Controller; |
10 | 12 |
import play.mvc.Result; |
13 |
+import play.mvc.With; |
|
11 | 14 |
|
12 | 15 |
/** |
13 | 16 |
* 프로젝트에 멤버로 등록해달라는 요청을 처리하는 컨트롤러 |
14 | 17 |
*/ |
18 |
+@With(AnonymousCheckAction.class) |
|
15 | 19 |
public class EnrollProjectApp extends Controller { |
16 | 20 |
|
17 | 21 |
/** |
... | ... | @@ -23,11 +27,9 @@ |
23 | 27 |
* @return |
24 | 28 |
*/ |
25 | 29 |
@Transactional |
30 |
+ @With(NullProjectCheckAction.class) |
|
26 | 31 |
public static Result enroll(String loginId, String projectName) { |
27 | 32 |
Project project = Project.findByOwnerAndProjectName(loginId, projectName); |
28 |
- if(project == null) { |
|
29 |
- return badRequest(); |
|
30 |
- } |
|
31 | 33 |
|
32 | 34 |
User user = UserApp.currentUser(); |
33 | 35 |
if (!ProjectUser.isGuest(project, user)) { |
... | ... | @@ -51,11 +53,9 @@ |
51 | 53 |
* @return |
52 | 54 |
*/ |
53 | 55 |
@Transactional |
56 |
+ @With(NullProjectCheckAction.class) |
|
54 | 57 |
public static Result cancelEnroll(String loginId, String proejctName) { |
55 | 58 |
Project project = Project.findByOwnerAndProjectName(loginId, proejctName); |
56 |
- if(project == null) { |
|
57 |
- return badRequest(); |
|
58 |
- } |
|
59 | 59 |
|
60 | 60 |
User user = UserApp.currentUser(); |
61 | 61 |
if (!ProjectUser.isGuest(project, user)) { |
--- app/controllers/IssueApp.java
+++ app/controllers/IssueApp.java
... | ... | @@ -3,18 +3,16 @@ |
3 | 3 |
import actions.NullProjectCheckAction; |
4 | 4 |
import com.avaje.ebean.ExpressionList; |
5 | 5 |
import com.avaje.ebean.Page; |
6 |
- |
|
7 |
-import controllers.annotation.ProjectAccess; |
|
6 |
+import controllers.annotation.IsAllowed; |
|
7 |
+import controllers.annotation.IsCreatable; |
|
8 | 8 |
import jxl.write.WriteException; |
9 | 9 |
import models.*; |
10 | 10 |
import models.enumeration.Operation; |
11 | 11 |
import models.enumeration.ResourceType; |
12 | 12 |
import models.enumeration.State; |
13 |
- |
|
14 | 13 |
import org.apache.commons.lang.StringUtils; |
15 | 14 |
import org.apache.tika.Tika; |
16 | 15 |
import org.codehaus.jackson.node.ObjectNode; |
17 |
- |
|
18 | 16 |
import play.data.Form; |
19 | 17 |
import play.db.ebean.Transactional; |
20 | 18 |
import play.i18n.Messages; |
... | ... | @@ -53,7 +51,7 @@ |
53 | 51 |
* @throws WriteException |
54 | 52 |
* @throws IOException |
55 | 53 |
*/ |
56 |
- @ProjectAccess(Operation.READ) |
|
54 |
+ @IsAllowed(Operation.READ) |
|
57 | 55 |
public static Result issues(String ownerName, String projectName, String state, String format, int pageNum) throws WriteException, IOException { |
58 | 56 |
Project project = ProjectApp.getProject(ownerName, projectName); |
59 | 57 |
|
... | ... | @@ -230,7 +228,7 @@ |
230 | 228 |
result.put("body", Messages.get("error.notfound.issue")); |
231 | 229 |
return ok(result); |
232 | 230 |
} else { |
233 |
- return notFound(ErrorViews.NotFound.render("error.notfound", project, "issue")); |
|
231 |
+ return notFound(ErrorViews.NotFound.render("error.notfound", project, ResourceType.ISSUE_POST.resource())); |
|
234 | 232 |
} |
235 | 233 |
} |
236 | 234 |
|
... | ... | @@ -278,18 +276,10 @@ |
278 | 276 |
* @param number 이슈 번호 |
279 | 277 |
* @return |
280 | 278 |
*/ |
281 |
- @With(NullProjectCheckAction.class) |
|
279 |
+ @IsAllowed(resourceType = ResourceType.ISSUE_POST, value = Operation.READ) |
|
282 | 280 |
public static Result timeline(String ownerName, String projectName, Long number) { |
283 | 281 |
Project project = ProjectApp.getProject(ownerName, projectName); |
284 |
- |
|
285 | 282 |
Issue issueInfo = Issue.findByNumber(project, number); |
286 |
- if (issueInfo == null) { |
|
287 |
- return notFound(ErrorViews.NotFound.render("error.notfound", project, "issue")); |
|
288 |
- } |
|
289 |
- |
|
290 |
- if (!AccessControl.isAllowed(UserApp.currentUser(), issueInfo.asResource(), Operation.READ)) { |
|
291 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
292 |
- } |
|
293 | 283 |
|
294 | 284 |
for (IssueLabel label: issueInfo.labels) { |
295 | 285 |
label.refresh(); |
... | ... | @@ -306,14 +296,11 @@ |
306 | 296 |
* @param ownerName 프로젝트 소유자 이름 |
307 | 297 |
* @param projectName 프로젝트 이름 |
308 | 298 |
* @return |
309 |
- * @see {@link AbstractPostingApp#newPostingForm(Project, ResourceType, play.mvc.Content)} |
|
310 | 299 |
*/ |
311 |
- @With(NullProjectCheckAction.class) |
|
300 |
+ @IsCreatable(ResourceType.ISSUE_POST) |
|
312 | 301 |
public static Result newIssueForm(String ownerName, String projectName) { |
313 | 302 |
Project project = ProjectApp.getProject(ownerName, projectName); |
314 |
- |
|
315 |
- return newPostingForm(project, ResourceType.ISSUE_POST, |
|
316 |
- create.render("title.newIssue", new Form<>(Issue.class), project)); |
|
303 |
+ return ok(create.render("title.newIssue", new Form<>(Issue.class), project)); |
|
317 | 304 |
} |
318 | 305 |
|
319 | 306 |
/** |
... | ... | @@ -446,14 +433,10 @@ |
446 | 433 |
* @throws IOException |
447 | 434 |
*/ |
448 | 435 |
@Transactional |
449 |
- @With(NullProjectCheckAction.class) |
|
436 |
+ @IsCreatable(ResourceType.ISSUE_POST) |
|
450 | 437 |
public static Result newIssue(String ownerName, String projectName) { |
451 | 438 |
Form<Issue> issueForm = new Form<>(Issue.class).bindFromRequest(); |
452 | 439 |
Project project = ProjectApp.getProject(ownerName, projectName); |
453 |
- |
|
454 |
- if (!AccessControl.isProjectResourceCreatable(UserApp.currentUser(), project, ResourceType.ISSUE_POST)) { |
|
455 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
456 |
- } |
|
457 | 440 |
|
458 | 441 |
if (issueForm.hasErrors()) { |
459 | 442 |
return badRequest(create.render("error.validation", issueForm, project)); |
... | ... | @@ -498,16 +481,10 @@ |
498 | 481 |
* @param number 이슈 번호 |
499 | 482 |
* @return |
500 | 483 |
*/ |
501 |
- @With(NullProjectCheckAction.class) |
|
484 |
+ @IsAllowed(resourceType = ResourceType.ISSUE_POST, value = Operation.UPDATE) |
|
502 | 485 |
public static Result editIssueForm(String ownerName, String projectName, Long number) { |
503 | 486 |
Project project = ProjectApp.getProject(ownerName, projectName); |
504 |
- |
|
505 | 487 |
Issue issue = Issue.findByNumber(project, number); |
506 |
- |
|
507 |
- if (!AccessControl.isAllowed(UserApp.currentUser(), issue.asResource(), Operation.UPDATE)) { |
|
508 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
509 |
- } |
|
510 |
- |
|
511 | 488 |
Form<Issue> editForm = new Form<>(Issue.class).fill(issue); |
512 | 489 |
|
513 | 490 |
return ok(edit.render("title.editIssue", editForm, issue, project)); |
... | ... | @@ -528,16 +505,13 @@ |
528 | 505 |
* @throws IOException |
529 | 506 |
*/ |
530 | 507 |
@Transactional |
531 |
- @With(NullProjectCheckAction.class) |
|
508 |
+ @IsAllowed(value = Operation.UPDATE, resourceType = ResourceType.ISSUE_POST) |
|
532 | 509 |
public static Result nextState(String ownerName, String projectName, Long number) { |
533 | 510 |
Project project = ProjectApp.getProject(ownerName, projectName); |
534 | 511 |
|
535 | 512 |
final Issue issue = Issue.findByNumber(project, number); |
536 | 513 |
|
537 | 514 |
Call redirectTo = routes.IssueApp.issue(project.owner, project.name, number); |
538 |
- if (!AccessControl.isAllowed(UserApp.currentUser(), issue.asResource(), Operation.UPDATE)) { |
|
539 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", issue.project)); |
|
540 |
- } |
|
541 | 515 |
issue.toNextState(); |
542 | 516 |
NotificationEvent notiEvent = NotificationEvent.afterStateChanged(issue.previousState(), issue, redirectTo.url()); |
543 | 517 |
IssueEvent.addFromNotificationEvent(notiEvent, issue, UserApp.currentUser().loginId); |
... | ... | @@ -635,7 +609,7 @@ |
635 | 609 |
* @ see {@link AbstractPostingApp#delete(play.db.ebean.Model, models.resource.Resource, Call)} |
636 | 610 |
*/ |
637 | 611 |
@Transactional |
638 |
- @With(NullProjectCheckAction.class) |
|
612 |
+ @IsAllowed(value = Operation.DELETE, resourceType = ResourceType.ISSUE_POST) |
|
639 | 613 |
public static Result deleteIssue(String ownerName, String projectName, Long number) { |
640 | 614 |
Project project = ProjectApp.getProject(ownerName, projectName); |
641 | 615 |
Issue issue = Issue.findByNumber(project, number); |
... | ... | @@ -660,29 +634,17 @@ |
660 | 634 |
* @see {@link AbstractPostingApp#newComment(models.Comment, play.data.Form} |
661 | 635 |
*/ |
662 | 636 |
@Transactional |
663 |
- @With(NullProjectCheckAction.class) |
|
637 |
+ @IsCreatable(ResourceType.ISSUE_COMMENT) |
|
664 | 638 |
public static Result newComment(String ownerName, String projectName, Long number) throws IOException { |
665 | 639 |
Project project = Project.findByOwnerAndProjectName(ownerName, projectName); |
666 |
- |
|
667 | 640 |
final Issue issue = Issue.findByNumber(project, number); |
668 |
- if (issue == null) { |
|
669 |
- return notFound(ErrorViews.NotFound.render("error.notfound")); |
|
670 |
- } |
|
671 | 641 |
Call redirectTo = routes.IssueApp.issue(project.owner, project.name, number); |
672 |
- Form<IssueComment> commentForm = new Form<>(IssueComment.class) |
|
673 |
- .bindFromRequest(); |
|
642 |
+ Form<IssueComment> commentForm = new Form<>(IssueComment.class).bindFromRequest(); |
|
674 | 643 |
|
675 | 644 |
if (commentForm.hasErrors()) { |
676 | 645 |
return badRequest(ErrorViews.BadRequest.render("error.validation", project)); |
677 | 646 |
} |
678 |
- |
|
679 |
- if (!AccessControl.isProjectResourceCreatable( |
|
680 |
- UserApp.currentUser(), project, ResourceType.ISSUE_COMMENT)) { |
|
681 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
682 |
- } |
|
683 |
- |
|
684 | 647 |
final IssueComment comment = commentForm.get(); |
685 |
- |
|
686 | 648 |
return newComment(comment, commentForm, redirectTo, new Runnable() { |
687 | 649 |
@Override |
688 | 650 |
public void run() { |
--- app/controllers/IssueLabelApp.java
+++ app/controllers/IssueLabelApp.java
... | ... | @@ -1,6 +1,7 @@ |
1 | 1 |
package controllers; |
2 | 2 |
|
3 |
-import actions.NullProjectCheckAction; |
|
3 |
+import controllers.annotation.IsAllowed; |
|
4 |
+import controllers.annotation.IsCreatable; |
|
4 | 5 |
import models.IssueLabel; |
5 | 6 |
import models.Project; |
6 | 7 |
import models.enumeration.Operation; |
... | ... | @@ -11,8 +12,6 @@ |
11 | 12 |
import play.mvc.Controller; |
12 | 13 |
import play.mvc.Http; |
13 | 14 |
import play.mvc.Result; |
14 |
-import play.mvc.With; |
|
15 |
-import utils.AccessControl; |
|
16 | 15 |
import utils.ErrorViews; |
17 | 16 |
|
18 | 17 |
import java.util.ArrayList; |
... | ... | @@ -43,17 +42,13 @@ |
43 | 42 |
* @param projectName 프로젝트의 이름 |
44 | 43 |
* @return 이슈라벨들을 달라는 요청에 대한 응답 |
45 | 44 |
*/ |
46 |
- @With(NullProjectCheckAction.class) |
|
45 |
+ @IsAllowed(Operation.READ) |
|
47 | 46 |
public static Result labels(String ownerName, String projectName) { |
48 | 47 |
if (!request().accepts("application/json")) { |
49 | 48 |
return status(Http.Status.NOT_ACCEPTABLE); |
50 | 49 |
} |
51 | 50 |
|
52 | 51 |
Project project = ProjectApp.getProject(ownerName, projectName); |
53 |
- |
|
54 |
- if (!AccessControl.isAllowed(UserApp.currentUser(), project.asResource(), Operation.READ)) { |
|
55 |
- return forbidden("You have no permission to access the project '" + project + "'."); |
|
56 |
- } |
|
57 | 52 |
|
58 | 53 |
List<Map<String, String>> labels = new ArrayList<>(); |
59 | 54 |
for (IssueLabel label : IssueLabel.findByProject(project)) { |
... | ... | @@ -93,16 +88,10 @@ |
93 | 88 |
* @return 이슈라벨을 추가해달라는 요청에 대한 응답 |
94 | 89 |
*/ |
95 | 90 |
@Transactional |
96 |
- @With(NullProjectCheckAction.class) |
|
91 |
+ @IsCreatable(ResourceType.ISSUE_LABEL) |
|
97 | 92 |
public static Result newLabel(String ownerName, String projectName) { |
98 | 93 |
Form<IssueLabel> labelForm = new Form<>(IssueLabel.class).bindFromRequest(); |
99 |
- |
|
100 | 94 |
Project project = ProjectApp.getProject(ownerName, projectName); |
101 |
- |
|
102 |
- if (!AccessControl.isProjectResourceCreatable(UserApp.currentUser(), project, ResourceType.ISSUE_LABEL)) { |
|
103 |
- return forbidden(ErrorViews.Forbidden.render("You have no permission to add an issue label to the project '" + |
|
104 |
- project + "'.", project)); |
|
105 |
- } |
|
106 | 95 |
|
107 | 96 |
IssueLabel label = labelForm.get(); |
108 | 97 |
label.project = project; |
... | ... | @@ -147,7 +136,7 @@ |
147 | 136 |
* @return 이슈라벨을 삭제해달라는 요청에 대한 응답 |
148 | 137 |
*/ |
149 | 138 |
@Transactional |
150 |
- @With(NullProjectCheckAction.class) |
|
139 |
+ @IsAllowed(value = Operation.DELETE, resourceType = ResourceType.ISSUE_LABEL) |
|
151 | 140 |
public static Result delete(String ownerName, String projectName, Long id) { |
152 | 141 |
// _method must be 'delete' |
153 | 142 |
DynamicForm bindedForm = form().bindFromRequest(); |
... | ... | @@ -157,17 +146,7 @@ |
157 | 146 |
} |
158 | 147 |
|
159 | 148 |
IssueLabel label = IssueLabel.finder.byId(id); |
160 |
- |
|
161 |
- if (label == null) { |
|
162 |
- return notFound(ErrorViews.NotFound.render("The label #" + id + " is not found.")); |
|
163 |
- } |
|
164 |
- |
|
165 |
- if (!AccessControl.isAllowed(UserApp.currentUser(), label.asResource(), Operation.DELETE)) { |
|
166 |
- return forbidden(ErrorViews.Forbidden.render("You have no permission to delete the label #" + label.id + ".", label.project)); |
|
167 |
- } |
|
168 |
- |
|
169 | 149 |
label.delete(); |
170 |
- |
|
171 | 150 |
return ok(); |
172 | 151 |
} |
173 | 152 |
} |
--- app/controllers/MilestoneApp.java
+++ app/controllers/MilestoneApp.java
... | ... | @@ -1,20 +1,28 @@ |
1 | 1 |
package controllers; |
2 | 2 |
|
3 |
-import actions.NullProjectCheckAction; |
|
4 |
-import models.*; |
|
5 |
-import models.enumeration.*; |
|
6 |
-import play.data.*; |
|
3 |
+import controllers.annotation.IsAllowed; |
|
4 |
+import controllers.annotation.IsCreatable; |
|
5 |
+import models.Attachment; |
|
6 |
+import models.Milestone; |
|
7 |
+import models.Project; |
|
8 |
+import models.enumeration.Direction; |
|
9 |
+import models.enumeration.Operation; |
|
10 |
+import models.enumeration.ResourceType; |
|
11 |
+import models.enumeration.State; |
|
12 |
+import play.data.Form; |
|
7 | 13 |
import play.db.ebean.Transactional; |
8 |
-import play.mvc.*; |
|
14 |
+import play.mvc.Controller; |
|
15 |
+import play.mvc.Result; |
|
9 | 16 |
import utils.AccessControl; |
10 | 17 |
import utils.Constants; |
11 | 18 |
import utils.ErrorViews; |
12 | 19 |
import utils.HttpUtil; |
13 |
-import views.html.milestone.*; |
|
20 |
+import views.html.milestone.create; |
|
21 |
+import views.html.milestone.edit; |
|
22 |
+import views.html.milestone.list; |
|
23 |
+import views.html.milestone.view; |
|
14 | 24 |
|
15 |
-import java.util.*; |
|
16 |
- |
|
17 |
-import org.apache.commons.lang3.StringUtils; |
|
25 |
+import java.util.List; |
|
18 | 26 |
|
19 | 27 |
import static play.data.Form.form; |
20 | 28 |
|
... | ... | @@ -46,13 +54,9 @@ |
46 | 54 |
* @param projectName |
47 | 55 |
* @return |
48 | 56 |
*/ |
49 |
- @With(NullProjectCheckAction.class) |
|
57 |
+ @IsAllowed(Operation.READ) |
|
50 | 58 |
public static Result milestones(String userName, String projectName) { |
51 | 59 |
Project project = ProjectApp.getProject(userName, projectName); |
52 |
- if (!AccessControl.isAllowed(UserApp.currentUser(), project.asResource(), Operation.READ)) { |
|
53 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
54 |
- } |
|
55 |
- |
|
56 | 60 |
MilestoneCondition mCondition = form(MilestoneCondition.class).bindFromRequest().get(); |
57 | 61 |
|
58 | 62 |
List<Milestone> milestones = Milestone.findMilestones(project.id, |
... | ... | @@ -75,14 +79,9 @@ |
75 | 79 |
* @param projectName |
76 | 80 |
* @return |
77 | 81 |
*/ |
78 |
- @With(NullProjectCheckAction.class) |
|
82 |
+ @IsCreatable(ResourceType.MILESTONE) |
|
79 | 83 |
public static Result newMilestoneForm(String userName, String projectName) { |
80 | 84 |
Project project = ProjectApp.getProject(userName, projectName); |
81 |
- |
|
82 |
- if(!AccessControl.isProjectResourceCreatable(UserApp.currentUser(), project, ResourceType.MILESTONE)) { |
|
83 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
84 |
- } |
|
85 |
- |
|
86 | 85 |
return ok(create.render("title.newMilestone", new Form<>(Milestone.class), project)); |
87 | 86 |
} |
88 | 87 |
|
... | ... | @@ -103,14 +102,10 @@ |
103 | 102 |
* @see {@link #validate(models.Project, play.data.Form)} |
104 | 103 |
*/ |
105 | 104 |
@Transactional |
106 |
- @With(NullProjectCheckAction.class) |
|
105 |
+ @IsCreatable(ResourceType.MILESTONE) |
|
107 | 106 |
public static Result newMilestone(String userName, String projectName) { |
108 | 107 |
Form<Milestone> milestoneForm = new Form<>(Milestone.class).bindFromRequest(); |
109 | 108 |
Project project = ProjectApp.getProject(userName, projectName); |
110 |
- |
|
111 |
- if(!AccessControl.isProjectResourceCreatable(UserApp.currentUser(), project, ResourceType.MILESTONE)) { |
|
112 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
113 |
- } |
|
114 | 109 |
|
115 | 110 |
validate(project, milestoneForm); |
116 | 111 |
if (milestoneForm.hasErrors()) { |
... | ... | @@ -158,14 +153,10 @@ |
158 | 153 |
* @param milestoneId |
159 | 154 |
* @return |
160 | 155 |
*/ |
161 |
- @With(NullProjectCheckAction.class) |
|
156 |
+ @IsAllowed(value = Operation.UPDATE, resourceType = ResourceType.MILESTONE) |
|
162 | 157 |
public static Result editMilestoneForm(String userName, String projectName, Long milestoneId) { |
163 | 158 |
Project project = ProjectApp.getProject(userName, projectName); |
164 | 159 |
Milestone milestone = Milestone.findById(milestoneId); |
165 |
- |
|
166 |
- if(!AccessControl.isAllowed(UserApp.currentUser(), milestone.asResource(), Operation.UPDATE)) { |
|
167 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
168 |
- } |
|
169 | 160 |
|
170 | 161 |
Form<Milestone> editForm = new Form<>(Milestone.class).fill(milestone); |
171 | 162 |
return ok(edit.render("title.editMilestone", editForm, milestoneId, project)); |
... | ... | @@ -186,15 +177,11 @@ |
186 | 177 |
* @return |
187 | 178 |
*/ |
188 | 179 |
@Transactional |
189 |
- @With(NullProjectCheckAction.class) |
|
180 |
+ @IsAllowed(value = Operation.UPDATE, resourceType = ResourceType.MILESTONE) |
|
190 | 181 |
public static Result editMilestone(String userName, String projectName, Long milestoneId) { |
191 | 182 |
Project project = ProjectApp.getProject(userName, projectName); |
192 | 183 |
Form<Milestone> milestoneForm = new Form<>(Milestone.class).bindFromRequest(); |
193 | 184 |
Milestone original = Milestone.findById(milestoneId); |
194 |
- |
|
195 |
- if(!AccessControl.isAllowed(UserApp.currentUser(), original.asResource(), Operation.UPDATE)) { |
|
196 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
197 |
- } |
|
198 | 185 |
|
199 | 186 |
if(!original.title.equals(milestoneForm.field("title").value())) { |
200 | 187 |
validate(project, milestoneForm); |
... | ... | @@ -232,13 +219,11 @@ |
232 | 219 |
* @return |
233 | 220 |
*/ |
234 | 221 |
@Transactional |
235 |
- @With(NullProjectCheckAction.class) |
|
222 |
+ @IsAllowed(value = Operation.DELETE, resourceType = ResourceType.MILESTONE) |
|
236 | 223 |
public static Result deleteMilestone(String userName, String projectName, Long id) { |
237 | 224 |
Project project = ProjectApp.getProject(userName, projectName); |
238 | 225 |
Milestone milestone = Milestone.findById(id); |
239 |
- if(!AccessControl.isAllowed(UserApp.currentUser(), milestone.asResource(), Operation.DELETE)) { |
|
240 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
241 |
- } |
|
226 |
+ |
|
242 | 227 |
if(!project.id.equals(milestone.project.id)) { |
243 | 228 |
return internalServerError(); |
244 | 229 |
} |
... | ... | @@ -263,16 +248,10 @@ |
263 | 248 |
* @return |
264 | 249 |
*/ |
265 | 250 |
@Transactional |
266 |
- @With(NullProjectCheckAction.class) |
|
251 |
+ @IsAllowed(value = Operation.UPDATE, resourceType = ResourceType.MILESTONE) |
|
267 | 252 |
public static Result open(String userName, String projectName, Long id) { |
268 |
- Project project = ProjectApp.getProject(userName, projectName); |
|
269 | 253 |
Milestone milestone = Milestone.findById(id); |
270 |
- if(!AccessControl.isAllowed(UserApp.currentUser(), milestone.asResource(), Operation.UPDATE)) { |
|
271 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
272 |
- } |
|
273 |
- |
|
274 | 254 |
milestone.open(); |
275 |
- |
|
276 | 255 |
return redirect(routes.MilestoneApp.milestone(userName, projectName, id)); |
277 | 256 |
} |
278 | 257 |
|
... | ... | @@ -286,16 +265,10 @@ |
286 | 265 |
* @return |
287 | 266 |
*/ |
288 | 267 |
@Transactional |
289 |
- @With(NullProjectCheckAction.class) |
|
268 |
+ @IsAllowed(value = Operation.UPDATE, resourceType = ResourceType.MILESTONE) |
|
290 | 269 |
public static Result close(String userName, String projectName, Long id) { |
291 |
- Project project = ProjectApp.getProject(userName, projectName); |
|
292 | 270 |
Milestone milestone = Milestone.findById(id); |
293 |
- if(!AccessControl.isAllowed(UserApp.currentUser(), milestone.asResource(), Operation.UPDATE)) { |
|
294 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
295 |
- } |
|
296 |
- |
|
297 | 271 |
milestone.close(); |
298 |
- |
|
299 | 272 |
return redirect(routes.MilestoneApp.milestone(userName, projectName, id)); |
300 | 273 |
} |
301 | 274 |
|
... | ... | @@ -310,17 +283,10 @@ |
310 | 283 |
* @param id |
311 | 284 |
* @return |
312 | 285 |
*/ |
313 |
- @With(NullProjectCheckAction.class) |
|
286 |
+ @IsAllowed(value = Operation.READ, resourceType = ResourceType.MILESTONE) |
|
314 | 287 |
public static Result milestone(String userName, String projectName, Long id) { |
315 | 288 |
Project project = ProjectApp.getProject(userName, projectName); |
316 | 289 |
Milestone milestone = Milestone.findById(id); |
317 |
- if(milestone == null) { |
|
318 |
- return notFound(ErrorViews.NotFound.render("error.notfound")); |
|
319 |
- } |
|
320 |
- |
|
321 |
- if (!AccessControl.isAllowed(UserApp.currentUser(), milestone.asResource(), Operation.READ)) { |
|
322 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
323 |
- } |
|
324 | 290 |
|
325 | 291 |
String paramState = request().getQueryString("state"); |
326 | 292 |
State state = State.getValue(paramState); |
--- app/controllers/ProjectApp.java
+++ app/controllers/ProjectApp.java
... | ... | @@ -1,16 +1,15 @@ |
1 | 1 |
package controllers; |
2 | 2 |
|
3 | 3 |
import actions.AnonymousCheckAction; |
4 |
- |
|
5 | 4 |
import actions.NullProjectCheckAction; |
5 |
+import com.avaje.ebean.ExpressionList; |
|
6 | 6 |
import com.avaje.ebean.Junction; |
7 | 7 |
import com.avaje.ebean.Page; |
8 |
-import com.avaje.ebean.ExpressionList; |
|
9 |
- |
|
10 |
-import controllers.annotation.ProjectAccess; |
|
8 |
+import controllers.annotation.IsAllowed; |
|
11 | 9 |
import models.*; |
12 |
-import models.enumeration.*; |
|
13 |
- |
|
10 |
+import models.enumeration.Operation; |
|
11 |
+import models.enumeration.ResourceType; |
|
12 |
+import models.enumeration.RoleType; |
|
14 | 13 |
import org.apache.commons.collections.CollectionUtils; |
15 | 14 |
import org.apache.commons.lang3.StringUtils; |
16 | 15 |
import org.codehaus.jackson.JsonNode; |
... | ... | @@ -18,28 +17,28 @@ |
18 | 17 |
import org.eclipse.jgit.api.errors.GitAPIException; |
19 | 18 |
import org.eclipse.jgit.api.errors.NoHeadException; |
20 | 19 |
import org.tmatesoft.svn.core.SVNException; |
21 |
- |
|
22 | 20 |
import play.data.Form; |
23 | 21 |
import play.data.validation.ValidationError; |
24 | 22 |
import play.db.ebean.Transactional; |
25 | 23 |
import play.libs.Json; |
26 |
-import play.mvc.*; |
|
24 |
+import play.mvc.Controller; |
|
25 |
+import play.mvc.Http; |
|
27 | 26 |
import play.mvc.Http.MultipartFormData; |
28 | 27 |
import play.mvc.Http.MultipartFormData.FilePart; |
28 |
+import play.mvc.Result; |
|
29 |
+import play.mvc.With; |
|
29 | 30 |
import playRepository.Commit; |
30 | 31 |
import playRepository.PlayRepository; |
31 | 32 |
import playRepository.RepositoryService; |
32 | 33 |
import scala.reflect.io.FileOperationException; |
33 |
-import utils.AccessControl; |
|
34 |
-import utils.Constants; |
|
35 |
-import utils.HttpUtil; |
|
36 |
-import utils.ErrorViews; |
|
37 |
-import utils.LabelSearchUtil; |
|
34 |
+import utils.*; |
|
38 | 35 |
import validation.ExConstraints.RestrictedValidator; |
39 |
-import views.html.project.*; |
|
36 |
+import views.html.project.create; |
|
37 |
+import views.html.project.delete; |
|
38 |
+import views.html.project.overview; |
|
39 |
+import views.html.project.setting; |
|
40 | 40 |
|
41 | 41 |
import javax.servlet.ServletException; |
42 |
- |
|
43 | 42 |
import java.io.IOException; |
44 | 43 |
import java.security.NoSuchAlgorithmException; |
45 | 44 |
import java.util.*; |
... | ... | @@ -91,7 +90,7 @@ |
91 | 90 |
} |
92 | 91 |
|
93 | 92 |
@With(AnonymousCheckAction.class) |
94 |
- @ProjectAccess(Operation.UPDATE) |
|
93 |
+ @IsAllowed(Operation.UPDATE) |
|
95 | 94 |
public static Result projectOverviewUpdate(String ownerId, String projectName){ |
96 | 95 |
JsonNode json = request().body().asJson(); |
97 | 96 |
Project targetProject = Project.findByOwnerAndProjectName(ownerId, projectName); |
... | ... | @@ -120,14 +119,10 @@ |
120 | 119 |
* @throws SVNException the svn exception |
121 | 120 |
* @throws GitAPIException the git api exception |
122 | 121 |
*/ |
123 |
- @With(NullProjectCheckAction.class) |
|
122 |
+ @IsAllowed(Operation.READ) |
|
124 | 123 |
public static Result project(String loginId, String projectName) throws IOException, ServletException, SVNException, GitAPIException { |
125 | 124 |
Project project = Project.findByOwnerAndProjectName(loginId, projectName); |
126 | 125 |
project.fixInvalidForkData(); |
127 |
- |
|
128 |
- if (!AccessControl.isAllowed(UserApp.currentUser(), project.asResource(), Operation.READ)) { |
|
129 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
130 |
- } |
|
131 | 126 |
|
132 | 127 |
PlayRepository repository = RepositoryService.getRepository(project); |
133 | 128 |
|
... | ... | @@ -174,14 +169,9 @@ |
174 | 169 |
* @param projectName |
175 | 170 |
* @return 프로젝트 정보 |
176 | 171 |
*/ |
177 |
- @With(NullProjectCheckAction.class) |
|
172 |
+ @IsAllowed(Operation.UPDATE) |
|
178 | 173 |
public static Result settingForm(String loginId, String projectName) throws Exception { |
179 | 174 |
Project project = Project.findByOwnerAndProjectName(loginId, projectName); |
180 |
- |
|
181 |
- if (!AccessControl.isAllowed(UserApp.currentUser(), project.asResource(), Operation.UPDATE)) { |
|
182 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
183 |
- } |
|
184 |
- |
|
185 | 175 |
Form<Project> projectForm = form(Project.class).fill(project); |
186 | 176 |
PlayRepository repository = RepositoryService.getRepository(project); |
187 | 177 |
return ok(setting.render("title.projectSetting", projectForm, project, repository.getBranches())); |
... | ... | @@ -340,14 +330,9 @@ |
340 | 330 |
* @param projectName the project name |
341 | 331 |
* @return 프로젝트폼, 프로젝트 정보 |
342 | 332 |
*/ |
343 |
- @With(NullProjectCheckAction.class) |
|
333 |
+ @IsAllowed(Operation.DELETE) |
|
344 | 334 |
public static Result deleteForm(String loginId, String projectName) { |
345 | 335 |
Project project = Project.findByOwnerAndProjectName(loginId, projectName); |
346 |
- |
|
347 |
- if (!AccessControl.isAllowed(UserApp.currentUser(), project.asResource(), Operation.UPDATE)) { |
|
348 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
349 |
- } |
|
350 |
- |
|
351 | 336 |
Form<Project> projectForm = form(Project.class).fill(project); |
352 | 337 |
return ok(delete.render("title.projectDelete", projectForm, project)); |
353 | 338 |
} |
... | ... | @@ -364,25 +349,19 @@ |
364 | 349 |
* @throws Exception the exception |
365 | 350 |
*/ |
366 | 351 |
@Transactional |
367 |
- @With(NullProjectCheckAction.class) |
|
352 |
+ @IsAllowed(Operation.DELETE) |
|
368 | 353 |
public static Result deleteProject(String loginId, String projectName) throws Exception { |
369 | 354 |
Project project = Project.findByOwnerAndProjectName(loginId, projectName); |
355 |
+ project.delete(); |
|
356 |
+ RepositoryService.deleteRepository(project); |
|
370 | 357 |
|
371 |
- if (AccessControl.isAllowed(UserApp.currentUser(), project.asResource(), Operation.DELETE)) { |
|
372 |
- project.delete(); |
|
373 |
- RepositoryService.deleteRepository(project); |
|
374 |
- |
|
375 |
- // XHR 호출에 의한 경우라면 204 No Content 와 Location 헤더로 응답한다 |
|
376 |
- if(HttpUtil.isRequestedWithXHR(request())){ |
|
377 |
- response().setHeader("Location", routes.Application.index().toString()); |
|
378 |
- return status(204); |
|
379 |
- } |
|
380 |
- |
|
381 |
- return redirect(routes.Application.index()); |
|
382 |
- } else { |
|
383 |
- flash(Constants.WARNING, "project.member.isManager"); |
|
384 |
- return redirect(routes.ProjectApp.settingForm(loginId, projectName)); |
|
358 |
+ // XHR 호출에 의한 경우라면 204 No Content 와 Location 헤더로 응답한다 |
|
359 |
+ if(HttpUtil.isRequestedWithXHR(request())){ |
|
360 |
+ response().setHeader("Location", routes.Application.index().toString()); |
|
361 |
+ return status(204); |
|
385 | 362 |
} |
363 |
+ |
|
364 |
+ return redirect(routes.Application.index()); |
|
386 | 365 |
} |
387 | 366 |
|
388 | 367 |
/** |
... | ... | @@ -398,16 +377,10 @@ |
398 | 377 |
* @return 프로젝트, 멤버목록, Role 목록 |
399 | 378 |
*/ |
400 | 379 |
@Transactional |
401 |
- @With(NullProjectCheckAction.class) |
|
380 |
+ @IsAllowed(Operation.UPDATE) |
|
402 | 381 |
public static Result members(String loginId, String projectName) { |
403 | 382 |
Project project = Project.findByOwnerAndProjectName(loginId, projectName); |
404 |
- |
|
405 |
- if (!AccessControl.isAllowed(UserApp.currentUser(), project.asResource(), Operation.UPDATE)) { |
|
406 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
407 |
- } |
|
408 |
- |
|
409 | 383 |
project.cleanEnrolledUsers(); |
410 |
- |
|
411 | 384 |
return ok(views.html.project.members.render("title.projectMembers", |
412 | 385 |
ProjectUser.findMemberListByProject(project.id), project, |
413 | 386 |
Role.getActiveRoles())); |
... | ... | @@ -427,7 +400,7 @@ |
427 | 400 |
* @param resourceType |
428 | 401 |
* @return |
429 | 402 |
*/ |
430 |
- @With(NullProjectCheckAction.class) |
|
403 |
+ @IsAllowed(Operation.READ) |
|
431 | 404 |
public static Result mentionList(String loginId, String projectName, Long number, String resourceType) { |
432 | 405 |
String prefer = HttpUtil.getPreferType(request(), HTML, JSON); |
433 | 406 |
if (prefer == null) { |
... | ... | @@ -466,15 +439,11 @@ |
466 | 439 |
* @throws GitAPIException |
467 | 440 |
* @throws SVNException |
468 | 441 |
*/ |
469 |
- @With(NullProjectCheckAction.class) |
|
442 |
+ @IsAllowed(Operation.READ) |
|
470 | 443 |
public static Result mentionListAtCommitDiff(String ownerLoginId, String projectName, String commitId, Long pullRequestId) |
471 | 444 |
throws IOException, UnsupportedOperationException, ServletException, |
472 | 445 |
SVNException { |
473 | 446 |
Project project = Project.findByOwnerAndProjectName(ownerLoginId, projectName); |
474 |
- |
|
475 |
- if (!AccessControl.isAllowed(UserApp.currentUser(), project.asResource(), Operation.READ)) { |
|
476 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
477 |
- } |
|
478 | 447 |
|
479 | 448 |
PullRequest pullRequest; |
480 | 449 |
Project fromProject = project; |
... | ... | @@ -516,15 +485,11 @@ |
516 | 485 |
* @throws GitAPIException |
517 | 486 |
* @throws SVNException |
518 | 487 |
*/ |
519 |
- @With(NullProjectCheckAction.class) |
|
488 |
+ @IsAllowed(Operation.READ) |
|
520 | 489 |
public static Result mentionListAtPullRequest(String ownerLoginId, String projectName, String commitId, Long pullRequestId) |
521 | 490 |
throws IOException, UnsupportedOperationException, ServletException, |
522 | 491 |
SVNException { |
523 | 492 |
Project project = Project.findByOwnerAndProjectName(ownerLoginId, projectName); |
524 |
- |
|
525 |
- if (!AccessControl.isAllowed(UserApp.currentUser(), project.asResource(), Operation.READ)) { |
|
526 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
527 |
- } |
|
528 | 493 |
|
529 | 494 |
PullRequest pullRequest = PullRequest.findById(pullRequestId); |
530 | 495 |
List<User> userList = new ArrayList<>(); |
... | ... | @@ -723,20 +688,14 @@ |
723 | 688 |
* @return |
724 | 689 |
*/ |
725 | 690 |
@Transactional |
726 |
- @With(NullProjectCheckAction.class) |
|
691 |
+ @IsAllowed(Operation.UPDATE) |
|
727 | 692 |
public static Result editMember(String loginId, String projectName, Long userId) { |
728 | 693 |
Project project = Project.findByOwnerAndProjectName(loginId, projectName); |
729 |
- |
|
730 |
- if (AccessControl.isAllowed(UserApp.currentUser(), project.asResource(), Operation.UPDATE)) { |
|
731 |
- if (project.isOwner(User.find.byId(userId))) { |
|
732 |
- return forbidden(ErrorViews.Forbidden.render("project.member.ownerMustBeAManager", project)); |
|
733 |
- } |
|
734 |
- ProjectUser.assignRole(userId, project.id, form(Role.class) |
|
735 |
- .bindFromRequest().get().id); |
|
736 |
- return status(Http.Status.NO_CONTENT); |
|
737 |
- } else { |
|
738 |
- return forbidden(ErrorViews.Forbidden.render("project.member.isManager", project)); |
|
694 |
+ if (project.isOwner(User.find.byId(userId))) { |
|
695 |
+ return forbidden(ErrorViews.Forbidden.render("project.member.ownerMustBeAManager", project)); |
|
739 | 696 |
} |
697 |
+ ProjectUser.assignRole(userId, project.id, form(Role.class).bindFromRequest().get().id); |
|
698 |
+ return status(Http.Status.NO_CONTENT); |
|
740 | 699 |
} |
741 | 700 |
|
742 | 701 |
/** |
... | ... | @@ -863,13 +822,9 @@ |
863 | 822 |
* @param projectName the project name |
864 | 823 |
* @return 프로젝트 태그 JSON 데이터 |
865 | 824 |
*/ |
866 |
- @With(NullProjectCheckAction.class) |
|
825 |
+ @IsAllowed(Operation.READ) |
|
867 | 826 |
public static Result labels(String owner, String projectName) { |
868 | 827 |
Project project = Project.findByOwnerAndProjectName(owner, projectName); |
869 |
- |
|
870 |
- if (!AccessControl.isAllowed(UserApp.currentUser(), project.asResource(), Operation.READ)) { |
|
871 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
872 |
- } |
|
873 | 828 |
|
874 | 829 |
if (!request().accepts("application/json")) { |
875 | 830 |
return status(Http.Status.NOT_ACCEPTABLE); |
... | ... | @@ -1005,7 +960,7 @@ |
1005 | 960 |
*/ |
1006 | 961 |
@Transactional |
1007 | 962 |
@With(AnonymousCheckAction.class) |
1008 |
- @ProjectAccess(Operation.DELETE) |
|
963 |
+ @IsAllowed(Operation.DELETE) |
|
1009 | 964 |
public static Result deletePushedBranch(String ownerName, String projectName, Long id) { |
1010 | 965 |
PushedBranch pushedBranch = PushedBranch.find.byId(id); |
1011 | 966 |
if (pushedBranch != null) { |
--- app/controllers/PullRequestApp.java
+++ app/controllers/PullRequestApp.java
... | ... | @@ -24,9 +24,7 @@ |
24 | 24 |
import actors.PullRequestMergingActor; |
25 | 25 |
import akka.actor.Props; |
26 | 26 |
import com.avaje.ebean.Page; |
27 |
-import controllers.annotation.IsCreatable; |
|
28 |
-import controllers.annotation.ProjectAccess; |
|
29 |
-import controllers.annotation.PullRequestAccess; |
|
27 |
+import controllers.annotation.*; |
|
30 | 28 |
import models.*; |
31 | 29 |
import models.enumeration.Operation; |
32 | 30 |
import models.enumeration.ResourceType; |
... | ... | @@ -62,6 +60,7 @@ |
62 | 60 |
/** |
63 | 61 |
* 프로젝트 복사(포크)와 코드 주고받기(풀리퀘) 기능을 다루는 컨트롤러 |
64 | 62 |
*/ |
63 |
+@IsOnlyGitAvailable |
|
65 | 64 |
public class PullRequestApp extends Controller { |
66 | 65 |
|
67 | 66 |
/** |
... | ... | @@ -349,15 +348,9 @@ |
349 | 348 |
* @param projectName |
350 | 349 |
* @return |
351 | 350 |
*/ |
352 |
- @ProjectAccess(Operation.READ) |
|
351 |
+ @IsAllowed(Operation.READ) |
|
353 | 352 |
public static Result pullRequests(String userName, String projectName, int pageNum) { |
354 |
- |
|
355 | 353 |
Project project = Project.findByOwnerAndProjectName(userName, projectName); |
356 |
- |
|
357 |
- if(!project.vcs.equals("GIT")) { |
|
358 |
- return badRequest(ErrorViews.BadRequest.render("Now, only git project is allowed this request.", project)); |
|
359 |
- } |
|
360 |
- |
|
361 | 354 |
Page<PullRequest> page = PullRequest.findPagingList(State.OPEN, project, pageNum - 1); |
362 | 355 |
return ok(list.render(project, page, "opened")); |
363 | 356 |
} |
... | ... | @@ -369,7 +362,7 @@ |
369 | 362 |
* @param projectName |
370 | 363 |
* @return |
371 | 364 |
*/ |
372 |
- @ProjectAccess(Operation.READ) |
|
365 |
+ @IsAllowed(Operation.READ) |
|
373 | 366 |
public static Result closedPullRequests(String userName, String projectName, int pageNum) { |
374 | 367 |
Project project = Project.findByOwnerAndProjectName(userName, projectName); |
375 | 368 |
Page<PullRequest> page = PullRequest.findClosedPagingList(project, pageNum - 1); |
... | ... | @@ -383,7 +376,7 @@ |
383 | 376 |
* @param projectName |
384 | 377 |
* @return |
385 | 378 |
*/ |
386 |
- @ProjectAccess(Operation.READ) |
|
379 |
+ @IsAllowed(Operation.READ) |
|
387 | 380 |
public static Result sentPullRequests(String userName, String projectName, int pageNum) { |
388 | 381 |
Project project = Project.findByOwnerAndProjectName(userName, projectName); |
389 | 382 |
Page<PullRequest> page = PullRequest.findSentPullRequests(project, pageNum - 1); |
... | ... | @@ -398,8 +391,7 @@ |
398 | 391 |
* @param pullRequestNumber |
399 | 392 |
* @return |
400 | 393 |
*/ |
401 |
- @ProjectAccess(Operation.READ) |
|
402 |
- @PullRequestAccess(Operation.READ) |
|
394 |
+ @IsAllowed(value = Operation.READ, resourceType = ResourceType.PULL_REQUEST) |
|
403 | 395 |
public static Result pullRequest(String userName, String projectName, long pullRequestNumber) { |
404 | 396 |
Project project = Project.findByOwnerAndProjectName(userName, projectName); |
405 | 397 |
PullRequest pullRequest = PullRequest.findOne(project, pullRequestNumber); |
... | ... | @@ -432,8 +424,7 @@ |
432 | 424 |
* @param pullRequestNumber |
433 | 425 |
* @return |
434 | 426 |
*/ |
435 |
- @ProjectAccess(Operation.READ) |
|
436 |
- @PullRequestAccess(Operation.READ) |
|
427 |
+ @IsAllowed(value = Operation.READ, resourceType = ResourceType.PULL_REQUEST) |
|
437 | 428 |
public static Result pullRequestState(String userName, String projectName, long pullRequestNumber) { |
438 | 429 |
Project project = Project.findByOwnerAndProjectName(userName, projectName); |
439 | 430 |
PullRequest pullRequest = PullRequest.findOne(project, pullRequestNumber); |
... | ... | @@ -470,8 +461,7 @@ |
470 | 461 |
* @param pullRequestNumber |
471 | 462 |
* @return |
472 | 463 |
*/ |
473 |
- @ProjectAccess(Operation.READ) |
|
474 |
- @PullRequestAccess(Operation.READ) |
|
464 |
+ @IsAllowed(value = Operation.READ, resourceType = ResourceType.PULL_REQUEST) |
|
475 | 465 |
public static Result pullRequestCommits(String userName, String projectName, long pullRequestNumber) { |
476 | 466 |
Project project = Project.findByOwnerAndProjectName(userName, projectName); |
477 | 467 |
PullRequest pullRequest = PullRequest.findOne(project, pullRequestNumber); |
... | ... | @@ -487,8 +477,7 @@ |
487 | 477 |
* @param pullRequestNumber |
488 | 478 |
* @return |
489 | 479 |
*/ |
490 |
- @ProjectAccess(Operation.READ) |
|
491 |
- @PullRequestAccess(Operation.READ) |
|
480 |
+ @IsAllowed(value = Operation.READ, resourceType = ResourceType.PULL_REQUEST) |
|
492 | 481 |
public static Result pullRequestChanges(String userName, String projectName, long pullRequestNumber) { |
493 | 482 |
Project project = Project.findByOwnerAndProjectName(userName, projectName); |
494 | 483 |
PullRequest pullRequest = PullRequest.findOne(project, pullRequestNumber); |
... | ... | @@ -516,8 +505,7 @@ |
516 | 505 |
*/ |
517 | 506 |
@Transactional |
518 | 507 |
@With(AnonymousCheckAction.class) |
519 |
- @ProjectAccess(Operation.READ) |
|
520 |
- @PullRequestAccess(Operation.ACCEPT) |
|
508 |
+ @IsAllowed(value = Operation.ACCEPT, resourceType = ResourceType.PULL_REQUEST) |
|
521 | 509 |
public static Result accept(final String userName, final String projectName, |
522 | 510 |
final long pullRequestNumber) { |
523 | 511 |
Project project = Project.findByOwnerAndProjectName(userName, projectName); |
... | ... | @@ -562,8 +550,7 @@ |
562 | 550 |
*/ |
563 | 551 |
@Transactional |
564 | 552 |
@With(AnonymousCheckAction.class) |
565 |
- @ProjectAccess(Operation.READ) |
|
566 |
- @PullRequestAccess(Operation.CLOSE) |
|
553 |
+ @IsAllowed(value = Operation.CLOSE, resourceType = ResourceType.PULL_REQUEST) |
|
567 | 554 |
public static Result close(String userName, String projectName, Long pullRequestNumber) { |
568 | 555 |
Project project = Project.findByOwnerAndProjectName(userName, projectName); |
569 | 556 |
PullRequest pullRequest = PullRequest.findOne(project, pullRequestNumber); |
... | ... | @@ -589,8 +576,7 @@ |
589 | 576 |
*/ |
590 | 577 |
@Transactional |
591 | 578 |
@With(AnonymousCheckAction.class) |
592 |
- @ProjectAccess(Operation.READ) |
|
593 |
- @PullRequestAccess(Operation.CLOSE) |
|
579 |
+ @IsAllowed(value = Operation.REOPEN, resourceType = ResourceType.PULL_REQUEST) |
|
594 | 580 |
public static Result open(String userName, String projectName, Long pullRequestNumber) { |
595 | 581 |
Project project = Project.findByOwnerAndProjectName(userName, projectName); |
596 | 582 |
PullRequest pullRequest = PullRequest.findOne(project, pullRequestNumber); |
... | ... | @@ -623,8 +609,7 @@ |
623 | 609 |
* @throws ServletException |
624 | 610 |
*/ |
625 | 611 |
@With(AnonymousCheckAction.class) |
626 |
- @ProjectAccess(Operation.READ) |
|
627 |
- @PullRequestAccess(Operation.UPDATE) |
|
612 |
+ @IsAllowed(value = Operation.UPDATE, resourceType = ResourceType.PULL_REQUEST) |
|
628 | 613 |
public static Result editPullRequestForm(String userName, String projectName, Long pullRequestNumber) throws IOException, GitAPIException { |
629 | 614 |
Project toProject = Project.findByOwnerAndProjectName(userName, projectName); |
630 | 615 |
PullRequest pullRequest = PullRequest.findOne(toProject, pullRequestNumber); |
... | ... | @@ -652,8 +637,7 @@ |
652 | 637 |
*/ |
653 | 638 |
@Transactional |
654 | 639 |
@With(AnonymousCheckAction.class) |
655 |
- @ProjectAccess(Operation.READ) |
|
656 |
- @PullRequestAccess(Operation.UPDATE) |
|
640 |
+ @IsAllowed(value = Operation.UPDATE, resourceType = ResourceType.PULL_REQUEST) |
|
657 | 641 |
public static Result editPullRequest(String userName, String projectName, Long pullRequestNumber) { |
658 | 642 |
Project toProject = Project.findByOwnerAndProjectName(userName, projectName); |
659 | 643 |
PullRequest pullRequest = PullRequest.findOne(toProject, pullRequestNumber); |
... | ... | @@ -693,8 +677,7 @@ |
693 | 677 |
*/ |
694 | 678 |
@Transactional |
695 | 679 |
@With(AnonymousCheckAction.class) |
696 |
- @ProjectAccess(Operation.READ) |
|
697 |
- @PullRequestAccess(Operation.UPDATE) |
|
680 |
+ @IsAllowed(value = Operation.UPDATE, resourceType = ResourceType.PULL_REQUEST) |
|
698 | 681 |
public static Result deleteFromBranch(String userName, String projectName, Long pullRequestNumber) { |
699 | 682 |
Project toProject = Project.findByOwnerAndProjectName(userName, projectName); |
700 | 683 |
PullRequest pullRequest = PullRequest.findOne(toProject, pullRequestNumber); |
... | ... | @@ -714,8 +697,7 @@ |
714 | 697 |
*/ |
715 | 698 |
@Transactional |
716 | 699 |
@With(AnonymousCheckAction.class) |
717 |
- @ProjectAccess(Operation.READ) |
|
718 |
- @PullRequestAccess(Operation.UPDATE) |
|
700 |
+ @IsAllowed(value = Operation.UPDATE, resourceType = ResourceType.PULL_REQUEST) |
|
719 | 701 |
public static Result restoreFromBranch(String userName, String projectName, Long pullRequestNumber) { |
720 | 702 |
Project toProject = Project.findByOwnerAndProjectName(userName, projectName); |
721 | 703 |
PullRequest pullRequest = PullRequest.findOne(toProject, pullRequestNumber); |
... | ... | @@ -739,7 +721,7 @@ |
739 | 721 |
* @throws SVNException |
740 | 722 |
*/ |
741 | 723 |
@Transactional |
742 |
- @ProjectAccess(Operation.READ) |
|
724 |
+ @IsAllowed(Operation.READ) |
|
743 | 725 |
public static Result commitView(String userName, String projectName, Long pullRequestNumber, String commitId) throws GitAPIException, SVNException, IOException, ServletException { |
744 | 726 |
Project toProject = Project.findByOwnerAndProjectName(userName, projectName); |
745 | 727 |
PullRequest pullRequest = PullRequest.findOne(toProject, pullRequestNumber); |
--- app/controllers/ReviewApp.java
+++ app/controllers/ReviewApp.java
... | ... | @@ -21,14 +21,14 @@ |
21 | 21 |
package controllers; |
22 | 22 |
|
23 | 23 |
import actions.AnonymousCheckAction; |
24 |
-import controllers.annotation.ProjectAccess; |
|
25 |
-import controllers.annotation.PullRequestAccess; |
|
24 |
+import controllers.annotation.IsAllowed; |
|
26 | 25 |
import models.NotificationEvent; |
27 | 26 |
import models.Project; |
28 | 27 |
import models.PullRequest; |
29 | 28 |
import models.PullRequestEvent; |
30 | 29 |
import models.enumeration.EventType; |
31 | 30 |
import models.enumeration.Operation; |
31 |
+import models.enumeration.ResourceType; |
|
32 | 32 |
import play.api.mvc.Call; |
33 | 33 |
import play.db.ebean.Transactional; |
34 | 34 |
import play.mvc.Controller; |
... | ... | @@ -38,12 +38,11 @@ |
38 | 38 |
/** |
39 | 39 |
* @author Keesun Baik |
40 | 40 |
*/ |
41 |
+@With(AnonymousCheckAction.class) |
|
41 | 42 |
public class ReviewApp extends Controller { |
42 | 43 |
|
43 | 44 |
@Transactional |
44 |
- @With(AnonymousCheckAction.class) |
|
45 |
- @ProjectAccess(Operation.READ) |
|
46 |
- @PullRequestAccess(Operation.ACCEPT) |
|
45 |
+ @IsAllowed(value = Operation.ACCEPT, resourceType = ResourceType.PULL_REQUEST) |
|
47 | 46 |
public static Result review(String userName, String projectName, Long pullRequestNumber) { |
48 | 47 |
Project project = Project.findByOwnerAndProjectName(userName, projectName); |
49 | 48 |
PullRequest pullRequest = PullRequest.findOne(project, pullRequestNumber); |
... | ... | @@ -57,9 +56,7 @@ |
57 | 56 |
} |
58 | 57 |
|
59 | 58 |
@Transactional |
60 |
- @With(AnonymousCheckAction.class) |
|
61 |
- @ProjectAccess(Operation.READ) |
|
62 |
- @PullRequestAccess(Operation.ACCEPT) |
|
59 |
+ @IsAllowed(value = Operation.ACCEPT, resourceType = ResourceType.PULL_REQUEST) |
|
63 | 60 |
public static Result unreview(String userName, String projectName, Long pullRequestNumber) { |
64 | 61 |
Project project = Project.findByOwnerAndProjectName(userName, projectName); |
65 | 62 |
PullRequest pullRequest = PullRequest.findOne(project, pullRequestNumber); |
--- app/controllers/StatisticsApp.java
+++ app/controllers/StatisticsApp.java
... | ... | @@ -1,17 +1,18 @@ |
1 | 1 |
package controllers; |
2 | 2 |
|
3 |
+import actions.NullProjectCheckAction; |
|
3 | 4 |
import models.Project; |
4 | 5 |
import play.mvc.Controller; |
5 | 6 |
import play.mvc.Result; |
6 |
-import utils.ErrorViews; |
|
7 |
+import play.mvc.With; |
|
7 | 8 |
import views.html.project.statistics; |
8 | 9 |
|
9 | 10 |
public class StatisticsApp extends Controller { |
11 |
+ |
|
12 |
+ @With(NullProjectCheckAction.class) |
|
10 | 13 |
public static Result statistics(String userName, String projectName) { |
11 | 14 |
Project project = Project.findByOwnerAndProjectName(userName, projectName); |
12 |
- if (project == null) { |
|
13 |
- return notFound(ErrorViews.NotFound.render("error.notfound")); |
|
14 |
- } |
|
15 | 15 |
return ok(statistics.render("statistics", project)); |
16 | 16 |
} |
17 |
+ |
|
17 | 18 |
} |
--- app/controllers/WatchProjectApp.java
+++ app/controllers/WatchProjectApp.java
... | ... | @@ -1,5 +1,7 @@ |
1 | 1 |
package controllers; |
2 | 2 |
|
3 |
+import actions.AnonymousCheckAction; |
|
4 |
+import controllers.annotation.IsAllowed; |
|
3 | 5 |
import models.Project; |
4 | 6 |
import models.User; |
5 | 7 |
import models.UserProjectNotification; |
... | ... | @@ -9,42 +11,31 @@ |
9 | 11 |
import play.mvc.Controller; |
10 | 12 |
import play.mvc.Result; |
11 | 13 |
import play.mvc.With; |
12 |
-import utils.AccessControl; |
|
13 |
-import utils.ErrorViews; |
|
14 | 14 |
import utils.WatchService; |
15 |
-import actions.AnonymousCheckAction; |
|
16 |
-import controllers.annotation.ProjectAccess; |
|
17 | 15 |
|
16 |
+@With(AnonymousCheckAction.class) |
|
18 | 17 |
public class WatchProjectApp extends Controller { |
19 | 18 |
|
20 |
- @ProjectAccess(Operation.READ) |
|
21 |
- @With(AnonymousCheckAction.class) |
|
19 |
+ @IsAllowed(Operation.READ) |
|
22 | 20 |
public static Result watch(String userName, String projectName) { |
23 | 21 |
Project project = Project.findByOwnerAndProjectName(userName, projectName); |
24 | 22 |
WatchService.watch(project.asResource()); |
25 | 23 |
return ok(); |
26 | 24 |
} |
27 | 25 |
|
28 |
- @ProjectAccess(Operation.READ) |
|
29 |
- @With(AnonymousCheckAction.class) |
|
26 |
+ @IsAllowed(Operation.READ) |
|
30 | 27 |
public static Result unwatch(String userName, String projectName) { |
31 | 28 |
Project project = Project.findByOwnerAndProjectName(userName, projectName); |
32 | 29 |
WatchService.unwatch(project.asResource()); |
33 | 30 |
return ok(); |
34 | 31 |
} |
35 | 32 |
|
36 |
- @With(AnonymousCheckAction.class) |
|
33 |
+ @IsAllowed(Operation.READ) |
|
37 | 34 |
public static Result toggle(Long projectId, String notificationType) { |
38 | 35 |
EventType notiType = EventType.valueOf(notificationType); |
39 | 36 |
Project project = Project.find.byId(projectId); |
40 | 37 |
User user = UserApp.currentUser(); |
41 | 38 |
|
42 |
- if(project == null) { |
|
43 |
- return notFound(ErrorViews.NotFound.render("No project matches given projectId '" + projectId + "'")); |
|
44 |
- } |
|
45 |
- if(!AccessControl.isAllowed(user, project.asResource(), Operation.READ)) { |
|
46 |
- return forbidden(ErrorViews.Forbidden.render("error.forbidden", project)); |
|
47 |
- } |
|
48 | 39 |
if(!WatchService.isWatching(user, project.asResource())) { |
49 | 40 |
return badRequest(Messages.get("error.notfound.watch")); |
50 | 41 |
} |
+++ app/controllers/annotation/IsAllowed.java
... | ... | @@ -0,0 +1,53 @@ |
1 | +/** | |
2 | + * Yobi, Project Hosting SW | |
3 | + * | |
4 | + * Copyright 2013 NAVER Corp. | |
5 | + * http://yobi.io | |
6 | + * | |
7 | + * @Author Keesun Baik | |
8 | + * | |
9 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
10 | + * you may not use this file except in compliance with the License. | |
11 | + * You may obtain a copy of the License at | |
12 | + * | |
13 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
14 | + * | |
15 | + * Unless required by applicable law or agreed to in writing, software | |
16 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
17 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
18 | + * See the License for the specific language governing permissions and | |
19 | + * limitations under the License. | |
20 | + */ | |
21 | +package controllers.annotation; | |
22 | + | |
23 | +import actions.IsAllowedAction; | |
24 | +import models.enumeration.Operation; | |
25 | +import models.enumeration.ResourceType; | |
26 | +import play.mvc.With; | |
27 | + | |
28 | +import java.lang.annotation.ElementType; | |
29 | +import java.lang.annotation.Retention; | |
30 | +import java.lang.annotation.RetentionPolicy; | |
31 | +import java.lang.annotation.Target; | |
32 | + | |
33 | +/** | |
34 | + * /{user.loginId}/{project.name}/** 에 해당하는 URL에 적용할 수 있는 리소스 존재 확인 및 권한 확인용 애노테이션. | |
35 | + * - URL 패턴에 대응하는 프로젝트가 있는 확인하다. 없으면 404 Not Found. | |
36 | + * - {@code resourceType}에 해당하는 리소스가 있는지 확인한다. 없으면 404 Not Found. | |
37 | + * - 현재 사용자가 {@code resourceType}에 해당하는 리소스에 {@code value}에 해당하는 권한이 있는지 확인한다. 권한이 없으면 403 Forbidden. | |
38 | + * | |
39 | + * 이 애노테이션으로 다룰 수 있는 리소스 타입은 | |
40 | + * {@link models.resource.Resource#getResourceObject(actions.support.PathParser, models.Project, models.enumeration.ResourceType)} | |
41 | + * 참조하고 필요하면 추가 해야 한다. | |
42 | + * | |
43 | + * @author Keesun Baik | |
44 | + * @see {@link actions.IsAllowedAction} | |
45 | + * @see {@link models.resource.Resource#getResourceObject(actions.support.PathParser, models.Project, models.enumeration.ResourceType)} | |
46 | + */ | |
47 | +@With(IsAllowedAction.class) | |
48 | +@Target({ElementType.TYPE, ElementType.METHOD}) | |
49 | +@Retention(RetentionPolicy.RUNTIME) | |
50 | +public @interface IsAllowed { | |
51 | + Operation value(); | |
52 | + ResourceType resourceType() default ResourceType.PROJECT; | |
53 | +} |
--- app/controllers/annotation/IsCreatable.java
+++ app/controllers/annotation/IsCreatable.java
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 |
* http://yobi.io |
6 | 6 |
* |
7 | 7 |
* @Author Wansoon Park, Keesun Baek |
8 |
- * |
|
8 |
+ * |
|
9 | 9 |
* Licensed under the Apache License, Version 2.0 (the "License"); |
10 | 10 |
* you may not use this file except in compliance with the License. |
11 | 11 |
* You may obtain a copy of the License at |
... | ... | @@ -30,9 +30,16 @@ |
30 | 30 |
import actions.IsCreatableAction; |
31 | 31 |
|
32 | 32 |
/** |
33 |
- * {@code project}의 {@code resourceType} 생성권한을 체크한다. |
|
34 |
- * @author Wansoon Park, Keesun Beak |
|
33 |
+ * /{user.loginId}/{project.name}/** 에 해당하는 URL에 적용할 수 있는 리소스 생성 권한 확인하는 애노테이션. |
|
34 |
+ * - URL 패턴에 대응하는 프로젝트가 있는 확인하다. 없으면 404 Not Found. |
|
35 |
+ * - 현재 사용자가 {@code resourceType}에 해당하는 리소스를 생성할 수 있는지 확인한다. 권한이 없으면 403 Forbidden. |
|
35 | 36 |
* |
37 |
+ * 이 애노테이션은 {@link utils.AccessControl#isProjectResourceCreatable(models.User, models.Project, models.enumeration.ResourceType)} |
|
38 |
+ * 을 사용한다. |
|
39 |
+ * |
|
40 |
+ * @author Wansoon Park, Keesun Baik |
|
41 |
+ * @see {@link actions.IsCreatableAction} |
|
42 |
+ * @see {@link utils.AccessControl#isProjectResourceCreatable(models.User, models.Project, models.enumeration.ResourceType)} |
|
36 | 43 |
*/ |
37 | 44 |
@With(IsCreatableAction.class) |
38 | 45 |
@Target({ElementType.TYPE, ElementType.METHOD}) |
--- app/controllers/annotation/PullRequestAccess.java
+++ app/controllers/annotation/IsOnlyGitAvailable.java
... | ... | @@ -4,8 +4,8 @@ |
4 | 4 |
* Copyright 2013 NAVER Corp. |
5 | 5 |
* http://yobi.io |
6 | 6 |
* |
7 |
- * @Author Wansoon Park, Keesun Baek |
|
8 |
- * |
|
7 |
+ * @Author Keesun Baik |
|
8 |
+ * |
|
9 | 9 |
* Licensed under the Apache License, Version 2.0 (the "License"); |
10 | 10 |
* you may not use this file except in compliance with the License. |
11 | 11 |
* You may obtain a copy of the License at |
... | ... | @@ -20,23 +20,25 @@ |
20 | 20 |
*/ |
21 | 21 |
package controllers.annotation; |
22 | 22 |
|
23 |
+import actions.IsOnlyGitAvailableAction; |
|
24 |
+import play.mvc.With; |
|
25 |
+ |
|
23 | 26 |
import java.lang.annotation.ElementType; |
24 | 27 |
import java.lang.annotation.Retention; |
25 | 28 |
import java.lang.annotation.RetentionPolicy; |
26 | 29 |
import java.lang.annotation.Target; |
27 | 30 |
|
28 |
-import models.enumeration.Operation; |
|
29 |
-import play.mvc.With; |
|
30 |
-import actions.PullRequestCheckAction; |
|
31 |
- |
|
32 | 31 |
/** |
33 |
- * {@code PullRequest}의 {@code Operation} 권한을 체크한다. |
|
34 |
- * @author Wansoon Park, Keesun Beak |
|
32 |
+ * /{user.loginId}/{project.name}/** 에 해당하는 URL에 적용할 수 있는 Git 프로젝트 확인용 애노테이션. |
|
33 |
+ * - URL 패턴에 대응하는 프로젝트가 있는 확인하다. 없으면 404 Not Found. |
|
34 |
+ * - 접근하려는 프로젝트가 Git 프로젝트인지 확인한다. Git 프로젝트가 아니면 400 BadRequest. |
|
35 | 35 |
* |
36 |
+ * @author Keesun Baik |
|
37 |
+ * @see {@link actions.IsOnlyGitAvailableAction} |
|
36 | 38 |
*/ |
37 |
-@With(PullRequestCheckAction.class) |
|
39 |
+@With(IsOnlyGitAvailableAction.class) |
|
38 | 40 |
@Target({ElementType.TYPE, ElementType.METHOD}) |
39 | 41 |
@Retention(RetentionPolicy.RUNTIME) |
40 |
-public @interface PullRequestAccess { |
|
41 |
- Operation value(); |
|
42 |
+public @interface IsOnlyGitAvailable { |
|
43 |
+ |
|
42 | 44 |
} |
--- app/controllers/annotation/ProjectAccess.java
... | ... | @@ -1,47 +0,0 @@ |
1 | -/** | |
2 | - * Yobi, Project Hosting SW | |
3 | - * | |
4 | - * Copyright 2013 NAVER Corp. | |
5 | - * http://yobi.io | |
6 | - * | |
7 | - * @Author Wansoon Park, Keesun Baek | |
8 | - * | |
9 | - * Licensed under the Apache License, Version 2.0 (the "License"); | |
10 | - * you may not use this file except in compliance with the License. | |
11 | - * You may obtain a copy of the License at | |
12 | - * | |
13 | - * http://www.apache.org/licenses/LICENSE-2.0 | |
14 | - * | |
15 | - * Unless required by applicable law or agreed to in writing, software | |
16 | - * distributed under the License is distributed on an "AS IS" BASIS, | |
17 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
18 | - * See the License for the specific language governing permissions and | |
19 | - * limitations under the License. | |
20 | - */ | |
21 | -package controllers.annotation; | |
22 | - | |
23 | -import java.lang.annotation.ElementType; | |
24 | -import java.lang.annotation.Retention; | |
25 | -import java.lang.annotation.RetentionPolicy; | |
26 | -import java.lang.annotation.Target; | |
27 | - | |
28 | -import models.enumeration.Operation; | |
29 | -import play.mvc.With; | |
30 | -import actions.ProjectCheckAction; | |
31 | - | |
32 | -/** | |
33 | - * {@code Project}의 {@code Operation} 권한을 체크한다. | |
34 | - * | |
35 | - * 이 애노테이션은 /user/project/** 패턴에 해당하는 요청만 처리할 수 있다. | |
36 | - * 그 이외 요청을 처리하는 핸들러에 사용하면 에러가 발생하고 요청이 처리되지 않는다. | |
37 | - * | |
38 | - * @author Wansoon Park, Keesun Beak | |
39 | - * | |
40 | - */ | |
41 | -@With(ProjectCheckAction.class) | |
42 | -@Target({ElementType.TYPE, ElementType.METHOD}) | |
43 | -@Retention(RetentionPolicy.RUNTIME) | |
44 | -public @interface ProjectAccess { | |
45 | - Operation value(); | |
46 | - boolean isGitOnly() default false; | |
47 | -} |
--- app/models/Posting.java
+++ app/models/Posting.java
... | ... | @@ -117,7 +117,7 @@ |
117 | 117 |
* @param number |
118 | 118 |
* @return |
119 | 119 |
*/ |
120 |
- public static Posting findByNumber(Project project, Long number) { |
|
120 |
+ public static Posting findByNumber(Project project, long number) { |
|
121 | 121 |
return AbstractPosting.findByNumber(finder, project, number); |
122 | 122 |
} |
123 | 123 |
|
--- app/models/resource/Resource.java
+++ app/models/resource/Resource.java
... | ... | @@ -1,5 +1,7 @@ |
1 | 1 |
package models.resource; |
2 | 2 |
|
3 |
+import actions.support.PathParser; |
|
4 |
+import controllers.routes; |
|
3 | 5 |
import models.*; |
4 | 6 |
import models.enumeration.ResourceType; |
5 | 7 |
import play.db.ebean.Model; |
... | ... | @@ -139,4 +141,37 @@ |
139 | 141 |
public Resource getContainer() { return null; } |
140 | 142 |
public Long getAuthorId() { return null; } |
141 | 143 |
public void delete() { throw new UnsupportedOperationException(); } |
144 |
+ |
|
145 |
+ /** |
|
146 |
+ * {@code parser}와 {@code project} 정보에서 {@code resourceType}에 해당하는 리소스를 찾는다. |
|
147 |
+ * - 해당하는 리소스가 있을 때는 {@link models.resource.ResourceConvertible} 타입 객체를 리턴한다. |
|
148 |
+ * - 해당하는 리소스가 없을 때는 리턴한 레퍼런스가 null일 수도 있다. |
|
149 |
+ * |
|
150 |
+ * @param parser |
|
151 |
+ * @param resourceType |
|
152 |
+ * @param project |
|
153 |
+ * @return |
|
154 |
+ * @see {@link actions.IsAllowedAction} |
|
155 |
+ */ |
|
156 |
+ public static ResourceConvertible getResourceObject(PathParser parser, Project project, ResourceType resourceType) { |
|
157 |
+ switch (resourceType) { |
|
158 |
+ case PROJECT: |
|
159 |
+ return project; |
|
160 |
+ case MILESTONE: |
|
161 |
+ return Milestone.findById(Long.parseLong(parser.getPathSegment(3))); |
|
162 |
+ case BOARD_POST: |
|
163 |
+ return Posting.findByNumber(project, Long.parseLong(parser.getPathSegment(3))); |
|
164 |
+ case ISSUE_POST: |
|
165 |
+ return Issue.findByNumber(project, Long.parseLong(parser.getPathSegment(3))); |
|
166 |
+ case ISSUE_LABEL: |
|
167 |
+ return IssueLabel.finder.byId(Long.parseLong(parser.getPathSegment(4))); |
|
168 |
+ case PULL_REQUEST: |
|
169 |
+ return PullRequest.findOne(project, Long.parseLong(parser.getPathSegment(3))); |
|
170 |
+ case COMMIT_COMMENT: |
|
171 |
+ return CommitComment.find.byId(Long.parseLong(parser.getPathSegment(5))); |
|
172 |
+ default: |
|
173 |
+ throw new IllegalAccessError(getInvalidResourceTypeMessage(resourceType)); |
|
174 |
+ } |
|
175 |
+ } |
|
176 |
+ |
|
142 | 177 |
} |
--- app/views/error/notfound.scala.html
+++ app/views/error/notfound.scala.html
... | ... | @@ -2,16 +2,18 @@ |
2 | 2 |
|
3 | 3 |
@getMenuType(target:String) = @{ |
4 | 4 |
target match { |
5 |
- case "issues" => utils.MenuType.ISSUE |
|
6 |
- case "post" => utils.MenuType.BOARD |
|
5 |
+ case "issue_post" => utils.MenuType.ISSUE |
|
6 |
+ case "board_post" => utils.MenuType.BOARD |
|
7 |
+ case "milestone" => utils.MenuType.MILESTONE |
|
7 | 8 |
case _ => utils.MenuType.PROJECT_HOME |
8 | 9 |
} |
9 | 10 |
} |
10 | 11 |
|
11 | 12 |
@getReturnURL(target:String) = @{ |
12 | 13 |
target match { |
13 |
- case "issues" => routes.IssueApp.issues(project.owner, project.name, "all") |
|
14 |
- case "post" => routes.BoardApp.posts(project.owner, project.name) |
|
14 |
+ case "issue_post" => routes.IssueApp.issues(project.owner, project.name, "all") |
|
15 |
+ case "board_post" => routes.BoardApp.posts(project.owner, project.name) |
|
16 |
+ case "milestone" => routes.MilestoneApp.milestones(project.owner, project.name) |
|
15 | 17 |
case _ => "javascript:history.back();" |
16 | 18 |
} |
17 | 19 |
} |
--- conf/messages
+++ conf/messages
... | ... | @@ -142,14 +142,17 @@ |
142 | 142 |
error.auth.unauthorized.comment = You need authorization to comment |
143 | 143 |
error.auth.unauthorized.waringMessage = You don't have authorization or aren't logged in |
144 | 144 |
error.badrequest = The request cannot be fulfilled due to bad syntax |
145 |
-error.forbidden = You need access Control! |
|
145 |
+error.badrequest.only.available.for.git = This request is only available for a git project. |
|
146 |
+error.forbidden = You are not authorized |
|
146 | 147 |
error.internalServerError = Server error occurred and the service is not available |
147 | 148 |
error.notfound = Page not found |
148 |
-error.notfound.issue = Issue not found |
|
149 |
-error.notfound.post = Post not found |
|
149 |
+error.notfound.code_comment = Commit-comment not found |
|
150 |
+error.notfound.issue_post = Issue not found |
|
151 |
+error.notfound.board_post = Post not found |
|
150 | 152 |
error.notfound.watch = Watch not found |
151 | 153 |
error.notfound.commit = Commit not found |
152 | 154 |
error.notfound.project = Project not found |
155 |
+error.notfound.milestone = Milestone not found |
|
153 | 156 |
error.required = Mandatory field is empty |
154 | 157 |
error.tooLargeText.title = Request text entity is too large |
155 | 158 |
error.tooLargeText.limit = Your request has an text entity which exceeds the limit "{0}" bytes. |
--- conf/messages.ja
+++ conf/messages.ja
... | ... | @@ -145,8 +145,8 @@ |
145 | 145 |
error.forbidden = 権限がありません |
146 | 146 |
error.internalServerError = サーバエラーでサービスを利用できません |
147 | 147 |
error.notfound = 存在しないページです |
148 |
-error.notfound.issue = 存在しないイシューです |
|
149 |
-error.notfound.post = 存在しないスレッドです |
|
148 |
+error.notfound.issue_post = 存在しないイシューです |
|
149 |
+error.notfound.board_post = 存在しないスレッドです |
|
150 | 150 |
error.notfound.watch = 存在しなおメッセージです |
151 | 151 |
error.notfound.commit = Commit not found |
152 | 152 |
error.required = 必須項目です |
--- conf/messages.ko
+++ conf/messages.ko
... | ... | @@ -142,14 +142,17 @@ |
142 | 142 |
error.auth.unauthorized.comment = 로그인 후 댓글 입력이 가능합니다. |
143 | 143 |
error.auth.unauthorized.waringMessage = 권한이 없거나 로그인을 하지 않았습니다. |
144 | 144 |
error.badrequest = 잘못된 요청입니다 |
145 |
+error.badrequest.only.available.for.git = GIT 프로젝트에서만 지원하는 요청입니다. |
|
145 | 146 |
error.forbidden = 권한이 없습니다 |
146 | 147 |
error.internalServerError = 서버 오류가 발생하여 서비스를 이용할 수 없습니다 |
147 | 148 |
error.notfound = 페이지를 찾을 수 없습니다 |
148 |
-error.notfound.issue = 존재하지 않는 이슈입니다 |
|
149 |
-error.notfound.post = 존재하지 않는 글입니다 |
|
149 |
+error.notfound.code_comment = 존재하지 않는 커밋 댓글입니다. |
|
150 |
+error.notfound.issue_post = 존재하지 않는 이슈입니다 |
|
151 |
+error.notfound.board_post = 존재하지 않는 글입니다 |
|
150 | 152 |
error.notfound.watch = 존재하지 않는 알림 정보입니다. |
151 | 153 |
error.notfound.commit = 존재하지 않는 커밋입니다. |
152 | 154 |
error.notfound.project = 존재하지 않는 프로젝트입니다. |
155 |
+error.notfound.milestone = 존재하지 않는 마일스톤입니다. |
|
153 | 156 |
error.required = 필수 입력란입니다. |
154 | 157 |
error.tooLargeText.title = 너무 큰 텍스트 데이터를 보냈습니다. |
155 | 158 |
error.tooLargeText.limit = 텍스트 데이터는 최대 "{0}" 바이트까지만 보낼 수 있습니다. |
--- test/actions/support/PathParserTest.java
+++ test/actions/support/PathParserTest.java
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 |
* http://yobi.io |
6 | 6 |
* |
7 | 7 |
* @Author Wansoon Park |
8 |
- * |
|
8 |
+ * |
|
9 | 9 |
* Licensed under the Apache License, Version 2.0 (the "License"); |
10 | 10 |
* you may not use this file except in compliance with the License. |
11 | 11 |
* You may obtain a copy of the License at |
... | ... | @@ -20,14 +20,8 @@ |
20 | 20 |
*/ |
21 | 21 |
package actions.support; |
22 | 22 |
|