From 95cb8dc2c6e4a670fec40366365121b776fdd9e3 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Mon, 24 Jul 2023 16:54:00 +0900 Subject: [PATCH 001/128] init security --- build.gradle | 1 + .../_core/errors/MyExceptionHandler.java | 48 ++++++++++ .../_core/errors/MyValidationHandler.java | 38 ++++++++ .../_core/errors/exception/Exception400.java | 27 ++++++ .../_core/errors/exception/Exception401.java | 22 +++++ .../_core/errors/exception/Exception403.java | 21 ++++ .../_core/errors/exception/Exception404.java | 21 ++++ .../_core/errors/exception/Exception500.java | 23 +++++ .../_core/security/CustomUserDetails.java | 54 +++++++++++ .../security/CustomUserDetailsService.java | 32 +++++++ .../security/JwtAuthenticationFilter.java | 64 +++++++++++++ .../_core/security/JwtTokenProvider.java | 38 ++++++++ .../_core/security/SecurityConfig.java | 96 +++++++++++++++++++ .../_core/util/ApiUtils.java | 34 +++++++ .../_core/util/DateUtils.java | 10 ++ .../_core/util/FilterResponseUtils.java | 26 +++++ .../example/kdtbe5_miniproject/user/User.java | 27 ++++++ .../user/UserRepository.java | 14 +++ .../kdtbe5_miniproject/user/UserService.java | 7 ++ 19 files changed, 603 insertions(+) create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/errors/MyExceptionHandler.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/errors/MyValidationHandler.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception400.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception401.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception403.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception404.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception500.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetails.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetailsService.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtAuthenticationFilter.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtTokenProvider.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/security/SecurityConfig.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/util/ApiUtils.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/util/DateUtils.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/util/FilterResponseUtils.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/user/User.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/user/UserService.java diff --git a/build.gradle b/build.gradle index 354ed98..b3e9142 100644 --- a/build.gradle +++ b/build.gradle @@ -32,6 +32,7 @@ dependencies { annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' + implementation group: 'com.auth0', name: 'java-jwt', version: '4.3.0' } tasks.named('test') { diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/MyExceptionHandler.java b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/MyExceptionHandler.java new file mode 100644 index 0000000..5da146c --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/MyExceptionHandler.java @@ -0,0 +1,48 @@ +package com.example.kdtbe5_miniproject._core.errors; + +import com.example.kdtbe5_miniproject._core.errors.exception.*; +import com.example.kdtbe5_miniproject._core.util.ApiUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + + +@Slf4j +@RequiredArgsConstructor +@RestControllerAdvice +public class MyExceptionHandler { + + @ExceptionHandler(Exception400.class) + public ResponseEntity badRequest(Exception400 e) { + return new ResponseEntity<>(e.body(), e.status()); + } + + @ExceptionHandler(Exception401.class) + public ResponseEntity unAuthorized(Exception401 e) { + return new ResponseEntity<>(e.body(), e.status()); + } + + @ExceptionHandler(Exception403.class) + public ResponseEntity forbidden(Exception403 e) { + return new ResponseEntity<>(e.body(), e.status()); + } + + @ExceptionHandler(Exception404.class) + public ResponseEntity notFound(Exception404 e) { + return new ResponseEntity<>(e.body(), e.status()); + } + + @ExceptionHandler(Exception500.class) + public ResponseEntity serverError(Exception500 e) { + return new ResponseEntity<>(e.body(), e.status()); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity unknownServerError(Exception e) { + ApiUtils.ApiResult apiResult = ApiUtils.error(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + return new ResponseEntity<>(apiResult, HttpStatus.INTERNAL_SERVER_ERROR); + } +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/MyValidationHandler.java b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/MyValidationHandler.java new file mode 100644 index 0000000..a80f0ab --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/MyValidationHandler.java @@ -0,0 +1,38 @@ +package com.example.kdtbe5_miniproject._core.errors; + +import com.example.kdtbe5_miniproject._core.errors.exception.Exception400; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.stereotype.Component; +import org.springframework.validation.Errors; + +@Aspect +@Component +public class MyValidationHandler { + @Pointcut("@annotation(org.springframework.web.bind.annotation.PostMapping)") + public void postMapping() { + } + + @Pointcut("@annotation(org.springframework.web.bind.annotation.PutMapping)") + public void putMapping() { + } + + @Before("postMapping() || putMapping()") + public void validationAdvice(JoinPoint jp) { + Object[] args = jp.getArgs(); + for (Object arg : args) { + if (arg instanceof Errors) { + Errors errors = (Errors) arg; + + if (errors.hasErrors()) { + throw new Exception400( + errors.getFieldErrors().get(0).getField(), + errors.getFieldErrors().get(0).getDefaultMessage() + ); + } + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception400.java b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception400.java new file mode 100644 index 0000000..3677040 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception400.java @@ -0,0 +1,27 @@ +package com.example.kdtbe5_miniproject._core.errors.exception; + +import com.example.kdtbe5_miniproject._core.util.ApiUtils; +import lombok.Getter; +import org.springframework.http.HttpStatus; + + +@Getter +public class Exception400 extends RuntimeException { + + private String key; + private String value; + + public Exception400(String key, String value) { + super(key + " : " + value); + this.key = key; + this.value = value; + } + + public ApiUtils.ApiResult body() { + return ApiUtils.error(getMessage(), HttpStatus.BAD_REQUEST); + } + + public HttpStatus status() { + return HttpStatus.BAD_REQUEST; + } +} \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception401.java b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception401.java new file mode 100644 index 0000000..ea564e2 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception401.java @@ -0,0 +1,22 @@ +package com.example.kdtbe5_miniproject._core.errors.exception; + + +import com.example.kdtbe5_miniproject._core.util.ApiUtils; +import lombok.Getter; +import org.springframework.http.HttpStatus; + + +@Getter +public class Exception401 extends RuntimeException { + public Exception401(String message) { + super(message); + } + + public ApiUtils.ApiResult body() { + return ApiUtils.error(getMessage(), HttpStatus.UNAUTHORIZED); + } + + public HttpStatus status() { + return HttpStatus.UNAUTHORIZED; + } +} \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception403.java b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception403.java new file mode 100644 index 0000000..465e5bd --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception403.java @@ -0,0 +1,21 @@ +package com.example.kdtbe5_miniproject._core.errors.exception; + +import com.example.kdtbe5_miniproject._core.util.ApiUtils; +import lombok.Getter; +import org.springframework.http.HttpStatus; + + +@Getter +public class Exception403 extends RuntimeException { + public Exception403(String message) { + super(message); + } + + public ApiUtils.ApiResult body() { + return ApiUtils.error(getMessage(), HttpStatus.FORBIDDEN); + } + + public HttpStatus status() { + return HttpStatus.FORBIDDEN; + } +} \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception404.java b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception404.java new file mode 100644 index 0000000..0feb80a --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception404.java @@ -0,0 +1,21 @@ +package com.example.kdtbe5_miniproject._core.errors.exception; + +import com.example.kdtbe5_miniproject._core.util.ApiUtils; +import lombok.Getter; +import org.springframework.http.HttpStatus; + + +@Getter +public class Exception404 extends RuntimeException { + public Exception404(String message) { + super(message); + } + + public ApiUtils.ApiResult body() { + return ApiUtils.error(getMessage(), HttpStatus.NOT_FOUND); + } + + public HttpStatus status() { + return HttpStatus.NOT_FOUND; + } +} \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception500.java b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception500.java new file mode 100644 index 0000000..ba32d8e --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception500.java @@ -0,0 +1,23 @@ +package com.example.kdtbe5_miniproject._core.errors.exception; + +import com.example.kdtbe5_miniproject._core.util.ApiUtils; +import lombok.Getter; +import org.springframework.http.HttpStatus; + + +@Getter +public class Exception500 extends RuntimeException { + public Exception500(String message) { + super(message); + } + + + public ApiUtils.ApiResult body() { + return ApiUtils.error(getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + } + + public HttpStatus status() { + return HttpStatus.INTERNAL_SERVER_ERROR; + } + +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetails.java b/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetails.java new file mode 100644 index 0000000..c6fe322 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetails.java @@ -0,0 +1,54 @@ +package com.example.kdtbe5_miniproject._core.security; + +import com.example.kdtbe5_miniproject.user.User; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.Arrays; +import java.util.Collection; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +@Getter +public class CustomUserDetails implements UserDetails { + + private final User user; + + @Override + public Collection getAuthorities() { + return Arrays.stream(user.getRoles().split(",")).map(SimpleGrantedAuthority::new).collect(Collectors.toList()); + } + + @Override + public String getPassword() { + return user.getPassword(); + } + + @Override + public String getUsername() { + return user.getUsername(); + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetailsService.java b/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetailsService.java new file mode 100644 index 0000000..1d5b6b7 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetailsService.java @@ -0,0 +1,32 @@ +package com.example.kdtbe5_miniproject._core.security; + +import com.example.kdtbe5_miniproject.user.User; +import com.example.kdtbe5_miniproject.user.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +import java.util.Optional; + +@RequiredArgsConstructor +@Service +public class CustomUserDetailsService implements UserDetailsService { + + private final UserRepository userRepository; + + // login 호출 + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + System.out.println("username : " + username); + Optional userOP = userRepository.findByUsername(username); + + if (userOP.isPresent()) { + return new CustomUserDetails(userOP.get()); + } else { + return null; + } + + } +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtAuthenticationFilter.java b/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtAuthenticationFilter.java new file mode 100644 index 0000000..ae515ac --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtAuthenticationFilter.java @@ -0,0 +1,64 @@ +package com.example.kdtbe5_miniproject._core.security; + + +import com.auth0.jwt.exceptions.JWTDecodeException; +import com.auth0.jwt.exceptions.SignatureVerificationException; +import com.auth0.jwt.exceptions.TokenExpiredException; +import com.auth0.jwt.interfaces.DecodedJWT; +import com.example.kdtbe5_miniproject.user.User; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@Slf4j +public class JwtAuthenticationFilter extends BasicAuthenticationFilter { + + public JwtAuthenticationFilter(AuthenticationManager authenticationManager) { + super(authenticationManager); + } + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { + String prefixJwt = request.getHeader(JwtTokenProvider.HEADER); + + if (prefixJwt == null) { + chain.doFilter(request, response); + return; + } + + String jwt = prefixJwt.replace(JwtTokenProvider.TOKEN_PREFIX, ""); + try { + DecodedJWT decodedJWT = JwtTokenProvider.verify(jwt); // 신원인증 끝 + Long id = decodedJWT.getClaim("id").asLong(); + String roles = decodedJWT.getClaim("role").asString(); + + User user = User.builder().id(id).roles(roles).build(); + CustomUserDetails myUserDetails = new CustomUserDetails(user); + Authentication authentication = + new UsernamePasswordAuthenticationToken( + myUserDetails, + myUserDetails.getPassword(), + myUserDetails.getAuthorities() + ); + SecurityContextHolder.getContext().setAuthentication(authentication); + log.debug("디버그 : 인증 객체 만들어짐"); + } catch (SignatureVerificationException sve) { + log.error("토큰 검증 실패"); + } catch (TokenExpiredException tee) { + log.error("토큰 만료됨"); + } catch (JWTDecodeException tee) { + log.error("토큰 만료됨"); + } finally { + chain.doFilter(request, response); + } + } +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtTokenProvider.java b/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtTokenProvider.java new file mode 100644 index 0000000..ea00f62 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtTokenProvider.java @@ -0,0 +1,38 @@ +package com.example.kdtbe5_miniproject._core.security; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.exceptions.SignatureVerificationException; +import com.auth0.jwt.exceptions.TokenExpiredException; +import com.auth0.jwt.interfaces.DecodedJWT; +import com.example.kdtbe5_miniproject.user.User; +import org.springframework.stereotype.Component; + +import java.util.Date; + + +@Component +public class JwtTokenProvider { + public static final Long EXP = 1000L * 60 * 60 * 48; // 48시간 - 테스트 하기 편함. + public static final String TOKEN_PREFIX = "Bearer "; // 스페이스 필요함 + public static final String HEADER = "Authorization"; + public static final String SECRET = "MySecretKey"; + + public static String create(User user) { + // 토큰에는 데이터를 담을 수 있다. 민감한 정보는 추가하면 절대 안된다. + String jwt = JWT.create() + .withSubject(user.getEmail()) + .withExpiresAt(new Date(System.currentTimeMillis() + EXP)) + .withClaim("id", user.getId()) + .withClaim("role", user.getRoles()) + .sign(Algorithm.HMAC512(SECRET)); + return TOKEN_PREFIX + jwt; + } + + public static DecodedJWT verify(String jwt) throws SignatureVerificationException, TokenExpiredException { + DecodedJWT decodedJWT = JWT.require(Algorithm.HMAC512(SECRET)) + .build().verify(jwt); + return decodedJWT; + } + +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/security/SecurityConfig.java b/src/main/java/com/example/kdtbe5_miniproject/_core/security/SecurityConfig.java new file mode 100644 index 0000000..0e2c4f6 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/security/SecurityConfig.java @@ -0,0 +1,96 @@ +package com.example.kdtbe5_miniproject._core.security; + +import com.example.kdtbe5_miniproject._core.errors.exception.Exception401; +import com.example.kdtbe5_miniproject._core.errors.exception.Exception403; +import com.example.kdtbe5_miniproject._core.util.FilterResponseUtils; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.factory.PasswordEncoderFactories; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; + +@Configuration +public class SecurityConfig { + + @Bean + public PasswordEncoder passwordEncoder() { + return PasswordEncoderFactories.createDelegatingPasswordEncoder(); + } + + @Bean + public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { + return authenticationConfiguration.getAuthenticationManager(); + } + + public class CustomSecurityFilterManager extends AbstractHttpConfigurer { + @Override + public void configure(HttpSecurity builder) throws Exception { + AuthenticationManager authenticationManager = builder.getSharedObject(AuthenticationManager.class); + builder.addFilter(new JwtAuthenticationFilter(authenticationManager)); + super.configure(builder); + } + } + + @Bean // 컴퍼넌트 스캔시에 @Bean이 붙은 메서드가 있으면 실행시켜서 리턴되는 값을 IoC에 등록하는 깃발 + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + // 1. CSRF 해제 + http.csrf().disable(); // postman 접근해야 함!! - CSR 할때!! + + // 2. iframe 거부 + http.headers().frameOptions().sameOrigin(); + + // 3. cors 재설정 + http.cors().configurationSource(configurationSource()); + + // 4. jSessionId가 응답이 될 때 세션영 역에서 사라진다 (이게 stateless) + http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); + + // 5. form 로긴 해제 (UsernamePasswordAuthenticationFilter 비활성화) + http.formLogin().disable(); + + // 6. 로그인 인증창이 뜨지 않게 비활성화 + http.httpBasic().disable(); + + // 7. 커스텀 필터 적용 (시큐리티 필터 교환) + http.apply(new CustomSecurityFilterManager()); + + // 8. 인증 실패 처리 + http.exceptionHandling().authenticationEntryPoint((request, response, authException) -> { + FilterResponseUtils.unAuthorized(response, new Exception401("인증되지 않았습니다")); + }); + + // 9. 권한 실패 처리 + http.exceptionHandling().accessDeniedHandler((request, response, accessDeniedException) -> { + FilterResponseUtils.forbidden(response, new Exception403("권한이 없습니다")); + }); + + // 11. 인증, 권한 필터 설정 + http.authorizeRequests( + authorize -> authorize.antMatchers("/account/**").authenticated() + .antMatchers("/admin/**").access("hasRole('ADMIN')") + .anyRequest().permitAll() + ); + return http.build(); + } + + public CorsConfigurationSource configurationSource() { + CorsConfiguration configuration = new CorsConfiguration(); + configuration.addAllowedHeader("*"); + configuration.addAllowedMethod("*"); // GET, POST, PUT, DELETE (Javascript 요청 허용) + // localhost:8080 백엔드, localhost:3000 프론트엔드 + configuration.addAllowedOriginPattern("*"); // 모든 IP 주소 허용 (프론트 앤드 IP만 허용 react) + configuration.setAllowCredentials(true); // 클라이언트에서 쿠키 요청 허용 + configuration.addExposedHeader("Authorization"); // 옛날에는 디폴트 였다. 지금은 아닙니다. + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", configuration); // /login, /board, /product/ + return source; + } +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/util/ApiUtils.java b/src/main/java/com/example/kdtbe5_miniproject/_core/util/ApiUtils.java new file mode 100644 index 0000000..bc71ac8 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/util/ApiUtils.java @@ -0,0 +1,34 @@ +package com.example.kdtbe5_miniproject._core.util; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import org.springframework.http.HttpStatus; + +// 공통 응답 DTO +public class ApiUtils { + public static ApiResult success(T response) { + return new ApiResult<>(true, response, null); + } + + public static ApiResult error(String message, HttpStatus status) { + return new ApiResult<>(false, null, new ApiError(message, status.value())); + } + + @Getter + @Setter + @AllArgsConstructor + public static class ApiResult { + private final boolean success; + private final T response; + private final ApiError error; + } + + @Getter + @Setter + @AllArgsConstructor + public static class ApiError { + private final String message; + private final int status; + } +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/util/DateUtils.java b/src/main/java/com/example/kdtbe5_miniproject/_core/util/DateUtils.java new file mode 100644 index 0000000..6fed68d --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/util/DateUtils.java @@ -0,0 +1,10 @@ +package com.example.kdtbe5_miniproject._core.util; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public class DateUtils { + public static String toStringFormat(LocalDateTime localDateTime) { + return localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + } +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/util/FilterResponseUtils.java b/src/main/java/com/example/kdtbe5_miniproject/_core/util/FilterResponseUtils.java new file mode 100644 index 0000000..842d981 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/util/FilterResponseUtils.java @@ -0,0 +1,26 @@ +package com.example.kdtbe5_miniproject._core.util; + +import com.example.kdtbe5_miniproject._core.errors.exception.Exception401; +import com.example.kdtbe5_miniproject._core.errors.exception.Exception403; +import com.fasterxml.jackson.databind.ObjectMapper; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +public class FilterResponseUtils { + public static void unAuthorized(HttpServletResponse resp, Exception401 e) throws IOException { + resp.setStatus(e.status().value()); + resp.setContentType("application/json; charset=utf-8"); + ObjectMapper om = new ObjectMapper(); + String responseBody = om.writeValueAsString(e.body()); + resp.getWriter().println(responseBody); + } + + public static void forbidden(HttpServletResponse resp, Exception403 e) throws IOException { + resp.setStatus(e.status().value()); + resp.setContentType("application/json; charset=utf-8"); + ObjectMapper om = new ObjectMapper(); + String responseBody = om.writeValueAsString(e.body()); + resp.getWriter().println(responseBody); + } +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/User.java b/src/main/java/com/example/kdtbe5_miniproject/user/User.java new file mode 100644 index 0000000..90c53e1 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/user/User.java @@ -0,0 +1,27 @@ +package com.example.kdtbe5_miniproject.user; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Getter +public class User { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String email; + private String roles; + private String username; + private String password; + +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java new file mode 100644 index 0000000..e29aa2b --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java @@ -0,0 +1,14 @@ +package com.example.kdtbe5_miniproject.user; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface UserRepository extends JpaRepository { + + + Optional findByUsername(@Param("username") String username); +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java new file mode 100644 index 0000000..95bb8a3 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java @@ -0,0 +1,7 @@ +package com.example.kdtbe5_miniproject.user; + +import org.springframework.stereotype.Service; + +@Service +public class UserService { +} From 258b77cf074ff1ea33d2fb4c841c4564115395cd Mon Sep 17 00:00:00 2001 From: JOOWON Date: Mon, 24 Jul 2023 17:21:07 +0900 Subject: [PATCH 002/128] =?UTF-8?q?yml=20=ED=99=98=EA=B2=BD=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-dev.yml | 29 +++++++++++++++++++++++ src/main/resources/application-prod.yml | 25 +++++++++++++++++++ src/main/resources/application-test.yml | 29 +++++++++++++++++++++++ src/main/resources/application.properties | 1 - src/main/resources/application.yml | 4 ++++ 5 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/application-dev.yml create mode 100644 src/main/resources/application-prod.yml create mode 100644 src/main/resources/application-test.yml delete mode 100644 src/main/resources/application.properties create mode 100644 src/main/resources/application.yml diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml new file mode 100644 index 0000000..b852d74 --- /dev/null +++ b/src/main/resources/application-dev.yml @@ -0,0 +1,29 @@ +server: + servlet: + encoding: + charset: utf-8 + force: true + port: 8080 +spring: + datasource: + url: jdbc:h2:mem:test;MODE=MySQL + driver-class-name: org.h2.Driver + username: sa + password: + h2: + console: + enabled: true + jpa: + hibernate: + ddl-auto: create + show-sql: true + properties: + hibernate: + format_sql: true + default_batch_fetch_size: 100 + open-in-view: false + +logging: + level: + '[MiniProject.Server]': DEBUG + '[org.hibernate.type]': TRACE \ No newline at end of file diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml new file mode 100644 index 0000000..b69d3b4 --- /dev/null +++ b/src/main/resources/application-prod.yml @@ -0,0 +1,25 @@ +server: + servlet: + encoding: + charset: utf-8 + force: true + port: 8080 +spring: + datasource: + url: jdbc:mariadb://${DB_HOST}:${DB_PORT}/${DB_NAME}?allowPublicKeyRetrieval=true&useSSL=false + # driver-class-name: org.mariadb.jdbc.Driver + username: ${DB_USERNAME} + password: ${DB_PASSWORD} + h2: + console: + enabled: true + jpa: + hibernate: + ddl-auto: none + properties: + default_batch_fetch_size: 100 + open-in-view: false + +logging: + level: + '[MiniProject.Server]': INFO \ No newline at end of file diff --git a/src/main/resources/application-test.yml b/src/main/resources/application-test.yml new file mode 100644 index 0000000..b852d74 --- /dev/null +++ b/src/main/resources/application-test.yml @@ -0,0 +1,29 @@ +server: + servlet: + encoding: + charset: utf-8 + force: true + port: 8080 +spring: + datasource: + url: jdbc:h2:mem:test;MODE=MySQL + driver-class-name: org.h2.Driver + username: sa + password: + h2: + console: + enabled: true + jpa: + hibernate: + ddl-auto: create + show-sql: true + properties: + hibernate: + format_sql: true + default_batch_fetch_size: 100 + open-in-view: false + +logging: + level: + '[MiniProject.Server]': DEBUG + '[org.hibernate.type]': TRACE \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties deleted file mode 100644 index 8b13789..0000000 --- a/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..41ba440 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,4 @@ +spring: + profiles: + active: + - dev \ No newline at end of file From a91128061870c09d8426096ea004fa39f471b7bb Mon Sep 17 00:00:00 2001 From: JOOWON Date: Mon, 24 Jul 2023 16:54:00 +0900 Subject: [PATCH 003/128] feat:init security --- build.gradle | 1 + .../_core/errors/MyExceptionHandler.java | 48 ++++++++++ .../_core/errors/MyValidationHandler.java | 38 ++++++++ .../_core/errors/exception/Exception400.java | 27 ++++++ .../_core/errors/exception/Exception401.java | 22 +++++ .../_core/errors/exception/Exception403.java | 21 ++++ .../_core/errors/exception/Exception404.java | 21 ++++ .../_core/errors/exception/Exception500.java | 23 +++++ .../_core/security/CustomUserDetails.java | 54 +++++++++++ .../security/CustomUserDetailsService.java | 32 +++++++ .../security/JwtAuthenticationFilter.java | 64 +++++++++++++ .../_core/security/JwtTokenProvider.java | 38 ++++++++ .../_core/security/SecurityConfig.java | 96 +++++++++++++++++++ .../_core/util/ApiUtils.java | 34 +++++++ .../_core/util/DateUtils.java | 10 ++ .../_core/util/FilterResponseUtils.java | 26 +++++ .../example/kdtbe5_miniproject/user/User.java | 27 ++++++ .../user/UserRepository.java | 14 +++ .../kdtbe5_miniproject/user/UserService.java | 7 ++ 19 files changed, 603 insertions(+) create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/errors/MyExceptionHandler.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/errors/MyValidationHandler.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception400.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception401.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception403.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception404.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception500.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetails.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetailsService.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtAuthenticationFilter.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtTokenProvider.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/security/SecurityConfig.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/util/ApiUtils.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/util/DateUtils.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/util/FilterResponseUtils.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/user/User.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/user/UserService.java diff --git a/build.gradle b/build.gradle index 354ed98..b3e9142 100644 --- a/build.gradle +++ b/build.gradle @@ -32,6 +32,7 @@ dependencies { annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' + implementation group: 'com.auth0', name: 'java-jwt', version: '4.3.0' } tasks.named('test') { diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/MyExceptionHandler.java b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/MyExceptionHandler.java new file mode 100644 index 0000000..5da146c --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/MyExceptionHandler.java @@ -0,0 +1,48 @@ +package com.example.kdtbe5_miniproject._core.errors; + +import com.example.kdtbe5_miniproject._core.errors.exception.*; +import com.example.kdtbe5_miniproject._core.util.ApiUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + + +@Slf4j +@RequiredArgsConstructor +@RestControllerAdvice +public class MyExceptionHandler { + + @ExceptionHandler(Exception400.class) + public ResponseEntity badRequest(Exception400 e) { + return new ResponseEntity<>(e.body(), e.status()); + } + + @ExceptionHandler(Exception401.class) + public ResponseEntity unAuthorized(Exception401 e) { + return new ResponseEntity<>(e.body(), e.status()); + } + + @ExceptionHandler(Exception403.class) + public ResponseEntity forbidden(Exception403 e) { + return new ResponseEntity<>(e.body(), e.status()); + } + + @ExceptionHandler(Exception404.class) + public ResponseEntity notFound(Exception404 e) { + return new ResponseEntity<>(e.body(), e.status()); + } + + @ExceptionHandler(Exception500.class) + public ResponseEntity serverError(Exception500 e) { + return new ResponseEntity<>(e.body(), e.status()); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity unknownServerError(Exception e) { + ApiUtils.ApiResult apiResult = ApiUtils.error(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + return new ResponseEntity<>(apiResult, HttpStatus.INTERNAL_SERVER_ERROR); + } +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/MyValidationHandler.java b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/MyValidationHandler.java new file mode 100644 index 0000000..a80f0ab --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/MyValidationHandler.java @@ -0,0 +1,38 @@ +package com.example.kdtbe5_miniproject._core.errors; + +import com.example.kdtbe5_miniproject._core.errors.exception.Exception400; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.stereotype.Component; +import org.springframework.validation.Errors; + +@Aspect +@Component +public class MyValidationHandler { + @Pointcut("@annotation(org.springframework.web.bind.annotation.PostMapping)") + public void postMapping() { + } + + @Pointcut("@annotation(org.springframework.web.bind.annotation.PutMapping)") + public void putMapping() { + } + + @Before("postMapping() || putMapping()") + public void validationAdvice(JoinPoint jp) { + Object[] args = jp.getArgs(); + for (Object arg : args) { + if (arg instanceof Errors) { + Errors errors = (Errors) arg; + + if (errors.hasErrors()) { + throw new Exception400( + errors.getFieldErrors().get(0).getField(), + errors.getFieldErrors().get(0).getDefaultMessage() + ); + } + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception400.java b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception400.java new file mode 100644 index 0000000..3677040 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception400.java @@ -0,0 +1,27 @@ +package com.example.kdtbe5_miniproject._core.errors.exception; + +import com.example.kdtbe5_miniproject._core.util.ApiUtils; +import lombok.Getter; +import org.springframework.http.HttpStatus; + + +@Getter +public class Exception400 extends RuntimeException { + + private String key; + private String value; + + public Exception400(String key, String value) { + super(key + " : " + value); + this.key = key; + this.value = value; + } + + public ApiUtils.ApiResult body() { + return ApiUtils.error(getMessage(), HttpStatus.BAD_REQUEST); + } + + public HttpStatus status() { + return HttpStatus.BAD_REQUEST; + } +} \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception401.java b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception401.java new file mode 100644 index 0000000..ea564e2 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception401.java @@ -0,0 +1,22 @@ +package com.example.kdtbe5_miniproject._core.errors.exception; + + +import com.example.kdtbe5_miniproject._core.util.ApiUtils; +import lombok.Getter; +import org.springframework.http.HttpStatus; + + +@Getter +public class Exception401 extends RuntimeException { + public Exception401(String message) { + super(message); + } + + public ApiUtils.ApiResult body() { + return ApiUtils.error(getMessage(), HttpStatus.UNAUTHORIZED); + } + + public HttpStatus status() { + return HttpStatus.UNAUTHORIZED; + } +} \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception403.java b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception403.java new file mode 100644 index 0000000..465e5bd --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception403.java @@ -0,0 +1,21 @@ +package com.example.kdtbe5_miniproject._core.errors.exception; + +import com.example.kdtbe5_miniproject._core.util.ApiUtils; +import lombok.Getter; +import org.springframework.http.HttpStatus; + + +@Getter +public class Exception403 extends RuntimeException { + public Exception403(String message) { + super(message); + } + + public ApiUtils.ApiResult body() { + return ApiUtils.error(getMessage(), HttpStatus.FORBIDDEN); + } + + public HttpStatus status() { + return HttpStatus.FORBIDDEN; + } +} \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception404.java b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception404.java new file mode 100644 index 0000000..0feb80a --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception404.java @@ -0,0 +1,21 @@ +package com.example.kdtbe5_miniproject._core.errors.exception; + +import com.example.kdtbe5_miniproject._core.util.ApiUtils; +import lombok.Getter; +import org.springframework.http.HttpStatus; + + +@Getter +public class Exception404 extends RuntimeException { + public Exception404(String message) { + super(message); + } + + public ApiUtils.ApiResult body() { + return ApiUtils.error(getMessage(), HttpStatus.NOT_FOUND); + } + + public HttpStatus status() { + return HttpStatus.NOT_FOUND; + } +} \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception500.java b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception500.java new file mode 100644 index 0000000..ba32d8e --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception500.java @@ -0,0 +1,23 @@ +package com.example.kdtbe5_miniproject._core.errors.exception; + +import com.example.kdtbe5_miniproject._core.util.ApiUtils; +import lombok.Getter; +import org.springframework.http.HttpStatus; + + +@Getter +public class Exception500 extends RuntimeException { + public Exception500(String message) { + super(message); + } + + + public ApiUtils.ApiResult body() { + return ApiUtils.error(getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + } + + public HttpStatus status() { + return HttpStatus.INTERNAL_SERVER_ERROR; + } + +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetails.java b/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetails.java new file mode 100644 index 0000000..c6fe322 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetails.java @@ -0,0 +1,54 @@ +package com.example.kdtbe5_miniproject._core.security; + +import com.example.kdtbe5_miniproject.user.User; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.Arrays; +import java.util.Collection; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +@Getter +public class CustomUserDetails implements UserDetails { + + private final User user; + + @Override + public Collection getAuthorities() { + return Arrays.stream(user.getRoles().split(",")).map(SimpleGrantedAuthority::new).collect(Collectors.toList()); + } + + @Override + public String getPassword() { + return user.getPassword(); + } + + @Override + public String getUsername() { + return user.getUsername(); + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetailsService.java b/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetailsService.java new file mode 100644 index 0000000..1d5b6b7 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetailsService.java @@ -0,0 +1,32 @@ +package com.example.kdtbe5_miniproject._core.security; + +import com.example.kdtbe5_miniproject.user.User; +import com.example.kdtbe5_miniproject.user.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +import java.util.Optional; + +@RequiredArgsConstructor +@Service +public class CustomUserDetailsService implements UserDetailsService { + + private final UserRepository userRepository; + + // login 호출 + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + System.out.println("username : " + username); + Optional userOP = userRepository.findByUsername(username); + + if (userOP.isPresent()) { + return new CustomUserDetails(userOP.get()); + } else { + return null; + } + + } +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtAuthenticationFilter.java b/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtAuthenticationFilter.java new file mode 100644 index 0000000..ae515ac --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtAuthenticationFilter.java @@ -0,0 +1,64 @@ +package com.example.kdtbe5_miniproject._core.security; + + +import com.auth0.jwt.exceptions.JWTDecodeException; +import com.auth0.jwt.exceptions.SignatureVerificationException; +import com.auth0.jwt.exceptions.TokenExpiredException; +import com.auth0.jwt.interfaces.DecodedJWT; +import com.example.kdtbe5_miniproject.user.User; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@Slf4j +public class JwtAuthenticationFilter extends BasicAuthenticationFilter { + + public JwtAuthenticationFilter(AuthenticationManager authenticationManager) { + super(authenticationManager); + } + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { + String prefixJwt = request.getHeader(JwtTokenProvider.HEADER); + + if (prefixJwt == null) { + chain.doFilter(request, response); + return; + } + + String jwt = prefixJwt.replace(JwtTokenProvider.TOKEN_PREFIX, ""); + try { + DecodedJWT decodedJWT = JwtTokenProvider.verify(jwt); // 신원인증 끝 + Long id = decodedJWT.getClaim("id").asLong(); + String roles = decodedJWT.getClaim("role").asString(); + + User user = User.builder().id(id).roles(roles).build(); + CustomUserDetails myUserDetails = new CustomUserDetails(user); + Authentication authentication = + new UsernamePasswordAuthenticationToken( + myUserDetails, + myUserDetails.getPassword(), + myUserDetails.getAuthorities() + ); + SecurityContextHolder.getContext().setAuthentication(authentication); + log.debug("디버그 : 인증 객체 만들어짐"); + } catch (SignatureVerificationException sve) { + log.error("토큰 검증 실패"); + } catch (TokenExpiredException tee) { + log.error("토큰 만료됨"); + } catch (JWTDecodeException tee) { + log.error("토큰 만료됨"); + } finally { + chain.doFilter(request, response); + } + } +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtTokenProvider.java b/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtTokenProvider.java new file mode 100644 index 0000000..ea00f62 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtTokenProvider.java @@ -0,0 +1,38 @@ +package com.example.kdtbe5_miniproject._core.security; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.exceptions.SignatureVerificationException; +import com.auth0.jwt.exceptions.TokenExpiredException; +import com.auth0.jwt.interfaces.DecodedJWT; +import com.example.kdtbe5_miniproject.user.User; +import org.springframework.stereotype.Component; + +import java.util.Date; + + +@Component +public class JwtTokenProvider { + public static final Long EXP = 1000L * 60 * 60 * 48; // 48시간 - 테스트 하기 편함. + public static final String TOKEN_PREFIX = "Bearer "; // 스페이스 필요함 + public static final String HEADER = "Authorization"; + public static final String SECRET = "MySecretKey"; + + public static String create(User user) { + // 토큰에는 데이터를 담을 수 있다. 민감한 정보는 추가하면 절대 안된다. + String jwt = JWT.create() + .withSubject(user.getEmail()) + .withExpiresAt(new Date(System.currentTimeMillis() + EXP)) + .withClaim("id", user.getId()) + .withClaim("role", user.getRoles()) + .sign(Algorithm.HMAC512(SECRET)); + return TOKEN_PREFIX + jwt; + } + + public static DecodedJWT verify(String jwt) throws SignatureVerificationException, TokenExpiredException { + DecodedJWT decodedJWT = JWT.require(Algorithm.HMAC512(SECRET)) + .build().verify(jwt); + return decodedJWT; + } + +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/security/SecurityConfig.java b/src/main/java/com/example/kdtbe5_miniproject/_core/security/SecurityConfig.java new file mode 100644 index 0000000..0e2c4f6 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/security/SecurityConfig.java @@ -0,0 +1,96 @@ +package com.example.kdtbe5_miniproject._core.security; + +import com.example.kdtbe5_miniproject._core.errors.exception.Exception401; +import com.example.kdtbe5_miniproject._core.errors.exception.Exception403; +import com.example.kdtbe5_miniproject._core.util.FilterResponseUtils; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.factory.PasswordEncoderFactories; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; + +@Configuration +public class SecurityConfig { + + @Bean + public PasswordEncoder passwordEncoder() { + return PasswordEncoderFactories.createDelegatingPasswordEncoder(); + } + + @Bean + public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { + return authenticationConfiguration.getAuthenticationManager(); + } + + public class CustomSecurityFilterManager extends AbstractHttpConfigurer { + @Override + public void configure(HttpSecurity builder) throws Exception { + AuthenticationManager authenticationManager = builder.getSharedObject(AuthenticationManager.class); + builder.addFilter(new JwtAuthenticationFilter(authenticationManager)); + super.configure(builder); + } + } + + @Bean // 컴퍼넌트 스캔시에 @Bean이 붙은 메서드가 있으면 실행시켜서 리턴되는 값을 IoC에 등록하는 깃발 + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + // 1. CSRF 해제 + http.csrf().disable(); // postman 접근해야 함!! - CSR 할때!! + + // 2. iframe 거부 + http.headers().frameOptions().sameOrigin(); + + // 3. cors 재설정 + http.cors().configurationSource(configurationSource()); + + // 4. jSessionId가 응답이 될 때 세션영 역에서 사라진다 (이게 stateless) + http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); + + // 5. form 로긴 해제 (UsernamePasswordAuthenticationFilter 비활성화) + http.formLogin().disable(); + + // 6. 로그인 인증창이 뜨지 않게 비활성화 + http.httpBasic().disable(); + + // 7. 커스텀 필터 적용 (시큐리티 필터 교환) + http.apply(new CustomSecurityFilterManager()); + + // 8. 인증 실패 처리 + http.exceptionHandling().authenticationEntryPoint((request, response, authException) -> { + FilterResponseUtils.unAuthorized(response, new Exception401("인증되지 않았습니다")); + }); + + // 9. 권한 실패 처리 + http.exceptionHandling().accessDeniedHandler((request, response, accessDeniedException) -> { + FilterResponseUtils.forbidden(response, new Exception403("권한이 없습니다")); + }); + + // 11. 인증, 권한 필터 설정 + http.authorizeRequests( + authorize -> authorize.antMatchers("/account/**").authenticated() + .antMatchers("/admin/**").access("hasRole('ADMIN')") + .anyRequest().permitAll() + ); + return http.build(); + } + + public CorsConfigurationSource configurationSource() { + CorsConfiguration configuration = new CorsConfiguration(); + configuration.addAllowedHeader("*"); + configuration.addAllowedMethod("*"); // GET, POST, PUT, DELETE (Javascript 요청 허용) + // localhost:8080 백엔드, localhost:3000 프론트엔드 + configuration.addAllowedOriginPattern("*"); // 모든 IP 주소 허용 (프론트 앤드 IP만 허용 react) + configuration.setAllowCredentials(true); // 클라이언트에서 쿠키 요청 허용 + configuration.addExposedHeader("Authorization"); // 옛날에는 디폴트 였다. 지금은 아닙니다. + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", configuration); // /login, /board, /product/ + return source; + } +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/util/ApiUtils.java b/src/main/java/com/example/kdtbe5_miniproject/_core/util/ApiUtils.java new file mode 100644 index 0000000..bc71ac8 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/util/ApiUtils.java @@ -0,0 +1,34 @@ +package com.example.kdtbe5_miniproject._core.util; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import org.springframework.http.HttpStatus; + +// 공통 응답 DTO +public class ApiUtils { + public static ApiResult success(T response) { + return new ApiResult<>(true, response, null); + } + + public static ApiResult error(String message, HttpStatus status) { + return new ApiResult<>(false, null, new ApiError(message, status.value())); + } + + @Getter + @Setter + @AllArgsConstructor + public static class ApiResult { + private final boolean success; + private final T response; + private final ApiError error; + } + + @Getter + @Setter + @AllArgsConstructor + public static class ApiError { + private final String message; + private final int status; + } +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/util/DateUtils.java b/src/main/java/com/example/kdtbe5_miniproject/_core/util/DateUtils.java new file mode 100644 index 0000000..6fed68d --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/util/DateUtils.java @@ -0,0 +1,10 @@ +package com.example.kdtbe5_miniproject._core.util; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public class DateUtils { + public static String toStringFormat(LocalDateTime localDateTime) { + return localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + } +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/util/FilterResponseUtils.java b/src/main/java/com/example/kdtbe5_miniproject/_core/util/FilterResponseUtils.java new file mode 100644 index 0000000..842d981 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/util/FilterResponseUtils.java @@ -0,0 +1,26 @@ +package com.example.kdtbe5_miniproject._core.util; + +import com.example.kdtbe5_miniproject._core.errors.exception.Exception401; +import com.example.kdtbe5_miniproject._core.errors.exception.Exception403; +import com.fasterxml.jackson.databind.ObjectMapper; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +public class FilterResponseUtils { + public static void unAuthorized(HttpServletResponse resp, Exception401 e) throws IOException { + resp.setStatus(e.status().value()); + resp.setContentType("application/json; charset=utf-8"); + ObjectMapper om = new ObjectMapper(); + String responseBody = om.writeValueAsString(e.body()); + resp.getWriter().println(responseBody); + } + + public static void forbidden(HttpServletResponse resp, Exception403 e) throws IOException { + resp.setStatus(e.status().value()); + resp.setContentType("application/json; charset=utf-8"); + ObjectMapper om = new ObjectMapper(); + String responseBody = om.writeValueAsString(e.body()); + resp.getWriter().println(responseBody); + } +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/User.java b/src/main/java/com/example/kdtbe5_miniproject/user/User.java new file mode 100644 index 0000000..90c53e1 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/user/User.java @@ -0,0 +1,27 @@ +package com.example.kdtbe5_miniproject.user; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Getter +public class User { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String email; + private String roles; + private String username; + private String password; + +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java new file mode 100644 index 0000000..e29aa2b --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java @@ -0,0 +1,14 @@ +package com.example.kdtbe5_miniproject.user; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +public interface UserRepository extends JpaRepository { + + + Optional findByUsername(@Param("username") String username); +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java new file mode 100644 index 0000000..95bb8a3 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java @@ -0,0 +1,7 @@ +package com.example.kdtbe5_miniproject.user; + +import org.springframework.stereotype.Service; + +@Service +public class UserService { +} From 2fda980cc5cb7162b1433f6d39c0807589711c7c Mon Sep 17 00:00:00 2001 From: JOOWON Date: Mon, 24 Jul 2023 17:21:07 +0900 Subject: [PATCH 004/128] =?UTF-8?q?chore:yml=20=ED=99=98=EA=B2=BD=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-dev.yml | 29 +++++++++++++++++++++++ src/main/resources/application-prod.yml | 25 +++++++++++++++++++ src/main/resources/application-test.yml | 29 +++++++++++++++++++++++ src/main/resources/application.properties | 1 - src/main/resources/application.yml | 4 ++++ 5 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/application-dev.yml create mode 100644 src/main/resources/application-prod.yml create mode 100644 src/main/resources/application-test.yml delete mode 100644 src/main/resources/application.properties create mode 100644 src/main/resources/application.yml diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml new file mode 100644 index 0000000..b852d74 --- /dev/null +++ b/src/main/resources/application-dev.yml @@ -0,0 +1,29 @@ +server: + servlet: + encoding: + charset: utf-8 + force: true + port: 8080 +spring: + datasource: + url: jdbc:h2:mem:test;MODE=MySQL + driver-class-name: org.h2.Driver + username: sa + password: + h2: + console: + enabled: true + jpa: + hibernate: + ddl-auto: create + show-sql: true + properties: + hibernate: + format_sql: true + default_batch_fetch_size: 100 + open-in-view: false + +logging: + level: + '[MiniProject.Server]': DEBUG + '[org.hibernate.type]': TRACE \ No newline at end of file diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml new file mode 100644 index 0000000..b69d3b4 --- /dev/null +++ b/src/main/resources/application-prod.yml @@ -0,0 +1,25 @@ +server: + servlet: + encoding: + charset: utf-8 + force: true + port: 8080 +spring: + datasource: + url: jdbc:mariadb://${DB_HOST}:${DB_PORT}/${DB_NAME}?allowPublicKeyRetrieval=true&useSSL=false + # driver-class-name: org.mariadb.jdbc.Driver + username: ${DB_USERNAME} + password: ${DB_PASSWORD} + h2: + console: + enabled: true + jpa: + hibernate: + ddl-auto: none + properties: + default_batch_fetch_size: 100 + open-in-view: false + +logging: + level: + '[MiniProject.Server]': INFO \ No newline at end of file diff --git a/src/main/resources/application-test.yml b/src/main/resources/application-test.yml new file mode 100644 index 0000000..b852d74 --- /dev/null +++ b/src/main/resources/application-test.yml @@ -0,0 +1,29 @@ +server: + servlet: + encoding: + charset: utf-8 + force: true + port: 8080 +spring: + datasource: + url: jdbc:h2:mem:test;MODE=MySQL + driver-class-name: org.h2.Driver + username: sa + password: + h2: + console: + enabled: true + jpa: + hibernate: + ddl-auto: create + show-sql: true + properties: + hibernate: + format_sql: true + default_batch_fetch_size: 100 + open-in-view: false + +logging: + level: + '[MiniProject.Server]': DEBUG + '[org.hibernate.type]': TRACE \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties deleted file mode 100644 index 8b13789..0000000 --- a/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..41ba440 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,4 @@ +spring: + profiles: + active: + - dev \ No newline at end of file From 91a5808f7dbb9a608199d3e49a497f1b8b65d999 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Tue, 25 Jul 2023 16:40:17 +0900 Subject: [PATCH 005/128] feat:#1 BaseTimeEntity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 공통 시간 entity 생성 --- .../executionHistory/executionHistory.lock | Bin 17 -> 17 bytes .gradle/8.1.1/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .../_core/util/BaseTimeEntity.java | 22 ++++++++++++++++++ 4 files changed, 22 insertions(+) create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/util/BaseTimeEntity.java diff --git a/.gradle/8.1.1/executionHistory/executionHistory.lock b/.gradle/8.1.1/executionHistory/executionHistory.lock index bc8695c52656492373e444b68d2f54a3274ee393..9f699e1abca244b4b06fd84b47ae978f7cb03c56 100644 GIT binary patch literal 17 TcmZQxX4AXdKwVOm0Rq?oC71%r literal 17 ScmZQxX4AXdKwVOm0SW*mkpja2 diff --git a/.gradle/8.1.1/fileHashes/fileHashes.lock b/.gradle/8.1.1/fileHashes/fileHashes.lock index b3b2bd9e458941fa689f1f166518d569023e4381..830f74f93f6a3f641c3fa91de380f488722c7cf4 100644 GIT binary patch literal 17 UcmZRc9`t<9-qrRW7$6`O06vffYybcN literal 17 TcmZRc9`t<9-qrRW7@z Date: Tue, 25 Jul 2023 16:40:35 +0900 Subject: [PATCH 006/128] feat:#1 User Domain --- .../example/kdtbe5_miniproject/user/User.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/User.java b/src/main/java/com/example/kdtbe5_miniproject/user/User.java index 90c53e1..6498696 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/User.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/User.java @@ -1,27 +1,31 @@ package com.example.kdtbe5_miniproject.user; +import com.example.kdtbe5_miniproject._core.util.BaseTimeEntity; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; +import javax.persistence.*; +import java.time.LocalDateTime; @Entity @AllArgsConstructor @NoArgsConstructor @Builder @Getter -public class User { +@Table(name = "user_tb") +public class User extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - private String email; - private String roles; private String username; private String password; + private String email; + private String phoneNumber; + private String position; //직급 + private String roles; //관리자, 사용자 + private Long numOfDayOff; + private LocalDateTime joinDate; } From c1c58b7b4725028b613a71916faf08bc7cec1bdb Mon Sep 17 00:00:00 2001 From: JOOWON Date: Tue, 25 Jul 2023 16:40:54 +0900 Subject: [PATCH 007/128] feat:#1 User Response/Request DTO --- .../Kdtbe5MiniProjectApplication.java | 2 + .../kdtbe5_miniproject/user/UserRequest.java | 54 +++++++++++++++++++ .../kdtbe5_miniproject/user/UserResponse.java | 25 +++++++++ 3 files changed, 81 insertions(+) create mode 100644 src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java diff --git a/src/main/java/com/example/kdtbe5_miniproject/Kdtbe5MiniProjectApplication.java b/src/main/java/com/example/kdtbe5_miniproject/Kdtbe5MiniProjectApplication.java index 735962c..99a1fda 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/Kdtbe5MiniProjectApplication.java +++ b/src/main/java/com/example/kdtbe5_miniproject/Kdtbe5MiniProjectApplication.java @@ -2,7 +2,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +@EnableJpaAuditing @SpringBootApplication public class Kdtbe5MiniProjectApplication { diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java new file mode 100644 index 0000000..ab409f0 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java @@ -0,0 +1,54 @@ +package com.example.kdtbe5_miniproject.user; + +import lombok.Getter; +import lombok.Setter; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.time.LocalDateTime; + +public class UserRequest { + @Getter + @Setter + public static class LoginDTO { + @Pattern(regexp = "^[a-zA-Z0-9]{2,20}$", message = "영문/숫자 2~20자 이내로 작성해주세요") + @NotEmpty + private String username; + @NotEmpty + @Size(min = 4, max = 20) + private String password; + } + + @Getter + @Setter + public static class JoinDTO { + @NotEmpty + @Pattern(regexp = "^[a-zA-Z0-9]{2,20}$", message = "영문/숫자 2~20자 이내로 작성해주세요") + private String username; + + @NotEmpty + @Size(min = 4, max = 20) + private String password; + + @NotEmpty + @Pattern(regexp = "^[\\w._%+-]+@[\\w.-]+\\.[a-zA-Z]{2,6}$", message = "이메일 형식으로 작성해주세요") + private String email; + + private String phoneNumber; + private String position; + private LocalDateTime joinDate; + + public User toEntity() { + return User.builder() + .username(username) + .password(password) + .email(email) + .phoneNumber(phoneNumber) + .position(position) + .roles("USER") + .joinDate(joinDate) + .build(); + } + } +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java new file mode 100644 index 0000000..ff423b7 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java @@ -0,0 +1,25 @@ +package com.example.kdtbe5_miniproject.user; + +import lombok.Getter; +import lombok.Setter; + +public class UserResponse { + + @Getter + @Setter + public static class JoinDTO { + private Long id; + private String username; + private String email; + private String position; + private String roles; + + public JoinDTO(User user) { + this.id = user.getId(); + this.username = user.getUsername(); + this.email = user.getEmail(); + this.position = user.getPosition(); + this.roles = user.getRoles(); + } + } +} From 30835a4df4b7c4226705b88671b54277ffba4934 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Tue, 25 Jul 2023 16:41:11 +0900 Subject: [PATCH 008/128] feat:#1 User Controller --- .../user/UserController.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/main/java/com/example/kdtbe5_miniproject/user/UserController.java diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java new file mode 100644 index 0000000..36d1719 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java @@ -0,0 +1,26 @@ +package com.example.kdtbe5_miniproject.user; + +import com.example.kdtbe5_miniproject._core.util.ApiUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.Errors; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; + +@RequiredArgsConstructor +@RestController +@Slf4j +public class UserController { + + private final UserService userService; + + @PostMapping("/join") + public ResponseEntity join(@RequestBody @Valid UserRequest.JoinDTO joinDTO, Errors errors) { + UserResponse.JoinDTO responseDTO = userService.joinUser(joinDTO); + return ResponseEntity.ok().body(ApiUtils.success(responseDTO)); + } +} \ No newline at end of file From 62e7ad64d4b3eefe46570bfd469d931f54f998f8 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Tue, 25 Jul 2023 16:41:17 +0900 Subject: [PATCH 009/128] feat:#1 User Service --- .../kdtbe5_miniproject/user/UserService.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java index 95bb8a3..77c1a8e 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java @@ -1,7 +1,21 @@ package com.example.kdtbe5_miniproject.user; +import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +@RequiredArgsConstructor @Service public class UserService { + + private final UserRepository userRepository; + private final PasswordEncoder passwordEncoder; + + @Transactional + public UserResponse.JoinDTO joinUser(UserRequest.JoinDTO joinDTO) { + joinDTO.setPassword(passwordEncoder.encode(joinDTO.getPassword())); + User userPS = userRepository.save(joinDTO.toEntity()); + return new UserResponse.JoinDTO(userPS); + } } From 4796e8e9d26903a17a490ba19ecf91559849e1d0 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Tue, 25 Jul 2023 16:41:37 +0900 Subject: [PATCH 010/128] feat:#1 UserDetails, isAdmin --- .../kdtbe5_miniproject/_core/security/CustomUserDetails.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetails.java b/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetails.java index c6fe322..1509d22 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetails.java +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetails.java @@ -32,6 +32,10 @@ public String getUsername() { return user.getUsername(); } + public boolean isAdmin() { + return user.getRoles().equals("admin"); //enum으로 수정 시 수정해야함 + } + @Override public boolean isAccountNonExpired() { return true; From ef046e23fcd4be82b7da2c15e2b8c5dad1cbc2f1 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Tue, 25 Jul 2023 16:46:31 +0900 Subject: [PATCH 011/128] chore:#1 git ignore --- .gitignore | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d843f13..0bc6eb7 100644 --- a/.gitignore +++ b/.gitignore @@ -115,4 +115,11 @@ fabric.properties hs_err_pid* replay_pid* -# End of https://www.toptal.com/developers/gitignore/api/java,intellij+all \ No newline at end of file +# End of https://www.toptal.com/developers/gitignore/api/java,intellij+all + +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ From 6af7ecce3c965249d8d08d0e196c4ba132a6112e Mon Sep 17 00:00:00 2001 From: JOOWON Date: Thu, 27 Jul 2023 13:26:14 +0900 Subject: [PATCH 012/128] =?UTF-8?q?feat:#1=20=EC=95=94=ED=98=B8=ED=99=94?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81=20(AES256)=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_core/util/EncryptUtils.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/util/EncryptUtils.java diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/util/EncryptUtils.java b/src/main/java/com/example/kdtbe5_miniproject/_core/util/EncryptUtils.java new file mode 100644 index 0000000..2eb869e --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/util/EncryptUtils.java @@ -0,0 +1,38 @@ +package com.example.kdtbe5_miniproject._core.util; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.util.Base64; + +public class EncryptUtils { + + public static String alg = "AES/CBC/PKCS5Padding"; + private static final String key = "a1b2c3d4e5f6g7h8i9j0k9j8i7h6g5f4"; + private static String iv = "a1b2c3d4e5f6g7h8"; + + public static String encrypt(String text) { + try { + Cipher cipher = Cipher.getInstance(alg); + SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES"); + IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes()); + cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivParameterSpec); + + byte[] encrypted = cipher.doFinal(text.getBytes("UTF-8")); + return Base64.getEncoder().encodeToString(encrypted); + } catch (Exception e) { + throw new RuntimeException(); //TODO 예외처리 custom + } + } + + public static String decrypt(String cipherText) throws Exception{ + Cipher cipher = Cipher.getInstance(alg); + SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(),"AES"); + IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes()); + cipher.init(Cipher.DECRYPT_MODE,keySpec,ivParameterSpec); + + byte[] decoded = Base64.getDecoder().decode(cipherText); + byte[] decrypted = cipher.doFinal(decoded); + return new String(decrypted, "UTF-8"); + } +} From 7e475f733b65a512ded945a23ab371e25882d5c1 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Thu, 27 Jul 2023 13:26:51 +0900 Subject: [PATCH 013/128] feat:#1 login history entity --- .../login_history/LoginHistory.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/main/java/com/example/kdtbe5_miniproject/login_history/LoginHistory.java diff --git a/src/main/java/com/example/kdtbe5_miniproject/login_history/LoginHistory.java b/src/main/java/com/example/kdtbe5_miniproject/login_history/LoginHistory.java new file mode 100644 index 0000000..732a250 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/login_history/LoginHistory.java @@ -0,0 +1,27 @@ +package com.example.kdtbe5_miniproject.login_history; + +import com.example.kdtbe5_miniproject.user.User; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import javax.persistence.*; +import java.time.LocalDateTime; + +@Entity +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Getter +@Table(name = "login_tb") +public class LoginHistory { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @ManyToOne(fetch = FetchType.LAZY) + private User user; + private String ip; + private String userAgent; + private LocalDateTime loginAt; +} From 0300242def952d10a4e2f481b14ac18b8142bceb Mon Sep 17 00:00:00 2001 From: JOOWON Date: Thu, 27 Jul 2023 13:27:04 +0900 Subject: [PATCH 014/128] feat:#1 login history repository --- .../login_history/LoginHistoryRepository.java | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/main/java/com/example/kdtbe5_miniproject/login_history/LoginHistoryRepository.java diff --git a/src/main/java/com/example/kdtbe5_miniproject/login_history/LoginHistoryRepository.java b/src/main/java/com/example/kdtbe5_miniproject/login_history/LoginHistoryRepository.java new file mode 100644 index 0000000..2d22c8a --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/login_history/LoginHistoryRepository.java @@ -0,0 +1,8 @@ +package com.example.kdtbe5_miniproject.login_history; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface LoginHistoryRepository extends JpaRepository { +} From 80d8ce6a33a074a30d7621f2bbab8edb1a1ff427 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Thu, 27 Jul 2023 13:27:10 +0900 Subject: [PATCH 015/128] feat:#1 login history service --- .../login_history/LoginHistoryService.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/main/java/com/example/kdtbe5_miniproject/login_history/LoginHistoryService.java diff --git a/src/main/java/com/example/kdtbe5_miniproject/login_history/LoginHistoryService.java b/src/main/java/com/example/kdtbe5_miniproject/login_history/LoginHistoryService.java new file mode 100644 index 0000000..1c020e6 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/login_history/LoginHistoryService.java @@ -0,0 +1,18 @@ +package com.example.kdtbe5_miniproject.login_history; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import javax.transaction.Transactional; + +@RequiredArgsConstructor +@Service +public class LoginHistoryService { + + private final LoginHistoryRepository loginHistoryRepository; + + @Transactional + public void save(LoginHistoryRequest.LoginHistoryDTO loginHistoryDTO) { + loginHistoryRepository.save(loginHistoryDTO.toEntity()); + } +} From 3a75195c689230dd50b1c93c58da85aff1e6ab87 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Thu, 27 Jul 2023 13:27:17 +0900 Subject: [PATCH 016/128] feat:#1 login history dto --- .../login_history/LoginHistoryRequest.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/main/java/com/example/kdtbe5_miniproject/login_history/LoginHistoryRequest.java diff --git a/src/main/java/com/example/kdtbe5_miniproject/login_history/LoginHistoryRequest.java b/src/main/java/com/example/kdtbe5_miniproject/login_history/LoginHistoryRequest.java new file mode 100644 index 0000000..1105258 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/login_history/LoginHistoryRequest.java @@ -0,0 +1,32 @@ +package com.example.kdtbe5_miniproject.login_history; + +import com.example.kdtbe5_miniproject.user.User; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.time.LocalDateTime; + +public class LoginHistoryRequest { + + @AllArgsConstructor + @NoArgsConstructor + @Getter + @Setter + public static class LoginHistoryDTO { + private User user; + private String ip; + private String userAgent; + private LocalDateTime loginAt; + + public LoginHistory toEntity() { + return LoginHistory.builder() + .user(user) + .ip(ip) + .userAgent(userAgent) + .loginAt(loginAt) + .build(); + } + } +} From 04b6675104732e7109aa8f3af35c9beb812cea19 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Thu, 27 Jul 2023 13:29:10 +0900 Subject: [PATCH 017/128] =?UTF-8?q?feat:#1=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EC=8B=9C=20=EC=82=AC=EC=9A=A9=EC=9E=90=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=95=94=ED=98=B8=ED=99=94=20=EC=A0=81=EC=9A=A9,?= =?UTF-8?q?=20=EC=A3=BC=EC=84=9D=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 암호화를 먼저 적용하면 헷갈릴 것 같아 주석처리 해뒀습니다 --- .../com/example/kdtbe5_miniproject/user/UserService.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java index 77c1a8e..e067a4e 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java @@ -1,5 +1,6 @@ package com.example.kdtbe5_miniproject.user; +import com.example.kdtbe5_miniproject._core.util.EncryptUtils; import lombok.RequiredArgsConstructor; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; @@ -15,6 +16,12 @@ public class UserService { @Transactional public UserResponse.JoinDTO joinUser(UserRequest.JoinDTO joinDTO) { joinDTO.setPassword(passwordEncoder.encode(joinDTO.getPassword())); + + //사용자 정보 암호화 - 기능 구현 시 헷갈릴 것 같아서 주석 처리 +// joinDTO.setUsername(EncryptUtils.encrypt(joinDTO.getUsername())); +// joinDTO.setPhoneNumber(EncryptUtils.encrypt(joinDTO.getPhoneNumber())); +// joinDTO.setEmail(EncryptUtils.encrypt(joinDTO.getEmail())); + User userPS = userRepository.save(joinDTO.toEntity()); return new UserResponse.JoinDTO(userPS); } From 731fc731d7cd040a03f0940cd37e0a83044eff8a Mon Sep 17 00:00:00 2001 From: JOOWON Date: Thu, 27 Jul 2023 13:30:03 +0900 Subject: [PATCH 018/128] =?UTF-8?q?feat:#1=20=EB=A1=9C=EA=B7=B8=EC=9D=B8?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/UserController.java | 49 ++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java index 36d1719..07445c0 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java @@ -1,26 +1,71 @@ package com.example.kdtbe5_miniproject.user; +import com.example.kdtbe5_miniproject._core.errors.exception.Exception401; +import com.example.kdtbe5_miniproject._core.security.CustomUserDetails; +import com.example.kdtbe5_miniproject._core.security.JwtTokenProvider; import com.example.kdtbe5_miniproject._core.util.ApiUtils; +import com.example.kdtbe5_miniproject._core.util.EncryptUtils; +import com.example.kdtbe5_miniproject.login_history.LoginHistoryRequest; +import com.example.kdtbe5_miniproject.login_history.LoginHistoryService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; import org.springframework.validation.Errors; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; +import java.time.LocalDateTime; @RequiredArgsConstructor @RestController @Slf4j public class UserController { + private final LoginHistoryService loginHistoryService; private final UserService userService; + private final AuthenticationManager authenticationManager; - @PostMapping("/join") + @PostMapping("/register") public ResponseEntity join(@RequestBody @Valid UserRequest.JoinDTO joinDTO, Errors errors) { UserResponse.JoinDTO responseDTO = userService.joinUser(joinDTO); - return ResponseEntity.ok().body(ApiUtils.success(responseDTO)); + log.info(joinDTO.getUsername() + " Joined"); + return ResponseEntity.ok().body(ApiUtils.success(responseDTO, HttpStatus.OK)); + } + + @PostMapping("/login") + public ResponseEntity login(@RequestBody @Valid UserRequest.LoginDTO loginDTO, Errors errors, HttpServletRequest request) { + try { + UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken + = new UsernamePasswordAuthenticationToken(loginDTO.getUsername(), loginDTO.getPassword()); + Authentication authentication = authenticationManager.authenticate(usernamePasswordAuthenticationToken); + CustomUserDetails myUserDetails = (CustomUserDetails) authentication.getPrincipal(); + log.info(EncryptUtils.decrypt(myUserDetails.getUsername()) + " Login"); + + String jwt = JwtTokenProvider.create(myUserDetails.getUser()); + addLoginHistory(request, myUserDetails); + + return ResponseEntity.ok().header("Authorization", jwt).body(ApiUtils.success(null, HttpStatus.OK)); + + } catch (Exception e) { + throw new Exception401("인증되지 않았습니다"); + } + } + + private void addLoginHistory(HttpServletRequest request, CustomUserDetails myUserDetails) { + LoginHistoryRequest.LoginHistoryDTO loginHistoryDTO = new LoginHistoryRequest.LoginHistoryDTO(); + + loginHistoryDTO.setUser(myUserDetails.getUser()); + loginHistoryDTO.setIp(request.getRemoteAddr()); + loginHistoryDTO.setUserAgent(request.getHeader("User-Agent")); + loginHistoryDTO.setLoginAt(LocalDateTime.now()); + + loginHistoryService.save(loginHistoryDTO); } } \ No newline at end of file From 236456e3d807de2914ddf570de71277ebee281ae Mon Sep 17 00:00:00 2001 From: JOOWON Date: Thu, 27 Jul 2023 13:30:30 +0900 Subject: [PATCH 019/128] =?UTF-8?q?feat:#1=20api=20=EC=9D=91=EB=8B=B5=20?= =?UTF-8?q?=ED=98=95=EC=8B=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 응답코드가 추가된 형태입니다 --- .../example/kdtbe5_miniproject/_core/util/ApiUtils.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/util/ApiUtils.java b/src/main/java/com/example/kdtbe5_miniproject/_core/util/ApiUtils.java index bc71ac8..0277521 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/_core/util/ApiUtils.java +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/util/ApiUtils.java @@ -7,20 +7,21 @@ // 공통 응답 DTO public class ApiUtils { - public static ApiResult success(T response) { - return new ApiResult<>(true, response, null); + public static ApiResult success(T data, HttpStatus status) { + return new ApiResult<>(status.value(), true, data, null); } public static ApiResult error(String message, HttpStatus status) { - return new ApiResult<>(false, null, new ApiError(message, status.value())); + return new ApiResult<>(status.value(), false, null, new ApiError(message, status.value())); } @Getter @Setter @AllArgsConstructor public static class ApiResult { + private int code; private final boolean success; - private final T response; + private final T data; private final ApiError error; } From 795e7173ba99afb00edacdc706225d1e7c5b9f54 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Thu, 27 Jul 2023 13:30:55 +0900 Subject: [PATCH 020/128] =?UTF-8?q?feat:#1=20user=EC=9D=98=20userId?= =?UTF-8?q?=EB=A5=BC=20=EC=9D=B4=EB=A9=94=EC=9D=BC=EB=A1=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_core/security/CustomUserDetails.java | 6 +++++- .../_core/security/CustomUserDetailsService.java | 6 +++--- .../com/example/kdtbe5_miniproject/user/UserRepository.java | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetails.java b/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetails.java index 1509d22..8c622dc 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetails.java +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetails.java @@ -29,7 +29,11 @@ public String getPassword() { @Override public String getUsername() { - return user.getUsername(); + return user.getEmail(); + } + + public Long getUserId() { + return user.getId(); } public boolean isAdmin() { diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetailsService.java b/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetailsService.java index 1d5b6b7..8d5e8f4 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetailsService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetailsService.java @@ -18,9 +18,9 @@ public class CustomUserDetailsService implements UserDetailsService { // login 호출 @Override - public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { - System.out.println("username : " + username); - Optional userOP = userRepository.findByUsername(username); + public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { + + Optional userOP = userRepository.findByEmail(email); if (userOP.isPresent()) { return new CustomUserDetails(userOP.get()); diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java index e29aa2b..af1e830 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java @@ -10,5 +10,5 @@ public interface UserRepository extends JpaRepository { - Optional findByUsername(@Param("username") String username); + Optional findByEmail(@Param("email") String email); } From beef9e7f29c26e69623acccc6901f8984af253ed Mon Sep 17 00:00:00 2001 From: JOOWON Date: Thu, 27 Jul 2023 13:31:11 +0900 Subject: [PATCH 021/128] =?UTF-8?q?feat:#1=20user=20DTO=20=ED=98=95?= =?UTF-8?q?=EC=8B=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/kdtbe5_miniproject/user/UserRequest.java | 7 ++----- .../kdtbe5_miniproject/user/UserResponse.java | 12 ++++++++++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java index ab409f0..504c278 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java @@ -12,7 +12,6 @@ public class UserRequest { @Getter @Setter public static class LoginDTO { - @Pattern(regexp = "^[a-zA-Z0-9]{2,20}$", message = "영문/숫자 2~20자 이내로 작성해주세요") @NotEmpty private String username; @NotEmpty @@ -24,19 +23,16 @@ public static class LoginDTO { @Setter public static class JoinDTO { @NotEmpty - @Pattern(regexp = "^[a-zA-Z0-9]{2,20}$", message = "영문/숫자 2~20자 이내로 작성해주세요") private String username; - @NotEmpty @Size(min = 4, max = 20) private String password; - @NotEmpty @Pattern(regexp = "^[\\w._%+-]+@[\\w.-]+\\.[a-zA-Z]{2,6}$", message = "이메일 형식으로 작성해주세요") private String email; - private String phoneNumber; private String position; + private Long numOfDayOff; private LocalDateTime joinDate; public User toEntity() { @@ -46,6 +42,7 @@ public User toEntity() { .email(email) .phoneNumber(phoneNumber) .position(position) + .numOfDayOff(numOfDayOff) .roles("USER") .joinDate(joinDate) .build(); diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java index ff423b7..be5b9b5 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java @@ -3,23 +3,31 @@ import lombok.Getter; import lombok.Setter; +import java.time.LocalDateTime; + public class UserResponse { @Getter @Setter public static class JoinDTO { private Long id; - private String username; private String email; + private String username; + private String phoneNumber; private String position; private String roles; + private Long numOfDayOff; + private LocalDateTime joinDate; public JoinDTO(User user) { this.id = user.getId(); - this.username = user.getUsername(); this.email = user.getEmail(); + this.username = user.getUsername(); + this.phoneNumber = user.getPhoneNumber(); this.position = user.getPosition(); this.roles = user.getRoles(); + this.numOfDayOff = user.getNumOfDayOff(); + this.joinDate = user.getJoinDate(); } } } From 2c8194e54015c5d708f45cac52ba0566d22d2bef Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Thu, 27 Jul 2023 19:17:12 +0900 Subject: [PATCH 022/128] =?UTF-8?q?fix:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8?= =?UTF-8?q?=EC=8B=9C=20username=20=EB=8C=80=EC=8B=A0=20email=EB=A1=9C=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=ED=95=A0=EC=88=98=20=EC=9E=88?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/kdtbe5_miniproject/user/UserController.java | 3 +-- .../java/com/example/kdtbe5_miniproject/user/UserRequest.java | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java index 07445c0..c48b730 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java @@ -43,10 +43,9 @@ public ResponseEntity join(@RequestBody @Valid UserRequest.JoinDTO joinDTO, E public ResponseEntity login(@RequestBody @Valid UserRequest.LoginDTO loginDTO, Errors errors, HttpServletRequest request) { try { UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken - = new UsernamePasswordAuthenticationToken(loginDTO.getUsername(), loginDTO.getPassword()); + = new UsernamePasswordAuthenticationToken(loginDTO.getEmail(), loginDTO.getPassword()); Authentication authentication = authenticationManager.authenticate(usernamePasswordAuthenticationToken); CustomUserDetails myUserDetails = (CustomUserDetails) authentication.getPrincipal(); - log.info(EncryptUtils.decrypt(myUserDetails.getUsername()) + " Login"); String jwt = JwtTokenProvider.create(myUserDetails.getUser()); addLoginHistory(request, myUserDetails); diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java index 504c278..cc58375 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java @@ -13,7 +13,7 @@ public class UserRequest { @Setter public static class LoginDTO { @NotEmpty - private String username; + private String email; @NotEmpty @Size(min = 4, max = 20) private String password; From 6df4b84d0f526a6fcdd68aa5ad3e63e22b8bfa4d Mon Sep 17 00:00:00 2001 From: JOOWON Date: Sat, 29 Jul 2023 00:47:48 +0900 Subject: [PATCH 023/128] =?UTF-8?q?refator:#7=20response=20=ED=98=95?= =?UTF-8?q?=EC=8B=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_core/util/ApiUtils.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/util/ApiUtils.java b/src/main/java/com/example/kdtbe5_miniproject/_core/util/ApiUtils.java index 0277521..f0b22eb 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/_core/util/ApiUtils.java +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/util/ApiUtils.java @@ -7,29 +7,31 @@ // 공통 응답 DTO public class ApiUtils { - public static ApiResult success(T data, HttpStatus status) { - return new ApiResult<>(status.value(), true, data, null); + public static ApiDataResult success(T data) { + return new ApiDataResult<>(true, data); } - public static ApiResult error(String message, HttpStatus status) { - return new ApiResult<>(status.value(), false, null, new ApiError(message, status.value())); + public static ApiMessageResult success(String message) { + return new ApiMessageResult<>(true, message); + } + + public static ApiMessageResult error(String message) { + return new ApiMessageResult<>(false, message); } @Getter @Setter @AllArgsConstructor - public static class ApiResult { - private int code; + public static class ApiDataResult { private final boolean success; private final T data; - private final ApiError error; } @Getter @Setter @AllArgsConstructor - public static class ApiError { + public static class ApiMessageResult { + private final boolean success; private final String message; - private final int status; } } From 9d3881101f1efc0e67c57b5c6c697583876eabe6 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Sat, 29 Jul 2023 00:48:15 +0900 Subject: [PATCH 024/128] =?UTF-8?q?refator:#7=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=EB=90=9C=20response=20=ED=98=95=EC=8B=9D=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kdtbe5_miniproject/_core/errors/MyExceptionHandler.java | 2 +- .../_core/errors/exception/Exception400.java | 4 ++-- .../_core/errors/exception/Exception401.java | 4 ++-- .../_core/errors/exception/Exception403.java | 4 ++-- .../_core/errors/exception/Exception404.java | 4 ++-- .../_core/errors/exception/Exception500.java | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/MyExceptionHandler.java b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/MyExceptionHandler.java index 5da146c..bfbac93 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/MyExceptionHandler.java +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/MyExceptionHandler.java @@ -42,7 +42,7 @@ public ResponseEntity serverError(Exception500 e) { @ExceptionHandler(Exception.class) public ResponseEntity unknownServerError(Exception e) { - ApiUtils.ApiResult apiResult = ApiUtils.error(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + ApiUtils.ApiMessageResult apiResult = ApiUtils.error(e.getMessage()); return new ResponseEntity<>(apiResult, HttpStatus.INTERNAL_SERVER_ERROR); } } diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception400.java b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception400.java index 3677040..286bcfb 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception400.java +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception400.java @@ -17,8 +17,8 @@ public Exception400(String key, String value) { this.value = value; } - public ApiUtils.ApiResult body() { - return ApiUtils.error(getMessage(), HttpStatus.BAD_REQUEST); + public ApiUtils.ApiMessageResult body() { + return ApiUtils.error(getMessage()); } public HttpStatus status() { diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception401.java b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception401.java index ea564e2..7735c53 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception401.java +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception401.java @@ -12,8 +12,8 @@ public Exception401(String message) { super(message); } - public ApiUtils.ApiResult body() { - return ApiUtils.error(getMessage(), HttpStatus.UNAUTHORIZED); + public ApiUtils.ApiMessageResult body() { + return ApiUtils.error(getMessage()); } public HttpStatus status() { diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception403.java b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception403.java index 465e5bd..fefcd45 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception403.java +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception403.java @@ -11,8 +11,8 @@ public Exception403(String message) { super(message); } - public ApiUtils.ApiResult body() { - return ApiUtils.error(getMessage(), HttpStatus.FORBIDDEN); + public ApiUtils.ApiMessageResult body() { + return ApiUtils.error(getMessage()); } public HttpStatus status() { diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception404.java b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception404.java index 0feb80a..3b3289e 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception404.java +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception404.java @@ -11,8 +11,8 @@ public Exception404(String message) { super(message); } - public ApiUtils.ApiResult body() { - return ApiUtils.error(getMessage(), HttpStatus.NOT_FOUND); + public ApiUtils.ApiMessageResult body() { + return ApiUtils.error(getMessage()); } public HttpStatus status() { diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception500.java b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception500.java index ba32d8e..41a25fd 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception500.java +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/Exception500.java @@ -12,8 +12,8 @@ public Exception500(String message) { } - public ApiUtils.ApiResult body() { - return ApiUtils.error(getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + public ApiUtils.ApiMessageResult body() { + return ApiUtils.error(getMessage()); } public HttpStatus status() { From 84ddb80232dba72401fd1d8c6da1f4a173a5c372 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Sat, 29 Jul 2023 00:48:27 +0900 Subject: [PATCH 025/128] =?UTF-8?q?refator:#7=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=EB=90=9C=20response=20=ED=98=95=EC=8B=9D=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/kdtbe5_miniproject/user/UserController.java | 7 +++---- .../com/example/kdtbe5_miniproject/user/UserRequest.java | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java index 07445c0..2333082 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java @@ -36,22 +36,21 @@ public class UserController { public ResponseEntity join(@RequestBody @Valid UserRequest.JoinDTO joinDTO, Errors errors) { UserResponse.JoinDTO responseDTO = userService.joinUser(joinDTO); log.info(joinDTO.getUsername() + " Joined"); - return ResponseEntity.ok().body(ApiUtils.success(responseDTO, HttpStatus.OK)); + return ResponseEntity.ok().body(ApiUtils.success(responseDTO)); } @PostMapping("/login") public ResponseEntity login(@RequestBody @Valid UserRequest.LoginDTO loginDTO, Errors errors, HttpServletRequest request) { try { UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken - = new UsernamePasswordAuthenticationToken(loginDTO.getUsername(), loginDTO.getPassword()); + = new UsernamePasswordAuthenticationToken(loginDTO.getEmail(), loginDTO.getPassword()); Authentication authentication = authenticationManager.authenticate(usernamePasswordAuthenticationToken); CustomUserDetails myUserDetails = (CustomUserDetails) authentication.getPrincipal(); - log.info(EncryptUtils.decrypt(myUserDetails.getUsername()) + " Login"); String jwt = JwtTokenProvider.create(myUserDetails.getUser()); addLoginHistory(request, myUserDetails); - return ResponseEntity.ok().header("Authorization", jwt).body(ApiUtils.success(null, HttpStatus.OK)); + return ResponseEntity.ok().header("Authorization", jwt).body(ApiUtils.success(null)); } catch (Exception e) { throw new Exception401("인증되지 않았습니다"); diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java index 504c278..cc58375 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java @@ -13,7 +13,7 @@ public class UserRequest { @Setter public static class LoginDTO { @NotEmpty - private String username; + private String email; @NotEmpty @Size(min = 4, max = 20) private String password; From 458c0932f2e8d2eb6c49a62efb056b38021674d0 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Mon, 31 Jul 2023 15:56:10 +0900 Subject: [PATCH 026/128] =?UTF-8?q?feat:=20#7=20=EB=8D=94=EB=AF=B8?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=83=9D=EC=84=B1,=20YML=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=ED=8E=B8=EC=A7=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-dev.yml | 6 ++ src/main/resources/db/data.sql | 77 ++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 src/main/resources/db/data.sql diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index b852d74..607397c 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -22,6 +22,12 @@ spring: format_sql: true default_batch_fetch_size: 100 open-in-view: false + defer-datasource-initialization: true + sql: + init: + data-locations: classpath*:db/data.sql + mode: always + platform: h2 logging: level: diff --git a/src/main/resources/db/data.sql b/src/main/resources/db/data.sql new file mode 100644 index 0000000..7072721 --- /dev/null +++ b/src/main/resources/db/data.sql @@ -0,0 +1,77 @@ +/* + user_tb dummy +*/ + +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) +values (1, '윤준호', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester01@gmail.com', '01012345678', '사원', 'ROLE_USER', '2023-07-27', '2023-07-27', '2023-07-27'); + +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) +values (2, '곽빈', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester02@gmail.com', '01012345678', '사원', 'ROLE_USER', '2023-07-27', '2023-07-27', '2023-07-27'); + +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) +values (3, '전형근', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester03@gmail.com', '01012345678', '사원', 'ROLE_USER', '2023-07-27', '2023-07-27', '2023-07-27'); + +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) +values (4, '이영하', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester04@gmail.com', '01012345678', '주임', 'ROLE_USER', '2023-07-27', '2022-11-27', '2023-07-27'); + +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) +values (5, '박치국', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester05@gmail.com', '01012345678', '대리', 'ROLE_USER', '2023-07-27', '2022-11-27', '2023-07-27'); + +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) +values (6, '양석환', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester06@gmail.com', '01012345678', '대리', 'ROLE_ADMIN', '2023-07-27', '2022-01-27', '2023-07-27'); + +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) +values (7, '정수빈', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester07@gmail.com', '01012345678', '과장', 'ROLE_USER', '2023-07-27', '2021-07-27', '2023-07-27'); + +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) +values (8, '김재환', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester08@gmail.com', '01012345678', '차장', 'ROLE_USER', '2023-07-27', '2021-06-27', '2023-07-27'); + +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) +values (9, '허경민', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester09@gmail.com', '01012345678', '차장', 'ROLE_ADMIN', '2023-07-27', '2020-04-27', '2023-07-27'); + +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) +values (10, '양의지', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester10@gmail.com', '01012345678', '부장', 'ROLE_ADMIN', '2023-07-27', '2023-07-27', '2023-07-27'); + +/* + login_tb dummy 10 + */ + +insert into login_tb (id, user_id, ip, user_agent, login_at) values (1, 10, '255.255.255.255', 'Mozilla/...','2023-07-27'); +insert into login_tb (id, user_id, ip, user_agent, login_at) values (2, 9, '255.255.255.0', 'Mozilla/...','2023-07-27'); +insert into login_tb (id, user_id, ip, user_agent, login_at) values (3, 8, '255.255.255.0', 'Mozilla/...','2023-07-27'); +insert into login_tb (id, user_id, ip, user_agent, login_at) values (4, 7, '255.255.255.0', 'Mozilla/...','2023-07-27'); +insert into login_tb (id, user_id, ip, user_agent, login_at) values (5, 6, '255.255.255.0', 'Mozilla/...','2023-07-27'); +insert into login_tb (id, user_id, ip, user_agent, login_at) values (6, 5, '255.255.255.0', 'Mozilla/...','2023-07-27'); +insert into login_tb (id, user_id, ip, user_agent, login_at) values (7, 4, '255.255.255.0', 'Mozilla/...','2023-07-27'); +insert into login_tb (id, user_id, ip, user_agent, login_at) values (8, 3, '255.255.255.1', 'Mozilla/...','2023-07-27'); +insert into login_tb (id, user_id, ip, user_agent, login_at) values (9, 2, '255.255.255.255', 'Mozilla/...','2023-07-27'); +insert into login_tb (id, user_id, ip, user_agent, login_at) values (10, 1, '255.255.255.255', 'Mozilla/...','2023-07-27'); + +/* + dayoff_tb dummy 10 + */ + +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (1, 10, '2023-08-27', '2023-08-27', '배고파서', '오후반차', '승인', 12); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (2, 6, '2023-08-27', '2023-08-27', '배고파서', '오전반차', '반려', 12); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (3, 9, '2023-08-28', '2023-08-28', '배고파서', '오후반차', '대기', 12); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (4, 10, '2023-08-29', '2023-08-29', '배고파서', '오전반차', '승인', 12); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (5, 9, '2023-09-02', '2023-09-02', '배고파서', '오후반차', '대기', 15); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (6, 8, '2023-09-04', '2023-09-05', '배고파서', '연차', '대기', 15); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (7, 7, '2023-09-06', '2023-09-06', '배고파서', '오후반차', '대기', 15); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (8, 8, '2023-09-27', '2023-09-27', '배고파서', '연차', '대기', 15); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (9, 9, '2023-09-27', '2023-09-27', '배고파서', '오후반차', '대기', 15); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (10, 10, '2023-09-29', '2023-09-29', '배고파서', '오후반차', '대기', 15); + +/* + duty_tb dummy 10 + */ +insert into duty_tb (id, user_id, date, reason, status) values (1, 1, '2023-08-01', '막내1', '승인'); +insert into duty_tb (id, user_id, date, reason, status) values (2, 2, '2023-08-02', '막내2', '승인'); +insert into duty_tb (id, user_id, date, reason, status) values (3, 3, '2023-08-03', '막내3', '승인'); +insert into duty_tb (id, user_id, date, reason, status) values (4, 1, '2023-08-04', '막내1', '승인'); +insert into duty_tb (id, user_id, date, reason, status) values (5, 2, '2023-08-05', '막내2', '승인'); +insert into duty_tb (id, user_id, date, reason, status) values (6, 3, '2023-08-06', '막내3', '승인'); +insert into duty_tb (id, user_id, date, reason, status) values (7, 1, '2023-08-07', '막내1', '대기'); +insert into duty_tb (id, user_id, date, reason, status) values (8, 2, '2023-08-08', '막내2', '대기'); +insert into duty_tb (id, user_id, date, reason, status) values (9, 3, '2023-08-09', '막내3', '대기'); +insert into duty_tb (id, user_id, date, reason, status) values (10, 1, '2023-08-10', '막내1', '반려'); \ No newline at end of file From ed933ed681c1c4a3a64bd6e02d85610f70f3f476 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Mon, 31 Jul 2023 15:56:37 +0900 Subject: [PATCH 027/128] =?UTF-8?q?feat:=20#7=20DayOff,=20Duty=20=EC=97=94?= =?UTF-8?q?=ED=8B=B0=ED=8B=B0=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kdtbe5_miniproject/dayoff/DayOff.java | 32 +++++++++++++++++++ .../example/kdtbe5_miniproject/duty/Duty.java | 29 +++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOff.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/duty/Duty.java diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOff.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOff.java new file mode 100644 index 0000000..941ff1f --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOff.java @@ -0,0 +1,32 @@ +package com.example.kdtbe5_miniproject.dayoff; + +import com.example.kdtbe5_miniproject.user.User; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import javax.persistence.*; +import java.time.LocalDate; + +@Entity +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Getter +@Table(name = "dayoff_tb") +public class DayOff { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + private User user; + + private LocalDate startDate; + private LocalDate endDate; + private String reason; + private String type; // 연차, 오전반차, 오후반차 + private String status; // 대기, 승인, 반려 + private Long numOfDayOff; +} \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/duty/Duty.java b/src/main/java/com/example/kdtbe5_miniproject/duty/Duty.java new file mode 100644 index 0000000..eff933b --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/duty/Duty.java @@ -0,0 +1,29 @@ +package com.example.kdtbe5_miniproject.duty; + +import com.example.kdtbe5_miniproject.user.User; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import javax.persistence.*; +import java.time.LocalDate; + +@Entity +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Getter +@Table(name = "duty_tb") +public class Duty { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + private User user; + + private LocalDate date; + private String reason; + private String status; // 대기, 승인, 반려 +} \ No newline at end of file From e3866f967dfe415c84125fe4b408c61ecd940636 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Mon, 31 Jul 2023 15:57:37 +0900 Subject: [PATCH 028/128] =?UTF-8?q?refactor:=20#7=20User=EC=9D=98=20JoinDa?= =?UTF-8?q?te=EB=A5=BC=20DayOff=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kdtbe5_miniproject/_core/util/BaseTimeEntity.java | 2 +- src/main/java/com/example/kdtbe5_miniproject/user/User.java | 5 ++--- .../com/example/kdtbe5_miniproject/user/UserRequest.java | 5 ++--- .../com/example/kdtbe5_miniproject/user/UserResponse.java | 5 ++--- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/util/BaseTimeEntity.java b/src/main/java/com/example/kdtbe5_miniproject/_core/util/BaseTimeEntity.java index 7bc481f..e7bb03e 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/_core/util/BaseTimeEntity.java +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/util/BaseTimeEntity.java @@ -18,5 +18,5 @@ public class BaseTimeEntity { private LocalDateTime createdAt; @LastModifiedDate - private LocalDateTime updateAt; + private LocalDateTime updatedAt; } diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/User.java b/src/main/java/com/example/kdtbe5_miniproject/user/User.java index 6498696..dd31b42 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/User.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/User.java @@ -7,7 +7,7 @@ import lombok.NoArgsConstructor; import javax.persistence.*; -import java.time.LocalDateTime; +import java.time.LocalDate; @Entity @AllArgsConstructor @@ -25,7 +25,6 @@ public class User extends BaseTimeEntity { private String phoneNumber; private String position; //직급 private String roles; //관리자, 사용자 - private Long numOfDayOff; - private LocalDateTime joinDate; + private LocalDate joinDate; } diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java index cc58375..9f7fc48 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java @@ -6,7 +6,7 @@ import javax.validation.constraints.NotEmpty; import javax.validation.constraints.Pattern; import javax.validation.constraints.Size; -import java.time.LocalDateTime; +import java.time.LocalDate; public class UserRequest { @Getter @@ -33,7 +33,7 @@ public static class JoinDTO { private String phoneNumber; private String position; private Long numOfDayOff; - private LocalDateTime joinDate; + private LocalDate joinDate; public User toEntity() { return User.builder() @@ -42,7 +42,6 @@ public User toEntity() { .email(email) .phoneNumber(phoneNumber) .position(position) - .numOfDayOff(numOfDayOff) .roles("USER") .joinDate(joinDate) .build(); diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java index be5b9b5..bd8ca0f 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java @@ -3,7 +3,7 @@ import lombok.Getter; import lombok.Setter; -import java.time.LocalDateTime; +import java.time.LocalDate; public class UserResponse { @@ -17,7 +17,7 @@ public static class JoinDTO { private String position; private String roles; private Long numOfDayOff; - private LocalDateTime joinDate; + private LocalDate joinDate; public JoinDTO(User user) { this.id = user.getId(); @@ -26,7 +26,6 @@ public JoinDTO(User user) { this.phoneNumber = user.getPhoneNumber(); this.position = user.getPosition(); this.roles = user.getRoles(); - this.numOfDayOff = user.getNumOfDayOff(); this.joinDate = user.getJoinDate(); } } From 4e60547f2e2e3226e1a90dc47929183ebe90b088 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Mon, 31 Jul 2023 15:58:16 +0900 Subject: [PATCH 029/128] =?UTF-8?q?refactor:=20#7=20AdminRepository=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=ED=9B=84=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit JPQL 사용 --- .../admin/AdminRepository.java | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java new file mode 100644 index 0000000..fc09f52 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java @@ -0,0 +1,70 @@ +package com.example.kdtbe5_miniproject.admin; + +import com.example.kdtbe5_miniproject.dayoff.DayOff; +import com.example.kdtbe5_miniproject.duty.Duty; +import com.example.kdtbe5_miniproject.user.User; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +import javax.persistence.EntityManager; +import javax.persistence.Query; +import java.util.List; + +@Repository +@RequiredArgsConstructor +public class AdminRepository { + + private final EntityManager entityManager; + + public List findDayOffByStatus(String status) { + Query query = entityManager.createQuery( + "SELECT d FROM DayOff d INNER JOIN d.user u WHERE d.status = :status", DayOff.class); + query.setParameter("status", status); + + return query.getResultList(); + } + + public List findDutyByStatus(String status) { + Query query = entityManager.createQuery( + "SELECT d FROM Duty d INNER JOIN d.user u WHERE d.status = :status", Duty.class); + query.setParameter("status", status); + + return query.getResultList(); + } + + public List findAllUsers() { + Query query = entityManager.createQuery( + "SELECT u FROM User u", User.class); + + return query.getResultList(); + } + + public User findUserById(Long userId) { + Query query = entityManager.createQuery( + "SELECT u FROM User u WHERE id = :id", User.class); + query.setParameter("id", userId); + + return (User) query.getSingleResult(); + } + + @Transactional + public void updateStatusById(Class type, Long id, String status) { + Query query = entityManager.createQuery( + "UPDATE " + type.getSimpleName() + " SET status = :status WHERE id = :id"); + query.setParameter("id", id); + query.setParameter("status", status); + query.executeUpdate(); + } + + @Transactional + public void updateUserById(Long id, String phoneNumber, String position, String roles) { + Query query = entityManager.createQuery( + "UPDATE User SET phoneNumber = :phoneNumber, position = :position, roles = : roles WHERE id = :id"); + query.setParameter("id", id); + query.setParameter("phoneNumber", phoneNumber); + query.setParameter("position", position); + query.setParameter("roles", roles); + query.executeUpdate(); + } +} From e6282484b6313a14ca815768f97af15cafb446f4 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Mon, 31 Jul 2023 15:58:25 +0900 Subject: [PATCH 030/128] =?UTF-8?q?refactor:=20#7=20AdminService=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=ED=9B=84=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit JPQL 사용 --- .../admin/AdminService.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java new file mode 100644 index 0000000..966d455 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java @@ -0,0 +1,47 @@ +package com.example.kdtbe5_miniproject.admin; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import javax.transaction.Transactional; +import java.util.List; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +@Service +public class AdminService { + + private final AdminRepository adminRepository; + + @Transactional + public List findWaitingDayOff() { + String status = "대기"; + return adminRepository.findDayOffByStatus(status).stream().map(AdminResponse.DayOffStatusDTO::new).collect(Collectors.toList()); + } + + @Transactional + public List findWaitingDuty() { + String status = "대기"; + return adminRepository.findDutyByStatus(status).stream().map(AdminResponse.DutyStatusDTO::new).collect(Collectors.toList()); + } + + @Transactional + public List findAllUsers() { + return adminRepository.findAllUsers().stream().map(AdminResponse.UsersDTO::new).collect(Collectors.toList()); + } + + @Transactional + public AdminResponse.UsersDTO findUserDetail(Long userId) { + return new AdminResponse.UsersDTO(adminRepository.findUserById(userId)); + } + + @Transactional + public void modifyStatus(Class type, Long id, AdminRequest.TreatDTO request) { + adminRepository.updateStatusById(type, id, request.getStatus()); + } + + @Transactional + public void modifyUser(Long id, AdminRequest.UserDetailsDTO request) { + adminRepository.updateUserById(id, request.getPhoneNumber(), request.getPosition(), request.getRoles()); + } +} From 8546bf3fe0198ef44c6ac08eb9be47db2273431d Mon Sep 17 00:00:00 2001 From: JOOWON Date: Mon, 31 Jul 2023 15:58:36 +0900 Subject: [PATCH 031/128] =?UTF-8?q?refactor:=20#7=20AdminController=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=ED=9B=84=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit JPQL 사용 --- .../admin/AdminController.java | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 src/main/java/com/example/kdtbe5_miniproject/admin/AdminController.java diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminController.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminController.java new file mode 100644 index 0000000..4366b06 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminController.java @@ -0,0 +1,61 @@ +package com.example.kdtbe5_miniproject.admin; + +import com.example.kdtbe5_miniproject._core.util.ApiUtils; +import com.example.kdtbe5_miniproject.dayoff.DayOff; +import com.example.kdtbe5_miniproject.duty.Duty; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.List; + +@RequiredArgsConstructor +@RestController +@Slf4j +public class AdminController { + + private final AdminService adminService; + + @GetMapping("/status") + public ResponseEntity waitingStatusList() { + + HashMap lists = new HashMap<>(); + lists.put("dayOffList", adminService.findWaitingDayOff()); + lists.put("dutyList", adminService.findWaitingDuty()); + + return ResponseEntity.ok().body(ApiUtils.success(lists)); + } + + @GetMapping("/users") + public ResponseEntity AllUsersList() { + return ResponseEntity.ok().body(ApiUtils.success(adminService.findAllUsers())); + } + + @GetMapping("/users/{userId}") + public ResponseEntity userDetails(@PathVariable Long userId) { + return ResponseEntity.ok().body(ApiUtils.success(adminService.findUserDetail(userId))); + } + + @PutMapping("/status/dayoff/{dayOffId}") + public ResponseEntity dayOffModify(@PathVariable Long dayOffId, @RequestBody AdminRequest.TreatDTO request) { + adminService.modifyStatus(DayOff.class, dayOffId, request); + + return ResponseEntity.ok().body(ApiUtils.success(request.getStatus() + "되었습니다.")); + } + + @PutMapping("/status/duty/{dutyId}") + public ResponseEntity dutyModify(@PathVariable Long dutyId, @RequestBody AdminRequest.TreatDTO request) { + adminService.modifyStatus(Duty.class, dutyId, request); + + return ResponseEntity.ok().body(ApiUtils.success(request.getStatus() + "되었습니다.")); + } + + @PutMapping("/users/update/{userId}") + public ResponseEntity userModify(@PathVariable Long userId, @RequestBody AdminRequest.UserDetailsDTO request) { + adminService.modifyUser(userId, request); + + return ResponseEntity.ok().body(ApiUtils.success("수정되었습니다.")); + } +} From 24ed5b7195b84b1a2472d3289ed43099f75ac3a5 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Mon, 31 Jul 2023 15:58:51 +0900 Subject: [PATCH 032/128] =?UTF-8?q?refactor:=20#7=20AdminRequest,=20Respon?= =?UTF-8?q?se=20DTO=20=EC=83=9D=EC=84=B1=20=ED=9B=84=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit JPQL 사용 --- .../admin/AdminRequest.java | 21 +++++ .../admin/AdminResponse.java | 78 +++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 src/main/java/com/example/kdtbe5_miniproject/admin/AdminRequest.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRequest.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRequest.java new file mode 100644 index 0000000..42cf125 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRequest.java @@ -0,0 +1,21 @@ +package com.example.kdtbe5_miniproject.admin; + +import lombok.Getter; +import lombok.Setter; + +public class AdminRequest { + + @Getter + @Setter + public static class TreatDTO { + private String status; + } + + @Getter + @Setter + public static class UserDetailsDTO { + private String phoneNumber; + private String position; + private String roles; + } +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java new file mode 100644 index 0000000..ba6e00e --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java @@ -0,0 +1,78 @@ +package com.example.kdtbe5_miniproject.admin; + +import com.example.kdtbe5_miniproject.dayoff.DayOff; +import com.example.kdtbe5_miniproject.duty.Duty; +import com.example.kdtbe5_miniproject.user.User; +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDate; + +public class AdminResponse { + + @Getter + @Setter + public static class DayOffStatusDTO { + private Long id; + private Long userId; + private String userName; + private LocalDate startDate; + private LocalDate endDate; + private String reason; + private String type; + private String status; + + public DayOffStatusDTO(DayOff dayOff) { + this.id = dayOff.getId(); + this.userId = dayOff.getUser().getId(); + this.userName = dayOff.getUser().getUsername(); + this.startDate = dayOff.getStartDate(); + this.endDate = dayOff.getEndDate(); + this.reason = dayOff.getReason(); + this.type = dayOff.getType(); + this.status = dayOff.getStatus(); + } + } + + @Getter + @Setter + public static class DutyStatusDTO { + private Long id; + private Long userId; + private String username; + private LocalDate date; + private String reason; + private String status; + + public DutyStatusDTO(Duty duty) { + this.id = duty.getId(); + this.userId = duty.getUser().getId(); + this.username = duty.getUser().getUsername(); + this.date = duty.getDate(); + this.reason = duty.getReason(); + this.status = duty.getStatus(); + } + } + + @Getter + @Setter + public static class UsersDTO { + private Long id; + private String username; + private String email; + private String phoneNumber; + private LocalDate joinDate; + private String position; + private String roles; + + public UsersDTO(User user) { + this.id = user.getId(); + this.username = user.getUsername(); + this.email = user.getEmail(); + this.phoneNumber = user.getPhoneNumber(); + this.joinDate = user.getJoinDate(); + this.position = user.getPosition(); + this.roles = user.getRoles(); + } + } +} From 448fed14a8453fd4a7122256a0e971a9394f3f23 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Mon, 31 Jul 2023 21:31:35 +0900 Subject: [PATCH 033/128] =?UTF-8?q?feat:=20#3=20UserService=20-=20?= =?UTF-8?q?=EB=B9=84=EB=B0=80=EB=B2=88=ED=98=B8=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kdtbe5_miniproject/user/UserService.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java index e067a4e..e7f6c77 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java @@ -1,6 +1,6 @@ package com.example.kdtbe5_miniproject.user; -import com.example.kdtbe5_miniproject._core.util.EncryptUtils; +import com.example.kdtbe5_miniproject._core.errors.exception.UnCorrectPasswordException; import lombok.RequiredArgsConstructor; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; @@ -25,4 +25,15 @@ public UserResponse.JoinDTO joinUser(UserRequest.JoinDTO joinDTO) { User userPS = userRepository.save(joinDTO.toEntity()); return new UserResponse.JoinDTO(userPS); } + + @Transactional + public void updatePwd(UserRequest.ModifyPwdDTO request) { + User user = userRepository.findById(request.getUserId()) + .orElseThrow(() -> new NullPointerException("사용자를 찾을 수 없습니다.")); + + if (!passwordEncoder.matches(request.getOldPassword(), user.getPassword())) { + throw new UnCorrectPasswordException("비밀번호가 일치하지 않습니다."); + } + userRepository.updateById(passwordEncoder.encode(request.getNewPassword()), request.getUserId()); + } } From f8bfef3145e980aee703e416c15afaee2e58bd28 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Mon, 31 Jul 2023 21:31:53 +0900 Subject: [PATCH 034/128] =?UTF-8?q?feat:=20#3=20UserRepository=20-=20?= =?UTF-8?q?=EB=B9=84=EB=B0=80=EB=B2=88=ED=98=B8=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=EC=BF=BC=EB=A6=AC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/kdtbe5_miniproject/user/UserRepository.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java index af1e830..9cd048b 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java @@ -1,8 +1,11 @@ package com.example.kdtbe5_miniproject.user; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; import java.util.Optional; @@ -11,4 +14,8 @@ public interface UserRepository extends JpaRepository { Optional findByEmail(@Param("email") String email); + + @Modifying + @Query(value = "UPDATE User SET password = :newPassword WHERE id = :id") + void updateById(@Param("newPassword") String newPassword, @Param("id") Long id); } From 5775bee34d67db5a93b2343ec49d291a84d19f1f Mon Sep 17 00:00:00 2001 From: JOOWON Date: Mon, 31 Jul 2023 21:32:15 +0900 Subject: [PATCH 035/128] =?UTF-8?q?feat:=20#3=20UserController,=20DTO=20?= =?UTF-8?q?=EB=B9=84=EB=B0=80=EB=B2=88=ED=98=B8=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/kdtbe5_miniproject/user/UserController.java | 9 +++++++-- .../com/example/kdtbe5_miniproject/user/UserRequest.java | 8 ++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java index 2333082..f96e439 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java @@ -4,18 +4,17 @@ import com.example.kdtbe5_miniproject._core.security.CustomUserDetails; import com.example.kdtbe5_miniproject._core.security.JwtTokenProvider; import com.example.kdtbe5_miniproject._core.util.ApiUtils; -import com.example.kdtbe5_miniproject._core.util.EncryptUtils; import com.example.kdtbe5_miniproject.login_history.LoginHistoryRequest; import com.example.kdtbe5_miniproject.login_history.LoginHistoryService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.validation.Errors; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @@ -67,4 +66,10 @@ private void addLoginHistory(HttpServletRequest request, CustomUserDetails myUse loginHistoryService.save(loginHistoryDTO); } + + @PutMapping("/mypage/updatePassword") + public ResponseEntity userPasswordModify(@RequestBody UserRequest.ModifyPwdDTO request) { + userService.updatePwd(request); + return ResponseEntity.ok().body(ApiUtils.success("변경되었습니다.")); + } } \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java index 9f7fc48..2cdd548 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java @@ -47,4 +47,12 @@ public User toEntity() { .build(); } } + + @Getter + @Setter + public static class ModifyPwdDTO { + private Long userId; + private String oldPassword; + private String newPassword; + } } From ebca4e3248598f909f9c3be4cb52e57643974c86 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Mon, 31 Jul 2023 21:32:35 +0900 Subject: [PATCH 036/128] =?UTF-8?q?feat:=20#3=20=EB=B9=84=EB=B0=80?= =?UTF-8?q?=EB=B2=88=ED=98=B8=EA=B0=80=20=EB=A7=9E=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EC=9D=84=20=EB=95=8C=20=EB=B0=9C=EC=83=9D=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../errors/exception/UnCorrectPasswordException.java | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/UnCorrectPasswordException.java diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/UnCorrectPasswordException.java b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/UnCorrectPasswordException.java new file mode 100644 index 0000000..f3c1d81 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/UnCorrectPasswordException.java @@ -0,0 +1,8 @@ +package com.example.kdtbe5_miniproject._core.errors.exception; + +public class UnCorrectPasswordException extends RuntimeException{ + + public UnCorrectPasswordException(String message) { + super(message); + } +} From aa09f61b1471e274fccf1789d61fbf10a4b9e99e Mon Sep 17 00:00:00 2001 From: JOOWON Date: Mon, 31 Jul 2023 21:34:02 +0900 Subject: [PATCH 037/128] =?UTF-8?q?feat:=20#3=20=EC=B0=BE=EB=8A=94=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=EC=9E=90=20=EC=A0=95=EB=B3=B4=EA=B0=80=20?= =?UTF-8?q?=EC=97=86=EC=9D=84=20=EB=95=8C=20=EB=B0=9C=EC=83=9D=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EC=98=88=EC=99=B8=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_core/errors/exception/UserNotFoundException.java | 8 ++++++++ .../com/example/kdtbe5_miniproject/user/UserService.java | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/UserNotFoundException.java diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/UserNotFoundException.java b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/UserNotFoundException.java new file mode 100644 index 0000000..91299b0 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/UserNotFoundException.java @@ -0,0 +1,8 @@ +package com.example.kdtbe5_miniproject._core.errors.exception; + +public class UserNotFoundException extends RuntimeException{ + + public UserNotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java index e7f6c77..33cd005 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java @@ -1,6 +1,7 @@ package com.example.kdtbe5_miniproject.user; import com.example.kdtbe5_miniproject._core.errors.exception.UnCorrectPasswordException; +import com.example.kdtbe5_miniproject._core.errors.exception.UserNotFoundException; import lombok.RequiredArgsConstructor; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; @@ -29,7 +30,7 @@ public UserResponse.JoinDTO joinUser(UserRequest.JoinDTO joinDTO) { @Transactional public void updatePwd(UserRequest.ModifyPwdDTO request) { User user = userRepository.findById(request.getUserId()) - .orElseThrow(() -> new NullPointerException("사용자를 찾을 수 없습니다.")); + .orElseThrow(() -> new UserNotFoundException("사용자를 찾을 수 없습니다.")); if (!passwordEncoder.matches(request.getOldPassword(), user.getPassword())) { throw new UnCorrectPasswordException("비밀번호가 일치하지 않습니다."); From 8104af5520fa31ab821a2bde19d538ade34ed55a Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Tue, 1 Aug 2023 05:31:11 +0900 Subject: [PATCH 038/128] =?UTF-8?q?feat:#3=20UserRequest=20/=20UpdateDTO?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/kdtbe5_miniproject/user/UserRequest.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java index 9f7fc48..0b7ce3a 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java @@ -30,6 +30,7 @@ public static class JoinDTO { @NotEmpty @Pattern(regexp = "^[\\w._%+-]+@[\\w.-]+\\.[a-zA-Z]{2,6}$", message = "이메일 형식으로 작성해주세요") private String email; + @Pattern(regexp = "^01(?:0|1|[6-9])\\d{7,8}$", message = "01011112222와 같은 형식으로 작성해주세요") private String phoneNumber; private String position; private Long numOfDayOff; @@ -47,4 +48,12 @@ public User toEntity() { .build(); } } + + @Getter + public static class UpdateDTO { + + @NotEmpty + @Pattern(regexp = "^01(?:0|1|[6-9])\\d{7,8}$", message = "01011112222와 같은 형식으로 작성해주세요") + private String phoneNumber; + } } From a116b57268751db012bc118bf65d42b74c43a6a2 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Tue, 1 Aug 2023 05:32:39 +0900 Subject: [PATCH 039/128] =?UTF-8?q?feat:#3=20User=20/=20updatePhoneNumber?= =?UTF-8?q?=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/example/kdtbe5_miniproject/user/User.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/User.java b/src/main/java/com/example/kdtbe5_miniproject/user/User.java index dd31b42..fd0bc9a 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/User.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/User.java @@ -27,4 +27,8 @@ public class User extends BaseTimeEntity { private String roles; //관리자, 사용자 private LocalDate joinDate; + public void updatePhoneNumber(String newPhoneNum) { + this.phoneNumber = newPhoneNum; + } + } From d1a9c429e1ec8c853af3719fa10aebf0695fc49c Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Tue, 1 Aug 2023 05:34:40 +0900 Subject: [PATCH 040/128] =?UTF-8?q?feat:#3=20UserService=20/=20updatePhone?= =?UTF-8?q?Number=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/kdtbe5_miniproject/user/UserService.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java index e067a4e..1282e7c 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java @@ -2,10 +2,14 @@ import com.example.kdtbe5_miniproject._core.util.EncryptUtils; import lombok.RequiredArgsConstructor; +import org.aspectj.apache.bcel.classfile.Module; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.security.Principal; +import java.util.Optional; + @RequiredArgsConstructor @Service public class UserService { @@ -25,4 +29,12 @@ public UserResponse.JoinDTO joinUser(UserRequest.JoinDTO joinDTO) { User userPS = userRepository.save(joinDTO.toEntity()); return new UserResponse.JoinDTO(userPS); } + + @Transactional + public void updatePhoneNumber(User updateUser, UserRequest.UpdateDTO updateDTO) { + Optional userOP = userRepository.findByEmail(updateUser.getEmail()); + User user = userOP.get(); + user.updatePhoneNumber(updateDTO.getPhoneNumber()); + } + } From 7f5881d6423a82881bd10e7230f1def4c10b8ff9 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Tue, 1 Aug 2023 05:34:59 +0900 Subject: [PATCH 041/128] =?UTF-8?q?feat:#3=20UserController=20/=20updatePh?= =?UTF-8?q?oneNumber=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kdtbe5_miniproject/user/UserController.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java index 2333082..ba43efe 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java @@ -14,13 +14,16 @@ import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.validation.Errors; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; +import java.security.Principal; import java.time.LocalDateTime; @RequiredArgsConstructor @@ -67,4 +70,11 @@ private void addLoginHistory(HttpServletRequest request, CustomUserDetails myUse loginHistoryService.save(loginHistoryDTO); } + + @PutMapping("/mypage/updatePhoneNumber") + private ResponseEntity updatePhoneNumber(@AuthenticationPrincipal User updateUser, @RequestBody @Valid UserRequest.UpdateDTO updateDTO, Errors errors) { + userService.updatePhoneNumber(updateUser, updateDTO); + return ResponseEntity.ok().body(ApiUtils.success("전화번호가 변경되었습니다.")); + } + } \ No newline at end of file From 0ac9cc2cf9523c7b9ffe4915513e6d1cdc5da186 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Tue, 1 Aug 2023 14:15:39 +0900 Subject: [PATCH 042/128] =?UTF-8?q?refacor:=20numOfDayOff=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=20Float=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/kdtbe5_miniproject/user/UserRequest.java | 2 +- .../java/com/example/kdtbe5_miniproject/user/UserResponse.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java index 0b7ce3a..9b38676 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java @@ -33,7 +33,7 @@ public static class JoinDTO { @Pattern(regexp = "^01(?:0|1|[6-9])\\d{7,8}$", message = "01011112222와 같은 형식으로 작성해주세요") private String phoneNumber; private String position; - private Long numOfDayOff; + private Float numOfDayOff; private LocalDate joinDate; public User toEntity() { diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java index bd8ca0f..7bb1b26 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java @@ -16,7 +16,7 @@ public static class JoinDTO { private String phoneNumber; private String position; private String roles; - private Long numOfDayOff; + private Float numOfDayOff; private LocalDate joinDate; public JoinDTO(User user) { From 933543adf468e828d375ca7695ef3aa528dd2436 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Tue, 1 Aug 2023 14:16:04 +0900 Subject: [PATCH 043/128] =?UTF-8?q?refacor:=20TODO=20=EA=B8=B0=EC=9E=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/kdtbe5_miniproject/dayoff/DayOff.java | 6 +++--- src/main/java/com/example/kdtbe5_miniproject/duty/Duty.java | 2 +- src/main/java/com/example/kdtbe5_miniproject/user/User.java | 5 +++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOff.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOff.java index 941ff1f..fa8a181 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOff.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOff.java @@ -26,7 +26,7 @@ public class DayOff { private LocalDate startDate; private LocalDate endDate; private String reason; - private String type; // 연차, 오전반차, 오후반차 - private String status; // 대기, 승인, 반려 - private Long numOfDayOff; + private String type; //TODO enum 타입으로 변경 (연자, 오전반차, 오후반차) + private String status; //TODO enum 타입으로 변경 (대기, 승인, 반려) + private Float numOfDayOff; } \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/duty/Duty.java b/src/main/java/com/example/kdtbe5_miniproject/duty/Duty.java index eff933b..0e7687c 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/duty/Duty.java +++ b/src/main/java/com/example/kdtbe5_miniproject/duty/Duty.java @@ -25,5 +25,5 @@ public class Duty { private LocalDate date; private String reason; - private String status; // 대기, 승인, 반려 + private String status; //TODO enum 타입으로 변경 (대기, 승인, 반려) } \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/User.java b/src/main/java/com/example/kdtbe5_miniproject/user/User.java index fd0bc9a..16aa4cb 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/User.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/User.java @@ -8,6 +8,7 @@ import javax.persistence.*; import java.time.LocalDate; +import java.util.function.LongConsumer; @Entity @AllArgsConstructor @@ -23,8 +24,8 @@ public class User extends BaseTimeEntity { private String password; private String email; private String phoneNumber; - private String position; //직급 - private String roles; //관리자, 사용자 + private String position; //TODO 직급 enum 타입으로 변경 + private String roles; //TODO 권한 enum 타입으로 변경 private LocalDate joinDate; public void updatePhoneNumber(String newPhoneNum) { From 1e29cd0043fb8d53522c96b69f74b2661a02c55d Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Tue, 1 Aug 2023 14:16:50 +0900 Subject: [PATCH 044/128] =?UTF-8?q?refacor:=20BaseTimeEntity=20>=20DateUti?= =?UTF-8?q?ls=20=EC=83=81=EC=86=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kdtbe5_miniproject/_core/util/BaseTimeEntity.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/util/BaseTimeEntity.java b/src/main/java/com/example/kdtbe5_miniproject/_core/util/BaseTimeEntity.java index e7bb03e..b36de28 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/_core/util/BaseTimeEntity.java +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/util/BaseTimeEntity.java @@ -12,11 +12,8 @@ @Getter @MappedSuperclass @EntityListeners(AuditingEntityListener.class) -public class BaseTimeEntity { - - @CreatedDate - private LocalDateTime createdAt; +public class BaseTimeEntity extends DateUtils{ @LastModifiedDate - private LocalDateTime updatedAt; + private LocalDateTime updateDate; //TODO 초가 소수점 단위로 생성되어서 저장됨, 소수점 이하 버리기 } From e504080be25fe5cff0d3105cc7fc42eb9239f934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=98=9C=EC=A7=80?= <128347921+bornin23@users.noreply.github.com> Date: Tue, 1 Aug 2023 14:48:58 +0900 Subject: [PATCH 045/128] =?UTF-8?q?fix:=20@Getter=20@Setter=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/kdtbe5_miniproject/user/UserRequest.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java index 3996902..a9c06fe 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java @@ -50,14 +50,13 @@ public User toEntity() { } @Getter - public static class UpdateDTO { - @NotEmpty @Pattern(regexp = "^01(?:0|1|[6-9])\\d{7,8}$", message = "01011112222와 같은 형식으로 작성해주세요") private String phoneNumber; } - + + @Getter @Setter public static class ModifyPwdDTO { private Long userId; From 7c31418a3cad4848dd9e1f7192b00319ae9c6b4b Mon Sep 17 00:00:00 2001 From: JOOWON <51067466+dali186@users.noreply.github.com> Date: Tue, 1 Aug 2023 15:11:00 +0900 Subject: [PATCH 046/128] =?UTF-8?q?fix:=20@Transactional=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/kdtbe5_miniproject/user/UserService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java index 4b4c386..16082ee 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java @@ -38,6 +38,7 @@ public void updatePhoneNumber(User updateUser, UserRequest.UpdateDTO updateDTO) user.updatePhoneNumber(updateDTO.getPhoneNumber()); } + @Transactional public void updatePwd(UserRequest.ModifyPwdDTO request) { User user = userRepository.findById(request.getUserId()) .orElseThrow(() -> new UserNotFoundException("사용자를 찾을 수 없습니다.")); From 08d3ca1a7deb4d2dae88cd5cb74421740e9096f9 Mon Sep 17 00:00:00 2001 From: Park SeongWook <116128609+gosuuk@users.noreply.github.com> Date: Tue, 1 Aug 2023 17:16:40 +0900 Subject: [PATCH 047/128] =?UTF-8?q?#[4]=20=EB=8B=B9=EC=A7=81=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D/=EC=82=AD=EC=A0=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../executionHistory/executionHistory.lock | Bin 17 -> 17 bytes .gradle/8.1.1/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .../exception/DutyNotFoundException.java | 7 +++ .../duty/DutyController.java | 41 +++++++++++++++ .../duty/DutyRepository.java | 15 ++++++ .../kdtbe5_miniproject/duty/DutyRequest.java | 19 +++++++ .../kdtbe5_miniproject/duty/DutyResponse.java | 24 +++++++++ .../kdtbe5_miniproject/duty/DutyService.java | 47 ++++++++++++++++++ 9 files changed, 153 insertions(+) create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/DutyNotFoundException.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/duty/DutyController.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/duty/DutyRepository.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/duty/DutyRequest.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/duty/DutyResponse.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/duty/DutyService.java diff --git a/.gradle/8.1.1/executionHistory/executionHistory.lock b/.gradle/8.1.1/executionHistory/executionHistory.lock index 9f699e1abca244b4b06fd84b47ae978f7cb03c56..cd5f608412274d6263040d5a0f1724c5fd0ef263 100644 GIT binary patch literal 17 TcmZQxX4AXdKwVOm0Rs2{C7%M( literal 17 TcmZQxX4AXdKwVOm0Rq?oC71%r diff --git a/.gradle/8.1.1/fileHashes/fileHashes.lock b/.gradle/8.1.1/fileHashes/fileHashes.lock index 830f74f93f6a3f641c3fa91de380f488722c7cf4..85871a1c7fd24ed2c056444d1af7e2f6c87e2aa2 100644 GIT binary patch literal 17 UcmZRc9`t<9-qrRW7$9I006x71nE(I) literal 17 UcmZRc9`t<9-qrRW7$6`O06vffYybcN diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index 730f30fb0312f8e35cdc5f113be8d710d1ff6779..e04b91165d7913c0dbbc22895932c9198894ea2b 100644 GIT binary patch literal 17 UcmZQ(h|7Fy<23ms0|aOR04gj4yZ`_I literal 17 UcmZQ(h|7Fy<23ms0|Y1l04gE_vH$=8 diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/DutyNotFoundException.java b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/DutyNotFoundException.java new file mode 100644 index 0000000..171da00 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/DutyNotFoundException.java @@ -0,0 +1,7 @@ +package com.example.kdtbe5_miniproject._core.errors.exception; + +public class DutyNotFoundException extends RuntimeException { + public DutyNotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyController.java b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyController.java new file mode 100644 index 0000000..6ed304f --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyController.java @@ -0,0 +1,41 @@ +package com.example.kdtbe5_miniproject.duty; + +import com.example.kdtbe5_miniproject._core.security.CustomUserDetails; +import com.example.kdtbe5_miniproject._core.util.ApiUtils; +import com.example.kdtbe5_miniproject.user.User; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; + +@RequiredArgsConstructor +@RestController +public class DutyController { + + private final DutyService dutyService; + + @PostMapping("/duty/register") + public ResponseEntity createDuty(@RequestBody @Valid DutyRequest.DutyDTO dutyDTO, @AuthenticationPrincipal CustomUserDetails customUserDetails) { + User user = customUserDetails.getUser(); + DutyResponse.DutyDTO responseDTO = dutyService.createDuty(dutyDTO, user.getId()); + return ResponseEntity.ok().body(ApiUtils.success(responseDTO)); + } + + + @GetMapping("/duty/applied") + public ResponseEntity getAppliedDuty(@AuthenticationPrincipal CustomUserDetails customUserDetails) { + User user = customUserDetails.getUser(); + List appliedDuties = dutyService.getAppliedDuties(user.getId()); + return ResponseEntity.ok().body(ApiUtils.success(appliedDuties)); + } + + @DeleteMapping("/duty/{dutyId}") + public ResponseEntity deleteDuty(@PathVariable Long dutyId, @AuthenticationPrincipal CustomUserDetails customUserDetails) { + User user = customUserDetails.getUser(); + dutyService.deleteDuty(dutyId, user.getId()); + return ResponseEntity.ok().body(ApiUtils.success("당직 신청이 취소되었습니다.")); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyRepository.java b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyRepository.java new file mode 100644 index 0000000..4c63cf9 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyRepository.java @@ -0,0 +1,15 @@ +package com.example.kdtbe5_miniproject.duty; + +import com.example.kdtbe5_miniproject.user.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface DutyRepository extends JpaRepository { + + Optional findByIdAndUser(Long id, User user); + List findAllByUser(User user); +} \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyRequest.java b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyRequest.java new file mode 100644 index 0000000..57772eb --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyRequest.java @@ -0,0 +1,19 @@ +package com.example.kdtbe5_miniproject.duty; + +import lombok.Getter; +import lombok.Setter; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.time.LocalDate; + +public class DutyRequest { + @Getter + @Setter + public static class DutyDTO { + @NotNull + private LocalDate date; + @NotEmpty + private String reason; + } +} \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyResponse.java b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyResponse.java new file mode 100644 index 0000000..9bfd49e --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyResponse.java @@ -0,0 +1,24 @@ +package com.example.kdtbe5_miniproject.duty; + +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDate; + +public class DutyResponse { + @Getter + @Setter + public static class DutyDTO { + private Long id; + private LocalDate date; + private String reason; + private String status; + + public DutyDTO(Duty duty) { + this.id = duty.getId(); + this.date = duty.getDate(); + this.reason = duty.getReason(); + this.status = duty.getStatus(); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyService.java b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyService.java new file mode 100644 index 0000000..13cc760 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyService.java @@ -0,0 +1,47 @@ +package com.example.kdtbe5_miniproject.duty; + +import com.example.kdtbe5_miniproject._core.errors.exception.DutyNotFoundException; +import com.example.kdtbe5_miniproject.user.User; +import com.example.kdtbe5_miniproject.user.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +@Service +public class DutyService { + + private final DutyRepository dutyRepository; + private final UserRepository userRepository; + + @Transactional + public DutyResponse.DutyDTO createDuty(DutyRequest.DutyDTO dutyDTO, Long userId) { + User user = userRepository.findById(userId).orElseThrow(() -> new IllegalArgumentException("잘못된 사용자 ID입니다.")); + Duty duty = Duty.builder() + .date(dutyDTO.getDate()) + .reason(dutyDTO.getReason()) + .status("대기") + .user(user) + .build(); + Duty createdDuty = dutyRepository.save(duty); + return new DutyResponse.DutyDTO(createdDuty); + } + + @Transactional(readOnly = true) + public List getAppliedDuties(Long userId) { + User user = userRepository.findById(userId).orElseThrow(() -> new IllegalArgumentException("잘못된 사용자 ID입니다.")); + return dutyRepository.findAllByUser(user).stream() + .map(DutyResponse.DutyDTO::new) + .collect(Collectors.toList()); + } + + @Transactional + public void deleteDuty(Long dutyId, Long userId) { + User user = userRepository.findById(userId).orElseThrow(() -> new IllegalArgumentException("잘못된 사용자 ID입니다.")); + Duty duty = dutyRepository.findByIdAndUser(dutyId, user).orElseThrow(() -> new DutyNotFoundException("당직을 찾을 수 없습니다.")); + dutyRepository.delete(duty); + } +} \ No newline at end of file From 5e6aaf9c07c0b573addf71e0613a894ee7aec176 Mon Sep 17 00:00:00 2001 From: Park SeongWook <116128609+gosuuk@users.noreply.github.com> Date: Tue, 1 Aug 2023 17:16:54 +0900 Subject: [PATCH 048/128] =?UTF-8?q?#[4]=20db=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/db/data.sql | 55 +++++++++++++--------------------- 1 file changed, 20 insertions(+), 35 deletions(-) diff --git a/src/main/resources/db/data.sql b/src/main/resources/db/data.sql index 7072721..bce4e65 100644 --- a/src/main/resources/db/data.sql +++ b/src/main/resources/db/data.sql @@ -1,41 +1,29 @@ /* user_tb dummy */ - -insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) -values (1, '윤준호', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester01@gmail.com', '01012345678', '사원', 'ROLE_USER', '2023-07-27', '2023-07-27', '2023-07-27'); - -insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) -values (2, '곽빈', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester02@gmail.com', '01012345678', '사원', 'ROLE_USER', '2023-07-27', '2023-07-27', '2023-07-27'); - -insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) -values (3, '전형근', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester03@gmail.com', '01012345678', '사원', 'ROLE_USER', '2023-07-27', '2023-07-27', '2023-07-27'); - -insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) -values (4, '이영하', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester04@gmail.com', '01012345678', '주임', 'ROLE_USER', '2023-07-27', '2022-11-27', '2023-07-27'); - -insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) -values (5, '박치국', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester05@gmail.com', '01012345678', '대리', 'ROLE_USER', '2023-07-27', '2022-11-27', '2023-07-27'); - -insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) -values (6, '양석환', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester06@gmail.com', '01012345678', '대리', 'ROLE_ADMIN', '2023-07-27', '2022-01-27', '2023-07-27'); - -insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) -values (7, '정수빈', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester07@gmail.com', '01012345678', '과장', 'ROLE_USER', '2023-07-27', '2021-07-27', '2023-07-27'); - -insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) -values (8, '김재환', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester08@gmail.com', '01012345678', '차장', 'ROLE_USER', '2023-07-27', '2021-06-27', '2023-07-27'); - -insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) -values (9, '허경민', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester09@gmail.com', '01012345678', '차장', 'ROLE_ADMIN', '2023-07-27', '2020-04-27', '2023-07-27'); - -insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) -values (10, '양의지', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester10@gmail.com', '01012345678', '부장', 'ROLE_ADMIN', '2023-07-27', '2023-07-27', '2023-07-27'); - +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) +values (1, '윤준호', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester01@gmail.com', '01012345678', '사원', 'ROLE_USER', '2023-07-27', '2023-07-27'); +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) +values (2, '곽빈', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester02@gmail.com', '01012345678', '사원', 'ROLE_USER', '2023-07-27', '2023-07-27'); +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) +values (3, '전형근', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester03@gmail.com', '01012345678', '사원', 'ROLE_USER', '2023-07-27', '2023-07-27'); +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) +values (4, '이영하', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester04@gmail.com', '01012345678', '주임', 'ROLE_USER', '2023-07-27', '2023-07-27'); +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) +values (5, '박치국', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester05@gmail.com', '01012345678', '대리', 'ROLE_USER', '2023-07-27', '2023-07-27'); +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) +values (6, '양석환', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester06@gmail.com', '01012345678', '대리', 'ROLE_ADMIN', '2023-07-27', '2023-07-27'); +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) +values (7, '정수빈', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester07@gmail.com', '01012345678', '과장', 'ROLE_USER', '2023-07-27', '2023-07-27'); +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) +values (8, '김재환', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester08@gmail.com', '01012345678', '차장', 'ROLE_USER', '2023-07-27', '2023-07-27'); +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) +values (9, '허경민', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester09@gmail.com', '01012345678', '차장', 'ROLE_ADMIN', '2023-07-27', '2023-07-27'); +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) +values (10, '양의지', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester10@gmail.com', '01012345678', '부장', 'ROLE_ADMIN', '2023-07-27', '2023-07-27'); /* login_tb dummy 10 */ - insert into login_tb (id, user_id, ip, user_agent, login_at) values (1, 10, '255.255.255.255', 'Mozilla/...','2023-07-27'); insert into login_tb (id, user_id, ip, user_agent, login_at) values (2, 9, '255.255.255.0', 'Mozilla/...','2023-07-27'); insert into login_tb (id, user_id, ip, user_agent, login_at) values (3, 8, '255.255.255.0', 'Mozilla/...','2023-07-27'); @@ -46,11 +34,9 @@ insert into login_tb (id, user_id, ip, user_agent, login_at) values (7, 4, '255. insert into login_tb (id, user_id, ip, user_agent, login_at) values (8, 3, '255.255.255.1', 'Mozilla/...','2023-07-27'); insert into login_tb (id, user_id, ip, user_agent, login_at) values (9, 2, '255.255.255.255', 'Mozilla/...','2023-07-27'); insert into login_tb (id, user_id, ip, user_agent, login_at) values (10, 1, '255.255.255.255', 'Mozilla/...','2023-07-27'); - /* dayoff_tb dummy 10 */ - insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (1, 10, '2023-08-27', '2023-08-27', '배고파서', '오후반차', '승인', 12); insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (2, 6, '2023-08-27', '2023-08-27', '배고파서', '오전반차', '반려', 12); insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (3, 9, '2023-08-28', '2023-08-28', '배고파서', '오후반차', '대기', 12); @@ -61,7 +47,6 @@ insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (8, 8, '2023-09-27', '2023-09-27', '배고파서', '연차', '대기', 15); insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (9, 9, '2023-09-27', '2023-09-27', '배고파서', '오후반차', '대기', 15); insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (10, 10, '2023-09-29', '2023-09-29', '배고파서', '오후반차', '대기', 15); - /* duty_tb dummy 10 */ From c2780110c0099d64381101019eab4ff6ea928acc Mon Sep 17 00:00:00 2001 From: JOOWON Date: Tue, 1 Aug 2023 17:17:21 +0900 Subject: [PATCH 049/128] =?UTF-8?q?refactor:=20#3=20SQL=20=EB=8D=94?= =?UTF-8?q?=EB=AF=B8=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/db/data.sql | 55 +++++++++++++--------------------- 1 file changed, 20 insertions(+), 35 deletions(-) diff --git a/src/main/resources/db/data.sql b/src/main/resources/db/data.sql index 7072721..bce4e65 100644 --- a/src/main/resources/db/data.sql +++ b/src/main/resources/db/data.sql @@ -1,41 +1,29 @@ /* user_tb dummy */ - -insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) -values (1, '윤준호', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester01@gmail.com', '01012345678', '사원', 'ROLE_USER', '2023-07-27', '2023-07-27', '2023-07-27'); - -insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) -values (2, '곽빈', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester02@gmail.com', '01012345678', '사원', 'ROLE_USER', '2023-07-27', '2023-07-27', '2023-07-27'); - -insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) -values (3, '전형근', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester03@gmail.com', '01012345678', '사원', 'ROLE_USER', '2023-07-27', '2023-07-27', '2023-07-27'); - -insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) -values (4, '이영하', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester04@gmail.com', '01012345678', '주임', 'ROLE_USER', '2023-07-27', '2022-11-27', '2023-07-27'); - -insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) -values (5, '박치국', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester05@gmail.com', '01012345678', '대리', 'ROLE_USER', '2023-07-27', '2022-11-27', '2023-07-27'); - -insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) -values (6, '양석환', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester06@gmail.com', '01012345678', '대리', 'ROLE_ADMIN', '2023-07-27', '2022-01-27', '2023-07-27'); - -insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) -values (7, '정수빈', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester07@gmail.com', '01012345678', '과장', 'ROLE_USER', '2023-07-27', '2021-07-27', '2023-07-27'); - -insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) -values (8, '김재환', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester08@gmail.com', '01012345678', '차장', 'ROLE_USER', '2023-07-27', '2021-06-27', '2023-07-27'); - -insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) -values (9, '허경민', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester09@gmail.com', '01012345678', '차장', 'ROLE_ADMIN', '2023-07-27', '2020-04-27', '2023-07-27'); - -insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, created_at, updated_at) -values (10, '양의지', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester10@gmail.com', '01012345678', '부장', 'ROLE_ADMIN', '2023-07-27', '2023-07-27', '2023-07-27'); - +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) +values (1, '윤준호', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester01@gmail.com', '01012345678', '사원', 'ROLE_USER', '2023-07-27', '2023-07-27'); +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) +values (2, '곽빈', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester02@gmail.com', '01012345678', '사원', 'ROLE_USER', '2023-07-27', '2023-07-27'); +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) +values (3, '전형근', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester03@gmail.com', '01012345678', '사원', 'ROLE_USER', '2023-07-27', '2023-07-27'); +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) +values (4, '이영하', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester04@gmail.com', '01012345678', '주임', 'ROLE_USER', '2023-07-27', '2023-07-27'); +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) +values (5, '박치국', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester05@gmail.com', '01012345678', '대리', 'ROLE_USER', '2023-07-27', '2023-07-27'); +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) +values (6, '양석환', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester06@gmail.com', '01012345678', '대리', 'ROLE_ADMIN', '2023-07-27', '2023-07-27'); +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) +values (7, '정수빈', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester07@gmail.com', '01012345678', '과장', 'ROLE_USER', '2023-07-27', '2023-07-27'); +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) +values (8, '김재환', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester08@gmail.com', '01012345678', '차장', 'ROLE_USER', '2023-07-27', '2023-07-27'); +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) +values (9, '허경민', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester09@gmail.com', '01012345678', '차장', 'ROLE_ADMIN', '2023-07-27', '2023-07-27'); +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) +values (10, '양의지', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester10@gmail.com', '01012345678', '부장', 'ROLE_ADMIN', '2023-07-27', '2023-07-27'); /* login_tb dummy 10 */ - insert into login_tb (id, user_id, ip, user_agent, login_at) values (1, 10, '255.255.255.255', 'Mozilla/...','2023-07-27'); insert into login_tb (id, user_id, ip, user_agent, login_at) values (2, 9, '255.255.255.0', 'Mozilla/...','2023-07-27'); insert into login_tb (id, user_id, ip, user_agent, login_at) values (3, 8, '255.255.255.0', 'Mozilla/...','2023-07-27'); @@ -46,11 +34,9 @@ insert into login_tb (id, user_id, ip, user_agent, login_at) values (7, 4, '255. insert into login_tb (id, user_id, ip, user_agent, login_at) values (8, 3, '255.255.255.1', 'Mozilla/...','2023-07-27'); insert into login_tb (id, user_id, ip, user_agent, login_at) values (9, 2, '255.255.255.255', 'Mozilla/...','2023-07-27'); insert into login_tb (id, user_id, ip, user_agent, login_at) values (10, 1, '255.255.255.255', 'Mozilla/...','2023-07-27'); - /* dayoff_tb dummy 10 */ - insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (1, 10, '2023-08-27', '2023-08-27', '배고파서', '오후반차', '승인', 12); insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (2, 6, '2023-08-27', '2023-08-27', '배고파서', '오전반차', '반려', 12); insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (3, 9, '2023-08-28', '2023-08-28', '배고파서', '오후반차', '대기', 12); @@ -61,7 +47,6 @@ insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (8, 8, '2023-09-27', '2023-09-27', '배고파서', '연차', '대기', 15); insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (9, 9, '2023-09-27', '2023-09-27', '배고파서', '오후반차', '대기', 15); insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (10, 10, '2023-09-29', '2023-09-29', '배고파서', '오후반차', '대기', 15); - /* duty_tb dummy 10 */ From a935336c9f7b5eab061caaa83c3fb97a4a352911 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Tue, 1 Aug 2023 17:17:46 +0900 Subject: [PATCH 050/128] =?UTF-8?q?refactor:=20#3=20UserController,=20?= =?UTF-8?q?=EC=A0=91=EA=B7=BC=EC=A0=9C=EC=96=B4=EC=9E=90=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/kdtbe5_miniproject/user/UserController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java index 5930cbd..da85b3b 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java @@ -71,8 +71,8 @@ private void addLoginHistory(HttpServletRequest request, CustomUserDetails myUse @PutMapping("/mypage/updatePhoneNumber") - private ResponseEntity updatePhoneNumber(@AuthenticationPrincipal User updateUser, @RequestBody @Valid UserRequest.UpdateDTO updateDTO, Errors errors) { - userService.updatePhoneNumber(updateUser, updateDTO); + public ResponseEntity updatePhoneNumber(@AuthenticationPrincipal CustomUserDetails updateUser, @RequestBody @Valid UserRequest.UpdateDTO updateDTO) { + userService.updatePhoneNumber(updateUser.getUserId(), updateDTO); return ResponseEntity.ok().body(ApiUtils.success("전화번호가 변경되었습니다.")); } From c3a0d2662557e68075275e5c6a8ca8b4510c1dc6 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Tue, 1 Aug 2023 17:18:53 +0900 Subject: [PATCH 051/128] =?UTF-8?q?refactor:=20#3=20DTO,=20=EC=96=B4?= =?UTF-8?q?=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/kdtbe5_miniproject/user/UserRequest.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java index 3996902..4233fef 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java @@ -48,16 +48,15 @@ public User toEntity() { .build(); } } - @Getter - public static class UpdateDTO { @NotEmpty @Pattern(regexp = "^01(?:0|1|[6-9])\\d{7,8}$", message = "01011112222와 같은 형식으로 작성해주세요") private String phoneNumber; } - + + @Getter @Setter public static class ModifyPwdDTO { private Long userId; From b96b7a10664845a98bb8d761d71418bd27c5c914 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Tue, 1 Aug 2023 17:19:17 +0900 Subject: [PATCH 052/128] =?UTF-8?q?refactor:=20#3=20Service,=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/kdtbe5_miniproject/user/UserService.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java index 4b4c386..9ddb68f 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java @@ -32,12 +32,13 @@ public UserResponse.JoinDTO joinUser(UserRequest.JoinDTO joinDTO) { } @Transactional - public void updatePhoneNumber(User updateUser, UserRequest.UpdateDTO updateDTO) { - Optional userOP = userRepository.findByEmail(updateUser.getEmail()); - User user = userOP.get(); + public void updatePhoneNumber(Long userId, UserRequest.UpdateDTO updateDTO) { + User user = userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException("사용자 정보가 없습니다.")); user.updatePhoneNumber(updateDTO.getPhoneNumber()); + userRepository.save(user); } + @Transactional public void updatePwd(UserRequest.ModifyPwdDTO request) { User user = userRepository.findById(request.getUserId()) .orElseThrow(() -> new UserNotFoundException("사용자를 찾을 수 없습니다.")); @@ -47,4 +48,4 @@ public void updatePwd(UserRequest.ModifyPwdDTO request) { } userRepository.updateById(passwordEncoder.encode(request.getNewPassword()), request.getUserId()); } -} +} \ No newline at end of file From d0cb2bc1ff7383a6f1dba35f82c8475e4e52ffb1 Mon Sep 17 00:00:00 2001 From: Park SeongWook <116128609+gosuuk@users.noreply.github.com> Date: Tue, 1 Aug 2023 18:29:06 +0900 Subject: [PATCH 053/128] =?UTF-8?q?#4=20DayOff=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../executionHistory/executionHistory.lock | Bin 17 -> 17 bytes .gradle/8.1.1/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .../dayoff/DayOffController.java | 46 ++++++++++++++++++ .../dayoff/DayOffRepository.java | 12 +++++ .../dayoff/DayOffRequest.java | 36 ++++++++++++++ .../dayoff/DayOffResponse.java | 41 ++++++++++++++++ .../dayoff/DayOffService.java | 45 +++++++++++++++++ 8 files changed, 180 insertions(+) create mode 100644 src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffController.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRepository.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRequest.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java diff --git a/.gradle/8.1.1/executionHistory/executionHistory.lock b/.gradle/8.1.1/executionHistory/executionHistory.lock index cd5f608412274d6263040d5a0f1724c5fd0ef263..fcace1cf413bf43dbdc7aad6300acb22354b98ef 100644 GIT binary patch literal 17 TcmZQxX4AXdKwVOm0Rm(JC9VSC literal 17 TcmZQxX4AXdKwVOm0Rs2{C7%M( diff --git a/.gradle/8.1.1/fileHashes/fileHashes.lock b/.gradle/8.1.1/fileHashes/fileHashes.lock index 85871a1c7fd24ed2c056444d1af7e2f6c87e2aa2..141fd4ed08a34b8d3fd54b9478a73249d67d841c 100644 GIT binary patch literal 17 UcmZRc9`t<9-qrRW7$D#@06z8w(f|Me literal 17 UcmZRc9`t<9-qrRW7$9I006x71nE(I) diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index e04b91165d7913c0dbbc22895932c9198894ea2b..abffdc79440f7e0b47f29cb4e7cf413753f48c2a 100644 GIT binary patch literal 17 UcmZQ(h|7Fy<23ms0|a;g04hoY+5i9m literal 17 UcmZQ(h|7Fy<23ms0|aOR04gj4yZ`_I diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffController.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffController.java new file mode 100644 index 0000000..12e0b9c --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffController.java @@ -0,0 +1,46 @@ +package com.example.kdtbe5_miniproject.dayoff; + +import com.example.kdtbe5_miniproject._core.security.CustomUserDetails; +import com.example.kdtbe5_miniproject._core.util.ApiUtils; +import com.example.kdtbe5_miniproject.user.User; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; + +@RequiredArgsConstructor +@RestController +public class DayOffController { + private final DayOffService dayOffService; + + @PostMapping("/dayoff/register") + public ResponseEntity registerDayOff(@RequestBody @Valid DayOffRequest.RegisterDTO registerDTO, @AuthenticationPrincipal CustomUserDetails customUserDetails) { + User user = customUserDetails.getUser(); + dayOffService.registerDayOff(user.getId(), registerDTO); + return ResponseEntity.ok().body(ApiUtils.success("등록이 완료되었습니다.")); + } + + @GetMapping("/dayoff/my") + public ResponseEntity myDayOffInfo(@AuthenticationPrincipal CustomUserDetails customUserDetails) { + User user = customUserDetails.getUser(); + DayOffResponse.MyDayOffDTO myDayOffDTO = dayOffService.myDayOffInfo(user.getId()); + return ResponseEntity.ok().body(ApiUtils.success(myDayOffDTO)); + } + + @GetMapping("/dayoff/applied") + public ResponseEntity myAppliedDayOffs(@AuthenticationPrincipal CustomUserDetails customUserDetails) { + User user = customUserDetails.getUser(); + DayOffResponse.AppliedDayOffDTO[] appliedDayOffDTOs = dayOffService.myAppliedDayOffs(user.getId()); + return ResponseEntity.ok().body(ApiUtils.success(appliedDayOffDTOs)); + } + + @DeleteMapping("/dayoff/{dayoffId}") + public ResponseEntity cancelDayOff(@PathVariable Long dayoffId, @AuthenticationPrincipal CustomUserDetails customUserDetails) { + User user = customUserDetails.getUser(); + dayOffService.cancelDayOff(dayoffId, user.getId()); + return ResponseEntity.ok().body(ApiUtils.success("연차 신청이 취소되었습니다.")); + } +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRepository.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRepository.java new file mode 100644 index 0000000..c1d2134 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRepository.java @@ -0,0 +1,12 @@ +package com.example.kdtbe5_miniproject.dayoff; + +import com.example.kdtbe5_miniproject.user.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface DayOffRepository extends JpaRepository { + List findByUser(User user); +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRequest.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRequest.java new file mode 100644 index 0000000..fa4df70 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRequest.java @@ -0,0 +1,36 @@ +package com.example.kdtbe5_miniproject.dayoff; + +import com.example.kdtbe5_miniproject.user.User; +import lombok.Getter; +import lombok.Setter; + +import javax.validation.constraints.NotNull; +import java.time.LocalDate; + +@Getter +@Setter +public class DayOffRequest { + + @Getter + @Setter + public static class RegisterDTO { + @NotNull + private String type; + @NotNull + private LocalDate startDate; + @NotNull + private LocalDate endDate; + @NotNull + private String reason; + + public DayOff toEntity(User user) { + return DayOff.builder() + .type(this.type) + .startDate(this.startDate) + .endDate(this.endDate) + .reason(this.reason) + .user(user) + .build(); + } + } +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java new file mode 100644 index 0000000..f30cd58 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java @@ -0,0 +1,41 @@ +package com.example.kdtbe5_miniproject.dayoff; + +import lombok.Getter; + +import java.time.LocalDate; + +@Getter +public class DayOffResponse { + + @Getter + public static class MyDayOffDTO { + private int valid; + private int expired; + private int used; + + public MyDayOffDTO(int valid, int expired, int used) { + this.valid = valid; + this.expired = expired; + this.used = used; + } + } + + @Getter + public static class AppliedDayOffDTO { + private Long id; + private String type; + private LocalDate startDate; + private LocalDate endDate; + private String reason; + private String status; + + public AppliedDayOffDTO(DayOff dayOff) { + this.id = dayOff.getId(); + this.type = dayOff.getType(); + this.startDate = dayOff.getStartDate(); + this.endDate = dayOff.getEndDate(); + this.reason = dayOff.getReason(); + this.status = dayOff.getStatus(); + } + } +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java new file mode 100644 index 0000000..c815737 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java @@ -0,0 +1,45 @@ +package com.example.kdtbe5_miniproject.dayoff; + +import com.example.kdtbe5_miniproject._core.errors.exception.UserNotFoundException; +import com.example.kdtbe5_miniproject.user.User; +import com.example.kdtbe5_miniproject.user.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@RequiredArgsConstructor +@Service +public class DayOffService { + private final DayOffRepository dayOffRepository; + private final UserRepository userRepository; + + @Transactional + public void registerDayOff(Long userId, DayOffRequest.RegisterDTO registerDTO) { + User user = userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException("사용자를 찾을 수 없습니다.")); + DayOff dayOff = registerDTO.toEntity(user); + dayOffRepository.save(dayOff); + } + + @Transactional(readOnly = true) + public DayOffResponse.MyDayOffDTO myDayOffInfo(Long userId) { + User user = userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException("사용자를 찾을 수 없습니다.")); + // TODO 휴가 로직을 수정해야함 + return new DayOffResponse.MyDayOffDTO(15, 0, 5); + } + + @Transactional(readOnly = true) + public DayOffResponse.AppliedDayOffDTO[] myAppliedDayOffs(Long userId) { + User user = userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException("사용자를 찾을 수 없습니다.")); + List dayOffs = dayOffRepository.findByUser(user); + return dayOffs.stream().map(DayOffResponse.AppliedDayOffDTO::new).toArray(DayOffResponse.AppliedDayOffDTO[]::new); + } + + @Transactional + public void cancelDayOff(Long dayoffId, Long userId) { + User user = userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException("사용자를 찾을 수 없습니다.")); + DayOff dayOff = dayOffRepository.findById(dayoffId).orElseThrow(() -> new UserNotFoundException("해당 연차 신청을 찾을 수 없습니다.")); + dayOffRepository.delete(dayOff); + } +} From 89315968cc168f8d01084c12c5afaa2793513e91 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Tue, 1 Aug 2023 19:37:02 +0900 Subject: [PATCH 054/128] =?UTF-8?q?refacor:#4=20dayoff=EC=9D=98=20?= =?UTF-8?q?=EC=86=8D=EC=84=B1=20type=EA=B3=BC=20status=EC=9D=98=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=EC=9D=84=20enum=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/kdtbe5_miniproject/dayoff/DayOff.java | 4 ++-- .../kdtbe5_miniproject/dayoff/DayOffStatus.java | 14 ++++++++++++++ .../kdtbe5_miniproject/dayoff/DayOffType.java | 14 ++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffStatus.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffType.java diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOff.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOff.java index fa8a181..8a54943 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOff.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOff.java @@ -26,7 +26,7 @@ public class DayOff { private LocalDate startDate; private LocalDate endDate; private String reason; - private String type; //TODO enum 타입으로 변경 (연자, 오전반차, 오후반차) - private String status; //TODO enum 타입으로 변경 (대기, 승인, 반려) + private DayOffType type; //연차(0), 오전반차(1), 오후반차(2) + private DayOffStatus status; //대기(0), 승인(1), 반려(2) private Float numOfDayOff; } \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffStatus.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffStatus.java new file mode 100644 index 0000000..8265dcf --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffStatus.java @@ -0,0 +1,14 @@ +package com.example.kdtbe5_miniproject.dayoff; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum DayOffStatus { + 대기(0), + 승인(1), + 반려(2); + + private final int typeStatus; +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffType.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffType.java new file mode 100644 index 0000000..babea8d --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffType.java @@ -0,0 +1,14 @@ +package com.example.kdtbe5_miniproject.dayoff; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum DayOffType { + 연차(0), + 오전반차(1), + 오후반차(2); + + private final int typeNumber; +} From 3781633ae4b0a2b6ab8949b5ef6122222fe4fa9a Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Tue, 1 Aug 2023 20:21:21 +0900 Subject: [PATCH 055/128] =?UTF-8?q?refacor:#4=20dayoff=EC=9D=98=20?= =?UTF-8?q?=EC=86=8D=EC=84=B1=20type=EA=B3=BC=20status=EC=9D=98=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=EC=9D=84=20enum=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/kdtbe5_miniproject/admin/AdminResponse.java | 6 ++++-- .../example/kdtbe5_miniproject/dayoff/DayOffRequest.java | 2 +- .../example/kdtbe5_miniproject/dayoff/DayOffResponse.java | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java index ba6e00e..3019629 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java @@ -1,6 +1,8 @@ package com.example.kdtbe5_miniproject.admin; import com.example.kdtbe5_miniproject.dayoff.DayOff; +import com.example.kdtbe5_miniproject.dayoff.DayOffStatus; +import com.example.kdtbe5_miniproject.dayoff.DayOffType; import com.example.kdtbe5_miniproject.duty.Duty; import com.example.kdtbe5_miniproject.user.User; import lombok.Getter; @@ -19,8 +21,8 @@ public static class DayOffStatusDTO { private LocalDate startDate; private LocalDate endDate; private String reason; - private String type; - private String status; + private DayOffType type; + private DayOffStatus status; public DayOffStatusDTO(DayOff dayOff) { this.id = dayOff.getId(); diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRequest.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRequest.java index fa4df70..060a61e 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRequest.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRequest.java @@ -15,7 +15,7 @@ public class DayOffRequest { @Setter public static class RegisterDTO { @NotNull - private String type; + private DayOffType type; @NotNull private LocalDate startDate; @NotNull diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java index f30cd58..f7a0dbf 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java @@ -23,11 +23,11 @@ public MyDayOffDTO(int valid, int expired, int used) { @Getter public static class AppliedDayOffDTO { private Long id; - private String type; + private DayOffType type; private LocalDate startDate; private LocalDate endDate; private String reason; - private String status; + private DayOffStatus status; public AppliedDayOffDTO(DayOff dayOff) { this.id = dayOff.getId(); From e779639be3c63efc6dc573e9e6087fbb5ff2e338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A7=80=EB=82=98?= Date: Tue, 1 Aug 2023 22:03:01 +0900 Subject: [PATCH 056/128] docs: README.md(1) --- README.md | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0a8bbda..e343c81 100644 --- a/README.md +++ b/README.md @@ -1 +1,52 @@ -# MiniProject \ No newline at end of file +![header](https://capsule-render.vercel.app/api?type=waving&color=auto&height=200§ion=header&text=Mini%20Project&fontSize=50) +# 연차당직 사이트(SpringBoot + React) + +### 🏆 프로젝트 소개 +프론트와 백엔드가 협업하여 만든 사이트입니다. 클라이언트의 일정관리를 손쉽게 유지관리 할 수 있습니다. + +### ✨ 개발기간 +**2023.07.24 ~ 2023.08.11** + +### 🎈 프로젝트 구성 +* 멤버구성 : 김주원, 박성욱, 한혜지, 김지나 +* 개발환경 : JAVA 11, IDE: IntelliJ, Build: Gradle, Framework: Spring-Boot 2.7.14, + Database: MySQL, ORM: Mybatis +* 사용기술 : Spring Web, Spring Data JPA, Spring DevTools, Spring Security, + JWT 4.3.0, h2database, lombok + +---- +### 📌주요 기능 + +* **회원가입** + 1. jwt이용, 비밀번호 단방향 암호화 + 2. 개인정보있는경우(이름,휴대폰,이메일) AES256양방향 암호화적용,복호화 + 3. 관련필드에 DB검색할떄도 검색조건을 암호화 + +* **로그인** + 1. jwt token 인증방식, spring security적용 + 2. login 성공 후 마지막 로그인 성공 날짜 업데이트 적용 + 3. login 성공 후 회원번호, user-agent, client ip, 시간 로그 등록처리 + 4. 일반로그인/관리자로그인 + +* **개인정보 수정** + + 1. 개인정보 수정,삭제, 수정된 일자 업데이트 + 2. 개인연차/당직 등록 + 3. 관리자 (유저의 권한 설정), 로그인 발급된 jwt token검증 + 4. 비밀번호변경(단방향 암호화), 전화번호변경 + +* **개인 연차/당직** + + 1. 신청내역, 사용내역, 등록, 조회, 취소(crud) + 2. 연차/당직 구분컬럼구성, 테이블1개설계 + 3. 저장/삭제 api구현필요 + 4. 내 연차일 수 + +* **관리자 기능** + + 1. 연차 승인/반려 + +* **사용자간공유** + + 1. 데이터 내려줄 조회 api 구현 + 2. 월별 캘린더 주간/일간 등 다양하게 표현 From 7cd576656e18c0bdd4d2022500f4ce95dcd16652 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Wed, 2 Aug 2023 01:15:44 +0900 Subject: [PATCH 057/128] =?UTF-8?q?refacor:#4=20DayOffService,=20DayOffCon?= =?UTF-8?q?troller=20>=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=A3=BC=EC=84=9D(?= =?UTF-8?q?=EC=84=A4=EB=AA=85)=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kdtbe5_miniproject/dayoff/DayOffController.java | 8 ++++++-- .../example/kdtbe5_miniproject/dayoff/DayOffService.java | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffController.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffController.java index 12e0b9c..e9980d9 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffController.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffController.java @@ -11,11 +11,13 @@ import javax.validation.Valid; import java.util.List; +@RequestMapping("/mypage") @RequiredArgsConstructor @RestController public class DayOffController { private final DayOffService dayOffService; + // 연차 신청 @PostMapping("/dayoff/register") public ResponseEntity registerDayOff(@RequestBody @Valid DayOffRequest.RegisterDTO registerDTO, @AuthenticationPrincipal CustomUserDetails customUserDetails) { User user = customUserDetails.getUser(); @@ -30,14 +32,16 @@ public ResponseEntity myDayOffInfo(@AuthenticationPrincipal CustomUserDetails return ResponseEntity.ok().body(ApiUtils.success(myDayOffDTO)); } - @GetMapping("/dayoff/applied") + // 내 연차 리스트 + @GetMapping("/dayoffList") public ResponseEntity myAppliedDayOffs(@AuthenticationPrincipal CustomUserDetails customUserDetails) { User user = customUserDetails.getUser(); DayOffResponse.AppliedDayOffDTO[] appliedDayOffDTOs = dayOffService.myAppliedDayOffs(user.getId()); return ResponseEntity.ok().body(ApiUtils.success(appliedDayOffDTOs)); } - @DeleteMapping("/dayoff/{dayoffId}") + // 연차 신청 취소 + @DeleteMapping("dayoff/{dayoffId}") public ResponseEntity cancelDayOff(@PathVariable Long dayoffId, @AuthenticationPrincipal CustomUserDetails customUserDetails) { User user = customUserDetails.getUser(); dayOffService.cancelDayOff(dayoffId, user.getId()); diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java index c815737..f9c38ea 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java @@ -15,6 +15,7 @@ public class DayOffService { private final DayOffRepository dayOffRepository; private final UserRepository userRepository; + // 연차 신청 @Transactional public void registerDayOff(Long userId, DayOffRequest.RegisterDTO registerDTO) { User user = userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException("사용자를 찾을 수 없습니다.")); @@ -29,6 +30,7 @@ public DayOffResponse.MyDayOffDTO myDayOffInfo(Long userId) { return new DayOffResponse.MyDayOffDTO(15, 0, 5); } + // 내 연차 리스트 @Transactional(readOnly = true) public DayOffResponse.AppliedDayOffDTO[] myAppliedDayOffs(Long userId) { User user = userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException("사용자를 찾을 수 없습니다.")); @@ -36,6 +38,7 @@ public DayOffResponse.AppliedDayOffDTO[] myAppliedDayOffs(Long userId) { return dayOffs.stream().map(DayOffResponse.AppliedDayOffDTO::new).toArray(DayOffResponse.AppliedDayOffDTO[]::new); } + // 연차 신청 취소 @Transactional public void cancelDayOff(Long dayoffId, Long userId) { User user = userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException("사용자를 찾을 수 없습니다.")); From 1dd8a3a2ce95ee789a1622e16b7be068ef284a84 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Wed, 2 Aug 2023 01:17:06 +0900 Subject: [PATCH 058/128] =?UTF-8?q?refacor:#4=20DayOffRequest,=20AdminResp?= =?UTF-8?q?onse=20>=20DayOff=EC=9D=98=20status=20=ED=83=80=EC=9E=85=20enum?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/kdtbe5_miniproject/admin/AdminResponse.java | 3 ++- .../com/example/kdtbe5_miniproject/dayoff/DayOffRequest.java | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java index 3019629..e1f1f7f 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java @@ -4,6 +4,7 @@ import com.example.kdtbe5_miniproject.dayoff.DayOffStatus; import com.example.kdtbe5_miniproject.dayoff.DayOffType; import com.example.kdtbe5_miniproject.duty.Duty; +import com.example.kdtbe5_miniproject.duty.DutyStatus; import com.example.kdtbe5_miniproject.user.User; import lombok.Getter; import lombok.Setter; @@ -44,7 +45,7 @@ public static class DutyStatusDTO { private String username; private LocalDate date; private String reason; - private String status; + private DutyStatus status; public DutyStatusDTO(Duty duty) { this.id = duty.getId(); diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRequest.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRequest.java index 060a61e..05247ab 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRequest.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRequest.java @@ -29,6 +29,7 @@ public DayOff toEntity(User user) { .startDate(this.startDate) .endDate(this.endDate) .reason(this.reason) + .status(DayOffStatus.valueOf("대기")) .user(user) .build(); } From abf6fc81731f0609882f36fd36f23aec2ab385a3 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Wed, 2 Aug 2023 01:18:11 +0900 Subject: [PATCH 059/128] =?UTF-8?q?refacor:#4=20DutyStatus=20Enum=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=83=9D=EC=84=B1=20=EB=B0=8F=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/kdtbe5_miniproject/duty/Duty.java | 2 +- .../kdtbe5_miniproject/duty/DutyResponse.java | 2 +- .../kdtbe5_miniproject/duty/DutyStatus.java | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/example/kdtbe5_miniproject/duty/DutyStatus.java diff --git a/src/main/java/com/example/kdtbe5_miniproject/duty/Duty.java b/src/main/java/com/example/kdtbe5_miniproject/duty/Duty.java index 0e7687c..c2f0d2f 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/duty/Duty.java +++ b/src/main/java/com/example/kdtbe5_miniproject/duty/Duty.java @@ -25,5 +25,5 @@ public class Duty { private LocalDate date; private String reason; - private String status; //TODO enum 타입으로 변경 (대기, 승인, 반려) + private DutyStatus status; //대기(0), 승인(1), 반려(2) } \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyResponse.java b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyResponse.java index 9bfd49e..e973a7e 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyResponse.java @@ -12,7 +12,7 @@ public static class DutyDTO { private Long id; private LocalDate date; private String reason; - private String status; + private DutyStatus status; public DutyDTO(Duty duty) { this.id = duty.getId(); diff --git a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyStatus.java b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyStatus.java new file mode 100644 index 0000000..2bd18bf --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyStatus.java @@ -0,0 +1,14 @@ +package com.example.kdtbe5_miniproject.duty; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum DutyStatus { + 대기(0), + 승인(1), + 반려(2); + + private final int typeStatus; +} From d73231a3d831a5f0ac6e22f627e2dcd45efcad68 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Wed, 2 Aug 2023 01:18:55 +0900 Subject: [PATCH 060/128] =?UTF-8?q?refacor:#4=20DutyRequest=20>=20ToEntity?= =?UTF-8?q?=20toEntity=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/kdtbe5_miniproject/duty/DutyRequest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyRequest.java b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyRequest.java index 57772eb..f5cee10 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyRequest.java +++ b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyRequest.java @@ -1,5 +1,6 @@ package com.example.kdtbe5_miniproject.duty; +import com.example.kdtbe5_miniproject.user.User; import lombok.Getter; import lombok.Setter; @@ -15,5 +16,14 @@ public static class DutyDTO { private LocalDate date; @NotEmpty private String reason; + + public Duty toEntity(User user) { + return Duty.builder() + .date(this.date) + .reason(this.reason) + .status(DutyStatus.valueOf("대기")) // 모르고 이부분을 안넣었습니다. + .user(user) + .build(); + } } } \ No newline at end of file From 64313ae9ddbe332c6f0b9696b04b63055c15d3b3 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Wed, 2 Aug 2023 01:20:44 +0900 Subject: [PATCH 061/128] =?UTF-8?q?refacor:#4=20DutyService=20>=20Duty.bui?= =?UTF-8?q?lder=EB=A5=BC=20toEntity=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/kdtbe5_miniproject/duty/DutyService.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyService.java b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyService.java index 13cc760..eb1efdd 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyService.java @@ -1,6 +1,7 @@ package com.example.kdtbe5_miniproject.duty; import com.example.kdtbe5_miniproject._core.errors.exception.DutyNotFoundException; +import com.example.kdtbe5_miniproject.dayoff.DayOff; import com.example.kdtbe5_miniproject.user.User; import com.example.kdtbe5_miniproject.user.UserRepository; import lombok.RequiredArgsConstructor; @@ -17,19 +18,16 @@ public class DutyService { private final DutyRepository dutyRepository; private final UserRepository userRepository; + // 당직 신청 @Transactional public DutyResponse.DutyDTO createDuty(DutyRequest.DutyDTO dutyDTO, Long userId) { User user = userRepository.findById(userId).orElseThrow(() -> new IllegalArgumentException("잘못된 사용자 ID입니다.")); - Duty duty = Duty.builder() - .date(dutyDTO.getDate()) - .reason(dutyDTO.getReason()) - .status("대기") - .user(user) - .build(); + Duty duty = dutyDTO.toEntity(user); Duty createdDuty = dutyRepository.save(duty); return new DutyResponse.DutyDTO(createdDuty); } + // 내 당직 리스트 @Transactional(readOnly = true) public List getAppliedDuties(Long userId) { User user = userRepository.findById(userId).orElseThrow(() -> new IllegalArgumentException("잘못된 사용자 ID입니다.")); @@ -38,6 +36,7 @@ public List getAppliedDuties(Long userId) { .collect(Collectors.toList()); } + // 당직 신청 취소 @Transactional public void deleteDuty(Long dutyId, Long userId) { User user = userRepository.findById(userId).orElseThrow(() -> new IllegalArgumentException("잘못된 사용자 ID입니다.")); From 1de167b21e5330fc8524049c022234179802c115 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Wed, 2 Aug 2023 01:21:10 +0900 Subject: [PATCH 062/128] =?UTF-8?q?refacor:#4=20DutyController=20>=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=A3=BC=EC=84=9D(=EC=84=A4?= =?UTF-8?q?=EB=AA=85)=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/kdtbe5_miniproject/duty/DutyController.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyController.java b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyController.java index 6ed304f..71e5563 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyController.java +++ b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyController.java @@ -11,12 +11,14 @@ import javax.validation.Valid; import java.util.List; +@RequestMapping("/mypage") @RequiredArgsConstructor @RestController public class DutyController { private final DutyService dutyService; + // 당직 신청 @PostMapping("/duty/register") public ResponseEntity createDuty(@RequestBody @Valid DutyRequest.DutyDTO dutyDTO, @AuthenticationPrincipal CustomUserDetails customUserDetails) { User user = customUserDetails.getUser(); @@ -24,7 +26,7 @@ public ResponseEntity createDuty(@RequestBody @Valid DutyRequest.DutyDTO duty return ResponseEntity.ok().body(ApiUtils.success(responseDTO)); } - + // 내 당직 리스트 @GetMapping("/duty/applied") public ResponseEntity getAppliedDuty(@AuthenticationPrincipal CustomUserDetails customUserDetails) { User user = customUserDetails.getUser(); @@ -32,6 +34,7 @@ public ResponseEntity getAppliedDuty(@AuthenticationPrincipal CustomUserDetai return ResponseEntity.ok().body(ApiUtils.success(appliedDuties)); } + // 당직 신청 취소 @DeleteMapping("/duty/{dutyId}") public ResponseEntity deleteDuty(@PathVariable Long dutyId, @AuthenticationPrincipal CustomUserDetails customUserDetails) { User user = customUserDetails.getUser(); From 9426abf810a13026029c9f4a3df0ebe5cebcc0da Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Wed, 2 Aug 2023 02:12:35 +0900 Subject: [PATCH 063/128] =?UTF-8?q?refacor:#4=20DutyController=20>=20getAp?= =?UTF-8?q?pliedDuty=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=A7=A4=ED=95=91=20?= =?UTF-8?q?url=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/kdtbe5_miniproject/duty/DutyController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyController.java b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyController.java index 71e5563..d420bbf 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyController.java +++ b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyController.java @@ -27,7 +27,7 @@ public ResponseEntity createDuty(@RequestBody @Valid DutyRequest.DutyDTO duty } // 내 당직 리스트 - @GetMapping("/duty/applied") + @GetMapping("/dutyList") public ResponseEntity getAppliedDuty(@AuthenticationPrincipal CustomUserDetails customUserDetails) { User user = customUserDetails.getUser(); List appliedDuties = dutyService.getAppliedDuties(user.getId()); From 58b895269ece37527fa470e6db37be2523827da8 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Wed, 2 Aug 2023 02:42:15 +0900 Subject: [PATCH 064/128] =?UTF-8?q?feature:=20UserRoles,=20UserPosition=20?= =?UTF-8?q?enum=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kdtbe5_miniproject/user/UserPosition.java | 16 ++++++++++++++++ .../kdtbe5_miniproject/user/UserRoles.java | 13 +++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 src/main/java/com/example/kdtbe5_miniproject/user/UserPosition.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/user/UserRoles.java diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserPosition.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserPosition.java new file mode 100644 index 0000000..c969c13 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserPosition.java @@ -0,0 +1,16 @@ +package com.example.kdtbe5_miniproject.user; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum UserPosition { + 사원(0), + 대리(1), + 과장(2), + 차장(3), + 부장(4); + + private final int typeNumber; +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserRoles.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserRoles.java new file mode 100644 index 0000000..c1f89a2 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserRoles.java @@ -0,0 +1,13 @@ +package com.example.kdtbe5_miniproject.user; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum UserRoles { + 일반(0), + 관리자(1); + + private final int typeNumber; +} From 243a1967c2065c057893baedf5124cfd1b5e0603 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Wed, 2 Aug 2023 02:59:23 +0900 Subject: [PATCH 065/128] =?UTF-8?q?refactor:=20User=EC=97=90=20enum=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/example/kdtbe5_miniproject/user/User.java | 4 ++-- .../java/com/example/kdtbe5_miniproject/user/UserRequest.java | 4 ++-- .../com/example/kdtbe5_miniproject/user/UserResponse.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/User.java b/src/main/java/com/example/kdtbe5_miniproject/user/User.java index 16aa4cb..8dd7a18 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/User.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/User.java @@ -24,8 +24,8 @@ public class User extends BaseTimeEntity { private String password; private String email; private String phoneNumber; - private String position; //TODO 직급 enum 타입으로 변경 - private String roles; //TODO 권한 enum 타입으로 변경 + private UserPosition position; //사원(0), 대리(1), 과장(2), 차장(3), 부장(4) + private UserRoles roles; //일반(0), 관리자(1) private LocalDate joinDate; public void updatePhoneNumber(String newPhoneNum) { diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java index 28a1a53..20b7e18 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserRequest.java @@ -32,7 +32,7 @@ public static class JoinDTO { private String email; @Pattern(regexp = "^01(?:0|1|[6-9])\\d{7,8}$", message = "01011112222와 같은 형식으로 작성해주세요") private String phoneNumber; - private String position; + private UserPosition position; private Float numOfDayOff; private LocalDate joinDate; @@ -43,7 +43,7 @@ public User toEntity() { .email(email) .phoneNumber(phoneNumber) .position(position) - .roles("USER") + .roles(UserRoles.valueOf("일반")) .joinDate(joinDate) .build(); } diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java index 7bb1b26..d444d07 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java @@ -14,8 +14,8 @@ public static class JoinDTO { private String email; private String username; private String phoneNumber; - private String position; - private String roles; + private UserPosition position; + private UserRoles roles; private Float numOfDayOff; private LocalDate joinDate; From 89fd920a65a0ffda84623834a6788d097b358e80 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Wed, 2 Aug 2023 03:38:12 +0900 Subject: [PATCH 066/128] =?UTF-8?q?refactor:=20AdminResponse,=20CustomUser?= =?UTF-8?q?Details=20>=20User=EC=97=90=20enum=20=ED=83=80=EC=9E=85=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_core/security/CustomUserDetails.java | 11 +++++++++-- .../kdtbe5_miniproject/admin/AdminResponse.java | 6 ++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetails.java b/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetails.java index 8c622dc..a5caaf4 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetails.java +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetails.java @@ -7,6 +7,7 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.stream.Collectors; @@ -17,9 +18,13 @@ public class CustomUserDetails implements UserDetails { private final User user; + //TODO : UserRoles를 Enum으로 변경하면서 오류가 생겨 getAuthorities(), isAdmin() 메서드 내용 수정했는데 확인 필요할 것 같아요 @Override public Collection getAuthorities() { - return Arrays.stream(user.getRoles().split(",")).map(SimpleGrantedAuthority::new).collect(Collectors.toList()); + Collection authorities = new ArrayList<>(); + authorities.add(()-> "ROLE_"+user.getRoles().getTypeNumber()); + return authorities; +// return Arrays.stream(user.getRoles().split(",")).map(SimpleGrantedAuthority::new).collect(Collectors.toList()); } @Override @@ -37,7 +42,9 @@ public Long getUserId() { } public boolean isAdmin() { - return user.getRoles().equals("admin"); //enum으로 수정 시 수정해야함 + if(user.getRoles().getTypeNumber()==1) + return true; + return false; } @Override diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java index e1f1f7f..1afec96 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java @@ -6,6 +6,8 @@ import com.example.kdtbe5_miniproject.duty.Duty; import com.example.kdtbe5_miniproject.duty.DutyStatus; import com.example.kdtbe5_miniproject.user.User; +import com.example.kdtbe5_miniproject.user.UserPosition; +import com.example.kdtbe5_miniproject.user.UserRoles; import lombok.Getter; import lombok.Setter; @@ -65,8 +67,8 @@ public static class UsersDTO { private String email; private String phoneNumber; private LocalDate joinDate; - private String position; - private String roles; + private UserPosition position; + private UserRoles roles; public UsersDTO(User user) { this.id = user.getId(); From c909539cd4c76a259cc31c46834e1ef333995651 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Wed, 2 Aug 2023 03:38:34 +0900 Subject: [PATCH 067/128] =?UTF-8?q?refactor:=20=EB=B3=80=EC=88=98=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/kdtbe5_miniproject/dayoff/DayOffStatus.java | 2 +- .../java/com/example/kdtbe5_miniproject/duty/DutyStatus.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffStatus.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffStatus.java index 8265dcf..174df3c 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffStatus.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffStatus.java @@ -10,5 +10,5 @@ public enum DayOffStatus { 승인(1), 반려(2); - private final int typeStatus; + private final int typeNumber; } diff --git a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyStatus.java b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyStatus.java index 2bd18bf..d4dc25a 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyStatus.java +++ b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyStatus.java @@ -10,5 +10,5 @@ public enum DutyStatus { 승인(1), 반려(2); - private final int typeStatus; + private final int typeNumber; } From 9429ebe2a8666b3f1b19c5775d416a343b7327ce Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Wed, 2 Aug 2023 04:18:05 +0900 Subject: [PATCH 068/128] =?UTF-8?q?refactor:=20Jwt=ED=86=A0=ED=81=B0?= =?UTF-8?q?=EC=97=90=20UserRole=20Enum=20=ED=83=80=EC=9E=85=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_core/security/CustomUserDetails.java | 1 + .../_core/security/JwtAuthenticationFilter.java | 7 ++++++- .../_core/security/JwtTokenProvider.java | 4 +++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetails.java b/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetails.java index a5caaf4..93d26ac 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetails.java +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/security/CustomUserDetails.java @@ -37,6 +37,7 @@ public String getUsername() { return user.getEmail(); } + //TODO 변경 확인 public Long getUserId() { return user.getId(); } diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtAuthenticationFilter.java b/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtAuthenticationFilter.java index ae515ac..6e09d69 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtAuthenticationFilter.java +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtAuthenticationFilter.java @@ -6,6 +6,7 @@ import com.auth0.jwt.exceptions.TokenExpiredException; import com.auth0.jwt.interfaces.DecodedJWT; import com.example.kdtbe5_miniproject.user.User; +import com.example.kdtbe5_miniproject.user.UserRoles; import lombok.extern.slf4j.Slf4j; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; @@ -13,6 +14,7 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; +import javax.persistence.criteria.CriteriaBuilder; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -36,12 +38,15 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse } String jwt = prefixJwt.replace(JwtTokenProvider.TOKEN_PREFIX, ""); + + // TODO 변경 확인 try { DecodedJWT decodedJWT = JwtTokenProvider.verify(jwt); // 신원인증 끝 Long id = decodedJWT.getClaim("id").asLong(); String roles = decodedJWT.getClaim("role").asString(); - User user = User.builder().id(id).roles(roles).build(); + User user = User.builder().id(id).roles(UserRoles.valueOf(roles)).build(); +// User user = User.builder().id(id).roles(roles).build(); CustomUserDetails myUserDetails = new CustomUserDetails(user); Authentication authentication = new UsernamePasswordAuthenticationToken( diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtTokenProvider.java b/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtTokenProvider.java index ea00f62..6d82582 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtTokenProvider.java +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtTokenProvider.java @@ -18,13 +18,15 @@ public class JwtTokenProvider { public static final String HEADER = "Authorization"; public static final String SECRET = "MySecretKey"; + // TODO 변경확인 public static String create(User user) { // 토큰에는 데이터를 담을 수 있다. 민감한 정보는 추가하면 절대 안된다. String jwt = JWT.create() .withSubject(user.getEmail()) .withExpiresAt(new Date(System.currentTimeMillis() + EXP)) .withClaim("id", user.getId()) - .withClaim("role", user.getRoles()) + .withClaim("role", user.getRoles().name()) +// .withClaim("role", user.getRoles()) .sign(Algorithm.HMAC512(SECRET)); return TOKEN_PREFIX + jwt; } From 9f6929c764b215bef42947d6ec4009659c12d974 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Wed, 2 Aug 2023 05:12:19 +0900 Subject: [PATCH 069/128] =?UTF-8?q?refactor:=20UserPosition=EC=97=90=20[?= =?UTF-8?q?=EC=A3=BC=EC=9E=84]=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/kdtbe5_miniproject/user/User.java | 2 +- .../example/kdtbe5_miniproject/user/UserPosition.java | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/User.java b/src/main/java/com/example/kdtbe5_miniproject/user/User.java index 8dd7a18..00fadb6 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/User.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/User.java @@ -24,7 +24,7 @@ public class User extends BaseTimeEntity { private String password; private String email; private String phoneNumber; - private UserPosition position; //사원(0), 대리(1), 과장(2), 차장(3), 부장(4) + private UserPosition position; //사원(0), 주임(1), 대리(2), 과장(3), 차장(4), 부장(5) private UserRoles roles; //일반(0), 관리자(1) private LocalDate joinDate; diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserPosition.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserPosition.java index c969c13..bde028d 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserPosition.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserPosition.java @@ -7,10 +7,11 @@ @RequiredArgsConstructor public enum UserPosition { 사원(0), - 대리(1), - 과장(2), - 차장(3), - 부장(4); + 주임(1), + 대리(2), + 과장(3), + 차장(4), + 부장(5); private final int typeNumber; } From 900c7e45867caf9a5f79356fbca3f0b958228927 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Wed, 2 Aug 2023 06:37:38 +0900 Subject: [PATCH 070/128] =?UTF-8?q?refactor:=20data.sql=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD,=20DBInit=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kdtbe5_miniproject/_core/util/DBInit.java | 48 +++++++++++++++ src/main/resources/db/data.sql | 60 +++++++++---------- 2 files changed, 78 insertions(+), 30 deletions(-) create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/util/DBInit.java diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/util/DBInit.java b/src/main/java/com/example/kdtbe5_miniproject/_core/util/DBInit.java new file mode 100644 index 0000000..f48ad9a --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/util/DBInit.java @@ -0,0 +1,48 @@ +package com.example.kdtbe5_miniproject._core.util; + +import com.example.kdtbe5_miniproject.user.User; +import com.example.kdtbe5_miniproject.user.UserPosition; +import com.example.kdtbe5_miniproject.user.UserRepository; +import com.example.kdtbe5_miniproject.user.UserRoles; +import lombok.RequiredArgsConstructor; +import org.springframework.boot.CommandLineRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Profile; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Component; + +import java.time.LocalDate; +import java.util.Arrays; + +@RequiredArgsConstructor +@Component +public class DBInit { + + private final PasswordEncoder passwordEncoder; + + @Profile("dev") + @Bean + CommandLineRunner initDB(UserRepository userRepository){ + return args -> { + User user = User.builder() + .username("최수현") + .password(passwordEncoder.encode("0000")) + .email("csh@fastcampus.com") + .phoneNumber("01011112222") + .position(UserPosition.valueOf("사원")) + .roles(UserRoles.valueOf("일반")) + .joinDate(LocalDate.now()) + .build(); + User admin = User.builder() + .username("한세희") + .password(passwordEncoder.encode("0000")) + .email("hsh@fastcampus.com") + .phoneNumber("01011112222") + .position(UserPosition.valueOf("부장")) + .roles(UserRoles.valueOf("관리자")) + .joinDate(LocalDate.now()) + .build(); + userRepository.saveAll(Arrays.asList(user, admin)); + }; + } +} diff --git a/src/main/resources/db/data.sql b/src/main/resources/db/data.sql index bce4e65..86a1ad4 100644 --- a/src/main/resources/db/data.sql +++ b/src/main/resources/db/data.sql @@ -2,25 +2,25 @@ user_tb dummy */ insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) -values (1, '윤준호', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester01@gmail.com', '01012345678', '사원', 'ROLE_USER', '2023-07-27', '2023-07-27'); +values (1, '윤준호', '0000', 'tester01@gmail.com', '01012345678', '0', '0', '2023-07-27', '2023-07-27'); insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) -values (2, '곽빈', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester02@gmail.com', '01012345678', '사원', 'ROLE_USER', '2023-07-27', '2023-07-27'); +values (2, '곽빈', '0000', 'tester02@gmail.com', '01012345678', '0', '0', '2023-07-27', '2023-07-27'); insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) -values (3, '전형근', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester03@gmail.com', '01012345678', '사원', 'ROLE_USER', '2023-07-27', '2023-07-27'); +values (3, '전형근', '0000', 'tester03@gmail.com', '01012345678', '0', '0', '2023-07-27', '2023-07-27'); insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) -values (4, '이영하', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester04@gmail.com', '01012345678', '주임', 'ROLE_USER', '2023-07-27', '2023-07-27'); +values (4, '이영하', '0000', 'tester04@gmail.com', '01012345678', '1', '0', '2023-07-27', '2023-07-27'); insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) -values (5, '박치국', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester05@gmail.com', '01012345678', '대리', 'ROLE_USER', '2023-07-27', '2023-07-27'); +values (5, '박치국', '0000', 'tester05@gmail.com', '01012345678', '2', '0', '2023-07-27', '2023-07-27'); insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) -values (6, '양석환', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester06@gmail.com', '01012345678', '대리', 'ROLE_ADMIN', '2023-07-27', '2023-07-27'); +values (6, '양석환', '0000', 'tester06@gmail.com', '01012345678', '2', '1', '2023-07-27', '2023-07-27'); insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) -values (7, '정수빈', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester07@gmail.com', '01012345678', '과장', 'ROLE_USER', '2023-07-27', '2023-07-27'); +values (7, '정수빈', '0000', 'tester07@gmail.com', '01012345678', '3', '0', '2023-07-27', '2023-07-27'); insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) -values (8, '김재환', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester08@gmail.com', '01012345678', '차장', 'ROLE_USER', '2023-07-27', '2023-07-27'); +values (8, '김재환', '0000', 'tester08@gmail.com', '01012345678', '4', '0', '2023-07-27', '2023-07-27'); insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) -values (9, '허경민', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester09@gmail.com', '01012345678', '차장', 'ROLE_ADMIN', '2023-07-27', '2023-07-27'); +values (9, '허경민', '0000', 'tester09@gmail.com', '01012345678', '4', '1', '2023-07-27', '2023-07-27'); insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) -values (10, '양의지', '$2a$10$HM42UGF28HVpYO8X2hDe/eDdOSpNd5tlM1YvEbACJY3ZSGBSCtwce', 'tester10@gmail.com', '01012345678', '부장', 'ROLE_ADMIN', '2023-07-27', '2023-07-27'); +values (10, '양의지', '0000', 'tester10@gmail.com', '01012345678', '5', '1', '2023-07-27', '2023-07-27'); /* login_tb dummy 10 */ @@ -37,26 +37,26 @@ insert into login_tb (id, user_id, ip, user_agent, login_at) values (10, 1, '255 /* dayoff_tb dummy 10 */ -insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (1, 10, '2023-08-27', '2023-08-27', '배고파서', '오후반차', '승인', 12); -insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (2, 6, '2023-08-27', '2023-08-27', '배고파서', '오전반차', '반려', 12); -insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (3, 9, '2023-08-28', '2023-08-28', '배고파서', '오후반차', '대기', 12); -insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (4, 10, '2023-08-29', '2023-08-29', '배고파서', '오전반차', '승인', 12); -insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (5, 9, '2023-09-02', '2023-09-02', '배고파서', '오후반차', '대기', 15); -insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (6, 8, '2023-09-04', '2023-09-05', '배고파서', '연차', '대기', 15); -insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (7, 7, '2023-09-06', '2023-09-06', '배고파서', '오후반차', '대기', 15); -insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (8, 8, '2023-09-27', '2023-09-27', '배고파서', '연차', '대기', 15); -insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (9, 9, '2023-09-27', '2023-09-27', '배고파서', '오후반차', '대기', 15); -insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (10, 10, '2023-09-29', '2023-09-29', '배고파서', '오후반차', '대기', 15); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (1, 10, '2023-08-27', '2023-08-27', '배고파서', '2', '1', 12); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (2, 6, '2023-08-27', '2023-08-27', '배고파서', '1', '2', 12); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (3, 9, '2023-08-28', '2023-08-28', '배고파서', '2', '0', 12); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (4, 10, '2023-08-29', '2023-08-29', '배고파서', '1', '1', 12); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (5, 9, '2023-09-02', '2023-09-02', '배고파서', '2', '0', 15); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (6, 8, '2023-09-04', '2023-09-05', '배고파서', '0', '0', 15); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (7, 7, '2023-09-06', '2023-09-06', '배고파서', '2', '0', 15); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (8, 8, '2023-09-27', '2023-09-27', '배고파서', '0', '0', 15); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (9, 9, '2023-09-27', '2023-09-27', '배고파서', '2', '0', 15); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (10, 10, '2023-09-29', '2023-09-29', '배고파서', '2', '0', 15); /* duty_tb dummy 10 */ -insert into duty_tb (id, user_id, date, reason, status) values (1, 1, '2023-08-01', '막내1', '승인'); -insert into duty_tb (id, user_id, date, reason, status) values (2, 2, '2023-08-02', '막내2', '승인'); -insert into duty_tb (id, user_id, date, reason, status) values (3, 3, '2023-08-03', '막내3', '승인'); -insert into duty_tb (id, user_id, date, reason, status) values (4, 1, '2023-08-04', '막내1', '승인'); -insert into duty_tb (id, user_id, date, reason, status) values (5, 2, '2023-08-05', '막내2', '승인'); -insert into duty_tb (id, user_id, date, reason, status) values (6, 3, '2023-08-06', '막내3', '승인'); -insert into duty_tb (id, user_id, date, reason, status) values (7, 1, '2023-08-07', '막내1', '대기'); -insert into duty_tb (id, user_id, date, reason, status) values (8, 2, '2023-08-08', '막내2', '대기'); -insert into duty_tb (id, user_id, date, reason, status) values (9, 3, '2023-08-09', '막내3', '대기'); -insert into duty_tb (id, user_id, date, reason, status) values (10, 1, '2023-08-10', '막내1', '반려'); \ No newline at end of file +insert into duty_tb (id, user_id, date, reason, status) values (1, 1, '2023-08-01', '막내1', '1'); +insert into duty_tb (id, user_id, date, reason, status) values (2, 2, '2023-08-02', '막내2', '1'); +insert into duty_tb (id, user_id, date, reason, status) values (3, 3, '2023-08-03', '막내3', '1'); +insert into duty_tb (id, user_id, date, reason, status) values (4, 1, '2023-08-04', '막내1', '1'); +insert into duty_tb (id, user_id, date, reason, status) values (5, 2, '2023-08-05', '막내2', '1'); +insert into duty_tb (id, user_id, date, reason, status) values (6, 3, '2023-08-06', '막내3', '1'); +insert into duty_tb (id, user_id, date, reason, status) values (7, 1, '2023-08-07', '막내1', '0'); +insert into duty_tb (id, user_id, date, reason, status) values (8, 2, '2023-08-08', '막내2', '0'); +insert into duty_tb (id, user_id, date, reason, status) values (9, 3, '2023-08-09', '막내3', '0'); +insert into duty_tb (id, user_id, date, reason, status) values (10, 1, '2023-08-10', '막내1', '2'); \ No newline at end of file From dc4ef84e150c002b9c14a13c3ba753de6670587f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A7=80=EB=82=98?= Date: Wed, 2 Aug 2023 15:21:14 +0900 Subject: [PATCH 071/128] =?UTF-8?q?feat:#1=20response=20mapping=20?= =?UTF-8?q?=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/kdtbe5_miniproject/user/UserController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java index 2333082..439cc3a 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java @@ -32,7 +32,7 @@ public class UserController { private final UserService userService; private final AuthenticationManager authenticationManager; - @PostMapping("/register") + @PostMapping("/join") public ResponseEntity join(@RequestBody @Valid UserRequest.JoinDTO joinDTO, Errors errors) { UserResponse.JoinDTO responseDTO = userService.joinUser(joinDTO); log.info(joinDTO.getUsername() + " Joined"); From 8cba392bb1b84e25069e805f30e0a10d8d4c4ae6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A7=80=EB=82=98?= Date: Wed, 2 Aug 2023 16:05:57 +0900 Subject: [PATCH 072/128] =?UTF-8?q?feat:#2=20logout=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_core/security/SecurityConfig.java | 7 +++++++ .../kdtbe5_miniproject/user/UserController.java | 16 ++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/security/SecurityConfig.java b/src/main/java/com/example/kdtbe5_miniproject/_core/security/SecurityConfig.java index 0e2c4f6..747a5c1 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/_core/security/SecurityConfig.java +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/security/SecurityConfig.java @@ -81,6 +81,13 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti return http.build(); } + protected void configure(HttpSecurity http)throws Exception { + http.logout() + .logoutSuccessUrl("/") //로그아웃 성공시 리다이렉트주소 + .invalidateHttpSession(true) //로그아웃 이후 세션 전체 삭제 여부 + .deleteCookies("JSSIONID"); + } + public CorsConfigurationSource configurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.addAllowedHeader("*"); diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java index da85b3b..4ad9099 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java @@ -13,13 +13,13 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; import org.springframework.validation.Errors; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; import java.security.Principal; import java.time.LocalDateTime; @@ -69,6 +69,14 @@ private void addLoginHistory(HttpServletRequest request, CustomUserDetails myUse loginHistoryService.save(loginHistoryDTO); } + @GetMapping(value = "/logout") + public String logout(HttpServletRequest request, HttpServletResponse response) { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication != null) { + new SecurityContextLogoutHandler().logout(request, response, authentication); + } + return "redirect:/login"; + } @PutMapping("/mypage/updatePhoneNumber") public ResponseEntity updatePhoneNumber(@AuthenticationPrincipal CustomUserDetails updateUser, @RequestBody @Valid UserRequest.UpdateDTO updateDTO) { From b299a68eb0a7aded3129147ba20c174a56ffd700 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Wed, 2 Aug 2023 18:21:36 +0900 Subject: [PATCH 073/128] =?UTF-8?q?refactor:=20#4=20dayoff,=20duty?= =?UTF-8?q?=EC=97=90=20applyAt,=20processAt=20=EC=B9=BC=EB=9F=BC=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/kdtbe5_miniproject/dayoff/DayOff.java | 3 +++ .../com/example/kdtbe5_miniproject/dayoff/DayOffRequest.java | 4 +++- src/main/java/com/example/kdtbe5_miniproject/duty/Duty.java | 2 ++ .../java/com/example/kdtbe5_miniproject/duty/DutyRequest.java | 4 +++- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOff.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOff.java index 8a54943..d77d887 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOff.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOff.java @@ -8,6 +8,7 @@ import javax.persistence.*; import java.time.LocalDate; +import java.time.LocalDateTime; @Entity @AllArgsConstructor @@ -29,4 +30,6 @@ public class DayOff { private DayOffType type; //연차(0), 오전반차(1), 오후반차(2) private DayOffStatus status; //대기(0), 승인(1), 반려(2) private Float numOfDayOff; + private LocalDate applyAt; + private LocalDate processAt; } \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRequest.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRequest.java index 05247ab..4b8020d 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRequest.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRequest.java @@ -23,14 +23,16 @@ public static class RegisterDTO { @NotNull private String reason; - public DayOff toEntity(User user) { + public DayOff toEntity(User user, float numOfDayOff) { return DayOff.builder() .type(this.type) .startDate(this.startDate) .endDate(this.endDate) .reason(this.reason) .status(DayOffStatus.valueOf("대기")) + .applyAt(LocalDate.now()) .user(user) + .numOfDayOff(numOfDayOff) .build(); } } diff --git a/src/main/java/com/example/kdtbe5_miniproject/duty/Duty.java b/src/main/java/com/example/kdtbe5_miniproject/duty/Duty.java index c2f0d2f..fd1db32 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/duty/Duty.java +++ b/src/main/java/com/example/kdtbe5_miniproject/duty/Duty.java @@ -26,4 +26,6 @@ public class Duty { private LocalDate date; private String reason; private DutyStatus status; //대기(0), 승인(1), 반려(2) + private LocalDate applyAt; + private LocalDate processAt; } \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyRequest.java b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyRequest.java index f5cee10..e5489be 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyRequest.java +++ b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyRequest.java @@ -16,12 +16,14 @@ public static class DutyDTO { private LocalDate date; @NotEmpty private String reason; + private LocalDate applyAt; public Duty toEntity(User user) { return Duty.builder() .date(this.date) .reason(this.reason) - .status(DutyStatus.valueOf("대기")) // 모르고 이부분을 안넣었습니다. + .status(DutyStatus.valueOf("대기")) + .applyAt(LocalDate.now()) .user(user) .build(); } From 61b9e3e1701803ba8c5496d55bd5d6c44ee52b5e Mon Sep 17 00:00:00 2001 From: JOOWON Date: Wed, 2 Aug 2023 19:04:26 +0900 Subject: [PATCH 074/128] =?UTF-8?q?refactor:=20=EB=B9=84=EB=B0=80=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EC=88=98=EC=A0=95=20=EC=8B=9C=20updateDate=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/kdtbe5_miniproject/user/UserRepository.java | 5 +++-- .../com/example/kdtbe5_miniproject/user/UserService.java | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java index 9cd048b..0c8773c 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java @@ -7,6 +7,7 @@ import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDateTime; import java.util.Optional; @Repository @@ -16,6 +17,6 @@ public interface UserRepository extends JpaRepository { Optional findByEmail(@Param("email") String email); @Modifying - @Query(value = "UPDATE User SET password = :newPassword WHERE id = :id") - void updateById(@Param("newPassword") String newPassword, @Param("id") Long id); + @Query(value = "UPDATE User SET password = :newPassword, updateDate = :now WHERE id = :id") + void updateById(@Param("newPassword") String newPassword, @Param("now")LocalDateTime now, @Param("id") Long id); } diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java index 9ddb68f..212a405 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java @@ -9,7 +9,8 @@ import org.springframework.transaction.annotation.Transactional; import java.security.Principal; -import java.util.Optional; +import java.time.LocalDate; +import java.time.LocalDateTime; @RequiredArgsConstructor @Service @@ -46,6 +47,6 @@ public void updatePwd(UserRequest.ModifyPwdDTO request) { if (!passwordEncoder.matches(request.getOldPassword(), user.getPassword())) { throw new UnCorrectPasswordException("비밀번호가 일치하지 않습니다."); } - userRepository.updateById(passwordEncoder.encode(request.getNewPassword()), request.getUserId()); + userRepository.updateById(passwordEncoder.encode(request.getNewPassword()), LocalDateTime.now(), request.getUserId()); } } \ No newline at end of file From ed8e8f48fc2f55fab815be843d7f059c298dfb01 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Wed, 2 Aug 2023 19:04:55 +0900 Subject: [PATCH 075/128] =?UTF-8?q?refactor:=20=EC=8B=9C=ED=81=90=EB=A6=AC?= =?UTF-8?q?=ED=8B=B0=20enum=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kdtbe5_miniproject/_core/security/SecurityConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/security/SecurityConfig.java b/src/main/java/com/example/kdtbe5_miniproject/_core/security/SecurityConfig.java index 0e2c4f6..9ca6dbc 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/_core/security/SecurityConfig.java +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/security/SecurityConfig.java @@ -75,7 +75,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti // 11. 인증, 권한 필터 설정 http.authorizeRequests( authorize -> authorize.antMatchers("/account/**").authenticated() - .antMatchers("/admin/**").access("hasRole('ADMIN')") + .antMatchers("/admin/**").access("hasRole('1')") .anyRequest().permitAll() ); return http.build(); From 5c64dcb15b6f64e4ef3227b2f2e87c26f72866c3 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Wed, 2 Aug 2023 19:05:13 +0900 Subject: [PATCH 076/128] =?UTF-8?q?refactor:=20DTO=20enum=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/AdminRequest.java | 27 ++++++++++++++++--- .../admin/AdminResponse.java | 19 +++++++++++++ 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRequest.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRequest.java index 42cf125..f2e885f 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRequest.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRequest.java @@ -1,21 +1,40 @@ package com.example.kdtbe5_miniproject.admin; +import com.example.kdtbe5_miniproject.dayoff.DayOffStatus; +import com.example.kdtbe5_miniproject.dayoff.DayOffType; +import com.example.kdtbe5_miniproject.duty.DutyStatus; +import com.example.kdtbe5_miniproject.user.UserPosition; +import com.example.kdtbe5_miniproject.user.UserRoles; import lombok.Getter; import lombok.Setter; +import javax.validation.constraints.NotEmpty; +import java.time.LocalDate; + public class AdminRequest { @Getter @Setter - public static class TreatDTO { - private String status; + public static class TreatDayOffDTO { + @NotEmpty + private DayOffStatus status; + } + + @Getter + @Setter + public static class TreatDutyDTO { + @NotEmpty + private DutyStatus status; } @Getter @Setter public static class UserDetailsDTO { + @NotEmpty private String phoneNumber; - private String position; - private String roles; + @NotEmpty + private UserPosition position; + @NotEmpty + private UserRoles roles; } } diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java index 1afec96..484e482 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java @@ -39,6 +39,24 @@ public DayOffStatusDTO(DayOff dayOff) { } } + @Getter + @Setter + public static class DayOffInfoDTO { + private Long id; + private DayOffType type; + private Float numOfDayOff; + private LocalDate startDate; + private LocalDate endDate; + + public DayOffInfoDTO(DayOff dayOff) { + this.id = dayOff.getId(); + this.type = dayOff.getType(); + this.numOfDayOff = dayOff.getNumOfDayOff(); + this.startDate = dayOff.getStartDate(); + this.endDate = dayOff.getEndDate(); + } + } + @Getter @Setter public static class DutyStatusDTO { @@ -69,6 +87,7 @@ public static class UsersDTO { private LocalDate joinDate; private UserPosition position; private UserRoles roles; + private Float numOfDayOff; public UsersDTO(User user) { this.id = user.getId(); From d97875995bd86ca700ea56259558a2651ad85db2 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Wed, 2 Aug 2023 19:05:51 +0900 Subject: [PATCH 077/128] =?UTF-8?q?refactor:=20enum=20=EC=A0=81=EC=9A=A9,?= =?UTF-8?q?=20=EC=8A=B9=EC=9D=B8/=EB=B0=98=EB=A0=A4=EC=8B=9C=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/AdminController.java | 12 ++-- .../admin/AdminRepository.java | 44 +++++++++++---- .../admin/AdminService.java | 55 +++++++++++++++++-- src/main/resources/db/data.sql | 3 + 4 files changed, 94 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminController.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminController.java index 4366b06..098c5c5 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminController.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminController.java @@ -1,11 +1,14 @@ package com.example.kdtbe5_miniproject.admin; +import com.example.kdtbe5_miniproject._core.security.CustomUserDetails; import com.example.kdtbe5_miniproject._core.util.ApiUtils; import com.example.kdtbe5_miniproject.dayoff.DayOff; import com.example.kdtbe5_miniproject.duty.Duty; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import java.util.HashMap; @@ -13,6 +16,7 @@ @RequiredArgsConstructor @RestController +@RequestMapping("/admin") @Slf4j public class AdminController { @@ -39,15 +43,15 @@ public ResponseEntity userDetails(@PathVariable Long userId) { } @PutMapping("/status/dayoff/{dayOffId}") - public ResponseEntity dayOffModify(@PathVariable Long dayOffId, @RequestBody AdminRequest.TreatDTO request) { - adminService.modifyStatus(DayOff.class, dayOffId, request); + public ResponseEntity dayOffModify(@PathVariable Long dayOffId, @RequestBody AdminRequest.TreatDayOffDTO request) { + adminService.modifyDayOffStatus(dayOffId, request); return ResponseEntity.ok().body(ApiUtils.success(request.getStatus() + "되었습니다.")); } @PutMapping("/status/duty/{dutyId}") - public ResponseEntity dutyModify(@PathVariable Long dutyId, @RequestBody AdminRequest.TreatDTO request) { - adminService.modifyStatus(Duty.class, dutyId, request); + public ResponseEntity dutyModify(@PathVariable Long dutyId, @RequestBody AdminRequest.TreatDutyDTO request) { + adminService.modifyDutyStatus(dutyId, request); return ResponseEntity.ok().body(ApiUtils.success(request.getStatus() + "되었습니다.")); } diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java index fc09f52..27da193 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java @@ -1,8 +1,12 @@ package com.example.kdtbe5_miniproject.admin; import com.example.kdtbe5_miniproject.dayoff.DayOff; +import com.example.kdtbe5_miniproject.dayoff.DayOffStatus; import com.example.kdtbe5_miniproject.duty.Duty; +import com.example.kdtbe5_miniproject.duty.DutyStatus; import com.example.kdtbe5_miniproject.user.User; +import com.example.kdtbe5_miniproject.user.UserPosition; +import com.example.kdtbe5_miniproject.user.UserRoles; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; @@ -17,7 +21,7 @@ public class AdminRepository { private final EntityManager entityManager; - public List findDayOffByStatus(String status) { + public List findDayOffByStatus(DayOffStatus status) { Query query = entityManager.createQuery( "SELECT d FROM DayOff d INNER JOIN d.user u WHERE d.status = :status", DayOff.class); query.setParameter("status", status); @@ -25,7 +29,15 @@ public List findDayOffByStatus(String status) { return query.getResultList(); } - public List findDutyByStatus(String status) { + public DayOff findDayOffById(Long id) { + Query query = entityManager.createQuery( + "SELECT d FROM DayOff d WHERE d.id = :id", DayOff.class); + query.setParameter("id", id); + + return (DayOff) query.getSingleResult(); + } + + public List findDutyByStatus(DutyStatus status) { Query query = entityManager.createQuery( "SELECT d FROM Duty d INNER JOIN d.user u WHERE d.status = :status", Duty.class); query.setParameter("status", status); @@ -33,32 +45,44 @@ public List findDutyByStatus(String status) { return query.getResultList(); } - public List findAllUsers() { + //TODO 최근 날짜로 조회 + public List findAllUsers() { Query query = entityManager.createQuery( - "SELECT u FROM User u", User.class); + "SELECT u, d.numOfDayOff FROM User u LEFT JOIN DayOff d ON u.id = d.user.id"); return query.getResultList(); } - public User findUserById(Long userId) { + public Object[] findUserById(Long userId) { Query query = entityManager.createQuery( - "SELECT u FROM User u WHERE id = :id", User.class); + "SELECT u, d.numOfDayOff FROM User u LEFT JOIN DayOff d ON u.id = d.user.id WHERE u.id = :id"); query.setParameter("id", userId); - return (User) query.getSingleResult(); + return (Object[]) query.getSingleResult(); + } + + + @Transactional + public void updateNumOfDayOffById(Long id, Float deduction, DayOffStatus status) { + Query query = entityManager.createQuery( + "UPDATE DayOff SET status = :status ,numOfDayOff = numOfDayOff - :deduction WHERE id = :id"); + query.setParameter("id", id); + query.setParameter("deduction", deduction); + query.setParameter("status", status); + query.executeUpdate(); } @Transactional - public void updateStatusById(Class type, Long id, String status) { + public void updateDutyById(Long id, DutyStatus status) { Query query = entityManager.createQuery( - "UPDATE " + type.getSimpleName() + " SET status = :status WHERE id = :id"); + "UPDATE Duty SET status = :status WHERE id = :id"); query.setParameter("id", id); query.setParameter("status", status); query.executeUpdate(); } @Transactional - public void updateUserById(Long id, String phoneNumber, String position, String roles) { + public void updateUserById(Long id, String phoneNumber, UserPosition position, UserRoles roles) { Query query = entityManager.createQuery( "UPDATE User SET phoneNumber = :phoneNumber, position = :position, roles = : roles WHERE id = :id"); query.setParameter("id", id); diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java index 966d455..ee86bab 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java @@ -1,9 +1,16 @@ package com.example.kdtbe5_miniproject.admin; +import com.example.kdtbe5_miniproject.dayoff.DayOff; +import com.example.kdtbe5_miniproject.dayoff.DayOffStatus; +import com.example.kdtbe5_miniproject.dayoff.DayOffType; +import com.example.kdtbe5_miniproject.duty.DutyStatus; +import com.example.kdtbe5_miniproject.user.User; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import javax.transaction.Transactional; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -15,29 +22,65 @@ public class AdminService { @Transactional public List findWaitingDayOff() { - String status = "대기"; + DayOffStatus status = DayOffStatus.대기; return adminRepository.findDayOffByStatus(status).stream().map(AdminResponse.DayOffStatusDTO::new).collect(Collectors.toList()); } @Transactional public List findWaitingDuty() { - String status = "대기"; + DutyStatus status = DutyStatus.대기; return adminRepository.findDutyByStatus(status).stream().map(AdminResponse.DutyStatusDTO::new).collect(Collectors.toList()); } @Transactional public List findAllUsers() { - return adminRepository.findAllUsers().stream().map(AdminResponse.UsersDTO::new).collect(Collectors.toList()); + List userList = new ArrayList<>(); + + List resultList = adminRepository.findAllUsers(); + for (Object[] result : resultList) { + AdminResponse.UsersDTO user = new AdminResponse.UsersDTO((User) result[0]); + user.setNumOfDayOff((Float) result[1]); + userList.add(user); + } + return userList; } @Transactional public AdminResponse.UsersDTO findUserDetail(Long userId) { - return new AdminResponse.UsersDTO(adminRepository.findUserById(userId)); + Object[] result = adminRepository.findUserById(userId); + AdminResponse.UsersDTO user = new AdminResponse.UsersDTO((User) result[0]); + user.setNumOfDayOff((Float) result[1]); + + return user; + } + + //TODO 음수일때 예외처리 + @Transactional + public void modifyDayOffStatus(Long id, AdminRequest.TreatDayOffDTO request) { + Float deduction = 0F; + if (request.getStatus().equals(DayOffStatus.승인)) { + AdminResponse.DayOffInfoDTO dayOff = new AdminResponse.DayOffInfoDTO(adminRepository.findDayOffById(id)); + if (dayOff.getType().equals(DayOffType.연차)) { + deduction = Float.valueOf(ChronoUnit.DAYS.between(dayOff.getStartDate(), dayOff.getEndDate())); + verifyApproval(deduction, dayOff.getNumOfDayOff()); + } else if (dayOff.getType().equals(DayOffType.오전반차) || dayOff.getType().equals(DayOffType.오후반차)) { + deduction = 0.5F; + } + } + adminRepository.updateNumOfDayOffById(id, deduction, request.getStatus()); + } + + private boolean verifyApproval(Float deduction, Float numOfDayOff) { + if (numOfDayOff - deduction < 0) { + throw new RuntimeException("남은 연차 일 수가 모자랍니다."); + } + return true; } + //TODO 날짜 중복 예외 @Transactional - public void modifyStatus(Class type, Long id, AdminRequest.TreatDTO request) { - adminRepository.updateStatusById(type, id, request.getStatus()); + public void modifyDutyStatus(Long id, AdminRequest.TreatDutyDTO request) { + adminRepository.updateDutyById(id, request.getStatus()); } @Transactional diff --git a/src/main/resources/db/data.sql b/src/main/resources/db/data.sql index 86a1ad4..f5b00ac 100644 --- a/src/main/resources/db/data.sql +++ b/src/main/resources/db/data.sql @@ -21,6 +21,8 @@ insert into user_tb (id, username, password, email, phone_number, position, role values (9, '허경민', '0000', 'tester09@gmail.com', '01012345678', '4', '1', '2023-07-27', '2023-07-27'); insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) values (10, '양의지', '0000', 'tester10@gmail.com', '01012345678', '5', '1', '2023-07-27', '2023-07-27'); +insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) +values (11, '어드민', '{bcrypt}$2a$10$eSkd/bMFAO6z4Qa.6wQJ1.xDJLbmvHcFE0xwiAekH3u2QlzUExA/q', 'admin@admin.com', '01012345678', '5', '1', '2023-07-27', '2023-07-27'); /* login_tb dummy 10 */ @@ -47,6 +49,7 @@ insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (8, 8, '2023-09-27', '2023-09-27', '배고파서', '0', '0', 15); insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (9, 9, '2023-09-27', '2023-09-27', '배고파서', '2', '0', 15); insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (10, 10, '2023-09-29', '2023-09-29', '배고파서', '2', '0', 15); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (11, 10, '2023-09-29', '2023-10-29', '배고파서', '0', '0', 15); /* duty_tb dummy 10 */ From dd53b6f6d812dcc314f7e61ae521d6a3c545b399 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Wed, 2 Aug 2023 19:08:46 +0900 Subject: [PATCH 078/128] =?UTF-8?q?refactor:=20#4=20=EC=A7=81=EA=B8=89?= =?UTF-8?q?=EB=B3=84=EB=A1=9C=20=EC=97=B0=EC=B0=A8=20=EC=B4=88=EA=B8=B0?= =?UTF-8?q?=EC=84=A4=EC=A0=95=EB=A7=8C=ED=95=B4=EC=84=9C=20=EB=B3=B4?= =?UTF-8?q?=EB=82=B4=EB=8A=94=20=EA=B8=B0=EB=8A=A5=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dayoff/DayOffController.java | 1 + .../dayoff/DayOffResponse.java | 8 +++--- .../dayoff/DayOffService.java | 28 ++++++++++++++++++- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffController.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffController.java index e9980d9..e89f659 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffController.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffController.java @@ -25,6 +25,7 @@ public ResponseEntity registerDayOff(@RequestBody @Valid DayOffRequest.Regist return ResponseEntity.ok().body(ApiUtils.success("등록이 완료되었습니다.")); } + // 나의 연차 개수 @GetMapping("/dayoff/my") public ResponseEntity myDayOffInfo(@AuthenticationPrincipal CustomUserDetails customUserDetails) { User user = customUserDetails.getUser(); diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java index f7a0dbf..b4bd77f 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java @@ -9,14 +9,14 @@ public class DayOffResponse { @Getter public static class MyDayOffDTO { - private int valid; + private float valid; + private float used; private int expired; - private int used; - public MyDayOffDTO(int valid, int expired, int used) { + public MyDayOffDTO(float valid, float used, int expired) { this.valid = valid; - this.expired = expired; this.used = used; + this.expired = expired; } } diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java index f9c38ea..dc2d1bb 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java @@ -2,6 +2,7 @@ import com.example.kdtbe5_miniproject._core.errors.exception.UserNotFoundException; import com.example.kdtbe5_miniproject.user.User; +import com.example.kdtbe5_miniproject.user.UserPosition; import com.example.kdtbe5_miniproject.user.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -20,14 +21,39 @@ public class DayOffService { public void registerDayOff(Long userId, DayOffRequest.RegisterDTO registerDTO) { User user = userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException("사용자를 찾을 수 없습니다.")); DayOff dayOff = registerDTO.toEntity(user); + dayOffRepository.save(dayOff); } + // 나의 남은 연차 (초기 연차만 설정) @Transactional(readOnly = true) public DayOffResponse.MyDayOffDTO myDayOffInfo(Long userId) { User user = userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException("사용자를 찾을 수 없습니다.")); // TODO 휴가 로직을 수정해야함 - return new DayOffResponse.MyDayOffDTO(15, 0, 5); + + float numOfDayOff = determineInitialDayOff(user); + + return new DayOffResponse.MyDayOffDTO(numOfDayOff, 0, 0); + } + + // 직급별 연차 계산 + private int determineInitialDayOff(User user) { + int position = user.getPosition().getTypeNumber(); + if (position == 0) { + return 15; // 사원 + } else if (position == 1) { + return 17; // 주임 + }else if (position == 2) { + return 20; // 대리 + }else if (position == 3) { + return 22; // 과장 + }else if (position == 4) { + return 23; // 차장 + } else if (position == 5) { + return 26; // 부장 + } else { + throw new IllegalArgumentException("직급: " + position); + } } // 내 연차 리스트 From 1bcc24ef4cf77a27dd93df38ec3bd812302e8bcc Mon Sep 17 00:00:00 2001 From: Park SeongWook <116128609+gosuuk@users.noreply.github.com> Date: Wed, 2 Aug 2023 19:34:29 +0900 Subject: [PATCH 079/128] =?UTF-8?q?#4=20Duty=20=EC=98=88=EC=99=B8=EC=B2=98?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../executionHistory/executionHistory.lock | Bin 17 -> 17 bytes .gradle/8.1.1/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .../duty/DutyRepository.java | 2 ++ .../kdtbe5_miniproject/duty/DutyService.java | 30 +++++++++++++++--- 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/.gradle/8.1.1/executionHistory/executionHistory.lock b/.gradle/8.1.1/executionHistory/executionHistory.lock index fcace1cf413bf43dbdc7aad6300acb22354b98ef..c1ad8d5c404895bee1b1d738f9609c72b6fe8a9d 100644 GIT binary patch literal 17 TcmZQxX4AXdKwVOm0RprDCA$Lc literal 17 TcmZQxX4AXdKwVOm0Rm(JC9VSC diff --git a/.gradle/8.1.1/fileHashes/fileHashes.lock b/.gradle/8.1.1/fileHashes/fileHashes.lock index 141fd4ed08a34b8d3fd54b9478a73249d67d841c..ff485eed87f27d9d8333238047f7f2cab7c8cc95 100644 GIT binary patch literal 17 VcmZRc9`t<9-qrRW7{GvW4gfyM1*8A~ literal 17 UcmZRc9`t<9-qrRW7$D#@06z8w(f|Me diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index abffdc79440f7e0b47f29cb4e7cf413753f48c2a..4a3eb311f06678a27400fd2040c0f36d501df4bf 100644 GIT binary patch literal 17 UcmZQ(h|7Fy<23ms0|aCM04iz&`Tzg` literal 17 UcmZQ(h|7Fy<23ms0|a;g04hoY+5i9m diff --git a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyRepository.java b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyRepository.java index 4c63cf9..9149314 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyRepository.java +++ b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyRepository.java @@ -4,6 +4,7 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.time.LocalDate; import java.util.List; import java.util.Optional; @@ -12,4 +13,5 @@ public interface DutyRepository extends JpaRepository { Optional findByIdAndUser(Long id, User user); List findAllByUser(User user); + List findAllByUserAndDate(User user, LocalDate date); } \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyService.java b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyService.java index eb1efdd..d4c7bb7 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyService.java @@ -1,6 +1,7 @@ package com.example.kdtbe5_miniproject.duty; import com.example.kdtbe5_miniproject._core.errors.exception.DutyNotFoundException; +import com.example.kdtbe5_miniproject._core.errors.exception.UserNotFoundException; import com.example.kdtbe5_miniproject.dayoff.DayOff; import com.example.kdtbe5_miniproject.user.User; import com.example.kdtbe5_miniproject.user.UserRepository; @@ -8,6 +9,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDate; import java.util.List; import java.util.stream.Collectors; @@ -21,16 +23,30 @@ public class DutyService { // 당직 신청 @Transactional public DutyResponse.DutyDTO createDuty(DutyRequest.DutyDTO dutyDTO, Long userId) { - User user = userRepository.findById(userId).orElseThrow(() -> new IllegalArgumentException("잘못된 사용자 ID입니다.")); + User user = userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException("사용자를 찾을 수 없습니다.")); + + // 지난 날짜에 당직을 신청하는지 확인 + LocalDate requestedDate = dutyDTO.getDate(); + if (requestedDate.isBefore(LocalDate.now())) { + throw new IllegalArgumentException("과거의 날짜에 당직을 신청할 수 없습니다."); + } + + // 당직을 같은날에 신청하는지 확인 + List existingDuties = dutyRepository.findAllByUserAndDate(user, requestedDate); + if (!existingDuties.isEmpty()) { + throw new IllegalArgumentException("당직은 같은 날에 두 번 신청할 수 없습니다."); + } + Duty duty = dutyDTO.toEntity(user); Duty createdDuty = dutyRepository.save(duty); return new DutyResponse.DutyDTO(createdDuty); } + // 내 당직 리스트 @Transactional(readOnly = true) public List getAppliedDuties(Long userId) { - User user = userRepository.findById(userId).orElseThrow(() -> new IllegalArgumentException("잘못된 사용자 ID입니다.")); + User user = userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException("사용자를 찾을 수 없습니다.")); return dutyRepository.findAllByUser(user).stream() .map(DutyResponse.DutyDTO::new) .collect(Collectors.toList()); @@ -39,8 +55,14 @@ public List getAppliedDuties(Long userId) { // 당직 신청 취소 @Transactional public void deleteDuty(Long dutyId, Long userId) { - User user = userRepository.findById(userId).orElseThrow(() -> new IllegalArgumentException("잘못된 사용자 ID입니다.")); - Duty duty = dutyRepository.findByIdAndUser(dutyId, user).orElseThrow(() -> new DutyNotFoundException("당직을 찾을 수 없습니다.")); + User user = userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException("사용자를 찾을 수 없습니다.")); + Duty duty = dutyRepository.findByIdAndUser(dutyId, user).orElseThrow(() -> new DutyNotFoundException("해당 당직 신청을 찾을 수 없습니다.")); + + // 본인 당직만 삭제 가능 + if (!duty.getUser().getId().equals(userId)) { + throw new IllegalArgumentException("당신의 당직만 삭제할 수 있습니다."); + } + dutyRepository.delete(duty); } } \ No newline at end of file From 30d4b28e98622f3c2ec4f78272e24d33034165d3 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Wed, 2 Aug 2023 19:39:31 +0900 Subject: [PATCH 080/128] =?UTF-8?q?refactor:=20#4=20=EC=97=B0=EC=B0=A8=20?= =?UTF-8?q?=EC=B4=88=EA=B8=B0=EC=84=A4=EC=A0=95=EB=A7=8C=20=ED=95=B4?= =?UTF-8?q?=EC=84=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/kdtbe5_miniproject/dayoff/DayOffService.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java index dc2d1bb..e53d9f1 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java @@ -20,7 +20,9 @@ public class DayOffService { @Transactional public void registerDayOff(Long userId, DayOffRequest.RegisterDTO registerDTO) { User user = userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException("사용자를 찾을 수 없습니다.")); - DayOff dayOff = registerDTO.toEntity(user); + + float numOfDayOff = determineInitialDayOff(user); + DayOff dayOff = registerDTO.toEntity(user, numOfDayOff); dayOffRepository.save(dayOff); } From 4f0033d9f8a2e39c727ff403484326163d53a362 Mon Sep 17 00:00:00 2001 From: Park SeongWook <116128609+gosuuk@users.noreply.github.com> Date: Wed, 2 Aug 2023 21:32:22 +0900 Subject: [PATCH 081/128] =?UTF-8?q?#4=20DayOff=20=EC=98=88=EC=99=B8?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../executionHistory/executionHistory.lock | Bin 17 -> 17 bytes .gradle/8.1.1/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .../kdtbe5_miniproject/dayoff/DayOff.java | 14 +++ .../dayoff/DayOffRepository.java | 1 + .../dayoff/DayOffResponse.java | 4 +- .../dayoff/DayOffService.java | 86 ++++++++++++++++-- .../dayoff/DayOffStatus.java | 3 +- 8 files changed, 99 insertions(+), 9 deletions(-) diff --git a/.gradle/8.1.1/executionHistory/executionHistory.lock b/.gradle/8.1.1/executionHistory/executionHistory.lock index c1ad8d5c404895bee1b1d738f9609c72b6fe8a9d..5988cc8991b47dacb07c5b41d5642b38135d0045 100644 GIT binary patch literal 17 TcmZQxX4AXdKwVOm0Ro%=CDQ{1 literal 17 TcmZQxX4AXdKwVOm0RprDCA$Lc diff --git a/.gradle/8.1.1/fileHashes/fileHashes.lock b/.gradle/8.1.1/fileHashes/fileHashes.lock index ff485eed87f27d9d8333238047f7f2cab7c8cc95..a1faa897f222edc69d164465981fb1b00e263293 100644 GIT binary patch literal 17 VcmZRc9`t<9-qrRW7{GwZ0{}jE1yKM1 literal 17 VcmZRc9`t<9-qrRW7{GvW4gfyM1*8A~ diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index 4a3eb311f06678a27400fd2040c0f36d501df4bf..67f0e7020eeb3a8ba33c73da1c39129a4800595f 100644 GIT binary patch literal 17 UcmZQ(h|7Fy<23ms0|d+i04ksaFaQ7m literal 17 UcmZQ(h|7Fy<23ms0|aCM04iz&`Tzg` diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOff.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOff.java index d77d887..5b57bd3 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOff.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOff.java @@ -32,4 +32,18 @@ public class DayOff { private Float numOfDayOff; private LocalDate applyAt; private LocalDate processAt; + + public float getUsedDayOff() { + if (this.status != null && this.status == DayOffStatus.valueOf("승인")) { + return this.numOfDayOff; + } else { + return 0f; + } + } + public void setStatus(DayOffStatus status) { + this.status = status; + } + public void setNumOfDayOff(float numOfDayOff) { + this.numOfDayOff = numOfDayOff; + } } \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRepository.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRepository.java index c1d2134..02c3d05 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRepository.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRepository.java @@ -9,4 +9,5 @@ @Repository public interface DayOffRepository extends JpaRepository { List findByUser(User user); + List findByUserAndStatus(User user, DayOffStatus status); } diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java index b4bd77f..4775a47 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java @@ -11,9 +11,9 @@ public class DayOffResponse { public static class MyDayOffDTO { private float valid; private float used; - private int expired; + private float expired; - public MyDayOffDTO(float valid, float used, int expired) { + public MyDayOffDTO(float valid, float used, float expired) { this.valid = valid; this.used = used; this.expired = expired; diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java index e53d9f1..878e35c 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java @@ -8,6 +8,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDate; import java.util.List; @RequiredArgsConstructor @@ -16,28 +17,87 @@ public class DayOffService { private final DayOffRepository dayOffRepository; private final UserRepository userRepository; + // 연차 신청 마감일 + private final LocalDate applicationDeadline = LocalDate.of(2023, 12, 31); + // 연차 신청 @Transactional public void registerDayOff(Long userId, DayOffRequest.RegisterDTO registerDTO) { User user = userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException("사용자를 찾을 수 없습니다.")); - float numOfDayOff = determineInitialDayOff(user); - DayOff dayOff = registerDTO.toEntity(user, numOfDayOff); + List dayOffs = dayOffRepository.findByUser(user); + + // 동일한 날짜에 신청했는지 체크 + for(DayOff dayOff : dayOffs) { + if (!((dayOff.getEndDate().isBefore(registerDTO.getStartDate()) || + dayOff.getEndDate().isEqual(registerDTO.getStartDate())) || + (dayOff.getStartDate().isAfter(registerDTO.getEndDate()) || + dayOff.getStartDate().isEqual(registerDTO.getEndDate())))) { + // 반차 체크 + if ((dayOff.getType() == DayOffType.오전반차 || dayOff.getType() == DayOffType.오후반차) && + dayOff.getType() == registerDTO.getType()) { + throw new IllegalArgumentException("신청하려는 날짜가 이미 등록된 연차와 겹칩니다."); + } + } + } + + // 연차 신청 마감일 체크 + if (LocalDate.now().isAfter(applicationDeadline)) { + throw new IllegalArgumentException("연차 신청 마감일이 지났습니다."); + } + + // 연차 유형에 따른 신청일 계산 + float appliedDayOff = 0.0f; + if (registerDTO.getType() == DayOffType.연차) { + appliedDayOff = registerDTO.getStartDate().datesUntil(registerDTO.getEndDate()).filter(d -> d.getDayOfWeek().getValue() < 6).count(); + } else if (registerDTO.getType() == DayOffType.오전반차 || registerDTO.getType() == DayOffType.오후반차) { + appliedDayOff = 0.5f; + } + // 지난 날짜에 대한 연차 신청 체크 + if (registerDTO.getStartDate().isBefore(LocalDate.now())) { + throw new IllegalArgumentException("지난 날짜에 대한 연차 신청은 불가능합니다."); + } + + // 남은 휴가 확인 + float totalDayOff = determineInitialDayOff(user); + float usedDayOff = 0f; + + for(DayOff dayOff : dayOffs){ + usedDayOff += dayOff.getStartDate().datesUntil(dayOff.getEndDate()).filter(d -> d.getDayOfWeek().getValue() < 6).count(); + } + + float remainingDayOff = totalDayOff - usedDayOff; + + if (remainingDayOff < appliedDayOff) { + throw new IllegalArgumentException("남은 연차가 부족합니다."); + } + + + DayOff dayOff = registerDTO.toEntity(user, appliedDayOff); dayOffRepository.save(dayOff); } + // 나의 남은 연차 (초기 연차만 설정) @Transactional(readOnly = true) public DayOffResponse.MyDayOffDTO myDayOffInfo(Long userId) { User user = userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException("사용자를 찾을 수 없습니다.")); - // TODO 휴가 로직을 수정해야함 - float numOfDayOff = determineInitialDayOff(user); + float totalDayOff = determineInitialDayOff(user); + float usedDayOff = 0; - return new DayOffResponse.MyDayOffDTO(numOfDayOff, 0, 0); + List dayOffs = dayOffRepository.findByUser(user); + for(DayOff dayOff : dayOffs){ + usedDayOff += dayOff.getUsedDayOff(); + } + + float remainingDayOff = totalDayOff - usedDayOff; + return new DayOffResponse.MyDayOffDTO(totalDayOff, usedDayOff, remainingDayOff); } + + // 직급별 연차 계산 private int determineInitialDayOff(User user) { int position = user.getPosition().getTypeNumber(); @@ -71,6 +131,20 @@ public DayOffResponse.AppliedDayOffDTO[] myAppliedDayOffs(Long userId) { public void cancelDayOff(Long dayoffId, Long userId) { User user = userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException("사용자를 찾을 수 없습니다.")); DayOff dayOff = dayOffRepository.findById(dayoffId).orElseThrow(() -> new UserNotFoundException("해당 연차 신청을 찾을 수 없습니다.")); - dayOffRepository.delete(dayOff); + + // 본인이 신청한 연차만 취소 가능하도록 체크 + if (!dayOff.getUser().getId().equals(userId)) { + throw new IllegalArgumentException("본인이 신청한 연차만 취소할 수 있습니다."); + } + + // 연차 신청의 상태를 취소로 변경 + if (dayOff.getStatus() == DayOffStatus.승인 || dayOff.getStatus() == DayOffStatus.반려) { + throw new IllegalArgumentException("이미 처리된 연차 신청은 취소할 수 없습니다."); + } + + dayOff.setStatus(DayOffStatus.valueOf("취소")); + + // 취소된 연차의 사용일수를 다시 복구 + dayOff.setNumOfDayOff(0.0f); } } diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffStatus.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffStatus.java index 174df3c..9764e8e 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffStatus.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffStatus.java @@ -8,7 +8,8 @@ public enum DayOffStatus { 대기(0), 승인(1), - 반려(2); + 반려(2), + 취소(3); private final int typeNumber; } From 9ef3a84ed540b7c12f692496364bc4effa1329e7 Mon Sep 17 00:00:00 2001 From: Park SeongWook <116128609+gosuuk@users.noreply.github.com> Date: Wed, 2 Aug 2023 22:00:01 +0900 Subject: [PATCH 082/128] =?UTF-8?q?#4=20DayOff=20=EC=98=88=EC=99=B8?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../8.1.1/executionHistory/executionHistory.lock | Bin 17 -> 17 bytes .gradle/8.1.1/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../buildOutputCleanup/buildOutputCleanup.lock | Bin 17 -> 17 bytes .../kdtbe5_miniproject/dayoff/DayOffService.java | 14 +++++++------- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.gradle/8.1.1/executionHistory/executionHistory.lock b/.gradle/8.1.1/executionHistory/executionHistory.lock index 5988cc8991b47dacb07c5b41d5642b38135d0045..04d1845f32db9a65f880aa90f442eb920b0ee0c9 100644 GIT binary patch literal 17 TcmZQxX4AXdKwVOm0Rln*CFKJb literal 17 TcmZQxX4AXdKwVOm0Ro%=CDQ{1 diff --git a/.gradle/8.1.1/fileHashes/fileHashes.lock b/.gradle/8.1.1/fileHashes/fileHashes.lock index a1faa897f222edc69d164465981fb1b00e263293..00217e341ac9c4479ca000025740df9bf9b7dd0b 100644 GIT binary patch literal 17 VcmZRc9`t<9-qrRW7{Gw39{@hS1(*N; literal 17 VcmZRc9`t<9-qrRW7{GwZ0{}jE1yKM1 diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock index 67f0e7020eeb3a8ba33c73da1c39129a4800595f..c36489534636d2c12e9f0e8a09b550ee147b6f71 100644 GIT binary patch literal 17 UcmZQ(h|7Fy<23ms0|Xob04l@;Q~&?~ literal 17 UcmZQ(h|7Fy<23ms0|d+i04ksaFaQ7m diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java index 878e35c..fe45305 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java @@ -33,9 +33,11 @@ public void registerDayOff(Long userId, DayOffRequest.RegisterDTO registerDTO) { dayOff.getEndDate().isEqual(registerDTO.getStartDate())) || (dayOff.getStartDate().isAfter(registerDTO.getEndDate()) || dayOff.getStartDate().isEqual(registerDTO.getEndDate())))) { - // 반차 체크 - if ((dayOff.getType() == DayOffType.오전반차 || dayOff.getType() == DayOffType.오후반차) && - dayOff.getType() == registerDTO.getType()) { + + // 동일한 날짜에 반차 두번 신청하는 경우를 제한 + if (dayOff.getType() != DayOffType.연차) { + throw new IllegalArgumentException("동일한 날짜에 반차를 두 번 신청할 수 없습니다."); + } else if (registerDTO.getType() != DayOffType.연차) { throw new IllegalArgumentException("신청하려는 날짜가 이미 등록된 연차와 겹칩니다."); } } @@ -142,9 +144,7 @@ public void cancelDayOff(Long dayoffId, Long userId) { throw new IllegalArgumentException("이미 처리된 연차 신청은 취소할 수 없습니다."); } - dayOff.setStatus(DayOffStatus.valueOf("취소")); - - // 취소된 연차의 사용일수를 다시 복구 - dayOff.setNumOfDayOff(0.0f); + // 취소된 연차를 삭제 + dayOffRepository.delete(dayOff); } } From 05cbcab368c23537a4289c0236d8848fd1c15506 Mon Sep 17 00:00:00 2001 From: Park SeongWook <116128609+gosuuk@users.noreply.github.com> Date: Thu, 3 Aug 2023 14:02:32 +0900 Subject: [PATCH 083/128] =?UTF-8?q?#17=20=EC=9B=94=EB=B3=84=20=EC=8A=A4?= =?UTF-8?q?=EC=BC=80=EC=A4=84,=20=EC=A0=84=EC=B2=B4=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=20=EC=A1=B0=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../schedule/ScheduleController.java | 33 ++++++++++++ .../schedule/ScheduleRepository.java | 41 +++++++++++++++ .../schedule/ScheduleResponse.java | 48 +++++++++++++++++ .../schedule/ScheduleService.java | 51 +++++++++++++++++++ .../user/UserRepository.java | 8 +-- .../kdtbe5_miniproject/user/UserResponse.java | 19 +++++-- 6 files changed, 191 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleController.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleRepository.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleResponse.java create mode 100644 src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleService.java diff --git a/src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleController.java b/src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleController.java new file mode 100644 index 0000000..b384a3e --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleController.java @@ -0,0 +1,33 @@ +package com.example.kdtbe5_miniproject.schedule; +import com.example.kdtbe5_miniproject._core.util.ApiUtils; +import com.example.kdtbe5_miniproject.user.UserResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDate; +import java.util.HashMap; +import java.util.List; +@RequestMapping("/mypage") +@RequiredArgsConstructor +@RestController +public class ScheduleController { + + private final ScheduleService scheduleService; + + // 월별 연차 + 당직 스케줄 + @GetMapping("/schedule/{year}/{month}") + public ResponseEntity scheduleByMonth(@PathVariable int year, @PathVariable int month) { + HashMap lists = new HashMap<>(); + lists.put("dayOffList", scheduleService.findDayOffScheduleByMonth(year, month)); + lists.put("dutyList", scheduleService.findDutyScheduleByMonth(year, month)); + + return ResponseEntity.ok().body(ApiUtils.success(lists)); + } + // 전체 사용자 목록 조회 + @GetMapping("/schedule/userList") + public ResponseEntity getAppliedDuty() { + List allUsers = scheduleService.getAllUsers(); + return ResponseEntity.ok().body(ApiUtils.success(allUsers)); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleRepository.java b/src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleRepository.java new file mode 100644 index 0000000..32dad3e --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleRepository.java @@ -0,0 +1,41 @@ +package com.example.kdtbe5_miniproject.schedule; +import com.example.kdtbe5_miniproject.dayoff.DayOff; +import com.example.kdtbe5_miniproject.dayoff.DayOffStatus; +import com.example.kdtbe5_miniproject.duty.Duty; +import com.example.kdtbe5_miniproject.duty.DutyStatus; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; +import javax.persistence.EntityManager; +import javax.persistence.Query; +import java.time.LocalDate; +import java.util.List; +@Repository +@RequiredArgsConstructor +public class ScheduleRepository { + private final EntityManager entityManager; + // 연차 + // 승인 status로 조회 + // 날짜 조회 추가 필요 + public List filterDayOffSchedule(DayOffStatus status, LocalDate startDate, LocalDate endDate) { + Query query = entityManager.createQuery( + "SELECT d FROM DayOff d INNER JOIN d.user u WHERE d.status = :status AND ((d.startDate >= :startDate AND d.startDate <= :endDate) OR (d.endDate >= :startDate AND d.endDate <= :endDate))", DayOff.class); + query.setParameter("status", status); + query.setParameter("startDate", startDate); + query.setParameter("endDate", endDate); + + return query.getResultList(); + } + + // 당직 + // 승인 status로 조회 + // 날짜 조회 추가 필요 + public List filterDutySchedule(DutyStatus status, LocalDate startDate, LocalDate endDate) { + Query query = entityManager.createQuery( + "SELECT d FROM Duty d INNER JOIN d.user u WHERE d.status = :status AND d.date BETWEEN :startDate AND :endDate", Duty.class); + query.setParameter("status", status); + query.setParameter("startDate", startDate); + query.setParameter("endDate", endDate); + + return query.getResultList(); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleResponse.java b/src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleResponse.java new file mode 100644 index 0000000..7bfe934 --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleResponse.java @@ -0,0 +1,48 @@ +package com.example.kdtbe5_miniproject.schedule; + +import com.example.kdtbe5_miniproject.dayoff.DayOff; +import com.example.kdtbe5_miniproject.duty.Duty; +import com.example.kdtbe5_miniproject.user.UserPosition; +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDate; + +public class ScheduleResponse { + + @Getter + @Setter + public static class DayOffScheduleDTO { + private Long id; + private Long userId; + private String username; + private UserPosition position; + private String reason; + + public DayOffScheduleDTO(DayOff dayOff) { + this.id = dayOff.getId(); + this.userId = dayOff.getUser().getId(); + this.username = dayOff.getUser().getUsername(); + this.position = dayOff.getUser().getPosition(); + this.reason = dayOff.getReason(); + } + } + + @Getter + @Setter + public static class DutyScheduleDTO { + private Long id; + private Long userId; + private String username; + private UserPosition position; + private String reason; + + public DutyScheduleDTO(Duty duty) { + this.id = duty.getId(); + this.userId = duty.getUser().getId(); + this.username = duty.getUser().getUsername(); + this.position = duty.getUser().getPosition(); + this.reason = duty.getReason(); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleService.java b/src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleService.java new file mode 100644 index 0000000..2d1db0d --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleService.java @@ -0,0 +1,51 @@ +package com.example.kdtbe5_miniproject.schedule; +import com.example.kdtbe5_miniproject.admin.AdminResponse; +import com.example.kdtbe5_miniproject.dayoff.DayOffStatus; +import com.example.kdtbe5_miniproject.duty.Duty; +import com.example.kdtbe5_miniproject.duty.DutyStatus; +import com.example.kdtbe5_miniproject.user.UserRepository; +import com.example.kdtbe5_miniproject.user.UserResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import javax.transaction.Transactional; +import java.time.LocalDate; +import java.time.temporal.TemporalAdjusters; +import java.util.List; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +@Service +public class ScheduleService { + private final UserRepository userRepository; + private final ScheduleRepository scheduleRepository; + + @Transactional + public List findDayOffScheduleByMonth(int year, int month) { + LocalDate startDate = LocalDate.of(year, month, 1); + LocalDate endDate = startDate.with(TemporalAdjusters.lastDayOfMonth()); + DayOffStatus status = DayOffStatus.valueOf("승인"); + + return scheduleRepository.filterDayOffSchedule(status, startDate, endDate).stream() + .map(ScheduleResponse.DayOffScheduleDTO::new) + .collect(Collectors.toList()); + } + + @Transactional + public List findDutyScheduleByMonth(int year, int month) { + LocalDate startDate = LocalDate.of(year, month, 1); + LocalDate endDate = startDate.with(TemporalAdjusters.lastDayOfMonth()); + DutyStatus status = DutyStatus.valueOf("승인"); + + return scheduleRepository.filterDutySchedule(status, startDate, endDate).stream() + .map(ScheduleResponse.DutyScheduleDTO::new) + .collect(Collectors.toList()); + } + // 전체 사용자 목록 조회 + @Transactional + public List getAllUsers() { + return userRepository.findAll().stream() + .map(UserResponse.AllUsersDTO::new) + .collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java index 9cd048b..2f632a3 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java @@ -1,5 +1,4 @@ package com.example.kdtbe5_miniproject.user; - import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; @@ -7,15 +6,16 @@ import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; +import java.util.List; import java.util.Optional; @Repository public interface UserRepository extends JpaRepository { - - Optional findByEmail(@Param("email") String email); - @Modifying @Query(value = "UPDATE User SET password = :newPassword WHERE id = :id") void updateById(@Param("newPassword") String newPassword, @Param("id") Long id); + + @Override + List findAll(); } diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java index d444d07..c6cd2f2 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java @@ -1,12 +1,9 @@ package com.example.kdtbe5_miniproject.user; - import lombok.Getter; import lombok.Setter; import java.time.LocalDate; - public class UserResponse { - @Getter @Setter public static class JoinDTO { @@ -18,7 +15,6 @@ public static class JoinDTO { private UserRoles roles; private Float numOfDayOff; private LocalDate joinDate; - public JoinDTO(User user) { this.id = user.getId(); this.email = user.getEmail(); @@ -29,4 +25,17 @@ public JoinDTO(User user) { this.joinDate = user.getJoinDate(); } } -} + + @Getter + public static class AllUsersDTO { + private Long id; + private String username; + private UserPosition position; + + public AllUsersDTO(User user) { + this.id = user.getId(); + this.username = user.getUsername(); + this.position = user.getPosition(); + } + } +} \ No newline at end of file From c62fb4d2cc8c167bbea0441ebf03dc8d41abfb97 Mon Sep 17 00:00:00 2001 From: Park SeongWook <116128609+gosuuk@users.noreply.github.com> Date: Thu, 3 Aug 2023 14:15:56 +0900 Subject: [PATCH 084/128] =?UTF-8?q?#17=20=EC=97=B0=EC=B0=A8=20=EC=8B=9C?= =?UTF-8?q?=EC=9E=91=EB=82=A0=EC=A7=9C,=20=EB=81=9D=EB=82=98=EB=8A=94=20?= =?UTF-8?q?=EB=82=A0=EC=A7=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kdtbe5_miniproject/schedule/ScheduleResponse.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleResponse.java b/src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleResponse.java index 7bfe934..5b03e02 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleResponse.java @@ -18,6 +18,8 @@ public static class DayOffScheduleDTO { private String username; private UserPosition position; private String reason; + private LocalDate startDate; + private LocalDate endDate; public DayOffScheduleDTO(DayOff dayOff) { this.id = dayOff.getId(); @@ -25,6 +27,8 @@ public DayOffScheduleDTO(DayOff dayOff) { this.username = dayOff.getUser().getUsername(); this.position = dayOff.getUser().getPosition(); this.reason = dayOff.getReason(); + this.startDate = dayOff.getStartDate(); + this.endDate = dayOff.getEndDate(); } } @@ -36,6 +40,7 @@ public static class DutyScheduleDTO { private String username; private UserPosition position; private String reason; + private LocalDate date; public DutyScheduleDTO(Duty duty) { this.id = duty.getId(); @@ -43,6 +48,7 @@ public DutyScheduleDTO(Duty duty) { this.username = duty.getUser().getUsername(); this.position = duty.getUser().getPosition(); this.reason = duty.getReason(); + this.date = duty.getDate(); } } -} \ No newline at end of file +} From bc11ad8711fd82eda714368a1b67e0e2710bd9e8 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Thu, 3 Aug 2023 16:23:22 +0900 Subject: [PATCH 085/128] =?UTF-8?q?feat:=20#1=20=ED=9A=8C=EC=9B=90?= =?UTF-8?q?=EA=B0=80=EC=9E=85=20=EC=8B=9C=20=EC=A4=91=EB=B3=B5=EB=90=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=A9=94=EC=9D=BC=20=EA=B0=80=EC=9E=85=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=EC=B2=98=EB=A6=AC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_core/errors/exception/DuplicatedEmailException.java | 8 ++++++++ .../com/example/kdtbe5_miniproject/user/UserService.java | 6 ++++++ 2 files changed, 14 insertions(+) create mode 100644 src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/DuplicatedEmailException.java diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/DuplicatedEmailException.java b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/DuplicatedEmailException.java new file mode 100644 index 0000000..c1b85ed --- /dev/null +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/errors/exception/DuplicatedEmailException.java @@ -0,0 +1,8 @@ +package com.example.kdtbe5_miniproject._core.errors.exception; + +public class DuplicatedEmailException extends RuntimeException{ + + public DuplicatedEmailException(String message) { + super(message); + } +} diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java index 9ddb68f..bed0e48 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java @@ -1,5 +1,6 @@ package com.example.kdtbe5_miniproject.user; +import com.example.kdtbe5_miniproject._core.errors.exception.DuplicatedEmailException; import com.example.kdtbe5_miniproject._core.errors.exception.UnCorrectPasswordException; import com.example.kdtbe5_miniproject._core.errors.exception.UserNotFoundException; import lombok.RequiredArgsConstructor; @@ -20,6 +21,11 @@ public class UserService { @Transactional public UserResponse.JoinDTO joinUser(UserRequest.JoinDTO joinDTO) { + + Optional userOP = userRepository.findByEmail(joinDTO.getEmail()); + if(userOP.isPresent()) + throw new DuplicatedEmailException("이미 사용중인 이메일입니다"); + joinDTO.setPassword(passwordEncoder.encode(joinDTO.getPassword())); //사용자 정보 암호화 - 기능 구현 시 헷갈릴 것 같아서 주석 처리 From 0fcf5354517384784ee40df899034d286eb2a037 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Thu, 3 Aug 2023 16:40:11 +0900 Subject: [PATCH 086/128] =?UTF-8?q?refactor:=20#7=20UserRepository=20?= =?UTF-8?q?=EC=B6=A9=EB=8F=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/kdtbe5_miniproject/user/UserRepository.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java index 0c8773c..92e033b 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserRepository.java @@ -8,6 +8,7 @@ import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; +import java.util.List; import java.util.Optional; @Repository @@ -19,4 +20,6 @@ public interface UserRepository extends JpaRepository { @Modifying @Query(value = "UPDATE User SET password = :newPassword, updateDate = :now WHERE id = :id") void updateById(@Param("newPassword") String newPassword, @Param("now")LocalDateTime now, @Param("id") Long id); + @Override + List findAll(); } From 8d2deafe97bdf3a906cb7f3e370d9a5d384be35d Mon Sep 17 00:00:00 2001 From: JOOWON Date: Thu, 3 Aug 2023 16:40:19 +0900 Subject: [PATCH 087/128] =?UTF-8?q?refactor:=20#7=20=EB=8D=94=EB=AF=B8?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/db/data.sql | 35 ++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/main/resources/db/data.sql b/src/main/resources/db/data.sql index f5b00ac..67889d8 100644 --- a/src/main/resources/db/data.sql +++ b/src/main/resources/db/data.sql @@ -22,7 +22,7 @@ values (9, '허경민', '0000', 'tester09@gmail.com', '01012345678', '4', '1', ' insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) values (10, '양의지', '0000', 'tester10@gmail.com', '01012345678', '5', '1', '2023-07-27', '2023-07-27'); insert into user_tb (id, username, password, email, phone_number, position, roles, join_date, update_date) -values (11, '어드민', '{bcrypt}$2a$10$eSkd/bMFAO6z4Qa.6wQJ1.xDJLbmvHcFE0xwiAekH3u2QlzUExA/q', 'admin@admin.com', '01012345678', '5', '1', '2023-07-27', '2023-07-27'); +values (11, '어드민', '{bcrypt}$2a$10$5nJepi7hydvCqZRDWjhlBe/isQmCbZFtmjUCAu8Bm7WAtfEfXMRUG', 'admin@admin.com', '01012345678', '5', '1', '2023-07-27', '2023-07-27'); /* login_tb dummy 10 */ @@ -39,17 +39,28 @@ insert into login_tb (id, user_id, ip, user_agent, login_at) values (10, 1, '255 /* dayoff_tb dummy 10 */ -insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (1, 10, '2023-08-27', '2023-08-27', '배고파서', '2', '1', 12); -insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (2, 6, '2023-08-27', '2023-08-27', '배고파서', '1', '2', 12); -insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (3, 9, '2023-08-28', '2023-08-28', '배고파서', '2', '0', 12); -insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (4, 10, '2023-08-29', '2023-08-29', '배고파서', '1', '1', 12); -insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (5, 9, '2023-09-02', '2023-09-02', '배고파서', '2', '0', 15); -insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (6, 8, '2023-09-04', '2023-09-05', '배고파서', '0', '0', 15); -insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (7, 7, '2023-09-06', '2023-09-06', '배고파서', '2', '0', 15); -insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (8, 8, '2023-09-27', '2023-09-27', '배고파서', '0', '0', 15); -insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (9, 9, '2023-09-27', '2023-09-27', '배고파서', '2', '0', 15); -insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (10, 10, '2023-09-29', '2023-09-29', '배고파서', '2', '0', 15); -insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off) values (11, 10, '2023-09-29', '2023-10-29', '배고파서', '0', '0', 15); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off, apply_at, process_at) +values (1, 10, '2023-08-27', '2023-08-27', '배고파서', '2', '1', 12, '2023-08-07', null); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off, apply_at, process_at) +values (2, 6, '2023-08-27', '2023-08-27', '배고파서', '1', '2', 12, '2023-08-08', null); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off, apply_at, process_at) +values (3, 9, '2023-08-28', '2023-08-28', '배고파서', '2', '0', 12, '2023-08-09', null); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off, apply_at, process_at) +values (4, 10, '2023-08-29', '2023-08-29', '배고파서', '1', '1', 12, '2023-08-10', null); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off, apply_at, process_at) +values (5, 9, '2023-09-02', '2023-09-02', '배고파서', '2', '0', 15, '2023-08-11', null); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off, apply_at, process_at) +values (6, 8, '2023-09-04', '2023-09-05', '배고파서', '0', '0', 15, '2023-08-12', null); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off, apply_at, process_at) +values (7, 7, '2023-09-06', '2023-09-06', '배고파서', '2', '0', 15, '2023-08-13', null); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off, apply_at, process_at) +values (8, 8, '2023-09-27', '2023-09-27', '배고파서', '0', '0', 15, '2023-08-14', null); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off, apply_at, process_at) +values (9, 9, '2023-09-27', '2023-09-27', '배고파서', '2', '0', 15, '2023-08-15', null); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off, apply_at, process_at) +values (10, 10, '2023-09-29', '2023-09-29', '배고파서', '2', '0', 15, '2023-08-16', null); +insert into dayoff_tb (id, user_id, start_date, end_date, reason, type, status, num_of_day_off, apply_at, process_at) +values (11, 10, '2023-09-29', '2023-10-29', '배고파서', '0', '0', 15, '2023-08-17', null); /* duty_tb dummy 10 */ From fb0e12275eeeb61b6d13970d661be52bea4594d4 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Thu, 3 Aug 2023 16:41:06 +0900 Subject: [PATCH 088/128] =?UTF-8?q?refactor:=20#7=20=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=EC=9E=90=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 사용자가 신청하면 남은 연차 차감, 관리자가 반려시 차감된 연차 다시 복구, --- .../admin/AdminService.java | 56 ++++++++++++++----- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java index ee86bab..6ff14de 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java @@ -1,6 +1,5 @@ package com.example.kdtbe5_miniproject.admin; -import com.example.kdtbe5_miniproject.dayoff.DayOff; import com.example.kdtbe5_miniproject.dayoff.DayOffStatus; import com.example.kdtbe5_miniproject.dayoff.DayOffType; import com.example.kdtbe5_miniproject.duty.DutyStatus; @@ -9,6 +8,7 @@ import org.springframework.stereotype.Service; import javax.transaction.Transactional; +import java.time.LocalDate; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; @@ -38,8 +38,8 @@ public List findAllUsers() { List resultList = adminRepository.findAllUsers(); for (Object[] result : resultList) { - AdminResponse.UsersDTO user = new AdminResponse.UsersDTO((User) result[0]); - user.setNumOfDayOff((Float) result[1]); + AdminResponse.UsersDTO user = new AdminResponse.UsersDTO((User) result[1]); + user.setNumOfDayOff((Float) result[2]); userList.add(user); } return userList; @@ -48,33 +48,63 @@ public List findAllUsers() { @Transactional public AdminResponse.UsersDTO findUserDetail(Long userId) { Object[] result = adminRepository.findUserById(userId); - AdminResponse.UsersDTO user = new AdminResponse.UsersDTO((User) result[0]); - user.setNumOfDayOff((Float) result[1]); + AdminResponse.UsersDTO user = new AdminResponse.UsersDTO((User) result[1]); + user.setNumOfDayOff((Float) result[2]); return user; } - //TODO 음수일때 예외처리 + //TODO 음수일때 예외처리, 반려일때 날짜 계산 후 차감 + + /** + * A의 연차가 15일 남아있을 때, + * 3일짜리 연차를 신청 -> 남은 연차 일 수가 12로 저장, dayOff_id = 1 + * 또 2일짜리 연차를 신청 -> 남은 연차 일 수가 10으로 저장, dayOff_id = 2 + * 3일짜리는 반려됨 -> 남은 연차 일 수가 13으로 저장, dayOff_id =1의 numOfDayOff = 13 + * 2일 짜리는 승인됨 -> 남은 연차 일 수가 10 저장, dayOff_id = 2의 numOfDayOff = 10 + * 가장 최근 데이터는 10, 알맞은 데이터는 13 + *

+ * 반려했을 때, 대기 상태인 DayOff의 남은 연차를 업데이트 + *

+ * A의 연차가 15일 남아있을 때, + * 3일짜리 연차를 신청 -> 남은 연차 일 수가 12로 저장, dayOff_id = 1 + * 또 2일짜리 연차를 신청 -> 남은 연차 일 수가 10으로 저장, dayOff_id = 2 + * 2일짜리가 반려됨 -> 남은 연차 일 수가 12로 저장, dayOff_id = 1의 남은 연차는 14로 저장됨 + * 3일짜리가 반려됨 -> 남은 연차 일 수가 17로 저장, + *

+ * 이전에 대기상태의 신청이 있다면 먼저 처리하도록 예외처리 + * 반려, 승인 중복 예외처리 + */ @Transactional public void modifyDayOffStatus(Long id, AdminRequest.TreatDayOffDTO request) { Float deduction = 0F; - if (request.getStatus().equals(DayOffStatus.승인)) { + if (request.getStatus().equals(DayOffStatus.반려)) { AdminResponse.DayOffInfoDTO dayOff = new AdminResponse.DayOffInfoDTO(adminRepository.findDayOffById(id)); if (dayOff.getType().equals(DayOffType.연차)) { deduction = Float.valueOf(ChronoUnit.DAYS.between(dayOff.getStartDate(), dayOff.getEndDate())); - verifyApproval(deduction, dayOff.getNumOfDayOff()); } else if (dayOff.getType().equals(DayOffType.오전반차) || dayOff.getType().equals(DayOffType.오후반차)) { deduction = 0.5F; } + modifyWaitingDayOffs(id, deduction); } - adminRepository.updateNumOfDayOffById(id, deduction, request.getStatus()); + adminRepository.updateNumOfDayOffById(id, deduction, request.getStatus(), LocalDate.now()); } - private boolean verifyApproval(Float deduction, Float numOfDayOff) { - if (numOfDayOff - deduction < 0) { - throw new RuntimeException("남은 연차 일 수가 모자랍니다."); + @Transactional + public void modifyWaitingDayOffs(Long id, Float deduction) { + //유저 아이디로 신청한 내역 중, 대기 상태인 것을 찾아서 + List waitingDayOffList = findWaitingDayOffList(id); + waitingDayOffList.remove(id); + //deduction으로 똑같이 업데이트, 추가하기 + for (Long waiting : waitingDayOffList) { + adminRepository.updateNumOfDayOffById(waiting, deduction); } - return true; + } + + @Transactional + public List findWaitingDayOffList(Long id) { + Long userId = adminRepository.findDayOffById(id).getUser().getId(); + return adminRepository.findDayOffByStatus(userId, DayOffStatus.대기); } //TODO 날짜 중복 예외 From 56aae84eb049f8fc956c003b688c4600f64fb85f Mon Sep 17 00:00:00 2001 From: JOOWON Date: Thu, 3 Aug 2023 16:41:18 +0900 Subject: [PATCH 089/128] =?UTF-8?q?refactor:=20#7=20=EC=83=88=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=EC=97=90=20=ED=95=84=EC=9A=94=ED=95=9C=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=EB=93=A4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/AdminRepository.java | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java index 27da193..91e7fc9 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java @@ -4,7 +4,6 @@ import com.example.kdtbe5_miniproject.dayoff.DayOffStatus; import com.example.kdtbe5_miniproject.duty.Duty; import com.example.kdtbe5_miniproject.duty.DutyStatus; -import com.example.kdtbe5_miniproject.user.User; import com.example.kdtbe5_miniproject.user.UserPosition; import com.example.kdtbe5_miniproject.user.UserRoles; import lombok.RequiredArgsConstructor; @@ -13,6 +12,7 @@ import javax.persistence.EntityManager; import javax.persistence.Query; +import java.time.LocalDate; import java.util.List; @Repository @@ -29,6 +29,16 @@ public List findDayOffByStatus(DayOffStatus status) { return query.getResultList(); } + public List findDayOffByStatus(Long userId, DayOffStatus status) { + Query query = entityManager.createQuery( + "SELECT d.id FROM DayOff d INNER JOIN d.user u WHERE d.status = :status AND d.user.id = :userId ORDER BY d.applyAt ASC"); + query.setParameter("status", status); + query.setParameter("userId", userId); + + return query.getResultList(); + } + + public DayOff findDayOffById(Long id) { Query query = entityManager.createQuery( "SELECT d FROM DayOff d WHERE d.id = :id", DayOff.class); @@ -47,15 +57,16 @@ public List findDutyByStatus(DutyStatus status) { //TODO 최근 날짜로 조회 public List findAllUsers() { + //대기 상태인 연차 중 numOfDayOff가 가장 낮은 값으로 가져옴 Query query = entityManager.createQuery( - "SELECT u, d.numOfDayOff FROM User u LEFT JOIN DayOff d ON u.id = d.user.id"); + "SELECT DISTINCT u.id, u, (SELECT MIN(d.numOfDayOff) FROM DayOff d WHERE d.user = u AND d.status = '0') FROM User u"); return query.getResultList(); } public Object[] findUserById(Long userId) { Query query = entityManager.createQuery( - "SELECT u, d.numOfDayOff FROM User u LEFT JOIN DayOff d ON u.id = d.user.id WHERE u.id = :id"); + "SELECT DISTINCT u.id, u, (SELECT MIN(d.numOfDayOff) FROM DayOff d WHERE d.user = u AND d.status = '0') FROM User u WHERE u.id = :id"); query.setParameter("id", userId); return (Object[]) query.getSingleResult(); @@ -63,12 +74,22 @@ public Object[] findUserById(Long userId) { @Transactional - public void updateNumOfDayOffById(Long id, Float deduction, DayOffStatus status) { + public void updateNumOfDayOffById(Long id, Float deduction, DayOffStatus status, LocalDate now) { Query query = entityManager.createQuery( - "UPDATE DayOff SET status = :status ,numOfDayOff = numOfDayOff - :deduction WHERE id = :id"); + "UPDATE DayOff SET status = :status ,numOfDayOff = numOfDayOff + :deduction, processAt = :now WHERE id = :id"); query.setParameter("id", id); query.setParameter("deduction", deduction); query.setParameter("status", status); + query.setParameter("now", now); + query.executeUpdate(); + } + + @Transactional + public void updateNumOfDayOffById(Long id, Float deduction) { + Query query = entityManager.createQuery( + "UPDATE DayOff SET numOfDayOff = numOfDayOff + :deduction WHERE id = :id"); + query.setParameter("id", id); + query.setParameter("deduction", deduction); query.executeUpdate(); } From 2d1a20b05b2c7424818a10d2d9f11d77eb5ff0ba Mon Sep 17 00:00:00 2001 From: JOOWON Date: Thu, 3 Aug 2023 16:41:40 +0900 Subject: [PATCH 090/128] =?UTF-8?q?refactor:=20#7=20=EC=97=B0=EC=B0=A8=20?= =?UTF-8?q?=EC=8A=B9=EC=9D=B8/=EB=B0=98=EB=A0=A4=20=EC=8B=9C=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/kdtbe5_miniproject/admin/AdminController.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminController.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminController.java index 098c5c5..0e0f60d 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminController.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminController.java @@ -1,14 +1,9 @@ package com.example.kdtbe5_miniproject.admin; -import com.example.kdtbe5_miniproject._core.security.CustomUserDetails; import com.example.kdtbe5_miniproject._core.util.ApiUtils; -import com.example.kdtbe5_miniproject.dayoff.DayOff; -import com.example.kdtbe5_miniproject.duty.Duty; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import java.util.HashMap; @@ -44,6 +39,9 @@ public ResponseEntity userDetails(@PathVariable Long userId) { @PutMapping("/status/dayoff/{dayOffId}") public ResponseEntity dayOffModify(@PathVariable Long dayOffId, @RequestBody AdminRequest.TreatDayOffDTO request) { + if (adminService.findWaitingDayOffList(dayOffId).get(0) != dayOffId) { + throw new RuntimeException("이미 처리된 요청이거나, 해당 사용자의 이전 요청을 먼저 처리해주세요."); + } adminService.modifyDayOffStatus(dayOffId, request); return ResponseEntity.ok().body(ApiUtils.success(request.getStatus() + "되었습니다.")); From d7332434b5e176328bb67a78cebc733a13763008 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Thu, 3 Aug 2023 16:44:46 +0900 Subject: [PATCH 091/128] =?UTF-8?q?refactor:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EC=8B=9C=20response=20=EB=82=B4=EC=9A=A9=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kdtbe5_miniproject/user/UserController.java | 13 +++++++++---- .../kdtbe5_miniproject/user/UserService.java | 3 +++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java index ef9db0c..e578def 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java @@ -33,13 +33,15 @@ public class UserController { private final UserService userService; private final AuthenticationManager authenticationManager; + // 회원가입 @PostMapping("/join") public ResponseEntity join(@RequestBody @Valid UserRequest.JoinDTO joinDTO, Errors errors) { - UserResponse.JoinDTO responseDTO = userService.joinUser(joinDTO); + userService.joinUser(joinDTO); log.info(joinDTO.getUsername() + " Joined"); - return ResponseEntity.ok().body(ApiUtils.success(responseDTO)); + return ResponseEntity.ok().body(ApiUtils.success("회원가입이 완료되었습니다")); } + // 로그인 @PostMapping("/login") public ResponseEntity login(@RequestBody @Valid UserRequest.LoginDTO loginDTO, Errors errors, HttpServletRequest request) { try { @@ -58,6 +60,7 @@ public ResponseEntity login(@RequestBody @Valid UserRequest.LoginDTO loginDTO } } + // 로그인 기록 private void addLoginHistory(HttpServletRequest request, CustomUserDetails myUserDetails) { LoginHistoryRequest.LoginHistoryDTO loginHistoryDTO = new LoginHistoryRequest.LoginHistoryDTO(); @@ -69,6 +72,7 @@ private void addLoginHistory(HttpServletRequest request, CustomUserDetails myUse loginHistoryService.save(loginHistoryDTO); } + // 로그아웃 @GetMapping(value = "/logout") public String logout(HttpServletRequest request, HttpServletResponse response) { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); @@ -78,13 +82,14 @@ public String logout(HttpServletRequest request, HttpServletResponse response) { return "redirect:/login"; } + // 핸드폰 번호 변경 @PutMapping("/mypage/updatePhoneNumber") public ResponseEntity updatePhoneNumber(@AuthenticationPrincipal CustomUserDetails updateUser, @RequestBody @Valid UserRequest.UpdateDTO updateDTO) { userService.updatePhoneNumber(updateUser.getUserId(), updateDTO); - return ResponseEntity.ok().body(ApiUtils.success("전화번호가 변경되었습니다.")); + return ResponseEntity.ok().body(ApiUtils.success("변경되었습니다.")); } - + // 비밀번호 변경 @PutMapping("/mypage/updatePassword") public ResponseEntity userPasswordModify(@RequestBody UserRequest.ModifyPwdDTO request) { userService.updatePwd(request); diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java index bed0e48..8166f76 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java @@ -19,6 +19,7 @@ public class UserService { private final UserRepository userRepository; private final PasswordEncoder passwordEncoder; + // 회원가입 @Transactional public UserResponse.JoinDTO joinUser(UserRequest.JoinDTO joinDTO) { @@ -37,6 +38,7 @@ public UserResponse.JoinDTO joinUser(UserRequest.JoinDTO joinDTO) { return new UserResponse.JoinDTO(userPS); } + // 핸드폰번호 변경 @Transactional public void updatePhoneNumber(Long userId, UserRequest.UpdateDTO updateDTO) { User user = userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException("사용자 정보가 없습니다.")); @@ -44,6 +46,7 @@ public void updatePhoneNumber(Long userId, UserRequest.UpdateDTO updateDTO) { userRepository.save(user); } + // 비밀번호 변경 @Transactional public void updatePwd(UserRequest.ModifyPwdDTO request) { User user = userRepository.findById(request.getUserId()) From 3ad1f55503d4357a19c14623899f68d41134e8a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=98=9C=EC=A7=80?= <128347921+bornin23@users.noreply.github.com> Date: Thu, 3 Aug 2023 17:13:54 +0900 Subject: [PATCH 092/128] fix: import java.util.Optional; --- .../java/com/example/kdtbe5_miniproject/user/UserService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java index 9c66342..5c921b9 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java @@ -12,6 +12,7 @@ import java.security.Principal; import java.time.LocalDate; import java.time.LocalDateTime; +import java.util.Optional; @RequiredArgsConstructor @Service @@ -58,4 +59,4 @@ public void updatePwd(UserRequest.ModifyPwdDTO request) { } userRepository.updateById(passwordEncoder.encode(request.getNewPassword()), LocalDateTime.now(), request.getUserId()); } -} \ No newline at end of file +} From a14370068ee2d887104cbf8e3ed0a8ecd4a79b53 Mon Sep 17 00:00:00 2001 From: Park SeongWook <116128609+gosuuk@users.noreply.github.com> Date: Thu, 3 Aug 2023 20:17:17 +0900 Subject: [PATCH 093/128] =?UTF-8?q?#4=20=EC=97=B0=EC=B0=A8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kdtbe5_miniproject/dayoff/DayOff.java | 3 +- .../dayoff/DayOffService.java | 45 +++++-------------- .../example/kdtbe5_miniproject/user/User.java | 19 ++++++++ 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOff.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOff.java index 5b57bd3..7ba9c04 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOff.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOff.java @@ -34,12 +34,13 @@ public class DayOff { private LocalDate processAt; public float getUsedDayOff() { - if (this.status != null && this.status == DayOffStatus.valueOf("승인")) { + if (this.status != null && (this.status == DayOffStatus.valueOf("승인") || this.status == DayOffStatus.valueOf("대기"))) { return this.numOfDayOff; } else { return 0f; } } + public void setStatus(DayOffStatus status) { this.status = status; } diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java index fe45305..f30e630 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java @@ -28,7 +28,7 @@ public void registerDayOff(Long userId, DayOffRequest.RegisterDTO registerDTO) { List dayOffs = dayOffRepository.findByUser(user); // 동일한 날짜에 신청했는지 체크 - for(DayOff dayOff : dayOffs) { + for (DayOff dayOff : dayOffs) { if (!((dayOff.getEndDate().isBefore(registerDTO.getStartDate()) || dayOff.getEndDate().isEqual(registerDTO.getStartDate())) || (dayOff.getStartDate().isAfter(registerDTO.getEndDate()) || @@ -49,10 +49,11 @@ public void registerDayOff(Long userId, DayOffRequest.RegisterDTO registerDTO) { } // 연차 유형에 따른 신청일 계산 - float appliedDayOff = 0.0f; + float appliedDayOff = 1.0f; if (registerDTO.getType() == DayOffType.연차) { appliedDayOff = registerDTO.getStartDate().datesUntil(registerDTO.getEndDate()).filter(d -> d.getDayOfWeek().getValue() < 6).count(); } else if (registerDTO.getType() == DayOffType.오전반차 || registerDTO.getType() == DayOffType.오후반차) { + // 반차일 경우 총 연차에서 0.5 차감 appliedDayOff = 0.5f; } @@ -62,64 +63,42 @@ public void registerDayOff(Long userId, DayOffRequest.RegisterDTO registerDTO) { } // 남은 휴가 확인 - float totalDayOff = determineInitialDayOff(user); + float totalDayOff = user.determineInitialDayOff(); float usedDayOff = 0f; - for(DayOff dayOff : dayOffs){ + for (DayOff dayOff : dayOffs) { usedDayOff += dayOff.getStartDate().datesUntil(dayOff.getEndDate()).filter(d -> d.getDayOfWeek().getValue() < 6).count(); } - float remainingDayOff = totalDayOff - usedDayOff; + float remainingDayOff = totalDayOff - usedDayOff - appliedDayOff; - if (remainingDayOff < appliedDayOff) { + if (remainingDayOff < 0) { throw new IllegalArgumentException("남은 연차가 부족합니다."); } - DayOff dayOff = registerDTO.toEntity(user, appliedDayOff); dayOffRepository.save(dayOff); } - // 나의 남은 연차 (초기 연차만 설정) @Transactional(readOnly = true) public DayOffResponse.MyDayOffDTO myDayOffInfo(Long userId) { User user = userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException("사용자를 찾을 수 없습니다.")); - float totalDayOff = determineInitialDayOff(user); + float totalDayOff = user.determineInitialDayOff(); float usedDayOff = 0; - List dayOffs = dayOffRepository.findByUser(user); + for(DayOff dayOff : dayOffs){ - usedDayOff += dayOff.getUsedDayOff(); + if (dayOff.getStatus() == DayOffStatus.승인 || dayOff.getStatus() == DayOffStatus.대기) { + usedDayOff += dayOff.getUsedDayOff(); + } } float remainingDayOff = totalDayOff - usedDayOff; return new DayOffResponse.MyDayOffDTO(totalDayOff, usedDayOff, remainingDayOff); } - - - // 직급별 연차 계산 - private int determineInitialDayOff(User user) { - int position = user.getPosition().getTypeNumber(); - if (position == 0) { - return 15; // 사원 - } else if (position == 1) { - return 17; // 주임 - }else if (position == 2) { - return 20; // 대리 - }else if (position == 3) { - return 22; // 과장 - }else if (position == 4) { - return 23; // 차장 - } else if (position == 5) { - return 26; // 부장 - } else { - throw new IllegalArgumentException("직급: " + position); - } - } - // 내 연차 리스트 @Transactional(readOnly = true) public DayOffResponse.AppliedDayOffDTO[] myAppliedDayOffs(Long userId) { diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/User.java b/src/main/java/com/example/kdtbe5_miniproject/user/User.java index 00fadb6..56fbe11 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/User.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/User.java @@ -32,4 +32,23 @@ public void updatePhoneNumber(String newPhoneNum) { this.phoneNumber = newPhoneNum; } + // 직급별 연차 계산 + public int determineInitialDayOff() { + int position = this.getPosition().getTypeNumber(); + if (position == 0) { + return 15; // 사원 + } else if (position == 1) { + return 17; // 주임 + } else if (position == 2) { + return 20; // 대리 + } else if (position == 3) { + return 22; // 과장 + } else if (position == 4) { + return 23; // 차장 + } else if (position == 5) { + return 26; // 부장 + } else { + throw new IllegalArgumentException("직급: " + position); + } + } } From ef4b456c4ed83fe55d5ca6c318ffce235901c91d Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Thu, 3 Aug 2023 23:16:35 +0900 Subject: [PATCH 094/128] =?UTF-8?q?chore:=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=A3=BC=EC=84=9D(=EC=84=A4=EB=AA=85)=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/kdtbe5_miniproject/admin/AdminController.java | 5 +++++ .../com/example/kdtbe5_miniproject/admin/AdminService.java | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminController.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminController.java index 0e0f60d..7e31a37 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminController.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminController.java @@ -17,6 +17,7 @@ public class AdminController { private final AdminService adminService; + // 승인 대기중인 연차&당직 목록 조회 @GetMapping("/status") public ResponseEntity waitingStatusList() { @@ -27,16 +28,19 @@ public ResponseEntity waitingStatusList() { return ResponseEntity.ok().body(ApiUtils.success(lists)); } + // 전체 사용자 세부정보 @GetMapping("/users") public ResponseEntity AllUsersList() { return ResponseEntity.ok().body(ApiUtils.success(adminService.findAllUsers())); } + // 특정 사용자 세부정보 @GetMapping("/users/{userId}") public ResponseEntity userDetails(@PathVariable Long userId) { return ResponseEntity.ok().body(ApiUtils.success(adminService.findUserDetail(userId))); } + // 연차 승인or반려 @PutMapping("/status/dayoff/{dayOffId}") public ResponseEntity dayOffModify(@PathVariable Long dayOffId, @RequestBody AdminRequest.TreatDayOffDTO request) { if (adminService.findWaitingDayOffList(dayOffId).get(0) != dayOffId) { @@ -47,6 +51,7 @@ public ResponseEntity dayOffModify(@PathVariable Long dayOffId, @RequestBody return ResponseEntity.ok().body(ApiUtils.success(request.getStatus() + "되었습니다.")); } + // 당직 승인or반려 @PutMapping("/status/duty/{dutyId}") public ResponseEntity dutyModify(@PathVariable Long dutyId, @RequestBody AdminRequest.TreatDutyDTO request) { adminService.modifyDutyStatus(dutyId, request); diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java index 6ff14de..f40ba44 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java @@ -20,18 +20,21 @@ public class AdminService { private final AdminRepository adminRepository; + // 승인 대기중인 연차 목록 @Transactional public List findWaitingDayOff() { DayOffStatus status = DayOffStatus.대기; return adminRepository.findDayOffByStatus(status).stream().map(AdminResponse.DayOffStatusDTO::new).collect(Collectors.toList()); } + // 승인 대기중인 당직 목록 @Transactional public List findWaitingDuty() { DutyStatus status = DutyStatus.대기; return adminRepository.findDutyByStatus(status).stream().map(AdminResponse.DutyStatusDTO::new).collect(Collectors.toList()); } + // 전체 사용자 세부정보 @Transactional public List findAllUsers() { List userList = new ArrayList<>(); @@ -45,6 +48,7 @@ public List findAllUsers() { return userList; } + // 특정 사용자 세부정보 @Transactional public AdminResponse.UsersDTO findUserDetail(Long userId) { Object[] result = adminRepository.findUserById(userId); From 00f7299057c521ede202b50b5fc08cca223a622b Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Fri, 4 Aug 2023 00:37:12 +0900 Subject: [PATCH 095/128] =?UTF-8?q?feat:=20login=20=ED=9B=84=20response?= =?UTF-8?q?=EC=97=90=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EA=B0=9D=EC=B2=B4?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=EB=8B=B4=EC=95=84=EC=84=9C=20=EB=B3=B4?= =?UTF-8?q?=EB=83=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/kdtbe5_miniproject/user/UserController.java | 4 +++- .../com/example/kdtbe5_miniproject/user/UserService.java | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java index e578def..444cf78 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java @@ -53,7 +53,9 @@ public ResponseEntity login(@RequestBody @Valid UserRequest.LoginDTO loginDTO String jwt = JwtTokenProvider.create(myUserDetails.getUser()); addLoginHistory(request, myUserDetails); - return ResponseEntity.ok().header("Authorization", jwt).body(ApiUtils.success(null)); + UserResponse.LoginDTO user = userService.loginInform(loginDTO); + + return ResponseEntity.ok().header("Authorization", jwt).body(ApiUtils.success(user)); } catch (Exception e) { throw new Exception401("인증되지 않았습니다"); diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java index 9c66342..38f2554 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserService.java @@ -12,6 +12,7 @@ import java.security.Principal; import java.time.LocalDate; import java.time.LocalDateTime; +import java.util.Optional; @RequiredArgsConstructor @Service @@ -39,6 +40,14 @@ public UserResponse.JoinDTO joinUser(UserRequest.JoinDTO joinDTO) { return new UserResponse.JoinDTO(userPS); } + // 로그인 사용자 정보 조회 + @Transactional + public UserResponse.LoginDTO loginInform(UserRequest.LoginDTO loginDTO) { + Optional userOP = userRepository.findByEmail(loginDTO.getEmail()); + UserResponse.LoginDTO user = userOP.get().toEntity(); + return user; + } + // 핸드폰번호 변경 @Transactional public void updatePhoneNumber(Long userId, UserRequest.UpdateDTO updateDTO) { From fb3c02f925b04141b3e38834a1cd60edd7d600be Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Fri, 4 Aug 2023 00:37:33 +0900 Subject: [PATCH 096/128] =?UTF-8?q?feat:=20User=20>=20toEntity()=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/kdtbe5_miniproject/user/User.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/User.java b/src/main/java/com/example/kdtbe5_miniproject/user/User.java index 00fadb6..7328720 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/User.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/User.java @@ -32,4 +32,16 @@ public void updatePhoneNumber(String newPhoneNum) { this.phoneNumber = newPhoneNum; } + public UserResponse.LoginDTO toEntity() { + return UserResponse.LoginDTO.builder() + .id(this.id) + .username(this.username) + .email(this.email) + .phoneNumber(this.phoneNumber) + .position(this.position) + .roles(this.roles) + .joinDate(this.joinDate) + .build(); + } + } From 722dcb01e97e80748897aa054432f17972c6bdf7 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Fri, 4 Aug 2023 00:38:30 +0900 Subject: [PATCH 097/128] =?UTF-8?q?feat:=20UserResponse=20>=20LoginDTO=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kdtbe5_miniproject/user/UserResponse.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java index c6cd2f2..9582398 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java @@ -1,4 +1,5 @@ package com.example.kdtbe5_miniproject.user; +import lombok.Builder; import lombok.Getter; import lombok.Setter; @@ -38,4 +39,17 @@ public AllUsersDTO(User user) { this.position = user.getPosition(); } } + + @Getter + @Builder + public static class LoginDTO { + private Long id; + private String username; + private String email; + private String phoneNumber; + private UserPosition position; + private UserRoles roles; + private LocalDate joinDate; + } + } \ No newline at end of file From 20e23b8d27082f780f75924bb1faa071bcb725eb Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Fri, 4 Aug 2023 00:39:51 +0900 Subject: [PATCH 098/128] =?UTF-8?q?refactor:=20DutyController=20>=20respon?= =?UTF-8?q?se=20=ED=98=95=ED=83=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/kdtbe5_miniproject/duty/DutyController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyController.java b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyController.java index d420bbf..cf23266 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyController.java +++ b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyController.java @@ -23,7 +23,7 @@ public class DutyController { public ResponseEntity createDuty(@RequestBody @Valid DutyRequest.DutyDTO dutyDTO, @AuthenticationPrincipal CustomUserDetails customUserDetails) { User user = customUserDetails.getUser(); DutyResponse.DutyDTO responseDTO = dutyService.createDuty(dutyDTO, user.getId()); - return ResponseEntity.ok().body(ApiUtils.success(responseDTO)); + return ResponseEntity.ok().body(ApiUtils.success("당직 신청이 완료되었습니다.")); } // 내 당직 리스트 From f3d3ca39ae1a447faada96cd9866bb30de4bc599 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Fri, 4 Aug 2023 00:40:59 +0900 Subject: [PATCH 099/128] =?UTF-8?q?refactor:=20DayOffController=20>=20regi?= =?UTF-8?q?sterDayOff()=20response=20=EB=A9=94=EC=84=B8=EC=A7=80=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/kdtbe5_miniproject/dayoff/DayOffController.java | 2 +- .../com/example/kdtbe5_miniproject/dayoff/DayOffService.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffController.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffController.java index e89f659..ce79b84 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffController.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffController.java @@ -22,7 +22,7 @@ public class DayOffController { public ResponseEntity registerDayOff(@RequestBody @Valid DayOffRequest.RegisterDTO registerDTO, @AuthenticationPrincipal CustomUserDetails customUserDetails) { User user = customUserDetails.getUser(); dayOffService.registerDayOff(user.getId(), registerDTO); - return ResponseEntity.ok().body(ApiUtils.success("등록이 완료되었습니다.")); + return ResponseEntity.ok().body(ApiUtils.success("연차 신청이 완료되었습니다.")); } // 나의 연차 개수 diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java index fe45305..cc64aee 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java @@ -21,6 +21,7 @@ public class DayOffService { private final LocalDate applicationDeadline = LocalDate.of(2023, 12, 31); // 연차 신청 + // TODO 이미 신청중인 날짜에 중복신청 하는 경우 예외처리 @Transactional public void registerDayOff(Long userId, DayOffRequest.RegisterDTO registerDTO) { User user = userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException("사용자를 찾을 수 없습니다.")); From 20005323075e75bf9699b09c6cc6dcce7dd878f9 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Fri, 4 Aug 2023 00:42:12 +0900 Subject: [PATCH 100/128] =?UTF-8?q?feat:=20AdminRequest=20>=20UserDetailDT?= =?UTF-8?q?O=20>=20phoneNumber=20=EC=A0=95=EA=B7=9C=ED=91=9C=ED=98=84?= =?UTF-8?q?=EC=8B=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/kdtbe5_miniproject/admin/AdminRequest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRequest.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRequest.java index f2e885f..b61999a 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRequest.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRequest.java @@ -9,6 +9,7 @@ import lombok.Setter; import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Pattern; import java.time.LocalDate; public class AdminRequest { @@ -31,6 +32,7 @@ public static class TreatDutyDTO { @Setter public static class UserDetailsDTO { @NotEmpty + @Pattern(regexp = "^01(?:0|1|[6-9])\\d{7,8}$", message = "01011112222와 같은 형식으로 작성해주세요") private String phoneNumber; @NotEmpty private UserPosition position; From bf7c61ba3f3116fc58b0dcaadc7901324bceb329 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Fri, 4 Aug 2023 00:43:00 +0900 Subject: [PATCH 101/128] =?UTF-8?q?feat:=20AdminResponse=20>=20DayOffStatu?= =?UTF-8?q?sDTO,=20DutyStatusDTO=20>=20position=20=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/kdtbe5_miniproject/admin/AdminResponse.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java index 484e482..094c532 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java @@ -21,6 +21,7 @@ public static class DayOffStatusDTO { private Long id; private Long userId; private String userName; + private UserPosition position; private LocalDate startDate; private LocalDate endDate; private String reason; @@ -31,6 +32,7 @@ public DayOffStatusDTO(DayOff dayOff) { this.id = dayOff.getId(); this.userId = dayOff.getUser().getId(); this.userName = dayOff.getUser().getUsername(); + this.position = dayOff.getUser().getPosition(); this.startDate = dayOff.getStartDate(); this.endDate = dayOff.getEndDate(); this.reason = dayOff.getReason(); @@ -63,6 +65,7 @@ public static class DutyStatusDTO { private Long id; private Long userId; private String username; + private UserPosition position; private LocalDate date; private String reason; private DutyStatus status; @@ -71,6 +74,7 @@ public DutyStatusDTO(Duty duty) { this.id = duty.getId(); this.userId = duty.getUser().getId(); this.username = duty.getUser().getUsername(); + this.position = duty.getUser().getPosition(); this.date = duty.getDate(); this.reason = duty.getReason(); this.status = duty.getStatus(); From c3a52596b5f68dd58882e497b9d9594e10adeacf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=98=9C=EC=A7=80?= <128347921+bornin23@users.noreply.github.com> Date: Fri, 4 Aug 2023 04:08:27 +0900 Subject: [PATCH 102/128] Update DayOffService.java --- .../com/example/kdtbe5_miniproject/dayoff/DayOffService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java index f30e630..1c38141 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java @@ -76,7 +76,7 @@ public void registerDayOff(Long userId, DayOffRequest.RegisterDTO registerDTO) { throw new IllegalArgumentException("남은 연차가 부족합니다."); } - DayOff dayOff = registerDTO.toEntity(user, appliedDayOff); + DayOff dayOff = registerDTO.toEntity(user, remainingDayOff); dayOffRepository.save(dayOff); } From eac46796877f0ff0fff0270300ab506e6ed09341 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=98=9C=EC=A7=80?= <128347921+bornin23@users.noreply.github.com> Date: Fri, 4 Aug 2023 14:02:31 +0900 Subject: [PATCH 103/128] Update DayOffService.java --- .../com/example/kdtbe5_miniproject/dayoff/DayOffService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java index e9392e6..ebd3400 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java @@ -77,7 +77,7 @@ public void registerDayOff(Long userId, DayOffRequest.RegisterDTO registerDTO) { throw new IllegalArgumentException("남은 연차가 부족합니다."); } - DayOff dayOff = registerDTO.toEntity(user, remainingDayOff); + DayOff dayOff = registerDTO.toEntity(user, appliedDayOff); dayOffRepository.save(dayOff); } From 43b7ebc0907c48d2d5fc7f891f55deda337b8a6d Mon Sep 17 00:00:00 2001 From: JOOWON Date: Fri, 4 Aug 2023 15:48:45 +0900 Subject: [PATCH 104/128] =?UTF-8?q?chore:=20=EB=B0=B0=ED=8F=AC=20=EC=84=B8?= =?UTF-8?q?=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 8 +++++++- src/main/resources/application-prod.yml | 14 ++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/build.gradle b/build.gradle index b3e9142..517b895 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group = 'com.example' -version = '0.0.1-SNAPSHOT' +version = '1.0' java { sourceCompatibility = '11' @@ -33,8 +33,14 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' implementation group: 'com.auth0', name: 'java-jwt', version: '4.3.0' + implementation group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: '3.1.4' } tasks.named('test') { + systemProperty 'file.encoding', 'UTF-8' useJUnitPlatform() } + +jar { + enabled = false +} \ No newline at end of file diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index b69d3b4..b003317 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -3,16 +3,14 @@ server: encoding: charset: utf-8 force: true - port: 8080 + port: 5000 spring: datasource: - url: jdbc:mariadb://${DB_HOST}:${DB_PORT}/${DB_NAME}?allowPublicKeyRetrieval=true&useSSL=false - # driver-class-name: org.mariadb.jdbc.Driver - username: ${DB_USERNAME} - password: ${DB_PASSWORD} - h2: - console: - enabled: true + url: jdbc:mariadb://${rds.hostname}:${rds.port}/${rds.db.name}?allowPublicKeyRetrieval=true&useSSL=false + driver-class-name: org.mariadb.jdbc.Driver + username: ${rds.username} + password: ${rds.password} + jpa: hibernate: ddl-auto: none From 33840c697fc9a207cf89c499809af98ae3bbfd50 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Fri, 4 Aug 2023 15:49:09 +0900 Subject: [PATCH 105/128] =?UTF-8?q?refactor:=20body=EC=97=90=20=EC=95=A1?= =?UTF-8?q?=EC=84=B8=EC=8A=A4=ED=86=A0=ED=81=B0=20=EB=8B=B4=EC=95=84?= =?UTF-8?q?=EC=84=9C=20=EB=84=98=EA=B2=A8=EC=A3=BC=EB=8A=94=20=EB=B0=A9?= =?UTF-8?q?=EC=8B=9D=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/kdtbe5_miniproject/user/UserController.java | 1 + .../java/com/example/kdtbe5_miniproject/user/UserResponse.java | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java index 444cf78..37b855c 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserController.java @@ -54,6 +54,7 @@ public ResponseEntity login(@RequestBody @Valid UserRequest.LoginDTO loginDTO addLoginHistory(request, myUserDetails); UserResponse.LoginDTO user = userService.loginInform(loginDTO); + user.setAccessToken(jwt); return ResponseEntity.ok().header("Authorization", jwt).body(ApiUtils.success(user)); diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java index 9582398..dd5ce1b 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java @@ -41,6 +41,7 @@ public AllUsersDTO(User user) { } @Getter + @Setter @Builder public static class LoginDTO { private Long id; @@ -50,6 +51,7 @@ public static class LoginDTO { private UserPosition position; private UserRoles roles; private LocalDate joinDate; + private String accessToken; } } \ No newline at end of file From 44b970ec2fefcc576b9d94289a4c33600f323ad4 Mon Sep 17 00:00:00 2001 From: Park SeongWook <116128609+gosuuk@users.noreply.github.com> Date: Fri, 4 Aug 2023 18:10:51 +0900 Subject: [PATCH 106/128] =?UTF-8?q?#4=20=EC=97=B0=EC=B0=A8,=20=EB=8B=B9?= =?UTF-8?q?=EC=A7=81=20Response=ED=95=A0=EB=95=8C=20enum=20=EC=88=AB?= =?UTF-8?q?=EC=9E=90=EB=A1=9C=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/kdtbe5_miniproject/dayoff/DayOffResponse.java | 8 ++++---- .../example/kdtbe5_miniproject/dayoff/DayOffStatus.java | 4 ++++ .../com/example/kdtbe5_miniproject/dayoff/DayOffType.java | 4 ++++ .../com/example/kdtbe5_miniproject/duty/DutyResponse.java | 7 ++++--- .../com/example/kdtbe5_miniproject/duty/DutyStatus.java | 6 +++++- 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java index 4775a47..2b2943e 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java @@ -23,19 +23,19 @@ public MyDayOffDTO(float valid, float used, float expired) { @Getter public static class AppliedDayOffDTO { private Long id; - private DayOffType type; + private int type; // 숫자로 변경 private LocalDate startDate; private LocalDate endDate; private String reason; - private DayOffStatus status; + private int status; // 숫자로 변경 public AppliedDayOffDTO(DayOff dayOff) { this.id = dayOff.getId(); - this.type = dayOff.getType(); + this.type = dayOff.getType().getValue(); // Enum의 숫자 값을 얻어옴 this.startDate = dayOff.getStartDate(); this.endDate = dayOff.getEndDate(); this.reason = dayOff.getReason(); - this.status = dayOff.getStatus(); + this.status = dayOff.getStatus().getValue(); // Enum의 숫자 값을 얻어옴 } } } diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffStatus.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffStatus.java index 9764e8e..811a0d4 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffStatus.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffStatus.java @@ -12,4 +12,8 @@ public enum DayOffStatus { 취소(3); private final int typeNumber; + + public int getValue() { + return this.typeNumber; + } } diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffType.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffType.java index babea8d..6f0556c 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffType.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffType.java @@ -11,4 +11,8 @@ public enum DayOffType { 오후반차(2); private final int typeNumber; + + public int getValue() { + return this.typeNumber; + } } diff --git a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyResponse.java b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyResponse.java index e973a7e..a29bca0 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyResponse.java @@ -5,20 +5,21 @@ import java.time.LocalDate; +@Getter public class DutyResponse { + @Getter - @Setter public static class DutyDTO { private Long id; private LocalDate date; private String reason; - private DutyStatus status; + private int status; // 숫자로 변경 public DutyDTO(Duty duty) { this.id = duty.getId(); this.date = duty.getDate(); this.reason = duty.getReason(); - this.status = duty.getStatus(); + this.status = duty.getStatus().getValue(); // Enum의 숫자 값을 얻어옴 } } } \ No newline at end of file diff --git a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyStatus.java b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyStatus.java index d4dc25a..f6ce719 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/duty/DutyStatus.java +++ b/src/main/java/com/example/kdtbe5_miniproject/duty/DutyStatus.java @@ -10,5 +10,9 @@ public enum DutyStatus { 승인(1), 반려(2); - private final int typeNumber; + private final int status; + + public int getValue() { + return this.status; + } } From 947d70f2b4d45151ebdecbe62c09612892746205 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Fri, 4 Aug 2023 22:50:59 +0900 Subject: [PATCH 107/128] =?UTF-8?q?refactor:=20response=EC=9D=98=20enum=20?= =?UTF-8?q?=EA=B0=92=20value=EB=A1=9C=20=EB=B0=98=ED=99=98=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../schedule/ScheduleResponse.java | 4 ++-- .../kdtbe5_miniproject/user/UserResponse.java | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleResponse.java b/src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleResponse.java index 5b03e02..dcbf97e 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleResponse.java @@ -16,7 +16,7 @@ public static class DayOffScheduleDTO { private Long id; private Long userId; private String username; - private UserPosition position; + private int position; private String reason; private LocalDate startDate; private LocalDate endDate; @@ -25,7 +25,7 @@ public DayOffScheduleDTO(DayOff dayOff) { this.id = dayOff.getId(); this.userId = dayOff.getUser().getId(); this.username = dayOff.getUser().getUsername(); - this.position = dayOff.getUser().getPosition(); + this.position = dayOff.getUser().getPosition().getTypeNumber(); this.reason = dayOff.getReason(); this.startDate = dayOff.getStartDate(); this.endDate = dayOff.getEndDate(); diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java b/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java index dd5ce1b..a6f98c8 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/UserResponse.java @@ -12,8 +12,8 @@ public static class JoinDTO { private String email; private String username; private String phoneNumber; - private UserPosition position; - private UserRoles roles; + private int position; + private int roles; private Float numOfDayOff; private LocalDate joinDate; public JoinDTO(User user) { @@ -21,8 +21,8 @@ public JoinDTO(User user) { this.email = user.getEmail(); this.username = user.getUsername(); this.phoneNumber = user.getPhoneNumber(); - this.position = user.getPosition(); - this.roles = user.getRoles(); + this.position = user.getPosition().getTypeNumber(); + this.roles = user.getRoles().getTypeNumber(); this.joinDate = user.getJoinDate(); } } @@ -31,12 +31,12 @@ public JoinDTO(User user) { public static class AllUsersDTO { private Long id; private String username; - private UserPosition position; + private int position; public AllUsersDTO(User user) { this.id = user.getId(); this.username = user.getUsername(); - this.position = user.getPosition(); + this.position = user.getPosition().getTypeNumber(); } } From 86caf3649c041348cbb7487c47adafa874cec7b9 Mon Sep 17 00:00:00 2001 From: Park SeongWook <116128609+gosuuk@users.noreply.github.com> Date: Fri, 4 Aug 2023 23:29:51 +0900 Subject: [PATCH 108/128] =?UTF-8?q?=ED=8F=AC=EC=A7=80=EC=85=98=EB=B3=84=20?= =?UTF-8?q?=EC=97=B0=EC=B0=A8=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20=EB=82=A8?= =?UTF-8?q?=EC=9D=80=20=EC=97=B0=EC=B0=A8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dayoff/DayOffResponse.java | 4 -- .../example/kdtbe5_miniproject/user/User.java | 42 ++++++++++++------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java index 2b2943e..ac06e73 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java @@ -10,13 +10,9 @@ public class DayOffResponse { @Getter public static class MyDayOffDTO { private float valid; - private float used; - private float expired; public MyDayOffDTO(float valid, float used, float expired) { this.valid = valid; - this.used = used; - this.expired = expired; } } diff --git a/src/main/java/com/example/kdtbe5_miniproject/user/User.java b/src/main/java/com/example/kdtbe5_miniproject/user/User.java index 5de8afe..b7eb240 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/user/User.java +++ b/src/main/java/com/example/kdtbe5_miniproject/user/User.java @@ -46,21 +46,33 @@ public UserResponse.LoginDTO toEntity() { // 직급별 연차 계산 public int determineInitialDayOff() { - int position = this.getPosition().getTypeNumber(); - if (position == 0) { - return 15; // 사원 - } else if (position == 1) { - return 17; // 주임 - } else if (position == 2) { - return 20; // 대리 - } else if (position == 3) { - return 22; // 과장 - } else if (position == 4) { - return 23; // 차장 - } else if (position == 5) { - return 26; // 부장 - } else { - throw new IllegalArgumentException("직급: " + position); + // 입사일로부터 1년이 지났는지 체크 + LocalDate now = LocalDate.now(); + LocalDate oneYearAfterJoinDate = this.getJoinDate().plusYears(1); + int initialDayOff; + + if (now.isBefore(oneYearAfterJoinDate)) { // 입사 후 1년 미만 + int monthOfJoin = this.getJoinDate().getMonthValue(); + initialDayOff = 11 - (monthOfJoin - 1); // 입사 월 기준으로 연차 계산 + } else { // 입사 후 1년 이상 + int position = this.getPosition().getTypeNumber(); + if (position == 0) { + initialDayOff = 15; // 사원 + } else if (position == 1) { + initialDayOff = 17; // 주임 + } else if (position == 2) { + initialDayOff = 19; // 대리 + } else if (position == 3) { + initialDayOff = 21; // 과장 + } else if (position == 4) { + initialDayOff = 23; // 차장 + } else if (position == 5) { + initialDayOff = 25; // 부장 + } else { + throw new IllegalArgumentException("직급: " + position); + } } + + return initialDayOff; } } From 807be3f88984937c3caa3a46ef2e3e00f2575187 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Fri, 4 Aug 2023 23:46:39 +0900 Subject: [PATCH 109/128] =?UTF-8?q?refactor:=20response=EC=9D=98=20enum=20?= =?UTF-8?q?=EA=B0=92=20value=EB=A1=9C=20=EB=B0=98=ED=99=98=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95=20(admin=20=EB=B6=80?= =?UTF-8?q?=EB=B6=84=20=EB=B0=98=EC=98=81=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/AdminController.java | 1 + .../admin/AdminResponse.java | 32 +++++++++---------- .../admin/AdminService.java | 4 +-- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminController.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminController.java index 7e31a37..806c1bc 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminController.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminController.java @@ -59,6 +59,7 @@ public ResponseEntity dutyModify(@PathVariable Long dutyId, @RequestBody Admi return ResponseEntity.ok().body(ApiUtils.success(request.getStatus() + "되었습니다.")); } + // 사용자 정보 변경 (전화번호, 직급, 권한) @PutMapping("/users/update/{userId}") public ResponseEntity userModify(@PathVariable Long userId, @RequestBody AdminRequest.UserDetailsDTO request) { adminService.modifyUser(userId, request); diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java index 094c532..27ca8a1 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java @@ -21,23 +21,23 @@ public static class DayOffStatusDTO { private Long id; private Long userId; private String userName; - private UserPosition position; + private int position; private LocalDate startDate; private LocalDate endDate; private String reason; - private DayOffType type; - private DayOffStatus status; + private int type; + private int status; public DayOffStatusDTO(DayOff dayOff) { this.id = dayOff.getId(); this.userId = dayOff.getUser().getId(); this.userName = dayOff.getUser().getUsername(); - this.position = dayOff.getUser().getPosition(); + this.position = dayOff.getUser().getPosition().getTypeNumber(); this.startDate = dayOff.getStartDate(); this.endDate = dayOff.getEndDate(); this.reason = dayOff.getReason(); - this.type = dayOff.getType(); - this.status = dayOff.getStatus(); + this.type = dayOff.getType().getTypeNumber(); + this.status = dayOff.getStatus().getTypeNumber(); } } @@ -45,14 +45,14 @@ public DayOffStatusDTO(DayOff dayOff) { @Setter public static class DayOffInfoDTO { private Long id; - private DayOffType type; + private int type; private Float numOfDayOff; private LocalDate startDate; private LocalDate endDate; public DayOffInfoDTO(DayOff dayOff) { this.id = dayOff.getId(); - this.type = dayOff.getType(); + this.type = dayOff.getType().getTypeNumber(); this.numOfDayOff = dayOff.getNumOfDayOff(); this.startDate = dayOff.getStartDate(); this.endDate = dayOff.getEndDate(); @@ -65,19 +65,19 @@ public static class DutyStatusDTO { private Long id; private Long userId; private String username; - private UserPosition position; + private int position; private LocalDate date; private String reason; - private DutyStatus status; + private int status; public DutyStatusDTO(Duty duty) { this.id = duty.getId(); this.userId = duty.getUser().getId(); this.username = duty.getUser().getUsername(); - this.position = duty.getUser().getPosition(); + this.position = duty.getUser().getPosition().getTypeNumber(); this.date = duty.getDate(); this.reason = duty.getReason(); - this.status = duty.getStatus(); + this.status = duty.getStatus().getValue(); } } @@ -89,8 +89,8 @@ public static class UsersDTO { private String email; private String phoneNumber; private LocalDate joinDate; - private UserPosition position; - private UserRoles roles; + private int position; + private int roles; private Float numOfDayOff; public UsersDTO(User user) { @@ -99,8 +99,8 @@ public UsersDTO(User user) { this.email = user.getEmail(); this.phoneNumber = user.getPhoneNumber(); this.joinDate = user.getJoinDate(); - this.position = user.getPosition(); - this.roles = user.getRoles(); + this.position = user.getPosition().getTypeNumber(); + this.roles = user.getRoles().getTypeNumber(); } } } diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java index f40ba44..4154d59 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java @@ -84,9 +84,9 @@ public void modifyDayOffStatus(Long id, AdminRequest.TreatDayOffDTO request) { Float deduction = 0F; if (request.getStatus().equals(DayOffStatus.반려)) { AdminResponse.DayOffInfoDTO dayOff = new AdminResponse.DayOffInfoDTO(adminRepository.findDayOffById(id)); - if (dayOff.getType().equals(DayOffType.연차)) { + if (dayOff.equals(DayOffType.연차)) { deduction = Float.valueOf(ChronoUnit.DAYS.between(dayOff.getStartDate(), dayOff.getEndDate())); - } else if (dayOff.getType().equals(DayOffType.오전반차) || dayOff.getType().equals(DayOffType.오후반차)) { + } else if (dayOff.equals(DayOffType.오전반차) || dayOff.equals(DayOffType.오후반차)) { deduction = 0.5F; } modifyWaitingDayOffs(id, deduction); From 949a6b89007aef01386c39b5d2f2a6baebb3ca33 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Sat, 5 Aug 2023 02:07:29 +0900 Subject: [PATCH 110/128] =?UTF-8?q?refactor:=20DayOffRequest=20>=20toEntit?= =?UTF-8?q?y()=20>=20numofDayOff=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kdtbe5_miniproject/dayoff/DayOffRequest.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRequest.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRequest.java index 4b8020d..8e8ab08 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRequest.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffRequest.java @@ -23,6 +23,7 @@ public static class RegisterDTO { @NotNull private String reason; + /* public DayOff toEntity(User user, float numOfDayOff) { return DayOff.builder() .type(this.type) @@ -35,5 +36,18 @@ public DayOff toEntity(User user, float numOfDayOff) { .numOfDayOff(numOfDayOff) .build(); } + */ + + public DayOff toEntity(User user) { + return DayOff.builder() + .type(this.type) + .startDate(this.startDate) + .endDate(this.endDate) + .reason(this.reason) + .status(DayOffStatus.valueOf("대기")) + .applyAt(LocalDate.now()) + .user(user) + .build(); + } } } From 397e899b887ff8ae50c70741f799d31ce9c365b9 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Sat, 5 Aug 2023 02:08:25 +0900 Subject: [PATCH 111/128] =?UTF-8?q?refactor:=20DayOffResponse=20>=20valid?= =?UTF-8?q?=20=EB=B3=80=EC=88=98=20=EB=AA=85=20numOfInitialDayOff=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/kdtbe5_miniproject/dayoff/DayOffResponse.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java index ac06e73..2cbbef3 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffResponse.java @@ -9,11 +9,17 @@ public class DayOffResponse { @Getter public static class MyDayOffDTO { - private float valid; + private float numOfInitialDayOff; + /* public MyDayOffDTO(float valid, float used, float expired) { this.valid = valid; } + */ + + public MyDayOffDTO(float numOfInitialDayOff) { + this.numOfInitialDayOff = numOfInitialDayOff; + } } @Getter From 0f60020fa1e7ed06bd707dabffeba6fb477933ae Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Sat, 5 Aug 2023 02:09:10 +0900 Subject: [PATCH 112/128] =?UTF-8?q?refactor:=20DayOffService=20>=20registe?= =?UTF-8?q?rDayOff(),=20myDayOffInfo()=20=EC=9D=98=20=EC=97=B0=EC=B0=A8?= =?UTF-8?q?=EC=9D=BC=EC=88=98=20=EA=B3=84=EC=82=B0=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dayoff/DayOffService.java | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java index ebd3400..c89fec2 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/dayoff/DayOffService.java @@ -49,6 +49,12 @@ public void registerDayOff(Long userId, DayOffRequest.RegisterDTO registerDTO) { throw new IllegalArgumentException("연차 신청 마감일이 지났습니다."); } + // 지난 날짜에 대한 연차 신청 체크 + if (registerDTO.getStartDate().isBefore(LocalDate.now())) { + throw new IllegalArgumentException("지난 날짜에 대한 연차 신청은 불가능합니다."); + } + + /* // 연차 유형에 따른 신청일 계산 float appliedDayOff = 1.0f; if (registerDTO.getType() == DayOffType.연차) { @@ -58,11 +64,6 @@ public void registerDayOff(Long userId, DayOffRequest.RegisterDTO registerDTO) { appliedDayOff = 0.5f; } - // 지난 날짜에 대한 연차 신청 체크 - if (registerDTO.getStartDate().isBefore(LocalDate.now())) { - throw new IllegalArgumentException("지난 날짜에 대한 연차 신청은 불가능합니다."); - } - // 남은 휴가 확인 float totalDayOff = user.determineInitialDayOff(); float usedDayOff = 0f; @@ -77,7 +78,12 @@ public void registerDayOff(Long userId, DayOffRequest.RegisterDTO registerDTO) { throw new IllegalArgumentException("남은 연차가 부족합니다."); } + */ + + /* DayOff dayOff = registerDTO.toEntity(user, appliedDayOff); + */ + DayOff dayOff = registerDTO.toEntity(user); dayOffRepository.save(dayOff); } @@ -86,7 +92,9 @@ public void registerDayOff(Long userId, DayOffRequest.RegisterDTO registerDTO) { public DayOffResponse.MyDayOffDTO myDayOffInfo(Long userId) { User user = userRepository.findById(userId).orElseThrow(() -> new UserNotFoundException("사용자를 찾을 수 없습니다.")); - float totalDayOff = user.determineInitialDayOff(); + float numOfInitialDayOff = user.determineInitialDayOff(); + + /* float usedDayOff = 0; List dayOffs = dayOffRepository.findByUser(user); @@ -97,7 +105,13 @@ public DayOffResponse.MyDayOffDTO myDayOffInfo(Long userId) { } float remainingDayOff = totalDayOff - usedDayOff; + */ + + /* return new DayOffResponse.MyDayOffDTO(totalDayOff, usedDayOff, remainingDayOff); + */ + + return new DayOffResponse.MyDayOffDTO(numOfInitialDayOff); } // 내 연차 리스트 From 6db437cd4eb49eea8ebb0e4752809a8b39c5bdb5 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Sat, 5 Aug 2023 02:11:11 +0900 Subject: [PATCH 113/128] =?UTF-8?q?refactor:=20AdminRepository=20>=20findA?= =?UTF-8?q?llUsers()=20numofDayOff=20=EA=B0=92=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EC=BF=BC=EB=A6=AC=EB=B6=80=EB=B6=84=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kdtbe5_miniproject/admin/AdminRepository.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java index 91e7fc9..755fa2f 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java @@ -56,6 +56,7 @@ public List findDutyByStatus(DutyStatus status) { } //TODO 최근 날짜로 조회 + /* public List findAllUsers() { //대기 상태인 연차 중 numOfDayOff가 가장 낮은 값으로 가져옴 Query query = entityManager.createQuery( @@ -63,6 +64,14 @@ public List findAllUsers() { return query.getResultList(); } + */ + public List findAllUsers() { + //대기 상태인 연차 중 numOfDayOff가 가장 낮은 값으로 가져옴 + Query query = entityManager.createQuery( + "SELECT DISTINCT u.id, u FROM User u"); + + return query.getResultList(); + } public Object[] findUserById(Long userId) { Query query = entityManager.createQuery( From 1cf6567260a81ec58b252a75d29ae402fd143ba1 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Sat, 5 Aug 2023 02:12:23 +0900 Subject: [PATCH 114/128] =?UTF-8?q?refactor:=20AdminResponse=20>=20UsersDT?= =?UTF-8?q?O=20>=20numOfDayOff=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/kdtbe5_miniproject/admin/AdminResponse.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java index 27ca8a1..6e48cf4 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java @@ -91,7 +91,7 @@ public static class UsersDTO { private LocalDate joinDate; private int position; private int roles; - private Float numOfDayOff; +// private Float numOfDayOff; public UsersDTO(User user) { this.id = user.getId(); From 2c97feafa3ddf908bf188289b677bd401f76a01d Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Sat, 5 Aug 2023 02:13:51 +0900 Subject: [PATCH 115/128] =?UTF-8?q?refactor:=20AdminService=20>=20findAllU?= =?UTF-8?q?sers(),=20findUserDetail()=20>=20=EC=82=AC=EC=9A=A9=EC=9E=90?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=EC=A1=B0=ED=9A=8C=EC=8B=9C=20numOfDayOff?= =?UTF-8?q?=20=EA=B0=92=20=EC=84=B8=ED=8C=85=ED=95=98=EB=8A=94=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/kdtbe5_miniproject/admin/AdminService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java index 4154d59..d0c432f 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java @@ -42,7 +42,7 @@ public List findAllUsers() { List resultList = adminRepository.findAllUsers(); for (Object[] result : resultList) { AdminResponse.UsersDTO user = new AdminResponse.UsersDTO((User) result[1]); - user.setNumOfDayOff((Float) result[2]); +// user.setNumOfDayOff((Float) result[2]); userList.add(user); } return userList; @@ -53,7 +53,7 @@ public List findAllUsers() { public AdminResponse.UsersDTO findUserDetail(Long userId) { Object[] result = adminRepository.findUserById(userId); AdminResponse.UsersDTO user = new AdminResponse.UsersDTO((User) result[1]); - user.setNumOfDayOff((Float) result[2]); +// user.setNumOfDayOff((Float) result[2]); return user; } From 7249fed1de829f73a8f7f56bf0edff90b8703e76 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Sat, 5 Aug 2023 02:25:51 +0900 Subject: [PATCH 116/128] =?UTF-8?q?refactor:=20AdminRepository=20>=20findU?= =?UTF-8?q?serById()=20numofDayOff=20=EA=B0=92=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EC=BF=BC=EB=A6=AC=EB=B6=80=EB=B6=84=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kdtbe5_miniproject/admin/AdminRepository.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java index 755fa2f..bd01a6e 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java @@ -73,6 +73,7 @@ public List findAllUsers() { return query.getResultList(); } + /* public Object[] findUserById(Long userId) { Query query = entityManager.createQuery( "SELECT DISTINCT u.id, u, (SELECT MIN(d.numOfDayOff) FROM DayOff d WHERE d.user = u AND d.status = '0') FROM User u WHERE u.id = :id"); @@ -80,7 +81,15 @@ public Object[] findUserById(Long userId) { return (Object[]) query.getSingleResult(); } + */ + public Object[] findUserById(Long userId) { + Query query = entityManager.createQuery( + "SELECT DISTINCT u.id, u FROM User u WHERE u.id = :id"); + query.setParameter("id", userId); + + return (Object[]) query.getSingleResult(); + } @Transactional public void updateNumOfDayOffById(Long id, Float deduction, DayOffStatus status, LocalDate now) { From 3f5ada23431dd918726afa5467eab8a86c3645dd Mon Sep 17 00:00:00 2001 From: JOOWON Date: Sat, 5 Aug 2023 03:51:31 +0900 Subject: [PATCH 117/128] =?UTF-8?q?refactor:=20=EC=97=B0=EC=B0=A8=20?= =?UTF-8?q?=EA=B3=84=EC=82=B0=20=EB=A9=94=EC=86=8C=EB=93=9C=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/AdminRepository.java | 30 +++++++------------ 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java index 91e7fc9..ef94697 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java @@ -4,6 +4,7 @@ import com.example.kdtbe5_miniproject.dayoff.DayOffStatus; import com.example.kdtbe5_miniproject.duty.Duty; import com.example.kdtbe5_miniproject.duty.DutyStatus; +import com.example.kdtbe5_miniproject.user.User; import com.example.kdtbe5_miniproject.user.UserPosition; import com.example.kdtbe5_miniproject.user.UserRoles; import lombok.RequiredArgsConstructor; @@ -56,49 +57,40 @@ public List findDutyByStatus(DutyStatus status) { } //TODO 최근 날짜로 조회 - public List findAllUsers() { + public List findAllUsers() { //대기 상태인 연차 중 numOfDayOff가 가장 낮은 값으로 가져옴 Query query = entityManager.createQuery( - "SELECT DISTINCT u.id, u, (SELECT MIN(d.numOfDayOff) FROM DayOff d WHERE d.user = u AND d.status = '0') FROM User u"); + "SELECT u From User u", User.class); return query.getResultList(); } - public Object[] findUserById(Long userId) { + public User findUserById(Long userId) { Query query = entityManager.createQuery( - "SELECT DISTINCT u.id, u, (SELECT MIN(d.numOfDayOff) FROM DayOff d WHERE d.user = u AND d.status = '0') FROM User u WHERE u.id = :id"); + "SELECT u FROM User u WHERE u.id = :id", User.class); query.setParameter("id", userId); - return (Object[]) query.getSingleResult(); + return (User) query.getSingleResult(); } @Transactional - public void updateNumOfDayOffById(Long id, Float deduction, DayOffStatus status, LocalDate now) { + public void updateNumOfDayOffById(Long id, DayOffStatus status, LocalDate now) { Query query = entityManager.createQuery( - "UPDATE DayOff SET status = :status ,numOfDayOff = numOfDayOff + :deduction, processAt = :now WHERE id = :id"); + "UPDATE DayOff SET status = :status, processAt = :now WHERE id = :id"); query.setParameter("id", id); - query.setParameter("deduction", deduction); query.setParameter("status", status); query.setParameter("now", now); query.executeUpdate(); } @Transactional - public void updateNumOfDayOffById(Long id, Float deduction) { + public void updateDutyById(Long id, DutyStatus status, LocalDate now) { Query query = entityManager.createQuery( - "UPDATE DayOff SET numOfDayOff = numOfDayOff + :deduction WHERE id = :id"); - query.setParameter("id", id); - query.setParameter("deduction", deduction); - query.executeUpdate(); - } - - @Transactional - public void updateDutyById(Long id, DutyStatus status) { - Query query = entityManager.createQuery( - "UPDATE Duty SET status = :status WHERE id = :id"); + "UPDATE Duty SET status = :status, processAt = :now WHERE id = :id"); query.setParameter("id", id); query.setParameter("status", status); + query.setParameter("now", now); query.executeUpdate(); } From d29b9348a5a1e063387ff64c8e99a5497d59f7d2 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Sat, 5 Aug 2023 03:51:47 +0900 Subject: [PATCH 118/128] =?UTF-8?q?refactor:=20numOfDayOff=20=EB=B0=98?= =?UTF-8?q?=ED=99=98=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/kdtbe5_miniproject/admin/AdminResponse.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java index 27ca8a1..f5014aa 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java @@ -91,7 +91,6 @@ public static class UsersDTO { private LocalDate joinDate; private int position; private int roles; - private Float numOfDayOff; public UsersDTO(User user) { this.id = user.getId(); From 6f55a78f65a12bf6cbed50bb037d251977b5bd51 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Sat, 5 Aug 2023 03:51:59 +0900 Subject: [PATCH 119/128] =?UTF-8?q?refactor:=20=EC=97=B0=EC=B0=A8=20?= =?UTF-8?q?=EA=B3=84=EC=82=B0=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/AdminService.java | 61 ++----------------- 1 file changed, 4 insertions(+), 57 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java index 4154d59..0b62294 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java @@ -37,72 +37,19 @@ public List findWaitingDuty() { // 전체 사용자 세부정보 @Transactional public List findAllUsers() { - List userList = new ArrayList<>(); - - List resultList = adminRepository.findAllUsers(); - for (Object[] result : resultList) { - AdminResponse.UsersDTO user = new AdminResponse.UsersDTO((User) result[1]); - user.setNumOfDayOff((Float) result[2]); - userList.add(user); - } - return userList; + return adminRepository.findAllUsers().stream().map(AdminResponse.UsersDTO::new).collect(Collectors.toList()); } // 특정 사용자 세부정보 @Transactional public AdminResponse.UsersDTO findUserDetail(Long userId) { - Object[] result = adminRepository.findUserById(userId); - AdminResponse.UsersDTO user = new AdminResponse.UsersDTO((User) result[1]); - user.setNumOfDayOff((Float) result[2]); - - return user; + return new AdminResponse.UsersDTO(adminRepository.findUserById(userId)); } - //TODO 음수일때 예외처리, 반려일때 날짜 계산 후 차감 - /** - * A의 연차가 15일 남아있을 때, - * 3일짜리 연차를 신청 -> 남은 연차 일 수가 12로 저장, dayOff_id = 1 - * 또 2일짜리 연차를 신청 -> 남은 연차 일 수가 10으로 저장, dayOff_id = 2 - * 3일짜리는 반려됨 -> 남은 연차 일 수가 13으로 저장, dayOff_id =1의 numOfDayOff = 13 - * 2일 짜리는 승인됨 -> 남은 연차 일 수가 10 저장, dayOff_id = 2의 numOfDayOff = 10 - * 가장 최근 데이터는 10, 알맞은 데이터는 13 - *

- * 반려했을 때, 대기 상태인 DayOff의 남은 연차를 업데이트 - *

- * A의 연차가 15일 남아있을 때, - * 3일짜리 연차를 신청 -> 남은 연차 일 수가 12로 저장, dayOff_id = 1 - * 또 2일짜리 연차를 신청 -> 남은 연차 일 수가 10으로 저장, dayOff_id = 2 - * 2일짜리가 반려됨 -> 남은 연차 일 수가 12로 저장, dayOff_id = 1의 남은 연차는 14로 저장됨 - * 3일짜리가 반려됨 -> 남은 연차 일 수가 17로 저장, - *

- * 이전에 대기상태의 신청이 있다면 먼저 처리하도록 예외처리 - * 반려, 승인 중복 예외처리 - */ @Transactional public void modifyDayOffStatus(Long id, AdminRequest.TreatDayOffDTO request) { - Float deduction = 0F; - if (request.getStatus().equals(DayOffStatus.반려)) { - AdminResponse.DayOffInfoDTO dayOff = new AdminResponse.DayOffInfoDTO(adminRepository.findDayOffById(id)); - if (dayOff.equals(DayOffType.연차)) { - deduction = Float.valueOf(ChronoUnit.DAYS.between(dayOff.getStartDate(), dayOff.getEndDate())); - } else if (dayOff.equals(DayOffType.오전반차) || dayOff.equals(DayOffType.오후반차)) { - deduction = 0.5F; - } - modifyWaitingDayOffs(id, deduction); - } - adminRepository.updateNumOfDayOffById(id, deduction, request.getStatus(), LocalDate.now()); - } - - @Transactional - public void modifyWaitingDayOffs(Long id, Float deduction) { - //유저 아이디로 신청한 내역 중, 대기 상태인 것을 찾아서 - List waitingDayOffList = findWaitingDayOffList(id); - waitingDayOffList.remove(id); - //deduction으로 똑같이 업데이트, 추가하기 - for (Long waiting : waitingDayOffList) { - adminRepository.updateNumOfDayOffById(waiting, deduction); - } + adminRepository.updateNumOfDayOffById(id, request.getStatus(), LocalDate.now()); } @Transactional @@ -114,7 +61,7 @@ public List findWaitingDayOffList(Long id) { //TODO 날짜 중복 예외 @Transactional public void modifyDutyStatus(Long id, AdminRequest.TreatDutyDTO request) { - adminRepository.updateDutyById(id, request.getStatus()); + adminRepository.updateDutyById(id, request.getStatus(), LocalDate.now()); } @Transactional From 2c47641f4968f8d90cc3958b5cc1eb021bb08d0b Mon Sep 17 00:00:00 2001 From: JOOWON Date: Sat, 5 Aug 2023 03:52:11 +0900 Subject: [PATCH 120/128] =?UTF-8?q?refactor:=20=EA=B2=80=EC=A6=9D=EB=8B=A8?= =?UTF-8?q?=EA=B3=84=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/kdtbe5_miniproject/admin/AdminController.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminController.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminController.java index 806c1bc..0b1f839 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminController.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminController.java @@ -43,9 +43,6 @@ public ResponseEntity userDetails(@PathVariable Long userId) { // 연차 승인or반려 @PutMapping("/status/dayoff/{dayOffId}") public ResponseEntity dayOffModify(@PathVariable Long dayOffId, @RequestBody AdminRequest.TreatDayOffDTO request) { - if (adminService.findWaitingDayOffList(dayOffId).get(0) != dayOffId) { - throw new RuntimeException("이미 처리된 요청이거나, 해당 사용자의 이전 요청을 먼저 처리해주세요."); - } adminService.modifyDayOffStatus(dayOffId, request); return ResponseEntity.ok().body(ApiUtils.success(request.getStatus() + "되었습니다.")); From 42ede77621650976038fa191098bbd675a37b0a4 Mon Sep 17 00:00:00 2001 From: HanHyeJi Date: Mon, 7 Aug 2023 17:30:27 +0900 Subject: [PATCH 121/128] =?UTF-8?q?refactor:=20ScheduleResponse=20>=20DayO?= =?UTF-8?q?ffScheduleDTO=20=ED=9C=B4=EA=B0=80=20type=20=EC=B6=94=EA=B0=80,?= =?UTF-8?q?=20DutyScheduleDTO=20>=20position=20int=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kdtbe5_miniproject/schedule/ScheduleResponse.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleResponse.java b/src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleResponse.java index dcbf97e..9991f27 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/schedule/ScheduleResponse.java @@ -18,6 +18,7 @@ public static class DayOffScheduleDTO { private String username; private int position; private String reason; + private int type; private LocalDate startDate; private LocalDate endDate; @@ -27,6 +28,7 @@ public DayOffScheduleDTO(DayOff dayOff) { this.username = dayOff.getUser().getUsername(); this.position = dayOff.getUser().getPosition().getTypeNumber(); this.reason = dayOff.getReason(); + this.type = dayOff.getType().getTypeNumber(); this.startDate = dayOff.getStartDate(); this.endDate = dayOff.getEndDate(); } @@ -38,7 +40,7 @@ public static class DutyScheduleDTO { private Long id; private Long userId; private String username; - private UserPosition position; + private int position; private String reason; private LocalDate date; @@ -46,7 +48,7 @@ public DutyScheduleDTO(Duty duty) { this.id = duty.getId(); this.userId = duty.getUser().getId(); this.username = duty.getUser().getUsername(); - this.position = duty.getUser().getPosition(); + this.position = duty.getUser().getPosition().getTypeNumber(); this.reason = duty.getReason(); this.date = duty.getDate(); } From 0f2657e145014236fd0c1ebdf3cb19edc8fa7a72 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Mon, 7 Aug 2023 17:31:08 +0900 Subject: [PATCH 122/128] refactor: UserResponse, id -> userId --- .../com/example/kdtbe5_miniproject/admin/AdminResponse.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java index f5014aa..dc5ac43 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminResponse.java @@ -84,7 +84,7 @@ public DutyStatusDTO(Duty duty) { @Getter @Setter public static class UsersDTO { - private Long id; + private Long userId; private String username; private String email; private String phoneNumber; @@ -93,7 +93,7 @@ public static class UsersDTO { private int roles; public UsersDTO(User user) { - this.id = user.getId(); + this.userId = user.getId(); this.username = user.getUsername(); this.email = user.getEmail(); this.phoneNumber = user.getPhoneNumber(); From 51cc6aa5542c5e3a09592ee106ec06c121a19f53 Mon Sep 17 00:00:00 2001 From: JOOWON Date: Mon, 7 Aug 2023 17:33:53 +0900 Subject: [PATCH 123/128] =?UTF-8?q?refactor:=20=ED=86=A0=ED=81=B0=20?= =?UTF-8?q?=EB=A7=8C=EB=A3=8C=20=EC=8B=9C=20401=20Error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_core/security/JwtAuthenticationFilter.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtAuthenticationFilter.java b/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtAuthenticationFilter.java index 6e09d69..c6cd113 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtAuthenticationFilter.java +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtAuthenticationFilter.java @@ -5,16 +5,19 @@ import com.auth0.jwt.exceptions.SignatureVerificationException; import com.auth0.jwt.exceptions.TokenExpiredException; import com.auth0.jwt.interfaces.DecodedJWT; +import com.example.kdtbe5_miniproject._core.util.ApiUtils; import com.example.kdtbe5_miniproject.user.User; import com.example.kdtbe5_miniproject.user.UserRoles; +import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; -import javax.persistence.criteria.CriteriaBuilder; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -55,15 +58,23 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse myUserDetails.getAuthorities() ); SecurityContextHolder.getContext().setAuthentication(authentication); + chain.doFilter(request, response); log.debug("디버그 : 인증 객체 만들어짐"); } catch (SignatureVerificationException sve) { log.error("토큰 검증 실패"); } catch (TokenExpiredException tee) { log.error("토큰 만료됨"); + AuthorizationTokenError(response); } catch (JWTDecodeException tee) { log.error("토큰 만료됨"); - } finally { - chain.doFilter(request, response); } } + + private void AuthorizationTokenError(HttpServletResponse response) throws IOException { + ObjectMapper objectMapper = new ObjectMapper(); + response.setCharacterEncoding("UTF-8"); + response.setStatus(HttpStatus.UNAUTHORIZED.value()); + response.setContentType(MediaType.APPLICATION_JSON_VALUE); + response.getWriter().write(objectMapper.writeValueAsString(ApiUtils.error("다시 로그인 해주세요"))); + } } From 2ea81f3aebcb27dc1e8f6c28a91e654d0e96e43c Mon Sep 17 00:00:00 2001 From: JOOWON Date: Mon, 7 Aug 2023 17:40:13 +0900 Subject: [PATCH 124/128] refactor: AdminRepository conflict resolve --- .../admin/AdminRepository.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java index a4e04ad..6fb214e 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java @@ -64,14 +64,6 @@ public List findAllUsers() { return query.getResultList(); } - */ - public List findAllUsers() { - //대기 상태인 연차 중 numOfDayOff가 가장 낮은 값으로 가져옴 - Query query = entityManager.createQuery( - "SELECT DISTINCT u.id, u FROM User u"); - - return query.getResultList(); - } public User findUserById(Long userId) { Query query = entityManager.createQuery( @@ -80,15 +72,6 @@ public User findUserById(Long userId) { return (User) query.getSingleResult(); } - */ - - public Object[] findUserById(Long userId) { - Query query = entityManager.createQuery( - "SELECT DISTINCT u.id, u FROM User u WHERE u.id = :id"); - query.setParameter("id", userId); - - return (Object[]) query.getSingleResult(); - } @Transactional public void updateNumOfDayOffById(Long id, DayOffStatus status, LocalDate now) { From 34c5e64e53ce2b3b673aab58f4b4ae58ca6039fd Mon Sep 17 00:00:00 2001 From: Park SeongWook <116128609+gosuuk@users.noreply.github.com> Date: Tue, 8 Aug 2023 10:11:36 +0900 Subject: [PATCH 125/128] #4 error refactor --- .../_core/security/JwtAuthenticationFilter.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtAuthenticationFilter.java b/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtAuthenticationFilter.java index c6cd113..8bc0b7e 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtAuthenticationFilter.java +++ b/src/main/java/com/example/kdtbe5_miniproject/_core/security/JwtAuthenticationFilter.java @@ -62,19 +62,21 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse log.debug("디버그 : 인증 객체 만들어짐"); } catch (SignatureVerificationException sve) { log.error("토큰 검증 실패"); + AuthorizationTokenError(response, "토큰 검증 실패"); } catch (TokenExpiredException tee) { log.error("토큰 만료됨"); - AuthorizationTokenError(response); - } catch (JWTDecodeException tee) { - log.error("토큰 만료됨"); + AuthorizationTokenError(response, "토큰 만료됨"); + } catch (JWTDecodeException jde) { + log.error("토큰 디코딩 실패"); + AuthorizationTokenError(response, "토큰 디코딩 실패"); } } - private void AuthorizationTokenError(HttpServletResponse response) throws IOException { + private void AuthorizationTokenError(HttpServletResponse response, String errorMessage) throws IOException { ObjectMapper objectMapper = new ObjectMapper(); response.setCharacterEncoding("UTF-8"); response.setStatus(HttpStatus.UNAUTHORIZED.value()); response.setContentType(MediaType.APPLICATION_JSON_VALUE); - response.getWriter().write(objectMapper.writeValueAsString(ApiUtils.error("다시 로그인 해주세요"))); + response.getWriter().write(objectMapper.writeValueAsString(ApiUtils.error(errorMessage))); } } From 198303bdcad150abc0ebb1cb09d54215bdfd334e Mon Sep 17 00:00:00 2001 From: JOOWON Date: Tue, 8 Aug 2023 18:11:52 +0900 Subject: [PATCH 126/128] =?UTF-8?q?refactor:=20=EC=97=B0=EC=B0=A8/?= =?UTF-8?q?=EB=8B=B9=EC=A7=81=20=EC=A1=B0=ED=9A=8C=20=EC=8B=9C=20status=20?= =?UTF-8?q?=EC=83=81=EA=B4=80=EC=97=86=EC=9D=B4=20=EB=8B=A4=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kdtbe5_miniproject/admin/AdminRepository.java | 10 ++++------ .../example/kdtbe5_miniproject/admin/AdminService.java | 6 ++---- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java index 6fb214e..ff16fcc 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminRepository.java @@ -22,10 +22,9 @@ public class AdminRepository { private final EntityManager entityManager; - public List findDayOffByStatus(DayOffStatus status) { + public List findDayOffByStatus() { Query query = entityManager.createQuery( - "SELECT d FROM DayOff d INNER JOIN d.user u WHERE d.status = :status", DayOff.class); - query.setParameter("status", status); + "SELECT d FROM DayOff d INNER JOIN d.user u", DayOff.class); return query.getResultList(); } @@ -48,10 +47,9 @@ public DayOff findDayOffById(Long id) { return (DayOff) query.getSingleResult(); } - public List findDutyByStatus(DutyStatus status) { + public List findDutyByStatus() { Query query = entityManager.createQuery( - "SELECT d FROM Duty d INNER JOIN d.user u WHERE d.status = :status", Duty.class); - query.setParameter("status", status); + "SELECT d FROM Duty d INNER JOIN d.user u", Duty.class); return query.getResultList(); } diff --git a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java index 0b62294..4413e65 100644 --- a/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java +++ b/src/main/java/com/example/kdtbe5_miniproject/admin/AdminService.java @@ -23,15 +23,13 @@ public class AdminService { // 승인 대기중인 연차 목록 @Transactional public List findWaitingDayOff() { - DayOffStatus status = DayOffStatus.대기; - return adminRepository.findDayOffByStatus(status).stream().map(AdminResponse.DayOffStatusDTO::new).collect(Collectors.toList()); + return adminRepository.findDayOffByStatus().stream().map(AdminResponse.DayOffStatusDTO::new).collect(Collectors.toList()); } // 승인 대기중인 당직 목록 @Transactional public List findWaitingDuty() { - DutyStatus status = DutyStatus.대기; - return adminRepository.findDutyByStatus(status).stream().map(AdminResponse.DutyStatusDTO::new).collect(Collectors.toList()); + return adminRepository.findDutyByStatus().stream().map(AdminResponse.DutyStatusDTO::new).collect(Collectors.toList()); } // 전체 사용자 세부정보 From 99e290dd648c3643ede427a8b3b1c13d30ad2d64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A7=80=EB=82=98?= Date: Fri, 18 Aug 2023 01:31:02 +0900 Subject: [PATCH 127/128] docs: README.md(2) --- README.md | 245 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 208 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index e343c81..acea04c 100644 --- a/README.md +++ b/README.md @@ -1,52 +1,223 @@ -![header](https://capsule-render.vercel.app/api?type=waving&color=auto&height=200§ion=header&text=Mini%20Project&fontSize=50) -# 연차당직 사이트(SpringBoot + React) +![header](https://capsule-render.vercel.app/api?type=waving&color=auto&height=160§ion=header&text=Mini%20Project&fontSize=50) + + + + + + + + + +# 온앤오프 (On&Off) ### 🏆 프로젝트 소개 -프론트와 백엔드가 협업하여 만든 사이트입니다. 클라이언트의 일정관리를 손쉽게 유지관리 할 수 있습니다. +프론트(React), 백엔드(SpringBoot/Java) 각팀이 협업하여 ui/ux부터 배포작업까지 완료한 사이드프로젝트입니다. +프로젝트명은 온앤오프이며, 해당 프로젝트는 클라이언트의 일정관리를 손쉽게 유지관리 할 수 있습니다. +
+>**배포링크 : https://on-n-off-mini.netlify.app/** +>
+>**개발기간 : 2023.07.24 ~ 2023.08.11** + + + + +
+## 📌 프로젝트 구조 +

+ Table of Contents +
    +
  1. + 프로젝트 소개 + +
  2. +
  3. 프로젝트 구조
  4. +
  5. 팀원 및 역할
  6. +
  7. + 프로젝트 스택 + +
  8. +
  9. ERD
  10. +
  11. 테이블 설계
  12. +
  13. + 주요 기능 + +
  14. +
  15. API 명세서
  16. +
+
+ +

(back to top)

+ + + + +## ✨ 팀원 및 역할 +| 김주원 | 박성욱 | 한혜지 | 김지나 | +| :----------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------: +| 초기 개발 세팅
회원가입
로그인
개인정보수정
관리자
배포
| 연차 페이지
당직 페이지
캘린더
배포
| 연차 페이지
당직 페이지
개인정보수정
캘린더
| 프로젝트 팀장
프로젝트세팅
로그인
+ +

(back to top)

+ + + + +## 🛠 프로젝트 스택(백엔드) +* 개발환경 : JAVA 11 +* IDE: IntelliJ +* Build: Gradle +* Framework: Spring-Boot 2.7.14 +* Database: MySQL +* ORM: Mybatis +* 사용기술 + - Spring Web + - Spring Data JPA + - Spring DevTools + - Spring Security + - JWT 4.3.0 + - h2database + - lombok + - Postman + - AWS EC2 + +

(back to top)

+ + + + +## 📖 ERD +![image](https://github.com/FC-MINI-6/MiniProject_BE/assets/78328327/c1b9c922-338e-4bb4-8316-752b248585b6) + +

(back to top)

+ + + + +## ⚖ 테이블 설계 +**1. 유저** +``` +CREATE TABLE user_tb +( + id INT PRIMARY KEY AUTO_INCREMENT, + email VARCHAR(20) NOT NULL UNIQUE, --로그인 ID로 사용 + password VARCHAR(20) NOT NULL, --유효성검사 + username VARCHAR(20) NOT NULL, --실명,유효성검사 + phone_number VARCHAR(20) NOT NULL, --유효성검사 + position VARCHAR(20) NOT NULL, --사원, 주임, 대리, 과장, 차장, 부장 + roles VARCHAR(10) NOT NULL, --note: 일반, 관리자 / ENUM DEFAULT '일반' + update_date TIMESTAMP --개인정보 최종 수정일/논의 +); +``` +**2. 로그인** +``` +CREATE TABLE login_tb +( + id INT PRIMARY KEY AUTO_INCREMENT, + user_id INT NOT NULL, + ip VARCHAR(50) NOT NULL, + user_agent VARCHAR(10) NOT NULL, + login_at TIMESTAMP, -### ✨ 개발기간 -**2023.07.24 ~ 2023.08.11** + FOREIGN KEY (user_id) REFERENCES user_tb(id) +); +``` +**3. 연차** +``` +CREATE TABLE dayoff_tb +( + id INT PRIMARY KEY AUTO_INCREMENT, + user_id INT NOT NULL, + num_of_dayoff FLOAT NOT NULL, --남은 연차 일수 + start_date DATE NOT NULL, --시작일 + end_date DATE NOT NULL, --종료일 + reason VARCHAR(30) NOT NULL, --사유 + type VARCHAR(10) NOT NULL, --연차, 오전반차, 오후반차 + status VARCHAR(10) NOT NULL, --대기, 승인, 반려 ENUM DEFAULT '대기' + apply_at DATE NOT NULL, + process_at DATE, -### 🎈 프로젝트 구성 -* 멤버구성 : 김주원, 박성욱, 한혜지, 김지나 -* 개발환경 : JAVA 11, IDE: IntelliJ, Build: Gradle, Framework: Spring-Boot 2.7.14, - Database: MySQL, ORM: Mybatis -* 사용기술 : Spring Web, Spring Data JPA, Spring DevTools, Spring Security, - JWT 4.3.0, h2database, lombok + FOREIGN KEY (user_id) REFERENCES user_tb(id) +); +``` +**4.당직** +``` +CREATE TABLE duty_tb +( + id INT PRIMARY KEY AUTO_INCREMENT, + user_id INT NOT NULL, + date DATE NOT NULL, --당직 날짜 + reason VARCHAR(30) NOT NULL, --사유 + status VARCHAR(10) NOT NULL, --대기, 승인, 반려 + apply_at DATE NOT NULL, + process_at DATE, ----- -### 📌주요 기능 + FOREIGN KEY (user_id) REFERENCES user_tb(id) +); +``` +

(back to top)

-* **회원가입** - 1. jwt이용, 비밀번호 단방향 암호화 - 2. 개인정보있는경우(이름,휴대폰,이메일) AES256양방향 암호화적용,복호화 - 3. 관련필드에 DB검색할떄도 검색조건을 암호화 -* **로그인** - 1. jwt token 인증방식, spring security적용 - 2. login 성공 후 마지막 로그인 성공 날짜 업데이트 적용 - 3. login 성공 후 회원번호, user-agent, client ip, 시간 로그 등록처리 - 4. 일반로그인/관리자로그인 -* **개인정보 수정** + +## 🎀 주요 기능 +

🔹 회원가입

+
    +
  1. jwt이용, 비밀번호 단방향 암호화
  2. +
  3. 개인정보있는경우(이름,휴대폰,이메일) AES256양방향 암호화적용,복호화
  4. +
  5. 관련필드에 DB검색할떄도 검색조건을 암호화
  6. +
+

🔹 로그인

+
    +
  1. jwt token 인증방식, spring security적용
  2. +
  3. login 성공 후 마지막 로그인 성공 날짜 업데이트 적용
  4. +
  5. login 성공 후 회원번호, user-agent, client ip, 시간 로그 등록처리
  6. +
  7. 일반로그인/관리자로그인
  8. +
+

🔹 개인정보수정

+
    +
  1. 개인정보 수정,삭제, 수정된 일자 업데이트
  2. +
  3. 개인연차/당직 등록
  4. +
  5. 관리자 (유저의 권한 설정), 로그인 발급된 jwt token검증
  6. +
  7. 비밀번호변경(단방향 암호화), 전화번호변경
  8. +
+

🔹 연차/당직

+
    +
  1. 신청내역, 사용내역, 등록, 조회, 취소(crud)
  2. +
  3. 연차/당직 구분컬럼구성, 테이블1개설계
  4. +
  5. 저장/삭제 api구현필요
  6. +
  7. 내 연차일 수
  8. +
+

🔹 관리자기능

+
    +
  1. 연차 승인
  2. +
  3. 연차 반려
  4. +
+

🔹 사용자간공유

+
    +
  1. 데이터 내려줄 조회 api 구현
  2. +
  3. 월별 캘린더 주간/일간 등 다양하게 표현
  4. +
- 1. 개인정보 수정,삭제, 수정된 일자 업데이트 - 2. 개인연차/당직 등록 - 3. 관리자 (유저의 권한 설정), 로그인 발급된 jwt token검증 - 4. 비밀번호변경(단방향 암호화), 전화번호변경 +

(back to top)

-* **개인 연차/당직** - 1. 신청내역, 사용내역, 등록, 조회, 취소(crud) - 2. 연차/당직 구분컬럼구성, 테이블1개설계 - 3. 저장/삭제 api구현필요 - 4. 내 연차일 수 -* **관리자 기능** + +## 📌 API 명세서 +![image](https://github.com/FC-MINI-6/MiniProject_BE/assets/78328327/eabdf3c6-c6df-44e9-a6b1-8d868c3f9e44) - 1. 연차 승인/반려 +

(back to top)

-* **사용자간공유** - 1. 데이터 내려줄 조회 api 구현 - 2. 월별 캘린더 주간/일간 등 다양하게 표현 From 867bbe041dbeb028f312813250e92bcf220eda99 Mon Sep 17 00:00:00 2001 From: This is Jina Kim Date: Fri, 18 Aug 2023 15:16:51 +0900 Subject: [PATCH 128/128] Update README.md(3) --- README.md | 57 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index acea04c..4c40cbe 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,20 @@ -![header](https://capsule-render.vercel.app/api?type=waving&color=auto&height=160§ion=header&text=Mini%20Project&fontSize=50) +![header](https://capsule-render.vercel.app/api?type=waving&color=auto&height=200§ion=header&text=MiniProject;%20On_n_Off&fontSize=50) - +
+ +
-# 온앤오프 (On&Off) +# 온앤오프 ### 🏆 프로젝트 소개 프론트(React), 백엔드(SpringBoot/Java) 각팀이 협업하여 ui/ux부터 배포작업까지 완료한 사이드프로젝트입니다. -프로젝트명은 온앤오프이며, 해당 프로젝트는 클라이언트의 일정관리를 손쉽게 유지관리 할 수 있습니다. +프로젝트명은 온앤오프(On&Off)이며, 해당 프로젝트는 클라이언트의 일정관리를 손쉽게 유지관리 할 수 있습니다.
>**배포링크 : https://on-n-off-mini.netlify.app/** >
@@ -20,7 +22,6 @@ -
## 📌 프로젝트 구조
@@ -34,6 +35,7 @@
  • 프로젝트 구조
  • +
  • 프로젝트 시현
  • 팀원 및 역할
  • 프로젝트 스택 @@ -63,9 +65,52 @@ + +> **로그인 / 회원관리** +> +| 로그인 | 회원관리 | +| :------------: | :------------: | +| ![로그인](https://github.com/FC-MINI-6/MiniProject_BE/assets/78328327/6b54f779-71b3-476e-87fb-518ca6ce88ea) | ![회원가입](https://github.com/FC-MINI-6/MiniProject_BE/assets/78328327/f3664f54-95c5-44cf-8f86-a0bd1d348a8d) | +
    + +> **메인(일반) / 메인(관리자)** +> +| 메인(일반) | 메인(관리자) | +| :------------: | :------------: | +| ![메인_일반](https://github.com/FC-MINI-6/MiniProject_BE/assets/78328327/80bc9c83-ba70-43db-a6f7-4fd8f8ac78ed) | ![메인_관리자](https://github.com/FC-MINI-6/MiniProject_BE/assets/78328327/767be3bc-bb80-483f-bcfe-ee46401813a0) | +
    + +> **관리자** +> +| 당직휴가관리 | 사원관리 | 사원관리_세부 정보 | +| :------------: | :------------: | :------------: | +| ![관리자_당직휴가관리](https://github.com/FC-MINI-6/MiniProject_BE/assets/78328327/91635bd8-8922-4a62-8799-72638014a8ae) | ![관리자_사원관리](https://github.com/FC-MINI-6/MiniProject_BE/assets/78328327/61c28bf7-9b06-4d7c-b94d-d5ac4018b740) | ![관리자_사원관리_세부 정보](https://github.com/FC-MINI-6/MiniProject_BE/assets/78328327/091fc659-e093-490b-b9d6-7710b621d8b5) | +
    + +> **휴가/당직** +> +| 휴가/당직관리 | 휴가등록 | 당직등록 | +| :------------: | :------------: | :------------: | +| ![휴가당직관리](https://github.com/FC-MINI-6/MiniProject_BE/assets/78328327/c0ba7031-a346-4b72-a23d-ff897c0727f5) | !![휴가등록](https://github.com/FC-MINI-6/MiniProject_BE/assets/78328327/272b7b58-b9c1-4e13-a2a3-77d8bcc2893d) | ![당직등록](https://github.com/FC-MINI-6/MiniProject_BE/assets/78328327/fd815383-5247-40ba-8b8e-04e7d4a81f73) | + +| 당직신청내역 | 휴가신청내역 | +| :------------: | :------------: | +| ![나의당직신청](https://github.com/FC-MINI-6/MiniProject_BE/assets/78328327/9953028c-a67d-41cc-b0b8-f271eb6173e8) | ![나의휴가신청](https://github.com/FC-MINI-6/MiniProject_BE/assets/78328327/ae5394ef-d7af-493a-8bea-740477326997) | +
    + +> **개인정보수정** +> +| 변경_전화번호 | 변경_비밀번호 | 캘린더 | +| :------------: | :------------: | :------------: | +| ![내정보변경_전화번호](https://github.com/FC-MINI-6/MiniProject_BE/assets/78328327/77f38877-a119-4120-955c-01cba08e29e2) | ![내정보변경_비밀번호](https://github.com/FC-MINI-6/MiniProject_BE/assets/78328327/c14ece09-9bcf-404b-853f-e8a1ecbabeab) | ![캘린더](https://github.com/FC-MINI-6/MiniProject_BE/assets/78328327/16e67ea1-4ae0-4d8d-a2a7-650729f2c68b) | + +

    (back to top)

    + + + ## ✨ 팀원 및 역할 -| 김주원 | 박성욱 | 한혜지 | 김지나 | +| 김주원 | 박성욱 | 한혜지 | 김지나 | | :----------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------: | 초기 개발 세팅
    회원가입
    로그인
    개인정보수정
    관리자
    배포
    | 연차 페이지
    당직 페이지
    캘린더
    배포
    | 연차 페이지
    당직 페이지
    개인정보수정
    캘린더
    | 프로젝트 팀장
    프로젝트세팅
    로그인