完成忘记密码重置功能
This commit is contained in:
parent
d4d7c7626e
commit
d90beedf52
|
@ -11,7 +11,6 @@ import lombok.Data;
|
|||
*/
|
||||
@Data
|
||||
public class ChangePasswordRequest {
|
||||
private String userId;
|
||||
private String oldPassword;
|
||||
private String newPassword;
|
||||
private String confirmPassword;
|
||||
|
|
|
@ -42,7 +42,7 @@ public class UserChangePassword extends BaseEntity<Long> {
|
|||
/**
|
||||
* User change password time
|
||||
*/
|
||||
@Column(name = "change_password_time", columnDefinition = "DATE COMMENT 'User change password time'")
|
||||
@Column(name = "change_password_time", columnDefinition = "DATETIME COMMENT 'User change password time'")
|
||||
private LocalDateTime changePasswordTime;
|
||||
|
||||
|
||||
|
@ -55,7 +55,8 @@ public class UserChangePassword extends BaseEntity<Long> {
|
|||
/**
|
||||
* User change password request time
|
||||
*/
|
||||
@Column(name = "request_date_change_password", columnDefinition = "DATE COMMENT 'User change password request " +
|
||||
@Column(name = "request_date_change_password", columnDefinition = "DATETIME COMMENT 'User change password request" +
|
||||
" " +
|
||||
"time'")
|
||||
private LocalDateTime requestDateChangePassword;
|
||||
|
||||
|
|
|
@ -17,6 +17,6 @@ public interface UserChangePasswordRepository extends CrudRepository<UserChangeP
|
|||
@Query(value = "select u from UserChangePassword u" +
|
||||
" where u.userId = ?1" +
|
||||
" and u.changed = false" +
|
||||
" and u.changePasswordCode = ?2")
|
||||
" and u.changePasswordCode = ?2 order by u.requestDateChangePassword desc")
|
||||
Optional<UserChangePassword> findByUserIdAndCode(long userId, String changePasswordCode);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package com.northtecom.visatrack.api.service.impl;
|
|||
|
||||
import com.northtecom.visatrack.api.base.util.EmailUtils;
|
||||
import com.northtecom.visatrack.api.data.entity.User;
|
||||
import com.northtecom.visatrack.api.data.entity.UserChangePassword;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
@ -64,15 +63,17 @@ public class EmailService {
|
|||
emailUtils.sendEmail(user.getUserEmail(), subject, htmlContent);
|
||||
}
|
||||
|
||||
public void sendChangePasswordEmailToUser(User user, UserChangePassword savedUserChangePassword) {
|
||||
public void sendChangePasswordEmailToUser(User user, String changePasswordCode) {
|
||||
log.info("Send change password email to user: {}", user);
|
||||
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("SiteName", "UsVisaTrack");
|
||||
map.put("SiteHost", "www.usvisatrack.com");
|
||||
map.put("SiteUrl", "https://www.usvisatrack.com/");
|
||||
map.put("UserName", user.getUserName());
|
||||
map.put("UserEmail", user.getUserEmail());
|
||||
map.put("UserId", user.getId());
|
||||
map.put("ChangePasswordCode", savedUserChangePassword.getChangePasswordCode());
|
||||
map.put("ChangePasswordCode", changePasswordCode);
|
||||
|
||||
String htmlContent = this.templateService.createHtml("email/ChangePassword.html", map);
|
||||
|
||||
|
@ -87,6 +88,7 @@ public class EmailService {
|
|||
HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("SiteName", "UsVisaTrack");
|
||||
map.put("SiteHost", "www.usvisatrack.com");
|
||||
map.put("SiteUrl", "https://www.usvisatrack.com/");
|
||||
map.put("UserName", user.getUserName());
|
||||
map.put("UserId", user.getId());
|
||||
|
||||
|
|
|
@ -15,7 +15,9 @@ import com.northtecom.visatrack.api.data.repository.UserRepository;
|
|||
import com.northtecom.visatrack.api.service.enums.UserStatus;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
|
@ -105,8 +107,8 @@ public class UserService implements UserDetailsService {
|
|||
emailService.sendWelcomeEmailToUser(savedUser);
|
||||
}
|
||||
|
||||
public boolean checkPasswordIsMatch(String userPassword, String password) {
|
||||
return passwordEncoder.matches(userPassword, password);
|
||||
public boolean checkPasswordIsMatch(String userEncodePassword, String checkPassword) {
|
||||
return passwordEncoder.matches(checkPassword, userEncodePassword);
|
||||
}
|
||||
|
||||
public String encodePassword(String password) {
|
||||
|
@ -152,6 +154,20 @@ public class UserService implements UserDetailsService {
|
|||
}
|
||||
|
||||
public void forgotPassword(String userEmail) {
|
||||
User user = userRepository.findByUserEmail(userEmail).orElseThrow(() -> new BaseException(Status.BAD_REQUEST,
|
||||
"User is not exist"));
|
||||
|
||||
UserChangePassword userChangePassword = new UserChangePassword();
|
||||
userChangePassword.setUserId(user.getId());
|
||||
userChangePassword.setOldPassword(user.getUserPassword());
|
||||
userChangePassword.setChangePasswordCode(RandomUtil.randomString(18));
|
||||
userChangePassword.setChanged(false);
|
||||
userChangePassword.setRequestDateChangePassword(LocalDateTime.now());
|
||||
|
||||
UserChangePassword savedUserChangePassword = userChangePasswordRepository.save(userChangePassword);
|
||||
|
||||
emailService.sendChangePasswordEmailToUser(user, savedUserChangePassword.getChangePasswordCode());
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -161,9 +177,14 @@ public class UserService implements UserDetailsService {
|
|||
(Status.BAD_REQUEST, "User is not exist"));
|
||||
|
||||
UserChangePassword userChangePassword =
|
||||
userChangePasswordRepository.findByUserIdAndCode(Long.parseLong(changePasswordForgotRequest.getUserId()), changePasswordForgotRequest.getNewPassword()).orElseThrow(() -> new BaseException
|
||||
userChangePasswordRepository.findByUserIdAndCode(Long.parseLong(changePasswordForgotRequest.getUserId()), changePasswordForgotRequest.getChangePasswordCode()).orElseThrow(() -> new BaseException
|
||||
(Status.BAD_REQUEST, "User is not exist"));
|
||||
|
||||
//更改密码过期
|
||||
if (userChangePassword.getRequestDateChangePassword().plusHours(24).isBefore(LocalDateTime.now())) {
|
||||
throw new BaseException(Status.BAD_REQUEST, "Change password code is expired");
|
||||
}
|
||||
|
||||
userChangePassword.setChanged(true);
|
||||
userChangePassword.setNewPassword(passwordEncoder.encode(changePasswordForgotRequest.getNewPassword()));
|
||||
userChangePassword.setChangePasswordTime(LocalDateTime.now());
|
||||
|
@ -175,19 +196,34 @@ public class UserService implements UserDetailsService {
|
|||
emailService.sendChangePasswordSuccessEmailToUser(user);
|
||||
}
|
||||
|
||||
public void changePassword(ChangePasswordRequest changePasswordRequest) {
|
||||
User user =
|
||||
userRepository.findById(Long.parseLong(changePasswordRequest.getUserId())).orElseThrow(() -> new BaseException
|
||||
(Status.BAD_REQUEST, "User is not exist"));
|
||||
|
||||
if (!checkPasswordIsMatch(user.getUserPassword(), changePasswordRequest.getOldPassword())) {
|
||||
@PreAuthorize("authentication.getPrincipal().toString()!=\"anonymousUser\"")
|
||||
public void changePassword(ChangePasswordRequest changePasswordRequest) {
|
||||
if (changePasswordRequest.getNewPassword().equals(changePasswordRequest.getOldPassword())) {
|
||||
throw new BaseException(Status.BAD_REQUEST, "New password is same as old password");
|
||||
}
|
||||
|
||||
if (!changePasswordRequest.getNewPassword().equals(changePasswordRequest.getConfirmPassword())) {
|
||||
throw new BaseException(Status.BAD_REQUEST, "New password and confirm password is not match");
|
||||
}
|
||||
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
VisaTrackUserDetail userDetail = (VisaTrackUserDetail) authentication.getPrincipal();
|
||||
|
||||
User dbUser =
|
||||
userRepository.findById(userDetail.getId()).orElseThrow(() -> new BaseException(Status.BAD_REQUEST,
|
||||
"User is not exist"));
|
||||
|
||||
if (!checkPasswordIsMatch(dbUser.getUserPassword(), changePasswordRequest.getOldPassword())) {
|
||||
throw new BaseException(Status.BAD_REQUEST, "Old password is not correct");
|
||||
}
|
||||
|
||||
UserChangePassword userChangePassword = new UserChangePassword();
|
||||
userChangePassword.setChanged(true);
|
||||
userChangePassword.setUserId(user.getId());
|
||||
userChangePassword.setOldPassword(encodePassword(changePasswordRequest.getOldPassword()));
|
||||
userChangePassword.setUserId(dbUser.getId());
|
||||
//使用数据库中的原始加密密码
|
||||
userChangePassword.setOldPassword(dbUser.getUserPassword());
|
||||
userChangePassword.setNewPassword(encodePassword(changePasswordRequest.getNewPassword()));
|
||||
userChangePassword.setRequestDateChangePassword(LocalDateTime.now());
|
||||
userChangePassword.setChangePasswordCode("");
|
||||
|
@ -195,9 +231,9 @@ public class UserService implements UserDetailsService {
|
|||
userChangePassword.setChangePasswordTime(LocalDateTime.now());
|
||||
UserChangePassword savedUserChangePassword = userChangePasswordRepository.save(userChangePassword);
|
||||
|
||||
user.setUserPassword(userChangePassword.getNewPassword());
|
||||
userRepository.save(user);
|
||||
dbUser.setUserPassword(userChangePassword.getNewPassword());
|
||||
userRepository.save(dbUser);
|
||||
|
||||
emailService.sendChangePasswordSuccessEmailToUser(user);
|
||||
emailService.sendChangePasswordSuccessEmailToUser(dbUser);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,239 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
|
||||
|
||||
<title>[(${SiteName})] - Track Your Visa Status</title>
|
||||
<style>
|
||||
b {
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
font-weight: 400;
|
||||
}
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Open Sans Regular'), local('OpenSans-Regular'), url(https://fonts.gstatic.com/s/opensans/v15/K88pR3goAWT7BTt32Z01mxJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
|
||||
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Open Sans Regular'), local('OpenSans-Regular'), url(https://fonts.gstatic.com/s/opensans/v15/RjgO7rYTmqiVp7vzi-Q5URJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
|
||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Open Sans Regular'), local('OpenSans-Regular'), url(https://fonts.gstatic.com/s/opensans/v15/LWCjsQkB6EMdfHrEVqA1KRJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Open Sans Regular'), local('OpenSans-Regular'), url(https://fonts.gstatic.com/s/opensans/v15/xozscpT2726on7jbcb_pAhJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
|
||||
unicode-range: U+0370-03FF;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Open Sans Regular'), local('OpenSans-Regular'), url(https://fonts.gstatic.com/s/opensans/v15/59ZRklaO5bWGqF5A9baEERJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Open Sans Regular'), local('OpenSans-Regular'), url(https://fonts.gstatic.com/s/opensans/v15/u-WUoqrET9fUeobQW7jkRRJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Open Sans Regular'), local('OpenSans-Regular'), url(https://fonts.gstatic.com/s/opensans/v15/cJZKeOuBrn4kERxqtaUH3VtXRa8TVwTICgirnJhmVJw.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
||||
}
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), url(https://fonts.gstatic.com/s/opensans/v15/MTP_ySUJH_bn48VBG8sNSq-j2U0lmluP9RWlSytm3ho.woff2) format('woff2');
|
||||
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), url(https://fonts.gstatic.com/s/opensans/v15/MTP_ySUJH_bn48VBG8sNSpX5f-9o1vgP2EXwfjgl7AY.woff2) format('woff2');
|
||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), url(https://fonts.gstatic.com/s/opensans/v15/MTP_ySUJH_bn48VBG8sNShWV49_lSm1NYrwo-zkhivY.woff2) format('woff2');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), url(https://fonts.gstatic.com/s/opensans/v15/MTP_ySUJH_bn48VBG8sNSqaRobkAwv3vxw3jMhVENGA.woff2) format('woff2');
|
||||
unicode-range: U+0370-03FF;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), url(https://fonts.gstatic.com/s/opensans/v15/MTP_ySUJH_bn48VBG8sNSv8zf_FOSsgRmwsS7Aa9k2w.woff2) format('woff2');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), url(https://fonts.gstatic.com/s/opensans/v15/MTP_ySUJH_bn48VBG8sNSj0LW-43aMEzIO6XUTLjad8.woff2) format('woff2');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), url(https://fonts.gstatic.com/s/opensans/v15/MTP_ySUJH_bn48VBG8sNSugdm0LZdjqr5-oayXSOefg.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#F7F7F7" contenteditable="false" data-gr-c-s-loaded="true" style="margin:0px; padding:0px; color:#333;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr style="background:#F7F7F7;">
|
||||
<td>
|
||||
<!-- main table stats-->
|
||||
<!--[if gte mso 9]>
|
||||
<table id="tableForOutlook" align="center">
|
||||
<tr>
|
||||
<td>
|
||||
<![endif]-->
|
||||
|
||||
<div style="max-width:100%; margin:0 auto; padding: 10px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" class="content"
|
||||
style="width: 100%; border-collapse: separate; border-spacing: 0;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; color: #333333; font-size: 15px; font-weight: 400; line-height: 1.4; padding: 15px 5px;">
|
||||
<h1 align="center"
|
||||
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; color: #333333; font-size: 18px; font-weight: 400; line-height: 1.4; margin: 0; padding: 0;">
|
||||
|
||||
You (or someone else) has requested to reset your password.</h1>
|
||||
<p>
|
||||
This password reset request is valid for the next 24 hours. Don't worry you can always
|
||||
ask for a new password using the following link
|
||||
[(@{${SiteUrl}})]forgotuserpassword.action
|
||||
</p>
|
||||
<p>
|
||||
If you did not initiate this change, please contact your administrator immediately.
|
||||
</p>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
class="email-content-main mobile-expand last-row-padding"
|
||||
>
|
||||
<table border="0" cellpadding="0" cellspacing="0" class="aui-button-email-container"
|
||||
style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333333">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="aui-button-email"
|
||||
style="padding: 0px; border-collapse: collapse; border-radius: 3px; padding: 5px; margin: 0; background: #3572b0; -moz-box-sizing: border-box; -webkit-font-smoothing: antialiased">
|
||||
<a class="aui-button-email-link"
|
||||
rel="noopener"
|
||||
style="color: #3b73af; text-decoration: none; color: #ffffff; font-weight: bold; padding: 6px; font-size: 14px; line-height: 1.429; font-family: Arial, sans-serif"
|
||||
target="_blank"
|
||||
th:href="@{https://www.usvisatrack.com/user/forgotPassword(id=${UserId},code=${ChangePasswordCode})}">Change password</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; color: #333333; font-size: 15px; font-weight: 400; line-height: 1.4; padding: 15px 5px;">
|
||||
<p>
|
||||
Here are the details of your account:
|
||||
</p>
|
||||
<p>
|
||||
Username [(@{${UserName}})]
|
||||
</p>
|
||||
<p>
|
||||
Email [(@{${UserEmail}})]
|
||||
</p>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!--[if gte mso 9]>
|
||||
</td></tr></table>
|
||||
<![endif]-->
|
||||
<!-- main table ends-->
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,189 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
|
||||
|
||||
<title>[(${SiteName})] - Track Your Visa Status</title>
|
||||
<style>
|
||||
b {
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
font-weight: 400;
|
||||
}
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Open Sans Regular'), local('OpenSans-Regular'), url(https://fonts.gstatic.com/s/opensans/v15/K88pR3goAWT7BTt32Z01mxJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
|
||||
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Open Sans Regular'), local('OpenSans-Regular'), url(https://fonts.gstatic.com/s/opensans/v15/RjgO7rYTmqiVp7vzi-Q5URJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
|
||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Open Sans Regular'), local('OpenSans-Regular'), url(https://fonts.gstatic.com/s/opensans/v15/LWCjsQkB6EMdfHrEVqA1KRJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Open Sans Regular'), local('OpenSans-Regular'), url(https://fonts.gstatic.com/s/opensans/v15/xozscpT2726on7jbcb_pAhJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
|
||||
unicode-range: U+0370-03FF;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Open Sans Regular'), local('OpenSans-Regular'), url(https://fonts.gstatic.com/s/opensans/v15/59ZRklaO5bWGqF5A9baEERJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Open Sans Regular'), local('OpenSans-Regular'), url(https://fonts.gstatic.com/s/opensans/v15/u-WUoqrET9fUeobQW7jkRRJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Open Sans Regular'), local('OpenSans-Regular'), url(https://fonts.gstatic.com/s/opensans/v15/cJZKeOuBrn4kERxqtaUH3VtXRa8TVwTICgirnJhmVJw.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
||||
}
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), url(https://fonts.gstatic.com/s/opensans/v15/MTP_ySUJH_bn48VBG8sNSq-j2U0lmluP9RWlSytm3ho.woff2) format('woff2');
|
||||
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), url(https://fonts.gstatic.com/s/opensans/v15/MTP_ySUJH_bn48VBG8sNSpX5f-9o1vgP2EXwfjgl7AY.woff2) format('woff2');
|
||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), url(https://fonts.gstatic.com/s/opensans/v15/MTP_ySUJH_bn48VBG8sNShWV49_lSm1NYrwo-zkhivY.woff2) format('woff2');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), url(https://fonts.gstatic.com/s/opensans/v15/MTP_ySUJH_bn48VBG8sNSqaRobkAwv3vxw3jMhVENGA.woff2) format('woff2');
|
||||
unicode-range: U+0370-03FF;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), url(https://fonts.gstatic.com/s/opensans/v15/MTP_ySUJH_bn48VBG8sNSv8zf_FOSsgRmwsS7Aa9k2w.woff2) format('woff2');
|
||||
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), url(https://fonts.gstatic.com/s/opensans/v15/MTP_ySUJH_bn48VBG8sNSj0LW-43aMEzIO6XUTLjad8.woff2) format('woff2');
|
||||
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), url(https://fonts.gstatic.com/s/opensans/v15/MTP_ySUJH_bn48VBG8sNSugdm0LZdjqr5-oayXSOefg.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#F7F7F7" contenteditable="false" data-gr-c-s-loaded="true" style="margin:0px; padding:0px; color:#333;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tbody>
|
||||
<tr style="background:#F7F7F7;">
|
||||
<td>
|
||||
<!-- main table stats-->
|
||||
<!--[if gte mso 9]>
|
||||
<table id="tableForOutlook" align="center">
|
||||
<tr>
|
||||
<td>
|
||||
<![endif]-->
|
||||
|
||||
<div style="max-width:100%; margin:0 auto; padding: 10px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" class="content"
|
||||
style="width: 100%; border-collapse: separate; border-spacing: 0;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center"
|
||||
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; color: #333333; font-size: 15px; font-weight: 400; line-height: 1.4; padding: 15px 5px;">
|
||||
<h1 align="center"
|
||||
style="font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; color: #333333; font-size: 18px; font-weight: 400; line-height: 1.4; margin: 0; padding: 0;">
|
||||
Hello, [(${UserName})]!</h1>
|
||||
<p>
|
||||
The password for your [(${SiteName})] account on <a rel="noopener"
|
||||
style="color: #3777b0; text-decoration: none;"
|
||||
target="_blank"
|
||||
th:href="@{${SiteUrl}}">[(@{${SiteUrl}})]</a>
|
||||
has successfully been changed.
|
||||
</p>
|
||||
<p>
|
||||
If you did not initiate this change, please contact your administrator immediately.
|
||||
</p>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!--[if gte mso 9]>
|
||||
</td></tr></table>
|
||||
<![endif]-->
|
||||
<!-- main table ends-->
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</body>
|
||||
|
||||
</html>
|
Loading…
Reference in New Issue