Skip to content

Commit

Permalink
Merge pull request #265 from effectivemade/backendApp/feature/calenda…
Browse files Browse the repository at this point in the history
…rDeleting

EO-456 Filtering out events declined by organiser
  • Loading branch information
zavyalov-daniil authored May 17, 2024
2 parents 0bd2478 + 0c6ca02 commit 773dc3a
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ class GoogleCalendarConverter(
}

/**
* Converts meeting [Event] to [Booking]
* Converts meeting [Event] to [Booking].
* If participant responseStatus is declined that participant will be filtered out.
*
* @param event [Event] to be converted
* @param owner specify this parameter to reduce the number
Expand All @@ -153,23 +154,25 @@ class GoogleCalendarConverter(
): Booking {
logger.debug("[toMeetingWorkspaceBooking] converting calendar event to meeting room booking model")
val organizer: String = event.organizer?.email ?: ""
val email = if (organizer != defaultAccount) {
val organizerEmail = if (organizer != defaultAccount) {
logger.trace("[toMeetingWorkspaceBooking] organizer email derived from event.organizer field")
organizer
} else {
logger.trace("[toMeetingWorkspaceBooking] organizer email derived from event description")
event.description?.substringBefore(" ") ?: ""
}
val recurrence = event.recurrence?.toString()?.getRecurrence()
val participantModels = participants ?: getParticipantsModels(event)

val booking = Booking(
owner = owner ?: getUserModel(email),
participants = participants ?: getParticipantsModels(event),
owner = owner ?: getUserModel(organizerEmail),
participants = participantModels,
workspace = workspace ?: getWorkspaceModel(getCalendarId(event)),
id = event.id ?: null,
beginBooking = toLocalInstant(event.start),
endBooking = toLocalInstant(event.end),
recurrence = recurrence?.let { RecurrenceConverter.recurrenceToModel(it) }
recurrence = recurrence?.let { RecurrenceConverter.recurrenceToModel(it) },
isDeclinedByOwner = participantModels.none { model -> model.email == organizerEmail }
)
logger.trace("[toMeetingWorkspaceBooking] {}", booking.toString())
return booking
Expand Down Expand Up @@ -208,7 +211,7 @@ class GoogleCalendarConverter(
*/
private fun getParticipantsModels(event: Event): List<UserModel> {
val attendees = event.attendees
.filter { attendee -> !attendee.isResource }
.filter { attendee -> !attendee.isResource && attendee.responseStatus != "declined" }
.map { attendee -> attendee.email }
return userRepository.findAllByEmails(attendees)
}
Expand All @@ -221,7 +224,8 @@ class GoogleCalendarConverter(
* @return Calendar ID of the workspace or default value.
*/
private fun getCalendarId(event: Event): String? {
return event.attendees?.firstOrNull { it?.resource ?: false }
return event.attendees
?.firstOrNull { it?.resource == true }
?.email
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
package office.effective.features.booking.repository

import com.google.api.client.googleapis.json.GoogleJsonResponseException
import com.google.api.client.util.DateTime
import com.google.api.services.calendar.Calendar
import com.google.api.services.calendar.model.Event
import kotlinx.coroutines.delay
import office.effective.common.constants.BookingConstants
import office.effective.common.exception.InstanceNotFoundException
import office.effective.common.exception.MissingIdException
import office.effective.common.exception.WorkspaceUnavailableException
import office.effective.features.calendar.repository.CalendarIdsRepository
import office.effective.features.booking.converters.GoogleCalendarConverter
import office.effective.features.booking.converters.toGoogleDateTime
import office.effective.features.calendar.repository.CalendarIdsRepository
import office.effective.features.user.repository.UserEntity
import office.effective.features.user.repository.UserRepository
import office.effective.model.Booking
import office.effective.features.user.repository.UserEntity
import org.slf4j.LoggerFactory
import java.time.Instant
import java.util.*
Expand Down Expand Up @@ -85,8 +85,32 @@ class BookingMeetingRepository(
*/
override fun findById(bookingId: String): Booking? {
logger.debug("[findById] retrieving a booking with id={}", bookingId)
val event: Event? = findByCalendarIdAndBookingId(bookingId)
return event?.let { googleCalendarConverter.toMeetingWorkspaceBooking(it) }
val calendars: List<String> = calendarIdsRepository.findAllCalendarsId()

val futures = calendars.map { calendarId ->
findEventAsync(bookingId, calendarId)
}

val event: Event? = CompletableFuture.allOf(*futures.toTypedArray())
.thenApply {
futures.map { it.get() }
}
.join()
.find { it != null }

if (event != null) {
val booking = googleCalendarConverter.toMeetingWorkspaceBooking(event)
if (!booking.isDeclinedByOwner) {
return booking
}
}
return null
}

private fun findEventAsync(eventId: String, calendarId: String): CompletableFuture<Event> {
return CompletableFuture.supplyAsync {
findByCalendarIdAndBookingId(eventId, calendarId)
}
}

/**
Expand Down Expand Up @@ -161,7 +185,7 @@ class BookingMeetingRepository(
val eventsWithWorkspace = basicQuery(eventRangeFrom, eventRangeTo, returnInstances, workspaceCalendarId)
.execute().items

return eventsWithWorkspace.toList().map { googleCalendarConverter.toMeetingWorkspaceBooking(it) }
return filterAndConvertToBookings(eventsWithWorkspace)
}

/**
Expand Down Expand Up @@ -280,15 +304,8 @@ class BookingMeetingRepository(

val eventsWithUser = getEventsWithQParam(calendars, userEmail, returnInstances, eventRangeFrom, eventRangeTo)

val result = mutableListOf<Booking>()
for (event in eventsWithUser) {
if (checkEventOrganizer(event, userEmail)) {
result.add(googleCalendarConverter.toMeetingWorkspaceBooking(event))
} else {
logger.trace("[findAllByOwnerId] filtered out event: {}", event)
}
}
return result
val additionalFilter: (Event) -> Boolean = { event -> checkEventOrganizer(event, userEmail) }
return filterAndConvertToBookings(eventsWithUser, additionalFilter)
}

/**
Expand Down Expand Up @@ -323,16 +340,8 @@ class BookingMeetingRepository(
.setQ(userEmail)
.execute().items

val result = mutableListOf<Booking>()
for (event in eventsWithUserAndWorkspace) {
if (checkEventOrganizer(event, userEmail)) {
result.add(googleCalendarConverter.toMeetingWorkspaceBooking(event))
} else {
logger.trace("[findAllByOwnerAndWorkspaceId] filtered out event: {}", event)
}
}

return result
val additionalFilter: (Event) -> Boolean = { event -> checkEventOrganizer(event, userEmail) }
return filterAndConvertToBookings(eventsWithUserAndWorkspace, additionalFilter)
}

/**
Expand All @@ -352,7 +361,35 @@ class BookingMeetingRepository(
)
val calendars: List<String> = calendarIdsRepository.findAllCalendarsId()
val events: List<Event> = getAllEvents(calendars, returnInstances, eventRangeFrom, eventRangeTo)
return events.map { googleCalendarConverter.toMeetingWorkspaceBooking(it) }

val result: MutableList<Booking> = mutableListOf()
for (event in events) {
val booking = googleCalendarConverter.toMeetingWorkspaceBooking(event)
if (!booking.isDeclinedByOwner) {
result.add(booking)
}
}
return filterAndConvertToBookings(events)
}

private fun filterAndConvertToBookings(
events: List<Event>,
additionalFilter: (Event) -> Boolean = { true }
): List<Booking> {
val result = mutableListOf<Booking>()
for (event in events) {
if (additionalFilter(event)) {
val booking = googleCalendarConverter.toMeetingWorkspaceBooking(event)
if (!booking.isDeclinedByOwner) {
result.add(googleCalendarConverter.toMeetingWorkspaceBooking(event))
} else {
logger.trace("[filterAndConvertToBookings] filtered out event deleted by owner: {}", event)
}
} else {
logger.trace("[filterAndConvertToBookings] filtered out event with wrong organizer: {}", event)
}
}
return result
}

/**
Expand Down Expand Up @@ -502,7 +539,9 @@ class BookingMeetingRepository(
.execute().items

for (event in sameTimeEvents) {
if (areEventsOverlap(eventToVerify, event) && eventsIsNotSame(eventToVerify, event)) {
if (areEventsOverlap(eventToVerify, event) &&
eventsIsNotSame(eventToVerify, event) &&
eventIsNotDeletedByOwner(event)) {
return true
}
}
Expand Down Expand Up @@ -557,4 +596,23 @@ class BookingMeetingRepository(
}
return firstEvent.id != secondEvent.id && eventsDoNotBelongToSameRecurringEvent
}

private fun eventIsNotDeletedByOwner(event: Event): Boolean {
val organiserEmail = findOrganiser(event)
for (attendee in event.attendees) {
if (attendee.email == organiserEmail && attendee.responseStatus == "declined") {
return false
}
}
return true
}

private fun findOrganiser(event: Event): String {
val organizer: String = event.organizer?.email ?: ""
return if (organizer != BookingConstants.DEFAULT_CALENDAR) {
organizer
} else {
event.description?.substringBefore(" ") ?: ""
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ data class Booking (
var beginBooking: Instant,
var endBooking: Instant,
var recurrence: RecurrenceModel?,
val recurringBookingId: String? = null
val recurringBookingId: String? = null,
val isDeclinedByOwner: Boolean = false
)

0 comments on commit 773dc3a

Please sign in to comment.