Merge branch 'master' of https://git.eactive.synology.me:8090/elink/simulator-v2
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
package com.eactive.testmaster.login.controller;
|
||||
|
||||
import com.eactive.testmaster.common.exception.UserNotFoundException;
|
||||
import com.eactive.testmaster.login.dto.PasswordResetDTO;
|
||||
import com.eactive.testmaster.login.entity.Token;
|
||||
import com.eactive.testmaster.login.service.TokenService;
|
||||
import com.eactive.testmaster.user.service.UserService;
|
||||
import java.time.LocalDateTime;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
/**
|
||||
* Created by Sungpil Hyun
|
||||
*/
|
||||
@Controller
|
||||
@ConditionalOnProperty(name = "password.reset.enabled", havingValue = "true")
|
||||
public class PasswordResetController {
|
||||
|
||||
public static final String RESET_PASSWORD = "page/resetPassword";
|
||||
public static final String FORGOT_PASSWORD = "page/forgotPassword";
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
|
||||
@Autowired
|
||||
private Validator validator;
|
||||
|
||||
|
||||
@GetMapping(value = "/forgot_password.do")
|
||||
public String forgotPasswordView() {
|
||||
return FORGOT_PASSWORD;
|
||||
}
|
||||
|
||||
/**
|
||||
* 비밀번호 초기화 링크를 생성한다.
|
||||
*
|
||||
* @param email
|
||||
* @param model
|
||||
* @return
|
||||
*/
|
||||
@PostMapping(value = "/forgot_password.do")
|
||||
public String requestPasswordReset(@RequestParam(value = "email", defaultValue = "0") String email,
|
||||
Model model) {
|
||||
try {
|
||||
userService.requestPasswordReset(email);
|
||||
} catch (UserNotFoundException e) {
|
||||
model.addAttribute("error", "존재하지 않는 이메일입니다.");
|
||||
return FORGOT_PASSWORD;
|
||||
} catch (Exception e) {
|
||||
model.addAttribute("error", "비밀번호 초기화 요청에 실패하였습니다.");
|
||||
return FORGOT_PASSWORD;
|
||||
}
|
||||
|
||||
return "redirect:/forgot_password.do?success";
|
||||
}
|
||||
|
||||
@GetMapping("/reset_password.do")
|
||||
public String resetPasswordView(@RequestParam(value = "token", defaultValue = "0") String tokenValue,
|
||||
Model model) {
|
||||
Token token = tokenService.findByToken(tokenValue);
|
||||
|
||||
if (token == null || token.getExpiresAt().isBefore(LocalDateTime.now())) {
|
||||
return "redirect:/forgot_password.do?expired";
|
||||
}
|
||||
|
||||
model.addAttribute("tokenValue", tokenValue);
|
||||
model.addAttribute("passwordReset", new PasswordResetDTO());
|
||||
return RESET_PASSWORD;
|
||||
}
|
||||
|
||||
@PostMapping("/reset_password.do")
|
||||
@Transactional
|
||||
public String resetPassword(@ModelAttribute("passwordResetRequest") PasswordResetDTO passwordReset,
|
||||
BindingResult bindingResult,
|
||||
Model model) {
|
||||
|
||||
Token token = tokenService.findByToken(passwordReset.getToken());
|
||||
|
||||
if (token == null || token.getExpiresAt().isBefore(LocalDateTime.now())) {
|
||||
return "redirect:/forgot_password.do?expired";
|
||||
}
|
||||
|
||||
validator.validate(passwordReset, bindingResult);
|
||||
|
||||
if (bindingResult.hasErrors()) {
|
||||
model.addAttribute("tokenValue", passwordReset.getToken());
|
||||
model.addAttribute("passwordReset", passwordReset);
|
||||
return RESET_PASSWORD;
|
||||
}
|
||||
|
||||
userService.resetPassword(token.getEmail(), passwordReset.getPassword());
|
||||
|
||||
tokenService.deleteToken(token);
|
||||
|
||||
return "redirect:/login";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.eactive.testmaster.login.dto;
|
||||
|
||||
import com.eactive.testmaster.common.validator.PasswordMatch;
|
||||
import java.io.Serializable;
|
||||
|
||||
@PasswordMatch(input = "password", confirm = "password2")
|
||||
public class PasswordResetDTO implements Serializable {
|
||||
|
||||
private String token;
|
||||
private String password;
|
||||
private String password2;
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getPassword2() {
|
||||
return password2;
|
||||
}
|
||||
|
||||
public void setPassword2(String password2) {
|
||||
this.password2 = password2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.eactive.testmaster.login.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "PT_TOKEN")
|
||||
public class Token implements Serializable {
|
||||
|
||||
public Token(String tokenValue, String email, LocalDateTime expiresAt) {
|
||||
this.tokenValue = tokenValue;
|
||||
this.email = email;
|
||||
this.expiresAt = expiresAt;
|
||||
}
|
||||
|
||||
public Token() {
|
||||
}
|
||||
|
||||
@Id
|
||||
@Column(name = "TOKEN")
|
||||
private String tokenValue;
|
||||
|
||||
private String email;
|
||||
|
||||
private LocalDateTime expiresAt;
|
||||
|
||||
public String getTokenValue() {
|
||||
return tokenValue;
|
||||
}
|
||||
|
||||
public void setTokenValue(String tokenValue) {
|
||||
this.tokenValue = tokenValue;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public LocalDateTime getExpiresAt() {
|
||||
return expiresAt;
|
||||
}
|
||||
|
||||
public void setExpiresAt(LocalDateTime expiresAt) {
|
||||
this.expiresAt = expiresAt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.eactive.testmaster.login.repository;
|
||||
|
||||
import com.eactive.testmaster.login.entity.Token;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface TokenRepository extends JpaRepository<Token, String> {
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.eactive.testmaster.login.service;
|
||||
|
||||
import com.eactive.testmaster.login.entity.Token;
|
||||
import com.eactive.testmaster.login.repository.TokenRepository;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
public class TokenService {
|
||||
|
||||
@Autowired
|
||||
private TokenRepository tokenRepository;
|
||||
|
||||
public Token createToken(String email) {
|
||||
String token = UUID.randomUUID().toString();
|
||||
LocalDateTime expiresAt = LocalDateTime.now().plusHours(24);
|
||||
Token tokenObj = new Token(token, email, expiresAt);
|
||||
return tokenRepository.save(tokenObj);
|
||||
}
|
||||
|
||||
public Token findByToken(String token) {
|
||||
return tokenRepository.findById(token).orElse(null);
|
||||
}
|
||||
|
||||
public void deleteToken(Token token) {
|
||||
tokenRepository.delete(token);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.eactive.testmaster.user.controller;
|
||||
|
||||
import com.eactive.testmaster.common.util.SecurityUtil;
|
||||
import com.eactive.testmaster.user.dto.StaffPasswordChangeRequestDTO;
|
||||
import com.eactive.testmaster.user.dto.UserRegisterDTO;
|
||||
import com.eactive.testmaster.user.dto.UserSearch;
|
||||
import com.eactive.testmaster.user.dto.UserUpdateDTO;
|
||||
@@ -25,8 +26,9 @@ import org.springframework.web.bind.annotation.RequestParam;
|
||||
@RequestMapping("/mgmt/users")
|
||||
public class UserMgmtController {
|
||||
|
||||
public static final String STAFF_USER_EDIT = "page/users/staffUserEdit";
|
||||
public static final String USERS_LIST_VIEW = "redirect:/mgmt/users/list_view.do";
|
||||
private static final String STAFF_USER_EDIT = "page/users/staffUserEdit";
|
||||
private static final String USERS_LIST_VIEW = "redirect:/mgmt/users/list_view.do";
|
||||
private static final String STAFF_PASSWORD_RESET_VIEW = "page/users/staffPasswordReset";
|
||||
|
||||
private final StaffUserService staffUserService;
|
||||
|
||||
@@ -129,4 +131,23 @@ public class UserMgmtController {
|
||||
return USERS_LIST_VIEW;
|
||||
}
|
||||
|
||||
@PostMapping("/staff_password_reset_view.do")
|
||||
public String staffPasswordReset(@ModelAttribute("passwordChangeRequest") StaffPasswordChangeRequestDTO passwordChangeRequestDTO) {
|
||||
StaffUser found = staffUserService.findById(passwordChangeRequestDTO.getId());
|
||||
passwordChangeRequestDTO.setUsername(found.getUsername());
|
||||
return STAFF_PASSWORD_RESET_VIEW;
|
||||
}
|
||||
|
||||
@PostMapping("/update_staff_password.do")
|
||||
public String updateStaffPassword(@ModelAttribute("passwordChangeRequest") StaffPasswordChangeRequestDTO passwordChangeRequestDTO,
|
||||
BindingResult bindingResult) {
|
||||
|
||||
validator.validate(passwordChangeRequestDTO, bindingResult);
|
||||
if (bindingResult.hasErrors()) {
|
||||
return STAFF_PASSWORD_RESET_VIEW;
|
||||
}
|
||||
staffUserService.updatePassword(passwordChangeRequestDTO.getId(), passwordChangeRequestDTO.getNewPassword());
|
||||
return USERS_LIST_VIEW;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.eactive.testmaster.user.dto;
|
||||
|
||||
import com.eactive.testmaster.common.validator.PasswordMatch;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
|
||||
@PasswordMatch(input = "newPassword", confirm = "newPassword2")
|
||||
public class StaffPasswordChangeRequestDTO {
|
||||
|
||||
@NotEmpty(message = "{field.required}")
|
||||
private String id;
|
||||
|
||||
private String username;
|
||||
|
||||
@NotEmpty(message = "{field.required}")
|
||||
private String newPassword;
|
||||
|
||||
@NotEmpty(message = "{field.required}")
|
||||
private String newPassword2;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getNewPassword() {
|
||||
return newPassword;
|
||||
}
|
||||
|
||||
public void setNewPassword(String newPassword) {
|
||||
this.newPassword = newPassword;
|
||||
}
|
||||
|
||||
public String getNewPassword2() {
|
||||
return newPassword2;
|
||||
}
|
||||
|
||||
public void setNewPassword2(String newPassword2) {
|
||||
this.newPassword2 = newPassword2;
|
||||
}
|
||||
}
|
||||
@@ -62,7 +62,15 @@ public class StaffUserService {
|
||||
|
||||
staffUserRepository.save(user);
|
||||
|
||||
}
|
||||
|
||||
public void updatePassword(String id, String newPassword) {
|
||||
StaffUser user = staffUserRepository.findById(id).orElseThrow(() -> new UserNotFoundException(USER_NOT_FOUND_MESSAGE));
|
||||
user.setUserSecurity(newPassword);
|
||||
user.setLockAt(EnabledStatus.N);
|
||||
user.setLockCnt(0);
|
||||
user.setLastLockDate(null);
|
||||
staffUserRepository.save(user);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,17 @@ package com.eactive.testmaster.user.service;
|
||||
import com.eactive.testmaster.common.entity.EnabledStatus;
|
||||
import com.eactive.testmaster.common.exception.UserNotFoundException;
|
||||
import com.eactive.testmaster.common.util.EncryptionUtil;
|
||||
import com.eactive.testmaster.login.entity.Token;
|
||||
import com.eactive.testmaster.login.service.TokenService;
|
||||
import com.eactive.testmaster.user.entity.StaffUser;
|
||||
import com.eactive.testmaster.user.entity.User;
|
||||
import com.eactive.testmaster.user.repository.StaffUserRepository;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
@@ -17,14 +24,23 @@ import org.springframework.stereotype.Service;
|
||||
//@Transactional(propagation = Propagation.NESTED)
|
||||
public class UserService implements UserDetailsService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(UserService.class);
|
||||
|
||||
|
||||
public static final String USER_NOT_FOUND_MESSAGE = "사용자 정보가 존재하지 않습니다.";
|
||||
|
||||
@Autowired
|
||||
StaffUserRepository staffUserRepository;
|
||||
private final StaffUserRepository staffUserRepository;
|
||||
|
||||
@Autowired
|
||||
private EncryptionUtil encryptionUtil;
|
||||
|
||||
private final TokenService tokenService;
|
||||
|
||||
public UserService(StaffUserRepository staffUserRepository, EncryptionUtil encryptionUtil, TokenService tokenService) {
|
||||
this.staffUserRepository = staffUserRepository;
|
||||
this.encryptionUtil = encryptionUtil;
|
||||
this.tokenService = tokenService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
try {
|
||||
@@ -65,6 +81,25 @@ public class UserService implements UserDetailsService {
|
||||
staffUserRepository.save((StaffUser) user);
|
||||
}
|
||||
|
||||
public void requestPasswordReset(String email) {
|
||||
|
||||
Token token = tokenService.createToken(email);
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
String formattedDateTime = token.getExpiresAt().format(formatter);
|
||||
|
||||
params.put("userId", email);
|
||||
params.put("token", token.getTokenValue());
|
||||
params.put("expiresAt", formattedDateTime);
|
||||
|
||||
logger.info("requestPasswordReset::params= {}", params);
|
||||
}
|
||||
|
||||
public void resetPassword(String email, String newPassword) {
|
||||
User user = findByUserId(email);
|
||||
updatePassword(user, newPassword);
|
||||
}
|
||||
|
||||
public void updateUser(User user) {
|
||||
staffUserRepository.save((StaffUser) user);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
<!doctype html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/base_layout}">
|
||||
|
||||
|
||||
<body>
|
||||
|
||||
<section layout:fragment="contentFragment">
|
||||
|
||||
<div class="container">
|
||||
<div class="mt-2">
|
||||
<h3 class="text-center">비밀번호 초기화</h3>
|
||||
</div>
|
||||
|
||||
<div class="container-md container-sm d-flex flex-column flex-wrap align-items-center justify-content-center">
|
||||
<div class="card col-lg-4 col-md-8">
|
||||
<div class="card-body">
|
||||
<form name="passwordResetRequest" id="passwordResetRequest" role="form" th:action="@{/forgot_password.do}" method="post">
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
|
||||
<div class="form-floating">
|
||||
<input id="email" type="text" class="form-control mb-3" name="email" maxlength="30" required/>
|
||||
<label class="form-label" for="email">User ID</label>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div th:if="${param.expired != null}">
|
||||
<p>비밀번호 초기화 링크가 만료되었습니다.</p>
|
||||
</div>
|
||||
<div th:if="${#strings.isEmpty(error) == false}">
|
||||
<p th:text="${error}"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<div class="d-flex flex-wrap align-items-center justify-content-center">
|
||||
<button type="button" class="btn btn-primary btn_reset">초기화 요청</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form th:if="${param.success != null}" class="col-lg-4 col-md-8" name="resetPassword" role="form" th:action="@{/reset_password.do}" method="get">
|
||||
<div class="card mt-2 ">
|
||||
<div class="card-body">
|
||||
<div class="form-floating">
|
||||
<input id="resetToken" type="text" class="form-control mb-3" name="token" placeholder="Reset Token" required/>
|
||||
<label class="form-label">Token</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<div class="d-flex flex-wrap align-items-center justify-content-center">
|
||||
<button type="submit" class="btn btn-primary">초기화 페이지 열기</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="mt-2 text-center">
|
||||
<span class="text-muted"><a th:href="@{/login}">로그인</a></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
</body>
|
||||
|
||||
|
||||
<th:block layout:fragment="contentScript">
|
||||
<script>
|
||||
$(function() {
|
||||
document.getElementById('passwordResetRequest').email.focus();
|
||||
let btnReset = document.querySelector('.btn_reset');
|
||||
|
||||
btnReset.addEventListener('click', function(event) {
|
||||
let form = document.getElementById('passwordResetRequest');
|
||||
if (!form.checkValidity()) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
} else {
|
||||
form.submit();
|
||||
}
|
||||
form.classList.add('was-validated');
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
</th:block>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,80 @@
|
||||
<!doctype html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/base_layout}">
|
||||
|
||||
|
||||
<body>
|
||||
|
||||
<section layout:fragment="contentFragment">
|
||||
|
||||
<div class="container">
|
||||
<div class="mt-2">
|
||||
<h3 class="text-center">비밀번호 초기화</h3>
|
||||
</div>
|
||||
|
||||
<div class="container-md container-sm d-flex flex-wrap align-items-center justify-content-center">
|
||||
<div class="card col-lg-4 col-md-8">
|
||||
<div class="card-body">
|
||||
<form name="passwordResetRequest" id="passwordResetRequest" role="form" th:action="@{/reset_password.do}" method="post" th:object="${passwordReset}">
|
||||
<input type="hidden" name="token" th:value="${tokenValue}">
|
||||
<div class="form-floating">
|
||||
<input class="form-control mb-3" th:classappend="${#fields.hasErrors('password')}? 'is-invalid'" name="password" id="password" th:field="*{password}" type="password"
|
||||
size="20" value="" maxlength="100" required>
|
||||
<label for="password" class="must" th:text="#{comUssUmt.userManagePasswordUpdt.pass}"></label>
|
||||
<th:block th:each="err : ${#fields.errors('password')}">
|
||||
<div th:text="${err}" class="invalid-feedback"></div>
|
||||
</th:block>
|
||||
</div>
|
||||
<!-- 비밀번호확인 -->
|
||||
<div class="form-floating">
|
||||
<input class="form-control mb-3" th:classappend="${#fields.hasErrors('password2')}? 'is-invalid'" name="password2" id="password2" th:field="*{password2}"
|
||||
type="password" size="20" value="" maxlength="100" required>
|
||||
<label for="password2" class="must" th:text="#{comUssUmt.userManagePasswordUpdt.passConfirm}"></label>
|
||||
<th:block th:each="err : ${#fields.errors('password2')}">
|
||||
<div th:text="${err}" class="invalid-feedback"></div>
|
||||
</th:block>
|
||||
</div>
|
||||
</form>
|
||||
<div th:if="${param.success != null}">
|
||||
<p>비밀번호 초기화 되었습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<div class="d-flex flex-wrap align-items-center justify-content-center">
|
||||
<button type="button" class="btn btn-primary btn_reset">저장</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2 text-center">
|
||||
<span class="text-muted"><a th:href="@{/login}">로그인</a></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
</body>
|
||||
|
||||
|
||||
<th:block layout:fragment="contentScript">
|
||||
<script>
|
||||
$(function() {
|
||||
document.getElementById('passwordResetRequest').password.focus();
|
||||
let btnReset = document.querySelector('.btn_reset');
|
||||
|
||||
btnReset.addEventListener('click', function(event) {
|
||||
let form = document.getElementById('passwordResetRequest');
|
||||
if (!form.checkValidity()) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
} else {
|
||||
form.submit();
|
||||
}
|
||||
form.classList.add('was-validated');
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
</th:block>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,90 @@
|
||||
<!doctype html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout/default_layout}">
|
||||
|
||||
|
||||
<body>
|
||||
|
||||
<section layout:fragment="contentFragment">
|
||||
<div class="container-fluid">
|
||||
<div class="card mt-2">
|
||||
<div class="card-header">
|
||||
<h3>사용자 비밀 번호 변경</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form name="passwordChangeRequest" id="passwordChangeRequest" class="form-horizontal form-horizontal_l" method="post" th:action="@{/mgmt/users/update_staff_password.do}"
|
||||
th:object="${passwordChangeRequest}">
|
||||
<!-- 사용자 이름 -->
|
||||
<input type="hidden" th:field="*{id}">
|
||||
<div class="form-floating">
|
||||
<input class="form-control mb-3" name="username" id="username" th:field="*{username}" type="text" size="20" value="" maxlength="100" readonly>
|
||||
<label for="username" class="must">이름</label>
|
||||
</div>
|
||||
<!-- 비밀번호 -->
|
||||
<div class="form-floating">
|
||||
<input class="form-control mb-3" th:classappend="${#fields.hasErrors('newPassword')}? 'is-invalid'" name="newPassword" id="newPassword" th:field="*{newPassword}" type="password"
|
||||
size="20" value="" maxlength="100" required>
|
||||
<label for="newPassword" class="must" th:text="#{comUssUmt.userManagePasswordUpdt.pass}"></label>
|
||||
<th:block th:each="err : ${#fields.errors('newPassword')}">
|
||||
<div th:text="${err}" class="invalid-feedback"></div>
|
||||
</th:block>
|
||||
</div>
|
||||
<!-- 비밀번호확인 -->
|
||||
<div class="form-floating">
|
||||
<input class="form-control mb-3" th:classappend="${#fields.hasErrors('newPassword2')}? 'is-invalid'" name="newPassword2" id="newPassword2" th:field="*{newPassword2}"
|
||||
type="password" size="20" value="" maxlength="100" required>
|
||||
<label for="newPassword2" class="must" th:text="#{comUssUmt.userManagePasswordUpdt.passConfirm}"></label>
|
||||
<th:block th:each="err : ${#fields.errors('newPassword2')}">
|
||||
<div th:text="${err}" class="invalid-feedback"></div>
|
||||
</th:block>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" style="position: absolute; top: 0; right: 0;">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">알림</strong>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button type="button" class="btn btn-primary btn_update"><i class="fa-sharp fa-solid fa-floppy-disk"></i> 저장</button>
|
||||
<a th:href="@{/mgmt/users/list_view.do}" class="btn btn-primary" th:title="#{button.cancel}"><i class="fa-sharp fa-solid fa-cancel"></i> [[#{button.cancel}]]</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</body>
|
||||
|
||||
|
||||
<th:block layout:fragment="contentScript">
|
||||
<script>
|
||||
$(function () {
|
||||
document.getElementById("passwordChangeRequest").newPassword.focus();
|
||||
let btnUpdate = document.querySelector(".btn_update");
|
||||
btnUpdate.addEventListener("click", function (event) {
|
||||
let form = document.getElementById("passwordChangeRequest");
|
||||
if (!form.checkValidity()) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
} else {
|
||||
form.submit();
|
||||
}
|
||||
form.classList.add('was-validated');
|
||||
});
|
||||
})
|
||||
</script>
|
||||
<script th:if="${resultMsg != null}">
|
||||
$(function () {
|
||||
var resultMsg = '[[#{${resultMsg}}]]';
|
||||
if (resultMsg !== "") {
|
||||
$('.toast-body').text(resultMsg);
|
||||
$('.toast').toast('show');
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
</th:block>
|
||||
|
||||
</html>
|
||||
@@ -9,7 +9,7 @@
|
||||
<div class="container-fluid">
|
||||
<div class="card mt-2">
|
||||
<div class="card-header">
|
||||
<h3>사용자 목록</h1>
|
||||
<h3>사용자 목록</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between">
|
||||
@@ -90,6 +90,9 @@
|
||||
<button type="button" class="btn btn-primary btn-sm me-2" th:onclick="fnSelectItem([[${row.esntlId}]])" th:value="#{button.update}"><i class="fa-sharp fa-solid fa-edit"></i>
|
||||
[[#{button.update}]]
|
||||
</button>
|
||||
<button type="submit" class="btn btn-primary btn-sm me-2" th:onclick="fnUpdatePassword([[${row.esntlId}]])" ><i class="fa-sharp fa-solid fa-edit"></i>
|
||||
비밀번호 변경
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -119,9 +122,17 @@
|
||||
document.searchForm.submit();
|
||||
}
|
||||
|
||||
function fnUpdatePassword(id) {
|
||||
document.listForm.method = 'POST';
|
||||
document.listForm.action = '[[@{/mgmt/users/staff_password_reset_view.do}]]';
|
||||
document.listForm.id.value = id;
|
||||
document.listForm.submit();
|
||||
}
|
||||
|
||||
function fnSelectItem(id) {
|
||||
location.href = "[[@{/mgmt/users/update_view.do}]]" + "?userId=" + id;
|
||||
}
|
||||
|
||||
$(function () {
|
||||
let fnSearch = document.querySelector(".btn_search");
|
||||
let fnDelete = document.querySelector(".btn_delete");
|
||||
|
||||
Reference in New Issue
Block a user