
Refactor Issue and Post.
* Rename Post to Posting. * Rename Comment to PostingComment. * Remove duplication between Issue and Posting.
@be6519d7c229d728a9c5c17fbae1913bee2fd7dc
--- app/Global.java
+++ app/Global.java
... | ... | @@ -19,28 +19,32 @@ |
19 | 19 |
|
20 | 20 |
private static void insertDefaults() { |
21 | 21 |
if (Ebean.find(User.class).findRowCount() == 0) { |
22 |
+ String initFileName = "initial-data.yml"; |
|
23 |
+ |
|
22 | 24 |
@SuppressWarnings("unchecked") |
23 | 25 |
Map<String, List<Object>> all = (Map<String, List<Object>>) Yaml |
24 |
- .load("initial-data.yml"); |
|
26 |
+ .load(initFileName); |
|
25 | 27 |
|
26 |
- Ebean.save(all.get("users")); |
|
27 |
- Ebean.save(all.get("projects")); |
|
28 |
- Ebean.save(all.get("milestones")); |
|
29 |
- Ebean.save(all.get("issues")); |
|
30 |
- Ebean.save(all.get("issueComments")); |
|
31 |
- Ebean.save(all.get("posts")); |
|
32 |
- Ebean.save(all.get("comments")); |
|
28 |
+ String[] entityNames = { |
|
29 |
+ "users", "projects", "milestones", |
|
30 |
+ "issues", "issueComments", |
|
31 |
+ "postings", "postingComments", |
|
32 |
+ "roles", "projectUsers", |
|
33 |
+ "taskBoards", "lines", "cards", "labels", "checkLists", |
|
34 |
+ "siteAdmins" |
|
35 |
+ }; |
|
33 | 36 |
|
34 |
- Ebean.save(all.get("roles")); |
|
35 |
- Ebean.save(all.get("projectUsers")); |
|
37 |
+ // Check whether every entities exist. |
|
38 |
+ for (String entityName : entityNames) { |
|
39 |
+ if (all.get(entityName) == null) { |
|
40 |
+ throw new RuntimeException("Failed to find the '" + entityName |
|
41 |
+ + "' entity in '" + initFileName + "'"); |
|
42 |
+ } |
|
43 |
+ } |
|
36 | 44 |
|
37 |
- Ebean.save(all.get("taskBoards")); |
|
38 |
- Ebean.save(all.get("lines")); |
|
39 |
- Ebean.save(all.get("cards")); |
|
40 |
- Ebean.save(all.get("labels")); |
|
41 |
- Ebean.save(all.get("checkLists")); |
|
42 |
- |
|
43 |
- Ebean.save(all.get("siteAdmins")); |
|
45 |
+ for (String entityName : entityNames) { |
|
46 |
+ Ebean.save(all.get(entityName)); |
|
47 |
+ } |
|
44 | 48 |
} |
45 | 49 |
} |
46 | 50 |
|
+++ app/controllers/AbstractPostingApp.java
... | ... | @@ -0,0 +1,116 @@ |
1 | +package controllers; | |
2 | + | |
3 | +import models.AbstractPosting; | |
4 | +import models.Comment; | |
5 | +import models.Project; | |
6 | +import models.Attachment; | |
7 | +import models.enumeration.Direction; | |
8 | +import models.enumeration.Matching; | |
9 | +import models.enumeration.Operation; | |
10 | + | |
11 | +import models.support.OrderParams; | |
12 | +import models.support.SearchParams; | |
13 | +import play.data.Form; | |
14 | +import play.mvc.Call; | |
15 | +import play.mvc.Content; | |
16 | +import utils.AccessControl; | |
17 | + | |
18 | +import play.mvc.Controller; | |
19 | +import play.mvc.Result; | |
20 | +import utils.Callback; | |
21 | +import utils.Constants; | |
22 | + | |
23 | +import java.io.IOException; | |
24 | + | |
25 | +public class AbstractPostingApp extends Controller { | |
26 | + public static final int ITEMS_PER_PAGE = 15; | |
27 | + | |
28 | + public static class SearchCondition { | |
29 | + public String orderBy; | |
30 | + public String orderDir; | |
31 | + public String filter; | |
32 | + public int pageNum; | |
33 | + | |
34 | + public SearchCondition() { | |
35 | + this.orderDir = Direction.DESC.direction(); | |
36 | + this.orderBy = "id"; | |
37 | + this.filter = ""; | |
38 | + this.pageNum = 1; | |
39 | + } | |
40 | + } | |
41 | + | |
42 | + public static Result newComment(Comment comment, Form<? extends Comment> commentForm, Call redirectTo, Callback updateCommentContainer) throws IOException { | |
43 | + if (session(UserApp.SESSION_USERID) == null) { | |
44 | + flash(Constants.WARNING, "user.login.alert"); | |
45 | + return redirect(redirectTo); | |
46 | + } | |
47 | + | |
48 | + if (commentForm.hasErrors()) { | |
49 | + flash(Constants.WARNING, "board.comment.empty"); | |
50 | + return redirect(redirectTo); | |
51 | + } | |
52 | + | |
53 | + comment.setAuthor(UserApp.currentUser()); | |
54 | + updateCommentContainer.run(); // this updates comment.issue or comment.posting; | |
55 | + Project project = comment.asResource().getProject(); | |
56 | + comment.save(); | |
57 | + | |
58 | + // Attach all of the files in the current user's temporary storage. | |
59 | + Attachment.attachFiles(UserApp.currentUser().id, project.id, comment.asResource().getType(), comment.id); | |
60 | + | |
61 | + return redirect(redirectTo); | |
62 | + } | |
63 | + | |
64 | + public static Result deletePosting(AbstractPosting posting, Call redirectTo) { | |
65 | + if (!AccessControl.isAllowed(UserApp.currentUser(), posting.asResource(), Operation.DELETE)) { | |
66 | + return forbidden(); | |
67 | + } | |
68 | + | |
69 | + posting.delete(); | |
70 | + | |
71 | + Attachment.deleteAll(posting.asResource().getType(), posting.id); | |
72 | + | |
73 | + return redirect(redirectTo); | |
74 | + } | |
75 | + | |
76 | + public static Result deleteComment(Comment comment, Call redirectTo) { | |
77 | + if (!AccessControl.isAllowed(UserApp.currentUser(), comment.asResource(), Operation.DELETE)) { | |
78 | + return forbidden(); | |
79 | + } | |
80 | + | |
81 | + comment.delete(); | |
82 | + | |
83 | + Attachment.deleteAll(comment.asResource().getType(), comment.id); | |
84 | + | |
85 | + return redirect(redirectTo); | |
86 | + } | |
87 | + | |
88 | + protected static Result editPosting(AbstractPosting original, AbstractPosting posting, Form<? extends AbstractPosting> postingForm, Call redirectTo, Callback updatePosting) { | |
89 | + if (postingForm.hasErrors()) { | |
90 | + return badRequest(postingForm.errors().toString()); | |
91 | + } | |
92 | + | |
93 | + posting.id = original.id; | |
94 | + posting.date = original.date; | |
95 | + posting.authorId = original.authorId; | |
96 | + posting.authorLoginId = original.authorLoginId; | |
97 | + posting.authorName = original.authorName; | |
98 | + posting.project = original.project; | |
99 | + updatePosting.run(); | |
100 | + original.update(); | |
101 | + | |
102 | + // Attach the files in the current user's temporary storage. | |
103 | + Attachment.attachFiles(UserApp.currentUser().id, original.project.id, original.asResource().getType(), original.id); | |
104 | + | |
105 | + return redirect(redirectTo); | |
106 | + } | |
107 | + | |
108 | + public static Result newPostingForm(Project project, Content content) { | |
109 | + if (UserApp.currentUser() == UserApp.anonymous) { | |
110 | + return unauthorized(views.html.project.unauthorized.render(project)); | |
111 | + } | |
112 | + | |
113 | + return ok(content); | |
114 | + } | |
115 | + | |
116 | +} |
--- app/controllers/BoardApp.java
+++ app/controllers/BoardApp.java
... | ... | @@ -6,85 +6,84 @@ |
6 | 6 |
|
7 | 7 |
import com.avaje.ebean.Page; |
8 | 8 |
|
9 |
-import models.Attachment; |
|
10 |
-import models.Comment; |
|
11 |
-import models.Post; |
|
12 |
-import models.Project; |
|
13 |
-import models.User; |
|
14 |
-import models.enumeration.Direction; |
|
9 |
+import models.*; |
|
15 | 10 |
import models.enumeration.Operation; |
16 | 11 |
import models.enumeration.ResourceType; |
17 |
-import play.data.Form; |
|
18 |
-import play.mvc.Controller; |
|
19 |
-import play.mvc.Result; |
|
20 |
-import utils.AccessControl; |
|
21 |
-import utils.Constants; |
|
12 |
+ |
|
13 |
+import models.support.FinderTemplate; |
|
14 |
+import models.support.OrderParams; |
|
15 |
+import models.support.SearchParams; |
|
16 |
+import models.enumeration.Direction; |
|
17 |
+import models.enumeration.Matching; |
|
22 | 18 |
import views.html.board.editPost; |
23 | 19 |
import views.html.board.newPost; |
24 | 20 |
import views.html.board.postList; |
25 | 21 |
|
26 |
-public class BoardApp extends Controller { |
|
22 |
+import utils.AccessControl; |
|
23 |
+import utils.Callback; |
|
24 |
+import utils.Constants; |
|
25 |
+import utils.JodaDateUtil; |
|
27 | 26 |
|
28 |
- //TODO 이 클래스는 원래 따로 존재해야 함. |
|
29 |
- public static class SearchCondition{ |
|
30 |
- public final static String ORDERING_KEY_ID = "id"; |
|
31 |
- public final static String ORDERING_KEY_TITLE = "title"; |
|
32 |
- public final static String ORDERING_KEY_AGE = "date"; |
|
33 |
- public final static String ORDERING_KEY_AUTHOR = "authorName"; |
|
27 |
+import play.data.Form; |
|
28 |
+import play.mvc.Call; |
|
29 |
+import play.mvc.Result; |
|
34 | 30 |
|
35 |
- public SearchCondition() { |
|
36 |
- this.order = Direction.DESC.direction(); |
|
37 |
- this.key = ORDERING_KEY_ID; |
|
38 |
- this.filter = ""; |
|
39 |
- this.pageNum = 1; |
|
31 |
+import java.io.IOException; |
|
32 |
+ |
|
33 |
+public class BoardApp extends AbstractPostingApp { |
|
34 |
+ public static class SearchCondition extends AbstractPostingApp.SearchCondition { |
|
35 |
+ OrderParams getOrderParams() { |
|
36 |
+ return new OrderParams().add( |
|
37 |
+ orderBy, Direction.getValue(orderDir)); |
|
40 | 38 |
} |
41 | 39 |
|
42 |
- public String order; |
|
43 |
- public String key; |
|
44 |
- public String filter; |
|
45 |
- public int pageNum; |
|
40 |
+ SearchParams getSearchParam(Project project) { |
|
41 |
+ return new SearchParams() |
|
42 |
+ .add("project.owner", project.owner, Matching.EQUALS) |
|
43 |
+ .add("project.name", project.name, Matching.EQUALS) |
|
44 |
+ .add("body", filter, Matching.CONTAINS); |
|
45 |
+ } |
|
46 | 46 |
} |
47 |
- |
|
48 | 47 |
|
49 | 48 |
public static Result posts(String userName, String projectName, int pageNum) { |
50 | 49 |
Form<SearchCondition> postParamForm = new Form<SearchCondition>(SearchCondition.class); |
51 |
- SearchCondition postSearchCondition = postParamForm.bindFromRequest().get(); |
|
52 |
- postSearchCondition.pageNum = pageNum - 1; |
|
50 |
+ SearchCondition searchCondition = postParamForm.bindFromRequest().get(); |
|
51 |
+ searchCondition.pageNum = pageNum - 1; |
|
53 | 52 |
Project project = ProjectApp.getProject(userName, projectName); |
54 | 53 |
|
55 | 54 |
if (!AccessControl.isCreatable(User.findByLoginId(session().get("loginId")), project, ResourceType.BOARD_POST)) { |
56 | 55 |
return unauthorized(views.html.project.unauthorized.render(project)); |
57 | 56 |
} |
58 | 57 |
|
59 |
- Page<Post> posts = Post.findOnePage(project.owner, project.name, postSearchCondition.pageNum, |
|
60 |
- Direction.getValue(postSearchCondition.order), postSearchCondition.key, postSearchCondition.filter); |
|
61 |
- return ok(postList.render("menu.board", project, posts, postSearchCondition)); |
|
58 |
+ SearchParams searchParam = searchCondition.getSearchParam(project); |
|
59 |
+ OrderParams orderParams = searchCondition.getOrderParams(); |
|
60 |
+ |
|
61 |
+ Page<Posting> posts = FinderTemplate.getPage( |
|
62 |
+ orderParams, searchParam, Posting.finder, ITEMS_PER_PAGE, searchCondition.pageNum); |
|
63 |
+ |
|
64 |
+ return ok(postList.render("menu.board", project, posts, searchCondition)); |
|
62 | 65 |
} |
63 | 66 |
|
64 | 67 |
public static Result newPostForm(String userName, String projectName) { |
65 | 68 |
Project project = ProjectApp.getProject(userName, projectName); |
66 |
- if (UserApp.currentUser() == UserApp.anonymous) { |
|
67 |
- return unauthorized(views.html.project.unauthorized.render(project)); |
|
68 |
- } |
|
69 |
- |
|
70 |
- return ok(newPost.render("board.post.new", new Form<Post>(Post.class), project)); |
|
69 |
+ return newPostingForm(project, |
|
70 |
+ newPost.render("board.post.new", new Form<Posting>(Posting.class), project)); |
|
71 | 71 |
} |
72 | 72 |
|
73 | 73 |
public static Result newPost(String userName, String projectName) { |
74 |
- Form<Post> postForm = new Form<Post>(Post.class).bindFromRequest(); |
|
74 |
+ Form<Posting> postForm = new Form<Posting>(Posting.class).bindFromRequest(); |
|
75 | 75 |
Project project = ProjectApp.getProject(userName, projectName); |
76 | 76 |
if (postForm.hasErrors()) { |
77 | 77 |
flash(Constants.WARNING, "board.post.empty"); |
78 | 78 |
|
79 | 79 |
return redirect(routes.BoardApp.newPost(userName, projectName)); |
80 | 80 |
} else { |
81 |
- Post post = postForm.get(); |
|
82 |
- post.authorId = UserApp.currentUser().id; |
|
83 |
- post.authorLoginId = UserApp.currentUser().loginId; |
|
84 |
- post.authorName = UserApp.currentUser().name; |
|
85 |
- post.commentCount = 0; |
|
81 |
+ Posting post = postForm.get(); |
|
82 |
+ post.date = JodaDateUtil.now(); |
|
83 |
+ post.setAuthor(UserApp.currentUser()); |
|
86 | 84 |
post.project = project; |
87 |
- Post.write(post); |
|
85 |
+ |
|
86 |
+ post.save(); |
|
88 | 87 |
|
89 | 88 |
// Attach all of the files in the current user's temporary storage. |
90 | 89 |
Attachment.attachFiles(UserApp.currentUser().id, project.id, ResourceType.BOARD_POST, post.id); |
... | ... | @@ -94,8 +93,8 @@ |
94 | 93 |
} |
95 | 94 |
|
96 | 95 |
public static Result post(String userName, String projectName, Long postId) { |
97 |
- Post post = Post.findById(postId); |
|
98 | 96 |
Project project = ProjectApp.getProject(userName, projectName); |
97 |
+ Posting post = Posting.finder.byId(postId); |
|
99 | 98 |
if (!AccessControl.isCreatable(User.findByLoginId(session().get("loginId")), project, ResourceType.BOARD_POST)) { |
100 | 99 |
return unauthorized(views.html.project.unauthorized.render(project)); |
101 | 100 |
} |
... | ... | @@ -104,45 +103,39 @@ |
104 | 103 |
flash(Constants.WARNING, "board.post.notExist"); |
105 | 104 |
return redirect(routes.BoardApp.posts(project.owner, project.name, 1)); |
106 | 105 |
} else { |
107 |
- Form<Comment> commentForm = new Form<Comment>(Comment.class); |
|
106 |
+ Form<PostingComment> commentForm = new Form<PostingComment>(PostingComment.class); |
|
108 | 107 |
return ok(views.html.board.post.render(post, commentForm, project)); |
109 | 108 |
} |
110 | 109 |
} |
111 | 110 |
|
112 |
- public static Result newComment(String userName, String projectName, Long postId) { |
|
113 |
- Form<Comment> commentForm = new Form<Comment>(Comment.class).bindFromRequest(); |
|
111 |
+ public static Result newComment(String userName, String projectName, Long postId) throws IOException { |
|
112 |
+ final Posting post = Posting.finder.byId(postId); |
|
113 |
+ Project project = post.project; |
|
114 |
+ Call redirectTo = routes.BoardApp.post(project.owner, project.name, postId); |
|
115 |
+ Form<PostingComment> commentForm = new Form<PostingComment>(PostingComment.class) |
|
116 |
+ .bindFromRequest(); |
|
114 | 117 |
|
115 |
- Project project = ProjectApp.getProject(userName, projectName); |
|
116 |
- if (commentForm.hasErrors()) { |
|
117 |
- flash(Constants.WARNING, "board.comment.empty"); |
|
118 |
- return redirect(routes.BoardApp.post(project.owner, project.name, postId)); |
|
119 |
- } else { |
|
120 |
- Comment comment = commentForm.get(); |
|
121 |
- comment.post = Post.findById(postId); |
|
122 |
- comment.authorId = UserApp.currentUser().id; |
|
123 |
- comment.authorLoginId = UserApp.currentUser().loginId; |
|
124 |
- comment.authorName = UserApp.currentUser().name; |
|
118 |
+ final PostingComment comment = commentForm.get(); |
|
125 | 119 |
|
126 |
- Comment.write(comment); |
|
127 |
- Post.countUpCommentCounter(postId); |
|
128 |
- |
|
129 |
- // Attach all of the files in the current user's temporary storage. |
|
130 |
- Attachment.attachFiles(UserApp.currentUser().id, project.id, ResourceType.BOARD_COMMENT, comment.id); |
|
131 |
- |
|
132 |
- return redirect(routes.BoardApp.post(project.owner, project.name, postId)); |
|
133 |
- } |
|
120 |
+ return newComment(comment, commentForm, redirectTo, new Callback() { |
|
121 |
+ @Override |
|
122 |
+ public void run() { |
|
123 |
+ comment.posting = post; |
|
124 |
+ } |
|
125 |
+ }); |
|
134 | 126 |
} |
135 | 127 |
|
136 | 128 |
public static Result deletePost(String userName, String projectName, Long postId) { |
137 |
- Project project = ProjectApp.getProject(userName, projectName); |
|
138 |
- Post.delete(postId); |
|
139 |
- Attachment.deleteAll(ResourceType.BOARD_POST, postId); |
|
140 |
- return redirect(routes.BoardApp.posts(project.owner, project.name, 1)); |
|
129 |
+ Posting posting = Posting.finder.byId(postId); |
|
130 |
+ Project project = posting.project; |
|
131 |
+ |
|
132 |
+ return deletePosting(posting, |
|
133 |
+ routes.BoardApp.posts(project.owner, project.name, 1)); |
|
141 | 134 |
} |
142 | 135 |
|
143 | 136 |
public static Result editPostForm(String userName, String projectName, Long postId) { |
144 |
- Post existPost = Post.findById(postId); |
|
145 |
- Form<Post> editForm = new Form<Post>(Post.class).fill(existPost); |
|
137 |
+ Posting existPost = Posting.finder.byId(postId); |
|
138 |
+ Form<Posting> editForm = new Form<Posting>(Posting.class).fill(existPost); |
|
146 | 139 |
Project project = ProjectApp.getProject(userName, projectName); |
147 | 140 |
|
148 | 141 |
if (AccessControl.isAllowed(UserApp.currentUser(), existPost.asResource(), Operation.UPDATE)) { |
... | ... | @@ -154,35 +147,25 @@ |
154 | 147 |
} |
155 | 148 |
|
156 | 149 |
public static Result editPost(String userName, String projectName, Long postId) { |
157 |
- Form<Post> postForm = new Form<Post>(Post.class).bindFromRequest(); |
|
150 |
+ Form<Posting> postForm = new Form<Posting>(Posting.class).bindFromRequest(); |
|
158 | 151 |
Project project = ProjectApp.getProject(userName, projectName); |
152 |
+ Posting post = postForm.get(); |
|
153 |
+ Posting original = Posting.finder.byId(postId); |
|
154 |
+ Call redirectTo = routes.BoardApp.posts(project.owner, project.name, 1); |
|
155 |
+ Callback doNothing = new Callback() { |
|
156 |
+ @Override |
|
157 |
+ public void run() { } |
|
158 |
+ }; |
|
159 | 159 |
|
160 |
- if (postForm.hasErrors()) { |
|
161 |
- flash(Constants.WARNING, "board.post.empty"); |
|
162 |
- return redirect(routes.BoardApp.editPost(userName, projectName, postId)); |
|
163 |
- } else { |
|
164 |
- |
|
165 |
- Post post = postForm.get(); |
|
166 |
- post.authorId = UserApp.currentUser().id; |
|
167 |
- post.authorName = UserApp.currentUser().name; |
|
168 |
- post.id = postId; |
|
169 |
- post.project = project; |
|
170 |
- |
|
171 |
- Post.edit(post); |
|
172 |
- |
|
173 |
- // Attach the files in the current user's temporary storage. |
|
174 |
- Attachment.attachFiles(UserApp.currentUser().id, project.id, ResourceType.BOARD_POST, post.id); |
|
175 |
- } |
|
176 |
- |
|
177 |
- return redirect(routes.BoardApp.posts(project.owner, project.name, 1)); |
|
178 |
- |
|
160 |
+ return editPosting(original, post, postForm, redirectTo, doNothing); |
|
179 | 161 |
} |
180 | 162 |
|
181 |
- public static Result deleteComment(String userName, String projectName, Long postId, Long commentId) { |
|
182 |
- Comment.delete(commentId); |
|
183 |
- Post.countDownCommentCounter(postId); |
|
184 |
- Attachment.deleteAll(ResourceType.BOARD_COMMENT, commentId); |
|
185 |
- return redirect(routes.BoardApp.post(userName, projectName, postId)); |
|
186 |
- } |
|
163 |
+ public static Result deleteComment(String userName, String projectName, Long postId, |
|
164 |
+ Long commentId) { |
|
165 |
+ Comment comment = PostingComment.find.byId(commentId); |
|
166 |
+ Project project = comment.asResource().getProject(); |
|
187 | 167 |
|
168 |
+ return deleteComment(comment, |
|
169 |
+ routes.BoardApp.post(project.owner, project.name, comment.getParent().id)); |
|
170 |
+ } |
|
188 | 171 |
} |
--- app/controllers/IssueApp.java
+++ app/controllers/IssueApp.java
... | ... | @@ -4,46 +4,107 @@ |
4 | 4 |
|
5 | 5 |
package controllers; |
6 | 6 |
|
7 |
-import java.io.File; |
|
8 |
-import java.io.IOException; |
|
9 |
-import java.io.UnsupportedEncodingException; |
|
10 |
-import java.util.List; |
|
11 |
- |
|
12 |
-import models.enumeration.ResourceType; |
|
13 |
- |
|
14 |
-import jxl.write.WriteException; |
|
15 |
- |
|
16 |
-import models.Assignee; |
|
17 |
-import models.Attachment; |
|
18 |
-import models.Issue; |
|
19 |
-import models.IssueComment; |
|
20 |
-import models.IssueLabel; |
|
21 |
-import models.Project; |
|
22 |
-import models.enumeration.Direction; |
|
23 |
-import models.enumeration.Operation; |
|
24 |
-import models.enumeration.State; |
|
7 |
+import models.*; |
|
8 |
+import models.enumeration.*; |
|
25 | 9 |
import models.support.FinderTemplate; |
26 | 10 |
import models.support.OrderParams; |
27 |
-import models.support.SearchCondition; |
|
11 |
+import models.support.SearchParams; |
|
28 | 12 |
|
29 |
-import org.apache.tika.Tika; |
|
30 |
- |
|
31 |
-import play.data.Form; |
|
32 |
-import play.mvc.Controller; |
|
33 |
-import play.mvc.Result; |
|
34 |
-import utils.AccessControl; |
|
35 |
-import utils.Constants; |
|
36 |
-import utils.HttpUtil; |
|
37 |
-import utils.JodaDateUtil; |
|
13 |
+import play.mvc.Http; |
|
38 | 14 |
import views.html.issue.editIssue; |
39 | 15 |
import views.html.issue.issue; |
40 | 16 |
import views.html.issue.issueList; |
41 | 17 |
import views.html.issue.newIssue; |
42 | 18 |
import views.html.issue.notExistingPage; |
43 | 19 |
|
20 |
+import utils.AccessControl; |
|
21 |
+import utils.Callback; |
|
22 |
+import utils.JodaDateUtil; |
|
23 |
+import utils.HttpUtil; |
|
24 |
+ |
|
25 |
+import play.data.Form; |
|
26 |
+import play.mvc.Call; |
|
27 |
+import play.mvc.Result; |
|
28 |
+ |
|
29 |
+import jxl.write.WriteException; |
|
30 |
+import org.apache.tika.Tika; |
|
44 | 31 |
import com.avaje.ebean.Page; |
45 | 32 |
|
46 |
-public class IssueApp extends Controller { |
|
33 |
+import java.io.File; |
|
34 |
+import java.io.IOException; |
|
35 |
+import java.io.UnsupportedEncodingException; |
|
36 |
+import java.util.ArrayList; |
|
37 |
+import java.util.List; |
|
38 |
+import java.util.Set; |
|
39 |
+ |
|
40 |
+public class IssueApp extends AbstractPostingApp { |
|
41 |
+ public static class SearchCondition extends AbstractPostingApp.SearchCondition { |
|
42 |
+ public String state; |
|
43 |
+ public Boolean commentedCheck; |
|
44 |
+ public Long milestoneId; |
|
45 |
+ public Set<Long> labelIds; |
|
46 |
+ public String authorLoginId; |
|
47 |
+ public Long assigneeId; |
|
48 |
+ |
|
49 |
+ public SearchCondition() { |
|
50 |
+ super(); |
|
51 |
+ milestoneId = null; |
|
52 |
+ state = State.OPEN.name(); |
|
53 |
+ commentedCheck = false; |
|
54 |
+ } |
|
55 |
+ public OrderParams getOrderParams() { |
|
56 |
+ return new OrderParams().add(orderBy, Direction.getValue(orderDir)); |
|
57 |
+ } |
|
58 |
+ |
|
59 |
+ public SearchParams getSearchParam(Project project) { |
|
60 |
+ SearchParams searchParams = new SearchParams(); |
|
61 |
+ |
|
62 |
+ searchParams.add("project.id", project.id, Matching.EQUALS); |
|
63 |
+ |
|
64 |
+ if (authorLoginId != null && !authorLoginId.isEmpty()) { |
|
65 |
+ User user = User.findByLoginId(authorLoginId); |
|
66 |
+ if (user != null) { |
|
67 |
+ searchParams.add("authorId", user.id, Matching.EQUALS); |
|
68 |
+ } else { |
|
69 |
+ List<Long> ids = new ArrayList<Long>(); |
|
70 |
+ for (User u : User.find.where().contains("loginId", authorLoginId).findList()) { |
|
71 |
+ ids.add(u.id); |
|
72 |
+ } |
|
73 |
+ searchParams.add("authorId", ids, Matching.IN); |
|
74 |
+ } |
|
75 |
+ } |
|
76 |
+ |
|
77 |
+ if (assigneeId != null) { |
|
78 |
+ searchParams.add("assignee.user.id", assigneeId, Matching.EQUALS); |
|
79 |
+ searchParams.add("assignee.project.id", project.id, Matching.EQUALS); |
|
80 |
+ } |
|
81 |
+ |
|
82 |
+ if (filter != null && !filter.isEmpty()) { |
|
83 |
+ searchParams.add("title", filter, Matching.CONTAINS); |
|
84 |
+ } |
|
85 |
+ |
|
86 |
+ if (milestoneId != null) { |
|
87 |
+ searchParams.add("milestone.id", milestoneId, Matching.EQUALS); |
|
88 |
+ } |
|
89 |
+ |
|
90 |
+ if (labelIds != null) { |
|
91 |
+ for (Long labelId : labelIds) { |
|
92 |
+ searchParams.add("labels.id", labelId, Matching.EQUALS); |
|
93 |
+ } |
|
94 |
+ } |
|
95 |
+ |
|
96 |
+ if (commentedCheck) { |
|
97 |
+ searchParams.add("numOfComments", AbstractPosting.NUMBER_OF_ONE_MORE_COMMENTS, Matching.GE); |
|
98 |
+ } |
|
99 |
+ |
|
100 |
+ State st = State.getValue(state); |
|
101 |
+ if (st.equals(State.OPEN) || st.equals(State.CLOSED)) { |
|
102 |
+ searchParams.add("state", st, Matching.EQUALS); |
|
103 |
+ } |
|
104 |
+ |
|
105 |
+ return searchParams; |
|
106 |
+ } |
|
107 |
+ } |
|
47 | 108 |
|
48 | 109 |
/** |
49 | 110 |
* 페이지 처리된 이슈들의 리스트를 보여준다. |
... | ... | @@ -65,8 +126,6 @@ |
65 | 126 |
|
66 | 127 |
Form<SearchCondition> issueParamForm = new Form<SearchCondition>(SearchCondition.class); |
67 | 128 |
SearchCondition issueParam = issueParamForm.bindFromRequest().get(); |
68 |
- OrderParams orderParams = new OrderParams().add(issueParam.sortBy, |
|
69 |
- Direction.getValue(issueParam.orderBy)); |
|
70 | 129 |
issueParam.state = state; |
71 | 130 |
issueParam.pageNum = pageNum - 1; |
72 | 131 |
|
... | ... | @@ -78,19 +137,20 @@ |
78 | 137 |
} |
79 | 138 |
|
80 | 139 |
if (format.equals("xls")) { |
81 |
- return issuesAsExcel(issueParam, orderParams, project, state); |
|
140 |
+ return issuesAsExcel(issueParam, issueParam.getOrderParams(), project, state); |
|
82 | 141 |
} else { |
83 |
- Page<Issue> issues = FinderTemplate.getPage(orderParams, issueParam.asSearchParam(project), |
|
84 |
- Issue.finder, Issue.ISSUE_COUNT_PER_PAGE, issueParam.pageNum); |
|
142 |
+ Page<Issue> issues = FinderTemplate.getPage( |
|
143 |
+ issueParam.getOrderParams(), issueParam.getSearchParam(project), |
|
144 |
+ Issue.finder, ITEMS_PER_PAGE, issueParam.pageNum); |
|
85 | 145 |
return ok(issueList.render("title.issueList", issues, issueParam, project)); |
86 | 146 |
} |
87 | 147 |
} |
88 | 148 |
|
89 | 149 |
public static Result issuesAsExcel(SearchCondition issueParam, OrderParams orderParams, Project project, |
90 | 150 |
String state) throws WriteException, IOException, UnsupportedEncodingException { |
91 |
- List<Issue> issues = FinderTemplate.findBy(orderParams, issueParam.asSearchParam(project), Issue.finder); |
|
151 |
+ List<Issue> issues = FinderTemplate.findBy(orderParams, issueParam.getSearchParam(project), Issue.finder); |
|
92 | 152 |
File excelFile = Issue.excelSave(issues, project.name + "_" + state + "_filter_" |
93 |
- + issueParam.filter + "_milestone_" + issueParam.milestone); |
|
153 |
+ + issueParam.filter + "_milestone_" + issueParam.milestoneId); |
|
94 | 154 |
|
95 | 155 |
String filename = HttpUtil.encodeContentDisposition(excelFile.getName()); |
96 | 156 |
|
... | ... | @@ -103,15 +163,20 @@ |
103 | 163 |
|
104 | 164 |
public static Result issue(String userName, String projectName, Long issueId) { |
105 | 165 |
Project project = ProjectApp.getProject(userName, projectName); |
106 |
- Issue issueInfo = Issue.findById(issueId); |
|
166 |
+ Issue issueInfo = Issue.finder.byId(issueId); |
|
167 |
+ |
|
168 |
+ if (!AccessControl.isCreatable(User.findByLoginId(session().get("loginId")), project, ResourceType.ISSUE_POST)) { |
|
169 |
+ return unauthorized(views.html.project.unauthorized.render(project)); |
|
170 |
+ } |
|
171 |
+ |
|
107 | 172 |
if (issueInfo == null) { |
108 | 173 |
return ok(notExistingPage.render("title.post.notExistingPage", project)); |
109 | 174 |
} else { |
110 | 175 |
for (IssueLabel label: issueInfo.labels) { |
111 | 176 |
label.refresh(); |
112 | 177 |
} |
113 |
- Form<IssueComment> commentForm = new Form<IssueComment>(IssueComment.class); |
|
114 |
- Issue targetIssue = Issue.findById(issueId); |
|
178 |
+ Form<Comment> commentForm = new Form<Comment>(Comment.class); |
|
179 |
+ Issue targetIssue = Issue.finder.byId(issueId); |
|
115 | 180 |
Form<Issue> editForm = new Form<Issue>(Issue.class).fill(targetIssue); |
116 | 181 |
return ok(issue.render("title.issueDetail", issueInfo, editForm, commentForm, project)); |
117 | 182 |
} |
... | ... | @@ -119,11 +184,8 @@ |
119 | 184 |
|
120 | 185 |
public static Result newIssueForm(String userName, String projectName) { |
121 | 186 |
Project project = ProjectApp.getProject(userName, projectName); |
122 |
- if (UserApp.currentUser() == UserApp.anonymous) { |
|
123 |
- return unauthorized(views.html.project.unauthorized.render(project)); |
|
124 |
- } |
|
125 |
- |
|
126 |
- return ok(newIssue.render("title.newIssue", new Form<Issue>(Issue.class), project)); |
|
187 |
+ return newPostingForm( |
|
188 |
+ project, newIssue.render("title.newIssue", new Form<Issue>(Issue.class), project)); |
|
127 | 189 |
} |
128 | 190 |
|
129 | 191 |
public static Result newIssue(String ownerName, String projectName) throws IOException { |
... | ... | @@ -134,35 +196,24 @@ |
134 | 196 |
} else { |
135 | 197 |
Issue newIssue = issueForm.get(); |
136 | 198 |
newIssue.date = JodaDateUtil.now(); |
137 |
- newIssue.authorId = UserApp.currentUser().id; |
|
138 |
- newIssue.authorLoginId = UserApp.currentUser().loginId; |
|
139 |
- newIssue.authorName = UserApp.currentUser().name; |
|
199 |
+ newIssue.setAuthor(UserApp.currentUser()); |
|
140 | 200 |
newIssue.project = project; |
141 |
- newIssue.state = State.OPEN; |
|
142 |
- if (newIssue.assignee.user.id != null) { |
|
143 |
- newIssue.assignee = Assignee.add(newIssue.assignee.user.id, project.id); |
|
144 |
- } else { |
|
145 |
- newIssue.assignee = null; |
|
146 |
- } |
|
147 |
- String[] labelIds = request().body().asMultipartFormData().asFormUrlEncoded() |
|
148 |
- .get("labelIds"); |
|
149 |
- if (labelIds != null) { |
|
150 |
- for (String labelId : labelIds) { |
|
151 |
- newIssue.labels.add(IssueLabel.findById(Long.parseLong(labelId))); |
|
152 |
- } |
|
153 |
- } |
|
154 | 201 |
|
155 |
- Long issueId = Issue.create(newIssue); |
|
202 |
+ newIssue.state = State.OPEN; |
|
203 |
+ addLabels(newIssue.labels, request()); |
|
204 |
+ |
|
205 |
+ newIssue.save(); |
|
156 | 206 |
|
157 | 207 |
// Attach all of the files in the current user's temporary storage. |
158 |
- Attachment.attachFiles(UserApp.currentUser().id, project.id, ResourceType.ISSUE_POST, issueId); |
|
208 |
+ Attachment.attachFiles(UserApp.currentUser().id, project.id, ResourceType.ISSUE_POST, newIssue.id); |
|
159 | 209 |
} |
210 |
+ |
|
160 | 211 |
return redirect(routes.IssueApp.issues(project.owner, project.name, |
161 | 212 |
State.OPEN.state(), "html", 1)); |
162 | 213 |
} |
163 | 214 |
|
164 | 215 |
public static Result editIssueForm(String userName, String projectName, Long id) { |
165 |
- Issue targetIssue = Issue.findById(id); |
|
216 |
+ Issue targetIssue = Issue.finder.byId(id); |
|
166 | 217 |
Form<Issue> editForm = new Form<Issue>(Issue.class).fill(targetIssue); |
167 | 218 |
Project project = ProjectApp.getProject(userName, projectName); |
168 | 219 |
if (!AccessControl.isAllowed(UserApp.currentUser(), targetIssue.asResource(), Operation.UPDATE)) { |
... | ... | @@ -172,86 +223,68 @@ |
172 | 223 |
return ok(editIssue.render("title.editIssue", editForm, targetIssue, project)); |
173 | 224 |
} |
174 | 225 |
|
175 |
- public static Result editIssue(String userName, String projectName, Long id) throws IOException { |
|
176 |
- Form<Issue> issueForm = new Form<Issue>(Issue.class).bindFromRequest(); |
|
177 |
- |
|
178 |
- if (issueForm.hasErrors()) { |
|
179 |
- return badRequest(issueForm.errors().toString()); |
|
180 |
- } |
|
181 |
- |
|
182 |
- Issue issue = issueForm.get(); |
|
183 |
- Issue originalIssue = Issue.findById(id); |
|
184 |
- |
|
185 |
- issue.id = id; |
|
186 |
- issue.date = originalIssue.date; |
|
187 |
- issue.authorId = originalIssue.authorId; |
|
188 |
- issue.authorLoginId = originalIssue.authorLoginId; |
|
189 |
- issue.authorName = originalIssue.authorName; |
|
190 |
- issue.project = originalIssue.project; |
|
191 |
- if (issue.assignee.user.id != null) { |
|
192 |
- issue.assignee = Assignee.add(issue.assignee.user.id, originalIssue.project.id); |
|
193 |
- } else { |
|
194 |
- issue.assignee = null; |
|
195 |
- } |
|
196 |
- String[] labelIds = request().body().asMultipartFormData().asFormUrlEncoded() |
|
226 |
+ public static void addLabels(Set<IssueLabel> labels, Http.Request request) { |
|
227 |
+ String[] labelIds = request.body().asMultipartFormData().asFormUrlEncoded() |
|
197 | 228 |
.get("labelIds"); |
198 | 229 |
if (labelIds != null) { |
199 | 230 |
for (String labelId : labelIds) { |
200 |
- issue.labels.add(IssueLabel.findById(Long.parseLong(labelId))); |
|
231 |
+ labels.add(IssueLabel.findById(Long.parseLong(labelId))); |
|
201 | 232 |
} |
202 | 233 |
} |
234 |
+ }; |
|
203 | 235 |
|
204 |
- Issue.edit(issue); |
|
236 |
+ public static Result editIssue(String userName, String projectName, Long id) throws IOException { |
|
237 |
+ Form<Issue> issueForm = new Form<Issue>(Issue.class).bindFromRequest(); |
|
238 |
+ final Issue issue = issueForm.get(); |
|
239 |
+ final Issue originalIssue = Issue.finder.byId(id); |
|
240 |
+ final Project project = originalIssue.project; |
|
241 |
+ Call redirectTo = |
|
242 |
+ routes.IssueApp.issues(project.owner, project.name, State.OPEN.name(), "html", 1); |
|
205 | 243 |
|
206 |
- // Attach the files in the current user's temporary storage. |
|
207 |
- Attachment.attachFiles(UserApp.currentUser().id, originalIssue.project.id, ResourceType.ISSUE_POST, id); |
|
244 |
+ // updateIssueBeforeSave.run would be called just before this issue is saved. |
|
245 |
+ // It updates some properties only for issues, such as assignee or labels, but not for non-issues. |
|
246 |
+ Callback updateIssueBeforeSave = new Callback() { |
|
247 |
+ @Override |
|
248 |
+ public void run() { |
|
249 |
+ issue.project = project; |
|
250 |
+ addLabels(issue.labels, request()); |
|
251 |
+ } |
|
252 |
+ }; |
|
208 | 253 |
|
209 |
- return redirect(routes.IssueApp.issues(originalIssue.project.owner, originalIssue.project.name, State.OPEN.name(), "html", 1)); |
|
254 |
+ return editPosting(originalIssue, issue, issueForm, redirectTo, updateIssueBeforeSave); |
|
210 | 255 |
} |
211 | 256 |
|
212 | 257 |
public static Result deleteIssue(String userName, String projectName, Long issueId) { |
213 |
- Project project = ProjectApp.getProject(userName, projectName); |
|
258 |
+ Issue issue = Issue.finder.byId(issueId); |
|
259 |
+ Project project = issue.project; |
|
214 | 260 |
|
215 |
- Issue.delete(issueId); |
|
216 |
- Attachment.deleteAll(ResourceType.ISSUE_POST, issueId); |
|
217 |
- return redirect(routes.IssueApp.issues(project.owner, project.name, |
|
218 |
- State.OPEN.state(), "html", 1)); |
|
261 |
+ return deletePosting(issue, routes.IssueApp.issues(project.owner, project.name, |
|
262 |
+ State.OPEN.state(), "html", 1)); |
|
219 | 263 |
} |
220 | 264 |
|
221 | 265 |
public static Result newComment(String userName, String projectName, Long issueId) throws IOException { |
266 |
+ final Issue issue = Issue.finder.byId(issueId); |
|
267 |
+ Project project = issue.project; |
|
268 |
+ Call redirectTo = routes.IssueApp.issue(project.owner, project.name, issueId); |
|
222 | 269 |
Form<IssueComment> commentForm = new Form<IssueComment>(IssueComment.class) |
223 | 270 |
.bindFromRequest(); |
224 |
- Project project = ProjectApp.getProject(userName, projectName); |
|
225 |
- if (session(UserApp.SESSION_USERID) == null){ |
|
226 |
- flash(Constants.WARNING, "user.login.alert"); |
|
227 |
- return redirect(routes.IssueApp.issue(project.owner, project.name, issueId)); |
|
228 |
- } |
|
229 |
- if (commentForm.hasErrors()) { |
|
230 |
- flash(Constants.WARNING, "board.comment.empty"); |
|
231 |
- return redirect(routes.IssueApp.issue(project.owner, project.name, issueId)); |
|
232 |
- } else { |
|
233 |
- IssueComment comment = commentForm.get(); |
|
234 |
- comment.issue = Issue.findById(issueId); |
|
235 |
- comment.authorId = UserApp.currentUser().id; |
|
236 |
- comment.authorLoginId = UserApp.currentUser().loginId; |
|
237 |
- comment.authorName = UserApp.currentUser().name; |
|
238 |
- Long commentId = IssueComment.create(comment); |
|
239 |
- Issue.updateNumOfComments(issueId); |
|
240 | 271 |
|
241 |
- // Attach all of the files in the current user's temporary storage. |
|
242 |
- Attachment.attachFiles(UserApp.currentUser().id, project.id, ResourceType.ISSUE_COMMENT, commentId); |
|
272 |
+ final IssueComment comment = commentForm.get(); |
|
243 | 273 |
|
244 |
- return redirect(routes.IssueApp.issue(project.owner, project.name, issueId)); |
|
245 |
- } |
|
274 |
+ return newComment(comment, commentForm, redirectTo, new Callback() { |
|
275 |
+ @Override |
|
276 |
+ public void run() { |
|
277 |
+ comment.issue = issue; |
|
278 |
+ } |
|
279 |
+ }); |
|
246 | 280 |
} |
247 | 281 |
|
248 | 282 |
public static Result deleteComment(String userName, String projectName, Long issueId, |
249 | 283 |
Long commentId) { |
250 |
- Project project = ProjectApp.getProject(userName, projectName); |
|
251 |
- IssueComment.delete(commentId); |
|
252 |
- Issue.updateNumOfComments(issueId); |
|
253 |
- Attachment.deleteAll(ResourceType.ISSUE_COMMENT, commentId); |
|
254 |
- return redirect(routes.IssueApp.issue(project.owner, project.name, issueId)); |
|
255 |
- } |
|
284 |
+ Comment comment = IssueComment.find.byId(commentId); |
|
285 |
+ Project project = comment.asResource().getProject(); |
|
256 | 286 |
|
287 |
+ return deleteComment(comment, |
|
288 |
+ routes.IssueApp.issue(project.owner, project.name, comment.getParent().id)); |
|
289 |
+ } |
|
257 | 290 |
} |
--- app/controllers/MilestoneApp.java
+++ app/controllers/MilestoneApp.java
... | ... | @@ -115,7 +115,7 @@ |
115 | 115 |
if(!project.id.equals(Milestone.findById(id).project.id)) { |
116 | 116 |
return internalServerError(); |
117 | 117 |
} |
118 |
- Milestone.delete(Milestone.findById(id)); |
|
118 |
+ Milestone.findById(id).delete(); |
|
119 | 119 |
return redirect(routes.MilestoneApp.manageMilestones(userName, projectName)); |
120 | 120 |
|
121 | 121 |
} |
--- app/controllers/ProjectApp.java
+++ app/controllers/ProjectApp.java
... | ... | @@ -167,7 +167,7 @@ |
167 | 167 |
|
168 | 168 |
if (AccessControl.isAllowed(UserApp.currentUser(), project.asResource(), Operation.DELETE)) { |
169 | 169 |
RepositoryService.deleteRepository(userName, projectName, project.vcs); |
170 |
- Project.delete(project.id); |
|
170 |
+ project.delete(); |
|
171 | 171 |
return redirect(routes.Application.index()); |
172 | 172 |
} else { |
173 | 173 |
flash(Constants.WARNING, "project.member.isManager"); |
... | ... | @@ -259,7 +259,7 @@ |
259 | 259 |
} |
260 | 260 |
|
261 | 261 |
Page<Project> projects = FinderTemplate.getPage( |
262 |
- orderParams, searchParams, Project.find, 10, pageNum - 1); |
|
262 |
+ orderParams, searchParams, Project.find, Project.PROJECT_COUNT_PER_PAGE, pageNum - 1); |
|
263 | 263 |
|
264 | 264 |
return ok(projectList.render("title.projectList", projects, filter, state)); |
265 | 265 |
} |
--- app/controllers/SearchApp.java
+++ app/controllers/SearchApp.java
... | ... | @@ -6,6 +6,7 @@ |
6 | 6 |
import com.avaje.ebean.*; |
7 | 7 |
import models.*; |
8 | 8 |
import play.mvc.*; |
9 |
+ |
|
9 | 10 |
import views.html.search.*; |
10 | 11 |
|
11 | 12 |
import static play.data.Form.form; |
... | ... | @@ -51,13 +52,13 @@ |
51 | 52 |
} |
52 | 53 |
|
53 | 54 |
Page<Issue> resultIssues = null; |
54 |
- Page<Post> resultPosts = null; |
|
55 |
+ Page<Posting> resultPosts = null; |
|
55 | 56 |
|
56 | 57 |
if(!condition.type.equals("post")) { |
57 |
- resultIssues = Issue.find(project, condition); |
|
58 |
+ resultIssues = AbstractPosting.find(Issue.finder, project, condition); |
|
58 | 59 |
} |
59 | 60 |
if(!condition.type.equals("issue")) { |
60 |
- resultPosts = Post.find(project, condition); |
|
61 |
+ resultPosts = AbstractPosting.find(Posting.finder, project, condition); |
|
61 | 62 |
} |
62 | 63 |
|
63 | 64 |
response().setHeader("Accept-Ranges", "pages"); |
--- app/controllers/SiteApp.java
+++ app/controllers/SiteApp.java
... | ... | @@ -94,7 +94,7 @@ |
94 | 94 |
} |
95 | 95 |
|
96 | 96 |
public static Result deleteProject(Long projectId){ |
97 |
- Project.delete(projectId); |
|
97 |
+ Project.find.byId(projectId).delete(); |
|
98 | 98 |
return redirect(routes.SiteApp.projectList("")); |
99 | 99 |
} |
100 | 100 |
|
+++ app/models/AbstractPosting.java
... | ... | @@ -0,0 +1,123 @@ |
1 | +package models; | |
2 | + | |
3 | +import com.avaje.ebean.Page; | |
4 | +import controllers.SearchApp; | |
5 | +import models.enumeration.ResourceType; | |
6 | +import models.resource.Resource; | |
7 | +import org.joda.time.Duration; | |
8 | +import play.data.format.Formats; | |
9 | +import play.data.validation.Constraints; | |
10 | +import play.db.ebean.*; | |
11 | +import utils.JodaDateUtil; | |
12 | + | |
13 | +import javax.persistence.*; | |
14 | +import javax.validation.constraints.Size; | |
15 | +import java.util.Date; | |
16 | + | |
17 | +import static com.avaje.ebean.Expr.contains; | |
18 | + | |
19 | +/** | |
20 | + * Created with IntelliJ IDEA. | |
21 | + * User: nori | |
22 | + * Date: 13. 3. 4 | |
23 | + * Time: 오후 6:17 | |
24 | + * To change this template use File | Settings | File Templates. | |
25 | + */ | |
26 | + | |
27 | +@MappedSuperclass | |
28 | +abstract public class AbstractPosting extends Model { | |
29 | + public static final int FIRST_PAGE_NUMBER = 0; | |
30 | + public static final int NUMBER_OF_ONE_MORE_COMMENTS = 1; | |
31 | + | |
32 | + private static final long serialVersionUID = 1L; | |
33 | + | |
34 | + @Id | |
35 | + public Long id; | |
36 | + | |
37 | + @Constraints.Required | |
38 | + @Size(max=255) | |
39 | + public String title; | |
40 | + | |
41 | + @Constraints.Required | |
42 | + @Lob | |
43 | + public String body; | |
44 | + | |
45 | + @Constraints.Required | |
46 | + @Formats.DateTime(pattern = "YYYY/MM/DD/hh/mm/ss") | |
47 | + public Date date; | |
48 | + | |
49 | + public Long authorId; | |
50 | + public String authorLoginId; | |
51 | + public String authorName; | |
52 | + | |
53 | + @ManyToOne | |
54 | + public Project project; | |
55 | + | |
56 | + // This field is only for ordering. This field should be persistent because | |
57 | + // Ebean does NOT sort entities by transient field. | |
58 | + public int numOfComments; | |
59 | + | |
60 | + abstract public int computeNumOfComments(); | |
61 | + | |
62 | + public AbstractPosting() { | |
63 | + this.date = JodaDateUtil.now(); | |
64 | + } | |
65 | + | |
66 | + public void save() { | |
67 | + numOfComments = computeNumOfComments(); | |
68 | + super.save(); | |
69 | + } | |
70 | + | |
71 | + public void update() { | |
72 | + numOfComments = computeNumOfComments(); | |
73 | + super.update(); | |
74 | + } | |
75 | + | |
76 | + public static <T> Page<T> find(Finder<Long, T> finder, Project project, SearchApp.ContentSearchCondition condition) { | |
77 | + String filter = condition.filter; | |
78 | + return finder.where().eq("project.id", project.id) | |
79 | + .or(contains("title", filter), contains("body", filter)) | |
80 | + .findPagingList(condition.pageSize).getPage(condition.page - 1); | |
81 | + } | |
82 | + | |
83 | + /** | |
84 | + * 현재 글을 쓴지 얼마나 되었는지를 얻어내는 함수 | |
85 | + * @return | |
86 | + */ | |
87 | + public Duration ago() { | |
88 | + return JodaDateUtil.ago(this.date); | |
89 | + } | |
90 | + | |
91 | + abstract public Resource asResource(); | |
92 | + | |
93 | + public Resource asResource(final ResourceType type) { | |
94 | + return new Resource() { | |
95 | + @Override | |
96 | + public Long getId() { | |
97 | + return id; | |
98 | + } | |
99 | + | |
100 | + @Override | |
101 | + public Project getProject() { | |
102 | + return project; | |
103 | + } | |
104 | + | |
105 | + @Override | |
106 | + public ResourceType getType() { | |
107 | + return type; | |
108 | + } | |
109 | + | |
110 | + @Override | |
111 | + public Long getAuthorId() { | |
112 | + return authorId; | |
113 | + } | |
114 | + }; | |
115 | + } | |
116 | + | |
117 | + @Transient | |
118 | + public void setAuthor(User user) { | |
119 | + authorId = user.id; | |
120 | + authorLoginId = user.loginId; | |
121 | + authorName = user.name; | |
122 | + } | |
123 | +} |
--- app/models/Comment.java
+++ app/models/Comment.java
... | ... | @@ -1,6 +1,5 @@ |
1 | 1 |
package models; |
2 | 2 |
|
3 |
-import models.enumeration.ResourceType; |
|
4 | 3 |
import models.resource.Resource; |
5 | 4 |
|
6 | 5 |
import org.joda.time.*; |
... | ... | @@ -12,10 +11,9 @@ |
12 | 11 |
import javax.validation.constraints.Size; |
13 | 12 |
import java.util.*; |
14 | 13 |
|
15 |
-@Entity |
|
16 |
-public class Comment extends Model { |
|
14 |
+@MappedSuperclass |
|
15 |
+abstract public class Comment extends Model { |
|
17 | 16 |
private static final long serialVersionUID = 1L; |
18 |
- private static Finder<Long, Comment> find = new Finder<Long, Comment>(Long.class, Comment.class); |
|
19 | 17 |
|
20 | 18 |
@Id |
21 | 19 |
public Long id; |
... | ... | @@ -26,60 +24,36 @@ |
26 | 24 |
@Constraints.Required |
27 | 25 |
public Date date; |
28 | 26 |
|
29 |
- public String filePath; |
|
30 | 27 |
public Long authorId; |
31 | 28 |
public String authorLoginId; |
32 | 29 |
public String authorName; |
33 |
- @ManyToOne |
|
34 |
- public Post post; |
|
35 | 30 |
|
36 | 31 |
public Comment() { |
37 |
- date = JodaDateUtil.now(); |
|
32 |
+ date = new Date(); |
|
38 | 33 |
} |
39 | 34 |
|
40 |
- public static Comment findById(Long id) { |
|
41 |
- return find.byId(id); |
|
42 |
- } |
|
43 |
- |
|
44 |
- public static Long write(Comment comment) { |
|
45 |
- comment.save(); |
|
46 |
- |
|
47 |
- return comment.id; |
|
48 |
- } |
|
49 |
- |
|
50 |
- public static List<Comment> findCommentsByPostId(Long postId) { |
|
51 |
- return find.where().eq("post.id", postId).findList(); |
|
52 |
- } |
|
53 |
- |
|
54 |
- public static boolean isAuthor(Long currentUserId, Long id) { |
|
55 |
- int findRowCount = find.where().eq("authorId", currentUserId).eq("id", id).findRowCount(); |
|
56 |
- return (findRowCount != 0) ? true : false; |
|
57 |
- } |
|
58 |
- |
|
59 |
- public Duration ago(){ |
|
35 |
+ public Duration ago() { |
|
60 | 36 |
return JodaDateUtil.ago(this.date); |
61 | 37 |
} |
62 | 38 |
|
63 |
- public static void delete(Long commentId) { |
|
64 |
- find.byId(commentId).delete(); |
|
39 |
+ abstract public Resource asResource(); |
|
40 |
+ |
|
41 |
+ abstract public AbstractPosting getParent(); |
|
42 |
+ |
|
43 |
+ @Transient |
|
44 |
+ public void setAuthor(User user) { |
|
45 |
+ authorId = user.id; |
|
46 |
+ authorLoginId = user.loginId; |
|
47 |
+ authorName = user.name; |
|
65 | 48 |
} |
66 | 49 |
|
67 |
- public Resource asResource() { |
|
68 |
- return new Resource() { |
|
69 |
- @Override |
|
70 |
- public Long getId() { |
|
71 |
- return id; |
|
72 |
- } |
|
50 |
+ public void save() { |
|
51 |
+ super.save(); |
|
52 |
+ getParent().save(); |
|
53 |
+ } |
|
73 | 54 |
|
74 |
- @Override |
|
75 |
- public Project getProject() { |
|
76 |
- return post.project; |
|
77 |
- } |
|
78 |
- |
|
79 |
- @Override |
|
80 |
- public ResourceType getType() { |
|
81 |
- return ResourceType.BOARD_COMMENT; |
|
82 |
- } |
|
83 |
- }; |
|
55 |
+ public void delete() { |
|
56 |
+ super.delete(); |
|
57 |
+ getParent().save(); |
|
84 | 58 |
} |
85 | 59 |
} |
--- app/models/Issue.java
+++ app/models/Issue.java
... | ... | @@ -1,7 +1,5 @@ |
1 | 1 |
package models; |
2 | 2 |
|
3 |
-import com.avaje.ebean.*; |
|
4 |
-import controllers.*; |
|
5 | 3 |
import jxl.*; |
6 | 4 |
import jxl.format.*; |
7 | 5 |
import jxl.format.Colour; |
... | ... | @@ -11,22 +9,14 @@ |
11 | 9 |
import jxl.write.*; |
12 | 10 |
import models.enumeration.*; |
13 | 11 |
import models.resource.Resource; |
14 |
-import models.support.*; |
|
15 |
-import org.joda.time.*; |
|
16 |
-import play.data.format.*; |
|
17 |
-import play.data.validation.*; |
|
18 |
-import play.db.ebean.*; |
|
19 | 12 |
import utils.*; |
20 | 13 |
|
21 | 14 |
import javax.persistence.*; |
22 |
-import javax.validation.constraints.Size; |
|
23 | 15 |
import java.io.*; |
24 | 16 |
import java.util.*; |
25 | 17 |
|
26 |
-import static com.avaje.ebean.Expr.*; |
|
27 |
- |
|
28 | 18 |
@Entity |
29 |
-public class Issue extends Model { |
|
19 |
+public class Issue extends AbstractPosting { |
|
30 | 20 |
/** |
31 | 21 |
* @param id 이슈 ID |
32 | 22 |
* @param title 이슈 제목 |
... | ... | @@ -35,7 +25,6 @@ |
35 | 25 |
* @param date 이슈 등록 날짜 |
36 | 26 |
* @param authorId 이슈 작성자 ID |
37 | 27 |
* @param project 이슈가 등록된 프로젝트 |
38 |
- * @param issueType 이슈 상세정보의 유형 |
|
39 | 28 |
* @param assigneeId 이슈에 배정된 담당자 Id |
40 | 29 |
* @param milestone 이슈가 등록된 마일스톤 |
41 | 30 |
* @param importance 이슈 상세정보의 중요도 |
... | ... | @@ -45,50 +34,25 @@ |
45 | 34 |
|
46 | 35 |
public static Finder<Long, Issue> finder = new Finder<Long, Issue>(Long.class, Issue.class); |
47 | 36 |
|
48 |
- public static final int FIRST_PAGE_NUMBER = 0; |
|
49 |
- public static final int ISSUE_COUNT_PER_PAGE = 25; |
|
50 |
- public static final int NUMBER_OF_ONE_MORE_COMMENTS = 1; |
|
51 | 37 |
public static final String DEFAULT_SORTER = "date"; |
52 | 38 |
public static final String TO_BE_ASSIGNED = "TBA"; |
53 | 39 |
|
54 |
- @Id |
|
55 |
- public Long id; |
|
56 |
- |
|
57 |
- @Constraints.Required |
|
58 |
- public String title; |
|
59 |
- |
|
60 |
- @Lob |
|
61 |
- public String body; |
|
62 |
- |
|
63 |
- @Formats.DateTime(pattern = "yyyy-MM-dd") |
|
64 |
- public Date date; |
|
65 |
- |
|
66 |
- public int numOfComments; |
|
67 |
- public Long milestoneId; |
|
68 |
- public Long authorId; |
|
69 |
- public String authorLoginId; |
|
70 |
- public String authorName; |
|
71 | 40 |
public State state; |
72 | 41 |
|
73 | 42 |
@ManyToOne |
74 |
- public Project project; |
|
43 |
+ public Milestone milestone; |
|
75 | 44 |
|
76 |
- @OneToMany(mappedBy = "issue", cascade = CascadeType.ALL) |
|
77 |
- public List<IssueComment> comments; |
|
78 |
- |
|
79 |
- @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL) |
|
45 |
+ @ManyToMany(fetch = FetchType.EAGER) |
|
80 | 46 |
public Set<IssueLabel> labels; |
81 | 47 |
|
82 |
- @ManyToOne(cascade = CascadeType.ALL) |
|
48 |
+ @ManyToOne |
|
83 | 49 |
public Assignee assignee; |
84 | 50 |
|
85 |
- public Issue(String title) { |
|
86 |
- this.title = title; |
|
87 |
- this.date = JodaDateUtil.now(); |
|
88 |
- } |
|
51 |
+ @OneToMany(cascade = CascadeType.ALL) |
|
52 |
+ public List<IssueComment> comments; |
|
89 | 53 |
|
90 |
- public Duration ago() { |
|
91 |
- return JodaDateUtil.ago(this.date); |
|
54 |
+ public int computeNumOfComments() { |
|
55 |
+ return comments.size(); |
|
92 | 56 |
} |
93 | 57 |
|
94 | 58 |
/** |
... | ... | @@ -99,122 +63,14 @@ |
99 | 63 |
return (this.assignee != null ? assignee.user.name : null); |
100 | 64 |
} |
101 | 65 |
|
102 |
- /** |
|
103 |
- * View에서 사용할 이슈 유형에 대한 옵션을 제공한다. Purpose : View에서 Select 부분에서 i18n를 사용하면서 |
|
104 |
- * 최대한 간단하게 하기 위함. |
|
105 |
- * |
|
106 |
- * @return |
|
107 |
- */ |
|
108 |
- public static Map<String, String> issueTypes() { |
|
109 |
- return new Options("issue.new.detailInfo.issueType.worst", |
|
110 |
- "issue.new.detailInfo.issueType.worse", "issue.new.detailInfo.issueType.bad", |
|
111 |
- "issue.new.detailInfo.issueType.enhancement", |
|
112 |
- "issue.new.detailInfo.issueType.recommendation"); |
|
113 |
- } |
|
66 |
+ public void save() { |
|
67 |
+ if (assignee != null && assignee.user.id != null) { |
|
68 |
+ assignee = Assignee.add(assignee.user.id, project.id); |
|
69 |
+ } else { |
|
70 |
+ assignee = null; |
|
71 |
+ } |
|
114 | 72 |
|
115 |
- /** |
|
116 |
- * View에서 사용할 OS유형에 대한 옵션을 제공한다. Purpose : View에서 Select 부분에서 i18n를 사용하면서 |
|
117 |
- * 최대한 간단하게 하기 위함. |
|
118 |
- * |
|
119 |
- * @return |
|
120 |
- */ |
|
121 |
- public static Map<String, String> osTypes() { |
|
122 |
- return new Options("issue.new.environment.osType.windows", |
|
123 |
- "issue.new.environment.osType.Mac", "issue.new.environment.osType.Linux"); |
|
124 |
- } |
|
125 |
- |
|
126 |
- /** |
|
127 |
- * View에서 사용할 브라우져 유형에 대한 옵션을 제공한다. Purpose : View에서 Select 부분에서 i18n를 사용하면서 |
|
128 |
- * 최대한 간단하게 하기 위함. |
|
129 |
- * |
|
130 |
- * @return |
|
131 |
- */ |
|
132 |
- public static Map<String, String> browserTypes() { |
|
133 |
- return new Options("issue.new.environment.browserType.ie", |
|
134 |
- "issue.new.environment.browserType.chrome", |
|
135 |
- "issue.new.environment.browserType.firefox", |
|
136 |
- "issue.new.environment.browserType.safari", |
|
137 |
- "issue.new.environment.browserType.opera"); |
|
138 |
- } |
|
139 |
- |
|
140 |
- /** |
|
141 |
- * View에서 사용할 DBMS 유형에 대한 옵션을 제공한다. Purpose : View에서 Select 부분에서 i18n를 사용하면서 |
|
142 |
- * 최대한 간단하게 하기 위함. |
|
143 |
- * |
|
144 |
- * @return |
|
145 |
- */ |
|
146 |
- public static Map<String, String> dbmsTypes() { |
|
147 |
- return new Options("issue.new.environment.dbmsType.postgreSQL", |
|
148 |
- "issue.new.environment.dbmsType.CUBRID", "issue.new.environment.dbmsType.MySQL"); |
|
149 |
- } |
|
150 |
- |
|
151 |
- /** |
|
152 |
- * View에서 사용할 중요도에 대한 옵션을 제공한다. Purpose : View에서 Select 부분에서 i18n를 사용하면서 최대한 |
|
153 |
- * 간단하게 하기 위함. |
|
154 |
- * |
|
155 |
- * @return |
|
156 |
- */ |
|
157 |
- public static Map<String, String> importances() { |
|
158 |
- return new Options("issue.new.result.importance.highest", |
|
159 |
- "issue.new.result.importance.high", "issue.new.result.importance.average", |
|
160 |
- "issue.new.result.importance.low", "issue.new.result.importance.lowest"); |
|
161 |
- } |
|
162 |
- |
|
163 |
- /** |
|
164 |
- * View에서 사용할 진단 결과에 대한 옵션을 제공한다. Purpose : View에서 Select 부분에서 i18n를 사용하면서 |
|
165 |
- * 최대한 간단하게 하기 위함. |
|
166 |
- * |
|
167 |
- * @return |
|
168 |
- */ |
|
169 |
- public static Map<String, String> diagnosisResults() { |
|
170 |
- return new Options("issue.new.result.diagnosisResult.bug", |
|
171 |
- "issue.new.result.diagnosisResult.fixed", |
|
172 |
- "issue.new.result.diagnosisResult.willNotFixed", |
|
173 |
- "issue.new.result.diagnosisResult.notaBug", |
|
174 |
- "issue.new.result.diagnosisResult.awaitingResponse", |
|
175 |
- "issue.new.result.diagnosisResult.unreproducible", |
|
176 |
- "issue.new.result.diagnosisResult.duplicated", |
|
177 |
- "issue.new.result.diagnosisResult.works4me"); |
|
178 |
- } |
|
179 |
- |
|
180 |
- /** |
|
181 |
- * 이슈 id로 이슈를 찾아준다. |
|
182 |
- * |
|
183 |
- * @param id |
|
184 |
- * @return |
|
185 |
- */ |
|
186 |
- public static Issue findById(Long id) { |
|
187 |
- return finder.byId(id); |
|
188 |
- } |
|
189 |
- |
|
190 |
- /** |
|
191 |
- * 이슈를 생성한다. |
|
192 |
- * |
|
193 |
- * @param issue |
|
194 |
- * @return |
|
195 |
- */ |
|
196 |
- public static Long create(Issue issue) { |
|
197 |
- issue.save(); |
|
198 |
- return issue.id; |
|
199 |
- } |
|
200 |
- |
|
201 |
- /** |
|
202 |
- * 이슈를 삭제한다. |
|
203 |
- * |
|
204 |
- * @param id |
|
205 |
- */ |
|
206 |
- public static void delete(Long id) { |
|
207 |
- Issue issue = finder.byId(id); |
|
208 |
- issue.delete(); |
|
209 |
- } |
|
210 |
- |
|
211 |
- /** |
|
212 |
- * 이슈를 수정 & 업데이트 한다. |
|
213 |
- * |
|
214 |
- * @param issue |
|
215 |
- */ |
|
216 |
- public static void edit(Issue issue) { |
|
217 |
- issue.update(); |
|
73 |
+ super.save(); |
|
218 | 74 |
} |
219 | 75 |
|
220 | 76 |
public static int countIssues(Long projectId, State state) { |
... | ... | @@ -223,166 +79,6 @@ |
223 | 79 |
} else { |
224 | 80 |
return finder.where().eq("project.id", projectId).eq("state", state).findRowCount(); |
225 | 81 |
} |
226 |
- } |
|
227 |
- |
|
228 |
- /** |
|
229 |
- * 미해결 탭을 눌렀을 때, open 상태의 이슈들을 찾아준다.. |
|
230 |
- * |
|
231 |
- * @param projectId |
|
232 |
- * @return |
|
233 |
- */ |
|
234 |
- public static Page<Issue> findOpenIssues(Long projectId) { |
|
235 |
- return Issue.findIssues(projectId, State.OPEN); |
|
236 |
- } |
|
237 |
- |
|
238 |
- /** |
|
239 |
- * 해결 탭을 눌렀을 때, closed 상태의 이슈들을 찾아준다. |
|
240 |
- * |
|
241 |
- * @param projectId |
|
242 |
- * @return |
|
243 |
- */ |
|
244 |
- public static Page<Issue> findClosedIssues(Long projectId) { |
|
245 |
- return Issue.findIssues(projectId, State.CLOSED); |
|
246 |
- } |
|
247 |
- |
|
248 |
- /** |
|
249 |
- * 해당 프로젝트의 State 외의 것들은 기본값들로 이뤄진 이슈들을 찾아준다. |
|
250 |
- * |
|
251 |
- * @param projectName |
|
252 |
- * @param state |
|
253 |
- * @return |
|
254 |
- */ |
|
255 |
- public static Page<Issue> findIssues(Long projectId, State state) { |
|
256 |
- return find(projectId, FIRST_PAGE_NUMBER, state, DEFAULT_SORTER, Direction.DESC, "", null, |
|
257 |
- null, false); |
|
258 |
- } |
|
259 |
- |
|
260 |
- /** |
|
261 |
- * 검색창에서 제공된 query(filter)와 댓글과 파일첨부된 이슈만 찾아주는 체크박스의 값에 따라 필터링된 이슈들을 찾아준다. |
|
262 |
- * |
|
263 |
- * @param projectId |
|
264 |
- * @param filter |
|
265 |
- * @param state |
|
266 |
- * @param commentedCheck |
|
267 |
- * @return |
|
268 |
- */ |
|
269 |
- public static Page<Issue> findFilteredIssues(Long projectId, String filter, State state, |
|
270 |
- boolean commentedCheck) { |
|
271 |
- return find(projectId, FIRST_PAGE_NUMBER, state, DEFAULT_SORTER, Direction.DESC, filter, |
|
272 |
- null, null, commentedCheck); |
|
273 |
- } |
|
274 |
- |
|
275 |
- /** |
|
276 |
- * 댓글이 달린 이슈들만 찾아준다. |
|
277 |
- * |
|
278 |
- * @param projectId |
|
279 |
- * @param filter |
|
280 |
- * @return |
|
281 |
- */ |
|
282 |
- public static Page<Issue> findCommentedIssues(Long projectId, String filter) { |
|
283 |
- return find(projectId, FIRST_PAGE_NUMBER, State.ALL, DEFAULT_SORTER, Direction.DESC, |
|
284 |
- filter, null, null, true); |
|
285 |
- } |
|
286 |
- |
|
287 |
- /** |
|
288 |
- * 마일스톤 Id에 의거해서 해당 마일스톤에 속한 이슈들을 찾아준다. |
|
289 |
- * |
|
290 |
- * @param projectId |
|
291 |
- * @param milestoneId |
|
292 |
- * @return |
|
293 |
- */ |
|
294 |
- public static Page<Issue> findIssuesByMilestoneId(Long projectId, Long milestoneId) { |
|
295 |
- return find(projectId, FIRST_PAGE_NUMBER, State.ALL, DEFAULT_SORTER, Direction.DESC, "", |
|
296 |
- milestoneId, null, false); |
|
297 |
- } |
|
298 |
- |
|
299 |
- /** |
|
300 |
- * 이슈들을 아래의 parameter들의 조건에 의거하여 Page형태로 반환한다. |
|
301 |
- * |
|
302 |
- * @param projectId |
|
303 |
- * project ID to finder issues |
|
304 |
- * @param pageNumber |
|
305 |
- * Page to display |
|
306 |
- * @param state |
|
307 |
- * state type of issue(OPEN or CLOSED |
|
308 |
- * @param sortBy |
|
309 |
- * Issue property used for sorting, but, it might be fixed to |
|
310 |
- * enum type |
|
311 |
- * @param order |
|
312 |
- * Sort order(either asc or desc) |
|
313 |
- * @param filter |
|
314 |
- * filter applied on the title column |
|
315 |
- * @param commentedCheck |
|
316 |
- * filter applied on the commetedCheck column, 댓글이 존재하는 이슈만 필터링 |
|
317 |
- * @return 위의 조건에 따라 필터링된 이슈들을 Page로 반환. |
|
318 |
- */ |
|
319 |
- public static Page<Issue> find(Long projectId, int pageNumber, State state, String sortBy, |
|
320 |
- Direction order, String filter, Long milestoneId, Set<Long> labelIds, |
|
321 |
- boolean commentedCheck) { |
|
322 |
- OrderParams orderParams = new OrderParams().add(sortBy, order); |
|
323 |
- SearchParams searchParams = new SearchParams() |
|
324 |
- .add("project.id", projectId, Matching.EQUALS); |
|
325 |
- |
|
326 |
- if (filter != null && !filter.isEmpty()) { |
|
327 |
- searchParams.add("title", filter, Matching.CONTAINS); |
|
328 |
- } |
|
329 |
- if (milestoneId != null) { |
|
330 |
- searchParams.add("milestoneId", milestoneId, Matching.EQUALS); |
|
331 |
- } |
|
332 |
- if (labelIds != null) { |
|
333 |
- // searchParams.add("labels.id", labelIds, Matching.IN); |
|
334 |
- for (Long labelId : labelIds) { |
|
335 |
- searchParams.add("labels.id", labelId, Matching.EQUALS); |
|
336 |
- } |
|
337 |
- } |
|
338 |
- if (commentedCheck) { |
|
339 |
- searchParams.add("numOfComments", NUMBER_OF_ONE_MORE_COMMENTS, Matching.GE); |
|
340 |
- } |
|
341 |
- |
|
342 |
- if (state == null) { |
|
343 |
- state = State.ALL; |
|
344 |
- } |
|
345 |
- switch (state) { |
|
346 |
- case OPEN: |
|
347 |
- searchParams.add("state", State.OPEN, Matching.EQUALS); |
|
348 |
- break; |
|
349 |
- case CLOSED: |
|
350 |
- searchParams.add("state", State.CLOSED, Matching.EQUALS); |
|
351 |
- break; |
|
352 |
- default: |
|
353 |
- } |
|
354 |
- return FinderTemplate.getPage(orderParams, searchParams, finder, ISSUE_COUNT_PER_PAGE, |
|
355 |
- pageNumber); |
|
356 |
- } |
|
357 |
- |
|
358 |
- /** |
|
359 |
- * 전체 컨텐츠 검색할 때 제목과 내용에 condition.filter를 포함하고 있는 이슈를 검색한다. |
|
360 |
- * |
|
361 |
- * @param project |
|
362 |
- * @param condition |
|
363 |
- * @return |
|
364 |
- */ |
|
365 |
- public static Page<Issue> find(Project project, SearchApp.ContentSearchCondition condition) { |
|
366 |
- String filter = condition.filter; |
|
367 |
- return finder.where().eq("project.id", project.id) |
|
368 |
- .or(contains("title", filter), contains("body", filter)) |
|
369 |
- .findPagingList(condition.pageSize).getPage(condition.page - 1); |
|
370 |
- } |
|
371 |
- |
|
372 |
- public static Long findAssigneeIdByIssueId(Long issueId) { |
|
373 |
- return finder.byId(issueId).assignee.user.id; |
|
374 |
- } |
|
375 |
- |
|
376 |
- /** |
|
377 |
- * 해당 마일스톤아이디로 관련 이슈를 검색한다. |
|
378 |
- * |
|
379 |
- * @param milestoneId |
|
380 |
- * @return |
|
381 |
- */ |
|
382 |
- public static List<Issue> findByMilestoneId(Long milestoneId) { |
|
383 |
- SearchParams searchParams = new SearchParams().add("milestoneId", milestoneId, |
|
384 |
- Matching.EQUALS); |
|
385 |
- return FinderTemplate.findBy(null, searchParams, finder); |
|
386 | 82 |
} |
387 | 83 |
|
388 | 84 |
/** |
... | ... | @@ -447,7 +143,7 @@ |
447 | 143 |
/** |
448 | 144 |
* excelSave에서 assignee를 리턴해준다. |
449 | 145 |
* |
450 |
- * @param uId |
|
146 |
+ * @param assignee |
|
451 | 147 |
* @return |
452 | 148 |
*/ |
453 | 149 |
private static String getAssigneeName(Assignee assignee) { |
... | ... | @@ -457,18 +153,6 @@ |
457 | 153 |
// FIXME 이것이 없이 테스트는 잘 작동하나, view에서 댓글이 달린 이슈들을 필터링하는 라디오버튼을 작동시에 이 메쏘드에서 |
458 | 154 |
// 시행하는 동기화 작업 없이는 작동을 하지 않는다. |
459 | 155 |
|
460 |
- /** |
|
461 |
- * comment가 delete되거나 create될 때, numOfComment와 comment.size()를 동기화 시켜준다. |
|
462 |
- * |
|
463 |
- * @param id |
|
464 |
- */ |
|
465 |
- public static void updateNumOfComments(Long id) { |
|
466 |
- |
|
467 |
- Issue issue = Issue.findById(id); |
|
468 |
- issue.numOfComments = issue.comments.size(); |
|
469 |
- issue.update(); |
|
470 |
- } |
|
471 |
- |
|
472 | 156 |
public boolean isOpen() { |
473 | 157 |
return this.state == State.OPEN; |
474 | 158 |
} |
... | ... | @@ -477,24 +161,9 @@ |
477 | 161 |
return this.state == State.CLOSED; |
478 | 162 |
} |
479 | 163 |
|
480 |
- public Resource asResource() { |
|
481 |
- return new Resource() { |
|
482 |
- @Override |
|
483 |
- public Long getId() { |
|
484 |
- return null; |
|
485 |
- } |
|
486 |
- |
|
487 |
- @Override |
|
488 |
- public Project getProject() { |
|
489 |
- return project; |
|
490 |
- } |
|
491 |
- |
|
492 |
- @Override |
|
493 |
- public ResourceType getType() { |
|
494 |
- return ResourceType.ISSUE_POST; |
|
495 |
- } |
|
496 |
- }; |
|
497 |
- } |
|
164 |
+ public Resource asResource() { |
|
165 |
+ return asResource(ResourceType.ISSUE_POST); |
|
166 |
+ } |
|
498 | 167 |
|
499 | 168 |
public Resource fieldAsResource(final ResourceType resourceType) { |
500 | 169 |
return new Resource() { |
--- app/models/IssueComment.java
+++ app/models/IssueComment.java
... | ... | @@ -1,74 +1,27 @@ |
1 |
-/** |
|
2 |
- * @author Taehyun Park |
|
3 |
- */ |
|
4 |
- |
|
5 | 1 |
package models; |
6 | 2 |
|
7 | 3 |
import models.enumeration.ResourceType; |
8 | 4 |
import models.resource.Resource; |
9 | 5 |
|
10 |
-import org.joda.time.*; |
|
11 |
-import play.data.validation.*; |
|
12 |
-import play.db.ebean.*; |
|
13 |
-import utils.*; |
|
14 |
- |
|
15 | 6 |
import javax.persistence.*; |
16 |
-import javax.validation.constraints.Size; |
|
17 |
-import java.util.*; |
|
18 | 7 |
|
19 | 8 |
@Entity |
20 |
-public class IssueComment extends Model { |
|
9 |
+public class IssueComment extends Comment { |
|
21 | 10 |
private static final long serialVersionUID = 1L; |
22 |
- private static Finder<Long, IssueComment> find = new Finder<Long, IssueComment>(Long.class, |
|
23 |
- IssueComment.class); |
|
24 |
- |
|
25 |
- @Id |
|
26 |
- public Long id; |
|
27 |
- |
|
28 |
- @Constraints.Required @Column(length = 4000) @Size(max=4000) |
|
29 |
- public String contents; |
|
30 |
- |
|
31 |
- public Date date; |
|
32 |
- public Long authorId; |
|
33 |
- public String authorLoginId; |
|
34 |
- public String authorName; |
|
35 |
- public String filePath; |
|
11 |
+ public static Finder<Long, IssueComment> find = new Finder<Long, IssueComment>(Long.class, IssueComment.class); |
|
36 | 12 |
|
37 | 13 |
@ManyToOne |
38 | 14 |
public Issue issue; |
39 | 15 |
|
40 | 16 |
public IssueComment() { |
41 |
- date = JodaDateUtil.now(); |
|
17 |
+ super(); |
|
42 | 18 |
} |
43 | 19 |
|
44 |
- public static IssueComment findById(Long id) { |
|
45 |
- return find.byId(id); |
|
46 |
- } |
|
47 |
- |
|
48 |
- public static Long create(IssueComment issueComment) { |
|
49 |
- issueComment.save(); |
|
50 |
- return issueComment.id; |
|
51 |
- } |
|
52 |
- |
|
53 |
- public String authorName() { |
|
54 |
- return User.find.byId(this.authorId).name; |
|
55 |
- } |
|
56 |
- |
|
57 |
- public static void delete(Long id) { |
|
58 |
- find.byId(id).delete(); |
|
59 |
- } |
|
60 |
- |
|
61 |
- public static boolean isAuthor(Long currentUserId, Long id) { |
|
62 |
- int findRowCount = find.where().eq("authorId", currentUserId).eq("id", id).findRowCount(); |
|
63 |
- return (findRowCount != 0) ? true : false; |
|
64 |
- } |
|
65 |
- |
|
66 |
- public Duration ago() { |
|
67 |
- return JodaDateUtil.ago(this.date); |
|
20 |
+ public AbstractPosting getParent() { |
|
21 |
+ return issue; |
|
68 | 22 |
} |
69 | 23 |
|
70 | 24 |
public Resource asResource() { |
71 |
- |
|
72 | 25 |
return new Resource() { |
73 | 26 |
@Override |
74 | 27 |
public Long getId() { |
... | ... | @@ -84,7 +37,11 @@ |
84 | 37 |
public ResourceType getType() { |
85 | 38 |
return ResourceType.ISSUE_COMMENT; |
86 | 39 |
} |
40 |
+ |
|
41 |
+ @Override |
|
42 |
+ public Long getAuthorId() { |
|
43 |
+ return authorId; |
|
44 |
+ } |
|
87 | 45 |
}; |
88 | 46 |
} |
89 | 47 |
} |
90 |
- |
--- app/models/IssueLabel.java
+++ app/models/IssueLabel.java
... | ... | @@ -50,6 +50,7 @@ |
50 | 50 |
return finder.byId(id); |
51 | 51 |
} |
52 | 52 |
|
53 |
+ @Transient |
|
53 | 54 |
public boolean exists() { |
54 | 55 |
return finder.where().eq("project.id", project.id) |
55 | 56 |
.eq("name", name).eq("color", color).findRowCount() > 0; |
--- app/models/Milestone.java
+++ app/models/Milestone.java
... | ... | @@ -14,7 +14,7 @@ |
14 | 14 |
public class Milestone extends Model { |
15 | 15 |
|
16 | 16 |
private static final long serialVersionUID = 1L; |
17 |
- private static Finder<Long, Milestone> find = new Finder<Long, Milestone>( |
|
17 |
+ public static Finder<Long, Milestone> find = new Finder<Long, Milestone>( |
|
18 | 18 |
Long.class, Milestone.class); |
19 | 19 |
|
20 | 20 |
public static String DEFAULT_SORTER = "dueDate"; |
... | ... | @@ -38,33 +38,38 @@ |
38 | 38 |
@ManyToOne |
39 | 39 |
public Project project; |
40 | 40 |
|
41 |
+ @OneToMany |
|
42 |
+ public Set<Issue> issues; |
|
43 |
+ |
|
44 |
+ public void delete() { |
|
45 |
+ // Set all issues' milestone to null. |
|
46 |
+ // I don't know why Ebean does not do this by itself. |
|
47 |
+ for(Issue issue : issues) { |
|
48 |
+ issue.milestone = null; |
|
49 |
+ issue.update(); |
|
50 |
+ } |
|
51 |
+ |
|
52 |
+ super.delete(); |
|
53 |
+ } |
|
54 |
+ |
|
41 | 55 |
public static void create(Milestone milestone) { |
42 | 56 |
milestone.save(); |
43 | 57 |
} |
44 | 58 |
|
45 | 59 |
public int getNumClosedIssues() { |
46 |
- return Issue.finder.where().eq("milestoneId", this.id).eq("state", State.CLOSED).findRowCount(); |
|
60 |
+ return Issue.finder.where().eq("milestone", this).eq("state", State.CLOSED).findRowCount(); |
|
47 | 61 |
} |
48 | 62 |
|
49 | 63 |
public int getNumOpenIssues() { |
50 |
- return Issue.finder.where().eq("milestoneId", this.id).eq("state", State.OPEN).findRowCount(); |
|
64 |
+ return Issue.finder.where().eq("milestone", this).eq("state", State.OPEN).findRowCount(); |
|
51 | 65 |
} |
52 |
- |
|
66 |
+ |
|
53 | 67 |
public int getNumTotalIssues() { |
54 |
- return Issue.findByMilestoneId(this.id).size(); |
|
68 |
+ return issues.size(); |
|
55 | 69 |
} |
56 | 70 |
|
57 | 71 |
public int getCompletionRate() { |
58 | 72 |
return new Double(((double) getNumClosedIssues() / (double) getNumTotalIssues()) * 100).intValue(); |
59 |
- } |
|
60 |
- |
|
61 |
- public static void delete(Milestone milestone) { |
|
62 |
- List<Issue> issues = Issue.findByMilestoneId(milestone.id); |
|
63 |
- milestone.delete(); |
|
64 |
- for (Issue issue : issues) { |
|
65 |
- issue.milestoneId = null; |
|
66 |
- issue.update(); |
|
67 |
- } |
|
68 | 73 |
} |
69 | 74 |
|
70 | 75 |
public static Milestone findById(Long id) { |
--- app/models/Post.java
... | ... | @@ -1,165 +0,0 @@ |
1 | -/** | |
2 | - * @author Ahn Hyeok Jun | |
3 | - */ | |
4 | - | |
5 | -package models; | |
6 | - | |
7 | -import com.avaje.ebean.*; | |
8 | -import controllers.*; | |
9 | -import models.enumeration.*; | |
10 | -import models.resource.Resource; | |
11 | -import models.support.*; | |
12 | -import org.joda.time.*; | |
13 | -import play.data.format.*; | |
14 | -import play.data.validation.*; | |
15 | -import play.db.ebean.*; | |
16 | -import utils.*; | |
17 | - | |
18 | -import javax.persistence.*; | |
19 | -import javax.validation.constraints.Size; | |
20 | -import java.util.*; | |
21 | - | |
22 | -import static com.avaje.ebean.Expr.*; | |
23 | -import static play.data.validation.Constraints.*; | |
24 | - | |
25 | -@Entity | |
26 | -public class Post extends Model { | |
27 | - private static final long serialVersionUID = 1L; | |
28 | - private static Finder<Long, Post> finder = new Finder<Long, Post>(Long.class, Post.class); | |
29 | - | |
30 | - @Id | |
31 | - public Long id; | |
32 | - | |
33 | - @Required @Size(max=255) | |
34 | - public String title; | |
35 | - | |
36 | - @Required @Lob | |
37 | - public String contents; | |
38 | - | |
39 | - @Required | |
40 | - @Formats.DateTime(pattern = "YYYY/MM/DD/hh/mm/ss") | |
41 | - public Date date; | |
42 | - | |
43 | - public int commentCount; | |
44 | - public String filePath; | |
45 | - | |
46 | - public Long authorId; | |
47 | - public String authorLoginId; | |
48 | - public String authorName; | |
49 | - | |
50 | - @OneToMany(mappedBy = "post", cascade = CascadeType.ALL) | |
51 | - public List<Comment> comments; | |
52 | - | |
53 | - @ManyToOne | |
54 | - public Project project; | |
55 | - | |
56 | - public Post() { | |
57 | - this.date = JodaDateUtil.now(); | |
58 | - } | |
59 | - | |
60 | - public static Post findById(Long id) { | |
61 | - return finder.byId(id); | |
62 | - } | |
63 | - | |
64 | - /** | |
65 | - * @param projectName | |
66 | - * 프로젝트이름 | |
67 | - * @param pageNum | |
68 | - * 페이지 번호 | |
69 | - * @param direction | |
70 | - * 오름차순(asc), 내림차순(decs) | |
71 | - * @param key | |
72 | - * 오름차순과 내림차수를 결정하는 기준 | |
73 | - * @return | |
74 | - */ | |
75 | - public static Page<Post> findOnePage(String ownerName, String projectName, int pageNum, | |
76 | - Direction direction, String key, String filter) { | |
77 | - SearchParams searchParam = new SearchParams() | |
78 | - .add("project.owner", ownerName, Matching.EQUALS) | |
79 | - .add("project.name", projectName, Matching.EQUALS) | |
80 | - .add("contents", filter, Matching.CONTAINS); | |
81 | - OrderParams orderParams = new OrderParams().add(key, direction); | |
82 | - return FinderTemplate.getPage(orderParams, searchParam, finder, 10, pageNum); | |
83 | - } | |
84 | - | |
85 | - public static Long write(Post post) { | |
86 | - post.save(); | |
87 | - return post.id; | |
88 | - } | |
89 | - | |
90 | - public static void delete(Long id) { | |
91 | - finder.byId(id).delete(); | |
92 | - } | |
93 | - | |
94 | - /** | |
95 | - * 댓글이 달릴때 체크를 하는 함수. | |
96 | - * @param id Post의 ID | |
97 | - */ | |
98 | - public static void countUpCommentCounter(Long id) { | |
99 | - Post post = finder.byId(id); | |
100 | - post.commentCount++; | |
101 | - post.update(); | |
102 | - } | |
103 | - | |
104 | - /** | |
105 | - * 현재 글을 쓴지 얼마나 되었는지를 얻어내는 함수 | |
106 | - * @return | |
107 | - */ | |
108 | - public Duration ago() { | |
109 | - return JodaDateUtil.ago(this.date); | |
110 | - } | |
111 | - | |
112 | - public static void edit(Post post) { | |
113 | - Post beforePost = findById(post.id); | |
114 | - post.commentCount = beforePost.commentCount; | |
115 | - if (post.filePath == null) { | |
116 | - post.filePath = beforePost.filePath; | |
117 | - } | |
118 | - post.update(); | |
119 | - } | |
120 | - | |
121 | - public static boolean isAuthor(Long currentUserId, Long id) { | |
122 | - int findRowCount = finder.where().eq("authorId", currentUserId).eq("id", id).findRowCount(); | |
123 | - return (findRowCount != 0) ? true : false; | |
124 | - } | |
125 | - | |
126 | - /** | |
127 | - * 전체 컨텐츠 검색할 때 제목과 내용에 condition.filter를 포함하고 있는 게시글를 검색한다. | |
128 | - * @param project | |
129 | - * @param condition | |
130 | - * @return | |
131 | - */ | |
132 | - public static Page<Post> find(Project project, SearchApp.ContentSearchCondition condition) { | |
133 | - String filter = condition.filter; | |
134 | - return finder.where() | |
135 | - .eq("project.id", project.id) | |
136 | - .or(contains("title", filter), contains("contents", filter)) | |
137 | - .findPagingList(condition.pageSize) | |
138 | - .getPage(condition.page - 1); | |
139 | - } | |
140 | - | |
141 | - public static void countDownCommentCounter(Long id) { | |
142 | - Post post = finder.byId(id); | |
143 | - post.commentCount--; | |
144 | - post.update(); | |
145 | - } | |
146 | - | |
147 | - public Resource asResource() { | |
148 | - return new Resource() { | |
149 | - @Override | |
150 | - public Long getId() { | |
151 | - return id; | |
152 | - } | |
153 | - | |
154 | - @Override | |
155 | - public Project getProject() { | |
156 | - return project; | |
157 | - } | |
158 | - | |
159 | - @Override | |
160 | - public ResourceType getType() { | |
161 | - return ResourceType.BOARD_POST; | |
162 | - } | |
163 | - }; | |
164 | - } | |
165 | -} |
+++ app/models/Posting.java
... | ... | @@ -0,0 +1,32 @@ |
1 | +/** | |
2 | + * @author Ahn Hyeok Jun | |
3 | + */ | |
4 | + | |
5 | +package models; | |
6 | + | |
7 | +import javax.persistence.*; | |
8 | + | |
9 | +import models.enumeration.ResourceType; | |
10 | +import models.resource.Resource; | |
11 | + | |
12 | +import java.util.*; | |
13 | + | |
14 | +@Entity | |
15 | +public class Posting extends AbstractPosting { | |
16 | + public static Finder<Long, Posting> finder = new Finder<Long, Posting>(Long.class, Posting.class); | |
17 | + | |
18 | + @OneToMany(cascade = CascadeType.ALL) | |
19 | + public List<PostingComment> comments; | |
20 | + | |
21 | + public int computeNumOfComments() { | |
22 | + return comments.size(); | |
23 | + } | |
24 | + | |
25 | + public Posting() { | |
26 | + super(); | |
27 | + } | |
28 | + | |
29 | + public Resource asResource() { | |
30 | + return asResource(ResourceType.BOARD_POST); | |
31 | + } | |
32 | +} |
+++ app/models/PostingComment.java
... | ... | @@ -0,0 +1,47 @@ |
1 | +package models; | |
2 | + | |
3 | +import models.enumeration.ResourceType; | |
4 | +import models.resource.Resource; | |
5 | + | |
6 | +import javax.persistence.*; | |
7 | + | |
8 | +@Entity | |
9 | +public class PostingComment extends Comment { | |
10 | + private static final long serialVersionUID = 1L; | |
11 | + public static Finder<Long, PostingComment> find = new Finder<Long, PostingComment>(Long.class, PostingComment.class); | |
12 | + | |
13 | + @ManyToOne | |
14 | + public Posting posting; | |
15 | + | |
16 | + public PostingComment() { | |
17 | + super(); | |
18 | + } | |
19 | + | |
20 | + public AbstractPosting getParent() { | |
21 | + return posting; | |
22 | + } | |
23 | + | |
24 | + public Resource asResource() { | |
25 | + return new Resource() { | |
26 | + @Override | |
27 | + public Long getId() { | |
28 | + return id; | |
29 | + } | |
30 | + | |
31 | + @Override | |
32 | + public Project getProject() { | |
33 | + return posting.project; | |
34 | + } | |
35 | + | |
36 | + @Override | |
37 | + public ResourceType getType() { | |
38 | + return ResourceType.NONISSUE_COMMENT; | |
39 | + } | |
40 | + | |
41 | + @Override | |
42 | + public Long getAuthorId() { | |
43 | + return authorId; | |
44 | + } | |
45 | + }; | |
46 | + } | |
47 | +} |
--- app/models/Project.java
+++ app/models/Project.java
... | ... | @@ -40,6 +40,8 @@ |
40 | 40 |
public static Finder<Long, Project> find = new Finder<Long, Project>( |
41 | 41 |
Long.class, Project.class); |
42 | 42 |
|
43 |
+ public static final int PROJECT_COUNT_PER_PAGE = 15; |
|
44 |
+ |
|
43 | 45 |
public static Comparator sortByNameWithIgnoreCase = new SortByNameWithIgnoreCase(); |
44 | 46 |
public static Comparator sortByNameWithIgnoreCaseDesc = new SortByNameWithIgnoreCaseDesc(); |
45 | 47 |
public static Comparator sortByDate = new SortByDate(); |
... | ... | @@ -65,13 +67,13 @@ |
65 | 67 |
public Date date; |
66 | 68 |
|
67 | 69 |
@OneToMany(mappedBy = "project", cascade = CascadeType.ALL) |
68 |
- public List<Issue> issues; |
|
70 |
+ public Set<Issue> issues; |
|
69 | 71 |
|
70 | 72 |
@OneToMany(mappedBy = "project", cascade = CascadeType.ALL) |
71 | 73 |
public List<ProjectUser> projectUser; |
72 | 74 |
|
73 | 75 |
@OneToMany(mappedBy = "project", cascade = CascadeType.ALL) |
74 |
- public List<Post> posts; |
|
76 |
+ public List<Posting> posts; |
|
75 | 77 |
|
76 | 78 |
@OneToMany(mappedBy = "project", cascade = CascadeType.ALL) |
77 | 79 |
public List<Milestone> milestones; |
... | ... | @@ -86,10 +88,6 @@ |
86 | 88 |
ProjectUser.assignRole(User.SITE_MANAGER_ID, newProject.id, |
87 | 89 |
RoleType.SITEMANAGER); |
88 | 90 |
return newProject.id; |
89 |
- } |
|
90 |
- |
|
91 |
- public static void delete(Long id) { |
|
92 |
- Project.find.byId(id).delete(); |
|
93 | 91 |
} |
94 | 92 |
|
95 | 93 |
public static Page<Project> findByName(String name, int pageSize, |
--- app/models/SiteAdmin.java
+++ app/models/SiteAdmin.java
... | ... | @@ -25,4 +25,4 @@ |
25 | 25 |
public static boolean exists(User user) { |
26 | 26 |
return user != null && find.where().eq("admin.id", user.id).findRowCount() > 0; |
27 | 27 |
} |
28 |
-}(No newline at end of file) |
|
28 |
+} |
--- app/models/User.java
+++ app/models/User.java
... | ... | @@ -11,6 +11,7 @@ |
11 | 11 |
import javax.persistence.Id; |
12 | 12 |
import javax.persistence.OneToMany; |
13 | 13 |
import javax.persistence.Table; |
14 |
+import javax.persistence.Transient; |
|
14 | 15 |
|
15 | 16 |
import models.enumeration.Direction; |
16 | 17 |
import models.enumeration.Matching; |
... | ... | @@ -153,6 +154,7 @@ |
153 | 154 |
.findList(); |
154 | 155 |
} |
155 | 156 |
|
157 |
+ @Transient |
|
156 | 158 |
public Long avatarId(){ |
157 | 159 |
return Attachment.findByContainer(ResourceType.USER_AVATAR, id).get(0).id; |
158 | 160 |
} |
--- app/models/enumeration/ResourceType.java
+++ app/models/enumeration/ResourceType.java
... | ... | @@ -2,15 +2,13 @@ |
2 | 2 |
|
3 | 3 |
public enum ResourceType { |
4 | 4 |
ISSUE_POST("issue_post"), |
5 |
- ISSUE_COMMENT("issue_comment"), |
|
6 | 5 |
ISSUE_ASSIGNEE("issue_assignee"), |
7 | 6 |
ISSUE_STATE("issue_state"), |
8 | 7 |
ISSUE_CATEGORY("issue_category"), |
9 | 8 |
ISSUE_MILESTONE("issue_milestone"), |
10 |
- ISSUE_NOTICE("issue_notice"), |
|
9 |
+ |
|
11 | 10 |
ISSUE_LABEL("issue_label"), |
12 | 11 |
BOARD_POST("board_post"), |
13 |
- BOARD_COMMENT("board_comment"), |
|
14 | 12 |
BOARD_CATEGORY("board_category"), |
15 | 13 |
BOARD_NOTICE("board_notice"), |
16 | 14 |
CODE("code"), |
... | ... | @@ -21,7 +19,9 @@ |
21 | 19 |
USER("user"), |
22 | 20 |
USER_AVATAR("user_avatar"), |
23 | 21 |
PROJECT("project"), |
24 |
- ATTACHMENT("attachment"); |
|
22 |
+ ATTACHMENT("attachment"), |
|
23 |
+ ISSUE_COMMENT("issue_comment"), |
|
24 |
+ NONISSUE_COMMENT("nonissue_comment"); |
|
25 | 25 |
|
26 | 26 |
private String resource; |
27 | 27 |
|
... | ... | @@ -41,4 +41,4 @@ |
41 | 41 |
} |
42 | 42 |
return ResourceType.ISSUE_POST; |
43 | 43 |
} |
44 |
-}(No newline at end of file) |
|
44 |
+} |
--- app/models/resource/Resource.java
+++ app/models/resource/Resource.java
... | ... | @@ -8,4 +8,5 @@ |
8 | 8 |
abstract public Project getProject(); |
9 | 9 |
abstract public ResourceType getType(); |
10 | 10 |
public Resource getContainer() { return null; }; |
11 |
-}(No newline at end of file) |
|
11 |
+ public Long getAuthorId() { return null; }; |
|
12 |
+} |
--- app/models/support/SearchCondition.java
... | ... | @@ -1,90 +0,0 @@ |
1 | -package models.support; | |
2 | - | |
3 | -import java.util.ArrayList; | |
4 | -import java.util.List; | |
5 | -import java.util.Set; | |
6 | - | |
7 | -import models.Issue; | |
8 | -import models.Project; | |
9 | -import models.User; | |
10 | -import models.enumeration.*; | |
11 | -/** | |
12 | - * | |
13 | - * @author Taehyun Park | |
14 | - * | |
15 | - */ | |
16 | -public class SearchCondition { | |
17 | - | |
18 | - public String filter; | |
19 | - public String sortBy; | |
20 | - public String orderBy; | |
21 | - public int pageNum; | |
22 | - | |
23 | - public String state; | |
24 | - public Boolean commentedCheck; | |
25 | - public Boolean fileAttachedCheck; | |
26 | - public Long milestone; | |
27 | - public Set<Long> labelIds; | |
28 | - public String authorLoginId; | |
29 | - public Long assigneeId; | |
30 | - | |
31 | - public SearchCondition() { | |
32 | - filter = ""; | |
33 | - sortBy = "date"; | |
34 | - orderBy = Direction.DESC.direction(); | |
35 | - pageNum = 0; | |
36 | - milestone = null; | |
37 | - state = State.OPEN.name(); | |
38 | - commentedCheck = false; | |
39 | - fileAttachedCheck = false; | |
40 | - } | |
41 | - | |
42 | - public SearchParams asSearchParam(Project project) { | |
43 | - SearchParams searchParams = new SearchParams(); | |
44 | - | |
45 | - searchParams.add("project.id", project.id, Matching.EQUALS); | |
46 | - | |
47 | - if (authorLoginId != null && !authorLoginId.isEmpty()) { | |
48 | - User user = User.findByLoginId(authorLoginId); | |
49 | - if (user != null) { | |
50 | - searchParams.add("authorId", user.id, Matching.EQUALS); | |
51 | - } else { | |
52 | - List<Long> ids = new ArrayList<Long>(); | |
53 | - for (User u : User.find.where().contains("loginId", authorLoginId).findList()) { | |
54 | - ids.add(u.id); | |
55 | - } | |
56 | - searchParams.add("authorId", ids, Matching.IN); | |
57 | - } | |
58 | - } | |
59 | - | |
60 | - if (assigneeId != null) { | |
61 | - searchParams.add("assignee.user.id", assigneeId, Matching.EQUALS); | |
62 | - searchParams.add("assignee.project.id", project.id, Matching.EQUALS); | |
63 | - } | |
64 | - | |
65 | - if (filter != null && !filter.isEmpty()) { | |
66 | - searchParams.add("title", filter, Matching.CONTAINS); | |
67 | - } | |
68 | - | |
69 | - if (milestone != null) { | |
70 | - searchParams.add("milestoneId", milestone, Matching.EQUALS); | |
71 | - } | |
72 | - | |
73 | - if (labelIds != null) { | |
74 | - for (Long labelId : labelIds) { | |
75 | - searchParams.add("labels.id", labelId, Matching.EQUALS); | |
76 | - } | |
77 | - } | |
78 | - | |
79 | - if (commentedCheck) { | |
80 | - searchParams.add("numOfComments", Issue.NUMBER_OF_ONE_MORE_COMMENTS, Matching.GE); | |
81 | - } | |
82 | - | |
83 | - State st = State.getValue(state); | |
84 | - if (st.equals(State.OPEN) || st.equals(State.CLOSED)) { | |
85 | - searchParams.add("state", st, Matching.EQUALS); | |
86 | - } | |
87 | - | |
88 | - return searchParams; | |
89 | - } | |
90 | -}(No newline at end of file) |
--- app/models/task/Card.java
+++ app/models/task/Card.java
... | ... | @@ -10,6 +10,7 @@ |
10 | 10 |
import javax.persistence.ManyToOne; |
11 | 11 |
import javax.persistence.OneToMany; |
12 | 12 |
import javax.persistence.OneToOne; |
13 |
+import javax.persistence.Transient; |
|
13 | 14 |
|
14 | 15 |
import org.codehaus.jackson.JsonNode; |
15 | 16 |
import org.codehaus.jackson.node.ArrayNode; |
... | ... | @@ -74,6 +75,7 @@ |
74 | 75 |
* checklist.save(); } |
75 | 76 |
*/ |
76 | 77 |
|
78 |
+ @Transient |
|
77 | 79 |
public JsonNode toJSON() { |
78 | 80 |
|
79 | 81 |
ObjectNode json = Json.newObject(); |
--- app/models/task/TaskBoard.java
+++ app/models/task/TaskBoard.java
... | ... | @@ -3,11 +3,7 @@ |
3 | 3 |
import java.util.ArrayList; |
4 | 4 |
import java.util.List; |
5 | 5 |
|
6 |
-import javax.persistence.CascadeType; |
|
7 |
-import javax.persistence.Entity; |
|
8 |
-import javax.persistence.Id; |
|
9 |
-import javax.persistence.OneToMany; |
|
10 |
-import javax.persistence.OneToOne; |
|
6 |
+import javax.persistence.*; |
|
11 | 7 |
|
12 | 8 |
import models.Project; |