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/check parking check eventarea #23

Merged
merged 19 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from 7 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
7 changes: 7 additions & 0 deletions docs/api/enforcement.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,13 @@ paths:
type: string
maxLength: 10
nullable: true
event_area:
description: >-
Event Area found by the provided location,
or null if the provided location is not in any
event area in the system.
type: string
nullable: true
time:
description: >-
Time used in the check. It will either be equal
Expand Down
30 changes: 18 additions & 12 deletions parkings/api/enforcement/check_parking.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from rest_framework.response import Response

from ...models import (
EventParking, Parking, ParkingCheck, PaymentZone, PermitArea,
EventArea, EventParking, Parking, ParkingCheck, PaymentZone, PermitArea,
PermitLookupItem)
from ...models.constants import GK25FIN_SRID, WGS84_SRID
from .permissions import IsEnforcer
Expand Down Expand Up @@ -60,10 +60,10 @@ def post(self, request):

zone = get_payment_zone(gk25_location, domain)
area = get_permit_area(gk25_location, domain)
event_area = get_event_area(gk25_location, domain)

(allowed_by, parking, end_time) = check_parking(
registration_number, zone, area, time, domain)

registration_number, zone, area, time, domain, event_area)
allowed = bool(allowed_by)

if not allowed:
Expand All @@ -72,14 +72,15 @@ def post(self, request):
# ago (where "a few minutes" is the grace duration)
past_time = time - get_grace_duration()
(_allowed_by, parking, end_time) = check_parking(
registration_number, zone, area, past_time, domain)
registration_number, zone, area, past_time, domain, event_area)

result = {
"allowed": allowed,
"end_time": end_time,
"location": {
"payment_zone": zone,
"permit_area": area.identifier if area else None,
"event_area": event_area.id if event_area else None,
},
"time": time,
}
Expand Down Expand Up @@ -132,15 +133,16 @@ def get_permit_area(location, domain):
area = PermitArea.objects.filter(geom__contains=location, domain=domain).first()
return area if area else None

# def get_event_area(location, domain):
# if location is None:
# return None
# now = timezone.now()
# area = EventArea.objects.filter(geom__contains=location, domain=domain, time_end__gte=now).first()
# return area if area else None

def get_event_area(location, domain):
if location is None:
return None
now = timezone.now()
area = EventArea.objects.filter(geom__contains=location, domain=domain, time_end__gte=now).first()
return area if area else None


def check_parking(registration_number, zone, area, time, domain):
def check_parking(registration_number, zone, area, time, domain, event_area):
"""
Check parking allowance from the database.

Expand Down Expand Up @@ -184,7 +186,11 @@ def check_parking(registration_number, zone, area, time, domain):
.filter(domain=domain)).first()

if active_event_parking:
return ("event parking", active_event_parking, active_event_parking.time_end)
if active_event_parking.event_area == event_area:
return ("event parking", active_event_parking, active_event_parking.time_end)
else:
# Event parking not parked in the assigned event area, i.e., not allowed.
return (None, active_event_parking, active_event_parking.time_end)

return (None, None, None)

Expand Down
10 changes: 10 additions & 0 deletions parkings/api/enforcement/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,18 @@

from django.conf import settings

from .check_parking import get_event_area


def get_grace_duration(default=datetime.timedelta(minutes=15)):
value = getattr(settings, 'PARKKIHUBI_TIME_OLD_PARKINGS_VISIBLE', None)
assert value is None or isinstance(value, datetime.timedelta)
return value if value is not None else default


def get_event_parkings_in_assigned_event_areas(queryset):
in_assigned_event_area = []
for event_parking in queryset.all():
if get_event_area(event_parking.location_gk25fin, domain=event_parking.domain) == event_parking.event_area:
in_assigned_event_area.append(event_parking.id)
return queryset.filter(id__in=in_assigned_event_area)
10 changes: 7 additions & 3 deletions parkings/api/enforcement/valid_parking.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@

from ...models import Parking
from .permissions import IsEnforcer
from .utils import get_grace_duration
from .utils import (
get_event_parkings_in_assigned_event_areas, get_grace_duration)


class ValidSerializer(serializers.ModelSerializer):
Expand Down Expand Up @@ -123,6 +124,7 @@ class Meta:

class ValidViewSet(viewsets.ReadOnlyModelViewSet):
permission_classes = [IsEnforcer]
model = None

class Meta:
abstract = True
Expand All @@ -140,7 +142,6 @@ def filter_queryset(self, queryset):
with the PARKKIHUBI_TIME_OLD_PARKINGS_VISIBLE setting.
"""
filtered_queryset = super().filter_queryset(queryset)

