geoblacklight_admin 0.4.1 → 0.5.0

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 (109) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +10 -55
  3. data/Rakefile +3 -0
  4. data/app/assets/javascripts/geoblacklight_admin/chosen.js +7 -3
  5. data/app/assets/javascripts/geoblacklight_admin/datepicker.js +2 -2
  6. data/app/assets/javascripts/geoblacklight_admin/inputmask.js +2 -2
  7. data/app/assets/javascripts/geoblacklight_admin/truncate.js +2 -2
  8. data/app/assets/javascripts/geoblacklight_admin.js +1 -4
  9. data/app/assets/stylesheets/geoblacklight_admin/_core.scss +3 -1
  10. data/app/assets/stylesheets/geoblacklight_admin/modules/_images.scss +4 -0
  11. data/app/assets/stylesheets/geoblacklight_admin/modules/_nav.scss +4 -0
  12. data/app/assets/stylesheets/geoblacklight_admin/modules/_results.scss +5 -0
  13. data/app/controllers/admin/admin_controller.rb +1 -1
  14. data/app/controllers/admin/advanced_search_controller.rb +0 -1
  15. data/app/controllers/admin/assets_controller.rb +142 -0
  16. data/app/controllers/admin/bulk_actions_controller.rb +1 -1
  17. data/app/controllers/admin/document_accesses_controller.rb +3 -3
  18. data/app/controllers/admin/document_assets_controller.rb +33 -23
  19. data/app/controllers/admin/documents_controller.rb +6 -2
  20. data/app/controllers/admin/ids_controller.rb +0 -1
  21. data/app/controllers/admin/imports_controller.rb +2 -2
  22. data/app/helpers/asset_helper.rb +8 -0
  23. data/app/helpers/document_helper.rb +4 -0
  24. data/app/helpers/geoblacklight_admin_helper.rb +11 -1
  25. data/{lib/generators/geoblacklight_admin/templates → app}/javascript/controllers/results_controller.js +38 -0
  26. data/app/javascript/entrypoints/engine.js +8 -0
  27. data/app/javascript/index.js +8 -0
  28. data/app/jobs/bulk_action_revert_document_job.rb +2 -2
  29. data/app/jobs/bulk_action_run_document_job.rb +5 -1
  30. data/app/jobs/bulk_action_run_job.rb +11 -1
  31. data/app/jobs/geoblacklight_admin/delete_thumbnail_job.rb +17 -0
  32. data/app/jobs/geoblacklight_admin/remove_parent_dct_references_uri_job.rb +16 -0
  33. data/app/jobs/geoblacklight_admin/set_parent_dct_references_uri_job.rb +19 -0
  34. data/app/jobs/geoblacklight_admin/store_image_job.rb +21 -2
  35. data/app/models/asset.rb +38 -0
  36. data/app/models/blacklight_api.rb +2 -2
  37. data/app/models/blacklight_api_facets.rb +1 -1
  38. data/app/models/blacklight_api_ids.rb +2 -2
  39. data/app/models/bulk_action_document_state_machine.rb +2 -4
  40. data/app/models/bulk_action_state_machine.rb +3 -3
  41. data/app/models/bulk_actions/change_publication_state.rb +10 -0
  42. data/app/models/document/reference.rb +24 -0
  43. data/app/models/document.rb +122 -11
  44. data/app/models/document_thumbnail_state_machine.rb +22 -0
  45. data/app/models/document_thumbnail_transition.rb +26 -0
  46. data/app/models/element.rb +1 -1
  47. data/app/models/geoblacklight_admin/field_mappings_btaa_aardvark.rb +7 -1
  48. data/app/models/geoblacklight_admin/schema.rb +37 -1
  49. data/app/models/geoblacklight_admin/solr_utils.rb +87 -0
  50. data/app/models/kithe/vips_cli_image_to_png.rb +114 -0
  51. data/app/services/geoblacklight_admin/image_service/iiif.rb +2 -2
  52. data/app/services/geoblacklight_admin/image_service/iiif_manifest.rb +111 -0
  53. data/app/services/geoblacklight_admin/image_service/tms.rb +50 -0
  54. data/app/services/geoblacklight_admin/image_service/wms.rb +1 -4
  55. data/app/services/geoblacklight_admin/image_service.rb +16 -40
  56. data/app/services/geoblacklight_admin/item_viewer.rb +1 -1
  57. data/app/uploaders/asset_uploader.rb +6 -11
  58. data/app/views/admin/assets/_form.html.erb +19 -0
  59. data/app/views/admin/assets/display_attach_form.html.erb +39 -0
  60. data/app/views/admin/assets/edit.html.erb +9 -0
  61. data/app/views/admin/assets/index.html.erb +75 -0
  62. data/app/views/admin/assets/show.html.erb +100 -0
  63. data/app/views/admin/bulk_actions/index.html.erb +50 -48
  64. data/app/views/admin/bulk_actions/show.html.erb +3 -2
  65. data/app/views/admin/document_accesses/index.html.erb +68 -64
  66. data/app/views/admin/document_assets/_form.html.erb +17 -0
  67. data/app/views/admin/document_assets/display_attach_form.html.erb +4 -9
  68. data/app/views/admin/document_assets/edit.html.erb +5 -0
  69. data/app/views/admin/document_assets/index.html.erb +88 -72
  70. data/app/views/admin/document_downloads/index.html.erb +64 -62
  71. data/app/views/admin/documents/_document.html.erb +37 -16
  72. data/app/views/admin/documents/_form.html.erb +21 -6
  73. data/app/views/admin/documents/_form_nav.html.erb +12 -3
  74. data/app/views/admin/documents/_result_selected_options.html.erb +6 -1
  75. data/app/views/admin/documents/admin.html.erb +210 -0
  76. data/app/views/admin/documents/index.html.erb +10 -1
  77. data/app/views/admin/documents/versions.html.erb +3 -3
  78. data/app/views/admin/elements/index.html.erb +55 -54
  79. data/app/views/admin/form_elements/index.html.erb +38 -35
  80. data/app/views/admin/imports/index.html.erb +52 -50
  81. data/app/views/admin/layouts/application.html.erb +7 -4
  82. data/app/views/admin/shared/_js_behaviors.html.erb +6 -3
  83. data/app/views/admin/shared/_navbar.html.erb +11 -8
  84. data/config/locales/documents.en.yml +6 -0
  85. data/config/routes.rb +1 -0
  86. data/config/vite.json +14 -0
  87. data/db/migrate/20240619171628_create_document_thumbnail_statesman.rb +18 -0
  88. data/lib/generators/geoblacklight_admin/config_generator.rb +63 -15
  89. data/lib/generators/geoblacklight_admin/install_generator.rb +1 -0
  90. data/lib/generators/geoblacklight_admin/templates/api_controller.rb +0 -2
  91. data/lib/generators/geoblacklight_admin/templates/base.html.erb +53 -0
  92. data/lib/generators/geoblacklight_admin/templates/config/initializers/kithe.rb +1 -0
  93. data/lib/generators/geoblacklight_admin/templates/config/settings.yml +15 -1
  94. data/lib/generators/geoblacklight_admin/templates/config/vite.json +16 -0
  95. data/lib/generators/geoblacklight_admin/templates/frontend/entrypoints/application.js +30 -0
  96. data/lib/generators/geoblacklight_admin/templates/package-test.json +10 -0
  97. data/lib/generators/geoblacklight_admin/templates/package.json +5 -29
  98. data/lib/generators/geoblacklight_admin/templates/vite.config.ts +8 -0
  99. data/lib/geoblacklight_admin/engine.rb +1 -0
  100. data/lib/geoblacklight_admin/rake_task.rb +5 -0
  101. data/lib/geoblacklight_admin/tasks/images.rake +33 -0
  102. data/lib/geoblacklight_admin/tasks/solr.rake +11 -0
  103. data/lib/geoblacklight_admin/version.rb +1 -1
  104. metadata +75 -19
  105. data/lib/generators/geoblacklight_admin/templates/javascript/controllers/application_controller.js +0 -17
  106. data/lib/generators/geoblacklight_admin/templates/javascript/controllers/document_controller.js +0 -26
  107. data/lib/generators/geoblacklight_admin/templates/javascript/controllers/index.js +0 -10
  108. data/lib/tasks/geoblacklight_admin/images.rake +0 -30
  109. data/lib/tasks/geoblacklight_admin.rake +0 -213
