Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/exceptional situations add municipality #362

Merged
merged 8 commits into from
Jun 27, 2024
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
5 changes: 5 additions & 0 deletions exceptional_situations/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class Meta:

class SituationAnnouncementSerializer(serializers.ModelSerializer):
location = SituationLocationSerializer()
municipalities = serializers.SerializerMethodField()

class Meta:
model = SituationAnnouncement
Expand All @@ -27,8 +28,12 @@ class Meta:
"end_time",
"additional_info",
"location",
"municipalities",
]

def get_municipalities(self, obj):
return [m.id for m in obj.municipalities.all()]

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

Expand Down
17 changes: 13 additions & 4 deletions exceptional_situations/api/views.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import django_filters
from django.db.models import Q
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import viewsets

Expand All @@ -23,6 +24,7 @@ class SituationFilter(django_filters.FilterSet):
start_time__lt = django_filters.DateTimeFilter(method="filter_start_time__lt")
end_time__gt = django_filters.DateTimeFilter(method="filter_end_time__gt")
end_time__lt = django_filters.DateTimeFilter(method="filter_end_time__lt")
municipalities = django_filters.CharFilter(method="filter_municipalities")

class Meta:
model = Situation
Expand Down Expand Up @@ -50,14 +52,21 @@ def filter_start_time__lt(self, queryset, fields, start_time):
ids = [obj.id for obj in queryset if obj.start_time < start_time]
return queryset.filter(id__in=ids)

def filter_end_time__gt(self, queryset, fields, start_time):
ids = [obj.id for obj in queryset if obj.start_time > start_time]
def filter_end_time__gt(self, queryset, fields, end_time):
ids = [obj.id for obj in queryset if obj.end_time > end_time]
return queryset.filter(id__in=ids)

def filter_end_time__lt(self, queryset, fields, start_time):
ids = [obj.id for obj in queryset if obj.start_time < start_time]
def filter_end_time__lt(self, queryset, fields, end_time):
ids = [obj.id for obj in queryset if obj.end_time < end_time]
return queryset.filter(id__in=ids)

def filter_municipalities(self, queryset, fields, municipalities):
municipalities = municipalities.split(",")
query = Q()
for municiaplity in municipalities:
query |= Q(announcements__municipalities__id__iexact=municiaplity.strip())
return queryset.filter(query).distinct()


class SituationViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Situation.objects.all()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from django.contrib.gis.geos import GEOSGeometry, Polygon
from django.core.management import BaseCommand
from django.utils import timezone
from munigeo.models import Municipality

from exceptional_situations.models import (
PROJECTION_SRID,
Expand Down Expand Up @@ -65,6 +66,19 @@ def create_location(self, geometry, announcement_data):
}
return get_or_create(SituationLocation, filter)

def get_municipality_lower_names(self, location_details):
names = []
road_address_location = location_details.get("roadAddressLocation", None)
if road_address_location:
primary_point = road_address_location.get("primaryPoint", None)
if primary_point:
names.append(primary_point["municipality"].lower())
secondary_point = road_address_location.get("secondaryPoint", None)
if secondary_point:
names.append(secondary_point["municipality"].lower())

return names

def create_announcement(self, announcement_data, location):
title = announcement_data.get("title", "")
description = announcement_data["location"].get("description", "")
Expand Down Expand Up @@ -97,7 +111,19 @@ def create_announcement(self, announcement_data, location):
"end_time": end_time,
"location": location,
}
return get_or_create(SituationAnnouncement, filter)

announcement = get_or_create(SituationAnnouncement, filter)
location_details = announcement_data.get("locationDetails", None)
if location_details:
announcement.municipalities.clear()
municipality_names = self.get_municipality_lower_names(location_details)
for name in municipality_names:
try:
municipality = Municipality.objects.get(id=name)
announcement.municipalities.add(municipality)
except Municipality.DoesNotExist:
logger.warning(f"Municipality {name} does not exists")
return announcement

def save_features(self, features):
num_imported = 0
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 4.1.13 on 2024-06-24 08:07

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("munigeo", "0016_address_modified_at_remove_auto_now"),
("exceptional_situations", "0002_alter_situationannouncement_location"),
]

operations = [
migrations.AddField(
model_name="situationannouncement",
name="municipalities",
field=models.ManyToManyField(to="munigeo.municipality"),
),
]
2 changes: 2 additions & 0 deletions exceptional_situations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from django.contrib.gis.db import models
from django.utils import timezone
from munigeo.models import Municipality

PROJECTION_SRID = 4326

Expand Down Expand Up @@ -39,6 +40,7 @@ class SituationAnnouncement(models.Model):
blank=True,
related_name="announcements",
)
municipalities = models.ManyToManyField(Municipality)

