dor-services 4.25.1 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/bin/dor-indexer +20 -19
  3. data/bin/dor-indexerd +3 -2
  4. data/config/certs/robots-dor-dev.crt +29 -0
  5. data/config/certs/robots-dor-dev.key +27 -0
  6. data/config/config_defaults.yml +0 -6
  7. data/config/dev_console_env.rb +65 -0
  8. data/config/environments/development.rb +84 -0
  9. data/config/environments/development.rb.old +84 -0
  10. data/config/environments/test.rb +84 -0
  11. data/lib/dor-services.rb +8 -18
  12. data/lib/dor/config.rb +18 -24
  13. data/lib/dor/datastreams/administrative_metadata_ds.rb +8 -7
  14. data/lib/dor/datastreams/content_metadata_ds.rb +200 -278
  15. data/lib/dor/datastreams/datastream_spec_solrizer.rb +1 -1
  16. data/lib/dor/datastreams/default_object_rights_ds.rb +10 -8
  17. data/lib/dor/datastreams/desc_metadata_ds.rb +30 -34
  18. data/lib/dor/datastreams/embargo_metadata_ds.rb +17 -13
  19. data/lib/dor/datastreams/events_ds.rb +12 -12
  20. data/lib/dor/datastreams/geo_metadata_ds.rb +3 -244
  21. data/lib/dor/datastreams/identity_metadata_ds.rb +34 -30
  22. data/lib/dor/datastreams/role_metadata_ds.rb +6 -6
  23. data/lib/dor/datastreams/simple_dublin_core_ds.rb +12 -9
  24. data/lib/dor/datastreams/version_metadata_ds.rb +14 -33
  25. data/lib/dor/datastreams/workflow_definition_ds.rb +18 -18
  26. data/lib/dor/datastreams/workflow_ds.rb +74 -65
  27. data/lib/dor/migrations/identifiable/assert_adminPolicy.rb +1 -1
  28. data/lib/dor/migrations/identifiable/fix_model_assertions.rb +1 -1
  29. data/lib/dor/migrations/identifiable/record_remediation.rb +2 -2
  30. data/lib/dor/migrations/identifiable/uriify_augmented_contentlocation_refs.rb +1 -1
  31. data/lib/dor/migrations/identifiable/uriify_contentlocation_refs.rb +1 -1
  32. data/lib/dor/migrations/processable/unify_workflows.rb +4 -4
  33. data/lib/dor/migrations/versionable/add_missing_version_md.rb +1 -1
  34. data/lib/dor/models/admin_policy_object.rb +1 -1
  35. data/lib/dor/models/assembleable.rb +3 -4
  36. data/lib/dor/models/collection.rb +0 -2
  37. data/lib/dor/models/contentable.rb +34 -35
  38. data/lib/dor/models/describable.rb +80 -122
  39. data/lib/dor/models/editable.rb +57 -73
  40. data/lib/dor/models/embargoable.rb +13 -15
  41. data/lib/dor/models/eventable.rb +3 -3
  42. data/lib/dor/models/geoable.rb +8 -9
  43. data/lib/dor/models/governable.rb +36 -54
  44. data/lib/dor/models/identifiable.rb +119 -115
  45. data/lib/dor/models/item.rb +4 -4
  46. data/lib/dor/models/itemizable.rb +9 -9
  47. data/lib/dor/models/presentable.rb +133 -0
  48. data/lib/dor/models/preservable.rb +4 -4
  49. data/lib/dor/models/processable.rb +29 -28
  50. data/lib/dor/models/publishable.rb +36 -30
  51. data/lib/dor/models/releasable.rb +310 -0
  52. data/lib/dor/models/shelvable.rb +14 -14
  53. data/lib/dor/models/upgradable.rb +13 -13
  54. data/lib/dor/models/versionable.rb +4 -7
  55. data/lib/dor/models/workflow_object.rb +16 -36
  56. data/lib/dor/services/cleanup_reset_service.rb +28 -34
  57. data/lib/dor/services/cleanup_service.rb +4 -4
  58. data/lib/dor/services/digital_stacks_service.rb +10 -10
  59. data/lib/dor/services/merge_service.rb +1 -1
  60. data/lib/dor/services/metadata_handlers/mdtoolkit_handler.rb +2 -2
  61. data/lib/dor/services/metadata_service.rb +20 -20
  62. data/lib/dor/services/registration_service.rb +26 -27
  63. data/lib/dor/services/reset_workspace_service.rb +15 -15
  64. data/lib/dor/services/sdr_ingest_service.rb +4 -4
  65. data/lib/dor/services/search_service.rb +4 -9
  66. data/lib/dor/services/suri_service.rb +5 -5
  67. data/lib/dor/services/technical_metadata_service.rb +3 -2
  68. data/lib/dor/utils/ng_tidy.rb +9 -9
  69. data/lib/dor/utils/predicate_patch.rb +1 -1
  70. data/lib/dor/utils/solr_doc_helper.rb +13 -5
  71. data/lib/dor/version.rb +1 -1
  72. data/lib/dor/workflow/document.rb +28 -30
  73. data/lib/dor/workflow/graph.rb +36 -36
  74. data/lib/dor/workflow/process.rb +12 -12
  75. data/lib/tasks/dor.rake +1 -1
  76. data/lib/tasks/rdoc.rake +3 -3
  77. metadata +67 -76
  78. data/lib/dor/datastreams/geo2mods.xsl +0 -867
  79. data/lib/dor/models/discoverable.rb +0 -64
  80. data/lib/dor/models/releaseable.rb +0 -357
  81. data/lib/dor/services/indexing_service.rb +0 -64
  82. data/lib/dor/utils/sdr_client.rb +0 -23
  83. data/lib/dor/utils/utc_date_field_mapper.rb +0 -7