@@ -293,6 +293,44 @@ export default class extends Controller {
293
293
  form.submit();
294
294
  }
295
295
 
296
+ harvestThumbnails(event) {
297
+ var el = document.querySelector('#bulk_action_field_name');
298
+ el.setAttribute('value', "Harvest Thumbnails");
299
+
300
+ // Set field value
301
+ var el = document.querySelector('#bulk_action_field_value');
302
+ el.setAttribute(
303
+ 'value',
304
+ event.currentTarget.innerHTML.toLowerCase().trim()
305
+ );
306
+
307
+ // Set scope value
308
+ this.setPubState(event);
309
+
310
+ // Submit form
311
+ var form = document.querySelector('#result-action-form');
312
+ form.submit();
313
+ }
314
+
315
+ deleteThumbnails(event) {
316
+ var el = document.querySelector('#bulk_action_field_name');
317
+ el.setAttribute('value', "Delete Thumbnails");
318
+
319
+ // Set field value
320
+ var el = document.querySelector('#bulk_action_field_value');
321
+ el.setAttribute(
322
+ 'value',
323
+ event.currentTarget.innerHTML.toLowerCase().trim()
324
+ );
325
+
326
+ // Set scope value
327
+ this.setPubState(event);
328
+
329
+ // Submit form
330
+ var form = document.querySelector('#result-action-form');
331
+ form.submit();
332
+ }
333
+
296
334
  bulkActionDelete(event) {
297
335
  event.preventDefault();
298
336
 
@@ -0,0 +1,8 @@
1
+ console.log('Vite ⚡️ Rails - GBL Admin')
2
+
3
+ // Stimulus
4
+ import { Application } from '@hotwired/stimulus'
5
+ import ResultsController from "../controllers/results_controller"
6
+
7
+ window.Stimulus = Application.start()
8
+ Stimulus.register("results", ResultsController)
@@ -0,0 +1,8 @@
1
+ console.log('Vite ⚡️ Rails - GBL Admin')
2
+
3
+ // Stimulus
4
+ import { Application } from '@hotwired/stimulus'
5
+ import ResultsController from "./controllers/results_controller"
6
+
7
+ window.Stimulus = Application.start()
8
+ Stimulus.register("results", ResultsController)
@@ -22,9 +22,9 @@ class BulkActionRevertDocumentJob < ApplicationJob
22
22
 
23
23
  versions = document.versions
24
24
  document = versions[doc.version].reify
25
- document.skip_callbacks = true
25
+ document&.skip_callbacks = true
26
26
 
27
- if document.save
27
+ if document&.save
28
28
  doc.state_machine.transition_to!(:success)
29
29
  else
30
30
  doc.state_machine.transition_to!(:failed)
@@ -10,8 +10,12 @@ class BulkActionRunDocumentJob < ApplicationJob
10
10
  update_publication_status(doc, field_value)
11
11
  when :update_delete
12
12
  update_delete(doc, field_value)
13
- # @TODO: Field Level changes
13
+ when :harvest_thumbnails
14
+ GeoblacklightAdmin::StoreImageJob.perform_later(doc.friendlier_id, doc.id, :priority)
15
+ when :delete_thumbnails
16
+ GeoblacklightAdmin::DeleteThumbnailJob.perform_later(doc.friendlier_id, doc.id, :priority)
14
17
  else
18
+ # @TODO: Field Level changes
15
19
  logger.debug("@TODO - #{field_name} => #{field_value}")
16
20
  end
17
21
  end
@@ -4,6 +4,11 @@
4
4
  class BulkActionRunJob < ApplicationJob
5
5
  queue_as :priority
6
6
 
7
+ after_perform do |job|
8
+ logger.debug("BulkActionRunJob - After Perform - #{job.arguments.first.id}")
9
+ job.arguments.first.state_machine.transition_to!(:complete)
10
+ end
11
+
7
12
  def perform(bulk_action)
8
13
  action = case bulk_action.field_name
9
14
  when "Publication State"
@@ -12,13 +17,18 @@ class BulkActionRunJob < ApplicationJob
12
17
  when "Delete"
13
18
  logger.debug("BulkAction: Delete")
14
19
  :update_delete
20
+ when "Harvest Thumbnails"
21
+ logger.debug("BulkAction: Harvest Thumbnails")
22
+ :harvest_thumbnails
23
+ when "Delete Thumbnails"
24
+ logger.debug("BulkAction: Delete Thumbnails")
25
+ :delete_thumbnails
15
26
  else
16
27
  :update_field_value
17
28
  end
18
29
 
19
30
  bulk_action.documents.each do |doc|
20
31
  BulkActionRunDocumentJob.perform_later(action, doc, bulk_action.field_name, bulk_action.field_value)
21
- doc.state_machine.transition_to!(:queued)
22
32
  end
23
33
 
24
34
  # Capture State
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GeoblacklightAdmin
4
+ class DeleteThumbnailJob < ApplicationJob
5
+ queue_as do
6
+ arguments.last
7
+ end
8
+
9
+ def perform(solr_document_id, bad_id = nil, queue = :priority)
10
+ document = Document.find_by_friendlier_id(solr_document_id)
11
+ if document.thumbnail.present?
12
+ document.thumbnail.destroy!
13
+ end
14
+ BulkActionDocument.find(bad_id).state_machine.transition_to!(:success) if bad_id.present?
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GeoblacklightAdmin
4
+ class RemoveParentDctReferencesUriJob < ApplicationJob
5
+ queue_as :priority
6
+
7
+ def perform(asset)
8
+ if asset.dct_references_uri_key.present?
9
+ asset.parent.dct_references_s.delete_if { |i| i.value == asset.full_file_url }
10
+ asset.parent.save!
11
+ end
12
+ rescue => e
13
+ Rails.logger.error "\nError - Removing parent dct_references URI: #{e.message} \n"
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GeoblacklightAdmin
4
+ class SetParentDctReferencesUriJob < ApplicationJob
5
+ queue_as :priority
6
+
7
+ def perform(asset)
8
+ if asset.dct_references_uri_key.present?
9
+ reference = Document::Reference.new
10
+ reference.category = asset.dct_references_uri_key
11
+ reference.value = asset.full_file_url
12
+ asset.parent.dct_references_s << reference
13
+ asset.parent.save!
14
+ end
15
+ rescue => e
16
+ Rails.logger.error "\nError - Setting parent DCT references URI: #{e.message}\n"
17
+ end
18
+ end
19
+ end
@@ -2,11 +2,30 @@
2
2
 
3
3
  module GeoblacklightAdmin
4
4
  class StoreImageJob < ApplicationJob
5
- queue_as :default
5
+ queue_as do
6
+ arguments.last
7
+ end
6
8
 
7
- def perform(solr_document_id)
9
+ def perform(solr_document_id, bad_id = nil, queue = :default)
10
+ # Find the document
8
11
  document = Document.find_by_friendlier_id(solr_document_id)
12
+
13
+ # Delete thumbnail if already present
14
+ if document&.thumbnail&.present?
15
+ document.thumbnail.destroy!
16
+ end
17
+
18
+ # Statesman
19
+ metadata = {}
20
+ metadata["solr_doc_id"] = solr_document_id
21
+ document.thumbnail_state_machine.transition_to!(:queued, metadata)
22
+
23
+ # Crawl politely
24
+ sleep(rand(1..5))
25
+
26
+ # Store the image
9
27
  GeoblacklightAdmin::ImageService.new(document).store
28
+ BulkActionDocument.find(bad_id).state_machine.transition_to!(:success) if bad_id.present?
10
29
  end
11
30
  end
12
31
  end
data/app/models/asset.rb CHANGED
@@ -1,13 +1,51 @@
1
1
  class Asset < Kithe::Asset
2
2
  include AttrJson::Record::QueryScopes
3
+ include Rails.application.routes.url_helpers
4
+
5
+ # Default Sort Order
6
+ default_scope { order(parent_id: :desc, created_at: :asc) }
3
7
 
4
8
  set_shrine_uploader(AssetUploader)
5
9
 
6
10
  # AttrJSON
7
11
  attr_json :thumbnail, :boolean, default: "false"
8
12
  attr_json :derivative_storage_type, :string, default: "public"
13
+ attr_json :dct_references_uri_key, :string
14
+ attr_json :label, :string
9
15
 
10
16
  DERIVATIVE_STORAGE_TYPE_LOCATIONS = {
11
17
  "public" => :kithe_derivatives
12
18
  }.freeze
19
+
20
+ def full_file_url
21
+ if Rails.env.development?
22
+ "http://localhost:3000" + file.url
23
+ else
24
+ file.url
25
+ end
26
+ end
27
+
28
+ # After Promotion Callbacks
29
+ after_promotion :set_parent_dct_references_uri
30
+
31
+ def set_parent_dct_references_uri
32
+ GeoblacklightAdmin::SetParentDctReferencesUriJob.perform_later(self) if parent_id.present?
33
+ end
34
+
35
+ # Before Destroy Callbacks
36
+ before_destroy :remove_parent_dct_references_uri
37
+
38
+ def remove_parent_dct_references_uri
39
+ GeoblacklightAdmin::RemoveParentDctReferencesUriJob.perform_later(self) if parent_id.present?
40
+ end
41
+
42
+ # After Save Callbacks
43
+ after_save :reindex_parent
44
+
45
+ def reindex_parent
46
+ parent.save if parent.present?
47
+ end
13
48
  end
49
+
50
+ # Allow DocumentAsset to be used as a synonym for Asset
51
+ DocumentAsset = Asset
@@ -30,11 +30,11 @@ class BlacklightApi
30
30
  end
31
31
 
32
32
  def facets
33
- fetch["included"]&.filter_map { |s| s if s["type"] == "facet" }
33
+ fetch["included"]&.select { |s| s["type"] == "facet" }
34
34
  end
35
35
 
36
36
  def sorts
37
- fetch["included"].filter_map { |s| s if s["type"] == "sort" }
37
+ fetch["included"].select { |s| s["type"] == "sort" }
38
38
  end
39
39
 
40
40
  def meta
@@ -15,6 +15,6 @@ class BlacklightApiFacets
15
15
  end
16
16
 
17
17
  def facets
18
- fetch["included"].filter_map { |s| s if s["type"] == "facet" } if fetch["included"].present?
18
+ fetch["included"].select { |s| s["type"] == "facet" } if fetch["included"].present?
19
19
  end
20
20
  end
@@ -33,11 +33,11 @@ class BlacklightApiIds
33
33
  end
34
34
 
35
35
  def facets
36
- fetch["included"]&.filter_map { |s| s if s["type"] == "facet" }
36
+ fetch["included"]&.select { |s| s["type"] == "facet" }
37
37
  end
38
38
 
39
39
  def sorts
40
- fetch["included"].filter_map { |s| s if s["type"] == "sort" }
40
+ fetch["included"].select { |s| s["type"] == "sort" }
41
41
  end
42
42
 
43
43
  def meta
@@ -9,8 +9,6 @@ class BulkActionDocumentStateMachine
9
9
  state :success
10
10
  state :failed
11
11
 
12
- transition from: :created, to: %i[queued success]
13
- transition from: :queued, to: %i[queued success failed]
14
- transition from: :success, to: %i[queued success failed]
15
- transition from: :failed, to: %i[queued success failed]
12
+ transition from: :created, to: %i[queued success failed]
13
+ transition from: :queued, to: %i[success failed]
16
14
  end
@@ -10,7 +10,7 @@ class BulkActionStateMachine
10
10
  state :failed
11
11
  state :reverted
12
12
 
13
- transition from: :created, to: %i[queued complete failed]
14
- transition from: :queued, to: %i[created queued complete failed]
15
- transition from: :complete, to: %i[queued reverted]
13
+ transition from: :created, to: %i[queued]
14
+ transition from: :queued, to: %i[created complete failed]
15
+ transition from: :complete, to: %i[reverted]
16
16
  end
@@ -18,4 +18,14 @@ module BulkActions
18
18
  class DraftDocument < BulkAction
19
19
  # Add specific methods and validations for DraftDocument here
20
20
  end
21
+
22
+ # Subclass for HarvestThumbnails
23
+ class HarvestThumbnails < BulkAction
24
+ # Add specific methods and validations for HarvestThumbnails here
25
+ end
26
+
27
+ # Subclass for DeleteThumbnails
28
+ class DeleteThumbnails < BulkAction
29
+ # Add specific methods and validations for DeleteThumbnails here
30
+ end
21
31
  end
@@ -90,6 +90,30 @@ class Document
90
90
  oembed: {
91
91
  label: "oEmbed",
92
92
  uri: "https://oembed.com"
93
+ },
94
+ cog: {
95
+ label: "COG",
96
+ uri: "https://github.com/cogeotiff/cog-spec"
97
+ },
98
+ pmtiles: {
99
+ label: "PMTiles",
100
+ uri: "https://github.com/protomaps/PMTiles"
101
+ },
102
+ xyz_tiles: {
103
+ label: "XYZ Tiles",
104
+ uri: "https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames"
105
+ },
106
+ wmts: {
107
+ label: "WMTS",
108
+ uri: "http://www.opengis.net/def/serviceType/ogc/wmts"
109
+ },
110
+ tile_json: {
111
+ label: "TileJSON",
112
+ uri: "https://github.com/mapbox/tilejson-spec"
113
+ },
114
+ tile_map_service: {
115
+ label: "Tile Map Service",
116
+ uri: "https://wiki.osgeo.org/wiki/Tile_Map_Service_Specification"
93
117
  }
94
118
  }.freeze
