aipscan 0.9.0.dev5__tar.gz → 0.9.0.dev10__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 (163) hide show
  1. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/.gitignore +1 -0
  2. aipscan-0.9.0.dev10/AIPscan/Aggregator/celery_helpers.py +46 -0
  3. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/database_helpers.py +2 -2
  4. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/mets_parse_helpers.py +18 -10
  5. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/task_helpers.py +0 -12
  6. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/tasks.py +13 -8
  7. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/templates/storage_service.html +2 -2
  8. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/tests/test_database_helpers.py +3 -2
  9. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/tests/test_task_helpers.py +0 -15
  10. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/tests/test_tasks.py +50 -33
  11. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/views.py +6 -6
  12. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Data/__init__.py +3 -2
  13. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Data/report_data.py +2 -2
  14. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Data/tests/test_largest_aips.py +2 -1
  15. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Data/tests/test_largest_files.py +3 -2
  16. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/templates/aips.html +3 -3
  17. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/templates/report_ingest_log_gantt.html +1 -1
  18. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/templates/report_ingest_log_tabular.html +6 -6
  19. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/templates/reports.html +4 -4
  20. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/views.py +13 -12
  21. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/__init__.py +12 -1
  22. aipscan-0.9.0.dev10/AIPscan/cli.py +168 -0
  23. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/decorators.py +3 -1
  24. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/helpers.py +41 -5
  25. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/models.py +1 -1
  26. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/static/js/aggregator/storage_service.js +22 -1
  27. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/templates/report_base.html +3 -2
  28. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/test_helpers.py +7 -0
  29. aipscan-0.9.0.dev10/AIPscan/tests/test_cli.py +133 -0
  30. aipscan-0.9.0.dev10/AIPscan/tests/test_helpers.py +65 -0
  31. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/tests/test_models.py +3 -2
  32. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/PKG-INFO +15 -15
  33. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/README.md +13 -14
  34. aipscan-0.9.0.dev10/build_config/entry/report_base.entry.js +5 -0
  35. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/build_config/plot_formats_count.config.js +4 -1
  36. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/package-lock.json +15 -15
  37. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/package.json +3 -3
  38. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/pyproject.toml +4 -2
  39. aipscan-0.9.0.dev5/AIPscan/Aggregator/celery_helpers.py +0 -12
  40. aipscan-0.9.0.dev5/AIPscan/tests/test_helpers.py +0 -29
  41. aipscan-0.9.0.dev5/build_config/entry/report_base.entry.js +0 -3
  42. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/API/__init__.py +0 -0
  43. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/API/fields.py +0 -0
  44. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/API/namespace_data.py +0 -0
  45. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/API/namespace_infos.py +0 -0
  46. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/API/namespace_report_data.py +0 -0
  47. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/API/views.py +0 -0
  48. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/__init__.py +0 -0
  49. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/forms.py +0 -0
  50. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/templates/confirm.html +0 -0
  51. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/templates/edit_storage_service.html +0 -0
  52. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/templates/result_message.html +0 -0
  53. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/templates/storage_services.html +0 -0
  54. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/tests/__init__.py +0 -0
  55. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/tests/fixtures/features_mets/features-mets-added-agents.xml +0 -0
  56. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/tests/fixtures/features_mets/features-mets.xml +0 -0
  57. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/tests/fixtures/images_mets/images.xml +0 -0
  58. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/tests/fixtures/iso_mets/iso_mets.xml +0 -0
  59. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/tests/fixtures/original_name_mets/dataverse_example.xml +0 -0
  60. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/tests/fixtures/original_name_mets/document-empty-dirs.xml +0 -0
  61. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/tests/fixtures/package_json/packages.json +0 -0
  62. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/tests/test_mets.py +0 -0
  63. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/tests/test_types.py +0 -0
  64. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/tests/test_views.py +0 -0
  65. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Aggregator/types.py +0 -0
  66. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Data/data.py +0 -0
  67. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Data/fields.py +0 -0
  68. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Data/report_data_typesense.py +0 -0
  69. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Data/tests/__init__.py +0 -0
  70. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Data/tests/test_agents_transfers.py +0 -0
  71. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Data/tests/test_aip_contents.py +0 -0
  72. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Data/tests/test_aips_by_format.py +0 -0
  73. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Data/tests/test_aips_by_puid.py +0 -0
  74. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Data/tests/test_format_versions_count.py +0 -0
  75. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Data/tests/test_formats_count.py +0 -0
  76. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Data/tests/test_preservation_derivatives.py +0 -0
  77. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Data/tests/test_storage_locations.py +0 -0
  78. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Home/__init__.py +0 -0
  79. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Home/views.py +0 -0
  80. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/__init__.py +0 -0
  81. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/database_helpers.py +0 -0
  82. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/helpers.py +0 -0
  83. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/report_aip_contents.py +0 -0
  84. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/report_aips_by_format.py +0 -0
  85. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/report_aips_by_puid.py +0 -0
  86. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/report_format_versions_count.py +0 -0
  87. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/report_formats_count.py +0 -0
  88. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/report_ingest_log.py +0 -0
  89. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/report_largest_aips.py +0 -0
  90. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/report_largest_files.py +0 -0
  91. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/report_preservation_derivatives.py +0 -0
  92. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/report_storage_locations.py +0 -0
  93. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/request_params.py +0 -0
  94. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/templates/aip.html +0 -0
  95. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/templates/chart_formats_count.html +0 -0
  96. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/templates/file.html +0 -0
  97. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/templates/plot_formats_count.html +0 -0
  98. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/templates/report_aip_contents.html +0 -0
  99. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/templates/report_aips_by_format.html +0 -0
  100. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/templates/report_aips_by_puid.html +0 -0
  101. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/templates/report_buttons.html +0 -0
  102. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/templates/report_buttons_print_only.html +0 -0
  103. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/templates/report_format_versions_count.html +0 -0
  104. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/templates/report_formats_count.html +0 -0
  105. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/templates/report_largest_aips.html +0 -0
  106. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/templates/report_largest_files.html +0 -0
  107. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/templates/report_preservation_derivatives.html +0 -0
  108. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/templates/report_storage_locations.html +0 -0
  109. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/templates/report_storage_locations_usage_over_time.html +0 -0
  110. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/tests/__init__.py +0 -0
  111. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/tests/fixtures/storage_location_usage_cumulative_aips.csv +0 -0
  112. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/tests/fixtures/storage_location_usage_cumulative_files.csv +0 -0
  113. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/tests/fixtures/storage_location_usage_cumulative_size.csv +0 -0
  114. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/tests/fixtures/storage_location_usage_differential_aips.csv +0 -0
  115. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/tests/fixtures/storage_location_usage_differential_files.csv +0 -0
  116. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/tests/fixtures/storage_location_usage_differential_size.csv +0 -0
  117. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/tests/test_aip_contents.py +0 -0
  118. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/tests/test_aips_by_file_format.py +0 -0
  119. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/tests/test_aips_by_puid.py +0 -0
  120. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/tests/test_format_versions_count.py +0 -0
  121. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/tests/test_formats_count.py +0 -0
  122. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/tests/test_helpers.py +0 -0
  123. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/tests/test_ingest_log.py +0 -0
  124. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/tests/test_largest_aips.py +0 -0
  125. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/tests/test_largest_files.py +0 -0
  126. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/tests/test_preservation_derivatives.py +0 -0
  127. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/tests/test_storage_locations.py +0 -0
  128. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/tests/test_update_dates.py +0 -0
  129. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/Reporter/tests/test_views.py +0 -0
  130. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/User/__init__.py +0 -0
  131. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/User/forms.py +0 -0
  132. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/User/views.py +0 -0
  133. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/celery.py +0 -0
  134. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/config.py +0 -0
  135. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/conftest.py +0 -0
  136. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/navbar.py +0 -0
  137. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/run.py +0 -0
  138. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/static/css/custom.css +0 -0
  139. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/static/css/style_ingest_log.css +0 -0
  140. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/static/favicon.ico +0 -0
  141. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/static/js/report.js +0 -0
  142. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/static/js/reporter/aips.js +0 -0
  143. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/static/js/reporter/chart_formats_count.js +0 -0
  144. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/static/js/reporter/plot_formats_count.js +0 -0
  145. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/static/js/reporter/reports.js +0 -0
  146. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/templates/base.html +0 -0
  147. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/templates/error/404.html +0 -0
  148. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/templates/partials/navbar.html +0 -0
  149. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/tests/__init__.py +0 -0
  150. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/tests/test_typesense_helpers.py +0 -0
  151. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/tests/test_typsense_test_helpers.py +0 -0
  152. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/typesense_helpers.py +0 -0
  153. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/typesense_test_helpers.py +0 -0
  154. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/AIPscan/worker.py +0 -0
  155. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/LICENSE +0 -0
  156. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/build.py +0 -0
  157. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/build_config/base.config.js +0 -0
  158. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/build_config/chart_formats_count.config.js +0 -0
  159. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/build_config/entry/base.entry.js +0 -0
  160. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/build_config/entry/chart_formats_count.entry.js +0 -0
  161. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/build_config/entry/plot_formats_count.entry.js +0 -0
  162. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/build_config/entry/shared/base_shared.js +0 -0
  163. {aipscan-0.9.0.dev5 → aipscan-0.9.0.dev10}/build_config/report_base.config.js +0 -0