if filtered_queryset:
return filtered_queryset

Expand Down Expand Up @@ -173,7 +174,10 @@ def _get_filterset(self, queryset):
return filter_backend.get_filterset(self.request, queryset, self)

def get_queryset(self):
return super().get_queryset().filter(domain=self.request.user.enforcer.enforced_domain)
queryset = super().get_queryset().filter(domain=self.request.user.enforcer.enforced_domain)
if self.__class__.__name__ == "ValidEventParkingViewSet":
queryset = queryset.filter(id__in=get_event_parkings_in_assigned_event_areas(self.queryset))
return queryset


class ValidParkingViewSet(ValidViewSet):
Expand Down
6 changes: 5 additions & 1 deletion parkings/api/monitoring/valid_parking.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from ...models import Parking
from ..common import WGS84InBBoxFilter
from ..enforcement.utils import get_event_parkings_in_assigned_event_areas
from .permissions import IsMonitor
from .serializers import ParkingSerializer

Expand Down Expand Up @@ -42,7 +43,10 @@ class ValidViewSet(viewsets.ReadOnlyModelViewSet):
bbox_filter_include_overlapping = True

def get_queryset(self):
return super().get_queryset().filter(domain=self.request.user.monitor.domain)
queryset = super().get_queryset().filter(domain=self.request.user.monitor.domain)
if self.__class__.__name__ == "ValidEventParkingViewSet":
queryset = queryset.filter(id__in=get_event_parkings_in_assigned_event_areas(self.queryset))
return queryset

class Meta:
abstract = True
Expand Down
64 changes: 53 additions & 11 deletions parkings/tests/api/enforcement/test_check_parking.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@
"location": {"longitude": 24.9, "latitude": 60.2},
}

PARKING_DATA_2 = {
"registration_number": "ABC-123",
"location": {"longitude": 26.4, "latitude": 64.2},
}


INVALID_PARKING_DATA = {
"registration_number": "ABC-123",
"location": {"longitude": 24.9, "latitude": 60.4},
Expand Down Expand Up @@ -91,21 +97,23 @@ def create_permit(domain, permit_series=None, end_time=None):
)


def test_check_parking_allowed_event_parking(enforcer_api_client, event_parking_factory, enforcer):
event_parking = event_parking_factory(registration_number="ABC-123", domain=enforcer.enforced_domain)
def test_check_parking_allowed_event_parking(enforcer_api_client, event_parking_factory, enforcer, event_area_factory):
event_area = event_area_factory.create(geom=create_area_geom(), domain=enforcer.enforced_domain)
event_parking = event_parking_factory(registration_number="ABC-123",
domain=enforcer.enforced_domain, event_area=event_area)
response = enforcer_api_client.post(list_url, data=PARKING_DATA)
assert response.status_code == HTTP_200_OK
assert response.data["allowed"] is True
assert response.data["end_time"] == event_parking.time_end

assert ParkingCheck.objects.filter(
registration_number=event_parking.registration_number).first().result["allowed"] is True


def test_check_parking_not_allowed_event_parking(enforcer_api_client, event_parking_factory, enforcer):
event_parking_factory(registration_number="CBA-123", domain=enforcer.enforced_domain)
def test_check_parking_not_allowed_event_parking(
enforcer_api_client, event_parking_factory, enforcer, event_area_factory):
event_area = event_area_factory.create(geom=create_area_geom(), domain=enforcer.enforced_domain)
event_parking_factory(registration_number="CBA-123", domain=enforcer.enforced_domain, event_area=event_area)
response = enforcer_api_client.post(list_url, data=PARKING_DATA)