95
119
 
@@ -18,26 +18,59 @@ class Document < Kithe::Work
18
18
  belongs_to :import, optional: true
19
19
 
20
20
  # Statesman
21
+ # - Publication State
21
22
  has_many :document_transitions, foreign_key: "kithe_model_id", autosave: false, dependent: :destroy,
22
23
  inverse_of: :document
24
+ # - Thumbnail State
25
+ has_many :document_thumbnail_transitions, foreign_key: "kithe_model_id", autosave: false, dependent: :destroy,
26
+ inverse_of: :document
23
27
 
24
- # DocumentAccesses
28
+ # Document Collections
29
+ # - DocumentAccesses
25
30
  has_many :document_accesses, primary_key: "friendlier_id", foreign_key: "friendlier_id", autosave: false, dependent: :destroy,
26
31
  inverse_of: :document
27
32
 
28
- # DocumentDownloads
33
+ # - DocumentDownloads
29
34
  has_many :document_downloads, primary_key: "friendlier_id", foreign_key: "friendlier_id", autosave: false, dependent: :destroy,
30
35
  inverse_of: :document
31
36
 
37
+ # DocumentAssets - Thumbnails, Attachments, etc
38
+ # @TODO: Redundant? Kithe also includes a members association
39
+ def document_assets
40
+ scope = Kithe::Asset
41
+ scope = scope.where(parent_id: id)
42
+
43
+ # scope = scope.page(params[:page]).per(20).order(created_at: :desc)
44
+ scope.includes(:parent)
45
+ end
46
+
47
+ def downloadable_assets
48
+ document_assets.select { |a| a.dct_references_uri_key == "download" }
49
+ end
50
+
32
51
  include Statesman::Adapters::ActiveRecordQueries[
33
52
  transition_class: DocumentTransition,
34
53
  initial_state: :draft
35
54
  ]
