geoblacklight_admin 0.0.1

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 (346) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +18 -0
  3. data/.gitignore +75 -0
  4. data/.standard.yml +4 -0
  5. data/Gemfile +59 -0
  6. data/LICENSE +21 -0
  7. data/README.md +84 -0
  8. data/Rakefile +72 -0
  9. data/app/assets/images/.keep +0 -0
  10. data/app/assets/images/aerial_photo.jpg +0 -0
  11. data/app/assets/images/archive-solid.svg +1 -0
  12. data/app/assets/images/bookmark-regular.svg +1 -0
  13. data/app/assets/images/bookmark-solid.svg +1 -0
  14. data/app/assets/images/btaa-logo.jpg +0 -0
  15. data/app/assets/images/cloud-download-alt-solid.svg +1 -0
  16. data/app/assets/images/file-import-solid.svg +1 -0
  17. data/app/assets/images/trash-alt-solid.svg +1 -0
  18. data/app/assets/javascripts/geoblacklight_admin/chosen.js +4 -0
  19. data/app/assets/javascripts/geoblacklight_admin/date_range_picker.js +173 -0
  20. data/app/assets/javascripts/geoblacklight_admin/datepicker.js +22 -0
  21. data/app/assets/javascripts/geoblacklight_admin/elements.js +38 -0
  22. data/app/assets/javascripts/geoblacklight_admin/exports.js +3 -0
  23. data/app/assets/javascripts/geoblacklight_admin/fields.js +11 -0
  24. data/app/assets/javascripts/geoblacklight_admin/geoblacklight_admin.js +2 -0
  25. data/app/assets/javascripts/geoblacklight_admin/inputmask.js +4 -0
  26. data/app/assets/javascripts/geoblacklight_admin/locale.js +5 -0
  27. data/app/assets/javascripts/geoblacklight_admin/sortable.js +2544 -0
  28. data/app/assets/javascripts/geoblacklight_admin/tooltips.js +3 -0
  29. data/app/assets/javascripts/geoblacklight_admin/truncate.js +4 -0
  30. data/app/assets/javascripts/geoblacklight_admin.js +40 -0
  31. data/app/assets/stylesheets/geoblacklight_admin/_core.scss +47 -0
  32. data/app/assets/stylesheets/geoblacklight_admin/modules/_autocomplete.scss +32 -0
  33. data/app/assets/stylesheets/geoblacklight_admin/modules/_blazer.scss +3 -0
  34. data/app/assets/stylesheets/geoblacklight_admin/modules/_code.scss +3 -0
  35. data/app/assets/stylesheets/geoblacklight_admin/modules/_datepicker.scss +477 -0
  36. data/app/assets/stylesheets/geoblacklight_admin/modules/_elements.scss +3 -0
  37. data/app/assets/stylesheets/geoblacklight_admin/modules/_forms.scss +28 -0
  38. data/app/assets/stylesheets/geoblacklight_admin/modules/_icons.scss +15 -0
  39. data/app/assets/stylesheets/geoblacklight_admin/modules/_nav.scss +9 -0
  40. data/app/assets/stylesheets/geoblacklight_admin/modules/_tables.scss +4 -0
  41. data/app/assets/stylesheets/geoblacklight_admin/modules/_toasts.scss +7 -0
  42. data/app/assets/stylesheets/geoblacklight_admin/modules/_visibility.scss +3 -0
  43. data/app/assets/stylesheets/geoblacklight_admin/settings/_variables.scss +1 -0
  44. data/app/channels/export_channel.rb +12 -0
  45. data/app/controllers/admin/admin_controller.rb +16 -0
  46. data/app/controllers/admin/advanced_search_controller.rb +365 -0
  47. data/app/controllers/admin/api_controller.rb +386 -0
  48. data/app/controllers/admin/bookmarks_controller.rb +68 -0
  49. data/app/controllers/admin/bulk_actions_controller.rb +94 -0
  50. data/app/controllers/admin/concerns/.keep +0 -0
  51. data/app/controllers/admin/concerns/upload_util.rb +8 -0
  52. data/app/controllers/admin/document_accesses_controller.rb +125 -0
  53. data/app/controllers/admin/document_assets_controller.rb +198 -0
  54. data/app/controllers/admin/document_downloads_controller.rb +127 -0
  55. data/app/controllers/admin/documents_controller.rb +219 -0
  56. data/app/controllers/admin/elements_controller.rb +81 -0
  57. data/app/controllers/admin/form_elements_controller.rb +81 -0
  58. data/app/controllers/admin/ids_controller.rb +379 -0
  59. data/app/controllers/admin/import_documents_controller.rb +18 -0
  60. data/app/controllers/admin/imports_controller.rb +105 -0
  61. data/app/controllers/admin/mappings_controller.rb +95 -0
  62. data/app/controllers/admin/notifications_controller.rb +51 -0
  63. data/app/controllers/admin/search_controller.rb +10 -0
  64. data/app/controllers/admin/users_controller.rb +10 -0
  65. data/app/helpers/bulk_actions_helper.rb +9 -0
  66. data/app/helpers/document_helper.rb +60 -0
  67. data/app/helpers/form_input_helper.rb +73 -0
  68. data/app/helpers/geoblacklight_admin_helper.rb +118 -0
  69. data/app/helpers/import_documents_helper.rb +5 -0
  70. data/app/helpers/mappings_helper.rb +27 -0
  71. data/app/indexers/document_indexer.rb +34 -0
  72. data/app/jobs/bulk_action_revert_document_job.rb +49 -0
  73. data/app/jobs/bulk_action_revert_job.rb +25 -0
  74. data/app/jobs/bulk_action_run_document_job.rb +42 -0
  75. data/app/jobs/bulk_action_run_job.rb +27 -0
  76. data/app/jobs/export_job.rb +72 -0
  77. data/app/jobs/export_json_job.rb +120 -0
  78. data/app/jobs/import_document_job.rb +25 -0
  79. data/app/jobs/import_run_job.rb +33 -0
  80. data/app/models/active_storage_attachment.rb +5 -0
  81. data/app/models/active_storage_blob.rb +5 -0
  82. data/app/models/api_search_builder.rb +12 -0
  83. data/app/models/application_record.rb +6 -0
  84. data/app/models/blacklight_api.rb +93 -0
  85. data/app/models/blacklight_api_facets.rb +15 -0
  86. data/app/models/blacklight_api_ids.rb +103 -0
  87. data/app/models/bookmark.rb +17 -0
  88. data/app/models/bulk_action.rb +88 -0
  89. data/app/models/bulk_action_document.rb +22 -0
  90. data/app/models/bulk_action_document_state_machine.rb +16 -0
  91. data/app/models/bulk_action_document_transition.rb +19 -0
  92. data/app/models/bulk_action_state_machine.rb +16 -0
  93. data/app/models/bulk_action_transition.rb +26 -0
  94. data/app/models/concerns/.keep +0 -0
  95. data/app/models/document/bbox_validator.rb +70 -0
  96. data/app/models/document/controlled_lists.rb +104 -0
  97. data/app/models/document/date_range_validator.rb +63 -0
  98. data/app/models/document/geom_validator.rb +117 -0
  99. data/app/models/document/reference.rb +107 -0
  100. data/app/models/document.rb +264 -0
  101. data/app/models/document_access.rb +35 -0
  102. data/app/models/document_download.rb +35 -0
  103. data/app/models/document_state_machine.rb +14 -0
  104. data/app/models/document_transition.rb +26 -0
  105. data/app/models/element.rb +90 -0
  106. data/app/models/form_control.rb +2 -0
  107. data/app/models/form_element.rb +19 -0
  108. data/app/models/form_feature.rb +2 -0
  109. data/app/models/form_group.rb +2 -0
  110. data/app/models/form_header.rb +2 -0
  111. data/app/models/geoblacklight_admin/field_mappings_btaa_aardvark.rb +379 -0
  112. data/app/models/geoblacklight_admin/field_mappings_gblv1.rb +344 -0
  113. data/app/models/geoblacklight_admin/iso_language_codes.rb +515 -0
  114. data/app/models/geoblacklight_admin/schema.rb +194 -0
  115. data/app/models/geoblacklight_admin.rb +3 -0
  116. data/app/models/import/csv_duplicates_validator.rb +36 -0
  117. data/app/models/import/csv_header_validator.rb +24 -0
  118. data/app/models/import.rb +186 -0
  119. data/app/models/import_btaa.rb +91 -0
  120. data/app/models/import_btaa_aardvark.rb +109 -0
  121. data/app/models/import_document.rb +34 -0
  122. data/app/models/import_document_state_machine.rb +12 -0
  123. data/app/models/import_document_transition.rb +19 -0
  124. data/app/models/import_gblv1.rb +92 -0
  125. data/app/models/import_state_machine.rb +16 -0
  126. data/app/models/import_transition.rb +26 -0
  127. data/app/models/mapping.rb +10 -0
  128. data/app/models/notification.rb +9 -0
  129. data/app/models/user.rb +26 -0
  130. data/app/notifications/export_notification.rb +30 -0
  131. data/app/services/export_csv_document_access_links_service.rb +47 -0
  132. data/app/services/export_csv_document_downloads_service.rb +47 -0
  133. data/app/services/export_csv_service.rb +44 -0
  134. data/app/services/export_json_service.rb +35 -0
  135. data/app/services/zip_file_generator.rb +56 -0
  136. data/app/views/admin/advanced_search/facets.json.jbuilder +80 -0
  137. data/app/views/admin/advanced_search/index.json.jbuilder +90 -0
  138. data/app/views/admin/api/_field.json.jbuilder +10 -0
  139. data/app/views/admin/api/fetch.json.jbuilder +86 -0
  140. data/app/views/admin/api/index.json.jbuilder +90 -0
  141. data/app/views/admin/bookmarks/_bookmark.json.jbuilder +4 -0
  142. data/app/views/admin/bookmarks/create.js.erb +7 -0
  143. data/app/views/admin/bookmarks/destroy.js.erb +7 -0
  144. data/app/views/admin/bookmarks/index.html.erb +21 -0
  145. data/app/views/admin/bookmarks/index.json.jbuilder +3 -0
  146. data/app/views/admin/bulk_actions/_bulk_action.json.jbuilder +4 -0
  147. data/app/views/admin/bulk_actions/_form.html.erb +17 -0
  148. data/app/views/admin/bulk_actions/edit.html.erb +6 -0
  149. data/app/views/admin/bulk_actions/index.html.erb +54 -0
  150. data/app/views/admin/bulk_actions/index.json.jbuilder +3 -0
  151. data/app/views/admin/bulk_actions/new.html.erb +5 -0
  152. data/app/views/admin/bulk_actions/show.html.erb +100 -0
  153. data/app/views/admin/bulk_actions/show.json.jbuilder +3 -0
  154. data/app/views/admin/devise/confirmations/new.html.erb +16 -0
  155. data/app/views/admin/devise/invitations/edit.html.erb +15 -0
  156. data/app/views/admin/devise/invitations/new.html.erb +15 -0
  157. data/app/views/admin/devise/mailer/invitation_instructions.html.erb +11 -0
  158. data/app/views/admin/devise/mailer/invitation_instructions.text.erb +11 -0
  159. data/app/views/admin/devise/passwords/edit.html.erb +26 -0
  160. data/app/views/admin/devise/passwords/new.html.erb +16 -0
  161. data/app/views/admin/devise/registrations/edit.html.erb +35 -0
  162. data/app/views/admin/devise/registrations/new.html.erb +30 -0
  163. data/app/views/admin/devise/sessions/new.html.erb +28 -0
  164. data/app/views/admin/devise/shared/_links.html.erb +27 -0
  165. data/app/views/admin/devise/unlocks/new.html.erb +16 -0
  166. data/app/views/admin/document_accesses/_document_access.json.jbuilder +4 -0
  167. data/app/views/admin/document_accesses/_form.html.erb +17 -0
  168. data/app/views/admin/document_accesses/destroy_all.html.erb +70 -0
  169. data/app/views/admin/document_accesses/edit.html.erb +5 -0
  170. data/app/views/admin/document_accesses/import.html.erb +70 -0
  171. data/app/views/admin/document_accesses/index.html.erb +74 -0
  172. data/app/views/admin/document_accesses/index.json.jbuilder +3 -0
  173. data/app/views/admin/document_accesses/new.html.erb +6 -0
  174. data/app/views/admin/document_accesses/show.html.erb +19 -0
  175. data/app/views/admin/document_accesses/show.json.jbuilder +3 -0
  176. data/app/views/admin/document_assets/display_attach_form.html.erb +44 -0
  177. data/app/views/admin/document_assets/index.html.erb +65 -0
  178. data/app/views/admin/document_downloads/_document_download.json.jbuilder +4 -0
  179. data/app/views/admin/document_downloads/_form.html.erb +15 -0
  180. data/app/views/admin/document_downloads/destroy_all.html.erb +70 -0
  181. data/app/views/admin/document_downloads/edit.html.erb +6 -0
  182. data/app/views/admin/document_downloads/import.html.erb +74 -0
  183. data/app/views/admin/document_downloads/index.html.erb +70 -0
  184. data/app/views/admin/document_downloads/index.json.jbuilder +3 -0
  185. data/app/views/admin/document_downloads/new.html.erb +5 -0
  186. data/app/views/admin/document_downloads/show.html.erb +24 -0
  187. data/app/views/admin/document_downloads/show.json.jbuilder +3 -0
  188. data/app/views/admin/documents/_document.html.erb +29 -0
  189. data/app/views/admin/documents/_document_bookmark.html.erb +17 -0
  190. data/app/views/admin/documents/_document_fields.html.erb +24 -0
  191. data/app/views/admin/documents/_form.html.erb +49 -0
  192. data/app/views/admin/documents/_form_control.html.erb +86 -0
  193. data/app/views/admin/documents/_form_group.html.erb +1 -0
  194. data/app/views/admin/documents/_form_header.html.erb +1 -0
  195. data/app/views/admin/documents/_form_nav.html.erb +21 -0
  196. data/app/views/admin/documents/_json_aardvark.jbuilder +47 -0
  197. data/app/views/admin/documents/_json_btaa_aardvark.jbuilder +16 -0
  198. data/app/views/admin/documents/_json_gbl_v1.jbuilder +32 -0
  199. data/app/views/admin/documents/_result_facets.html.erb +35 -0
  200. data/app/views/admin/documents/_result_pagination.html.erb +21 -0
  201. data/app/views/admin/documents/_result_selected_options.html.erb +54 -0
  202. data/app/views/admin/documents/_result_selection_options.html.erb +10 -0
  203. data/app/views/admin/documents/_result_toggle.html.erb +13 -0
  204. data/app/views/admin/documents/edit.html.erb +7 -0
  205. data/app/views/admin/documents/features/_assets.html.erb +3 -0
  206. data/app/views/admin/documents/features/_institutional_access_links.html.erb +3 -0
  207. data/app/views/admin/documents/features/_multiple_download_links.html.erb +27 -0
  208. data/app/views/admin/documents/fetch.json_aardvark.jbuilder +9 -0
  209. data/app/views/admin/documents/fetch.json_btaa_aardvark.jbuilder +9 -0
  210. data/app/views/admin/documents/fetch.json_gbl_v1.jbuilder +9 -0
  211. data/app/views/admin/documents/index.html.erb +49 -0
  212. data/app/views/admin/documents/index.json_aardvark.jbuilder +9 -0
  213. data/app/views/admin/documents/index.json_btaa_aardvark.jbuilder +9 -0
  214. data/app/views/admin/documents/index.json_gbl_v1.jbuilder +9 -0
  215. data/app/views/admin/documents/show.json_aardvark.jbuilder +3 -0
  216. data/app/views/admin/documents/show.json_btaa_aardvark.jbuilder +3 -0
  217. data/app/views/admin/documents/show.json_gbl_v1.jbuilder +3 -0
  218. data/app/views/admin/documents/versions.html.erb +110 -0
  219. data/app/views/admin/elements/_element.json.jbuilder +2 -0
  220. data/app/views/admin/elements/_form.html.erb +45 -0
  221. data/app/views/admin/elements/edit.html.erb +6 -0
  222. data/app/views/admin/elements/index.html.erb +68 -0
  223. data/app/views/admin/elements/index.json.jbuilder +1 -0
  224. data/app/views/admin/elements/new.html.erb +5 -0
  225. data/app/views/admin/elements/show.html.erb +121 -0
  226. data/app/views/admin/elements/show.json.jbuilder +1 -0
  227. data/app/views/admin/form_elements/_form.html.erb +46 -0
  228. data/app/views/admin/form_elements/_form_element.json.jbuilder +2 -0
  229. data/app/views/admin/form_elements/edit.html.erb +6 -0
  230. data/app/views/admin/form_elements/index.html.erb +49 -0
  231. data/app/views/admin/form_elements/index.json.jbuilder +1 -0
  232. data/app/views/admin/form_elements/new.html.erb +5 -0
  233. data/app/views/admin/form_elements/show.html.erb +19 -0
  234. data/app/views/admin/form_elements/show.json.jbuilder +1 -0
  235. data/app/views/admin/ids/fetch.json.jbuilder +86 -0
  236. data/app/views/admin/ids/index.json.jbuilder +41 -0
  237. data/app/views/admin/import_documents/show.html.haml +20 -0
  238. data/app/views/admin/imports/_form.html.erb +27 -0
  239. data/app/views/admin/imports/_import.json.jbuilder +4 -0
  240. data/app/views/admin/imports/_show_failed_tab.html.erb +37 -0
  241. data/app/views/admin/imports/_show_success_tab.html.erb +31 -0
  242. data/app/views/admin/imports/edit.html.erb +8 -0
  243. data/app/views/admin/imports/index.html.erb +56 -0
  244. data/app/views/admin/imports/index.json.jbuilder +3 -0
  245. data/app/views/admin/imports/new.html.erb +7 -0
  246. data/app/views/admin/imports/show.html.erb +123 -0
  247. data/app/views/admin/imports/show.json.jbuilder +3 -0
  248. data/app/views/admin/layouts/application.html.erb +30 -0
  249. data/app/views/admin/layouts/blazer/application.html.erb +23 -0
  250. data/app/views/admin/layouts/mailer.html.erb +13 -0
  251. data/app/views/admin/layouts/mailer.text.erb +1 -0
  252. data/app/views/admin/mappings/_form.html.erb +17 -0
  253. data/app/views/admin/mappings/_mapping.json.jbuilder +4 -0
  254. data/app/views/admin/mappings/edit.html.erb +6 -0
  255. data/app/views/admin/mappings/index.html.erb +37 -0
  256. data/app/views/admin/mappings/index.json.jbuilder +3 -0
  257. data/app/views/admin/mappings/new.html.erb +5 -0
  258. data/app/views/admin/mappings/show.html.erb +27 -0
  259. data/app/views/admin/mappings/show.json.jbuilder +3 -0
  260. data/app/views/admin/notifications/_notification.html.haml +31 -0
  261. data/app/views/admin/notifications/index.html.erb +54 -0
  262. data/app/views/admin/notifications/update.js.erb +7 -0
  263. data/app/views/admin/search/index.html.erb +38 -0
  264. data/app/views/admin/shared/_flash_messages.html.erb +5 -0
  265. data/app/views/admin/shared/_footer.html.erb +56 -0
  266. data/app/views/admin/shared/_js_behaviors.html.erb +147 -0
  267. data/app/views/admin/shared/_navbar.html.erb +78 -0
  268. data/app/views/admin/shared/_navbar_blazer.html.erb +42 -0
  269. data/app/views/admin/shared/_schema_timestamp.html.erb +16 -0
  270. data/app/views/admin/shared/_toast.html.erb +13 -0
  271. data/app/views/admin/users/index.html.erb +21 -0
  272. data/config/authorities/formats.yml +25 -0
  273. data/config/authorities/languages.yml +50 -0
  274. data/config/authorities/resource_type.yml +82 -0
  275. data/config/blazer.yml +79 -0
  276. data/config/gbl_v1_schema.json +118 -0
  277. data/config/geomg_aardvark_schema.json +211 -0
  278. data/config/geomg_schema.json +123 -0
  279. data/config/locales/devise.en.yml +65 -0
  280. data/config/locales/devise_invitable.en.yml +31 -0
  281. data/config/locales/documents.en.yml +189 -0
  282. data/config/locales/en.yml +51 -0
  283. data/config/locales/geoblacklight.en.yml +178 -0
  284. data/config/locales/simple_form.en.yml +31 -0
  285. data/config/routes.rb +162 -0
  286. data/db/migrate/20230316183001_add_geoblacklight_admin.rb +399 -0
  287. data/db/seeds.rb +26 -0
  288. data/db/seeds_elements.csv +56 -0
  289. data/db/seeds_elements.numbers +0 -0
  290. data/db/seeds_form_elements.csv +71 -0
  291. data/db/seeds_form_elements.numbers +0 -0
  292. data/db/structure.sql +816 -0
  293. data/geoblacklight_admin.gemspec +67 -0
  294. data/lib/generators/geoblacklight_admin/config_generator.rb +336 -0
  295. data/lib/generators/geoblacklight_admin/example_docs_generator.rb +18 -0
  296. data/lib/generators/geoblacklight_admin/helpers_generator.rb +18 -0
  297. data/lib/generators/geoblacklight_admin/install_generator.rb +60 -0
  298. data/lib/generators/geoblacklight_admin/jobs_generator.rb +21 -0
  299. data/lib/generators/geoblacklight_admin/models_generator.rb +23 -0
  300. data/lib/generators/geoblacklight_admin/templates/.env.development.example +28 -0
  301. data/lib/generators/geoblacklight_admin/templates/.solr_wrapper.yml +7 -0
  302. data/lib/generators/geoblacklight_admin/templates/_user_util_links.html.erb +30 -0
  303. data/lib/generators/geoblacklight_admin/templates/config/database.yml +18 -0
  304. data/lib/generators/geoblacklight_admin/templates/config/geomg_aardvark_schema.json +211 -0
  305. data/lib/generators/geoblacklight_admin/templates/config/initializers/geoblacklight_admin.rb +25 -0
  306. data/lib/generators/geoblacklight_admin/templates/config/initializers/kithe.rb +31 -0
  307. data/lib/generators/geoblacklight_admin/templates/config/initializers/pagy.rb +158 -0
  308. data/lib/generators/geoblacklight_admin/templates/config/initializers/statesman.rb +7 -0
  309. data/lib/generators/geoblacklight_admin/templates/javascript/channels/consumer.js +6 -0
  310. data/lib/generators/geoblacklight_admin/templates/javascript/channels/export_channel.js +30 -0
  311. data/lib/generators/geoblacklight_admin/templates/javascript/channels/index.js +5 -0
  312. data/lib/generators/geoblacklight_admin/templates/javascript/controllers/application_controller.js +17 -0
  313. data/lib/generators/geoblacklight_admin/templates/javascript/controllers/document_controller.js +26 -0
  314. data/lib/generators/geoblacklight_admin/templates/javascript/controllers/index.js +10 -0
  315. data/lib/generators/geoblacklight_admin/templates/javascript/controllers/results_controller.js +310 -0
  316. data/lib/generators/geoblacklight_admin/templates/javascript/packs/application.js +23 -0
  317. data/lib/generators/geoblacklight_admin/templates/javascript/src/js/admin/qa_autocomplete.js +1134 -0
  318. data/lib/generators/geoblacklight_admin/templates/package.json +32 -0
  319. data/lib/generators/geoblacklight_admin/templates/solr/README-geoblacklight-solr-development.txt +3 -0
  320. data/lib/generators/geoblacklight_admin/templates/solr/conf/_rest_managed.json +3 -0
  321. data/lib/generators/geoblacklight_admin/templates/solr/conf/admin-extra.html +31 -0
  322. data/lib/generators/geoblacklight_admin/templates/solr/conf/core.properties +5 -0
  323. data/lib/generators/geoblacklight_admin/templates/solr/conf/elevate.xml +36 -0
  324. data/lib/generators/geoblacklight_admin/templates/solr/conf/mapping-ISOLatin1Accent.txt +246 -0
  325. data/lib/generators/geoblacklight_admin/templates/solr/conf/protwords.txt +21 -0
  326. data/lib/generators/geoblacklight_admin/templates/solr/conf/schema.xml +229 -0
  327. data/lib/generators/geoblacklight_admin/templates/solr/conf/scripts.conf +24 -0
  328. data/lib/generators/geoblacklight_admin/templates/solr/conf/solrconfig.xml +266 -0
  329. data/lib/generators/geoblacklight_admin/templates/solr/conf/spellings.txt +2 -0
  330. data/lib/generators/geoblacklight_admin/templates/solr/conf/stopwords.txt +58 -0
  331. data/lib/generators/geoblacklight_admin/templates/solr/conf/stopwords_en.txt +58 -0
  332. data/lib/generators/geoblacklight_admin/templates/solr/conf/synonyms.txt +43 -0
  333. data/lib/generators/geoblacklight_admin/templates/solr/conf/xslt/example.xsl +132 -0
  334. data/lib/generators/geoblacklight_admin/templates/solr/conf/xslt/example_atom.xsl +67 -0
  335. data/lib/generators/geoblacklight_admin/templates/solr/conf/xslt/example_rss.xsl +66 -0
  336. data/lib/generators/geoblacklight_admin/templates/solr/conf/xslt/luke.xsl +337 -0
  337. data/lib/generators/geoblacklight_admin/templates/solr/snapshots/.keep +0 -0
  338. data/lib/generators/geoblacklight_admin/views_generator.rb +19 -0
  339. data/lib/geoblacklight_admin/engine.rb +20 -0
  340. data/lib/geoblacklight_admin/version.rb +5 -0
  341. data/lib/geoblacklight_admin.rb +7 -0
  342. data/lib/tasks/.keep +0 -0
  343. data/lib/tasks/geoblacklight_admin.rake +209 -0
  344. data/spec/test_app_templates/lib/generators/test_app_generator.rb +35 -0
  345. data/template.rb +16 -0
  346. metadata +1037 -0
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Date Range Validation
4
+ #
5
+ # Allow: YYYY-YYYY, *-YYYY, YYYY-*, Start YYYY == End YYYY
6
+ # Disallow: YYYX-YYYY, YYYY-, 2000-1999, YYYY-YYYY?
7
+ class Document
8
+ # DateRangeValidator
9
+ class DateRangeValidator < ActiveModel::Validator
10
+ def validate(record)
11
+ valid_date_ranges = true
12
+ record.send(GeoblacklightAdmin::Schema.instance.solr_fields[:date_range]).each do |date_range|
13
+ # Empty is fine
14
+ if date_range.blank?
15
+ valid_date_ranges = true
16
+ return valid_date_ranges
17
+ end
18
+
19
+ # Must split into two via '-'
20
+ if date_range.split("-").size != 2
21
+ record.errors.add(GeoblacklightAdmin::Schema.instance.solr_fields[:date_range], "invalid date range present - missing YYYY-YYYY value")
22
+ valid_date_ranges = false
23
+ return valid_date_ranges
24
+ end
25
+
26
+ start_date, end_date = date_range.split("-")
27
+
28
+ unless valid_yyyy(start_date)
29
+ record.errors.add(GeoblacklightAdmin::Schema.instance.solr_fields[:date_range], "invalid start date - bad YYYY-YYYY value, only integers or the wildcard '*' allowed")
30
+ valid_date_ranges = false
31
+ end
32
+
33
+ unless valid_yyyy(end_date)
34
+ record.errors.add(GeoblacklightAdmin::Schema.instance.solr_fields[:date_range], "invalid end date - bad YYYY-YYYY value, only integers or the wildcard '*' allowed")
35
+ valid_date_ranges = false
36
+ end
37
+
38
+ # Allow only 1 wildcard
39
+ if start_date == "*" && end_date == "*"
40
+ record.errors.add(GeoblacklightAdmin::Schema.instance.solr_fields[:date_range], "invalid only one wildcard can be used")
41
+ valid_date_ranges = false
42
+ end
43
+
44
+ # Avoid 1996-1946
45
+ if start_date[/\d+/] && end_date[/\d+/]
46
+ unless start_date.to_i <= end_date.to_i
47
+ record.errors.add(GeoblacklightAdmin::Schema.instance.solr_fields[:date_range], "invalid start date must be less than the end date")
48
+ valid_date_ranges = false
49
+ end
50
+ end
51
+ end
52
+ valid_date_ranges
53
+ end
54
+
55
+ def valid_yyyy(date)
56
+ if date[/\D/]
57
+ return false unless date == "*"
58
+ else
59
+ true
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rgeo"
4
+
5
+ # GEOM Validation
6
+ #
7
+ # Uses local logic to parse and validate ENVELOPE values
8
+ # Uses RGeo to parse and validate POLYGON or MULTIPOLYGON values
9
+ class Document
10
+ # GeomValidator
11
+ class GeomValidator < ActiveModel::Validator
12
+ def validate(record)
13
+ # Assume true for empty values
14
+ valid_geom = true
15
+
16
+ if record.send(GeoblacklightAdmin::Schema.instance.solr_fields[:geometry]).present?
17
+ valid_geom = if record.send(GeoblacklightAdmin::Schema.instance.solr_fields[:geometry]).start_with?("ENVELOPE")
18
+ # Sane ENVELOPE?
19
+ proper_envelope(record)
20
+ else
21
+ # Sane GEOM?
22
+ proper_geom(record)
23
+ end
24
+ end
25
+
26
+ valid_geom
27
+ end
28
+
29
+ # Validates ENVELOPE
30
+ def proper_envelope(record)
31
+ geom = record.send(GeoblacklightAdmin::Schema.instance.solr_fields[:geometry])
32
+ begin
33
+ valid_geom, error_message = valid_envelope?(geom.delete("ENVELOPE()"))
34
+ rescue => e
35
+ valid_geom = false
36
+ record.errors.add(GeoblacklightAdmin::Schema.instance.solr_fields[:geometry], "Invalid envelope: #{e}")
37
+ end
38
+
39
+ unless valid_geom
40
+ record.errors.add(GeoblacklightAdmin::Schema.instance.solr_fields[:geometry], "Invalid envelope: #{error_message}")
41
+ end
42
+
43
+ valid_geom
44
+ end
45
+
46
+ # Validates POLYGON and MULTIPOLYGON
47
+ def proper_geom(record)
48
+ geom = record.send(GeoblacklightAdmin::Schema.instance.solr_fields[:geometry])
49
+ begin
50
+ valid_geom = if RGeo::Cartesian::Factory.new.parse_wkt(geom)
51
+ true
52
+ else
53
+ false
54
+ end
55
+ rescue => e
56
+ valid_geom = false
57
+ record.errors.add(GeoblacklightAdmin::Schema.instance.solr_fields[:geometry], "Invalid geometry: #{e}")
58
+ end
59
+
60
+ # Guard against a whole world polygons
61
+ if geom == "POLYGON((-180 90, 180 90, 180 -90, -180 -90, -180 90))"
62
+ valid_geom = false
63
+ record.errors.add(GeoblacklightAdmin::Schema.instance.solr_fields[:geometry], "Invalid polygon: all points are coplanar input, Solr will not index")
64
+ end
65
+
66
+ valid_geom
67
+ end
68
+
69
+ def valid_envelope?(envelope)
70
+ # Default to true
71
+ valid_envelope = true
72
+ error_message = ""
73
+
74
+ # Min/Max - W,E,N,S
75
+ # ENVELOPE(-180,180,90,-90)
76
+ min_max = [-180.0, 180.0, 90.0, -90.0]
77
+ envelope = envelope.split(",")
78
+
79
+ # Reject ENVELOPE(-118.00.0000,-88.00.0000,51.00.0000,42.00.0000)
80
+ # - Double period float-ish things?
81
+ envelope.each do |val|
82
+ if val.count(".") >= 2
83
+ valid_envelope = false
84
+ error_message = "invalid ENVELOPE(W,E,N,S) syntax - found multiple periods in coordinate value(s)."
85
+ end
86
+ end
87
+
88
+ # @TODO: Essentially duplicated logic from bbox_validator.rb, DRY it up
89
+ if envelope.size != 4
90
+ valid_envelope = false
91
+ error_message = "invalid ENVELOPE(W,E,N,S) syntax"
92
+ # W
93
+ elsif envelope[0].to_f < min_max[0]
94
+ valid_envelope = false
95
+ error_message = "invalid minX present"
96
+ # E
97
+ elsif envelope[1].to_f > min_max[1]
98
+ valid_envelope = false
99
+ error_message = "invalid maX present"
100
+ # N
101
+ elsif envelope[2].to_f > min_max[2]
102
+ valid_envelope = false
103
+ error_message = "invalid maxY present"
104
+ # S
105
+ elsif envelope[3].to_f < min_max[3]
106
+ valid_envelope = false
107
+ error_message = "invalid minY present"
108
+ # Solr - maxY must be >= minY
109
+ elsif envelope[3].to_f >= envelope[2].to_f
110
+ valid_envelope = false
111
+ error_message = "maxY must be >= minY"
112
+ end
113
+
114
+ [valid_envelope, error_message]
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Document
4
+ class Document
5
+ # Reference
6
+ class Reference
7
+ # Via GBL Wiki
8
+ # https://github.com/geoblacklight/geoblacklight/wiki/External-references
9
+ REFERENCE_VALUES = {
10
+ wcs: {
11
+ label: "Web Coverage Service (WCS)",
12
+ uri: "http://www.opengis.net/def/serviceType/ogc/wcs"
13
+ },
14
+ wms: {
15
+ label: "Web Mapping Service (WMS)",
16
+ uri: "http://www.opengis.net/def/serviceType/ogc/wms"
17
+ },
18
+ wfs: {
19
+ label: "Web Feature Service (WFS)",
20
+ uri: "http://www.opengis.net/def/serviceType/ogc/wfs"
21
+ },
22
+ iiif_image: {
23
+ label: "IIIF Image API",
24
+ uri: "http://iiif.io/api/image"
25
+ },
26
+ iiif_manifest: {
27
+ label: "IIIF Manifest",
28
+ uri: "http://iiif.io/api/presentation#manifest"
29
+ },
30
+ image: {
31
+ label: "Image file",
32
+ uri: "http://schema.org/image"
33
+ },
34
+ download: {
35
+ label: "Direct download file",
36
+ uri: "http://schema.org/downloadUrl"
37
+ },
38
+ thumbnail: {
39
+ label: "Thumbnail file",
40
+ uri: "http://schema.org/thumbnailUrl"
41
+ },
42
+ documentation_download: {
43
+ label: "Data dictionary / documentation download",
44
+ uri: "http://lccn.loc.gov/sh85035852"
45
+ },
46
+ documentation_external: {
47
+ label: "Full layer description",
48
+ uri: "http://schema.org/url"
49
+ },
50
+ metadata_iso: {
51
+ label: "Metadata in ISO 19139",
52
+ uri: "http://www.isotc211.org/schemas/2005/gmd/"
53
+ },
54
+ metadata_fgdc: {
55
+ label: "Metadata in FGDC",
56
+ uri: "http://www.opengis.net/cat/csw/csdgm"
57
+ },
58
+ metadata_mods: {
59
+ label: "Metadata in MODS",
60
+ uri: "http://www.loc.gov/mods/v3"
61
+ },
62
+ metadata_html: {
63
+ label: "Metadata in HTML",
64
+ uri: "http://www.w3.org/1999/xhtml"
65
+ },
66
+ arcgis_feature_layer: {
67
+ label: "ArcGIS FeatureLayer",
68
+ uri: "urn:x-esri:serviceType:ArcGIS#FeatureLayer"
69
+ },
70
+ arcgis_tiled_map_layer: {
71
+ label: "ArcGIS TiledMapLayer",
72
+ uri: "urn:x-esri:serviceType:ArcGIS#TiledMapLayer"
73
+ },
74
+ arcgis_dynamic_map_layer: {
75
+ label: "ArcGIS DynamicMapLayer",
76
+ uri: "urn:x-esri:serviceType:ArcGIS#DynamicMapLayer"
77
+ },
78
+ arcgis_image_map_layer: {
79
+ label: "ArcGIS ImageMapLayer",
80
+ uri: "urn:x-esri:serviceType:ArcGIS#ImageMapLayer"
81
+ },
82
+ harvard_download: {
83
+ label: "Harvard Download",
84
+ uri: "http://schema.org/DownloadAction"
85
+ },
86
+ open_index_map: {
87
+ label: "OpenIndexMap",
88
+ uri: "https://openindexmaps.org"
89
+ },
90
+ oembed: {
91
+ label: "oEmbed",
92
+ uri: "https://oembed.com"
93
+ }
94
+ }.freeze
95
+
96
+ include AttrJson::Model
97
+
98
+ validates :category, :value, presence: true
99
+ validates :category, inclusion:
100
+ {in: REFERENCE_VALUES.stringify_keys.keys,
101
+ allow_blank: true,
102
+ message: "%<value>s is not a valid category"}
103
+
104
+ attr_json :category, :string
105
+ attr_json :value, :string
106
+ end
107
+ end
@@ -0,0 +1,264 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Document
4
+ class Document < Kithe::Work
5
+ include AttrJson::Record::QueryScopes
6
+ include ActiveModel::Validations
7
+
8
+ attr_accessor :skip_callbacks
9
+
10
+ has_paper_trail
11
+ belongs_to :import, optional: true
12
+
13
+ # Statesman
14
+ has_many :document_transitions, foreign_key: "kithe_model_id", autosave: false, dependent: :destroy, inverse_of: :document
15
+
16
+ # DocumentAccesses
17
+ has_many :document_accesses, primary_key: "friendlier_id", foreign_key: "friendlier_id", autosave: false, dependent: :destroy,
18
+ inverse_of: :document
19
+
20
+ # DocumentDownloads
21
+ has_many :document_downloads, primary_key: "friendlier_id", foreign_key: "friendlier_id", autosave: false, dependent: :destroy,
22
+ inverse_of: :document
23
+
24
+ include Statesman::Adapters::ActiveRecordQueries[
25
+ transition_class: DocumentTransition,
26
+ initial_state: :draft
27
+ ]
28
+
29
+ def state_machine
30
+ @state_machine ||= DocumentStateMachine.new(self, transition_class: DocumentTransition)
31
+ end
32
+
33
+ delegate :current_state, to: :state_machine
34
+
35
+ before_save :transition_publication_state, unless: :skip_callbacks
36
+ before_save :set_geometry
37
+
38
+ # Indexer
39
+ self.kithe_indexable_mapper = DocumentIndexer.new
40
+
41
+ # Validations
42
+ validates :title, :dct_accessRights_s, :gbl_resourceClass_sm, :geomg_id_s, presence: true
43
+
44
+ # Test for collection and restricted
45
+ validates :dct_format_s, presence: true, if: :a_downloadable_resource?
46
+
47
+ # Downloadable Resouce
48
+ def a_downloadable_resource?
49
+ references_json.include?("downloadUrl")
50
+ end
51
+
52
+ validates_with Document::DateRangeValidator
53
+ validates_with Document::BboxValidator
54
+ validates_with Document::GeomValidator
55
+
56
+ # Definte our AttrJSON attributes
57
+ Element.all.each do |attribute|
58
+ next if attribute.solr_field == "dct_references_s"
59
+
60
+ if attribute.repeatable?
61
+ attr_json attribute.solr_field.to_sym, attribute.field_type.to_sym, array: true, default: -> { [] }
62
+ else
63
+ attr_json attribute.solr_field.to_sym, attribute.field_type.to_sym, default: ""
64
+ end
65
+ end
66
+
67
+ attr_json :dct_references_s, Document::Reference.to_type, array: true, default: -> { [] }
68
+
69
+ # Index Transformations - *_json functions
70
+ def references_json
71
+ references = ActiveSupport::HashWithIndifferentAccess.new
72
+ send(GeoblacklightAdmin::Schema.instance.solr_fields[:reference]).each { |ref| references[Document::Reference::REFERENCE_VALUES[ref.category.to_sym][:uri]] = ref.value }
73
+ references = apply_downloads(references)
74
+ references.to_json
75
+ end
76
+
77
+ def apply_downloads(references)
78
+ dct_downloads = references["http://schema.org/downloadUrl"]
79
+ # Make sure downloads exist!
80
+ if document_downloads.present?
81
+ multiple_downloads = multiple_downloads_array
82
+ multiple_downloads << {label: download_text(send(GeoblacklightAdmin::Schema.instance.solr_fields[:format])), url: dct_downloads} if dct_downloads.present?
83
+ references[:"http://schema.org/downloadUrl"] = multiple_downloads
84
+ end
85
+ references
86
+ end
87
+
88
+ def multiple_downloads_array
89
+ document_downloads.collect { |d| {label: d.label, url: d.value} }
90
+ end
91
+
92
+ ### From GBL
93
+ ##
94
+ # Looks up properly formatted names for formats
95
+ #
96
+ def proper_case_format(format)
97
+ if I18n.exists?("geoblacklight.formats.#{format.to_s.parameterize(separator: "_")}")
98
+ I18n.t("geoblacklight.formats.#{format.to_s.parameterize(separator: "_")}")
99
+ else
100
+ format
101
+ end
102
+ end
103
+
104
+ ##
105
+ # Wraps download text with proper_case_format
106
+ #
107
+ def download_text(format)
108
+ download_format = proper_case_format(format)
109
+ prefix = "Original "
110
+ begin
111
+ format = download_format
112
+ rescue
113
+ # Need to rescue if format doesn't exist
114
+ end
115
+ value = prefix + format.to_s
116
+ value.html_safe
117
+ end
118
+ ### End / From GBL
119
+
120
+ def access_json
121
+ access = {}
122
+ access_urls.each { |au| access[au.institution_code] = au.access_url }
123
+ access.to_json
124
+ end
125
+
126
+ def created_at_dt
127
+ created_at&.utc&.iso8601
128
+ end
129
+
130
+ def gbl_mdModified_dt
131
+ updated_at&.utc&.iso8601
132
+ end
133
+
134
+ # Ensures a manually created "title" makes it into the attr_json "title"
135
+ def dct_title_s
136
+ title
137
+ end
138
+
139
+ def date_range_json
140
+ date_ranges = []
141
+ unless send(GeoblacklightAdmin::Schema.instance.solr_fields[:date_range]).all?(&:blank?)
142
+ send(GeoblacklightAdmin::Schema.instance.solr_fields[:date_range]).each do |date_range|
143
+ start_d, end_d = date_range.split("-")
144
+ start_d = "*" if start_d == "YYYY" || start_d.nil?
145
+ end_d = "*" if end_d == "YYYY" || end_d.nil?
146
+ date_ranges << "[#{start_d} TO #{end_d}]" if start_d.present?
147
+ end
148
+ end
149
+ date_ranges
150
+ end
151
+
152
+ def solr_year_json
153
+ return [] if send(GeoblacklightAdmin::Schema.instance.solr_fields[:date_range]).blank?
154
+
155
+ start_d, _end_d = send(GeoblacklightAdmin::Schema.instance.solr_fields[:date_range]).first.split("-")
156
+ [start_d] if start_d.presence
157
+ end
158
+ alias_method :gbl_indexYear_im, :solr_year_json
159
+
160
+ # Export Transformations - to_*
161
+ def to_csv
162
+ attributes = GeoblacklightAdmin::Schema.instance.exportable_fields
163
+ attributes.map do |key, value|
164
+ if value[:delimited]
165
+ send(value[:destination])&.join("|")
166
+ elsif value[:destination] == "dct_references_s"
167
+ dct_references_s_to_csv(key, value[:destination])
168
+ elsif value[:destination] == "b1g_publication_state_s"
169
+ send(:current_state)
170
+ else
171
+ send(value[:destination])
172
+ end
173
+ end
174
+ end
175
+
176
+ def to_traject
177
+ Kithe::Model.find_by_friendlier_id(friendlier_id).update_index(writer: Traject::DebugWriter.new({}))
178
+ end
179
+
180
+ def dct_references_s_to_csv(key, destination)
181
+ send(destination).detect { |ref| ref.category == GeoblacklightAdmin::Schema.instance.dct_references_mappings[key] }.value
182
+ rescue NoMethodError
183
+ nil
184
+ end
185
+
186
+ def current_version
187
+ versions.last.index
188
+ end
189
+
190
+ # Institutional Access URLs
191
+ def access_urls
192
+ DocumentAccess.where(friendlier_id: friendlier_id).order(institution_code: :asc)
193
+ end
194
+
195
+ def derive_locn_geometry
196
+ if send(GeoblacklightAdmin::Schema.instance.solr_fields[:geometry]).present?
197
+ send(GeoblacklightAdmin::Schema.instance.solr_fields[:geometry])
198
+ elsif send(GeoblacklightAdmin::Schema.instance.solr_fields[:bounding_box]).present?
199
+ derive_polygon
200
+ else
201
+ ""
202
+ end
203
+ end
204
+
205
+ # Convert BBOX to GEOM Polygon
206
+ def derive_polygon
207
+ if send(GeoblacklightAdmin::Schema.instance.solr_fields[:bounding_box]).present?
208
+ # Guard against a whole world polygons
209
+ if send(GeoblacklightAdmin::Schema.instance.solr_fields[:bounding_box]) == "-180,-90,180,90"
210
+ "ENVELOPE(-180,180,90,-90)"
211
+ else
212
+ # "W,S,E,N" convert to "POLYGON((W N, E N, E S, W S, W N))"
213
+ w, s, e, n = send(GeoblacklightAdmin::Schema.instance.solr_fields[:bounding_box]).split(",")
214
+ "POLYGON((#{w} #{n}, #{e} #{n}, #{e} #{s}, #{w} #{s}, #{w} #{n}))"
215
+ end
216
+ else
217
+ ""
218
+ end
219
+ end
220
+
221
+ def set_geometry
222
+ if locn_geometry.blank? && self&.dcat_bbox&.present?
223
+ self.locn_geometry = derive_polygon
224
+ end
225
+ end
226
+
227
+ # Convert GEOM for Solr Indexing
228
+ def derive_dcat_bbox
229
+ if send(GeoblacklightAdmin::Schema.instance.solr_fields[:bounding_box]).present?
230
+ # "W,S,E,N" convert to "ENVELOPE(W,E,N,S)"
231
+ w, s, e, n = send(GeoblacklightAdmin::Schema.instance.solr_fields[:bounding_box]).split(",")
232
+ "ENVELOPE(#{w},#{e},#{n},#{s})"
233
+ else
234
+ ""
235
+ end
236
+ end
237
+
238
+ def derive_dcat_centroid
239
+ if send(GeoblacklightAdmin::Schema.instance.solr_fields[:bounding_box]).present?
240
+ w, s, e, n = send(GeoblacklightAdmin::Schema.instance.solr_fields[:bounding_box]).split(",")
241
+ "#{(n.to_f + s.to_f) / 2},#{(e.to_f + w.to_f) / 2}"
242
+ else
243
+ ""
244
+ end
245
+ end
246
+
247
+ # Convert three char language code to proper string
248
+ def iso_language_mapping
249
+ mapping = []
250
+
251
+ if send(GeoblacklightAdmin::Schema.instance.solr_fields[:language]).present?
252
+ send(GeoblacklightAdmin::Schema.instance.solr_fields[:language]).each do |lang|
253
+ mapping << GeoblacklightAdmin::IsoLanguageCodes.call[lang]
254
+ end
255
+ end
256
+ mapping
257
+ end
258
+
259
+ private
260
+
261
+ def transition_publication_state
262
+ state_machine.transition_to!(publication_state.downcase) if publication_state_changed?
263
+ end
264
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ # DocumentAccess
4
+ class DocumentAccess < ApplicationRecord
5
+ belongs_to :document, foreign_key: :friendlier_id, primary_key: :friendlier_id
6
+ after_save :reindex_document
7
+
8
+ # Validations
9
+ validates :institution_code, :access_url, presence: true
10
+
11
+ def self.import(file)
12
+ logger.debug("CSV Import")
13
+ CSV.foreach(file.path, headers: true) do |row|
14
+ logger.debug("CSV Row: #{row.to_hash}")
15
+ document_access = DocumentAccess.find_or_initialize_by(friendlier_id: row[0], institution_code: row[1])
16
+ document_access.update(row.to_hash)
17
+ end
18
+ end
19
+
20
+ def self.destroy_all(file)
21
+ logger.debug("CSV Destroy")
22
+ CSV.foreach(file.path, headers: true) do |row|
23
+ logger.debug("CSV Row: #{row.to_hash}")
24
+ DocumentAccess.destroy_by(id: row[0], friendlier_id: row[1])
25
+ end
26
+ end
27
+
28
+ def to_csv
29
+ attributes.values
30
+ end
31
+
32
+ def reindex_document
33
+ document.save
34
+ end
35
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ # DocumentDownload
4
+ class DocumentDownload < ApplicationRecord
5
+ belongs_to :document, inverse_of: :document_downloads, foreign_key: :friendlier_id, primary_key: :friendlier_id
6
+ after_save :reindex_document
7
+
8
+ # Validations
9
+ validates :label, :value, presence: true
10
+
11
+ def self.import(file)
12
+ logger.debug("CSV Import")
13
+ CSV.foreach(file.path, headers: true) do |row|
14
+ logger.debug("CSV Row: #{row.to_hash}")
15
+ document_download = DocumentDownload.find_or_initialize_by(friendlier_id: row[0], label: row[1], value: row[2])
16
+ document_download.update(row.to_hash)
17
+ end
18
+ end
19
+
20
+ def self.destroy_all(file)
21
+ logger.debug("CSV Destroy")
22
+ CSV.foreach(file.path, headers: true) do |row|
23
+ logger.debug("CSV Row: #{row.to_hash}")
24
+ DocumentDownload.destroy_by(id: row[0], friendlier_id: row[1])
25
+ end
26
+ end
27
+
28
+ def to_csv
29
+ attributes.values
30
+ end
31
+
32
+ def reindex_document
33
+ document.save
34
+ end
35
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Document Statesman
4
+ class DocumentStateMachine
5
+ include Statesman::Machine
6
+
7
+ state :draft, initial: true
8
+ state :published
9
+ state :unpublished
10
+
11
+ transition from: :draft, to: %i[draft published unpublished]
12
+ transition from: :published, to: %i[draft published unpublished]
13
+ transition from: :unpublished, to: %i[draft published unpublished]
14
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Add Document Statesman Transitions
4
+ class DocumentTransition < ApplicationRecord
5
+ include Statesman::Adapters::ActiveRecordTransition
6
+
7
+ # If your transition table doesn't have the default `updated_at` timestamp column,
8
+ # you'll need to configure the `updated_timestamp_column` option, setting it to
9
+ # another column name (e.g. `:updated_on`) or `nil`.
10
+ #
11
+ # self.updated_timestamp_column = :updated_on
12
+ # self.updated_timestamp_column = nil
13
+
14
+ belongs_to :document, inverse_of: :document_transitions, foreign_key: "kithe_model_id"
15
+
16
+ after_destroy :update_most_recent, if: :most_recent?
17
+
18
+ private
19
+
20
+ def update_most_recent
21
+ last_transition = document.document_transitions.order(:sort_key).last
22
+ return if last_transition.blank?
23
+
24
+ last_transition.update_column(:most_recent, true)
25
+ end
26
+ end