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

Merge branch 'improve/issue-926-notimail-html-template' of dlab/hive
from pull request 1172
@78b2db1d45dc24e731c32c728fa1864f183560d9
--- app/assets/stylesheets/less/_yobiUI.less
+++ app/assets/stylesheets/less/_yobiUI.less
... | ... | @@ -290,14 +290,14 @@ |
290 | 290 |
.fake-file-wrap { |
291 | 291 |
position: relative; display:block; clear:both; |
292 | 292 |
overflow: hidden; cursor:pointer; |
293 |
- width:70px; /*margin-top:10px;*/ |
|
294 | 293 |
&:hover { |
295 | 294 |
background:darken(@white, 10%); |
296 | 295 |
} |
297 | 296 |
|
298 | 297 |
.file { |
299 | 298 |
position: absolute; z-index:2; cursor:pointer; |
300 |
- top:0; left: 5px; /*-15px;*/ width:100px; |
|
299 |
+ top:0; left: 5px; /*-15px;*/ |
|
300 |
+ min-width:100px; width:100%; |
|
301 | 301 |
.opacity(0); |
302 | 302 |
} |
303 | 303 |
} |
--- app/controllers/UserApp.java
+++ app/controllers/UserApp.java
... | ... | @@ -42,10 +42,7 @@ |
42 | 42 |
import play.mvc.*; |
43 | 43 |
import play.mvc.Http.Cookie; |
44 | 44 |
import utils.*; |
45 |
-import views.html.user.edit; |
|
46 |
-import views.html.user.login; |
|
47 |
-import views.html.user.signup; |
|
48 |
-import views.html.user.view; |
|
45 |
+import views.html.user.*; |
|
49 | 46 |
|
50 | 47 |
import java.util.*; |
51 | 48 |
|
... | ... | @@ -563,6 +560,52 @@ |
563 | 560 |
} |
564 | 561 |
|
565 | 562 |
@With(AnonymousCheckAction.class) |
563 |
+ public static Result editUserInfoByTabForm(String tabId) { |
|
564 |
+ User user = UserApp.currentUser(); |
|
565 |
+ Form<User> userForm = new Form<>(User.class); |
|
566 |
+ userForm = userForm.fill(user); |
|
567 |
+ |
|
568 |
+ switch(UserInfoFormTabType.fromString(tabId)){ |
|
569 |
+ case PASSWORD: |
|
570 |
+ return ok(edit_password.render(userForm, user)); |
|
571 |
+ case NOTIFICATIONS: |
|
572 |
+ return ok(edit_notifications.render(userForm, user)); |
|
573 |
+ case EMAILS: |
|
574 |
+ return ok(edit_emails.render(userForm, user)); |
|
575 |
+ default: |
|
576 |
+ case PROFILE: |
|
577 |
+ return ok(edit.render(userForm, user)); |
|
578 |
+ } |
|
579 |
+ } |
|
580 |
+ |
|
581 |
+ private enum UserInfoFormTabType { |
|
582 |
+ PROFILE("profile"), |
|
583 |
+ PASSWORD("password"), |
|
584 |
+ NOTIFICATIONS("notifications"), |
|
585 |
+ EMAILS("emails"); |
|
586 |
+ |
|
587 |
+ private String tabId; |
|
588 |
+ |
|
589 |
+ UserInfoFormTabType(String tabId) { |
|
590 |
+ this.tabId = tabId; |
|
591 |
+ } |
|
592 |
+ |
|
593 |
+ public String value(){ |
|
594 |
+ return tabId; |
|
595 |
+ } |
|
596 |
+ |
|
597 |
+ public static UserInfoFormTabType fromString(String text) |
|
598 |
+ throws IllegalArgumentException { |
|
599 |
+ for(UserInfoFormTabType tab : UserInfoFormTabType.values()){ |
|
600 |
+ if (tab.value().equalsIgnoreCase(text)) { |
|
601 |
+ return tab; |
|
602 |
+ } |
|
603 |
+ } |
|
604 |
+ throw new IllegalArgumentException("Invalid tabId"); |
|
605 |
+ } |
|
606 |
+ } |
|
607 |
+ |
|
608 |
+ @With(AnonymousCheckAction.class) |
|
566 | 609 |
@Transactional |
567 | 610 |
public static Result editUserInfo() { |
568 | 611 |
Form<User> userForm = new Form<>(User.class).bindFromRequest("name", "email"); |
--- app/controllers/WatchApp.java
+++ app/controllers/WatchApp.java
... | ... | @@ -27,7 +27,11 @@ |
27 | 27 |
import models.resource.ResourceParam; |
28 | 28 |
import play.mvc.Controller; |
29 | 29 |
import play.mvc.Result; |
30 |
+import play.i18n.Messages; |
|
30 | 31 |
import utils.AccessControl; |
32 |
+import utils.HttpUtil; |
|
33 |
+import utils.RouteUtil; |
|
34 |
+import org.apache.commons.lang3.StringUtils; |
|
31 | 35 |
|
32 | 36 |
public class WatchApp extends Controller { |
33 | 37 |
public static Result watch(ResourceParam resourceParam) { |
... | ... | @@ -57,6 +61,34 @@ |
57 | 61 |
|
58 | 62 |
Watch.unwatch(user, resource); |
59 | 63 |
|
60 |
- return ok(); |
|
64 |
+ if (HttpUtil.isJSONPreferred(request())) { |
|
65 |
+ return ok(); |
|
66 |
+ } else { |
|
67 |
+ String message = getUnwatchMessage(resource); |
|
68 |
+ |
|
69 |
+ if(!StringUtils.isEmpty(message)) { |
|
70 |
+ flash(utils.Constants.SUCCESS, message); |
|
71 |
+ } |
|
72 |
+ |
|
73 |
+ return redirect(RouteUtil.getUrl(resource.getType(), resource.getId())); |
|
74 |
+ } |
|
75 |
+ } |
|
76 |
+ |
|
77 |
+ private static String getUnwatchMessage(Resource resource){ |
|
78 |
+ switch(resource.getType()) { |
|
79 |
+ case ISSUE_POST: |
|
80 |
+ case ISSUE_COMMENT: |
|
81 |
+ return Messages.get("issue.unwatch.start"); |
|
82 |
+ case BOARD_POST: |
|
83 |
+ case NONISSUE_COMMENT: |
|
84 |
+ return Messages.get("post.unwatch.start"); |
|
85 |
+ case PULL_REQUEST: |
|
86 |
+ case REVIEW_COMMENT: |
|
87 |
+ return Messages.get("pullRequest.unwatch.start"); |
|
88 |
+ case PROJECT: |
|
89 |
+ return Messages.get("project.unwatch.start"); |
|
90 |
+ default: |
|
91 |
+ return ""; |
|
92 |
+ } |
|
61 | 93 |
} |
62 | 94 |
} |
--- app/models/NotificationMail.java
+++ app/models/NotificationMail.java
... | ... | @@ -22,6 +22,7 @@ |
22 | 22 |
|
23 | 23 |
import info.schleichardt.play2.mailplugin.Mailer; |
24 | 24 |
import models.enumeration.UserState; |
25 |
+import models.resource.Resource; |
|
25 | 26 |
import org.apache.commons.lang.exception.ExceptionUtils; |
26 | 27 |
import org.apache.commons.mail.HtmlEmail; |
27 | 28 |
import org.joda.time.DateTime; |
... | ... | @@ -191,7 +192,7 @@ |
191 | 192 |
String reference = Url.removeFragment(event.getUrlToView()); |
192 | 193 |
|
193 | 194 |
email.setSubject(event.title); |
194 |
- email.setHtmlMsg(getHtmlMessage(lang, message, urlToView)); |
|
195 |
+ email.setHtmlMsg(getHtmlMessage(lang, message, urlToView, event.getResource())); |
|
195 | 196 |
email.setTextMsg(getPlainMessage(lang, message, urlToView)); |
196 | 197 |
email.setCharset("utf-8"); |
197 | 198 |
email.addHeader("References", "<" + reference + "@" + Config.getHostname() + ">"); |
... | ... | @@ -207,9 +208,21 @@ |
207 | 208 |
} |
208 | 209 |
} |
209 | 210 |
|
210 |
- private static String getHtmlMessage(Lang lang, String message, String urlToView) { |
|
211 |
- Document doc = Jsoup.parse(Markdown.render(message)); |
|
211 |
+ private static String getHtmlMessage(Lang lang, String message, String urlToView, Resource resource) { |
|
212 |
+ String content = getRenderedHTMLWithTemplate(lang, Markdown.render(message), urlToView, resource); |
|
213 |
+ Document doc = Jsoup.parse(content); |
|
212 | 214 |
|
215 |
+ handleLinks(doc); |
|
216 |
+ handleImages(doc); |
|
217 |
+ |
|
218 |
+ return doc.html(); |
|
219 |
+ } |
|
220 |
+ |
|
221 |
+ private static String getRenderedHTMLWithTemplate(Lang lang, String message, String urlToView, Resource resource){ |
|
222 |
+ return views.html.common.notificationMail.render(lang, message, urlToView, resource).toString(); |
|
223 |
+ } |
|
224 |
+ |
|
225 |
+ private static void handleLinks(Document doc){ |
|
213 | 226 |
String[] attrNames = {"src", "href"}; |
214 | 227 |
for (String attrName : attrNames) { |
215 | 228 |
Elements tags = doc.select("*[" + attrName + "]"); |
... | ... | @@ -224,15 +237,6 @@ |
224 | 237 |
} |
225 | 238 |
} |
226 | 239 |
} |
227 |
- |
|
228 |
- handleImages(doc); |
|
229 |
- |
|
230 |
- if (urlToView != null) { |
|
231 |
- doc.body().append(String.format("<hr><a href=\"%s\">%s</a>", urlToView, |
|
232 |
- Messages.get(lang, "notification.linkToView", utils.Config.getSiteName()))); |
|
233 |
- } |
|
234 |
- |
|
235 |
- return doc.html(); |
|
236 | 240 |
} |
237 | 241 |
|
238 | 242 |
private static void handleImages(Document doc){ |
... | ... | @@ -252,5 +256,4 @@ |
252 | 256 |
|
253 | 257 |
return msg; |
254 | 258 |
} |
255 |
- |
|
256 | 259 |
} |
+++ app/views/common/notificationMail.scala.html
... | ... | @@ -0,0 +1,42 @@ |
1 | +@** | |
2 | +* Yobi, Project Hosting SW | |
3 | +* | |
4 | +* Copyright 2014 NAVER Corp. | |
5 | +* http://yobi.io | |
6 | +* | |
7 | +* @Author Jihan Kim | |
8 | +* | |
9 | +* Licensed under the Apache License, Version 2.0 (the "License"); | |
10 | +* you may not use this file except in compliance with the License. | |
11 | +* You may obtain a copy of the License at | |
12 | +* | |
13 | +* http://www.apache.org/licenses/LICENSE-2.0 | |
14 | +* | |
15 | +* Unless required by applicable law or agreed to in writing, software | |
16 | +* distributed under the License is distributed on an "AS IS" BASIS, | |
17 | +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
18 | +* See the License for the specific language governing permissions and | |
19 | +* limitations under the License. | |
20 | +**@ | |
21 | +@(userLanguage:Lang, message:String, urlToView:String = null, resource:models.resource.Resource) | |
22 | + | |
23 | +@getFooterLinkHTML(link:String, anchorText:String) = { | |
24 | + <a href="@link" target="_blank" style="color:#4399e2; text-decoration:underline;">@anchorText</a> | |
25 | +} | |
26 | + | |
27 | +<div style="font-family:'Helvetica Neue','Helvetica','Arial','나눔고딕','NanumGothic','NanumGothicOTF','Apple SD Gothic Neo','맑은 고딕',sans-serif;"> | |
28 | + @Html(message) | |
29 | +</div> | |
30 | + | |
31 | +<hr style="border:0; border-bottom:1px solid #ddd; margin:20px 0;"> | |
32 | + | |
33 | +@if(urlToView != null){ | |
34 | +<a href="@urlToView" target="_blank"> | |
35 | + @Messages("notification.linkToView", utils.Config.getSiteName()) | |
36 | +</a> | |
37 | +} | |
38 | + | |
39 | +<div style="max-width:410px;margin-top:20px;color:#989898;text-align:justify;word-break:break-all;font-size:11px;font-family:'Helvetica Neue','Helvetica','Arial','나눔고딕','NanumGothic','NanumGothicOTF','Apple SD Gothic Neo','맑은 고딕',sans-serif;"> | |
40 | + @Html(Messages("notification.off.unwatch", getFooterLinkHTML(routes.WatchApp.unwatch(resource.asParameter).toString, Messages("notification.unwatch"))))<br> | |
41 | + @Html(Messages("notification.off.settings", getFooterLinkHTML(routes.UserApp.editUserInfoByTabForm("notifications").toString, Messages("userinfo.changeNotifications")))) | |
42 | +</div> |
--- app/views/user/edit.scala.html
+++ app/views/user/edit.scala.html
... | ... | @@ -31,30 +31,61 @@ |
31 | 31 |
</div> |
32 | 32 |
<div class="page-wrap-outer"> |
33 | 33 |
<div class="page-wrap"> |
34 |
- <ul id="editUserinfo" class="nav nav-tabs mt20"> |
|
35 |
- <li class="active"><a href="#profile" data-toggle="tab">@Messages("userinfo.editProfile")</a></li> |
|
36 |
- <li><a href="#changePassword" data-toggle="tab">@Messages("userinfo.changePassword")</a></li> |
|
37 |
- <li><a href="#watch" data-toggle="tab">@Messages("userinfo.changeNotifications")</a></li> |
|
38 |
- <li><a href="#email" data-toggle="tab">@Messages("userinfo.changeEmails")</a></li> |
|
39 |
- </ul> |
|
34 |
+ @partial_edit_tabmenu("profile") |
|
40 | 35 |
|
41 |
- <div class="tab-content"> |
|
42 |
- <div id="profile" class="tab-pane active"> |
|
43 |
- @partial_edit_profile(user) |
|
44 |
- </div> |
|
36 |
+ <form id="frmBasic" method="post" action="@routes.UserApp.editUserInfo" class="pull-left"> |
|
37 |
+ <dl> |
|
38 |
+ <dt>@Messages("user.name")</dt> |
|
39 |
+ <dd class="mt10"> |
|
40 |
+ <input type="text" name="name" class="text" value="@user.name"> |
|
41 |
+ </dd> |
|
42 |
+ <dt>@Messages("user.email")</dt> |
|
43 |
+ <dd class="mt10"> |
|
44 |
+ <input type="email" name="email" class="text" value="@user.email"> |
|
45 |
+ </dd> |
|
46 |
+ <dd> |
|
47 |
+ <button type="submit" class="ybtn ybtn-success">@Messages("userinfo.editProfile")</button> |
|
48 |
+ </dd> |
|
49 |
+ </dl> |
|
50 |
+ </form> |
|
45 | 51 |
|
46 |
- <div id="email" class="tab-pane"> |
|
47 |
- @partial_edit_email(user) |
|
48 |
- </div> |
|
52 |
+ <form method="post" action="@routes.UserApp.editUserInfo" class="pull-left" style="margin-left:50px; padding-left:50px; border-left:1px solid #ddd;"> |
|
53 |
+ <input type="hidden" name="name" value="@user.name"> |
|
54 |
+ <input type="hidden" name="email" value="@user.email"> |
|
49 | 55 |
|
50 |
- <div id="changePassword" class="tab-pane"> |
|
51 |
- @partial_edit_password(user) |
|
56 |
+ <div class="avatar-frm"> |
|
57 |
+ <div class="avatar-wrap xlarge"> |
|
58 |
+ <img src="@user.avatarUrl" style="width:128px; max-width:none;" /> |
|
59 |
+ <div class="progress"></div> |
|
52 | 60 |
</div> |
61 |
+ <div class="btn-wrap mt10 center-txt"> |
|
62 |
+ <div class="ybtn ybtn-small fake-file-wrap btnUploadAvatar"> |
|
63 |
+ @Messages("userinfo.changeAvatar")<!-- |
|
64 |
+ --><input id="avatarFile" type="file" class="file" name="filePath" accept="image/*"> |
|
65 |
+ </div> |
|
66 |
+ </div> |
|
67 |
+ </div> |
|
68 |
+ </form> |
|
53 | 69 |
|
54 |
- <div id="watch" class="tab-pane"> |
|
55 |
- @partial_edit_watch(user) |
|
70 |
+ <div id="avatarCropWrap" class="modal hide" role="dialog" data-backdrop="static"> |
|
71 |
+ <div class="modal-header center-txt"> |
|
72 |
+ <div class="avatar-wrap xlarge"> |
|
73 |
+ <img style="width:128px; max-width:none;"/> |
|
56 | 74 |
</div> |
75 |
+ </div> |
|
76 |
+ <div class="modal-body"> |
|
77 |
+ <img style="max-width:500px;"> |
|
78 |
+ <canvas width="128" height="128" class="hide"></canvas> |
|
79 |
+ </div> |
|
80 |
+ <div class="modal-footer"> |
|
81 |
+ <button type="button" class="ybtn ybtn-default" data-dismiss="modal">@Messages("button.cancel")</button> |
|
82 |
+ <button type="button" class="ybtn ybtn-success btnSubmitCrop">@Messages("button.save")</button> |
|
83 |
+ </div> |
|
57 | 84 |
</div> |
85 |
+ |
|
86 |
+ <link rel="stylesheet" type="text/css" href="@routes.Assets.at("stylesheets/jcrop/jquery.Jcrop.css")" /> |
|
87 |
+ <script type="text/javascript" src="@routes.Assets.at("javascripts/lib/jquery/jquery.Jcrop.min.js")"></script> |
|
88 |
+ <script type="text/javascript" src="@routes.Assets.at("javascripts/lib/canvas-to-blob.js")"></script> |
|
58 | 89 |
</div> |
59 | 90 |
</div> |
60 | 91 |
<script type="text/javascript"> |
+++ app/views/user/edit_emails.scala.html
... | ... | @@ -0,0 +1,90 @@ |
1 | +@** | |
2 | +* Yobi, Project Hosting SW | |
3 | +* | |
4 | +* Copyright 2014 NAVER Corp. | |
5 | +* http://yobi.io | |
6 | +* | |
7 | +* @Author Jihan Kim | |
8 | +* | |
9 | +* Licensed under the Apache License, Version 2.0 (the "License"); | |
10 | +* you may not use this file except in compliance with the License. | |
11 | +* You may obtain a copy of the License at | |
12 | +* | |
13 | +* http://www.apache.org/licenses/LICENSE-2.0 | |
14 | +* | |
15 | +* Unless required by applicable law or agreed to in writing, software | |
16 | +* distributed under the License is distributed on an "AS IS" BASIS, | |
17 | +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
18 | +* See the License for the specific language governing permissions and | |
19 | +* limitations under the License. | |
20 | +**@ | |
21 | +@(userForm:Form[User], user:User) | |
22 | + | |
23 | +@import helper._ | |
24 | +@import utils.TemplateHelper._ | |
25 | +@import utils.GravatarUtil._ | |
26 | + | |
27 | +@siteLayout(user.loginId, utils.MenuType.USER) { | |
28 | +<div class="site-breadcrumb-outer"> | |
29 | + <div class="site-breadcrumb-inner"> | |
30 | + <h3>@Messages("userinfo.accountSetting")</h3> | |
31 | + </div> | |
32 | +</div> | |
33 | +<div class="page-wrap-outer"> | |
34 | + <div class="page-wrap"> | |
35 | + @partial_edit_tabmenu("emails") | |
36 | + | |
37 | + <form action="@routes.UserApp.addEmail" method="post" class="form-inline inner-bubble"> | |
38 | + <input type="text" placeholder="@Messages("user.email.new")" name="email" class="text uname"> | |
39 | + <button type="submit" class="ybtn ybtn-success">@Messages("button.add")</button> | |
40 | + </form> | |
41 | + | |
42 | + <hr> | |
43 | + | |
44 | + <p> | |
45 | + @Messages("emails.main.email.descr")<br> | |
46 | + @Messages("emails.sub.email.descr") | |
47 | + </p> | |
48 | + | |
49 | + <table class="table mt20"> | |
50 | + <tr> | |
51 | + <td> | |
52 | + <img src="@getAvatar(user.email, 40)" width="40" height="40"> | |
53 | + <strong class="ml10">@user.email</strong> | |
54 | + <span class="label-head vmiddle ml10">@Messages("emails.main.email")</span> | |
55 | + </td> | |
56 | + <td style="text-align:right;"> | |
57 | + </td> | |
58 | + </tr> | |
59 | + | |
60 | + @for(mail <- user.emails){ | |
61 | + <tr> | |
62 | + <td> | |
63 | + <img src="@getAvatar(mail.email, 40)" width="40" height="40"> | |
64 | + <span class="ml10">@mail.email</span> | |
65 | + </td> | |
66 | + <td style="text-align:right; vertical-align: middle;"> | |
67 | + <button type="button" data-request-method="delete" data-request-uri="@routes.UserApp.deleteEmail(mail.id)" class="ybtn ybtn-small ybtn-danger"> | |
68 | + @Messages("button.delete") | |
69 | + </button> | |
70 | + @if(mail.valid) { | |
71 | + <button type="button" data-request-method="put" href="@routes.UserApp.setAsMainEmail(mail.id)" class="ybtn ybtn-small" style="width:150px;"> | |
72 | + @Messages("emails.set.as.main") | |
73 | + </button> | |
74 | + } else { | |
75 | + <button type="button" data-request-method="post" href="@routes.UserApp.sendValidationEmail(mail.id)" class="ybtn ybtn-small" style="width:150px;"> | |
76 | + <i class="yobicon-error2 orange-txt mr5" style="vertical-align: bottom;"></i>@Messages("emails.send.validatino.mail") | |
77 | + </button> | |
78 | + } | |
79 | + </td> | |
80 | + </tr> | |
81 | + } | |
82 | + </table> | |
83 | + </div> | |
84 | +</div> | |
85 | +<script type="text/javascript"> | |
86 | + $(function(){ | |
87 | + $yobi.loadModule("user.Setting"); | |
88 | + }); | |
89 | +</script> | |
90 | +} |
+++ app/views/user/edit_notifications.scala.html
... | ... | @@ -0,0 +1,82 @@ |
1 | +@** | |
2 | +* Yobi, Project Hosting SW | |
3 | +* | |
4 | +* Copyright 2014 NAVER Corp. | |
5 | +* http://yobi.io | |
6 | +* | |
7 | +* @Author Jihan Kim | |
8 | +* | |
9 | +* Licensed under the Apache License, Version 2.0 (the "License"); | |
10 | +* you may not use this file except in compliance with the License. | |
11 | +* You may obtain a copy of the License at | |
12 | +* | |
13 | +* http://www.apache.org/licenses/LICENSE-2.0 | |
14 | +* | |
15 | +* Unless required by applicable law or agreed to in writing, software | |
16 | +* distributed under the License is distributed on an "AS IS" BASIS, | |
17 | +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
18 | +* See the License for the specific language governing permissions and | |
19 | +* limitations under the License. | |
20 | +**@ | |
21 | +@(userForm:Form[User], user:User) | |
22 | + | |
23 | +@import helper._ | |
24 | +@import utils.TemplateHelper._ | |
25 | + | |
26 | +@siteLayout(user.loginId, utils.MenuType.USER) { | |
27 | +<div class="site-breadcrumb-outer"> | |
28 | + <div class="site-breadcrumb-inner"> | |
29 | + <h3>@Messages("userinfo.accountSetting")</h3> | |
30 | + </div> | |
31 | +</div> | |
32 | +<div class="page-wrap-outer"> | |
33 | + <div class="page-wrap"> | |
34 | + @partial_edit_tabmenu("notifications") | |
35 | + | |
36 | + <div> | |
37 | + @defining(UserProjectNotification.getProjectNotifications(user)) { notiMap => | |
38 | + <ul id="notification-projects" class="unstyled lst-stacked span3 mr20"> | |
39 | + @defining(Watch.findBy(user, ResourceType.PROJECT)) { watches => | |
40 | + @if(watches.size > 0) { | |
41 | + @for(i <- 0 until watches.size) { | |
42 | + @defining(Project.find.byId(watches.get(i).resourceId.toLong)) { project => | |
43 | + <li @if(i == 0){class="active"}><a href="#@project.id" data-toggle="tab">@project.owner / @project.name</a></li> | |
44 | + } | |
45 | + } | |
46 | + } | |
47 | + } | |
48 | + </ul> | |
49 | + <div class="tab-content"> | |
50 | + @defining(Watch.findBy(user, ResourceType.PROJECT)) { watches => | |
51 | + @if(watches.size > 0) { | |
52 | + @for(i <- 0 until watches.size) { | |
53 | + @defining(Project.find.byId(watches.get(i).resourceId.toLong)) { project => | |
54 | + <div id="@project.id" class="tab-pane @if(i == 0){active}"> | |
55 | + <table class="table table-striped table-bordered"> | |
56 | + @for(notiType <- models.enumeration.EventType.notiTypes) { | |
57 | + <tr> | |
58 | + <th>@notiType.getDescr</th> | |
59 | + <td> | |
60 | + <div class="switch" data-on-label="On" data-off-label="Off"> | |
61 | + <input class="notiUpdate" data-href="@routes.WatchProjectApp.toggle(project.id, notiType.name())" type="checkbox" data-toggle="switch" @if(UserProjectNotification.isEnabledNotiType(notiMap, project, notiType)){ checked="checked" }> | |
62 | + </div> | |
63 | + </td> | |
64 | + </tr> | |
65 | + } | |
66 | + </table> | |
67 | + </div> | |
68 | + } | |
69 | + } | |
70 | + } | |
71 | + } | |
72 | + </div> | |
73 | + } | |
74 | + </div> | |
75 | + </div> | |
76 | +</div> | |
77 | +<script type="text/javascript"> | |
78 | + $(function(){ | |
79 | + $yobi.loadModule("user.Setting"); | |
80 | + }); | |
81 | +</script> | |
82 | +} |
+++ app/views/user/edit_password.scala.html
... | ... | @@ -0,0 +1,63 @@ |
1 | +@** | |
2 | +* Yobi, Project Hosting SW | |
3 | +* | |
4 | +* Copyright 2014 NAVER Corp. | |
5 | +* http://yobi.io | |
6 | +* | |
7 | +* @Author Jihan Kim | |
8 | +* | |
9 | +* Licensed under the Apache License, Version 2.0 (the "License"); | |
10 | +* you may not use this file except in compliance with the License. | |
11 | +* You may obtain a copy of the License at | |
12 | +* | |
13 | +* http://www.apache.org/licenses/LICENSE-2.0 | |
14 | +* | |
15 | +* Unless required by applicable law or agreed to in writing, software | |
16 | +* distributed under the License is distributed on an "AS IS" BASIS, | |
17 | +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
18 | +* See the License for the specific language governing permissions and | |
19 | +* limitations under the License. | |
20 | +**@ | |
21 | +@(userForm:Form[User], user:User) | |
22 | + | |
23 | +@import helper._ | |
24 | +@import utils.TemplateHelper._ | |
25 | + | |
26 | +@siteLayout(user.loginId, utils.MenuType.USER) { | |
27 | +<div class="site-breadcrumb-outer"> | |
28 | + <div class="site-breadcrumb-inner"> | |
29 | + <h3>@Messages("userinfo.accountSetting")</h3> | |
30 | + </div> | |
31 | +</div> | |
32 | +<div class="page-wrap-outer"> | |
33 | + <div class="page-wrap"> | |
34 | + @partial_edit_tabmenu("password") | |
35 | + | |
36 | + <form id="frmPassword" method="post" action="@routes.UserApp.resetUserPassword"> | |
37 | + <input type="hidden" name="loginId" value="@user.loginId" /> | |
38 | + <dl> | |
39 | + <dt>@Messages("user.currentPassword")</dt> | |
40 | + <dd class="mt10"> | |
41 | + <input type="password" id="oldPassword" name="oldPassword" value="" autocomplete="off" /> | |
42 | + </dd> | |
43 | + <dt>@Messages("user.newPassword")</dt> | |
44 | + <dd class="mt10"> | |
45 | + <input type="password" id="password" name="password" value="" autocomplete="off" /> | |
46 | + </dd> | |
47 | + <dt>@Messages("validation.retypePassword")</dt> | |
48 | + <dd class="mt10"> | |
49 | + <input type="password" id="retypedPassword" name="retypedPassword" value="" autocomplete="off" /> | |
50 | + </dd> | |
51 | + <dd> | |
52 | + <button type="submit" class="ybtn ybtn-success">@Messages("userinfo.changePassword")</button> | |
53 | + </dd> | |
54 | + </dl> | |
55 | + </form> | |
56 | + </div> | |
57 | +</div> | |
58 | +<script type="text/javascript"> | |
59 | + $(function(){ | |
60 | + $yobi.loadModule("user.Setting"); | |
61 | + }); | |
62 | +</script> | |
63 | +} |
--- app/views/user/partial_edit_email.scala.html
... | ... | @@ -1,70 +0,0 @@ |
1 | -@** | |
2 | -* Yobi, Project Hosting SW | |
3 | -* | |
4 | -* Copyright 2014 NAVER Corp. | |
5 | -* http://yobi.io | |
6 | -* | |
7 | -* @Author Jihan Kim | |
8 | -* | |
9 | -* Licensed under the Apache License, Version 2.0 (the "License"); | |
10 | -* you may not use this file except in compliance with the License. | |
11 | -* You may obtain a copy of the License at | |
12 | -* | |
13 | -* http://www.apache.org/licenses/LICENSE-2.0 | |
14 | -* | |
15 | -* Unless required by applicable law or agreed to in writing, software | |
16 | -* distributed under the License is distributed on an "AS IS" BASIS, | |
17 | -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
18 | -* See the License for the specific language governing permissions and | |
19 | -* limitations under the License. | |
20 | -**@ | |
21 | -@(user:User) | |
22 | - | |
23 | -@import utils.GravatarUtil._ | |
24 | - | |
25 | -<form action="@routes.UserApp.addEmail" method="post" class="form-inline inner-bubble"> | |
26 | - <input type="text" placeholder="@Messages("user.email.new")" name="email" class="text uname"> | |
27 | - <button type="submit" class="ybtn ybtn-success">@Messages("button.add")</button> | |
28 | -</form> | |
29 | - | |
30 | -<hr> | |
31 | - | |
32 | -<p> | |
33 | - @Messages("emails.main.email.descr")<br> | |
34 | - @Messages("emails.sub.email.descr") | |
35 | -</p> | |
36 | - | |
37 | -<table class="table mt20"> | |
38 | - <tr> | |
39 | - <td> | |
40 | - <img src="@getAvatar(user.email, 40)" width="40" height="40"> | |
41 | - <strong class="ml10">@user.email</strong> | |
42 | - <span class="label-head vmiddle ml10">@Messages("emails.main.email")</span> | |
43 | - </td> | |
44 | - <td style="text-align:right;"> | |
45 | - </td> | |
46 | - </tr> | |
47 | - | |
48 | - @for(mail <- user.emails){ | |
49 | - <tr> | |
50 | - <td> | |
51 | - <img src="@getAvatar(mail.email, 40)" width="40" height="40"> | |
52 | - <span class="ml10">@mail.email</span> | |
53 | - </td> | |
54 | - <td style="text-align:right; vertical-align: middle;"> | |
55 | - <button type="button" data-request-method="delete" data-request-uri="@routes.UserApp.deleteEmail(mail.id)" class="ybtn ybtn-small ybtn-danger"> | |
56 | - @Messages("button.delete") | |
57 | - </button> | |
58 | - @if(mail.valid) { | |
59 | - <button type="button" data-request-method="put" href="@routes.UserApp.setAsMainEmail(mail.id)" class="ybtn ybtn-small" style="width:150px;"> | |
60 | - @Messages("emails.set.as.main") | |
61 | - </button> | |
62 | - } else { | |
63 | - <button type="button" data-request-method="post" href="@routes.UserApp.sendValidationEmail(mail.id)" class="ybtn ybtn-small" style="width:150px;"> | |
64 | - <i class="yobicon-error2 orange-txt mr5" style="vertical-align: bottom;"></i>@Messages("emails.send.validatino.mail") | |
65 | - </button> | |
66 | - } | |
67 | - </td> | |
68 | - </tr> | |
69 | - } | |
70 | -</table> |
--- app/views/user/partial_edit_password.scala.html
... | ... | @@ -1,42 +0,0 @@ |
1 | -@** | |
2 | -* Yobi, Project Hosting SW | |
3 | -* | |
4 | -* Copyright 2014 NAVER Corp. | |
5 | -* http://yobi.io | |
6 | -* | |
7 | -* @Author Jihan Kim | |
8 | -* | |
9 | -* Licensed under the Apache License, Version 2.0 (the "License"); | |
10 | -* you may not use this file except in compliance with the License. | |
11 | -* You may obtain a copy of the License at | |
12 | -* | |
13 | -* http://www.apache.org/licenses/LICENSE-2.0 | |
14 | -* | |
15 | -* Unless required by applicable law or agreed to in writing, software | |
16 | -* distributed under the License is distributed on an "AS IS" BASIS, | |
17 | -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
18 | -* See the License for the specific language governing permissions and | |
19 | -* limitations under the License. | |
20 | -**@ | |
21 | -@(user:User) | |
22 | - | |
23 | -<form id="frmPassword" method="post" action="@routes.UserApp.resetUserPassword"> | |
24 | - <input type="hidden" name="loginId" value="@user.loginId" /> | |
25 | - <dl> | |
26 | - <dt>@Messages("user.currentPassword")</dt> | |
27 | - <dd class="mt10"> | |
28 | - <input type="password" id="oldPassword" name="oldPassword" value="" autocomplete="off" /> | |
29 | - </dd> | |
30 | - <dt>@Messages("user.newPassword")</dt> | |
31 | - <dd class="mt10"> | |
32 | - <input type="password" id="password" name="password" value="" autocomplete="off" /> | |
33 | - </dd> | |
34 | - <dt>@Messages("validation.retypePassword")</dt> | |
35 | - <dd class="mt10"> | |
36 | - <input type="password" id="retypedPassword" name="retypedPassword" value="" autocomplete="off" /> | |
37 | - </dd> | |
38 | - <dd> | |
39 | - <button type="submit" class="ybtn ybtn-success">@Messages("userinfo.changePassword")</button> | |
40 | - </dd> | |
41 | - </dl> | |
42 | -</form> |
--- app/views/user/partial_edit_profile.scala.html
... | ... | @@ -1,75 +0,0 @@ |
1 | -@** | |
2 | -* Yobi, Project Hosting SW | |
3 | -* | |
4 | -* Copyright 2014 NAVER Corp. | |
5 | -* http://yobi.io | |
6 | -* | |
7 | -* @Author Jihan Kim | |
8 | -* | |
9 | -* Licensed under the Apache License, Version 2.0 (the "License"); | |
10 | -* you may not use this file except in compliance with the License. | |
11 | -* You may obtain a copy of the License at | |
12 | -* | |
13 | -* http://www.apache.org/licenses/LICENSE-2.0 | |
14 | -* | |
15 | -* Unless required by applicable law or agreed to in writing, software | |
16 | -* distributed under the License is distributed on an "AS IS" BASIS, | |
17 | -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
18 | -* See the License for the specific language governing permissions and | |
19 | -* limitations under the License. | |
20 | -**@ | |
21 | -@(user:User) | |
22 | - | |
23 | -<form id="frmBasic" method="post" action="@routes.UserApp.editUserInfo" class="pull-left"> | |
24 | -<dl> | |
25 | - <dt>@Messages("user.name")</dt> | |
26 | - <dd class="mt10"> | |
27 | - <input type="text" name="name" class="text" value="@user.name"> | |
28 | - </dd> | |
29 | - <dt>@Messages("user.email")</dt> | |
30 | - <dd class="mt10"> | |
31 | - <input type="email" name="email" class="text" value="@user.email"> | |
32 | - </dd> | |
33 | - <dd> | |
34 | - <button type="submit" class="ybtn ybtn-success">@Messages("userinfo.editProfile")</button> | |
35 | - </dd> | |
36 | -</dl> | |
37 | -</form> | |
38 | - | |
39 | -<form method="post" action="@routes.UserApp.editUserInfo" class="pull-left" style="margin-left:50px; padding-left:50px; border-left:1px solid #ddd;"> | |
40 | - <input type="hidden" name="name" value="@user.name"> | |
41 | - <input type="hidden" name="email" value="@user.email"> | |
42 | - | |
43 | - <div class="avatar-frm"> | |
44 | - <div class="avatar-wrap xlarge"> | |
45 | - <img src="@user.avatarUrl" style="width:128px; max-width:none;" /> | |
46 | - <div class="progress"></div> | |
47 | - </div> | |
48 | - <div class="btn-wrap mt10 center-txt"> | |
49 | - <div class="ybtn ybtn-small fake-file-wrap btnUploadAvatar"> | |
50 | - @Messages("userinfo.changeAvatar")<!-- | |
51 | - --><input id="avatarFile" type="file" class="file" name="filePath" accept="image/*"> | |
52 | - </div> | |
53 | - </div> | |
54 | - </div> | |
55 | -</form> | |
56 | - | |
57 | -<div id="avatarCropWrap" class="modal hide" role="dialog" data-backdrop="static"> | |
58 | - <div class="modal-header center-txt"> | |
59 | - <div class="avatar-wrap xlarge"> | |
60 | - <img style="width:128px; max-width:none;"/> | |
61 | - </div> | |
62 | - </div> | |
63 | - <div class="modal-body"> | |
64 | - <img style="max-width:500px;"> | |
65 | - <canvas width="128" height="128" class="hide"></canvas> | |
66 | - </div> | |
67 | - <div class="modal-footer"> | |
68 | - <button type="button" class="ybtn ybtn-default" data-dismiss="modal">@Messages("button.cancel")</button> | |
69 | - <button type="button" class="ybtn ybtn-success btnSubmitCrop">@Messages("button.save")</button> | |
70 | - </div> | |
71 | -</div> | |
72 | - | |
73 | -<link rel="stylesheet" type="text/css" href="@routes.Assets.at("stylesheets/jcrop/jquery.Jcrop.css")" /> | |
74 | -<script type="text/javascript" src="@routes.Assets.at("javascripts/lib/jquery/jquery.Jcrop.min.js")"></script> | |
75 | -<script type="text/javascript" src="@routes.Assets.at("javascripts/lib/canvas-to-blob.js")"></script> |
--- app/views/user/partial_edit_watch.scala.html
... | ... | @@ -1,61 +0,0 @@ |
1 | -@** | |
2 | -* Yobi, Project Hosting SW | |
3 | -* | |
4 | -* Copyright 2014 NAVER Corp. | |
5 | -* http://yobi.io | |
6 | -* | |
7 | -* @Author Jihan Kim | |
8 | -* | |
9 | -* Licensed under the Apache License, Version 2.0 (the "License"); | |
10 | -* you may not use this file except in compliance with the License. | |
11 | -* You may obtain a copy of the License at | |
12 | -* | |
13 | -* http://www.apache.org/licenses/LICENSE-2.0 | |
14 | -* | |
15 | -* Unless required by applicable law or agreed to in writing, software | |
16 | -* distributed under the License is distributed on an "AS IS" BASIS, | |
17 | -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
18 | -* See the License for the specific language governing permissions and | |
19 | -* limitations under the License. | |
20 | -**@ | |
21 | -@(user:User) | |
22 | - | |
23 | -@import utils.TemplateHelper._ | |
24 | - | |
25 | -@defining(UserProjectNotification.getProjectNotifications(user)) { notiMap => | |
26 | -<ul class="unstyled lst-stacked span3" style="margin-right: 20px;"> | |
27 | - @defining(Watch.findBy(user, ResourceType.PROJECT)) { watches => | |
28 | - @if(watches.size > 0) { | |
29 | - @for(i <- 0 until watches.size) { | |
30 | - @defining(Project.find.byId(watches.get(i).resourceId.toLong)) { project => | |
31 | - <li @if(i == 0){class="active"}><a href="#@project.id" data-toggle="tab">@project.owner / @project.name</a></li> | |
32 | - } | |
33 | - } | |
34 | - } | |
35 | - } | |
36 | -</ul> | |
37 | -<div class="tab-content"> | |
38 | - @defining(Watch.findBy(user, ResourceType.PROJECT)) { watches => | |
39 | - @if(watches.size > 0) { | |
40 | - @for(i <- 0 until watches.size) { | |
41 | - @defining(Project.find.byId(watches.get(i).resourceId.toLong)) { project => | |
42 | - <div class="tab-pane @if(i == 0){active}" id="@project.id"> | |
43 | - <table class="table table-striped table-bordered"> | |
44 | - @for(notiType <- models.enumeration.EventType.notiTypes) { | |
45 | - <tr> | |
46 | - <th>@notiType.getDescr</th> | |
47 | - <td> | |
48 | - <div class="switch" data-on-label="On" data-off-label="Off"> | |
49 | - <input class="notiUpdate" data-href="@routes.WatchProjectApp.toggle(project.id, notiType.name())" type="checkbox" data-toggle="switch" @if(UserProjectNotification.isEnabledNotiType(notiMap, project, notiType)){ checked="checked" }> | |
50 | - </div> | |
51 | - </td> | |
52 | - </tr> | |
53 | - } | |
54 | - </table> | |
55 | - </div> | |
56 | - } | |
57 | - } | |
58 | - } | |
59 | - } | |
60 | -</div> | |
61 | -} |
--- conf/messages
+++ conf/messages
... | ... | @@ -323,6 +323,8 @@ |
323 | 323 |
notification.member.request.cancel.title = [{0}] {1} cancels the request to be a member. |
324 | 324 |
notification.member.request.title = [{0}] {1} wants to join your project |
325 | 325 |
notification.none = No notification has been received. |
326 |
+notification.off.unwatch = You can {0} or |
|
327 |
+notification.off.settings = change settings at {0} if you want mute this. |
|
326 | 328 |
notification.organization.member.enroll.accept = Joined as a member. |
327 | 329 |
notification.organization.member.enroll.cancel = The request for joining your group has been canceled. |
328 | 330 |
notification.organization.member.enroll.request = Received a request for joining your group. |
... | ... | @@ -358,6 +360,7 @@ |
358 | 360 |
notification.type.pullrequest.state.changed = Pull request Status changed. |
359 | 361 |
notification.type.pullrequest.unreviewed = Pull request review is canceled. |
360 | 362 |
notification.type.review.state.changed = Review Thread State Change |
363 |
+notification.unwatch = Unwatch |
|
361 | 364 |
notification.watch = Watch |
362 | 365 |
notification.will.help = When you watch project, you will receive notifications. |
363 | 366 |
organization.create = Create Group |
... | ... | @@ -541,6 +544,7 @@ |
541 | 544 |
project.transfer.requestion = Do you want to transfer this project? |
542 | 545 |
project.transfer.this = Transfer this project |
543 | 546 |
project.unwatch = Unwatch |
547 |
+project.unwatch.start = Notifications of this project has muted |
|
544 | 548 |
project.vcs = Repository type |
545 | 549 |
project.watch = Watch |
546 | 550 |
project.watching = Watching |
--- conf/messages.ko
+++ conf/messages.ko
... | ... | @@ -323,6 +323,8 @@ |
323 | 323 |
notification.member.request.cancel.title = [{0}] {1} 님이 멤버 요청을 취소하였습니다. |
324 | 324 |
notification.member.request.title = [{0}] {1} 님이 멤버 요청을 보냈습니다. |
325 | 325 |
notification.none = 알림 메시지가 없습니다. |
326 |
+notification.off.unwatch = {0}를 눌러 더 이상 알림을 받지 않거나, |
|
327 |
+notification.off.settings = 알림 수신 여부를 {0}에서 수정하실 수 있습니다. |
|
326 | 328 |
notification.organization.member.enroll.accept = 멤버로 등록됨 |
327 | 329 |
notification.organization.member.enroll.cancel = 멤버 등록 요청이 취소됨 |
328 | 330 |
notification.organization.member.enroll.request = 멤버 등록 요청을 받음 |
... | ... | @@ -358,6 +360,7 @@ |
358 | 360 |
notification.type.pullrequest.state.changed = 코드보내기 상태 변경 |
359 | 361 |
notification.type.pullrequest.unreviewed = 코드보내기 리뷰가 취소되었습니다. |
360 | 362 |
notification.type.review.state.changed = 리뷰 스레드 상태 변경 |
363 |
+notification.unwatch = 그만 지켜보기 |
|
361 | 364 |
notification.watch = 지켜보기 |
362 | 365 |
notification.will.help = 프로젝트를 지켜보면 다음 이벤트가 발생할 때 알림 메시지를 받습니다. |
363 | 366 |
organization.create = 그룹 만들기 |
... | ... | @@ -541,6 +544,7 @@ |
541 | 544 |
project.transfer.requestion = 프로젝트를 이관하시겠습니까? |
542 | 545 |
project.transfer.this = 프로젝트를 이관합니다. |
543 | 546 |
project.unwatch = 그만 지켜보기 |
547 |
+project.unwatch.start = 프로젝트를 더 이상 지켜보지 않습니다 |
|
544 | 548 |
project.vcs = 코드 관리 시스템 |
545 | 549 |
project.watch = 지켜보기 |
546 | 550 |
project.watching = 지켜보기 중 |
--- conf/routes
+++ conf/routes
... | ... | @@ -50,6 +50,7 @@ |
50 | 50 |
GET /users/signupform controllers.UserApp.signupForm() |
51 | 51 |
POST /users/signup controllers.UserApp.newUser() |
52 | 52 |
GET /user/editform controllers.UserApp.editUserInfoForm() |
53 |
+GET /user/editform/:tabId controllers.UserApp.editUserInfoByTabForm(tabId: String) |
|
53 | 54 |
POST /user/edit controllers.UserApp.editUserInfo() |
54 | 55 |
POST /user/resetPassword controllers.UserApp.resetUserPassword() |
55 | 56 |
GET /user/isUsed controllers.UserApp.isUsed(name:String) |
... | ... | @@ -241,6 +242,7 @@ |
241 | 242 |
# Watch |
242 | 243 |
POST /watch controllers.WatchApp.watch(resource: models.resource.ResourceParam) |
243 | 244 |
POST /unwatch controllers.WatchApp.unwatch(resource: models.resource.ResourceParam) |
245 |
+GET /unwatch controllers.WatchApp.unwatch(resource: models.resource.ResourceParam) |
|
244 | 246 |
|
245 | 247 |
# Statistics |
246 | 248 |
GET /:user/:project/statistics controllers.StatisticsApp.statistics(user, project) |
--- public/javascripts/service/yobi.user.Setting.js
+++ public/javascripts/service/yobi.user.Setting.js
... | ... | @@ -37,6 +37,7 @@ |
37 | 37 |
|
38 | 38 |
_initFormValidator(); |
39 | 39 |
_initAvatarUploader(); |
40 |
+ _showNotificationTab(); |
|
40 | 41 |
} |
41 | 42 |
|
42 | 43 |
/** |
... | ... | @@ -396,6 +397,10 @@ |
396 | 397 |
}) |
397 | 398 |
} |
398 | 399 |
|
400 |
+ function _showNotificationTab(){ |
|
401 |
+ $('#notification-projects a[href="' + location.hash + '"]').tab("show"); |
|
402 |
+ } |
|
403 |
+ |
|
399 | 404 |
_init(htOptions || {}); |
400 | 405 |
}; |
401 | 406 |
})("yobi.user.Setting"); |
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?