Skip to content

Commit

Permalink
Use locations data from Location model
Browse files Browse the repository at this point in the history
  • Loading branch information
norkans7 committed Jan 9, 2025
1 parent 6492f11 commit 07f7128
Show file tree
Hide file tree
Showing 26 changed files with 334 additions and 226 deletions.
4 changes: 2 additions & 2 deletions temba/api/internal/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from rest_framework import serializers

from temba.locations.models import AdminBoundary
from temba.locations.models import Location
from temba.templates.models import Template, TemplateTranslation
from temba.tickets.models import Shortcut

Expand All @@ -14,7 +14,7 @@ def to_representation(self, instance):

class LocationReadSerializer(serializers.ModelSerializer):
class Meta:
model = AdminBoundary
model = Location
fields = ("osm_id", "name", "path")


Expand Down
2 changes: 1 addition & 1 deletion temba/api/internal/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def test_locations(self):
self.assertPostNotAllowed(endpoint_url)
self.assertDeleteNotAllowed(endpoint_url)

# no country, no results
# no location on org, no results
self.assertGet(endpoint_url + "?level=state", [self.agent], results=[])

self.setUpLocations()
Expand Down
18 changes: 8 additions & 10 deletions temba/api/internal/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from django.db.models import Prefetch, Q

from temba.channels.models import Channel
from temba.locations.models import AdminBoundary
from temba.locations.models import Location
from temba.notifications.models import Notification
from temba.templates.models import Template, TemplateTranslation
from temba.tickets.models import Shortcut
Expand Down Expand Up @@ -36,16 +36,16 @@ class LocationsEndpoint(ListAPIMixin, BaseEndpoint):
"""

LEVELS = {
"state": AdminBoundary.LEVEL_STATE,
"district": AdminBoundary.LEVEL_DISTRICT,
"ward": AdminBoundary.LEVEL_WARD,
"state": Location.LEVEL_STATE,
"district": Location.LEVEL_DISTRICT,
"ward": Location.LEVEL_WARD,
}

class Pagination(CursorPagination):
ordering = ("name", "id")
offset_cutoff = 100000

model = AdminBoundary
model = Location
serializer_class = serializers.LocationReadSerializer
pagination_class = Pagination

Expand All @@ -54,12 +54,10 @@ def derive_queryset(self):
level = self.LEVELS.get(self.request.query_params.get("level"))
query = self.request.query_params.get("query")

if not org.country or not level:
return AdminBoundary.objects.none()
if not org.location or not level:
return Location.objects.none()

qs = AdminBoundary.objects.filter(
path__startswith=f"{org.country.name} {AdminBoundary.PATH_SEPARATOR}", level=level
)
qs = Location.objects.filter(path__startswith=f"{org.location.name} {Location.PATH_SEPARATOR}", level=level)

if query:
qs = qs.filter(Q(path__icontains=query))
Expand Down
8 changes: 4 additions & 4 deletions temba/api/v2/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from temba.contacts.models import URN, Contact, ContactField, ContactGroup, ContactNote, ContactURN
from temba.flows.models import Flow, FlowRun, FlowStart
from temba.globals.models import Global
from temba.locations.models import AdminBoundary
from temba.locations.models import Location
from temba.mailroom import modifiers
from temba.msgs.models import Broadcast, Label, Media, Msg, OptIn
from temba.orgs.models import Org, OrgRole, User
Expand Down Expand Up @@ -123,7 +123,7 @@ def run_validation(self, data=serializers.empty):
# ============================================================


class AdminBoundaryReadSerializer(ReadSerializer):
class LocationReadSerializer(ReadSerializer):
parent = serializers.SerializerMethodField()
aliases = serializers.SerializerMethodField()
geometry = serializers.SerializerMethodField()
Expand All @@ -136,12 +136,12 @@ def get_aliases(self, obj):

def get_geometry(self, obj):
if self.context["include_geometry"] and obj.simplified_geometry:
return json.loads(obj.simplified_geometry.geojson)
return obj.simplified_geometry
else:
return None

class Meta:
model = AdminBoundary
model = Location
fields = ("osm_id", "name", "parent", "level", "aliases", "geometry")


Expand Down
18 changes: 10 additions & 8 deletions temba/api/v2/tests/test_boundaries.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from django.contrib.gis.geos import GEOSGeometry
from django.urls import reverse

from temba.locations.models import BoundaryAlias
from temba.locations.models import LocationAlias
from temba.tests import matchers

from . import APITest
Expand All @@ -17,11 +16,14 @@ def test_endpoint(self):

self.setUpLocations()

BoundaryAlias.create(self.org, self.admin, self.state1, "Kigali")
BoundaryAlias.create(self.org, self.admin, self.state2, "East Prov")
BoundaryAlias.create(self.org2, self.admin2, self.state1, "Other Org") # shouldn't be returned
LocationAlias.create(self.org, self.admin, self.state1, "Kigali")
LocationAlias.create(self.org, self.admin, self.state2, "East Prov")
LocationAlias.create(self.org2, self.admin2, self.state1, "Other Org") # shouldn't be returned

self.state1.simplified_geometry = GEOSGeometry("MULTIPOLYGON(((1 1, 1 -1, -1 -1, -1 1, 1 1)))")
self.state1.simplified_geometry = {
"type": "MultiPolygon",
"coordinates": [[[[1, 1], [1, -1], [-1, -1], [-1, 1], [1, 1]]]],
}
self.state1.save()

# test without geometry
Expand Down Expand Up @@ -136,7 +138,7 @@ def test_endpoint(self):
)

# if org doesn't have a country, just return no results
self.org.country = None
self.org.save(update_fields=("country",))
self.org.location = None
self.org.save(update_fields=("location",))

self.assertGet(endpoint_url, [self.admin], results=[])
16 changes: 8 additions & 8 deletions temba/api/v2/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from temba.contacts.models import Contact, ContactField, ContactGroup, ContactNote, ContactURN
from temba.flows.models import Flow, FlowRun, FlowStart, FlowStartCount
from temba.globals.models import Global
from temba.locations.models import AdminBoundary, BoundaryAlias
from temba.locations.models import Location, LocationAlias
from temba.msgs.models import Broadcast, BroadcastMsgCount, Label, LabelCount, Media, Msg, MsgFolder, OptIn
from temba.orgs.models import OrgMembership, User
from temba.orgs.views.mixins import OrgPermsMixin
Expand All @@ -43,7 +43,7 @@
)
from ..views import BaseAPIView, BulkWriteAPIMixin, DeleteAPIMixin, ListAPIMixin, WriteAPIMixin
from .serializers import (
AdminBoundaryReadSerializer,
LocationReadSerializer,
ArchiveReadSerializer,
BroadcastReadSerializer,
BroadcastWriteSerializer,
Expand Down Expand Up @@ -453,19 +453,19 @@ class BoundariesEndpoint(ListAPIMixin, BaseEndpoint):
class Pagination(CursorPagination):
ordering = ("osm_id",)

model = AdminBoundary
serializer_class = AdminBoundaryReadSerializer
model = Location
serializer_class = LocationReadSerializer
pagination_class = Pagination

def derive_queryset(self):
org = self.request.org
if not org.country:
return AdminBoundary.objects.none()
if not org.location:
return Location.objects.none()

queryset = org.country.get_descendants(include_self=True)
queryset = org.location.get_descendants(include_self=True)

queryset = queryset.prefetch_related(
Prefetch("aliases", queryset=BoundaryAlias.objects.filter(org=org).order_by("name"))
Prefetch("aliases", queryset=LocationAlias.objects.filter(org=org).order_by("name"))
)

return queryset.defer(None).select_related("parent")
Expand Down
2 changes: 1 addition & 1 deletion temba/channels/android/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
class AndroidTest(TembaTest):
def test_register_unsupported_android(self):
# remove our explicit country so it needs to be derived from channels
self.org.country = None
self.org.location = None
self.org.save()

Channel.objects.all().delete()
Expand Down
2 changes: 1 addition & 1 deletion temba/channels/types/android/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class AndroidTypeTest(TembaTest, CRUDLTestMixin):
@mock_mailroom
def test_claim(self, mr_mocks):
# remove our explicit country so it needs to be derived from channels
self.org.country = None
self.org.location = None
self.org.timezone = "UTC"
self.org.save(update_fields=("country", "timezone"))

Expand Down
6 changes: 3 additions & 3 deletions temba/contacts/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

from temba import mailroom
from temba.channels.models import Channel
from temba.locations.models import AdminBoundary
from temba.locations.models import Location
from temba.mailroom import ContactSpec, modifiers, queue_populate_dynamic_group
from temba.orgs.models import DependencyMixin, Export, ExportType, Org, OrgRole, User
from temba.utils import format_number, on_transaction_commit
Expand Down Expand Up @@ -843,7 +843,7 @@ def get_field_serialized(self, field) -> str:

def get_field_value(self, field: ContactField):
"""
Given the passed in contact field object, returns the value (as a string, decimal, datetime, AdminBoundary)
Given the passed in contact field object, returns the value (as a string, decimal, datetime, Location)
for this contact or None.
"""

Expand All @@ -861,7 +861,7 @@ def get_field_value(self, field: ContactField):
elif field.value_type == ContactField.TYPE_NUMBER:
return Decimal(string_value)
elif field.value_type in [ContactField.TYPE_STATE, ContactField.TYPE_DISTRICT, ContactField.TYPE_WARD]:
return AdminBoundary.get_by_path(self.org, string_value)
return Location.get_by_path(self.org, string_value)

def get_field_display(self, field: ContactField) -> str:
"""
Expand Down
16 changes: 8 additions & 8 deletions temba/contacts/tests/test_contact.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from temba.channels.models import ChannelEvent
from temba.contacts.models import URN, Contact, ContactField, ContactGroup, ContactURN
from temba.flows.models import Flow
from temba.locations.models import AdminBoundary
from temba.locations.models import Location
from temba.mailroom import modifiers
from temba.msgs.models import Msg, SystemLabel
from temba.orgs.models import Org
Expand Down Expand Up @@ -932,10 +932,10 @@ def test_set_location_fields(self):
not_state_field = self.create_field("not_state", "Not State", value_type=ContactField.TYPE_TEXT)

