diff --git a/results-tabulation-api/api/ElectionApi.py b/results-tabulation-api/api/ElectionApi.py index 4deae891..e782f3b3 100644 --- a/results-tabulation-api/api/ElectionApi.py +++ b/results-tabulation-api/api/ElectionApi.py @@ -6,7 +6,7 @@ from exception.messages import MESSAGE_CODE_ELECTION_NOT_FOUND from orm.entities.Election.election_helper import get_root_token from orm.entities import Election -from schemas import ElectionSchema as Schema +from schemas import ElectionSchema as Schema, AreaMapSchema from util import RequestBody, get_paginated_query @@ -60,3 +60,18 @@ def create(body): @authorize(required_roles=[ADMIN_ROLE]) def getRootToken(electionId): return get_root_token(electionId=electionId) + + +@authorize(required_roles=ALL_ROLES) +def get_area_map(electionId=None): + election = Election.get_by_id(electionId=electionId) + if election is None: + raise NotFoundException( + message="Election not found (electionId=%d)" % electionId, + code=MESSAGE_CODE_ELECTION_NOT_FOUND + ) + + extended_election = election.get_extended_election() + area_map = extended_election.get_area_map() + + return AreaMapSchema(many=True).dump(area_map).data diff --git a/results-tabulation-api/ext/ExtendedElection/ExtendedElectionParliamentaryElection2020/__init__.py b/results-tabulation-api/ext/ExtendedElection/ExtendedElectionParliamentaryElection2020/__init__.py index 68807164..95077982 100644 --- a/results-tabulation-api/ext/ExtendedElection/ExtendedElectionParliamentaryElection2020/__init__.py +++ b/results-tabulation-api/ext/ExtendedElection/ExtendedElectionParliamentaryElection2020/__init__.py @@ -120,7 +120,8 @@ def get_area_map_query(self): electoral_district.c.areaName.label("electoralDistrictName"), counting_centre.c.areaId.label("countingCentreId"), counting_centre.c.areaName.label("countingCentreName"), - Election.Model.voteType + Election.Model.voteType, + Election.Model.electionId ] query_filter = [ diff --git a/results-tabulation-api/ext/ExtendedElection/ExtendedElectionPresidentialElection2019/__init__.py b/results-tabulation-api/ext/ExtendedElection/ExtendedElectionPresidentialElection2019/__init__.py index ebff251c..660d7a51 100644 --- a/results-tabulation-api/ext/ExtendedElection/ExtendedElectionPresidentialElection2019/__init__.py +++ b/results-tabulation-api/ext/ExtendedElection/ExtendedElectionPresidentialElection2019/__init__.py @@ -107,7 +107,8 @@ def get_area_map_query(self): electoral_district.c.areaName.label("electoralDistrictName"), counting_centre.c.areaId.label("countingCentreId"), counting_centre.c.areaName.label("countingCentreName"), - Election.Model.voteType + Election.Model.voteType, + Election.Model.electionId ] query_filter = [ diff --git a/results-tabulation-api/ext/ExtendedElection/__init__.py b/results-tabulation-api/ext/ExtendedElection/__init__.py index 45a41fd5..302e171b 100644 --- a/results-tabulation-api/ext/ExtendedElection/__init__.py +++ b/results-tabulation-api/ext/ExtendedElection/__init__.py @@ -60,117 +60,12 @@ def get_area_map_for_tally_sheet(self, tally_sheet): return self.get_area_map(area=area) - def get_area_map(self, area, group_by=None, filter=None): - from orm.enums import AreaTypeEnum - + def get_area_map(self): area_map_subquery = self.get_area_map_query().subquery() - column_name_list = [ - "pollingStationId", "pollingStationName", - "pollingDistrictId", "pollingDistrictName", - "countingCentreId", "countingCentreName", - "pollingDivisionId", "pollingDivisionName", - "electoralDistrictId", "electoralDistrictName", - "countryId", "countryName" - ] - column_name_to_column_map = { - "pollingStationId": area_map_subquery.c.pollingStationId, - "pollingStationName": area_map_subquery.c.pollingStationName, - "pollingDistrictId": area_map_subquery.c.pollingDistrictId, - "pollingDistrictName": area_map_subquery.c.pollingDistrictName, - "countingCentreId": area_map_subquery.c.countingCentreId, - "countingCentreName": area_map_subquery.c.countingCentreName, - "pollingDivisionId": area_map_subquery.c.pollingDivisionId, - "pollingDivisionName": area_map_subquery.c.pollingDivisionName, - "electoralDistrictId": area_map_subquery.c.electoralDistrictId, - "electoralDistrictName": area_map_subquery.c.electoralDistrictName, - "countryId": area_map_subquery.c.countryId, - "countryName": area_map_subquery.c.countryName - } - query_args = [] - query_filter = [] - query_group_by = [] - area_and_vote_type_wise_group_by_map = { - AreaTypeEnum.CountingCentre: [ - "countingCentreId", - "countingCentreName", - "pollingDivisionId", - "pollingDivisionName", - "electoralDistrictId", - "electoralDistrictName", - "countryId", - "countryName" - ], - AreaTypeEnum.PollingStation: [ - "pollingDistrictId", - "pollingDistrictName", - "pollingStationId", - "pollingStationName", - "countingCentreId", - "countingCentreName", - "pollingDivisionId", - "pollingDivisionName", - "electoralDistrictId", - "electoralDistrictName", - "countryId", - "countryName" - ], - AreaTypeEnum.PollingDivision: [ - "pollingDivisionId", - "pollingDivisionName", - "electoralDistrictId", - "electoralDistrictName", - "countryId", - "countryName" - ], - AreaTypeEnum.ElectoralDistrict: [ - "electoralDistrictId", - "electoralDistrictName", - "countryId", - "countryName" - ], - AreaTypeEnum.Country: [ - "countryId", - "countryName" - ] - } - - area_and_vote_type_wise_filter_map = { - AreaTypeEnum.PollingStation: [area_map_subquery.c.pollingStationId == area.areaId], - AreaTypeEnum.PollingDistrict: [area_map_subquery.c.pollingDistrictId == area.areaId], - AreaTypeEnum.CountingCentre: [area_map_subquery.c.countingCentreId == area.areaId], - AreaTypeEnum.PollingDivision: [area_map_subquery.c.pollingDivisionId == area.areaId], - AreaTypeEnum.ElectoralDistrict: [area_map_subquery.c.electoralDistrictId == area.areaId], - AreaTypeEnum.Country: [area_map_subquery.c.countryId == area.areaId] - } - - if group_by is None: - if area.areaType in area_and_vote_type_wise_group_by_map: - group_by = area_and_vote_type_wise_group_by_map[area.areaType] - else: - group_by = [] - - for column_name in column_name_list: - column = column_name_to_column_map[column_name] - if column_name in group_by: - query_group_by.append(column) - - # Append the column to query. - query_args.append(column) - else: - query_args.append(bindparam(column_name, None)) - - if filter is None: - if area.areaType in area_and_vote_type_wise_filter_map: - filter = area_and_vote_type_wise_filter_map[area.areaType] - else: - filter = [] - - query_filter = filter - - area_map = db.session.query(*query_args).filter(*query_filter).group_by(*query_group_by).all() - - return area_map + return db.session.query(area_map_subquery).filter( + area_map_subquery.c.electionId.in_(self.election.get_this_and_below_election_ids()) + ) def get_area_map_query(self): @@ -216,7 +111,8 @@ def get_area_map_query(self): polling_station.c.areaName.label("pollingStationName"), counting_centre.c.areaId.label("countingCentreId"), counting_centre.c.areaName.label("countingCentreName"), - Election.Model.voteType + Election.Model.voteType, + Election.Model.electionId ).filter( country__electoral_district.parentAreaId == country.c.areaId, country__electoral_district.childAreaId == electoral_district.c.areaId, diff --git a/results-tabulation-api/schemas/__init__.py b/results-tabulation-api/schemas/__init__.py index 7adbe6f1..521e5aad 100644 --- a/results-tabulation-api/schemas/__init__.py +++ b/results-tabulation-api/schemas/__init__.py @@ -395,7 +395,7 @@ class Meta: "electionId", # "areaId", # "area", - "areaMapList", + # "areaMapList", "latestVersion", "metaDataList", # "workflowInstance", diff --git a/results-tabulation-api/swagger.yml b/results-tabulation-api/swagger.yml index 401493e5..b3474846 100644 --- a/results-tabulation-api/swagger.yml +++ b/results-tabulation-api/swagger.yml @@ -178,6 +178,53 @@ paths: schema: $ref: '#/components/schemas/ApiResponse' + /election/{electionId}/area-map: + get: + tags: + - Election + summary: Get Area Map + operationId: api.ElectionApi.get_area_map + parameters: + - name: electionId + in: path + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: Successful operation. + content: + application/json: + schema: + type: array + items: + type: object + '400': + description: Bad request. + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + '401': + description: Unauthorized. + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + '404': + description: Resource was not found. + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + '500': + description: Unexpected error. + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + /election: get: tags: diff --git a/results-tabulation-ui/src/services/election.provider.js b/results-tabulation-ui/src/services/election.provider.js index 986cd10f..10df937c 100644 --- a/results-tabulation-ui/src/services/election.provider.js +++ b/results-tabulation-ui/src/services/election.provider.js @@ -1,5 +1,6 @@ import React, {useState} from "react"; import { + ENDPOINT_PATH_ELECTION_AREA_MAP_BY_ID, ENDPOINT_PATH_ELECTIONS, ENDPOINT_PATH_ELECTIONS_BY_ID, request @@ -17,8 +18,13 @@ export function ElectionProvider(props) { const saveElectionToState = (election) => { const {electionId, metaDataList = [], parties} = election; - election.metaDataMap = getMetaDataMap(metaDataList); - election.partyMap = getPartyMap(parties); + if (!election.metaDataMap) { + election.metaDataMap = getMetaDataMap(metaDataList); + } + + if (!election.partyMap) { + election.partyMap = getPartyMap(parties); + } // To avoid duplicated election fetches while state update wait state.electionMap[electionId] = {...election}; @@ -96,12 +102,29 @@ export function ElectionProvider(props) { return election; }; + + const getElectionAreaMap = async (electionId) => { + let election = await getElectionById(electionId); + + if (!election.electionAreaMap) { + const electionAreaMap = await request({ + url: ENDPOINT_PATH_ELECTION_AREA_MAP_BY_ID(electionId), + method: 'get', // default, + }); + + saveElectionToState(Object.assign(election, {electionAreaMap})); + } + + return election.electionAreaMap; + }; + return {props.children} diff --git a/results-tabulation-ui/src/services/tabulation-api/index.js b/results-tabulation-ui/src/services/tabulation-api/index.js index 26fd5e8b..3a66e2ed 100644 --- a/results-tabulation-ui/src/services/tabulation-api/index.js +++ b/results-tabulation-ui/src/services/tabulation-api/index.js @@ -4,6 +4,7 @@ import {getAccessToken} from "../../auth"; export const ENDPOINT_PATH_ELECTIONS = () => "/election"; export const ENDPOINT_PATH_ELECTIONS_BY_ID = (electionId) => `/election/${electionId}`; +export const ENDPOINT_PATH_ELECTION_AREA_MAP_BY_ID = (electionId) => `/election/${electionId}/area-map`; export const ENDPOINT_PATH_AREAS = () => "/area"; export const ENDPOINT_PATH_AREAS_BY_ID = (areaId) => `/area/${areaId}`; export const ENDPOINT_PATH_TALLY_SHEETS = () => "/tally-sheet"; diff --git a/results-tabulation-ui/src/services/tally-sheet.provider.js b/results-tabulation-ui/src/services/tally-sheet.provider.js index 32b29d6a..093e2d5c 100644 --- a/results-tabulation-ui/src/services/tally-sheet.provider.js +++ b/results-tabulation-ui/src/services/tally-sheet.provider.js @@ -31,6 +31,7 @@ export function TallySheetProvider(props) { tallySheet.election = await electionContext.getElectionById(tallySheet.electionId); tallySheet.workflowInstance.actions = tallySheet.workflowInstanceActions; tallySheet.area = tallySheet.submission.area; + tallySheet.areaMapList = await electionContext.getElectionAreaMap(tallySheet.electionId); // TODO fetch actions and area maps