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

[feat] 마이핑글 참여 완료/예정 번개 리스트 api 생성 #86

Merged
merged 5 commits into from
Jan 17, 2024
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
@@ -1,27 +1,40 @@
package org.pingle.pingleserver.controller;

import jakarta.annotation.Nullable;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.pingle.pingleserver.annotation.GUserId;
import org.pingle.pingleserver.annotation.UserId;
import org.pingle.pingleserver.constant.Constants;
import org.pingle.pingleserver.dto.common.ApiResponse;
import org.pingle.pingleserver.dto.response.MyPingleResponse;
import org.pingle.pingleserver.dto.response.UserInfoResponse;
import org.pingle.pingleserver.dto.type.SuccessMessage;
import org.pingle.pingleserver.service.MeetingService;
import org.pingle.pingleserver.service.UserService;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/v1/users")
@RequiredArgsConstructor
public class UserController {

private final MeetingService meetingService;
private final UserService userService;

@GetMapping("/me")
public ApiResponse<UserInfoResponse> getLoginUserInfo(@UserId Long userId){
return ApiResponse.success(SuccessMessage.OK, userService.getUserInfo(userId));
}

@GetMapping("/me/meetings")
public ApiResponse<List<MyPingleResponse>> getMyPingles (@GUserId Long userId, @NotNull @RequestParam boolean participation,
@RequestHeader(Constants.TEAM_ID)Long teamId) {
return ApiResponse.success(SuccessMessage.OK, meetingService.getMyPingles(userId, teamId, participation));
}

@DeleteMapping("/leave")
public ApiResponse<Void> leave(@UserId Long userId, @Nullable @RequestHeader(Constants.APPLE_LOGOUT_HEADER) String code){
userService.leave(userId, code);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package org.pingle.pingleserver.dto.response;

import lombok.AccessLevel;
import lombok.Builder;
import org.pingle.pingleserver.domain.Meeting;
import org.pingle.pingleserver.domain.enums.MCategory;
import org.pingle.pingleserver.utils.TimeUtil;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

@Builder(access = AccessLevel.PRIVATE)
public record MyPingleResponse(Long id, MCategory category, String name, String ownerName, String location,
String dDay, String date, String startAt, String endAt, int maxParticipants,
int curParticipants, boolean isOwner) {

private static final String DDAYPREFIX = "D";
private static final String DDAY = "D-Day";
private static final String DONE = "Done";

public static MyPingleResponse of(Meeting meeting, String ownerName, boolean isOwner) {
return MyPingleResponse.builder()
.id(meeting.getId())
.category(meeting.getCategory())
.name(meeting.getName())
.ownerName(ownerName)
.location(meeting.getPin().getName())
.dDay(createDDay(meeting.getStartAt(), meeting.getEndAt()))
.date(TimeUtil.getDateFromDateTime(meeting.getStartAt()))
.startAt(TimeUtil.getTimeFromDateTime(meeting.getStartAt()))
.endAt(TimeUtil.getTimeFromDateTime(meeting.getEndAt()))
.maxParticipants(meeting.getMaxParticipants())
.curParticipants(meeting.getUserMeetingList().size())
.isOwner(isOwner)
.build();
}

private static String createDDay(LocalDateTime startAt, LocalDateTime endAt) {
LocalDate startDate = startAt.toLocalDate();
if(LocalDateTime.now().isAfter(endAt)) //현재가 이후면 참
return DONE;
if(ChronoUnit.DAYS.between(startDate, LocalDate.now()) == 0)
return DDAY;
return DDAYPREFIX + ChronoUnit.DAYS.between(startDate, LocalDate.now());//12일 13일 -> 1
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,33 @@
import org.pingle.pingleserver.domain.enums.MCategory;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import org.springframework.data.repository.query.Param;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

public interface MeetingRepository extends JpaRepository<Meeting, Long> {

@Query("SELECT DISTINCT m FROM Meeting m " +
"JOIN FETCH m.pin p " +
"JOIN FETCH p.team t " +
"JOIN UserMeeting um ON um.meeting = m " +
"WHERE um.user.id = :userId " +
" AND (:teamId IS NULL OR t.id = :teamId) " +
" AND m.startAt > :currentDateTime " +
"ORDER BY m.startAt ASC")
List<Meeting> findUnparticipatedMeetingsForUsersInTeamOrderByTime(Long userId, Long teamId, @Param("currentDateTime")LocalDateTime currentDateTime);

@Query("SELECT DISTINCT m FROM Meeting m " +
"JOIN FETCH m.pin p " +
"JOIN FETCH p.team t " +
"JOIN UserMeeting um ON um.meeting = m " +
"WHERE um.user.id = :userId " +
" AND (:teamId IS NULL OR t.id = :teamId) " +
" AND m.startAt <= :currentDateTime " +
"ORDER BY m.startAt DESC")
List<Meeting> findParticipatedMeetingsForUsersInTeamOrderByTime(Long userId, Long teamId, @Param("currentDateTime")LocalDateTime currentDateTime);

@Query("SELECT COUNT(m) FROM Meeting m WHERE m.pin.id = :pinId AND m.startAt > CURRENT_TIMESTAMP")
int countMeetingsForPinWithoutCategory(Long pinId);

Expand Down
25 changes: 25 additions & 0 deletions src/main/java/org/pingle/pingleserver/service/MeetingService.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import org.pingle.pingleserver.domain.Meeting;
import org.pingle.pingleserver.domain.Pin;
import org.pingle.pingleserver.domain.UserMeeting;
import org.pingle.pingleserver.domain.enums.MRole;
import org.pingle.pingleserver.dto.request.MeetingRequest;
import org.pingle.pingleserver.dto.response.MyPingleResponse;
import org.pingle.pingleserver.dto.response.ParticipantsResponse;
import org.pingle.pingleserver.dto.type.ErrorMessage;
import org.pingle.pingleserver.exception.CustomException;
Expand All @@ -13,6 +15,8 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Service
Expand Down Expand Up @@ -44,6 +48,26 @@ public ParticipantsResponse getParticipants(Long meetingId) {
return ParticipantsResponse.of(userMeetings);
}

public List<MyPingleResponse> getMyPingles(Long userId, Long teamId, boolean participation) {
List<Meeting> myMeetings = new ArrayList<>();
if(participation) // 참여 완려 -> 이미 시작 startAt이 현재보다
myMeetings = meetingRepository.findParticipatedMeetingsForUsersInTeamOrderByTime(userId, teamId, LocalDateTime.now());
if(!participation) // 참여하지 않은 것 == 나중에 일어날 것 -> startat이 현재보다 늦음
myMeetings = meetingRepository.findUnparticipatedMeetingsForUsersInTeamOrderByTime(userId, teamId, LocalDateTime.now());
return myMeetings.stream()
.map(meeting -> MyPingleResponse.of(meeting, getOwnerName(meeting), isOwner(userId, meeting.getId()))).toList();
}

private String getOwnerName(Meeting meeting) {
UserMeeting userMeeting = userMeetingRepository.findByMeetingAndMeetingRole(meeting, MRole.OWNER)
.orElseThrow(() ->new CustomException(ErrorMessage.RESOURCE_NOT_FOUND));
return userMeeting.getUser().getName();
}

private boolean isOwner(Long userId, Long meetingId) {
return userMeetingRepository.existsByUserIdAndMeetingIdAndMeetingRole(userId, meetingId, MRole.OWNER);
}

@Transactional
public void deleteMeeting(Long userId, Long meetingId) {
Meeting meeting = meetingRepository.findById(meetingId).orElseThrow(() -> new CustomException(ErrorMessage.RESOURCE_NOT_FOUND));
Expand All @@ -53,3 +77,4 @@ public void deleteMeeting(Long userId, Long meetingId) {
meetingRepository.delete(meeting);
}
}

38 changes: 12 additions & 26 deletions src/main/java/org/pingle/pingleserver/service/PinService.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@
import org.pingle.pingleserver.repository.PinRepository;
import org.pingle.pingleserver.repository.TeamRepository;
import org.pingle.pingleserver.repository.UserMeetingRepository;
import org.pingle.pingleserver.utils.TimeUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
Expand All @@ -50,20 +49,20 @@ public List<PinResponse> getPinsFilterByCategory(Long teamId, MCategory category
public List<MeetingResponse> getMeetingsDetail(Long userId, Long pinId, MCategory category) {
Pin pin = pinRepository.findById(pinId).orElseThrow(() -> new CustomException(ErrorMessage.RESOURCE_NOT_FOUND));
Comparator<Meeting> comparator = Comparator.comparing(Meeting::getStartAt);
List<Meeting> meetingList = pin.getMeetings();
meetingList.sort(comparator);//핀의 모든 미팅을 시간순으로 정렬
List<Meeting> meetingList = pin.getMeetingList();
meetingList.sort(comparator);
List<MeetingResponse> responseList = new ArrayList<>();
if(category == null) {
for (Meeting meeting : meetingList) {
responseList.add(MeetingResponse.builder()
.id(meeting.getId())
.category(meeting.getCategory())
.name(meeting.getName())
.ownerName(getOwnerName(meeting))//만든사람
.ownerName(getOwnerName(meeting))
.location(pin.getName())
.date(getDateFromDateTime(meeting.getStartAt()))//meeting start 날짜 parsing
.startAt(getTimeFromDateTime(meeting.getStartAt()))//start 시간 parsing
.endAt(getTimeFromDateTime(meeting.getEndAt()))//end 시간 parsing
.date(TimeUtil.getDateFromDateTime(meeting.getStartAt()))
.startAt(TimeUtil.getTimeFromDateTime(meeting.getStartAt()))
.endAt(TimeUtil.getTimeFromDateTime(meeting.getEndAt()))
.maxParticipants(meeting.getMaxParticipants())
.curParticipants(getCurParticipants(meeting))
.isParticipating(isParticipating(userId, meeting))
Expand All @@ -73,18 +72,18 @@ public List<MeetingResponse> getMeetingsDetail(Long userId, Long pinId, MCategor
}
return responseList;
}
// 및 카테고리에 포함한 것만

for (Meeting meeting : meetingList) {
if(meeting.getCategory().getValue().equals(category.getValue())) {
responseList.add(MeetingResponse.builder()
.id(meeting.getId())
.category(meeting.getCategory())
.name(meeting.getName())
.ownerName(getOwnerName(meeting))//만든사람
.ownerName(getOwnerName(meeting))
.location(pin.getName())
.date(getDateFromDateTime(meeting.getStartAt()))//meeting start 날짜 parsing
.startAt(getTimeFromDateTime(meeting.getStartAt()))//start 시간 parsing
.endAt(getTimeFromDateTime(meeting.getEndAt()))//end 시간 parsing
.date(TimeUtil.getDateFromDateTime(meeting.getStartAt()))
.startAt(TimeUtil.getTimeFromDateTime(meeting.getStartAt()))
.endAt(TimeUtil.getTimeFromDateTime(meeting.getEndAt()))
.maxParticipants(meeting.getMaxParticipants())
.curParticipants(getCurParticipants(meeting))
.isParticipating(isParticipating(userId, meeting))
Expand All @@ -94,7 +93,6 @@ public List<MeetingResponse> getMeetingsDetail(Long userId, Long pinId, MCategor
}
}
return responseList;

}

@Transactional
Expand Down Expand Up @@ -124,7 +122,6 @@ public List<PinResponse> getPins(Long teamId, MCategory category) {
meetingRepository.countMeetingsForPinWithoutCategory(pin.getId()));
}).toList();
}

pins = pinRepository.findPinsWithCategoryAndTimeBefore(teamId, category);
return pins.stream()
.map(pin -> PinResponse.of(pin, category, meetingRepository.countMeetingsForPinWithCategory(pin.getId(), category))).toList();
Expand All @@ -141,8 +138,6 @@ public List<MeetingResponse> getMeetings(Long pinId, Long userId, MCategory cate
return meetings.stream()
.map(meeting -> MeetingResponse.of(meeting, getOwnerName(meeting), getCurParticipants(meeting),
isParticipating(userId, meeting), isOwner(userId, meeting.getId()))).toList();


}

private boolean checkMeetingsCategoryOfPin(Pin pin, MCategory category) {
Expand All @@ -168,15 +163,6 @@ private boolean isParticipating(Long userId, Meeting meeting) {
return userMeetingRepository.existsByUserIdAndMeeting(userId, meeting);
}

private String getDateFromDateTime(LocalDateTime localDateTime) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
return localDateTime.format(formatter);
}
private String getTimeFromDateTime(LocalDateTime localDateTime) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
return localDateTime.format(formatter);
}

private boolean isOwner(Long userId, Long meetingId) {
return userMeetingRepository.existsByUserIdAndMeetingIdAndMeetingRole(userId, meetingId, MRole.OWNER);
}
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/org/pingle/pingleserver/utils/TimeUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.pingle.pingleserver.utils;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class TimeUtil {
public static String getDateFromDateTime(LocalDateTime localDateTime) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
return localDateTime.format(formatter);
}

public static String getTimeFromDateTime(LocalDateTime localDateTime) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
return localDateTime.format(formatter);
}
}
Loading