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 @@ -7,6 +7,7 @@
import com.ject.studytrip.mission.domain.repository.DailyMissionQueryRepository;
import com.ject.studytrip.mission.domain.repository.DailyMissionRepository;
import com.ject.studytrip.trip.domain.model.DailyGoal;
import com.ject.studytrip.trip.domain.model.TripCategory;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
Expand Down Expand Up @@ -44,7 +45,27 @@ public List<DailyMission> getValidDailyMissionsByIds(
return dailyMissions;
}

public List<DailyMission> getValidDailyMissionByIdsWithMissionAndStamp(
Long dailyGoalId, List<Long> dailyMissionIds) {
List<DailyMission> dailyMissions =
dailyMissionQueryRepository.findAllByIdsFetchJoinMissionAndStamp(dailyMissionIds);

DailyMissionPolicy.validateExistAll(dailyMissions, dailyMissionIds);
dailyMissions.forEach(
dailyMission -> {
DailyMissionPolicy.validateBelongsToDailyGoal(dailyMission, dailyGoalId);
DailyMissionPolicy.validateNotDeleted(dailyMission);
});

return dailyMissions;
}

public List<DailyMission> getDailyMissionsByDailyGoal(Long dailyGoalId) {
return dailyMissionQueryRepository.findAllByDailyGoalIdFetchJoinMission(dailyGoalId);
}

public void validateSelectedDailyMissions(
TripCategory tripCategory, List<DailyMission> dailyMissions) {
DailyMissionPolicy.validateCourseTripStampConsistency(tripCategory, dailyMissions);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ public void updateMissionOrders(Long stampId, UpdateMissionOrderRequest request)
}
}

public void updateCompleted(Mission mission) {
MissionPolicy.validateNotDeleted(mission);
MissionPolicy.validateCompleted(mission);

mission.updateCompleted();
}