@@ -6,8 +6,8 @@ module Dor
6
6
  include Upgradable
7
7
 
8
8
  included do
9
- has_metadata :name => 'DC', :type => SimpleDublinCoreDs, :label => 'Dublin Core Record for self object'
10
- has_metadata :name => 'identityMetadata', :type => Dor::IdentityMetadataDS, :label => 'Identity Metadata'
9
+ has_metadata :name => "DC", :type => SimpleDublinCoreDs, :label => 'Dublin Core Record for self object'
10
+ has_metadata :name => "identityMetadata", :type => Dor::IdentityMetadataDS, :label => 'Identity Metadata'
11
11
  end
12
12
 
13
13
  module ClassMethods
@@ -18,22 +18,24 @@ module Dor
18
18
  end
19
19
  end
20
20
 
21
- def initialize attrs = {}
21
+ def initialize attrs={}
22
22
  if Dor::Config.suri.mint_ids
23
- attrs = attrs.merge!({:pid => Dor::SuriService.mint_id, :new_object => true}) unless attrs[:pid]
23
+ unless attrs[:pid]
24
+ attrs = attrs.merge!({:pid=>Dor::SuriService.mint_id, :new_object => true})
25
+ end
24
26
  end
25
27
  super
26
28
  end
27
29
 
28
30
  # helper method to get the tags as an array
29
31
  def tags
30
- identityMetadata.tag
32
+ self.identityMetadata.tag
31
33
  end
32
34
 
33
35
  # helper method to get just the content type tag
34
36
  def content_type_tag
35
- content_tag = tags.select {|tag| tag.include?('Process : Content Type')}
36
- content_tag.size == 1 ? content_tag[0].split(':').last.strip : ''
37
+ content_tag=tags.select {|tag| tag.include?('Process : Content Type')}
38
+ content_tag.size == 1 ? content_tag[0].split(':').last.strip : ""
37
39
  end
38
40
 
39
41
  # Syntactic sugar for identifying applied DOR Concerns
@@ -51,131 +53,134 @@ module Dor
51
53
  end
52
54
  end
53
55
 
54
- @@collection_hash = {}
55
- @@apo_hash = {}
56
- @@hydrus_apo_hash = {}
57
- @@hydrus_collection_hash = {}
58
- def to_solr(solr_doc = {}, *args)
59
- assert_content_model
60
- super(solr_doc)
56
+ ## Module-level variables, shared between ALL mixin includers!
57
+ @@collection_hash={}
58
+ @@apo_hash={}
59
+ @@hydrus_apo_hash={}
60
+ @@hydrus_collection_hash={}
61
+
62
+ def to_solr(solr_doc=Hash.new, *args)
63
+ self.assert_content_model
64
+ super(solr_doc, *args)
61
65
  solr_doc[Dor::INDEX_VERSION_FIELD] = Dor::VERSION