@@ -3,6 +3,7 @@ celerytasks.db
3
3
  AIPscan/Aggregator/downloads/
4
4
  AIPscan/static/dist/
5
5
 
6
+ /.env
6
7
  [.]venv/
7
8
  node_modules/
8
9
  .tox/
@@ -0,0 +1,46 @@
1
+ import logging
2
+ from functools import wraps
3
+
4
+ from AIPscan import db
5
+ from AIPscan.models import package_tasks
6
+
7
+ logger = logging.getLogger(__name__)
8
+
9
+
10
+ def write_celery_update(package_lists_task, workflow_coordinator):
11
+ # Write status update to celery model.
12
+ package_task = package_tasks(
13
+ package_task_id=package_lists_task.id,
14
+ workflow_coordinator_id=workflow_coordinator.request.id,
15
+ )
16
+ db.session.add(package_task)
17
+ db.session.commit()
18
+
19
+
20
+ def with_db_session(func):
21
+ """Ensure the scoped session is cleaned up around each call."""
22
+
23
+ @wraps(func)
24
+ def wrapper(*args, **kwargs):
25
+ func_name = func.__name__
26
+ try:
27
+ return func(*args, **kwargs)
28
+ except Exception:
29
+ logger.exception("Unhandled exception in %s", func_name)
30
+ try:
31
+ db.session.rollback()
32
+ logger.debug("Rolled back session after error in %s", func_name)
33
+ except Exception:
34
+ logger.exception(
35
+ "Failed to rollback session after error in %s", func_name
36
+ )
37
+ raise
38
+ finally:
39
+ try:
40
+ db.session.remove()
41
+ except Exception:
42
+ logger.exception(
43
+ "Failed to dispose session after call to %s", func_name
44
+ )
45
+
46
+ return wrapper
@@ -300,7 +300,7 @@ def _add_normalization_date(file_id):
300
300
 
