Skip to content

Commit

Permalink
Merge pull request #289 from IoTeaTime/feature/288-body-validation-check
Browse files Browse the repository at this point in the history
feat: 요청 body validation check 추가
  • Loading branch information
ywonchae1 authored Dec 13, 2024
2 parents 023d775 + 22b54df commit 2a17b0c
Show file tree
Hide file tree
Showing 27 changed files with 92 additions and 116 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,31 @@

import io.swagger.v3.oas.annotations.Operation;
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.EmailRequest;
import org.ioteatime.meonghanyangserver.auth.dto.request.IssuePasswordRequest;
import org.ioteatime.meonghanyangserver.auth.dto.request.LoginRequest;
import org.ioteatime.meonghanyangserver.auth.dto.request.VerifyEmailRequest;
import org.ioteatime.meonghanyangserver.common.api.Api;
import org.ioteatime.meonghanyangserver.member.dto.request.JoinRequest;
import org.springframework.web.bind.annotation.RequestBody;

@Tag(name = "Auth Api", description = "인증 관련 API 목록입니다.")
public interface AuthApi {
@Operation(summary = "회원 가입을 합니다.", description = "담당자: 서유진")
Api<Object> registerUser(@Valid @RequestBody JoinRequest userDto);
Api<?> registerUser(JoinRequest userDto);

@Operation(summary = "인증 메일 전송", description = "담당자: 양원채")
Api<?> sendEmailCode(@Valid @RequestBody EmailRequest email);
Api<?> sendEmailCode(EmailRequest email);

@Operation(summary = "메일 인증 코드 검증", description = "담당자: 양원채")
Api<?> verifyEmail(@Valid @RequestBody VerifyEmailRequest verifyEmailRequest);
Api<?> verifyEmail(VerifyEmailRequest verifyEmailRequest);

@Operation(summary = "로그인을 합니다.", description = "담당자: 최민석")
Api<LoginResponse> login(@RequestBody @Valid LoginRequest loginRequest);
Api<LoginResponse> login(LoginRequest loginRequest);

@Operation(summary = "이메일 중복을 확인 합니다.", description = "담당자: 조경재")
Api<?> duplicateEmail(@Valid @RequestBody EmailRequest email);
Api<?> duplicateEmail(EmailRequest email);

@Operation(summary = "임시 비밀번호를 발급해줍니다.", description = "담당자: 최민석")
Api<?> issuePassword(@Valid @RequestBody IssuePasswordRequest issuePasswordRequest);
Api<?> issuePassword(IssuePasswordRequest issuePasswordRequest);
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,26 @@ public class AuthController implements AuthApi {
private final AuthService authService;

@PostMapping("/sign-up")
public Api<Object> registerUser(@RequestBody JoinRequest userDto) {
public Api<?> registerUser(@Valid @RequestBody JoinRequest userDto) {
authService.joinProcess(userDto);
return Api.success(AuthSuccessType.SIGN_UP);
}

@PostMapping("/email-verification")
public Api<?> sendEmailCode(@RequestBody EmailRequest emailReq) {
public Api<?> sendEmailCode(@Valid @RequestBody EmailRequest emailReq) {
authService.send(emailReq.email());
return Api.success(AuthSuccessType.SEND_EMAIL_CODE);
}

@PostMapping("/check-verification")
public Api<?> verifyEmail(VerifyEmailRequest verifyEmailRequest) {
public Api<?> verifyEmail(@Valid @RequestBody VerifyEmailRequest verifyEmailRequest) {
authService.verifyEmailCode(verifyEmailRequest.email(), verifyEmailRequest.code());
return Api.success(AuthSuccessType.VERIFY_EMAIL_CODE);
}

// Email 중복 확인
@PostMapping("/check-email")
public Api<?> duplicateEmail(@RequestBody EmailRequest emailReq) {
public Api<?> duplicateEmail(@Valid @RequestBody EmailRequest emailReq) {
authService.verifyEmail(emailReq.email());
return Api.success(AuthSuccessType.EMAIL_VERIFIED);
}
Expand All @@ -51,7 +51,7 @@ public Api<?> issuePassword(@Valid @RequestBody IssuePasswordRequest issuePasswo
}

@PostMapping("/sign-in")
public Api<LoginResponse> login(LoginRequest loginRequest) {
public Api<LoginResponse> login(@Valid @RequestBody LoginRequest loginRequest) {
LoginResponse loginResponse = authService.login(loginRequest);
return Api.success(AuthSuccessType.SIGN_IN, loginResponse);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package org.ioteatime.meonghanyangserver.auth.dto.request;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

public record LoginRequest(
@NotBlank @Schema(description = "이메일", example = "[email protected]") String email,
@NotBlank @Schema(description = "비밀번호", example = "testpassword") String password) {}
@NotBlank @Schema(description = "이메일", example = "[email protected]") @Email String email,
@NotBlank
@Schema(description = "비밀번호", example = "testpassword")
@Size(min = 8, max = 20, message = "비밀번호는 8자 이상 20자 이하여야 합니다.")
String password) {}
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
import jakarta.validation.constraints.NotNull;

public record VerifyEmailRequest(
@Email @NotNull @Schema(description = "이메일", example = "[email protected]") String email,
@NotNull @Schema(description = "이메일", example = "[email protected]") @Email String email,
@NotNull @Schema(description = "인증 코드", example = "XV23W1") String code) {}
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public MemberSimpleResponse joinProcess(JoinRequest userDto) {
}

public void send(String email) {
String code = getCode();
String code = getCode(6);
emailCodeRepository.save(EmailCode.builder().email(email).code(code).build());
String mailSubject = "[\uD83D\uDC36 멍하냥] 이메일 인증 코드입니다.";
String mailContent =
Expand All @@ -109,14 +109,14 @@ public void send(String email) {
// sesClient.sendEmail(email, mailSubject, mailContent);
}

private static String getCode() {
private static String getCode(int length) {
ThreadLocalRandom random = ThreadLocalRandom.current();

List<String> authStr = new CopyOnWriteArrayList<>();
for (int i = 0; i < 3; i++) {
for (int i = 0; i < length / 2; i++) {
authStr.add(String.valueOf(random.nextInt(10)));
}
for (int i = 0; i < 3; i++) {
for (int i = 0; i < length / 2; i++) {
authStr.add(String.valueOf((char) (random.nextInt(26) + 65)));
}

Expand Down Expand Up @@ -148,7 +148,7 @@ public void issuePassword(IssuePasswordRequest issuePasswordRequest) {
.findByEmail(issuePasswordRequest.email())
.orElseThrow(() -> new NotFoundException(AuthErrorType.NOT_FOUND));
// 임시비밀번호 발급
String password = getCode();
String password = getCode(10);

String encodedPassword = bCryptPasswordEncoder.encode(password);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,18 @@
import org.ioteatime.meonghanyangserver.cctv.dto.response.CctvInfoListResponse;
import org.ioteatime.meonghanyangserver.cctv.dto.response.CctvInfoResponse;
import org.ioteatime.meonghanyangserver.common.api.Api;
import org.ioteatime.meonghanyangserver.common.utils.LoginMember;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;

@Tag(name = "CCTV Api", description = "CCTV 관련 API 목록입니다.")
public interface CctvApi {
@Operation(summary = "MASTER 회원이 CCTV 퇴출", description = "담당자: 양원채")
Api<?> out(@LoginMember Long userId, @PathVariable Long cctvId);
Api<?> out(Long userId, Long cctvId);

@Operation(summary = "CCTV 정보 목록 조회", description = "담당자: 최민석")
Api<CctvInfoListResponse> cctvInfoList(@LoginMember Long memberId, @PathVariable Long groupId);
Api<CctvInfoListResponse> cctvInfoList(Long memberId, Long groupId);

@Operation(summary = "CCTV 이름 변경", description = "담당자: 양원채")
Api<CctvInfoResponse> updateNickName(
@LoginMember Long memberId, @RequestBody UpdateCctvNickname request);
Api<CctvInfoResponse> updateNickName(Long memberId, UpdateCctvNickname request);

@Operation(summary = "CCTV 정보", description = "담당자: 양원채")
Api<CctvInfoResponse> cctvInfo(@PathVariable("cctvId") Long cctvId);
Api<CctvInfoResponse> cctvInfo(Long cctvId);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.ioteatime.meonghanyangserver.cctv.controller;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.ioteatime.meonghanyangserver.cctv.dto.request.UpdateCctvNickname;
import org.ioteatime.meonghanyangserver.cctv.dto.response.CctvInfoListResponse;
Expand Down Expand Up @@ -31,7 +32,7 @@ public Api<CctvInfoListResponse> cctvInfoList(

@PatchMapping
public Api<CctvInfoResponse> updateNickName(
@LoginMember Long memberId, @RequestBody UpdateCctvNickname request) {
@LoginMember Long memberId, @Valid @RequestBody UpdateCctvNickname request) {
CctvInfoResponse response = cctvService.updateNickname(memberId, request);
return Api.success(CctvSuccessType.UPDATE_NICKNAME, response);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@
import org.ioteatime.meonghanyangserver.cctv.dto.response.CctvSelfInfoResponse;
import org.ioteatime.meonghanyangserver.cctv.dto.response.CreateCctvResponse;
import org.ioteatime.meonghanyangserver.common.api.Api;
import org.ioteatime.meonghanyangserver.common.utils.LoginMember;
import org.springframework.web.bind.annotation.RequestBody;

@Tag(name = "CCTV Device Api", description = "CCTV 기기에서 요청할 수 있는 API 목록입니다.")
public interface CctvDeviceApi {
// 토큰이 없어도 가능해야 함
@Operation(summary = "CCTV 기기 생성 요청", description = "담당자: 임지인")
Api<CreateCctvResponse> createCctv(@RequestBody CreateCctvRequest createCctvRequest);
Api<CreateCctvResponse> createCctv(CreateCctvRequest createCctvRequest);

@Operation(summary = "CCTV 정보", description = "담당자: 최민석")
Api<CctvSelfInfoResponse> cctvInfo(@LoginMember Long cctvId);
Api<CctvSelfInfoResponse> cctvInfo(Long cctvId);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.ioteatime.meonghanyangserver.cctv.controller;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.ioteatime.meonghanyangserver.cctv.dto.request.CreateCctvRequest;
import org.ioteatime.meonghanyangserver.cctv.dto.response.CctvSelfInfoResponse;
Expand All @@ -17,7 +18,8 @@ public class CctvDeviceController implements CctvDeviceApi {
private final CctvService cctvService;

@PostMapping
public Api<CreateCctvResponse> createCctv(@RequestBody CreateCctvRequest createCctvRequest) {
public Api<CreateCctvResponse> createCctv(
@Valid @RequestBody CreateCctvRequest createCctvRequest) {
CreateCctvResponse createCctvResponse = cctvService.createCctv(createCctvRequest);
return Api.success(CctvSuccessType.CREATE_CCTV, createCctvResponse);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ public enum CommonErrorType implements ErrorTypeCode {
NO_SUCH_ELEMENT("NO SUCH ELEMENT", "요소가 존재하지 않습니다"),
IO("I/O", "I/O 오류가 발생하였습니다."),
ILLEGAL_ARGUMENT("ILLEGAL ARGUMENT", "인자 값이 올바르지 않습니다."),
INTERNAL_SERVER("INTERNAL SERVER", "서버 에러가 발생하였습니다. 로그를 확인해 주세요.");
INTERNAL_SERVER("INTERNAL SERVER", "서버 에러가 발생하였습니다. 로그를 확인해 주세요."),
REQUEST_VALIDATION("INVALID VALUE", "요청 형식이 올바르지 않습니다.");

private final String message;
private final String description;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,14 @@
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.common.utils.LoginMember;
import org.ioteatime.meonghanyangserver.fcm.dto.request.SaveFcmTokenRequest;
import org.ioteatime.meonghanyangserver.fcm.dto.response.FcmTopicResponse;
import org.springframework.web.bind.annotation.RequestBody;

@Tag(name = "Fcm Api", description = "알림 관련 API 목록입니다.")
public interface FcmApi {
@Operation(summary = "FCM 토큰 저장", description = "담당자: 양원채")
Api<?> saveToken(
@LoginMember Long memberId, @RequestBody SaveFcmTokenRequest createFcmTokenRequest);
Api<?> saveToken(Long memberId, SaveFcmTokenRequest createFcmTokenRequest);

@Operation(summary = "그룹의 FCM 토픽 조회", description = "담당자: 양원채")
Api<FcmTopicResponse> findFcmTopicByGroupId(@LoginMember Long memberId);
Api<FcmTopicResponse> findFcmTopicByGroupId(Long memberId);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.ioteatime.meonghanyangserver.fcm.controller;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.ioteatime.meonghanyangserver.common.api.Api;
import org.ioteatime.meonghanyangserver.common.type.FcmSuccessType;
Expand All @@ -17,7 +18,8 @@ public class FcmController implements FcmApi {

@PostMapping("/token")
public Api<?> saveToken(
@LoginMember Long memberId, @RequestBody SaveFcmTokenRequest createFcmTokenRequest) {
@LoginMember Long memberId,
@Valid @RequestBody SaveFcmTokenRequest createFcmTokenRequest) {
fcmService.saveToken(memberId, createFcmTokenRequest.token());
return Api.success(FcmSuccessType.SAVE);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ private void exceptionHandle(HttpServletResponse response, ApiExceptionImpl exce
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");

Api<Object> apiResponse = Api.fail(exception);
Api<?> apiResponse = Api.fail(exception);
ObjectMapper objectMapper = new ObjectMapper();
String jsonResponse = objectMapper.writeValueAsString(apiResponse);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,24 @@

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.ioteatime.meonghanyangserver.cctv.dto.response.CctvInviteResponse;
import org.ioteatime.meonghanyangserver.common.api.Api;
import org.ioteatime.meonghanyangserver.common.utils.LoginMember;
import org.ioteatime.meonghanyangserver.group.dto.request.CreateGroupRequest;
import org.ioteatime.meonghanyangserver.group.dto.response.CreateGroupResponse;
import org.ioteatime.meonghanyangserver.group.dto.response.GroupResponse;
import org.ioteatime.meonghanyangserver.group.dto.response.GroupTotalResponse;
import org.springframework.web.bind.annotation.RequestBody;

@Tag(name = "Group Api", description = "Group 관련 API 목록입니다.")
public interface GroupApi {
@Operation(summary = "그룹을 생성합니다.", description = "담당자: 최민석")
Api<CreateGroupResponse> createGroup(
@LoginMember Long memberId, @Valid @RequestBody CreateGroupRequest createGroupRequest);
Api<CreateGroupResponse> createGroup(Long memberId, CreateGroupRequest createGroupRequest);

@Operation(summary = "그룹 초대를 위해 그룹 id를 조회합니다", description = "담당자: 임지인")
Api<GroupResponse> getGroupInfo(@LoginMember Long memberId);
Api<GroupResponse> getGroupInfo(Long memberId);

@Operation(summary = "그룹 id와 신호 채널 이름을 전달합니다.", description = "담당자: 임지인")
Api<CctvInviteResponse> generateCctvInvite(@LoginMember Long memberId);
Api<CctvInviteResponse> generateCctvInvite(Long memberId);

@Operation(summary = "그룹 통합 정보를 조회합니다.", description = "담당자: 최민석")
Api<GroupTotalResponse> getGroupTotalData(@LoginMember Long memberId);
Api<GroupTotalResponse> getGroupTotalData(Long memberId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,25 @@
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.common.utils.LoginMember;
import org.ioteatime.meonghanyangserver.groupmember.dto.request.JoinGroupMemberRequest;
import org.ioteatime.meonghanyangserver.groupmember.dto.response.GroupMemberInfoListResponse;
import org.ioteatime.meonghanyangserver.groupmember.dto.response.GroupMemberResponse;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;

@Tag(name = "Group Member Api", description = "Group Member 관련 API 목록입니다.")
public interface GroupMemberApi {

@Operation(summary = "참여자가 그룹과 역할을 조회합니다.", description = "담당자: 임지인")
Api<GroupMemberResponse> getGroupMemberInfo(@LoginMember Long memberId);
Api<GroupMemberResponse> getGroupMemberInfo(Long memberId);

@Operation(summary = "참여자가 그룹에 입장을 요청합니다.", description = "담당자: 임지인")
Api<?> joinGroupAsMember(
@LoginMember Long memberId, @RequestBody JoinGroupMemberRequest joinGroupMemberRequest);
Api<?> joinGroupAsMember(Long memberId, JoinGroupMemberRequest joinGroupMemberRequest);

@Operation(summary = "방장이 그룹에서 참여자를 제외합니다.", description = "담당자: 최민석")
Api<?> deleteMasterGroupMember(
@LoginMember Long memberId,
@PathVariable Long groupId,
@PathVariable Long groupMemberId);
Api<?> deleteMasterGroupMember(Long memberId, Long groupId, Long groupMemberId);

@Operation(summary = "그룹에서 참여자가 스스로 퇴장합니다.", description = "담당자: 최민석")
Api<?> deleteGroupMember(@LoginMember Long memberId, @PathVariable Long groupId);
Api<?> deleteGroupMember(Long memberId, Long groupId);

@Operation(summary = "그룹 참여자들의 정보를 조회합니다.", description = "담당자: 최민석")
Api<GroupMemberInfoListResponse> getGroupMemberInfoList(
@LoginMember Long memberId, @PathVariable Long groupId);
Api<GroupMemberInfoListResponse> getGroupMemberInfoList(Long memberId, Long groupId);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.ioteatime.meonghanyangserver.groupmember.controller;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.ioteatime.meonghanyangserver.common.api.Api;
import org.ioteatime.meonghanyangserver.common.type.GroupSuccessType;
Expand All @@ -25,7 +26,7 @@ public Api<GroupMemberResponse> getGroupMemberInfo(@LoginMember Long memberId) {
@PostMapping("/viewer")
public Api<?> joinGroupAsMember(
@LoginMember Long memberId,
@RequestBody JoinGroupMemberRequest joinGroupMemberRequest) {
@Valid @RequestBody JoinGroupMemberRequest joinGroupMemberRequest) {
groupMemberService.joinGroupMember(memberId, joinGroupMemberRequest);
return Api.success(GroupSuccessType.JOIN_GROUP_MEMBER);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class ApiExceptionHandler {
private final SlackService slackService;

@ExceptionHandler(value = ApiExceptionImpl.class)
public ResponseEntity<Api<Object>> apiResponseEntity(ApiExceptionImpl apiExceptionImpl) {
public ResponseEntity<Api<?>> apiResponseEntity(ApiExceptionImpl apiExceptionImpl) {
log.info("{}", apiExceptionImpl);
slackService.sendSlackMessage(apiExceptionImpl.getHttpStatus(), apiExceptionImpl, "error");
return ResponseEntity.status(apiExceptionImpl.getHttpStatus())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public void onLogoutSuccess(
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");

Api<Object> apiResponse = Api.success(AuthSuccessType.SIGN_OUT);
Api<?> apiResponse = Api.success(AuthSuccessType.SIGN_OUT);
ObjectMapper objectMapper = new ObjectMapper();
String jsonResponse = objectMapper.writeValueAsString(apiResponse);

Expand Down
Loading

0 comments on commit 2a17b0c

Please sign in to comment.