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 @@ -114,9 +114,9 @@ public CommonResponse<CrewMonthlyCanlendarResponse> getMonthlyEvent(

@GetMapping("/events/upcoming")
@Operation(summary = "upcoming 일정 조회", description = "크루의 upcoming 일정 조회하는 API 입니다.")
public CommonResponse<CrewUpcomingEventResponse> getUpcomingEvent(@MemberCrew Crew crew) {
public CommonResponse<EventResponseDto> getUpcomingEvent(@MemberCrew Crew crew) {

CrewUpcomingEventResponse response = crewEventService.getCrewUpcomingEvent(crew);
EventResponseDto response = crewEventService.getCrewUpcomingEvent(crew);
return new CommonResponse<>("크루 다가오는 일정 조회 성공", response);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import java.util.List;

public record CrewUpcomingEventResponse(
public record EventResponseDto(
List<EventProfileResponse> eventProfiles
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import org.springframework.transaction.annotation.Transactional;
import run.backend.domain.crew.dto.common.DayStatusDto;
import run.backend.domain.crew.dto.response.CrewMonthlyCanlendarResponse;
import run.backend.domain.crew.dto.response.CrewUpcomingEventResponse;
import run.backend.domain.crew.dto.response.EventResponseDto;
import run.backend.domain.crew.dto.response.CrewWeeklyEventResponse;
import run.backend.domain.crew.dto.response.EventProfileResponse;
import run.backend.domain.crew.entity.Crew;
Expand Down Expand Up @@ -52,13 +52,13 @@ public CrewMonthlyCanlendarResponse getCrewMonthlyCalendar(Crew crew, int year,
return new CrewMonthlyCanlendarResponse(statusMap);
}

public CrewUpcomingEventResponse getCrewUpcomingEvent(Crew crew) {
public EventResponseDto getCrewUpcomingEvent(Crew crew) {

LocalDate today = LocalDate.now();

List<Event> events = eventRepository.findAllByCrewAndDateAfter(crew, today);
List<EventProfileResponse> eventProfiles = eventMapper.toEventProfileList(events);

return new CrewUpcomingEventResponse(eventProfiles);
return new EventResponseDto(eventProfiles);
}
}
20 changes: 13 additions & 7 deletions src/main/java/run/backend/domain/event/entity/JoinEvent.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
package run.backend.domain.event.entity;

import jakarta.persistence.*;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;
import run.backend.domain.member.entity.Member;
import run.backend.global.common.BaseEntity;

import java.time.LocalDateTime;

@Entity
@Getter
@Table(name = "join_events")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@SQLDelete(sql = "UPDATE join_events SET deleted_at = NOW() WHERE id = ?")
@Where(clause = "deleted_at IS NULL")
public class JoinEvent extends BaseEntity {

@Id
Expand All @@ -40,8 +50,4 @@ public JoinEvent(
this.member = member;
this.event = event;
}

public void softDelete() {
this.setDeletedAt(LocalDateTime.now());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;
import run.backend.domain.crew.entity.Crew;
import run.backend.domain.event.enums.RepeatCycle;
import run.backend.domain.event.enums.WeekDay;
Expand All @@ -18,6 +20,8 @@
@Getter
@Table(name = "periodic_events")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@SQLDelete(sql = "UPDATE periodic_events SET deleted_at = NOW() WHERE id = ?")
@Where(clause = "deleted_at IS NULL")
public class PeriodicEvent extends BaseEntity {

@Id
Expand Down Expand Up @@ -111,8 +115,4 @@ public void updatePeriodicEvent(
this.member = runningCaptain;
}
}

public void softDelete() {
this.setDeletedAt(java.time.LocalDateTime.now());
}
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,44 @@
package run.backend.domain.event.repository;

import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import run.backend.domain.crew.dto.response.EventProfileResponse;
import run.backend.domain.event.entity.Event;
import run.backend.domain.event.entity.JoinEvent;
import run.backend.domain.member.entity.Member;

import java.util.Optional;

public interface JoinEventRepository extends JpaRepository<JoinEvent, Long> {

void deleteByEventAndMember(Event event, Member member);

@Query("SELECT j FROM JoinEvent j WHERE j.event = :event AND j.member = :member AND j.deletedAt IS NULL")
@Query("SELECT j FROM JoinEvent j WHERE j.event = :event AND j.member = :member")
Optional<JoinEvent> findByEventAndMember(@Param("event") Event event, @Param("member") Member member);

@Query("SELECT j FROM JoinEvent j WHERE j.event = :event AND j.deletedAt IS NULL")
List<JoinEvent> findByEventAndNotDeleted(@Param("event") Event event);
@Query("SELECT j FROM JoinEvent j WHERE j.event = :event")
List<JoinEvent> findByEvent(@Param("event") Event event);

@Query("SELECT j FROM JoinEvent j WHERE j.event = :event AND j.isRunning = true AND j.deletedAt IS NULL")
@Query("SELECT j FROM JoinEvent j WHERE j.event = :event AND j.event.status = 'COMPLETED'")
List<JoinEvent> findActualParticipantsByEvent(@Param("event") Event event);

boolean existsByEventAndMemberAndDeletedAtIsNull(Event event, Member member);
@Query("SELECT j FROM JoinEvent j WHERE j.member = :member " +
"AND j.event.date >= :startDate AND j.event.date <= :endDate " +
"AND j.event.status = 'COMPLETED'")
List<JoinEvent> findMonthlyParticipatedEvents(@Param("member") Member member,
@Param("startDate") LocalDate startDate,
@Param("endDate") LocalDate endDate);

@Query("""
SELECT new run.backend.domain.crew.dto.response.EventProfileResponse(\
e.id, e.title, e.date, e.startTime, e.endTime, e.expectedParticipants) \
FROM JoinEvent j JOIN j.event e \
WHERE j.member = :member \
AND e.date >= :startDate AND e.date <= :endDate \
AND e.status = 'COMPLETED' ORDER BY e.date DESC""")
List<EventProfileResponse> findMonthlyCompletedEvents(@Param("member") Member member,
@Param("startDate") LocalDate startDate,
@Param("endDate") LocalDate endDate);

boolean existsByEventAndMember(Event event, Member member);
}
11 changes: 5 additions & 6 deletions src/main/java/run/backend/domain/event/service/EventService.java
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ private Member validateNewRunningCaptain(EventInfoRequest request, Event event)

private void updateRunningCaptain(Event event, Member newRunningCaptain) {
joinEventRepository.findByEventAndMember(event, event.getMember())
.ifPresent(JoinEvent::softDelete);
.ifPresent(joinEventRepository::delete);

JoinEvent newJoinEvent = eventMapper.toJoinEvent(event, newRunningCaptain);
joinEventRepository.save(newJoinEvent);
Expand All @@ -132,7 +132,7 @@ private void handlePeriodicEventUpdate(Event event, EventInfoRequest request,
RepeatCycle requestedRepeatCycle = request.repeatCycle();

if (requestedRepeatCycle == null || requestedRepeatCycle == RepeatCycle.NONE) {
existingPeriodicEvent.ifPresent(PeriodicEvent::softDelete);
existingPeriodicEvent.ifPresent(periodicEventRepository::delete);
} else {
if (existingPeriodicEvent.isPresent()) {
PeriodicEvent periodicEvent = existingPeriodicEvent.get();
Expand Down Expand Up @@ -173,7 +173,7 @@ public EventDetailResponse getEventDetail(Long eventId) {
private List<JoinEvent> getParticipants(Event event, EventStatus status) {
return status == EventStatus.COMPLETED
? joinEventRepository.findActualParticipantsByEvent(event)
: joinEventRepository.findByEventAndNotDeleted(event);
: joinEventRepository.findByEvent(event);
}

@Transactional
Expand All @@ -182,7 +182,7 @@ public void joinEvent(Long eventId, Member member) {
Event event = eventRepository.findById(eventId)
.orElseThrow(EventNotFound::new);

if (joinEventRepository.existsByEventAndMemberAndDeletedAtIsNull(event, member)) {
if (joinEventRepository.existsByEventAndMember(event, member)) {
throw new AlreadyJoinedEvent();
}

Expand All @@ -201,8 +201,7 @@ public void cancelJoinEvent(Long eventId, Member member) {
JoinEvent joinEvent = joinEventRepository.findByEventAndMember(event, member)
.orElseThrow(JoinEventNotFound::new);

joinEvent.softDelete();
joinEventRepository.save(joinEvent);
joinEventRepository.delete(joinEvent);

event.decrementExpectedParticipants();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import run.backend.domain.crew.dto.response.EventResponseDto;
import run.backend.domain.member.dto.request.MemberInfoRequest;
import run.backend.domain.member.dto.response.MemberCrewStatusResponse;
import run.backend.domain.member.dto.response.MemberInfoResponse;
import run.backend.domain.member.dto.response.MemberParticipatedCountResponse;
import run.backend.domain.member.entity.Member;
import run.backend.domain.member.service.MemberService;
import run.backend.global.annotation.member.Login;
Expand Down Expand Up @@ -48,4 +55,20 @@ public CommonResponse<MemberCrewStatusResponse> getMembersCrewExists(@Login Memb
MemberCrewStatusResponse response = memberService.getMembersCrewExists(member);
return new CommonResponse<>("유저 크루 가입 여부 조회 완료", response);
}

@GetMapping("/participated/preview")
@Operation(summary = "유저의 이번 시즌 참여 횟수 조회", description = "유저가 이번 달에 참여한 러닝 횟수를 조회하는 API 입니다.")
public CommonResponse<MemberParticipatedCountResponse> getParticipatedCount(@Login Member member) {

MemberParticipatedCountResponse response = memberService.getParticipatedEventCount(member);
return new CommonResponse<>("유저의 이번 시즌 참여 횟수 조회 성공", response);
}

@GetMapping("/participated")
@Operation(summary = "유저의 이번 시즌 참여한 러닝 리스트 조회", description = "유저가 이번 시즌에 참여한 러닝 리스트를 조회하는 API 입니다.")
public CommonResponse<EventResponseDto> getParticipated(@Login Member member) {

EventResponseDto response = memberService.getParticipatedEvent(member);
return new CommonResponse<>("러닝에 대한 상세 참여 내역 조회 성공", response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package run.backend.domain.member.dto.response;

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

public record MemberParticipatedCountResponse(
@Schema(description = "유저의 이번 시즌 참여 횟수", example = "4")
Long participatedCount
) {
}
37 changes: 35 additions & 2 deletions src/main/java/run/backend/domain/member/service/MemberService.java
Original file line number Diff line number Diff line change
@@ -1,21 +1,29 @@
package run.backend.domain.member.service;

import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import run.backend.domain.crew.dto.response.EventResponseDto;
import run.backend.domain.crew.dto.response.EventProfileResponse;
import run.backend.domain.crew.entity.Crew;
import run.backend.domain.crew.entity.JoinCrew;
import run.backend.domain.crew.enums.JoinStatus;
import run.backend.domain.crew.repository.JoinCrewRepository;
import run.backend.domain.event.entity.JoinEvent;
import run.backend.domain.event.repository.JoinEventRepository;
import run.backend.domain.file.service.FileService;
import run.backend.domain.member.dto.request.MemberInfoRequest;
import run.backend.domain.member.dto.response.MemberCrewStatusResponse;
import run.backend.domain.member.dto.response.MemberInfoResponse;
import run.backend.domain.member.dto.response.MemberParticipatedCountResponse;
import run.backend.domain.member.entity.Member;
import run.backend.domain.member.repository.MemberRepository;

import java.util.Optional;
import run.backend.global.dto.DateRange;
import run.backend.global.util.DateRangeUtil;

@Service
@RequiredArgsConstructor
Expand All @@ -25,6 +33,8 @@ public class MemberService {
private final FileService fileService;
private final MemberRepository memberRepository;
private final JoinCrewRepository joinCrewRepository;
private final JoinEventRepository joinEventRepository;
private final DateRangeUtil dateRangeUtil;

public MemberInfoResponse getMemberInfo(Member member) {

Expand Down Expand Up @@ -59,4 +69,27 @@ public MemberCrewStatusResponse getMembersCrewExists(Member member) {
}
return new MemberCrewStatusResponse(joinCrew.get().getJoinStatus().toString());
}

public MemberParticipatedCountResponse getParticipatedEventCount(Member member) {

LocalDate today = LocalDate.now();
DateRange monthRange = dateRangeUtil.getMonthRange(today.getYear(), today.getMonthValue());

List<JoinEvent> monthlyJoinEvents = joinEventRepository.findMonthlyParticipatedEvents(
member, monthRange.start(), monthRange.end());

Long participatedCount = (long) monthlyJoinEvents.size();
return new MemberParticipatedCountResponse(participatedCount);
}

public EventResponseDto getParticipatedEvent(Member member) {

LocalDate today = LocalDate.now();
DateRange monthRange = dateRangeUtil.getMonthRange(today.getYear(), today.getMonthValue());

List<EventProfileResponse> eventProfiles = joinEventRepository.findMonthlyCompletedEvents(
member, monthRange.start(), monthRange.end());

return new EventResponseDto(eventProfiles);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import org.mockito.junit.jupiter.MockitoExtension;
import run.backend.domain.crew.dto.common.DayStatusDto;
import run.backend.domain.crew.dto.response.CrewMonthlyCanlendarResponse;
import run.backend.domain.crew.dto.response.CrewUpcomingEventResponse;
import run.backend.domain.crew.dto.response.EventResponseDto;
import run.backend.domain.crew.dto.response.CrewWeeklyEventResponse;
import run.backend.domain.crew.dto.response.EventProfileResponse;
import run.backend.domain.crew.entity.Crew;
Expand Down Expand Up @@ -128,7 +128,7 @@ void shouldReturnUpcomingEvent() {
when(eventMapper.toEventProfileList(events)).thenReturn(eventProfiles);

// when
CrewUpcomingEventResponse response = crewEventService.getCrewUpcomingEvent(crew);
EventResponseDto response = crewEventService.getCrewUpcomingEvent(crew);

// then
assertThat(response.eventProfiles()).isEqualTo(eventProfiles);
Expand Down
Loading