Yi EungJun 2014-04-08
Give all permissions for an issue to its assignee
@983493878ef7e7a328f227beb952953996514ed4
app/utils/AccessControl.java
--- app/utils/AccessControl.java
+++ app/utils/AccessControl.java
@@ -1,5 +1,7 @@
 package utils;
 
+import models.Assignee;
+import models.Issue;
 import models.Project;
 import models.ProjectUser;
 import models.User;
@@ -70,7 +72,7 @@
     }
 
     public static boolean isResourceCreatable(User user, Resource container, ResourceType resourceType) {
-        if (isAllowedIfAuthor(user, container)) {
+        if (isAllowedIfAuthor(user, container) || isAllowedIfAssignee(user, container)) {
             return true;
         }
 
@@ -157,7 +159,8 @@
     private static boolean isProjectResourceAllowed(User user, Project project, Resource resource, Operation operation) {
         if (user.isSiteManager()
                 || ProjectUser.isManager(user.id, project.id)
-                || isAllowedIfAuthor(user, resource)) {
+                || isAllowedIfAuthor(user, resource)
+                || isAllowedIfAssignee(user, resource)) {
             return true;
         }
 
@@ -269,4 +272,26 @@
             return false;
         }
     }
+
+    /**
+     * Checks if an user has a permission to do something to the given
+     * resource as an assignee.
+     *
+     * Returns true if and only if these are all true:
+     * - {@code resource} gives permission to read, modify and delete to its assignee.
+     * - {@code user} is an assignee of the resource.
+     *
+     * @param user
+     * @param resource
+     * @return true if the user has the permission
+     */
+    private static boolean isAllowedIfAssignee(User user, Resource resource) {
+        switch (resource.getType()) {
+        case ISSUE_POST:
+            Assignee assignee = Issue.finder.byId(Long.valueOf(resource.getId())).assignee;
+            return assignee != null && assignee.user.id.equals(user.id);
+        default:
+            return false;
+        }
+    }
 }
docs/technical/access-control.md
--- docs/technical/access-control.md
+++ docs/technical/access-control.md
@@ -4,6 +4,8 @@
 * 사이트 관리자: 모든 권한
 * 저자: 자신이 만든 이슈, 게시물, 댓글에 대한 모든 권한
     * 다만 자신이 만든 이슈나 게시물에 다른 사람이 댓글을 단 경우, 그 댓글에 대한 수정/삭제 권한은 갖지 않는다.
+* 담당자: 자신이 담당한 이슈, 게시물, 댓글에 대한 모든 권한
+    * 다만 자신이 담당한 이슈나 게시물에 다른 사람이 댓글을 단 경우, 그 댓글에 대한 수정/삭제 권한은 갖지 않는다.
 
 공개 프로젝트
 =============
test/controllers/IssueAppTest.java
--- test/controllers/IssueAppTest.java
+++ test/controllers/IssueAppTest.java
@@ -23,6 +23,7 @@
     private User manager;
     private User member;
     private User author;
+    private User assignee;
     private User nonmember;
     private User anonymous;
     private Issue issue;
@@ -50,6 +51,7 @@
         manager = User.findByLoginId("yobi");
         member = User.findByLoginId("laziel");
         author = User.findByLoginId("nori");
+        assignee = User.findByLoginId("alecsiel");
         nonmember = User.findByLoginId("doortts");
         anonymous = new NullUser();
 
@@ -58,6 +60,7 @@
         issue.setTitle("hello");
         issue.setBody("world");
         issue.setAuthor(author);
+        issue.setAssignee(Assignee.add(assignee.id, project.id));
         issue.save();
 
         assertThat(this.admin.isSiteManager()).describedAs("admin is Site Admin.").isTrue();
@@ -65,6 +68,7 @@
         assertThat(ProjectUser.isManager(member.id, project.id)).describedAs("member is a manager").isFalse();
         assertThat(ProjectUser.isMember(member.id, project.id)).describedAs("member is a member").isTrue();
         assertThat(ProjectUser.isMember(author.id, project.id)).describedAs("author is a member").isFalse();
+        assertThat(ProjectUser.isMember(assignee.id, project.id)).describedAs("assignee is a member").isFalse();
         assertThat(project.isPublic).describedAs("project is public").isFalse();
     }
 
@@ -151,6 +155,14 @@
         assertThat(status(result)).describedAs("Author can edit own issue.").isEqualTo(SEE_OTHER);
     }
 
+    @Test
+    public void editByAssignee() {
+        // When
+        Result result = editBy(assignee);
+
+        // Then
+        assertThat(status(result)).describedAs("Assignee can edit own issue.").isEqualTo(SEE_OTHER);
+    }
 
     @Test
     public void editByAdmin() {
@@ -202,6 +214,14 @@
         assertThat(status(result)).describedAs("Author can delete own issue.").isEqualTo(SEE_OTHER);
     }
 
+    @Test
+    public void deleteByAssignee() {
+        // When
+        Result result = deleteBy(assignee);
+
+        // Then
+        assertThat(status(result)).describedAs("Assignee can delete own issue.").isEqualTo(SEE_OTHER);
+    }
 
     @Test
     public void deleteByAdmin() {
@@ -382,6 +402,23 @@
     }
 
     @Test
+    public void watchByAssignee() {
+        // Given
+        Resource resource = issue.asResource();
+
+        // When
+        Result result = callAction(
+                controllers.routes.ref.WatchApp.watch(resource.asParameter()),
+                fakeRequest()
+                        .withSession(UserApp.SESSION_USERID, assignee.id.toString())
+        );
+
+        // Then
+        issue.refresh();
+        assertThat(status(result)).isEqualTo(OK);
+    }
+
+    @Test
     public void unwatch() {
         // Given
         Resource resource = issue.asResource();
@@ -419,4 +456,22 @@
         issue.refresh();
         assertThat(status(result)).isEqualTo(OK);
     }
+
+    @Test
+    public void unwatchByAssignee() {
+        // Given
+        Resource resource = issue.asResource();
+
+        // When
+        Result result = callAction(
+                controllers.routes.ref.WatchApp.unwatch(resource.asParameter()),
+                fakeRequest()
+                        .withSession(UserApp.SESSION_USERID, assignee.id.toString())
+        );
+
+        // Then
+        issue.refresh();
+        assertThat(status(result)).isEqualTo(OK);
+    }
+
 }
Add a comment
List