130 lines
4.6 KiB
Python
130 lines
4.6 KiB
Python
# passerelle - uniform access to multiple data sources and services
|
|
# Copyright (C) 2021 Entr'ouvert
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify it
|
|
# under the terms of the GNU Affero General Public License as published
|
|
# by the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Affero General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
from urllib.parse import urljoin
|
|
|
|
from django.conf import settings
|
|
from django.db import models
|
|
from django.db.models import Q
|
|
from django.utils.translation import gettext_lazy as _
|
|
|
|
from passerelle.apps.sector.models import (
|
|
MAX_HOUSENUMBER,
|
|
PARITY_ALL,
|
|
PARITY_EVEN,
|
|
PARITY_ODD,
|
|
Sectorization,
|
|
SectorResource,
|
|
)
|
|
from passerelle.base.models import BaseResource
|
|
from passerelle.utils.api import endpoint
|
|
|
|
|
|
class AddressResource(BaseResource):
|
|
sectors = models.ManyToManyField(
|
|
SectorResource, blank=True, related_name='resources', verbose_name=_('Sectorizations')
|
|
)
|
|
|
|
category = _('Geographic information system')
|
|
|
|
class Meta:
|
|
abstract = True
|
|
|
|
@classmethod
|
|
def get_manager_form_class(cls, **kwargs):
|
|
if not SectorResource.objects.exists():
|
|
kwargs['exclude'] = tuple(kwargs.get('exclude') or ()) + ('sectors',)
|
|
return super().get_manager_form_class(**kwargs)
|
|
|
|
def export_json(self):
|
|
d = super().export_json()
|
|
d['sectors'] = [sector.slug for sector in self.sectors.all()]
|
|
return d
|
|
|
|
@classmethod
|
|
def import_json_real(cls, overwrite, instance, d, **kwargs):
|
|
sectors = d.pop('sectors', [])
|
|
instance = super().import_json_real(overwrite, instance, d, **kwargs)
|
|
if instance and overwrite:
|
|
instance.sectors.clear()
|
|
for slug in sectors:
|
|
sector = SectorResource.objects.filter(slug=slug).first()
|
|
if sector:
|
|
instance.sectors.add(sector)
|
|
return instance
|
|
|
|
def sectorize(self, address):
|
|
"""
|
|
add 'sectors' entry in address.
|
|
address is a Nominatim formatted dict and should contain 'street_id' and
|
|
'house_number' in its 'address' dict.
|
|
"""
|
|
if not self.sectors.exists():
|
|
return
|
|
address['sectors'] = {}
|
|
|
|
street_id = address['address'].get('street_id')
|
|
if not street_id:
|
|
address['sectorization_error'] = 'missing street_id in address'
|
|
return
|
|
|
|
try:
|
|
house_number = int(address['address'].get('house_number'))
|
|
except (TypeError, ValueError):
|
|
house_number = None
|
|
|
|
query = Sectorization.objects.filter(sector__resource__in=self.sectors.all(), street_id=street_id)
|
|
if house_number is not None:
|
|
query = query.filter(min_housenumber__lte=house_number, max_housenumber__gte=house_number)
|
|
parity = PARITY_ODD if house_number % 2 else PARITY_EVEN
|
|
query = query.filter(Q(parity=PARITY_ALL) | Q(parity=parity))
|
|
else:
|
|
query = query.filter(parity=PARITY_ALL, min_housenumber=0, max_housenumber=MAX_HOUSENUMBER)
|
|
for sectorization in query.reverse():
|
|
address['sectors'][sectorization.sector.resource.slug] = {
|
|
'id': sectorization.sector.slug,
|
|
'text': sectorization.sector.title,
|
|
}
|
|
|
|
@endpoint(
|
|
name='sectors',
|
|
description=_('List related Sectorizations'),
|
|
perm='OPEN',
|
|
parameters={
|
|
'id': {'description': _('Sector Identifier (slug)')},
|
|
'q': {'description': _('Filter by Sector Title or Identifier')},
|
|
},
|
|
)
|
|
def sectors_(self, request, q=None, id=None):
|
|
query = self.sectors.all()
|
|
if id is not None:
|
|
query = query.filter(slug=id)
|
|
elif q is not None:
|
|
query = query.filter(Q(slug__icontains=q) | Q(title__icontains=q))
|
|
return {
|
|
'data': [
|
|
{
|
|
'id': resource.slug,
|
|
'text': resource.title,
|
|
'description': resource.description,
|
|
'sectors_url': urljoin(
|
|
settings.SITE_BASE_URL, '%ssectors/' % resource.get_absolute_url()
|
|
),
|
|
}
|
|
for resource in query
|
|
]
|
|
}
|