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 @@ -11,6 +11,7 @@
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDate;
import java.time.LocalDateTime;

@RestController
Expand All @@ -24,7 +25,7 @@ public class MissionController {
@Operation(summary = "나의 미션 목록 조회 API", description = "진행중 또는 완료된 미션 목록을 커서 기반으로 조회합니다.")
public ApiResponse<MissionResponse.MyMissionListDTO> getMyMissions(
@RequestParam MissionStatus status,
@RequestParam(required = false) LocalDateTime cursorDeadline,
@RequestParam(required = false) LocalDate cursorDeadline,
@RequestParam(required = false) Long cursorId,
@RequestParam(defaultValue = "10") int size
) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package com.example.umc9th.domain.mission.converter;

import com.example.umc9th.domain.mission.dto.MissionRequest;
import com.example.umc9th.domain.mission.dto.MissionResponse;
import com.example.umc9th.domain.mission.entity.Mission;
import com.example.umc9th.domain.mission.entity.MissionByMember;
import com.example.umc9th.domain.store.entity.Store;
import org.springframework.data.domain.Slice;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
Expand All @@ -30,7 +33,7 @@ public static MissionResponse.MyMissionListDTO toMyMissionListDTO(Slice<MissionB
.collect(Collectors.toList());

// 다음 페이지 조회를 위해 커서 값들을 초기화
LocalDateTime nextCursorDeadline = null;
LocalDate nextCursorDeadline = null;
Long nextCursorId = null;

// 현재 페이지의 미션 목록이 비어있지 않다면, 다음 페이지를 조회할 커서 설정
Expand All @@ -50,4 +53,22 @@ public static MissionResponse.MyMissionListDTO toMyMissionListDTO(Slice<MissionB
.nextCursorId(nextCursorId)
.build();
}

// DTO -> Entity 변환
public static Mission toMission(MissionRequest.MissionAddDTO request, Store store) {
return Mission.builder()
.store(store)
.content(request.getContent())
.deadline(request.getDeadline())
.targetAmount(request.getTargetAmount())
.rewardPoint(request.getRewardPoint())
.build();
}

// Entity -> DTO 변환 (생성 응답)
public static MissionResponse.MissionAddResultDTO toMissionAddResultDTO(Mission mission) {
return MissionResponse.MissionAddResultDTO.builder()
.missionId(mission.getId())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.example.umc9th.domain.mission.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Getter;

import java.time.LocalDate;
import java.time.LocalDateTime;

public class MissionRequest {

@Getter
@Schema(description = "미션 등록 요청 정보")
public static class MissionAddDTO {

private String content;

private LocalDate deadline;

private Integer targetAmount;

private Integer rewardPoint;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static class MyMissionDTO {
private String missionContent;
private Integer rewardPoint;
private Integer targetAmount;
private LocalDateTime deadline;
private LocalDate deadline;
}

@Getter
Expand All @@ -33,7 +33,15 @@ public static class MyMissionListDTO {

private List<MyMissionDTO> missionList;
private Boolean hasNext;
private LocalDateTime nextCursorDeadline;
private LocalDate nextCursorDeadline;
private Long nextCursorId;
}

@Getter
@Builder
@AllArgsConstructor
@Schema(description = "미션 추가 응답")
public static class MissionAddResultDTO {
private Long missionId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import com.example.umc9th.global.apiPayload.code.BaseEntity;
import jakarta.persistence.*;
import lombok.*;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
Expand All @@ -23,7 +25,7 @@ public class Mission extends BaseEntity {
private String content;

@Column(nullable = false)
private LocalDateTime deadline;
private LocalDate deadline;

@Column(nullable = false)
private Integer targetAmount;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

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

Expand Down Expand Up @@ -39,7 +40,7 @@ public interface MissionByMemberRepository extends JpaRepository<MissionByMember
Slice<MissionByMember> findMyMissionsWithCompoundCursor(
@Param("memberId") Long memberId,
@Param("status") MissionStatus status,
@Param("cursorDeadline") LocalDateTime cursorDeadline,
@Param("cursorDeadline") LocalDate cursorDeadline,
@Param("cursorId") Long cursorId,
Pageable pageable
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
import com.example.umc9th.domain.mission.dto.MissionResponse;
import com.example.umc9th.domain.mission.entity.enums.MissionStatus;

import java.time.LocalDate;
import java.time.LocalDateTime;

public interface MissionService {

// 나의 미션 목록 조회
MissionResponse.MyMissionListDTO getMyMissions(Long memberId, MissionStatus status, LocalDateTime cursorDeadline, Long cursorId, int size);
MissionResponse.MyMissionListDTO getMyMissions(Long memberId, MissionStatus status, LocalDate cursorDeadline, Long cursorId, int size);

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;

@Service
Expand All @@ -21,7 +22,7 @@ public class MissionServiceImpl implements MissionService {
private final MissionByMemberRepository missionByMemberRepository;

@Override
public MissionResponse.MyMissionListDTO getMyMissions(Long memberId, MissionStatus status, LocalDateTime cursorDeadline, Long cursorId, int size) {
public MissionResponse.MyMissionListDTO getMyMissions(Long memberId, MissionStatus status, LocalDate cursorDeadline, Long cursorId, int size) {

// 1. Pageable 객체 생성 (커서 기반이므로 페이지 번호는 항상 0)
PageRequest pageRequest = PageRequest.of(0, size);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
package com.example.umc9th.domain.store.controller;

import com.example.umc9th.domain.mission.converter.MissionConverter;
import com.example.umc9th.domain.mission.dto.MissionRequest;
import com.example.umc9th.domain.mission.dto.MissionResponse;
import com.example.umc9th.domain.mission.entity.Mission;
import com.example.umc9th.domain.store.dto.StoreResponse;
import com.example.umc9th.domain.store.entity.enums.StoreSortType;
import com.example.umc9th.domain.store.service.StoreService;
import com.example.umc9th.global.apiPayload.ApiResponse;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;

@RestController
@RequiredArgsConstructor
Expand Down Expand Up @@ -38,4 +40,19 @@ public ApiResponse<StoreResponse.StoreListDTO> searchStores(
StoreResponse.StoreListDTO response = storeService.searchStores(region, keyword, sortType, cursorId);
return ApiResponse.onSuccess(response);
}

@Operation(summary = "가게에 미션 추가 API", description = "특정 가게(store)에 새로운 미션을 추가합니다.")
@PostMapping("/{storeId}/missions")
public ApiResponse<MissionResponse.MissionAddResultDTO> addMission(
@PathVariable(name = "storeId") Long storeId,
@RequestBody @Valid MissionRequest.MissionAddDTO request
) {
// 3. StoreCommandService의 메소드 호출
Mission newMission = storeService.addMissionToStore(storeId, request);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Converter로 반환하는거까지 service에서 하면 깔끔할거같아요!


// 4. MissionConverter로 응답 DTO 변환
MissionResponse.MissionAddResultDTO response = MissionConverter.toMissionAddResultDTO(newMission);

return ApiResponse.onSuccess(response);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.example.umc9th.domain.store.service;

import com.example.umc9th.domain.mission.dto.MissionRequest;
import com.example.umc9th.domain.mission.entity.Mission;
import com.example.umc9th.domain.store.dto.StoreResponse;
import com.example.umc9th.domain.store.entity.enums.StoreSortType;

Expand All @@ -11,4 +13,12 @@ StoreResponse.StoreListDTO searchStores(
StoreSortType sortType,
Long cursorId
);

/**
* 가게에 미션을 추가하는 로직
* @param storeId 가게 ID
* @param request 미션 추가 DTO
* @return 생성된 Mission 엔티티
*/
Mission addMissionToStore(Long storeId, MissionRequest.MissionAddDTO request);
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
package com.example.umc9th.domain.store.service;

import com.example.umc9th.domain.mission.converter.MissionConverter;
import com.example.umc9th.domain.mission.dto.MissionRequest;
import com.example.umc9th.domain.mission.entity.Mission;
import com.example.umc9th.domain.mission.repository.MissionRepository;
import com.example.umc9th.domain.store.converter.StoreConverter;
import com.example.umc9th.domain.store.dto.StoreResponse;
import com.example.umc9th.domain.store.entity.Store;
import com.example.umc9th.domain.store.entity.enums.StoreSortType;
import com.example.umc9th.domain.store.repository.StoreRepository;
import com.example.umc9th.domain.store.repository.StoreRepositoryCustom;
import com.example.umc9th.global.apiPayload.code.status.ErrorStatus;
import com.example.umc9th.global.apiPayload.exception.handler.ErrorHandler;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Slice;
import org.springframework.stereotype.Service;
Expand All @@ -16,6 +23,8 @@
public class StoreServiceImpl implements StoreService {

private final StoreRepositoryCustom storeRepositoryCustom;
private final StoreRepository storeRepository;
private final MissionRepository missionRepository;

@Override
public StoreResponse.StoreListDTO searchStores(
Expand All @@ -24,4 +33,19 @@ public StoreResponse.StoreListDTO searchStores(
Slice<Store> storeSlice = storeRepositoryCustom.searchStores(region, keyword, sortType, cursorId);
return StoreConverter.toStoreListDTO(storeSlice);
}

@Transactional
@Override
public Mission addMissionToStore(Long storeId, MissionRequest.MissionAddDTO request) {

// 1. 가게(Store) 조회
Store store = storeRepository.findById(storeId)
.orElseThrow(() -> new ErrorHandler(ErrorStatus.STORE_NOT_FOUND));

// 2. DTO -> Entity 변환
Mission newMission = MissionConverter.toMission(request, store);

// 3. Mission 저장
return missionRepository.save(newMission);
}
}