dor-services 5.2.0 → 5.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +5 -13
  2. data/config/certs/robots-dor-dev.crt +29 -0
  3. data/config/certs/robots-dor-dev.key +27 -0
  4. data/config/config_defaults.yml +2 -0
  5. data/config/dev_console_env.rb +77 -0
  6. data/lib/dor-services.rb +31 -27
  7. data/lib/dor/config.rb +25 -19
  8. data/lib/dor/datastreams/administrative_metadata_ds.rb +19 -20
  9. data/lib/dor/datastreams/content_metadata_ds.rb +238 -177
  10. data/lib/dor/datastreams/datastream_spec_solrizer.rb +1 -1
  11. data/lib/dor/datastreams/default_object_rights_ds.rb +99 -16
  12. data/lib/dor/datastreams/desc_metadata_ds.rb +37 -34
  13. data/lib/dor/datastreams/embargo_metadata_ds.rb +16 -16
  14. data/lib/dor/datastreams/events_ds.rb +2 -2
  15. data/lib/dor/datastreams/geo_metadata_ds.rb +5 -10
  16. data/lib/dor/datastreams/identity_metadata_ds.rb +22 -22
  17. data/lib/dor/datastreams/rights_metadata_ds.rb +43 -32
  18. data/lib/dor/datastreams/role_metadata_ds.rb +5 -5
  19. data/lib/dor/datastreams/simple_dublin_core_ds.rb +13 -14
  20. data/lib/dor/datastreams/version_metadata_ds.rb +22 -23
  21. data/lib/dor/datastreams/workflow_definition_ds.rb +15 -15
  22. data/lib/dor/datastreams/workflow_ds.rb +64 -70
  23. data/lib/dor/exceptions.rb +0 -1
  24. data/lib/dor/migrations/identifiable/uriify_augmented_contentlocation_refs.rb +4 -4
  25. data/lib/dor/migrations/processable/unify_workflows.rb +1 -1
  26. data/lib/dor/models/admin_policy_object.rb +4 -4
  27. data/lib/dor/models/assembleable.rb +2 -3
  28. data/lib/dor/models/collection.rb +1 -1
  29. data/lib/dor/models/contentable.rb +113 -108
  30. data/lib/dor/models/describable.rb +136 -95
  31. data/lib/dor/models/editable.rb +205 -119
  32. data/lib/dor/models/embargoable.rb +16 -16
  33. data/lib/dor/models/eventable.rb +2 -2
  34. data/lib/dor/models/geoable.rb +3 -3
  35. data/lib/dor/models/governable.rb +25 -26
  36. data/lib/dor/models/identifiable.rb +66 -55
  37. data/lib/dor/models/item.rb +0 -1
  38. data/lib/dor/models/itemizable.rb +7 -8
  39. data/lib/dor/models/preservable.rb +7 -8
  40. data/lib/dor/models/processable.rb +76 -73
  41. data/lib/dor/models/publishable.rb +25 -30
  42. data/lib/dor/models/releaseable.rb +118 -155
  43. data/lib/dor/models/rightsable.rb +2 -3
  44. data/lib/dor/models/set.rb +1 -1
  45. data/lib/dor/models/shelvable.rb +8 -10
  46. data/lib/dor/models/upgradable.rb +5 -6
  47. data/lib/dor/models/versionable.rb +3 -4
  48. data/lib/dor/models/workflow_object.rb +15 -16
  49. data/lib/dor/services/cleanup_reset_service.rb +15 -16
  50. data/lib/dor/services/cleanup_service.rb +2 -4
  51. data/lib/dor/services/digital_stacks_service.rb +10 -13
  52. data/lib/dor/services/merge_service.rb +8 -9
  53. data/lib/dor/services/metadata_handlers/catalog_handler.rb +1 -1
  54. data/lib/dor/services/metadata_handlers/mdtoolkit_handler.rb +3 -3
  55. data/lib/dor/services/metadata_service.rb +19 -20
  56. data/lib/dor/services/registration_service.rb +80 -61
  57. data/lib/dor/services/reset_workspace_service.rb +6 -10
  58. data/lib/dor/services/sdr_ingest_service.rb +15 -16
  59. data/lib/dor/services/search_service.rb +18 -23
  60. data/lib/dor/services/suri_service.rb +6 -6
  61. data/lib/dor/services/technical_metadata_service.rb +27 -44
  62. data/lib/dor/utils/ng_tidy.rb +3 -3
  63. data/lib/dor/utils/sdr_client.rb +2 -3
  64. data/lib/dor/utils/solr_doc_helper.rb +1 -3
  65. data/lib/dor/version.rb +1 -1
  66. data/lib/dor/workflow/document.rb +43 -40
  67. data/lib/dor/workflow/graph.rb +26 -26
  68. data/lib/dor/workflow/process.rb +34 -35
  69. data/lib/tasks/rdoc.rake +5 -5
  70. metadata +129 -111
  71. data/lib/dor/models/presentable.rb +0 -146
@@ -5,8 +5,8 @@ module Dor
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- has_metadata :name => "provenanceMetadata", :type => ActiveFedora::OmDatastream, :label => 'Provenance Metadata'
9
- has_metadata :name => "technicalMetadata", :type => ActiveFedora::OmDatastream, :label => 'Technical Metadata', :control_group => 'M'
8
+ has_metadata :name => 'provenanceMetadata', :type => ActiveFedora::OmDatastream, :label => 'Provenance Metadata'
9
+ has_metadata :name => 'technicalMetadata', :type => ActiveFedora::OmDatastream, :label => 'Technical Metadata', :control_group => 'M'
10
10
  end
11
11
 
12
12
  def build_provenanceMetadata_datastream(workflow_id, event_text)
@@ -15,24 +15,24 @@ module Dor
15
15
  ds = datastreams[dsname]
16
16
  ds.label = 'Provenance Metadata' unless datastreams.keys.include?(dsname)
17
17
  ds.ng_xml = workflow_provenance
18
- ds.content=ds.ng_xml.to_s
18
+ ds.content = ds.ng_xml.to_s
19
19
  ds.save
20
20
  end
21
21
 
22
- def build_technicalMetadata_datastream(ds=nil)
22
+ def build_technicalMetadata_datastream(ds = nil)
23
23
  TechnicalMetadataService.add_update_technical_metadata(self)
24
24
  end
25
25
 
26
26
  def sdr_ingest_transfer(agreement_id)
27
- SdrIngestService.transfer(self,agreement_id)
27
+ SdrIngestService.transfer(self, agreement_id)
28
28
  end
29
29
 
30
30
  # @return [Nokogiri::Document]
31
31
  def create_workflow_provenance(workflow_id, event_text)
32
32
  builder = Nokogiri::XML::Builder.new do |xml|
