
Give all permissions for an issue to its assignee
@983493878ef7e7a328f227beb952953996514ed4
--- app/utils/AccessControl.java
+++ app/utils/AccessControl.java
... | ... | @@ -1,5 +1,7 @@ |
1 | 1 |
package utils; |
2 | 2 |
|
3 |
+import models.Assignee; |
|
4 |
+import models.Issue; |
|
3 | 5 |
import models.Project; |
4 | 6 |
import models.ProjectUser; |
5 | 7 |
import models.User; |
... | ... | @@ -70,7 +72,7 @@ |
70 | 72 |
} |
71 | 73 |
|
72 | 74 |
public static boolean isResourceCreatable(User user, Resource container, ResourceType resourceType) { |
73 |
- if (isAllowedIfAuthor(user, container)) { |
|
75 |
+ if (isAllowedIfAuthor(user, container) || isAllowedIfAssignee(user, container)) { |
|
74 | 76 |
return true; |
75 | 77 |
} |
76 | 78 |
|
... | ... | @@ -157,7 +159,8 @@ |
157 | 159 |
private static boolean isProjectResourceAllowed(User user, Project project, Resource resource, Operation operation) { |
158 | 160 |
if (user.isSiteManager() |
159 | 161 |
|| ProjectUser.isManager(user.id, project.id) |
160 |
- || isAllowedIfAuthor(user, resource)) { |
|
162 |
+ || isAllowedIfAuthor(user, resource) |
|
163 |
+ || isAllowedIfAssignee(user, resource)) { |
|
161 | 164 |
return true; |
162 | 165 |
} |
163 | 166 |
|
... | ... | @@ -269,4 +272,26 @@ |
269 | 272 |
return false; |
270 | 273 |
} |
271 | 274 |
} |
275 |
+ |
|
276 |
+ /** |
|
277 |
+ * Checks if an user has a permission to do something to the given |
|
278 |
+ * resource as an assignee. |
|
279 |
+ * |
|
280 |
+ * Returns true if and only if these are all true: |
|
281 |
+ * - {@code resource} gives permission to read, modify and delete to its assignee. |
|
282 |
+ * - {@code user} is an assignee of the resource. |
|
283 |
+ * |
|
284 |
+ * @param user |
|
285 |
+ * @param resource |
|
286 |
+ * @return true if the user has the permission |
|
287 |
+ */ |
|
288 |
+ private static boolean isAllowedIfAssignee(User user, Resource resource) { |
|
289 |
+ switch (resource.getType()) { |
|
290 |
+ case ISSUE_POST: |
|
291 |
+ Assignee assignee = Issue.finder.byId(Long.valueOf(resource.getId())).assignee; |
|
292 |
+ return assignee != null && assignee.user.id.equals(user.id); |
|
293 |
+ default: |
|
294 |
+ return false; |
|
295 |
+ } |
|
296 |
+ } |
|
272 | 297 |
} |
--- docs/technical/access-control.md
+++ docs/technical/access-control.md
... | ... | @@ -4,6 +4,8 @@ |
4 | 4 |
* 사이트 관리자: 모든 권한 |
5 | 5 |
* 저자: 자신이 만든 이슈, 게시물, 댓글에 대한 모든 권한 |
6 | 6 |
* 다만 자신이 만든 이슈나 게시물에 다른 사람이 댓글을 단 경우, 그 댓글에 대한 수정/삭제 권한은 갖지 않는다. |
7 |
+* 담당자: 자신이 담당한 이슈, 게시물, 댓글에 대한 모든 권한 |
|
8 |
+ * 다만 자신이 담당한 이슈나 게시물에 다른 사람이 댓글을 단 경우, 그 댓글에 대한 수정/삭제 권한은 갖지 않는다. |
|
7 | 9 |
|
8 | 10 |
공개 프로젝트 |
9 | 11 |
============= |
--- test/controllers/IssueAppTest.java
+++ test/controllers/IssueAppTest.java
... | ... | @@ -23,6 +23,7 @@ |
23 | 23 |
private User manager; |
24 | 24 |
private User member; |
25 | 25 |
private User author; |
26 |
+ private User assignee; |
|
26 | 27 |
private User nonmember; |
27 | 28 |
private User anonymous; |
28 | 29 |
private Issue issue; |
... | ... | @@ -50,6 +51,7 @@ |
50 | 51 |
manager = User.findByLoginId("yobi"); |
51 | 52 |
member = User.findByLoginId("laziel"); |
52 | 53 |
author = User.findByLoginId("nori"); |
54 |
+ assignee = User.findByLoginId("alecsiel"); |
|
53 | 55 |
nonmember = User.findByLoginId("doortts"); |
54 | 56 |
anonymous = new NullUser(); |
55 | 57 |
|
... | ... | @@ -58,6 +60,7 @@ |
58 | 60 |
issue.setTitle("hello"); |
59 | 61 |
issue.setBody("world"); |
60 | 62 |
issue.setAuthor(author); |
63 |
+ issue.setAssignee(Assignee.add(assignee.id, project.id)); |
|
61 | 64 |
issue.save(); |
62 | 65 |
|
63 | 66 |
assertThat(this.admin.isSiteManager()).describedAs("admin is Site Admin.").isTrue(); |
... | ... | @@ -65,6 +68,7 @@ |
65 | 68 |
assertThat(ProjectUser.isManager(member.id, project.id)).describedAs("member is a manager").isFalse(); |
66 | 69 |
assertThat(ProjectUser.isMember(member.id, project.id)).describedAs("member is a member").isTrue(); |
67 | 70 |
assertThat(ProjectUser.isMember(author.id, project.id)).describedAs("author is a member").isFalse(); |
71 |
+ assertThat(ProjectUser.isMember(assignee.id, project.id)).describedAs("assignee is a member").isFalse(); |
|
68 | 72 |
assertThat(project.isPublic).describedAs("project is public").isFalse(); |
69 | 73 |
} |
70 | 74 |
|
... | ... | @@ -151,6 +155,14 @@ |
151 | 155 |
assertThat(status(result)).describedAs("Author can edit own issue.").isEqualTo(SEE_OTHER); |
152 | 156 |
} |
153 | 157 |
|
158 |
+ @Test |
|
159 |
+ public void editByAssignee() { |
|
160 |
+ // When |
|
161 |
+ Result result = editBy(assignee); |
|
162 |
+ |
|
163 |
+ // Then |
|
164 |
+ assertThat(status(result)).describedAs("Assignee can edit own issue.").isEqualTo(SEE_OTHER); |
|
165 |
+ } |
|
154 | 166 |
|
155 | 167 |
@Test |
156 | 168 |
public void editByAdmin() { |
... | ... | @@ -202,6 +214,14 @@ |
202 | 214 |
assertThat(status(result)).describedAs("Author can delete own issue.").isEqualTo(SEE_OTHER); |
203 | 215 |
} |
204 | 216 |
|
217 |
+ @Test |
|
218 |
+ public void deleteByAssignee() { |
|
219 |
+ // When |
|
220 |
+ Result result = deleteBy(assignee); |
|
221 |
+ |
|
222 |
+ // Then |
|
223 |
+ assertThat(status(result)).describedAs("Assignee can delete own issue.").isEqualTo(SEE_OTHER); |
|
224 |
+ } |
|
205 | 225 |
|
206 | 226 |
@Test |
207 | 227 |
public void deleteByAdmin() { |
... | ... | @@ -382,6 +402,23 @@ |
382 | 402 |
} |
383 | 403 |
|
384 | 404 |
@Test |
405 |
+ public void watchByAssignee() { |
|
406 |
+ // Given |
|
407 |
+ Resource resource = issue.asResource(); |
|
408 |
+ |
|
409 |
+ // When |
|
410 |
+ Result result = callAction( |
|
411 |
+ controllers.routes.ref.WatchApp.watch(resource.asParameter()), |
|
412 |
+ fakeRequest() |
|
413 |
+ .withSession(UserApp.SESSION_USERID, assignee.id.toString()) |
|
414 |
+ ); |
|
415 |
+ |
|
416 |
+ // Then |
|
417 |
+ issue.refresh(); |
|
418 |
+ assertThat(status(result)).isEqualTo(OK); |
|
419 |
+ } |
|
420 |
+ |
|
421 |
+ @Test |
|
385 | 422 |
public void unwatch() { |
386 | 423 |
// Given |
387 | 424 |
Resource resource = issue.asResource(); |
... | ... | @@ -419,4 +456,22 @@ |
419 | 456 |
issue.refresh(); |
420 | 457 |
assertThat(status(result)).isEqualTo(OK); |
421 | 458 |
} |
459 |
+ |
|
460 |
+ @Test |
|
461 |
+ public void unwatchByAssignee() { |
|
462 |
+ // Given |
|
463 |
+ Resource resource = issue.asResource(); |
|
464 |
+ |
|
465 |
+ // When |
|
466 |
+ Result result = callAction( |
|
467 |
+ controllers.routes.ref.WatchApp.unwatch(resource.asParameter()), |
|
468 |
+ fakeRequest() |
|
469 |
+ .withSession(UserApp.SESSION_USERID, assignee.id.toString()) |
|
470 |
+ ); |
|
471 |
+ |
|
472 |
+ // Then |
|
473 |
+ issue.refresh(); |
|
474 |
+ assertThat(status(result)).isEqualTo(OK); |
|
475 |
+ } |
|
476 |
+ |
|
422 | 477 |
} |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?