62
- solr_doc[solr_name('indexed_at', :date)] = Time.now.utc.xmlschema
63
- add_solr_value(solr_doc, 'indexed_day', Time.now.beginning_of_day.utc.xmlschema, :string, [:searchable, :facetable])
66
+ solr_doc['indexed_at_dtsi' ] = Time.now.utc.xmlschema
67
+ solr_doc['indexed_day_dtsi'] = Time.now.beginning_of_day.utc.xmlschema # technically unnecessary, but convenient
64
68
  datastreams.values.each do |ds|
65
- next if ds.new?
66
- add_solr_value(solr_doc, 'ds_specs', ds.datastream_spec_string, :string, [:displayable])
69
+ add_solr_value(solr_doc,'ds_specs',ds.datastream_spec_string,:string,[:displayable]) unless ds.new?
67
70
  end
68
- add_solr_value(solr_doc, 'title_sort', label, :string, [:sortable])
69
- rels_doc = Nokogiri::XML(datastreams['RELS-EXT'].content)
70
- apos = rels_doc.search('//rdf:RDF/rdf:Description/hydra:isGovernedBy', 'hydra' => 'http://projecthydra.org/ns/relations#', 'fedora' => 'info:fedora/fedora-system:def/relations-external#', 'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#' )
71
+ add_solr_value(solr_doc, 'title_sort', self.label, :string, [:sortable])
72
+ title_attrs = [:searchable, :facetable, :displayable]
73
+ rels_doc = Nokogiri::XML(self.datastreams['RELS-EXT'].content)
74
+ apos=rels_doc.search('//rdf:RDF/rdf:Description/hydra:isGovernedBy','hydra' => 'http://projecthydra.org/ns/relations#', 'fedora' => 'info:fedora/fedora-system:def/relations-external#', 'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#' )
71
75
  apos.each do |apo_node|
72
76
  druid = apo_node['rdf:resource']
73
- next unless druid
74
- druid = druid.gsub('info:fedora/','')
77
+ next unless druid # TODO: a warning about the bad APO would be nice
78
+ druid=druid.gsub('info:fedora/','')
79
+ # check cache first
75
80
  if @@apo_hash.has_key?(druid) || @@hydrus_apo_hash.has_key?(druid)
76
- add_solr_value(solr_doc, 'hydrus_apo_title', @@hydrus_apo_hash[druid], :string, [:searchable, :facetable]) if @@hydrus_apo_hash.has_key? druid
77
- add_solr_value(solr_doc, 'apo_title', @@apo_hash[druid] , :string, [:searchable, :facetable]) if @@apo_hash.has_key? druid
81
+ add_solr_value(solr_doc, "hydrus_apo_title", @@hydrus_apo_hash[druid], :string, title_attrs) if @@hydrus_apo_hash.has_key? druid
82
+ add_solr_value(solr_doc, "apo_title", @@apo_hash[druid] , :string, title_attrs) if @@apo_hash.has_key? druid
78
83
  else
79
84
  begin
80
- apo_object = Dor.find(druid)
85
+ apo_object=Dor.find(druid)
81
86
  if apo_object.tags.include? 'Project : Hydrus'
82
- add_solr_value(solr_doc, 'hydrus_apo_title', apo_object.label, :string, [:searchable, :facetable])
83
- @@hydrus_apo_hash[druid] = apo_object.label
87
+ add_solr_value(solr_doc, "hydrus_apo_title", apo_object.label, :string, title_attrs)
88
+ @@hydrus_apo_hash[druid]=apo_object.label
84
89
  else
85
- add_solr_value(solr_doc, 'apo_title', apo_object.label, :string, [:searchable, :facetable])
86
- @@apo_hash[druid] = apo_object.label
90
+ add_solr_value(solr_doc, "apo_title", apo_object.label, :string, title_attrs)
91
+ @@apo_hash[druid]=apo_object.label
87
92
  end
88
93
  rescue
89
- add_solr_value(solr_doc, 'apo_title', druid, :string, [:searchable, :facetable])
94
+ add_solr_value(solr_doc, "apo_title", druid, :string, title_attrs)
90
95
  end
91
96
  end
92
97
  end
