Skip to content

Commit

Permalink
feat: 검수 중인 장소에 대한 장소 등록 허가 API 구현 (#398)
Browse files Browse the repository at this point in the history
* feat: 임시용 TemporaryPlaceService 생성

* refactor: 바뀐 요구사항에 맞게 createPlace 로직 리팩터링

* refactor: 바뀐 API 명세에 따라 컨트롤러 로직 리팩터링

* fix: 잘못된 base64 디코딩 과정 수정

* feat: 장소 등록 API에 매니저 인터셉터 적용

* feat: 등록할 장소 기준 반경 20M 내에 또 다른 등록된 장소가 존재한다면 예외를 터뜨리도록 수정

* test: 주변 반경 20M 내에 등록된 장소가 있을 때 예외 발생 확인을 위한 테스트 코드 추가

* refactor: collect() 에서 toList() 로 변경

* chore: 주석 삭제
  • Loading branch information
kokodak authored Oct 5, 2023
1 parent ef00542 commit 6587564
Show file tree
Hide file tree
Showing 11 changed files with 224 additions and 170 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class ManagerAuthInterceptor implements HandlerInterceptor {

public static final int AUTH_HEADER_INFO_SIZE = 2;

public static final String AUTH_HEADER_TYPE = "Basic ";
public static final String AUTH_HEADER_TYPE = "Basic";

@Value("${manager.id}")
private String id;
Expand All @@ -41,12 +41,12 @@ private List<String> extractHeaderInfo(final HttpServletRequest request) {
if (header == null) {
throw new AuthException(NOT_EXIST_HEADER);
}
final String decodedHeader = new String(Base64.getDecoder().decode(header));
if (!decodedHeader.startsWith(AUTH_HEADER_TYPE)) {
final String[] authHeader = header.split(" ");
if (!AUTH_HEADER_TYPE.equalsIgnoreCase(authHeader[0])) {
throw new AuthException(INVALID_HEADER);
}
final String decodedHeaderWithoutType = decodedHeader.replace(AUTH_HEADER_TYPE, "");
final String[] idAndPassword = decodedHeaderWithoutType.split(":");
final String decodedHeader = new String(Base64.getDecoder().decode(authHeader[1]));
final String[] idAndPassword = decodedHeader.split(":");
if (idAndPassword.length != AUTH_HEADER_INFO_SIZE) {
throw new AuthException(INVALID_HEADER);
}
Expand Down
19 changes: 15 additions & 4 deletions backend/src/main/java/com/now/naaga/common/config/WebConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import com.now.naaga.auth.presentation.argumentresolver.MemberAuthArgumentResolver;
import com.now.naaga.auth.presentation.argumentresolver.PlayerArgumentResolver;
import com.now.naaga.auth.presentation.interceptor.AuthInterceptor;
import com.now.naaga.auth.presentation.interceptor.ManagerAuthInterceptor;
import com.now.naaga.common.presentation.interceptor.RequestMatcherInterceptor;
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
Expand All @@ -13,8 +15,6 @@
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
public class WebConfig implements WebMvcConfigurer {

Expand All @@ -24,20 +24,25 @@ public class WebConfig implements WebMvcConfigurer {

private final AuthInterceptor authInterceptor;

private final ManagerAuthInterceptor managerAuthInterceptor;

@Value("${manager.origin-url}")
private String managerUriPath;

public WebConfig(final PlayerArgumentResolver playerArgumentResolver,
final MemberAuthArgumentResolver memberAuthArgumentResolver,
final AuthInterceptor authInterceptor) {
final AuthInterceptor authInterceptor,
final ManagerAuthInterceptor managerAuthInterceptor) {
this.playerArgumentResolver = playerArgumentResolver;
this.memberAuthArgumentResolver = memberAuthArgumentResolver;
this.authInterceptor = authInterceptor;
this.managerAuthInterceptor = managerAuthInterceptor;
}

@Override
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(mapAuthInterceptor());
registry.addInterceptor(mapManagerAuthInterceptor());
}

private HandlerInterceptor mapAuthInterceptor() {
Expand All @@ -51,7 +56,13 @@ private HandlerInterceptor mapAuthInterceptor() {
.excludeRequestPattern("/**/*.gif")
.excludeRequestPattern("/**/*.ico")
.excludeRequestPattern("/ranks")
.excludeRequestPattern("/**", HttpMethod.OPTIONS);
.excludeRequestPattern("/**", HttpMethod.OPTIONS)
.excludeRequestPattern("/places", HttpMethod.POST);
}

private HandlerInterceptor mapManagerAuthInterceptor() {
return new RequestMatcherInterceptor(managerAuthInterceptor)
.includeRequestPattern("/places", HttpMethod.POST);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import static com.now.naaga.place.exception.PlaceExceptionType.NO_EXIST;

import com.now.naaga.common.domain.OrderType;
import com.now.naaga.common.infrastructure.FileManager;
import com.now.naaga.place.application.dto.CreatePlaceCommand;
import com.now.naaga.place.application.dto.FindAllPlaceCommand;
import com.now.naaga.place.application.dto.FindPlaceByIdCommand;
Expand All @@ -17,13 +16,10 @@
import com.now.naaga.place.persistence.repository.PlaceRepository;
import com.now.naaga.player.application.PlayerService;
import com.now.naaga.player.domain.Player;
import java.io.File;
import com.now.naaga.temporaryplace.application.TemporaryPlaceService;
import java.util.List;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

@Transactional
@Service
Expand All @@ -33,22 +29,22 @@ public class PlaceService {

private final PlayerService playerService;

private final TemporaryPlaceService temporaryPlaceService;

private final PlaceCheckService placeCheckService;

private final PlaceRecommendService placeRecommendService;

private final FileManager<MultipartFile> fileManager;

public PlaceService(final PlaceRepository placeRepository,
final PlayerService playerService,
final TemporaryPlaceService temporaryPlaceService,
final PlaceCheckService placeCheckService,
final PlaceRecommendService placeRecommendService,
final FileManager<MultipartFile> fileManager) {
final PlaceRecommendService placeRecommendService) {
this.placeRepository = placeRepository;
this.playerService = playerService;
this.temporaryPlaceService = temporaryPlaceService;
this.placeCheckService = placeCheckService;
this.placeRecommendService = placeRecommendService;
this.fileManager = fileManager;
}

@Transactional(readOnly = true)
Expand All @@ -63,7 +59,7 @@ public List<Place> findAllPlace(final FindAllPlaceCommand findAllPlaceCommand) {
@Transactional(readOnly = true)
public Place findPlaceById(final FindPlaceByIdCommand findPlaceByIdCommand) {
return placeRepository.findById(findPlaceByIdCommand.placeId())
.orElseThrow(() -> new PlaceException(NO_EXIST));
.orElseThrow(() -> new PlaceException(NO_EXIST));
}

@Transactional(readOnly = true)
Expand All @@ -73,23 +69,18 @@ public Place recommendPlaceByPosition(final RecommendPlaceCommand recommendPlace
}

public Place createPlace(final CreatePlaceCommand createPlaceCommand) {
final Position position = createPlaceCommand.position();
placeCheckService.checkOtherPlaceNearby(position);
final File uploadPath = fileManager.save(createPlaceCommand.imageFile());
try {
final Long playerId = createPlaceCommand.playerId();
final Player registeredPlayer = playerService.findPlayerById(playerId);
final Place place = new Place(
createPlaceCommand.name(),
createPlaceCommand.description(),
position,
fileManager.convertToUrlPath(uploadPath),
registeredPlayer);
placeRepository.save(place);
return place;
} catch (final RuntimeException exception) {
uploadPath.delete();
throw exception;
}
placeCheckService.checkOtherPlaceNearby(createPlaceCommand.position());

final Long registeredPlayerId = createPlaceCommand.registeredPlayerId();
final Player registeredPlayer = playerService.findPlayerById(registeredPlayerId);
final Place place = new Place(createPlaceCommand.name(),
createPlaceCommand.description(),
createPlaceCommand.position(),
createPlaceCommand.imageUrl(),
registeredPlayer);

placeRepository.save(place);
temporaryPlaceService.deleteById(createPlaceCommand.temporaryPlaceId());
return place;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,24 @@

import com.now.naaga.place.domain.Position;
import com.now.naaga.place.presentation.dto.CreatePlaceRequest;
import com.now.naaga.player.presentation.dto.PlayerRequest;
import org.springframework.web.multipart.MultipartFile;

public record CreatePlaceCommand(Long playerId,
String name,
public record CreatePlaceCommand(String name,
String description,
Position position,
MultipartFile imageFile) {
String imageUrl,
Long registeredPlayerId,
Long temporaryPlaceId) {

public static CreatePlaceCommand of(final PlayerRequest playerRequest,
final CreatePlaceRequest createPlaceRequest) {
public static CreatePlaceCommand from(final CreatePlaceRequest createPlaceRequest) {
Position position = Position.of(createPlaceRequest.latitude(), createPlaceRequest.longitude());

return new CreatePlaceCommand(
playerRequest.playerId(),
createPlaceRequest.name(),
createPlaceRequest.description(),
position,
createPlaceRequest.imageFile()
createPlaceRequest.imageUrl(),
createPlaceRequest.registeredPlayerId(),
createPlaceRequest.temporaryPlaceId()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
Expand Down Expand Up @@ -54,14 +54,13 @@ public ResponseEntity<PlaceResponse> findPlaceById(@PathVariable Long placeId) {
}

@PostMapping
public ResponseEntity<PlaceResponse> createPlace(@Auth final PlayerRequest playerRequest,
@ModelAttribute final CreatePlaceRequest createPlaceRequest) {
CreatePlaceCommand createPlaceCommand = CreatePlaceCommand.of(playerRequest, createPlaceRequest);
final Place savedPlace = placeService.createPlace(createPlaceCommand);
final PlaceResponse response = PlaceResponse.from(savedPlace);
public ResponseEntity<PlaceResponse> createPlace(@RequestBody final CreatePlaceRequest createPlaceRequest) {
final CreatePlaceCommand createPlaceCommand = CreatePlaceCommand.from(createPlaceRequest);
final Place place = placeService.createPlace(createPlaceCommand);
final PlaceResponse response = PlaceResponse.from(place);
return ResponseEntity
.status(HttpStatus.CREATED)
.location(URI.create("/places/" + savedPlace.getId()))
.location(URI.create("/places/" + place.getId()))
.body(response);
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.now.naaga.place.presentation.dto;

import org.springframework.web.multipart.MultipartFile;

public record CreatePlaceRequest(String name,
String description,
Double latitude,
Double longitude,
MultipartFile imageFile) {
String imageUrl,
Long registeredPlayerId,
Long temporaryPlaceId) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.now.naaga.place.domain.Place;
import java.util.List;
import java.util.stream.Collectors;

public record PlaceResponse(Long id,
String name,
Expand All @@ -22,7 +21,7 @@ public static PlaceResponse from(final Place savedPlace) {

public static List<PlaceResponse> convertToPlaceResponses(final List<Place> places) {
return places.stream()
.map(PlaceResponse::from)
.collect(Collectors.toList());
.map(PlaceResponse::from)
.toList();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.now.naaga.temporaryplace.application;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Transactional
@Service
public class TemporaryPlaceService {

public void deleteById(final Long id) {
return;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ class ManagerAuthInterceptorTest {
@Test
void Auth_헤더를_Base64_헤더를_디코딩해서_관리자_로그인을_처리한다() throws Exception {
// given
final String s = "Basic "+id+":"+password;
final String s = id + ":" + password;
final String authHeader = new String(Base64.getEncoder().encode(s.getBytes()));
final MockHttpServletRequest request = new MockHttpServletRequest();
final MockHttpServletResponse response = new MockHttpServletResponse();
final Controller controller = Mockito.mock(Controller.class);
request.addHeader("Authorization", authHeader);
request.addHeader("Authorization", "Basic " + authHeader);

// when
final boolean expected = managerAuthInterceptor.preHandle(request, response, controller);
Expand All @@ -53,12 +53,12 @@ class ManagerAuthInterceptorTest {
@Test
void 잘못된_관리자_정보를_입력하면_예외를_발생한다() throws Exception {
// given
final String s = "Basic wrongId:wrongPW";
final String s = "wrongId:wrongPW";
final String authHeader = new String(Base64.getEncoder().encode(s.getBytes()));
final MockHttpServletRequest request = new MockHttpServletRequest();
final MockHttpServletResponse response = new MockHttpServletResponse();
final Controller controller = Mockito.mock(Controller.class);
request.addHeader("Authorization", authHeader);
request.addHeader("Authorization", "Basic " + authHeader);

// when & then
assertThatThrownBy(() -> managerAuthInterceptor.preHandle(request, response, controller)).isInstanceOf(AuthException.class);
Expand Down
Loading

0 comments on commit 6587564

Please sign in to comment.