Skip to content

Commit

Permalink
Merge 49c53b7 into 646c36a
Browse files Browse the repository at this point in the history
  • Loading branch information
adrian-lara committed Jun 29, 2020
2 parents 646c36a + 49c53b7 commit 9dd637a
Show file tree
Hide file tree
Showing 3 changed files with 285 additions and 0 deletions.
4 changes: 4 additions & 0 deletions seed/api/v3/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from seed.views.v3.data_quality_checks import DataQualityCheckViewSet
from seed.views.v3.data_quality_check_rules import DataQualityCheckRuleViewSet
from seed.views.v3.datasets import DatasetViewSet
from seed.views.v3.geocode import GeocodeViewSet
from seed.views.v3.import_files import ImportFileViewSet
from seed.views.v3.labels import LabelViewSet
from seed.views.v3.label_inventories import LabelInventoryViewSet
Expand All @@ -22,6 +23,7 @@
from seed.views.v3.organization_users import OrganizationUserViewSet
from seed.views.v3.properties import PropertyViewSet
from seed.views.v3.taxlots import TaxlotViewSet
from seed.views.v3.ubid import UbidViewSet
from seed.views.v3.users import UserViewSet

api_v3_router = routers.DefaultRouter()
Expand All @@ -30,13 +32,15 @@
api_v3_router.register(r'columns', ColumnViewSet, base_name='columns')
api_v3_router.register(r'cycles', CycleViewSet, base_name='cycles')
api_v3_router.register(r'datasets', DatasetViewSet, base_name='datasets')
api_v3_router.register(r'geocode', GeocodeViewSet, base_name='geocode')
api_v3_router.register(r'labels', LabelViewSet, base_name='labels')
api_v3_router.register(r'data_quality_checks', DataQualityCheckViewSet, base_name='data_quality_checks')
api_v3_router.register(r'import_files', ImportFileViewSet, base_name='import_files')
api_v3_router.register(r'meters', MeterViewSet, base_name='meters')
api_v3_router.register(r'organizations', OrganizationViewSet, base_name='organizations')
api_v3_router.register(r'properties', PropertyViewSet, base_name='properties')
api_v3_router.register(r'taxlots', TaxlotViewSet, base_name='taxlots')
api_v3_router.register(r'ubid', UbidViewSet, base_name='ubid')
api_v3_router.register(r'users', UserViewSet, base_name='user')

data_quality_checks_router = nested_routers.NestedSimpleRouter(api_v3_router, r'data_quality_checks', lookup="nested")
Expand Down
145 changes: 145 additions & 0 deletions seed/views/v3/geocode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# !/usr/bin/env python
# encoding: utf-8

from django.db.models import Subquery
from django.http import JsonResponse

from drf_yasg.utils import swagger_auto_schema

from rest_framework import viewsets
from rest_framework.decorators import action

from seed.decorators import ajax_request_class

from seed.lib.superperms.orgs.decorators import has_perm_class

from seed.models.properties import PropertyState, PropertyView
from seed.models.tax_lots import TaxLotState, TaxLotView
from seed.utils.api import api_endpoint_class, OrgMixin
from seed.utils.api_schema import AutoSchemaHelper
from seed.utils.geocode import geocode_buildings


class GeocodeViewSet(viewsets.ViewSet, OrgMixin):

@swagger_auto_schema(
manual_parameters=[AutoSchemaHelper.query_org_id_field()],
request_body=AutoSchemaHelper.schema_factory(
{
'property_view_ids': ['integer'],
'taxlot_view_ids': ['integer'],
},
description='IDs by inventory type for records to be geocoded.'
)
)
@api_endpoint_class
@ajax_request_class
@has_perm_class('can_modify_data')
@action(detail=False, methods=['POST'])
def geocode_by_ids(self, request):
body = dict(request.data)
org_id = self.get_organization(request)
property_view_ids = body.get('property_view_ids')
taxlot_view_ids = body.get('taxlot_view_ids')

