diff --git a/src/main/java/javalab/umc7th_mission/apiPayload/code/status/ErrorStatus.java b/src/main/java/javalab/umc7th_mission/apiPayload/code/status/ErrorStatus.java index 996dfda..8d9ec3f 100644 --- a/src/main/java/javalab/umc7th_mission/apiPayload/code/status/ErrorStatus.java +++ b/src/main/java/javalab/umc7th_mission/apiPayload/code/status/ErrorStatus.java @@ -17,6 +17,7 @@ public enum ErrorStatus implements BaseErrorCode { NICKNAME_NOT_EXIST(HttpStatus.BAD_REQUEST, "MEMBER4002", "닉네임은 필수 입니다."), ARTICLE_NOT_FOUND(HttpStatus.NOT_FOUND, "ARTICLE4001", "게시글이 없습니다."), TEMP_EXCEPTION(HttpStatus.BAD_REQUEST, "TEMP4001", "이거는 테스트"); + FOOD_CATEGORY_NOT_FOUND(HttpStatus.NOT_FOUND, "FOOD4001", "존재하지 않는 음식 카테고리입니다."); private final HttpStatus httpStatus; private final String code; private final String message; diff --git a/src/main/java/javalab/umc7th_mission/apiPayload/exception/ExceptionAdvice.java b/src/main/java/javalab/umc7th_mission/apiPayload/exception/ExceptionAdvice.java index 196411c..44aa7af 100644 --- a/src/main/java/javalab/umc7th_mission/apiPayload/exception/ExceptionAdvice.java +++ b/src/main/java/javalab/umc7th_mission/apiPayload/exception/ExceptionAdvice.java @@ -1,4 +1,4 @@ -package umc.spring.apiPayload.exception; +package javalab.umc7th_mission.apiPayload.exception; import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.ConstraintViolationException; diff --git a/src/main/java/javalab/umc7th_mission/apiPayload/exception/GeneralException.java b/src/main/java/javalab/umc7th_mission/apiPayload/exception/GeneralException.java index b33c32f..e4a31e5 100644 --- a/src/main/java/javalab/umc7th_mission/apiPayload/exception/GeneralException.java +++ b/src/main/java/javalab/umc7th_mission/apiPayload/exception/GeneralException.java @@ -1,4 +1,4 @@ -package umc.spring.apiPayload.exception; +package javalab.umc7th_mission.apiPayload.exception; import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/src/main/java/javalab/umc7th_mission/apiPayload/exception/handler/FoodCategoryHandler.java b/src/main/java/javalab/umc7th_mission/apiPayload/exception/handler/FoodCategoryHandler.java new file mode 100644 index 0000000..0bfd2d7 --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/apiPayload/exception/handler/FoodCategoryHandler.java @@ -0,0 +1,10 @@ +package javalab.umc7th_mission.apiPayload.exception.handler; + +import umc.spring.apiPayload.code.BaseErrorCode; +import umc.spring.apiPayload.exception.GeneralException; + +public class FoodCategoryHandler extends GeneralException { + public FoodCategoryHandler(BaseErrorCode errorCode) { + super(errorCode); + } +} \ No newline at end of file diff --git a/src/main/java/javalab/umc7th_mission/apiPayload/exception/handler/TempHandler.java b/src/main/java/javalab/umc7th_mission/apiPayload/exception/handler/TempHandler.java index a07b3f9..16fdb5e 100644 --- a/src/main/java/javalab/umc7th_mission/apiPayload/exception/handler/TempHandler.java +++ b/src/main/java/javalab/umc7th_mission/apiPayload/exception/handler/TempHandler.java @@ -1,4 +1,4 @@ -package umc.spring.apiPayload.exception.handler; +package javalab.umc7th_mission.apiPayload.exception.handler; import umc.spring.apiPayload.code.BaseErrorCode; import umc.spring.apiPayload.exception.GeneralException; diff --git a/src/main/java/javalab/umc7th_mission/controller/MemberRestController.java b/src/main/java/javalab/umc7th_mission/controller/MemberRestController.java new file mode 100644 index 0000000..c2eede2 --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/controller/MemberRestController.java @@ -0,0 +1,50 @@ +package javalab.umc7th_mission.controller; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import umc.spring.apiPayload.ApiResponse; +import umc.spring.apiPayload.exception.GeneralException; +import umc.spring.converter.MemberConverter; +import umc.spring.domain.Member; +import umc.spring.dto.MemberRequestDTO; +import umc.spring.dto.MemberResponseDTO; +import umc.spring.service.MemberService.MemberCommandService; +import umc.spring.service.MissionService.MissionService; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/members") +public class MemberRestController { + + private final MemberCommandService memberCommandService; + private final MissionService missionService; + + @PostMapping("/") + public ApiResponse join(@RequestBody @Valid MemberRequestDTO.JoinDto request){ + Member member = memberCommandService.joinMember(request); + return ApiResponse.onSuccess(MemberConverter.toJoinResultDTO(member)); + } + + // 미션 도전 시작 API + @PostMapping("/{memberId}/missions/{missionId}/start") + public ResponseEntity> startMission( + @PathVariable Long memberId, @PathVariable Long missionId) { + + try { + missionService.startMission(memberId, missionId); // MissionService에서 도전 시작 처리 + // 미션 도전 성공 시 응답 + return ResponseEntity.ok(ApiResponse.onSuccess("미션 도전이 시작되었습니다.")); + } catch (GeneralException e) { + // 이미 도전 중인 미션인 경우 + ApiResponse errorResponse = ApiResponse.onFailure("BAD_REQUEST", "이미 도전 중인 미션입니다.", null); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse); + } catch (Exception e) { + // 기타 서버 오류 발생 시 + ApiResponse errorResponse = ApiResponse.onFailure("INTERNAL_SERVER_ERROR", "서버 오류: " + e.getMessage(), null); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse); + } + } +} diff --git a/src/main/java/javalab/umc7th_mission/controller/MissionController.java b/src/main/java/javalab/umc7th_mission/controller/MissionController.java new file mode 100644 index 0000000..68f18b8 --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/controller/MissionController.java @@ -0,0 +1,34 @@ +package javalab.umc7th_mission.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import umc.spring.dto.MissionRequestDTO; +import umc.spring.dto.MissionResponseDTO; +import umc.spring.service.MissionService.MissionService; + +import jakarta.validation.Valid; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/mission") +public class MissionController { + + private final MissionService missionService; + + @PostMapping + public ResponseEntity addMission(@RequestBody @Valid MissionRequestDTO request) { + try { + // 성공적으로 미션을 추가한 경우 + MissionResponseDTO response = missionService.addMission(request); + return ResponseEntity.ok(response); + } catch (IllegalArgumentException e) { + // 클라이언트 요청 오류 + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage()); + } catch (Exception e) { + // 서버 내부 오류 + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("서버 에러: " + e.getMessage()); + } + } +} diff --git a/src/main/java/javalab/umc7th_mission/controller/ReviewController.java b/src/main/java/javalab/umc7th_mission/controller/ReviewController.java new file mode 100644 index 0000000..d79ace2 --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/controller/ReviewController.java @@ -0,0 +1,23 @@ +package javalab.umc7th_mission.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import umc.spring.dto.ReviewRequestDTO; +import umc.spring.dto.ReviewResponseDTO; +import umc.spring.service.ReviewService.ReviewService; + +@RestController +@RequestMapping("/review") +@RequiredArgsConstructor +public class ReviewController { + + private final ReviewService reviewService; + + // 리뷰 추가 API + @PostMapping + public ResponseEntity addReview(@RequestBody ReviewRequestDTO request) { + ReviewResponseDTO response = reviewService.addReview(request); + return ResponseEntity.ok(response); + } +} \ No newline at end of file diff --git a/src/main/java/javalab/umc7th_mission/controller/StoreController.java b/src/main/java/javalab/umc7th_mission/controller/StoreController.java new file mode 100644 index 0000000..f9c7d27 --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/controller/StoreController.java @@ -0,0 +1,28 @@ +package javalab.umc7th_mission.controller; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +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 umc.spring.apiPayload.ApiResponse; +import umc.spring.converter.StoreConverter; +import umc.spring.domain.Store; +import umc.spring.dto.StoreRequestDTO; +import umc.spring.dto.StoreResponseDTO; +import umc.spring.service.StoreService.StoreService; + +@RestController +@RequestMapping("/stores") +@RequiredArgsConstructor +public class StoreController { + + private final StoreService storeService; + + @PostMapping("/") + public ApiResponse addStore(@RequestBody @Valid StoreRequestDTO request) { + Store store = storeService.addStore(request); + return ApiResponse.onSuccess(StoreConverter.toStoreResponseDTO(store)); // 응답 DTO로 변환하여 반환 + } +} diff --git a/src/main/java/javalab/umc7th_mission/controller/TempController.java b/src/main/java/javalab/umc7th_mission/controller/TempController.java index 6f530a4..a118084 100644 --- a/src/main/java/javalab/umc7th_mission/controller/TempController.java +++ b/src/main/java/javalab/umc7th_mission/controller/TempController.java @@ -1,4 +1,4 @@ -package umc.spring.controller; +package javalab.umc7th_mission.controller; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; diff --git a/src/main/java/javalab/umc7th_mission/converter/MemberConverter.java b/src/main/java/javalab/umc7th_mission/converter/MemberConverter.java new file mode 100644 index 0000000..0ac1b50 --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/converter/MemberConverter.java @@ -0,0 +1,44 @@ +package umc.spring.converter; + +import umc.spring.domain.Member; +import umc.spring.domain.enums.Gender; +import umc.spring.dto.MemberRequestDTO; +import umc.spring.dto.MemberResponseDTO; + +import java.time.LocalDateTime; +import java.util.ArrayList; + +public class MemberConverter { + + public static MemberResponseDTO.JoinResultDTO toJoinResultDTO(Member member){ + return MemberResponseDTO.JoinResultDTO.builder() + .memberId(member.getId()) + .createdAt(LocalDateTime.now()) + .build(); + } + + public static Member toMember(MemberRequestDTO.JoinDto request){ + + Gender gender = null; + + switch (request.getGender()){ + case 1: + gender = Gender.MALE; + break; + case 2: + gender = Gender.FEMALE; + break; + case 3: + gender = Gender.NONE; + break; + } + + return Member.builder() + .address(request.getAddress()) + .specAddress(request.getSpecAddress()) + .gender(gender) + .name(request.getName()) + .memberPreferList(new ArrayList<>()) + .build(); + } +} diff --git a/src/main/java/javalab/umc7th_mission/converter/MemberPreferConverter.java b/src/main/java/javalab/umc7th_mission/converter/MemberPreferConverter.java new file mode 100644 index 0000000..e6090a2 --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/converter/MemberPreferConverter.java @@ -0,0 +1,21 @@ +package umc.spring.converter; + +import umc.spring.domain.foodCategory; +import umc.spring.domain.mapping.MemberPrefer; + +import java.util.List; +import java.util.stream.Collectors; + +public class MemberPreferConverter { + + public static List toMemberPreferList(List foodCategoryList){ + + return foodCategoryList.stream() + .map(foodCategory -> + MemberPrefer.builder() + .foodCategory(foodCategory) + .build() + ).collect(Collectors.toList()); + } +} + diff --git a/src/main/java/javalab/umc7th_mission/converter/MissionConverter.java b/src/main/java/javalab/umc7th_mission/converter/MissionConverter.java new file mode 100644 index 0000000..bc15274 --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/converter/MissionConverter.java @@ -0,0 +1,16 @@ +package umc.spring.converter; + +import umc.spring.domain.Mission; +import umc.spring.dto.MissionResponseDTO; + +public class MissionConverter { + public static MissionResponseDTO toMissionResponseDTO(Mission mission) { + return MissionResponseDTO.builder() + .id(mission.getId()) + .missionSpec(mission.getMissionSpec()) + .reward(mission.getReward()) + .deadline(mission.getDeadline()) + .storeName(mission.getStore().getName()) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/javalab/umc7th_mission/converter/StoreConverter.java b/src/main/java/javalab/umc7th_mission/converter/StoreConverter.java new file mode 100644 index 0000000..1b52d5f --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/converter/StoreConverter.java @@ -0,0 +1,26 @@ +package umc.spring.converter; + +import umc.spring.domain.Region; +import umc.spring.domain.Store; +import umc.spring.dto.StoreRequestDTO; +import umc.spring.dto.StoreResponseDTO; + +public class StoreConverter { + public static Store toStore(StoreRequestDTO request, Region region) { + return Store.builder() + .name(request.getName()) + .address(request.getAddress()) + .region(region) + .score(request.getScore()) // score 값 추가 + .build(); + } + + public static StoreResponseDTO toStoreResponseDTO(Store store) { + return StoreResponseDTO.builder() + .id(store.getId()) + .name(store.getName()) + .address(store.getAddress()) + .regionName(store.getRegion().getName()) // 지역 이름도 포함 + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/javalab/umc7th_mission/dto/MemberRequestDTO.java b/src/main/java/javalab/umc7th_mission/dto/MemberRequestDTO.java new file mode 100644 index 0000000..e91f130 --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/dto/MemberRequestDTO.java @@ -0,0 +1,32 @@ +package umc.spring.dto; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Getter; +import umc.spring.validation.annotation.ExistCategories; + +import java.util.List; + +public class MemberRequestDTO { + + @Getter + public static class JoinDto{ + @NotBlank + String name; + @NotNull + Integer gender; + @NotNull + Integer birthYear; + @NotNull + Integer birthMonth; + @NotNull + Integer birthDay; + @Size(min = 5, max = 12) + String address; + @Size(min = 5, max = 12) + String specAddress; + @ExistCategories + List preferCategory; + } +} diff --git a/src/main/java/javalab/umc7th_mission/dto/MemberResponseDTO.java b/src/main/java/javalab/umc7th_mission/dto/MemberResponseDTO.java new file mode 100644 index 0000000..ed880a8 --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/dto/MemberResponseDTO.java @@ -0,0 +1,20 @@ +package umc.spring.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +public class MemberResponseDTO { + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class JoinResultDTO{ + Long memberId; + LocalDateTime createdAt; + } +} \ No newline at end of file diff --git a/src/main/java/javalab/umc7th_mission/dto/MissionRequestDTO.java b/src/main/java/javalab/umc7th_mission/dto/MissionRequestDTO.java new file mode 100644 index 0000000..e7af10a --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/dto/MissionRequestDTO.java @@ -0,0 +1,15 @@ +package umc.spring.dto; + +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDate; + +@Getter +@Setter +public class MissionRequestDTO { + private String missionSpec; + private int reward; + private LocalDate deadline; + private Long storeId; +} \ No newline at end of file diff --git a/src/main/java/javalab/umc7th_mission/dto/MissionResponseDTO.java b/src/main/java/javalab/umc7th_mission/dto/MissionResponseDTO.java new file mode 100644 index 0000000..6d7782a --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/dto/MissionResponseDTO.java @@ -0,0 +1,18 @@ +package umc.spring.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; + +import java.time.LocalDate; + +@Getter +@AllArgsConstructor +@Builder +public class MissionResponseDTO { + private Long id; + private String missionSpec; + private int reward; + private LocalDate deadline; + private String storeName; +} diff --git a/src/main/java/javalab/umc7th_mission/dto/ReviewRequestDTO.java b/src/main/java/javalab/umc7th_mission/dto/ReviewRequestDTO.java new file mode 100644 index 0000000..0502a95 --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/dto/ReviewRequestDTO.java @@ -0,0 +1,23 @@ +package umc.spring.dto; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class ReviewRequestDTO { + + @NotNull + private Long storeId; + + @NotNull + private Long memberId; + + @NotBlank + private String title; + + @NotNull + private Float score; +} \ No newline at end of file diff --git a/src/main/java/javalab/umc7th_mission/dto/ReviewResponseDTO.java b/src/main/java/javalab/umc7th_mission/dto/ReviewResponseDTO.java new file mode 100644 index 0000000..5fd3b9a --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/dto/ReviewResponseDTO.java @@ -0,0 +1,15 @@ +package umc.spring.dto; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class ReviewResponseDTO { + + private Long id; + private String title; + private Float score; + private Long storeId; + private Long memberId; +} diff --git a/src/main/java/javalab/umc7th_mission/dto/StoreRequestDTO.java b/src/main/java/javalab/umc7th_mission/dto/StoreRequestDTO.java new file mode 100644 index 0000000..8c45787 --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/dto/StoreRequestDTO.java @@ -0,0 +1,22 @@ +package umc.spring.dto; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class StoreRequestDTO { + @NotBlank + private String name; + + @NotBlank + private String address; + + @NotNull + private Long regionId; + + @NotNull + private Float score; +} diff --git a/src/main/java/javalab/umc7th_mission/dto/StoreResponseDTO.java b/src/main/java/javalab/umc7th_mission/dto/StoreResponseDTO.java new file mode 100644 index 0000000..b9d9d0e --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/dto/StoreResponseDTO.java @@ -0,0 +1,15 @@ +package umc.spring.dto; + +import lombok.*; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class StoreResponseDTO { + private Long id; + private String name; + private String address; + private String regionName; +} diff --git a/src/main/java/javalab/umc7th_mission/repository/FoodCategoryRepository.java b/src/main/java/javalab/umc7th_mission/repository/FoodCategoryRepository.java new file mode 100644 index 0000000..8238b5f --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/repository/FoodCategoryRepository.java @@ -0,0 +1,7 @@ +package umc.spring.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import umc.spring.domain.foodCategory; + +public interface FoodCategoryRepository extends JpaRepository { +} diff --git a/src/main/java/javalab/umc7th_mission/repository/MemberMissionRepository.java b/src/main/java/javalab/umc7th_mission/repository/MemberMissionRepository.java new file mode 100644 index 0000000..8b217af --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/repository/MemberMissionRepository.java @@ -0,0 +1,14 @@ +package umc.spring.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import umc.spring.domain.Member; +import umc.spring.domain.Mission; +import umc.spring.domain.mapping.MemberMission; +import umc.spring.domain.enums.MissionStatus; + +public interface MemberMissionRepository extends JpaRepository { + + boolean existsByMemberIdAndMissionIdAndStatus(Long memberId, Long missionId, MissionStatus status); + + boolean existsByMissionIdAndStatus(Long missionId, MissionStatus missionStatus); +} diff --git a/src/main/java/javalab/umc7th_mission/repository/MemberMissionRepository/MemberMissionRepository.java b/src/main/java/javalab/umc7th_mission/repository/MemberMissionRepository/MemberMissionRepository.java deleted file mode 100644 index 7c43276..0000000 --- a/src/main/java/javalab/umc7th_mission/repository/MemberMissionRepository/MemberMissionRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package javalab.umc7th_mission.repository.MemberMissionRepository; - -import javalab.umc7th_mission.domain.mapping.MemberMission; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface MemberMissionRepository extends JpaRepository, MemberMissionRepositoryCustom { -} \ No newline at end of file diff --git a/src/main/java/javalab/umc7th_mission/repository/MemberMissionRepository/MemberMissionRepositoryCustom.java b/src/main/java/javalab/umc7th_mission/repository/MemberMissionRepository/MemberMissionRepositoryCustom.java deleted file mode 100644 index db6b0e6..0000000 --- a/src/main/java/javalab/umc7th_mission/repository/MemberMissionRepository/MemberMissionRepositoryCustom.java +++ /dev/null @@ -1,8 +0,0 @@ -package javalab.umc7th_mission.repository.MemberMissionRepository; - -import javalab.umc7th_mission.web.dto.MissionDto; -import java.util.List; - -public interface MemberMissionRepositoryCustom { - List findIncompleteMissionsByMemberId(Long memberId); -} \ No newline at end of file diff --git a/src/main/java/javalab/umc7th_mission/repository/MemberMissionRepository/MemberMissionRepositoryImpl.java b/src/main/java/javalab/umc7th_mission/repository/MemberMissionRepository/MemberMissionRepositoryImpl.java deleted file mode 100644 index 2d387c7..0000000 --- a/src/main/java/javalab/umc7th_mission/repository/MemberMissionRepository/MemberMissionRepositoryImpl.java +++ /dev/null @@ -1,36 +0,0 @@ -package javalab.umc7th_mission.repository.MemberMissionRepository; - -import com.querydsl.core.types.Projections; -import com.querydsl.jpa.impl.JPAQueryFactory; -import ext.javalab.umc7th_mission.domain.QMemberMission; -import ext.javalab.umc7th_mission.domain.QMission; -import javalab.umc7th_mission.web.dto.MissionDto; -import lombok.AllArgsConstructor; -import org.springframework.stereotype.Repository; - -import java.util.List; - -@Repository -@AllArgsConstructor -public class MemberMissionRepositoryImpl implements MemberMissionRepositoryCustom { - - private final JPAQueryFactory jpaQueryFactory; - private final QMemberMission memberMission = QMemberMission.memberMission; - private final QMission mission = QMission.mission; - - @Override - public List findIncompleteMissionsByMemberId(Long memberId) { - return jpaQueryFactory - .select(Projections.constructor( - MissionDto.class, - mission.id, - mission.mission_spec, - mission.reward) - ) - .from(memberMission) - .join(memberMission.mission, mission) - .where(memberMission.member.id.eq(memberId) - .and(memberMission.status.ne("COMPLETED"))) - .fetch(); - } -} \ No newline at end of file diff --git a/src/main/java/javalab/umc7th_mission/repository/MemberRepository.java b/src/main/java/javalab/umc7th_mission/repository/MemberRepository.java new file mode 100644 index 0000000..8403ec7 --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/repository/MemberRepository.java @@ -0,0 +1,7 @@ +package umc.spring.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import umc.spring.domain.Member; + +public interface MemberRepository extends JpaRepository { +} diff --git a/src/main/java/javalab/umc7th_mission/repository/MemberRepository/MemberRepository.java b/src/main/java/javalab/umc7th_mission/repository/MemberRepository/MemberRepository.java deleted file mode 100644 index 82c8ea2..0000000 --- a/src/main/java/javalab/umc7th_mission/repository/MemberRepository/MemberRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package javalab.umc7th_mission.repository.MemberRepository; - -import javalab.umc7th_mission.domain.Member; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface MemberRepository extends JpaRepository, MemberRepositoryCustom { -} diff --git a/src/main/java/javalab/umc7th_mission/repository/MemberRepository/MemberRepositoryCustom.java b/src/main/java/javalab/umc7th_mission/repository/MemberRepository/MemberRepositoryCustom.java deleted file mode 100644 index a059ef3..0000000 --- a/src/main/java/javalab/umc7th_mission/repository/MemberRepository/MemberRepositoryCustom.java +++ /dev/null @@ -1,7 +0,0 @@ -package javalab.umc7th_mission.repository.MemberRepository; - -import javalab.umc7th_mission.web.dto.MemberDto; - -public interface MemberRepositoryCustom { - MemberDto findMemberDtoById(Long id); -} \ No newline at end of file diff --git a/src/main/java/javalab/umc7th_mission/repository/MemberRepository/MemberRepositoryImpl.java b/src/main/java/javalab/umc7th_mission/repository/MemberRepository/MemberRepositoryImpl.java deleted file mode 100644 index 80129b6..0000000 --- a/src/main/java/javalab/umc7th_mission/repository/MemberRepository/MemberRepositoryImpl.java +++ /dev/null @@ -1,30 +0,0 @@ -package javalab.umc7th_mission.repository.MemberRepository; - -import com.querydsl.core.types.Projections; -import com.querydsl.jpa.impl.JPAQueryFactory; -import ext.javalab.umc7th_mission.domain.QMember; -import javalab.umc7th_mission.web.dto.MemberDto; -import lombok.AllArgsConstructor; -import org.springframework.stereotype.Repository; - -@Repository -@AllArgsConstructor -public class MemberRepositoryImpl implements MemberRepositoryCustom { - - private final JPAQueryFactory jpaQueryFactory; - private final QMember member = QMember.member; - - @Override - public MemberDto findMemberDtoById(Long id) { - return jpaQueryFactory - .select(Projections.constructor( - MemberDto.class, - member.name, - member.email, - member.point) - ) - .from(member) - .where(member.id.eq(id)) - .fetchOne(); - } -} diff --git a/src/main/java/javalab/umc7th_mission/repository/MissionRepository.java b/src/main/java/javalab/umc7th_mission/repository/MissionRepository.java new file mode 100644 index 0000000..1b043da --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/repository/MissionRepository.java @@ -0,0 +1,10 @@ +package umc.spring.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import umc.spring.domain.Mission; +import umc.spring.domain.enums.MissionStatus; + +public interface MissionRepository extends JpaRepository { + // 미션이 이미 도전 중인지 확인 + boolean existsByStatusAndId(MissionStatus status, Long id); +} diff --git a/src/main/java/javalab/umc7th_mission/repository/MissionRepository/MissionRepository.java b/src/main/java/javalab/umc7th_mission/repository/MissionRepository/MissionRepository.java deleted file mode 100644 index e46fcd7..0000000 --- a/src/main/java/javalab/umc7th_mission/repository/MissionRepository/MissionRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package javalab.umc7th_mission.repository.MissionRepository; - -import javalab.umc7th_mission.domain.Mission; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface MissionRepository extends JpaRepository, MissionRepositoryCustom { -} diff --git a/src/main/java/javalab/umc7th_mission/repository/MissionRepository/MissionRepositoryCustom.java b/src/main/java/javalab/umc7th_mission/repository/MissionRepository/MissionRepositoryCustom.java deleted file mode 100644 index 2fb8f93..0000000 --- a/src/main/java/javalab/umc7th_mission/repository/MissionRepository/MissionRepositoryCustom.java +++ /dev/null @@ -1,10 +0,0 @@ -package javalab.umc7th_mission.repository.MissionRepository; - -import javalab.umc7th_mission.web.dto.MissionDto; -import org.springframework.data.domain.Pageable; - -import java.util.List; - -public interface MissionRepositoryCustom { - List findAvailableMissions(Long memberId, Pageable pageable); -} diff --git a/src/main/java/javalab/umc7th_mission/repository/MissionRepository/MissionRepositoryImpl.java b/src/main/java/javalab/umc7th_mission/repository/MissionRepository/MissionRepositoryImpl.java deleted file mode 100644 index 8a3cc78..0000000 --- a/src/main/java/javalab/umc7th_mission/repository/MissionRepository/MissionRepositoryImpl.java +++ /dev/null @@ -1,49 +0,0 @@ -package javalab.umc7th_mission.repository.MissionRepository; - -import com.querydsl.core.types.Projections; -import com.querydsl.jpa.JPAExpressions; -import com.querydsl.jpa.impl.JPAQueryFactory; -import ext.javalab.umc7th_mission.domain.QMission; -import ext.javalab.umc7th_mission.domain.QRestaurant; -import ext.javalab.umc7th_mission.domain.mapping.QMemberMission; -import javalab.umc7th_mission.web.dto.MissionDto; -import lombok.AllArgsConstructor; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Repository; - -import java.util.List; - -@Repository -@AllArgsConstructor -public class MissionRepositoryImpl implements MissionRepositoryCustom { - - private final JPAQueryFactory jpaQueryFactory; - private final QMission mission = QMission.mission; - - @Override - public List findAvailableMissions(Long memberId, Pageable pageable) { - QRestaurant restaurant = QRestaurant.restaurant; - QMemberMission memberMission = QMemberMission.memberMission; - - return jpaQueryFactory - .select(Projections.constructor( - MissionDto.class, - mission.id, - mission.content, - restaurant.name, - mission.reward) - ) - .from(mission) - .join(mission.restaurant, restaurant) - .where(mission.id.notIn( - JPAExpressions - .select(memberMission.mission.id) - .from(memberMission) - .where(memberMission.member.id.eq(memberId)) - )) - .orderBy(mission.deadline.asc()) - .offset(pageable.getOffset()) - .limit(pageable.getPageSize()) - .fetch(); - } -} diff --git a/src/main/java/javalab/umc7th_mission/repository/RegionRepository.java b/src/main/java/javalab/umc7th_mission/repository/RegionRepository.java new file mode 100644 index 0000000..eab260f --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/repository/RegionRepository.java @@ -0,0 +1,13 @@ +package umc.spring.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import umc.spring.domain.Region; + + +import java.util.Optional; + +@Repository +public interface RegionRepository extends JpaRepository { + Optional findById(Long id); +} \ No newline at end of file diff --git a/src/main/java/javalab/umc7th_mission/repository/ReviewRepository.java b/src/main/java/javalab/umc7th_mission/repository/ReviewRepository.java new file mode 100644 index 0000000..5589b48 --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/repository/ReviewRepository.java @@ -0,0 +1,9 @@ +package umc.spring.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import umc.spring.domain.Review; + +@Repository +public interface ReviewRepository extends JpaRepository { +} diff --git a/src/main/java/javalab/umc7th_mission/repository/ReviewRepository/ReviewRepository.java b/src/main/java/javalab/umc7th_mission/repository/ReviewRepository/ReviewRepository.java deleted file mode 100644 index 0d7a09d..0000000 --- a/src/main/java/javalab/umc7th_mission/repository/ReviewRepository/ReviewRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package javalab.umc7th_mission.repository.ReviewRepository; - -import javalab.umc7th_mission.domain.Review; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface ReviewRepository extends JpaRepository, ReviewRepositoryCustom { -} diff --git a/src/main/java/javalab/umc7th_mission/repository/ReviewRepository/ReviewRepositoryCustom.java b/src/main/java/javalab/umc7th_mission/repository/ReviewRepository/ReviewRepositoryCustom.java deleted file mode 100644 index 737c78a..0000000 --- a/src/main/java/javalab/umc7th_mission/repository/ReviewRepository/ReviewRepositoryCustom.java +++ /dev/null @@ -1,8 +0,0 @@ -package javalab.umc7th_mission.repository.ReviewRepository; - -import javalab.umc7th_mission.web.dto.MemberDto; -import java.util.List; - -public interface ReviewRepositoryCustom { - List findMembersByStoreId(Long storeId); -} diff --git a/src/main/java/javalab/umc7th_mission/repository/ReviewRepository/ReviewRepositoryImpl.java b/src/main/java/javalab/umc7th_mission/repository/ReviewRepository/ReviewRepositoryImpl.java deleted file mode 100644 index b0b567a..0000000 --- a/src/main/java/javalab/umc7th_mission/repository/ReviewRepository/ReviewRepositoryImpl.java +++ /dev/null @@ -1,35 +0,0 @@ -package javalab.umc7th_mission.repository.ReviewRepository; - -import com.querydsl.core.types.Projections; -import com.querydsl.jpa.impl.JPAQueryFactory; -import ext.javalab.umc7th_mission.domain.QReview; -import ext.javalab.umc7th_mission.domain.QMember; -import javalab.umc7th_mission.web.dto.MemberDto; -import lombok.AllArgsConstructor; -import org.springframework.stereotype.Repository; - -import java.util.List; - -@Repository -@AllArgsConstructor -public class ReviewRepositoryImpl implements ReviewRepositoryCustom { - - private final JPAQueryFactory jpaQueryFactory; - private final QReview review = QReview.review; - private final QMember member = QMember.member; - - @Override - public List findMembersByStoreId(Long storeId) { - return jpaQueryFactory - .select(Projections.constructor( - MemberDto.class, - member.name, - member.email, - member.point) - ) - .from(review) - .join(review.member, member) - .where(review.store.id.eq(storeId)) - .fetch(); - } -} \ No newline at end of file diff --git a/src/main/java/javalab/umc7th_mission/repository/StoreRepository.java b/src/main/java/javalab/umc7th_mission/repository/StoreRepository.java new file mode 100644 index 0000000..460b598 --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/repository/StoreRepository.java @@ -0,0 +1,8 @@ +package umc.spring.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import umc.spring.domain.Store; + +@Repository +public interface StoreRepository extends JpaRepository {} diff --git a/src/main/java/javalab/umc7th_mission/repository/StoreRepository/StoreRepository.java b/src/main/java/javalab/umc7th_mission/repository/StoreRepository/StoreRepository.java deleted file mode 100644 index 2f80a35..0000000 --- a/src/main/java/javalab/umc7th_mission/repository/StoreRepository/StoreRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package javalab.umc7th_mission.repository.StoreRepository; - -import javalab.umc7th_mission.domain.Store; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface StoreRepository extends JpaRepository, StoreRepositoryCustom { -} \ No newline at end of file diff --git a/src/main/java/javalab/umc7th_mission/repository/StoreRepository/StoreRepositoryCustom.java b/src/main/java/javalab/umc7th_mission/repository/StoreRepository/StoreRepositoryCustom.java deleted file mode 100644 index 87f80d8..0000000 --- a/src/main/java/javalab/umc7th_mission/repository/StoreRepository/StoreRepositoryCustom.java +++ /dev/null @@ -1,8 +0,0 @@ -package javalab.umc7th_mission.repository.StoreRepository; - -import javalab.umc7th_mission.web.dto.MissionDto; -import java.util.List; - -public interface StoreRepositoryCustom { - List findMissionsByRegionId(Long regionId); -} \ No newline at end of file diff --git a/src/main/java/javalab/umc7th_mission/repository/StoreRepository/StoreRepositoryImpl.java b/src/main/java/javalab/umc7th_mission/repository/StoreRepository/StoreRepositoryImpl.java deleted file mode 100644 index 2af92aa..0000000 --- a/src/main/java/javalab/umc7th_mission/repository/StoreRepository/StoreRepositoryImpl.java +++ /dev/null @@ -1,36 +0,0 @@ -package javalab.umc7th_mission.repository.StoreRepository; - -import com.querydsl.core.types.Projections; -import com.querydsl.jpa.impl.JPAQueryFactory; -import ext.javalab.umc7th_mission.domain.QStore; -import ext.javalab.umc7th_mission.domain.QMission; -import javalab.umc7th_mission.web.dto.MissionDto; -import lombok.AllArgsConstructor; -import org.springframework.stereotype.Repository; - -import java.util.List; - -@Repository -@AllArgsConstructor -public class StoreRepositoryImpl implements StoreRepositoryCustom { - - private final JPAQueryFactory jpaQueryFactory; - private final QStore store = QStore.store; - private final QMission mission = QMission.mission; - - @Override - public List findMissionsByRegionId(Long regionId) { - return jpaQueryFactory - .select(Projections.constructor( - MissionDto.class, - mission.id, - mission.mission_spec, - store.name, - mission.reward) - ) - .from(mission) - .join(mission.store, store) - .where(store.region.id.eq(regionId)) - .fetch(); - } -} \ No newline at end of file diff --git a/src/main/java/javalab/umc7th_mission/service/MemberService/MemberCommandService.java b/src/main/java/javalab/umc7th_mission/service/MemberService/MemberCommandService.java new file mode 100644 index 0000000..c4e6934 --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/service/MemberService/MemberCommandService.java @@ -0,0 +1,8 @@ +package umc.spring.service.MemberService; + +import umc.spring.domain.Member; +import umc.spring.dto.MemberRequestDTO; + +public interface MemberCommandService { + Member joinMember(MemberRequestDTO.JoinDto request); +} diff --git a/src/main/java/javalab/umc7th_mission/service/MemberService/MemberCommandServiceImpl.java b/src/main/java/javalab/umc7th_mission/service/MemberService/MemberCommandServiceImpl.java new file mode 100644 index 0000000..6aa27c0 --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/service/MemberService/MemberCommandServiceImpl.java @@ -0,0 +1,44 @@ +package umc.spring.service.MemberService; + +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import umc.spring.apiPayload.code.status.ErrorStatus; +import umc.spring.apiPayload.exception.handler.FoodCategoryHandler; +import umc.spring.converter.MemberConverter; +import umc.spring.converter.MemberPreferConverter; +import umc.spring.domain.Member; +import umc.spring.domain.foodCategory; +import umc.spring.domain.mapping.MemberPrefer; +import umc.spring.dto.MemberRequestDTO; +import umc.spring.repository.FoodCategoryRepository; +import umc.spring.repository.MemberRepository; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class MemberCommandServiceImpl implements MemberCommandService{ + + private final MemberRepository memberRepository; + + private final FoodCategoryRepository foodCategoryRepository; + + @Override + @Transactional + public Member joinMember(MemberRequestDTO.JoinDto request) { + + Member newMember = MemberConverter.toMember(request); + List foodCategoryList = request.getPreferCategory().stream() + .map(category -> { + return foodCategoryRepository.findById(category).orElseThrow(() -> new FoodCategoryHandler(ErrorStatus.FOOD_CATEGORY_NOT_FOUND)); + }).collect(Collectors.toList()); + + List memberPreferList = MemberPreferConverter.toMemberPreferList(foodCategoryList); + + memberPreferList.forEach(memberPrefer -> {memberPrefer.setMember(newMember);}); + + return memberRepository.save(newMember); + } +} \ No newline at end of file diff --git a/src/main/java/javalab/umc7th_mission/service/MissionService/MissionService.java b/src/main/java/javalab/umc7th_mission/service/MissionService/MissionService.java new file mode 100644 index 0000000..187abce --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/service/MissionService/MissionService.java @@ -0,0 +1,80 @@ +package umc.spring.service.MissionService; + +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import umc.spring.apiPayload.exception.GeneralException; +import umc.spring.domain.Member; +import umc.spring.domain.Mission; +import umc.spring.domain.Store; +import umc.spring.domain.enums.MissionStatus; +import umc.spring.domain.mapping.MemberMission; +import umc.spring.dto.MissionRequestDTO; +import umc.spring.dto.MissionResponseDTO; +import umc.spring.repository.MemberMissionRepository; +import umc.spring.repository.MemberRepository; +import umc.spring.repository.MissionRepository; +import umc.spring.repository.StoreRepository; + +import static umc.spring.apiPayload.code.status.ErrorStatus.MEMBER_NOT_FOUND; +import static umc.spring.apiPayload.code.status.ErrorStatus._FORBIDDEN; + +@Service +@RequiredArgsConstructor +public class MissionService { + + private final MissionRepository missionRepository; + private final StoreRepository storeRepository; + private final MemberRepository memberRepository; + private final MemberMissionRepository memberMissionRepository; + + + @Transactional + public MissionResponseDTO addMission(MissionRequestDTO request) { + // 가게 정보 확인 + Store store = storeRepository.findById(request.getStoreId()) + .orElseThrow(() -> new IllegalArgumentException("Store를 찾을 수 없습니다.")); + + // Mission 생성 및 저장 + Mission mission = Mission.builder() + .missionSpec(request.getMissionSpec()) + .reward(request.getReward()) + .deadline(request.getDeadline()) + .store(store) + .status(MissionStatus.COMPLETE) // status 값 기본 설정 + .build(); + + Mission savedMission = missionRepository.save(mission); + + // MissionResponseDTO 반환 + return new MissionResponseDTO( + savedMission.getId(), + savedMission.getMissionSpec(), + savedMission.getReward(), + savedMission.getDeadline(), + store.getName() + ); + } + + @Transactional + public void startMission(Long memberId, Long missionId) { + // 1. Member와 Mission 조회 + Member member = memberRepository.findById(memberId) + .orElseThrow(() -> new GeneralException(MEMBER_NOT_FOUND)); + Mission mission = missionRepository.findById(missionId) + .orElseThrow(() -> new GeneralException(MEMBER_NOT_FOUND)); + + // 2. 이미 도전 중인지 확인 + boolean isAlreadyChallenging = memberMissionRepository.existsByMemberIdAndMissionIdAndStatus( + memberId, missionId, MissionStatus.CHALLENGING + ); + + if (isAlreadyChallenging) { + throw new GeneralException(_FORBIDDEN); + } + + // 3. MemberMission 객체 생성 및 저장 + MemberMission memberMission = MemberMission.create(member, mission, MissionStatus.CHALLENGING); + memberMissionRepository.save(memberMission); + } +} \ No newline at end of file diff --git a/src/main/java/javalab/umc7th_mission/service/ReviewService/ReviewService.java b/src/main/java/javalab/umc7th_mission/service/ReviewService/ReviewService.java new file mode 100644 index 0000000..86592c7 --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/service/ReviewService/ReviewService.java @@ -0,0 +1,55 @@ +package umc.spring.service.ReviewService; + +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import umc.spring.apiPayload.code.status.ErrorStatus; +import umc.spring.apiPayload.exception.GeneralException; +import umc.spring.domain.Member; +import umc.spring.domain.Review; +import umc.spring.domain.Store; +import umc.spring.dto.ReviewRequestDTO; +import umc.spring.dto.ReviewResponseDTO; +import umc.spring.repository.MemberRepository; +import umc.spring.repository.ReviewRepository; +import umc.spring.repository.StoreRepository; + +@Service +@RequiredArgsConstructor +public class ReviewService { + + private final ReviewRepository reviewRepository; + private final StoreRepository storeRepository; + private final MemberRepository memberRepository; + + @Transactional + public ReviewResponseDTO addReview(ReviewRequestDTO request) { + // Store 확인 + Store store = storeRepository.findById(request.getStoreId()) + .orElseThrow(() -> new GeneralException(ErrorStatus.FOOD_CATEGORY_NOT_FOUND)); + + // Member 확인 + Member member = memberRepository.findById(request.getMemberId()) + .orElseThrow(() -> new GeneralException(ErrorStatus.MEMBER_NOT_FOUND)); + + // Review 생성 + Review review = Review.builder() + .title(request.getTitle()) + .score(request.getScore()) + .store(store) + .member(member) + .build(); + + // Review 저장 + review = reviewRepository.save(review); + + // 응답 DTO 생성 및 반환 + return ReviewResponseDTO.builder() + .id(review.getId()) + .title(review.getTitle()) + .score(review.getScore()) + .storeId(store.getId()) + .memberId(member.getId()) + .build(); + } +} diff --git a/src/main/java/javalab/umc7th_mission/service/StoreService/StoreService.java b/src/main/java/javalab/umc7th_mission/service/StoreService/StoreService.java new file mode 100644 index 0000000..48bd624 --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/service/StoreService/StoreService.java @@ -0,0 +1,32 @@ +package umc.spring.service.StoreService; + +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import umc.spring.apiPayload.code.status.ErrorStatus; +import umc.spring.apiPayload.exception.GeneralException; +import umc.spring.converter.StoreConverter; +import umc.spring.domain.Region; +import umc.spring.domain.Store; +import umc.spring.dto.StoreRequestDTO; +import umc.spring.repository.StoreRepository; +import umc.spring.repository.RegionRepository; + +@Service +@RequiredArgsConstructor +public class StoreService { + + private final StoreRepository storeRepository; + private final RegionRepository regionRepository; + + @Transactional + public Store addStore(StoreRequestDTO request) { + // 지역 정보 확인 + Region region = regionRepository.findById(request.getRegionId()) + .orElseThrow(() -> new GeneralException(ErrorStatus.FOOD_CATEGORY_NOT_FOUND)); + + // Store 생성 + Store store = StoreConverter.toStore(request, region); + return storeRepository.save(store); + } +} diff --git a/src/main/java/javalab/umc7th_mission/validation/annotation/ExistCategories.java b/src/main/java/javalab/umc7th_mission/validation/annotation/ExistCategories.java new file mode 100644 index 0000000..93fe35a --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/validation/annotation/ExistCategories.java @@ -0,0 +1,18 @@ +package umc.spring.validation.annotation; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; +import umc.spring.validation.validator.CategoriesExistValidator; + +import java.lang.annotation.*; + +@Documented +@Constraint(validatedBy = CategoriesExistValidator.class) +@Target( { ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER }) +@Retention(RetentionPolicy.RUNTIME) +public @interface ExistCategories { + + String message() default "해당하는 카테고리가 존재하지 않습니다."; + Class[] groups() default {}; + Class[] payload() default {}; +} diff --git a/src/main/java/javalab/umc7th_mission/validation/annotation/MissionChallengeValidation.java b/src/main/java/javalab/umc7th_mission/validation/annotation/MissionChallengeValidation.java new file mode 100644 index 0000000..f9ebb0e --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/validation/annotation/MissionChallengeValidation.java @@ -0,0 +1,22 @@ +package umc.spring.validation.annotation; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; +import umc.spring.validation.validator.MissionChallengeValidator; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +// 커스텀 어노테이션 정의 +@Constraint(validatedBy = MissionChallengeValidator.class) +@Target({ ElementType.FIELD, ElementType.PARAMETER }) +@Retention(RetentionPolicy.RUNTIME) +public @interface MissionChallengeValidation { + String message() default "이미 도전 중인 미션입니다."; // 기본 오류 메시지 + + Class[] groups() default {}; // 그룹 + + Class[] payload() default {}; // 추가적인 메타데이터 +} diff --git a/src/main/java/javalab/umc7th_mission/validation/validator/CategoriesExistValidator.java b/src/main/java/javalab/umc7th_mission/validation/validator/CategoriesExistValidator.java new file mode 100644 index 0000000..d55ed47 --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/validation/validator/CategoriesExistValidator.java @@ -0,0 +1,38 @@ +package umc.spring.validation.validator; + + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import umc.spring.apiPayload.code.status.ErrorStatus; +import umc.spring.repository.FoodCategoryRepository; +import umc.spring.validation.annotation.ExistCategories; + +import java.util.List; + +@Component +@RequiredArgsConstructor +public class CategoriesExistValidator implements ConstraintValidator> { + + private final FoodCategoryRepository foodCategoryRepository; + + @Override + public void initialize(ExistCategories constraintAnnotation) { + ConstraintValidator.super.initialize(constraintAnnotation); + } + + @Override + public boolean isValid(List values, ConstraintValidatorContext context) { + boolean isValid = values.stream() + .allMatch(value -> foodCategoryRepository.existsById(value)); + + if (!isValid) { + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate(ErrorStatus.FOOD_CATEGORY_NOT_FOUND.toString()).addConstraintViolation(); + } + + return isValid; + + } +} diff --git a/src/main/java/javalab/umc7th_mission/validation/validator/MissionChallengeValidator.java b/src/main/java/javalab/umc7th_mission/validation/validator/MissionChallengeValidator.java new file mode 100644 index 0000000..b97bf01 --- /dev/null +++ b/src/main/java/javalab/umc7th_mission/validation/validator/MissionChallengeValidator.java @@ -0,0 +1,21 @@ +package umc.spring.validation.validator; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import lombok.RequiredArgsConstructor; +import umc.spring.domain.enums.MissionStatus; +import umc.spring.repository.MemberMissionRepository; +import umc.spring.validation.annotation.MissionChallengeValidation; + +@RequiredArgsConstructor +public class MissionChallengeValidator implements ConstraintValidator { + + private final MemberMissionRepository memberMissionRepository; + + @Override + public boolean isValid(Long missionId, ConstraintValidatorContext context) { + // 미션에 대해 도전 중인 상태가 있는지 확인 + boolean isMissionChallenging = memberMissionRepository.existsByMissionIdAndStatus(missionId, MissionStatus.CHALLENGING); + return !isMissionChallenging; // 이미 도전 중인 미션은 실패로 처리 + } +}