36
55
 
56
+ # @TODO: Rename this to publication_state_machine
37
57
  def state_machine
38
58
  @state_machine ||= DocumentStateMachine.new(self, transition_class: DocumentTransition)
39
59
  end
40
60
 
61
+ include Statesman::Adapters::ActiveRecordQueries[
62
+ transition_class: DocumentThumbnailTransition,
63
+ initial_state: :initialized
64
+ ]
65
+
66
+ def thumbnail_state_machine
67
+ @thumbnail_state_machine ||= DocumentThumbnailStateMachine.new(self, transition_class: DocumentThumbnailTransition)
68
+ end
69
+
70
+ def raw_solr_document
71
+ Blacklight.default_index.connection.get("select", {params: {q: "id:\"#{geomg_id_s}\""}})["response"]["docs"][0]
72
+ end
73
+
41
74
  delegate :current_state, to: :state_machine
42
75
 
43
76
  before_save :transition_publication_state, unless: :skip_callbacks
@@ -78,27 +111,101 @@ class Document < Kithe::Work
78
111
  # Index Transformations - *_json functions
79
112
  def references
80
113
  references = ActiveSupport::HashWithIndifferentAccess.new
114
+
115
+ # Prep value arrays
116
+ send(GeoblacklightAdmin::Schema.instance.solr_fields[:reference]).each do |ref|
117
+ references[Document::Reference::REFERENCE_VALUES[ref.category.to_sym][:uri]] = []
118
+ end
119
+
120
+ # Seed value arrays
81
121
  send(GeoblacklightAdmin::Schema.instance.solr_fields[:reference]).each do |ref|