if property_view_ids:
property_views = PropertyView.objects.filter(
id__in=property_view_ids,
cycle__organization_id=org_id
)
properties = PropertyState.objects.filter(
id__in=Subquery(property_views.values('state_id'))
)
geocode_buildings(properties)

if taxlot_view_ids:
taxlot_views = TaxLotView.objects.filter(
id__in=taxlot_view_ids,
cycle__organization_id=org_id
)
taxlots = TaxLotState.objects.filter(
id__in=Subquery(taxlot_views.values('state_id'))
)
geocode_buildings(taxlots)

return JsonResponse({'status': 'success'})

@swagger_auto_schema(
manual_parameters=[AutoSchemaHelper.query_org_id_field()],
request_body=AutoSchemaHelper.schema_factory(
{
'property_view_ids': ['integer'],
'taxlot_view_ids': ['integer'],
},
description='IDs by inventory type for records to be used in building a geocoding summary.'
)
)
@api_endpoint_class
@ajax_request_class
@has_perm_class('can_view_data')
@action(detail=False, methods=['POST'])
def confidence_summary(self, request):
body = dict(request.data)
org_id = self.get_organization(request)
property_view_ids = body.get('property_view_ids')
taxlot_view_ids = body.get('taxlot_view_ids')

result = {}

if property_view_ids:
property_views = PropertyView.objects.filter(
id__in=property_view_ids,
cycle__organization_id=org_id
)
result["properties"] = {
'not_geocoded': PropertyState.objects.filter(
id__in=Subquery(property_views.values('state_id')),
geocoding_confidence__isnull=True
).count(),
'high_confidence': PropertyState.objects.filter(
id__in=Subquery(property_views.values('state_id')),
geocoding_confidence__startswith='High'
).count(),
'low_confidence': PropertyState.objects.filter(
id__in=Subquery(property_views.values('state_id')),
geocoding_confidence__startswith='Low'
).count(),
'manual': PropertyState.objects.filter(
id__in=Subquery(property_views.values('state_id')),
geocoding_confidence='Manually geocoded (N/A)'
).count(),
'missing_address_components': PropertyState.objects.filter(
id__in=Subquery(property_views.values('state_id')),
geocoding_confidence='Missing address components (N/A)'
).count(),
}

if taxlot_view_ids:
taxlot_views = TaxLotView.objects.filter(
id__in=taxlot_view_ids,
cycle__organization_id=org_id
)
result["tax_lots"] = {
'not_geocoded': TaxLotState.objects.filter(
id__in=Subquery(taxlot_views.values('state_id')),
geocoding_confidence__isnull=True
).count(),
'high_confidence': TaxLotState.objects.filter(
id__in=Subquery(taxlot_views.values('state_id')),
geocoding_confidence__startswith='High'
).count(),
'low_confidence': TaxLotState.objects.filter(
id__in=Subquery(taxlot_views.values('state_id')),
geocoding_confidence__startswith='Low'
).count(),
'manual': TaxLotState.objects.filter(
id__in=Subquery(taxlot_views.values('state_id')),
geocoding_confidence='Manually geocoded (N/A)'
).count(),
'missing_address_components': TaxLotState.objects.filter(
id__in=Subquery(taxlot_views.values('state_id')),
geocoding_confidence='Missing address components (N/A)'
).count(),
}

return result
136 changes: 136 additions & 0 deletions seed/views/v3/ubid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
# !/usr/bin/env python
# encoding: utf-8

from django.db.models import Subquery
from django.http import JsonResponse

from drf_yasg.utils import swagger_auto_schema

from rest_framework import viewsets
from rest_framework.decorators import action

from seed.decorators import ajax_request_class
from seed.lib.superperms.orgs.decorators import has_perm_class
from seed.models.properties import PropertyState, PropertyView
from seed.models.tax_lots import TaxLotState, TaxLotView
from seed.utils.api import api_endpoint_class, OrgMixin
from seed.utils.api_schema import AutoSchemaHelper
from seed.utils.ubid import decode_unique_ids