93
- collections = rels_doc.search('//rdf:RDF/rdf:Description/fedora:isMemberOfCollection', 'fedora' => 'info:fedora/fedora-system:def/relations-external#', 'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#')
98
+ collections=rels_doc.search('//rdf:RDF/rdf:Description/fedora:isMemberOfCollection','fedora' => 'info:fedora/fedora-system:def/relations-external#', 'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#' )
94
99
  collections.each do |collection_node|
95
- druid = collection_node['rdf:resource']
96
- next unless druid
97
- druid = druid.gsub('info:fedora/', '')
100
+ druid=collection_node['rdf:resource']
101
+ next unless druid ## TODO: warning here would also be useful
102
+ druid=druid.gsub('info:fedora/','')
98
103
  if @@collection_hash.has_key?(druid) || @@hydrus_collection_hash.has_key?(druid)
99
- add_solr_value(solr_doc, 'hydrus_collection_title', @@hydrus_collection_hash[druid], :string, [:searchable, :facetable]) if @@hydrus_collection_hash.has_key? druid
100
- add_solr_value(solr_doc, 'collection_title', @@collection_hash[druid], :string, [:searchable, :facetable]) if @@collection_hash.has_key? druid
104
+ add_solr_value(solr_doc, "hydrus_collection_title", @@hydrus_collection_hash[druid], :string, title_attrs) if @@hydrus_collection_hash.has_key? druid
105
+ add_solr_value(solr_doc, "collection_title", @@collection_hash[druid], :string, title_attrs) if @@collection_hash.has_key? druid
101
106
  else
102
107
  begin
103
- collection_object = Dor.find(druid)
108
+ collection_object=Dor.find(druid)
104
109
  if collection_object.tags.include? 'Project : Hydrus'
105
- add_solr_value(solr_doc, 'hydrus_collection_title', collection_object.label, :string, [:searchable, :facetable])
106
- @@hydrus_collection_hash[druid] = collection_object.label
110
+ add_solr_value(solr_doc, "hydrus_collection_title", collection_object.label, :string, title_attrs)
111
+ @@hydrus_collection_hash[druid]=collection_object.label
107
112
  else
108
- add_solr_value(solr_doc, 'collection_title', collection_object.label, :string, [:searchable, :facetable])
109
- @@collection_hash[druid] = collection_object.label
113
+ add_solr_value(solr_doc, "collection_title", collection_object.label, :string, title_attrs)
114
+ @@collection_hash[druid]=collection_object.label
110
115
  end
111
116
  rescue
112
- add_solr_value(solr_doc, 'collection_title', druid, :string, [:searchable, :facetable])
117
+ add_solr_value(solr_doc, "collection_title", druid, :string, title_attrs)
113
118
  end
114
119
  end
115
120
  end
116
- # Fix for ActiveFedora 3.3 to ensure all date fields are properly formatted as UTC XML Schema datetime strings
117
- solr_doc.each_pair { |k, v|
118
- next unless k =~ /(_dt|_date)$/
119
- if v.is_a?(Array)
120
- solr_doc[k] = v.collect { |t| Time.parse(t.to_s).utc.xmlschema }
121
- else
122
- solr_doc[k] = Time.parse(v.to_s).utc.xmlschema
123
- end
124
- }
121
+ solr_doc["metadata_source_ssi"] = self.identity_metadata_source
125
122
  solr_doc
126
123
  end
127
124
 
125
+ #@return [String] calculated value for Solr index
126
+ def identity_metadata_source
127
+ if self.identityMetadata.otherId('catkey').first ||
128
+ self.identityMetadata.otherId('barcode').first
129
+ 'Symphony'
130
+ elsif self.identityMetadata.otherId('mdtoolkit').first
131
+ 'Metadata Toolkit'
132
+ else
133
+ 'DOR'
134
+ end
135
+ end
136
+
128
137
  def set_source_id(source_id)
129
- identityMetadata.sourceId = source_id
138
+ self.identityMetadata.sourceId = source_id
130
139
  end
131
140
 
132
- def add_other_Id(type, val)
133
- if identityMetadata.otherId(type).length > 0
134
- raise 'There is an existing entry for '+node_name+', consider using update_other_identifier.'
141
+ def add_other_Id(type,val)
142
+ if self.identityMetadata.otherId(type).length>0
143
+ raise 'There is an existing entry for '+type+', consider using update_other_Id().'
135
144
  end
136
- identity_metadata_ds = identityMetadata
137
- identity_metadata_ds.add_otherId(type+':'+val)
145
+ self.identityMetadata.add_otherId(type+':'+val)
138
146
  end