82
- references[Document::Reference::REFERENCE_VALUES[ref.category.to_sym][:uri]] = ref.value
122
+ # @TODO: Need to support multiple entries per key here
123
+ references[Document::Reference::REFERENCE_VALUES[ref.category.to_sym][:uri]] << ref.value
124
+ end
125
+
126
+ logger.debug("\n\nDocument#references > seeded: #{references}")
127
+
128
+ # Apply Downloads
129
+ references = apply_downloads(references)
130
+
131
+ logger.debug("Document#references > downloads: #{references}\n\n")
132
+
133
+ # Need to flatten the arrays here to avoid the following potential error:
134
+ # - ArgumentError: Please use symbols for polymorphic route arguments.
135
+ # - Via: app/helpers/geoblacklight_helper.rb:224:in `render_references_url'
136
+ references.each do |key, value|
137
+ next if key == "http://schema.org/downloadUrl"
138
+ if value.is_a?(Array) && value.length == 1
139
+ references[key] = value.first
140
+ end
83
141
  end
84
- apply_downloads(references)
142
+
143
+ references
85
144
  end
86
145
 
87
146
  def references_json
88
147
  references.to_json
89
148
  end
90
149
 
150
+ def asset_label(asset)
151
+ if asset.label.present?
152
+ asset.label
153
+ else
154
+ asset.title
155
+ end
156
+ end
157
+
158
+ # Apply Downloads
159
+ # 1. Native Aardvark Downloads
160
+ # 2. Multiple Document Download Links
161
+ # 3. Downloadable Document Assets
91
162
  def apply_downloads(references)
