From abdae420a0a1156d572a0bf4dee0c7f4b2842d82 Mon Sep 17 00:00:00 2001
From: uhensler <urs.hensler@frentix.com>
Date: Fri, 3 Jul 2020 11:39:14 +0200
Subject: [PATCH] OO-4630: Respect full day events when filtering by end date

---
 .../ui/AppointmentsPeekViewController.java    | 15 ++-------------
 .../appointments/AppointmentsService.java     | 11 +++++++++++
 .../manager/AppointmentsServiceImpl.java      | 12 ++++++++++++
 .../ui/TopicsRunCoachController.java          |  2 +-
 .../appointments/ui/TopicsRunController.java  |  2 +-
 .../appointments/AppointmentsServiceTest.java | 19 +++++++++++++++++++
 6 files changed, 46 insertions(+), 15 deletions(-)

diff --git a/src/main/java/org/olat/course/nodes/appointments/ui/AppointmentsPeekViewController.java b/src/main/java/org/olat/course/nodes/appointments/ui/AppointmentsPeekViewController.java
index 25da0039b2f..899be996f1c 100644
--- a/src/main/java/org/olat/course/nodes/appointments/ui/AppointmentsPeekViewController.java
+++ b/src/main/java/org/olat/course/nodes/appointments/ui/AppointmentsPeekViewController.java
@@ -119,21 +119,10 @@ public class AppointmentsPeekViewController extends BasicController {
 		return null;
 	}
 
