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

#14 [FEAT] 개인 대시보드 퍼즐 조회 API #17

Merged
merged 4 commits into from
Jul 15, 2023
Merged
Show file tree
Hide file tree
Changes from 3 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 @@ -26,14 +26,14 @@

@Service
@RequiredArgsConstructor
@Transactional
public class AuthServiceImpl implements AuthService {
private final JwtTokenProvider jwtTokenProvider;
private final KakaoAuthService kakaoAuthService;
private final MemberRepository memberRepository;
private final UserProjectRepository userProjectRepository;

@Override
@Transactional
public AuthResponseDto socialLogin(String socialAccessToken, AuthRequestDto authRequestDto) throws NoSuchAlgorithmException, InvalidKeySpecException {

if (authRequestDto.getSocialPlatform() == null) {
Expand Down Expand Up @@ -77,6 +77,7 @@ public AuthResponseDto socialLogin(String socialAccessToken, AuthRequestDto auth
}

@Override
@Transactional
public AuthTokenResponseDto getNewToken(String accessToken, String refreshToken) {
return AuthTokenResponseDto.of(accessToken,refreshToken);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

@RequiredArgsConstructor
@Component
public class KakaoAuthService {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.puzzling.puzzlingServer.api.project.controller;

import com.puzzling.puzzlingServer.api.project.dto.response.ProjectOwnPuzzleResponseDto;
import com.puzzling.puzzlingServer.api.project.dto.response.ProjectResponseDto;
import com.puzzling.puzzlingServer.api.project.dto.response.ProjectVerifyResponseDto;
import com.puzzling.puzzlingServer.api.project.service.ProjectService;
Expand All @@ -24,4 +25,9 @@ public ApiResponse<ProjectVerifyResponseDto> verifyProjectCode(@RequestParam Str
public ApiResponse<ProjectResponseDto> getProjectAll(@PathVariable Long memberId) {
return ApiResponse.success(SuccessStatus.GET_PROJECT_ALL_SUCCESS, projectService.getProjectAll(memberId));
}

@GetMapping("member/{memberId}/project/{projectId}/puzzle")
public ApiResponse<ProjectOwnPuzzleResponseDto> getMyPuzzles(@PathVariable Long memberId, @PathVariable Long projectId, @RequestParam String today) {
return ApiResponse.success(SuccessStatus.GET_PROJECT_MY_PUZZLE_SUCCESS, projectService.getMyPuzzles(memberId, projectId, today));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.puzzling.puzzlingServer.api.project.dto.response;

import com.puzzling.puzzlingServer.api.project.domain.Project;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

import static lombok.AccessLevel.PRIVATE;

@Getter
@NoArgsConstructor(access = PRIVATE)
@AllArgsConstructor
public class ProjectMyPuzzleObjectDto {
private String nickname;
private int puzzleCount;

public static ProjectMyPuzzleObjectDto of (String nickname, int puzzleCount) {
return new ProjectMyPuzzleObjectDto(nickname, puzzleCount);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.puzzling.puzzlingServer.api.project.dto.response;

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

import java.util.List;

import static lombok.AccessLevel.PRIVATE;

@Getter
@NoArgsConstructor(access = PRIVATE)
@AllArgsConstructor
public class ProjectOwnPuzzleResponseDto {
private ProjectMyPuzzleObjectDto myPuzzle;
private List<PuzzleObjectDto> userPuzzleBoard;
private Boolean isReviewDay;
private Boolean hasTodayReview;

public static ProjectOwnPuzzleResponseDto of(ProjectMyPuzzleObjectDto projectMyPuzzleObjectDto, List<PuzzleObjectDto> userPuzzleBoard,
Boolean isReviewDay, Boolean hasTodayReview) {
return new ProjectOwnPuzzleResponseDto(projectMyPuzzleObjectDto, userPuzzleBoard, isReviewDay, hasTodayReview);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.puzzling.puzzlingServer.api.project.dto.response;

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

import static lombok.AccessLevel.PRIVATE;

@Getter
@NoArgsConstructor(access = PRIVATE)
@AllArgsConstructor
public class PuzzleObjectDto {
private String reviewDate;
private Long reviewId;
private String puzzleAssetName;

public static PuzzleObjectDto of(String reviewDate, Long reviewId, String puzzleAssetName) {
return new PuzzleObjectDto(reviewDate, reviewId, puzzleAssetName);
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
package com.puzzling.puzzlingServer.api.project.service.Impl;

import com.puzzling.puzzlingServer.api.member.domain.Member;
import com.puzzling.puzzlingServer.api.member.repository.MemberRepository;
import com.puzzling.puzzlingServer.api.project.domain.UserProject;
import com.puzzling.puzzlingServer.api.project.dto.response.ProjectResponseDto;
import com.puzzling.puzzlingServer.api.project.dto.response.*;
import com.puzzling.puzzlingServer.api.project.repository.ProjectRepository;
import com.puzzling.puzzlingServer.api.project.domain.Project;
import com.puzzling.puzzlingServer.api.project.dto.response.ProjectVerifyResponseDto;
import com.puzzling.puzzlingServer.api.project.repository.UserProjectRepository;
import com.puzzling.puzzlingServer.api.project.service.ProjectService;
import com.puzzling.puzzlingServer.api.review.domain.Review;
import com.puzzling.puzzlingServer.api.review.repository.ReviewRepository;
import com.puzzling.puzzlingServer.common.exception.BadRequestException;
import com.puzzling.puzzlingServer.common.exception.NotFoundException;
import com.puzzling.puzzlingServer.common.response.ErrorStatus;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.TextStyle;
import java.util.*;
import java.util.stream.Collectors;

@Service
Expand All @@ -22,6 +33,8 @@ public class ProjectServiceImpl implements ProjectService {

private final ProjectRepository projectRepository;
private final UserProjectRepository userProjectRepository;
private final MemberRepository memberRepository;
private final ReviewRepository reviewRepository;

@Override
@Transactional
Expand All @@ -42,4 +55,59 @@ public List<ProjectResponseDto> getProjectAll(Long memberId) {
.map(project -> ProjectResponseDto.of(project))
.collect(Collectors.toList());
}

@Override
@Transactional
public ProjectOwnPuzzleResponseDto getMyPuzzles(Long memberId, Long projectId, String today) {
if (today.equals("") || today == null) {
throw new BadRequestException(ErrorStatus.VALIDATION_REQUEST_MISSING_EXCEPTION.getMessage());
}
Member findMember = findMemberById(memberId);
int puzzleCount = reviewRepository.findByUserIdAndProjectId(memberId, projectId).size();
ProjectMyPuzzleObjectDto projectMyPuzzleObjectDto = ProjectMyPuzzleObjectDto.of(findMember.getName(), puzzleCount);

Pageable pageable = PageRequest.of(0, 15); // 첫 번째 페이지, 페이지 크기 15
Page<Review> pageReviews = reviewRepository.findTop15ByMemberIdAndProjectId(memberId, projectId, pageable);
List<Review> top15Reviews = pageReviews.getContent();

Boolean isReviewDay = checkTodayIsReviewDay(today, projectId);
Boolean hasTodayReview = reviewRepository.existsReviewByReviewDate(today);

List<PuzzleObjectDto> result = new ArrayList<>();
int idx = 1;
for (Review review : top15Reviews) {
result.add(PuzzleObjectDto.of(review.getReviewDate(), review.getId(), "puzzleA" + idx++));
}

if (isReviewDay) {
if (!hasTodayReview) {
result.add(PuzzleObjectDto.of(null, null, "puzzleD" + idx));
}
}
return ProjectOwnPuzzleResponseDto.of(projectMyPuzzleObjectDto,result,isReviewDay,hasTodayReview);
}

private Member findMemberById(Long memberId) {
return memberRepository.findById(memberId)
.orElseThrow(() -> new BadRequestException(ErrorStatus.INVALID_MEMBER.getMessage()));
}

private Project findProjectById(Long projectId) {
return projectRepository.findById(projectId)
.orElseThrow(() -> new NotFoundException(ErrorStatus.NOT_FOUND_PROJECT.getMessage()));
}

private Boolean checkTodayIsReviewDay (String today, Long projectId) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate todayDate = LocalDate.parse(today, formatter);

DayOfWeek dayOfWeek = todayDate.getDayOfWeek();
Locale koreanLocale = new Locale("ko", "KR");
String dayOfWeekKorean = dayOfWeek.getDisplayName(TextStyle.SHORT, koreanLocale);

String reviewCycle = findProjectById(projectId).getReviewCycle();
List<String> weekdayList = Arrays.asList(reviewCycle.split(","));
return weekdayList.contains(dayOfWeekKorean);
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.puzzling.puzzlingServer.api.project.service;

import com.puzzling.puzzlingServer.api.project.domain.Project;
import com.puzzling.puzzlingServer.api.project.dto.response.ProjectOwnPuzzleResponseDto;
import com.puzzling.puzzlingServer.api.project.dto.response.ProjectResponseDto;
import com.puzzling.puzzlingServer.api.project.dto.response.ProjectVerifyResponseDto;

Expand All @@ -13,4 +14,7 @@ public interface ProjectService {

//* 참여 중인 프로젝트 리스트 조회
List<ProjectResponseDto> getProjectAll(Long memberId);

//* 개인 대시보드 퍼즐 조회
ProjectOwnPuzzleResponseDto getMyPuzzles(Long memberId, Long projectId, String today);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.puzzling.puzzlingServer.api.review.repository;

import com.puzzling.puzzlingServer.api.review.domain.Review;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.List;


public interface ReviewRepository extends JpaRepository<Review, Long> {
List<Review> findByUserIdAndProjectId(Long memberId, Long projectId);

@Query("SELECT r FROM Review r WHERE r.userId = :memberId AND r.projectId = :projectId ORDER BY r.createdAt ASC")
Page<Review> findTop15ByMemberIdAndProjectId(Long memberId, Long projectId, Pageable pageable);

boolean existsReviewByReviewDate(String date);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.client.HttpClientErrorException;

import java.time.format.DateTimeParseException;

import static com.puzzling.puzzlingServer.common.response.ErrorStatus.KAKAO_UNAUTHORIZED_USER;

@RestControllerAdvice
public class ControllerExceptionAdvice {
Expand All @@ -30,4 +35,17 @@ public ResponseEntity<ApiResponse> handleIllegalArgument(IllegalArgumentExcepti
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(ApiResponse.fail(HttpStatus.BAD_REQUEST.value(), ex.getMessage()));
}

@ExceptionHandler(DateTimeParseException.class)
public ResponseEntity<ApiResponse> handleDateTimeParseException(DateTimeParseException ex) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(ApiResponse.fail(HttpStatus.BAD_REQUEST.value(), "요청하는 날짜 형식이 올바르지 않습니다."));
}

@ExceptionHandler(HttpClientErrorException.class)
public ResponseEntity<ApiResponse> handleHttpClientErrorException(HttpClientErrorException ex) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
.body(ApiResponse.fail(HttpStatus.UNAUTHORIZED.value(), KAKAO_UNAUTHORIZED_USER.getMessage()));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public enum ErrorStatus {
* 404 NOT_FOUND
*/
NOT_FOUND_PROJECT_CODE("유효하지 않은 초대코드에요. 코드를 확인해 주세요."),
NOT_FOUND_PROJECT("해당하는 프로젝트가 없습니다"),


/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public enum SuccessStatus {
*/
PROJECT_VERIFY_SUCCESS(HttpStatus.OK, "초대코드 유효성 검사 성공"),
GET_PROJECT_ALL_SUCCESS(HttpStatus.OK, "진행 중인 프로젝트 리스트 조회 성공"),
GET_PROJECT_MY_PUZZLE_SUCCESS(HttpStatus.OK, "개인 대시보드 퍼즐 조회 성공")
;

private final HttpStatus httpStatus;
Expand Down
Loading