# add duplicate district in different states
east_province = AdminBoundary.create(osm_id="R005", name="East Province", level=1, parent=self.country)
AdminBoundary.create(osm_id="R004", name="Remera", level=2, parent=east_province)
kigali = AdminBoundary.objects.get(name="Kigali City")
AdminBoundary.create(osm_id="R003", name="Remera", level=2, parent=kigali)
east_province = Location.create(osm_id="R005", name="East Province", level=1, parent=self.country)
Location.create(osm_id="R004", name="Remera", level=2, parent=east_province)
kigali = Location.objects.get(name="Kigali City")
Location.create(osm_id="R003", name="Remera", level=2, parent=kigali)

joe = Contact.objects.get(pk=self.joe.pk)
self.set_contact_field(joe, "district", "Remera")
Expand All @@ -961,9 +961,9 @@ def test_set_location_fields(self):
def test_set_location_ward_fields(self):
self.setUpLocations()

state = AdminBoundary.create(osm_id="3710302", name="Kano", level=1, parent=self.country)
district = AdminBoundary.create(osm_id="3710307", name="Bichi", level=2, parent=state)
AdminBoundary.create(osm_id="3710377", name="Bichi", level=3, parent=district)
state = Location.create(osm_id="3710302", name="Kano", level=1, parent=self.country)
district = Location.create(osm_id="3710307", name="Bichi", level=2, parent=state)
Location.create(osm_id="3710377", name="Bichi", level=3, parent=district)

