Skip to content

Commit

Permalink
Merge pull request #1743 from emko-274/minor_revisions
Browse files Browse the repository at this point in the history
  • Loading branch information
emko-274 authored Aug 15, 2024
2 parents 740f608 + b92a233 commit 05f7e11
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 25 deletions.
8 changes: 2 additions & 6 deletions src/backend/expungeservice/charge_classifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -465,12 +465,8 @@ def _sex_crime(statute):
elif statute in SexCrime.romeo_and_juliet_exceptions:
question_string = """
Select "No" if all of the following are true:
1. Are you required to report as a sex offender?
2. Do you have any charges that are not eligible for expungement?
3. Is your sex offense conviction a Class A or Class B Felony?
If your answer to ALL 3 of these questions is "NO", this charge may be eligible for expungement.
1. Are you required to report as a sex offender?
2. Do you have any charges that are not eligible for expungement?
"""
options = {
"Yes": RomeoAndJulietIneligibleSexCrime(),
Expand Down
14 changes: 13 additions & 1 deletion src/backend/expungeservice/endpoints/pdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,21 @@ def post(self):
demo = request_data.get("demo")
search = Demo if demo else Search
record_summary = search().build_response() # type: ignore
zip_path, zip_name = FormFilling.build_zip(record_summary, user_information)
response = search().post() # type: ignore
record = json.loads(response)["record"]
aliases = request_data["aliases"]
source = MarkdownRenderer.to_markdown(record, aliases=aliases)
summary_pdf_bytes = MarkdownToPDF.to_pdf("Expungement analysis", source)
summary_filename = FormFilling.build_summary_filename(aliases)
zip_path, zip_name = FormFilling.build_zip(record_summary, user_information, summary_pdf_bytes, summary_filename)
return send_file(zip_path, as_attachment=True, attachment_filename=zip_name)

@staticmethod
def build_summary_filename(aliases):
first_alias = aliases[0]
name = f"{first_alias['first_name']}_{first_alias['last_name']}".upper()
return f"{name}_record_summary.pdf"


def register(app):
app.add_url_rule("/api/pdf", view_func=Pdf.as_view("pdf"))
Expand Down
73 changes: 65 additions & 8 deletions src/backend/expungeservice/form_filling.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
from typing import List, Dict, Tuple, Union, Callable, Optional
from zipfile import ZipFile
from collections import UserDict

from pdfrw import PdfReader, PdfWriter, PdfDict, PdfObject, PdfName, PdfString


from expungeservice.models.case import Case
from expungeservice.models.charge import Charge, EditStatus
from expungeservice.models.charge_types.contempt_of_court import ContemptOfCourt
Expand Down Expand Up @@ -353,7 +353,6 @@ class PDFFieldMapper(UserDict):

def __init__(self, pdf_source_path: str, source_data: UserInfo):
super().__init__()

self.pdf_source_path = pdf_source_path
self.source_data = source_data
self.data = self.extra_mappings()
Expand Down Expand Up @@ -451,6 +450,30 @@ def extra_mappings(self):
"(the District Attorney at address 2)": s.da_address,
"(Name typed or printed_2)": s.full_name,
}


class SUMMARY_REPORT:
def __init__(self, path: str):
self.writer = PdfWriter()
try:
self._pdf = PdfReader(path)
except Exception as e:
with open(path, 'wb') as f:
self.writer.write(f)
print(e)
self._pdf = f

def add_text(self, markdown: bytes):
_pdf = PdfReader(fdata=markdown)
self.writer.addpages(_pdf.pages)

def write(self, path: str):
self.writer.addpages(self._pdf.pages)

trailer = self.writer.trailer
trailer.Root.AcroForm = self._pdf.Root.AcroForm

self.writer.write(path, trailer=trailer)


class PDF:
Expand Down Expand Up @@ -574,9 +597,10 @@ class FormFilling:
COUNTIES_NEEDING_CONVICTION_OR_ARREST_ORDER = ["umatilla", "multnomah"]
COUNTIES_NEEDING_COUNTY_SPECIFIC_DOWNLOAD_NAME = ["umatilla"]
OSP_PDF_NAME = "OSP_Form"
#COMPILED_PDF_NAME = "COMPILED_MOTIONS"

