doortts doortts 2016-11-13
api: Support posting import by api
@a735115efbc6fae64a0779979193fbe5e2e33515
app/actions/AbstractProjectCheckAction.java
--- app/actions/AbstractProjectCheckAction.java
+++ app/actions/AbstractProjectCheckAction.java
@@ -36,6 +36,7 @@
 import utils.RedirectUtil;
 
 import static play.mvc.Controller.flash;
+import static play.mvc.Http.Context.current;
 
 /**
  * Checks if the project which meets the request of a pattern,
@@ -49,9 +50,20 @@
 public abstract class AbstractProjectCheckAction<T> extends Action<T> {
     @Override
     public final Promise<Result> call(Context context) throws Throwable {
+        String ownerLoginId = null;
+        String projectName = null;
+
         PathParser parser = new PathParser(context);
-        String ownerLoginId = parser.getOwnerLoginId();
-        String projectName = parser.getProjectName();
+        if (current().request().getHeader(UserApp.USER_TOKEN_HEADER) != null) {
+            // eg. context.request().path() : /-_-api/v1/owners/doortts/projects/Test/posts
+            String[] base = context.request().path().split("/owners/");
+            String[] partial = base[1].split("/");
+            ownerLoginId = partial[0];
+            projectName = partial[2];
+        } else {
+            ownerLoginId = parser.getOwnerLoginId();
+            projectName = parser.getProjectName();
+        }
 
         Project project = Project.findByOwnerAndProjectName(ownerLoginId, projectName);
 
app/controllers/AbstractPostingApp.java
--- app/controllers/AbstractPostingApp.java
+++ app/controllers/AbstractPostingApp.java
@@ -20,6 +20,7 @@
  */
 package controllers;
 
+import com.fasterxml.jackson.databind.JsonNode;
 import controllers.annotation.AnonymousCheck;
 import models.*;
 import models.enumeration.Direction;
@@ -135,6 +136,23 @@
         }
     }
 
+    public static void attachUploadFilesToPost(JsonNode files, Resource resource) {
+        if(files.isArray() && files.size() > 0){
+            String [] fileIds = new String[files.size()];
+            int idx = 0;
+            for (JsonNode fileNo : files) {
+                fileIds[idx] = fileNo.asText();
+                idx++;
+            }
+            int attachedFileCount = Attachment.moveOnlySelected(UserApp.currentUser().asResource(), resource,
+                    fileIds);
+            if( attachedFileCount != files.size()){
+                flash(Constants.TITLE, Messages.get("post.popup.fileAttach.hasMissing", files.size() - attachedFileCount));
+                flash(Constants.DESCRIPTION, Messages.get("post.popup.fileAttach.hasMissing.description", getTemporaryFilesServerKeepUpTimeOfMinuntes()));
+            }
+        }
+    }
+
     private static long getTemporaryFilesServerKeepUpTimeOfMinuntes() {
         return AttachmentApp.TEMPORARYFILES_KEEPUP_TIME_MILLIS/(60*1000l);
     }
app/controllers/AttachmentApp.java
--- app/controllers/AttachmentApp.java
+++ app/controllers/AttachmentApp.java
@@ -62,7 +62,10 @@
         }
         File file = filePart.getFile();
 
-        User uploader = accessedWithToken(request().getHeader("Yona-Token"));
+        User uploader = UserApp.currentUser();
+        if (uploader.isAnonymous()) {
+            uploader = User.findByUserToken(request().getHeader("Yona-Token"));
+        }
 
         // Anonymous cannot upload a file.
         if (uploader.isAnonymous()) {
@@ -117,19 +120,6 @@
             // Why not 204? Because 204 doesn't allow response to have a body,
             // so we cannot tell what is same with the file you try to add.
             return ok(responseBody);
-        }
-    }
-
-    private static User accessedWithToken(String token){
-        User user = null;
-        if(token != null) {
-            user = User.find.where().eq("token", token).findUnique();
-        }
-
-        if(user == null){
-            return User.anonymous;
-        } else {
-            return user;
         }
     }
 
app/controllers/BoardApi.java
--- app/controllers/BoardApi.java
+++ app/controllers/BoardApi.java
@@ -9,13 +9,16 @@
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
-import models.IssueLabel;
-import models.Posting;
-import models.Project;
+import controllers.annotation.IsCreatable;
+import models.*;
+import models.enumeration.ResourceType;
+import org.joda.time.DateTime;
 import play.db.ebean.Transactional;
 import play.libs.Json;
 import play.mvc.Result;
+import utils.JodaDateUtil;
 
+import java.util.Date;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -34,7 +37,6 @@
         Set<IssueLabel> labels = new HashSet<>();
 
         for(JsonNode node: json){
-            System.out.println("node: " + node);
             Long labelId = Long.parseLong(node.asText());
             labels.add(IssueLabel.finder.byId(labelId));
         }
@@ -48,4 +50,42 @@
         return ok(result);
     }
 
+    @Transactional
+    @IsCreatable(ResourceType.BOARD_POST)
+    public static Result newPostByJson(String owner, String projectName) {
+        ObjectNode result = Json.newObject();
+        JsonNode json = request().body().asJson();
+        if(json == null) {
+            return badRequest("Expecting Json data");
+        }
+
+        Project project = Project.findByOwnerAndProjectName(owner, projectName);
+
+        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();
+        }
+        attachUploadFilesToPost(files, post.asResource());
+
+        return ok(result);
+    }
+
+    private static Date getCreatedDate(long timestamp){
+        if(timestamp == 0){
+            return JodaDateUtil.now();
+        }
+        return new DateTime(timestamp * 1000).toDate();
+    }
 }
