Skip to content

Commit

Permalink
Merge pull request #17 from lsn5963/feat/quest
Browse files Browse the repository at this point in the history
퀘스트 수정,삭제, 조회 로직
  • Loading branch information
lsn5963 authored Aug 10, 2024
2 parents 76c7d08 + 9153501 commit 8a5367d
Show file tree
Hide file tree
Showing 14 changed files with 303 additions and 15 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,7 @@ out/

### ELSE ###
application.yml
application-s3.yml
#application-s3.yml
classpath:/database/application-database.yml
classpath:/oauth2/application-oauth2.yml
classpath:/s3/application-s3.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class Character extends BaseEntity {
private Long todayExp;
private Long level;
@JsonIgnore
@OneToMany(mappedBy = "character")
@OneToMany(mappedBy = "character", fetch = FetchType.LAZY)
private List<Quest> quests = new ArrayList<>();
@OneToMany(mappedBy = "character")
private List<Item> items = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.noplanb.domain.quest.application;

import com.noplanb.domain.character.domain.Character;
import com.noplanb.domain.character.repository.CharacterRepository;
import com.noplanb.domain.quest.domain.Quest;
import com.noplanb.domain.quest.dto.res.RetrieveCalendarRes;
import com.noplanb.global.payload.ApiResponse;
import com.noplanb.global.payload.exception.CharacterNotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.YearMonth;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class CalendarService {
private final CharacterRepository characterRepository;

public ResponseEntity<?> retrieveQuest(YearMonth date, Long id) {
Character character = characterRepository.findById(id).orElseThrow(CharacterNotFoundException::new);
List<Quest> quests = character.getQuests();
// YearMonth 필터링
List<Quest> filteredByDate = quests.stream()
.filter(quest -> YearMonth.from(quest.getCreatedAt().toLocalDate()).equals(date))
.collect(Collectors.toList());

List<RetrieveCalendarRes> calendarRes = filteredByDate.stream().
map(f -> RetrieveCalendarRes.builder()
.id(f.getId())
.exp(f.getExp())
.build())
.collect(Collectors.toList());

ApiResponse apiResponse = ApiResponse.builder()
.check(true)
.information(calendarRes)
.build();

return ResponseEntity.ok(apiResponse);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,26 @@
import com.noplanb.domain.character.repository.CharacterRepository;
import com.noplanb.domain.quest.domain.Quest;
import com.noplanb.domain.quest.dto.req.CreateQuestReq;
import com.noplanb.domain.quest.dto.req.ModifyQuestReq;
import com.noplanb.domain.quest.dto.res.RetrieveLevelAndTodayExpRes;
import com.noplanb.domain.quest.dto.res.RetrieveQuestRes;
import com.noplanb.domain.quest.repository.QuestRepository;
import com.noplanb.global.payload.ApiResponse;
import com.noplanb.global.payload.Message;
import com.noplanb.global.payload.exception.CharacterNotFoundException;
import com.noplanb.global.payload.exception.QuestNotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.noplanb.global.payload.ErrorCode.CHARACTER_NOT_FOUND;

Expand All @@ -42,13 +50,70 @@ public ResponseEntity<?> createQuest(CreateQuestReq createQuestReq, Long id) {
//양방향 연관관계
character.getQuests().add(quest);

ApiResponse apiResponse = ApiResponse.builder()
.check(true)
.information((Message.builder().message("퀘스트를 만들었습니다.").build()))
return createApiResponse((Message.builder().message("퀘스트를 만들었습니다.").build()));
}
public ResponseEntity<?> retrieveQuest(LocalDate localDate, Long id) {
Character character = characterRepository.findById(id).orElseThrow(CharacterNotFoundException::new);
List<Quest> quests = character.getQuests();
// 특정 날짜에 해당하는 퀘스트 필터링 후 미완료 완료 로 정렬 후 생성순으로 정렬
List<RetrieveQuestRes> retrieveQuestResList = quests.stream()
.filter(quest -> quest.getCreatedAt().toLocalDate().isEqual(localDate))
.sorted(Comparator.comparing(Quest::getIsComplete)
.thenComparing(Quest::getCreatedAt))
.map(quest -> RetrieveQuestRes.builder()
.id(quest.getId())
.contents(quest.getContents())
.exp(quest.getExp())
.isComplete(quest.getIsComplete())
.build())
.collect(Collectors.toList());

return createApiResponse(retrieveQuestResList);
}

public ResponseEntity<?> retrieveLevelAndTodayExp(Long id) {
Character character = characterRepository.findById(id).orElseThrow(CharacterNotFoundException::new);
Long level = character.getLevel();
Long acquireExp = character.getTotalExp() - (((level-1)*level)/2)*10;

RetrieveLevelAndTodayExpRes retrieveLevelAndTodayExpRes = RetrieveLevelAndTodayExpRes.builder()
.level(level)
.acquireExp(acquireExp)
.needExp(level*10)
.todayExp(character.getTodayExp())
.build();

return ResponseEntity.ok(apiResponse);
return createApiResponse(retrieveLevelAndTodayExpRes);
}
@Transactional
public ResponseEntity<?> modifyQuest(Long id, ModifyQuestReq modifyQuestReq) {
Character character = characterRepository.findById(id).orElseThrow(CharacterNotFoundException::new);
List<Quest> quests = character.getQuests();
// 퀘스트 날짜 가져오기
Quest quest = quests.stream().filter(q -> q.getId().equals(modifyQuestReq.getId()))
.findFirst()
.orElseThrow(QuestNotFoundException::new);

quest.updateContents(modifyQuestReq.getContents());
return createApiResponse(Message.builder().message("퀘스트를 수정했습니다.").build());
}
@Transactional
public ResponseEntity<?> deleteQuest(Long userId,Long id) {
Character character = characterRepository.findById(userId).orElseThrow(CharacterNotFoundException::new);
List<Quest> quests = character.getQuests();

Quest quest = quests.stream().filter(q -> q.getId().equals(id))
.findFirst()
.orElseThrow(QuestNotFoundException::new);
questRepository.delete(quest);

return createApiResponse(Message.builder().message("퀘스트를 삭제했습니다.").build());
}
private <T> ResponseEntity<ApiResponse> createApiResponse(T information) {
ApiResponse apiResponse = ApiResponse.builder()
.check(true)
.information(information)
.build();
return ResponseEntity.ok(apiResponse);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.noplanb.domain.quest.controller;

import com.noplanb.domain.quest.application.CalendarService;
import com.noplanb.domain.quest.dto.res.RetrieveCalendarRes;
import com.noplanb.domain.quest.dto.res.RetrieveQuestRes;
import com.noplanb.global.payload.ErrorResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import java.time.LocalDate;
import java.time.YearMonth;

@Controller
@RequiredArgsConstructor
@RequestMapping("/api/v1/calendar")
@Tag(name = "CalendarController", description = "CalendarController입니다.")
public class CalendarController {
private final CalendarService calendarService;
@GetMapping("/{date}/{id}")
@Operation(summary = "달력 경험치 조회", description = "달력경험치를 조회할 때 사용하는 API")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "달력 조회 성공", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = RetrieveCalendarRes.class))}),
@ApiResponse(responseCode = "400", description = "달력 조회 실패", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class))}),
})
public ResponseEntity<?> retrieveCalendar(
// @Parameter(description = "Access Token을 입력해주세요.", required = true) @CurrentUser UserPrincipal userPrincipal,
@Parameter(example = "2024-08", description = "날짜를 입력해주세요", required = true) @PathVariable("date") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) YearMonth date,
@Parameter(description = "Access Token을 입력해주세요.", required = true) @PathVariable Long id){
return calendarService.retrieveQuest(date,id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import com.noplanb.domain.quest.application.QuestService;
import com.noplanb.domain.quest.dto.req.CreateQuestReq;
import com.noplanb.domain.quest.dto.req.ModifyQuestReq;
import com.noplanb.domain.quest.dto.res.RetrieveLevelAndTodayExpRes;
import com.noplanb.domain.quest.dto.res.RetrieveQuestRes;
import com.noplanb.global.payload.ErrorResponse;
import com.noplanb.global.payload.Message;
import io.swagger.v3.oas.annotations.Operation;
Expand All @@ -12,28 +15,78 @@
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDate;

@Controller
@RequiredArgsConstructor
@RequestMapping("/api/v1")
@RequestMapping("/api/v1/quest")
@Tag(name = "QuestController", description = "QuestController입니다.")
public class QuestController {
private final QuestService questService;

@PostMapping("/{id}")
@Operation(summary = "퀘스트생성", description = "퀘스트를 생성할 때 사용하는 API")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "댓글 작성 성공", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = Message.class))}),
@ApiResponse(responseCode = "400", description = "댓글 작성 실패", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class))}),
@ApiResponse(responseCode = "200", description = "퀘스트 작성 성공", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = Message.class))}),
@ApiResponse(responseCode = "400", description = "퀘스트 작성 실패", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class))}),
})
public ResponseEntity<?> createQuest(
// @Parameter(description = "Access Token을 입력해주세요.", required = true) @CurrentUser UserPrincipal userPrincipal,
@PathVariable Long id,
@Parameter(description = "Schemas의 CreateQuestReq를 참고해주세요", required = true) @RequestBody CreateQuestReq createQuestReq){
@Parameter(description = "Access Token을 입력해주세요.", required = true) @PathVariable Long id,
@Parameter(description = "퀘스트생성 dto Req입니다.", required = true) @RequestBody CreateQuestReq createQuestReq){

return questService.createQuest(createQuestReq, id);
}
@GetMapping("/{date}/{id}")
@Operation(summary = "퀘스트조회", description = "퀘스트를 조회할 때 사용하는 API")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "퀘스트 조회 성공", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = RetrieveQuestRes.class))}),
@ApiResponse(responseCode = "400", description = "퀘스트 조회 실패", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class))}),
})
public ResponseEntity<?> retrieveQuest(
// @Parameter(description = "Access Token을 입력해주세요.", required = true) @CurrentUser UserPrincipal userPrincipal,
@Parameter(example = "2024-08-09", description = "날짜를 입력해주세요", required = true) @PathVariable("date") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date,
@Parameter(description = "Access Token을 입력해주세요.", required = true) @PathVariable Long id){
System.out.println("date = " + date);
return questService.retrieveQuest(date,id);
}
@GetMapping("/{id}")
@Operation(summary = "메인페이지 상당부분", description = "메인페이지 상당부부을 조회할 떄 사용하는 API")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "메인페이지 상당부분 조회 성공", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = RetrieveLevelAndTodayExpRes.class))}),
@ApiResponse(responseCode = "400", description = "메인페이지 상당부분 조회 실패", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class))}),
})
public ResponseEntity<?> retrieveLevelAndTodayExp(
// @Parameter(description = "Access Token을 입력해주세요.", required = true) @CurrentUser UserPrincipal userPrincipal,
@Parameter(description = "Access Token을 입력해주세요.", required = true) @PathVariable Long id) {
return questService.retrieveLevelAndTodayExp(id);
}