139
147
 
140
- def update_other_Id(type, new_val, val = nil)
141
- identity_metadata_ds = identityMetadata
142
- ds_xml = identity_metadata_ds.ng_xml
143
- # split the thing they sent in to find the node name
144
- updated = false
145
- ds_xml.search('//otherId[@name=\''+type+'\']').each do |node|
146
- next unless node.content == val || val.nil?
147
- node.content = new_val
148
- updated = true
148
+ def update_other_Id(type, new_val, val=nil)
149
+ updated=false
150
+ self.identityMetadata.ng_xml.search('//otherId[@name=\''+type+'\']').each do |node|
151
+ if node.content==val || val.nil?
152
+ node.content=new_val
153
+ updated=true
154
+ end
149
155
  end
150
- updated
156
+ return updated
151
157
  end
152
158
 
153
- def remove_other_Id(type, val = nil)
154
- ds_xml = identityMetadata.ng_xml
155
- # split the thing they sent in to find the node name
156
- removed = false
157
- ds_xml.search('//otherId[@name=\''+type+'\']').each do |node|
158
- next unless node.content === val || val.nil?
159
- node.remove
160
- removed = true
159
+ def remove_other_Id(type, val=nil)
160
+ removed=false
161
+ self.identityMetadata.ng_xml.search('//otherId[@name=\''+type+'\']').each do |node|
162
+ if node.content===val || val.nil?
163
+ node.remove
164
+ removed=true
165
+ end
161
166
  end
162
- removed
167
+ return removed
163
168
  end
164
169
 
165
170
  # turns a tag string into an array with one element per tag part.
166
171
  # split on ":", disregard leading and trailing whitespace on tokens.
167
172
  def split_tag_to_arr(tag_str)
168
- tag_str.split(':').map {|str| str.strip}
173
+ return tag_str.split(":").map {|str| str.strip}
169
174
  end
170
175
 
171
176
  # turn a tag array back into a tag string with a standard format
172
177
  def normalize_tag_arr(tag_arr)
173
- tag_arr.join(' : ')
178
+ return tag_arr.join(' : ')
174
179
  end
175
180
 
176
181
  # take a tag string and return a normalized tag string
177
182
  def normalize_tag(tag_str)
178
- normalize_tag_arr(split_tag_to_arr(tag_str))
183
+ return normalize_tag_arr(split_tag_to_arr(tag_str))
179
184
  end
180
185
 
181
186
  # take a proposed tag string and a list of the existing tags for the object being edited. if
@@ -183,66 +188,65 @@ module Dor
183
188
  # explanatory message.
184
189
  def validate_and_normalize_tag(tag_str, existing_tag_list)
185
190
  tag_arr = validate_tag_format(tag_str)
191
+
186
192
  # note that the comparison for duplicate tags is case-insensitive, but we don't change case as part of the normalized version
187
193
  # we return, because we want to preserve the user's intended case.
188
194
  normalized_tag = normalize_tag_arr(tag_arr)
189
195
  dupe_existing_tag = existing_tag_list.detect { |existing_tag| normalize_tag(existing_tag).downcase == normalized_tag.downcase }
190
- raise "An existing tag (#{dupe_existing_tag}) is the same, consider using update_tag?" if dupe_existing_tag
191
- normalized_tag
196
+ if dupe_existing_tag
197
+ raise "An existing tag (#{dupe_existing_tag}) is the same, consider using update_tag?"
198
+ end
199
+
200
+ return normalized_tag
192
201
  end
193
202
 
194
- # Ensure that an administrative tag meets the proper mininum format
195
- # @param [String] tag_str the tag
196
- # @return [Array] the tag split into an array via ':'
203
+ #Ensure that an administrative tag meets the proper mininum format
204
+ #
205
+ #@params tag_str [String] the tag
206
+ #
207
+ #@return [Array] the tag split into an array via ':'
197
208
  def validate_tag_format(tag_str)
198
209
  tag_arr = split_tag_to_arr(tag_str)
