Skip to content
Open
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,7 +2,6 @@

import lombok.Builder;

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

public class MissionResponseDto {
Expand All @@ -22,4 +21,25 @@ public record GetMission (
public record CountMissions(
int count
){}

@Builder
public record GetMissionsPaged(
List<GetMission> missions,
Integer pageNumber,
Integer pageSize,
Integer totalPages,
Long totalElements,
Boolean first,
Boolean last
) {
@Builder
public record GetMission(
Long missionId,
String storeName,
String title,
String content,
Integer reward,
String status
) {}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,21 @@ public record ReviewItem (
LocalDateTime createdAt
){}
}

@Builder
public record GetMyReviewsPaged(
List<ReviewItem> reviews,
Boolean hasNext,
String nextCursor,
Integer pageSize
) {
@Builder
public record ReviewItem(
Long reviewId,
String nickname,
String stars,
String content,
LocalDateTime createdAt
) {}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@


import com.umc.umc10th.domain.review.entity.Review;
import com.umc.umc10th.domain.review.enums.Stars;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
Expand All @@ -29,4 +31,30 @@ boolean existsByStoreAndUser(
@Param("storeId") Long storeId,
@Param("userId") Long userId
);

Slice<Review> findReviewsByUser_IdOrderByIdDesc(
Long userId,
Pageable pageable
);

Slice<Review> findReviewsByUser_IdAndIdLessThanOrderByIdDesc(
Long userId,
Long idCursor,
Pageable pageable
);

Slice<Review> findReviewsByUser_IdOrderByStarsDescIdDesc(
Long userId,
Pageable pageable
);

@Query("SELECT r FROM Review r WHERE r.user.id = :userId " +
"AND (r.stars < :starsCursor OR (r.stars = :starsCursor AND r.id < :idCursor)) " +
"ORDER BY r.stars DESC, r.id DESC")
Slice<Review> findReviewsByUser_IdOrderByStarsDesc(
@Param("userId") Long userId,
@Param("starsCursor") Stars starsCursor,
@Param("idCursor") Long idCursor,
Pageable pageable
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.umc.umc10th.domain.user.service.UserService;
import com.umc.umc10th.global.apipayload.ApiResponse;
import com.umc.umc10th.global.apipayload.code.BaseSuccessCode;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

Expand All @@ -16,7 +17,7 @@ public class UserAuthController {
private final UserService userService;

// @PostMapping("/signup")
// public ApiResponse<Void> getInfo(@RequestBody UserRequestDto.CreateUser dto) {
// public ApiResponse<Void> getInfo(@Valid @RequestBody UserRequestDto.CreateUser dto) {
// BaseSuccessCode code = UserSuccessCode.OK;
// userService.createUser(dto);
// return ApiResponse.onSuccess(code);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package com.umc.umc10th.domain.user.controller;

import com.umc.umc10th.domain.mission.dto.response.MissionResponseDto;
import com.umc.umc10th.domain.review.dto.response.ReviewResponseDto;
import com.umc.umc10th.domain.user.apipayload.code.UserSuccessCode;
import com.umc.umc10th.domain.user.dto.request.UserRequestDto;
import com.umc.umc10th.domain.user.dto.response.UserResponseDto;
import com.umc.umc10th.domain.user.service.UserService;
import com.umc.umc10th.global.apipayload.ApiResponse;
import com.umc.umc10th.global.apipayload.code.BaseSuccessCode;
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
@RequestMapping("/api/users")
Expand All @@ -26,11 +26,30 @@ public ApiResponse<UserResponseDto.GetInfo> getInfo() {
}

@GetMapping("/me/missions")
public ApiResponse<MissionResponseDto.GetMissions> getMissions(@RequestParam Long locationId, @RequestParam String status) {
BaseSuccessCode code = UserSuccessCode.OK;
return ApiResponse.onSuccess(code, userService.getMissions(locationId, status));
public ApiResponse<MissionResponseDto.GetMissionsPaged> getMissions(
@RequestParam Long locationId,
@RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(defaultValue = "0") Integer pageNumber,
@RequestBody @Valid UserRequestDto.GetMissionsRequest request) {

return ApiResponse.onSuccess(
UserSuccessCode.OK,
userService.getMissions(locationId, pageSize, pageNumber, request)
);
}

@GetMapping("/me/reviews")
public ApiResponse<ReviewResponseDto.GetMyReviewsPaged> getMyReviews(
@RequestParam Long userId,
@RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(defaultValue = "-1") String cursor,
@RequestParam(defaultValue = "ID") String query) {

return ApiResponse.onSuccess(
UserSuccessCode.OK,
userService.getMyReviews(userId, pageSize, cursor, query)
);
}
// @GetMapping("/me/missions/count")
// public ApiResponse<MissionResponseDto.CountMissions> countMissions(@RequestParam Long locationId) {
// BaseSuccessCode code = UserSuccessCode.OK;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,61 @@
package com.umc.umc10th.domain.user.converter;

import com.umc.umc10th.domain.mission.dto.response.MissionResponseDto;
import com.umc.umc10th.domain.review.dto.response.ReviewResponseDto;
import com.umc.umc10th.domain.review.entity.Review;
import com.umc.umc10th.domain.user.entity.UserDoingMission;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Slice;

import java.util.List;

public class UserConverter {

public static MissionResponseDto.GetMissionsPaged toGetMissionsPaged(
Page<UserDoingMission> page) {

List<MissionResponseDto.GetMissionsPaged.GetMission> missions =
page.getContent().stream()
.map(udm -> MissionResponseDto.GetMissionsPaged.GetMission.builder()
.missionId(udm.getMission().getId())
.storeName(udm.getMission().getStore().getStoreName())
.title(udm.getMission().getTitle())
.content(udm.getMission().getContent())
.reward(udm.getMission().getReward())
.status(udm.getIsCompleted() ? "COMPLETED" : "IN_PROGRESS")
.build())
.toList();

return MissionResponseDto.GetMissionsPaged.builder()
.missions(missions)
.pageNumber(page.getNumber())
.pageSize(page.getSize())
.totalPages(page.getTotalPages())
.totalElements(page.getTotalElements())
.first(page.isFirst())
.last(page.isLast())
.build();
}

public static ReviewResponseDto.GetMyReviewsPaged toGetMyReviewsPaged(
Slice<Review> slice, String nextCursor) {

List<ReviewResponseDto.GetMyReviewsPaged.ReviewItem> reviews =
slice.getContent().stream()
.map(r -> ReviewResponseDto.GetMyReviewsPaged.ReviewItem.builder()
.reviewId(r.getId())
.nickname(r.getUser().getName())
.stars(r.getStars().name())
.content(r.getContent())
.createdAt(r.getCreatedAt())
.build())
.toList();

return ReviewResponseDto.GetMyReviewsPaged.builder()
.reviews(reviews)
.hasNext(slice.hasNext())
.nextCursor(nextCursor)
.pageSize(slice.getSize())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.umc.umc10th.domain.user.enums.Provider;
import com.umc.umc10th.domain.user.enums.ServiceRole;
import com.umc.umc10th.domain.user.enums.Sex;
import jakarta.validation.constraints.*;
import lombok.Builder;

import java.time.LocalDate;
Expand All @@ -20,4 +21,10 @@ public record CreateUser (
String address,
String phone
){}

@Builder
public record GetMissionsRequest(
@NotNull(message = "사용자 ID는 필수입니다")
Long userId
) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,10 @@ Page<UserDoingMission> findMyMissions(
@Param("status") String status,
Pageable pageable
);

Page<UserDoingMission> findAllByUser_IdAndMission_Location_Id(
Long userId,
Long locationId,
Pageable pageable
);
}
66 changes: 66 additions & 0 deletions src/main/java/com/umc/umc10th/domain/user/service/UserService.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
import com.umc.umc10th.domain.mission.dto.response.MissionResponseDto;
import com.umc.umc10th.domain.review.dto.response.ReviewResponseDto;
import com.umc.umc10th.domain.review.entity.Review;
import com.umc.umc10th.domain.review.enums.Stars;
import com.umc.umc10th.domain.review.repository.ReviewRepository;
import com.umc.umc10th.domain.user.converter.UserConverter;
import com.umc.umc10th.domain.user.dto.request.UserRequestDto;
import com.umc.umc10th.domain.user.dto.response.UserResponseDto;
import com.umc.umc10th.domain.user.entity.User;
import com.umc.umc10th.domain.user.entity.UserDoingMission;
Expand All @@ -13,6 +16,7 @@
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.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand Down Expand Up @@ -78,4 +82,66 @@ public ReviewResponseDto.GetMyReviews getMyReviews() {
.reviews(items)
.build();
}

public MissionResponseDto.GetMissionsPaged getMissions(
Long locationId,
Integer pageSize,
Integer pageNumber,
UserRequestDto.GetMissionsRequest request
) {

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

Page<UserDoingMission> page =
userDoingMissionRepository.findAllByUser_IdAndMission_Location_Id(
request.userId(), locationId, pageRequest
);

return UserConverter.toGetMissionsPaged(page);
}

public ReviewResponseDto.GetMyReviewsPaged getMyReviews(
Long userId, Integer pageSize, String cursor, String query) { // ← 파라미터 분리

PageRequest pageRequest = PageRequest.of(0, pageSize);
Slice<Review> slice;

if (!cursor.equals("-1")) {
String[] split = cursor.split(":");
switch (query.toUpperCase()) {
case "ID" -> {
Long idCursor = Long.parseLong(split[1]);
slice = reviewRepository.findReviewsByUser_IdAndIdLessThanOrderByIdDesc(
userId, idCursor, pageRequest
);
}
case "STARS" -> {
Stars starsCursor = Stars.valueOf(split[0]);
Long idCursor = Long.parseLong(split[1]);
slice = reviewRepository.findReviewsByUser_IdOrderByStarsDesc(
userId, starsCursor, idCursor, pageRequest
);
}
default -> throw new IllegalArgumentException("유효하지 않은 정렬 기준입니다: " + query);
}
} else {
slice = switch (query.toUpperCase()) {
case "STARS" -> reviewRepository.findReviewsByUser_IdOrderByStarsDescIdDesc(
userId, pageRequest
);
default -> reviewRepository.findReviewsByUser_IdOrderByIdDesc(
userId, pageRequest
);
};
}

String nextCursor = null;
if (slice.hasNext() && !slice.getContent().isEmpty()) {
List<Review> content = slice.getContent();
Review last = content.get(content.size() - 1);
nextCursor = last.getStars().name() + ":" + last.getId();
}

return UserConverter.toGetMyReviewsPaged(slice, nextCursor);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.net.BindException;
import java.util.stream.Collectors;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@RestControllerAdvice
Expand All @@ -28,16 +29,16 @@ public ResponseEntity<ApiResponse<Void>> handleProjectException(
}

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ApiResponse<Void>> handleMethodArgumentValidation(
MethodArgumentNotValidException e) {
public ResponseEntity<ApiResponse<Map<String, String>>> handleMethodArgumentValidation(
MethodArgumentNotValidException e
) {

String message = e.getBindingResult().getFieldErrors().stream()
.map(fe -> fe.getField() + ": " + fe.getDefaultMessage())
.collect(Collectors.joining(", "));
Map<String, String> errors = new HashMap<>();
e.getBindingResult().getFieldErrors().forEach(error -> { errors.put(error.getField(), error.getDefaultMessage()); });

BaseErrorCode code = GeneralErrorCode.BAD_REQUEST;
return ResponseEntity.status(code.getStatus())
.body(ApiResponse.onFailure(code, null));
.body(ApiResponse.onFailure(code, errors));
}

@ExceptionHandler(BindException.class)
Expand Down