@PatchMapping("/{id}")
@Operation(summary = "퀘스트 수정", description = "퀘스트 수정할 때 사용하는 API")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "퀘스트 수정 성공", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = Message.class))}),
@ApiResponse(responseCode = "400", description = "퀘스트 수정 실패", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class))}),
})
public ResponseEntity<?> modifyQuest(
@Parameter(description = "Access Token을 입력해주세요.", required = true) @PathVariable Long id,
@Parameter(description = "퀘스트수정 dto Req입니다.", required = true) @RequestBody ModifyQuestReq modifyQuestReq) {
return questService.modifyQuest(id, modifyQuestReq);
}
@DeleteMapping("/{userId}/{id}")
@Operation(summary = "퀘스트 삭제", description = "퀘스트 삭제할 때 사용하는 API")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "퀘스트 삭제 성공", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = Message.class))}),
@ApiResponse(responseCode = "400", description = "퀘스트 삭제 실패", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class))}),
})
public ResponseEntity<?> deleteQuest(
@Parameter(description = "Access Token을 입력해주세요.", required = true) @PathVariable Long userId,
@Parameter(description = "삭제할 퀘스트 아이디를 입력해주세요.", required = true) @PathVariable Long id){
return questService.deleteQuest(userId,id);
}

}
3 changes: 3 additions & 0 deletions src/main/java/com/noplanb/domain/quest/domain/Quest.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@ public class Quest extends BaseEntity {
public void updateCharacter(Character character) {
this.character = character;
}
public void updateContents(String contents) {
this.contents = contents;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;

@Getter
public class CreateQuestReq {
@Schema(type = "String", example = "청소하기", description = "퀘스트 내용")
Expand Down
15 changes: 15 additions & 0 deletions src/main/java/com/noplanb/domain/quest/dto/req/ModifyQuestReq.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.noplanb.domain.quest.dto.req;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
@Schema(description = "ModifyQuestReq")
public class ModifyQuestReq {
@Schema(type = "Long", example = "1", description = "퀘스트 ID")
private Long id;
@Schema(type = "String", example = "빨래하기", description = "퀘스트 내용")
private String contents;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.noplanb.domain.quest.dto.res;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Getter;
@Builder
@Getter
public class RetrieveCalendarRes {
@Schema(type = "Long", example = "1", description = "퀘스트 아이디")
private Long id;
@Schema(type = "Long", example = "5", description = "퀘스트 경험치")
private Long exp;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.noplanb.domain.quest.dto.res;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Getter;

@Builder
@Getter
public class RetrieveLevelAndTodayExpRes {
@Schema(type = "Long", example = "11", description = "현재 레벨")
private Long level;
@Schema(type = "Long", example = "5", description = "다음 레벨업까지 획득한 경험치")
private Long acquireExp;
@Schema(type = "Long", example = "10", description = "다음 레벨업까지 필요한 경험치")
private Long needExp;
@Schema(type = "Long", example = "5", description = "오늘 얻은 경험치")
private Long todayExp;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.noplanb.domain.quest.dto.res;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
public class RetrieveQuestRes {
@Schema(type = "Long", example = "1", description = "퀘스트 아이디")
private Long id;
@Schema(type = "String", example = "청소하기", description = "퀘스트 내용")
private String contents;
@Schema(type = "Long", example = "5", description = "퀘스트 경험치")
private Long exp;
@Schema(type = "Boolean", example = "true", description = "퀘스트 완료 여부")
private Boolean isComplete;
}
Loading

0 comments on commit 8a5367d

Please sign in to comment.