199
- raise "Invalid tag structure: tag '#{tag_str}' must have at least 2 elements" if tag_arr.length < 2
200
- raise "Invalid tag structure: tag '#{tag_str}' contains empty elements" if tag_arr.detect {|str| str.empty?}
201
- tag_arr
210
+
211
+ if tag_arr.length < 2
212
+ raise ArgumentError, "Invalid tag structure: tag '#{tag_str}' must have at least 2 elements"
213
+ end
214
+
215
+ if tag_arr.detect {|str| str.empty?}
216
+ raise ArgumentError, "Invalid tag structure: tag '#{tag_str}' contains empty elements"
217
+ end
218
+ return tag_arr
202
219
  end
203
220
 
204
- # Add an administrative tag to an item, you will need to seperately save the item to write it to fedora
205
- # @param tag [string] The tag you wish to add
221
+ #Add an administrative tag to an item, you will need to seperately save the item to write it to fedora
222
+ #
223
+ #param tag [string] The tag you wish to add
206
224
  def add_tag(tag)
207
- identity_metadata_ds = identityMetadata
208
- normalized_tag = validate_and_normalize_tag(tag, identity_metadata_ds.tags)
209
- identity_metadata_ds.add_value(:tag, normalized_tag)
225
+ identity_metadata_ds = self.identityMetadata
226
+ normalized_tag = validate_and_normalize_tag(tag, identity_metadata_ds.tags)
227
+ identity_metadata_ds.add_value(:tag, normalized_tag)
210
228
  end
211
229
 
212
230
  def remove_tag(tag)
213
- identity_metadata_ds = identityMetadata
214
- ds_xml = identity_metadata_ds.ng_xml
215
231
  removed = false
216
- ds_xml.search('//tag').each do |node|
232
+ self.identityMetadata.ng_xml.search('//tag').each do |node|
217
233
  if normalize_tag(node.content) === normalize_tag(tag)
218
234
  node.remove
219
235
  removed = true
220
236
  end
221
237
  end
222
- removed
223
- end
224
-
225
- # Removes all displayTypes from an item in preparation of adding a new display type
226
- # @return Boolean True if displayTypes were removed, False if no displayTypes were removed
227
- def remove_displayTypes
228
- removed = false
229
- identityMetadata.ng_xml.search('//displayType').each do |node|
230
- node.remove
231
- removed = true
232
- end
233
- removed
238
+ return removed
234
239
  end
235
240
 
236
241
  def update_tag(old_tag, new_tag)
237
- identity_metadata_ds = identityMetadata
238
- ds_xml = identity_metadata_ds.ng_xml
239
242
  updated = false
240
- ds_xml.search('//tag').each do |node|
241
- next unless normalize_tag(node.content) == normalize_tag(old_tag)
242
- node.content = normalize_tag(new_tag)
243
- updated = true
243
+ self.identityMetadata.ng_xml.search('//tag').each do |node|
244
+ if normalize_tag(node.content) == normalize_tag(old_tag)
245
+ node.content = normalize_tag(new_tag)
246
+ updated = true
247
+ end
244
248
  end
245
- updated
249
+ return updated
246
250
  end
247
251
  end
248
252
  end
@@ -1,7 +1,7 @@
1
1
  module Dor
2
2
  module BasicItem
3
3
  extend ActiveSupport::Concern
4
-
4
+
5
5
  include Identifiable
6
6
  include Processable
7
7
  include Governable
@@ -13,11 +13,11 @@ module Dor
13
13
  include Assembleable
14
14
  include Versionable
15
15
  include Contentable
16
- include Discoverable
17
16
  include Geoable
18
- include Releaseable
17
+ include Releasable
18
+
19
19
  end
20
-
20
+
21
21
  class Abstract < ::ActiveFedora::Base
22
22
  include Identifiable
23
23
  end
@@ -8,20 +8,20 @@ module Dor
8
8
  included do
9
9
  has_metadata :name => "contentMetadata", :type => Dor::ContentMetadataDS, :label => 'Content Metadata', :control_group => 'M'
10
10
  end
11
-
11
+
12
12
  DIFF_FILENAME = 'cm_inv_diff'
13
13
  DIFF_QUERY = DIFF_FILENAME.gsub('_', '-')
14
14
 
15
15
  # Deletes all cm_inv_diff files in the workspace for the Item
16
16
  def clear_diff_cache
17
17
  if Dor::Config.stacks.local_workspace_root.nil?
18
- raise ArgumentError, 'Missing Dor::Config.stacks.local_workspace_root'
18
+ raise ArgumentError, 'Missing Dor::Config.stacks.local_workspace_root'
19
19
  end