163
+ multiple_downloads = []
164
+
92
165
  dct_downloads = references["http://schema.org/downloadUrl"]
93
- # Make sure downloads exist!
94
- if document_downloads.present?
95
- multiple_downloads = multiple_downloads_array
96
- if dct_downloads.present?
166
+
167
+ logger.debug("Document#dct_downloads > init: #{dct_downloads}\n\n")
168
+
169
+ # Native Aardvark Downloads
170
+ # - Via CSV Import or via the webform
171
+ if dct_downloads.present?
172
+ dct_downloads.each do |download|
97
173
  multiple_downloads << {label: download_text(send(GeoblacklightAdmin::Schema.instance.solr_fields[:format])),
98
- url: dct_downloads}
174
+ url: download}
175
+ end
176
+ end
177
+
178
+ logger.debug("Document#multiple_downloads > aardvark: #{multiple_downloads.inspect}\n\n")
179
+
180
+ # Multiple Document Download Links
181
+ # - Via DocumentDownloads
182
+ if document_downloads.present?
183
+ multiple_downloads << multiple_downloads_array
184
+ end
185
+
186
+ logger.debug("Document#dct_downloads > document_downloads: #{multiple_downloads.inspect}\n\n")
187
+
188
+ # Downloadable Document Assets
189
+ # - Via DocumentAssets (Assets)
190
+ # - With Downloadable URI
191
+ if downloadable_assets.present?
192
+ downloadable_assets.each do |asset|
193
+ logger.debug("\n\n Document#dct_downloads > dupe?: #{multiple_downloads.detect { |d| d[:url].include?(asset.file.url) }}\n\n")
194
+
195
+ if multiple_downloads.detect { |d| d[:url].include?(asset.file.url) }
196
+ logger.debug("\n\n Detected duplicate download URL: #{asset.file.url}\n\n")
197
+ index = multiple_downloads.index { |d| d[:url].include?(asset.file.url) }
198
+ multiple_downloads[index] = {label: asset_label(asset), url: asset.file.url}
199
+ else
200
+ logger.debug("\n\n No duplicate found - Adding downloadable asset: #{asset.file.url}\n\n")
201
+ multiple_downloads << {label: asset_label(asset), url: asset.file.url}
202
+ end
99
203
  end