301
301
  :param file_id: File ID
302
302
  """
303
- file_ = File.query.get(file_id)
303
+ file_ = db.session.get(File, file_id)
304
304
  creation_event = Event.query.filter_by(file_id=file_.id, type="creation").first()
305
305
  if creation_event is not None:
306
306
  file_.date_created = creation_event.date
@@ -309,7 +309,7 @@ def _add_normalization_date(file_id):
309
309
 
310
310
  def _add_premis_object_xml(fs_entry, file_id):
311
311
  """Add string representation of PREMIS Object to File object."""
312
- file_ = File.query.get(file_id)
312
+ file_ = db.session.get(File, file_id)
313
313
 
314
314
  if hasattr(fs_entry, "amdsecs"):
315
315
  for ss in fs_entry.amdsecs[0].subsections:
@@ -2,13 +2,15 @@
2
2
  information from an AIP METS file.
3
3
  """
4
4
 
5
+ import os
6
+
5
7
  import lxml
6
8
  import metsrw
7
9
  import requests
8
10
 
9
11
  from AIPscan.Aggregator.task_helpers import create_numbered_subdirs
10
12
  from AIPscan.Aggregator.task_helpers import get_mets_url
11
- from AIPscan.Aggregator.task_helpers import write_mets
13
+ from AIPscan.helpers import stream_write_and_hash
12
14
 
13
15
 
14
16
  class METSError(Exception):
@@ -83,17 +85,23 @@ def get_aip_original_name(mets):
83
85
  def download_mets(
84
86
  storage_service, package_uuid, relative_path_to_mets, timestamp, package_list_no
85
87
  ):
86
- """Download METS from the storage service."""
88
+ """Download METS from the storage service.
87
89
 
88
- # Request the METS file.
89
- mets_response = requests.get(
90
- get_mets_url(storage_service, package_uuid, relative_path_to_mets)
91
- )
90
+ The METS document is streamed directly to disk while its SHA256 digest is
91
+ computed so that the caller can avoid re-reading the file.
92
+ """
92
93
 
93
- # Create a directory to download the METS to.
94
94
  numbered_subdir = create_numbered_subdirs(timestamp, package_list_no)
95
+ download_file = os.path.join(numbered_subdir, f"METS.{package_uuid}.xml")
95
96
 
96
- # Output METS to a convenient location to later be parsed.
97
- download_file = write_mets(mets_response, package_uuid, numbered_subdir)
97
+ mets_response = requests.get(
98
+ get_mets_url(storage_service, package_uuid, relative_path_to_mets),
99
+ stream=True,
100
+ )
101
+
102
+ try:
103
+ mets_hash = stream_write_and_hash(mets_response, download_file)
104
+ finally:
105
+ mets_response.close()
98
106
 
99
- return download_file
107
+ return download_file, mets_hash
@@ -142,17 +142,5 @@ def create_numbered_subdirs(timestamp, package_list_number):
142
142
  return numbered_subdir
143
143
 
144
144
 
145
- def write_mets(http_response, package_uuid, subdir):
146
- """Given a http response containing our METS data, create the path
147
- we want to store our METS at, and then stream the response into a
148
- file.
149
- """
150
- mets_file = f"METS.{package_uuid}.xml"
151
- download_file = os.path.join(subdir, mets_file)
152
- with open(download_file, "wb") as file:
153
- file.write(http_response.content)
154
- return download_file
155
-
156
-
157
145
  def summarize_fetch_job_results(fetch_job):
158
146
  return f"aips: '{fetch_job.total_aips}'; sips: '{fetch_job.total_sips}'; dips: '{fetch_job.total_dips}'; deleted: '{fetch_job.total_deleted_aips}'; replicated: '{fetch_job.total_replicas}'"
@@ -9,6 +9,7 @@ from celery.utils.log import get_task_logger
9
9
  from AIPscan import db
10
10
  from AIPscan import typesense_helpers
11
11
  from AIPscan.Aggregator import database_helpers
12
+ from AIPscan.Aggregator.celery_helpers import with_db_session
12
13
  from AIPscan.Aggregator.celery_helpers import write_celery_update
13
14
  from AIPscan.Aggregator.mets_parse_helpers import METSError
14
15
  from AIPscan.Aggregator.mets_parse_helpers import download_mets