20
- druid = DruidTools::Druid.new(pid, Dor::Config.stacks.local_workspace_root)
20
+ druid = DruidTools::Druid.new(self.pid, Dor::Config.stacks.local_workspace_root)
21
21
  diff_pattern = File.join(druid.temp_dir, DIFF_FILENAME + '.*')
22
22
  FileUtils.rm_f Dir.glob(diff_pattern)
23
23
  end
24
-
24
+
25
25
  # Retrieves file difference manifest for contentMetadata from SDR
26
26
  #
27
27
  # @param [String] subset keyword for file attributes :shelve, :preserve, :publish. Default is :all.
@@ -29,7 +29,7 @@ module Dor
29
29
  # @return [String] XML contents of cm_inv_diff manifest
30
30
  def get_content_diff(subset = :all, version = nil)
31
31
  if Dor::Config.stacks.local_workspace_root.nil?
32
- raise Dor::ParameterError, 'Missing Dor::Config.stacks.local_workspace_root'
32
+ raise Dor::ParameterError, 'Missing Dor::Config.stacks.local_workspace_root'
33
33
  end
34
34
  unless %w{all shelve preserve publish}.include?(subset.to_s)
35
35
  raise Dor::ParameterError, "Invalid subset value: #{subset}"
@@ -40,17 +40,17 @@ module Dor
40
40
  raise Dor::ParameterError, 'Missing Dor::Config.sdr.rest_client'
41
41
  end
42
42
  sdr_client = Dor::Config.sdr.rest_client
43
- current_content = datastreams['contentMetadata'].content
43
+ current_content = self.datastreams['contentMetadata'].content
44
44
  if current_content.nil?
45
45
  raise Dor::Exception, "Missing contentMetadata datastream"
46
46
  end
47
47
  query_string = { :subset => subset.to_s }
48
48
  query_string[:version] = version.to_s unless version.nil?
49
49
  query_string = URI.encode_www_form(query_string)
50
- sdr_query = "objects/#{pid}/#{DIFF_QUERY}?#{query_string}"
50
+ sdr_query = "objects/#{self.pid}/#{DIFF_QUERY}?#{query_string}"
51
51
  response = sdr_client[sdr_query].post(current_content, :content_type => 'application/xml')
52
52
  response
53
53
  end
54
-
54
+
55
55
  end