100
- references[:"http://schema.org/downloadUrl"] = multiple_downloads
101
204
  end
205
+
206
+ logger.debug("Document#dct_downloads > downloadable_assets: #{multiple_downloads.inspect}\n\n")
207
+
208
+ references[:"http://schema.org/downloadUrl"] = multiple_downloads.flatten unless multiple_downloads.empty?
102
209
  references
103
210
  end
104
211
 
@@ -231,8 +338,9 @@ class Document < Kithe::Work
231
338
 
232
339
  ### End / From GBL
233
340
 
341
+ # Thumbnail is a special case of document_assets
234
342
  def thumbnail
235
- members.find { |m| m.respond_to?(:thumbnail) }
343
+ members.find { |m| m.respond_to?(:thumbnail) && m.thumbnail? }
236
344
  end
237
345
 
238
346
  def access_json
@@ -282,6 +390,9 @@ class Document < Kithe::Work
282
390
  if value[:delimited]
283
391
  send(value[:destination])&.join("|")
284
392
  elsif value[:destination] == "dct_references_s"
393
+ # @TODO: Downloads need to be handled differently
394
+ # - Need to support multiple entries per key here
395
+ # - Need to respect label and url
285
396
  dct_references_s_to_csv(key, value[:destination])
286
397
  elsif value[:destination] == "b1g_publication_state_s"
