
notification: Add noti mail send option
User can choose to send modification mail or not
@5f643760bdf65d0145aa5ec6d7b14585e66bf39b
--- app/assets/stylesheets/less/_page.less
+++ app/assets/stylesheets/less/_page.less
... | ... | @@ -6239,3 +6239,16 @@ |
6239 | 6239 |
border-radius: 2px; |
6240 | 6240 |
color: #3592B5; |
6241 | 6241 |
} |
6242 |
+ |
|
6243 |
+.send-notification-check { |
|
6244 |
+ vertical-align: middle; |
|
6245 |
+ padding: 9px; |
|
6246 |
+ border-radius: 3px; |
|
6247 |
+ strong { |
|
6248 |
+ margin-right: 5px; |
|
6249 |
+ } |
|
6250 |
+ .checkbox.inline { |
|
6251 |
+ padding-top: 0px; |
|
6252 |
+ } |
|
6253 |
+} |
|
6254 |
+ |
--- app/controllers/AbstractPostingApp.java
+++ app/controllers/AbstractPostingApp.java
... | ... | @@ -33,6 +33,8 @@ |
33 | 33 |
import play.mvc.*; |
34 | 34 |
import utils.*; |
35 | 35 |
|
36 |
+import java.util.Map; |
|
37 |
+ |
|
36 | 38 |
@AnonymousCheck |
37 | 39 |
public class AbstractPostingApp extends Controller { |
38 | 40 |
public static final int ITEMS_PER_PAGE = 15; |
... | ... | @@ -156,4 +158,18 @@ |
156 | 158 |
} |
157 | 159 |
return StringUtils.isNotBlank(files[0]); |
158 | 160 |
} |
161 |
+ |
|
162 |
+ protected static boolean isSelectedToSendNotificationMail() { |
|
163 |
+ Map<String,String[]> data; |
|
164 |
+ if (isMultiPartFormData()) { |
|
165 |
+ data = request().body().asMultipartFormData().asFormUrlEncoded(); |
|
166 |
+ } else { |
|
167 |
+ data = request().body().asFormUrlEncoded(); |
|
168 |
+ } |
|
169 |
+ return "yes".equalsIgnoreCase(HttpUtil.getFirstValueFromQuery(data, "notificationMail")); |
|
170 |
+ } |
|
171 |
+ |
|
172 |
+ private static boolean isMultiPartFormData() { |
|
173 |
+ return request().body().asMultipartFormData() != null; |
|
174 |
+ } |
|
159 | 175 |
} |
--- app/controllers/BoardApp.java
+++ app/controllers/BoardApp.java
... | ... | @@ -234,6 +234,9 @@ |
234 | 234 |
@Override |
235 | 235 |
public void run() { |
236 | 236 |
post.comments = original.comments; |
237 |
+ if(isSelectedToSendNotificationMail() || !original.isAuthoredBy(UserApp.currentUser())){ |
|
238 |
+ NotificationEvent.afterNewPost(post); |
|
239 |
+ } |
|
237 | 240 |
} |
238 | 241 |
}; |
239 | 242 |
|
... | ... | @@ -294,7 +297,9 @@ |
294 | 297 |
if (existingComment != null) { |
295 | 298 |
existingComment.contents = comment.contents; |
296 | 299 |
savedComment = saveComment(existingComment, getContainerUpdater(posting, comment)); |
297 |
- NotificationEvent.afterCommentUpdated(savedComment); |
|
300 |
+ if(isSelectedToSendNotificationMail() || !existingComment.isAuthoredBy(UserApp.currentUser())){ |
|
301 |
+ NotificationEvent.afterCommentUpdated(savedComment); |
|
302 |
+ } |
|
298 | 303 |
} else { |
299 | 304 |
savedComment = saveComment(comment, getContainerUpdater(posting, comment)); |
300 | 305 |
NotificationEvent.afterNewComment(savedComment); |
--- app/controllers/CommentApp.java
+++ app/controllers/CommentApp.java
... | ... | @@ -21,6 +21,7 @@ |
21 | 21 |
package controllers; |
22 | 22 |
|
23 | 23 |
import controllers.annotation.AnonymousCheck; |
24 |
+import models.Comment; |
|
24 | 25 |
import models.enumeration.Operation; |
25 | 26 |
import models.resource.Resource; |
26 | 27 |
import play.db.ebean.Transactional; |
... | ... | @@ -54,5 +55,8 @@ |
54 | 55 |
} |
55 | 56 |
} |
56 | 57 |
|
58 |
+ public static boolean isCurrentUserTheAuthor(Comment comment){ |
|
59 |
+ return UserApp.currentUser().loginId.equals(comment.authorLoginId); |
|
60 |
+ } |
|
57 | 61 |
|
58 | 62 |
} |
--- app/controllers/IssueApp.java
+++ app/controllers/IssueApp.java
... | ... | @@ -524,9 +524,11 @@ |
524 | 524 |
issue.comments = originalIssue.comments; |
525 | 525 |
addLabels(issue, request()); |
526 | 526 |
|
527 |
- addAssigneeChangedNotification(issue, originalIssue); |
|
528 |
- addStateChangedNotification(issue, originalIssue); |
|
529 |
- addBodyChangedNotification(issue, originalIssue); |
|
527 |
+ if(isSelectedToSendNotificationMail() || !originalIssue.isAuthoredBy(UserApp.currentUser())){ |
|
528 |
+ addAssigneeChangedNotification(issue, originalIssue); |
|
529 |
+ addStateChangedNotification(issue, originalIssue); |
|
530 |
+ addBodyChangedNotification(issue, originalIssue); |
|
531 |
+ } |
|
530 | 532 |
} |
531 | 533 |
}; |
532 | 534 |
|
... | ... | @@ -602,7 +604,9 @@ |
602 | 604 |
if (existingComment != null) { |
603 | 605 |
existingComment.contents = comment.contents; |
604 | 606 |
savedComment = saveComment(existingComment, getContainerUpdater(issue, comment)); |
605 |
- NotificationEvent.afterCommentUpdated(savedComment); |
|
607 |
+ if(isSelectedToSendNotificationMail() || !existingComment.isAuthoredBy(UserApp.currentUser())){ |
|
608 |
+ NotificationEvent.afterCommentUpdated(savedComment); |
|
609 |
+ } |
|
606 | 610 |
} else { |
607 | 611 |
savedComment = saveComment(comment, getContainerUpdater(issue, comment)); |
608 | 612 |
NotificationEvent.afterNewComment(savedComment); |
--- app/models/AbstractPosting.java
+++ app/models/AbstractPosting.java
... | ... | @@ -23,6 +23,7 @@ |
23 | 23 |
import models.enumeration.ResourceType; |
24 | 24 |
import models.resource.Resource; |
25 | 25 |
import models.resource.ResourceConvertible; |
26 |
+import org.apache.commons.lang.StringUtils; |
|
26 | 27 |
import org.joda.time.Duration; |
27 | 28 |
import play.data.format.Formats; |
28 | 29 |
import play.data.validation.Constraints; |
... | ... | @@ -30,6 +31,7 @@ |
30 | 31 |
import play.db.ebean.Transactional; |
31 | 32 |
import utils.JodaDateUtil; |
32 | 33 |
|
34 |
+import javax.annotation.Nonnull; |
|
33 | 35 |
import javax.persistence.*; |
34 | 36 |
import javax.validation.constraints.Size; |
35 | 37 |
import java.util.Date; |
... | ... | @@ -257,4 +259,8 @@ |
257 | 259 |
} |
258 | 260 |
|
259 | 261 |
public abstract void checkLabels() throws IssueLabel.IssueLabelException; |
262 |
+ |
|
263 |
+ public boolean isAuthoredBy(@Nonnull User user){ |
|
264 |
+ return StringUtils.equalsIgnoreCase(this.authorLoginId, user.loginId); |
|
265 |
+ } |
|
260 | 266 |
} |
--- app/models/Comment.java
+++ app/models/Comment.java
... | ... | @@ -23,6 +23,7 @@ |
23 | 23 |
import com.avaje.ebean.annotation.Transactional; |
24 | 24 |
import models.resource.Resource; |
25 | 25 |
import models.resource.ResourceConvertible; |
26 |
+import org.apache.commons.lang.StringUtils; |
|
26 | 27 |
import org.apache.commons.lang3.builder.EqualsBuilder; |
27 | 28 |
import org.apache.commons.lang3.builder.HashCodeBuilder; |
28 | 29 |
import org.joda.time.Duration; |
... | ... | @@ -30,6 +31,7 @@ |
30 | 31 |
import play.db.ebean.Model; |
31 | 32 |
import utils.JodaDateUtil; |
32 | 33 |
|
34 |
+import javax.annotation.Nonnull; |
|
33 | 35 |
import javax.persistence.Id; |
34 | 36 |
import javax.persistence.Lob; |
35 | 37 |
import javax.persistence.MappedSuperclass; |
... | ... | @@ -153,4 +155,8 @@ |
153 | 155 |
.append(authorName) |
154 | 156 |
.toHashCode(); |
155 | 157 |
} |
158 |
+ |
|
159 |
+ public boolean isAuthoredBy(@Nonnull User user){ |
|
160 |
+ return StringUtils.equalsIgnoreCase(this.authorLoginId, user.loginId); |
|
161 |
+ } |
|
156 | 162 |
} |
--- app/views/board/edit.scala.html
+++ app/views/board/edit.scala.html
... | ... | @@ -78,6 +78,14 @@ |
78 | 78 |
</div> |
79 | 79 |
|
80 | 80 |
<div class="actions"> |
81 |
+ @if(posting.getAuthor.equals(UserApp.currentUser()) && !posting.readme){ |
|
82 |
+ <span class="send-notification-check"> |
|
83 |
+ <label class="checkbox inline"> |
|
84 |
+ <input type="checkbox" name="notificationMail" id="notificationMail" value="yes" checked> |
|
85 |
+ <strong>@Messages("notification.send.mail")</strong> |
|
86 |
+ </label> |
|
87 |
+ </span> |
|
88 |
+ } |
|
81 | 89 |
<button class="ybtn ybtn-info" tabindex="3">@Messages("button.save")</button><!-- |
82 | 90 |
--><a href="javascript:history.back();" class="ybtn" tabindex="4">@Messages("button.cancel")</a> |
83 | 91 |
</div> |
--- app/views/board/partial_comments.scala.html
+++ app/views/board/partial_comments.scala.html
... | ... | @@ -63,7 +63,7 @@ |
63 | 63 |
</span> |
64 | 64 |
</div> |
65 | 65 |
|
66 |
- @common.commentUpdateForm(comment.id, routes.BoardApp.newComment(project.owner, project.name, post.getNumber).toString(), comment.contents) |
|
66 |
+ @common.commentUpdateForm(comment, routes.BoardApp.newComment(project.owner, project.name, post.getNumber).toString(), comment.contents) |
|
67 | 67 |
|
68 | 68 |
<div id="comment-body-@comment.id"> |
69 | 69 |
<div class="comment-body markdown-wrap" data-via-email="@OriginalEmail.exists(comment.asResource)">@Html(Markdown.render(comment.contents, project))</div> |
--- app/views/common/commentUpdateForm.scala.html
+++ app/views/common/commentUpdateForm.scala.html
... | ... | @@ -18,18 +18,26 @@ |
18 | 18 |
* See the License for the specific language governing permissions and |
19 | 19 |
* limitations under the License. |
20 | 20 |
**@ |
21 |
-@(commentId:Long, action:String, contents:String) |
|
21 |
+@(comment:Comment, action:String, contents:String) |
|
22 | 22 |
|
23 |
-<div id="comment-editform-@commentId" class="comment-update-form"> |
|
23 |
+<div id="comment-editform-@comment.id" class="comment-update-form"> |
|
24 | 24 |
<form action="@action" method="post"> |
25 |
- <input type="hidden" name="id" value="@commentId"> |
|
25 |
+ <input type="hidden" name="id" value="@comment.id"> |
|
26 | 26 |
|
27 | 27 |
<div class="write-comment-box"> |
28 | 28 |
<div class="write-comment-wrap"> |
29 | 29 |
@common.editor("contents", contents,"", "update-comment-body") |
30 | 30 |
|
31 | 31 |
<div class="right-txt comment-update-button"> |
32 |
- <button type="button" class="ybtn ybtn-cancel" data-comment-id="@commentId">@Messages("button.cancel")</button> |
|
32 |
+ @if(comment.isAuthoredBy(UserApp.currentUser())){ |
|
33 |
+ <span class="send-notification-check" data-toggle='popover' data-trigger="hover" data-placement="top" data-content="@Messages("notification.send.mail.warning")"> |
|
34 |
+ <label class="checkbox inline"> |
|
35 |
+ <input type="checkbox" name="notificationMail" id="notificationMail" value="yes" checked> |
|
36 |
+ <strong>@Messages("notification.send.mail")</strong> |
|
37 |
+ </label> |
|
38 |
+ </span> |
|
39 |
+ } |
|
40 |
+ <button type="button" class="ybtn ybtn-cancel" data-comment-id="@comment.id">@Messages("button.cancel")</button> |
|
33 | 41 |
<button type="submit" class="ybtn ybtn-info">@Messages("button.save")</button> |
34 | 42 |
</div> |
35 | 43 |
</div> |
--- app/views/issue/edit.scala.html
+++ app/views/issue/edit.scala.html
... | ... | @@ -71,6 +71,14 @@ |
71 | 71 |
@** end of fileUploader **@ |
72 | 72 |
|
73 | 73 |
<div class=" actrow right-txt"> |
74 |
+ @if(issue.isAuthoredBy(UserApp.currentUser())){ |
|
75 |
+ <span class="send-notification-check"> |
|
76 |
+ <label class="checkbox inline"> |
|
77 |
+ <input type="checkbox" name="notificationMail" id="notificationMail" value="yes" checked> |
|
78 |
+ <strong>@Messages("notification.send.mail")</strong> |
|
79 |
+ </label> |
|
80 |
+ </span> |
|
81 |
+ } |
|
74 | 82 |
<button type="submit" class="ybtn ybtn-info">@Messages("button.save")</button><!-- |
75 | 83 |
--><a href="javascript:history.back();" class="ybtn">@Messages("button.cancel")</a> |
76 | 84 |
</div> |
--- app/views/issue/partial_comments.scala.html
+++ app/views/issue/partial_comments.scala.html
... | ... | @@ -144,7 +144,7 @@ |
144 | 144 |
</span> |
145 | 145 |
</div> |
146 | 146 |
|
147 |
- @common.commentUpdateForm(comment.id, routes.IssueApp.newComment(project.owner, project.name, issue.getNumber).toString(), comment.contents) |
|
147 |
+ @common.commentUpdateForm(comment, routes.IssueApp.newComment(project.owner, project.name, issue.getNumber).toString(), comment.contents) |
|
148 | 148 |
|
149 | 149 |
<div id="comment-body-@comment.id"> |
150 | 150 |
<div class="comment-body markdown-wrap" data-via-email="@OriginalEmail.exists(comment.asResource)">@Html(Markdown.render(comment.contents, project))</div> |
--- conf/messages
+++ conf/messages
... | ... | @@ -394,6 +394,8 @@ |
394 | 394 |
notification.reviewthread.reopened = Review thread reopened |
395 | 395 |
notification.reviewthread.inTheFile = In {0}: |
396 | 396 |
notification.type.comment.updated = Comment updated |
397 |
+notification.send.mail = Send notification mail |
|
398 |
+notification.send.mail.warning = If you are not original author, this option will be ignored. Noti mail will be sent. |
|
397 | 399 |
notification.type.issue.assignee.changed = Issue assignee changed. |
398 | 400 |
notification.type.issue.body.changed = Issue body changed |
399 | 401 |
notification.type.issue.referred.from.commit = Issue mentioned in commit |
--- conf/messages.ko-KR
+++ conf/messages.ko-KR
... | ... | @@ -393,6 +393,8 @@ |
393 | 393 |
notification.reviewthread.reopened = 리뷰 스레드 다시 열림 |
394 | 394 |
notification.reviewthread.inTheFile = {0} 에서: |
395 | 395 |
notification.type.comment.updated = 댓글 수정 |
396 |
+notification.send.mail = 수정에 대한 알림 메일 발송 |
|
397 |
+notification.send.mail.warning = 만약 해당글의 원 작성자가 아니라면 이 옵션은 무시되고 알림 메일이 발송됩니다. |
|
396 | 398 |
notification.type.issue.assignee.changed = 이슈 담당자 변경 |
397 | 399 |
notification.type.issue.body.changed = 이슈 본문 변경 |
398 | 400 |
notification.type.issue.referred.from.commit = 커밋에서의 이슈 언급 |
--- public/javascripts/common/yobi.Comment.js
+++ public/javascripts/common/yobi.Comment.js
... | ... | @@ -53,6 +53,7 @@ |
53 | 53 |
|
54 | 54 |
$('#comment-editform-' + commentId).toggle(); |
55 | 55 |
$('#comment-body-' + commentId).toggle(); |
56 |
+ $("[data-toggle='popover']").popover(); |
|
56 | 57 |
} |
57 | 58 |
|
58 | 59 |
/** |
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?