-	private Optional<Appointment> getNextAppointment(List<Appointment> loadedAppointments) {
-		List<Appointment> appointments = new ArrayList<>(loadedAppointments.size());
+	private Optional<Appointment> getNextAppointment(List<Appointment> appointments) {
 		Date now = new Date();
-		for (Appointment appointment: loadedAppointments) {
-			Date begin = appointment.getStart();
-			Date end = appointment.getEnd();
-			Date ajustedEnd = new Date(end.getTime());
-			if (DateUtils.isSameDate(begin, end) && DateUtils.isSameTime(begin, end)) {
-				ajustedEnd = DateUtils.setTime(ajustedEnd, 23, 59, 59);
-			}
-			if (now.before(ajustedEnd)) {
-				appointments.add(appointment);
-			}
-		}
 		Optional<Appointment> appointment = appointments.stream()
+				.filter(a -> appointmentsService.isEndAfter(a, now))
 				.sorted((a1, a2) -> a1.getStart().compareTo(a2.getStart()))
 				.limit(1)
 				.findFirst();
diff --git a/src/main/java/org/olat/modules/appointments/AppointmentsService.java b/src/main/java/org/olat/modules/appointments/AppointmentsService.java
index 43337edf995..3b7c7d3f966 100644
--- a/src/main/java/org/olat/modules/appointments/AppointmentsService.java
+++ b/src/main/java/org/olat/modules/appointments/AppointmentsService.java
@@ -20,6 +20,7 @@
 package org.olat.modules.appointments;
 
 import java.util.Collection;
+import java.util.Date;
 import java.util.List;
 import java.util.Map;
 
@@ -101,6 +102,16 @@ public interface AppointmentsService {
 
 	public void deleteAppointment(Appointment appointment);
 	
+	/**
+	 * Checks whether the end of the appointment is after the due date.
+	 * It respects full day events.
+	 *
+	 * @param appointment
+	 * @param dueDate
+	 * @return
+	 */
+	public boolean isEndAfter(Appointment appointment, Date dueDate);
+	
 	/**
 	 * Gets the key of the topic and the according count of appointments.
 	 *
diff --git a/src/main/java/org/olat/modules/appointments/manager/AppointmentsServiceImpl.java b/src/main/java/org/olat/modules/appointments/manager/AppointmentsServiceImpl.java
index 3489742990b..3e554d39e79 100644
--- a/src/main/java/org/olat/modules/appointments/manager/AppointmentsServiceImpl.java
+++ b/src/main/java/org/olat/modules/appointments/manager/AppointmentsServiceImpl.java
@@ -40,6 +40,7 @@ import org.olat.core.commons.services.notifications.NotificationsManager;
 import org.olat.core.commons.services.notifications.PublisherData;
 import org.olat.core.commons.services.notifications.SubscriptionContext;
 import org.olat.core.id.Identity;
+import org.olat.core.util.DateUtils;
 import org.olat.core.util.StringHelper;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
@@ -434,6 +435,17 @@ public class AppointmentsServiceImpl implements AppointmentsService {
 		appointmentDao.delete(appointment);
 	}
 	
+	@Override
+	public boolean isEndAfter(Appointment appointment, Date dueDate) {
+		Date begin = appointment.getStart();
+		Date end = appointment.getEnd();
+		Date ajustedEnd = new Date(end.getTime());
+		if (DateUtils.isSameDate(begin, end) && DateUtils.isSameTime(begin, end)) {
+			ajustedEnd = DateUtils.setTime(ajustedEnd, 23, 59, 59);
+		}
+		return ajustedEnd.after(dueDate);
+	}
+	
 	@Override
 	public Map<Long, Long> getTopicKeyToAppointmentCount(AppointmentSearchParams params, boolean freeOnly) {
 		return appointmentDao.loadTopicKeyToAppointmentCount(params, freeOnly);
diff --git a/src/main/java/org/olat/modules/appointments/ui/TopicsRunCoachController.java b/src/main/java/org/olat/modules/appointments/ui/TopicsRunCoachController.java
index 3758190dff1..719fa9c6a7a 100644
--- a/src/main/java/org/olat/modules/appointments/ui/TopicsRunCoachController.java
+++ b/src/main/java/org/olat/modules/appointments/ui/TopicsRunCoachController.java
@@ -221,7 +221,7 @@ public class TopicsRunCoachController extends BasicController {
 		} else {
 			nextAppointment = appointments.stream()
 					.filter(a -> Appointment.Status.confirmed == a.getStatus())
-					.filter(a1 -> now.before(a1.getEnd()))
+					.filter(a -> appointmentsService.isEndAfter(a, now))
 					.sorted((a1, a2) -> a1.getStart().compareTo(a2.getStart()))
 					.findFirst();
 		}
diff --git a/src/main/java/org/olat/modules/appointments/ui/TopicsRunController.java b/src/main/java/org/olat/modules/appointments/ui/TopicsRunController.java
index 9b48ca61356..4357e20c682 100644
--- a/src/main/java/org/olat/modules/appointments/ui/TopicsRunController.java
+++ b/src/main/java/org/olat/modules/appointments/ui/TopicsRunController.java
@@ -236,7 +236,7 @@ public class TopicsRunController extends BasicController implements Activateable
 			Date now = new Date();
 			Optional<Appointment> nextAppointment = myTopicParticipations.stream()
 					.map(Participation::getAppointment)
-					.filter(a1 -> now.before(a1.getEnd()))
+					.filter(a -> appointmentsService.isEndAfter(a, now))
 					.sorted((a1, a2) -> a1.getStart().compareTo(a2.getStart()))
 					.findFirst();
 			Appointment appointment = nextAppointment.isPresent()
diff --git a/src/test/java/org/olat/modules/appointments/AppointmentsServiceTest.java b/src/test/java/org/olat/modules/appointments/AppointmentsServiceTest.java
index 992c455d951..2a840936e8e 100644
--- a/src/test/java/org/olat/modules/appointments/AppointmentsServiceTest.java
+++ b/src/test/java/org/olat/modules/appointments/AppointmentsServiceTest.java
@@ -76,6 +76,25 @@ public class AppointmentsServiceTest extends OlatTestCase {
 						organizerDelete);
 	}
 	
+	@Test
+	public void shouldCheckEndAfterDueDate() {
+		Appointment appointment = sut.createUnsavedAppointment(null);
+		appointment.setStart(new GregorianCalendar(2020, 2, 3, 10, 0, 0).getTime());
+		appointment.setEnd(new GregorianCalendar(2020, 2, 3, 11, 0, 0).getTime());
+		assertThat(sut.isEndAfter(appointment, new GregorianCalendar(2020, 2, 3, 12, 0, 0).getTime())).isFalse();
+		
+		appointment = sut.createUnsavedAppointment(null);
+		appointment.setStart(new GregorianCalendar(2020, 2, 3, 10, 0, 0).getTime());
+		appointment.setEnd(new GregorianCalendar(2020, 2, 3, 14, 0, 0).getTime());
+		assertThat(sut.isEndAfter(appointment, new GregorianCalendar(2020, 2, 3, 12, 0, 0).getTime())).isTrue();
+		
+		// full day
+		appointment = sut.createUnsavedAppointment(null);
+		appointment.setStart(new GregorianCalendar(2020, 2, 3, 10, 0, 0).getTime());
+		appointment.setEnd(new GregorianCalendar(2020, 2, 3, 10, 0, 0).getTime());
+		assertThat(sut.isEndAfter(appointment, new GregorianCalendar(2020, 2, 3, 12, 0, 0).getTime())).isTrue();
+	}
+	
 	@Test
 	public void createParticipationShouldCreateParticiption() {
 		Identity participant1 = JunitTestHelper.createAndPersistIdentityAsRndUser("ap");
-- 
GitLab