33
- xml.provenanceMetadata(:objectId => self.pid) {
33
+ xml.provenanceMetadata(:objectId => pid) {
34
34
  xml.agent(:name => 'DOR') {
35
- xml.what(:object => self.pid) {
35
+ xml.what(:object => pid) {
36
36
  xml.event(:who => "DOR-#{workflow_id}", :when => Time.new.iso8601) {
37
37
  xml.text(event_text)
38
38
  }
@@ -42,6 +42,5 @@ module Dor
42
42
  end
43
43
  builder.doc
44
44
  end
45
-
46
45
  end
47
46
  end
@@ -11,9 +11,9 @@ module Dor
11
11
  after_initialize :set_workflows_datastream_location
12
12
  end
13
13
 
14
- #verbiage we want to use to describe an item when it has completed a particular step
14
+ # verbiage we want to use to describe an item when it has completed a particular step
15
15
  STATUS_CODE_DISP_TXT = {
16
- 0 => 'Unknown Status', #if there are no milestones for the current version, someone likely messed up the versioning process.
16
+ 0 => 'Unknown Status', # if there are no milestones for the current version, someone likely messed up the versioning process.
17
17
  1 => 'Registered',
18
18
  2 => 'In accessioning',
19
19
  3 => 'In accessioning (described)',
@@ -25,54 +25,55 @@ module Dor
25
25
  9 => 'Opened'
26
26
  }
27
27
 
28
- #milestones from accessioning and the order they happen in
28
+ # milestones from accessioning and the order they happen in
29
29
  STEPS = {
30
- 'registered' => 1,
31
- 'submitted' => 2,
32
- 'described' => 3,
33
- 'published' => 4,
34
- 'deposited' => 5,
30
+ 'registered' => 1,
31
+ 'submitted' => 2,
32
+ 'described' => 3,
33
+ 'published' => 4,
34
+ 'deposited' => 5,
35
35
  'accessioned' => 6,
36
- 'indexed' => 7,
37
- 'shelved' => 8,
38
- 'opened' => 1
36
+ 'indexed' => 7,
37
+ 'shelved' => 8,
38
+ 'opened' => 9
39
39
  }
40
40
 
41
41
  # This is a work-around for some strange logic in ActiveFedora that
42
42
  # don't allow self.workflows.new? to work if we load the object using
43
43
  # .load_instance_from_solr.
44
44
  def set_workflows_datastream_location
45
- return if self.respond_to?(:inner_object) && self.inner_object.is_a?(ActiveFedora::SolrDigitalObject)
46
- return unless self.workflows.new?
45
+ return if self.respond_to?(:inner_object) && inner_object.is_a?(ActiveFedora::SolrDigitalObject)
46
+ return unless workflows.new?
47
47
  workflows.mimeType = 'application/xml'
48
- workflows.dsLocation = File.join(Dor::Config.workflow.url,"dor/objects/#{self.pid}/workflows")
48
+ workflows.dsLocation = File.join(Dor::Config.workflow.url, "dor/objects/#{pid}/workflows")
49
49
  end
50
50
 
51
51
  def empty_datastream?(datastream)
52
- if datastream.new?
53
- true
54
- elsif datastream.class.respond_to?(:xml_template)
52
+ return true if datastream.new?
53
+ if datastream.class.respond_to?(:xml_template)
55
54
  datastream.content.to_s.empty? || EquivalentXml.equivalent?(datastream.content, datastream.class.xml_template)
56
55
  else
57
56
  datastream.content.to_s.empty?
58
57
  end
59
58
  end
60
59
 
61
- # Takes the name of a datastream, as a string.
62
60
  # Tries to find a file for the datastream.
63
- # Returns the path to it or nil.
61
+ # @param [String] datastream name of a datastream
62
+ # @return [String, nil] path to datastream or nil
64
63
  def find_metadata_file(datastream)
65
64
  druid = DruidTools::Druid.new(pid, Dor::Config.stacks.local_workspace_root)
66
- return druid.find_metadata("#{datastream}.xml")
65
+ druid.find_metadata("#{datastream}.xml")
67
66
  end
68
67
 
69
- # Takes the name of a datastream, as a string (fooMetadata).
70
68
  # Builds that datastream using the content of a file if such a file
71
69
  # exists and is newer than the object's current datastream; otherwise,
72
70
  # builds the datastream by calling build_fooMetadata_datastream.
71
+ # @param [String] datastream name of a datastream (e.g. "fooMetadata")
72
+ # @param [Boolean] force overwrite existing datastream
73
+ # @param [Boolean] is_required
74
+ # @return [SomeDatastream]
73
75
  def build_datastream(datastream, force = false, is_required = false)
74
- # See if the datastream exists as a file and if the file's
75
- # timestamp is newer than the datastream's timestamp.
76
+ # See if datastream exists as a file and if the file's timestamp is newer than datastream's timestamp.
76
77
  ds = datastreams[datastream]
77
78
  filename = find_metadata_file(datastream)
78
79
  use_file = filename && (ds.createDate.nil? || File.mtime(filename) >= ds.createDate)
@@ -85,15 +86,13 @@ module Dor
85
86
  elsif force || empty_datastream?(ds)
86
87
  meth = "build_#{datastream}_datastream".to_sym
87
88
  if respond_to?(meth)
88
- content = self.send(meth, ds)
89
+ send(meth, ds)
89
90
  ds.save unless ds.digital_object.new?
90
91
  end
91
92
  end
92
93
  # Check for success.
93
- if is_required && empty_datastream?(ds)
94
- raise "Required datastream #{datastream} could not be populated!"
95
- end
96
- return ds
94
+ raise "Required datastream #{datastream} could not be populated!" if is_required && empty_datastream?(ds)
95
+ ds
97
96
  end
98
97
 
99
98
  def cleanup
@@ -101,20 +100,20 @@ module Dor
101
100
  end
102
101
 
103
102
  def milestones
104
- Dor::WorkflowService.get_milestones('dor',self.pid)
103
+ Dor::WorkflowService.get_milestones('dor', pid)
105
104
  end
106
105
 
107
106
  # @return [Hash] including :current_version, :status_code and :status_time
108
107
  def status_info
109
108
  current_version = '1'
110
109
  begin
111
- current_version = self.versionMetadata.current_version_id
110
+ current_version = versionMetadata.current_version_id
112
111
  rescue
113
112
  end
114
113
 
115
114
  current_milestones = []
116
- #only get steps that are part of accessioning and part of the current version. That can mean they were archived with the current version
117
- #number, or they might be active (no version number).
115
+ # only get steps that are part of accessioning and part of the current version. That can mean they were archived with the current version
116
+ # number, or they might be active (no version number).
118
117
  milestones.each do |m|
119
118
  if STEPS.keys.include?(m[:milestone]) && (m[:version].nil? || m[:version] == current_version)
120
119
  current_milestones << m unless m[:milestone] == 'registered' && current_version.to_i > 1
@@ -122,57 +121,57 @@ module Dor
122
121
  end
123
122
 
124
123
  status_code = 0
125
- status_time = ''
126
- #for each milestone in the current version, see if it comes after the current 'last' step, if so, make it the last and record the date/time
124
+ status_time = nil
125
+ # for each milestone in the current version, see if it comes after the current 'last' step, if so, make it the last and record the date/time
127
126
  current_milestones.each do |m|
128
- name = m[:milestone]
129
- time = m[:at].utc.xmlschema
130
- next unless STEPS.keys.include?(name) && STEPS[name] > status_code
131
- status_code = STEPS[name]
132
- status_time = time
127
+ m_name = m[:milestone]
128
+ m_time = m[:at].utc.xmlschema
129
+ next unless STEPS.keys.include?(m_name) && (!status_time || m_time > status_time)
130
+ status_code = STEPS[m_name]
131
+ status_time = m_time
133
132
  end
134
133
 
135
- return {:current_version => current_version, :status_code => status_code, :status_time => status_time}
134
+ {:current_version => current_version, :status_code => status_code, :status_time => status_time}
136
135
  end
137
136
 
138
137
  # @param [Boolean] include_time
139
138
  # @return [String] single composed status from status_info
140
- def status(include_time=false)
141
- status_info_hash = status_info()
139
+ def status(include_time = false)
140
+ status_info_hash = status_info
142
141
  current_version, status_code, status_time = status_info_hash[:current_version], status_info_hash[:status_code], status_info_hash[:status_time]
143
142
 
144
- #use the translation table to get the appropriate verbage for the latest step
143
+ # use the translation table to get the appropriate verbage for the latest step
145
144
  result = "v#{current_version} #{STATUS_CODE_DISP_TXT[status_code]}"
146
145
  result += " #{format_date(status_time)}" if include_time
147
- return result
146
+ result
148
147
  end
149
148
 
150
149
  # return the text translation of the status code, minus any trailing parenthetical explanation
151
150
  # e.g. 'In accessioning (described)' and 'In accessioning (described, published)' both come back
152
151
  # as 'In accessioning'
153
152
  def simplified_status_code_disp_txt(status_code)
154
- return STATUS_CODE_DISP_TXT[status_code].gsub(/\(.*\)$/, '').strip
153
+ STATUS_CODE_DISP_TXT[status_code].gsub(/\(.*\)$/, '').strip
155
154
  end
156
155
 
157
- def to_solr(solr_doc=Hash.new, *args)
156
+ def to_solr(solr_doc = {}, *args)
158
157
  super(solr_doc, *args)
159
158
  sortable_milestones = {}
160
- current_version='1'
159
+ current_version = '1'
161
160
  begin
162
- current_version = self.versionMetadata.current_version_id
161
+ current_version = versionMetadata.current_version_id
163
162
  rescue
164
163
  end
165
- current_version_num=current_version.to_i
164
+ current_version_num = current_version.to_i
166
165
 
167
166
  if self.respond_to?('versionMetadata')
168
- #add an entry with version id, tag and description for each version
167
+ # add an entry with version id, tag and description for each version
169
168
  while current_version_num > 0
170
- add_solr_value(solr_doc, 'versions', current_version_num.to_s + ';' + self.versionMetadata.tag_for_version(current_version_num.to_s) + ';' + self.versionMetadata.description_for_version(current_version_num.to_s), :string, [:displayable])
169
+ add_solr_value(solr_doc, 'versions', current_version_num.to_s + ';' + versionMetadata.tag_for_version(current_version_num.to_s) + ';' + versionMetadata.description_for_version(current_version_num.to_s), :string, [:displayable])
171
170
  current_version_num -= 1
172
171
  end
173
172
  end
174
173
 
175
- self.milestones.each do |milestone|
174
+ milestones.each do |milestone|
176
175
  timestamp = milestone[:at].utc.xmlschema
177
176
  sortable_milestones[milestone[:milestone]] ||= []
178
177
  sortable_milestones[milestone[:milestone]] << timestamp
@@ -184,26 +183,26 @@ module Dor
184
183
 
185
184
  sortable_milestones.each do |milestone, unordered_dates|
186
185
  dates = unordered_dates.sort
187
- #create the published_dttsi and published_day fields and the like
186
+ # create the published_dttsi and published_day fields and the like
188
187
  dates.each do |date|
189
188
  solr_doc["#{milestone}_dttsim"] ||= []
190
189
  solr_doc["#{milestone}_dttsim"] << date unless solr_doc["#{milestone}_dttsim"].include?(date)
191
190
  end
192
- #fields for OAI havester to sort on: _dttsi is trie date +stored +indexed (single valued, i.e. sortable)
191
+ # fields for OAI havester to sort on: _dttsi is trie date +stored +indexed (single valued, i.e. sortable)
193
192
  solr_doc["#{milestone}_earliest_dttsi"] = dates.first
194
193
  solr_doc["#{milestone}_latest_dttsi" ] = dates.last
195
194
  end
196
- solr_doc["status_ssi"] = status # status is singular (i.e. the current one)
197
- solr_doc["current_version_isi"] = current_version.to_i
198
- solr_doc["modified_latest_dttsi"] = self.modified_date.to_datetime.utc.strftime('%FT%TZ')
199
- add_solr_value(solr_doc, "rights", rights, :string, [:symbol]) if self.respond_to? :rights
195
+ solr_doc['status_ssi'] = status # status is singular (i.e. the current one)
196
+ solr_doc['current_version_isi'] = current_version.to_i
197
+ solr_doc['modified_latest_dttsi'] = modified_date.to_datetime.utc.strftime('%FT%TZ')
198
+ add_solr_value(solr_doc, 'rights', rights, :string, [:symbol]) if self.respond_to? :rights
200
199
 
201
- status_info_hash = status_info()
200
+ status_info_hash = status_info
202
201
  status_code = status_info_hash[:status_code]
203
202
  add_solr_value(solr_doc, 'processing_status_text', simplified_status_code_disp_txt(status_code), :string, [:stored_sortable])
204
203
  solr_doc['processing_status_code_isi'] = status_code # no _isi in Solrizer's default descriptors
205
204
 
206
- return solr_doc
205
+ solr_doc
207
206
  end
208
207
 
209
208
  # Initilizes workflow for the object in the workflow service
@@ -212,26 +211,30 @@ module Dor
212
211
  # @param [String] name of the workflow to be initialized
213
212
  # @param [Boolean] create_ds create a 'workflows' datastream in Fedora for the object
214
213
  # @param [Integer] priority the workflow's priority level
215
- def initialize_workflow(name, create_ds=true, priority=0)
214
+ def create_workflow(name, create_ds = true, priority = 0)
216
215
  priority = workflows.current_priority if priority == 0
217
216
  opts = { :create_ds => create_ds, :lane_id => default_workflow_lane }
218
217
  opts[:priority] = priority if priority > 0
219
- Dor::WorkflowService.create_workflow(Dor::WorkflowObject.initial_repo(name), self.pid, name, Dor::WorkflowObject.initial_workflow(name), opts)
218
+ Dor::WorkflowService.create_workflow(Dor::WorkflowObject.initial_repo(name), pid, name, Dor::WorkflowObject.initial_workflow(name), opts)
219
+ workflows.content(true) # refresh the copy of the workflows datastream
220
220
  end
221
221
 
222
- private
223
- #handles formating utc date/time to human readable
224
- # XXX: bad form to hardcode TZ here. Code smell abounds.
225
- def format_date datetime
222
+ def initialize_workflow(name, create_ds = true, priority = 0)
223
+ warn 'WARNING: initialize_workflow is deprecated, use create_workflow instead'
224
+ create_workflow(name, create_ds, priority)
225
+ end
226
226
 
227
- d = datetime.is_a?(Time) ? datetime :
228
- DateTime.parse(datetime).in_time_zone(ActiveSupport::TimeZone.new("Pacific Time (US & Canada)"))
229
- I18n.l(d).strftime('%Y-%m-%d %I:%M%p')
230
- rescue
231
- d = datetime.is_a?(Time) ? datetime : Time.parse(datetime.to_s)
232
- d.strftime('%Y-%m-%d %I:%M%p')
227
+ private
233
228
 
229
+ # handles formating utc date/time to human readable
230
+ # XXX: bad form to hardcode TZ here. Code smell abounds.
231
+ def format_date(datetime)
232
+ d = datetime.is_a?(Time) ? datetime :
233
+ DateTime.parse(datetime).in_time_zone(ActiveSupport::TimeZone.new('Pacific Time (US & Canada)'))
234
+ I18n.l(d).strftime('%Y-%m-%d %I:%M%p')
235
+ rescue
236
+ d = datetime.is_a?(Time) ? datetime : Time.parse(datetime.to_s)
237
+ d.strftime('%Y-%m-%d %I:%M%p')
234
238
  end
235
239
  end
236
-
237
240
  end
@@ -7,14 +7,13 @@ module Dor
7
7
  include Governable
8
8
  include Describable
9
9
  include Itemizable
10
- include Presentable
11
10
  include Rightsable
12
11
 
13
12
  def public_relationships
14
- include_elements = ['fedora:isMemberOf','fedora:isMemberOfCollection']
15
- rels_doc = Nokogiri::XML(self.datastreams['RELS-EXT'].content)
13
+ include_elements = ['fedora:isMemberOf', 'fedora:isMemberOfCollection', 'fedora:isConstituentOf']
14
+ rels_doc = Nokogiri::XML(datastreams['RELS-EXT'].content)
16
15
  rels_doc.xpath('/rdf:RDF/rdf:Description/*', { 'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#' }).each do |rel|
17
- unless include_elements.include?([rel.namespace.prefix,rel.name].join(':'))
16
+ unless include_elements.include?([rel.namespace.prefix, rel.name].join(':'))
18
17
  rel.next_sibling.remove if rel.next_sibling.content.strip.empty?
19
18
  rel.remove
20
19
  end
@@ -22,29 +21,30 @@ module Dor
22
21
  rels_doc
23
22
  end
24
23
 
25
- #Generate the public .xml for a PURL page.
26
- #@return [xml] The public xml for the item
27
- #
24
+ # Generate the public .xml for a PURL page.
25
+ # @return [xml] The public xml for the item
28
26
  def public_xml
29
- pub = Nokogiri::XML("<publicObject/>").root
27
+ pub = Nokogiri::XML('<publicObject/>').root
30
28
  pub['id'] = pid
31
- pub['published'] = Time.now.xmlschema
32
- release_xml=Nokogiri(self.generate_release_xml).xpath('//release')
29
+ pub['published'] = Time.now.utc.xmlschema
30
+ pub['publishVersion'] = 'dor-services/' + Dor::VERSION
31
+ release_xml = Nokogiri(generate_release_xml).xpath('//release')
33
32
 
34
- im=self.datastreams['identityMetadata'].ng_xml.clone
35
- im.search('//release').each {|node| node.remove} # remove any <release> tags from public xml which have full history
33
+ im = datastreams['identityMetadata'].ng_xml.clone
34
+ im.search('//release').each(&:remove) # remove any <release> tags from public xml which have full history
36
35
  im.root.add_child(release_xml)
37
36
 
38
37
  pub.add_child(im.root) # add in modified identityMetadata datastream
39
- pub.add_child(self.datastreams['contentMetadata'].public_xml.root.clone)
40
- pub.add_child(self.datastreams['rightsMetadata'].ng_xml.root.clone)
38
+ pub.add_child(datastreams['contentMetadata'].public_xml.root.clone)
39
+ pub.add_child(datastreams['rightsMetadata'].ng_xml.root.clone)
41
40
 
42
41
  rels = public_relationships.root
43
42
  pub.add_child(rels.clone) unless rels.nil? # TODO: Should never be nil in practice; working around an ActiveFedora quirk for testing
44
- pub.add_child(self.generate_dublin_core.root.clone)
43
+ pub.add_child(generate_dublin_core.root.clone)
45
44
  @public_xml_doc = pub # save this for possible IIIF Presentation manifest
46
- pub.add_child(Nokogiri(self.generate_release_xml).root.clone) unless release_xml.children.size == 0 #If there are no release_tags, this prevents an empty <releaseData/> from being added
47
- #Note we cannot base this on if an individual object has release tags or not, because the collection may cause one to be generated for an item, so we need to calculate it and then look at the final result
45
+ pub.add_child(Nokogiri(generate_release_xml).root.clone) unless release_xml.children.size == 0 # If there are no release_tags, this prevents an empty <releaseData/> from being added
46
+ # Note we cannot base this on if an individual object has release tags or not, because the collection may cause one to be generated for an item,
47
+ # so we need to calculate it and then look at the final result.s
48
48
  new_pub = Nokogiri::XML(pub.to_xml) { |x| x.noblanks }
49
49
  new_pub.encoding = 'UTF-8'
50
50
  new_pub.to_xml
@@ -55,29 +55,24 @@ module Dor
55
55
  def publish_metadata
56
56
  rights = datastreams['rightsMetadata'].ng_xml.clone.remove_namespaces!
57
57
  if rights.at_xpath("//rightsMetadata/access[@type='discover']/machine/world")
58
- dc_xml = self.generate_dublin_core.to_xml {|config| config.no_declaration}
58
+ dc_xml = generate_dublin_core.to_xml {|config| config.no_declaration}
59
59
  DigitalStacksService.transfer_to_document_store(pid, dc_xml, 'dc')
60
- DigitalStacksService.transfer_to_document_store(pid, self.datastreams['identityMetadata'].to_xml, 'identityMetadata')
61
- DigitalStacksService.transfer_to_document_store(pid, self.datastreams['contentMetadata'].to_xml, 'contentMetadata')
62
- DigitalStacksService.transfer_to_document_store(pid, self.datastreams['rightsMetadata'].to_xml, 'rightsMetadata')
63
- DigitalStacksService.transfer_to_document_store(pid, public_xml, 'public')
64
- if self.metadata_format == 'mods'
65
- DigitalStacksService.transfer_to_document_store(pid, self.generate_public_desc_md, 'mods')
66
- end
67
- if iiif_presentation_manifest_needed? @public_xml_doc
68
- DigitalStacksService.transfer_to_document_store(pid, build_iiif_manifest(@public_xml_doc), 'manifest')
60
+ %w(identityMetadata contentMetadata rightsMetadata).each do |stream|
61
+ DigitalStacksService.transfer_to_document_store(pid, datastreams[stream].to_xml, stream)
69
62
  end
63
+ DigitalStacksService.transfer_to_document_store(pid, public_xml, 'public')
64
+ DigitalStacksService.transfer_to_document_store(pid, generate_public_desc_md, 'mods') if metadata_format == 'mods'
70
65
  else
71
66
  # Clear out the document cache for this item
72
67
  DigitalStacksService.prune_purl_dir pid
73
68
  end
74
69
  end
75
- #call the dor services app to have it publish the metadata
70
+
71
+ # Call dor services app to have it publish the metadata
76
72
  def publish_metadata_remotely
77
- dor_services = RestClient::Resource.new(Config.dor_services.url+"/v1/objects/#{pid}/publish")
73
+ dor_services = RestClient::Resource.new(Config.dor_services.url + "/v1/objects/#{pid}/publish")
78
74
  dor_services.post ''
79
75
  dor_services.url
80
76
  end
81
77
  end
82
-
83
78
  end
@@ -11,18 +11,16 @@ module Dor
11
11
  # @param release_tags [Hash, Array<Hash>] hash of a single release tag or an array of many such hashes
12
12
  # @raise [ArgumentError] Raised if the tags are improperly supplied
13
13
  def add_release_nodes_and_start_releaseWF(release_tags)
14
- release_tags = [release_tags] unless release_tags.class == Array
14
+ release_tags = [release_tags] unless release_tags.is_a?(Array)
15
15
 
16
- #Add in each tag
16
+ # Add in each tag
17
17
  release_tags.each do |r_tag|
18
- self.add_release_node(r_tag[:release],r_tag)
18
+ add_release_node(r_tag[:release], r_tag)
19
19
  end
20
20
 
21
- #Save the item to dor so the robots work with the latest data
22
- self.save
23
-
24
- #Intialize the release workflow
25
- self.initialize_workflow('releaseWF')
21
+ # Save item to dor so the robots work with the latest data
22
+ save
23
+ initialize_workflow('releaseWF')
26
24
  end
27
25
 
28
26
  # Generate XML structure for inclusion to Purl
@@ -30,70 +28,60 @@ module Dor
30
28
  def generate_release_xml
31
29
  builder = Nokogiri::XML::Builder.new do |xml|
32
30
  xml.releaseData {
33
- self.released_for.each do |project, released_value|
34
- xml.release(released_value["release"],:to=>project)
31
+ released_for.each do |project, released_value|
32
+ xml.release(released_value['release'], :to => project)
35
33
  end
36
34
  }
37
- end
38
- return builder.to_xml
35
+ end
36
+ builder.to_xml
39
37
  end
40
38
 
41
- # Determine which projects an item is released for
39
+ # Determine projects in which an item is released
40
+ # @param [Boolean] skip_live_purl set true to skip requesting from purl backend
42
41
  # @return [Hash{String => Boolean}] all namespaces, keys are Project name Strings, values are Boolean
43
- def released_for
42
+ def released_for(skip_live_purl = false)
44
43
  released_hash = {}
45
44
 
46
- #Get release tags on the item itself
47
- release_tags_on_this_item = self.release_nodes
48
-
49
- #Get any self tags on this item
50
- self_release_tags = self.get_self_release_tags(release_tags_on_this_item)
51
-
52
- #Get the most recent self tag for all targets and save their result since most recent self always trumps any other non self tags
53
- latest_self_tags = self.get_newest_release_tag(self_release_tags)
54
- latest_self_tags.keys.each do |target|
55
- released_hash[target] = self.clean_release_tag_for_purl(latest_self_tags[target])
45
+ # Get the most recent self tag for all targets and retain their result since most recent self always trumps any other non self tags
46
+ latest_self_tags = get_newest_release_tag get_self_release_tags(release_nodes)
47
+ latest_self_tags.each do |key, payload|
48
+ released_hash[key] = {'release' => payload['release']}
56
49
  end
57
50
 
58
- #With Self Tags Resolved We Now need to deal with tags on all sets this object is part of
59
-
60
- potential_applicable_release_tags = {} #This will be where we store all tags that apply, regardless of their timestamp
61
-
62
- #Get all release tags on the item and strip out the what = self ones, we've already processed all the self tags on this item
63
- potential_applicable_release_tags = get_tags_for_what_value(self.get_release_tags_for_item_and_all_governing_sets, 'collection')
64
-
65
- administrative_tags = self.tags #Get them once here and pass them down
66
-
67
- #We now have the keys for all potential releases, we need to check the tags and the most recent time stamp with an explicit true or false wins, in a nil case, the lack of an explicit false tag we do nothing
68
- (potential_applicable_release_tags.keys-released_hash.keys).each do |key| #don't bother checking the ones already added to the release hash, they were added due to a self tag and that has won
69
- latest_applicable_tag_for_key = latest_applicable_release_tag_in_array(potential_applicable_release_tags[key], administrative_tags)
70
- unless latest_applicable_tag_for_key.nil? #We have a valid tag, record it
71
- released_hash[key] = self.clean_release_tag_for_purl(latest_applicable_tag_for_key)
72
- end
73
-
51
+ # With Self Tags resolved we now need to deal with tags on all sets this object is part of.
52
+ # Get all release tags on the item and strip out the what = self ones, we've already processed all the self tags on this item.
53
+ # This will be where we store all tags that apply, regardless of their timestamp:
54
+ potential_applicable_release_tags = get_tags_for_what_value(get_release_tags_for_item_and_all_governing_sets, 'collection')
55
+ administrative_tags = tags # Get admin tags once here and pass them down
56
+
57
+ # We now have the keys for all potential releases, we need to check the tags: the most recent timestamp with an explicit true or false wins.
58
+ # In a nil case, the lack of an explicit false tag we do nothing.
59
+ (potential_applicable_release_tags.keys - released_hash.keys).each do |key| # don't bother checking if already added to the release hash, they were added due to a self tag so that has won
60
+ latest_tag = latest_applicable_release_tag_in_array(potential_applicable_release_tags[key], administrative_tags)
61
+ next if latest_tag.nil? # Otherwise, we have a valid tag, record it
62
+ released_hash[key] = {'release' => latest_tag['release']}
74
63
  end
75
64
 
76
- #See what the application is currently released for on Purl. If something is released in purl but not listed here, it needs to be added as a false
77
- released_hash = self.add_tags_from_purl(released_hash)
78
-
79
- return released_hash
65
+ # See what the application is currently released for on Purl. If released in purl but not listed here, it needs to be added as a false
66
+ add_tags_from_purl(released_hash) unless skip_live_purl
67
+ released_hash
80
68
  end
81
69
 
82
70
  # Take a hash of tags as obtained via Dor::Item.release_tags and returns all self tags
83
71
  # @param tags [Hash] a hash of tags obtained via Dor::Item.release_tags or matching format
84
72
  # @return [Hash] a hash of self tags for each to value
85
73
  def get_self_release_tags(tags)
86
- return get_tags_for_what_value(tags, 'self')
74
+ get_tags_for_what_value(tags, 'self')
87
75
  end
88
76
 
89
77
  # Take an item and get all of its release tags and all tags on collections it is a member of it
90
78
  # @return [Hash] a hash of all tags
91
79
  def get_release_tags_for_item_and_all_governing_sets
92
- return_tags = self.release_nodes || {}
93
- self.collections.each do |collection|
94
- return_tags = combine_two_release_tag_hashes(return_tags, Dor::Item.find(collection.id).get_release_tags_for_item_and_all_governing_sets) #this will function recurvisely so parents of parents are found
80
+ return_tags = release_nodes || {}
81
+ collections.each do |collection|
82
+ return_tags = combine_two_release_tag_hashes(return_tags, Dor::Item.find(collection.id).get_release_tags_for_item_and_all_governing_sets) # recurvise so parents of parents are found
95
83
  end
96
- return return_tags
84
+ return_tags
97
85
  end
98
86
 
99
87
  # Take two hashes of tags and combine them, will not overwrite but will enforce uniqueness of the tags
@@ -105,7 +93,7 @@ module Dor
105
93
  hash_one[key] = hash_two[key] if hash_one[key].nil?
106
94
  hash_one[key] = (hash_one[key] + hash_two[key]).uniq unless hash_one[key].nil?
107
95
  end
108
- return hash_one
96
+ hash_one
109
97
  end
110
98
 
111
99
  # Take a hash of tags and return all tags with the matching what target
@@ -115,34 +103,17 @@ module Dor
115
103
  def get_tags_for_what_value(tags, what_target)
116
104
  return_hash = {}
117
105
  tags.keys.each do |key|
118
- self_tags = tags[key].select{|tag| tag['what'] == what_target.downcase}
106
+ self_tags = tags[key].select {|tag| tag['what'] == what_target.downcase}
119
107
  return_hash[key] = self_tags if self_tags.size > 0
120
108
  end
121
- return return_hash
109
+ return_hash
122
110
  end
123
111
 
124
112
  # Take a hash of tags as obtained via Dor::Item.release_tags and returns the newest tag for each namespace
125
113
  # @param tags [Hash] a hash of tags obtained via Dor::Item.release_tags or matching format
126
114
  # @return [Hash] a hash of latest tags for each to value
127
115
  def get_newest_release_tag(tags)
128
- return_hash = {}
129
- tags.keys.each do |key|
130
- latest_for_key = newest_release_tag_in_an_array(tags[key])
131
- return_hash[key] = latest_for_key
132
- end
133
- return return_hash
134
- end
135
-
136
- # Take a tag and return only the attributes we want to put into purl
137
- # @param tag [Hash] a tag
138
- # @return [Hash] a hash of the attributes we want for purl
139
- def clean_release_tag_for_purl(tag)
140
- for_purl = ['release']
141
- return_hash = {}
142
- for_purl.each do |attr|
143
- return_hash[attr] = tag[attr]
144
- end
145
- return return_hash
116
+ Hash[tags.map {|key, val| [key, newest_release_tag_in_an_array(val)]}]
146
117
  end
147
118
 
148
119
  # Takes an array of release tags and returns the most recent one
@@ -153,51 +124,50 @@ module Dor
153
124
  array_of_tags.each do |tag|
154
125
  latest_tag_in_array = tag if tag['when'] > latest_tag_in_array['when']
155
126
  end
156
- return latest_tag_in_array
127
+ latest_tag_in_array
157
128
  end
158
129
 
159
130
  # Takes a tag and returns true or false if it applies to the specific item
160
131
  # @param release_tag [Hash] the tag in a hashed form
161
132
  # @param admin_tags [Array] the administrative tags on an item, if not supplied it will attempt to retrieve them
162
133
  # @return [Boolean] true or false if it applies (not true or false if it is released, that is the release_tag data)
163
- def does_release_tag_apply(release_tag, admin_tags=false)
164
- #Is the tag global or restricted
165
- return true if release_tag['tag'].nil? #there is no specific tag specificied, so that means this tag is global to all members of the collection, it applies, return true
166
-
167
- admin_tags = self.tags unless admin_tags #We use false instead of [], since an item can have no admin_tags that which point we'd be passing down this variable as [] and would not an attempt to retrieve it
168
- return admin_tags.include?(release_tag['tag'])
134
+ def does_release_tag_apply(release_tag, admin_tags = false)
135
+ # Is the tag global or restricted
136
+ return true if release_tag['tag'].nil? # no specific tag specificied means this tag is global to all members of the collection
137
+ admin_tags = tags unless admin_tags # We use false instead of [], since an item can have no admin_tags at which point we'd be passing this var as [] and would not attempt to retrieve it
138
+ admin_tags.include?(release_tag['tag'])
169
139
  end
170
140
 
171
141
  # Takes an array of release tags and returns the most recent one that applies to this item
172
142
  # @param release_tags [Array] an array of release tags in hashed form
173
143
  # @param admin_tags [Array] the administrative tags on an on item
174
- # @return [Hash] the tag
144
+ # @return [Hash] the tag, or nil if none applicable
175
145
  def latest_applicable_release_tag_in_array(release_tags, admin_tags)
176
146
  newest_tag = newest_release_tag_in_an_array(release_tags)
177
- return newest_tag if does_release_tag_apply(newest_tag, admin_tags) #Return true if we have it
147
+ return newest_tag if does_release_tag_apply(newest_tag, admin_tags)
178
148
 
179
- #The latest tag wasn't applicable, slice it off and try again
180
- #This could be optimized by reordering on the timestamp and just running down it instead of constantly resorting, at least if we end up getting numerous release tags on an item
149
+ # The latest tag wasn't applicable, slice it off and try again
150
+ # This could be optimized by reordering on the timestamp and just running down it instead of constantly resorting, at least if we end up getting numerous release tags on an item
181
151
  release_tags.slice!(release_tags.index(newest_tag))
182
152
 
183
- return latest_applicable_release_tag_in_array(release_tags, admin_tags) if release_tags.size > 0 #Try again after dropping the one that wasn't applicable
184
- return nil #We're out of tags, no applicable ones
153
+ return latest_applicable_release_tag_in_array(release_tags, admin_tags) if release_tags.size > 0 # Try again after dropping the inapplicable
154
+ nil # We're out of tags, no applicable ones
185
155
  end
186
156
 
187
157
  # Helper method to get the release tags as a nodeset
188
158
  # @return [Nokogiri::XML::NodeSet] all release tags and their attributes
189
159
  def release_tags
190
- release_tags = self.identityMetadata.ng_xml.xpath('//release')
160
+ release_tags = identityMetadata.ng_xml.xpath('//release')
191
161
  return_hash = {}
192
162
  release_tags.each do |release_tag|
193
- hashed_node = self.release_tag_node_to_hash(release_tag)
163
+ hashed_node = release_tag_node_to_hash(release_tag)
194
164
  if !return_hash[hashed_node[:to]].nil?
195
165
  return_hash[hashed_node[:to]] << hashed_node[:attrs]
196
166
  else
197
167
  return_hash[hashed_node[:to]] = [hashed_node[:attrs]]
198
168
  end
199
169
  end
200
- return return_hash
170
+ return_hash
201
171
  end
202
172
 
203
173
  # Convert one release element into a Hash
@@ -206,21 +176,20 @@ module Dor
206
176
  def release_tag_node_to_hash(rtag)
207
177
  to = 'to'
208
178
  release = 'release'
209
- when_word = 'when' #TODO: Make to and when_word load from some config file instead of hardcoded here
179
+ when_word = 'when' # TODO: Make to and when_word load from some config file instead of hardcoded here
210
180
  attrs = rtag.attributes
211
181
  return_hash = { :to => attrs[to].value }
212
- attrs.tap { |a| a.delete(to)}
213
- attrs[release] = rtag.text.downcase == "true" #save release as a boolean
182
+ attrs.tap { |a| a.delete(to) }
183
+ attrs[release] = rtag.text.downcase == 'true' # save release as a boolean
214
184
  return_hash[:attrs] = attrs
215
185
 
216
- #convert all the attrs beside :to to strings, they are currently Nokogiri::XML::Attr
217
- (return_hash[:attrs].keys-[to]).each do |a|
218
- return_hash[:attrs][a] = return_hash[:attrs][a].to_s if a != release
186
+ # convert all the attrs beside :to to strings, they are currently Nokogiri::XML::Attr
187
+ (return_hash[:attrs].keys - [to]).each do |a|
188
+ return_hash[:attrs][a] = return_hash[:attrs][a].to_s if a != release
219
189
  end
220
190
 
221
- return_hash[:attrs][when_word] = Time.parse(return_hash[:attrs][when_word]) #convert when to a datetime
222
-
223
- return return_hash
191
+ return_hash[:attrs][when_word] = Time.parse(return_hash[:attrs][when_word]) # convert when to a datetime
192
+ return_hash
224
193
  end
225
194
 
226
195
  # Determine if the supplied tag is a valid release tag that meets all requirements
@@ -228,8 +197,8 @@ module Dor
228
197
  # @param attrs [hash] A hash of attributes for the tag, must contain: :when, a ISO 8601 timestamp; :who, to identify who or what added the tag; and :to, a string identifying the release target
229
198
  # @raise [RuntimeError] Raises an error of the first fault in the release tag
230
199
  # @return [Boolean] Returns true if no errors found
231
- def valid_release_attributes_and_tag(tag, attrs={})
232
- raise ArgumentError, ":when is not iso8601" if attrs[:when].match('\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z').nil?
200
+ def valid_release_attributes_and_tag(tag, attrs = {})
201
+ raise ArgumentError, ':when is not iso8601' if attrs[:when].match('\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z').nil?
233
202
  [:who, :to, :what].each do |check_attr|
234
203
  raise ArgumentError, "#{check_attr} not supplied as a String" if attrs[check_attr].class != String
235
204
  end
@@ -238,10 +207,10 @@ module Dor
238
207
  %w(self collection).each do |allowed_what_value|
239
208
  what_correct = true if attrs[:what] == allowed_what_value
240
209
  end
241
- raise ArgumentError, ":what must be self or collection" unless what_correct
242
- raise ArgumentError, "the value set for this tag is not a boolean" if !!tag != tag
243
- validate_tag_format(attrs[:tag]) unless attrs[:tag].nil? #Will Raise exception if invalid tag
244
- return true
210
+ raise ArgumentError, ':what must be self or collection' unless what_correct
211
+ raise ArgumentError, 'the value set for this tag is not a boolean' if !!tag != tag # rubocop:disable Style/DoubleNegation
212
+ validate_tag_format(attrs[:tag]) unless attrs[:tag].nil? # Will Raise exception if invalid tag
213
+ true
245
214
  end
246
215
 
247
216
  # Add a release node for the item
@@ -255,17 +224,16 @@ module Dor
255
224
  #
256
225
  # @example
257
226
  # item.add_tag(true,:release,{:tag=>'Fitch : Batch2',:what=>'self',:to=>'Searchworks',:who=>'petucket', :displayType='filmstrip'})
258
- def add_release_node(release, attrs={})
259
- identity_metadata_ds = self.identityMetadata
260
- attrs[:when] = Time.now.utc.iso8601 if attrs[:when].nil? #add the timestamp
261
- attrs[:displayType] = 'file' if attrs[:displayType].nil? #default to file is no display type is passed
227
+ def add_release_node(release, attrs = {})
228
+ identity_metadata_ds = identityMetadata
229
+ attrs[:when] = Time.now.utc.iso8601 if attrs[:when].nil? # add the timestamp
230
+ attrs[:displayType] = 'file' if attrs[:displayType].nil? # default to file is no display type is passed
262
231
  valid_release_attributes(release, attrs)
263
232
 
264
- #Remove the old displayType and then add the one for this tag
233
+ # Remove the old displayType and then add the one for this tag
265
234
  remove_displayTypes
266
235
  identity_metadata_ds.add_value(:displayType, attrs[:displayType], {})
267
-
268
- return identity_metadata_ds.add_value(:release, release.to_s, attrs)
236
+ identity_metadata_ds.add_value(:release, release.to_s, attrs)
269
237
  end
270
238
 
271
239
  # Determine if the supplied tag is a valid release node that meets all requirements
@@ -274,8 +242,8 @@ module Dor
274
242
  # @param attrs [hash] A hash of attributes for the tag, must contain :when, a ISO 8601 timestamp and :who to identify who or what added the tag, :to,
275
243
  # @raise [ArgumentError] Raises an error of the first fault in the release tag
276
244
  # @return [Boolean] Returns true if no errors found
277
- def valid_release_attributes(tag, attrs={})
278
- raise ArgumentError, ":when is not iso8601" if attrs[:when].match('\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z').nil?
245
+ def valid_release_attributes(tag, attrs = {})
246
+ raise ArgumentError, ':when is not iso8601' if attrs[:when].match('\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z').nil?
279
247
  [:who, :to, :what].each do |check_attr|
280
248
  raise ArgumentError, "#{check_attr} not supplied as a String" if attrs[check_attr].class != String
281
249
  end
@@ -284,28 +252,28 @@ module Dor
284
252
  %w(self collection).each do |allowed_what_value|
285
253
  what_correct = true if attrs[:what] == allowed_what_value
286
254
  end
287
- raise ArgumentError, ":what must be self or collection" unless what_correct
288
- raise ArgumentError, "the value set for this tag is not a boolean" if !!tag != tag
289
- raise ArgumentError, ":displayType must be passed in as a String" unless attrs[:displayType].class == String
255
+ raise ArgumentError, ':what must be self or collection' unless what_correct
256
+ raise ArgumentError, 'the value set for this tag is not a boolean' if !!tag != tag # rubocop:disable Style/DoubleNegation
257
+ raise ArgumentError, ':displayType must be passed in as a String' unless attrs[:displayType].class == String
290
258
 
291
- validate_tag_format(attrs[:tag]) unless attrs[:tag].nil? #Will Raise exception if invalid tag
292
- return true
259
+ validate_tag_format(attrs[:tag]) unless attrs[:tag].nil? # Will Raise exception if invalid tag
260
+ true
293
261
  end
294
262
 
295
263
  # Helper method to get the release nodes as a nodeset
296
264
  # @return [Nokogiri::XML::NodeSet] of all release tags and their attributes
297
265
  def release_nodes
298
- release_tags = self.identityMetadata.ng_xml.xpath('//release')
266
+ release_tags = identityMetadata.ng_xml.xpath('//release')
299
267
  return_hash = {}
300
268
  release_tags.each do |release_tag|
301
- hashed_node = self.release_tag_node_to_hash(release_tag)
269
+ hashed_node = release_tag_node_to_hash(release_tag)
302
270
  if !return_hash[hashed_node[:to]].nil?
303
271
  return_hash[hashed_node[:to]] << hashed_node[:attrs]
304
272
  else
305
- return_hash[hashed_node[:to]] = [hashed_node[:attrs]]
273
+ return_hash[hashed_node[:to]] = [hashed_node[:attrs]]
306
274
  end
307
275
  end
308
- return return_hash
276
+ return_hash
309
277
  end
310
278
 
311
279
  # Get a list of all release nodes found in a purl document
@@ -313,81 +281,76 @@ module Dor
313
281
  # @raise [OpenURI::HTTPError]
314
282
  # @return [Nokogiri::HTML::Document] parsed XML for the druid or an empty document if no purl is found
315
283
  def get_xml_from_purl
316
- handler = Proc.new do |exception, attempt_number, total_delay|
317
- #We assume a 404 means the document has never been published before and thus has no purl
318
- #The strip is needed before the actual message is "404 "
319
- return Nokogiri::HTML::Document.new if exception.message.strip == "404"
284
+ url = form_purl_url
285
+ handler = proc do |exception, attempt_number, total_delay|
286
+ # We assume a 404 means the document has never been published before and thus has no purl
287
+ Dor.logger.warn "[Attempt #{attempt_number}] GET #{url} -- #{exception.class}: #{exception.message}; #{total_delay} seconds elapsed."
288
+ raise exception unless exception.is_a? OpenURI::HTTPError
289
+ return Nokogiri::HTML::Document.new if exception.message.strip == '404' # strip is needed if the actual message is "404 "
320
290
  end
321
291
 
322
- with_retries(:max_retries => 5, :base_sleep_seconds => 3, :max_sleep_seconds=> 5, :rescue => OpenURI::HTTPError, :handler => handler) {
323
- #If you change the method used for opening the webpage, you can change the :rescue param to handle the new method's errors
324
- return Nokogiri::HTML(open(self.form_purl_url))
325
- }
292
+ with_retries(:max_retries => 3, :base_sleep_seconds => 3, :max_sleep_seconds => 5, :handler => handler) do |attempt|
293
+ # If you change the method used for opening the webpage, you can change the :rescue param to handle the new method's errors
294
+ Dor.logger.info "[Attempt #{attempt}] GET #{url}"
295
+ return Nokogiri::HTML(OpenURI.open_uri(url))
296
+ end
326
297
  end
327
298
 
328
299
  # Since purl does not use the druid: prefix but much of dor does, use this function to strip the druid: if needed
329
300
  # @return [String] the druid sans the druid: or if there was no druid: prefix, the entire string you passed
330
301
  def remove_druid_prefix
331
- druid_prefix = "druid:"
332
- return self.id.split(druid_prefix)[1] if self.id.split(druid_prefix).size > 1
333
- return druid
302
+ druid_prefix = 'druid:'
303
+ return id.split(druid_prefix)[1] if id.split(druid_prefix).size > 1
304
+ druid
334
305
  end
335
306
 
336
307
  # Take the and create the entire purl url that will usable for the open method in open-uri, returns http
337
- # @return [String], the full url
308
+ # @return [String] the full url
338
309
  def form_purl_url
339
- prefix = "http://"
340
- return prefix + Dor::Config.stacks.document_cache_host + "/#{self.remove_druid_prefix}.xml"
310
+ 'https://' + Dor::Config.stacks.document_cache_host + "/#{remove_druid_prefix}.xml"
341
311
  end
342
312
 
343
313
  # Pull all release nodes from the public xml obtained via the purl query
344
314
  # @param doc [Nokogiri::HTML::Document] The druid of the object you want
345
315
  # @return [Array] An array containing all the release tags
346
316
  def get_release_tags_from_purl_xml(doc)
347
- nodes = doc.xpath("//html/body/publicobject/releasedata").children
348
- #We only want the nodes with a name that isn't text
349
- return_array = []
350
- nodes.each do |n|
351
- return_array << n.attr('to') if !n.name.nil? && n.name.downcase != "text"
352
- end
353
- return return_array.uniq
317
+ nodes = doc.xpath('//html/body/publicobject/releasedata').children
318
+ # We only want the nodes with a name that isn't text
319
+ nodes.reject {|n| n.name.nil? || n.name.downcase == 'text'}.map {|n| n.attr('to')}.uniq
354
320
  end
355
321
 
356
322
  # Pull all release nodes from the public xml obtained via the purl query
357
323
  # @return [Array] An array containing all the release tags
358
324
  def get_release_tags_from_purl
359
- xml = self.get_xml_from_purl
360
- return self.get_release_tags_from_purl_xml(xml)
325
+ get_release_tags_from_purl_xml(get_xml_from_purl)
361
326
  end
362
327
 
363
328
  # This function calls purl and gets a list of all release tags currently in purl. It then compares to the list you have generated.
364
329
  # Any tag that is on purl, but not in the newly generated list is added to the new list with a value of false.
365
- #
366
330
  # @param new_tags [Hash{String => Boolean}] all new tags in the form of !{"Project" => Boolean}
367
- # @return [Hash], a hash in the same form as new_tags, with all missing tags not in new_tags, but in current_tag_names, added in with a Boolean value of false
331
+ # @return [Hash] same form as new_tags, with all missing tags not in new_tags, but in current_tag_names, added in with a Boolean value of false
368
332
  def add_tags_from_purl(new_tags)
369
- tags_currently_in_purl = self.get_release_tags_from_purl
333
+ tags_currently_in_purl = get_release_tags_from_purl
370
334
  missing_tags = tags_currently_in_purl.map(&:downcase) - new_tags.keys.map(&:downcase)
371
335
  missing_tags.each do |missing_tag|
372
- new_tags[missing_tag.capitalize] = {"release"=>false}
336
+ new_tags[missing_tag.capitalize] = {'release' => false}
373
337
  end
374
- return new_tags
338
+ new_tags
375
339
  end
376
340
 
377
- def to_solr(solr_doc=Hash.new, *args)
341
+ def to_solr(solr_doc = {}, *args)
378
342
  super(solr_doc, *args)
379
343
 
380
- #TODO: sort of worried about the performance impact in bulk reindex
344
+ # TODO: sort of worried about the performance impact in bulk reindex
381
345
  # situations, since released_for recurses all parent collections. jmartin 2015-07-14
382
- released_for().each { |key, val|
383
- add_solr_value(solr_doc, "released_to", key, :symbol, []) if val
346
+ released_for(true).each { |key, val|
347
+ add_solr_value(solr_doc, 'released_to', key, :symbol, []) if val
384
348
  }
385
349
 
386
- #TODO: need to solrize whether item is released to purl? does released_for
387
- # return that? logic is: "True when there is a published lifecycle and Access
388
- # Rights is anything but Dark"
350
+ # TODO: need to solrize whether item is released to purl? does released_for return that?
351
+ # logic is: "True when there is a published lifecycle and Access Rights is anything but Dark"
389
352
 
390
- return solr_doc
353
+ solr_doc
391
354
  end
392
355
  end
393
356
  end