56
- end
56
+ end
@@ -0,0 +1,133 @@
1
+ require 'iiif/presentation'
2
+
3
+ module Dor
4
+ module Presentable
5
+
6
+ DC_NS = {"dc"=>"http://purl.org/dc/elements/1.1/", "oai_dc"=>"http://www.openarchives.org/OAI/2.0/oai_dc/"}
7
+
8
+ def iiif_presentation_manifest_needed? pub_obj_doc
9
+ if(pub_obj_doc.at_xpath('/publicObject/contentMetadata[@type="image"]/resource[@type="image"]'))
10
+ return true
11
+ elsif(pub_obj_doc.at_xpath('/publicObject/contentMetadata[@type="book"]/resource[@type="page"]'))
12
+ return true
13
+ else
14
+ return false
15
+ end
16
+ end
17
+
18
+ # Bypass this method if there are no image resources in contentMetadata
19
+ def build_iiif_manifest pub_obj_doc
20
+ id = self.pid.split(':').last
21
+
22
+ lbl_node = pub_obj_doc.at_xpath '//oai_dc:dc/dc:title', DC_NS
23
+ if lbl_node.nil?
24
+ lbl_node = pub_obj_doc.at_xpath('/publicObject/identityMetadata/objectLabel')
25
+ end
26
+ raise "Unable to build IIIF Presentation manifest: No identityMetadata/objectLabel or dc:title" if lbl_node.nil?
27
+ lbl = lbl_node.text
28
+
29
+ purl_base_uri = "https://#{Dor::Config.stacks.document_cache_host}/#{id}"
30
+
31
+ manifest_data = {
32
+ '@id' => "#{purl_base_uri}/iiif/manifest.json",
33
+ 'label' => lbl,
34
+ 'attribution' => 'Provided by the Stanford University Libraries',
35
+ 'seeAlso' => {
36
+ '@id' => "#{purl_base_uri}.mods",
37
+ 'format' => 'application/mods+xml'
38
+ }
39
+ }
40
+ # Use the human copyright statement for attribution if present
41
+ if(cr = pub_obj_doc.at_xpath('/publicObject/rightsMetadata/copyright/human[@type="copyright"]'))
42
+ manifest_data['attribution'] = cr.text
43
+ end
44
+
45
+ manifest = IIIF::Presentation::Manifest.new manifest_data
46
+
47
+ # Set viewingHint to paged if this is a book
48
+ if(pub_obj_doc.at_xpath('/publicObject/contentMetadata[@type="book"]'))
49
+ manifest.viewingHint = "paged"
50
+ end
51
+
52
+ metadata = []
53
+ # make into method, pass in xpath and label
54
+ add_metadata 'Creator', '//oai_dc:dc/dc:creator', metadata, pub_obj_doc
55
+ add_metadata 'Contributor', '//oai_dc:dc/dc:contributor', metadata, pub_obj_doc
56
+ add_metadata 'Publisher', '//oai_dc:dc/dc:publisher', metadata, pub_obj_doc
57
+ add_metadata 'Date', '//oai_dc:dc/dc:date', metadata, pub_obj_doc
58
+
59
+ # Save off the first dc:description without displayLabel
60
+ if(desc = pub_obj_doc.at_xpath('//oai_dc:dc/dc:description[not(@displayLabel)]', DC_NS))
61
+ manifest.description = desc.text
62
+ end
63
+
64
+ manifest.metadata = metadata unless metadata.empty?
65
+
66
+ seq_data = {
67
+ '@id' => "#{purl_base_uri}/sequence-1",
68
+ 'label' => 'Current order'
69
+ }
70
+ sequence = IIIF::Presentation::Sequence.new seq_data
71
+
72
+ # for each resource image, create a canvas
73
+ count = 0
74
+ pub_obj_doc.xpath('/publicObject/contentMetadata/resource[@type="image" or @type="page"]').each do |res_node|
75
+ count += 1
76
+ img_file_name = res_node.at_xpath('file/@id').text.split('.').first
77
+ height = res_node.at_xpath('file/imageData/@height').text.to_i
78
+ width = res_node.at_xpath('file/imageData/@width').text.to_i
79
+ stacks_uri = "#{Dor::Config.stacks.url}/image/iiif/#{id}%2F#{img_file_name}"
80
+
81
+ canv = IIIF::Presentation::Canvas.new
82
+ canv['@id'] = "#{purl_base_uri}/canvas/canvas-#{count}"
83
+ canv.label = res_node.at_xpath('label').text
84
+ canv.height = height
85
+ canv.width = width
86
+
87
+ anno = IIIF::Presentation::Annotation.new
88
+ anno['@id'] = "#{purl_base_uri}/imageanno/anno-#{count}"
89
+ anno['on'] = canv['@id']
90
+
91
+ img_res = IIIF::Presentation::ImageResource.new
92
+ img_res['@id'] = "#{stacks_uri}/full/full/0/default.jpg"
93
+ img_res.format = 'image/jpeg'
94
+ img_res.height = height
95
+ img_res.width = width
96
+
97
+ svc = IIIF::Service.new ({
98
+ '@context' => 'http://iiif.io/api/image/2/context.json',
99
+ '@id' => stacks_uri,
100
+ 'profile' => Dor::Config.stacks.iiif_profile
101
+ })
102
+
103
+ # Use the first image to create a thumbnail on the manifest
104
+ if count == 1
105
+ thumb = IIIF::Presentation::Resource.new
106
+ thumb['@id'] = "#{stacks_uri}/full/400,/0/default.jpg"
107
+ thumb.service = svc
108
+ manifest.thumbnail = thumb
109
+ end
110
+
111
+ img_res.service = svc
112
+ anno.resource = img_res
113
+ canv.images << anno
114
+ sequence.canvases << canv
115
+ end
116
+
117
+ manifest.sequences << sequence
118
+ manifest.to_json(:pretty => true)
119
+ end
120
+
121
+ def add_metadata label, xpath, metadata, pub_obj_doc
122
+ nodes = pub_obj_doc.xpath xpath, DC_NS
123
+ nodes.each do |node|
124
+ h = {
125
+ 'label' => label,
126
+ 'value' => node.text
127
+ }
128
+ metadata << h
129
+ end
130
+ end
131
+
132
+ end
133
+ end