class UbidViewSet(viewsets.ViewSet, OrgMixin):
@swagger_auto_schema(
manual_parameters=[AutoSchemaHelper.query_org_id_field()],
request_body=AutoSchemaHelper.schema_factory(
{
'property_view_ids': ['integer'],
'taxlot_view_ids': ['integer'],
},
description='IDs by inventory type for records to have their UBID decoded.'
)
)
@api_endpoint_class
@ajax_request_class
@has_perm_class('can_modify_data')
@action(detail=False, methods=['POST'])
def decode_by_ids(self, request):
body = dict(request.data)
org_id = self.get_organization(request)
property_view_ids = body.get('property_view_ids')
taxlot_view_ids = body.get('taxlot_view_ids')

if property_view_ids:
property_views = PropertyView.objects.filter(
id__in=property_view_ids,
cycle__organization_id=org_id
)
properties = PropertyState.objects.filter(
id__in=Subquery(property_views.values('state_id'))
)
decode_unique_ids(properties)

if taxlot_view_ids:
taxlot_views = TaxLotView.objects.filter(
id__in=taxlot_view_ids,
cycle__organization_id=org_id
)
taxlots = TaxLotState.objects.filter(
id__in=Subquery(taxlot_views.values('state_id'))
)
decode_unique_ids(taxlots)

return JsonResponse({'status': 'success'})

@swagger_auto_schema(
manual_parameters=[AutoSchemaHelper.query_org_id_field()],
request_body=AutoSchemaHelper.schema_factory(
{
'property_view_ids': ['integer'],
'taxlot_view_ids': ['integer'],
},
description='IDs by inventory type for records to be used in building a UBID decoding summary.'
)
)
@ajax_request_class
@has_perm_class('can_view_data')
@action(detail=False, methods=['POST'])
def decode_results(self, request):
body = dict(request.data)
org_id = self.get_organization(request)

ubid_unpopulated = 0
ubid_successfully_decoded = 0
ubid_not_decoded = 0
ulid_unpopulated = 0
ulid_successfully_decoded = 0
ulid_not_decoded = 0
property_view_ids = body.get('property_view_ids')
taxlot_view_ids = body.get('taxlot_view_ids')
if property_view_ids:
property_views = PropertyView.objects.filter(
id__in=property_view_ids,
cycle__organization_id=org_id
)
property_states = PropertyState.objects.filter(id__in=Subquery(property_views.values('state_id')))

ubid_unpopulated = property_states.filter(ubid__isnull=True).count()
ubid_successfully_decoded = property_states.filter(
ubid__isnull=False,
bounding_box__isnull=False,
centroid__isnull=False
).count()
# for ubid_not_decoded, bounding_box could be populated from a GeoJSON import
ubid_not_decoded = property_states.filter(
ubid__isnull=False,
centroid__isnull=True
).count()

if taxlot_view_ids:
taxlot_views = TaxLotView.objects.filter(
id__in=taxlot_view_ids,
cycle__organization_id=org_id
)
taxlot_states = TaxLotState.objects.filter(id__in=Subquery(taxlot_views.values('state_id')))

ulid_unpopulated = taxlot_states.filter(ulid__isnull=True).count()
ulid_successfully_decoded = taxlot_states.filter(
ulid__isnull=False,
bounding_box__isnull=False,
centroid__isnull=False
).count()
# for ulid_not_decoded, bounding_box could be populated from a GeoJSON import
ulid_not_decoded = taxlot_states.filter(
ulid__isnull=False,
centroid__isnull=True
).count()

result = {
"ubid_unpopulated": ubid_unpopulated,
"ubid_successfully_decoded": ubid_successfully_decoded,
"ubid_not_decoded": ubid_not_decoded,
"ulid_unpopulated": ulid_unpopulated,
"ulid_successfully_decoded": ulid_successfully_decoded,
"ulid_not_decoded": ulid_not_decoded,
}

return result

0 comments on commit 9dd637a

Please sign in to comment.