@Transactional
public void deleteMission(Long stampId, Mission mission) {
validateMissionIsActiveAndBelongsToStamp(stampId, mission);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
public enum DailyMissionErrorCode implements ErrorCode {
// 400
DAILY_MISSION_ALREADY_DELETED(HttpStatus.BAD_REQUEST, "이미 삭제된 데일리 미션입니다."),
COURSE_TRIP_STAMP_MISMATCH(HttpStatus.BAD_REQUEST, "코스형 여행의 데일리 미션들은 모두 동일한 스탬프여야 합니다."),

// 403
DAILY_MISSION_NOT_BELONG_TO_DAILY_GOAL(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
import com.ject.studytrip.global.exception.CustomException;
import com.ject.studytrip.mission.domain.error.DailyMissionErrorCode;
import com.ject.studytrip.mission.domain.model.DailyMission;
import com.ject.studytrip.trip.domain.model.TripCategory;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;

Expand All @@ -24,4 +27,18 @@ public static void validateNotDeleted(DailyMission dailyMission) {
if (dailyMission.getDeletedAt() != null)
throw new CustomException(DailyMissionErrorCode.DAILY_MISSION_ALREADY_DELETED);
}

public static void validateCourseTripStampConsistency(
TripCategory tripCategory, List<DailyMission> dailyMissions) {
if (tripCategory != TripCategory.COURSE) return;

Set<Long> stampIds =
dailyMissions.stream()
.map(dailyMission -> dailyMission.getMission().getStamp().getId())
.collect(Collectors.toSet());

if (stampIds.size() != 1) {
throw new CustomException(DailyMissionErrorCode.COURSE_TRIP_STAMP_MISMATCH);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@

public interface DailyMissionQueryRepository {
List<DailyMission> findAllByDailyGoalIdFetchJoinMission(Long dailyGoalId);

List<DailyMission> findAllByIdsFetchJoinMissionAndStamp(List<Long> ids);
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package com.ject.studytrip.mission.infra.jpa;
package com.ject.studytrip.mission.infra.querydsl;

import com.ject.studytrip.mission.domain.model.DailyMission;
import com.ject.studytrip.mission.domain.model.QDailyMission;
import com.ject.studytrip.mission.domain.model.QMission;
import com.ject.studytrip.mission.domain.repository.DailyMissionQueryRepository;
import com.ject.studytrip.stamp.domain.model.QStamp;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
import lombok.RequiredArgsConstructor;
Expand All @@ -15,6 +16,7 @@ public class DailyMissionQueryRepositoryAdapter implements DailyMissionQueryRepo
private final JPAQueryFactory queryFactory;
private final QDailyMission dailyMission = QDailyMission.dailyMission;
private final QMission mission = QMission.mission;
private final QStamp stamp = QStamp.stamp;

@Override
public List<DailyMission> findAllByDailyGoalIdFetchJoinMission(Long dailyGoalId) {
Expand All @@ -25,4 +27,16 @@ public List<DailyMission> findAllByDailyGoalIdFetchJoinMission(Long dailyGoalId)
.where(dailyMission.dailyGoal.id.eq(dailyGoalId), dailyMission.deletedAt.isNull())
.fetch();
}

@Override
public List<DailyMission> findAllByIdsFetchJoinMissionAndStamp(List<Long> ids) {
return queryFactory
.selectFrom(dailyMission)
.join(dailyMission.mission, mission)
.fetchJoin()
.join(mission.stamp, stamp)
.fetchJoin()
.where(dailyMission.id.in(ids))
.fetch();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.ject.studytrip.mission.infra.jpa;
package com.ject.studytrip.mission.infra.querydsl;

import com.ject.studytrip.mission.domain.model.Mission;
import com.ject.studytrip.mission.domain.model.QMission;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,18 @@ public Pomodoro getValidPomodoroByDailyGoal(Long dailyGoalId) {

return pomodoro;
}

public void updateTotalFocusTime(Long dailyGoalId, int totalFocusTimeInMinutes) {
PomodoroPolicy.validateTotalFocusTimeNotNegative(totalFocusTimeInMinutes);

Pomodoro pomodoro =
pomodoroRepository
.findByDailyGoalId(dailyGoalId)
.orElseThrow(
() -> new CustomException(PomodoroErrorCode.POMODORO_NOT_FOUND));
PomodoroPolicy.validateNotDeleted(pomodoro);

int totalFocusTimeInSeconds = totalFocusTimeInMinutes * 60;
pomodoro.updateTotalFocusTimeInSeconds(totalFocusTimeInSeconds);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
public enum PomodoroErrorCode implements ErrorCode {
// 400
POMODORO_ALREADY_DELETED(HttpStatus.BAD_REQUEST, "이미 삭제된 뽀모도로입니다."),
POMODORO_NEGATIVE_FOCUS_TIME(HttpStatus.BAD_REQUEST, "뽀모도로 총 집중시간(분)은 음수일 수 없습니다."),

// 404
POMODORO_NOT_FOUND(HttpStatus.NOT_FOUND, "요청한 뽀모도로 정보를 찾을 수 없습니다."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ public static Pomodoro of(
.build();
}

public void updateTotalFocusTimeInSeconds(int totalFocusTimeInSeconds) {
this.totalFocusTimeInSeconds = totalFocusTimeInSeconds;
}

public void updateDeletedAt() {
this.deletedAt = LocalDateTime.now();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,10 @@ public static void validateNotDeleted(Pomodoro pomodoro) {
if (pomodoro.getDeletedAt() != null)
throw new CustomException(PomodoroErrorCode.POMODORO_ALREADY_DELETED);
}

public static void validateTotalFocusTimeNotNegative(int totalFocusTime) {
if (totalFocusTime < 0) {
throw new CustomException(PomodoroErrorCode.POMODORO_NEGATIVE_FOCUS_TIME);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
import com.ject.studytrip.stamp.presentation.dto.request.UpdateStampOrderRequest;
import com.ject.studytrip.trip.domain.model.Trip;
import com.ject.studytrip.trip.domain.model.TripCategory;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
Expand All @@ -23,7 +21,6 @@
@Service
@RequiredArgsConstructor
public class StampService {

private final StampRepository stampRepository;
private final StampQueryRepository stampQueryRepository;

Expand Down Expand Up @@ -137,6 +134,44 @@ public Stamp getFirstInCompleteStampForCourseTrip(Long tripId) {
.orElseThrow(() -> new CustomException(StampErrorCode.STAMP_NOT_FOUND));
}

public String getStampNameByTripCategory(TripCategory tripCategory, List<Stamp> stamps) {
// 스탬프 목록이 비어있지 않은지 검증
StampPolicy.validateStampListNotEmpty(stamps);
stamps.forEach(StampPolicy::validateNotDeleted);

if (tripCategory == TripCategory.COURSE) {
return getCourseStampName(stamps);
}

return getExplorationStampName(stamps);
}

private String getCourseStampName(List<Stamp> stamps) {
return new HashSet<>(stamps).iterator().next().getName();
}

private String getExplorationStampName(List<Stamp> stamps) {
// 스탬프별 개수 집계
Map<Stamp, Long> stampCountMap =
stamps.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

// 최대 개수를 가진 스탬프들 찾기
long maxCount = stampCountMap.values().stream().max(Long::compareTo).orElse(0L);

List<Stamp> maxCountStamps =
stampCountMap.entrySet().stream()
.filter(entry -> entry.getValue().equals(maxCount))
.map(Map.Entry::getKey)
.toList();

// 가장 이른 생성 시간을 가진 스탬프 선택
return maxCountStamps.stream()
.min(Comparator.comparing(Stamp::getCreatedAt))
.map(Stamp::getName)
.orElse("");
}

public void validateStampBelongsToTrip(Long tripId, Stamp stamp) {
StampPolicy.validateStampBelongsToTrip(tripId, stamp);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public enum StampErrorCode implements ErrorCode {
STAMP_ALREADY_DELETED(HttpStatus.BAD_REQUEST, "이미 삭제된 스탬프입니다."),
CANNOT_UPDATE_ORDER_FOR_EXPLORATION_TRIP(HttpStatus.BAD_REQUEST, "탐험형 여행의 스탬프 순서는 변경할 수 없습니다."),
INVALID_STAMP_ID_IN_REQUEST(HttpStatus.BAD_REQUEST, "존재하지 않는 스탬프 ID가 포함되어 있습니다. "),
STAMP_LIST_CANNOT_BE_EMPTY(HttpStatus.BAD_REQUEST, "스탬프 목록은 비어있을 수 없습니다."),

// 403
STAMP_NOT_BELONG_TO_TRIP(HttpStatus.FORBIDDEN, "해당 스탬프는 요청한 여행에 속하지 않습니다."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,10 @@ public static void validateUpdateStampOrders(
if (orderedStampIds.size() != savedStamps.size())
throw new CustomException(StampErrorCode.INVALID_STAMP_ID_IN_REQUEST);
}

public static void validateStampListNotEmpty(List<Stamp> stamps) {
if (stamps.isEmpty()) {
throw new CustomException(StampErrorCode.STAMP_LIST_CANNOT_BE_EMPTY);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.ject.studytrip.studylog.application.dto;

import com.ject.studytrip.mission.application.dto.DailyMissionInfo;
import com.ject.studytrip.studylog.domain.model.StudyLogDailyMission;

public record StudyLogDailyMissionInfo(
Long studyLogDailyMissionId, DailyMissionInfo dailyMissionInfo) {
public static StudyLogDailyMissionInfo from(StudyLogDailyMission studyLogDailyMission) {
return new StudyLogDailyMissionInfo(
studyLogDailyMission.getId(),
DailyMissionInfo.from(studyLogDailyMission.getDailyMission()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.ject.studytrip.studylog.application.dto;

import com.ject.studytrip.studylog.domain.model.StudyLog;
import com.ject.studytrip.studylog.domain.model.StudyLogDailyMission;
import java.util.List;

public record StudyLogDetail(
StudyLogInfo studyLogInfo, List<StudyLogDailyMissionInfo> studyLogDailyMissionInfos) {
public static StudyLogDetail from(
StudyLog studyLog, List<StudyLogDailyMission> studyLogDailyMissions) {
return new StudyLogDetail(
StudyLogInfo.from(studyLog),
studyLogDailyMissions.stream().map(StudyLogDailyMissionInfo::from).toList());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.ject.studytrip.studylog.application.dto;

import com.ject.studytrip.global.util.DateUtil;
import com.ject.studytrip.studylog.domain.model.StudyLog;

public record StudyLogInfo(
Long studyLogId,
String title,
String content,
String createdAt,
String updatedAt,
String deletedAt) {
public static StudyLogInfo from(StudyLog studyLog) {
return new StudyLogInfo(
studyLog.getId(),
studyLog.getTitle(),
studyLog.getContent(),
DateUtil.formatDateTime(studyLog.getCreatedAt()),
DateUtil.formatDateTime(studyLog.getUpdatedAt()),
DateUtil.formatDateTime(studyLog.getDeletedAt()));
}
}
Loading