[Notice] Announcing the End of Demo Server [Read me]

add logic code for Issue state change and some code refactoring on Issue
@ab58bb0ebe1ab6799e2e526457702d4796f4a99d
--- app/controllers/IssueApp.java
+++ app/controllers/IssueApp.java
... | ... | @@ -13,6 +13,7 @@ |
13 | 13 |
import models.enumeration.IssueState; |
14 | 14 |
import models.enumeration.StateType; |
15 | 15 |
import models.support.SearchCondition; |
16 |
+import play.Logger; |
|
16 | 17 |
import play.data.Form; |
17 | 18 |
import play.mvc.Controller; |
18 | 19 |
import play.mvc.Http.MultipartFormData; |
... | ... | @@ -22,7 +23,6 @@ |
22 | 23 |
import utils.Constants; |
23 | 24 |
import views.html.issue.editIssue; |
24 | 25 |
import views.html.issue.issue; |
25 |
-import views.html.issue.issueError; |
|
26 | 26 |
import views.html.issue.issueList; |
27 | 27 |
import views.html.issue.newIssue; |
28 | 28 |
import views.html.issue.notExistingPage; |
... | ... | @@ -77,10 +77,9 @@ |
77 | 77 |
} else { |
78 | 78 |
Issue newIssue = issueForm.get(); |
79 | 79 |
newIssue.authorId = UserApp.currentUser().id; |
80 |
- newIssue.authorName = UserApp.currentUser().name; |
|
81 | 80 |
newIssue.project = project; |
82 | 81 |
newIssue.state = IssueState.ENROLLED; |
83 |
- newIssue.updateStatusType(newIssue.state); |
|
82 |
+// newIssue.updateStatusType(); |
|
84 | 83 |
newIssue.filePath = saveFile(request()); |
85 | 84 |
Issue.create(newIssue); |
86 | 85 |
} |
... | ... | @@ -102,15 +101,15 @@ |
102 | 101 |
return badRequest(issueForm.errors().toString()); |
103 | 102 |
} else { |
104 | 103 |
Issue issue = issueForm.get(); |
105 |
- issue.authorId = UserApp.currentUser().id; |
|
106 |
- issue.authorName = UserApp.currentUser().name; |
|
104 |
+// issue.authorId = UserApp.currentUser().id; |
|
107 | 105 |
issue.id = id; |
108 | 106 |
issue.date = Issue.findById(id).date; |
109 | 107 |
issue.filePath = saveFile(request()); |
110 | 108 |
issue.project = project; |
111 |
- if (issue.assigneeId != null) { |
|
112 |
- issue.state = IssueState.ASSIGNED; |
|
113 |
- } |
|
109 |
+ issue.updateState(issue); |
|
110 |
+ |
|
111 |
+ Logger.error("assigneeId :_"+issue.assigneeId +"// diagnoisResult:_" + issue.diagnosisResult); |
|
112 |
+ // issue.updateStateType(); |
|
114 | 113 |
Issue.edit(issue); |
115 | 114 |
} |
116 | 115 |
return redirect(routes.IssueApp.issues(project.owner, project.name, StateType.ALL.name())); |
... | ... | @@ -135,7 +134,6 @@ |
135 | 134 |
IssueComment comment = commentForm.get(); |
136 | 135 |
comment.issue = Issue.findById(issueId); |
137 | 136 |
comment.authorId = UserApp.currentUser().id; |
138 |
- comment.authorName = UserApp.currentUser().name; |
|
139 | 137 |
comment.filePath = saveFile(request()); |
140 | 138 |
IssueComment.create(comment); |
141 | 139 |
Issue.updateNumOfComments(issueId); |
--- app/models/Issue.java
+++ app/models/Issue.java
... | ... | @@ -1,13 +1,11 @@ |
1 | 1 |
package models; |
2 | 2 |
|
3 | 3 |
import static com.avaje.ebean.Expr.contains; |
4 |
-import static models.enumeration.IssueState.ASSIGNED; |
|
5 | 4 |
|
6 | 5 |
import java.io.File; |
7 | 6 |
import java.io.IOException; |
8 | 7 |
import java.util.ArrayList; |
9 | 8 |
import java.util.Date; |
10 |
-import java.util.LinkedHashMap; |
|
11 | 9 |
import java.util.List; |
12 | 10 |
import java.util.Map; |
13 | 11 |
|
... | ... | @@ -93,522 +91,583 @@ |
93 | 91 |
*/ |
94 | 92 |
@Entity |
95 | 93 |
public class Issue extends Model { |
96 |
- private static final long serialVersionUID = 1L; |
|
97 |
- private static Finder<Long, Issue> find = new Finder<Long, Issue>( |
|
98 |
- Long.class, Issue.class); |
|
94 |
+ private static final long serialVersionUID = 1L; |
|
95 |
+ private static Finder<Long, Issue> find = new Finder<Long, Issue>(Long.class, Issue.class); |
|
99 | 96 |
|
100 |
- public static final int FIRST_PAGE_NUMBER = 0; |
|
101 |
- public static final int ISSUE_COUNT_PER_PAGE = 25; |
|
102 |
- public static final int NUMBER_OF_ONE_MORE_COMMENTS = 1; |
|
103 |
- public static final String DEFAULT_SORTER = "date"; |
|
104 |
- public static final String TO_BE_ASSIGNED = "TBA"; |
|
97 |
+ public static final int FIRST_PAGE_NUMBER = 0; |
|
98 |
+ public static final int ISSUE_COUNT_PER_PAGE = 25; |
|
99 |
+ public static final int NUMBER_OF_ONE_MORE_COMMENTS = 1; |
|
100 |
+ public static final String DEFAULT_SORTER = "date"; |
|
101 |
+ public static final String TO_BE_ASSIGNED = "TBA"; |
|
105 | 102 |
|
106 |
- @Id |
|
107 |
- public Long id; |
|
103 |
+ @Id |
|
104 |
+ public Long id; |
|
108 | 105 |
|
109 |
- @Constraints.Required |
|
110 |
- public String title; |
|
106 |
+ @Constraints.Required |
|
107 |
+ public String title; |
|
111 | 108 |
|
112 |
- @Constraints.Required |
|
113 |
- public String body; |
|
109 |
+ @Constraints.Required |
|
110 |
+ public String body; |
|
114 | 111 |
|
115 |
- @Formats.DateTime(pattern = "yyyy-MM-dd") |
|
116 |
- public Date date; |
|
112 |
+ @Formats.DateTime(pattern = "yyyy-MM-dd") |
|
113 |
+ public Date date; |
|
117 | 114 |
|
118 |
- public Long milestoneId; |
|
119 |
- public Long assigneeId; |
|
120 |
- public Long authorId; |
|
121 |
- public String authorName; |
|
122 |
- public IssueState state; |
|
123 |
- public StateType stateType; |
|
124 |
- public String issueType; |
|
125 |
- public String componentName; |
|
126 |
- // TODO 첨부 파일이 여러개인경우는? |
|
127 |
- public String filePath; |
|
128 |
- public String osType; |
|
129 |
- public String browserType; |
|
130 |
- public String dbmsType; |
|
131 |
- public String importance; |
|
132 |
- public String diagnosisResult; |
|
115 |
+ public int numOfComments; |
|
116 |
+ public Long milestoneId; |
|
117 |
+ public Long assigneeId; |
|
118 |
+ public Long authorId; |
|
119 |
+ public IssueState state; |
|
120 |
+ public StateType stateType; |
|
121 |
+ public String issueType; |
|
122 |
+ public String componentName; |
|
123 |
+ // TODO 첨부 파일이 여러개인경우는? |
|
124 |
+ public String filePath; |
|
125 |
+ public String osType; |
|
126 |
+ public String browserType; |
|
127 |
+ public String dbmsType; |
|
128 |
+ public String importance; |
|
129 |
+ public String diagnosisResult; |
|
133 | 130 |
|
134 |
- @ManyToOne |
|
135 |
- public Project project; |
|
131 |
+ @ManyToOne |
|
132 |
+ public Project project; |
|
136 | 133 |
|
137 |
- @OneToMany(mappedBy = "issue", cascade = CascadeType.ALL) |
|
138 |
- public List<IssueComment> comments = new ArrayList<IssueComment>(); |
|
134 |
+ @OneToMany(mappedBy = "issue", cascade = CascadeType.ALL) |
|
135 |
+ public List<IssueComment> comments = new ArrayList<IssueComment>(); |
|
139 | 136 |
|
140 |
- public int numOfComments; |
|
141 |
- |
|
142 |
- public Issue() { |
|
143 |
- this.date = JodaDateUtil.now(); |
|
144 |
- } |
|
145 |
- |
|
146 |
- public String issueTypeLabel() { |
|
147 |
- return issueTypes().get(issueType); |
|
148 |
- } |
|
149 |
- |
|
150 |
- public static Map<String, String> issueTypes() { |
|
151 |
- return new Options( |
|
152 |
- "issue.new.detailInfo.issueType.worst", |
|
153 |
- "issue.new.detailInfo.issueType.worse", |
|
154 |
- "issue.new.detailInfo.issueType.bad", |
|
155 |
- "issue.new.detailInfo.issueType.enhancement", |
|
156 |
- "issue.new.detailInfo.issueType.recommendation"); |
|
157 |
- } |
|
158 |
- |
|
159 |
- public static Map<String, String> osTypes() { |
|
160 |
- return new Options( |
|
161 |
- "issue.new.environment.osType.windows", |
|
162 |
- "issue.new.environment.osType.Mac", |
|
163 |
- "issue.new.environment.osType.Linux"); |
|
137 |
+ public Issue() { |
|
138 |
+ this.date = JodaDateUtil.now(); |
|
164 | 139 |
} |
165 |
- |
|
166 |
- public static Map<String, String> browserTypes() { |
|
167 |
- return new Options( |
|
168 |
- "issue.new.environment.browserType.ie", |
|
140 |
+ |
|
141 |
+ public String issueTypeLabel() { |
|
142 |
+ return issueTypes().get(issueType); |
|
143 |
+ } |
|
144 |
+ |
|
145 |
+ public Duration ago() { |
|
146 |
+ return JodaDateUtil.ago(this.date); |
|
147 |
+ } |
|
148 |
+ |
|
149 |
+ public String reporterName() { |
|
150 |
+ return User.findNameById(this.authorId); |
|
151 |
+ } |
|
152 |
+ |
|
153 |
+ /** |
|
154 |
+ * issueList, issue view에서 assignee의 이름을 출력해준다. 아래의 getAssigneeName과 합쳐질 수 |
|
155 |
+ * 있을듯. |
|
156 |
+ */ |
|
157 |
+ public String assigneeName() { |
|
158 |
+ |
|
159 |
+ return (this.assigneeId != null ? User.findNameById(this.assigneeId) : "issue.noAssignee"); |
|
160 |
+ } |
|
161 |
+ |
|
162 |
+ /** |
|
163 |
+ * 이슈의 오픈 상태를 확인한다. |
|
164 |
+ * |
|
165 |
+ * @return boolean |
|
166 |
+ */ |
|
167 |
+ public boolean isOpen() { |
|
168 |
+ return StateType.OPEN.equals(this.stateType); |
|
169 |
+ } |
|
170 |
+ |
|
171 |
+ /** |
|
172 |
+ * View에서 스트링값으로 변환하도록 한다. |
|
173 |
+ * |
|
174 |
+ * @return |
|
175 |
+ */ |
|
176 |
+ public String state() { |
|
177 |
+ if (this.state.equals(IssueState.ASSIGNED)) { |
|
178 |
+ return IssueState.ASSIGNED.state(); |
|
179 |
+ } else if (this.state.equals(IssueState.SOLVED)) { |
|
180 |
+ return IssueState.SOLVED.state(); |
|
181 |
+ } else if (this.state.equals(IssueState.FINISHED)) { |
|
182 |
+ return IssueState.FINISHED.state(); |
|
183 |
+ } else |
|
184 |
+ return IssueState.ENROLLED.state(); |
|
185 |
+ } |
|
186 |
+ |
|
187 |
+ /** |
|
188 |
+ * 해당 이슈의 상태(state) 따라서 탭 기능에서 구분 짖는(stateType) 것이 해결인지 미해결인지 값을 결정해준다. |
|
189 |
+ * diagnosisResult가 2인 경우는 현 진단결과 선택 란에서 "수정완료"를 의미하므로, 이슈 정상 해결을 의미한다. |
|
190 |
+ * |
|
191 |
+ * @param state |
|
192 |
+ */ |
|
193 |
+ public void updateStateType(Issue issue) { |
|
194 |
+ |
|
195 |
+ if (this.state == null || this.state.equals(IssueState.ASSIGNED) |
|
196 |
+ || this.state.equals(IssueState.ENROLLED)) { |
|
197 |
+ this.stateType = StateType.OPEN; |
|
198 |
+ } else { |
|
199 |
+ this.stateType = StateType.CLOSED; |
|
200 |
+ } |
|
201 |
+ } |
|
202 |
+ |
|
203 |
+ /** |
|
204 |
+ * 이슈의 담당자(assignee) 배정과 이슈의 진단결과(diagnosisResult)에 따라 이슈의 상태를 정해진 로직에 따라 |
|
205 |
+ * 변경한다. |
|
206 |
+ * |
|
207 |
+ * @param issue |
|
208 |
+ */ |
|
209 |
+ public void updateState(Issue issue) { |
|
210 |
+ |
|
211 |
+ if (isEnrolled(issue)) { |
|
212 |
+ this.state = IssueState.ENROLLED; |
|
213 |
+ } else if (isFinished(issue)) { |
|
214 |
+ this.state = IssueState.FINISHED; |
|
215 |
+ } else if (isAssigned(issue)) { |
|
216 |
+ this.state = IssueState.ASSIGNED; |
|
217 |
+ } else if (isSolved(issue)) { |
|
218 |
+ this.state = IssueState.SOLVED; |
|
219 |
+ } else |
|
220 |
+ this.state = IssueState.ENROLLED; |
|
221 |
+ |
|
222 |
+ updateStateType(issue); |
|
223 |
+ } |
|
224 |
+ |
|
225 |
+ /** |
|
226 |
+ * 이슈가 담당자와 진단결과가 없는 경우에는 "등록" 상태임을 확인해준다. |
|
227 |
+ * |
|
228 |
+ * @param issue |
|
229 |
+ * @return boolean |
|
230 |
+ */ |
|
231 |
+ public boolean isEnrolled(Issue issue) { |
|
232 |
+ |
|
233 |
+ if (issue.assigneeId == null && issue.diagnosisResult.equals("")) { |
|
234 |
+ return true; |
|
235 |
+ } else |
|
236 |
+ return false; |
|
237 |
+ } |
|
238 |
+ |
|
239 |
+ /** |
|
240 |
+ * 이슈가 담당자는 배정받고, 진단결과가 없는 경우에는 "진행중" 상태임을 확인해준다. |
|
241 |
+ * |
|
242 |
+ * @param issue |
|
243 |
+ * @return |
|
244 |
+ */ |
|
245 |
+ public boolean isAssigned(Issue issue) { |
|
246 |
+ |
|
247 |
+ if (issue.assigneeId != null && issue.diagnosisResult.equals("")) { |
|
248 |
+ return true; |
|
249 |
+ } else |
|
250 |
+ return false; |
|
251 |
+ } |
|
252 |
+ |
|
253 |
+ /** |
|
254 |
+ * 이슈가 담당자를 배정받고 진단결과가 2번째 수정완료(추후 변경 가능) 인 경우에는 "해결" 상태임을 확인해준다. |
|
255 |
+ * |
|
256 |
+ * @param issue |
|
257 |
+ * @return |
|
258 |
+ */ |
|
259 |
+ public boolean isSolved(Issue issue) { |
|
260 |
+ |
|
261 |
+ if (issue.assigneeId != null && issue.diagnosisResult.equals("2")) { |
|
262 |
+ return true; |
|
263 |
+ } else |
|
264 |
+ return false; |
|
265 |
+ } |
|
266 |
+ |
|
267 |
+ /** |
|
268 |
+ * 이슈가 담당자의 유무와 상관 없이, 진단결과가 2번째 수정완료가 아닌 다른 사유가 존재한 경우에는 "닫힘" 상태임을 확인해준다. |
|
269 |
+ * |
|
270 |
+ * @param issue |
|
271 |
+ * @return |
|
272 |
+ */ |
|
273 |
+ |
|
274 |
+ public boolean isFinished(Issue issue) { |
|
275 |
+ |
|
276 |
+ if (!issue.diagnosisResult.equals("2") && !issue.diagnosisResult.equals("")) { |
|
277 |
+ return true; |
|
278 |
+ } else |
|
279 |
+ return false; |
|
280 |
+ } |
|
281 |
+ |
|
282 |
+ /** |
|
283 |
+ * View에서 사용할 이슈 유형에 대한 옵션을 제공한다. Purpose : View에서 Select 부분에서 i18n를 사용하면서 |
|
284 |
+ * 최대한 간단하게 하기 위함. |
|
285 |
+ * |
|
286 |
+ * @return |
|
287 |
+ */ |
|
288 |
+ public static Map<String, String> issueTypes() { |
|
289 |
+ return new Options("issue.new.detailInfo.issueType.worst", |
|
290 |
+ "issue.new.detailInfo.issueType.worse", "issue.new.detailInfo.issueType.bad", |
|
291 |
+ "issue.new.detailInfo.issueType.enhancement", |
|
292 |
+ "issue.new.detailInfo.issueType.recommendation"); |
|
293 |
+ } |
|
294 |
+ |
|
295 |
+ /** |
|
296 |
+ * View에서 사용할 OS유형에 대한 옵션을 제공한다. Purpose : View에서 Select 부분에서 i18n를 사용하면서 |
|
297 |
+ * 최대한 간단하게 하기 위함. |
|
298 |
+ * |
|
299 |
+ * @return |
|
300 |
+ */ |
|
301 |
+ public static Map<String, String> osTypes() { |
|
302 |
+ return new Options("issue.new.environment.osType.windows", |
|
303 |
+ "issue.new.environment.osType.Mac", "issue.new.environment.osType.Linux"); |
|
304 |
+ } |
|
305 |
+ |
|
306 |
+ /** |
|
307 |
+ * View에서 사용할 브라우져 유형에 대한 옵션을 제공한다. Purpose : View에서 Select 부분에서 i18n를 사용하면서 |
|
308 |
+ * 최대한 간단하게 하기 위함. |
|
309 |
+ * |
|
310 |
+ * @return |
|
311 |
+ */ |
|
312 |
+ public static Map<String, String> browserTypes() { |
|
313 |
+ return new Options("issue.new.environment.browserType.ie", |
|
169 | 314 |
"issue.new.environment.browserType.chrome", |
170 | 315 |
"issue.new.environment.browserType.firefox", |
171 | 316 |
"issue.new.environment.browserType.safari", |
172 | 317 |
"issue.new.environment.browserType.opera"); |
173 | 318 |
} |
174 |
- |
|
175 |
- public static Map<String, String> dbmsTypes() { |
|
176 |
- return new Options( |
|
177 |
- "issue.new.environment.dbmsType.postgreSQL", |
|
178 |
- "issue.new.environment.dbmsType.CUBRID", |
|
179 |
- "issue.new.environment.dbmsType.MySQL"); |
|
319 |
+ |
|
320 |
+ /** |
|
321 |
+ * View에서 사용할 DBMS 유형에 대한 옵션을 제공한다. Purpose : View에서 Select 부분에서 i18n를 사용하면서 |
|
322 |
+ * 최대한 간단하게 하기 위함. |
|
323 |
+ * |
|
324 |
+ * @return |
|
325 |
+ */ |
|
326 |
+ public static Map<String, String> dbmsTypes() { |
|
327 |
+ return new Options("issue.new.environment.dbmsType.postgreSQL", |
|
328 |
+ "issue.new.environment.dbmsType.CUBRID", "issue.new.environment.dbmsType.MySQL"); |
|
180 | 329 |
} |
181 |
- |
|
182 |
- public static Map<String, String> importances() { |
|
183 |
- return new Options( |
|
184 |
- "issue.new.result.importance.highest", |
|
185 |
- "issue.new.result.importance.high", |
|
186 |
- "issue.new.result.importance.average", |
|
187 |
- "issue.new.result.importance.low", |
|
188 |
- "issue.new.result.importance.lowest"); |
|
330 |
+ |
|
331 |
+ /** |
|
332 |
+ * View에서 사용할 중요도에 대한 옵션을 제공한다. Purpose : View에서 Select 부분에서 i18n를 사용하면서 최대한 |
|
333 |
+ * 간단하게 하기 위함. |
|
334 |
+ * |
|
335 |
+ * @return |
|
336 |
+ */ |
|
337 |
+ public static Map<String, String> importances() { |
|
338 |
+ return new Options("issue.new.result.importance.highest", |
|
339 |
+ "issue.new.result.importance.high", "issue.new.result.importance.average", |
|
340 |
+ "issue.new.result.importance.low", "issue.new.result.importance.lowest"); |
|
189 | 341 |
} |
190 |
- |
|
191 |
- public static Map<String, String> diagnosisResults() { |
|
192 |
- return new Options( |
|
193 |
- "issue.new.result.diagnosisResult.bug", |
|
342 |
+ |
|
343 |
+ /** |
|
344 |
+ * View에서 사용할 진단 결과에 대한 옵션을 제공한다. Purpose : View에서 Select 부분에서 i18n를 사용하면서 |
|
345 |
+ * 최대한 간단하게 하기 위함. |
|
346 |
+ * |
|
347 |
+ * @return |
|
348 |
+ */ |
|
349 |
+ public static Map<String, String> diagnosisResults() { |
|
350 |
+ return new Options("issue.new.result.diagnosisResult.bug", |
|
194 | 351 |
"issue.new.result.diagnosisResult.fixed", |
195 | 352 |
"issue.new.result.diagnosisResult.willNotFixed", |
196 | 353 |
"issue.new.result.diagnosisResult.notaBug", |
197 | 354 |
"issue.new.result.diagnosisResult.awaitingResponse", |
198 | 355 |
"issue.new.result.diagnosisResult.unreproducible", |
199 | 356 |
"issue.new.result.diagnosisResult.duplicated", |
200 |
- "issue.new.result.diagnosisResult.works4me" |
|
201 |
- ); |
|
357 |
+ "issue.new.result.diagnosisResult.works4me"); |
|
202 | 358 |
} |
203 |
- |
|
204 | 359 |
|
205 |
- /** |
|
206 |
- * View에서 스트링값으로 변환하도록 한다. |
|
207 |
- * |
|
208 |
- * @return |
|
209 |
- */ |
|
210 |
- public String state() { |
|
211 |
- if (this.state == ASSIGNED) { |
|
212 |
- return IssueState.ASSIGNED.state(); |
|
213 |
- } else if (this.state == IssueState.SOLVED) { |
|
214 |
- return IssueState.SOLVED.state(); |
|
215 |
- } else if (this.state == IssueState.FINISHED) { |
|
216 |
- return IssueState.FINISHED.state(); |
|
217 |
- } else |
|
218 |
- return IssueState.ENROLLED.state(); |
|
219 |
- } |
|
360 |
+ /** |
|
361 |
+ * 이슈 id로 이슈를 찾아준다. |
|
362 |
+ * |
|
363 |
+ * @param id |
|
364 |
+ * @return |
|
365 |
+ */ |
|
366 |
+ public static Issue findById(Long id) { |
|
367 |
+ return find.byId(id); |
|
368 |
+ } |
|
220 | 369 |
|
221 |
- /** |
|
222 |
- * 해당 이슈의 상태(state) 따라서 탭 기능에서 구분 짖는(stateType) 것이 해결인지 미해결인지 값을 결정해준다. |
|
223 |
- * |
|
224 |
- * @param state |
|
225 |
- */ |
|
370 |
+ /** |
|
371 |
+ * 이슈를 생성한다. |
|
372 |
+ * |
|
373 |
+ * @param issue |
|
374 |
+ * @return |
|
375 |
+ */ |
|
376 |
+ public static Long create(Issue issue) { |
|
377 |
+ issue.save(); |
|
378 |
+ if (issue.milestoneId != null) { |
|
379 |
+ Milestone milestone = Milestone.findById(issue.milestoneId); |
|
380 |
+ milestone.add(issue); |
|
381 |
+ } |
|
382 |
+ issue.updateStateType(issue); |
|
383 |
+ return issue.id; |
|
384 |
+ } |
|
226 | 385 |
|
227 |
- public void updateStatusType(IssueState state) { |
|
228 |
- if (this.state == ASSIGNED || this.state == IssueState.ENROLLED) { |
|
229 |
- this.stateType = StateType.OPEN; |
|
230 |
- } else if (this.state == IssueState.SOLVED |
|
231 |
- || this.state == IssueState.FINISHED) { |
|
232 |
- this.stateType = StateType.CLOSED; |
|
233 |
- } |
|
234 |
- } |
|
386 |
+ /** |
|
387 |
+ * 이슈를 삭제한다. |
|
388 |
+ * |
|
389 |
+ * @param id |
|
390 |
+ */ |
|
391 |
+ public static void delete(Long id) { |
|
392 |
+ Issue issue = find.byId(id); |
|
393 |
+ if (!issue.milestoneId.equals(0l) || issue.milestoneId != null) { |
|
394 |
+ Milestone milestone = Milestone.findById(issue.milestoneId); |
|
395 |
+ milestone.delete(issue); |
|
396 |
+ } |
|
397 |
+ issue.delete(); |
|
398 |
+ } |
|
235 | 399 |
|
236 |
- /** |
|
237 |
- * 이슈 id로 이슈를 찾아준다. |
|
238 |
- * |
|
239 |
- * @param id |
|
240 |
- * @return |
|
241 |
- */ |
|
242 |
- public static Issue findById(Long id) { |
|
243 |
- return find.byId(id); |
|
244 |
- } |
|
400 |
+ /** |
|
401 |
+ * 미해결 탭을 눌렀을 때, open 상태의 이슈들을 찾아준다.. |
|
402 |
+ * |
|
403 |
+ * @param projectName |
|
404 |
+ * @return |
|
405 |
+ */ |
|
406 |
+ public static Page<Issue> findOpenIssues(String projectName) { |
|
407 |
+ return Issue.findIssues(projectName, StateType.OPEN); |
|
408 |
+ } |
|
245 | 409 |
|
246 |
- /** |
|
247 |
- * 이슈를 생성한다. |
|
248 |
- * |
|
249 |
- * @param issue |
|
250 |
- * @return |
|
251 |
- */ |
|
252 |
- public static Long create(Issue issue) { |
|
253 |
- issue.save(); |
|
254 |
- if (issue.milestoneId != null) { |
|
255 |
- Milestone milestone = Milestone.findById(issue.milestoneId); |
|
256 |
- milestone.add(issue); |
|
257 |
- } |
|
258 |
- return issue.id; |
|
259 |
- } |
|
410 |
+ /** |
|
411 |
+ * 해결 탭을 눌렀을 때, closed 상태의 이슈들을 찾아준다. |
|
412 |
+ * |
|
413 |
+ * @param projectName |
|
414 |
+ * @return |
|
415 |
+ */ |
|
416 |
+ public static Page<Issue> findClosedIssues(String projectName) { |
|
417 |
+ return Issue.findIssues(projectName, StateType.CLOSED); |
|
418 |
+ } |
|
260 | 419 |
|
261 |
- /** |
|
262 |
- * 이슈를 삭제한다. |
|
263 |
- * |
|
264 |
- * @param id |
|
265 |
- */ |
|
266 |
- public static void delete(Long id) { |
|
267 |
- Issue issue = find.byId(id); |
|
268 |
- if (!issue.milestoneId.equals(0l) || issue.milestoneId != null) { |
|
269 |
- Milestone milestone = Milestone.findById(issue.milestoneId); |
|
270 |
- milestone.delete(issue); |
|
271 |
- } |
|
272 |
- issue.delete(); |
|
273 |
- } |
|
420 |
+ /** |
|
421 |
+ * 해당 프로젝트의 State 외의 것들은 기본값들로 이뤄진 이슈들을 찾아준다. |
|
422 |
+ * |
|
423 |
+ * @param projectName |
|
424 |
+ * @param state |
|
425 |
+ * @return |
|
426 |
+ */ |
|
427 |
+ public static Page<Issue> findIssues(String projectName, StateType state) { |
|
428 |
+ return findIssues(projectName, FIRST_PAGE_NUMBER, state, DEFAULT_SORTER, Direction.DESC, |
|
429 |
+ "", null, false, false); |
|
430 |
+ } |
|
274 | 431 |
|
275 |
- /** |
|
276 |
- * 미해결 탭을 눌렀을 때, open 상태의 이슈들을 찾아준다.. |
|
277 |
- * |
|
278 |
- * @param projectName |
|
279 |
- * @return |
|
280 |
- */ |
|
281 |
- public static Page<Issue> findOpenIssues(String projectName) { |
|
282 |
- return Issue.findIssues(projectName, StateType.OPEN); |
|
283 |
- } |
|
432 |
+ /** |
|
433 |
+ * 검색창에서 제공된 query(filter)와 댓글과 파일첨부된 이슈만 찾아주는 체크박스의 값에 따라 필터링된 이슈들을 찾아준다. |
|
434 |
+ * |
|
435 |
+ * @param projectName |
|
436 |
+ * @param filter |
|
437 |
+ * @param state |
|
438 |
+ * @param commentedCheck |
|
439 |
+ * @param fileAttachedCheck |
|
440 |
+ * @return |
|
441 |
+ */ |
|
442 |
+ public static Page<Issue> findFilteredIssues(String projectName, String filter, |
|
443 |
+ StateType state, boolean commentedCheck, boolean fileAttachedCheck) { |
|
444 |
+ return findIssues(projectName, FIRST_PAGE_NUMBER, state, DEFAULT_SORTER, Direction.DESC, |
|
445 |
+ filter, null, commentedCheck, fileAttachedCheck); |
|
446 |
+ } |
|
284 | 447 |
|
285 |
- /** |
|
286 |
- * 해결 탭을 눌렀을 때, closed 상태의 이슈들을 찾아준다. |
|
287 |
- * |
|
288 |
- * @param projectName |
|
289 |
- * @return |
|
290 |
- */ |
|
291 |
- public static Page<Issue> findClosedIssues(String projectName) { |
|
292 |
- return Issue.findIssues(projectName, StateType.CLOSED); |
|
293 |
- } |
|
448 |
+ /** |
|
449 |
+ * 댓글이 달린 이슈들만 찾아준다. |
|
450 |
+ * |
|
451 |
+ * @param projectName |
|
452 |
+ * @param filter |
|
453 |
+ * @return |
|
454 |
+ */ |
|
455 |
+ public static Page<Issue> findCommentedIssues(String projectName, String filter) { |
|
456 |
+ return findIssues(projectName, FIRST_PAGE_NUMBER, StateType.ALL, DEFAULT_SORTER, |
|
457 |
+ Direction.DESC, filter, null, true, false); |
|
458 |
+ } |
|
294 | 459 |
|
295 |
- /** |
|
296 |
- * 해당 프로젝트의 State 외의 것들은 기본값들로 이뤄진 이슈들을 찾아준다. |
|
297 |
- * |
|
298 |
- * @param projectName |
|
299 |
- * @param state |
|
300 |
- * @return |
|
301 |
- */ |
|
302 |
- public static Page<Issue> findIssues(String projectName, StateType state) { |
|
303 |
- return findIssues(projectName, FIRST_PAGE_NUMBER, state, |
|
304 |
- DEFAULT_SORTER, Direction.DESC, "", null, false, false); |
|
305 |
- } |
|
460 |
+ /** |
|
461 |
+ * 파일이 첨부된 이슈들만 찾아준다. |
|
462 |
+ * |
|
463 |
+ * @param projectName |
|
464 |
+ * @param filter |
|
465 |
+ * @return |
|
466 |
+ */ |
|
306 | 467 |
|
307 |
- /** |
|
308 |
- * 검색창에서 제공된 query(filter)와 댓글과 파일첨부된 이슈만 찾아주는 체크박스의 값에 따라 필터링된 이슈들을 찾아준다. |
|
309 |
- * |
|
310 |
- * @param projectName |
|
311 |
- * @param filter |
|
312 |
- * @param state |
|
313 |
- * @param commentedCheck |
|
314 |
- * @param fileAttachedCheck |
|
315 |
- * @return |
|
316 |
- */ |
|
317 |
- public static Page<Issue> findFilteredIssues(String projectName, |
|
318 |
- String filter, StateType state, boolean commentedCheck, |
|
319 |
- boolean fileAttachedCheck) { |
|
320 |
- return findIssues(projectName, FIRST_PAGE_NUMBER, state, |
|
321 |
- DEFAULT_SORTER, Direction.DESC, filter, null, commentedCheck, |
|
322 |
- fileAttachedCheck); |
|
323 |
- } |
|
468 |
+ public static Page<Issue> findFileAttachedIssues(String projectName, String filter) { |
|
469 |
+ return findIssues(projectName, FIRST_PAGE_NUMBER, StateType.ALL, DEFAULT_SORTER, |
|
470 |
+ Direction.DESC, filter, null, false, true); |
|
471 |
+ } |
|
324 | 472 |
|
325 |
- /** |
|
326 |
- * 댓글이 달린 이슈들만 찾아준다. |
|
327 |
- * |
|
328 |
- * @param projectName |
|
329 |
- * @param filter |
|
330 |
- * @return |
|
331 |
- */ |
|
332 |
- public static Page<Issue> findCommentedIssues(String projectName, |
|
333 |
- String filter) { |
|
334 |
- return findIssues(projectName, FIRST_PAGE_NUMBER, StateType.ALL, |
|
335 |
- DEFAULT_SORTER, Direction.DESC, filter, null, true, false); |
|
336 |
- } |
|
473 |
+ /** |
|
474 |
+ * 마일스톤 Id에 의거해서 해당 마일스톤에 속한 이슈들을 찾아준다. |
|
475 |
+ * |
|
476 |
+ * @param projectName |
|
477 |
+ * @param milestoneId |
|
478 |
+ * @return |
|
479 |
+ */ |
|
480 |
+ public static Page<Issue> findIssuesByMilestoneId(String projectName, Long milestoneId) { |
|
481 |
+ return findIssues(projectName, FIRST_PAGE_NUMBER, StateType.ALL, DEFAULT_SORTER, |
|
482 |
+ Direction.DESC, "", milestoneId, false, false); |
|
483 |
+ } |
|
337 | 484 |
|
338 |
- /** |
|
339 |
- * 파일이 첨부된 이슈들만 찾아준다. |
|
340 |
- * |
|
341 |
- * @param projectName |
|
342 |
- * @param filter |
|
343 |
- * @return |
|
344 |
- */ |
|
485 |
+ /** |
|
486 |
+ * 이슈들을 아래의 parameter들의 조건에 의거하여 Page형태로 반환한다. |
|
487 |
+ * |
|
488 |
+ * @param projectName |
|
489 |
+ * project ID to find issues |
|
490 |
+ * @param pageNumber |
|
491 |
+ * Page to display |
|
492 |
+ * @param state |
|
493 |
+ * state type of issue(OPEN or CLOSED |
|
494 |
+ * @param sortBy |
|
495 |
+ * Issue property used for sorting, but, it might be fixed to |
|
496 |
+ * enum type |
|
497 |
+ * @param order |
|
498 |
+ * Sort order(either asc or desc) |
|
499 |
+ * @param filter |
|
500 |
+ * filter applied on the title column |
|
501 |
+ * @param commentedCheck |
|
502 |
+ * filter applied on the commetedCheck column, 댓글이 존재하는 이슈만 필터링 |
|
503 |
+ * @param fileAttachedCheck |
|
504 |
+ * filter applied on the fileAttachedCheck column, 파일이 업로드된 이슈만 |
|
505 |
+ * 필터링 |
|
506 |
+ * @return 위의 조건에 따라 필터링된 이슈들을 Page로 반환. |
|
507 |
+ */ |
|
508 |
+ public static Page<Issue> findIssues(String projectName, int pageNumber, StateType state, |
|
509 |
+ String sortBy, Direction order, String filter, Long milestoneId, |
|
510 |
+ boolean commentedCheck, boolean fileAttachedCheck) { |
|
345 | 511 |
|
346 |
- public static Page<Issue> findFileAttachedIssues(String projectName, |
|
347 |
- String filter) { |
|
348 |
- return findIssues(projectName, FIRST_PAGE_NUMBER, StateType.ALL, |
|
349 |
- DEFAULT_SORTER, Direction.DESC, filter, null, false, true); |
|
350 |
- } |
|
512 |
+ OrderParams orderParams = new OrderParams().add(sortBy, order); |
|
513 |
+ SearchParams searchParams = new SearchParams().add("project.name", projectName, |
|
514 |
+ Matching.EQUALS); |
|
351 | 515 |
|
352 |
- /** |
|
353 |
- * 마일스톤 Id에 의거해서 해당 마일스톤에 속한 이슈들을 찾아준다. |
|
354 |
- * |
|
355 |
- * @param projectName |
|
356 |
- * @param milestoneId |
|
357 |
- * @return |
|
358 |
- */ |
|
359 |
- public static Page<Issue> findIssuesByMilestoneId(String projectName, |
|
360 |
- Long milestoneId) { |
|
361 |
- return findIssues(projectName, FIRST_PAGE_NUMBER, StateType.ALL, |
|
362 |
- DEFAULT_SORTER, Direction.DESC, "", milestoneId, false, false); |
|
363 |
- } |
|
516 |
+ if (filter != null && !filter.isEmpty()) { |
|
517 |
+ searchParams.add("title", filter, Matching.CONTAINS); |
|
518 |
+ } |
|
519 |
+ if (milestoneId != null) { |
|
520 |
+ searchParams.add("milestoneId", milestoneId, Matching.EQUALS); |
|
521 |
+ } |
|
522 |
+ if (commentedCheck) { |
|
523 |
+ searchParams.add("numOfComments", NUMBER_OF_ONE_MORE_COMMENTS, Matching.GE); |
|
524 |
+ } |
|
525 |
+ if (fileAttachedCheck) { |
|
526 |
+ searchParams.add("filePath", "", Matching.NOT_EQUALS); |
|
527 |
+ } |
|
528 |
+ if (state == null) { |
|
529 |
+ state = StateType.ALL; |
|
530 |
+ } |
|
531 |
+ switch (state) |
|
532 |
+ { |
|
533 |
+ case OPEN: |
|
534 |
+ searchParams.add("stateType", StateType.OPEN, Matching.EQUALS); |
|
535 |
+ break; |
|
536 |
+ case CLOSED: |
|
537 |
+ searchParams.add("stateType", StateType.CLOSED, Matching.EQUALS); |
|
538 |
+ break; |
|
539 |
+ default: |
|
540 |
+ } |
|
541 |
+ return FinderTemplate.getPage(orderParams, searchParams, find, ISSUE_COUNT_PER_PAGE, |
|
542 |
+ pageNumber); |
|
543 |
+ } |
|
364 | 544 |
|
365 |
- /** |
|
366 |
- * 이슈들을 아래의 parameter들의 조건에 의거하여 Page형태로 반환한다. |
|
367 |
- * |
|
368 |
- * @param projectName |
|
369 |
- * project ID to find issues |
|
370 |
- * @param pageNumber |
|
371 |
- * Page to display |
|
372 |
- * @param state |
|
373 |
- * state type of issue(OPEN or CLOSED |
|
374 |
- * @param sortBy |
|
375 |
- * Issue property used for sorting, but, it might be fixed to |
|
376 |
- * enum type |
|
377 |
- * @param order |
|
378 |
- * Sort order(either asc or desc) |
|
379 |
- * @param filter |
|
380 |
- * filter applied on the title column |
|
381 |
- * @param commentedCheck |
|
382 |
- * filter applied on the commetedCheck column, 댓글이 존재하는 이슈만 필터링 |
|
383 |
- * @param fileAttachedCheck |
|
384 |
- * filter applied on the fileAttachedCheck column, 파일이 업로드된 이슈만 |
|
385 |
- * 필터링 |
|
386 |
- * @return 위의 조건에 따라 필터링된 이슈들을 Page로 반환. |
|
387 |
- */ |
|
388 |
- public static Page<Issue> findIssues(String projectName, int pageNumber, |
|
389 |
- StateType state, String sortBy, Direction order, String filter, |
|
390 |
- Long milestoneId, boolean commentedCheck, boolean fileAttachedCheck) { |
|
545 |
+ public static Long findAssigneeIdByIssueId(String projectName, Long issueId) { |
|
546 |
+ return find.byId(issueId).assigneeId; |
|
547 |
+ } |
|
391 | 548 |
|
392 |
- OrderParams orderParams = new OrderParams().add(sortBy, order); |
|
393 |
- SearchParams searchParams = new SearchParams().add("project.name", |
|
394 |
- projectName, Matching.EQUALS); |
|
549 |
+ /** |
|
550 |
+ * 해당 마일스톤아이디로 관련 이슈를 검색한다. |
|
551 |
+ * |
|
552 |
+ * @param milestoneId |
|
553 |
+ * @return |
|
554 |
+ */ |
|
555 |
+ public static List<Issue> findByMilestoneId(Long milestoneId) { |
|
556 |
+ SearchParams searchParams = new SearchParams().add("milestoneId", milestoneId, |
|
557 |
+ Matching.EQUALS); |
|
558 |
+ return FinderTemplate.findBy(null, searchParams, find); |
|
559 |
+ } |
|
395 | 560 |
|
396 |
- if (filter != null && !filter.isEmpty()) { |
|
397 |
- searchParams.add("title", filter, Matching.CONTAINS); |
|
398 |
- } |
|
399 |
- if (milestoneId != null) { |
|
400 |
- searchParams.add("milestoneId", milestoneId, Matching.EQUALS); |
|
401 |
- } |
|
402 |
- if (commentedCheck) { |
|
403 |
- searchParams.add("numOfComments", NUMBER_OF_ONE_MORE_COMMENTS, |
|
404 |
- Matching.GE); |
|
405 |
- } |
|
406 |
- if (fileAttachedCheck) { |
|
407 |
- searchParams.add("filePath", "", Matching.NOT_EQUALS); |
|
408 |
- } |
|
409 |
- if (state == null) { |
|
410 |
- state = StateType.ALL; |
|
411 |
- } |
|
412 |
- switch (state) { |
|
413 |
- case OPEN: |
|
414 |
- searchParams.add("stateType", StateType.OPEN, Matching.EQUALS); |
|
415 |
- break; |
|
416 |
- case CLOSED: |
|
417 |
- searchParams.add("stateType", StateType.CLOSED, Matching.EQUALS); |
|
418 |
- break; |
|
419 |
- } |
|
420 |
- return FinderTemplate.getPage(orderParams, searchParams, find, |
|
421 |
- ISSUE_COUNT_PER_PAGE, pageNumber); |
|
422 |
- } |
|
561 |
+ public static void edit(Issue issue) { |
|
562 |
+ Issue previousIssue = findById(issue.id); |
|
563 |
+ if (issue.filePath == null) { |
|
564 |
+ issue.filePath = previousIssue.filePath; |
|
565 |
+ } |
|
566 |
+ issue.updateStateType(issue); |
|
567 |
+ issue.update(); |
|
568 |
+ } |
|
423 | 569 |
|
424 |
- public static Long findAssigneeIdByIssueId(String projectName, Long issueId) { |
|
425 |
- return find.byId(issueId).assigneeId; |
|
426 |
- } |
|
570 |
+ /** |
|
571 |
+ * JXL 라이브러리를 이용하여 엑셀 파일로 저장하며, 해당 파일이 저장된 주소를 반환한다. |
|
572 |
+ * |
|
573 |
+ * @param resultList |
|
574 |
+ * 엑셀로 저장하고자 하는 리스트 |
|
575 |
+ * @param pageName |
|
576 |
+ * 엑셀로 저장하고자 하는 목록의 페이지(내용, ex 이슈, 게시물 등) 이름 |
|
577 |
+ * @return |
|
578 |
+ * @throws Exception |
|
579 |
+ */ |
|
580 |
+ public static String excelSave(List<Issue> resultList, String pageName) throws Exception { |
|
581 |
+ String excelFile = pageName + "_" + JodaDateUtil.today().getTime() + ".xls"; |
|
582 |
+ String fullPath = "public/uploadFiles/" + excelFile; |
|
583 |
+ WritableWorkbook workbook = null; |
|
584 |
+ WritableSheet sheet = null; |
|
427 | 585 |
|
428 |
- /** |
|
429 |
- * 이슈의 오픈 상태를 확인한다. |
|
430 |
- * |
|
431 |
- * @return boolean |
|
432 |
- */ |
|
433 |
- public boolean isOpen() { |
|
434 |
- return StateType.OPEN.equals(this.stateType); |
|
435 |
- } |
|
586 |
+ try { |
|
587 |
+ WritableFont wf1 = new WritableFont(WritableFont.TIMES, 13, WritableFont.BOLD, false, |
|
588 |
+ UnderlineStyle.SINGLE, Colour.BLUE_GREY, ScriptStyle.NORMAL_SCRIPT); |
|
589 |
+ WritableCellFormat cf1 = new WritableCellFormat(wf1); |
|
590 |
+ cf1.setBorder(Border.ALL, BorderLineStyle.DOUBLE); |
|
591 |
+ cf1.setAlignment(Alignment.CENTRE); |
|
436 | 592 |
|
437 |
- /** |
|
438 |
- * 해당 마일스톤아이디로 관련 이슈를 검색한다. |
|
439 |
- * |
|
440 |
- * @param milestoneId |
|
441 |
- * @return |
|
442 |
- */ |
|
443 |
- public static List<Issue> findByMilestoneId(Long milestoneId) { |
|
444 |
- SearchParams searchParams = new SearchParams().add("milestoneId", |
|
445 |
- milestoneId, Matching.EQUALS); |
|
446 |
- return FinderTemplate.findBy(null, searchParams, find); |
|
447 |
- } |
|
593 |
+ WritableFont wf2 = new WritableFont(WritableFont.TAHOMA, 11, WritableFont.NO_BOLD, |
|
594 |
+ false, UnderlineStyle.NO_UNDERLINE, Colour.BLACK, ScriptStyle.NORMAL_SCRIPT); |
|
595 |
+ WritableCellFormat cf2 = new WritableCellFormat(wf2); |
|
596 |
+ cf2.setShrinkToFit(true); |
|
597 |
+ cf2.setBorder(Border.ALL, BorderLineStyle.THIN); |
|
598 |
+ cf2.setAlignment(Alignment.CENTRE); |
|
448 | 599 |
|
449 |
- public static void edit(Issue issue) { |
|
450 |
- Issue previousIssue = findById(issue.id); |
|
451 |
- if (issue.filePath == null) { |
|
452 |
- issue.filePath = previousIssue.filePath; |
|
453 |
- } |
|
454 |
- issue.update(); |
|
455 |
- } |
|
600 |
+ workbook = Workbook.createWorkbook(new File(fullPath)); |
|
601 |
+ sheet = workbook.createSheet(String.valueOf(JodaDateUtil.today().getTime()), 0); |
|
456 | 602 |
|
457 |
- /** |
|
458 |
- * JXL 라이브러리를 이용하여 엑셀 파일로 저장하며, 해당 파일이 저장된 주소를 반환한다. |
|
459 |
- * |
|
460 |
- * @param resultList |
|
461 |
- * 엑셀로 저장하고자 하는 리스트 |
|
462 |
- * @param pageName |
|
463 |
- * 엑셀로 저장하고자 하는 목록의 페이지(내용, ex 이슈, 게시물 등) 이름 |
|
464 |
- * @return |
|
465 |
- * @throws Exception |
|
466 |
- */ |
|
467 |
- public static String excelSave(List<Issue> resultList, String pageName) |
|
468 |
- throws Exception { |
|
469 |
- String excelFile = pageName + "_" + JodaDateUtil.today().getTime() |
|
470 |
- + ".xls"; |
|
471 |
- String fullPath = "public/uploadFiles/" + excelFile; |
|
472 |
- WritableWorkbook workbook = null; |
|
473 |
- WritableSheet sheet = null; |
|
603 |
+ String[] labalArr = { "ID", "STATE", "TITLE", "ASSIGNEE", "DATE" }; |
|
474 | 604 |
|
475 |
- try { |
|
476 |
- WritableFont wf1 = new WritableFont(WritableFont.TIMES, 13, |
|
477 |
- WritableFont.BOLD, false, UnderlineStyle.SINGLE, |
|
478 |
- Colour.BLUE_GREY, ScriptStyle.NORMAL_SCRIPT); |
|
479 |
- WritableCellFormat cf1 = new WritableCellFormat(wf1); |
|
605 |
+ for (int i = 0; i < labalArr.length; i++) { |
|
606 |
+ sheet.addCell(new Label(i, 0, labalArr[i], cf1)); |
|
607 |
+ sheet.setColumnView(i, 20); |
|
608 |
+ } |
|
609 |
+ for (int i = 1; i < resultList.size() + 1; i++) { |
|
610 |
+ Issue issue = (Issue) resultList.get(i - 1); |
|
611 |
+ int colcnt = 0; |
|
612 |
+ sheet.addCell(new Label(colcnt++, i, issue.id.toString(), cf2)); |
|
613 |
+ sheet.addCell(new Label(colcnt++, i, issue.state.toString(), cf2)); |
|
614 |
+ sheet.addCell(new Label(colcnt++, i, issue.title, cf2)); |
|
615 |
+ sheet.addCell(new Label(colcnt++, i, getAssigneeName(issue.assigneeId), cf2)); |
|
616 |
+ sheet.addCell(new Label(colcnt++, i, issue.date.toString(), cf2)); |
|
617 |
+ } |
|
618 |
+ workbook.write(); |
|
619 |
+ } catch (Exception e) { |
|
620 |
+ e.printStackTrace(); |
|
621 |
+ throw e; |
|
622 |
+ } finally { |
|
623 |
+ try { |
|
624 |
+ if (workbook != null) |
|
625 |
+ workbook.close(); |
|
626 |
+ } catch (WriteException e) { |
|
627 |
+ e.printStackTrace(); |
|
628 |
+ } catch (IOException e) { |
|
629 |
+ e.printStackTrace(); |
|
630 |
+ } |
|
631 |
+ } |
|
632 |
+ return excelFile; |
|
633 |
+ } |
|
480 | 634 |
|
481 |
- cf1.setBorder(Border.ALL, BorderLineStyle.DOUBLE); |
|
635 |
+ /** |
|
636 |
+ * excelSave에서 assignee를 리턴해준다. |
|
637 |
+ * |
|
638 |
+ * @param uId |
|
639 |
+ * @return |
|
640 |
+ */ |
|
641 |
+ private static String getAssigneeName(Long uId) { |
|
642 |
+ return (uId != null ? User.findNameById(uId) : TO_BE_ASSIGNED); |
|
643 |
+ } |
|
482 | 644 |
|
483 |
- cf1.setAlignment(Alignment.CENTRE); |
|
645 |
+ // FIXME 이것이 없이 테스트는 잘 작동하나, view에서 댓글이 달린 이슈들을 필터링하는 라디오버튼을 작동시에 이 메쏘드에서 |
|
646 |
+ // 시행하는 동기화 작업 없이는 작동을 하지 않는다. |
|
484 | 647 |
|
485 |
- WritableFont wf2 = new WritableFont(WritableFont.TAHOMA, 11, |
|
486 |
- WritableFont.NO_BOLD, false, UnderlineStyle.NO_UNDERLINE, |
|
487 |
- Colour.BLACK, ScriptStyle.NORMAL_SCRIPT); |
|
488 |
- WritableCellFormat cf2 = new WritableCellFormat(wf2); |
|
489 |
- cf2.setShrinkToFit(true); |
|
490 |
- cf2.setBorder(Border.ALL, BorderLineStyle.THIN); |
|
491 |
- cf2.setAlignment(Alignment.CENTRE); |
|
648 |
+ /** |
|
649 |
+ * comment가 delete되거나 create될 때, numOfComment와 comment.size()를 동기화 시켜준다. |
|
650 |
+ * |
|
651 |
+ * @param id |
|
652 |
+ */ |
|
653 |
+ public static void updateNumOfComments(Long id) { |
|
492 | 654 |
|
493 |
- workbook = Workbook.createWorkbook(new File(fullPath)); |
|
494 |
- sheet = workbook.createSheet( |
|
495 |
- String.valueOf(JodaDateUtil.today().getTime()), 0); |
|
655 |
+ Issue issue = Issue.findById(id); |
|
656 |
+ issue.numOfComments = issue.comments.size(); |
|
657 |
+ issue.update(); |
|
658 |
+ } |
|
496 | 659 |
|
497 |
- String[] labalArr = { "ID", "STATE", "TITLE", "ASSIGNEE", "DATE" }; |
|
498 |
- |
|
499 |
- for (int i = 0; i < labalArr.length; i++) { |
|
500 |
- sheet.addCell(new Label(i, 0, labalArr[i], cf1)); |
|
501 |
- sheet.setColumnView(i, 20); |
|
502 |
- } |
|
503 |
- for (int i = 1; i < resultList.size() + 1; i++) { |
|
504 |
- Issue issue = (Issue) resultList.get(i - 1); |
|
505 |
- int colcnt = 0; |
|
506 |
- sheet.addCell(new Label(colcnt++, i, issue.id.toString(), cf2)); |
|
507 |
- sheet.addCell(new Label(colcnt++, i, issue.state.toString(), |
|
508 |
- cf2)); |
|
509 |
- sheet.addCell(new Label(colcnt++, i, issue.title, cf2)); |
|
510 |
- sheet.addCell(new Label(colcnt++, i, |
|
511 |
- getAssigneeName(issue.assigneeId), cf2)); |
|
512 |
- sheet.addCell(new Label(colcnt++, i, issue.date.toString(), cf2)); |
|
513 |
- } |
|
514 |
- workbook.write(); |
|
515 |
- } catch (Exception e) { |
|
516 |
- e.printStackTrace(); |
|
517 |
- throw e; |
|
518 |
- } finally { |
|
519 |
- try { |
|
520 |
- if (workbook != null) |
|
521 |
- workbook.close(); |
|
522 |
- } catch (WriteException e) { |
|
523 |
- e.printStackTrace(); |
|
524 |
- } catch (IOException e) { |
|
525 |
- e.printStackTrace(); |
|
526 |
- } |
|
527 |
- } |
|
528 |
- |
|
529 |
- return excelFile; |
|
530 |
- } |
|
531 |
- |
|
532 |
- public String reporterName() { |
|
533 |
- return this.authorName; |
|
534 |
- //return User.findNameById(this.authorId); |
|
535 |
- } |
|
536 |
- |
|
537 |
- /** |
|
538 |
- * issueList, issue view에서 assignee의 이름을 출력해준다. 아래의 getAssigneeName과 합쳐질 수 |
|
539 |
- * 있을듯. |
|
540 |
- */ |
|
541 |
- public String assigneeName() { |
|
542 |
- |
|
543 |
- return (this.assigneeId != null ? User.findNameById(this.assigneeId) |
|
544 |
- : "issue.noAssignee"); |
|
545 |
- } |
|
546 |
- |
|
547 |
- /** |
|
548 |
- * excelSave에서 assignee를 리턴해준다. |
|
549 |
- * |
|
550 |
- * @param uId |
|
551 |
- * @return |
|
552 |
- */ |
|
553 |
- private static String getAssigneeName(Long uId) { |
|
554 |
- return (uId != null ? User.findNameById(uId) : TO_BE_ASSIGNED); |
|
555 |
- } |
|
556 |
- |
|
557 |
- // FIXME 이것이 없이 테스트는 잘 작동하나, view에서 댓글이 달린 이슈들을 필터링하는 라디오버튼을 작동시에 이 메쏘드에서 |
|
558 |
- // 시행하는 동기화 작업 없이는 작동을 하지 않는다. |
|
559 |
- |
|
560 |
- /** |
|
561 |
- * comment가 delete되거나 create될 때, numOfComment와 comment.size()를 동기화 시켜준다. |
|
562 |
- * |
|
563 |
- * @param id |
|
564 |
- */ |
|
565 |
- public static void updateNumOfComments(Long id) { |
|
566 |
- |
|
567 |
- Issue issue = Issue.findById(id); |
|
568 |
- issue.numOfComments = issue.comments.size(); |
|
569 |
- issue.update(); |
|
570 |
- } |
|
571 |
- |
|
572 |
- public static boolean isAuthor(Long currentUserId, Long id) { |
|
573 |
- int findRowCount = find.where().eq("authorId", currentUserId) |
|
574 |
- .eq("id", id).findRowCount(); |
|
575 |
- return (findRowCount != 0) ? true : false; |
|
576 |
- } |
|
577 |
- |
|
578 |
- public Duration ago() { |
|
579 |
- return JodaDateUtil.ago(this.date); |
|
580 |
- } |
|
581 |
- |
|
582 |
- /** |
|
583 |
- * 전체 컨텐츠 검색할 때 제목과 내용에 condition.filter를 포함하고 있는 이슈를 검색한다. |
|
584 |
- * |
|
585 |
- * @param project |
|
586 |
- * @param condition |
|
587 |
- * @return |
|
588 |
- */ |
|
589 |
- public static Page<Issue> findIssues(Project project, |
|
590 |
- SearchApp.ContentSearchCondition condition) { |
|
591 |
- String filter = condition.filter; |
|
592 |
- return find.where().eq("project.id", project.id) |
|
593 |
- .or(contains("title", filter), contains("body", filter)) |
|
594 |
- .findPagingList(condition.pageSize).getPage(condition.page - 1); |
|
595 |
- } |
|
596 |
- // ======= |
|
597 |
- // public boolean isAuthor(Long currentUserId, Long objectId, String |
|
598 |
- // projectName) { |
|
599 |
- // |
|
600 |
- // boolean authorIs; |
|
601 |
- // if (currentUserId == findById(objectId).reporterId |
|
602 |
- // || RoleCheck.roleCheck(currentUserId, project.id, |
|
603 |
- // PermissionResource.PROJECT.resource(), |
|
604 |
- // PermissionOperation.SETTING.operation())) { |
|
605 |
- // authorIs = true; |
|
606 |
- // } else { |
|
607 |
- // |
|
608 |
- // } |
|
609 |
- // |
|
610 |
- // return authorIs; |
|
611 |
- // |
|
612 |
- // } |
|
613 |
- // >>>>>>> Stashed changes |
|
660 |
+ /** |
|
661 |
+ * 전체 컨텐츠 검색할 때 제목과 내용에 condition.filter를 포함하고 있는 이슈를 검색한다. |
|
662 |
+ * |
|
663 |
+ * @param project |
|
664 |
+ * @param condition |
|
665 |
+ * @return |
|
666 |
+ */ |
|
667 |
+ public static Page<Issue> findIssues(Project project, SearchApp.ContentSearchCondition condition) { |
|
668 |
+ String filter = condition.filter; |
|
669 |
+ return find.where().eq("project.id", project.id) |
|
670 |
+ .or(contains("title", filter), contains("body", filter)) |
|
671 |
+ .findPagingList(condition.pageSize).getPage(condition.page - 1); |
|
672 |
+ } |
|
614 | 673 |
} |
--- app/views/issue/issue.scala.html
+++ app/views/issue/issue.scala.html
... | ... | @@ -125,10 +125,13 @@ |
125 | 125 |
<input type="hidden" value="@issue.title" name="title"/> |
126 | 126 |
<input type="hidden" value="@issue.body" name="body"/> |
127 | 127 |
<input type="hidden" value="@issue.authorId" name="authorId"/> |
128 |
- <input type="submit" class="btn pull-right" value=@Messages("button.save") /> |
|
128 |
+ <div class = "btn pull-right"> |
|
129 |
+ <input type="submit" value=@Messages("button.save") /> |
|
130 |
+ <input type="button" id=makeFinished value="이슈 해결" /> |
|
131 |
+ </div> |
|
129 | 132 |
} |
130 | 133 |
} |
131 |
- |
|
134 |
+ |
|
132 | 135 |
</div> |
133 | 136 |
<!-- 여기서 부터 덧글 --> |
134 | 137 |
@for(comment <- issue.comments){ |
--- app/views/issue/newIssue.scala.html
+++ app/views/issue/newIssue.scala.html
... | ... | @@ -15,7 +15,7 @@ |
15 | 15 |
</div> |
16 | 16 |
@form(action = routes.IssueApp.saveIssue(project.owner, project.name), |
17 | 17 |
'enctype -> "multipart/form-data", |
18 |
- 'class -> "form-horizontal"){ |
|
18 |
+ 'class -> "horizontal form-horizontal") { |
|
19 | 19 |
<fieldset> |
20 | 20 |
@inputText( |
21 | 21 |
issueForm("title"), |
... | ... | @@ -26,8 +26,9 @@ |
26 | 26 |
'_showConstraints -> false, |
27 | 27 |
'_label-> Messages("label.contents")) |
28 | 28 |
</fieldset> |
29 |
+ |
|
29 | 30 |
<i class = "icon-file"></i>@Messages("post.new.fileAttach") <a id="fileUpload" data-toggle="modal" href="#askFilePath" class="btn">@Messages("button.selectFile")</a> |
30 |
- <div class="modal hide" id="askFilePath"> |
|
31 |
+ <div class="modal hide" id="askFilePath"> |
|
31 | 32 |
<div class="modal-header"> |
32 | 33 |
<button type="button" class="close" data-dismiss="modal">@Messages("button.popup.exit")</button> |
33 | 34 |
<h3>@Messages("post.popup.fileAttach.title")</h3> |
... | ... | @@ -40,11 +41,12 @@ |
40 | 41 |
<a href="#" class="btn" data-dismiss="modal">@Messages("button.cancel")</a> |
41 | 42 |
<a href="#" class="btn btn-primary" data-dismiss="modal">@Messages("button.confirm")</a> |
42 | 43 |
</div> |
43 |
- </div> |
|
44 |
- </br></Sbr> |
|
44 |
+ </div> |
|
45 |
+ </br></br> |
|
46 |
+ |
|
45 | 47 |
<fieldset> |
46 | 48 |
<div class="well"> |
47 |
- <h4> @Messages("issue.new.environment")</h4> |
|
49 |
+ <legend><b>@Messages("issue.new.environment")</b></legend> |
|
48 | 50 |
<div class="well form-inline"> |
49 | 51 |
@selectEx( |
50 | 52 |
issueForm("osType"), |
... | ... | @@ -68,9 +70,10 @@ |
68 | 70 |
</div> |
69 | 71 |
</div> |
70 | 72 |
</fieldset> |
73 |
+ |
|
71 | 74 |
<fieldset> |
72 | 75 |
<div class="well"> |
73 |
- <h4>@Messages("issue.new.detailInfo")</h4> |
|
76 |
+ <legend><b>@Messages("issue.new.detailInfo")</b></legend> |
|
74 | 77 |
<div class="well form-inline"> |
75 | 78 |
@isVisible(models.enumeration.Resource.ISSUE_CATEGORY) { |
76 | 79 |
@selectEx( |
... | ... | @@ -111,7 +114,7 @@ |
111 | 114 |
</fieldset> |
112 | 115 |
<fieldset> |
113 | 116 |
<div class="well"> |
114 |
- <h4> @Messages("issue.new.result")</h4> |
|
117 |
+ <legend><b>@Messages("issue.new.result")</b></legend> |
|
115 | 118 |
<div class="well form-inline"> |
116 | 119 |
@isVisible(models.enumeration.Resource.ISSUE_IMPORTANCE) { |
117 | 120 |
@selectEx( |
... | ... | @@ -132,7 +135,7 @@ |
132 | 135 |
</div> |
133 | 136 |
</div> |
134 | 137 |
</fieldset> |
135 |
- } |
|
138 |
+ |
|
136 | 139 |
<div class="row pull-right"> |
137 | 140 |
<div class="actions"> |
138 | 141 |
<input type="submit" class="btn btn-primary" value="@Messages("button.save")"> |
... | ... | @@ -140,4 +143,4 @@ |
140 | 143 |
</div> |
141 | 144 |
</div> |
142 | 145 |
} |
143 |
- |
|
146 |
+}(No newline at end of file) |
--- app/views/selectEx.scala.html
+++ app/views/selectEx.scala.html
... | ... | @@ -1,5 +1,7 @@ |
1 | 1 |
@(field: play.api.data.Field, options: Seq[(String,String)], args: (Symbol,Any)*) |
2 | 2 |
@import helper.input |
3 |
+@import helper.FieldConstructor |
|
4 |
+@implicitFieldConstructor = @{ FieldConstructor(twitterBootstrapInput.render) } |
|
3 | 5 |
|
4 | 6 |
@input(field, args:_*) { (id, name, value, htmlArgs) => |
5 | 7 |
<select id="@id" name="@name" @toHtmlArgs(htmlArgs)> |
--- test/models/IssueTest.java
+++ test/models/IssueTest.java
... | ... | @@ -1,19 +1,20 @@ |
1 | 1 |
package models; |
2 | 2 |
|
3 |
-import com.avaje.ebean.Page; |
|
4 |
-import controllers.SearchApp; |
|
3 |
+import static org.fest.assertions.Assertions.assertThat; |
|
4 |
+ |
|
5 |
+import java.util.List; |
|
6 |
+ |
|
5 | 7 |
import models.enumeration.IssueState; |
6 | 8 |
import models.enumeration.StateType; |
9 |
+ |
|
7 | 10 |
import org.junit.Ignore; |
8 | 11 |
import org.junit.Test; |
9 | 12 |
|
10 |
-import play.Logger; |
|
11 | 13 |
import utils.JodaDateUtil; |
12 | 14 |
|
13 |
-import java.io.File; |
|
14 |
-import java.util.List; |
|
15 |
+import com.avaje.ebean.Page; |
|
15 | 16 |
|
16 |
-import static org.fest.assertions.Assertions.assertThat; |
|
17 |
+import controllers.SearchApp; |
|
17 | 18 |
|
18 | 19 |
public class IssueTest extends ModelTest<Issue> { |
19 | 20 |
|
... | ... | @@ -26,6 +27,7 @@ |
26 | 27 |
issue.state = IssueState.ASSIGNED; |
27 | 28 |
issue.authorId = User.findById(1l).id; |
28 | 29 |
issue.milestoneId = 4l; |
30 |
+ issue.issueType = "issue.new.detailInfo.issueType.worst"; |
|
29 | 31 |
// When |
30 | 32 |
// Then |
31 | 33 |
assertThat(Issue.create(issue)).isNotNull(); |
... | ... | @@ -171,22 +173,6 @@ |
171 | 173 |
assertThat(Issue.findById(3l).numOfComments).isEqualTo(0); |
172 | 174 |
} |
173 | 175 |
|
174 |
- @Test |
|
175 |
- @Ignore |
|
176 |
- public void isAuthor() throws Exception { |
|
177 |
- // Given |
|
178 |
- Long currentUserId_hobi = 2l; |
|
179 |
- Long issueId1 = 1l; |
|
180 |
- Long issueId2 = 2l; |
|
181 |
- // When |
|
182 |
- boolean result1 = Issue.isAuthor(currentUserId_hobi, issueId1); |
|
183 |
- boolean result2 = Issue.isAuthor(currentUserId_hobi, issueId2); |
|
184 |
- // Then |
|
185 |
- assertThat(result1).isEqualTo(true); |
|
186 |
- assertThat(result2).isEqualTo(false); |
|
187 |
- |
|
188 |
- } |
|
189 |
- |
|
190 | 176 |
@Test |
191 | 177 |
public void findIssues() { |
192 | 178 |
// Given |
--- test/models/MilestoneTest.java
+++ test/models/MilestoneTest.java
... | ... | @@ -245,7 +245,7 @@ |
245 | 245 |
public void updateIssue() throws Exception { |
246 | 246 |
//Given |
247 | 247 |
Issue issue = new Issue(); |
248 |
- issue.updateStatusType(IssueState.ENROLLED); |
|
248 |
+ issue.updateStateType(issue); |
|
249 | 249 |
issue.milestoneId = 6l; |
250 | 250 |
issue.update(5l); |
251 | 251 |
|
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?