doortts doortts 2017-07-08
api: Refactorings
- Remove json postfix from method name
- Extract some local methods
- Exporting feature: Project all Labels

and so on..
@79a92f1d7c527345acf536a9734901415cbbf03c
app/controllers/api/BoardApi.java
--- app/controllers/api/BoardApi.java
+++ app/controllers/api/BoardApi.java
@@ -1,6 +1,6 @@
 /**
  * Yona, Project Hosting SW
- *
+ * <p>
  * Copyright 2016 the original author or authors.
  */
 
@@ -8,8 +8,7 @@
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
-import controllers.AbstractPostingApp;
-import controllers.UserApp;
+import controllers.*;
 import controllers.annotation.IsAllowed;
 import controllers.annotation.IsCreatable;
 import models.*;
@@ -19,12 +18,16 @@
 import play.db.ebean.Transactional;
 import play.libs.Json;
 import play.mvc.Result;
+import utils.AccessControl;
+import utils.ErrorViews;
 import utils.JodaDateUtil;
+import utils.RouteUtil;
 
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Set;
+import java.io.IOException;
+import java.util.*;
 
+import static controllers.api.IssueApi.findAuthor;
+import static controllers.api.IssueApi.parseDateString;
 import static play.libs.Json.toJson;
 
 public class BoardApi extends AbstractPostingApp {
@@ -32,14 +35,14 @@
     @Transactional
     public static Result updatePostLabel(String owner, String projectName, Long number) {
         JsonNode json = request().body().asJson();
-        if(json == null) {
+        if (json == null) {
             return badRequest("Expecting Json data");
         }
         Project project = Project.findByOwnerAndProjectName(owner, projectName);
         Posting posting = Posting.findByNumber(project, number);
         Set<IssueLabel> labels = new HashSet<>();
 
-        for(JsonNode node: json){
+        for (JsonNode node : json) {
             Long labelId = Long.parseLong(node.asText());
             labels.add(IssueLabel.finder.byId(labelId));
         }
@@ -67,40 +70,90 @@
 
     @Transactional
     @IsCreatable(ResourceType.BOARD_POST)
-    public static Result newPostByJson(String owner, String projectName) {
+    public static Result newPostings(String owner, String projectName) {
         ObjectNode result = Json.newObject();
+        JsonNode json = request().body().asJson();
+        if (json == null) {
+            return badRequest(result.put("message", "Expecting Json data"));
+        }
+
+        JsonNode postingsNode = json.findValue("posts");
+        if (postingsNode == null || !postingsNode.isArray()) {
+            return badRequest(result.put("message", "No posts key exists or value wasn't array!"));
+        }
+
+        Project project = Project.findByOwnerAndProjectName(owner, projectName);
+
+        List<JsonNode> createdPostings = new ArrayList<>();
+        for (JsonNode postingNode : postingsNode) {
+            createdPostings.add(createPostingNode(postingNode, project));
+        }
+
+        return created(toJson(createdPostings));
+    }
+
+    private static JsonNode createPostingNode(JsonNode json, Project project) {
+        JsonNode files = json.findValue("temporaryUploadFiles");
+
+        final Posting posting = new Posting();
+
+        posting.setAuthor(findAuthor(json.findValue("author")));
+        posting.project = project;
+        posting.title = json.findValue("title").asText();
+        posting.body = json.findValue("body").asText();
+        posting.createdDate = parseDateString(json.findValue("createdAt"));
+        posting.updatedDate = parseDateString(json.findValue("updatedAt"));
+        posting.numOfComments = 0;
+
+        if (json.findValue("number") != null && json.findValue("number").asLong() > 0) {
+            posting.saveWithNumber(json.findValue("number").asLong());
+        } else {
+            posting.save();
+        }
+        attachUploadFilesToPost(files, posting.asResource());
+
+        ObjectNode result = Json.newObject();
+        result.put("status", 201);
+        result.put("location",
+                controllers.routes.BoardApp.post(project.owner, project.name, posting.getNumber()).toString());
+        return result;
+
+    }
+
+    @Transactional
+    @IsCreatable(ResourceType.NONISSUE_COMMENT)
+    public static Result newPostingComment(String ownerName, String projectName, Long number)
+            throws IOException {
         JsonNode json = request().body().asJson();
         if(json == null) {
             return badRequest("Expecting Json data");
         }
 
-        Project project = Project.findByOwnerAndProjectName(owner, projectName);
+        Project project = Project.findByOwnerAndProjectName(ownerName, projectName);
+        final Posting posting = Posting.findByNumber(project, number);
 
-        User user = User.findUserIfTokenExist(UserApp.currentUser());
-        JsonNode files = json.findValue("temporaryUploadFiles");
-
-        final Posting post = new Posting();
-
-        post.createdDate = getCreatedDate(json.findValue("created").asLong());
-        post.updatedDate = getCreatedDate(json.findValue("created").asLong());
-        post.setAuthor(user);
-        post.project = project;
-        post.title = json.findValue("title").asText();
-        post.body = json.findValue("body").asText();
-        if(json.findValue("id") != null && json.findValue("id").asLong() > 0){
-            post.saveWithNumber(json.findValue("id").asLong());
-        } else {
-            post.save();
+        if (!AccessControl.isResourceCreatable(
+                UserApp.currentUser(), posting.asResource(), ResourceType.NONISSUE_COMMENT)) {
+            return forbidden(ErrorViews.Forbidden.render("error.forbidden", project));
         }
-        attachUploadFilesToPost(files, post.asResource());
 
-        return ok(result);
-    }
+        User user = findAuthor(json.findValue("author"));
+        String body = json.findValue("body").asText();
 
-    private static Date getCreatedDate(long timestamp){
-        if(timestamp == 0){
-            return JodaDateUtil.now();
-        }
-        return new DateTime(timestamp * 1000).toDate();
+        final PostingComment comment = new PostingComment(posting, user, body);
+
+        comment.createdDate = parseDateString(json.findValue("createdAt"));
+        comment.setAuthor(user);
+        comment.posting = posting;
+        comment.save();
+
+        play.Logger.warn(json.findValue("temporaryUploadFiles").asText());
+        attachUploadFilesToPost(json.findValue("temporaryUploadFiles"), comment.asResource());
+
+        ObjectNode result = Json.newObject();
+        result.put("status", 201);
+        result.put("location", RouteUtil.getUrl(comment));
+
+        return created(result);
     }
 }
app/controllers/api/IssueApi.java
--- app/controllers/api/IssueApi.java
+++ app/controllers/api/IssueApi.java
@@ -28,6 +28,7 @@
 import java.text.SimpleDateFormat;
 import java.util.*;
 
+import static controllers.api.UserApi.createUserNode;
 import static play.libs.Json.toJson;
 
 public class IssueApi extends AbstractPostingApp {
@@ -66,7 +67,7 @@
 
     @Transactional
     @IsCreatable(ResourceType.ISSUE_POST)
-    public static Result newIssueByJson(String owner, String projectName) {
+    public static Result newIssues(String owner, String projectName) {
         ObjectNode result = Json.newObject();
         JsonNode json = request().body().asJson();
         if (json == null) {
@@ -103,6 +104,7 @@
         issue.assignee = findAssginee(json.findValue("assignees"), project);
         issue.milestone = findMilestone(json.findValue("milestoneTitle"), project);
         issue.dueDate = findDueDate(json.findValue("dueDate"));
+        issue.numOfComments = 0;
 
         if(json.findValue("number") != null && json.findValue("number").asLong() > 0){
             issue.saveWithNumber(json.findValue("number").asLong());
@@ -149,7 +151,7 @@
 
     @Transactional
     @IsCreatable(ResourceType.ISSUE_COMMENT)
-    public static Result newIssueCommentByJson(String ownerName, String projectName, Long number)
+    public static Result newIssueComment(String ownerName, String projectName, Long number)
             throws IOException {
         JsonNode json = request().body().asJson();
         if(json == null) {
@@ -178,18 +180,21 @@
         attachUploadFilesToPost(json.findValue("temporaryUploadFiles"), comment.asResource());
 
         ObjectNode result = Json.newObject();
-        result.put("status", 200);
+        result.put("status", 201);
         result.put("location", RouteUtil.getUrl(comment));
 
-        return ok(result);
+        return created(result);
     }
 
-    private static User findAuthor(JsonNode authorNode){
+    public static User findAuthor(JsonNode authorNode){
         if (authorNode != null) {
             String email = authorNode.findValue("email").asText();
             User originalAuthor = User.findByEmail(email);
             if (originalAuthor != null) {
                 return originalAuthor;
+            } else {
+                createUserNode(authorNode);
+                return User.findByEmail(email);
             }
         }
 
app/controllers/api/ProjectApi.java
--- app/controllers/api/ProjectApi.java
+++ app/controllers/api/ProjectApi.java
@@ -62,7 +62,7 @@
         json.put("issueCount", project.issues.size());
         json.put("postCount", project.posts.size());
         json.put("milestoneCount", project.milestones.size());
-        json.put("labels", projectLabels(project));
+        json.put("labels", getAllLabels(project.issueLabels));
         json.put("issues", composePosts(project, Issue.finder));
         json.put("posts", composePosts(project, Posting.finder));
         json.put("milestones", toJson(project.milestones.stream()
@@ -369,6 +369,18 @@
         return toJson(labels);
     }
 
+    public static JsonNode getAllLabels(List<IssueLabel> issueLabels) {
+        List<ObjectNode> labels = new ArrayList<>();
+        for(IssueLabel label: issueLabels){
+            ObjectNode labelNode = Json.newObject();
+            labelNode.put("labelName", label.name);
+            labelNode.put("labelColor", label.color);
+            labelNode.put("labelCategory", label.category.name);
+            labels.add(labelNode);
+        }
+        return toJson(labels);
+    }
+
     public static List<ObjectNode> composePlainCommentsJson(AbstractPosting posting) {
         List<ObjectNode> comments = new ArrayList<>();
         for (Comment comment : posting.getComments()) {
app/controllers/api/UserApi.java
--- app/controllers/api/UserApi.java
+++ app/controllers/api/UserApi.java
@@ -113,7 +113,7 @@
         return created(toJson(createdUsers));
     }
 
-    private static JsonNode createUserNode(JsonNode userNode) {
+    public static JsonNode createUserNode(JsonNode userNode) {
         ObjectNode createdUserNode = Json.newObject();
 
         String loginId = userNode.findValue("loginId").asText();
app/models/AbstractPosting.java
--- app/models/AbstractPosting.java
+++ app/models/AbstractPosting.java
@@ -141,8 +141,12 @@
 
     @Transactional
     public void update() {
-        numOfComments = computeNumOfComments();
-        super.update();
+        try {
+            numOfComments = computeNumOfComments();
+            super.update();
+        } catch (OptimisticLockException ole) {
+            play.Logger.warn("OptimisticLockException: " + ole.getMessage());
+        }
         updateMention();
     }
 
app/models/Assignee.java
--- app/models/Assignee.java
+++ app/models/Assignee.java
@@ -20,6 +20,7 @@
  */
 package models;
 
+import org.apache.commons.collections.CollectionUtils;
 import play.data.validation.Constraints.Required;
 import play.db.ebean.Model;
 
conf/routes
--- conf/routes
+++ conf/routes
@@ -41,10 +41,11 @@
 GET            /-_-api/v1/                                                             controllers.Application.index()
 GET            /-_-api/v1/owners/:owner/projects/:projectName/exports                  controllers.api.ProjectApi.exports(owner:String, projectName:String)
 GET            /-_-api/v1/owners/:owner/projects/:projectName/posts/$number<[0-9]+>/watchers   controllers.api.WatcherApi.getWatchers(owner:String, projectName:String, number:Long)
-POST           /-_-api/v1/owners/:owner/projects/:projectName/posts                    controllers.api.BoardApi.newPostByJson(owner:String, projectName:String)
+POST           /-_-api/v1/owners/:owner/projects/:projectName/posts                    controllers.api.BoardApi.newPostings(owner:String, projectName:String)
+POST           /-_-api/v1/owners/:owner/projects/:projectName/posts/:number/comments  controllers.api.BoardApi.newPostingComment(owner:String, projectName:String, number:Long)
 POST           /-_-api/v1/owners/:owner/projects/:projectName/postlabel/:number        controllers.api.BoardApi.updatePostLabel(owner:String, projectName:String, number:Long)
-POST           /-_-api/v1/owners/:owner/projects/:projectName/issues                   controllers.api.IssueApi.newIssueByJson(owner:String, projectName:String)
-POST           /-_-api/v1/owners/:owner/projects/:projectName/issues/:number/comments  controllers.api.IssueApi.newIssueCommentByJson(owner:String, projectName:String, number:Long)
+POST           /-_-api/v1/owners/:owner/projects/:projectName/issues                   controllers.api.IssueApi.newIssues(owner:String, projectName:String)
+POST           /-_-api/v1/owners/:owner/projects/:projectName/issues/:number/comments  controllers.api.IssueApi.newIssueComment(owner:String, projectName:String, number:Long)
 POST           /-_-api/v1/owners/:owner/projects/:projectName/issuelabel/:number       controllers.api.IssueApi.updateIssueLabel(owner:String, projectName:String, number:Long)
 POST           /-_-api/v1/owners/:owner/projects/:projectName/milestones               controllers.api.MilestoneApi.newMilestone(owner:String, projectName:String)
 GET            /-_-api/v1/hello                                                        controllers.api.GlobalApi.hello()
Add a comment
List