Skip to content

Commit

Permalink
Feat: 가이드라인 관련된 로직 및 테스트 코드 구현 (#53)
Browse files Browse the repository at this point in the history
* feat: 가이드라인 dto(request) 추가

* refactor: 엔터티 이름 수정

* feat: GuardGuidelineRepository 추가

* refactor: 매개변수에 코드컨벤션 적용해 수정

* refactor: type 필드의 데이터 타입 String에서 enum으로 변경

* refactor: dto에서 type 필드 데이터 타입 수정

* feat: GuardGuidelineRepository 구현

* feat: GuardGuidelineService 추가 및 구현

* refactor: type 필드 종류 수정

* feat: GuardGuidelineController 구현

* feat: GuardGuidelineNotFoundException 구현

* feat: ControllerAdvice 구현

* refactor: Reformat Code

* refactor: 엔터티 테스트를 위한 getID()메서드 추가

* refactor: Reformat Code

* feat: 엔터티 테스트 코드 작성

* feat: Repository 테스트 코드 작성

* refactor: 사용하지 않는 매개변수 삭제

* refactor: 기본생성자 접근 제한자 protected로 수정

* feat: 해당 시니어에 대한 보호자 검증에 실패했을 때 발생시킬 예외클래스 구현

* refactor: 가이드라인 업데이트 및 추가 시 해당 시니어의 보호자인지 회원검증하는 로직 추가

* refactor: 기본 생성자의 접근제한자를 protected로 수정

* refactor: 엔터티만 독립적으로 테스트하도록 수정 및 @DisplayName 추가

* refactor: GuardGuidelineRepositoryTest에 @DisplayName 추가
  • Loading branch information
eunsoni authored Oct 12, 2024
1 parent 164f38a commit 7708ed4
Show file tree
Hide file tree
Showing 13 changed files with 401 additions and 43 deletions.
Original file line number Diff line number Diff line change
@@ -1,53 +1,57 @@
package com.example.sinitto.guardGuideline.controller;

import com.example.sinitto.common.annotation.MemberId;
import com.example.sinitto.guardGuideline.dto.GuardGuidelineRequest;
import com.example.sinitto.guardGuideline.dto.GuardGuidelineResponse;
import com.example.sinitto.guardGuideline.entity.GuardGuideline;
import com.example.sinitto.guardGuideline.service.GuardGuidelineService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/api/guardguidelines")
@Tag(name = "[미구현][의논필요]보호자용 가이드라인", description = "보호자가 입력하는 시니어별 가이드라인 관련 API")
@Tag(name = "보호자용 가이드라인", description = "보호자가 입력하는 시니어별 가이드라인 관련 API")
public class GuardGuidelineController {

private final GuardGuidelineService guardGuidelineService;

public GuardGuidelineController(GuardGuidelineService guardGuidelineService) {this.guardGuidelineService = guardGuidelineService;}

@Operation(summary = "가이드라인 추가", description = "보호자가 시니어별 가이드라인을 추가합니다.")
@PostMapping
public ResponseEntity<String> addGuideline(@RequestBody GuardGuidelineRequest request) {
// 임시 응답
public ResponseEntity<String> addGuardGuideline(@MemberId Long memberId, @RequestBody GuardGuidelineRequest guardGuidelineRequest) {
guardGuidelineService.addGuardGuideline(memberId, guardGuidelineRequest);
return ResponseEntity.ok("가이드라인이 추가되었습니다.");
}

@Operation(summary = "카테고리에 해당하는 모든 가이드라인 조회", description = "시니또용 앱에서 카테고리에 해당하는 모든 가이드라인들을 요청할 때 필요합니다.")
@GetMapping("/{seniorId}/{typeId}")
public ResponseEntity<List<GuardGuidelineResponse>> getGuidelinesByCategory(@PathVariable Long seniorId, @PathVariable Long typeId) {
// 임시 응답
return ResponseEntity.ok(new ArrayList<>());
@GetMapping("/{seniorId}/{type}")
public ResponseEntity<List<GuardGuidelineResponse>> getGuardGuidelinesByCategory(@PathVariable Long seniorId, @PathVariable GuardGuideline.Type type) {
return ResponseEntity.ok(guardGuidelineService.readAllGuardGuidelinesByCategory(seniorId, type));
}

@Operation(summary = "가이드라인 수정", description = "보호자가 특정 가이드라인을 수정할 때 필요합니다.")
@PutMapping("/{guidelineId}")
public ResponseEntity<String> updateGuideline(@PathVariable Long guidelineId, @RequestBody GuardGuidelineRequest request) {
// 임시 응답
public ResponseEntity<String> updateGuardGuideline(@MemberId Long memberId, @PathVariable Long guidelineId, @RequestBody GuardGuidelineRequest guardGuidelineRequest) {
guardGuidelineService.updateGuardGuideline(memberId, guidelineId, guardGuidelineRequest);
return ResponseEntity.ok("가이드라인이 수정되었습니다.");
}

@Operation(summary = "모든 가이드라인 조회(시니어별로)", description = "보호자가 가이드라인 수정을 위해 시니어별로 모든 가이드라인을 요청할 때 필요합니다.")
@GetMapping("/{seniorId}")
public ResponseEntity<List<GuardGuidelineResponse>> getAllGuidelinesBySenior(@PathVariable Long seniorId) {
// 임시 응답
return ResponseEntity.ok(new ArrayList<>());
public ResponseEntity<List<GuardGuidelineResponse>> getAllGuardGuidelinesBySenior(@PathVariable Long seniorId) {

return ResponseEntity.ok(guardGuidelineService.readAllGuardGuidelinesBySenior(seniorId));
}

@Operation(summary = "특정 가이드라인 조회", description = "보호자용 API입니다.")
@GetMapping("/{guidelineId}")
public ResponseEntity<GuardGuidelineResponse> getGuideline(@PathVariable Long guidelineId) {
// 임시 응답
return ResponseEntity.ok(new GuardGuidelineResponse(null, null));
public ResponseEntity<GuardGuidelineResponse> getGuardGuideline(@PathVariable Long guidelineId) {
return ResponseEntity.ok(guardGuidelineService.readGuardGuideline(guidelineId));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.example.sinitto.guardGuideline.controller;

import com.example.sinitto.guardGuideline.exception.GuardGuidelineNotFoundException;
import com.example.sinitto.guardGuideline.exception.SeniorAndGuardMemberMismatchException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ProblemDetail;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.net.URI;

@RestControllerAdvice(basePackages = "com.example.sinitto.guardGuideline")
public class GuardGuidelineControllerAdvice {

@ExceptionHandler(GuardGuidelineNotFoundException.class)
public ResponseEntity<ProblemDetail> handleGuardGuidelineNotFoundException(GuardGuidelineNotFoundException e) {
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.NOT_FOUND, e.getMessage());
problemDetail.setType(URI.create("/error/guideline-not-found"));
problemDetail.setTitle("Guideline Not Found");

return ResponseEntity.status(HttpStatus.NOT_FOUND).body(problemDetail);
}

@ExceptionHandler(SeniorAndGuardMemberMismatchException.class)
public ResponseEntity<ProblemDetail> handleSeniorAndGuardMemberMismatchException(SeniorAndGuardMemberMismatchException e) {
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, e.getMessage());
problemDetail.setType(URI.create("/error/member-mismatch"));
problemDetail.setTitle("Senior and Guard Member Mismatch");

return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(problemDetail);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
package com.example.sinitto.guardGuideline.dto;

public record GuardGuidelineRequest() {
}
import com.example.sinitto.guardGuideline.entity.GuardGuideline;

public record GuardGuidelineRequest(
Long seniorId,
GuardGuideline.Type type,
String title,
String content
) {}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.example.sinitto.guardGuideline.dto;

import com.example.sinitto.guardGuideline.entity.GuardGuideline;

public record GuardGuidelineResponse(
GuardGuideline.Type type,
String title,
String content) {
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.example.sinitto.guardGuideline.entity;

import com.example.sinitto.member.entity.Senior;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;

@Entity
public class GuardGuideline {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull
@Enumerated(EnumType.STRING)
private Type type;
@NotNull
private String title;
@NotNull
private String content;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "senior_id")
@NotNull
@OnDelete(action = OnDeleteAction.CASCADE)
private Senior senior;

protected GuardGuideline() {
}

public GuardGuideline(Type type, String title, String content, Senior senior) {
this.type = type;
this.title = title;
this.content = content;
this.senior = senior;
}


public void updateGuardGuideline(Type type, String title, String content) {
this.type = type;
this.title = title;
this.content = content;
}

public Long getId() {
return id;
}

public Type getType() {
return type;
}

public String getTitle() {
return title;
}

public String getContent() {
return content;
}

public Senior getSenior() {
return senior;
}


public enum Type {
TAXI,
DELIVERY
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.example.sinitto.guardGuideline.exception;

public class GuardGuidelineNotFoundException extends RuntimeException {
public GuardGuidelineNotFoundException(String message) {super(message);}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.example.sinitto.guardGuideline.exception;

public class SeniorAndGuardMemberMismatchException extends RuntimeException {
public SeniorAndGuardMemberMismatchException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.example.sinitto.guardGuideline.repository;

import com.example.sinitto.guardGuideline.entity.GuardGuideline;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;


@Repository
public interface GuardGuidelineRepository extends JpaRepository<GuardGuideline, Long> {
List<GuardGuideline> findBySeniorId(Long seniorId);

List<GuardGuideline> findBySeniorIdAndType(Long seniorId, GuardGuideline.Type type);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package com.example.sinitto.guardGuideline.service;


import com.example.sinitto.guard.exception.SeniorNotFoundException;
import com.example.sinitto.guard.repository.SeniorRepository;
import com.example.sinitto.guardGuideline.dto.GuardGuidelineRequest;
import com.example.sinitto.guardGuideline.dto.GuardGuidelineResponse;
import com.example.sinitto.guardGuideline.entity.GuardGuideline;
import com.example.sinitto.guardGuideline.entity.GuardGuideline.Type;
import com.example.sinitto.guardGuideline.exception.GuardGuidelineNotFoundException;
import com.example.sinitto.guardGuideline.exception.SeniorAndGuardMemberMismatchException;
import com.example.sinitto.guardGuideline.repository.GuardGuidelineRepository;
import com.example.sinitto.member.entity.Senior;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
public class GuardGuidelineService {

private final GuardGuidelineRepository guardGuidelineRepository;
private final SeniorRepository seniorRepository;

public GuardGuidelineService (GuardGuidelineRepository guardGuidelineRepository, SeniorRepository seniorRepository){
this.guardGuidelineRepository = guardGuidelineRepository;
this.seniorRepository = seniorRepository;
}

@Transactional
public void addGuardGuideline(Long memberId, GuardGuidelineRequest guardGuidelineRequest) {
Senior senior = seniorRepository.findById(guardGuidelineRequest.seniorId()).orElseThrow(
() -> new SeniorNotFoundException("시니어를 찾을 수 없습니다.")
);
if (senior.isNotGuard(memberId)) {
throw new SeniorAndGuardMemberMismatchException("해당 Guard의 Senior가 아닙니다.");
}

guardGuidelineRepository.save(new GuardGuideline(guardGuidelineRequest.type(), guardGuidelineRequest.title(), guardGuidelineRequest.content(), senior));
}

@Transactional(readOnly = true)
public List<GuardGuidelineResponse> readAllGuardGuidelinesByCategory(Long seniorId, Type type){
List<GuardGuideline> guardGuidelines = guardGuidelineRepository.findBySeniorIdAndType(seniorId, type);

return guardGuidelines.stream()
.map(m -> new GuardGuidelineResponse(m.getType(), m.getTitle(), m.getContent()))
.toList();
}

@Transactional
public void updateGuardGuideline(Long memberId, Long guidelineId, GuardGuidelineRequest guardGuidelineRequest) {
GuardGuideline guardGuideline = guardGuidelineRepository.findById(guidelineId).orElseThrow(
()-> new GuardGuidelineNotFoundException("해당 가이드라인이 존재하지 않습니다.")
);

Senior senior = seniorRepository.findById(guardGuidelineRequest.seniorId()).orElseThrow(
() -> new SeniorNotFoundException("시니어를 찾을 수 없습니다.")
);

if (senior.isNotGuard(memberId)) {
throw new SeniorAndGuardMemberMismatchException("해당 Guard의 Senior가 아닙니다.");
}

guardGuideline.updateGuardGuideline(guardGuidelineRequest.type(), guardGuidelineRequest.title(), guardGuidelineRequest.content());
}

@Transactional(readOnly = true)
public List<GuardGuidelineResponse> readAllGuardGuidelinesBySenior(Long seniorId){
List<GuardGuideline> guardGuidelines = guardGuidelineRepository.findBySeniorId(seniorId);

return guardGuidelines.stream()
.map(m -> new GuardGuidelineResponse(m.getType(), m.getTitle(), m.getContent()))
.toList();
}

@Transactional(readOnly = true)
public GuardGuidelineResponse readGuardGuideline(Long guidelineId){
GuardGuideline guardGuideline = guardGuidelineRepository.findById(guidelineId).orElseThrow(
()-> new GuardGuidelineNotFoundException("해당 가이드라인이 존재하지 않습니다.")
);

return new GuardGuidelineResponse(guardGuideline.getType(), guardGuideline.getTitle(), guardGuideline.getContent());
}

}
4 changes: 4 additions & 0 deletions src/main/java/com/example/sinitto/member/entity/Senior.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ public Senior(String name, String phoneNumber, Member member) {
protected Senior() {
}

public boolean isNotGuard(Long memberId) {
return !this.member.getId().equals(memberId);
}

public void updateSenior(String name, String phoneNumber) {
this.name = name;
this.phoneNumber = phoneNumber;
Expand Down
Loading

0 comments on commit 7708ed4

Please sign in to comment.