docassemble.AssemblyLine 3.1.0__tar.gz → 3.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. {docassemble_assemblyline-3.1.0/docassemble.AssemblyLine.egg-info → docassemble_assemblyline-3.2.0}/PKG-INFO +1 -1
  2. docassemble_assemblyline-3.2.0/docassemble/AssemblyLine/__init__.py +1 -0
  3. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/al_document.py +169 -55
  4. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/al_document.yml +77 -1
  5. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/al_visual.yml +21 -4
  6. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/demo_search_sessions.yml +12 -1
  7. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/interview_list.yml +39 -3
  8. docassemble_assemblyline-3.2.0/docassemble/AssemblyLine/data/questions/test_aldocument_background_assembly.yml +65 -0
  9. docassemble_assemblyline-3.2.0/docassemble/AssemblyLine/data/sources/translation_es_broken.xlsx +0 -0
  10. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/requirements.txt +2 -1
  11. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/sessions.py +184 -21
  12. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0/docassemble.AssemblyLine.egg-info}/PKG-INFO +1 -1
  13. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble.AssemblyLine.egg-info/SOURCES.txt +2 -0
  14. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/setup.py +1 -1
  15. docassemble_assemblyline-3.1.0/docassemble/AssemblyLine/__init__.py +0 -1
  16. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/LICENSE +0 -0
  17. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/MANIFEST.in +0 -0
  18. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/README.md +0 -0
  19. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/al_courts.py +0 -0
  20. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/al_general.py +0 -0
  21. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/al_code.yml +0 -0
  22. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/al_language.yml +0 -0
  23. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/al_package.yml +0 -0
  24. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/al_package_unstyled.yml +0 -0
  25. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/al_question_test.yml +0 -0
  26. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/al_reminders.yml +0 -0
  27. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/al_saved_sessions.yml +0 -0
  28. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/al_saved_sessions_store.yml +0 -0
  29. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/al_settings.yml +0 -0
  30. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/al_terms_of_use.yml +0 -0
  31. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/assembly_line.yml +0 -0
  32. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/assembly_line_unstyled.yml +0 -0
  33. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/feedback.yml +0 -0
  34. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/ql_baseline.yml +0 -0
  35. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/ql_catchall.yml +0 -0
  36. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/reserved_words.yml +0 -0
  37. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/test_al_table_document.yml +0 -0
  38. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/test_aladdendum.yml +0 -0
  39. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/test_alcourts.yml +0 -0
  40. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/test_aldocument.yml +0 -0
  41. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/test_alexhibit.yml +0 -0
  42. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/test_alexhibit_maxsize.yml +0 -0
  43. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/test_bundle_parity.yml +0 -0
  44. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/test_familiar_disambiguation.yml +0 -0
  45. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/questions/test_question_library.yml +0 -0
  46. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/sources/README.md +0 -0
  47. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/sources/es-words.yml +0 -0
  48. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/sources/languages.yml +0 -0
  49. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/sources/test_aldocument.feature +0 -0
  50. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_docx_1.docx +0 -0
  51. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_jpg_1.jpg +0 -0
  52. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_pdf_1.pdf +0 -0
  53. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/sources/test_alexhibit_png_1.png +0 -0
  54. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/sources/test_question_library.feature +0 -0
  55. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/sources/translation_es.xlsx +0 -0
  56. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/sources/translation_ht.xlsx +0 -0
  57. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/sources/translation_pt.xlsx +0 -0
  58. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/static/README.md +0 -0
  59. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/static/al_audio.css +0 -0
  60. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/static/al_audio.js +0 -0
  61. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/static/aldocument.css +0 -0
  62. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/static/aldocument.js +0 -0
  63. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/static/interview_list.css +0 -0
  64. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/static/limit_upload_size.js +0 -0
  65. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/static/lt1-pullout-10-getting-organized.pdf +0 -0
  66. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/static/ma_logo.png +0 -0
  67. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/static/placeholder.png +0 -0
  68. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/static/seal.jpg +0 -0
  69. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/static/styles.css +0 -0
  70. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/templates/README.md +0 -0
  71. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/templates/al_basic_addendum.docx +0 -0
  72. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/templates/exhibit_cover_sheet.docx +0 -0
  73. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/templates/exhibit_table_of_contents.docx +0 -0
  74. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/templates/general_cover_sheet.docx +0 -0
  75. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/templates/sample_word_template.docx +0 -0
  76. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/templates/test_aldocument_docx_1.docx +0 -0
  77. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/data/templates/test_aldocument_pdf_1.pdf +0 -0
  78. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/language.py +0 -0
  79. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/project_maintenance.py +0 -0
  80. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/py.typed +0 -0
  81. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/test_al_document.py +0 -0
  82. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/test_al_general.py +0 -0
  83. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/AssemblyLine/test_language.py +0 -0
  84. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble/__init__.py +0 -0
  85. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble.AssemblyLine.egg-info/dependency_links.txt +0 -0
  86. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble.AssemblyLine.egg-info/namespace_packages.txt +0 -0
  87. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble.AssemblyLine.egg-info/not-zip-safe +0 -0
  88. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble.AssemblyLine.egg-info/requires.txt +0 -0
  89. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/docassemble.AssemblyLine.egg-info/top_level.txt +0 -0
  90. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/pyproject.toml +0 -0
  91. {docassemble_assemblyline-3.1.0 → docassemble_assemblyline-3.2.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: docassemble.AssemblyLine
3
- Version: 3.1.0
3
+ Version: 3.2.0
4
4
  Home-page: https://courtformsonline.org
5
5
  Author: Suffolk Legal Innovation and Technology Lab
6
6
  Author-email: qsteenhuis@suffolk.edu
@@ -0,0 +1 @@
1
+ __version__ = '3.2.0'
@@ -35,6 +35,7 @@ from math import floor
35
35
  import subprocess
36
36
  from collections import ChainMap
37
37
  import pikepdf
38
+ from typing import Tuple
38
39
 
39
40
  __all__ = [
40
41
  "ALAddendumField",
@@ -1822,6 +1823,107 @@ class ALDocumentBundle(DAList):
1822
1823
  editable.append(doc)
1823
1824
  return editable
1824
1825
 
1826
+ def get_cacheable_documents(
1827
+ self,
1828
+ key: str = "final",
1829
+ pdf: bool = True,
1830
+ docx: bool = False,
1831
+ original: bool = False,
1832
+ refresh: bool = True,
1833
+ pdfa: bool = False,
1834
+ include_zip: bool = True,
1835
+ include_full_pdf: bool = False,
1836
+ append_matching_suffix: bool = True,
1837
+ ) -> Tuple[List[Dict[str, DAFile]], Optional[DAFile], Optional[DAFile]]:
1838
+ """
1839
+ Generates a cache of all enabled documents in the bundle, and returns it in a structure that can be cached
1840
+ and returned for use in a background process.
1841
+
1842
+ The result looks like this:
1843
+
1844
+ [
1845
+ {"title": "Document 1", "pdf": DAFile, "docx": DAFile, download_filename: str},
1846
+ ],
1847
+ DAFile, # Zip of whole bundle
1848
+ DAFile # PDF of whole bundle
1849
+
1850
+ Args:
1851
+ key (str): Identifier for the document version, default is "final".
1852
+ pdf (bool): Flag to include a PDF version of each file, default is True.
1853
+ docx (bool): Flag to include a DOCX version of each file, default is False.
1854
+ original (bool): Flag to include the original version of each file, default is False.
1855
+ refresh (bool): Flag to reconsider the 'enabled' attribute, default is True.
1856
+ pdfa (bool): Flag to return documents in PDF/A format, default is False.
1857
+ include_zip (bool): Flag to include a zip option, default is True.
1858
+ include_full_pdf (bool): Flag to include a PDF version of the whole bundle, default is False.
1859
+ append_matching_suffix (bool): Flag to determine if matching suffix should be appended to file name, default is True.
1860
+
1861
+ Returns:
1862
+ Tuple[List[Dict[str, DAFile]], Optional[DAFile], Optional[DAFile]]: A list of dictionaries containing the enabled documents, a zip file of the whole bundle, and a PDF of the whole
1863
+ """
1864
+ # reduce idempotency delays
1865
+ enabled_docs = self.enabled_documents(refresh=refresh)
1866
+ for doc in enabled_docs:
1867
+ doc.title
1868
+
1869
+ results = []
1870
+
1871
+ for doc in enabled_docs:
1872
+ result = {"title": doc.title}
1873
+ filename_root = os.path.splitext(str(doc.filename))[0]
1874
+ if pdf:
1875
+ result["pdf"] = doc.as_pdf(
1876
+ key=key,
1877
+ refresh=refresh,
1878
+ pdfa=pdfa,
1879
+ append_matching_suffix=append_matching_suffix,
1880
+ )
1881
+ result["download_filename"] = filename_root + ".pdf"
1882
+ if docx and doc._is_docx(key=key):
1883
+ result["docx"] = doc.as_docx(
1884
+ key=key,
1885
+ refresh=refresh,
1886
+ append_matching_suffix=append_matching_suffix,
1887
+ )
1888
+ result["download_filename"] = filename_root + ".docx"
1889
+ if original:
1890
+ result["original"] = doc[key]
1891
+ result["download_filename"] = doc.filename
1892
+
1893
+ try:
1894
+ # If it's possible, set the file extension to the actual filetype
1895
+ # This is mostly necessary if people omit the file extension in attachment block
1896
+ # for filetype="original"
1897
+ if original:
1898
+ download_doc = result["original"]
1899
+ else:
1900
+ download_doc = result["docx"]
1901
+ ext = next(
1902
+ iter(
1903
+ mimetypes.guess_all_extensions(
1904
+ download_doc.mimetype, strict=True
1905
+ )
1906
+ )
1907
+ )
1908
+ result["download_filename"] = filename_root + ext
1909
+ except:
1910
+ pass
1911
+ results.append(result)
1912
+
1913
+ if len(enabled_docs) > 1 and include_zip:
1914
+ bundled_zip = self.as_zip(
1915
+ key=key, format="original" if original else "docx" if docx else "pdf"
1916
+ )
1917
+ else:
1918
+ bundled_zip = None
1919
+
1920
+ if len(enabled_docs) > 1 and include_full_pdf:
1921
+ bundled_pdf = self.as_pdf(key=key, pdfa=pdfa)
1922
+ else:
1923
+ bundled_pdf = None
1924
+
1925
+ return results, bundled_zip, bundled_pdf
1926
+
1825
1927
  def download_list_html(
1826
1928
  self,
1827
1929
  key: str = "final",
@@ -1838,6 +1940,9 @@ class ALDocumentBundle(DAList):
1838
1940
  zip_icon: str = "file-archive",
1839
1941
  append_matching_suffix: bool = True,
1840
1942
  include_email: bool = False,
1943
+ use_previously_cached_files: bool = False,
1944
+ include_full_pdf: bool = False,
1945
+ full_pdf_label: Optional[str] = None,
1841
1946
  ) -> str:
1842
1947
  """
1843
1948
  Constructs an HTML table displaying a list of documents with 'view' and 'download' buttons.
@@ -1857,6 +1962,9 @@ class ALDocumentBundle(DAList):
1857
1962
  zip_icon (str): Icon for the zip option, default is "file-archive".
1858
1963
  append_matching_suffix (bool): Flag to determine if matching suffix should be appended to file name, default is True.
1859
1964
  include_email (bool): Flag to include an email option, default is False.
1965
+ use_previously_cached_files (bool): Flag to use previously cached files (e.g., made in background) if defined. default is False.
1966
+ include_full_pdf (bool): Flag to include a full PDF option, default is False.
1967
+ full_pdf_label (Optional[str]): Label for the full PDF option. If not provided, uses the generic template for `self.full_pdf_label` ("Download all").
1860
1968
 
1861
1969
  Returns:
1862
1970
  str: HTML representation of a table with documents and their associated actions.
@@ -1864,52 +1972,40 @@ class ALDocumentBundle(DAList):
1864
1972
  if not hasattr(self, "_cached_zip_label"):
1865
1973
  self._cached_zip_label = str(self.zip_label)
1866
1974
 
1867
- # Trigger some variables up top to avoid idempotency issues
1868
- enabled_docs = self.enabled_documents(refresh=refresh)
1869
- for doc in enabled_docs:
1870
- doc.title
1871
- if format == "pdf":
1872
- doc.as_pdf(
1873
- key=key,
1874
- refresh=refresh,
1875
- pdfa=pdfa,
1876
- append_matching_suffix=append_matching_suffix,
1877
- ) # Generate cached file for this session
1975
+ if not hasattr(self, "_cached_full_pdf_label"):
1976
+ self._cached_full_pdf_label = str(self.full_pdf_label)
1977
+
1978
+ if use_previously_cached_files and hasattr(self, "_downloadable_files"):
1979
+ downloadable_files, bundled_zip, bundled_pdf = self._downloadable_files
1980
+ else:
1981
+ downloadable_files, bundled_zip, bundled_pdf = self.get_cacheable_documents(
1982
+ key=key,
1983
+ pdf=(format == "pdf" or view == True),
1984
+ docx=format == "docx",
1985
+ original=format == "original",
1986
+ refresh=refresh,
1987
+ pdfa=pdfa,
1988
+ include_zip=include_zip,
1989
+ include_full_pdf=include_full_pdf,
1990
+ append_matching_suffix=append_matching_suffix,
1991
+ )
1878
1992
 
1879
1993
  html = f'<div class="container al_table al_doc_table" id="{ html_safe_str(self.instanceName) }">'
1880
1994
 
1881
- for doc in enabled_docs:
1882
- filename_root = os.path.splitext(str(doc.filename))[0]
1883
- # Do our best to use the provided filename + the extension from requested filetype
1884
- if format == "original":
1885
- download_doc = doc[key]
1886
- download_filename = doc.filename
1887
- if format == "docx" and doc._is_docx(key=key):
1888
- download_doc = doc.as_docx(
1889
- key=key, append_matching_suffix=append_matching_suffix
1890
- )
1891
- download_filename = filename_root + ".docx"
1892
- else:
1893
- download_doc = doc.as_pdf(
1894
- key=key, append_matching_suffix=append_matching_suffix
1895
- )
1896
- download_filename = filename_root + ".pdf"
1995
+ for result in downloadable_files:
1996
+ title = result["title"]
1997
+ download_filename = result.get("download_filename", "document")
1897
1998
 
1898
- try:
1899
- # If it's possible, set the file extension to the actual filetype
1900
- # This is mostly necessary if people omit the file extension in attachment block
1901
- # for filetype="original"
1902
- ext = next(
1903
- iter(
1904
- mimetypes.guess_all_extensions(
1905
- download_doc.mimetype, strict=True
1906
- )
1907
- )
1908
- )
1909
- download_filename = filename_root + ext
1910
- except:
1911
- pass
1999
+ if format == "original" and "original" in result:
2000
+ download_doc = result["original"]
2001
+ elif format == "docx" and "docx" in result:
2002
+ download_doc = result["docx"]
2003
+ elif "pdf" in result:
2004
+ download_doc = result["pdf"]
2005
+ else:
2006
+ continue # Skip if the desired format is not available
1912
2007
 
2008
+ # Construct the download button
1913
2009
  doc_download_button = action_button_html(
1914
2010
  download_doc.url_for(
1915
2011
  attachment=True, display_filename=download_filename
@@ -1920,12 +2016,14 @@ class ALDocumentBundle(DAList):
1920
2016
  size="md",
1921
2017
  classname="al_download al_button",
1922
2018
  )
1923
- if view and doc.as_pdf().url_for().endswith(".pdf"):
2019
+
2020
+ # Construct the view button if needed
2021
+ if view and "pdf" in result and result["pdf"].url_for().endswith(".pdf"):
2022
+ # Use .pdf as the filename extension
2023
+ view_filename = os.path.splitext(download_filename)[0] + ".pdf"
1924
2024
  doc_view_button = action_button_html(
1925
- doc.as_pdf(key=key).url_for(
1926
- attachment=False,
1927
- display_filename=filename_root + ".pdf",
1928
- append_matching_suffix=append_matching_suffix,
2025
+ result["pdf"].url_for(
2026
+ attachment=False, display_filename=view_filename
1929
2027
  ),
1930
2028
  label=view_label,
1931
2029
  icon=view_icon,
@@ -1936,31 +2034,47 @@ class ALDocumentBundle(DAList):
1936
2034
  buttons = [doc_view_button, doc_download_button]
1937
2035
  else:
1938
2036
  buttons = [doc_download_button]
1939
- html += table_row(doc.title, buttons)
1940
2037
 
1941
- # Add a zip file row if there's more than one doc
1942
- filename_root = os.path.splitext(str(self.filename))[0]
1943
- if len(enabled_docs) > 1 and include_zip:
2038
+ html += table_row(title, buttons)
2039
+
2040
+ # Add a zip file row if included
2041
+ if include_zip and bundled_zip:
1944
2042
  if not zip_label:
1945
2043
  zip_label = self._cached_zip_label
1946
- # Zip file will match the format of the download table
1947
- zip = self.as_zip(key=key, format=format, include_pdf=view)
2044
+ filename_root = os.path.splitext(str(self.filename))[0]
1948
2045
  zip_button = action_button_html(
1949
- zip.url_for(attachment=False, display_filename=filename_root + ".zip"),
2046
+ bundled_zip.url_for(
2047
+ attachment=False, display_filename=filename_root + ".zip"
2048
+ ),
1950
2049
  label=zip_label,
1951
2050
  icon=zip_icon,
1952
2051
  color="primary",
1953
2052
  size="md",
1954
2053
  classname="al_zip al_button",
1955
2054
  )
1956
- html += table_row(zip.title, zip_button)
2055
+ html += table_row(zip_label, zip_button)
2056
+
2057
+ if include_full_pdf and bundled_pdf:
2058
+ if not full_pdf_label:
2059
+ full_pdf_label = self._cached_full_pdf_label
2060
+ filename_root = os.path.splitext(str(self.filename))[0]
2061
+ full_pdf_button = action_button_html(
2062
+ bundled_pdf.url_for(
2063
+ attachment=False, display_filename=filename_root + ".pdf"
2064
+ ),
2065
+ label=full_pdf_label,
2066
+ icon="file-pdf",
2067
+ color="primary",
2068
+ size="md",
2069
+ classname="al_full_pdf al_button",
2070
+ )
2071
+ html += table_row(full_pdf_label, full_pdf_button)
1957
2072
 
1958
2073
  if include_email:
1959
2074
  html += self.send_email_table_row(key=key)
1960
2075
 
1961
2076
  html += "\n</div>"
1962
2077
 
1963
- # Discuss: Do we want a table with the ability to have a merged pdf row?
1964
2078
  return html
1965
2079
 
1966
2080
  def download_html(
@@ -88,9 +88,85 @@ template: x.zip_label
88
88
  content: |
89
89
  Download all
90
90
  ---
91
+ generic object: ALDocumentBundle
92
+ template: x.full_pdf_label
93
+ content: |
94
+ Download as one PDF
95
+ ---
91
96
  id: al exhibit ocr pages bg
92
97
  event: al_exhibit_ocr_pages
93
98
  code: |
94
99
  to_pdf = action_argument('to_pdf')
95
100
  from_file = action_argument('from_file')
96
- background_response(ocrmypdf_task(from_file, to_pdf))
101
+ background_response(ocrmypdf_task(from_file, to_pdf))
102
+ ---
103
+ ############## Background document assembly #################
104
+ ---
105
+ generic object: ALDocumentBundle
106
+ code: |
107
+ x.generate_downloads_task = background_action(x.attr_name('create_downloads'))
108
+ ---
109
+ generic object: ALDocumentBundle
110
+ event: x.create_downloads
111
+ code: |
112
+ download_response = x.get_cacheable_documents(key="final", pdf=True, include_full_pdf=True)
113
+ background_response_action(x.attr_name('save_downloads'), download_response=download_response)
114
+ ---
115
+ generic object: ALDocumentBundle
116
+ code: |
117
+ x.generate_downloads_with_docx_task = background_action(x.attr_name('create_downloads_with_docx'))
118
+ ---
119
+ generic object: ALDocumentBundle
120
+ event: x.create_downloads_with_docx
121
+ code: |
122
+ download_response = x.get_cacheable_documents(key="final", pdf=True, docx=True, include_full_pdf=True)
123
+ background_response_action(x.attr_name('save_downloads'), download_response=download_response)
124
+ ---
125
+ generic object: ALDocumentBundle
126
+ event: x.save_downloads
127
+ code: |
128
+ x._downloadable_files = action_argument('download_response')
129
+
130
+ background_response()
131
+ ---
132
+ id: waiting screen
133
+ question: |
134
+ Please wait while we make your documents
135
+ subquestion: |
136
+ This can take a few minutes.
137
+
138
+ <div class="spinner-border text-primary d-flex justify-content-center" role="status">
139
+ <span class="sr-only">Making documents...</span>
140
+ </div>
141
+ event: al_download_waiting_screen
142
+ reload: True
143
+ ---
144
+ ########## Background preview assembly ################
145
+ ---
146
+ generic object: ALDocumentBundle
147
+ code: |
148
+ x.generate_preview_task = background_action(x.attr_name('generate_preview_event'))
149
+ ---
150
+ generic object: ALDocumentBundle
151
+ event: x.generate_preview_event
152
+ code: |
153
+ preview_response = x.as_pdf(key="preview")
154
+ background_response_action(x.attr_name('save_preview'), preview_response=preview_response)
155
+ ---
156
+ generic object: ALDocumentBundle
157
+ event: x.save_preview
158
+ code: |
159
+ x._preview_file = action_argument('preview_response')
160
+ background_response()
161
+ ---
162
+ id: preview waiting screen
163
+ question: |
164
+ Please wait while we generate a preview of your document
165
+ subquestion: |
166
+ This can take a few minutes.
167
+
168
+ <div class="spinner-border text-primary d-flex justify-content-center" role="status">
169
+ <span class="sr-only">Generating preview...</span>
170
+ </div>
171
+ event: al_preview_waiting_screen
172
+ reload: True
@@ -163,17 +163,34 @@ code: |
163
163
  package_name = str(user_info().package)
164
164
  ---
165
165
  code: |
166
+ # github_repo_name is used to direct issue feedback to the right repository
167
+ # Normally you will customize this in your package
166
168
  if package_name and not "playground" in package_name:
167
169
  github_repo_name = package_name.replace('.','-')
168
170
  else:
169
171
  github_repo_name = "docassemble-AssemblyLine"
170
172
  ---
171
173
  code: |
172
- # Username or organization name for Github repositories
173
- # Used to direct feedback to the right place and to check for
174
- # the last commit date.
174
+ # github_about_repo_name is used to lookup the last commit date on the default about page
175
+ # defaults to the same value as github_repo_name
176
+ github_about_repo_name = github_repo_name
177
+ ---
178
+ code: |
179
+ # github_user is the `username` or `organization name` part of the URL
180
+ # on github where you want the feedback form to create issues. I.e., the owner of that repository.
181
+
182
+ # Example: if you want issues to appear on a repository at https://github.com/suffolklitlab/docassemble-AssemblyLine,
183
+ # then `github_user` should be `suffolklitlab`
184
+
185
+ # defaults to the "default repository owner" value in the global configuration, under the "github issues" section
186
+
175
187
  github_user = get_config("github issues",{}).get("default repository owner","").strip() or "suffolklitlab"
176
188
  ---
189
+ code: |
190
+ # github_about_user is used to lookup the last commit date on the default about page
191
+ # defaults to the same value as github_user
192
+ github_about_user = github_user
193
+ ---
177
194
  code: |
178
195
  feedback_form = "docassemble.AssemblyLine:feedback.yml"
179
196
  ---
@@ -347,7 +364,7 @@ code: |
347
364
  github_url = "https://github.com/" + github_user + "/" + github_repo_name
348
365
  ---
349
366
  code: |
350
- res = github_modified_date(github_user, github_repo_name)
367
+ res = github_modified_date(github_about_user, github_about_repo_name)
351
368
  if res:
352
369
  package_updated_on = res.format('yyyy-MM-dd')
353
370
  else:
@@ -25,9 +25,20 @@ subquestion: |
25
25
  Searching is not case sensitive.
26
26
  fields:
27
27
  - Keyword: search_keyword
28
+ - Limit metadata column: limit_column_name
29
+ required: False
30
+ - To value: limit_column_value
31
+ required: False
28
32
  ---
29
33
  code: |
30
- matching_results = find_matching_sessions(search_keyword, user_id="all")
34
+ if limit_column_name:
35
+ matching_results = find_matching_sessions(
36
+ search_keyword, user_id="all", metadata_filters = {
37
+ limit_column_name: (limit_column_value, "ILIKE")
38
+ }
39
+ )
40
+ else:
41
+ matching_results = find_matching_sessions(search_keyword, user_id="all")
31
42
  ---
32
43
  event: no_matches
33
44
  question: |
@@ -132,6 +132,7 @@ code: |
132
132
  sections:
133
133
  - section_in_progress_forms: In progress forms
134
134
  - section_answer_sets: Answer sets
135
+ - section_search: Search
135
136
  progressive: False
136
137
  ---
137
138
  # A code block is the only way to show navigation with custom labels (mako isn't allowed in `sections`)
@@ -144,7 +145,10 @@ code: |
144
145
  },
145
146
  {
146
147
  "section_answer_sets": ANSWER_SETS_TITLE or word("Answer sets")
147
- }
148
+ },
149
+ {
150
+ "section_search": word("Search")
151
+ },
148
152
  ]
149
153
  )
150
154
  ---
@@ -261,6 +265,10 @@ subquestion: |
261
265
  documents.
262
266
  % endif
263
267
 
268
+ % if showifdef("limit_filename") or showifdef("search_keyword"):
269
+ ${ session_list_html(answers = find_matching_sessions(filenames={limit_filename} if limit_filename else None, keyword=search_keyword), filename=None, limit=20, offset=session_page*20, exclude_filenames=al_sessions_to_exclude_from_interview_list, exclude_newly_started_sessions=True) }
270
+
271
+ % else:
264
272
  ${ session_list_html(filename=None, limit=20, offset=session_page*20, exclude_filenames=al_sessions_to_exclude_from_interview_list, exclude_newly_started_sessions=True) }
265
273
 
266
274
  <nav aria-label="Page navigation">
@@ -273,8 +281,12 @@ subquestion: |
273
281
  % endif
274
282
  </ul>
275
283
  </nav>
276
- % else:
277
- You do not have any current forms in progress
284
+ % endif
285
+
286
+ % endif
287
+
288
+ % if showifdef("limit_filename") or showifdef("search_keyword"):
289
+ ${ action_button_html(url_action("delete_results_action"), label=word("Clear search results"), size="md", color="secondary", icon="times-circle", id_tag="al-clear-search-results") }
278
290
  % endif
279
291
  # TODO: might be able to save some DB queries here but performance is good
280
292
  section: section_in_progress_forms
@@ -304,6 +316,25 @@ script:
304
316
  });
305
317
  </script>
306
318
  ---
319
+ continue button field: section_search
320
+ section: section_search
321
+ question: |
322
+ Search
323
+ % if PAGE_QUESTION:
324
+ ${ str(PAGE_QUESTION).lower() }
325
+ % else:
326
+ in progress forms
327
+ % endif
328
+ subquestion: |
329
+ Use a keyword to find results that match the title or description of the session.
330
+ fields:
331
+ - Limit by form title (optional): limit_filename
332
+ required: False
333
+ code: |
334
+ get_combined_filename_list()
335
+ - Search term (optional): search_keyword
336
+ required: False
337
+ ---
307
338
  event: section_answer_sets
308
339
  id: answer set list
309
340
  question: |
@@ -441,3 +472,8 @@ code: |
441
472
  ),
442
473
  )
443
474
  )
475
+ ---
476
+ event: delete_results_action
477
+ code: |
478
+ undefine("limit_filename")
479
+ undefine("search_keyword")
@@ -0,0 +1,65 @@
1
+ ---
2
+ include:
3
+ - assembly_line.yml
4
+ ---
5
+ metadata:
6
+ title: ALDocument Background Processing
7
+ ---
8
+ mandatory: True
9
+ code: |
10
+ intro_screen
11
+ if not al_user_bundle.generate_preview_task.ready():
12
+ al_preview_waiting_screen
13
+ preview_screen
14
+ # if not al_user_bundle.generate_downloads_task.ready(): # Without DOCX
15
+ if not al_user_bundle.generate_downloads_with_docx_task.ready(): # With DOCX
16
+ al_download_waiting_screen
17
+ download_screen
18
+ ---
19
+ continue button field: intro_screen
20
+ question: |
21
+ Intro screen
22
+ ---
23
+ id: preview_screen
24
+ continue button field: preview_screen
25
+ question: |
26
+ Preview the documents
27
+ subquestion: |
28
+ Your documents are ready for preview.
29
+
30
+ Click the thumbnail below to view the preview of your documents. It will open in a new tab.
31
+
32
+ ${ al_user_bundle._preview_file }
33
+ ---
34
+ id: download
35
+ event: download_screen
36
+ question: |
37
+ Download the documents
38
+ subquestion: |
39
+ Your documents are ready for download.
40
+
41
+ ${ al_user_bundle.download_list_html(use_previously_cached_files=True, include_full_pdf=True) }
42
+ ---
43
+ objects:
44
+ - al_user_bundle: ALDocumentBundle.using(
45
+ elements = [pdf_1, docx_1],
46
+ title = "Background processed bundle",
47
+ enabled = True,
48
+ filename = "background_processed_bundle",
49
+ )
50
+ ---
51
+ objects:
52
+ - pdf_1: ALDocument.using( title="PDF 1 with a lot of text for the title of this document", filename="pdf_doc_1", enabled=True, has_addendum=False )
53
+ - docx_1: ALDocument.using( title="Docx 1 also with a lot of text for the title of this document", filename="docx_doc_1", enabled=True, has_addendum=False )
54
+ ---
55
+ attachment:
56
+ variable name: pdf_1[i]
57
+ pdf template file: test_aldocument_pdf_1.pdf
58
+ filename: pdf_1
59
+ fields:
60
+ - "sample_field": "Sample input"
61
+ ---
62
+ attachment:
63
+ variable name: docx_1[i]
64
+ docx template file: test_aldocument_docx_1.docx
65
+ filename: docx_1
@@ -5,4 +5,5 @@ pandas-stubs
5
5
  sqlalchemy[mypy]
6
6
  types-PyYAML
7
7
  PyGithub
8
- types-requests
8
+ types-requests
9
+ types-psycopg2