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 @@ -2,8 +2,12 @@

import endolphin.backend.domain.personal_event.dto.PersonalEventRequest;
import endolphin.backend.domain.personal_event.dto.PersonalEventResponse;
import endolphin.backend.domain.personal_event.dto.SyncResponse;
import endolphin.backend.domain.user.UserService;
import endolphin.backend.domain.user.entity.User;
import endolphin.backend.global.dto.ListResponse;
import endolphin.backend.global.error.ErrorResponse;
import endolphin.backend.global.util.DeferredResultManager;
import io.swagger.v3.oas.annotations.Operation;
import endolphin.backend.global.util.URIUtil;
import io.swagger.v3.oas.annotations.media.ArraySchema;
Expand All @@ -16,6 +20,7 @@
import jakarta.validation.constraints.NotNull;
import java.net.URI;
import java.time.LocalDate;

import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
Expand All @@ -27,6 +32,7 @@
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.context.request.async.DeferredResult;

@Tag(name = "Personal Event", description = "개인 일정 관리 API")
@RestController
Expand All @@ -35,6 +41,8 @@
public class PersonalEventController {

private final PersonalEventService personalEventService;
private final DeferredResultManager deferredResultManager;
private final UserService userService;

@Operation(summary = "개인 일정 조회", description = "사용자의 개인 일정을 주 단위로 조회합니다.")
@ApiResponses(value = {
Expand All @@ -53,8 +61,9 @@ public class PersonalEventController {
public ResponseEntity<ListResponse<PersonalEventResponse>> getPersonalEvents(
@Valid @NotNull @RequestParam LocalDate startDate,
@Valid @NotNull @RequestParam LocalDate endDate) {
ListResponse<PersonalEventResponse> response = personalEventService.listPersonalEvents(
startDate, endDate);
ListResponse<PersonalEventResponse> response =
personalEventService.listPersonalEvents(startDate, endDate);

return ResponseEntity.ok(response);
}

Expand Down Expand Up @@ -118,4 +127,19 @@ public ResponseEntity<Void> deletePersonalEvent(
personalEventService.deleteWithRequest(personalEventId, syncWithGoogleCalendar);
return ResponseEntity.noContent().build();
}

@Operation(summary = "개인 일정 동기화", description = "개인 일정을 실시간으로 동기화합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "일정 동기화 성공"),
@ApiResponse(responseCode = "401", description = "인증 실패",
content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(responseCode = "500", description = "서버 오류",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
@GetMapping("/sync")
public DeferredResult<ResponseEntity<SyncResponse>> poll() {
User user = userService.getCurrentUser();

return deferredResultManager.create(user);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,18 @@
import endolphin.backend.global.error.exception.ApiException;
import endolphin.backend.global.error.exception.ErrorCode;
import endolphin.backend.global.google.dto.GoogleEvent;
import endolphin.backend.global.google.enums.GoogleEventStatus;
import endolphin.backend.domain.personal_event.event.InsertPersonalEvent;
import endolphin.backend.global.util.IdGenerator;
import endolphin.backend.global.util.Validator;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
Expand All @@ -52,15 +51,15 @@ public class PersonalEventService {
private final CalendarService calendarService;

@Transactional(readOnly = true)
public ListResponse<PersonalEventResponse> listPersonalEvents(LocalDate startDate,
LocalDate endDate) {
public ListResponse<PersonalEventResponse> listPersonalEvents(
LocalDate startDate, LocalDate endDate) {
User user = userService.getCurrentUser();

Validator.validateDateTimeRange(startDate, endDate);

List<PersonalEventResponse> personalEventResponseList = personalEventRepository.findFilteredPersonalEvents(
user, startDate, endDate)
.stream().map(PersonalEventResponse::fromEntity).toList();
user, startDate, endDate).stream().map(PersonalEventResponse::fromEntity).toList();

return new ListResponse<>(personalEventResponseList);
}

Expand Down Expand Up @@ -220,24 +219,19 @@ public void preprocessPersonalEvents(User user, Discussion discussion) {
personalEventPreprocessor.preprocess(personalEvents, discussion, user);
}

public Set<LocalDate> syncWithGoogleEvents(List<GoogleEvent> googleEvents, User user,
public void syncWithGoogleEvents(List<GoogleEvent> googleEvents, User user,
String googleCalendarId) {
List<Discussion> discussions = discussionParticipantService.getDiscussionsByUserId(
user.getId());
Set<LocalDate> changedDates = new HashSet<>();
for (GoogleEvent googleEvent : googleEvents) {
log.info("Processing Google event: {}", googleEvent);
if (googleEvent.status().equals(GoogleEventStatus.CONFIRMED)) {
upsertPersonalEventByGoogleEvent(googleEvent, discussions, user, googleCalendarId,
changedDates);
changedDates.add(googleEvent.startDateTime().toLocalDate());
changedDates.add(googleEvent.endDateTime().toLocalDate());
} else if (googleEvent.status().equals(GoogleEventStatus.CANCELLED)) {
deletePersonalEventByGoogleEvent(googleEvent, discussions, user, googleCalendarId,
changedDates);
switch (googleEvent.status()) {
case CONFIRMED -> upsertPersonalEventByGoogleEvent(
googleEvent, discussions, user, googleCalendarId);
case CANCELLED -> deletePersonalEventByGoogleEvent(
googleEvent, discussions, user, googleCalendarId);
}
}
return changedDates;
}

private void validatePersonalEventUser(PersonalEvent personalEvent, User user) {
Expand All @@ -246,15 +240,13 @@ private void validatePersonalEventUser(PersonalEvent personalEvent, User user) {
}
}

private void upsertPersonalEventByGoogleEvent(GoogleEvent googleEvent,
List<Discussion> discussions, User user, String googleCalendarId,
Set<LocalDate> changedDates) {
private void upsertPersonalEventByGoogleEvent(
GoogleEvent googleEvent, List<Discussion> discussions, User user, String googleCalendarId) {
log.info("Upserting personal event by Google event: {}", googleEvent);
personalEventRepository.findByGoogleEventIdAndCalendarId(googleEvent.eventId(),
googleCalendarId)

personalEventRepository
.findByGoogleEventIdAndCalendarId(googleEvent.eventId(), googleCalendarId)
.ifPresentOrElse(personalEvent -> {
changedDates.add(personalEvent.getStartTime().toLocalDate());
changedDates.add(personalEvent.getEndTime().toLocalDate());
updatePersonalEvent(
PersonalEventRequest.of(googleEvent, personalEvent.getIsAdjustable()),
personalEvent, user, discussions);
Expand All @@ -272,14 +264,11 @@ private void upsertPersonalEventByGoogleEvent(GoogleEvent googleEvent,
}

private void deletePersonalEventByGoogleEvent(GoogleEvent googleEvent,
List<Discussion> discussions, User user, String googleCalendarId,
Set<LocalDate> changedDates) {
List<Discussion> discussions, User user, String googleCalendarId) {
log.info("Deleting personal event by Google event: {}", googleEvent);
personalEventRepository.findByGoogleEventIdAndCalendarId(googleEvent.eventId(),
googleCalendarId)
personalEventRepository
.findByGoogleEventIdAndCalendarId(googleEvent.eventId(), googleCalendarId)
.ifPresent(personalEvent -> {
changedDates.add(personalEvent.getStartTime().toLocalDate());
changedDates.add(personalEvent.getEndTime().toLocalDate());
deletePersonalEvent(personalEvent, user, discussions);
});
}
Expand Down Expand Up @@ -343,5 +332,4 @@ public void deletePersonalEventsByDiscussionId(Long discussionId) {
personalEventRepository.deleteAll(events);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package endolphin.backend.domain.personal_event.dto;

import endolphin.backend.global.google.dto.GoogleEvent;
import java.time.LocalDateTime;

public record SyncPersonalEvent(
String googleEventId,
String title,
LocalDateTime startDateTime,
LocalDateTime endDateTime,
String status
) {
public static SyncPersonalEvent from(GoogleEvent event) {
return new SyncPersonalEvent(event.eventId(), event.summary(), event.startDateTime(),
event.endDateTime(), event.status().getValue());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package endolphin.backend.domain.personal_event.dto;

import java.util.List;

public record SyncResponse(
List<SyncPersonalEvent> events,
String type
) {
public static SyncResponse timeout() {
return new SyncResponse(null, "timeout");
}

public static SyncResponse sync(List<SyncPersonalEvent> events) {
return new SyncResponse(events, "sync");
}

public static SyncResponse replaced() {
return new SyncResponse(null, "replaced");
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package endolphin.backend.domain.personal_event.event.handler;

import endolphin.backend.domain.personal_event.PersonalEventService;
import endolphin.backend.domain.personal_event.dto.SyncPersonalEvent;
import endolphin.backend.domain.personal_event.dto.SyncResponse;
import endolphin.backend.domain.user.entity.User;
import endolphin.backend.global.google.dto.GoogleEvent;
import endolphin.backend.global.google.event.GoogleEventChanged;
import endolphin.backend.global.sse.SseEmitters;
import java.time.LocalDate;
import endolphin.backend.global.util.DeferredResultManager;
import java.util.List;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
Expand All @@ -19,7 +19,7 @@
public class PersonalEventHandler {

private final PersonalEventService personalEventService;
private final SseEmitters sseEmitters;
private final DeferredResultManager deferredResultManager;

@EventListener(classes = {GoogleEventChanged.class})
public void sync(GoogleEventChanged event) {
Expand All @@ -29,10 +29,13 @@ public void sync(GoogleEventChanged event) {
User user = event.user();
log.info("Syncing personal events for user {}", user.getId());
String googleCalendarId = event.googleCalendarId();
Set<LocalDate> changedDates = personalEventService.syncWithGoogleEvents(events, user,
googleCalendarId);
personalEventService.syncWithGoogleEvents(events, user, googleCalendarId);

sseEmitters.sendToUser(user.getId(), changedDates);
if (deferredResultManager.hasActiveConnection(user)) {
List<SyncPersonalEvent> syncPersonalEvents =
events.stream().map(SyncPersonalEvent::from).toList();
deferredResultManager.setResult(user, SyncResponse.sync(syncPersonalEvents));
}
} catch (Exception e) {
log.error("Failed to sync personal events", e);
}
Expand Down

This file was deleted.

This file was deleted.

Loading
Loading