From 710f60be78d469b8e1f651933a564956d6cbb4aa Mon Sep 17 00:00:00 2001
From: Hangzhi Yu <hangzhi@protonmail.com>
Date: Sun, 2 Feb 2025 19:25:06 +0100
Subject: [PATCH 1/4] Fix constraint for all day events

---
 aleksis/core/models.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/aleksis/core/models.py b/aleksis/core/models.py
index c02ec1548..a080955bf 100644
--- a/aleksis/core/models.py
+++ b/aleksis/core/models.py
@@ -1713,7 +1713,7 @@ class CalendarEvent(CalendarEventMixin, ExtensiblePolymorphicModel, RecurrenceMo
                 check=Q(datetime_end__gt=F("datetime_start")), name="datetime_start_before_end"
             ),
             models.CheckConstraint(
-                check=Q(date_end__gt=F("date_start")), name="date_start_before_end"
+                check=Q(date_end__gte=F("date_start")), name="date_start_before_end"
             ),
             models.CheckConstraint(
                 check=~(Q(datetime_start__isnull=False, timezone="") & ~Q(recurrences="")),
-- 
GitLab


From 30942148e2cc9e392938867244dfceeddb584f1e Mon Sep 17 00:00:00 2001
From: Hangzhi Yu <hangzhi@protonmail.com>
Date: Sun, 2 Feb 2025 19:42:51 +0100
Subject: [PATCH 2/4] Fix handling of all day events in backend and frontend

---
 aleksis/core/frontend/components/calendar/Calendar.vue | 5 ++++-
 aleksis/core/models.py                                 | 7 ++-----
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/aleksis/core/frontend/components/calendar/Calendar.vue b/aleksis/core/frontend/components/calendar/Calendar.vue
index d8fcdfe39..511af38d5 100644
--- a/aleksis/core/frontend/components/calendar/Calendar.vue
+++ b/aleksis/core/frontend/components/calendar/Calendar.vue
@@ -217,7 +217,10 @@ export default {
         .flatMap((cf) =>
           cf.events.map((event) => {
             const start = this.$parseISODate(event.start);
-            const end = this.$parseISODate(event.end);
+            let end = this.$parseISODate(event.end);
+            if (event.allDay) {
+              end = end.minus({ days: 1 });
+            }
             return {
               ...event,
               category: cf.verboseName,
diff --git a/aleksis/core/models.py b/aleksis/core/models.py
index a080955bf..fcf9384b2 100644
--- a/aleksis/core/models.py
+++ b/aleksis/core/models.py
@@ -1561,11 +1561,8 @@ class CalendarEvent(CalendarEventMixin, ExtensiblePolymorphicModel, RecurrenceMo
         """Return the end datetime of the calendar event."""
         if reference_object.datetime_end:
             return reference_object.datetime_end.astimezone(reference_object.timezone)
-        if reference_object.date_end == reference_object.date_start:
-            # Rule for all day events: If the event is only one day long,
-            # the end date has to be empty
-            return None
-        return reference_object.date_end
+        # RFC 5545 states that the end date is not inclusive
+        return reference_object.date_end + timedelta(days=1)
 
     @classmethod
     def value_rrule(
-- 
GitLab


From 1b5563ebe89612e80bec7a94ad5679aa5e0c0c00 Mon Sep 17 00:00:00 2001
From: Hangzhi Yu <hangzhi@protonmail.com>
Date: Sun, 2 Feb 2025 20:05:26 +0100
Subject: [PATCH 3/4] Add test

---
 aleksis/core/tests/regression/test_regression.py | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/aleksis/core/tests/regression/test_regression.py b/aleksis/core/tests/regression/test_regression.py
index a578145db..c4e2b393e 100644
--- a/aleksis/core/tests/regression/test_regression.py
+++ b/aleksis/core/tests/regression/test_regression.py
@@ -1,4 +1,5 @@
 import base64
+from datetime import date
 
 from django.contrib.auth import get_user_model
 from django.test import override_settings
@@ -6,7 +7,7 @@ from django.urls import reverse
 
 import pytest
 
-from aleksis.core.models import Group, OAuthApplication, Person
+from aleksis.core.models import Holiday, Group, OAuthApplication, Person
 
 pytestmark = pytest.mark.django_db
 
@@ -147,3 +148,16 @@ def test_change_password_not_logged_in(client):
 
     assert response.status_code == 200
     assert "Please login to see this page." in response.content.decode("utf-8")
+
+
+def test_all_day_events_end_date():
+    """Tests that CalendarEvent's value method returns a non-inclusive end date for all day events.
+
+    https://edugit.org/AlekSIS/official/AlekSIS-Core/-/issues/1199
+    """
+    holiday = Holiday.objects.create(
+        date_start=date(2024, 2, 1), date_end=date(2024, 2, 1), holiday_name="Test Holiday"
+    )
+
+    assert holiday.value_start_datetime(holiday) == date(2024, 2, 1)
+    assert holiday.value_end_datetime(holiday) == date(2024, 2, 2)
-- 
GitLab


From e2283936c7538f43f12026af15e5184f43c637e7 Mon Sep 17 00:00:00 2001
From: Hangzhi Yu <hangzhi@protonmail.com>
Date: Sun, 2 Feb 2025 20:12:32 +0100
Subject: [PATCH 4/4] Fix constraint in migration

---
 .../0071_constrain_calendar_event_starting_before_ending.py     | 2 +-
 aleksis/core/tests/regression/test_regression.py                | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/aleksis/core/migrations/0071_constrain_calendar_event_starting_before_ending.py b/aleksis/core/migrations/0071_constrain_calendar_event_starting_before_ending.py
index cd1620e7d..4567be588 100644
--- a/aleksis/core/migrations/0071_constrain_calendar_event_starting_before_ending.py
+++ b/aleksis/core/migrations/0071_constrain_calendar_event_starting_before_ending.py
@@ -16,7 +16,7 @@ class Migration(migrations.Migration):
         ),
         migrations.AddConstraint(
             model_name='calendarevent',
-            constraint=models.CheckConstraint(check=Q(date_end__gt=F('date_start')),
+            constraint=models.CheckConstraint(check=Q(date_end__gte=F('date_start')),
                                               name="date_start_before_end"
             ),
         ),
diff --git a/aleksis/core/tests/regression/test_regression.py b/aleksis/core/tests/regression/test_regression.py
index c4e2b393e..74e41227a 100644
--- a/aleksis/core/tests/regression/test_regression.py
+++ b/aleksis/core/tests/regression/test_regression.py
@@ -7,7 +7,7 @@ from django.urls import reverse
 
 import pytest
 
-from aleksis.core.models import Holiday, Group, OAuthApplication, Person
+from aleksis.core.models import Group, Holiday, OAuthApplication, Person
 
 pytestmark = pytest.mark.django_db
 
-- 
GitLab