diff --git a/calendar_utils/models.py b/calendar_utils/models.py index 1b3f4abf15dffcb62388505cc32393407cba7142..6caf230f352a2887a93dcea798ee7e170091770b 100644 --- a/calendar_utils/models.py +++ b/calendar_utils/models.py @@ -43,3 +43,36 @@ class Calendar(models.Model): self.future_events = list(map(_convert_arrow_to_datetime, future)) self.last_update = arrow.utcnow().datetime self.save() + + +class CalendarMixin(models.Model): + """ + Mixin to be used in other models, like site settings, which adds relation + to Calendar. + """ + + calendar_url = models.URLField( + "URL kalendáře ve formátu iCal", blank=True, null=True + ) + calendar = models.ForeignKey(Calendar, null=True, on_delete=models.PROTECT) + + class Meta: + abstract = True + + def save(self, *args, **kwargs): + # create or update related Calendar + if self.calendar_url: + if self.calendar: + if self.calendar.url != self.calendar_url: + self.calendar.url = self.calendar_url + self.calendar.save() + else: + self.calendar = Calendar.objects.create(url=self.calendar_url) + self.calendar.update_source() + + # delete related Calendar when URL is cleared + if not self.calendar_url and self.calendar: + self.calendar.delete() + self.calendar = None + + super().save(*args, **kwargs) diff --git a/tests/calendar_utils/conftest.py b/tests/calendar_utils/conftest.py index 736f38060ae6167881bc105562e4a609d52dc5e8..36da9cecb1f63e7d2e8e5ce4f7ba79e82adf8dc8 100644 --- a/tests/calendar_utils/conftest.py +++ b/tests/calendar_utils/conftest.py @@ -1,8 +1,27 @@ from pathlib import Path import pytest +from django.db import connection + +from calendar_utils.models import CalendarMixin @pytest.fixture(scope="session") def sample(): return (Path(__file__).parent / "sample.ics").read_text() + + +class DummyModel(CalendarMixin): + class Meta: + app_label = "__tests" + + +@pytest.fixture(scope="session") +def Dummy(django_db_setup, django_db_blocker): + with django_db_blocker.unblock(): + with connection.schema_editor() as editor: + editor.create_model(DummyModel) + yield DummyModel + with django_db_blocker.unblock(): + with connection.schema_editor() as editor: + editor.delete_model(DummyModel) diff --git a/tests/calendar_utils/test_models.py b/tests/calendar_utils/test_models.py index b81e21484bcc58e40b00f2601fd09b5137adc378..b24dd63841829389a7accf621ab1b3ed700f0faf 100644 --- a/tests/calendar_utils/test_models.py +++ b/tests/calendar_utils/test_models.py @@ -79,3 +79,64 @@ def test_calendar__save_and_load_events__no_values(): cal.refresh_from_db() assert cal.past_events is None assert cal.future_events is None + + +def test_calendar_mixin__no_calendar_url(Dummy): + obj = Dummy.objects.create() + assert obj.calendar is None + + +def test_calendar_mixin__set_calendar_url(Dummy, mocker): + m_update = mocker.patch.object(Calendar, "update_source") + url = fake.url() + + obj = Dummy.objects.create(calendar_url=url) + + obj.refresh_from_db() + assert obj.calendar_url == url + assert obj.calendar.url == url + assert m_update.call_count == 1 + + +def test_calendar_mixin__update_calendar_url(Dummy, mocker): + m_update = mocker.patch.object(Calendar, "update_source") + obj = Dummy.objects.create(calendar_url=fake.url()) + url = fake.url() + m_update.reset_mock() + + obj.calendar_url = url + obj.save() + + obj.refresh_from_db() + assert obj.calendar_url == url + assert obj.calendar.url == url + assert m_update.call_count == 1 + + +def test_calendar_mixin__unchanged_calendar_url(Dummy, mocker): + m_update = mocker.patch.object(Calendar, "update_source") + url = fake.url() + obj = Dummy.objects.create(calendar_url=url) + m_update.reset_mock() + + obj.save() + + obj.refresh_from_db() + assert obj.calendar_url == url + assert obj.calendar.url == url + assert m_update.call_count == 1 + + +def test_calendar_mixin__clear_calendar_url(Dummy, mocker): + m_update = mocker.patch.object(Calendar, "update_source") + obj = Dummy.objects.create(calendar_url=fake.url()) + m_update.reset_mock() + + obj.calendar_url = None + obj.save() + + obj.refresh_from_db() + assert obj.calendar_url is None + assert obj.calendar is None + assert m_update.call_count == 0 + assert Calendar.objects.count() == 0