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
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ plugins {
id 'io.spring.dependency-management' version '1.1.7'
id 'com.diffplug.spotless' version '6.21.0'
id 'org.flywaydb.flyway' version '11.11.2'
id 'org.jetbrains.kotlin.jvm'
}

group = 'com.ject'
Expand Down Expand Up @@ -77,6 +78,7 @@ dependencies {
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
testImplementation 'org.mockito:mockito-core'
testImplementation 'org.mockito:mockito-junit-jupiter'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
}

jar.enabled = false // 일반 JAR 파일 생성 비활성화
Expand Down
5 changes: 5 additions & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
pluginManagement {
plugins {
id 'org.jetbrains.kotlin.jvm' version '2.2.20'
}
}
rootProject.name = 'studytrip-server'
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.ject.studytrip.member.application.dto;

import com.ject.studytrip.trip.application.dto.TripCountInfo;
import com.ject.studytrip.trip.application.dto.TripCount;

public record MemberDetail(MemberInfo memberInfo, TripCountInfo tripCount, long studyLogCount) {
public record MemberDetail(MemberInfo memberInfo, TripCount tripCount, long studyLogCount) {
public static MemberDetail from(
MemberInfo memberInfo, TripCountInfo tripCount, long studyLogCount) {
MemberInfo memberInfo, TripCount tripCount, long studyLogCount) {
return new MemberDetail(memberInfo, tripCount, studyLogCount);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import com.ject.studytrip.member.presentation.dto.request.PresignProfileImageRequest;
import com.ject.studytrip.member.presentation.dto.request.UpdateMemberRequest;
import com.ject.studytrip.studylog.application.service.StudyLogQueryService;
import com.ject.studytrip.trip.application.dto.TripCountInfo;
import com.ject.studytrip.trip.application.dto.TripCount;
import com.ject.studytrip.trip.application.service.TripQueryService;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
Expand Down Expand Up @@ -62,7 +62,7 @@ public void deleteMember(Long memberId) {
@Transactional(readOnly = true)
public MemberDetail getMemberDetail(Long memberId) {
Member member = memberQueryService.getValidMember(memberId);
TripCountInfo tripCount = tripQueryService.getActiveTripCountsByMemberId(memberId);
TripCount tripCount = tripQueryService.getActiveTripCountsByMemberId(memberId);
long studyLogCount = studyLogQueryService.getActiveStudyLogCountByMemberId(memberId);

MemberInfo memberInfo = MemberInfo.from(member);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import com.ject.studytrip.member.application.dto.MemberInfo;
import com.ject.studytrip.member.domain.model.MemberCategory;
import com.ject.studytrip.trip.application.dto.TripCountInfo;
import com.ject.studytrip.trip.application.dto.TripCount;
import io.swagger.v3.oas.annotations.media.Schema;

public record LoadMemberDetailResponse(
Expand All @@ -15,7 +15,7 @@ public record LoadMemberDetailResponse(
@Schema(description = "탐험형 여행 개수") long exploreTripCount,
@Schema(description = "학습 기록 개수") long studyLogCount) {
public static LoadMemberDetailResponse of(
MemberInfo memberInfo, TripCountInfo tripCount, long studyLogCount) {
MemberInfo memberInfo, TripCount tripCount, long studyLogCount) {
return new LoadMemberDetailResponse(
memberInfo.memberId(),
memberInfo.email(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,8 @@ public List<Mission> getValidMissionsWithStamp(List<Long> missionIds) {

return missions;
}

public long countCompletedMissionsByTripId(Long tripId) {
return missionQueryRepository.countCompletedMissionsByTripId(tripId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ public interface MissionQueryRepository {
long deleteAllByDeletedAtIsNotNull();

long deleteAllByDeletedStampOwner();

long countCompletedMissionsByTripId(Long tripId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.ject.studytrip.mission.domain.model.QMission;
import com.ject.studytrip.mission.domain.repository.MissionQueryRepository;
import com.ject.studytrip.stamp.domain.model.QStamp;
import com.ject.studytrip.trip.domain.model.QTrip;
import com.querydsl.jpa.JPAExpressions;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
Expand All @@ -16,6 +17,7 @@ public class MissionQueryRepositoryAdapter implements MissionQueryRepository {
private final JPAQueryFactory queryFactory;
private final QMission mission = QMission.mission;
private final QStamp stamp = QStamp.stamp;
private final QTrip trip = QTrip.trip;

@Override
public List<Mission> findAllByIdsInFetchJoinStamp(List<Long> ids) {
Expand Down Expand Up @@ -59,6 +61,25 @@ public long deleteAllByDeletedStampOwner() {
.execute();
}

@Override
public long countCompletedMissionsByTripId(Long tripId) {
Long count =
queryFactory
.select(mission.id.count())
.from(mission)
.join(mission.stamp, stamp)
.join(stamp.trip, trip)
.where(
trip.id.eq(tripId),
mission.completed.isTrue(),
mission.deletedAt.isNull(),
stamp.deletedAt.isNull(),
trip.deletedAt.isNull())
.fetchOne();

return count != null ? count : 0L;
}

// @Override
// public long countByStampIdAndDeletedAtIsNull(Long stampId) {
// Long count =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.ject.studytrip.pomodoro.domain.error.PomodoroErrorCode;
import com.ject.studytrip.pomodoro.domain.model.Pomodoro;
import com.ject.studytrip.pomodoro.domain.policy.PomodoroPolicy;
import com.ject.studytrip.pomodoro.domain.repository.PomodoroQueryRepository;
import com.ject.studytrip.pomodoro.domain.repository.PomodoroRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
Expand All @@ -12,6 +13,7 @@
@RequiredArgsConstructor
public class PomodoroQueryService {
private final PomodoroRepository pomodoroRepository;
private final PomodoroQueryRepository pomodoroQueryRepository;

public Pomodoro getValidPomodoroByDailyGoal(Long dailyGoalId) {
Pomodoro pomodoro =
Expand All @@ -24,4 +26,8 @@ public Pomodoro getValidPomodoroByDailyGoal(Long dailyGoalId) {

return pomodoro;
}

public long getTotalFocusHoursByTripId(Long tripId) {
return pomodoroQueryRepository.sumFocusHoursByTripId(tripId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ public interface PomodoroQueryRepository {
long deleteAllByDeletedAtIsNotNull();

long deleteAllByDeletedDailyGoalOwner();

long sumFocusHoursByTripId(Long tripId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.ject.studytrip.pomodoro.domain.model.QPomodoro;
import com.ject.studytrip.pomodoro.domain.repository.PomodoroQueryRepository;
import com.ject.studytrip.trip.domain.model.QDailyGoal;
import com.ject.studytrip.trip.domain.model.QTrip;
import com.querydsl.jpa.JPAExpressions;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
Expand All @@ -14,6 +15,7 @@ public class PomodoroQueryRepositoryAdapter implements PomodoroQueryRepository {
private final JPAQueryFactory queryFactory;
private final QPomodoro pomodoro = QPomodoro.pomodoro;
private final QDailyGoal dailyGoal = QDailyGoal.dailyGoal;
private final QTrip trip = QTrip.trip;

@Override
public long deleteAllByDeletedAtIsNotNull() {
Expand All @@ -31,4 +33,24 @@ public long deleteAllByDeletedDailyGoalOwner() {
.where(dailyGoal.deletedAt.isNotNull())))
.execute();
}

@Override
public long sumFocusHoursByTripId(Long tripId) {
Integer totalSeconds =
queryFactory
.select(pomodoro.totalFocusTimeInSeconds.sum())
.from(pomodoro)
.join(pomodoro.dailyGoal, dailyGoal)
.join(dailyGoal.trip, trip)
.where(
trip.id.eq(tripId),
pomodoro.deletedAt.isNull(),
dailyGoal.deletedAt.isNull(),
trip.deletedAt.isNull())
.fetchOne();

long seconds = totalSeconds == null ? 0L : totalSeconds.longValue();

return seconds / 3600L; // 정수 시간(내림)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@

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

public record StudyLogDetail(
StudyLogInfo studyLogInfo, List<StudyLogDailyMissionInfo> studyLogDailyMissionInfos) {
public static StudyLogDetail from(
StudyLog studyLog, List<StudyLogDailyMission> studyLogDailyMissions) {
List<StudyLogDailyMission> safeStudyLogDailyMissions =
Optional.ofNullable(studyLogDailyMissions).orElse(Collections.emptyList());

return new StudyLogDetail(
StudyLogInfo.from(studyLog),
studyLogDailyMissions.stream().map(StudyLogDailyMissionInfo::from).toList());
safeStudyLogDailyMissions.stream().map(StudyLogDailyMissionInfo::from).toList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.ject.studytrip.studylog.domain.policy.StudyLogPolicy;
import com.ject.studytrip.studylog.domain.repository.StudyLogQueryRepository;
import com.ject.studytrip.studylog.domain.repository.StudyLogRepository;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Slice;
Expand Down Expand Up @@ -37,4 +38,18 @@ public StudyLog getValidStudyLog(Long studyLogId) {

return studyLog;
}

public List<StudyLog> getValidStudyLogs(List<Long> studyLogIds) {
List<StudyLog> studyLogs = studyLogRepository.findAllByIdIn(studyLogIds);

StudyLogPolicy.validateExistAll(studyLogs, studyLogIds);
studyLogs.forEach(StudyLogPolicy::validateNotDeleted);

return studyLogs;
}

public Slice<StudyLog> getStudyLogsSliceByTripReportId(Long tripReportId, int page, int size) {
return studyLogQueryRepository.findSliceByTripReportIdOrderByCreatedAtDesc(
tripReportId, PageRequest.of(page, size));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.ject.studytrip.global.exception.CustomException;
import com.ject.studytrip.studylog.domain.error.StudyLogErrorCode;
import com.ject.studytrip.studylog.domain.model.StudyLog;
import java.util.List;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;

Expand All @@ -13,4 +14,11 @@ public static void validateNotDeleted(StudyLog studyLog) {
throw new CustomException(StudyLogErrorCode.STUDY_LOG_ALREADY_DELETED);
}
}

public static void validateExistAll(List<StudyLog> foundStudyLogs, List<Long> requestedIds) {
boolean isEquals = foundStudyLogs.size() == requestedIds.size();
if (!isEquals) {
throw new CustomException(StudyLogErrorCode.STUDY_LOG_NOT_FOUND);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,7 @@ public interface StudyLogQueryRepository {
long deleteAllByDeletedMemberOwner();

long deleteAllByDeletedDailyGoalOwner();

Slice<StudyLog> findSliceByTripReportIdOrderByCreatedAtDesc(
Long tripReportId, Pageable pageable);
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package com.ject.studytrip.studylog.domain.repository;

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

public interface StudyLogRepository {

StudyLog save(StudyLog studyLog);

Optional<StudyLog> findById(Long studyLogId);

List<StudyLog> findAllByIdIn(Collection<Long> studyLogIds);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package com.ject.studytrip.studylog.infra.jpa;

import com.ject.studytrip.studylog.domain.model.StudyLog;
import java.util.Collection;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;

public interface StudyLogJpaRepository extends JpaRepository<StudyLog, Long> {}
public interface StudyLogJpaRepository extends JpaRepository<StudyLog, Long> {
List<StudyLog> findAllByIdIn(Collection<Long> studyLogIds);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.ject.studytrip.studylog.domain.model.StudyLog;
import com.ject.studytrip.studylog.domain.repository.StudyLogRepository;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
Expand All @@ -20,4 +22,9 @@ public StudyLog save(StudyLog studyLog) {
public Optional<StudyLog> findById(Long studyLogId) {
return studyLogJpaRepository.findById(studyLogId);
}

@Override
public List<StudyLog> findAllByIdIn(Collection<Long> studyLogIds) {
return studyLogJpaRepository.findAllByIdIn(studyLogIds);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.ject.studytrip.studylog.domain.model.StudyLog;
import com.ject.studytrip.studylog.domain.repository.StudyLogQueryRepository;
import com.ject.studytrip.trip.domain.model.QDailyGoal;
import com.ject.studytrip.trip.domain.model.QTripReportStudyLog;
import com.querydsl.jpa.JPAExpressions;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
Expand All @@ -22,6 +23,7 @@ public class StudyLogQueryRepositoryAdapter implements StudyLogQueryRepository {
private final QStudyLog studyLog = QStudyLog.studyLog;
private final QDailyGoal dailyGoal = QDailyGoal.dailyGoal;
private final QMember member = QMember.member;
private final QTripReportStudyLog tripReportStudyLog = QTripReportStudyLog.tripReportStudyLog;

@Override
public long countActiveStudyLogsByMemberId(Long memberId) {
Expand Down Expand Up @@ -84,4 +86,26 @@ public long deleteAllByDeletedDailyGoalOwner() {
.where(dailyGoal.deletedAt.isNotNull())))
.execute();
}

@Override
public Slice<StudyLog> findSliceByTripReportIdOrderByCreatedAtDesc(
Long tripReportId, Pageable pageable) {
List<StudyLog> content =
queryFactory
.select(studyLog)
.from(tripReportStudyLog)
.join(tripReportStudyLog.studyLog, studyLog)
.where(
tripReportStudyLog.tripReport.id.eq(tripReportId),
studyLog.deletedAt.isNull())
.orderBy(studyLog.createdAt.desc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize() + 1)
.fetch();

boolean hasNext = content.size() > pageable.getPageSize();
List<StudyLog> result = hasNext ? content.subList(0, pageable.getPageSize()) : content;

return new SliceImpl<>(result, pageable, hasNext);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.ject.studytrip.trip.application.dto;

public record PresignedTripReportImageInfo(Long tripReportId, String tmpKey, String presignedUrl) {
public static PresignedTripReportImageInfo of(
Long tripReportId, String tmpKey, String presignedUrl) {
return new PresignedTripReportImageInfo(tripReportId, tmpKey, presignedUrl);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.ject.studytrip.trip.application.dto;

public record TripCount(long course, long explore) {
public static TripCount of(long course, long explore) {
return new TripCount(course, explore);
}
}

This file was deleted.

Loading