@staticmethod
def build_zip(record_summary: RecordSummary, user_information_dict: Dict[str, str]) -> Tuple[str, str]:
def build_zip(record_summary: RecordSummary, user_information_dict: Dict[str, str], summary: bytes, summary_filename: str) -> Tuple[str, str]:
temp_dir = mkdtemp()
zip_file_name = "expungement_packet.zip"
zip_path = path.join(mkdtemp(), zip_file_name)
Expand All @@ -585,6 +609,7 @@ def build_zip(record_summary: RecordSummary, user_information_dict: Dict[str, st
sid = FormFilling._unify_sids(record_summary)

all_case_results = []
all_motions_to_set_aside = []
has_eligible_convictions = False
for case in record_summary.record.cases:
case_results = CaseResults.build(case, user_information_dict, sid)
Expand All @@ -594,18 +619,39 @@ def build_zip(record_summary: RecordSummary, user_information_dict: Dict[str, st
all_case_results.append(case_results)
if case_results.is_expungeable_now:
file_info = FormFilling._create_and_write_pdf(case_results, temp_dir)
zip_file.write(*file_info)
all_motions_to_set_aside.append(file_info[2])
zip_file.write(*file_info[0:2])

user_information_dict_2: Dict[str, object] = {**user_information_dict}
user_information_dict_2["counties_with_cases_to_expunge"] = FormFilling.counties_with_cases_to_expunge(
all_case_results
)
user_information_dict_2["has_eligible_convictions"] = has_eligible_convictions
osp_file_info = FormFilling._create_and_write_pdf(user_information_dict_2, temp_dir)
zip_file.write(*osp_file_info)
zip_file.write(*osp_file_info[0:2])

if len(all_motions_to_set_aside) > 1:
compiled = all_motions_to_set_aside[0]
for pdf in all_motions_to_set_aside[1:len(all_motions_to_set_aside)]:
compiled.writer.addpages(pdf._pdf.pages)
comp_name = "COMPILED.pdf"
comp_path = path.join(temp_dir, comp_name)
compiled.write(comp_path)
zip_file.write(comp_path, comp_name)

summary_report = FormFilling._create_and_write_summary_pdf(summary_filename, summary, temp_dir)
zip_file.write(*summary_report)

zip_file.close()

return zip_path, zip_file_name

@staticmethod
def build_summary_filename(aliases):
first_alias = aliases[0]
name = f"{first_alias['first_name']}_{first_alias['last_name']}".upper()
return f"{name}_record_summary.pdf"

@staticmethod
def _unify_sids(record_summary: RecordSummary) -> str:
"""
Expand Down Expand Up @@ -674,14 +720,25 @@ def _create_pdf(source_data: UserInfo, validate_initial_pdf_state=False) -> PDF:
file_name = FormFilling._get_pdf_file_name(source_data)
source_dir = path.join(Path(__file__).parent, "files")
pdf_path = path.join(source_dir, file_name)

mapper = PDFFieldMapper(pdf_path, source_data)
return PDF.fill_form(mapper, validate_initial_pdf_state)

@staticmethod
def _create_and_write_summary_pdf(file_name: str, markdown: bytes, temp_dir: str):
source_dir = path.join(Path(__file__).parent, "files")
pdf_path = path.join(source_dir, file_name)
pdf = SUMMARY_REPORT(pdf_path)

pdf.add_text(markdown)
write_file_path, write_file_name = path.join(temp_dir, file_name), file_name
pdf.writer.write(write_file_path)
return write_file_path, write_file_name


@staticmethod
def _create_and_write_pdf(
data: Union[Dict, UserInfo], dir: str, validate_initial_pdf_state=False
) -> Tuple[str, str]:
) -> Tuple[str, str, PDF]:
if isinstance(data, UserInfo):
source_data = data
else:
Expand All @@ -696,7 +753,7 @@ def _create_and_write_pdf(
write_file_path, write_file_name = FormFilling._build_download_file_path(dir, source_data)
pdf.write(write_file_path)

return write_file_path, write_file_name
return write_file_path, write_file_name, pdf

@staticmethod
def counties_with_cases_to_expunge(all_case_results: List[CaseResults]):
Expand Down
1 change: 1 addition & 0 deletions src/backend/expungeservice/pdf/markdown_renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ def to_markdown(record: Dict, header: Optional[str] = None, aliases: List[Dict]
]

county_fines = [x for x in record["summary"]["county_fines"]]

eligible_charges_by_date = record["summary"]["charges_grouped_by_eligibility_and_case"]
future_eligible_charges = [
(key, eligible_charges_for_date)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,10 @@ Additionally, you have charges for which the online records do not contain enoug
## Balance Due by County
{% for county in county_fines %}
{% if county['case_fines'] | length > 0 %}
{{county['county_name']}}
<b>{{county['county_name']}}</b>

{% for fine in county['case_fines'] %}
{{fine['case_number']}} - {{fine['balance']}}
{{fine['case_number']}} - ${{fine['balance']}}
{% endfor %}
{% endif %}
{% endfor %}
Expand Down
5 changes: 3 additions & 2 deletions src/backend/tests/pdf/expected/custom_header.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ These convictions are eligible as soon as the balance of fines on the case is pa


## Balance Due by County
Multnomah
CASEJD1 - 529.08
<b>Multnomah</b>
CASEJD1 - $529.08

### Disclaimer:
RecordSponge is not your lawyer. The results below should be used as a guide only. If you are relying on this information to expunge your record, please email [email protected] for free consultation.
5 changes: 3 additions & 2 deletions src/backend/tests/pdf/expected/default.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ These convictions are eligible as soon as the balance of fines on the case is pa


## Balance Due by County
Multnomah
CASEJD1 - 529.08
<b>Multnomah</b>
CASEJD1 - $529.08

### Disclaimer:
RecordSponge is not your lawyer. The results below should be used as a guide only. If you are relying on this information to expunge your record, please email [email protected] for free consultation.
20 changes: 16 additions & 4 deletions src/backend/tests/test_form_filling.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from datetime import datetime

import pytest
import pdfkit
from unittest.mock import patch, Mock, MagicMock

from expungeservice.expunger import Expunger
Expand Down Expand Up @@ -62,7 +63,9 @@ def test_normal_conviction_uses_multnomah_conviction_form():
record = CrawlerFactory.create(JohnDoe.SINGLE_CASE_RECORD, {"CASEJD1": CaseDetails.CASEJD74})
expunger_result = Expunger.run(record)
merged_record = RecordMerger.merge([record], [expunger_result], [])

record_summary = RecordSummarizer.summarize(merged_record, {})

user_information = {
"full_name": "",
"date_of_birth": "",
Expand All @@ -72,12 +75,14 @@ def test_normal_conviction_uses_multnomah_conviction_form():
"state": "",
"zip_code": "",
}
zip_path, zip_name = FormFilling.build_zip(record_summary, user_information)

mock_pdf = pdfkit.from_string("jd", False, options={"quiet": ""})
zip_path = FormFilling.build_zip(record_summary, user_information, mock_pdf, "JOHN_DOE_record_summary.pdf")[0]
temp_dir = mkdtemp()
with ZipFile(zip_path, "r") as zip_ref:
zip_ref.extractall(temp_dir)
for _root, _dir, files in os.walk(temp_dir):
assert len(files) == 1
assert len(files) == 2


#########################################
Expand Down Expand Up @@ -117,18 +122,21 @@ def test_form_fields_are_filled(self, mock_mkdtemp, MockZipFile, MockPdfWriter,
with open(pickle_file, "rb") as file:
record_summary = pickle.load(file)

FormFilling.build_zip(record_summary, user_information)
mock_pdf = pdfkit.from_string("jd", False, options={"quiet": ""})

FormFilling.build_zip(record_summary, user_information, mock_pdf, "JOHN_DOE_record_summary.pdf")

# Check PDF form fields are correct.
addpages_call_args_list = MockPdfWriter.return_value.addpages.call_args_list
for i, args_list in enumerate(addpages_call_args_list):
for i, args_list in enumerate(addpages_call_args_list[0:4]):
document_id = "document_" + str(i)
args, _ = args_list
pages = args[0]
for idx, page in enumerate(pages):
for annotation in page.Annots or []:
assert self.expected_form_values[document_id][idx][annotation.T] == annotation.V, annotation.T


# Check PDF writer write paths.
pdf_write_call_args_list = MockPdfWriter.return_value.write.call_args_list
file_paths = [pdf_write_call_args_list[i][0][0] for i, _ in enumerate(pdf_write_call_args_list)]
Expand All @@ -137,6 +145,8 @@ def test_form_fields_are_filled(self, mock_mkdtemp, MockZipFile, MockPdfWriter,
"foo/COMMON NAME_110000_baker.pdf",
"foo/COMMON A NAME_120000_baker.pdf",
"foo/OSP_Form.pdf",
"foo/COMPILED.pdf",
"foo/JOHN_DOE_record_summary.pdf"
]
assert set(file_paths) == set(expected_file_paths)

Expand All @@ -148,6 +158,8 @@ def test_form_fields_are_filled(self, mock_mkdtemp, MockZipFile, MockPdfWriter,
("foo/COMMON NAME_110000_baker.pdf", "COMMON NAME_110000_baker.pdf"),
("foo/COMMON A NAME_120000_baker.pdf", "COMMON A NAME_120000_baker.pdf"),
("foo/OSP_Form.pdf", "OSP_Form.pdf"),
("foo/COMPILED.pdf", "COMPILED.pdf"),
("foo/JOHN_DOE_record_summary.pdf", "JOHN_DOE_record_summary.pdf")
]
assert set(zip_write_args) == set(expected_zip_write_args)

Expand Down

0 comments on commit 05f7e11

Please sign in to comment.