Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions legal-api/src/legal_api/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,11 @@ class _Config(): # pylint: disable=too-few-public-methods
STAGE_1_DELAY = int(os.getenv('STAGE_1_DELAY', '42'))
STAGE_2_DELAY = int(os.getenv('STAGE_2_DELAY', '30'))

# Document Record Service Settings
DRS_BASE_URL = os.getenv('DRS_BASE_URL', '')
DRS_ACCOUNT_ID = os.getenv('DRS_ACCOUNT_ID', '')
DRS_X_API_KEY = os.getenv('DRS_X_API_KEY', '')

TESTING = False
DEBUG = False

Expand Down
17 changes: 17 additions & 0 deletions legal-api/src/legal_api/resources/v2/document.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

from legal_api.models import Document, Filing
from legal_api.services.minio import MinioService
from legal_api.services.document_record import DocumentRecordService
from legal_api.utils.auth import jwt


Expand Down Expand Up @@ -77,3 +78,19 @@ def get_minio_document(document_key: str):
return jsonify(
message=f'Error getting file {document_key}.'
), HTTPStatus.INTERNAL_SERVER_ERROR

@bp.route('/<string:document_class>/<string:document_type>', methods=['POST', 'OPTIONS'])
@cross_origin(origin='*')
@jwt.requires_auth
def upload_document(document_class: str, document_type: str):
"""Upload document file to Document Record Service."""

return DocumentRecordService.upload_document(document_class, document_type), HTTPStatus.OK

@bp.route('/drs/<string:document_service_id>', methods=['DELETE'])
@cross_origin(origin='*')
@jwt.requires_auth
def delete_document(document_service_id: str):
"""Delete document file from Document Record Service."""

return DocumentRecordService.delete_document(document_service_id), HTTPStatus.OK
1 change: 1 addition & 0 deletions legal-api/src/legal_api/services/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from .furnishing_documents_service import FurnishingDocumentsService
from .involuntary_dissolution import InvoluntaryDissolutionService
from .minio import MinioService
from .document_record import DocumentRecordService
from .mras_service import MrasService
from .naics import NaicsService
from .namex import NameXService
Expand Down
125 changes: 125 additions & 0 deletions legal-api/src/legal_api/services/document_record.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Copyright © 2021 Province of British Columbia
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an 'AS IS' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""This module is a wrapper for Document Record Service."""

import base64
from typing import Optional
import requests
from flask import current_app, request
from flask_babel import _

import PyPDF2

class DocumentRecordService:
"""Document Storage class."""


@staticmethod
def upload_document(document_class: str, document_type: str) -> dict:
"""Upload document to Docuemtn Record Service."""
query_params = request.args.to_dict()
file = request.files.get('file')
# Ensure file exists
if not file:
current_app.logger.debug('No file found in request.')
return {'data': 'File not provided'}
current_app.logger.debug(f'Upload file to document record service {file.filename}')
Comment thread Fixed
DRS_BASE_URL = current_app.config.get('DRS_BASE_URL', '') # pylint: disable=invalid-name
url = f'{DRS_BASE_URL}documents/{document_class}/{document_type}'

# Validate file size and encryption status before submitting to DRS.
validation_error = DocumentRecordService.validate_pdf(file, request.content_length)
if validation_error:
return {
'error': validation_error
}

file_content = file.read()

try:
# Read and encode the file content as base64
file_content = file.read()
file_base64 = base64.b64encode(file_content).decode('utf-8')

response_body = requests.post(
url,
params=query_params,
json={
'filename': file.filename,
'content': file_base64,
'content_type': file.content_type,
},
headers={
'x-apikey': current_app.config.get('DRS_X_API_KEY', ''),
'Account-Id': current_app.config.get('DRS_ACCOUNT_ID', ''),
'Content-Type': 'application/pdf'
}
).json()

current_app.logger.debug(f'Upload file to document record service {response_body}')
return {
'documentServiceId': response_body['documentServiceId'],
'consumerDocumentId': response_body['consumerDocumentId'],
'consumerFilename': response_body['consumerFilename']
}
except Exception as e:
current_app.logger.debug(f"Error on uploading document {e}")
return {}

@staticmethod
def delete_document(document_service_id: str) -> dict:
"""Delete document from Document Record Service."""
DRS_BASE_URL = current_app.config.get('DRS_BASE_URL', '') # pylint: disable=invalid-name
url = f'{DRS_BASE_URL}documents/{document_service_id}'

try:
response = requests.patch(
url, json={ 'removed': True },
headers={
'x-apikey': current_app.config.get('DRS_X_API_KEY', ''),
'Account-Id': current_app.config.get('DRS_ACCOUNT_ID', ''),
}
).json()
current_app.logger.debug(f'Delete document from document record service {response}')
return response
except Exception as e:
current_app.logger.debug(f'Error on deleting document {e}')
return {}

@staticmethod
def validate_pdf(file, content_length) -> Optional[list]:
"""Validate the PDF file."""
msg = []
try:
pdf_reader = PyPDF2.PdfFileReader(file)

# Check that all pages in the pdf are letter size and able to be processed.
if any(x.mediaBox.getWidth() != 612 or x.mediaBox.getHeight() != 792 for x in pdf_reader.pages):
msg.append({'error': _('Document must be set to fit onto 8.5” x 11” letter-size paper.'),
'path': file.filename})
Comment thread
flutistar marked this conversation as resolved.
Outdated

if content_length > 30000000:
msg.append({'error': _('File exceeds maximum size.'), 'path': file.filename})

if pdf_reader.isEncrypted:
msg.append({'error': _('File must be unencrypted.'), 'path': file.filename})

except Exception as e:
msg.append({'error': _('Invalid file.'), 'path': file.filename})
current_app.logger.debug(e)

if msg:
return msg

return None
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ def validate(filing_json: dict) -> Optional[Error]: # pylint: disable=too-many-
return msg # Cannot continue validation without legal_type

msg.extend(validate_business_in_colin(filing_json, filing_type))
msg.extend(validate_continuation_in_authorization(filing_json, filing_type))
Comment thread
flutistar marked this conversation as resolved.
msg.extend(_validate_foreign_jurisdiction(filing_json, filing_type, legal_type))
msg.extend(validate_name_request(filing_json, legal_type, filing_type))

Expand Down Expand Up @@ -126,10 +125,7 @@ def _validate_foreign_jurisdiction(filing_json: dict, filing_type: str, legal_ty
foreign_jurisdiction['country'] == 'CA' and
((region := foreign_jurisdiction.get('region')) and region == 'AB')):
affidavit_file_key_path = f'{foreign_jurisdiction_path}/affidavitFileKey'
if file_key := foreign_jurisdiction.get('affidavitFileKey'):
if err := validate_pdf(file_key, affidavit_file_key_path, False):
msg.extend(err)
else:
Comment thread
flutistar marked this conversation as resolved.
if not foreign_jurisdiction.get('affidavitFileKey'):
msg.append({'error': 'Affidavit from the directors is required.', 'path': affidavit_file_key_path})
try:
# Check the incorporation date is in valid format
Expand Down