class Meta:
ordering = ["start_time"]
Expand Down
20 changes: 16 additions & 4 deletions exceptional_situations/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import pytest
from django.contrib.gis.geos import GEOSGeometry
from django.utils import timezone
from munigeo.models import Municipality
from rest_framework.test import APIClient

from exceptional_situations.models import (
Expand All @@ -20,6 +21,15 @@ def api_client():
return APIClient()


@pytest.mark.django_db
@pytest.fixture
def municipalities():
Municipality.objects.create(id="turku", name="Turku")
Municipality.objects.create(id="lieto", name="Lieto")
Municipality.objects.create(id="raisio", name="Raisio")
return Municipality.objects.all()


@pytest.mark.django_db
@pytest.fixture
def situation_types():
Expand Down Expand Up @@ -48,25 +58,27 @@ def locations():

@pytest.mark.django_db
@pytest.fixture
def announcements(locations):
def announcements(locations, municipalities):
json_data = {"test_key": "test_value"}
SituationAnnouncement.objects.create(
sa = SituationAnnouncement.objects.create(
title="two hours",
description="two hours long situation",
additional_info=json_data,
location=locations[0],
start_time=NOW - timedelta(hours=1),
end_time=NOW + timedelta(hours=1),
)
SituationAnnouncement.objects.create(
sa.municipalities.add(municipalities.filter(id="turku").first())
sa.municipalities.add(municipalities.filter(id="lieto").first())
sa = SituationAnnouncement.objects.create(
title="two days",
description="two days long situation",
additional_info=json_data,
location=locations[1],
start_time=NOW - timedelta(days=1),
end_time=NOW + timedelta(days=1),
)

sa.municipalities.add(municipalities.filter(id="raisio").first())
return SituationAnnouncement.objects.all()


Expand Down
15 changes: 13 additions & 2 deletions exceptional_situations/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def test_situations_list(api_client, situations, inactive_situations):
"end_time",
"additional_info",
"location",
"municipalities",
}
location = announcement["location"]
assert location.keys() == {"id", "location", "geometry", "details"}
Expand Down Expand Up @@ -102,12 +103,12 @@ def test_situation_filter_by_end_time(api_client, situations):
SITUATION_LIST_URL
+ f"?end_time__gt={datetime.strftime(end_time, DATETIME_FORMAT)}"
)
assert response.json()["count"] == 1
assert response.json()["count"] == 2
response = api_client.get(
SITUATION_LIST_URL
+ f"?end_time__lt={datetime.strftime(end_time, DATETIME_FORMAT)}"
)
assert response.json()["count"] == 1
assert response.json()["count"] == 0

end_time = timezone.now() - timedelta(days=2)
response = api_client.get(
Expand All @@ -122,6 +123,14 @@ def test_situation_filter_by_end_time(api_client, situations):
assert response.json()["count"] == 0


@pytest.mark.django_db
def test_filter_by_municipalities(api_client, situations):
response = api_client.get(SITUATION_LIST_URL + "?municipalities=raisio,lieto")
assert response.json()["count"] == 2
response = api_client.get(SITUATION_LIST_URL + "?municipalities=turku")
assert response.json()["count"] == 1


@pytest.mark.django_db
def test_situation_types_list(api_client, situation_types):
response = api_client.get(reverse("exceptional_situations:situation_type-list"))
Expand Down Expand Up @@ -163,6 +172,7 @@ def test_announcement_list(api_client, announcements):
"end_time",
"additional_info",
"location",
"municipalities",
}
location = result_data["location"]
assert location.keys() == {"id", "location", "geometry", "details"}
Expand All @@ -186,6 +196,7 @@ def test_announcement_retrieve(api_client, announcements):
"end_time",
"additional_info",
"location",
"municipalities",
}
assert json_data["id"] == announcements[0].pk

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ def import_command(*args, **kwargs):

@pytest.mark.django_db
@freeze_time("2024-06-11 12:00:00", tz_offset=2)
def test_import_traffic_situation():
def test_import_traffic_situation(municipalities):
import_command(test_importer=data)
assert SituationType.objects.count() == 1
assert SituationType.objects.first().type_name == "ROAD_WORK"
Expand All @@ -352,6 +352,9 @@ def test_import_traffic_situation():
assert location.details["primaryPoint"]["roadName"] == "Turun kehätie"
announcement = SituationAnnouncement.objects.first()
assert announcement in situation.announcements.all()
assert announcement.municipalities.filter(
id=municipalities.get(id="turku").id
).exists()
assert announcement.title == "Tie 40, eli Turun kehätie, Turku. Tietyö. "
assert "aikutusalue 1,1 km, suuntaan Kärsämäen " in announcement.description
assert (
Expand Down
Loading