From b1d7bb9c9f602da2cdd3bf1916132f96e0e42773 Mon Sep 17 00:00:00 2001 From: Bryce Willey Date: Thu, 15 Jan 2026 11:56:29 -0600 Subject: [PATCH] Adds a maximum size per document param Needs, since Tyler lets courts restrict individual document uploads, as well as the envelope as a whole, so adds a `maximum_size_per_doc` parameter that acts per document (which is needed so folks don't upload one file within the limit and then another one out of the limit on the second screen, which would be rejected by Tyler; this has happened in production recently). --- docassemble/AssemblyLine/al_document.py | 7 +++++ .../data/questions/ql_baseline.yml | 27 ++++++++++++++++--- .../data/questions/test_alexhibit_maxsize.yml | 2 +- pyproject.toml | 3 +++ 4 files changed, 35 insertions(+), 4 deletions(-) diff --git a/docassemble/AssemblyLine/al_document.py b/docassemble/AssemblyLine/al_document.py index 6cf647a8..5705efd8 100644 --- a/docassemble/AssemblyLine/al_document.py +++ b/docassemble/AssemblyLine/al_document.py @@ -2877,6 +2877,7 @@ class ALExhibitList(DAList): Attributes: maximum_size (int): The maximum allowed size in bytes of the entire document. + maximum_size_per_doc (int): The maximum allowed size in bytes per document in the list auto_label (bool): If True, automatically numbers exhibits for cover page and table of contents. Defaults to True. auto_labeler (Callable): An optional function or lambda to transform the exhibit's index to a label. Uses A..Z labels by default. @@ -3075,6 +3076,7 @@ class ALExhibitDocument(ALDocument): auto_ocr: bool bates_prefix: str maximum_size: int + maximum_size_per_doc: int suffix_to_append: str exhibits: ALExhibitList table_of_contents: DAFile @@ -3099,8 +3101,13 @@ def init(self, *pargs, **kwargs) -> None: else: self.include_exhibit_cover_pages = True self.exhibits.include_exhibit_cover_pages = True + if hasattr(self, "maximum_size_per_doc"): + self.exhibits.maximum_size_per_doc = self.maximum_size_per_doc if hasattr(self, "maximum_size"): self.exhibits.maximum_size = self.maximum_size + if not hasattr(self, "maximum_size_per_doc"): + self.maximum_size_per_doc = self.maximum_size + self.exhibits.maximum_size_per_doc = self.maximum_size if hasattr(self, "include_table_of_contents"): self.exhibits.include_table_of_contents = self.include_table_of_contents else: diff --git a/docassemble/AssemblyLine/data/questions/ql_baseline.yml b/docassemble/AssemblyLine/data/questions/ql_baseline.yml index 2d486d4f..5ec9fb10 100644 --- a/docassemble/AssemblyLine/data/questions/ql_baseline.yml +++ b/docassemble/AssemblyLine/data/questions/ql_baseline.yml @@ -1882,6 +1882,9 @@ validation code: | if hasattr(x, 'maximum_size'): if full_size > x.maximum_size: validation_error(f"Upload a file smaller than {humanize.naturalsize(x.maximum_size)}") + if hasattr(x, 'maximum_size_per_doc'): + if full_size > x.maximum_size_per_doc: + validation_error(f"Upload a file smaller than {humanize.naturalsize(x.maximum_size)}") try: pdf_concatenate(x[0].pages) except: @@ -1910,6 +1913,9 @@ fields: "image/png, image/jpeg, .doc,.docx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/pdf,.pdf" validation code: | this_doc_size = sum(a_page.size_in_bytes() for a_page in x[i].pages) + if hasattr(x, 'maximum_size_per_doc'): + if this_doc_size > x.maximum_size_per_doc: + validation_error(f"This document should be smaller than {humanize.naturalsize(x.maximum_size_per_doc)}") if this_doc_size > (15 * 1024 * 1024): validation_error("Upload a file smaller than 15 MB.") if hasattr(x, 'maximum_size'): @@ -1930,9 +1936,19 @@ question: | subquestion: | You have uploaded ${ x[i].pages.num_pages() } pages so far. + <% current_doc_size = sum(ap.size_in_bytes() for ap in x[i].pages.complete_elements()) %> + % if hasattr(x, 'maximum_size_per_doc'): + This document must be smaller than ${ humanize.naturalsize(x.maximum_size_per_doc) }. + % if not hasattr(x, 'maximum_size') or x.maximum_size_per_doc - current_doc_size < x.maximum_size - x.size_in_bytes() - current_doc_size: + You can upload ${ humanize.naturalsize(x.maximum_size_per_doc - current_doc_size) } more. + % else: + You can upload ${ humanize.naturalsize(x.maximum_size - x.size_in_bytes() - current_doc_size) } more. + % endif + % endif + % if hasattr(x, 'maximum_size'): The total size of all exhibits must be less than ${ humanize.naturalsize(x.maximum_size) }. - You can upload ${ humanize.naturalsize(x.maximum_size - x.size_in_bytes() - sum(ap.size_in_bytes() for ap in x[i].pages.complete_elements()))} more. + You can upload ${ humanize.naturalsize(x.maximum_size - x.size_in_bytes() - current_doc_size) } more. % endif ${ collapse_template(x[i].in_progress_template )} @@ -1968,11 +1984,16 @@ fields: "image/png, image/jpeg, .doc,.docx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/pdf,.pdf" validation code: | page_size = x[i].pages[j].size_in_bytes() + this_doc_size = sum(a_page.size_in_bytes() for a_page in x[i].pages.complete_elements()) + page_size + log(f"length of completed elements: {len(x[i].pages.complete_elements())}") + if hasattr(x, 'maximum_size_per_doc'): + if this_doc_size > x.maximum_size_per_doc: + suggested_size = x.maximum_size_per_doc - (this_doc_size - page_size) + validation_error(f"This document must be smaller than {humanize.naturalsize(x.maximum_size_per_doc) }. Upload a file smaller than {humanize.naturalsize(suggested_size)}.") + if page_size > (15 * 1024 * 1024): validation_error("Upload a file smaller than 15 MB.") if hasattr(x, 'maximum_size'): - # this_doc_size already includes `page_size` - this_doc_size = sum(a_page.size_in_bytes() for a_page in x[i].pages.complete_elements()) full_size = x.size_in_bytes() + this_doc_size if full_size > x.maximum_size: suggested_size = x.maximum_size - (full_size - page_size) diff --git a/docassemble/AssemblyLine/data/questions/test_alexhibit_maxsize.yml b/docassemble/AssemblyLine/data/questions/test_alexhibit_maxsize.yml index 5c2b5e59..e3861156 100644 --- a/docassemble/AssemblyLine/data/questions/test_alexhibit_maxsize.yml +++ b/docassemble/AssemblyLine/data/questions/test_alexhibit_maxsize.yml @@ -10,7 +10,7 @@ objects: - exhibits_bundle_defaults_1: ALDocumentBundle.using(elements=[exhibit_doc_defaults_1], filename="exhibits_bundle_defaults", title="Exhibits with defaults") --- objects: - - exhibit_doc_defaults_1: ALExhibitDocument.using(title="Exhibits doc defaults", filename="exhibits_doc_defaults", maximum_size=1*1024*1024 ) + - exhibit_doc_defaults_1: ALExhibitDocument.using(title="Exhibits doc defaults", filename="exhibits_doc_defaults", maximum_size=3*1024*1024, maximum_size_per_doc=1*1024*1024) --- id: gather_main event: gather_main diff --git a/pyproject.toml b/pyproject.toml index 2c555218..978a1edc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,6 +36,9 @@ extend-exclude = '(__init__.py|setup.py)' check-property-returns = false check-overridden = false check-class = true +disable = [ + "SIG305" +] [tool.mypy] # global options