self.create_field("state", "State", value_type=ContactField.TYPE_STATE)
self.create_field("district", "District", value_type=ContactField.TYPE_DISTRICT)
Expand Down
6 changes: 3 additions & 3 deletions temba/contacts/tests/test_contactcrudl.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from temba.contacts.models import URN, Contact, ContactExport, ContactField
from temba.flows.models import FlowSession, FlowStart
from temba.ivr.models import Call
from temba.locations.models import AdminBoundary
from temba.locations.models import Location
from temba.msgs.models import Msg
from temba.orgs.models import Export, OrgRole
from temba.schedules.models import Schedule
Expand All @@ -32,8 +32,8 @@ class ContactCRUDLTest(CRUDLTestMixin, TembaTest):
def setUp(self):
super().setUp()

self.country = AdminBoundary.create(osm_id="171496", name="Rwanda", level=0)
AdminBoundary.create(osm_id="1708283", name="Kigali", level=1, parent=self.country)
self.location = Location.create(osm_id="171496", name="Rwanda", level=0)
Location.create(osm_id="1708283", name="Kigali", level=1, parent=self.location)

self.create_field("age", "Age", value_type="N", show_in_table=True)
self.create_field("home", "Home", value_type="S", show_in_table=True, priority=10)
Expand Down
2 changes: 1 addition & 1 deletion temba/flows/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,7 @@ def get_features(self, org) -> list:
features.append("classifier")
if org.get_resthooks():
features.append("resthook")
if org.country_id:
if org.location_id:
features.append("locations")

return features
Expand Down
Loading

0 comments on commit 07f7128

Please sign in to comment.