diff --git a/edivorce/apps/core/efilinghub.py b/edivorce/apps/core/efilinghub.py index 931f372d..6415a929 100644 --- a/edivorce/apps/core/efilinghub.py +++ b/edivorce/apps/core/efilinghub.py @@ -1,12 +1,18 @@ +import hashlib import json -import requests import logging +import re +import requests import uuid from django.conf import settings from django.core.exceptions import PermissionDenied 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 + logger = logging.getLogger(__name__) PACKAGE_DOCUMENT_FORMAT = { @@ -49,7 +55,7 @@ PACKAGE_FORMAT = { class EFilingHub: - def __init__(self): + def __init__(self, initial_filing): self.client_id = settings.EFILING_HUB_CLIENT_ID self.client_secret = settings.EFILING_HUB_CLIENT_SECRET self.token_base_url = settings.EFILING_HUB_TOKEN_BASE_URL @@ -57,6 +63,7 @@ class EFilingHub: self.api_base_url = settings.EFILING_HUB_API_BASE_URL self.submission_id = None + self.initial_filing = initial_filing def _get_token(self, request): payload = f'client_id={self.client_id}&grant_type=client_credentials&client_secret={self.client_secret}' @@ -177,14 +184,83 @@ class EFilingHub: reverse('dashboard_nav', args=['check_with_registry'])) package['navigationUrls']['error'] = request.build_absolute_uri( reverse('dashboard_nav', args=['check_with_registry'])) - package['navigationUrls']['cancel'] = request.build_absolute_uri( - reverse('dashboard_nav', args=['check_with_registry'])) + if self.initial_filing: + package['navigationUrls']['cancel'] = request.build_absolute_uri( + reverse('dashboard_nav', args=['initial_filing'])) + else: + package['navigationUrls']['cancel'] = request.build_absolute_uri( + reverse('dashboard_nav', args=['final_filing'])) return package + def _get_data(self, request, responses, uploaded, generated): + + post_files = [] + documents = [] + + for form in generated: + document = self._get_document(form['doc_type'], 0) + pdf_response = pdf_form(request, str(form['form_number'])) + document['md5'] = hashlib.md5(pdf_response.content).hexdigest() + post_files.append(('files', (document['name'], pdf_response.content))) + documents.append(document) + + for form in uploaded: + party_code = form['party_code'] + doc_type = form['doc_type'] + pdf_response = images_to_pdf(request, doc_type, party_code) + if pdf_response.status_code == 200: + document = self._get_document(doc_type, party_code) + document['md5'] = hashlib.md5(pdf_response.content).hexdigest() + post_files.append(('files', (document['name'], pdf_response.content))) + documents.append(document) + + # generate the list of parties to send to eFiling Hub + parties = [] + + party1 = PACKAGE_PARTY_FORMAT.copy() + party1['firstName'] = responses.get('given_name_1_you', '').strip() + party1['middleName'] = (responses.get('given_name_2_you', '') + + ' ' + + responses.get('given_name_3_you', '')).strip() + party1['lastName'] = responses.get('last_name_you', '').strip() + parties.append(party1) + + party2 = PACKAGE_PARTY_FORMAT.copy() + party2['firstName'] = responses.get('given_name_1_spouse', '').strip() + party2['middleName'] = (responses.get('given_name_2_spouse', '') + + ' ' + + responses.get('given_name_3_spouse', '')).strip() + party2['lastName'] = responses.get('last_name_spouse', '').strip() + parties.append(party2) + + location_name = responses.get('court_registry_for_filing', '') + location = list_of_registries.get(location_name, '0000') + + package_data = self._format_package(request, post_files, documents, parties, location) + + return package_data, post_files + + def _get_document(self, doc_type, party_code): + document = PACKAGE_DOCUMENT_FORMAT.copy() + filename = self._get_filename(doc_type, party_code) + document['name'] = filename + document['type'] = doc_type + return document + + def _get_filename(self, doc_type, party_code): + form_name = Document.form_types[doc_type] + slug = re.sub('[^0-9a-zA-Z]+', '-', form_name).strip('-') + if party_code == 0: + return slug + ".pdf" + elif party_code == 1: + return slug + "--Claimant1.pdf" + else: + return slug + "--Claimant2.pdf" + # -- EFILING HUB INTERFACE -- - def upload(self, request, files, documents=None, parties=None, location=None): + def upload(self, request, responses, uploaded, generated): """ Does an initial upload of documents and gets the generated eFiling Hub url. :param parties: @@ -202,6 +278,8 @@ class EFilingHub: if bce_id is None: raise PermissionDenied() + package_data, files = self._get_data(request, responses, uploaded, generated) + url = f'{self.api_base_url}/submission/documents' response = self._get_api(request, url, transaction_id, bce_id, headers={}, files=files) if response.status_code == 200: @@ -212,7 +290,6 @@ class EFilingHub: headers = { 'Content-Type': 'application/json' } - package_data = self._format_package(request, files, documents, parties, location) url = f"{self.api_base_url}/submission/{response['submissionId']}/generateUrl" response = self._get_api(request, url, transaction_id, bce_id, headers=headers, data=json.dumps(package_data)) diff --git a/edivorce/apps/core/middleware/keycloak.py b/edivorce/apps/core/middleware/keycloak.py index b25187ef..a4260536 100644 --- a/edivorce/apps/core/middleware/keycloak.py +++ b/edivorce/apps/core/middleware/keycloak.py @@ -2,8 +2,6 @@ from django.conf import settings from mozilla_django_oidc.auth import OIDCAuthenticationBackend from mozilla_django_oidc.utils import absolutify -from ..models import BceidUser - class EDivorceKeycloakBackend(OIDCAuthenticationBackend): @@ -35,7 +33,7 @@ class EDivorceKeycloakBackend(OIDCAuthenticationBackend): user.user_guid = claims.get('universal-id', '') user.save() - self.request.session['bcgov_userguid'] = user.user_guid + self.request.session['bcgov_userguid'] = user.user_guid return user @@ -47,6 +45,8 @@ class EDivorceKeycloakBackend(OIDCAuthenticationBackend): def keycloak_logout(request): + request.session.flush() + redirect_uri = absolutify(request, settings.FORCE_SCRIPT_NAME) return f'{settings.KEYCLOAK_LOGOUT}?redirect_uri={redirect_uri}' diff --git a/edivorce/apps/core/tests/test_efiling_hub.py b/edivorce/apps/core/tests/test_efiling_hub.py index 79e3380b..6bf11565 100644 --- a/edivorce/apps/core/tests/test_efiling_hub.py +++ b/edivorce/apps/core/tests/test_efiling_hub.py @@ -47,7 +47,7 @@ class EFilingHubTests(TransactionTestCase): middleware.process_request(self.request) self.request.session.save() - self.hub = EFilingHub() + self.hub = EFilingHub(initial_filing=True) 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/urls.py b/edivorce/apps/core/urls.py index ce578fac..fb749177 100644 --- a/edivorce/apps/core/urls.py +++ b/edivorce/apps/core/urls.py @@ -1,7 +1,7 @@ from django.conf.urls import url from django.urls import path -from .views import main, system, pdf, api +from .views import main, system, pdf, api, efiling urlpatterns = [ # url(r'^guide$', styleguide.guide), @@ -13,17 +13,16 @@ urlpatterns = [ # we add an extra 'x' to the file extension so the siteminder proxy doesn't treat it as an image path('api/documents///x//', api.DocumentView.as_view(), name='document'), - url(r'^signin$', main.signin, name="signin"), + url(r'^signin$', main.after_login, name="signin"), url(r'^register$', main.register, name="register"), url(r'^register_sc$', main.register_sc, name="register_sc"), - url(r'^logout$', main.logout, name="logout"), url(r'^overview$', main.overview, name="overview"), url(r'^success$', main.success, name="success"), url(r'^incomplete$', main.incomplete, name="incomplete"), url(r'^intercept$', main.intercept_page, name="intercept"), url(r'^dashboard/(?P.*)', main.dashboard_nav, name="dashboard_nav"), - path('submit/initial', main.submit_initial_files, name="submit_initial_files"), - path('submit/final', main.submit_final_files, name="submit_final_files"), + path('submit/initial', efiling.submit_initial_files, name="submit_initial_files"), + path('submit/final', efiling.submit_final_files, name="submit_final_files"), url(r'^health$', system.health), url(r'^legal$', main.legal, name="legal"), url(r'^acknowledgements$', main.acknowledgements, name="acknowledgements"), diff --git a/edivorce/apps/core/utils/cso_filing.py b/edivorce/apps/core/utils/cso_filing.py index de99abc6..fd1c5bd8 100644 --- a/edivorce/apps/core/utils/cso_filing.py +++ b/edivorce/apps/core/utils/cso_filing.py @@ -1,22 +1,29 @@ import random -import re from django.conf import settings +from edivorce.apps.core.efilinghub import EFilingHub from edivorce.apps.core.models import Document, UserResponse from edivorce.apps.core.utils.derived import get_derived_data -def file_documents(user, responses, initial=False): - (forms, _) = forms_to_file(responses, initial) +def file_documents(request, responses, initial=False): + user = request.user + (uploaded, generated) = forms_to_file(responses, initial) missing_forms = [] - for form in forms: + for form in uploaded: docs = Document.objects.filter(bceid_user=user, doc_type=form['doc_type'], party_code=form.get('party_code', 0)) if docs.count() == 0: missing_forms.append(Document.form_types[form['doc_type']]) if missing_forms: - return missing_forms + return missing_forms, None + + hub = EFilingHub(initial_filing=initial) + redirect_url, msg = hub.upload(request, responses, uploaded, generated) + + if redirect_url: + return None, redirect_url # Save dummy data for now. Eventually replace with data from CSO prefix = 'initial' if initial else 'final' @@ -150,14 +157,3 @@ def forms_to_file(responses_dict, initial=False): return [], [] return uploaded, generated - - -def get_filename(doc_type, party_code): - form_name = Document.form_types[doc_type] - slug = re.sub('[^0-9a-zA-Z]+', '-', form_name).strip('-') - if party_code == 0: - return slug + ".pdf" - elif party_code == 1: - return slug + "--Claimant1.pdf" - else: - return slug + "--Claimant2.pdf" diff --git a/edivorce/apps/core/views/efiling.py b/edivorce/apps/core/views/efiling.py new file mode 100644 index 00000000..30b3231b --- /dev/null +++ b/edivorce/apps/core/views/efiling.py @@ -0,0 +1,43 @@ +from django.contrib import messages +from django.shortcuts import redirect +from django.urls import reverse +from django.contrib.auth.decorators import login_required + +from ..decorators import prequal_completed +from ..utils.cso_filing import file_documents +from ..utils.user_response import get_data_for_user + + +@login_required +@prequal_completed +def submit_initial_files(request): + return _submit_files(request, initial=True) + + +@login_required +@prequal_completed +def submit_final_files(request): + return _submit_files(request, initial=False) + + +def _submit_files(request, initial=False): + responses_dict = get_data_for_user(request.user) + if initial: + original_step = 'initial_filing' + next_page = 'wait_for_number' + else: + original_step = 'final_filing' + next_page = 'next_steps' + + missing_forms, hub_redirect_url = file_documents(request, responses_dict, initial=initial) + + if hub_redirect_url: + return redirect(hub_redirect_url) + + if missing_forms: + next_page = original_step + for form_name in missing_forms: + messages.add_message(request, messages.ERROR, f'Missing documents for {form_name}') + responses_dict['active_page'] = next_page + + return redirect(reverse('dashboard_nav', kwargs={'nav_step': next_page}), context=responses_dict) diff --git a/edivorce/apps/core/views/main.py b/edivorce/apps/core/views/main.py index 9399751f..639ce056 100644 --- a/edivorce/apps/core/views/main.py +++ b/edivorce/apps/core/views/main.py @@ -1,17 +1,12 @@ -import datetime -import hashlib - from django.conf import settings from django.contrib import messages from django.shortcuts import render, redirect from django.urls import reverse -from django.utils import timezone 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.cso_filing import file_documents, forms_to_file, get_filename -from ..efilinghub import EFilingHub, PACKAGE_PARTY_FORMAT, PACKAGE_DOCUMENT_FORMAT +from ..utils.cso_filing import forms_to_file from ..utils.question_step_mapping import list_of_registries 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 @@ -22,7 +17,6 @@ from ..utils.user_response import ( get_responses_from_session, get_responses_from_session_grouped_by_steps, ) -from .pdf import images_to_pdf, pdf_form def home(request): @@ -117,34 +111,15 @@ def register_sc(request): return redirect(settings.REGISTER_BCSC_URL) -def signin(request): +def after_login(request): if not request.user.is_authenticated: return render(request, '407.html') - # I think Django might be doing this automatically now that we have switched to mozilla-django-oidc? - # if timezone.now() - request.user.last_login > datetime.timedelta(minutes=1): - # request.user.last_login = timezone.now() - # request.user.save() - copy_session_to_db(request, request.user) return redirect(settings.PROXY_BASE_URL + settings.FORCE_SCRIPT_NAME[:-1] + '/overview') -def logout(request): - """ - Clear session and log out of BCeID - """ - request.session.flush() - - response = redirect(settings.LOGOUT_URL) - - if settings.DEPLOYMENT_TYPE in ['localdev', 'minishift']: - response = redirect('/') - - return response - - @login_required @prequal_completed @intercept @@ -205,95 +180,6 @@ def dashboard_nav(request, nav_step): return render(request, template_name=template_name, context=responses_dict) -@login_required -@prequal_completed -def submit_initial_files(request): - return _submit_files(request, initial=True) - - -@login_required -@prequal_completed -def submit_final_files(request): - return _submit_files(request, initial=False) - - -def _submit_files(request, initial=False): - responses_dict = get_data_for_user(request.user) - if initial: - original_step = 'initial_filing' - next_page = 'wait_for_number' - else: - original_step = 'final_filing' - next_page = 'next_steps' - missing_forms = file_documents(request.user, responses_dict, initial=initial) - if missing_forms: - next_page = original_step - for form_name in missing_forms: - messages.add_message(request, messages.ERROR, f'Missing documents for {form_name}') - responses_dict['active_page'] = next_page - - ################# - # todo: refactor this!!!! - - post_files = [] - documents = [] - - (uploaded, generated) = forms_to_file(responses_dict, initial) - - for form in generated: - pdf_response = pdf_form(request, str(form['form_number'])) - document = PACKAGE_DOCUMENT_FORMAT.copy() - filename = get_filename(form['doc_type'], 0) - document['name'] = filename - document['type'] = form['doc_type'] - document['md5'] = hashlib.md5(pdf_response.content).hexdigest() - post_files.append(('files', (filename, pdf_response.content))) - documents.append(document) - - for form in uploaded: - pdf_response = images_to_pdf(request, form['doc_type'], form['party_code']) - if pdf_response.status_code == 200: - document = PACKAGE_DOCUMENT_FORMAT.copy() - filename = get_filename(form['doc_type'], 0) - document['name'] = filename - document['type'] = form['doc_type'] - document['md5'] = hashlib.md5(pdf_response.content).hexdigest() - post_files.append(('files', (filename, pdf_response.content))) - documents.append(document) - - # generate the list of parties to send to eFiling Hub - parties = [] - - party1 = PACKAGE_PARTY_FORMAT.copy() - party1['firstName'] = responses_dict.get('given_name_1_you', '').strip() - party1['middleName'] = (responses_dict.get('given_name_2_you', '') + - ' ' + - responses_dict.get('given_name_3_you', '')).strip() - party1['lastName'] = responses_dict.get('last_name_you', '').strip() - parties.append(party1) - - party2 = PACKAGE_PARTY_FORMAT.copy() - party2['firstName'] = responses_dict.get('given_name_1_spouse', '').strip() - party2['middleName'] = (responses_dict.get('given_name_2_spouse', '') + - ' ' + - responses_dict.get('given_name_3_spouse', '')).strip() - party2['lastName'] = responses_dict.get('last_name_spouse', '').strip() - parties.append(party2) - - location_name = responses_dict.get('court_registry_for_filing', '') - location = list_of_registries.get(location_name, '0000') - - hub = EFilingHub() - redirect_url, msg = hub.upload(request, post_files, documents, parties, location) - - if redirect_url: - return redirect(redirect_url) - - ################# - - return redirect(reverse('dashboard_nav', kwargs={'nav_step': next_page}), context=responses_dict) - - @login_required @prequal_completed def question(request, step, sub_step=None): diff --git a/edivorce/apps/poc/views.py b/edivorce/apps/poc/views.py index 69c8c566..f6f09fae 100644 --- a/edivorce/apps/poc/views.py +++ b/edivorce/apps/poc/views.py @@ -99,7 +99,7 @@ class EfilingHubUpload(FormView): party['lastName'] = 'Test' parties.append(party) - hub = EFilingHub() + hub = EFilingHub(initial_filing=True) redirect, msg = hub.upload(request, post_files, parties=parties) if redirect: self.success_url = redirect