app/controllers/UserApp.java
--- app/controllers/UserApp.java
+++ app/controllers/UserApp.java
@@ -70,6 +70,7 @@
     public static final String DEFAULT_GROUP = "own";
     public static final String DEFAULT_SELECTED_TAB = "projects";
     public static final String TOKEN_USER = "TOKEN_USER";
+    public static final String USER_TOKEN_HEADER = "Yona-Token";
 
     @AnonymousCheck
     public static Result users(String query) {
@@ -361,6 +362,11 @@
         User user = getUserFromSession();
         if (!user.isAnonymous()) {
             return user;
+        } else {
+            user = User.findUserIfTokenExist(user);
+        }
+        if(!user.isAnonymous()) {
+            return user;
         }
         return getUserFromContext();
     }
app/models/AbstractPosting.java
--- app/models/AbstractPosting.java
+++ app/models/AbstractPosting.java
@@ -143,6 +143,14 @@
     }
 
     @Transactional
+    public void saveWithNumber(long number) {
+        this.number = number;
+        numOfComments = computeNumOfComments();
+        super.save();
+        updateMention();
+    }
+
+    @Transactional
     public void update() {
         numOfComments = computeNumOfComments();
         super.update();
app/models/Attachment.java
--- app/models/Attachment.java
+++ app/models/Attachment.java
@@ -84,11 +84,15 @@
      * @return an attachment which matches up with the given one.
      */
     private static Attachment findBy(Attachment attach) {
-        return find.where()
+         List<Attachment> list = find.where()
                 .eq("name", attach.name)
                 .eq("hash", attach.hash)
                 .eq("containerType", attach.containerType)
-                .eq("containerId", attach.containerId).findUnique();
+                .eq("containerId", attach.containerId).findList();
+        if( list.size() > 0) {
+            return list.get(0);
+        }
+        return null;
     }
 
     /**
app/models/User.java
--- app/models/User.java
+++ app/models/User.java
@@ -275,6 +275,30 @@
         }
     }
 
+    public static User findByUserToken(String token){
+        User user = null;
+        if(token != null) {
+            user = User.find.where().eq("token", token).findUnique();
+        }
+
+        if(user != null){
+            return user;
+        }
+
+        return User.anonymous;
+    }
+
+    public static User findUserIfTokenExist(User user){
+        if(!user.isAnonymous()){
+            return user;
+        }
+        String userToken = play.mvc.Http.Context.current().request().getHeader(UserApp.USER_TOKEN_HEADER);
+        if( userToken != null) {
+            return User.findByUserToken(userToken);
+        }
+        return User.anonymous;
+    }
+
     /**
      *
      * Find a user by email account.
app/utils/AccessControl.java
--- app/utils/AccessControl.java
+++ app/utils/AccessControl.java
@@ -58,6 +58,7 @@
      * @return true if the user has the permission
      */
     public static boolean isProjectResourceCreatable(User user, Project project, ResourceType resourceType) {
+        user = User.findUserIfTokenExist(user);
         // Anonymous user cannot create anything.
         if (user == null || user.isAnonymous()) {
             return false;
app/utils/HttpUtil.java
--- app/utils/HttpUtil.java
+++ app/utils/HttpUtil.java
@@ -74,8 +74,7 @@
      *
      * @param request  the request of the client
      * @param types    the supported types
-     * @return the most preferred type; {@code null} if the client has no
-     *         preference among the supported types.
+     * @return the most preferred type;
      */
     public static String getPreferType(Http.Request request, String ... types) {
         // acceptedTypes is sorted by preference.
@@ -86,7 +85,7 @@
                 }
             }
         }
-        return null;
+        return "text/html";  // Default fallback. Should not be null!
     }
 
     /**
build.sbt
--- build.sbt
+++ build.sbt
@@ -16,6 +16,7 @@
   "com.h2database" % "h2" % "1.3.176",
   // JDBC driver for mariadb
   "org.mariadb.jdbc" % "mariadb-java-client" % "1.3.6",
+  "net.contentobjects.jnotify" % "jnotify" % "0.94",
   // Core Library
   "org.eclipse.jgit" % "org.eclipse.jgit" % "3.5.3.201412180710-r",
   // Smart HTTP Servlet
conf/routes
--- conf/routes
+++ conf/routes
@@ -23,7 +23,8 @@
 
 GET            /-_-api                                                                controllers.Application.index()
 GET            /-_-api/v1/                                                            controllers.Application.index()
-POST           /-_-api/v1/owners/:owner/projects/:projectName/:number                 controllers.BoardApi.updatePostLabel(owner:String, projectName:String, number:Long)
+POST           /-_-api/v1/owners/:owner/projects/:projectName/posts                   controllers.BoardApi.newPostByJson(owner:String, projectName:String)
+POST           /-_-api/v1/owners/:owner/projects/:projectName/postlabel/:number       controllers.BoardApi.updatePostLabel(owner:String, projectName:String, number:Long)
 
 # Import
 GET            /import                                                                controllers.ImportApp.importForm()
Add a comment
List