287
398
  send(:current_state)
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Document Thumbnail State Machine
4
+ class DocumentThumbnailStateMachine
5
+ include Statesman::Machine
6
+
7
+ state :initialized, initial: true
8
+ state :queued
9
+ state :processing
10
+ state :succeeded
11
+ state :failed
12
+ state :placeheld
13
+
14
+ # Queued => Background Job Init
15
+ # Processing => Failed, Placeheld, Succeeded
16
+ transition from: :initialized, to: %i[queued processing]
17
+ transition from: :queued, to: %i[queued processing]
18
+ transition from: :processing, to: %i[queued processing placeheld succeeded failed]
19
+ transition from: :placeheld, to: %i[queued processing failed]
20
+ transition from: :failed, to: %i[queued processing]
21
+ transition from: :succeeded, to: %i[queued processing]
22
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Add Document Thumbnail State Transitions
4
+ class DocumentThumbnailTransition < 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_thumbnail_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_thumbnail_transitions.order(:sort_key).last
22
+ return if last_transition.blank?
23
+
24
+ last_transition.update_column(:most_recent, true)
25
+ end
26
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Element < ApplicationRecord
4
- serialize :html_attributes
4
+ serialize :html_attributes, coder: JSON
5
5
 
6
6
  # Scopes
7
7
  scope :formable, -> { where(formable: true) }
@@ -372,7 +372,13 @@ module GeoblacklightAdmin
372
372
  "urn:x-esri:serviceType:ArcGIS#ImageMapLayer": "arcgis_image_map_layer",
373
373
  "http://schema.org/DownloadAction": "harvard",
374
374
  "https://openindexmaps.org": "open_index_map",
375
- "https://oembed.com": "oembed"
375
+ "https://oembed.com": "oembed",
376
+ "https://github.com/cogeotiff/cog-spec": "cog",
377
+ "https://github.com/protomaps/PMTiles": "pmtiles",
378
+ "https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames": "xyz_tiles",
379
+ "http://www.opengis.net/def/serviceType/ogc/wmts": "wmts",
380
+ "https://github.com/mapbox/tilejson-spec": "tile_json",
381
+ "https://wiki.osgeo.org/wiki/Tile_Map_Service_Specification": "tile_map_service"
376
382
  })
377
383
  end
378
384
  end