diff --git a/egovframe-template-simple-react-contribution/src/components/commonCode/CheckBox.jsx b/egovframe-template-simple-react-contribution/src/components/commonCode/CheckBox.jsx index 10c0822..d3c09ee 100644 --- a/egovframe-template-simple-react-contribution/src/components/commonCode/CheckBox.jsx +++ b/egovframe-template-simple-react-contribution/src/components/commonCode/CheckBox.jsx @@ -2,16 +2,13 @@ import React, {useCallback, useEffect, useState} from "react"; import Form from "react-bootstrap/Form"; import * as EgovNet from "api/egovFetch"; -function CheckBox({name, grpCd, selectedValue}){ +function CheckBox({name, grpCd}){ const [checkBox, setCheckBox] = useState(); useEffect(() => { getCodeItemList() }, []); - useEffect(() => { - setCheckedValue(selectedValue) - }, [checkBox]); function getCodeItemList() { EgovNet.requestFetch( @@ -41,16 +38,6 @@ function CheckBox({name, grpCd, selectedValue}){ ); } - function setCheckedValue(selectedValue){ - debugger - const checkBoxDiv = document.querySelector("#"+grpCd+"_checkBoxDiv") - checkBoxDiv.childNodes.forEach(function (input){ - if(selectedValue.includes(input.children[0].value)){ - input.checked = true; - } - }) - } - return (
{checkBox} diff --git a/egovframe-template-simple-react-contribution/src/pages/admin/users/List.jsx b/egovframe-template-simple-react-contribution/src/pages/admin/users/List.jsx index 15b2c51..9dfa66b 100644 --- a/egovframe-template-simple-react-contribution/src/pages/admin/users/List.jsx +++ b/egovframe-template-simple-react-contribution/src/pages/admin/users/List.jsx @@ -8,6 +8,7 @@ import * as EgovNet from "api/egovFetch"; import {itemIdxByPage} from "utils/calc"; import Modal from "react-bootstrap/Modal"; import UserInfoModal from "./UserInfoModal"; +import CODE from "../../../constants/code"; function List(props) { @@ -57,7 +58,7 @@ function List(props) {
{item.email}
{item.phoneNum}
{item.status}
-
+
); }); @@ -78,6 +79,28 @@ function List(props) { handleShow() setModalBody() } + + function removeUserInfo(seq){ + if(window.confirm("삭제하시겠습니까?\n복구할 수 없습니다.")){ + EgovNet.requestFetch( + '/admin/users/info', + { + method: "DELETE", + headers: { + 'Content-type': 'application/json' + }, + body: JSON.stringify({userSeq: seq}) + }, + (resp) => { + if (Number(resp.resultCode) === Number(CODE.RCV_SUCCESS)) { + alert("삭제되었습니다.") + }else{ + alert("삭제를 실패하였습니다.") + } + } + ) + } + } return (
diff --git a/egovframe-template-simple-react-contribution/src/pages/admin/users/UserInfoModal.jsx b/egovframe-template-simple-react-contribution/src/pages/admin/users/UserInfoModal.jsx index 92a519d..95b1f72 100644 --- a/egovframe-template-simple-react-contribution/src/pages/admin/users/UserInfoModal.jsx +++ b/egovframe-template-simple-react-contribution/src/pages/admin/users/UserInfoModal.jsx @@ -7,10 +7,11 @@ import Col from "react-bootstrap/Col"; import Button from "react-bootstrap/Button"; import SelectOption from "components/commonCode/SelectOption"; import CheckBox from "components/commonCode/CheckBox"; +import CODE from "../../../constants/code"; function UserInfoModal({userSeq}){ - const [userInfo, setUserInfo] = useState({ userId: '', password: '', passwordChk: '', userNm: '', email: '', phoneNum: '', userSe:'', userRole:'', status:''}); + const [userInfo, setUserInfo] = useState({ userSeq: '', userId: '', password: '', passwordChk: '', userNm: '', email: '', phoneNum: '', userSe:'', userRole:'', status:''}); function getModalContent(){ EgovNet.requestFetch( @@ -19,18 +20,20 @@ function UserInfoModal({userSeq}){ method: "GET" }, (resp) => { - const respInfo = { - userId: resp.result.userInfo.userId, - userNm: resp.result.userInfo.userNm, - email: resp.result.userInfo.email, - phoneNum: resp.result.userInfo.phoneNum, + const respInfo = resp.result.userInfo; + const info = { + userSeq: respInfo.userSeq, + userId: respInfo.userId, + userNm: respInfo.userNm, + email: respInfo.email, + phoneNum: respInfo.phoneNum, password: "", passwordChk: "", - userSe: resp.result.userInfo.userSe, - userRole: resp.result.userInfo.userRole, - status: resp.result.userInfo.status + userSe: respInfo.userSe, + userRole: respInfo.userRole, + status: respInfo.status } - setUserInfo(respInfo); + setUserInfo(info); }, (resp) => { console.log("err response : ", resp); @@ -39,13 +42,68 @@ function UserInfoModal({userSeq}){ } function userInfoChange(e){ - debugger + e.preventDefault(); + e.stopPropagation(); + const form = e.target; + const info = { + userSeq: form.userSeq.value, + userId: form.userId.value, + password: form.password.value, + passwordChk: form.passwordChk.value, + userNm: form.userNm.value, + email: form.email.value, + phoneNum: form.phoneNum.value, + userSe: form.userSe.value, + userRole: '', + status: form.status.value, + } + let userRole = ''; + form.userRole.forEach(function (input){ + if(input.checked){ + userRole += input.value+',' + } + }) + if(userRole){ + info.userRole = userRole.slice(0, -1) + } + EgovNet.requestFetch( + '/admin/users/info', + { + method: "PUT", + headers: { + 'Content-type': 'application/json' + }, + body: JSON.stringify(info) + }, + (resp) => { + if (Number(resp.resultCode) === Number(CODE.RCV_SUCCESS)) { + alert("저장되었습니다.") + }else if(Number(resp.resultCode) === Number(CODE.RCV_ERROR_AUTH)){ + console.log("토큰 갱신중.") + }else{ + alert(resp.result.resultMessage) + } + } + ) } useEffect(() => { getModalContent(); }, []); + useEffect(()=>{ + const checkBoxDiv = document.querySelector("#ROLE_checkBoxDiv") + const userRole = userInfo.userRole; + if(userRole){ + checkBoxDiv.childNodes.forEach(function (div){ + const input = div.children[0]; + if(userRole.includes(input.value)){ + input.checked = true; + } + }) + } + }, [userInfo]); + return ( <> @@ -55,12 +113,13 @@ function UserInfoModal({userSeq}){
{userInfoChange(e)}} noValidate> + 아이디 - + @@ -116,7 +175,7 @@ function UserInfoModal({userSeq}){ 사용자 권한 - + diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/users/AdminUsersController.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/users/AdminUsersController.java index 1c4247e..dc69c89 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/users/AdminUsersController.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/users/AdminUsersController.java @@ -2,18 +2,26 @@ package com.dbnt.kcscbackend.admin.users; import com.dbnt.kcscbackend.admin.users.service.AdminUsersService; +import com.dbnt.kcscbackend.auth.entity.LoginVO; import com.dbnt.kcscbackend.auth.entity.UserInfo; import com.dbnt.kcscbackend.config.common.BaseController; +import com.dbnt.kcscbackend.config.common.ResponseCode; import com.dbnt.kcscbackend.config.common.ResultVO; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.validation.Errors; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; +import javax.validation.Valid; import java.util.HashMap; import java.util.Map; @@ -65,4 +73,67 @@ public class AdminUsersController extends BaseController { return resultVO; } + @Operation( + summary = "사용자 정보 수정", + description = "사용자 정보 수정", + tags = {"AdminUsersController"} + ) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "수정 성공"), + @ApiResponse(responseCode = "403", description = "인가된 사용자가 아님") + }) + @RequestMapping(method = RequestMethod.PUT, value = "/info") + public ResultVO modifyUserInfo(@RequestBody @Valid UserInfo info, Errors errors, @AuthenticationPrincipal LoginVO user) throws Exception{ + ResultVO resultVO = new ResultVO(); + Map resultMap = new HashMap<>(); + if(errors.hasErrors()){ + StringBuilder msg = new StringBuilder(); + for(FieldError error: errors.getFieldErrors()){ + msg.append(error.getDefaultMessage()); + msg.append("\n"); + } + resultMap.put("resultCode", ResponseCode.INPUT_CHECK_ERROR.getCode()); + resultMap.put("resultMessage", msg.toString()); + }else if(!info.getPassword().equals(info.getPasswordChk())){ + resultMap.put("resultCode", ResponseCode.SAVE_ERROR.getCode()); + resultMap.put("resultMessage", "비밀번호 확인이 잘못 입력되었습니다."); + }else { + Integer insertResult = adminUsersService.updateUserInfo(info, user.getId()); + if(insertResult!=null){ + if(insertResult==-1){ + resultMap.put("resultCode", ResponseCode.SAVE_ERROR.getCode()); + resultMap.put("resultMessage", "수정 대상이 존재하지 않습니다."); + }else if(insertResult==-2){ + resultMap.put("resultCode", ResponseCode.SAVE_ERROR.getCode()); + resultMap.put("resultMessage", "가입된 이메일입니다."); + }else{ + resultMap.put("resultCode", ResponseCode.SUCCESS.getCode()); + resultMap.put("resultMessage", "저장 되었습니다."); + } + }else{ + resultMap.put("resultCode", ResponseCode.SAVE_ERROR.getCode()); + resultMap.put("resultMessage", "저장에 실패하였습니다."); + } + } + resultVO.setResult(resultMap); + return resultVO; + } + + @Operation( + summary = "사용자 정보 삭제", + description = "사용자 정보 삭제", + tags = {"AdminUsersController"} + ) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "삭제 성공"), + @ApiResponse(responseCode = "403", description = "인가된 사용자가 아님") + }) + @RequestMapping(method = RequestMethod.DELETE, value = "/info", consumes = MediaType.APPLICATION_JSON_VALUE) + public ResultVO deleteUserInfo(UserInfo info) throws Exception{ + ResultVO resultVO = new ResultVO(); + adminUsersService.deleteUserInfo(info.getUserSeq()); + resultVO.setResultCode(ResponseCode.SUCCESS.getCode()); + return resultVO; + } + } diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/users/service/AdminUsersService.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/users/service/AdminUsersService.java index 7b1d7ca..c5c7671 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/users/service/AdminUsersService.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/admin/users/service/AdminUsersService.java @@ -6,7 +6,9 @@ import com.dbnt.kcscbackend.auth.repository.UserInfoRepository; import lombok.RequiredArgsConstructor; import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDateTime; import java.util.List; @Service @@ -29,4 +31,37 @@ public class AdminUsersService extends EgovAbstractServiceImpl { info.setPassword(null); return info; } + + @Transactional + public Integer updateUserInfo(UserInfo info, String updateUser) { + UserInfo savedInfo = userInfoRepository.findById(info.getUserSeq()).orElse(null); + UserInfo emailChk = userInfoRepository.findByEmail(info.getEmail()).orElse(null); + if(savedInfo==null){ + return -1; + }else if(emailChk != null){ + if(!emailChk.getUserSeq().equals(info.getUserSeq())){ + return -2; + } + } + + savedInfo.setUserNm(info.getUserNm()); + if(!info.getPassword().isEmpty()){ + savedInfo.setPassword(info.convertPassword(info.getPassword())); + } + savedInfo.setEmail(info.getEmail()); + savedInfo.setPhoneNum(info.getPhoneNum()); + savedInfo.setUserSe(info.getUserSe()); + savedInfo.setUserRole(info.getUserRole()); + savedInfo.setStatus(info.getStatus()); + savedInfo.setLastChgId(updateUser); + savedInfo.setLastChgDt(LocalDateTime.now()); + + return savedInfo.getUserSeq(); + } + + @Transactional + public void deleteUserInfo(Integer userSeq) { + userInfoRepository.deleteById(userSeq); + } + } diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/entity/UserInfo.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/entity/UserInfo.java index 869c47e..5e22327 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/entity/UserInfo.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/entity/UserInfo.java @@ -2,6 +2,7 @@ package com.dbnt.kcscbackend.auth.entity; import com.dbnt.kcscbackend.config.common.BoardParams; import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -11,8 +12,12 @@ import org.springframework.format.annotation.DateTimeFormat; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder; import javax.persistence.*; +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Collection; @@ -32,16 +37,23 @@ public class UserInfo extends BoardParams implements UserDetails{ @Column(name = "user_seq") private Integer userSeq; @Column(name = "user_id") + @Pattern(regexp = "^[a-zA-Z]{1}[a-zA-Z0-9_]{4,11}$") + @NotBlank(message = "아이디를 입력해주세요.") private String userId; @Column(name = "password") private String password; @Column(name = "email") + @Email(message = "이메일 형식에 맞지 않습니다.") + @Schema(description = "이메일주소") + @NotBlank(message = "이메일을 입력해주세요.") private String email; @Column(name = "user_se") private String userSe; @Column(name = "user_nm") + @NotBlank(message = "이름을 입력해주세요.") private String userNm; @Column(name = "phone_num") + @NotBlank(message = "연락처를 입력해주세요.") private String phoneNum; @Column(name = "user_role") private String userRole; @@ -56,6 +68,9 @@ public class UserInfo extends BoardParams implements UserDetails{ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime lastChgDt; + @Transient + private String passwordChk; + @Override @JsonIgnore public Collection getAuthorities() { @@ -92,4 +107,11 @@ public class UserInfo extends BoardParams implements UserDetails{ return getStatus().equals("USE_ST"); } + + + public String convertPassword(String password){ + Pbkdf2PasswordEncoder passwordEncoder = new Pbkdf2PasswordEncoder(); + return passwordEncoder.encode(password); + } + } diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/service/impl/EgovLoginServiceImpl.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/service/impl/EgovLoginServiceImpl.java index 07d27aa..1f07ead 100644 --- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/service/impl/EgovLoginServiceImpl.java +++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/service/impl/EgovLoginServiceImpl.java @@ -59,7 +59,7 @@ public class EgovLoginServiceImpl extends EgovAbstractServiceImpl implements Ego } UserInfo info = new UserInfo(); info.setUserId(loginVO.getId()); - info.setPassword(convertPassword(loginVO.getPassword())); + info.setPassword(info.convertPassword(loginVO.getPassword())); info.setUserNm(loginVO.getUserNm()); info.setEmail(loginVO.getEmail()); info.setPhoneNum(loginVO.getPhoneNum()); @@ -85,7 +85,7 @@ public class EgovLoginServiceImpl extends EgovAbstractServiceImpl implements Ego int rdNum = rd.nextInt(95)+33; password.append((char)rdNum); } - user.setPassword(convertPassword(password.toString())); + user.setPassword(user.convertPassword(password.toString())); return password.toString(); } return null; @@ -184,9 +184,4 @@ public class EgovLoginServiceImpl extends EgovAbstractServiceImpl implements Ego return result; } - - private String convertPassword(String password){ - Pbkdf2PasswordEncoder passwordEncoder = new Pbkdf2PasswordEncoder(); - return passwordEncoder.encode(password); - } } \ No newline at end of file