From e5f5f26cccac1d83bf3fe15409df6a83ef9da5af Mon Sep 17 00:00:00 2001 From: Michael Olund Date: Wed, 18 Nov 2020 17:14:04 -0800 Subject: [PATCH] DIV-1015 - Get Court Locations from API --- .../apps/core/tests/test_efiling_packaging.py | 9 +- .../core/tests/test_efiling_submission.py | 2 +- edivorce/apps/core/utils/court_locations.py | 79 ++++++++ edivorce/apps/core/utils/efiling_hub_api.py | 48 ++--- edivorce/apps/core/utils/efiling_packaging.py | 19 +- .../apps/core/utils/efiling_submission.py | 40 +++- .../apps/core/utils/question_step_mapping.py | 184 ------------------ edivorce/apps/core/views/efiling.py | 5 +- edivorce/apps/core/views/main.py | 5 +- edivorce/settings/base.py | 5 + 10 files changed, 155 insertions(+), 241 deletions(-) create mode 100644 edivorce/apps/core/utils/court_locations.py diff --git a/edivorce/apps/core/tests/test_efiling_packaging.py b/edivorce/apps/core/tests/test_efiling_packaging.py index 2f0f45ab..76f77c41 100644 --- a/edivorce/apps/core/tests/test_efiling_packaging.py +++ b/edivorce/apps/core/tests/test_efiling_packaging.py @@ -17,7 +17,8 @@ class EFilingPackagingTests(TransactionTestCase): middleware.process_request(self.request) self.request.session.save() - self.packaging = EFilingPackaging(initial_filing=True) + self.packaging = EFilingPackaging(initial_filing=True, + court_locations={"Vancouver": {"location_id": "6011"}}) def test_format_package(self): files = [] @@ -49,18 +50,18 @@ class EFilingPackagingTests(TransactionTestCase): responses = { "court_registry_for_filing": "Vancouver" } - location = self.packaging._get_location(responses) + location = self.packaging._get_location(None, responses) self.assertEqual(location, '6011') def test_get_location_fail(self): responses = { "court_registry_for_filing": "Tokyo" } - location = self.packaging._get_location(responses) + location = self.packaging._get_location(None, responses) self.assertEqual(location, '0000') responses = {} - location = self.packaging._get_location(responses) + location = self.packaging._get_location(None, responses) self.assertEqual(location, '0000') def test_get_json_data_signing_location(self): diff --git a/edivorce/apps/core/tests/test_efiling_submission.py b/edivorce/apps/core/tests/test_efiling_submission.py index c86832f3..1ff58da2 100644 --- a/edivorce/apps/core/tests/test_efiling_submission.py +++ b/edivorce/apps/core/tests/test_efiling_submission.py @@ -46,8 +46,8 @@ class EFilingSubmissionTests(TransactionTestCase): middleware.process_request(self.request) self.request.session.save() - self.hub = EFilingSubmission(initial_filing=True) self.packaging = EFilingPackaging(initial_filing=True) + self.hub = EFilingSubmission(initial_filing=True, packaging=self.packaging) def _mock_response(self, status=200, text="Text", json_data=None, raise_for_status=None): mock_resp = mock.Mock() diff --git a/edivorce/apps/core/utils/court_locations.py b/edivorce/apps/core/utils/court_locations.py new file mode 100644 index 00000000..204aeadd --- /dev/null +++ b/edivorce/apps/core/utils/court_locations.py @@ -0,0 +1,79 @@ +import json +import logging +import requests +import uuid + +from django.conf import settings +from django.core.cache import cache +from django.core.exceptions import PermissionDenied + +from .efiling_hub_api import EFilingHubApi + +logger = logging.getLogger(__name__) + + +class CourtLocations(EFilingHubApi): + + def __init__(self): + self.access_token = None + self.refresh_token = None + EFilingHubApi.__init__(self) + + def _get_api(self, request, url, bceid_guid, headers={}): + # make sure we have an access token + if not self.access_token: + if not self._get_token(request): + raise Exception('EFH - Unable to get API Token') + + headers = self._set_headers(headers, bceid_guid, self.access_token) + response = requests.get(url, headers=headers) + logging.debug(f'EFH - Get Locations {response.status_code} {response.text}') + + if response.status_code == 401: + # not authorized .. try refreshing token + if self._refresh_token(request): + headers = self._set_headers(headers, bceid_guid, self.access_token) + response = requests.get(url, headers=headers) + logging.debug(f'EFH - Get Locations Retry {response.status_code} {response.text}') + + return response + + def courts(self, request): + + if cache.get('courts'): + return cache.get('courts') + + bceid_guid = self._get_bceid(request) + + # if bceid_guid is None .. we basically have an anonymous user so raise an error + if bceid_guid is None: + raise PermissionDenied() + + url = f'{self.api_base_url}/courts?courtLevel=S' + print('DEBUG: ' + url) + + response = self._get_api(request, url, bceid_guid, headers={}) + + if response.status_code == 200: + cso_locations = json.loads(response.text) + locations = {} + + for location in cso_locations['courts']: + city = location['address']['cityName'] + locations[city] = { + 'address_1': location['address']['addressLine1'], + 'address_2': location['address']['addressLine2'], + 'address_3': location['address']['addressLine3'], + 'postal': location['address']['postalCode'], + 'location_id': location['identifierCode'] + } + + cache.set('courts', locations) + + return locations + + if response.status_code == 401: + print(response.headers.get('WWW-Authenticate', '')) + return {"error": {"status_code": "401", "text": "authentication failed"}} + + return {"error": {"status_code": str(response.status_code), "text": response.text}} diff --git a/edivorce/apps/core/utils/efiling_hub_api.py b/edivorce/apps/core/utils/efiling_hub_api.py index 7cd2c312..83455575 100644 --- a/edivorce/apps/core/utils/efiling_hub_api.py +++ b/edivorce/apps/core/utils/efiling_hub_api.py @@ -6,8 +6,6 @@ import uuid from django.conf import settings from django.core.exceptions import PermissionDenied -from .efiling_packaging import EFilingPackaging - logger = logging.getLogger(__name__) @@ -65,38 +63,6 @@ class EFilingHubApi: return True return False - def _get_api(self, request, url, bceid_guid, headers={}, data=None, transaction_id=None, files=None): - # make sure we have an access token - if not self.access_token: - if not self._get_token(request): - raise Exception('EFH - Unable to get API Token') - - headers.update({ - 'X-Transaction-Id': transaction_id, - 'X-User-Id': bceid_guid, - 'Authorization': f'Bearer {self.access_token}' - }) - - if not data: - data = {} - - response = requests.post(url, headers=headers, data=data, files=files) - logging.debug(f'EFH - Get API {response.status_code} {response.text}') - - if response.status_code == 401: - # not authorized .. try refreshing token - if self._refresh_token(request): - headers.update({ - 'X-Transaction-Id': transaction_id, - 'X-User-Id': bceid_guid, - 'Authorization': f'Bearer {self.access_token}' - }) - - response = requests.post(url, headers=headers, data=data, files=files) - logging.debug(f'EFH - Get API Retry {response.status_code} {response.text}') - - return response - def _get_bceid(self, request): def _get_raw_bceid(request): @@ -112,3 +78,17 @@ class EFilingHubApi: if guid: return str(uuid.UUID(guid)) return guid + + def _set_headers(self, headers, bceid_guid, access_token, transaction_id=None): + if transaction_id: + headers.update({ + 'X-User-Id': bceid_guid, + 'Authorization': f'Bearer {self.access_token}', + 'X-Transaction-Id': transaction_id + }) + else: + headers.update({ + 'X-User-Id': bceid_guid, + 'Authorization': f'Bearer {self.access_token}' + }) + return headers diff --git a/edivorce/apps/core/utils/efiling_packaging.py b/edivorce/apps/core/utils/efiling_packaging.py index 539f32b2..9b32c5c3 100644 --- a/edivorce/apps/core/utils/efiling_packaging.py +++ b/edivorce/apps/core/utils/efiling_packaging.py @@ -7,9 +7,9 @@ import re from django.conf import settings from django.urls import reverse -from edivorce.apps.core.models import Document -from edivorce.apps.core.utils.question_step_mapping import list_of_registries -from edivorce.apps.core.views.pdf import images_to_pdf, pdf_form +from ..models import Document +from ..views.pdf import images_to_pdf, pdf_form +from .court_locations import CourtLocations logger = logging.getLogger(__name__) @@ -102,13 +102,14 @@ NJF_JSON_FORMAT = { class EFilingPackaging: - def __init__(self, initial_filing): + def __init__(self, initial_filing, court_locations=None): self.initial_filing = initial_filing + self.court_locations = court_locations def format_package(self, request, responses, files, documents): package = PACKAGE_FORMAT.copy() package['filingPackage']['documents'] = documents - package['filingPackage']['court']['location'] = self._get_location(responses) + package['filingPackage']['court']['location'] = self._get_location(request, responses) package['filingPackage']['parties'] = self._get_parties(responses) file_number = self._get_file_number(responses) if file_number: @@ -312,10 +313,12 @@ class EFilingPackaging: return parties - def _get_location(self, responses): + def _get_location(self, request, responses): location_name = responses.get('court_registry_for_filing', '') - return list_of_registries.get(location_name, - {'location_id': '0000'}).get('location_id') + if not self.court_locations: + self.court_locations = CourtLocations().courts(request) + return self.court_locations.get(location_name, + {'location_id': '0000'}).get('location_id') def _get_file_number(self, responses): if not self.initial_filing: diff --git a/edivorce/apps/core/utils/efiling_submission.py b/edivorce/apps/core/utils/efiling_submission.py index 23c59997..610ffc20 100644 --- a/edivorce/apps/core/utils/efiling_submission.py +++ b/edivorce/apps/core/utils/efiling_submission.py @@ -6,7 +6,6 @@ import uuid from django.conf import settings from django.core.exceptions import PermissionDenied -from .efiling_packaging import EFilingPackaging from .efiling_hub_api import EFilingHubApi logger = logging.getLogger(__name__) @@ -14,9 +13,9 @@ logger = logging.getLogger(__name__) class EFilingSubmission(EFilingHubApi): - def __init__(self, initial_filing): + def __init__(self, initial_filing, packaging): self.initial_filing = initial_filing - self.packaging = EFilingPackaging(initial_filing) + self.packaging = packaging self.submission_id = None self.access_token = None self.refresh_token = None @@ -34,6 +33,30 @@ class EFilingSubmission(EFilingHubApi): request.session['transaction_id'] = guid return guid + def _get_api(self, request, url, bceid_guid, headers={}, data=None, transaction_id=None, files=None): + # make sure we have an access token + if not self.access_token: + if not self._get_token(request): + raise Exception('EFH - Unable to get API Token') + + headers = self._set_headers(headers, bceid_guid, self.access_token, transaction_id) + + if not data: + data = {} + + response = requests.post(url, headers=headers, data=data, files=files) + logging.debug(f'EFH - Get API {response.status_code} {response.text}') + + if response.status_code == 401: + # not authorized .. try refreshing token + if self._refresh_token(request): + headers = self._set_headers(headers, bceid_guid, self.access_token, transaction_id) + + response = requests.post(url, headers=headers, data=data, files=files) + logging.debug(f'EFH - Get API Retry {response.status_code} {response.text}') + + return response + def upload(self, request, responses, files, documents=None, parties=None): """ Does an initial upload of documents and gets the generated eFiling Hub url. @@ -55,10 +78,15 @@ class EFilingSubmission(EFilingHubApi): url = f'{self.api_base_url}/submission/documents' print('DEBUG: ' + url) try: - response = self._get_api(request, url, transaction_id, - bceid_guid, headers={}, files=files) + response = self._get_api(request, url, bceid_guid, headers={}, + transaction_id=transaction_id, files=files) except: - return settings.FORCE_SCRIPT_NAME + "dashboard/initial_filing?no_connection=1", None + if self.initial_filing: + error_route = 'initial_filing' + else: + error_route = 'final_filing' + + return settings.FORCE_SCRIPT_NAME + f"dashboard/{error_route}?no_connection=1", None if response.status_code == 200: response = json.loads(response.text) diff --git a/edivorce/apps/core/utils/question_step_mapping.py b/edivorce/apps/core/utils/question_step_mapping.py index 74a83d5d..e27fdf23 100644 --- a/edivorce/apps/core/utils/question_step_mapping.py +++ b/edivorce/apps/core/utils/question_step_mapping.py @@ -310,187 +310,3 @@ page_step_mapping = { 'location': 'filing_locations', 'signing_filing': 'signing_filing', } - -""" List of court registries """ -list_of_registries = { - 'Abbotsford': { - 'address_1': '32203 South Fraser Way', - 'address_2': '', - 'postal': 'V2T 1W6', - 'location_id': '3561' - }, - 'Campbell River': { - 'address_1': '500 - 13th Avenue', - 'address_2': '', - 'postal': 'V9W 6P1', - 'location_id': '1031' - }, - 'Chilliwack': { - 'address_1': '46085 Yale Road', - 'address_2': '', - 'postal': 'V2P 2L8', - 'location_id': '3521' - }, - 'Courtenay': { - 'address_1': 'Room 100', - 'address_2': '420 Cumberland Road', - 'postal': 'V9N 2C4', - 'location_id': '1041' - }, - 'Cranbrook': { - 'address_1': 'Room 147', - 'address_2': '102 - 11th Avenue South', - 'postal': 'V1C 2P3', - 'location_id': '4711' - }, - 'Dawson Creek': { - 'address_1': '1201 - 103rd Avenue', - 'address_2': '', - 'postal': 'V1G 4J2', - 'location_id': '5731' - }, - 'Duncan': { - 'address_1': '238 Government Street', - 'address_2': '', - 'postal': 'V9L 1A5', - 'location_id': '1051' - }, - 'Fort Nelson': { - 'address_1': 'Bag 1000', - 'address_2': '4604 Sunset Drive', - 'postal': 'V0C 1R0', - 'location_id': '5751' - }, - 'Fort St. John': { - 'address_1': '10600 - 100 Street', - 'address_2': '', - 'postal': 'V1J 4L6', - 'location_id': '5771' - }, - 'Golden': { - 'address_1': '837 Park Drive', - 'address_2': '', - 'postal': 'V0A 1H0', - 'location_id': '4741' - }, - 'Kamloops': { - 'address_1': '223 - 455 Columbia Street', - 'address_2': '', - 'postal': 'V2C 6K4', - 'location_id': '4781' - }, - 'Kelowna': { - 'address_1': '1355 Water Street', - 'address_2': '', - 'postal': 'V1Y 9R3', - 'location_id': '4801' - }, - 'Nanaimo': { - 'address_1': '35 Front Street', - 'address_2': '', - 'postal': 'V9R 5J1', - 'location_id': '1091' - }, - 'Nelson': { - 'address_1': '320 Ward Street', - 'address_2': '', - 'postal': 'V1L 1S6', - 'location_id': '4871' - }, - 'New Westminster': { - 'address_1': 'Begbie Square', - 'address_2': '651 Carnarvon Street', - 'postal': 'V3M 1C9', - 'location_id': '3581' - }, - 'Penticton': { - 'address_1': '100 Main Street', - 'address_2': '', - 'postal': 'V2A 5A5', - 'location_id': '4891' - }, - 'Port Alberni': { - 'address_1': '2999 - 4th Avenue', - 'address_2': '', - 'postal': 'V9Y 8A5', - 'location_id': '1121' - }, - 'Powell River': { - 'address_1': '103 - 6953 Alberni Street', - 'address_2': '', - 'postal': 'V8A 2B8', - 'location_id': '1145' - }, - 'Prince George': { - 'address_1': 'J.O. Wilson Square', - 'address_2': '250 George Street', - 'postal': 'V2L 5S2', - 'location_id': '5891' - }, - 'Prince Rupert': { - 'address_1': '100 Market Place', - 'address_2': '', - 'postal': 'V8J 1B8', - 'location_id': '5901' - }, - 'Quesnel': { - 'address_1': '305 - 350 Barlow Avenue', - 'address_2': '', - 'postal': 'V2J 2C1', - 'location_id': '5921' - }, - 'Revelstoke': { - 'address_1': '1123 West 2nd Street', - 'address_2': '', - 'postal': 'V0E 2S0', - 'location_id': '4911' - }, - 'Rossland': { - 'address_1': 'P.O. Box 639', - 'address_2': '2288 Columbia Avenue', - 'postal': 'V0G 1Y0', - 'location_id': '4921' - }, - 'Salmon Arm': { - 'address_1': '550 - 2nd Avenue NE', - 'address_2': 'PO Box 100, Station Main', - 'postal': 'V1E 4S4', - 'location_id': '4941' - }, - 'Smithers': { - 'address_1': 'No. 40, Bag 5000', - 'address_2': '3793 Alfred Avenue', - 'postal': 'V0J 2N0', - 'location_id': '5931' - }, - 'Terrace': { - 'address_1': '3408 Kalum Street', - 'address_2': '', - 'postal': 'V8G 2N6', - 'location_id': '5951' - }, - 'Vancouver': { - 'address_1': '800 Smithe Street', - 'address_2': '', - 'postal': 'V6Z 2E1', - 'location_id': '6011' - }, - 'Vernon': { - 'address_1': '3001 - 27th Street', - 'address_2': '', - 'postal': 'V1T 4W5', - 'location_id': '4971' - }, - 'Victoria': { - 'address_1': '850 Burdett Avenue', - 'address_2': '', - 'postal': 'V8W 1B4', - 'location_id': '1201' - }, - 'Williams Lake': { - 'address_1': '540 Borland Street', - 'address_2': '', - 'postal': 'V2G lR8', - 'location_id': '5971' - } -} diff --git a/edivorce/apps/core/views/efiling.py b/edivorce/apps/core/views/efiling.py index ba08fc72..5e397012 100644 --- a/edivorce/apps/core/views/efiling.py +++ b/edivorce/apps/core/views/efiling.py @@ -13,6 +13,7 @@ from ..models import Document, UserResponse from ..utils.efiling_documents import forms_to_file from ..utils.efiling_packaging import EFilingPackaging from ..utils.efiling_submission import EFilingSubmission +from ..utils.court_locations import CourtLocations from ..utils.user_response import get_data_for_user MAX_MEGABYTES = 10 @@ -109,8 +110,8 @@ def _validate_and_submit_documents(request, responses, initial=False): def _package_and_submit(request, uploaded, generated, responses, initial): """ Build the efiling package and submit it to the efiling hub """ - hub = EFilingSubmission(initial_filing=initial) - packaging = EFilingPackaging(initial_filing=initial) + packaging = EFilingPackaging(initial) + hub = EFilingSubmission(initial, packaging) post_files, documents = packaging.get_files(request, responses, uploaded, generated) redirect_url, msg = hub.upload(request, responses, post_files, documents) return msg, redirect_url diff --git a/edivorce/apps/core/views/main.py b/edivorce/apps/core/views/main.py index 3478f10e..b48094d5 100644 --- a/edivorce/apps/core/views/main.py +++ b/edivorce/apps/core/views/main.py @@ -8,7 +8,7 @@ from django.contrib.auth.decorators import login_required from edivorce.apps.core.utils.derived import get_derived_data from ..decorators import intercept, prequal_completed from ..utils.efiling_documents import forms_to_file -from ..utils.question_step_mapping import list_of_registries +from ..utils.court_locations import CourtLocations from ..utils.step_completeness import get_error_dict, get_missed_question_keys, get_step_completeness, is_complete, get_formatted_incomplete_list from ..utils.template_step_order import template_step_order from ..utils.user_response import ( @@ -232,7 +232,8 @@ def question(request, step, sub_step=None): responses_dict['active_page'] = step # If page is filing location page, add registries dictionary for list of court registries if step == "location": - responses_dict['registries'] = sorted(list_of_registries.keys()) + courts = CourtLocations().courts(request) + responses_dict['registries'] = sorted(courts.keys()) responses_dict['sub_step'] = sub_step responses_dict['derived'] = derived diff --git a/edivorce/settings/base.py b/edivorce/settings/base.py index d67035c4..750ed2b9 100644 --- a/edivorce/settings/base.py +++ b/edivorce/settings/base.py @@ -109,6 +109,11 @@ REST_FRAMEWORK = { ] } +CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache' + } +} LOGGING = { 'version': 1,