From 1c3135e0e62544733039b494f751fc4f9cbef4c9 Mon Sep 17 00:00:00 2001 From: juuso-j Date: Tue, 18 Jul 2023 14:48:25 +0300 Subject: [PATCH 1/3] Count service units by division --- services/api.py | 77 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 25 deletions(-) diff --git a/services/api.py b/services/api.py index d37244eba..4148ad780 100644 --- a/services/api.py +++ b/services/api.py @@ -210,6 +210,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) @@ -300,7 +326,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): @@ -315,6 +347,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: @@ -530,6 +572,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) @@ -720,6 +769,7 @@ class Meta: "accessibility_property_hash", "identifier_hash", "public", + "syllables_fi", "search_column_fi", "search_column_sv", "search_column_en", @@ -916,30 +966,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: From b2c0e55eaa1f0ca4eacc97f6fe3f5b51aa004b39 Mon Sep 17 00:00:00 2001 From: juuso-j Date: Tue, 18 Jul 2023 15:04:32 +0300 Subject: [PATCH 2/3] Add include and division params to /service endpoint --- specification.swagger.yaml | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) 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 From 584a4367089d1f6bf40c768dfa98b569f56c56cc Mon Sep 17 00:00:00 2001 From: Juuso Jokiniemi <68938778+juuso-j@users.noreply.github.com> Date: Tue, 18 Jul 2023 15:36:11 +0300 Subject: [PATCH 3/3] Change action to v3 --- .github/workflows/run-tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index c72649628..feeb729fd 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -19,9 +19,9 @@ jobs: LAM_COUNTER_API_BASE_URL: https://tie.digitraffic.fi/api/tms/v1/history steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python 3.10.0 - uses: actions/setup-python@v2 + uses: actions/setup-python@v3 with: python-version: 3.10.0 - name: Install required Ubuntu packages @@ -50,7 +50,7 @@ jobs: pip install coverage coverage report -m - name: Upload Coverage to Codecov - uses: codecov/codecov-action@v2 + uses: codecov/codecov-action@v3 # Majority of the tests require database services: # Label used to access the service container