@@ -19,7 +20,6 @@ from AIPscan.Aggregator.task_helpers import parse_package_list_file
19
20
  from AIPscan.Aggregator.task_helpers import process_package_object
20
21
  from AIPscan.Aggregator.task_helpers import summarize_fetch_job_results
21
22
  from AIPscan.celery import celery
22
- from AIPscan.helpers import file_sha256_hash
23
23
  from AIPscan.models import AIP
24
24
  from AIPscan.models import Agent
25
25
  from AIPscan.models import FetchJob
@@ -63,7 +63,7 @@ def start_mets_task(
63
63
  """Initiate a get_mets task worker and record the event in the
64
64
  celery database.
65
65
  """
66
- storage_service = StorageService.query.get(storage_service_id)
66
+ storage_service = db.session.get(StorageService, storage_service_id)
67
67
  storage_location = database_helpers.create_or_update_storage_location(
68
68
  current_location, storage_service
69
69
  )
@@ -111,6 +111,7 @@ def delete_aip(uuid):
111
111
 
112
112
 
113
113
  @celery.task(bind=True)
114
+ @with_db_session
114
115
  def workflow_coordinator(
115
116
  self, timestamp, storage_service_id, fetch_job_id, packages_directory
116
117
  ):
@@ -179,6 +180,7 @@ def make_request(request_url, request_url_without_api_key):
179
180
 
180
181
 
181
182
  @celery.task(bind=True)
183
+ @with_db_session
182
184
  def package_lists_request(self, storage_service_id, timestamp, packages_directory):
183
185
  """Request package lists from the storage service. Package lists
184
186
  will contain details of the AIPs that we want to download.
@@ -188,7 +190,7 @@ def package_lists_request(self, storage_service_id, timestamp, packages_director
188
190
  COUNT = "total_count"
189
191
  IN_PROGRESS = "IN PROGRESS"
190
192
 
191
- storage_service = StorageService.query.get(storage_service_id)
193
+ storage_service = db.session.get(StorageService, storage_service_id)
192
194
 
193
195
  (
194
196
  base_url,
@@ -245,6 +247,7 @@ def start_index_task(fetch_job_id):
245
247
 
246
248
 
247
249
  @celery.task()
250
+ @with_db_session
248
251
  def index_task(fetch_job_id):
249
252
  # Update Typesense index
250
253
  typesense_helpers.initialize_index()
@@ -268,6 +271,7 @@ def index_task(fetch_job_id):
268
271
 
269
272
 
270
273
  @celery.task()
274
+ @with_db_session
271
275
  def get_mets(
272
276
  package_uuid,
273
277
  aip_size,
@@ -300,8 +304,8 @@ def get_mets(
300
304
  tasklogger = customlogger
301
305
 
302
306
  # Download METS file
303
- storage_service = StorageService.query.get(storage_service_id)
304
- download_file = download_mets(
307
+ storage_service = db.session.get(StorageService, storage_service_id)
308
+ download_file, mets_hash = download_mets(
305
309
  storage_service,
306
310
  package_uuid,
307
311
  relative_path_to_mets,
@@ -309,7 +313,6 @@ def get_mets(
309
313
  package_list_no,
310
314
  )
311
315
  mets_name = os.path.basename(download_file)
312
- mets_hash = file_sha256_hash(download_file)
313
316
 
314
317
  # If METS file's hash matches an existing value, this is a duplicate of an
315
318
  # existing AIP and we can safely ignore it.
@@ -370,8 +373,9 @@ def get_mets(
370
373
 
371
374
 
372
375
  @celery.task()
376
+ @with_db_session
373
377
  def delete_fetch_job(fetch_job_id):
374
- fetch_job = FetchJob.query.get(fetch_job_id)
378
+ fetch_job = db.session.get(FetchJob, fetch_job_id)
375
379
  if os.path.exists(fetch_job.download_directory):
376
380
  shutil.rmtree(fetch_job.download_directory)
377
381
  db.session.delete(fetch_job)
@@ -379,8 +383,9 @@ def delete_fetch_job(fetch_job_id):
379
383
 
380
384
 
381
385
  @celery.task()
386
+ @with_db_session
382
387
  def delete_storage_service(storage_service_id):
383
- storage_service = StorageService.query.get(storage_service_id)
388
+ storage_service = db.session.get(StorageService, storage_service_id)
384
389
  mets_fetch_jobs = FetchJob.query.filter_by(
385
390
  storage_service_id=storage_service_id
386
391
  ).all()
@@ -21,7 +21,7 @@
21
21
  </td>
22
22
  <td>
23
23
  <span id="apikey">&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull;&bull; </span>
24
- <i id="apikeyBtn" class="fa fa-eye" aria-hidden="true"></i>
24
+ <i id="apikeyBtn" class="fa-solid fa-eye" aria-hidden="true"></i>
25
25
  </td>
26
26
  </tr>
27
27
  <tr><td width=20%><strong>Download limit</strong></td><td>{{ storage_service.download_limit}}</td></tr>
@@ -62,7 +62,7 @@
62
62
  <td>{{ mets_fetch_job.download_start }}</td>
63
63
  <td>{% if mets_fetch_job.download_end %} {{ mets_fetch_job.download_end - mets_fetch_job.download_start }} {% endif %}</td>
64
64
  <td>{{ mets_fetch_job.total_packages }} packages
65
- <i class="fa fa-info-circle fa-lg" id="{{ mets_fetch_job.id }}" style="margin-left: 5px;"></i><br/>
65
+ <i class="fa-solid fa-circle-info fa-lg" id="{{ mets_fetch_job.id }}" style="margin-left: 5px;"></i><br/>
66
66
  <div class="stats" id="stats-{{ mets_fetch_job.id }}">
67
67
  <span class="text-muted">
68
68
  <small>
@@ -5,6 +5,7 @@ from datetime import datetime
5
5
  import metsrw
6
6
  import pytest
7
7
 
8
+ from AIPscan import db
8
9
  from AIPscan.Aggregator import database_helpers
9
10
  from AIPscan.Aggregator import types
10
11
  from AIPscan.conftest import ORIGIN_PIPELINE
@@ -294,7 +295,7 @@ def test_create_or_update_storage_location(
294
295
  "AIPscan.Aggregator.database_helpers.create_storage_location_object"
295
296
  )
296
297
 
297
- storage_service = StorageService.query.get(1)
298
+ storage_service = db.session.get(StorageService, 1)
298
299
 
299
300
  storage_location = database_helpers.create_or_update_storage_location(
300
301
  current_location=current_location, storage_service=storage_service
@@ -331,7 +332,7 @@ def test_create_or_update_pipeline(
331
332
  )
332
333
  get_storage_service_api_url.return_value = (None, None)
333
334
 
334
- storage_service = StorageService.query.get(1)
335
+ storage_service = db.session.get(StorageService, 1)
335
336
 
336
337
  pipeline = database_helpers.create_or_update_pipeline(
337
338
  origin_pipeline=origin_pipeline, storage_service=storage_service
@@ -1,6 +1,5 @@
1
1
  import json
2
2
  import os
3
- import uuid
4
3
  from datetime import datetime
5
4
 
6
5
  import pytest
@@ -175,20 +174,6 @@ def test_create_numbered_subdirs(timestamp, package_list_number, result, mocker)
175
174
  assert subdir_string == result
176
175
 
177
176
 
178
- def test_write_mets(mocker, tmpdir):
179
- """Ensure that METS is written to expected location."""
180
- CONTENT = b"test content"
181
- http_response = mocker.MagicMock()
182
- http_response.content = CONTENT
183
- package_uuid = str(uuid.uuid4())
184
- expected_path = os.path.join(tmpdir, f"METS.{package_uuid}.xml")
185
-
186
- actual_path = task_helpers.write_mets(http_response, package_uuid, tmpdir)
187
- assert expected_path == actual_path
188
- with open(actual_path, "rb") as mets_file:
189
- assert mets_file.read() == CONTENT
190
-
191
-
192
177
  @pytest.fixture()
193
178
  def packages():
194
179
  fixtures_path = os.path.join("package_json", "packages.json")
@@ -7,6 +7,7 @@ from datetime import datetime
7
7
  import celery
8
8
  import pytest
9
9
 
10
+ from AIPscan import db
10
11
  from AIPscan import test_helpers
11
12
  from AIPscan.Aggregator.tasks import TaskError
12
13
  from AIPscan.Aggregator.tasks import delete_aip
@@ -67,16 +68,21 @@ def test_get_mets_task(app_instance, tmpdir, mocker, fixture_path, package_uuid)
67
68
  timestamp_str,
68
69
  package_list_no,
69
70
  ):
70
- return mets_file
71
+ return mets_file, test_helpers.file_sha256_hash(mets_file)
71
72
 
72
73
  mocker.patch("AIPscan.Aggregator.tasks.download_mets", mock_download_mets)
73
74
  delete_mets_file = mocker.patch("AIPscan.Aggregator.tasks.os.remove")
74
75
 
75
76
  storage_service = test_helpers.create_test_storage_service()
77
+ storage_service_id = storage_service.id
78
+
76
79
  storage_location = test_helpers.create_test_storage_location(
77
- storage_service_id=storage_service.id
80
+ storage_service_id=storage_service_id
78
81
  )
79
- pipeline = test_helpers.create_test_pipeline(storage_service_id=storage_service.id)
82
+ storage_location_id = storage_location.id
83
+
84
+ pipeline = test_helpers.create_test_pipeline(storage_service_id=storage_service_id)
85
+ pipeline_id = pipeline.id
80
86
 
81
87
  get_storage_location = mocker.patch(
82
88
  "AIPscan.Aggregator.database_helpers.create_or_update_storage_location"
@@ -84,7 +90,7 @@ def test_get_mets_task(app_instance, tmpdir, mocker, fixture_path, package_uuid)
84
90
  get_storage_location.return_value = storage_location
85
91
 
86
92
  # No AIPs should exist at this point.
87
- aips = _get_aips(storage_service.id)
93
+ aips = _get_aips(storage_service_id)
88
94
  assert not aips
89
95
 
90
96
  # Set up custom logger and add handler to capture output
@@ -93,8 +99,9 @@ def test_get_mets_task(app_instance, tmpdir, mocker, fixture_path, package_uuid)
93
99
 
94
100
  # Create AIP and verify record.
95
101
  fetch_job1 = test_helpers.create_test_fetch_job(
96
- storage_service_id=storage_service.id
102
+ storage_service_id=storage_service_id
97
103
  )
104
+ fetch_job1_id = fetch_job1.id
98
105
  get_mets(
99
106
  package_uuid=package_uuid,
100
107
  aip_size=1000,
@@ -103,22 +110,24 @@ def test_get_mets_task(app_instance, tmpdir, mocker, fixture_path, package_uuid)
103
110
  .replace(microsecond=0)
104
111
  .strftime("%Y-%m-%d-%H-%M-%S"),
105
112
  package_list_no=1,
106
- storage_service_id=storage_service.id,
107
- storage_location_id=storage_location.id,
108
- fetch_job_id=fetch_job1.id,
109
- origin_pipeline_id=pipeline.id,
113
+ storage_service_id=storage_service_id,
114
+ storage_location_id=storage_location_id,
115
+ fetch_job_id=fetch_job1_id,
116
+ origin_pipeline_id=pipeline_id,
110
117
  customlogger=customlogger,
111
118
  )
112
- aips = _get_aips(storage_service.id)
119
+ aips = _get_aips(storage_service_id)
113
120
  assert len(aips) == 1
114
- assert len(fetch_job1.aips) == 1
121
+ fetch_job1_refreshed = db.session.get(FetchJob, fetch_job1_id)
122
+ assert len(fetch_job1_refreshed.aips) == 1
115
123
 
116
124
  original_mets_sha256 = aips[0].mets_sha256
117
125
 
118
126
  # Try to create AIP again and verify no duplicate is created.
119
127
  fetch_job2 = test_helpers.create_test_fetch_job(
120
- storage_service_id=storage_service.id
128
+ storage_service_id=storage_service_id
121
129
  )
130
+ fetch_job2_id = fetch_job2.id
122
131
  get_mets(
123
132
  package_uuid=package_uuid,
124
133
  aip_size=1000,
@@ -127,23 +136,26 @@ def test_get_mets_task(app_instance, tmpdir, mocker, fixture_path, package_uuid)
127
136
  .replace(microsecond=0)
128
137
  .strftime("%Y-%m-%d-%H-%M-%S"),
129
138
  package_list_no=1,
130
- storage_service_id=storage_service.id,
131
- storage_location_id=storage_location.id,
132
- fetch_job_id=fetch_job2.id,
133
- origin_pipeline_id=pipeline.id,
139
+ storage_service_id=storage_service_id,
140
+ storage_location_id=storage_location_id,
141
+ fetch_job_id=fetch_job2_id,
142
+ origin_pipeline_id=pipeline_id,
134
143
  )
135
- aips = _get_aips(storage_service.id)
144
+ aips = _get_aips(storage_service_id)
136
145
  assert len(aips) == 1
137
146
  assert aips[0].mets_sha256 == original_mets_sha256
138
- assert len(fetch_job1.aips) == 1
139
- assert len(fetch_job2.aips) == 0
147
+ fetch_job1_refreshed = db.session.get(FetchJob, fetch_job1_id)
148
+ fetch_job2_refreshed = db.session.get(FetchJob, fetch_job2_id)
149
+ assert len(fetch_job1_refreshed.aips) == 1
150
+ assert len(fetch_job2_refreshed.aips) == 0
140
151
 
141
152
  # Replace METS with a new METS file and run again. The old AIP record
142
153
  # should be deleted and replaced with one from the new METS.
143
154
  mets_file = os.path.join(FIXTURES_DIR, "iso_mets", "iso_mets.xml")
144
155
  fetch_job3 = test_helpers.create_test_fetch_job(
145
- storage_service_id=storage_service.id
156
+ storage_service_id=storage_service_id
146
157
  )
158
+ fetch_job3_id = fetch_job3.id
147
159
  get_mets(
148
160
  package_uuid=package_uuid,
149
161
  aip_size=1000,
@@ -152,17 +164,20 @@ def test_get_mets_task(app_instance, tmpdir, mocker, fixture_path, package_uuid)
152
164
  .replace(microsecond=0)
153
165
  .strftime("%Y-%m-%d-%H-%M-%S"),
154
166
  package_list_no=1,
155
- storage_service_id=storage_service.id,
156
- storage_location_id=storage_location.id,
157
- fetch_job_id=fetch_job3.id,
158
- origin_pipeline_id=pipeline.id,
167
+ storage_service_id=storage_service_id,
168
+ storage_location_id=storage_location_id,
169
+ fetch_job_id=fetch_job3_id,
170
+ origin_pipeline_id=pipeline_id,
159
171
  )
160
- aips = _get_aips(storage_service.id)
172
+ aips = _get_aips(storage_service_id)
161
173
  assert len(aips) == 1
162
174
  assert aips[0].mets_sha256 != original_mets_sha256
163
- assert len(fetch_job1.aips) == 0
164
- assert len(fetch_job2.aips) == 0
165
- assert len(fetch_job3.aips) == 1
175
+ fetch_job1_refreshed = db.session.get(FetchJob, fetch_job1_id)
176
+ fetch_job2_refreshed = db.session.get(FetchJob, fetch_job2_id)
177
+ fetch_job3_refreshed = db.session.get(FetchJob, fetch_job3_id)
178
+ assert len(fetch_job1_refreshed.aips) == 0
179
+ assert len(fetch_job2_refreshed.aips) == 0
180
+ assert len(fetch_job3_refreshed.aips) == 1
166
181
 
167
182
  delete_calls = [
168
183
  mocker.call(os.path.join(FIXTURES_DIR, fixture_path)),
@@ -369,22 +384,24 @@ def test_start_index_task(app_instance, mocker):
369
384
 
370
385
  # Create test fetch job
371
386
  storage_service = test_helpers.create_test_storage_service()
387
+ storage_service_id = storage_service.id
372
388
 
373
389
  fetch_job = test_helpers.create_test_fetch_job(
374
- storage_service_id=storage_service.id
390
+ storage_service_id=storage_service_id
375
391
  )
392
+ fetch_job_id = fetch_job.id
376
393
 
377
394
  # At this point no index_tasks should exist for the fetch job
378
- index_task_obj = index_tasks.query.filter_by(fetch_job_id=fetch_job.id).first()
395
+ index_task_obj = index_tasks.query.filter_by(fetch_job_id=fetch_job_id).first()
379
396
  assert index_task_obj is None
380
397
 
381
398
  # Start mock index task, making sure it got started with the right value
382
- start_index_task(fetch_job.id)
399
+ start_index_task(fetch_job_id)
383
400
 
384
- mock_index_task.assert_called_with(fetch_job.id)
401
+ mock_index_task.assert_called_with(fetch_job_id)
385
402
 
386
403
  # At this point an index_tasks should exist for the fetch job
387
- index_task_obj = index_tasks.query.filter_by(fetch_job_id=fetch_job.id).first()
404
+ index_task_obj = index_tasks.query.filter_by(fetch_job_id=fetch_job_id).first()
388
405
  assert type(index_task_obj) is index_tasks
389
406
 
390
407
 
@@ -87,7 +87,7 @@ def ss_default():
87
87
 
88
88
  @aggregator.route("/storage_service/<storage_service_id>", methods=["GET"])
89
89
  def storage_service(storage_service_id):
90
- storage_service = StorageService.query.get(storage_service_id)
90
+ storage_service = db.session.get(StorageService, storage_service_id)
91
91
 
92
92
  if storage_service is None:
93
93
  abort(404)
@@ -111,7 +111,7 @@ def storage_services():
111
111
  @aggregator.route("/edit_storage_service/<storage_service_id>", methods=["GET", "POST"])
112
112
  def edit_storage_service(storage_service_id):
113
113
  form = StorageServiceForm()
114
- storage_service = StorageService.query.get(storage_service_id)
114
+ storage_service = db.session.get(StorageService, storage_service_id)
115
115
 
116
116
  if storage_service is None:
117
117
  abort(404)
@@ -175,7 +175,7 @@ def new_storage_service():
175
175
  "aggregator.ss_default",
176
176
  )
177
177
  def delete_storage_service(storage_service_id):
178
- storage_service = StorageService.query.get(storage_service_id)
178
+ storage_service = db.session.get(StorageService, storage_service_id)
179
179
 
180
180
  if storage_service is None:
181
181
  abort(404)
@@ -192,7 +192,7 @@ def delete_storage_service(storage_service_id):
192
192
  @aggregator.route("/new_fetch_job/<fetch_job_id>", methods=["POST"])
193
193
  def new_fetch_job(fetch_job_id):
194
194
  """Fetch and process AIP METS files from Storage Service."""
195
- storage_service = StorageService.query.get(fetch_job_id)
195
+ storage_service = db.session.get(StorageService, fetch_job_id)
196
196
 
197
197
  # Check Storage Service credentials and return 400 if invalid prior to
198
198
  # creating the Fetch Job and kicking off the Celery task.
@@ -251,12 +251,12 @@ def new_fetch_job(fetch_job_id):
251
251
  "aggregator.ss_default",
252
252
  )
253
253
  def delete_fetch_job(fetch_job_id):
254
- fetch_job = FetchJob.query.get(fetch_job_id)
254
+ fetch_job = db.session.get(FetchJob, fetch_job_id)
255
255
 
256
256
  if fetch_job is None:
257
257
  abort(404)
258
258
 
259
- storage_service = StorageService.query.get(fetch_job.storage_service_id)
259
+ storage_service = db.session.get(StorageService, fetch_job.storage_service_id)
260
260
  tasks.delete_fetch_job.delay(fetch_job_id)
261
261
 
262
262
  flash(f"Fetch job {fetch_job.download_start} is being deleted")
@@ -1,3 +1,4 @@
1
+ from AIPscan import db
1
2
  from AIPscan.Data import fields
2
3
  from AIPscan.models import StorageLocation
3
4
  from AIPscan.models import StorageService
@@ -14,7 +15,7 @@ def _get_storage_service(storage_service_id):
14
15
 
15
16
  :returns: StorageService object or None
16
17
  """
17
- return StorageService.query.get(storage_service_id)
18
+ return db.session.get(StorageService, storage_service_id)
18
19
 
19
20
 
20
21
  def get_storage_service_name(storage_service_id):
@@ -29,7 +30,7 @@ def get_storage_service_name(storage_service_id):
29
30
 
30
31
  def _get_storage_location(storage_location_id):
31
32
  """Return Storage Location with ID or None."""
32
- return StorageLocation.query.get(storage_location_id)
33
+ return db.session.get(StorageLocation, storage_location_id)
33
34
 
34
35
 
35
36
  def get_storage_location_description(storage_location_id):
@@ -270,7 +270,7 @@ def largest_files(
270
270
  except AttributeError:
271
271
  pass
272
272
 
273
- matching_aip = AIP.query.get(file_.aip_id)
273
+ matching_aip = db.session.get(AIP, file_.aip_id)
274
274
  if matching_aip is not None:
275
275
  file_info[fields.FIELD_AIP_NAME] = matching_aip.transfer_name
276
276
  file_info[fields.FIELD_AIP_UUID] = matching_aip.uuid
@@ -684,7 +684,7 @@ def _get_days_covered_by_date_range(storage_service_id, start_date, end_date):
684
684
  :returns: List of strings like "YYYY-MM-DD"
685
685
  """
686
686
  if start_date == datetime.min:
687
- storage_service = StorageService.query.get(storage_service_id)
687
+ storage_service = db.session.get(StorageService, storage_service_id)
688
688
  start_date = storage_service.earliest_aip_created
689
689
  if end_date >= datetime.now():
690
690
  end_date = datetime.now()
@@ -1,5 +1,6 @@
1
1
  import pytest
2
2
 
3
+ from AIPscan import db
3
4
  from AIPscan import typesense_helpers
4
5
  from AIPscan import typesense_test_helpers
5
6
  from AIPscan.Data import fields
@@ -48,7 +49,7 @@ def test_largest_aips(
48
49
 
49
50
 
50
51
  def test_largest_aips_typesense(app_with_populated_files, enable_typesense, mocker):
51
- doc = typesense_helpers.model_instance_to_document(AIP, AIP.query.get(1))
52
+ doc = typesense_helpers.model_instance_to_document(AIP, db.session.get(AIP, 1))
52
53
  fake_results = {"hits": [{"document": doc}]}
53
54
 
54
55
  typesense_test_helpers.fake_collection(mocker, fake_results)
@@ -3,6 +3,7 @@ import uuid
3
3
 
4
4
  import pytest
5
5
 
6
+ from AIPscan import db
6
7
  from AIPscan import typesense_helpers
7
8
  from AIPscan import typesense_test_helpers
8
9
  from AIPscan.Data import fields
@@ -116,7 +117,7 @@ def test_largest_files_elements(
116
117
  mock_get_ss_name = mocker.patch("AIPscan.Data._get_storage_service")
117
118
  mock_get_ss_name.return_value = MOCK_STORAGE_SERVICE
118
119
 
119
- mock_get_aip = mocker.patch("sqlalchemy.orm.query.Query.get")
120
+ mock_get_aip = mocker.patch("AIPscan.Data.report_data.db.session.get")
120
121
  mock_get_aip.return_value = MOCK_AIP
121
122
 
122
123
  report = report_data.largest_files(
@@ -147,7 +148,7 @@ def test_largest_files_elements(
147
148
 
148
149
 
149
150
  def test_largest_files_typesense(app_with_populated_files, enable_typesense, mocker):
150
- doc = typesense_helpers.model_instance_to_document(File, File.query.get(1))
151
+ doc = typesense_helpers.model_instance_to_document(File, db.session.get(File, 1))
151
152
  doc["transfer_name"] = "Test AIP"
152
153
  doc["aip_uuid"] = "111111111111-1111-1111-11111111"
153
154
 
@@ -12,14 +12,14 @@
12
12
 
13
13
  <div class="float-end">
14
14
  <form action="{{ url_for('reporter.view_aips') }}" method="GET" class="pr-3" id="queryform">
15
- <i class="fas fa-search"></i> Search <input name="query" id="query"/><input type="submit" hidden/>
15
+ <i class="fa-solid fa-magnifying-glass"></i> Search <input name="query" id="query"/><input type="submit" hidden/>
16
16
  </form>
17
17
  </div>
18
18
 
19
19
  <div class="report-opts" style="margin-bottom: 0.2em;">
20
20
  <div>
21
21
  <span class="fixed-width-menu-span-left">
22
- <i class="fa fa-database" aria-hidden="true"></i>
22
+ <i class="fa-solid fa-database" aria-hidden="true"></i>
23
23
  Storage Service
24
24
  </span>
25
25
  <select id="ss" method="GET" action="/">
@@ -36,7 +36,7 @@
36
36
  <div class="report-opts" style="margin-bottom: 1em;">
37
37
  <div>
38
38
  <span class="fixed-width-menu-span-left">
39
- <i class="fa fa-archive" aria-hidden="true"></i>
39
+ <i class="fa-solid fa-box-archive" aria-hidden="true"></i>
40
40
  Location
41
41
  </span>
42
42
  <select id="sl" method="GET" action="/">