Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@
import com.umc.jaengchalttak.global.apiPayload.ApiResponse;
import com.umc.jaengchalttak.global.apiPayload.code.BaseSuccessCode;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.List;

@Tag(name = "1:1 문의 API", description = "1:1 문의 관련 API입니다.")
@RestController
@RequestMapping("/api/inquiry")
public class InquiryController {
Expand Down Expand Up @@ -56,7 +59,7 @@ public ApiResponse<InquiryInfoResDTO> getInquiryInfo(@PathVariable Long inquiryI

@Operation(summary = "1대1 문의 제출", description = "유저가 새로운 1대1 문의를 작성합니다.")
@PostMapping
public ApiResponse<String> submitInquiry(@RequestBody SubmitInquiryReqDTO request) {
public ApiResponse<String> submitInquiry(@Valid @RequestBody SubmitInquiryReqDTO request) {
BaseSuccessCode code = InquirySuccessCode.SUBMIT_INQUIRY_CREATED;
return ApiResponse.onSuccess(code, "1대1 문의 제출 성공!");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
package com.umc.jaengchalttak.domain.inquiry.dto.request;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import java.util.List;

public record SubmitInquiryReqDTO(
@NotBlank(message = "문의 제목은 필수입니다.")
@Size(max = 50, message = "문의 제목은 50자 이내여야 합니다.")
String inquiryTitle,

@NotBlank(message = "문의 내용은 필수입니다.")
@Size(max = 500, message = "문의 내용은 500자 이내여야 합니다.")
String inquiryContent,

@NotBlank(message = "문의 타입은 필수입니다.")
@Size(max = 20, message = "문의 타입은 20자 이내여야 합니다.")
String inquiryType,

List<String> photo
) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public class Inquiry {

// ====== 연관관계 매핑 ======
@OneToMany(mappedBy = "inquiry", cascade = CascadeType.ALL, orphanRemoval = true)
@Builder.Default
private List<InquiryPhoto> inquiryPhotos = new ArrayList<>();

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@
import com.umc.jaengchalttak.domain.mission.dto.response.MissionsProgressResDTO;
import com.umc.jaengchalttak.domain.mission.dto.response.MyMissionResDTO;
import com.umc.jaengchalttak.domain.mission.payload.code.MissionSuccessCode;
import com.umc.jaengchalttak.domain.mission.service.MissionService;
import com.umc.jaengchalttak.domain.mission.service.UserMissionService;
import com.umc.jaengchalttak.domain.user.enums.Address;
import com.umc.jaengchalttak.global.apiPayload.ApiResponse;
import com.umc.jaengchalttak.global.apiPayload.code.BaseSuccessCode;
import com.umc.jaengchalttak.global.dto.OffsetPagination;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Min;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.List;

@Tag(name = "미션 API", description = "미션 관련 API입니다.")
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/mission")
Expand All @@ -43,11 +43,23 @@ public ApiResponse<MyMissionResDTO> getMyMissionList(@RequestParam("userId") Lon

@Operation(summary = "진행 상태별 내 미션 조회", description = "유저가 진행 중이거나 이미 완료한 미션 목록을 필터링하여 조회합니다.")
@GetMapping("/me")
public ApiResponse<List<MissionsProgressResDTO>> getMyMissionsByProgress(@RequestParam("userId") Long userId,
@RequestParam("isProgress") boolean isProgress,
@Min(value = 1, message = "페이지 번호는 1 이상이어야 합니다.")
@RequestParam(value = "page", defaultValue = "1") int page) {
List<MissionsProgressResDTO> result = userMissionService.getUserMissionsByProgress(userId, isProgress, page);
public ApiResponse<OffsetPagination<MissionsProgressResDTO>> getMyMissionsByProgress(
@RequestParam Long userId,
@RequestParam boolean isProgress,

@RequestParam(defaultValue = "3")
@Min(value = 1, message = "페이지 크기는 1 이상이어야 합니다.")
Integer pageSize,

@RequestParam(defaultValue = "0")
@Min(value = 0, message = "페이지 번호는 0 이상이어야 합니다.")
Integer pageNumber,

@RequestParam(required = false)
String sort
) {
OffsetPagination<MissionsProgressResDTO> result =
userMissionService.getUserMissionsByProgress(userId, isProgress, pageSize, pageNumber, sort);

BaseSuccessCode code = MissionSuccessCode.MISSION_BY_PROGRESS_OK;
return ApiResponse.onSuccess(code, result);
Expand All @@ -56,15 +68,15 @@ public ApiResponse<List<MissionsProgressResDTO>> getMyMissionsByProgress(@Reques

@Operation(summary = "미션 도전하기", description = "특정 미션을 수행 목록에 추가하고 진행 상태로 변경합니다.")
@PostMapping
public ApiResponse<String> startMission(@RequestBody StartMissionReqDTO request) {
public ApiResponse<String> startMission(@Valid @RequestBody StartMissionReqDTO request) {
BaseSuccessCode code = MissionSuccessCode.START_MISSION_CREATED;
return ApiResponse.onSuccess(code, "미션 진행 시작!");
}


@Operation(summary = "미션 완료 인증", description = "진행 중인 미션에 대해 완료 증빙을 제출하고 성공 처리를 요청합니다.")
@PostMapping("/success")
public ApiResponse<String> completeMission(@RequestBody CompleteMissionReqDTO request) {
public ApiResponse<String> completeMission(@Valid @RequestBody CompleteMissionReqDTO request) {
BaseSuccessCode code = MissionSuccessCode.COMPLETE_MISSION_CREATED;
return ApiResponse.onSuccess(code, "미션 수행 완료!");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public static MissionsProgressResDTO toMissionsProgressResDTO(UserMission userMi
return MissionsProgressResDTO.builder()
.storeId(userMission.getMission().getStore().getId())
.storeName(userMission.getMission().getStore().getStoreName())
.userMissionId(userMission.getId())
.missionName(userMission.getMission().getMissionName())
.missionPoint(userMission.getMission().getMissionPoint())
.missionAmount(userMission.getMission().getMissionAmount())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
package com.umc.jaengchalttak.domain.mission.dto.request;

import jakarta.validation.constraints.NotNull;

public record CompleteMissionReqDTO(
@NotNull(message = "사용자 ID는 필수입니다.")
Long userId,

@NotNull(message = "미션 ID는 필수입니다.")
Long missionId,

@NotNull(message = "가게 ID는 필수입니다.")
Long storeId
) { }
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package com.umc.jaengchalttak.domain.mission.dto.request;

import jakarta.validation.constraints.NotNull;

public record StartMissionReqDTO(
@NotNull(message = "사용자 ID는 필수입니다.")
Long userId,

@NotNull(message = "미션 ID는 필수입니다.")
Long missionId
) { }
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
public record MissionsProgressResDTO(
Long storeId,
String storeName,
Long userMissionId,
String missionName,
Integer missionPoint,
Integer missionAmount,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.umc.jaengchalttak.domain.store.entity.Store;
import jakarta.persistence.*;
import jakarta.validation.constraints.Min;
import lombok.*;
import java.time.LocalDate;
import java.util.ArrayList;
Expand All @@ -23,9 +24,11 @@ public class Mission {
@Column(nullable = false, length = 50)
private String missionName;

@Min(value = 1, message = "미션 포인트는 1점 이상이어야 합니다.")
@Column(nullable = false)
private Integer missionPoint;

@Min(value = 1, message = "미션 금액은 1원 이상이어야 합니다.")
@Column(nullable = false)
private Integer missionAmount;

Expand All @@ -41,4 +44,6 @@ public class Mission {
@OneToMany(mappedBy = "mission", cascade = CascadeType.REMOVE)
private List<UserMission> userMissionList = new ArrayList<>();



}
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,23 @@
indexes = {
@Index(name = "idx_user_mission_user_progress", columnList = "user_id, is_progress")
}
)@Getter
)
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
@IdClass(UserMissionId.class) // 복합 키 매핑
@EntityListeners(AuditingEntityListener.class)
public class UserMission {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_mission_id")
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;

@Id
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "mission_id", nullable = false)
private Mission mission;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package com.umc.jaengchalttak.domain.mission.repository;

import com.umc.jaengchalttak.domain.mission.entity.Mission;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface MissionRepository extends JpaRepository <Mission, Long> {
Page<Mission> findAllByStoreId(Long storeId, Pageable pageable);
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
package com.umc.jaengchalttak.domain.mission.repository;

import com.umc.jaengchalttak.domain.mission.entity.UserMission;
import com.umc.jaengchalttak.domain.mission.entity.UserMissionId;
import com.umc.jaengchalttak.domain.mission.enums.ProgressStatus;
import com.umc.jaengchalttak.domain.user.enums.Address;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

@Repository
public interface UserMissionRepository extends JpaRepository<UserMission, UserMissionId> {
public interface UserMissionRepository extends JpaRepository<UserMission, Long> {

// 특정 사용자의 상태별(진행 중/완료 등) 미션 내역을 페이징하여 조회
// 사용자 미션, 미션, 가게를 가져옴
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import com.umc.jaengchalttak.domain.user.payload.UserException;
import com.umc.jaengchalttak.domain.user.payload.code.UserErrorCode;
import com.umc.jaengchalttak.domain.user.repository.UserRepository;
import com.umc.jaengchalttak.global.converter.GlobalConverter;
import com.umc.jaengchalttak.global.dto.OffsetPagination;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
Expand All @@ -19,8 +21,6 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@RequiredArgsConstructor
public class UserMissionService {
Expand All @@ -30,10 +30,13 @@ public class UserMissionService {

private static final int PAGE_SIZE = 3;


// 사용자 지역에서 현재 도전할 수 있는 새로운 미션 목록을 조회 (홈 화면)
@Transactional(readOnly = true)
public MyMissionResDTO getAvailableMissionsByAddress(Long userId, Address address, int page) {
public MyMissionResDTO getAvailableMissionsByAddress(
Long userId,
Address address,
int page
) {
User user = userRepository.findByIdWithServiceUseAllow(userId)
.orElseThrow(() -> new UserException(UserErrorCode.USER_NOT_FOUND));

Expand All @@ -58,30 +61,32 @@ public MyMissionResDTO getAvailableMissionsByAddress(Long userId, Address addres

// 진행 중/진행 완료 상태인 내 미션 조회
@Transactional(readOnly = true)
public List<MissionsProgressResDTO> getUserMissionsByProgress (Long userId, boolean isProgress, int page) {
// userId 존재하는지 확인
if (!userRepository.existsById(userId)) {
throw new UserException(UserErrorCode.USER_NOT_FOUND);
}

public OffsetPagination<MissionsProgressResDTO> getUserMissionsByProgress (
Long userId,
boolean isProgress,
Integer pageSize,
Integer pageNumber,
String sort
) {
// true면 진행 완료, false면 진행 중
ProgressStatus status = isProgress ? ProgressStatus.COMPLETED : ProgressStatus.IN_PROGRESS;

// mission.id 기준으로 내림차순 정렬
Pageable pageable = PageRequest.of(
page - 1,
PAGE_SIZE,
Sort.by(Sort.Direction.DESC, "mission.id")
);
Sort sortInfo = (sort != null && !sort.isBlank()) ?
Sort.by(sort) :
Sort.by("id").descending();

PageRequest pageRequest = PageRequest.of(pageNumber, pageSize, sortInfo);

// JPQL로 조회
Page<UserMission> userMissionList = userMissionRepository.
findByUserAndProgressWithMissionAndStore(userId, status, pageable);
findByUserAndProgressWithMissionAndStore(userId, status, pageRequest);

// converter가 엔티티 리스트를 DTO로 변환
return userMissionList.stream()
.map(MissionConverter::toMissionsProgressResDTO)
.toList();

return GlobalConverter.toOffsetPagination(
userMissionList.map(MissionConverter::toMissionsProgressResDTO).toList(),
userMissionList.getNumber(),
userMissionList.getSize()
);

}

Expand Down
Loading