Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Backend] feat : 간단한 todo API 작성 #86

Merged
merged 4 commits into from
Jun 3, 2024
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 @@ -2,18 +2,20 @@

import com.isp.backend.domain.member.entity.Member;
import com.isp.backend.domain.schedule.entity.Schedule;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;
import java.util.Optional;

public interface ScheduleRepository extends JpaRepository<Schedule, Long> {
Optional<Schedule> findById(Long id);
Optional<Schedule> findByIdAndActivatedIsTrue(Long scheduleId);
@EntityGraph(attributePaths = {"checkLists"})
@Query("SELECT s FROM Schedule s LEFT JOIN FETCH s.country WHERE s.member = :member AND s.activated = true ORDER BY s.updatedAt DESC")
List<Schedule> findSchedulesByMember(@Param("member") Member member);
@EntityGraph(attributePaths = {"checkLists"})
@Query("SELECT s FROM Schedule s LEFT JOIN FETCH s.scheduleDetails WHERE s.member = :member ORDER BY s.id DESC")
List<Schedule> findTop5ByMemberOrderByIdDescWithDetails(@Param("member") Member member);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

@Slf4j
@RequiredArgsConstructor
@Transactional
@Transactional(readOnly = true)
@Service
public class ScheduleServiceImpl implements ScheduleService {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.isp.backend.domain.scheduleDetail.controller;

import com.isp.backend.domain.scheduleDetail.dto.request.CheckListRequest;
import com.isp.backend.domain.scheduleDetail.dto.response.CheckListResponse;
import com.isp.backend.domain.scheduleDetail.service.CheckListService;
import com.isp.backend.global.security.CustomUserDetails;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.* ;

import java.util.List;

@RestController
@RequestMapping("/schedules")
@RequiredArgsConstructor
public class CheckListController {

private final CheckListService checkListService;

/** 일정 체크리스트 저장 API **/
@PostMapping("/{scheduleId}/checklists")
public ResponseEntity<List<CheckListResponse>> addCheckLists(@AuthenticationPrincipal CustomUserDetails customUserDetails,
@PathVariable Long scheduleId, @RequestBody List<CheckListRequest> checkListRequests) {
String memberUid = customUserDetails.getUsername();
List<CheckListResponse> checkListResponses = checkListService.addCheckLists(memberUid, scheduleId, checkListRequests);
return ResponseEntity.ok(checkListResponses);
}


/** 여행 체크리스트 조회 API **/
@GetMapping("/{scheduleId}/checklists")
public ResponseEntity<List<CheckListResponse>> getCheckLists(@AuthenticationPrincipal CustomUserDetails customUserDetails,
@PathVariable Long scheduleId) {
String memberUid = customUserDetails.getUsername();
List<CheckListResponse> checkListResponses = checkListService.getCheckLists(memberUid, scheduleId);
return ResponseEntity.ok(checkListResponses);
}


/** 여행 체크리스트 삭제 API **/
@DeleteMapping("/{scheduleId}/checklists/{checkListId}")
public ResponseEntity<List<CheckListResponse>> deleteCheckList(@AuthenticationPrincipal CustomUserDetails customUserDetails,
@PathVariable Long scheduleId,
@PathVariable Long checkListId) {
String memberUid = customUserDetails.getUsername();
List<CheckListResponse> checkListResponses = checkListService.deleteCheckList(memberUid, scheduleId, checkListId);
return ResponseEntity.ok(checkListResponses);
}


/** 여행 체크리스트 수정 API **/
@PutMapping("/{scheduleId}/checklists")
public ResponseEntity<List<CheckListResponse>> updateCheckLists(@AuthenticationPrincipal CustomUserDetails customUserDetails,
@PathVariable Long scheduleId,
@RequestBody List<CheckListResponse> checkListResponses) {
String memberUid = customUserDetails.getUsername();
List<CheckListResponse> updatedCheckListResponses = checkListService.updateCheckLists(memberUid, scheduleId, checkListResponses);
return ResponseEntity.ok(updatedCheckListResponses);
}


}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.isp.backend.domain.scheduleDetail.dto.request;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class CheckListRequest {

private String todo;

private boolean check;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.isp.backend.domain.scheduleDetail.dto.response;

import com.isp.backend.domain.scheduleDetail.entity.CheckList;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class CheckListResponse {
private Long id;
private String todo;
private boolean check;

public CheckListResponse(CheckList checkList) {
this.id = checkList.getId();
this.todo = checkList.getTodo();
this.check = checkList.isChecked();
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.isp.backend.domain.scheduleDetail.entity;

import com.isp.backend.domain.schedule.entity.Schedule;
import com.isp.backend.global.common.BaseEntity;
import jakarta.persistence.*;
import lombok.*;

@Getter
@AllArgsConstructor
@Entity
@Builder
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "checkList")
public class CheckList extends BaseEntity {

@Id
@Column(name = "id", unique = true, nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String todo ;

@Column(nullable = false)
private boolean isChecked = false;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "schedule_id", nullable = false)
private Schedule schedule;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.isp.backend.domain.scheduleDetail.repository;

import com.isp.backend.domain.schedule.entity.Schedule;
import com.isp.backend.domain.scheduleDetail.entity.CheckList;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface CheckListRepository extends JpaRepository<CheckList, Long> {
List<CheckList> findBySchedule(Schedule schedule);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.isp.backend.domain.scheduleDetail.service;

import com.isp.backend.domain.scheduleDetail.dto.request.CheckListRequest;
import com.isp.backend.domain.scheduleDetail.dto.response.CheckListResponse;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

public interface CheckListService {
@Transactional
List<CheckListResponse> addCheckLists(String uid, Long scheduleId, List<CheckListRequest> checkListRequests);

@Transactional(readOnly = true)
List<CheckListResponse> getCheckLists(String uid, Long scheduleId);

@Transactional
List<CheckListResponse> deleteCheckList(String uid, Long scheduleId, Long checkListId);

@Transactional
List<CheckListResponse> updateCheckLists(String uid, Long scheduleId, List<CheckListResponse> checkListResponses);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package com.isp.backend.domain.scheduleDetail.service;

import com.isp.backend.domain.member.entity.Member;
import com.isp.backend.domain.schedule.entity.Schedule;
import com.isp.backend.domain.schedule.repository.ScheduleRepository;
import com.isp.backend.domain.schedule.service.ScheduleService;
import com.isp.backend.domain.scheduleDetail.dto.request.CheckListRequest;
import com.isp.backend.domain.scheduleDetail.dto.response.CheckListResponse;
import com.isp.backend.domain.scheduleDetail.entity.CheckList;
import com.isp.backend.domain.scheduleDetail.repository.CheckListRepository;
import com.isp.backend.global.exception.schedule.CheckListNotFoundException;
import com.isp.backend.global.exception.schedule.NotYourScheduleException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Transactional
@Service
public class CheckListServiceImpl implements CheckListService {
private final CheckListRepository checkListRepository;
private final ScheduleService scheduleService;


/** 여행 체크리스트 추가 API **/
@Override
@Transactional
public List<CheckListResponse> addCheckLists(String uid, Long scheduleId, List<CheckListRequest> checkListRequests) {
Member findMember = scheduleService.validateUserCheck(uid);
Schedule findSchedule = scheduleService.validateSchedule(scheduleId);
// 자신의 여행 일정인지 확인
if (!findSchedule.getMember().equals(findMember)) {
throw new NotYourScheduleException();
}

List<CheckListResponse> responses = new ArrayList<>();
for (CheckListRequest request : checkListRequests) {
CheckList checkList = CheckList.builder()
.todo(request.getTodo())
.isChecked(request.isCheck())
.schedule(findSchedule)
.build();
checkListRepository.save(checkList);
responses.add(new CheckListResponse(checkList));
}

return responses;
}


/** 여행 체크리스트 조회 API **/
@Override
@Transactional(readOnly = true)
public List<CheckListResponse> getCheckLists(String uid, Long scheduleId) {
Member findMember = scheduleService.validateUserCheck(uid);
Schedule findSchedule = scheduleService.validateSchedule(scheduleId);
// 자신의 여행 일정인지 확인
if (!findSchedule.getMember().equals(findMember)) {
throw new NotYourScheduleException();
}

List<CheckList> checkLists = checkListRepository.findBySchedule(findSchedule);
List<CheckListResponse> responses = checkLists.stream()
.map(CheckListResponse::new)
.collect(Collectors.toList());

return responses;
}


/** 여행 체크리스트 삭제 API **/
@Override
@Transactional
public List<CheckListResponse> deleteCheckList(String uid, Long scheduleId, Long checkListId) {
Member findMember = scheduleService.validateUserCheck(uid);
Schedule findSchedule = scheduleService.validateSchedule(scheduleId);
CheckList checkList = checkListRepository.findById(checkListId)
.orElseThrow(CheckListNotFoundException::new);

// 자신의 여행 일정인지 확인 + 체크리스트가 해당 스케줄에 속하는지 확인
if (!findSchedule.getMember().equals(findMember) || !checkList.getSchedule().equals(findSchedule)) {
throw new NotYourScheduleException();
}

checkListRepository.delete(checkList);

List<CheckList> checkLists = checkListRepository.findBySchedule(findSchedule);
List<CheckListResponse> responses = checkLists.stream()
.map(CheckListResponse::new)
.collect(Collectors.toList());

return responses;
}


/** 여행 체크리스트 수정 API **/
@Override
@Transactional
public List<CheckListResponse> updateCheckLists(String uid, Long scheduleId, List<CheckListResponse> checkListResponses) {
Member findMember = scheduleService.validateUserCheck(uid);
Schedule findSchedule = scheduleService.validateSchedule(scheduleId);

if (!findSchedule.getMember().equals(findMember)) {
throw new NotYourScheduleException();
}

for (CheckListResponse response : checkListResponses) {
CheckList checkList = checkListRepository.findById(response.getId())
.orElseThrow(CheckListNotFoundException::new);
if (!checkList.getSchedule().equals(findSchedule)) {
throw new NotYourScheduleException();
}
checkList.setTodo(response.getTodo());
checkList.setChecked(response.isCheck());
}

List<CheckList> updatedCheckLists = checkListRepository.findBySchedule(findSchedule);
List<CheckListResponse> responses = updatedCheckLists.stream()
.map(CheckListResponse::new)
.collect(Collectors.toList());

return responses;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public enum ErrorCode {
NOT_YOUR_SCHEDULE(HttpStatus.UNAUTHORIZED, "S003", "사용자의 여행 일정이 아닙니다."),
IMAGE_NOT_FOUND(HttpStatus.NOT_FOUND, "S004", "이미지를 찾을 수 없습니다."),
IATA_CODE_NOT_FOUND(HttpStatus.NOT_FOUND, "S005", "해당 국가의 공항 코드를 찾을 수 없습니다."),
CHECK_LIST_NOT_FOUND(HttpStatus.NOT_FOUND, "S006", "체크리스트를 찾을 수 없습니다"),

// Flight & Hotel
AMADEUS_SEARCH_FAILED(HttpStatus.INTERNAL_SERVER_ERROR,"F001", "아마데우스 요청을 가져오는 중 오류를 발생했습니다."),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.isp.backend.global.exception.schedule;

import com.isp.backend.global.exception.CustomException;
import com.isp.backend.global.exception.ErrorCode;

import java.util.function.Supplier;


public class CheckListNotFoundException extends CustomException {

public CheckListNotFoundException() {
super(ErrorCode.CHECK_LIST_NOT_FOUND);
}

}
Loading