signup: Introduce signup email verification
@8c3db373897e1ba89a68f8257255e2e256314453
--- app/controllers/UserApp.java
+++ app/controllers/UserApp.java
... | ... | @@ -49,6 +49,7 @@ |
49 | 49 |
import java.util.*; |
50 | 50 |
|
51 | 51 |
import static com.feth.play.module.mail.Mailer.getEmailName; |
52 |
+import static models.NotificationMail.isAllowedEmailDomains; |
|
52 | 53 |
import static play.data.Form.form; |
53 | 54 |
import static play.libs.Json.toJson; |
54 | 55 |
import static utils.HtmlUtil.defaultSanitize; |
... | ... | @@ -79,6 +80,8 @@ |
79 | 80 |
.getBoolean("application.use.social.login.only", false); |
80 | 81 |
public static final String FLASH_MESSAGE_KEY = "message"; |
81 | 82 |
public static final String FLASH_ERROR_KEY = "error"; |
83 |
+ private static boolean usingEmailVerification = play.Configuration.root() |
|
84 |
+ .getBoolean("application.use.email.verification", false); |
|
82 | 85 |
|
83 | 86 |
@AnonymousCheck |
84 | 87 |
public static Result users(String query) { |
... | ... | @@ -201,7 +204,7 @@ |
201 | 204 |
|
202 | 205 |
User sourceUser = User.findByLoginKey(authInfoForm.get().loginIdOrEmail); |
203 | 206 |
|
204 |
- if (isUseSignUpConfirm()) { |
|
207 |
+ if (isUsingSignUpConfirm()) { |
|
205 | 208 |
if (User.findByLoginId(sourceUser.loginId).state == UserState.LOCKED) { |
206 | 209 |
flash(Constants.WARNING, "user.locked"); |
207 | 210 |
return redirect(getLoginFormURLWithRedirectURL()); |
... | ... | @@ -220,6 +223,10 @@ |
220 | 223 |
authenticate = authenticateWithPlainPassword(sourceUser.loginId, authInfoForm.get().password); |
221 | 224 |
} |
222 | 225 |
|
226 |
+ if(authenticate.isLocked()){ |
|
227 |
+ flash(Constants.WARNING, "user.locked"); |
|
228 |
+ return logout(); |
|
229 |
+ } |
|
223 | 230 |
if (!authenticate.isAnonymous()) { |
224 | 231 |
addUserInfoToSession(authenticate); |
225 | 232 |
|
... | ... | @@ -276,7 +283,7 @@ |
276 | 283 |
|
277 | 284 |
User sourceUser = User.findByLoginKey(authInfoForm.get().loginIdOrEmail); |
278 | 285 |
|
279 |
- if (isUseSignUpConfirm()) { |
|
286 |
+ if (isUsingSignUpConfirm()) { |
|
280 | 287 |
if (User.findByLoginId(sourceUser.loginId).state == UserState.LOCKED) { |
281 | 288 |
return forbidden(getObjectNodeWithMessage("user.locked")); |
282 | 289 |
} |
... | ... | @@ -291,6 +298,10 @@ |
291 | 298 |
user = authenticateWithLdap(authInfoForm.get().loginIdOrEmail, authInfoForm.get().password); |
292 | 299 |
} else { |
293 | 300 |
user = authenticateWithPlainPassword(sourceUser.loginId, authInfoForm.get().password); |
301 |
+ } |
|
302 |
+ |
|
303 |
+ if(user.isLocked()){ |
|
304 |
+ return forbidden(getObjectNodeWithMessage("user.locked")); |
|
294 | 305 |
} |
295 | 306 |
|
296 | 307 |
if (!user.isAnonymous()) { |
... | ... | @@ -364,15 +375,27 @@ |
364 | 375 |
validate(newUserForm); |
365 | 376 |
if (newUserForm.hasErrors()) { |
366 | 377 |
return badRequest(signup.render("title.signup", newUserForm)); |
367 |
- } else { |
|
368 |
- User user = createNewUser(newUserForm.get()); |
|
369 |
- if (user.state == UserState.LOCKED) { |
|
370 |
- flash(Constants.INFO, "user.signup.requested"); |
|
371 |
- } else { |
|
372 |
- addUserInfoToSession(user); |
|
373 |
- } |
|
374 |
- return redirect(routes.Application.index()); |
|
375 | 378 |
} |
379 |
+ |
|
380 |
+ if (!isAllowedEmailDomains(newUserForm.get().email)) { |
|
381 |
+ flash(Constants.INFO, "user.unacceptable.email.domain"); |
|
382 |
+ return badRequest(signup.render("title.signup", newUserForm)); |
|
383 |
+ } |
|
384 |
+ |
|
385 |
+ User user = createNewUser(newUserForm.get()); |
|
386 |
+ if (isUsingEmailVerification()) { |
|
387 |
+ if (isAllowedEmailDomains(user.email)) { |
|
388 |
+ flash(Constants.INFO, "user.verification.mail.sent"); |
|
389 |
+ } else { |
|
390 |
+ flash(Constants.INFO, "user.unacceptable.email.domain"); |
|
391 |
+ } |
|
392 |
+ } |
|
393 |
+ if (user.state == UserState.LOCKED && isUsingSignUpConfirm()) { |
|
394 |
+ flash(Constants.INFO, "user.signup.requested"); |
|
395 |
+ } else { |
|
396 |
+ addUserInfoToSession(user); |
|
397 |
+ } |
|
398 |
+ return redirect(routes.Application.index()); |
|
376 | 399 |
} |
377 | 400 |
|
378 | 401 |
private static String newLoginIdWithoutDup(final String candidate, int num) { |
... | ... | @@ -394,9 +417,18 @@ |
394 | 417 |
forceOAuthLogout(); |
395 | 418 |
return User.anonymous; |
396 | 419 |
} |
420 |
+ if (!isAllowedEmailDomains(userCredential.email)) { |
|
421 |
+ flash(Constants.INFO, "user.unacceptable.email.domain"); |
|
422 |
+ userCredential.delete(); |
|
423 |
+ forceOAuthLogout(); |
|
424 |
+ return User.anonymous; |
|
425 |
+ } |
|
397 | 426 |
User created = createUserDelegate(userCredential.name, userCredential.email, null); |
398 | 427 |
|
399 |
- if (created.state == UserState.LOCKED) { |
|
428 |
+ if(isUsingEmailVerification() && created.isLocked()){ |
|
429 |
+ flash(Constants.INFO, "user.verification.mail.sent"); |
|
430 |
+ forceOAuthLogout(); |
|
431 |
+ } else if (created.state == UserState.LOCKED) { |
|
400 | 432 |
flash(Constants.INFO, "user.signup.requested"); |
401 | 433 |
forceOAuthLogout(); |
402 | 434 |
} |
... | ... | @@ -406,7 +438,6 @@ |
406 | 438 |
userCredential.user = created; |
407 | 439 |
userCredential.update(); |
408 | 440 |
|
409 |
- sendMailAboutUserCreationByOAuth(userCredential, created); |
|
410 | 441 |
return created; |
411 | 442 |
} |
412 | 443 |
|
... | ... | @@ -431,24 +462,81 @@ |
431 | 462 |
return createNewUser(user); |
432 | 463 |
} |
433 | 464 |
|
434 |
- private static void sendMailAboutUserCreationByOAuth(UserCredential userCredential, User created) { |
|
435 |
- Mail mail = new Mail("New account for Yona", getNewAccountMailBody(created), new String[] { getEmailName(userCredential.name, userCredential.email) }); |
|
465 |
+ public static Result verifyUser(String loginId, String verificationCode){ |
|
466 |
+ if(!UserApp.currentUser().isAnonymous()) { |
|
467 |
+ return redirect(routes.Application.index()); |
|
468 |
+ } |
|
469 |
+ UserVerification uv = UserVerification.findbyLoginIdAndVerificationCode(loginId, verificationCode); |
|
470 |
+ if(uv == null){ |
|
471 |
+ return notFound("Invalid verification"); |
|
472 |
+ } |
|
473 |
+ if (uv.isValidDate()) { |
|
474 |
+ User user = User.findByLoginId(loginId); |
|
475 |
+ user.state = UserState.ACTIVE; |
|
476 |
+ user.update(); |
|
477 |
+ uv.invalidate(); |
|
478 |
+ return ok(verified.render("", loginId)); |
|
479 |
+ } |
|
480 |
+ return notFound("Invalid verification"); |
|
481 |
+ } |
|
482 |
+ |
|
483 |
+ private static void sendMailAfterUserCreation(User created) { |
|
484 |
+ if (!isAllowedEmailDomains(created.email)) { |
|
485 |
+ flash(Constants.INFO, "user.unacceptable.email.domain"); |
|
486 |
+ return; |
|
487 |
+ } |
|
488 |
+ Mail mail = new Mail(Messages.get("user.verification.signup.confirm") |
|
489 |
+ + ": " + getServeIndexPageUrl(), |
|
490 |
+ getNewAccountMailBody(created), |
|
491 |
+ new String[] { getEmailName(created.email, created.name) }); |
|
436 | 492 |
Mailer mailer = Mailer.getCustomMailer(Configuration.root().getConfig("play-easymail")); |
437 | 493 |
mailer.sendMail(mail); |
438 | 494 |
} |
439 | 495 |
|
440 | 496 |
private static Body getNewAccountMailBody(User user){ |
441 | 497 |
String passwordResetUrl = getServeIndexPageUrl() + routes.PasswordResetApp.lostPassword(); |
442 |
- String html = "ID: " + user.loginId + "<br/>\n" |
|
443 |
- + "PW: " + user.password + "<br/>\n" |
|
444 |
- + "Email: " + user.email + "<br/>\n<br/>\n<br/>\n" |
|
445 |
- + "Password reset: <a href='" + passwordResetUrl + "' target='_blank'>" |
|
446 |
- + passwordResetUrl + "</a><br/>\n<br/>\n"; |
|
447 |
- String text = "ID: " + user.loginId + "\n" |
|
448 |
- + "PW: " + user.password + "\n" |
|
449 |
- + "Email: " + user.email + "\n\n\n" |
|
450 |
- + "Password reset: " + passwordResetUrl + "\n\n"; |
|
451 |
- return new Body(text, html); |
|
498 |
+ StringBuilder html = new StringBuilder(); |
|
499 |
+ StringBuilder plainText = new StringBuilder(); |
|
500 |
+ |
|
501 |
+ if(isUsingEmailVerification()){ |
|
502 |
+ setVerificationMessage(user, html, plainText); |
|
503 |
+ } |
|
504 |
+ setSignupInfomation(user, passwordResetUrl, html, plainText); |
|
505 |
+ return new Body(plainText.toString(), html.toString()); |
|
506 |
+ } |
|
507 |
+ |
|
508 |
+ private static void setSignupInfomation(User user, String passwordResetUrl, StringBuilder html, StringBuilder plainText) { |
|
509 |
+ html.append("URL: <a href='").append(getServeIndexPageUrl()).append("'>") |
|
510 |
+ .append(getServeIndexPageUrl()).append("</a><br/>\n") |
|
511 |
+ .append("ID: ").append(user.loginId).append("<br/>\n") |
|
512 |
+ .append("Email: ").append(user.email).append("<br/>\n<br/>\n") |
|
513 |
+ .append("Password reset: <a href='").append(passwordResetUrl).append("' target='_blank'>") |
|
514 |
+ .append(passwordResetUrl).append("</a><br/>\n"); |
|
515 |
+ plainText.append("URL: ").append(getServeIndexPageUrl()).append("\n") |
|
516 |
+ .append("ID: ").append(user.loginId).append("\n") |
|
517 |
+ .append("Email: ").append(user.email).append("\n\n") |
|
518 |
+ .append("Password reset: ").append(passwordResetUrl).append("\n"); |
|
519 |
+ } |
|
520 |
+ |
|
521 |
+ private static void setVerificationMessage(User user, StringBuilder html, StringBuilder plainText) { |
|
522 |
+ UserVerification verification = UserVerification.findbyUser(user); |
|
523 |
+ if(verification == null){ |
|
524 |
+ verification = UserVerification.newVerification(user); |
|
525 |
+ } |
|
526 |
+ String verificationUrl = getServeIndexPageUrl() |
|
527 |
+ + routes.UserApp.verifyUser(user.loginId, verification.verificationCode).toString(); |
|
528 |
+ html.append("<h1>").append(Messages.get("user.verification")).append("</h1>\n"); |
|
529 |
+ html.append("<hr />\n"); |
|
530 |
+ html.append("<p><a href='").append(verificationUrl).append("'>") |
|
531 |
+ .append(Messages.get("user.verification.link.click")).append("</a></p>\n"); |
|
532 |
+ html.append("<br />\n"); |
|
533 |
+ html.append("<br />\n"); |
|
534 |
+ |
|
535 |
+ plainText.append(Messages.get("user.verification")).append("\n"); |
|
536 |
+ plainText.append("--------------------------\n"); |
|
537 |
+ plainText.append(verificationUrl).append("\n"); |
|
538 |
+ plainText.append("\n"); |
|
539 |
+ plainText.append("\n"); |
|
452 | 540 |
} |
453 | 541 |
|
454 | 542 |
private static String getServeIndexPageUrl(){ |
... | ... | @@ -794,6 +882,10 @@ |
794 | 882 |
} |
795 | 883 |
} |
796 | 884 |
|
885 |
+ private static boolean isUsingEmailVerification() { |
|
886 |
+ return usingEmailVerification; |
|
887 |
+ } |
|
888 |
+ |
|
797 | 889 |
private enum UserInfoFormTabType { |
798 | 890 |
PROFILE("profile"), |
799 | 891 |
PASSWORD("password"), |
... | ... | @@ -1068,7 +1160,7 @@ |
1068 | 1160 |
} |
1069 | 1161 |
} |
1070 | 1162 |
|
1071 |
- public static boolean isUseSignUpConfirm(){ |
|
1163 |
+ public static boolean isUsingSignUpConfirm(){ |
|
1072 | 1164 |
Configuration config = play.Play.application().configuration(); |
1073 | 1165 |
Boolean useSignUpConfirm = config.getBoolean("signup.require.admin.confirm"); |
1074 | 1166 |
if(useSignUpConfirm == null) { |
... | ... | @@ -1114,17 +1206,24 @@ |
1114 | 1206 |
RandomNumberGenerator rng = new SecureRandomNumberGenerator(); |
1115 | 1207 |
user.passwordSalt = rng.nextBytes().toBase64(); |
1116 | 1208 |
user.password = hashedPassword(user.password, user.passwordSalt); |
1117 |
- if (isUseSignUpConfirm()) { |
|
1209 |
+ if (isUsingSignUpConfirm() || isUsingEmailVerification()) { |
|
1118 | 1210 |
user.state = UserState.LOCKED; |
1119 | 1211 |
} else { |
1120 | 1212 |
user.state = UserState.ACTIVE; |
1121 | 1213 |
} |
1122 | 1214 |
User.create(user); |
1123 | 1215 |
Email.deleteOtherInvalidEmails(user.email); |
1216 |
+ if (isUsingEmailVerification()) { |
|
1217 |
+ UserVerification.newVerification(user); |
|
1218 |
+ sendMailAfterUserCreation(user); |
|
1219 |
+ } |
|
1124 | 1220 |
return user; |
1125 | 1221 |
} |
1126 | 1222 |
|
1127 | 1223 |
public static void addUserInfoToSession(User user) { |
1224 |
+ if(user.isLocked()){ |
|
1225 |
+ return; |
|
1226 |
+ } |
|
1128 | 1227 |
String key = new Sha256Hash(new Date().toString(), ByteSource.Util.bytes(user.passwordSalt), 1024) |
1129 | 1228 |
.toBase64(); |
1130 | 1229 |
CacheStore.yonaUsers.put(user.id, user); |
--- app/models/NotificationMail.java
+++ app/models/NotificationMail.java
... | ... | @@ -435,7 +435,7 @@ |
435 | 435 |
|
436 | 436 |
if(StringUtils.isNotBlank(Application.ALLOWED_SENDING_MAIL_DOMAINS)){ |
437 | 437 |
for(String domain: Application.ALLOWED_SENDING_MAIL_DOMAINS.split(",")){ |
438 |
- acceptableDomains.add(StringUtils.defaultString(domain, "").trim()); |
|
438 |
+ acceptableDomains.add(StringUtils.defaultString(domain, "").toLowerCase().trim()); |
|
439 | 439 |
} |
440 | 440 |
} |
441 | 441 |
|
... | ... | @@ -451,6 +451,24 @@ |
451 | 451 |
return filteredUsers; |
452 | 452 |
} |
453 | 453 |
|
454 |
+ public static boolean isAllowedEmailDomains(String email) { |
|
455 |
+ List<String> acceptableDomains = new ArrayList<>(); |
|
456 |
+ |
|
457 |
+ if(StringUtils.isBlank(Application.ALLOWED_SENDING_MAIL_DOMAINS)){ |
|
458 |
+ return true; |
|
459 |
+ } else { |
|
460 |
+ for (String domain : Application.ALLOWED_SENDING_MAIL_DOMAINS.split(",")) { |
|
461 |
+ acceptableDomains.add(StringUtils.defaultString(domain, "").toLowerCase().trim()); |
|
462 |
+ } |
|
463 |
+ } |
|
464 |
+ |
|
465 |
+ String domain = getDomainFromEmail(email); |
|
466 |
+ if(domain == null || !acceptableDomains.contains(domain.toLowerCase())) { |
|
467 |
+ return false; |
|
468 |
+ } |
|
469 |
+ return true; |
|
470 |
+ } |
|
471 |
+ |
|
454 | 472 |
private static int getPartialRecipientSize(Set<User> receivers) { |
455 | 473 |
if (recipientLimit == RECIPIENT_NO_LIMIT) { |
456 | 474 |
return receivers.size(); |
--- app/models/User.java
+++ app/models/User.java
... | ... | @@ -973,4 +973,8 @@ |
973 | 973 |
list.addAll(projects); |
974 | 974 |
return list; |
975 | 975 |
} |
976 |
+ |
|
977 |
+ public boolean isLocked() { |
|
978 |
+ return this.state == UserState.LOCKED || this.state == UserState.DELETED; |
|
979 |
+ } |
|
976 | 980 |
} |
--- app/models/UserCredential.java
+++ app/models/UserCredential.java
... | ... | @@ -142,4 +142,18 @@ |
142 | 142 |
public static List<UserCredential> findByUserId(Long id){ |
143 | 143 |
return find.where().eq("user.id", id).findList(); |
144 | 144 |
} |
145 |
+ |
|
146 |
+ @Override |
|
147 |
+ public String toString() { |
|
148 |
+ return "UserCredential{" + |
|
149 |
+ "id=" + id + |
|
150 |
+ ", user=" + user + |
|
151 |
+ ", loginId='" + loginId + '\'' + |
|
152 |
+ ", email='" + email + '\'' + |
|
153 |
+ ", name='" + name + '\'' + |
|
154 |
+ ", active=" + active + |
|
155 |
+ ", emailValidated=" + emailValidated + |
|
156 |
+ ", linkedAccounts=" + linkedAccounts + |
|
157 |
+ '}'; |
|
158 |
+ } |
|
145 | 159 |
} |
+++ app/models/UserVerification.java
... | ... | @@ -0,0 +1,77 @@ |
1 | +/** | |
2 | + * Yona, 21st Century Project Hosting SW | |
3 | + * <p> | |
4 | + * Copyright Yona & Yobi Authors & NAVER Corp. | |
5 | + * https://yona.io | |
6 | + **/ | |
7 | +package models; | |
8 | + | |
9 | +import play.db.ebean.Model; | |
10 | + | |
11 | +import javax.persistence.Entity; | |
12 | +import javax.persistence.Id; | |
13 | +import javax.persistence.OneToOne; | |
14 | +import java.util.Date; | |
15 | +import java.util.List; | |
16 | +import java.util.UUID; | |
17 | + | |
18 | +@Entity | |
19 | +public class UserVerification extends Model { | |
20 | + private static final long serialVersionUID = 7819377239127603471L; | |
21 | + | |
22 | + public static final Model.Finder<Long, UserVerification> find = new Finder<>(Long.class, UserVerification.class); | |
23 | + | |
24 | + @Id | |
25 | + public Long id; | |
26 | + | |
27 | + @OneToOne | |
28 | + public User user; | |
29 | + | |
30 | + public String loginId; | |
31 | + | |
32 | + public String verificationCode; | |
33 | + | |
34 | + public Long timestamp; | |
35 | + | |
36 | + public static UserVerification newVerification(User user) { | |
37 | + UserVerification v = new UserVerification(); | |
38 | + v.user = user; | |
39 | + v.loginId = user.loginId; | |
40 | + v.verificationCode = UUID.randomUUID().toString(); | |
41 | + v.timestamp = new Date().getTime(); | |
42 | + v.save(); | |
43 | + return v; | |
44 | + } | |
45 | + | |
46 | + public static UserVerification findbyUser(User user) { | |
47 | + List<UserVerification> list = find.where().eq("user.id", user.id).findList(); | |
48 | + if (list != null && list.size() > 0) { | |
49 | + return list.get(0); | |
50 | + } else { | |
51 | + return null; | |
52 | + } | |
53 | + } | |
54 | + | |
55 | + public static UserVerification findbyLoginIdAndVerificationCode(String loginId, String verificationCode) { | |
56 | + List<UserVerification> list = find.where().eq("login_id", loginId) | |
57 | + .eq("verificationCode", verificationCode).findList(); | |
58 | + if (list != null && list.size() > 0) { | |
59 | + return list.get(0); | |
60 | + } else { | |
61 | + return null; | |
62 | + } | |
63 | + } | |
64 | + | |
65 | + public boolean isValidDate(){ | |
66 | + if( this.timestamp + 60*60*24 > new Date().getTime()) { | |
67 | + return true; | |
68 | + } else { | |
69 | + this.delete(); | |
70 | + return false; | |
71 | + } | |
72 | + } | |
73 | + | |
74 | + public void invalidate(){ | |
75 | + this.delete(); | |
76 | + } | |
77 | +} |
--- app/views/user/signup.scala.html
+++ app/views/user/signup.scala.html
... | ... | @@ -31,7 +31,7 @@ |
31 | 31 |
<p class="tag-line">@Messages("app.description")</p> |
32 | 32 |
</div> |
33 | 33 |
|
34 |
- @if(UserApp.isUseSignUpConfirm){ |
|
34 |
+ @if(UserApp.isUsingSignUpConfirm){ |
|
35 | 35 |
<div class="center-txt"> |
36 | 36 |
<p>@Messages("title.signupConfirmDesc")</p> |
37 | 37 |
<p>@Html(Messages("title.signupConfirmDesc2", new StringBuilder(User.findByLoginId(SiteAdmin.SITEADMIN_DEFAULT_LOGINID).email).reverse().toString()))</p> |
+++ app/views/user/verified.scala.html
... | ... | @@ -0,0 +1,20 @@ |
1 | +@** | |
2 | +* Yona, 21st Century Project Hosting SW | |
3 | +* | |
4 | +* Copyright Yona & Yobi Authors & NAVER Corp. | |
5 | +* https://yona.io | |
6 | +**@ | |
7 | +@(message: String, loginId:String) | |
8 | + | |
9 | +@siteLayout(message, utils.MenuType.NONE) { | |
10 | +<div class="page full"> | |
11 | + <div class="center-wrap tag-line-wrap reset-password"> | |
12 | + <h1 class="title"> | |
13 | + @Html(Messages("user.verified")) | |
14 | + </h1> | |
15 | + <p>@loginId</p> | |
16 | + <hr /> | |
17 | + <p class="tag-line">@Messages("user.verified.detail")</p> | |
18 | + </div> | |
19 | +</div> | |
20 | +} |
--- conf/application.conf.default
+++ conf/application.conf.default
... | ... | @@ -21,9 +21,40 @@ |
21 | 21 |
# want to allow that, set signup.require.confirm to true. |
22 | 22 |
application.allowsAnonymousAccess=true |
23 | 23 |
|
24 |
+# |
|
25 |
+# Signup options |
|
26 |
+# ~~~~~~~~~~~~~~ |
|
27 |
+ |
|
24 | 28 |
# If you wants to make the user available to use yona |
25 | 29 |
# after the server administrator approved,uncomment below |
30 |
+# |
|
26 | 31 |
# signup.require.admin.confirm = true |
32 |
+ |
|
33 |
+# If you only want to allow for signing up in specific email domains, |
|
34 |
+# use the following option. |
|
35 |
+# application.allowed.sending.mail.domains = "gmail.com, your-company.com" |
|
36 |
+# And "" is option for no restriction. |
|
37 |
+# |
|
38 |
+# application.allowed.sending.mail.domains = "" |
|
39 |
+ |
|
40 |
+# If following email verification option is true, all user will be locked when it sign-up, |
|
41 |
+# until user click the verification link of verification confirm mail |
|
42 |
+# |
|
43 |
+# application.use.email.verification = true |
|
44 |
+ |
|
45 |
+# If you enable to use social login or email verification, set followings |
|
46 |
+play-easymail { |
|
47 |
+ from { |
|
48 |
+ # Mailing from address |
|
49 |
+ email="projects.yona@gmail.com" |
|
50 |
+ |
|
51 |
+ # Mailing name |
|
52 |
+ name="yona-no-reply" |
|
53 |
+ |
|
54 |
+ # Seconds between sending mail through Akka (defaults to 1) |
|
55 |
+ # delay=1 |
|
56 |
+ } |
|
57 |
+} |
|
27 | 58 |
|
28 | 59 |
# Notification |
29 | 60 |
# ~~~~~ |
... | ... | @@ -270,6 +301,8 @@ |
270 | 301 |
# 2,147,483,454 bytes = 2Gb |
271 | 302 |
application.maxFileSize = 2147483454 |
272 | 303 |
|
304 |
+ |
|
305 |
+ |
|
273 | 306 |
# Social Login Support |
274 | 307 |
# ~~~~~~~~~~~~~~~~~~~~ |
275 | 308 |
# Social login settings for Yona |
... | ... | @@ -298,20 +331,6 @@ |
298 | 331 |
baseDN = "ou=scientists,dc=example,dc=com" |
299 | 332 |
# If your ldap service's distinguishedName is 'CN=username,OU=user,DC=abc,DC=com', postfix is 'OU=xxx,DC=abc,DC=com' |
300 | 333 |
distinguishedNamePostfix = "OU=user,DC=abc,DC=com" |
301 |
-} |
|
302 |
- |
|
303 |
-# If you enable to use social login, set followings |
|
304 |
-play-easymail { |
|
305 |
- from { |
|
306 |
- # Mailing from address |
|
307 |
- email="your@mail-adress.com" |
|
308 |
- |
|
309 |
- # Mailing name |
|
310 |
- name="Yona Admin" |
|
311 |
- |
|
312 |
- # Seconds between sending mail through Akka (defaults to 1) |
|
313 |
- # delay=1 |
|
314 |
- } |
|
315 | 334 |
} |
316 | 335 |
|
317 | 336 |
include "social-login.conf" |
+++ conf/evolutions/default/15.sql
... | ... | @@ -0,0 +1,17 @@ |
1 | +# --- !Ups | |
2 | +CREATE TABLE user_verification ( | |
3 | + id BIGINT AUTO_INCREMENT NOT NULL, | |
4 | + user_id BIGINT, | |
5 | + login_id VARCHAR(255), | |
6 | + verification_code VARCHAR(255), | |
7 | + timestamp BIGINT, | |
8 | + CONSTRAINT pk_user_verification PRIMARY KEY (id), | |
9 | + CONSTRAINT fk_user_verification_user FOREIGN KEY (user_id) REFERENCES n4user (id) on DELETE CASCADE | |
10 | +) | |
11 | +row_format=compressed, key_block_size=8; | |
12 | + | |
13 | +CREATE index ix_user_verification_user_1 ON user_verification (user_id); | |
14 | +CREATE index ix_user_verification_user_2 ON user_verification (login_id, verification_code); | |
15 | + | |
16 | +# --- !Downs | |
17 | +DROP TABLE user_verification; |
--- conf/messages
+++ conf/messages
... | ... | @@ -988,6 +988,13 @@ |
988 | 988 |
user.signup.requested = Sign-up request has been sent. Site admin will review and accept your request. Thanks. |
989 | 989 |
user.signupBtn = Sign up |
990 | 990 |
user.signupId = User ID (lower case) |
991 |
+user.unacceptable.email.domain = Your email domain doesn't allowed. |
|
992 |
+user.verification.mail.sent = User verification mail was sent. |
|
993 |
+user.verification = User verification |
|
994 |
+user.verification.signup.confirm = New Sign-up Confirm |
|
995 |
+user.verification.link.click = Click to verify |
|
996 |
+user.verified = Verified User |
|
997 |
+user.verified.detail = User is verified. Try login. |
|
991 | 998 |
user.wrongEmail.alert = Wrong email address. |
992 | 999 |
user.wrongPassword.alert = Wrong password! |
993 | 1000 |
user.wrongloginId.alert = Enter Valid ID |
--- conf/messages.ko-KR
+++ conf/messages.ko-KR
... | ... | @@ -982,6 +982,13 @@ |
982 | 982 |
user.signup.requested = 가입 요청을 보냈습니다. 사이트 관리자가 검토/승인 후 사용가능합니다. 감사합니다. |
983 | 983 |
user.signupBtn = 참여하기 |
984 | 984 |
user.signupId = 아이디 |
985 |
+user.verification.mail.sent = 사용자 정보 확인을 위한 메일을 보냈습니다 |
|
986 |
+user.verification = 사용자 정보 확인 |
|
987 |
+user.verification.signup.confirm = 새 가입 확인 |
|
988 |
+user.verification.link.click = 유효 이메일 확인을 위해 클릭하세요 |
|
989 |
+user.verified = 확인된 사용자 |
|
990 |
+user.verified.detail = 사용자 정보가 확인되었습니다. 다시 로그인 해주세요 |
|
991 |
+user.unacceptable.email.domain = 가입이 허용되지 않은 이메일 도메인 입니다. |
|
985 | 992 |
user.wrongEmail.alert = 이메일이 잘못되었습니다. |
986 | 993 |
user.wrongPassword.alert = 잘못된 비밀번호입니다! |
987 | 994 |
user.wrongloginId.alert = 올바른 아이디를 입력하세요. |
--- conf/routes
+++ conf/routes
... | ... | @@ -127,6 +127,7 @@ |
127 | 127 |
POST /lostPassword controllers.PasswordResetApp.requestResetPasswordEmail() |
128 | 128 |
GET /resetPassword controllers.PasswordResetApp.resetPasswordForm(s:String) |
129 | 129 |
POST /resetPassword controllers.PasswordResetApp.resetPassword() |
130 |
+GET /verify/:loginId/:verificationCode controllers.UserApp.verifyUser(loginId:String, verificationCode:String) |
|
130 | 131 |
GET /sites/postList controllers.SiteApp.postList(pageNum: Int ?= 1) |
131 | 132 |
GET /sites/issueList controllers.SiteApp.issueList(pageNum: Int ?= 1) |
132 | 133 |
|
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?