Skip to content

Commit

Permalink
Merge pull request #20 from PawWithU/feat/19-nickname-isduplicated-api
Browse files Browse the repository at this point in the history
[Feature] 닉네임 중복 검사 API 구현
  • Loading branch information
kyeong-hyeok authored Oct 28, 2023
2 parents 79866a4 + 9d67b43 commit ec2b270
Show file tree
Hide file tree
Showing 8 changed files with 173 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ public SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospe
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(request ->
request.requestMatchers(mvcMatcherBuilder.pattern("/login")).permitAll()
.requestMatchers(mvcMatcherBuilder.pattern("/sign-up/**")).permitAll()
.requestMatchers(mvcMatcherBuilder.pattern("volunteers/sign-up/**")).permitAll()
.requestMatchers(mvcMatcherBuilder.pattern("intermediaries/sign-up/**")).permitAll()
.requestMatchers(mvcMatcherBuilder.pattern("/h2-console/**")).permitAll()
.requestMatchers(mvcMatcherBuilder.pattern("/css/**")).permitAll()
.requestMatchers(mvcMatcherBuilder.pattern("/js/**")).permitAll()
Expand All @@ -48,7 +49,7 @@ public SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospe
.requestMatchers(mvcMatcherBuilder.pattern("/swagger-ui/**")).permitAll()
.requestMatchers(mvcMatcherBuilder.pattern("/swagger-resources/**")).permitAll()
.requestMatchers(mvcMatcherBuilder.pattern("/v3/api-docs/**")).permitAll()
.requestMatchers(mvcMatcherBuilder.pattern("/members/userName/isDuplicated")).permitAll()
.requestMatchers(mvcMatcherBuilder.pattern("/volunteers/nickname/isDuplicated")).permitAll()
.anyRequest().authenticated())
.exceptionHandling(exception -> exception
.authenticationEntryPoint(jwtAuthenticationEntryPoint)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,11 @@
import org.springframework.http.ResponseEntity;
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;

@Tag(name = "Sign-Up", description = "Sign-Up API")
@RestController
@RequiredArgsConstructor
@RequestMapping("/sign-up")
public class SignUpController {

private final AuthService authService;
Expand All @@ -34,7 +32,7 @@ public class SignUpController {
, description = "1. 이미 존재하는 이메일입니다. \t\n 2. 이미 존재하는 사용자 닉네임입니다."
, content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
@PostMapping
@PostMapping("volunteers/sign-up")
public ResponseEntity<Void> signUp(@RequestBody VolunteerSignUpRequest volunteerSignUpRequest) {
authService.signUp(volunteerSignUpRequest);
return ResponseEntity.noContent().build();
Expand All @@ -46,7 +44,7 @@ public ResponseEntity<Void> signUp(@RequestBody VolunteerSignUpRequest volunteer
, description = "V1, 이메일 형식에 맞지 않습니다. \t\n V1, 이메일은 필수 입력 값입니다. \t\n A1, 이미 존재하는 이메일입니다. \t\n A4, 이메일 인증 코드 전송을 실패했습니다."
, content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
@PostMapping("/email")
@PostMapping(value = {"/volunteers/sign-up/email", "/intermediaries/sign-up/email"})
public ResponseEntity<EmailResponse> mailConfirm(@RequestBody @Valid EmailRequest emailRequest){
EmailResponse emailResponse = emailService.sendEmail(emailRequest);
return ResponseEntity.ok(emailResponse);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.pawwithu.connectdog.domain.volunteer.controller;

import com.pawwithu.connectdog.domain.volunteer.dto.request.NicknameRequest;
import com.pawwithu.connectdog.domain.volunteer.dto.response.NicknameResponse;
import com.pawwithu.connectdog.domain.volunteer.service.VolunteerService;
import com.pawwithu.connectdog.error.dto.ErrorResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
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;

@Tag(name = "Volunteer", description = "Volunteer API")
@RestController
@RequiredArgsConstructor
@RequestMapping("/volunteers")
public class VolunteerController {

private final VolunteerService volunteerService;

@Operation(summary = "닉네임 중복 여부 확인", description = "닉네임 중복 여부를 확인합니다.",
responses = {
@ApiResponse(responseCode = "200", description = "닉네임 중복 여부 확인 성공")
, @ApiResponse(responseCode = "400", description = "V1, 닉네임은 한글, 숫자만 사용가능합니다. \t\n V1, 닉네임은 필수 입력 값입니다. \t\n V1, 2~10자의 닉네임이어야 합니다.", content = @Content(schema = @Schema(implementation = ErrorResponse.class)))})
@PostMapping("/nickname/isDuplicated")
public ResponseEntity<NicknameResponse> isNicknameDuplicated(@RequestBody @Valid NicknameRequest nickNameRequest) {
NicknameResponse response = volunteerService.isNicknameDuplicated(nickNameRequest);
return ResponseEntity.ok(response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.pawwithu.connectdog.domain.volunteer.dto.request;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;

public record NicknameRequest(@Pattern(regexp = "^[가-힣0-9]*$", message = "닉네임은 한글, 숫자만 사용가능합니다.")
@NotBlank(message = "닉네임은 필수 입력 값입니다.")
@Size(min=2, max=10, message = "2~10자의 닉네임이어야 합니다.")String nickname) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.pawwithu.connectdog.domain.volunteer.dto.response;

public record NicknameResponse(Boolean isDuplicated) {

public static NicknameResponse of(Boolean isDuplicated){
return new NicknameResponse(isDuplicated);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.pawwithu.connectdog.domain.volunteer.service;

import com.pawwithu.connectdog.domain.volunteer.dto.request.NicknameRequest;
import com.pawwithu.connectdog.domain.volunteer.dto.response.NicknameResponse;
import com.pawwithu.connectdog.domain.volunteer.repository.VolunteerRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
@Transactional
@RequiredArgsConstructor
public class VolunteerService {

private final VolunteerRepository volunteerRepository;

@Transactional(readOnly = true)
public NicknameResponse isNicknameDuplicated(NicknameRequest nickNameRequest) {
Boolean isDuplicated = volunteerRepository.existsByNickname(nickNameRequest.nickname());
NicknameResponse response = NicknameResponse.of(isDuplicated);
return response;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.pawwithu.connectdog.domain.volunteer.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.pawwithu.connectdog.domain.volunteer.dto.request.NicknameRequest;
import com.pawwithu.connectdog.domain.volunteer.dto.response.NicknameResponse;
import com.pawwithu.connectdog.domain.volunteer.service.VolunteerService;
import com.pawwithu.connectdog.utils.TestUserArgumentResolver;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.filter.CharacterEncodingFilter;

import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;


@ExtendWith(MockitoExtension.class)
class VolunteerControllerTest {

@InjectMocks
private VolunteerController volunteerController;
@Mock
private VolunteerService volunteerService;
private ObjectMapper objectMapper = new ObjectMapper();
private MockMvc mockMvc;

@BeforeEach
void setUp() {
mockMvc = MockMvcBuilders.standaloneSetup(volunteerController)
.setCustomArgumentResolvers(new TestUserArgumentResolver())
.addFilter(new CharacterEncodingFilter("UTF-8", true))
.build();
}

@Test
void 닉네임_중복_검사() throws Exception {
//given
NicknameRequest request = new NicknameRequest("코넥독123");
NicknameResponse response = new NicknameResponse(false);

//when
given(volunteerService.isNicknameDuplicated(request)).willReturn(response);
ResultActions result = mockMvc.perform(
post("/volunteers/nickname/isDuplicated")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request))
);

//then
result.andExpect(status().isOk());
verify(volunteerService, times(1)).isNicknameDuplicated(request);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.pawwithu.connectdog.utils;

import org.springframework.core.MethodParameter;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;

public class TestUserArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().equals(UserDetails.class);
}

@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
UserDetails userDetails = mock(UserDetails.class);
given(userDetails.getUsername()).willReturn("email");
return userDetails;
}
}

0 comments on commit ec2b270

Please sign in to comment.