diff --git a/services/api.py b/services/api.py index 0eb0a1d80..5fd368141 100644 --- a/services/api.py +++ b/services/api.py @@ -200,6 +200,32 @@ def root_service_nodes(services): ) +def resolve_divisions(divisions): + div_list = [] + for division_path in divisions: + if division_path.startswith("ocd-division"): + muni_ocd_id = division_path + else: + ocd_id_base = r"[\w0-9~_.-]+" + match_re = r"(%s)/([\w_-]+):(%s)" % (ocd_id_base, ocd_id_base) + m = re.match(match_re, division_path, re.U) + if not m: + raise ParseError("'division' must be of form 'muni/type:id'") + + arr = division_path.split("/") + muni_ocd_id = make_muni_ocd_id(arr.pop(0), "/".join(arr)) + try: + div = AdministrativeDivision.objects.select_related("geometry").get( + ocd_id=muni_ocd_id + ) + except AdministrativeDivision.DoesNotExist: + raise ParseError( + "administrative division with OCD ID '%s' not found" % muni_ocd_id + ) + div_list.append(div) + return div_list + + class JSONAPISerializer(serializers.ModelSerializer): def __init__(self, *args, **kwargs): super(JSONAPISerializer, self).__init__(*args, **kwargs) @@ -290,7 +316,13 @@ def root_service_nodes(self, obj): class Meta: model = ServiceNode - fields = "__all__" + exclude = ( + "search_column_fi", + "search_column_sv", + "search_column_en", + "syllables_fi", + "service_reference", + ) class ServiceSerializer(TranslatedModelSerializer, JSONAPISerializer): @@ -305,6 +337,16 @@ def to_representation(self, obj): total += unit_count.count ret["unit_count"]["municipality"][div_name] = unit_count.count ret["unit_count"]["total"] = total + + divisions = self.context.get("divisions", []) + include_fields = self.context.get("include", []) + if "unit_count_per_division" in include_fields and divisions: + ret["unit_count_per_division"] = {} + div_list = resolve_divisions(divisions) + for div in div_list: + ret["unit_count_per_division"][div.name] = Unit.objects.filter( + services=obj.pk, location__within=div.geometry.boundary + ).count() return ret class Meta: @@ -520,6 +562,13 @@ class ServiceViewSet(JSONAPIViewSet, viewsets.ReadOnlyModelViewSet): queryset = Service.objects.all() serializer_class = ServiceSerializer + def get_serializer_context(self): + ret = super(ServiceViewSet, self).get_serializer_context() + query_params = self.request.query_params + division = query_params.get("division", "") + ret["divisions"] = [x.strip() for x in division.split(",") if x] + return ret + def get_queryset(self): queryset = ( super(ServiceViewSet, self) @@ -710,6 +759,7 @@ class Meta: "accessibility_property_hash", "identifier_hash", "public", + "syllables_fi", "search_column_fi", "search_column_sv", "search_column_en", @@ -906,30 +956,7 @@ def validate_service_node_ids(service_node_ids): # Divisions can be specified with form: # division=helsinki/kaupunginosa:kallio,vantaa/äänestysalue:5 d_list = filters["division"].lower().split(",") - div_list = [] - for division_path in d_list: - if division_path.startswith("ocd-division"): - muni_ocd_id = division_path - else: - ocd_id_base = r"[\w0-9~_.-]+" - match_re = r"(%s)/([\w_-]+):(%s)" % (ocd_id_base, ocd_id_base) - m = re.match(match_re, division_path, re.U) - if not m: - raise ParseError("'division' must be of form 'muni/type:id'") - - arr = division_path.split("/") - muni_ocd_id = make_muni_ocd_id(arr.pop(0), "/".join(arr)) - try: - div = AdministrativeDivision.objects.select_related("geometry").get( - ocd_id=muni_ocd_id - ) - except AdministrativeDivision.DoesNotExist: - raise ParseError( - "administrative division with OCD ID '%s' not found" - % muni_ocd_id - ) - div_list.append(div) - + div_list = resolve_divisions(d_list) if div_list: mp = div_list.pop(0).geometry.boundary for div in div_list: diff --git a/specification.swagger.yaml b/specification.swagger.yaml index 6f3151ef8..6af3edfc1 100644 --- a/specification.swagger.yaml +++ b/specification.swagger.yaml @@ -300,7 +300,25 @@ paths: schema: type: integer example: 811 - - $ref: "#/components/parameters/include_param" + - name: include + in: query + style: form + explode: false + description: "Enable count service by division with: "include=unit_count_per_division"" + type: string + - name: division + in: query + style: form + explode: false + description: A comma-separated list of administrative divisions to be used when unit + counting by service and division. Use either full division ids or shorthands of the form + muni/type\:id + required: false + schema: + type: array + items: + type: string + example: ocd-division/country:fi/kunta:raisio - $ref: "#/components/parameters/only_param" - $ref: "#/components/parameters/geometry_param" /service/: @@ -313,7 +331,7 @@ paths: - service parameters: - $ref: "#/components/parameters/page_param" - - $ref: "#/components/parameters/pagesize_param" + - $ref: "#/components/parameters/pagesize_param" - name: id in: query style: form @@ -324,6 +342,7 @@ paths: items: type: integer example: 811,663 + responses: "200": description: List of services, paginated