assert response.status_code == HTTP_200_OK
assert response.data["allowed"] is False
assert response.data["end_time"] is None
Expand All @@ -114,18 +122,52 @@ def test_check_parking_not_allowed_event_parking(enforcer_api_client, event_park
registration_number=PARKING_DATA["registration_number"]).first().result["allowed"] is False


def test_check_event_parking_with_time_end_null(enforcer_api_client, event_parking_factory, enforcer):
def test_check_event_parking_parked_in_wrong_event_area(
enforcer_api_client, event_parking_factory, enforcer, event_area_factory):
event_area_1 = event_area_factory.create(geom=create_area_geom(), domain=enforcer.enforced_domain)
event_area_2 = event_area_factory.create(geom=create_area_geom(geom=GEOM_2), domain=enforcer.enforced_domain)
# Parked inside event_area_2, i.e., inside GEOM_2, but event_area_1 is assigned
location = Point(PARKING_DATA_2["location"]["longitude"], PARKING_DATA_2["location"]["latitude"], srid=WGS84_SRID)
event_parking = event_parking_factory(registration_number="ABC-123",
domain=enforcer.enforced_domain, event_area=event_area_1, location=location)
response = enforcer_api_client.post(list_url, data=PARKING_DATA_2)
assert response.status_code == HTTP_200_OK
assert response.data["location"]["event_area"] == event_area_2.id
assert response.data["allowed"] is False
assert response.data["end_time"] == event_parking.time_end
assert ParkingCheck.objects.filter(
registration_number=PARKING_DATA["registration_number"]).first().result["allowed"] is False


def test_check_event_parking_outside_event_area(
enforcer_api_client, event_parking_factory, enforcer, event_area_factory):
event_area = event_area_factory.create(geom=create_area_geom(), domain=enforcer.enforced_domain)
location = Point(PARKING_DATA_2["location"]["longitude"], PARKING_DATA_2["location"]["latitude"], srid=WGS84_SRID)
event_parking = event_parking_factory(registration_number="ABC-123",
domain=enforcer.enforced_domain, event_area=event_area, location=location)
response = enforcer_api_client.post(list_url, data=PARKING_DATA_2)
assert response.status_code == HTTP_200_OK
assert response.data["location"]["event_area"] is None
assert response.data["allowed"] is False
assert response.data["end_time"] == event_parking.time_end
assert ParkingCheck.objects.filter(
registration_number=PARKING_DATA["registration_number"]).first().result["allowed"] is False


def test_check_event_parking_with_time_end_null(
enforcer_api_client, event_parking_factory, enforcer, event_area_factory):
time_end = None
now = timezone.now()
time_start = now - timedelta(hours=1)
event_area = event_area_factory.create(geom=create_area_geom(), domain=enforcer.enforced_domain)
event_parking_factory(registration_number="ABC-123", domain=enforcer.enforced_domain,
time_start=time_start, time_end=time_end)
time_start=time_start, time_end=time_end, event_area=event_area)

response = enforcer_api_client.post(list_url, data=PARKING_DATA)
assert response.status_code == HTTP_200_OK
assert response.data["allowed"] is True
assert response.data["end_time"] is None

assert response.data["location"]["event_area"] == event_area.id
assert ParkingCheck.objects.filter(
registration_number=PARKING_DATA["registration_number"]).first().result["allowed"] is True

Expand Down Expand Up @@ -195,7 +237,7 @@ def test_check_parking_invalid_location(enforcer_api_client, staff_user):

assert response.status_code == HTTP_200_OK
assert response.data["location"] == {
'payment_zone': None, 'permit_area': None}
'event_area': None, 'payment_zone': None, 'permit_area': None}
assert response.data["allowed"] is False


Expand All @@ -208,7 +250,7 @@ def test_returned_data_has_correct_schema(enforcer_api_client):
assert isinstance(data["allowed"], bool)
assert data["end_time"] is None
assert isinstance(data["location"], dict)
assert sorted(data["location"].keys()) == ["payment_zone", "permit_area"]
assert sorted(data["location"].keys()) == ["event_area", "payment_zone", "permit_area"]
assert isinstance(data["time"], datetime.datetime)


Expand Down
Loading
Loading