From aa505e5338e30ace7871b5adb8ecdcd9803ae197 Mon Sep 17 00:00:00 2001 From: bestKUFO Date: Fri, 25 Oct 2024 13:57:55 +0900 Subject: [PATCH 01/18] =?UTF-8?q?feat:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EC=9D=B4=EB=A9=94=EC=9D=BC=20=EC=A4=91=EB=B3=B5=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=20=EA=B8=B0=EB=8A=A5=EA=B5=AC=ED=98=84=20(#2?= =?UTF-8?q?2)=20(KAN-75)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/exception/ApiException.java | 4 +- .../common/exception/ApiExceptionItf.java | 2 +- .../config/SecurityConfig.java | 23 ++++++++++ .../user/controller/UserController.java | 22 +++++++++ .../user/domain/UserEntity.java | 18 ++++++++ .../user/dto/request/UserDto.java | 46 +++++++++++++++++++ .../user/dto/response/UserSimpleResponse.java | 14 ++++++ .../user/repository/UserRepository.java | 11 ++++- .../user/repository/UserRepositoryImpl.java | 9 ++++ .../user/service/UserService.java | 22 +++++++++ src/main/resources/application-dev.yaml | 6 +-- 11 files changed, 170 insertions(+), 7 deletions(-) create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/config/SecurityConfig.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/user/dto/request/UserDto.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/user/dto/response/UserSimpleResponse.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java diff --git a/src/main/java/org/ioteatime/meonghanyangserver/common/exception/ApiException.java b/src/main/java/org/ioteatime/meonghanyangserver/common/exception/ApiException.java index 22b37c74..3537e58b 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/common/exception/ApiException.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/common/exception/ApiException.java @@ -1,11 +1,11 @@ -package org.team5.interview_partner.common.exception; +package org.ioteatime.meonghanyangserver.common.exception; import lombok.Getter; import org.ioteatime.meonghanyangserver.common.error.TypeCodeIfs; @Getter public class ApiException extends RuntimeException - implements org.team5.interview_partner.common.exception.ApiExceptionItf { + implements org.ioteatime.meonghanyangserver.common.exception.ApiExceptionItf { private final TypeCodeIfs typeCodeIfs; private final String errorDescription; diff --git a/src/main/java/org/ioteatime/meonghanyangserver/common/exception/ApiExceptionItf.java b/src/main/java/org/ioteatime/meonghanyangserver/common/exception/ApiExceptionItf.java index 39817c8e..20ada8cc 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/common/exception/ApiExceptionItf.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/common/exception/ApiExceptionItf.java @@ -1,4 +1,4 @@ -package org.team5.interview_partner.common.exception; +package org.ioteatime.meonghanyangserver.common.exception; import org.ioteatime.meonghanyangserver.common.error.TypeCodeIfs; diff --git a/src/main/java/org/ioteatime/meonghanyangserver/config/SecurityConfig.java b/src/main/java/org/ioteatime/meonghanyangserver/config/SecurityConfig.java new file mode 100644 index 00000000..f363b56d --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/config/SecurityConfig.java @@ -0,0 +1,23 @@ +package org.ioteatime.meonghanyangserver.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.web.SecurityFilterChain; + +@Configuration +@EnableWebSecurity +public class SecurityConfig { + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http.csrf(csrf -> csrf.disable()); // 모든 요청 허용 + http.authorizeHttpRequests((auth)->{ + auth.requestMatchers("/**").permitAll() + .anyRequest() + .authenticated(); + }); + return http.build(); + } +} \ No newline at end of file diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java new file mode 100644 index 00000000..9d603c6b --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java @@ -0,0 +1,22 @@ +package org.ioteatime.meonghanyangserver.user.controller; + +import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.common.api.Api; +import org.ioteatime.meonghanyangserver.user.dto.response.UserSimpleResponse; +import org.ioteatime.meonghanyangserver.user.service.UserService; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/openApi/auth") +public class UserController { + + private final UserService userService; + + // Email 중복 확인 + @GetMapping("/checkEmail/{email}") + public Api duplicateEmail(@PathVariable String email) { + UserSimpleResponse response = userService.userProcess(email); + return Api.OK(response); + } +} \ No newline at end of file diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/domain/UserEntity.java b/src/main/java/org/ioteatime/meonghanyangserver/user/domain/UserEntity.java index ec753692..042d3f95 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/domain/UserEntity.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/domain/UserEntity.java @@ -1,11 +1,13 @@ package org.ioteatime.meonghanyangserver.user.domain; import jakarta.persistence.*; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @Getter @Entity +@Table(name = "base") @NoArgsConstructor public class UserEntity { @Id @@ -22,4 +24,20 @@ public class UserEntity { private String password; @Column private String profileImgUrl; + + @Builder + public UserEntity( + Long id, + String email, + String password, + String nickname, + String profileImgUrl) { + this.id = id; + this.email = email; + this.password = password; + this.nickname = nickname; + this.profileImgUrl = profileImgUrl; + + } + } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/dto/request/UserDto.java b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/request/UserDto.java new file mode 100644 index 00000000..fce16d30 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/request/UserDto.java @@ -0,0 +1,46 @@ +package org.ioteatime.meonghanyangserver.user.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.*; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +public class UserDto { + + @NotBlank(message = "이메일을 입력해주세요.") + @Email(message = "이메일 형식으로 입력해주세요.") + @Schema(description = "사용자의 이메일", example = "test@test.com", requiredMode = Schema.RequiredMode.REQUIRED) + private String email; + + @NotBlank(message = "비밀번호를 입력해주세요.") + @Schema(description = "사용자의 비밀번호", example = "testpassword", requiredMode = Schema.RequiredMode.REQUIRED) + private String password; + + @NotBlank(message = "비밀번호를 확인해주세요.") + @Schema(description = "비밀번호 확인", example = "testpassword", requiredMode = Schema.RequiredMode.REQUIRED) + private String passwordConfirm; + + @NotBlank(message = "닉네임을 입력해주세요.") + @Schema(description = "사용자의 닉네임", example = "mynickname", requiredMode = Schema.RequiredMode.REQUIRED) + private String nickname; + + @Schema(description = "사용자의 프로필 이미지 URL", example = "http://example.com/example.jpg") + private String profileImgUrl; + + @Builder + public UserDto( + String email, + String password, + String passwordConfirm, + String nickname, + String profileImgUrl) { + this.email = email; + this.password = password; + this.passwordConfirm = passwordConfirm; + this.nickname = nickname; + this.profileImgUrl = profileImgUrl; + } +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/dto/response/UserSimpleResponse.java b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/response/UserSimpleResponse.java new file mode 100644 index 00000000..9759e919 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/response/UserSimpleResponse.java @@ -0,0 +1,14 @@ +package org.ioteatime.meonghanyangserver.user.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UserSimpleResponse { + private Long id; + private String email; +// ID랑 Email을 DTO에서 받아 보내줘야함. +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/repository/UserRepository.java b/src/main/java/org/ioteatime/meonghanyangserver/user/repository/UserRepository.java index e59bf71f..f9ea26f0 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/repository/UserRepository.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/repository/UserRepository.java @@ -1,3 +1,12 @@ package org.ioteatime.meonghanyangserver.user.repository; -public interface UserRepository {} +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface UserRepository { + + Optional findByEmail(String email); + +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/repository/UserRepositoryImpl.java b/src/main/java/org/ioteatime/meonghanyangserver/user/repository/UserRepositoryImpl.java index 46a3a476..8c92e188 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/repository/UserRepositoryImpl.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/repository/UserRepositoryImpl.java @@ -1,10 +1,19 @@ package org.ioteatime.meonghanyangserver.user.repository; import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; import org.springframework.stereotype.Repository; +import java.util.Optional; + @Repository @RequiredArgsConstructor public class UserRepositoryImpl implements UserRepository { private final JpaUserRepository jpaUserRepository; + + @Override + public Optional findByEmail(String email) { + return jpaUserRepository.findByEmail(email); + } + } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java b/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java new file mode 100644 index 00000000..e68c5dd7 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java @@ -0,0 +1,22 @@ +package org.ioteatime.meonghanyangserver.user.service; + +import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.common.error.ErrorTypeCode; +import org.ioteatime.meonghanyangserver.common.exception.ApiException; +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; +import org.springframework.stereotype.Service; +import org.ioteatime.meonghanyangserver.user.dto.response.UserSimpleResponse; +import org.ioteatime.meonghanyangserver.user.repository.UserRepository; + +@Service +@RequiredArgsConstructor +public class UserService { + + private final UserRepository userRepository; + + public UserSimpleResponse userProcess(String email) { + UserEntity userEntity = userRepository.findByEmail(email).orElseThrow(()->new ApiException(ErrorTypeCode.NULL_POINT)); + UserSimpleResponse userSimpleResponse = new UserSimpleResponse(userEntity.getId(), userEntity.getEmail()); + return userSimpleResponse; + } +} diff --git a/src/main/resources/application-dev.yaml b/src/main/resources/application-dev.yaml index 42849148..8bdb5aec 100644 --- a/src/main/resources/application-dev.yaml +++ b/src/main/resources/application-dev.yaml @@ -9,14 +9,14 @@ spring: properties: dialect: org.hibernate.dialect.MariaDBDialect hibernate: - ddl-auto: validate + ddl-auto: update default_batch_fetch_size: 100 servlet: multipart: - location: D:\\shieldus\\interviewPartner\\uploads\\ + location: C:\\multipart\\uploads\\ max-file-size: 10MB max-request-size: 10MB token: expiration-time: 86400000 - secret: VisitBBCfortrustedreportingonthelatestworldandUSnewssp + secret: VisitBBCfortrustedreportingonthelatestworldandUSnewssp \ No newline at end of file From 2c82e108b33e1da635fe189ea992053524635a5c Mon Sep 17 00:00:00 2001 From: bestKUFO Date: Fri, 25 Oct 2024 17:54:47 +0900 Subject: [PATCH 02/18] =?UTF-8?q?fix:=20auth=20=EB=B0=8F=20user=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC=20(#22)=20(KAN-75)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/controller/AuthController.java | 15 +++++++++++---- .../auth/dto/request/EmailCheckRequest.java | 10 ++++++++++ .../auth/service/AuthService.java | 11 +++++++++++ .../user/controller/UserController.java | 13 +------------ .../user/dto/request/UserDto.java | 9 +++------ .../user/service/UserService.java | 13 ------------- 6 files changed, 36 insertions(+), 35 deletions(-) create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/auth/dto/request/EmailCheckRequest.java diff --git a/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthController.java b/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthController.java index 690bcd95..236e6445 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthController.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthController.java @@ -2,14 +2,13 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.auth.dto.request.EmailCheckRequest; import org.ioteatime.meonghanyangserver.auth.dto.request.SendEmailRequest; import org.ioteatime.meonghanyangserver.auth.service.AuthService; import org.ioteatime.meonghanyangserver.common.api.Api; import org.ioteatime.meonghanyangserver.user.dto.UserDto; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.ioteatime.meonghanyangserver.user.dto.response.UserSimpleResponse; +import org.springframework.web.bind.annotation.*; @RestController @RequiredArgsConstructor @@ -28,4 +27,12 @@ public Api verifyEmail(@Valid @RequestBody SendEmailRequest sendEmailReq) { authService.send(sendEmailReq.email()); return Api.OK(); } + + // Email 중복 확인 + @PostMapping("/check-email") + public Api duplicateEmail( + @RequestBody EmailCheckRequest emailCheckRequest) { + UserSimpleResponse response = authService.verifyEmail(emailCheckRequest); + return Api.OK(response); + } } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/auth/dto/request/EmailCheckRequest.java b/src/main/java/org/ioteatime/meonghanyangserver/auth/dto/request/EmailCheckRequest.java new file mode 100644 index 00000000..65d0bb72 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/auth/dto/request/EmailCheckRequest.java @@ -0,0 +1,10 @@ +package org.ioteatime.meonghanyangserver.auth.dto.request; + +import jakarta.validation.constraints.NotBlank; +import lombok.Getter; + +@Getter +public class EmailCheckRequest { + + @NotBlank private String email; +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/auth/service/AuthService.java b/src/main/java/org/ioteatime/meonghanyangserver/auth/service/AuthService.java index 7172363d..e2e3a7b5 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/auth/service/AuthService.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/auth/service/AuthService.java @@ -1,7 +1,10 @@ package org.ioteatime.meonghanyangserver.auth.service; import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.auth.dto.request.EmailCheckRequest; import org.ioteatime.meonghanyangserver.clients.google.GoogleMailClient; +import org.ioteatime.meonghanyangserver.common.error.ErrorTypeCode; +import org.ioteatime.meonghanyangserver.common.exception.ApiException; import org.ioteatime.meonghanyangserver.user.domain.UserEntity; import org.ioteatime.meonghanyangserver.user.dto.UserDto; import org.ioteatime.meonghanyangserver.user.dto.response.UserSimpleResponse; @@ -36,4 +39,12 @@ public void send(String email) { // TODO. Redis 적용 후 코드 발급 구현 필요 googleMailClient.sendMail(email, "hello", "world"); } + + public UserSimpleResponse verifyEmail(EmailCheckRequest emailCheckRequest) { + UserEntity userEntity = + userRepository + .findByEmail(emailCheckRequest.getEmail()) + .orElseThrow(() -> new ApiException(ErrorTypeCode.NULL_POINT)); + return new UserSimpleResponse(userEntity.getId(), userEntity.getEmail()); + } } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java index 85767357..78b1342e 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java @@ -3,12 +3,8 @@ import lombok.RequiredArgsConstructor; import org.ioteatime.meonghanyangserver.common.api.Api; import org.ioteatime.meonghanyangserver.user.dto.response.UserDetailResponse; -import org.ioteatime.meonghanyangserver.user.dto.response.UserSimpleResponse; import org.ioteatime.meonghanyangserver.user.service.UserService; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; @RestController @RequiredArgsConstructor @@ -21,11 +17,4 @@ public Api getUserDetail(Long userId) { UserDetailResponse userDto = userService.getUserDetail(userId); return Api.OK(userDto); } - - // Email 중복 확인 - @GetMapping("/checkEmail/{email}") - public Api duplicateEmail(@PathVariable String email) { - UserSimpleResponse response = userService.userProcess(email); - return Api.OK(response); - } } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/dto/request/UserDto.java b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/request/UserDto.java index fec5c28f..fba74147 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/dto/request/UserDto.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/request/UserDto.java @@ -3,10 +3,10 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.*; import lombok.Builder; -import lombok.Data; +import lombok.Getter; import lombok.NoArgsConstructor; -@Data +@Getter @NoArgsConstructor public class UserDto { @@ -33,10 +33,7 @@ public class UserDto { private String passwordConfirm; @NotBlank(message = "닉네임을 입력해주세요.") - @Schema( - description = "사용자의 닉네임", - example = "mynickname", - requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "사용자의 닉네임") private String nickname; @Schema(description = "사용자의 프로필 이미지 URL", example = "http://example.com/example.jpg") diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java b/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java index 65a263a6..113d6353 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java @@ -1,11 +1,8 @@ package org.ioteatime.meonghanyangserver.user.service; import lombok.RequiredArgsConstructor; -import org.ioteatime.meonghanyangserver.common.error.ErrorTypeCode; -import org.ioteatime.meonghanyangserver.common.exception.ApiException; import org.ioteatime.meonghanyangserver.user.domain.UserEntity; import org.ioteatime.meonghanyangserver.user.dto.response.UserDetailResponse; -import org.ioteatime.meonghanyangserver.user.dto.response.UserSimpleResponse; import org.ioteatime.meonghanyangserver.user.repository.UserRepository; import org.springframework.stereotype.Service; @@ -23,14 +20,4 @@ public UserDetailResponse getUserDetail(Long userId) { return UserDetailResponse.from(userEntity); } - - public UserSimpleResponse userProcess(String email) { - UserEntity userEntity = - userRepository - .findByEmail(email) - .orElseThrow(() -> new ApiException(ErrorTypeCode.NULL_POINT)); - UserSimpleResponse userSimpleResponse = - new UserSimpleResponse(userEntity.getId(), userEntity.getEmail()); - return userSimpleResponse; - } } From 0101eaa3d75b9994b97213290b0f2bca0d11e4e6 Mon Sep 17 00:00:00 2001 From: bestKUFO Date: Tue, 29 Oct 2024 10:19:33 +0900 Subject: [PATCH 03/18] =?UTF-8?q?fix:=20=EC=A4=91=EB=B3=B5=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=A0=95=EB=A6=AC=20(#22)=20(KAN-75)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../meonghanyangserver/auth/controller/AuthApi.java | 3 +-- .../auth/controller/AuthController.java | 5 ++--- .../auth/dto/request/EmailCheckRequest.java | 10 ---------- .../meonghanyangserver/auth/service/AuthService.java | 5 ++--- 4 files changed, 5 insertions(+), 18 deletions(-) delete mode 100644 src/main/java/org/ioteatime/meonghanyangserver/auth/dto/request/EmailCheckRequest.java diff --git a/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthApi.java b/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthApi.java index 64836e16..2fe08240 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthApi.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthApi.java @@ -4,7 +4,6 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import org.ioteatime.meonghanyangserver.auth.dto.reponse.LoginResponse; -import org.ioteatime.meonghanyangserver.auth.dto.request.EmailCheckRequest; import org.ioteatime.meonghanyangserver.auth.dto.request.LoginRequest; import org.ioteatime.meonghanyangserver.auth.dto.request.SendEmailRequest; import org.ioteatime.meonghanyangserver.common.api.Api; @@ -24,5 +23,5 @@ public interface AuthApi { Api login(@RequestBody @Valid LoginRequest loginRequest); @Operation(summary = "이메일 중복을 확인 합니다.") - Api duplicateEmail(@RequestBody EmailCheckRequest emailCheckRequest); + Api duplicateEmail(@Valid @RequestBody SendEmailRequest email); } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthController.java b/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthController.java index a0c08c4a..0f4b7cff 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthController.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthController.java @@ -3,7 +3,6 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.ioteatime.meonghanyangserver.auth.dto.reponse.LoginResponse; -import org.ioteatime.meonghanyangserver.auth.dto.request.EmailCheckRequest; import org.ioteatime.meonghanyangserver.auth.dto.request.LoginRequest; import org.ioteatime.meonghanyangserver.auth.dto.request.SendEmailRequest; import org.ioteatime.meonghanyangserver.auth.service.AuthService; @@ -33,8 +32,8 @@ public Api verifyEmail(@Valid @RequestBody SendEmailRequest sendEmailReq) { // Email 중복 확인 @PostMapping("/check-email") public Api duplicateEmail( - @RequestBody EmailCheckRequest emailCheckRequest) { - UserSimpleResponse response = authService.verifyEmail(emailCheckRequest); + @Valid @RequestBody SendEmailRequest sendEmailReq) { + UserSimpleResponse response = authService.verifyEmail(sendEmailReq.email()); return Api.OK(response); } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/auth/dto/request/EmailCheckRequest.java b/src/main/java/org/ioteatime/meonghanyangserver/auth/dto/request/EmailCheckRequest.java deleted file mode 100644 index 65d0bb72..00000000 --- a/src/main/java/org/ioteatime/meonghanyangserver/auth/dto/request/EmailCheckRequest.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.ioteatime.meonghanyangserver.auth.dto.request; - -import jakarta.validation.constraints.NotBlank; -import lombok.Getter; - -@Getter -public class EmailCheckRequest { - - @NotBlank private String email; -} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/auth/service/AuthService.java b/src/main/java/org/ioteatime/meonghanyangserver/auth/service/AuthService.java index a1f0a6c5..74297c55 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/auth/service/AuthService.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/auth/service/AuthService.java @@ -2,7 +2,6 @@ import lombok.RequiredArgsConstructor; import org.ioteatime.meonghanyangserver.auth.dto.reponse.LoginResponse; -import org.ioteatime.meonghanyangserver.auth.dto.request.EmailCheckRequest; import org.ioteatime.meonghanyangserver.auth.dto.request.LoginRequest; import org.ioteatime.meonghanyangserver.clients.google.GoogleMailClient; import org.ioteatime.meonghanyangserver.common.error.ErrorTypeCode; @@ -77,10 +76,10 @@ public void send(String email) { googleMailClient.sendMail(email, "hello", "world"); } - public UserSimpleResponse verifyEmail(EmailCheckRequest emailCheckRequest) { + public UserSimpleResponse verifyEmail(String email) { UserEntity userEntity = userRepository - .findByEmail(emailCheckRequest.getEmail()) + .findByEmail(email) .orElseThrow(() -> new ApiException(ErrorTypeCode.NULL_POINT)); return new UserSimpleResponse(userEntity.getId(), userEntity.getEmail()); } From 4f95d0a580f6903cb1b548e51a5411e8c0f3bb8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=AF=BC=EC=84=9D?= <47300870+seok019283501@users.noreply.github.com> Date: Tue, 29 Oct 2024 10:40:58 +0900 Subject: [PATCH 04/18] =?UTF-8?q?feat:=20group,=20group=20user,=20video,?= =?UTF-8?q?=20cctv=20entity=20=EC=83=9D=EC=84=B1=20(#35)=20(KAN-91)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cctv/domain/CctvEntity.java | 24 ++++++++++++++ .../group/controller/GroupApi.java | 8 +++++ .../group/controller/GroupController.java | 4 +++ .../group/domain/GroupEntity.java | 33 +++++++++++++++++++ .../group/domain/GroupUserEntity.java | 26 +++++++++++++++ .../group/domain/GroupUserId.java | 13 ++++++++ .../group/service/GroupService.java | 4 +++ .../video/entity/VideoEntity.java | 29 ++++++++++++++++ 8 files changed, 141 insertions(+) create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/cctv/domain/CctvEntity.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupApi.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupController.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupEntity.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserEntity.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserId.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupService.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/video/entity/VideoEntity.java diff --git a/src/main/java/org/ioteatime/meonghanyangserver/cctv/domain/CctvEntity.java b/src/main/java/org/ioteatime/meonghanyangserver/cctv/domain/CctvEntity.java new file mode 100644 index 00000000..182cb667 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/cctv/domain/CctvEntity.java @@ -0,0 +1,24 @@ +package org.ioteatime.meonghanyangserver.cctv.domain; + +import jakarta.persistence.*; +import lombok.Data; +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; + +@Data +@Entity +@Table(name = "cctv") +public class CctvEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne + @JoinColumn(name = "group_id", nullable = false) + private GroupEntity group; + + @Column(nullable = false, length = 20) + private String cctvNickname; + + @Column(nullable = false, length = 100) + private String kvsChannelName; +} \ No newline at end of file diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupApi.java b/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupApi.java new file mode 100644 index 00000000..3c4da094 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupApi.java @@ -0,0 +1,8 @@ +package org.ioteatime.meonghanyangserver.group.controller; + +import io.swagger.v3.oas.annotations.tags.Tag; + +@Tag(name = "Group Api", description = "Group 관련 API 목록입니다.") +public interface GroupApi { + +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupController.java b/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupController.java new file mode 100644 index 00000000..58c58abe --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupController.java @@ -0,0 +1,4 @@ +package org.ioteatime.meonghanyangserver.group.controller; + +public class GroupController { +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupEntity.java b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupEntity.java new file mode 100644 index 00000000..99f0094c --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupEntity.java @@ -0,0 +1,33 @@ +package org.ioteatime.meonghanyangserver.group.domain; + +import jakarta.persistence.*; +import lombok.Data; +import org.ioteatime.meonghanyangserver.cctv.domain.CctvEntity; +import org.ioteatime.meonghanyangserver.video.entity.VideoEntity; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +@Entity +@Table(name = "group") +public class GroupEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false, length = 100) + private String groupName; + + @Column(nullable = false) + private LocalDateTime createdAt = LocalDateTime.now(); + + @OneToMany(mappedBy = "group", cascade = CascadeType.ALL) + private List cctvs; + + @OneToMany(mappedBy = "group", cascade = CascadeType.ALL) + private List videos; + + @OneToMany(mappedBy = "group", cascade = CascadeType.ALL) + private List groupUsers; +} \ No newline at end of file diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserEntity.java b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserEntity.java new file mode 100644 index 00000000..5a917a9c --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserEntity.java @@ -0,0 +1,26 @@ +package org.ioteatime.meonghanyangserver.group.domain; + +import jakarta.persistence.*; +import lombok.Data; +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; + +@Data +@Entity +@Table(name = "group_user") +public class GroupUserEntity { + @EmbeddedId + private GroupUserId id; + + @Column(nullable = false, length = 10) + private String role; + + @ManyToOne + @MapsId("groupId") + @JoinColumn(name = "group_id") + private GroupEntity group; + + @ManyToOne + @MapsId("userId") + @JoinColumn(name = "user_id") + private UserEntity user; +} \ No newline at end of file diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserId.java b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserId.java new file mode 100644 index 00000000..a08c4768 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserId.java @@ -0,0 +1,13 @@ +package org.ioteatime.meonghanyangserver.group.domain; + +import jakarta.persistence.Embeddable; +import lombok.Data; + +import java.io.Serializable; + +@Data +@Embeddable +public class GroupUserId implements Serializable { + private Long groupId; + private Long userId; +} \ No newline at end of file diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupService.java b/src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupService.java new file mode 100644 index 00000000..60cb2c8e --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupService.java @@ -0,0 +1,4 @@ +package org.ioteatime.meonghanyangserver.group.service; + +public class GroupService { +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/video/entity/VideoEntity.java b/src/main/java/org/ioteatime/meonghanyangserver/video/entity/VideoEntity.java new file mode 100644 index 00000000..505825b9 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/video/entity/VideoEntity.java @@ -0,0 +1,29 @@ +package org.ioteatime.meonghanyangserver.video.entity; + +import jakarta.persistence.*; +import lombok.Data; +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; + +import java.time.LocalDateTime; + +@Data +@Entity +@Table(name = "video") +public class VideoEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false, length = 50) + private String videoName; + + @ManyToOne + @JoinColumn(name = "group_id", nullable = false) + private GroupEntity group; + + @Column(nullable = false, length = 100) + private String videoPath; + + @Column(nullable = false) + private LocalDateTime createdAt; +} \ No newline at end of file From 243988566f09f2668eed696f6b3960bf77468c8a Mon Sep 17 00:00:00 2001 From: OziinG Date: Tue, 29 Oct 2024 13:22:51 +0900 Subject: [PATCH 05/18] =?UTF-8?q?feat:=20User=20Password=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20=EA=B5=AC=ED=98=84=20(#36)=20(KAN-92)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/controller/UserApi.java | 4 ++++ .../user/controller/UserController.java | 12 ++++++++---- .../user/domain/UserEntity.java | 10 ++++++++++ .../user/service/UserService.java | 17 +++++++++++++++++ 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserApi.java b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserApi.java index 0cef54b9..649eb536 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserApi.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserApi.java @@ -5,6 +5,7 @@ import org.ioteatime.meonghanyangserver.common.api.Api; import org.ioteatime.meonghanyangserver.user.dto.response.UserDetailResponse; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; @Tag(name = "User Api", description = "유저 관련 API 목록입니다.") public interface UserApi { @@ -14,4 +15,7 @@ public interface UserApi { @Operation(summary = "회원 정보를 삭제합니다.") Api deleteUser(@PathVariable("userId") Long userId); + + @Operation(summary = "회원의 비밀번호를 변경합니다.") + Api changeUserPassword(@PathVariable("userId") Long userId, @RequestBody String newPassword); } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java index bd6accc2..a287a9f5 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java @@ -4,10 +4,7 @@ import org.ioteatime.meonghanyangserver.common.api.Api; import org.ioteatime.meonghanyangserver.user.dto.response.UserDetailResponse; import org.ioteatime.meonghanyangserver.user.service.UserService; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; @RestController @RequiredArgsConstructor @@ -26,4 +23,11 @@ public Api deleteUser(Long userId) { userService.deleteUser(userId); return Api.OK(); } + + @PutMapping("/{userId}") + public Api changeUserPassword( + Long userId, String newPassword) { + userService.changeUserPassword(userId, newPassword); + return Api.OK(); + } } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/domain/UserEntity.java b/src/main/java/org/ioteatime/meonghanyangserver/user/domain/UserEntity.java index f2e9adf0..de6de94c 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/domain/UserEntity.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/domain/UserEntity.java @@ -4,6 +4,8 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.ioteatime.meonghanyangserver.common.error.ErrorTypeCode; +import org.ioteatime.meonghanyangserver.common.exception.ApiException; @Getter @Entity @@ -32,4 +34,12 @@ public UserEntity(String nickname, String email, String password, String profile this.password = password; this.profileImgUrl = profileImgUrl; } + + public void setPassword(String encodedPassword) { + if (encodedPassword == null || encodedPassword.isBlank()) { + throw new ApiException( + ErrorTypeCode.BAD_REQUEST, "Password is empty"); + } + this.password = encodedPassword; + } } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java b/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java index 8c65361f..6093abdc 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java @@ -1,9 +1,12 @@ package org.ioteatime.meonghanyangserver.user.service; import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.common.error.ErrorTypeCode; +import org.ioteatime.meonghanyangserver.common.exception.ApiException; import org.ioteatime.meonghanyangserver.user.domain.UserEntity; import org.ioteatime.meonghanyangserver.user.dto.response.UserDetailResponse; import org.ioteatime.meonghanyangserver.user.repository.UserRepository; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; @Service @@ -11,6 +14,7 @@ public class UserService { private final UserRepository userRepository; + private final BCryptPasswordEncoder bCryptPasswordEncoder; public UserDetailResponse getUserDetail(Long userId) { UserEntity userEntity = @@ -24,4 +28,17 @@ public UserDetailResponse getUserDetail(Long userId) { public void deleteUser(Long userId) { userRepository.deleteById(userId); } + + public void changeUserPassword(Long userId, String newPassword) { + UserEntity userEntity = + userRepository + .findById(userId) + .orElseThrow(() -> new ApiException( + ErrorTypeCode.BAD_REQUEST, "User not found")); + + String encodedPassword = bCryptPasswordEncoder.encode(newPassword); + + userEntity.setPassword(encodedPassword); + userRepository.save(userEntity); + } } From 47f8eb5f386dcc8a06bd2621168839e2233e944f Mon Sep 17 00:00:00 2001 From: OziinG Date: Tue, 29 Oct 2024 13:28:33 +0900 Subject: [PATCH 06/18] =?UTF-8?q?fix:=20Spotless=20=EC=A0=81=EC=9A=A9=20(#?= =?UTF-8?q?36)=20(KAN-92)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../meonghanyangserver/user/controller/UserApi.java | 3 ++- .../meonghanyangserver/user/controller/UserController.java | 3 +-- .../meonghanyangserver/user/domain/UserEntity.java | 3 +-- .../meonghanyangserver/user/service/UserService.java | 6 ++++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserApi.java b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserApi.java index 649eb536..00942c7a 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserApi.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserApi.java @@ -17,5 +17,6 @@ public interface UserApi { Api deleteUser(@PathVariable("userId") Long userId); @Operation(summary = "회원의 비밀번호를 변경합니다.") - Api changeUserPassword(@PathVariable("userId") Long userId, @RequestBody String newPassword); + Api changeUserPassword( + @PathVariable("userId") Long userId, @RequestBody String newPassword); } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java index a287a9f5..12a37aa0 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java @@ -25,8 +25,7 @@ public Api deleteUser(Long userId) { } @PutMapping("/{userId}") - public Api changeUserPassword( - Long userId, String newPassword) { + public Api changeUserPassword(Long userId, String newPassword) { userService.changeUserPassword(userId, newPassword); return Api.OK(); } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/domain/UserEntity.java b/src/main/java/org/ioteatime/meonghanyangserver/user/domain/UserEntity.java index de6de94c..2cfe8810 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/domain/UserEntity.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/domain/UserEntity.java @@ -37,8 +37,7 @@ public UserEntity(String nickname, String email, String password, String profile public void setPassword(String encodedPassword) { if (encodedPassword == null || encodedPassword.isBlank()) { - throw new ApiException( - ErrorTypeCode.BAD_REQUEST, "Password is empty"); + throw new ApiException(ErrorTypeCode.BAD_REQUEST, "Password is empty"); } this.password = encodedPassword; } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java b/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java index 6093abdc..2c517c8d 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java @@ -33,8 +33,10 @@ public void changeUserPassword(Long userId, String newPassword) { UserEntity userEntity = userRepository .findById(userId) - .orElseThrow(() -> new ApiException( - ErrorTypeCode.BAD_REQUEST, "User not found")); + .orElseThrow( + () -> + new ApiException( + ErrorTypeCode.BAD_REQUEST, "User not found")); String encodedPassword = bCryptPasswordEncoder.encode(newPassword); From 897670a4b89348e5b92c8abddf0cc5b00349fae5 Mon Sep 17 00:00:00 2001 From: OziinG Date: Tue, 29 Oct 2024 13:36:38 +0900 Subject: [PATCH 07/18] =?UTF-8?q?fix:=20JPA=20Dirty=20check=20Save=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#36)=20(KAN-92)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ioteatime/meonghanyangserver/user/service/UserService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java b/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java index 2c517c8d..700a3803 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java @@ -41,6 +41,5 @@ public void changeUserPassword(Long userId, String newPassword) { String encodedPassword = bCryptPasswordEncoder.encode(newPassword); userEntity.setPassword(encodedPassword); - userRepository.save(userEntity); } } From 7a4d8f4d70eb7d582ad3be192abce372c8c75a9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=AF=BC=EC=84=9D?= <47300870+seok019283501@users.noreply.github.com> Date: Tue, 29 Oct 2024 15:23:33 +0900 Subject: [PATCH 08/18] =?UTF-8?q?feat:=20group=20=EC=83=9D=EC=84=B1=20api?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84=20(#35)=20(KAN-91)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cctv/domain/CctvEntity.java | 2 +- .../common/utils/JwtUtils.java | 2 + .../config/SecurityConfig.java | 16 +++++-- .../group/controller/GroupApi.java | 7 ++- .../group/controller/GroupController.java | 22 +++++++++- .../group/domain/GroupEntity.java | 20 +++++---- .../group/domain/GroupUserEntity.java | 17 +++++--- .../group/domain/GroupUserId.java | 9 ++-- .../group/domain/enums/GroupUserRole.java | 11 +++++ .../dto/response/CreateGroupResponse.java | 5 +++ .../group/mapper/group/GroupEntityMapper.java | 10 +++++ .../mapper/group/GroupResponseMapper.java | 11 +++++ .../groupuser/GroupUserEntityMapper.java | 22 ++++++++++ .../repository/group/GroupRepository.java | 7 +++ .../repository/group/GroupRepositoryImpl.java | 16 +++++++ .../repository/group/JpaGroupRepository.java | 6 +++ .../groupuser/GroupUserRepository.java | 10 +++++ .../groupuser/GroupUserRepositoryImpl.java | 23 ++++++++++ .../groupuser/JpaGroupUserRepository.java | 10 +++++ .../group/service/GroupService.java | 43 +++++++++++++++++++ .../group/service/GroupUserService.java | 29 +++++++++++++ .../user/dto/CustomUserDetail.java | 10 ++--- .../video/entity/VideoEntity.java | 5 +-- 23 files changed, 282 insertions(+), 31 deletions(-) create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/domain/enums/GroupUserRole.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/dto/response/CreateGroupResponse.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/mapper/group/GroupEntityMapper.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/mapper/group/GroupResponseMapper.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/mapper/groupuser/GroupUserEntityMapper.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/GroupRepository.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/GroupRepositoryImpl.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/JpaGroupRepository.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/GroupUserRepository.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/GroupUserRepositoryImpl.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/JpaGroupUserRepository.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupUserService.java diff --git a/src/main/java/org/ioteatime/meonghanyangserver/cctv/domain/CctvEntity.java b/src/main/java/org/ioteatime/meonghanyangserver/cctv/domain/CctvEntity.java index 182cb667..1dad7384 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/cctv/domain/CctvEntity.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/cctv/domain/CctvEntity.java @@ -21,4 +21,4 @@ public class CctvEntity { @Column(nullable = false, length = 100) private String kvsChannelName; -} \ No newline at end of file +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/common/utils/JwtUtils.java b/src/main/java/org/ioteatime/meonghanyangserver/common/utils/JwtUtils.java index 48644bbc..a9950384 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/common/utils/JwtUtils.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/common/utils/JwtUtils.java @@ -33,6 +33,7 @@ public String generateAccessToken(UserEntity userEntity) { String jwtToken = Jwts.builder() .claim("name", userEntity.getNickname()) + .claim("sub", userEntity.getEmail()) .claim("jti", String.valueOf(userEntity.getId())) .claim("role", "ROLE_USER") .claim("iat", nowDate) @@ -49,6 +50,7 @@ public String generateRefreshToken(UserEntity userEntity) { String jwtToken = Jwts.builder() .claim("name", userEntity.getNickname()) + .claim("sub", userEntity.getEmail()) .claim("jti", String.valueOf(userEntity.getId())) .claim("role", "ROLE_USER") .claim("iat", nowDate) diff --git a/src/main/java/org/ioteatime/meonghanyangserver/config/SecurityConfig.java b/src/main/java/org/ioteatime/meonghanyangserver/config/SecurityConfig.java index e28b1df0..5cc5feb9 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/config/SecurityConfig.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/config/SecurityConfig.java @@ -1,5 +1,7 @@ package org.ioteatime.meonghanyangserver.config; +import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.filter.JwtRequestFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -7,10 +9,14 @@ import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration @EnableWebSecurity +@RequiredArgsConstructor public class SecurityConfig { + private final JwtRequestFilter jwtRequestFilter; + @Bean BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); @@ -19,14 +25,18 @@ BCryptPasswordEncoder bCryptPasswordEncoder() { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.csrf(CsrfConfigurer::disable); - http.authorizeHttpRequests( (auth) -> - auth.requestMatchers("/open-api/**", "/swagger-ui/**", "/v3/**", "/error") + auth.requestMatchers( + "/open-api/**", + "/swagger-ui/**", + "/v3/**", + "/error", + "/api/**") .permitAll() .anyRequest() .authenticated()); - + http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class); return http.build(); } } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupApi.java b/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupApi.java index 3c4da094..dccbf7cb 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupApi.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupApi.java @@ -1,8 +1,13 @@ package org.ioteatime.meonghanyangserver.group.controller; +import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import org.ioteatime.meonghanyangserver.common.api.Api; +import org.ioteatime.meonghanyangserver.group.dto.response.CreateGroupResponse; +import org.springframework.security.core.Authentication; @Tag(name = "Group Api", description = "Group 관련 API 목록입니다.") public interface GroupApi { - + @Operation(summary = "그룹을 생성합니다.") + Api createGroup(Authentication authentication); } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupController.java b/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupController.java index 58c58abe..097c32a7 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupController.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupController.java @@ -1,4 +1,24 @@ package org.ioteatime.meonghanyangserver.group.controller; -public class GroupController { +import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.common.api.Api; +import org.ioteatime.meonghanyangserver.group.dto.response.CreateGroupResponse; +import org.ioteatime.meonghanyangserver.group.service.GroupService; +import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/group") +public class GroupController implements GroupApi { + private final GroupService groupService; + + @Override + @PostMapping + public Api createGroup(Authentication authentication) { + CreateGroupResponse createGroupResponse = groupService.createGroup(authentication); + return Api.OK(createGroupResponse); + } } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupEntity.java b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupEntity.java index 99f0094c..b5cd0b89 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupEntity.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupEntity.java @@ -1,16 +1,21 @@ package org.ioteatime.meonghanyangserver.group.domain; import jakarta.persistence.*; +import java.time.LocalDateTime; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import org.ioteatime.meonghanyangserver.cctv.domain.CctvEntity; import org.ioteatime.meonghanyangserver.video.entity.VideoEntity; -import java.time.LocalDateTime; -import java.util.List; - @Data @Entity -@Table(name = "group") +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Table(name = "`group`") public class GroupEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -20,14 +25,11 @@ public class GroupEntity { private String groupName; @Column(nullable = false) - private LocalDateTime createdAt = LocalDateTime.now(); + private LocalDateTime createdAt; @OneToMany(mappedBy = "group", cascade = CascadeType.ALL) private List cctvs; @OneToMany(mappedBy = "group", cascade = CascadeType.ALL) private List videos; - - @OneToMany(mappedBy = "group", cascade = CascadeType.ALL) - private List groupUsers; -} \ No newline at end of file +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserEntity.java b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserEntity.java index 5a917a9c..c00cc67a 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserEntity.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserEntity.java @@ -1,18 +1,25 @@ package org.ioteatime.meonghanyangserver.group.domain; import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; +import org.ioteatime.meonghanyangserver.group.domain.enums.GroupUserRole; import org.ioteatime.meonghanyangserver.user.domain.UserEntity; @Data @Entity @Table(name = "group_user") +@AllArgsConstructor +@NoArgsConstructor +@Builder public class GroupUserEntity { - @EmbeddedId - private GroupUserId id; + @EmbeddedId private GroupUserId id; @Column(nullable = false, length = 10) - private String role; + @Enumerated(value = EnumType.STRING) + private GroupUserRole role; @ManyToOne @MapsId("groupId") @@ -21,6 +28,6 @@ public class GroupUserEntity { @ManyToOne @MapsId("userId") - @JoinColumn(name = "user_id") + @JoinColumn(name = "user_id", unique = true) private UserEntity user; -} \ No newline at end of file +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserId.java b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserId.java index a08c4768..698f5e84 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserId.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserId.java @@ -1,13 +1,16 @@ package org.ioteatime.meonghanyangserver.group.domain; import jakarta.persistence.Embeddable; -import lombok.Data; - import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; @Data @Embeddable +@AllArgsConstructor +@NoArgsConstructor public class GroupUserId implements Serializable { private Long groupId; private Long userId; -} \ No newline at end of file +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/domain/enums/GroupUserRole.java b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/enums/GroupUserRole.java new file mode 100644 index 00000000..8a80ed3c --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/enums/GroupUserRole.java @@ -0,0 +1,11 @@ +package org.ioteatime.meonghanyangserver.group.domain.enums; + +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public enum GroupUserRole { + ROLE_USER("USER"), + ROLE_MASTER("MASTER"); + + private final String description; +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/dto/response/CreateGroupResponse.java b/src/main/java/org/ioteatime/meonghanyangserver/group/dto/response/CreateGroupResponse.java new file mode 100644 index 00000000..aac3864c --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/dto/response/CreateGroupResponse.java @@ -0,0 +1,5 @@ +package org.ioteatime.meonghanyangserver.group.dto.response; + +import java.time.LocalDateTime; + +public record CreateGroupResponse(Long groupId, String groupName, LocalDateTime createdAt) {} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/group/GroupEntityMapper.java b/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/group/GroupEntityMapper.java new file mode 100644 index 00000000..d5b74487 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/group/GroupEntityMapper.java @@ -0,0 +1,10 @@ +package org.ioteatime.meonghanyangserver.group.mapper.group; + +import java.time.LocalDateTime; +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; + +public class GroupEntityMapper { + public static GroupEntity toEntity(String groupName) { + return GroupEntity.builder().groupName(groupName).createdAt(LocalDateTime.now()).build(); + } +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/group/GroupResponseMapper.java b/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/group/GroupResponseMapper.java new file mode 100644 index 00000000..38a46c7d --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/group/GroupResponseMapper.java @@ -0,0 +1,11 @@ +package org.ioteatime.meonghanyangserver.group.mapper.group; + +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; +import org.ioteatime.meonghanyangserver.group.dto.response.CreateGroupResponse; + +public class GroupResponseMapper { + public static CreateGroupResponse toResponse(GroupEntity groupEntity) { + return new CreateGroupResponse( + groupEntity.getId(), groupEntity.getGroupName(), groupEntity.getCreatedAt()); + } +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/groupuser/GroupUserEntityMapper.java b/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/groupuser/GroupUserEntityMapper.java new file mode 100644 index 00000000..7e615951 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/groupuser/GroupUserEntityMapper.java @@ -0,0 +1,22 @@ +package org.ioteatime.meonghanyangserver.group.mapper.groupuser; + +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; +import org.ioteatime.meonghanyangserver.group.domain.GroupUserEntity; +import org.ioteatime.meonghanyangserver.group.domain.GroupUserId; +import org.ioteatime.meonghanyangserver.group.domain.enums.GroupUserRole; +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; + +public class GroupUserEntityMapper { + + // master mapper + public static GroupUserEntity toEntity( + GroupEntity groupEntity, UserEntity userEntity, GroupUserRole groupUserRole) { + return GroupUserEntity.builder() + .id(new GroupUserId(groupEntity.getId(), userEntity.getId())) + .user(userEntity) + .role(groupUserRole) + .group(groupEntity) + .user(userEntity) + .build(); + } +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/GroupRepository.java b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/GroupRepository.java new file mode 100644 index 00000000..871c3f2c --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/GroupRepository.java @@ -0,0 +1,7 @@ +package org.ioteatime.meonghanyangserver.group.repository.group; + +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; + +public interface GroupRepository { + GroupEntity createGroup(GroupEntity groupEntity); +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/GroupRepositoryImpl.java b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/GroupRepositoryImpl.java new file mode 100644 index 00000000..6da5012b --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/GroupRepositoryImpl.java @@ -0,0 +1,16 @@ +package org.ioteatime.meonghanyangserver.group.repository.group; + +import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class GroupRepositoryImpl implements GroupRepository { + private final JpaGroupRepository jpaGroupRepository; + + @Override + public GroupEntity createGroup(GroupEntity groupEntity) { + return jpaGroupRepository.save(groupEntity); + } +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/JpaGroupRepository.java b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/JpaGroupRepository.java new file mode 100644 index 00000000..379a500c --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/JpaGroupRepository.java @@ -0,0 +1,6 @@ +package org.ioteatime.meonghanyangserver.group.repository.group; + +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface JpaGroupRepository extends JpaRepository {} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/GroupUserRepository.java b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/GroupUserRepository.java new file mode 100644 index 00000000..61a3ab08 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/GroupUserRepository.java @@ -0,0 +1,10 @@ +package org.ioteatime.meonghanyangserver.group.repository.groupuser; + +import org.ioteatime.meonghanyangserver.group.domain.GroupUserEntity; +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; + +public interface GroupUserRepository { + GroupUserEntity createGroupUser(GroupUserEntity groupUserEntity); + + boolean findGroupUser(UserEntity userEntity); +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/GroupUserRepositoryImpl.java b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/GroupUserRepositoryImpl.java new file mode 100644 index 00000000..fa79b6f8 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/GroupUserRepositoryImpl.java @@ -0,0 +1,23 @@ +package org.ioteatime.meonghanyangserver.group.repository.groupuser; + +import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.group.domain.GroupUserEntity; +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class GroupUserRepositoryImpl implements GroupUserRepository { + private final JpaGroupUserRepository jpaGroupUserRepository; + + @Override + public GroupUserEntity createGroupUser(GroupUserEntity groupUserEntity) { + return jpaGroupUserRepository.save(groupUserEntity); + } + + @Override + public boolean findGroupUser(UserEntity userEntity) { + boolean groupUser = jpaGroupUserRepository.existsByUser(userEntity); + return groupUser; + } +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/JpaGroupUserRepository.java b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/JpaGroupUserRepository.java new file mode 100644 index 00000000..ad0d23b7 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/JpaGroupUserRepository.java @@ -0,0 +1,10 @@ +package org.ioteatime.meonghanyangserver.group.repository.groupuser; + +import org.ioteatime.meonghanyangserver.group.domain.GroupUserEntity; +import org.ioteatime.meonghanyangserver.group.domain.GroupUserId; +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface JpaGroupUserRepository extends JpaRepository { + boolean existsByUser(UserEntity userEntity); +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupService.java b/src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupService.java index 60cb2c8e..3165fa3c 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupService.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupService.java @@ -1,4 +1,47 @@ package org.ioteatime.meonghanyangserver.group.service; +import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.common.error.ErrorTypeCode; +import org.ioteatime.meonghanyangserver.common.exception.ApiException; +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; +import org.ioteatime.meonghanyangserver.group.domain.enums.GroupUserRole; +import org.ioteatime.meonghanyangserver.group.dto.response.CreateGroupResponse; +import org.ioteatime.meonghanyangserver.group.mapper.group.GroupEntityMapper; +import org.ioteatime.meonghanyangserver.group.mapper.group.GroupResponseMapper; +import org.ioteatime.meonghanyangserver.group.repository.group.GroupRepository; +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; +import org.ioteatime.meonghanyangserver.user.dto.CustomUserDetail; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor public class GroupService { + private final GroupRepository groupRepository; + private final GroupUserService groupUserService; + + // create group + public CreateGroupResponse createGroup(Authentication authentication) { + CustomUserDetail userDetails = (CustomUserDetail) authentication.getPrincipal(); + + UserEntity userEntity = userDetails.getUserEntity(); + + boolean groupUserEntity = groupUserService.findGroupUser(userEntity); + + if (groupUserEntity) { + throw new ApiException(ErrorTypeCode.BAD_REQUEST); + } + + String roomName = userEntity.getNickname() + " 그룹"; + + GroupEntity groupEntity = GroupEntityMapper.toEntity(roomName); + + GroupEntity newGroupEntity = groupRepository.createGroup(groupEntity); + + groupUserService.createGroupUser(newGroupEntity, userEntity, GroupUserRole.ROLE_MASTER); + + CreateGroupResponse createGroupResponse = GroupResponseMapper.toResponse(newGroupEntity); + + return createGroupResponse; + } } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupUserService.java b/src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupUserService.java new file mode 100644 index 00000000..ff66d15d --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupUserService.java @@ -0,0 +1,29 @@ +package org.ioteatime.meonghanyangserver.group.service; + +import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; +import org.ioteatime.meonghanyangserver.group.domain.GroupUserEntity; +import org.ioteatime.meonghanyangserver.group.domain.enums.GroupUserRole; +import org.ioteatime.meonghanyangserver.group.mapper.groupuser.GroupUserEntityMapper; +import org.ioteatime.meonghanyangserver.group.repository.groupuser.GroupUserRepository; +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class GroupUserService { + private final GroupUserRepository groupUserRepository; + + // input user + public void createGroupUser( + GroupEntity groupEntity, UserEntity userEntity, GroupUserRole groupUserRole) { + GroupUserEntity groupUserEntity = + GroupUserEntityMapper.toEntity(groupEntity, userEntity, groupUserRole); + groupUserRepository.createGroupUser(groupUserEntity); + } + + public boolean findGroupUser(UserEntity userEntity) { + boolean groupUser = groupUserRepository.findGroupUser(userEntity); + return groupUser; + } +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/dto/CustomUserDetail.java b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/CustomUserDetail.java index b5f0a225..20e24d13 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/dto/CustomUserDetail.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/CustomUserDetail.java @@ -12,10 +12,10 @@ @Data @RequiredArgsConstructor public class CustomUserDetail implements UserDetails { - private UserEntity usersEntity; + private UserEntity userEntity; - public CustomUserDetail(UserEntity usersEntity) { - this.usersEntity = usersEntity; + public CustomUserDetail(UserEntity userEntity) { + this.userEntity = userEntity; } @Override @@ -25,11 +25,11 @@ public Collection getAuthorities() { @Override public String getPassword() { - return usersEntity.getPassword(); + return userEntity.getPassword(); } @Override public String getUsername() { - return usersEntity.getEmail(); + return userEntity.getEmail(); } } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/video/entity/VideoEntity.java b/src/main/java/org/ioteatime/meonghanyangserver/video/entity/VideoEntity.java index 505825b9..8316ff27 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/video/entity/VideoEntity.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/video/entity/VideoEntity.java @@ -1,11 +1,10 @@ package org.ioteatime.meonghanyangserver.video.entity; import jakarta.persistence.*; +import java.time.LocalDateTime; import lombok.Data; import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; -import java.time.LocalDateTime; - @Data @Entity @Table(name = "video") @@ -26,4 +25,4 @@ public class VideoEntity { @Column(nullable = false) private LocalDateTime createdAt; -} \ No newline at end of file +} From 65c53febd6c201040ebb52a975165423be141fa1 Mon Sep 17 00:00:00 2001 From: OziinG Date: Tue, 29 Oct 2024 15:26:02 +0900 Subject: [PATCH 09/18] =?UTF-8?q?refector:=20jwt=20=EA=B8=B0=EB=B0=98=20Us?= =?UTF-8?q?er=20identify=20(#36)=20(KAN-92)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/utils/JwtUtils.java | 2 ++ .../config/SecurityConfig.java | 15 +++++++++++++-- .../user/controller/UserApi.java | 5 ++++- .../user/controller/UserController.java | 17 ++++++++++++++--- .../user/dto/CustomUserDetail.java | 10 +++++----- .../user/service/UserService.java | 11 ++++++++--- 6 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/ioteatime/meonghanyangserver/common/utils/JwtUtils.java b/src/main/java/org/ioteatime/meonghanyangserver/common/utils/JwtUtils.java index 48644bbc..a9950384 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/common/utils/JwtUtils.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/common/utils/JwtUtils.java @@ -33,6 +33,7 @@ public String generateAccessToken(UserEntity userEntity) { String jwtToken = Jwts.builder() .claim("name", userEntity.getNickname()) + .claim("sub", userEntity.getEmail()) .claim("jti", String.valueOf(userEntity.getId())) .claim("role", "ROLE_USER") .claim("iat", nowDate) @@ -49,6 +50,7 @@ public String generateRefreshToken(UserEntity userEntity) { String jwtToken = Jwts.builder() .claim("name", userEntity.getNickname()) + .claim("sub", userEntity.getEmail()) .claim("jti", String.valueOf(userEntity.getId())) .claim("role", "ROLE_USER") .claim("iat", nowDate) diff --git a/src/main/java/org/ioteatime/meonghanyangserver/config/SecurityConfig.java b/src/main/java/org/ioteatime/meonghanyangserver/config/SecurityConfig.java index e28b1df0..60eb66ea 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/config/SecurityConfig.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/config/SecurityConfig.java @@ -1,5 +1,7 @@ package org.ioteatime.meonghanyangserver.config; +import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.filter.JwtRequestFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -7,10 +9,14 @@ import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration @EnableWebSecurity +@RequiredArgsConstructor public class SecurityConfig { + private final JwtRequestFilter jwtRequestFilter; + @Bean BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); @@ -22,11 +28,16 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests( (auth) -> - auth.requestMatchers("/open-api/**", "/swagger-ui/**", "/v3/**", "/error") + auth.requestMatchers( + "/open-api/**", + "/swagger-ui/**", + "/v3/**", + "/error", + "/api/**") .permitAll() .anyRequest() .authenticated()); - + http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class); return http.build(); } } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserApi.java b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserApi.java index 00942c7a..53be25a9 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserApi.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserApi.java @@ -2,8 +2,11 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import org.ioteatime.meonghanyangserver.common.api.Api; +import org.ioteatime.meonghanyangserver.user.dto.request.ChangePasswordRequest; import org.ioteatime.meonghanyangserver.user.dto.response.UserDetailResponse; +import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; @@ -18,5 +21,5 @@ public interface UserApi { @Operation(summary = "회원의 비밀번호를 변경합니다.") Api changeUserPassword( - @PathVariable("userId") Long userId, @RequestBody String newPassword); + Authentication authentication, @RequestBody @Valid ChangePasswordRequest request); } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java index 12a37aa0..4981b73e 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java @@ -1,9 +1,13 @@ package org.ioteatime.meonghanyangserver.user.controller; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.ioteatime.meonghanyangserver.common.api.Api; +import org.ioteatime.meonghanyangserver.user.dto.CustomUserDetail; +import org.ioteatime.meonghanyangserver.user.dto.request.ChangePasswordRequest; import org.ioteatime.meonghanyangserver.user.dto.response.UserDetailResponse; import org.ioteatime.meonghanyangserver.user.service.UserService; +import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.*; @RestController @@ -24,9 +28,16 @@ public Api deleteUser(Long userId) { return Api.OK(); } - @PutMapping("/{userId}") - public Api changeUserPassword(Long userId, String newPassword) { - userService.changeUserPassword(userId, newPassword); + @PutMapping("/password") + public Api changeUserPassword( + Authentication authentication, @RequestBody @Valid ChangePasswordRequest request) { + + CustomUserDetail userDetails = (CustomUserDetail) authentication.getPrincipal(); + Long userId = userDetails.getUserEntity().getId(); + + userService.changeUserPassword( + userId, request.getCurrentPassword(), request.getNewPassword()); + return Api.OK(); } } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/dto/CustomUserDetail.java b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/CustomUserDetail.java index b5f0a225..20e24d13 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/dto/CustomUserDetail.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/CustomUserDetail.java @@ -12,10 +12,10 @@ @Data @RequiredArgsConstructor public class CustomUserDetail implements UserDetails { - private UserEntity usersEntity; + private UserEntity userEntity; - public CustomUserDetail(UserEntity usersEntity) { - this.usersEntity = usersEntity; + public CustomUserDetail(UserEntity userEntity) { + this.userEntity = userEntity; } @Override @@ -25,11 +25,11 @@ public Collection getAuthorities() { @Override public String getPassword() { - return usersEntity.getPassword(); + return userEntity.getPassword(); } @Override public String getUsername() { - return usersEntity.getEmail(); + return userEntity.getEmail(); } } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java b/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java index 700a3803..825eda80 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java @@ -8,6 +8,7 @@ import org.ioteatime.meonghanyangserver.user.repository.UserRepository; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @Service @RequiredArgsConstructor @@ -29,7 +30,8 @@ public void deleteUser(Long userId) { userRepository.deleteById(userId); } - public void changeUserPassword(Long userId, String newPassword) { + @Transactional + public void changeUserPassword(Long userId, String currentPassword, String newPassword) { UserEntity userEntity = userRepository .findById(userId) @@ -38,8 +40,11 @@ public void changeUserPassword(Long userId, String newPassword) { new ApiException( ErrorTypeCode.BAD_REQUEST, "User not found")); - String encodedPassword = bCryptPasswordEncoder.encode(newPassword); + if (!bCryptPasswordEncoder.matches(currentPassword, userEntity.getPassword())) { + throw new ApiException(ErrorTypeCode.BAD_REQUEST, "현재 비밀번호가 일치하지 않습니다."); + } - userEntity.setPassword(encodedPassword); + // Dirty-Checking Password Change + userEntity.setPassword(bCryptPasswordEncoder.encode(newPassword)); } } From 66c22af2119eb0959b1270a8ae9421d3834889bb Mon Sep 17 00:00:00 2001 From: OziinG Date: Tue, 29 Oct 2024 15:27:57 +0900 Subject: [PATCH 10/18] =?UTF-8?q?feat:=20Password=20validation=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20(#36)=20(KAN-92)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/request/ChangePasswordRequest.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/user/dto/request/ChangePasswordRequest.java diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/dto/request/ChangePasswordRequest.java b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/request/ChangePasswordRequest.java new file mode 100644 index 00000000..e3373c41 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/request/ChangePasswordRequest.java @@ -0,0 +1,18 @@ +package org.ioteatime.meonghanyangserver.user.dto.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +public class ChangePasswordRequest { + + @NotBlank(message = "현재 비밀번호는 필수 입력값") + private String currentPassword; + + @NotBlank(message = "새 비밀번호는 필수 입력값") + @Size(min = 8, max = 20, message = "비밀번호는 8자 이상 20자 이하여야 합니다.") + private String newPassword; +} From b9962d11cab6522e557ca4dbfb16b79863fddfd0 Mon Sep 17 00:00:00 2001 From: OziinG Date: Tue, 29 Oct 2024 15:44:40 +0900 Subject: [PATCH 11/18] =?UTF-8?q?refactor:=20Controller,=20Service=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC=20(#36)=20(KAN-92)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/controller/UserController.java | 7 +------ .../meonghanyangserver/user/service/UserService.java | 10 +++++++++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java index 4981b73e..6331d7ca 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java @@ -3,7 +3,6 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.ioteatime.meonghanyangserver.common.api.Api; -import org.ioteatime.meonghanyangserver.user.dto.CustomUserDetail; import org.ioteatime.meonghanyangserver.user.dto.request.ChangePasswordRequest; import org.ioteatime.meonghanyangserver.user.dto.response.UserDetailResponse; import org.ioteatime.meonghanyangserver.user.service.UserService; @@ -32,11 +31,7 @@ public Api deleteUser(Long userId) { public Api changeUserPassword( Authentication authentication, @RequestBody @Valid ChangePasswordRequest request) { - CustomUserDetail userDetails = (CustomUserDetail) authentication.getPrincipal(); - Long userId = userDetails.getUserEntity().getId(); - - userService.changeUserPassword( - userId, request.getCurrentPassword(), request.getNewPassword()); + userService.changeUserPassword(authentication, request); return Api.OK(); } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java b/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java index 825eda80..59e5a94a 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java @@ -4,8 +4,11 @@ import org.ioteatime.meonghanyangserver.common.error.ErrorTypeCode; import org.ioteatime.meonghanyangserver.common.exception.ApiException; import org.ioteatime.meonghanyangserver.user.domain.UserEntity; +import org.ioteatime.meonghanyangserver.user.dto.CustomUserDetail; +import org.ioteatime.meonghanyangserver.user.dto.request.ChangePasswordRequest; import org.ioteatime.meonghanyangserver.user.dto.response.UserDetailResponse; import org.ioteatime.meonghanyangserver.user.repository.UserRepository; +import org.springframework.security.core.Authentication; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -31,7 +34,12 @@ public void deleteUser(Long userId) { } @Transactional - public void changeUserPassword(Long userId, String currentPassword, String newPassword) { + public void changeUserPassword(Authentication authentication, ChangePasswordRequest request) { + String currentPassword = request.getCurrentPassword(); + String newPassword = request.getNewPassword(); + CustomUserDetail userDetails = (CustomUserDetail) authentication.getPrincipal(); + Long userId = userDetails.getUserEntity().getId(); + UserEntity userEntity = userRepository .findById(userId) From c00040b180da5b693687d297088c3f70b1d6aec5 Mon Sep 17 00:00:00 2001 From: bestKUFO Date: Tue, 29 Oct 2024 17:43:25 +0900 Subject: [PATCH 12/18] =?UTF-8?q?fix:=20conflict=20=ED=95=B4=EA=B2=B0=20(#?= =?UTF-8?q?22)=20(KAN-75)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix: group conflict 해결 (#22) (KAN-75) --- .../auth/controller/AuthApi.java | 11 +++-- .../auth/controller/AuthController.java | 19 +++++--- .../auth/dto/reponse/RefreshResponse.java | 14 ++++++ ...endEmailRequest.java => EmailRequest.java} | 2 +- .../auth/service/AuthService.java | 37 ++++++++++++++- .../cctv/domain/CctvEntity.java | 24 ++++++++++ .../common/utils/JwtUtils.java | 2 + .../config/SecurityConfig.java | 16 +++++-- .../group/controller/GroupApi.java | 13 +++++ .../group/controller/GroupController.java | 24 ++++++++++ .../group/domain/GroupEntity.java | 35 ++++++++++++++ .../group/domain/GroupUserEntity.java | 33 +++++++++++++ .../group/domain/GroupUserId.java | 16 +++++++ .../group/domain/enums/GroupUserRole.java | 11 +++++ .../dto/response/CreateGroupResponse.java | 5 ++ .../group/mapper/group/GroupEntityMapper.java | 10 ++++ .../mapper/group/GroupResponseMapper.java | 11 +++++ .../groupuser/GroupUserEntityMapper.java | 22 +++++++++ .../repository/group/GroupRepository.java | 7 +++ .../repository/group/GroupRepositoryImpl.java | 16 +++++++ .../repository/group/JpaGroupRepository.java | 6 +++ .../groupuser/GroupUserRepository.java | 10 ++++ .../groupuser/GroupUserRepositoryImpl.java | 23 +++++++++ .../groupuser/JpaGroupUserRepository.java | 10 ++++ .../group/service/GroupService.java | 47 +++++++++++++++++++ .../group/service/GroupUserService.java | 29 ++++++++++++ .../redis/RefreshTokenRepository.java | 5 +- .../user/dto/CustomUserDetail.java | 10 ++-- .../user/dto/request/UserDto.java | 15 ++---- .../user/dto/response/UserSimpleResponse.java | 8 +++- .../video/entity/VideoEntity.java | 28 +++++++++++ 31 files changed, 486 insertions(+), 33 deletions(-) create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/auth/dto/reponse/RefreshResponse.java rename src/main/java/org/ioteatime/meonghanyangserver/auth/dto/request/{SendEmailRequest.java => EmailRequest.java} (91%) create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/cctv/domain/CctvEntity.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupApi.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupController.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupEntity.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserEntity.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserId.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/domain/enums/GroupUserRole.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/dto/response/CreateGroupResponse.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/mapper/group/GroupEntityMapper.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/mapper/group/GroupResponseMapper.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/mapper/groupuser/GroupUserEntityMapper.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/GroupRepository.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/GroupRepositoryImpl.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/JpaGroupRepository.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/GroupUserRepository.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/GroupUserRepositoryImpl.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/JpaGroupUserRepository.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupService.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupUserService.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/video/entity/VideoEntity.java diff --git a/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthApi.java b/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthApi.java index 2fe08240..05a964f8 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthApi.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthApi.java @@ -4,12 +4,14 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import org.ioteatime.meonghanyangserver.auth.dto.reponse.LoginResponse; +import org.ioteatime.meonghanyangserver.auth.dto.reponse.RefreshResponse; +import org.ioteatime.meonghanyangserver.auth.dto.request.EmailRequest; import org.ioteatime.meonghanyangserver.auth.dto.request.LoginRequest; -import org.ioteatime.meonghanyangserver.auth.dto.request.SendEmailRequest; import org.ioteatime.meonghanyangserver.common.api.Api; import org.ioteatime.meonghanyangserver.user.dto.UserDto; import org.ioteatime.meonghanyangserver.user.dto.response.UserSimpleResponse; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; @Tag(name = "Auth Api", description = "인증 관련 API 목록입니다.") public interface AuthApi { @@ -17,11 +19,14 @@ public interface AuthApi { Api registerUser(@Valid @RequestBody UserDto userDto); @Operation(summary = "인증 메일 전송") - Api verifyEmail(@Valid @RequestBody SendEmailRequest email); + Api verifyEmail(@Valid @RequestBody EmailRequest email); @Operation(summary = "로그인을 합니다.") Api login(@RequestBody @Valid LoginRequest loginRequest); @Operation(summary = "이메일 중복을 확인 합니다.") - Api duplicateEmail(@Valid @RequestBody SendEmailRequest email); + Api duplicateEmail(@Valid @RequestBody EmailRequest email); + + @Operation(summary = "토큰을 다시 생성합니다.") + Api refreshToken(@RequestHeader("Authorization") String authorizationHeader); } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthController.java b/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthController.java index 0f4b7cff..17aad109 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthController.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthController.java @@ -3,8 +3,9 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.ioteatime.meonghanyangserver.auth.dto.reponse.LoginResponse; +import org.ioteatime.meonghanyangserver.auth.dto.reponse.RefreshResponse; +import org.ioteatime.meonghanyangserver.auth.dto.request.EmailRequest; import org.ioteatime.meonghanyangserver.auth.dto.request.LoginRequest; -import org.ioteatime.meonghanyangserver.auth.dto.request.SendEmailRequest; import org.ioteatime.meonghanyangserver.auth.service.AuthService; import org.ioteatime.meonghanyangserver.common.api.Api; import org.ioteatime.meonghanyangserver.user.dto.UserDto; @@ -24,16 +25,15 @@ public Api registerUser(@Valid @RequestBody UserDto userDto) { } @PostMapping("/email-verification") - public Api verifyEmail(@Valid @RequestBody SendEmailRequest sendEmailReq) { - authService.send(sendEmailReq.email()); + public Api verifyEmail(@Valid @RequestBody EmailRequest emailReq) { + authService.send(emailReq.email()); return Api.OK(); } // Email 중복 확인 @PostMapping("/check-email") - public Api duplicateEmail( - @Valid @RequestBody SendEmailRequest sendEmailReq) { - UserSimpleResponse response = authService.verifyEmail(sendEmailReq.email()); + public Api duplicateEmail(@Valid @RequestBody EmailRequest emailReq) { + UserSimpleResponse response = authService.verifyEmail(emailReq.email()); return Api.OK(response); } @@ -43,4 +43,11 @@ public Api login(LoginRequest loginRequest) { LoginResponse loginResponse = authService.login(loginRequest); return Api.CREATE(loginResponse); } + + @PostMapping("/refresh-token") + public Api refreshToken( + @RequestHeader("Authorization") String authorizationHeader) { + RefreshResponse refreshResponse = authService.reissueAccessToken(authorizationHeader); + return Api.OK(refreshResponse); + } } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/auth/dto/reponse/RefreshResponse.java b/src/main/java/org/ioteatime/meonghanyangserver/auth/dto/reponse/RefreshResponse.java new file mode 100644 index 00000000..71d170d6 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/auth/dto/reponse/RefreshResponse.java @@ -0,0 +1,14 @@ +package org.ioteatime.meonghanyangserver.auth.dto.reponse; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@Builder +@AllArgsConstructor +public class RefreshResponse { + private String accessToken; +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/auth/dto/request/SendEmailRequest.java b/src/main/java/org/ioteatime/meonghanyangserver/auth/dto/request/EmailRequest.java similarity index 91% rename from src/main/java/org/ioteatime/meonghanyangserver/auth/dto/request/SendEmailRequest.java rename to src/main/java/org/ioteatime/meonghanyangserver/auth/dto/request/EmailRequest.java index 16bfebdf..39d8c8a8 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/auth/dto/request/SendEmailRequest.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/auth/dto/request/EmailRequest.java @@ -5,6 +5,6 @@ import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotNull; -public record SendEmailRequest( +public record EmailRequest( @Valid @Email @NotNull @Schema(description = "이메일", example = "example@gmail.com") String email) {} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/auth/service/AuthService.java b/src/main/java/org/ioteatime/meonghanyangserver/auth/service/AuthService.java index 74297c55..fdf049eb 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/auth/service/AuthService.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/auth/service/AuthService.java @@ -2,6 +2,7 @@ import lombok.RequiredArgsConstructor; import org.ioteatime.meonghanyangserver.auth.dto.reponse.LoginResponse; +import org.ioteatime.meonghanyangserver.auth.dto.reponse.RefreshResponse; import org.ioteatime.meonghanyangserver.auth.dto.request.LoginRequest; import org.ioteatime.meonghanyangserver.clients.google.GoogleMailClient; import org.ioteatime.meonghanyangserver.common.error.ErrorTypeCode; @@ -81,6 +82,40 @@ public UserSimpleResponse verifyEmail(String email) { userRepository .findByEmail(email) .orElseThrow(() -> new ApiException(ErrorTypeCode.NULL_POINT)); - return new UserSimpleResponse(userEntity.getId(), userEntity.getEmail()); + return UserSimpleResponse.from(userEntity); + } + + public RefreshResponse reissueAccessToken(String authorizationHeader) { + String refreshToken = authorizationHeader.replace("Bearer ", ""); + + RefreshToken storedToken = + refreshTokenRepository + .findByRefreshToken(refreshToken) + .orElseThrow( + () -> + new ApiException( + ErrorTypeCode.BAD_REQUEST, + "유효하지 않은 Refresh token입니다.")); + + if (!storedToken.getRefreshToken().equals(refreshToken)) { + throw new ApiException(ErrorTypeCode.BAD_REQUEST, "토큰이 일치하지 않습니다."); + } + + String email = jwtUtils.getSubjectFromToken(refreshToken); + UserEntity userEntity = + userRepository + .findByEmail(email) + .orElseThrow( + () -> + new ApiException( + ErrorTypeCode.BAD_REQUEST, "유효하지 않은 사용자입니다.")); + + if (!jwtUtils.validateToken(refreshToken, userEntity)) { + throw new ApiException(ErrorTypeCode.BAD_REQUEST, "Refresh token이 만료되었습니다."); + } + + String newAccessToken = jwtUtils.generateAccessToken(userEntity); + + return new RefreshResponse(newAccessToken); } } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/cctv/domain/CctvEntity.java b/src/main/java/org/ioteatime/meonghanyangserver/cctv/domain/CctvEntity.java new file mode 100644 index 00000000..1dad7384 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/cctv/domain/CctvEntity.java @@ -0,0 +1,24 @@ +package org.ioteatime.meonghanyangserver.cctv.domain; + +import jakarta.persistence.*; +import lombok.Data; +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; + +@Data +@Entity +@Table(name = "cctv") +public class CctvEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne + @JoinColumn(name = "group_id", nullable = false) + private GroupEntity group; + + @Column(nullable = false, length = 20) + private String cctvNickname; + + @Column(nullable = false, length = 100) + private String kvsChannelName; +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/common/utils/JwtUtils.java b/src/main/java/org/ioteatime/meonghanyangserver/common/utils/JwtUtils.java index 48644bbc..a9950384 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/common/utils/JwtUtils.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/common/utils/JwtUtils.java @@ -33,6 +33,7 @@ public String generateAccessToken(UserEntity userEntity) { String jwtToken = Jwts.builder() .claim("name", userEntity.getNickname()) + .claim("sub", userEntity.getEmail()) .claim("jti", String.valueOf(userEntity.getId())) .claim("role", "ROLE_USER") .claim("iat", nowDate) @@ -49,6 +50,7 @@ public String generateRefreshToken(UserEntity userEntity) { String jwtToken = Jwts.builder() .claim("name", userEntity.getNickname()) + .claim("sub", userEntity.getEmail()) .claim("jti", String.valueOf(userEntity.getId())) .claim("role", "ROLE_USER") .claim("iat", nowDate) diff --git a/src/main/java/org/ioteatime/meonghanyangserver/config/SecurityConfig.java b/src/main/java/org/ioteatime/meonghanyangserver/config/SecurityConfig.java index e28b1df0..5cc5feb9 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/config/SecurityConfig.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/config/SecurityConfig.java @@ -1,5 +1,7 @@ package org.ioteatime.meonghanyangserver.config; +import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.filter.JwtRequestFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -7,10 +9,14 @@ import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration @EnableWebSecurity +@RequiredArgsConstructor public class SecurityConfig { + private final JwtRequestFilter jwtRequestFilter; + @Bean BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); @@ -19,14 +25,18 @@ BCryptPasswordEncoder bCryptPasswordEncoder() { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.csrf(CsrfConfigurer::disable); - http.authorizeHttpRequests( (auth) -> - auth.requestMatchers("/open-api/**", "/swagger-ui/**", "/v3/**", "/error") + auth.requestMatchers( + "/open-api/**", + "/swagger-ui/**", + "/v3/**", + "/error", + "/api/**") .permitAll() .anyRequest() .authenticated()); - + http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class); return http.build(); } } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupApi.java b/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupApi.java new file mode 100644 index 00000000..dccbf7cb --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupApi.java @@ -0,0 +1,13 @@ +package org.ioteatime.meonghanyangserver.group.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.ioteatime.meonghanyangserver.common.api.Api; +import org.ioteatime.meonghanyangserver.group.dto.response.CreateGroupResponse; +import org.springframework.security.core.Authentication; + +@Tag(name = "Group Api", description = "Group 관련 API 목록입니다.") +public interface GroupApi { + @Operation(summary = "그룹을 생성합니다.") + Api createGroup(Authentication authentication); +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupController.java b/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupController.java new file mode 100644 index 00000000..097c32a7 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupController.java @@ -0,0 +1,24 @@ +package org.ioteatime.meonghanyangserver.group.controller; + +import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.common.api.Api; +import org.ioteatime.meonghanyangserver.group.dto.response.CreateGroupResponse; +import org.ioteatime.meonghanyangserver.group.service.GroupService; +import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/group") +public class GroupController implements GroupApi { + private final GroupService groupService; + + @Override + @PostMapping + public Api createGroup(Authentication authentication) { + CreateGroupResponse createGroupResponse = groupService.createGroup(authentication); + return Api.OK(createGroupResponse); + } +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupEntity.java b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupEntity.java new file mode 100644 index 00000000..b5cd0b89 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupEntity.java @@ -0,0 +1,35 @@ +package org.ioteatime.meonghanyangserver.group.domain; + +import jakarta.persistence.*; +import java.time.LocalDateTime; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.ioteatime.meonghanyangserver.cctv.domain.CctvEntity; +import org.ioteatime.meonghanyangserver.video.entity.VideoEntity; + +@Data +@Entity +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Table(name = "`group`") +public class GroupEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false, length = 100) + private String groupName; + + @Column(nullable = false) + private LocalDateTime createdAt; + + @OneToMany(mappedBy = "group", cascade = CascadeType.ALL) + private List cctvs; + + @OneToMany(mappedBy = "group", cascade = CascadeType.ALL) + private List videos; +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserEntity.java b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserEntity.java new file mode 100644 index 00000000..c00cc67a --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserEntity.java @@ -0,0 +1,33 @@ +package org.ioteatime.meonghanyangserver.group.domain; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.ioteatime.meonghanyangserver.group.domain.enums.GroupUserRole; +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; + +@Data +@Entity +@Table(name = "group_user") +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class GroupUserEntity { + @EmbeddedId private GroupUserId id; + + @Column(nullable = false, length = 10) + @Enumerated(value = EnumType.STRING) + private GroupUserRole role; + + @ManyToOne + @MapsId("groupId") + @JoinColumn(name = "group_id") + private GroupEntity group; + + @ManyToOne + @MapsId("userId") + @JoinColumn(name = "user_id", unique = true) + private UserEntity user; +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserId.java b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserId.java new file mode 100644 index 00000000..698f5e84 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserId.java @@ -0,0 +1,16 @@ +package org.ioteatime.meonghanyangserver.group.domain; + +import jakarta.persistence.Embeddable; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Embeddable +@AllArgsConstructor +@NoArgsConstructor +public class GroupUserId implements Serializable { + private Long groupId; + private Long userId; +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/domain/enums/GroupUserRole.java b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/enums/GroupUserRole.java new file mode 100644 index 00000000..8a80ed3c --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/enums/GroupUserRole.java @@ -0,0 +1,11 @@ +package org.ioteatime.meonghanyangserver.group.domain.enums; + +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public enum GroupUserRole { + ROLE_USER("USER"), + ROLE_MASTER("MASTER"); + + private final String description; +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/dto/response/CreateGroupResponse.java b/src/main/java/org/ioteatime/meonghanyangserver/group/dto/response/CreateGroupResponse.java new file mode 100644 index 00000000..aac3864c --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/dto/response/CreateGroupResponse.java @@ -0,0 +1,5 @@ +package org.ioteatime.meonghanyangserver.group.dto.response; + +import java.time.LocalDateTime; + +public record CreateGroupResponse(Long groupId, String groupName, LocalDateTime createdAt) {} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/group/GroupEntityMapper.java b/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/group/GroupEntityMapper.java new file mode 100644 index 00000000..d5b74487 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/group/GroupEntityMapper.java @@ -0,0 +1,10 @@ +package org.ioteatime.meonghanyangserver.group.mapper.group; + +import java.time.LocalDateTime; +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; + +public class GroupEntityMapper { + public static GroupEntity toEntity(String groupName) { + return GroupEntity.builder().groupName(groupName).createdAt(LocalDateTime.now()).build(); + } +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/group/GroupResponseMapper.java b/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/group/GroupResponseMapper.java new file mode 100644 index 00000000..38a46c7d --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/group/GroupResponseMapper.java @@ -0,0 +1,11 @@ +package org.ioteatime.meonghanyangserver.group.mapper.group; + +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; +import org.ioteatime.meonghanyangserver.group.dto.response.CreateGroupResponse; + +public class GroupResponseMapper { + public static CreateGroupResponse toResponse(GroupEntity groupEntity) { + return new CreateGroupResponse( + groupEntity.getId(), groupEntity.getGroupName(), groupEntity.getCreatedAt()); + } +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/groupuser/GroupUserEntityMapper.java b/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/groupuser/GroupUserEntityMapper.java new file mode 100644 index 00000000..7e615951 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/groupuser/GroupUserEntityMapper.java @@ -0,0 +1,22 @@ +package org.ioteatime.meonghanyangserver.group.mapper.groupuser; + +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; +import org.ioteatime.meonghanyangserver.group.domain.GroupUserEntity; +import org.ioteatime.meonghanyangserver.group.domain.GroupUserId; +import org.ioteatime.meonghanyangserver.group.domain.enums.GroupUserRole; +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; + +public class GroupUserEntityMapper { + + // master mapper + public static GroupUserEntity toEntity( + GroupEntity groupEntity, UserEntity userEntity, GroupUserRole groupUserRole) { + return GroupUserEntity.builder() + .id(new GroupUserId(groupEntity.getId(), userEntity.getId())) + .user(userEntity) + .role(groupUserRole) + .group(groupEntity) + .user(userEntity) + .build(); + } +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/GroupRepository.java b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/GroupRepository.java new file mode 100644 index 00000000..871c3f2c --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/GroupRepository.java @@ -0,0 +1,7 @@ +package org.ioteatime.meonghanyangserver.group.repository.group; + +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; + +public interface GroupRepository { + GroupEntity createGroup(GroupEntity groupEntity); +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/GroupRepositoryImpl.java b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/GroupRepositoryImpl.java new file mode 100644 index 00000000..6da5012b --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/GroupRepositoryImpl.java @@ -0,0 +1,16 @@ +package org.ioteatime.meonghanyangserver.group.repository.group; + +import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class GroupRepositoryImpl implements GroupRepository { + private final JpaGroupRepository jpaGroupRepository; + + @Override + public GroupEntity createGroup(GroupEntity groupEntity) { + return jpaGroupRepository.save(groupEntity); + } +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/JpaGroupRepository.java b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/JpaGroupRepository.java new file mode 100644 index 00000000..379a500c --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/JpaGroupRepository.java @@ -0,0 +1,6 @@ +package org.ioteatime.meonghanyangserver.group.repository.group; + +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface JpaGroupRepository extends JpaRepository {} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/GroupUserRepository.java b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/GroupUserRepository.java new file mode 100644 index 00000000..61a3ab08 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/GroupUserRepository.java @@ -0,0 +1,10 @@ +package org.ioteatime.meonghanyangserver.group.repository.groupuser; + +import org.ioteatime.meonghanyangserver.group.domain.GroupUserEntity; +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; + +public interface GroupUserRepository { + GroupUserEntity createGroupUser(GroupUserEntity groupUserEntity); + + boolean findGroupUser(UserEntity userEntity); +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/GroupUserRepositoryImpl.java b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/GroupUserRepositoryImpl.java new file mode 100644 index 00000000..fa79b6f8 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/GroupUserRepositoryImpl.java @@ -0,0 +1,23 @@ +package org.ioteatime.meonghanyangserver.group.repository.groupuser; + +import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.group.domain.GroupUserEntity; +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class GroupUserRepositoryImpl implements GroupUserRepository { + private final JpaGroupUserRepository jpaGroupUserRepository; + + @Override + public GroupUserEntity createGroupUser(GroupUserEntity groupUserEntity) { + return jpaGroupUserRepository.save(groupUserEntity); + } + + @Override + public boolean findGroupUser(UserEntity userEntity) { + boolean groupUser = jpaGroupUserRepository.existsByUser(userEntity); + return groupUser; + } +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/JpaGroupUserRepository.java b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/JpaGroupUserRepository.java new file mode 100644 index 00000000..ad0d23b7 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/JpaGroupUserRepository.java @@ -0,0 +1,10 @@ +package org.ioteatime.meonghanyangserver.group.repository.groupuser; + +import org.ioteatime.meonghanyangserver.group.domain.GroupUserEntity; +import org.ioteatime.meonghanyangserver.group.domain.GroupUserId; +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface JpaGroupUserRepository extends JpaRepository { + boolean existsByUser(UserEntity userEntity); +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupService.java b/src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupService.java new file mode 100644 index 00000000..3165fa3c --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupService.java @@ -0,0 +1,47 @@ +package org.ioteatime.meonghanyangserver.group.service; + +import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.common.error.ErrorTypeCode; +import org.ioteatime.meonghanyangserver.common.exception.ApiException; +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; +import org.ioteatime.meonghanyangserver.group.domain.enums.GroupUserRole; +import org.ioteatime.meonghanyangserver.group.dto.response.CreateGroupResponse; +import org.ioteatime.meonghanyangserver.group.mapper.group.GroupEntityMapper; +import org.ioteatime.meonghanyangserver.group.mapper.group.GroupResponseMapper; +import org.ioteatime.meonghanyangserver.group.repository.group.GroupRepository; +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; +import org.ioteatime.meonghanyangserver.user.dto.CustomUserDetail; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class GroupService { + private final GroupRepository groupRepository; + private final GroupUserService groupUserService; + + // create group + public CreateGroupResponse createGroup(Authentication authentication) { + CustomUserDetail userDetails = (CustomUserDetail) authentication.getPrincipal(); + + UserEntity userEntity = userDetails.getUserEntity(); + + boolean groupUserEntity = groupUserService.findGroupUser(userEntity); + + if (groupUserEntity) { + throw new ApiException(ErrorTypeCode.BAD_REQUEST); + } + + String roomName = userEntity.getNickname() + " 그룹"; + + GroupEntity groupEntity = GroupEntityMapper.toEntity(roomName); + + GroupEntity newGroupEntity = groupRepository.createGroup(groupEntity); + + groupUserService.createGroupUser(newGroupEntity, userEntity, GroupUserRole.ROLE_MASTER); + + CreateGroupResponse createGroupResponse = GroupResponseMapper.toResponse(newGroupEntity); + + return createGroupResponse; + } +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupUserService.java b/src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupUserService.java new file mode 100644 index 00000000..ff66d15d --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupUserService.java @@ -0,0 +1,29 @@ +package org.ioteatime.meonghanyangserver.group.service; + +import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; +import org.ioteatime.meonghanyangserver.group.domain.GroupUserEntity; +import org.ioteatime.meonghanyangserver.group.domain.enums.GroupUserRole; +import org.ioteatime.meonghanyangserver.group.mapper.groupuser.GroupUserEntityMapper; +import org.ioteatime.meonghanyangserver.group.repository.groupuser.GroupUserRepository; +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class GroupUserService { + private final GroupUserRepository groupUserRepository; + + // input user + public void createGroupUser( + GroupEntity groupEntity, UserEntity userEntity, GroupUserRole groupUserRole) { + GroupUserEntity groupUserEntity = + GroupUserEntityMapper.toEntity(groupEntity, userEntity, groupUserRole); + groupUserRepository.createGroupUser(groupUserEntity); + } + + public boolean findGroupUser(UserEntity userEntity) { + boolean groupUser = groupUserRepository.findGroupUser(userEntity); + return groupUser; + } +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/redis/RefreshTokenRepository.java b/src/main/java/org/ioteatime/meonghanyangserver/redis/RefreshTokenRepository.java index 7b6881e5..909a8fef 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/redis/RefreshTokenRepository.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/redis/RefreshTokenRepository.java @@ -1,5 +1,8 @@ package org.ioteatime.meonghanyangserver.redis; +import java.util.Optional; import org.springframework.data.repository.CrudRepository; -public interface RefreshTokenRepository extends CrudRepository {} +public interface RefreshTokenRepository extends CrudRepository { + Optional findByRefreshToken(String refreshToken); +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/dto/CustomUserDetail.java b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/CustomUserDetail.java index b5f0a225..20e24d13 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/dto/CustomUserDetail.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/CustomUserDetail.java @@ -12,10 +12,10 @@ @Data @RequiredArgsConstructor public class CustomUserDetail implements UserDetails { - private UserEntity usersEntity; + private UserEntity userEntity; - public CustomUserDetail(UserEntity usersEntity) { - this.usersEntity = usersEntity; + public CustomUserDetail(UserEntity userEntity) { + this.userEntity = userEntity; } @Override @@ -25,11 +25,11 @@ public Collection getAuthorities() { @Override public String getPassword() { - return usersEntity.getPassword(); + return userEntity.getPassword(); } @Override public String getUsername() { - return usersEntity.getEmail(); + return userEntity.getEmail(); } } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/dto/request/UserDto.java b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/request/UserDto.java index fba74147..ad1708f5 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/dto/request/UserDto.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/request/UserDto.java @@ -12,24 +12,15 @@ public class UserDto { @NotBlank(message = "이메일을 입력해주세요.") @Email(message = "이메일 형식으로 입력해주세요.") - @Schema( - description = "사용자의 이메일", - example = "test@test.com", - requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "사용자의 이메일", example = "example@gmail.com") private String email; @NotBlank(message = "비밀번호를 입력해주세요.") - @Schema( - description = "사용자의 비밀번호", - example = "testpassword", - requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "사용자의 비밀번호", example = "testpassword") private String password; @NotBlank(message = "비밀번호를 확인해주세요.") - @Schema( - description = "비밀번호 확인", - example = "testpassword", - requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "비밀번호 확인", example = "testpassword") private String passwordConfirm; @NotBlank(message = "닉네임을 입력해주세요.") diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/dto/response/UserSimpleResponse.java b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/response/UserSimpleResponse.java index fcb97239..eee86b71 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/dto/response/UserSimpleResponse.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/response/UserSimpleResponse.java @@ -1,3 +1,9 @@ package org.ioteatime.meonghanyangserver.user.dto.response; -public record UserSimpleResponse(Long id, String email) {} +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; + +public record UserSimpleResponse(Long id, String email) { + public static UserSimpleResponse from(UserEntity user) { + return new UserSimpleResponse(user.getId(), user.getEmail()); + } +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/video/entity/VideoEntity.java b/src/main/java/org/ioteatime/meonghanyangserver/video/entity/VideoEntity.java new file mode 100644 index 00000000..8316ff27 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/video/entity/VideoEntity.java @@ -0,0 +1,28 @@ +package org.ioteatime.meonghanyangserver.video.entity; + +import jakarta.persistence.*; +import java.time.LocalDateTime; +import lombok.Data; +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; + +@Data +@Entity +@Table(name = "video") +public class VideoEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false, length = 50) + private String videoName; + + @ManyToOne + @JoinColumn(name = "group_id", nullable = false) + private GroupEntity group; + + @Column(nullable = false, length = 100) + private String videoPath; + + @Column(nullable = false) + private LocalDateTime createdAt; +} From 844b55ce057303c687f529fa8aabd0e321747565 Mon Sep 17 00:00:00 2001 From: bestKUFO Date: Tue, 29 Oct 2024 17:43:25 +0900 Subject: [PATCH 13/18] =?UTF-8?q?fix:=20conflict=20=ED=95=B4=EA=B2=B0=20(#?= =?UTF-8?q?22)=20(KAN-75)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix: group conflict 해결 (#22) (KAN-75) --- .../auth/controller/AuthApi.java | 11 +++-- .../auth/controller/AuthController.java | 19 +++++--- .../auth/dto/reponse/RefreshResponse.java | 14 ++++++ ...endEmailRequest.java => EmailRequest.java} | 2 +- .../auth/service/AuthService.java | 37 ++++++++++++++- .../cctv/domain/CctvEntity.java | 24 ++++++++++ .../common/utils/JwtUtils.java | 2 + .../config/SecurityConfig.java | 16 +++++-- .../group/controller/GroupApi.java | 13 +++++ .../group/controller/GroupController.java | 24 ++++++++++ .../group/domain/GroupEntity.java | 35 ++++++++++++++ .../group/domain/GroupUserEntity.java | 33 +++++++++++++ .../group/domain/GroupUserId.java | 16 +++++++ .../group/domain/enums/GroupUserRole.java | 11 +++++ .../dto/response/CreateGroupResponse.java | 5 ++ .../group/mapper/group/GroupEntityMapper.java | 10 ++++ .../mapper/group/GroupResponseMapper.java | 11 +++++ .../groupuser/GroupUserEntityMapper.java | 22 +++++++++ .../repository/group/GroupRepository.java | 7 +++ .../repository/group/GroupRepositoryImpl.java | 16 +++++++ .../repository/group/JpaGroupRepository.java | 6 +++ .../groupuser/GroupUserRepository.java | 10 ++++ .../groupuser/GroupUserRepositoryImpl.java | 23 +++++++++ .../groupuser/JpaGroupUserRepository.java | 10 ++++ .../group/service/GroupService.java | 47 +++++++++++++++++++ .../group/service/GroupUserService.java | 29 ++++++++++++ .../redis/RefreshTokenRepository.java | 5 +- .../user/controller/UserApi.java | 8 ++++ .../user/controller/UserController.java | 17 +++++-- .../user/domain/UserEntity.java | 9 ++++ .../user/dto/CustomUserDetail.java | 10 ++-- .../dto/request/ChangePasswordRequest.java | 18 +++++++ .../user/dto/request/UserDto.java | 15 ++---- .../user/dto/response/UserSimpleResponse.java | 8 +++- .../user/service/UserService.java | 31 ++++++++++++ .../video/entity/VideoEntity.java | 28 +++++++++++ 36 files changed, 565 insertions(+), 37 deletions(-) create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/auth/dto/reponse/RefreshResponse.java rename src/main/java/org/ioteatime/meonghanyangserver/auth/dto/request/{SendEmailRequest.java => EmailRequest.java} (91%) create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/cctv/domain/CctvEntity.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupApi.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupController.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupEntity.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserEntity.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserId.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/domain/enums/GroupUserRole.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/dto/response/CreateGroupResponse.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/mapper/group/GroupEntityMapper.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/mapper/group/GroupResponseMapper.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/mapper/groupuser/GroupUserEntityMapper.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/GroupRepository.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/GroupRepositoryImpl.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/JpaGroupRepository.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/GroupUserRepository.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/GroupUserRepositoryImpl.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/JpaGroupUserRepository.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupService.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupUserService.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/user/dto/request/ChangePasswordRequest.java create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/video/entity/VideoEntity.java diff --git a/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthApi.java b/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthApi.java index 2fe08240..05a964f8 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthApi.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthApi.java @@ -4,12 +4,14 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import org.ioteatime.meonghanyangserver.auth.dto.reponse.LoginResponse; +import org.ioteatime.meonghanyangserver.auth.dto.reponse.RefreshResponse; +import org.ioteatime.meonghanyangserver.auth.dto.request.EmailRequest; import org.ioteatime.meonghanyangserver.auth.dto.request.LoginRequest; -import org.ioteatime.meonghanyangserver.auth.dto.request.SendEmailRequest; import org.ioteatime.meonghanyangserver.common.api.Api; import org.ioteatime.meonghanyangserver.user.dto.UserDto; import org.ioteatime.meonghanyangserver.user.dto.response.UserSimpleResponse; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; @Tag(name = "Auth Api", description = "인증 관련 API 목록입니다.") public interface AuthApi { @@ -17,11 +19,14 @@ public interface AuthApi { Api registerUser(@Valid @RequestBody UserDto userDto); @Operation(summary = "인증 메일 전송") - Api verifyEmail(@Valid @RequestBody SendEmailRequest email); + Api verifyEmail(@Valid @RequestBody EmailRequest email); @Operation(summary = "로그인을 합니다.") Api login(@RequestBody @Valid LoginRequest loginRequest); @Operation(summary = "이메일 중복을 확인 합니다.") - Api duplicateEmail(@Valid @RequestBody SendEmailRequest email); + Api duplicateEmail(@Valid @RequestBody EmailRequest email); + + @Operation(summary = "토큰을 다시 생성합니다.") + Api refreshToken(@RequestHeader("Authorization") String authorizationHeader); } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthController.java b/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthController.java index 0f4b7cff..17aad109 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthController.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthController.java @@ -3,8 +3,9 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.ioteatime.meonghanyangserver.auth.dto.reponse.LoginResponse; +import org.ioteatime.meonghanyangserver.auth.dto.reponse.RefreshResponse; +import org.ioteatime.meonghanyangserver.auth.dto.request.EmailRequest; import org.ioteatime.meonghanyangserver.auth.dto.request.LoginRequest; -import org.ioteatime.meonghanyangserver.auth.dto.request.SendEmailRequest; import org.ioteatime.meonghanyangserver.auth.service.AuthService; import org.ioteatime.meonghanyangserver.common.api.Api; import org.ioteatime.meonghanyangserver.user.dto.UserDto; @@ -24,16 +25,15 @@ public Api registerUser(@Valid @RequestBody UserDto userDto) { } @PostMapping("/email-verification") - public Api verifyEmail(@Valid @RequestBody SendEmailRequest sendEmailReq) { - authService.send(sendEmailReq.email()); + public Api verifyEmail(@Valid @RequestBody EmailRequest emailReq) { + authService.send(emailReq.email()); return Api.OK(); } // Email 중복 확인 @PostMapping("/check-email") - public Api duplicateEmail( - @Valid @RequestBody SendEmailRequest sendEmailReq) { - UserSimpleResponse response = authService.verifyEmail(sendEmailReq.email()); + public Api duplicateEmail(@Valid @RequestBody EmailRequest emailReq) { + UserSimpleResponse response = authService.verifyEmail(emailReq.email()); return Api.OK(response); } @@ -43,4 +43,11 @@ public Api login(LoginRequest loginRequest) { LoginResponse loginResponse = authService.login(loginRequest); return Api.CREATE(loginResponse); } + + @PostMapping("/refresh-token") + public Api refreshToken( + @RequestHeader("Authorization") String authorizationHeader) { + RefreshResponse refreshResponse = authService.reissueAccessToken(authorizationHeader); + return Api.OK(refreshResponse); + } } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/auth/dto/reponse/RefreshResponse.java b/src/main/java/org/ioteatime/meonghanyangserver/auth/dto/reponse/RefreshResponse.java new file mode 100644 index 00000000..71d170d6 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/auth/dto/reponse/RefreshResponse.java @@ -0,0 +1,14 @@ +package org.ioteatime.meonghanyangserver.auth.dto.reponse; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@Builder +@AllArgsConstructor +public class RefreshResponse { + private String accessToken; +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/auth/dto/request/SendEmailRequest.java b/src/main/java/org/ioteatime/meonghanyangserver/auth/dto/request/EmailRequest.java similarity index 91% rename from src/main/java/org/ioteatime/meonghanyangserver/auth/dto/request/SendEmailRequest.java rename to src/main/java/org/ioteatime/meonghanyangserver/auth/dto/request/EmailRequest.java index 16bfebdf..39d8c8a8 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/auth/dto/request/SendEmailRequest.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/auth/dto/request/EmailRequest.java @@ -5,6 +5,6 @@ import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotNull; -public record SendEmailRequest( +public record EmailRequest( @Valid @Email @NotNull @Schema(description = "이메일", example = "example@gmail.com") String email) {} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/auth/service/AuthService.java b/src/main/java/org/ioteatime/meonghanyangserver/auth/service/AuthService.java index 74297c55..fdf049eb 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/auth/service/AuthService.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/auth/service/AuthService.java @@ -2,6 +2,7 @@ import lombok.RequiredArgsConstructor; import org.ioteatime.meonghanyangserver.auth.dto.reponse.LoginResponse; +import org.ioteatime.meonghanyangserver.auth.dto.reponse.RefreshResponse; import org.ioteatime.meonghanyangserver.auth.dto.request.LoginRequest; import org.ioteatime.meonghanyangserver.clients.google.GoogleMailClient; import org.ioteatime.meonghanyangserver.common.error.ErrorTypeCode; @@ -81,6 +82,40 @@ public UserSimpleResponse verifyEmail(String email) { userRepository .findByEmail(email) .orElseThrow(() -> new ApiException(ErrorTypeCode.NULL_POINT)); - return new UserSimpleResponse(userEntity.getId(), userEntity.getEmail()); + return UserSimpleResponse.from(userEntity); + } + + public RefreshResponse reissueAccessToken(String authorizationHeader) { + String refreshToken = authorizationHeader.replace("Bearer ", ""); + + RefreshToken storedToken = + refreshTokenRepository + .findByRefreshToken(refreshToken) + .orElseThrow( + () -> + new ApiException( + ErrorTypeCode.BAD_REQUEST, + "유효하지 않은 Refresh token입니다.")); + + if (!storedToken.getRefreshToken().equals(refreshToken)) { + throw new ApiException(ErrorTypeCode.BAD_REQUEST, "토큰이 일치하지 않습니다."); + } + + String email = jwtUtils.getSubjectFromToken(refreshToken); + UserEntity userEntity = + userRepository + .findByEmail(email) + .orElseThrow( + () -> + new ApiException( + ErrorTypeCode.BAD_REQUEST, "유효하지 않은 사용자입니다.")); + + if (!jwtUtils.validateToken(refreshToken, userEntity)) { + throw new ApiException(ErrorTypeCode.BAD_REQUEST, "Refresh token이 만료되었습니다."); + } + + String newAccessToken = jwtUtils.generateAccessToken(userEntity); + + return new RefreshResponse(newAccessToken); } } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/cctv/domain/CctvEntity.java b/src/main/java/org/ioteatime/meonghanyangserver/cctv/domain/CctvEntity.java new file mode 100644 index 00000000..1dad7384 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/cctv/domain/CctvEntity.java @@ -0,0 +1,24 @@ +package org.ioteatime.meonghanyangserver.cctv.domain; + +import jakarta.persistence.*; +import lombok.Data; +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; + +@Data +@Entity +@Table(name = "cctv") +public class CctvEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne + @JoinColumn(name = "group_id", nullable = false) + private GroupEntity group; + + @Column(nullable = false, length = 20) + private String cctvNickname; + + @Column(nullable = false, length = 100) + private String kvsChannelName; +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/common/utils/JwtUtils.java b/src/main/java/org/ioteatime/meonghanyangserver/common/utils/JwtUtils.java index 48644bbc..a9950384 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/common/utils/JwtUtils.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/common/utils/JwtUtils.java @@ -33,6 +33,7 @@ public String generateAccessToken(UserEntity userEntity) { String jwtToken = Jwts.builder() .claim("name", userEntity.getNickname()) + .claim("sub", userEntity.getEmail()) .claim("jti", String.valueOf(userEntity.getId())) .claim("role", "ROLE_USER") .claim("iat", nowDate) @@ -49,6 +50,7 @@ public String generateRefreshToken(UserEntity userEntity) { String jwtToken = Jwts.builder() .claim("name", userEntity.getNickname()) + .claim("sub", userEntity.getEmail()) .claim("jti", String.valueOf(userEntity.getId())) .claim("role", "ROLE_USER") .claim("iat", nowDate) diff --git a/src/main/java/org/ioteatime/meonghanyangserver/config/SecurityConfig.java b/src/main/java/org/ioteatime/meonghanyangserver/config/SecurityConfig.java index e28b1df0..5cc5feb9 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/config/SecurityConfig.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/config/SecurityConfig.java @@ -1,5 +1,7 @@ package org.ioteatime.meonghanyangserver.config; +import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.filter.JwtRequestFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -7,10 +9,14 @@ import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration @EnableWebSecurity +@RequiredArgsConstructor public class SecurityConfig { + private final JwtRequestFilter jwtRequestFilter; + @Bean BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); @@ -19,14 +25,18 @@ BCryptPasswordEncoder bCryptPasswordEncoder() { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.csrf(CsrfConfigurer::disable); - http.authorizeHttpRequests( (auth) -> - auth.requestMatchers("/open-api/**", "/swagger-ui/**", "/v3/**", "/error") + auth.requestMatchers( + "/open-api/**", + "/swagger-ui/**", + "/v3/**", + "/error", + "/api/**") .permitAll() .anyRequest() .authenticated()); - + http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class); return http.build(); } } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupApi.java b/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupApi.java new file mode 100644 index 00000000..dccbf7cb --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupApi.java @@ -0,0 +1,13 @@ +package org.ioteatime.meonghanyangserver.group.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.ioteatime.meonghanyangserver.common.api.Api; +import org.ioteatime.meonghanyangserver.group.dto.response.CreateGroupResponse; +import org.springframework.security.core.Authentication; + +@Tag(name = "Group Api", description = "Group 관련 API 목록입니다.") +public interface GroupApi { + @Operation(summary = "그룹을 생성합니다.") + Api createGroup(Authentication authentication); +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupController.java b/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupController.java new file mode 100644 index 00000000..097c32a7 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/controller/GroupController.java @@ -0,0 +1,24 @@ +package org.ioteatime.meonghanyangserver.group.controller; + +import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.common.api.Api; +import org.ioteatime.meonghanyangserver.group.dto.response.CreateGroupResponse; +import org.ioteatime.meonghanyangserver.group.service.GroupService; +import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/group") +public class GroupController implements GroupApi { + private final GroupService groupService; + + @Override + @PostMapping + public Api createGroup(Authentication authentication) { + CreateGroupResponse createGroupResponse = groupService.createGroup(authentication); + return Api.OK(createGroupResponse); + } +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupEntity.java b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupEntity.java new file mode 100644 index 00000000..b5cd0b89 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupEntity.java @@ -0,0 +1,35 @@ +package org.ioteatime.meonghanyangserver.group.domain; + +import jakarta.persistence.*; +import java.time.LocalDateTime; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.ioteatime.meonghanyangserver.cctv.domain.CctvEntity; +import org.ioteatime.meonghanyangserver.video.entity.VideoEntity; + +@Data +@Entity +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Table(name = "`group`") +public class GroupEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false, length = 100) + private String groupName; + + @Column(nullable = false) + private LocalDateTime createdAt; + + @OneToMany(mappedBy = "group", cascade = CascadeType.ALL) + private List cctvs; + + @OneToMany(mappedBy = "group", cascade = CascadeType.ALL) + private List videos; +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserEntity.java b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserEntity.java new file mode 100644 index 00000000..c00cc67a --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserEntity.java @@ -0,0 +1,33 @@ +package org.ioteatime.meonghanyangserver.group.domain; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.ioteatime.meonghanyangserver.group.domain.enums.GroupUserRole; +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; + +@Data +@Entity +@Table(name = "group_user") +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class GroupUserEntity { + @EmbeddedId private GroupUserId id; + + @Column(nullable = false, length = 10) + @Enumerated(value = EnumType.STRING) + private GroupUserRole role; + + @ManyToOne + @MapsId("groupId") + @JoinColumn(name = "group_id") + private GroupEntity group; + + @ManyToOne + @MapsId("userId") + @JoinColumn(name = "user_id", unique = true) + private UserEntity user; +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserId.java b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserId.java new file mode 100644 index 00000000..698f5e84 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/GroupUserId.java @@ -0,0 +1,16 @@ +package org.ioteatime.meonghanyangserver.group.domain; + +import jakarta.persistence.Embeddable; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Embeddable +@AllArgsConstructor +@NoArgsConstructor +public class GroupUserId implements Serializable { + private Long groupId; + private Long userId; +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/domain/enums/GroupUserRole.java b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/enums/GroupUserRole.java new file mode 100644 index 00000000..8a80ed3c --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/domain/enums/GroupUserRole.java @@ -0,0 +1,11 @@ +package org.ioteatime.meonghanyangserver.group.domain.enums; + +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public enum GroupUserRole { + ROLE_USER("USER"), + ROLE_MASTER("MASTER"); + + private final String description; +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/dto/response/CreateGroupResponse.java b/src/main/java/org/ioteatime/meonghanyangserver/group/dto/response/CreateGroupResponse.java new file mode 100644 index 00000000..aac3864c --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/dto/response/CreateGroupResponse.java @@ -0,0 +1,5 @@ +package org.ioteatime.meonghanyangserver.group.dto.response; + +import java.time.LocalDateTime; + +public record CreateGroupResponse(Long groupId, String groupName, LocalDateTime createdAt) {} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/group/GroupEntityMapper.java b/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/group/GroupEntityMapper.java new file mode 100644 index 00000000..d5b74487 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/group/GroupEntityMapper.java @@ -0,0 +1,10 @@ +package org.ioteatime.meonghanyangserver.group.mapper.group; + +import java.time.LocalDateTime; +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; + +public class GroupEntityMapper { + public static GroupEntity toEntity(String groupName) { + return GroupEntity.builder().groupName(groupName).createdAt(LocalDateTime.now()).build(); + } +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/group/GroupResponseMapper.java b/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/group/GroupResponseMapper.java new file mode 100644 index 00000000..38a46c7d --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/group/GroupResponseMapper.java @@ -0,0 +1,11 @@ +package org.ioteatime.meonghanyangserver.group.mapper.group; + +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; +import org.ioteatime.meonghanyangserver.group.dto.response.CreateGroupResponse; + +public class GroupResponseMapper { + public static CreateGroupResponse toResponse(GroupEntity groupEntity) { + return new CreateGroupResponse( + groupEntity.getId(), groupEntity.getGroupName(), groupEntity.getCreatedAt()); + } +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/groupuser/GroupUserEntityMapper.java b/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/groupuser/GroupUserEntityMapper.java new file mode 100644 index 00000000..7e615951 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/mapper/groupuser/GroupUserEntityMapper.java @@ -0,0 +1,22 @@ +package org.ioteatime.meonghanyangserver.group.mapper.groupuser; + +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; +import org.ioteatime.meonghanyangserver.group.domain.GroupUserEntity; +import org.ioteatime.meonghanyangserver.group.domain.GroupUserId; +import org.ioteatime.meonghanyangserver.group.domain.enums.GroupUserRole; +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; + +public class GroupUserEntityMapper { + + // master mapper + public static GroupUserEntity toEntity( + GroupEntity groupEntity, UserEntity userEntity, GroupUserRole groupUserRole) { + return GroupUserEntity.builder() + .id(new GroupUserId(groupEntity.getId(), userEntity.getId())) + .user(userEntity) + .role(groupUserRole) + .group(groupEntity) + .user(userEntity) + .build(); + } +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/GroupRepository.java b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/GroupRepository.java new file mode 100644 index 00000000..871c3f2c --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/GroupRepository.java @@ -0,0 +1,7 @@ +package org.ioteatime.meonghanyangserver.group.repository.group; + +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; + +public interface GroupRepository { + GroupEntity createGroup(GroupEntity groupEntity); +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/GroupRepositoryImpl.java b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/GroupRepositoryImpl.java new file mode 100644 index 00000000..6da5012b --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/GroupRepositoryImpl.java @@ -0,0 +1,16 @@ +package org.ioteatime.meonghanyangserver.group.repository.group; + +import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class GroupRepositoryImpl implements GroupRepository { + private final JpaGroupRepository jpaGroupRepository; + + @Override + public GroupEntity createGroup(GroupEntity groupEntity) { + return jpaGroupRepository.save(groupEntity); + } +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/JpaGroupRepository.java b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/JpaGroupRepository.java new file mode 100644 index 00000000..379a500c --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/group/JpaGroupRepository.java @@ -0,0 +1,6 @@ +package org.ioteatime.meonghanyangserver.group.repository.group; + +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface JpaGroupRepository extends JpaRepository {} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/GroupUserRepository.java b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/GroupUserRepository.java new file mode 100644 index 00000000..61a3ab08 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/GroupUserRepository.java @@ -0,0 +1,10 @@ +package org.ioteatime.meonghanyangserver.group.repository.groupuser; + +import org.ioteatime.meonghanyangserver.group.domain.GroupUserEntity; +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; + +public interface GroupUserRepository { + GroupUserEntity createGroupUser(GroupUserEntity groupUserEntity); + + boolean findGroupUser(UserEntity userEntity); +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/GroupUserRepositoryImpl.java b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/GroupUserRepositoryImpl.java new file mode 100644 index 00000000..fa79b6f8 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/GroupUserRepositoryImpl.java @@ -0,0 +1,23 @@ +package org.ioteatime.meonghanyangserver.group.repository.groupuser; + +import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.group.domain.GroupUserEntity; +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class GroupUserRepositoryImpl implements GroupUserRepository { + private final JpaGroupUserRepository jpaGroupUserRepository; + + @Override + public GroupUserEntity createGroupUser(GroupUserEntity groupUserEntity) { + return jpaGroupUserRepository.save(groupUserEntity); + } + + @Override + public boolean findGroupUser(UserEntity userEntity) { + boolean groupUser = jpaGroupUserRepository.existsByUser(userEntity); + return groupUser; + } +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/JpaGroupUserRepository.java b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/JpaGroupUserRepository.java new file mode 100644 index 00000000..ad0d23b7 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/repository/groupuser/JpaGroupUserRepository.java @@ -0,0 +1,10 @@ +package org.ioteatime.meonghanyangserver.group.repository.groupuser; + +import org.ioteatime.meonghanyangserver.group.domain.GroupUserEntity; +import org.ioteatime.meonghanyangserver.group.domain.GroupUserId; +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface JpaGroupUserRepository extends JpaRepository { + boolean existsByUser(UserEntity userEntity); +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupService.java b/src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupService.java new file mode 100644 index 00000000..3165fa3c --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupService.java @@ -0,0 +1,47 @@ +package org.ioteatime.meonghanyangserver.group.service; + +import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.common.error.ErrorTypeCode; +import org.ioteatime.meonghanyangserver.common.exception.ApiException; +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; +import org.ioteatime.meonghanyangserver.group.domain.enums.GroupUserRole; +import org.ioteatime.meonghanyangserver.group.dto.response.CreateGroupResponse; +import org.ioteatime.meonghanyangserver.group.mapper.group.GroupEntityMapper; +import org.ioteatime.meonghanyangserver.group.mapper.group.GroupResponseMapper; +import org.ioteatime.meonghanyangserver.group.repository.group.GroupRepository; +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; +import org.ioteatime.meonghanyangserver.user.dto.CustomUserDetail; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class GroupService { + private final GroupRepository groupRepository; + private final GroupUserService groupUserService; + + // create group + public CreateGroupResponse createGroup(Authentication authentication) { + CustomUserDetail userDetails = (CustomUserDetail) authentication.getPrincipal(); + + UserEntity userEntity = userDetails.getUserEntity(); + + boolean groupUserEntity = groupUserService.findGroupUser(userEntity); + + if (groupUserEntity) { + throw new ApiException(ErrorTypeCode.BAD_REQUEST); + } + + String roomName = userEntity.getNickname() + " 그룹"; + + GroupEntity groupEntity = GroupEntityMapper.toEntity(roomName); + + GroupEntity newGroupEntity = groupRepository.createGroup(groupEntity); + + groupUserService.createGroupUser(newGroupEntity, userEntity, GroupUserRole.ROLE_MASTER); + + CreateGroupResponse createGroupResponse = GroupResponseMapper.toResponse(newGroupEntity); + + return createGroupResponse; + } +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupUserService.java b/src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupUserService.java new file mode 100644 index 00000000..ff66d15d --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/group/service/GroupUserService.java @@ -0,0 +1,29 @@ +package org.ioteatime.meonghanyangserver.group.service; + +import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; +import org.ioteatime.meonghanyangserver.group.domain.GroupUserEntity; +import org.ioteatime.meonghanyangserver.group.domain.enums.GroupUserRole; +import org.ioteatime.meonghanyangserver.group.mapper.groupuser.GroupUserEntityMapper; +import org.ioteatime.meonghanyangserver.group.repository.groupuser.GroupUserRepository; +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class GroupUserService { + private final GroupUserRepository groupUserRepository; + + // input user + public void createGroupUser( + GroupEntity groupEntity, UserEntity userEntity, GroupUserRole groupUserRole) { + GroupUserEntity groupUserEntity = + GroupUserEntityMapper.toEntity(groupEntity, userEntity, groupUserRole); + groupUserRepository.createGroupUser(groupUserEntity); + } + + public boolean findGroupUser(UserEntity userEntity) { + boolean groupUser = groupUserRepository.findGroupUser(userEntity); + return groupUser; + } +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/redis/RefreshTokenRepository.java b/src/main/java/org/ioteatime/meonghanyangserver/redis/RefreshTokenRepository.java index 7b6881e5..909a8fef 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/redis/RefreshTokenRepository.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/redis/RefreshTokenRepository.java @@ -1,5 +1,8 @@ package org.ioteatime.meonghanyangserver.redis; +import java.util.Optional; import org.springframework.data.repository.CrudRepository; -public interface RefreshTokenRepository extends CrudRepository {} +public interface RefreshTokenRepository extends CrudRepository { + Optional findByRefreshToken(String refreshToken); +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserApi.java b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserApi.java index 0cef54b9..53be25a9 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserApi.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserApi.java @@ -2,9 +2,13 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import org.ioteatime.meonghanyangserver.common.api.Api; +import org.ioteatime.meonghanyangserver.user.dto.request.ChangePasswordRequest; import org.ioteatime.meonghanyangserver.user.dto.response.UserDetailResponse; +import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; @Tag(name = "User Api", description = "유저 관련 API 목록입니다.") public interface UserApi { @@ -14,4 +18,8 @@ public interface UserApi { @Operation(summary = "회원 정보를 삭제합니다.") Api deleteUser(@PathVariable("userId") Long userId); + + @Operation(summary = "회원의 비밀번호를 변경합니다.") + Api changeUserPassword( + Authentication authentication, @RequestBody @Valid ChangePasswordRequest request); } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java index bd6accc2..6331d7ca 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java @@ -1,13 +1,13 @@ package org.ioteatime.meonghanyangserver.user.controller; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.ioteatime.meonghanyangserver.common.api.Api; +import org.ioteatime.meonghanyangserver.user.dto.request.ChangePasswordRequest; import org.ioteatime.meonghanyangserver.user.dto.response.UserDetailResponse; import org.ioteatime.meonghanyangserver.user.service.UserService; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.*; @RestController @RequiredArgsConstructor @@ -26,4 +26,13 @@ public Api deleteUser(Long userId) { userService.deleteUser(userId); return Api.OK(); } + + @PutMapping("/password") + public Api changeUserPassword( + Authentication authentication, @RequestBody @Valid ChangePasswordRequest request) { + + userService.changeUserPassword(authentication, request); + + return Api.OK(); + } } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/domain/UserEntity.java b/src/main/java/org/ioteatime/meonghanyangserver/user/domain/UserEntity.java index 798af256..60af3e89 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/domain/UserEntity.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/domain/UserEntity.java @@ -4,6 +4,8 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.ioteatime.meonghanyangserver.common.error.ErrorTypeCode; +import org.ioteatime.meonghanyangserver.common.exception.ApiException; @Getter @Entity @@ -34,4 +36,11 @@ public UserEntity( this.nickname = nickname; this.profileImgUrl = profileImgUrl; } + + public void setPassword(String encodedPassword) { + if (encodedPassword == null || encodedPassword.isBlank()) { + throw new ApiException(ErrorTypeCode.BAD_REQUEST, "Password is empty"); + } + this.password = encodedPassword; + } } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/dto/CustomUserDetail.java b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/CustomUserDetail.java index b5f0a225..20e24d13 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/dto/CustomUserDetail.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/CustomUserDetail.java @@ -12,10 +12,10 @@ @Data @RequiredArgsConstructor public class CustomUserDetail implements UserDetails { - private UserEntity usersEntity; + private UserEntity userEntity; - public CustomUserDetail(UserEntity usersEntity) { - this.usersEntity = usersEntity; + public CustomUserDetail(UserEntity userEntity) { + this.userEntity = userEntity; } @Override @@ -25,11 +25,11 @@ public Collection getAuthorities() { @Override public String getPassword() { - return usersEntity.getPassword(); + return userEntity.getPassword(); } @Override public String getUsername() { - return usersEntity.getEmail(); + return userEntity.getEmail(); } } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/dto/request/ChangePasswordRequest.java b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/request/ChangePasswordRequest.java new file mode 100644 index 00000000..e3373c41 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/request/ChangePasswordRequest.java @@ -0,0 +1,18 @@ +package org.ioteatime.meonghanyangserver.user.dto.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +public class ChangePasswordRequest { + + @NotBlank(message = "현재 비밀번호는 필수 입력값") + private String currentPassword; + + @NotBlank(message = "새 비밀번호는 필수 입력값") + @Size(min = 8, max = 20, message = "비밀번호는 8자 이상 20자 이하여야 합니다.") + private String newPassword; +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/dto/request/UserDto.java b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/request/UserDto.java index fba74147..ad1708f5 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/dto/request/UserDto.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/request/UserDto.java @@ -12,24 +12,15 @@ public class UserDto { @NotBlank(message = "이메일을 입력해주세요.") @Email(message = "이메일 형식으로 입력해주세요.") - @Schema( - description = "사용자의 이메일", - example = "test@test.com", - requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "사용자의 이메일", example = "example@gmail.com") private String email; @NotBlank(message = "비밀번호를 입력해주세요.") - @Schema( - description = "사용자의 비밀번호", - example = "testpassword", - requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "사용자의 비밀번호", example = "testpassword") private String password; @NotBlank(message = "비밀번호를 확인해주세요.") - @Schema( - description = "비밀번호 확인", - example = "testpassword", - requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "비밀번호 확인", example = "testpassword") private String passwordConfirm; @NotBlank(message = "닉네임을 입력해주세요.") diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/dto/response/UserSimpleResponse.java b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/response/UserSimpleResponse.java index fcb97239..eee86b71 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/dto/response/UserSimpleResponse.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/response/UserSimpleResponse.java @@ -1,3 +1,9 @@ package org.ioteatime.meonghanyangserver.user.dto.response; -public record UserSimpleResponse(Long id, String email) {} +import org.ioteatime.meonghanyangserver.user.domain.UserEntity; + +public record UserSimpleResponse(Long id, String email) { + public static UserSimpleResponse from(UserEntity user) { + return new UserSimpleResponse(user.getId(), user.getEmail()); + } +} diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java b/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java index 8c65361f..59e5a94a 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java @@ -1,16 +1,24 @@ package org.ioteatime.meonghanyangserver.user.service; import lombok.RequiredArgsConstructor; +import org.ioteatime.meonghanyangserver.common.error.ErrorTypeCode; +import org.ioteatime.meonghanyangserver.common.exception.ApiException; import org.ioteatime.meonghanyangserver.user.domain.UserEntity; +import org.ioteatime.meonghanyangserver.user.dto.CustomUserDetail; +import org.ioteatime.meonghanyangserver.user.dto.request.ChangePasswordRequest; import org.ioteatime.meonghanyangserver.user.dto.response.UserDetailResponse; import org.ioteatime.meonghanyangserver.user.repository.UserRepository; +import org.springframework.security.core.Authentication; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @Service @RequiredArgsConstructor public class UserService { private final UserRepository userRepository; + private final BCryptPasswordEncoder bCryptPasswordEncoder; public UserDetailResponse getUserDetail(Long userId) { UserEntity userEntity = @@ -24,4 +32,27 @@ public UserDetailResponse getUserDetail(Long userId) { public void deleteUser(Long userId) { userRepository.deleteById(userId); } + + @Transactional + public void changeUserPassword(Authentication authentication, ChangePasswordRequest request) { + String currentPassword = request.getCurrentPassword(); + String newPassword = request.getNewPassword(); + CustomUserDetail userDetails = (CustomUserDetail) authentication.getPrincipal(); + Long userId = userDetails.getUserEntity().getId(); + + UserEntity userEntity = + userRepository + .findById(userId) + .orElseThrow( + () -> + new ApiException( + ErrorTypeCode.BAD_REQUEST, "User not found")); + + if (!bCryptPasswordEncoder.matches(currentPassword, userEntity.getPassword())) { + throw new ApiException(ErrorTypeCode.BAD_REQUEST, "현재 비밀번호가 일치하지 않습니다."); + } + + // Dirty-Checking Password Change + userEntity.setPassword(bCryptPasswordEncoder.encode(newPassword)); + } } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/video/entity/VideoEntity.java b/src/main/java/org/ioteatime/meonghanyangserver/video/entity/VideoEntity.java new file mode 100644 index 00000000..8316ff27 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/video/entity/VideoEntity.java @@ -0,0 +1,28 @@ +package org.ioteatime.meonghanyangserver.video.entity; + +import jakarta.persistence.*; +import java.time.LocalDateTime; +import lombok.Data; +import org.ioteatime.meonghanyangserver.group.domain.GroupEntity; + +@Data +@Entity +@Table(name = "video") +public class VideoEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false, length = 50) + private String videoName; + + @ManyToOne + @JoinColumn(name = "group_id", nullable = false) + private GroupEntity group; + + @Column(nullable = false, length = 100) + private String videoPath; + + @Column(nullable = false) + private LocalDateTime createdAt; +} From 11627ac8e58070b6438cc9c80b6db043d35f62a4 Mon Sep 17 00:00:00 2001 From: bestKUFO Date: Wed, 30 Oct 2024 09:33:50 +0900 Subject: [PATCH 14/18] =?UTF-8?q?fix:=20conflict=20=ED=95=B4=EA=B2=B0=20(#?= =?UTF-8?q?22)=20(KAN-75)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../meonghanyangserver/auth/controller/AuthApi.java | 6 ------ .../meonghanyangserver/auth/controller/AuthController.java | 6 ------ .../meonghanyangserver/auth/service/AuthService.java | 3 --- 3 files changed, 15 deletions(-) diff --git a/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthApi.java b/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthApi.java index 3ad48c03..05a964f8 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthApi.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthApi.java @@ -5,10 +5,7 @@ import jakarta.validation.Valid; import org.ioteatime.meonghanyangserver.auth.dto.reponse.LoginResponse; import org.ioteatime.meonghanyangserver.auth.dto.reponse.RefreshResponse; -<<<<<<< HEAD import org.ioteatime.meonghanyangserver.auth.dto.request.EmailRequest; -======= ->>>>>>> 62ffa31dd136cdd1181a8eebe8d5a6380205b3bf import org.ioteatime.meonghanyangserver.auth.dto.request.LoginRequest; import org.ioteatime.meonghanyangserver.common.api.Api; import org.ioteatime.meonghanyangserver.user.dto.UserDto; @@ -27,12 +24,9 @@ public interface AuthApi { @Operation(summary = "로그인을 합니다.") Api login(@RequestBody @Valid LoginRequest loginRequest); -<<<<<<< HEAD @Operation(summary = "이메일 중복을 확인 합니다.") Api duplicateEmail(@Valid @RequestBody EmailRequest email); -======= ->>>>>>> 62ffa31dd136cdd1181a8eebe8d5a6380205b3bf @Operation(summary = "토큰을 다시 생성합니다.") Api refreshToken(@RequestHeader("Authorization") String authorizationHeader); } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthController.java b/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthController.java index d1d70914..17aad109 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthController.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/auth/controller/AuthController.java @@ -4,18 +4,12 @@ import lombok.RequiredArgsConstructor; import org.ioteatime.meonghanyangserver.auth.dto.reponse.LoginResponse; import org.ioteatime.meonghanyangserver.auth.dto.reponse.RefreshResponse; -<<<<<<< HEAD import org.ioteatime.meonghanyangserver.auth.dto.request.EmailRequest; -======= ->>>>>>> 62ffa31dd136cdd1181a8eebe8d5a6380205b3bf import org.ioteatime.meonghanyangserver.auth.dto.request.LoginRequest; import org.ioteatime.meonghanyangserver.auth.service.AuthService; import org.ioteatime.meonghanyangserver.common.api.Api; import org.ioteatime.meonghanyangserver.user.dto.UserDto; -<<<<<<< HEAD import org.ioteatime.meonghanyangserver.user.dto.response.UserSimpleResponse; -======= ->>>>>>> 62ffa31dd136cdd1181a8eebe8d5a6380205b3bf import org.springframework.web.bind.annotation.*; @RestController diff --git a/src/main/java/org/ioteatime/meonghanyangserver/auth/service/AuthService.java b/src/main/java/org/ioteatime/meonghanyangserver/auth/service/AuthService.java index 691f74b7..fdf049eb 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/auth/service/AuthService.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/auth/service/AuthService.java @@ -77,7 +77,6 @@ public void send(String email) { googleMailClient.sendMail(email, "hello", "world"); } -<<<<<<< HEAD public UserSimpleResponse verifyEmail(String email) { UserEntity userEntity = userRepository @@ -86,8 +85,6 @@ public UserSimpleResponse verifyEmail(String email) { return UserSimpleResponse.from(userEntity); } -======= ->>>>>>> 62ffa31dd136cdd1181a8eebe8d5a6380205b3bf public RefreshResponse reissueAccessToken(String authorizationHeader) { String refreshToken = authorizationHeader.replace("Bearer ", ""); From 0869bba24fc6257666c71efb433eab902f7e6fac Mon Sep 17 00:00:00 2001 From: ywonchae1 Date: Wed, 30 Oct 2024 10:10:54 +0900 Subject: [PATCH 15/18] =?UTF-8?q?feat:=20=EC=8A=A4=EC=9B=A8=EA=B1=B0?= =?UTF-8?q?=EC=97=90=20=EB=B0=B0=ED=8F=AC=20=EC=84=9C=EB=B2=84,=20?= =?UTF-8?q?=EB=A1=9C=EC=BB=AC=20=EC=84=9C=EB=B2=84=20=EC=84=A4=EC=A0=95?= =?UTF-8?q?=EA=B3=BC=20Authorization=20=ED=97=A4=EB=8D=94=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EC=B6=94=EA=B0=80=20(#41)=20(KAN-96)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/OpenApiConfig.java | 53 ++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/ioteatime/meonghanyangserver/config/OpenApiConfig.java b/src/main/java/org/ioteatime/meonghanyangserver/config/OpenApiConfig.java index 45b45a60..50df160b 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/config/OpenApiConfig.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/config/OpenApiConfig.java @@ -3,6 +3,13 @@ import io.swagger.v3.oas.annotations.OpenAPIDefinition; import io.swagger.v3.oas.annotations.info.Contact; import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; +import io.swagger.v3.oas.models.servers.Server; +import java.util.List; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @OpenAPIDefinition( @@ -13,4 +20,48 @@ version = "v1", contact = @Contact(name = "서유진", email = "seoyoujin97@gmail.com"))) @Configuration -public class OpenApiConfig {} +public class OpenApiConfig { + @Bean + public OpenAPI openAPI() { + SecurityScheme apiKey = + new SecurityScheme() + .type(SecurityScheme.Type.APIKEY) + .in(SecurityScheme.In.HEADER) + .name("Authorization"); + + SecurityRequirement securityRequirement = new SecurityRequirement().addList("Bearer Token"); + + Server productionServer = new Server(); + productionServer.setDescription("Production Server"); + productionServer.setUrl("https://my-server-name.com"); + + Server localServer = new Server(); + localServer.setDescription("Local Server"); + localServer.setUrl("http://localhost:8080"); + + return new OpenAPI() + .addSecurityItem(getSecurityRequirement()) + .components(getAuthComponent()) + .servers(List.of(productionServer, localServer)) + .components(new Components().addSecuritySchemes("Bearer Token", apiKey)) + .addSecurityItem(securityRequirement); + } + + private SecurityRequirement getSecurityRequirement() { + String jwt = "JWT"; + return new SecurityRequirement().addList(jwt); + } + + private Components getAuthComponent() { + return new Components() + .addSecuritySchemes( + "JWT", + new SecurityScheme() + .name("JWT") + .type(SecurityScheme.Type.HTTP) + .scheme("bearer") + .bearerFormat("JWT") + .in(SecurityScheme.In.HEADER) + .name("Authorization")); + } +} From eac7ca028df2b6a8d7bb935197679e7da6e2ab53 Mon Sep 17 00:00:00 2001 From: ywonchae1 Date: Wed, 30 Oct 2024 10:11:16 +0900 Subject: [PATCH 16/18] =?UTF-8?q?feat:=20Security=20Context=EC=97=90=20?= =?UTF-8?q?=EB=8B=B4=EB=8A=94=20=EA=B0=9D=EC=B2=B4=EC=97=90=20id=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=EC=B6=94=EA=B0=80=20(#41)=20(KAN-96)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../meonghanyangserver/user/dto/CustomUserDetail.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/dto/CustomUserDetail.java b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/CustomUserDetail.java index 20e24d13..cda2c663 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/dto/CustomUserDetail.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/dto/CustomUserDetail.java @@ -32,4 +32,8 @@ public String getPassword() { public String getUsername() { return userEntity.getEmail(); } + + public Long getId() { + return userEntity.getId(); + } } From 74bd84853e7f1ec8e22646cb5e4172e7727672ca Mon Sep 17 00:00:00 2001 From: ywonchae1 Date: Wed, 30 Oct 2024 10:11:30 +0900 Subject: [PATCH 17/18] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=ED=9A=8C=EC=9B=90=20id=20=EC=A0=95=EB=B3=B4=20=EA=B0=80?= =?UTF-8?q?=EC=A0=B8=EC=98=A4=EB=8A=94=20=EC=95=A0=EB=85=B8=ED=85=8C?= =?UTF-8?q?=EC=9D=B4=EC=85=98=20=EA=B5=AC=ED=98=84=20(#41)=20(KAN-96)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../meonghanyangserver/common/utils/LoginMember.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/main/java/org/ioteatime/meonghanyangserver/common/utils/LoginMember.java diff --git a/src/main/java/org/ioteatime/meonghanyangserver/common/utils/LoginMember.java b/src/main/java/org/ioteatime/meonghanyangserver/common/utils/LoginMember.java new file mode 100644 index 00000000..3f949451 --- /dev/null +++ b/src/main/java/org/ioteatime/meonghanyangserver/common/utils/LoginMember.java @@ -0,0 +1,12 @@ +package org.ioteatime.meonghanyangserver.common.utils; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.springframework.security.core.annotation.AuthenticationPrincipal; + +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +@AuthenticationPrincipal(expression = "id == null ? 0L : id") +public @interface LoginMember {} From 824c41b3f7a1b65c4a620b12c268ceed86ccf332 Mon Sep 17 00:00:00 2001 From: ywonchae1 Date: Wed, 30 Oct 2024 10:11:37 +0900 Subject: [PATCH 18/18] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=ED=9A=8C=EC=9B=90=20id=20=EC=A0=95=EB=B3=B4=20=EA=B0=80?= =?UTF-8?q?=EC=A0=B8=EC=98=A4=EB=8A=94=20=EC=95=A0=EB=85=B8=ED=85=8C?= =?UTF-8?q?=EC=9D=B4=EC=85=98=20=EC=A0=81=EC=9A=A9=20(#41)=20(KAN-96)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/controller/UserApi.java | 6 +++--- .../user/controller/UserController.java | 14 ++++++-------- .../user/service/UserService.java | 6 +----- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserApi.java b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserApi.java index 53be25a9..4dc43ddb 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserApi.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserApi.java @@ -4,9 +4,9 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import org.ioteatime.meonghanyangserver.common.api.Api; +import org.ioteatime.meonghanyangserver.common.utils.LoginMember; import org.ioteatime.meonghanyangserver.user.dto.request.ChangePasswordRequest; import org.ioteatime.meonghanyangserver.user.dto.response.UserDetailResponse; -import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; @@ -17,9 +17,9 @@ public interface UserApi { Api getUserDetail(@PathVariable("userId") Long userId); @Operation(summary = "회원 정보를 삭제합니다.") - Api deleteUser(@PathVariable("userId") Long userId); + Api deleteUser(@LoginMember Long userId); @Operation(summary = "회원의 비밀번호를 변경합니다.") Api changeUserPassword( - Authentication authentication, @RequestBody @Valid ChangePasswordRequest request); + @LoginMember Long userId, @RequestBody @Valid ChangePasswordRequest request); } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java index 6331d7ca..fb0f438f 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/controller/UserController.java @@ -3,10 +3,10 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.ioteatime.meonghanyangserver.common.api.Api; +import org.ioteatime.meonghanyangserver.common.utils.LoginMember; import org.ioteatime.meonghanyangserver.user.dto.request.ChangePasswordRequest; import org.ioteatime.meonghanyangserver.user.dto.response.UserDetailResponse; import org.ioteatime.meonghanyangserver.user.service.UserService; -import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.*; @RestController @@ -16,23 +16,21 @@ public class UserController implements UserApi { private final UserService userService; @GetMapping("/{userId}") - public Api getUserDetail(Long userId) { + public Api getUserDetail(@PathVariable("userId") Long userId) { UserDetailResponse userDto = userService.getUserDetail(userId); return Api.OK(userDto); } - @DeleteMapping("/{userId}") - public Api deleteUser(Long userId) { + @DeleteMapping + public Api deleteUser(@LoginMember Long userId) { userService.deleteUser(userId); return Api.OK(); } @PutMapping("/password") public Api changeUserPassword( - Authentication authentication, @RequestBody @Valid ChangePasswordRequest request) { - - userService.changeUserPassword(authentication, request); - + @LoginMember Long userId, @RequestBody @Valid ChangePasswordRequest request) { + userService.changeUserPassword(userId, request); return Api.OK(); } } diff --git a/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java b/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java index 59e5a94a..ea0aed1f 100644 --- a/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java +++ b/src/main/java/org/ioteatime/meonghanyangserver/user/service/UserService.java @@ -4,11 +4,9 @@ import org.ioteatime.meonghanyangserver.common.error.ErrorTypeCode; import org.ioteatime.meonghanyangserver.common.exception.ApiException; import org.ioteatime.meonghanyangserver.user.domain.UserEntity; -import org.ioteatime.meonghanyangserver.user.dto.CustomUserDetail; import org.ioteatime.meonghanyangserver.user.dto.request.ChangePasswordRequest; import org.ioteatime.meonghanyangserver.user.dto.response.UserDetailResponse; import org.ioteatime.meonghanyangserver.user.repository.UserRepository; -import org.springframework.security.core.Authentication; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -34,11 +32,9 @@ public void deleteUser(Long userId) { } @Transactional - public void changeUserPassword(Authentication authentication, ChangePasswordRequest request) { + public void changeUserPassword(Long userId, ChangePasswordRequest request) { String currentPassword = request.getCurrentPassword(); String newPassword = request.getNewPassword(); - CustomUserDetail userDetails = (CustomUserDetail) authentication.getPrincipal(); - Long userId = userDetails.getUserEntity().getId(); UserEntity userEntity = userRepository