ddr-models 2.6.2 → 2.7.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/.travis.yml +1 -1
  4. data/Gemfile +2 -3
  5. data/app/models/collection.rb +11 -3
  6. data/app/models/component.rb +54 -4
  7. data/app/models/item.rb +1 -2
  8. data/config/initializers/active_fedora_base.rb +8 -5
  9. data/config/initializers/rubydora_monkey_patch.rb +11 -0
  10. data/config/initializers/subscriptions.rb +16 -9
  11. data/config/locales/ddr-models.en.yml +3 -0
  12. data/ddr-models.gemspec +3 -2
  13. data/lib/ddr/actions/virus_check.rb +10 -16
  14. data/lib/ddr/auth.rb +0 -8
  15. data/lib/ddr/datastreams.rb +13 -2
  16. data/lib/ddr/datastreams/administrative_metadata_datastream.rb +9 -0
  17. data/lib/ddr/datastreams/content_datastream.rb +5 -0
  18. data/lib/ddr/datastreams/datastream_behavior.rb +60 -15
  19. data/lib/ddr/datastreams/delete_external_files.rb +29 -0
  20. data/lib/ddr/datastreams/descriptive_metadata_datastream.rb +33 -33
  21. data/lib/ddr/datastreams/external_file_datastream.rb +69 -0
  22. data/lib/ddr/datastreams/fits_datastream.rb +15 -5
  23. data/lib/ddr/datastreams/intermediate_file_datastream.rb +5 -0
  24. data/lib/ddr/datastreams/metadata_datastream.rb +15 -17
  25. data/lib/ddr/datastreams/multires_image_datastream.rb +5 -0
  26. data/lib/ddr/derivatives.rb +1 -0
  27. data/lib/ddr/derivatives/ptif_generator.rb +5 -1
  28. data/lib/ddr/derivatives/update_derivatives.rb +23 -0
  29. data/lib/ddr/events/deletion_event.rb +5 -9
  30. data/lib/ddr/events/event.rb +7 -9
  31. data/lib/ddr/events/ingestion_event.rb +5 -9
  32. data/lib/ddr/events/update_event.rb +12 -5
  33. data/lib/ddr/index.rb +0 -1
  34. data/lib/ddr/index/csv_query_result.rb +10 -2
  35. data/lib/ddr/index/fields.rb +10 -9
  36. data/lib/ddr/index/filter.rb +1 -0
  37. data/lib/ddr/managers/derivatives_manager.rb +84 -98
  38. data/lib/ddr/managers/technical_metadata_manager.rb +20 -5
  39. data/lib/ddr/models.rb +24 -24
  40. data/lib/ddr/models/base.rb +98 -74
  41. data/lib/ddr/models/cache.rb +20 -0
  42. data/lib/ddr/models/engine.rb +4 -6
  43. data/lib/ddr/models/file_management.rb +57 -152
  44. data/lib/ddr/models/fixity_checkable.rb +0 -5
  45. data/lib/ddr/models/has_admin_metadata.rb +4 -2
  46. data/lib/ddr/models/has_children.rb +35 -1
  47. data/lib/ddr/models/has_content.rb +3 -33
  48. data/lib/ddr/models/has_intermediate_file.rb +18 -0
  49. data/lib/ddr/models/has_multires_image.rb +12 -15
  50. data/lib/ddr/models/has_struct_metadata.rb +2 -38
  51. data/lib/ddr/models/indexing.rb +160 -163
  52. data/lib/ddr/models/permanent_id.rb +26 -49
  53. data/lib/ddr/models/solr_document.rb +21 -19
  54. data/lib/ddr/models/structure.rb +168 -41
  55. data/lib/ddr/models/structures/agent.rb +49 -0
  56. data/lib/ddr/models/structures/div.rb +64 -0
  57. data/lib/ddr/models/structures/f_locat.rb +54 -0
  58. data/lib/ddr/models/structures/file.rb +52 -0
  59. data/lib/ddr/models/structures/file_grp.rb +35 -0
  60. data/lib/ddr/models/structures/file_sec.rb +22 -0
  61. data/lib/ddr/models/structures/fptr.rb +31 -0
  62. data/lib/ddr/models/structures/mets_hdr.rb +37 -0
  63. data/lib/ddr/models/structures/mptr.rb +49 -0
  64. data/lib/ddr/models/structures/struct_map.rb +40 -0
  65. data/lib/ddr/models/version.rb +1 -1
  66. data/lib/ddr/notifications.rb +10 -12
  67. data/lib/ddr/utils.rb +29 -16
  68. data/lib/ddr/vocab.rb +15 -17
  69. data/lib/ddr/vocab/asset.rb +29 -19
  70. data/lib/ddr/vocab/contact.rb +5 -7
  71. data/lib/ddr/vocab/display.rb +6 -8
  72. data/lib/ddr/vocab/duke_terms.rb +8 -10
  73. data/lib/ddr/vocab/rdf_vocabulary_parser.rb +37 -39
  74. data/lib/ddr/vocab/roles.rb +17 -19
  75. data/lib/ddr/vocab/vocabulary.rb +26 -26
  76. data/spec/datastreams/external_file_datastream_spec.rb +37 -0
  77. data/spec/derivatives/png_generator_spec.rb +21 -25
  78. data/spec/derivatives/ptif_generator_spec.rb +22 -26
  79. data/spec/dummy/config/environments/test.rb +1 -1
  80. data/spec/dummy/db/schema.rb +23 -23
  81. data/spec/factories/structure_factories.rb +8 -2
  82. data/spec/fixtures/imageA.jpg +0 -0
  83. data/spec/fixtures/imageB.jpg +0 -0
  84. data/spec/index/csv_query_result_spec.rb +3 -3
  85. data/spec/index/fields_spec.rb +7 -6
  86. data/spec/managers/derivatives_manager_spec.rb +105 -112
  87. data/spec/managers/technical_metadata_manager_spec.rb +22 -18
  88. data/spec/models/active_fedora_base_spec.rb +0 -106
  89. data/spec/models/active_fedora_datastream_spec.rb +33 -2
  90. data/spec/models/attachment_spec.rb +0 -2
  91. data/spec/models/cache_spec.rb +32 -0
  92. data/spec/models/collection_spec.rb +43 -19
  93. data/spec/models/component_spec.rb +41 -51
  94. data/spec/models/descriptive_metadata_datastream_spec.rb +99 -87
  95. data/spec/models/events_spec.rb +50 -69
  96. data/spec/models/file_management_spec.rb +79 -187
  97. data/spec/models/has_children_spec.rb +54 -3
  98. data/spec/models/has_struct_metadata_spec.rb +32 -38
  99. data/spec/models/indexing_spec.rb +11 -6
  100. data/spec/models/item_spec.rb +21 -7
  101. data/spec/models/permanent_id_spec.rb +1 -5
  102. data/spec/models/solr_document_spec.rb +13 -41
  103. data/spec/models/structure_spec.rb +85 -16
  104. data/spec/models/structures/agent_spec.rb +30 -0
  105. data/spec/models/structures/div_spec.rb +26 -0
  106. data/spec/models/structures/f_locat_spec.rb +78 -0
  107. data/spec/models/structures/file_grp_spec.rb +23 -0
  108. data/spec/models/structures/file_sec_spec.rb +22 -0
  109. data/spec/models/structures/file_spec.rb +60 -0
  110. data/spec/models/structures/fptr_spec.rb +23 -0
  111. data/spec/models/structures/mets_hdr_spec.rb +26 -0
  112. data/spec/models/structures/mptr_spec.rb +25 -0
  113. data/spec/models/structures/struct_map_spec.rb +24 -0
  114. data/spec/models/target_spec.rb +0 -2
  115. data/spec/spec_helper.rb +4 -9
  116. data/spec/support/shared_examples_for_ddr_models.rb +96 -156
  117. data/spec/support/shared_examples_for_has_content.rb +56 -30
  118. data/spec/support/shared_examples_for_has_intermediate_spec.rb +28 -0
  119. data/spec/support/shared_examples_for_non_collection_models.rb +5 -0
  120. data/spec/support/structural_metadata_helper.rb +230 -59
  121. data/spec/utils_spec.rb +0 -2
  122. metadata +86 -44
  123. data/app/helpers/models_helper.rb +0 -10
  124. data/lib/ddr/auth/legacy/abstract_legacy_permissions.rb +0 -17
  125. data/lib/ddr/auth/legacy/legacy_authorization.rb +0 -44
  126. data/lib/ddr/auth/legacy/legacy_default_permissions.rb +0 -33
  127. data/lib/ddr/auth/legacy/legacy_permissions.rb +0 -33
  128. data/lib/ddr/auth/legacy/legacy_roles.rb +0 -25
  129. data/lib/ddr/index/legacy_license_fields.rb +0 -12
  130. data/lib/ddr/jobs.rb +0 -12
  131. data/lib/ddr/jobs/fits_file_characterization.rb +0 -13
  132. data/lib/ddr/jobs/fixity_check.rb +0 -13
  133. data/lib/ddr/jobs/job.rb +0 -36
  134. data/lib/ddr/jobs/queue.rb +0 -27
  135. data/lib/ddr/jobs/update_index.rb +0 -13
  136. data/lib/ddr/models/access_controllable.rb +0 -24
  137. data/lib/ddr/models/struct_div.rb +0 -63
  138. data/spec/auth/legacy_default_permissions_spec.rb +0 -37
  139. data/spec/auth/legacy_permissions_spec.rb +0 -37
  140. data/spec/helpers/models_helper_spec.rb +0 -11
  141. data/spec/jobs/fits_file_characterization_spec.rb +0 -16
  142. data/spec/jobs/fixity_check_spec.rb +0 -22
  143. data/spec/jobs/job_spec.rb +0 -40
  144. data/spec/jobs/update_index_spec.rb +0 -22
  145. data/spec/models/struct_div_spec.rb +0 -70
  146. data/spec/support/shared_examples_for_access_controllables.rb +0 -6
@@ -35,13 +35,15 @@ module Ddr::Models
35
35
  event = ActiveSupport::Notifications::Event.new(*args)
36
36
  repo_id, identifier_id, reason = event.payload.values_at(:pid, :permanent_id, :reason)
37
37
  case event.name
38
- when /workflow/
39
- update!(repo_id) if auto_update?
40
- when /^deaccession/
38
+ when Base::UPDATE
39
+ if auto_update? && event.payload[:attributes_changed].include?("workflow_state")
40
+ update!(repo_id)
41
+ end
42
+ when Base::DEACCESSION
41
43
  if auto_update? && identifier_id
42
44
  deaccession!(repo_id, identifier_id, reason)
43
45
  end
44
- when /^destroy/
46
+ when Base::DELETE
45
47
  if auto_update? && identifier_id
46
48
  delete!(repo_id, identifier_id, reason)
47
49
  end
@@ -104,21 +106,23 @@ module Ddr::Models
104
106
  end
105
107
 
106
108
  def assign!(id = nil)
107
- ActiveSupport::Notifications.instrument("assign.permanent_id", pid: repo_object.id) do |payload|
108
- assign(id)
109
- software = [ "ddr-models #{Ddr::Models::VERSION}", Ezid::Client.version ].join("; ")
110
- detail = <<-EOS
111
- Permanent ID: #{repo_object.permanent_id}
112
- Permanent URL: #{repo_object.permanent_url}
113
-
114
- EZID Metadata:
115
- #{identifier.metadata}
116
- EOS
117
- payload.merge!(summary: "Permanent ID assignment",
118
- detail: detail,
119
- software: software,
120
- permanent_id: identifier.id)
109
+ if assigned?
110
+ raise AlreadyAssigned,
111
+ "Repository object \"#{repo_object.id}\" has already been assigned permanent id \"#{repo_object.permanent_id}\"."
121
112
  end
113
+ @identifier = case id
114
+ when identifier_class
115
+ id
116
+ when String
117
+ find_identifier(id)
118
+ when nil
119
+ mint_identifier
120
+ end
121
+ repo_object.reload
122
+ repo_object.permanent_id = identifier.id
123
+ repo_object.permanent_url = PERMANENT_URL_BASE + identifier.id
124
+ repo_object.save!
125
+ set_metadata!
122
126
  end
123
127
 
124
128
  def assigned?
@@ -126,10 +130,11 @@ EZID Metadata:
126
130
  end
127
131
 
128
132
  def update!
129
- ActiveSupport::Notifications.instrument("update.permanent_id", pid: repo_object.id) do |payload|
130
- update
131
- payload.merge!(permanent_id: identifier.id)
133
+ if !assigned?
134
+ raise IdentifierNotAssigned,
135
+ "Cannot update identifier for repository object \"#{repo_object.id}\"; not assigned."
132
136
  end
137
+ set_status!
133
138
  end
134
139
 
135
140
  def deaccession!(reason = nil)
@@ -220,34 +225,6 @@ EZID Metadata:
220
225
  identifier_class.mint(*args)
221
226
  end
222
227
 
223
- def update
224
- if !assigned?
225
- raise IdentifierNotAssigned,
226
- "Cannot update identifier for repository object \"#{repo_object.id}\"; not assigned."
227
- end
228
- set_status!
229
- end
230
-
231
- def assign(id = nil)
232
- if assigned?
233
- raise AlreadyAssigned,
234
- "Repository object \"#{repo_object.id}\" has already been assigned permanent id \"#{repo_object.permanent_id}\"."
235
- end
236
- @identifier = case id
237
- when identifier_class
238
- id
239
- when String
240
- find_identifier(id)
241
- when nil
242
- mint_identifier
243
- end
244
- repo_object.reload
245
- repo_object.permanent_id = identifier.id
246
- repo_object.permanent_url = PERMANENT_URL_BASE + identifier.id
247
- repo_object.save!
248
- set_metadata!
249
- end
250
-
251
228
  def delete_or_make_unavailable(reason)
252
229
  if repo_id && identifier_repo_id && ( identifier_repo_id != repo_id )
253
230
  raise Error, "Identifier \"#{identifier_id}\" is assigned to a different repository object \"#{repo_id}\"."
@@ -184,14 +184,10 @@ module Ddr::Models
184
184
  @roles ||= Ddr::Auth::Roles::DetachedRoleSet.from_json(access_role)
185
185
  end
186
186
 
187
- def struct_maps
188
- JSON.parse(fetch(Ddr::Index::Fields::STRUCT_MAPS))
187
+ def structure
188
+ JSON.parse(fetch(Ddr::Index::Fields::STRUCTURE))
189
189
  rescue
190
- {}
191
- end
192
-
193
- def struct_map(type='default')
194
- struct_maps.present? ? struct_maps.fetch(type) : nil
190
+ nil
195
191
  end
196
192
 
197
193
  def effective_permissions(agents)
@@ -217,8 +213,12 @@ module Ddr::Models
217
213
  end
218
214
  end
219
215
 
220
- def multires_image_file_paths(type='default')
221
- struct_map_docs(type).map { |doc| doc.multires_image_file_path }.compact
216
+ def multires_image_file_paths
217
+ if structure
218
+ structure_docs.map { |doc| doc.multires_image_file_path }.compact
219
+ else
220
+ []
221
+ end
222
222
  end
223
223
 
224
224
  # DRY HasAdminMetadata
@@ -260,18 +260,20 @@ module Ddr::Models
260
260
  end
261
261
  end
262
262
 
263
- def struct_map_docs(type='default')
264
- struct_map_pids(type).map { |pid| self.class.find(pid) }.compact
263
+ def structure_docs
264
+ structure_repo_ids.map { |repo_id| self.class.find(repo_id) }.compact
265
265
  end
266
266
 
267
- # For simplicity, initial implementation returns PID's only from top-level
268
- # (i.e., not nested) div's. This is done since we have not clarified what
269
- # an _ordered_ list of PID's should look like if struct map contains nested
270
- # div's.
271
- def struct_map_pids(type='default')
272
- struct_map(type)['divs'].map { |d| d['fptrs'].present? ? d['fptrs'].first : nil}.compact
273
- rescue
274
- []
267
+ # For simplicity, initial implementation returns repo ID's only from top-level
268
+ # (i.e., not nested) contents. This is done since we have not clarified what
269
+ # an _ordered_ list of repo ID's should look like if structure contains nested
270
+ # contents.
271
+ def structure_repo_ids
272
+ default_struct_map['contents'].map { |content| content['contents'].map { |content| content['repo_id'] } }.flatten
273
+ end
274
+
275
+ def default_struct_map
276
+ structure['default'] || structure.values.first
275
277
  end
276
278
 
277
279
  end
@@ -1,56 +1,183 @@
1
- module Ddr
2
- module Models
3
- #
4
- # Wraps a Nokogiri (XML) Document
5
- #
6
- class Structure < SimpleDelegator
7
-
8
- def initialize(xml_doc=nil)
9
- super
10
- end
1
+ module Ddr::Models
2
+ #
3
+ # Wraps a Nokogiri (XML) 'mets' Document
4
+ #
5
+ class Structure < SimpleDelegator
11
6
 
12
- def struct_maps
13
- @struct_maps ||= build_struct_maps(structMap_nodes)
14
- end
7
+ TYPE_DEFAULT = 'default'.freeze
15
8
 
16
- def structMap_node(type='default')
17
- xpath("//xmlns:structMap[@TYPE='#{type}']").first
18
- end
9
+ # Based on the PCDM Extension 'Use' ontology -- https://github.com/duraspace/pcdm/blob/master/pcdm-ext/use.rdf
10
+ USE_EXTRACTED_TEXT = 'ExtractedText'.freeze
11
+ USE_INTERMEDIATE_FILE = 'IntermediateFile'.freeze
12
+ USE_ORIGINAL_FILE = 'OriginalFile'.freeze
13
+ USE_PRESERVATION_MASTER_FILE = 'PreservationMasterFile'.freeze
14
+ USE_SERVICE_FILE = 'ServiceFile'.freeze
15
+ USE_THUMBNAIL_IMAGE = 'ThumbnailImage'.freeze
16
+ USE_TRANSCRIPT = 'Transcript'.freeze
19
17
 
20
- def fptr_nodes(type='default')
21
- structMap_node(type).xpath('//xmlns:fptr')
22
- end
18
+ def filesec
19
+ @filesec ||= Ddr::Models::Structures::FileSec.new(fileSec_node)
20
+ end
23
21
 
24
- def as_xml_document
25
- __getobj__
26
- end
22
+ def files
23
+ @files ||= collect_files
24
+ end
27
25
 
28
- private
26
+ def uses
27
+ @uses ||= collect_uses
28
+ end
29
29
 
30
- def structMap_nodes
31
- xpath("//xmlns:structMap")
30
+ def structmap(type=nil)
31
+ sm = type ? structMap_node(type) : structMap_nodes.first
32
+ @structmap ||= Ddr::Models::Structures::StructMap.new(sm)
33
+ end
34
+
35
+ def structmaps
36
+ @structmaps ||= structMap_nodes.map { |sm| Ddr::Models::Structures::StructMap.new(sm) }
37
+ end
38
+
39
+ def metshdr
40
+ @metshdr ||= Ddr::Models::Structures::MetsHdr.new(metsHdr_node)
41
+ end
42
+
43
+ def creator
44
+ @creator ||= metshdr.empty? ? nil
45
+ : Ddr::Models::Structures::MetsHdr.new(metsHdr_node).agents.first.name
46
+ end
47
+
48
+ def repository_maintained?
49
+ creator == Ddr::Models::Structures::Agent::NAME_REPOSITORY_DEFAULT
50
+ end
51
+
52
+ def dereferenced_structure
53
+ deref_struct = {}
54
+ structmaps.each do |sm|
55
+ deref_struct[sm.type] = sm.dereferenced_hash
32
56
  end
57
+ deref_struct
58
+ end
59
+
60
+ def as_xml_document
61
+ __getobj__
62
+ end
63
+
64
+ def add_metshdr(id:nil, createdate:nil, lastmoddate:nil, recordstatus:nil)
65
+ metshdr = Ddr::Models::Structures::MetsHdr.build(id: id, createdate: createdate, lastmoddate: lastmoddate,
66
+ recordstatus: recordstatus, document: as_xml_document)
67
+ root.add_child(metshdr)
68
+ metshdr
69
+ end
70
+
71
+ def add_agent(parent:, id:nil, role:, otherrole:nil, type:nil, othertype:nil, name:nil)
72
+ agent = Ddr::Models::Structures::Agent.build(id: id, role: role, otherrole: otherrole, type: type,
73
+ othertype: othertype, name: name, document: as_xml_document)
74
+ parent.add_child(agent)
75
+ agent
76
+ end
77
+
78
+ def add_filesec(id:nil)
79
+ filesec = Ddr::Models::Structures::FileSec.build(id: id, document: as_xml_document)
80
+ root.add_child(filesec)
81
+ filesec
82
+ end
83
+
84
+ def add_filegrp(parent:, id:nil, use:nil)
85
+ filegrp = Ddr::Models::Structures::FileGrp.build(id: id, use: use, document: as_xml_document)
86
+ parent.add_child(filegrp)
87
+ filegrp
88
+ end
33
89
 
34
- def build_struct_maps(structMap_nodes)
35
- smaps = {}
36
- structMap_nodes.each do |structMap_node|
37
- type = structMap_node['TYPE'] || 'default'
38
- raise StandardError, "Multiple '#{type}' structMaps" if smaps[type].present?
39
- smaps[type] = Ddr::Models::StructDiv.new(structMap_node)
40
- end
41
- smaps
90
+ def add_file(parent:, id:SecureRandom.uuid, use:nil)
91
+ file = Ddr::Models::Structures::File.build(id: id, use: use, document: as_xml_document)
92
+ parent.add_child(file)
93
+ file
94
+ end
95
+
96
+ def add_flocat(parent:, id:nil, loctype:'ARK', otherloctype: nil, use:nil, href:)
97
+ flocat = Ddr::Models::Structures::FLocat.build(id: id, loctype: loctype, otherloctype: otherloctype, use: use,
98
+ href: href, document: as_xml_document)
99
+ parent.add_child(flocat)
100
+ flocat
101
+ end
102
+
103
+ def add_structmap(id:nil, label:nil, type:)
104
+ structmap = Ddr::Models::Structures::StructMap.build(id: id, label: label, type: type, document: as_xml_document)
105
+ root.add_child(structmap)
106
+ structmap
107
+ end
108
+
109
+ def add_div(parent:, id:nil, label:nil, order:nil, orderlabel: nil, type:nil)
110
+ div = Ddr::Models::Structures::Div.build(id: id, label: label, order:order, orderlabel: orderlabel, type: type,
111
+ document: as_xml_document)
112
+ parent.add_child(div)
113
+ div
114
+ end
115
+
116
+ def add_fptr(parent:, id: nil, fileid:)
117
+ fptr = Ddr::Models::Structures::Fptr.build(id: id, fileid: fileid, document: as_xml_document)
118
+ parent.add_child(fptr)
119
+ fptr
120
+ end
121
+
122
+ def add_mptr(parent:, id: nil, loctype:'ARK', otherloctype: nil, href:)
123
+ mptr = Ddr::Models::Structures::Mptr.build(id: id, loctype: loctype, otherloctype: otherloctype, href: href,
124
+ document: as_xml_document)
125
+ parent.add_child(mptr)
126
+ mptr
127
+ end
128
+
129
+ private
130
+
131
+ def fileSec_node
132
+ xpath("//xmlns:fileSec").first
133
+ end
134
+
135
+ def structMap_nodes
136
+ xpath("//xmlns:structMap")
137
+ end
138
+
139
+ def structMap_node(type)
140
+ xpath("//xmlns:structMap[@TYPE='#{type}']").first
141
+ end
142
+
143
+ def metsHdr_node
144
+ xpath("//xmlns:metsHdr")
145
+ end
146
+
147
+ def file_nodes
148
+ xpath("//xmlns:file")
149
+ end
150
+
151
+ def flocat_nodes
152
+ xpath("//xmlns:FLocat")
153
+ end
154
+
155
+ def collect_files
156
+ files = {}
157
+ file_nodes.each do |file_node|
158
+ file = Ddr::Models::Structures::File.new(file_node)
159
+ files[file.id] = file
42
160
  end
161
+ files
162
+ end
43
163
 
44
- def self.template
45
- Nokogiri::XML(
46
- '<mets xmlns="http://www.loc.gov/METS/" xmlns:xlink="http://www.w3.org/1999/xlink">
47
- <structMap TYPE="default" />
48
- </mets>'
49
- ) do |config|
50
- config.noblanks
51
- end
164
+ def collect_uses
165
+ uses = {}
166
+ flocat_nodes.each do |flocat_node|
167
+ flocat = Ddr::Models::Structures::FLocat.new(flocat_node)
168
+ uses[flocat.effective_use] ||= []
169
+ uses[flocat.effective_use] << flocat
52
170
  end
171
+ uses
172
+ end
53
173
 
174
+ def self.xml_template
175
+ Nokogiri::XML(
176
+ '<mets xmlns="http://www.loc.gov/METS/" xmlns:xlink="http://www.w3.org/1999/xlink" />'
177
+ ) do |config|
178
+ config.noblanks
179
+ end
54
180
  end
181
+
55
182
  end
56
183
  end
@@ -0,0 +1,49 @@
1
+ module Ddr::Models::Structures
2
+ #
3
+ # Wraps a Nokogiri (XML) 'agent' node
4
+ #
5
+ class Agent < SimpleDelegator
6
+
7
+ ROLE_CREATOR = 'CREATOR'.freeze
8
+
9
+ NAME_REPOSITORY_DEFAULT = 'REPOSITORY DEFAULT'.freeze
10
+
11
+ def id
12
+ self['ID']
13
+ end
14
+
15
+ def role
16
+ self['ROLE']
17
+ end
18
+
19
+ def otherrole
20
+ self['OTHERROLE']
21
+ end
22
+
23
+ def type
24
+ self['TYPE']
25
+ end
26
+
27
+ def othertype
28
+ self['OTHERTYPE']
29
+ end
30
+
31
+ def name
32
+ xpath('xmlns:name').first.content
33
+ end
34
+
35
+ def self.build(args)
36
+ node = Nokogiri::XML::Node.new('agent', args[:document])
37
+ node['ID'] = args[:id] if args[:id]
38
+ node['ROLE'] = args[:role] if args[:role]
39
+ node['OTHERROLE'] = args[:otherrole] if args[:otherrole]
40
+ node['TYPE'] = args[:type] if args[:type]
41
+ node['OTHERTYPE'] = args[:othertype] if args[:othertype]
42
+ name_node = Nokogiri::XML::Node.new('name', args[:document])
43
+ name_node.content = args[:name]
44
+ node.add_child(name_node)
45
+ node
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,64 @@
1
+ module Ddr::Models::Structures
2
+ #
3
+ # Wraps a Nokogiri (XML) 'div' node
4
+ #
5
+ class Div < SimpleDelegator
6
+
7
+ def id
8
+ self['ID']
9
+ end
10
+
11
+ def label
12
+ self['LABEL']
13
+ end
14
+
15
+ def order
16
+ self['ORDER']
17
+ end
18
+
19
+ def orderlabel
20
+ self['ORDERLABEL']
21
+ end
22
+
23
+ def type
24
+ self['TYPE']
25
+ end
26
+
27
+ def divs
28
+ xpath('xmlns:div').map { |node| Div.new(node) }
29
+ end
30
+
31
+ def fptrs
32
+ xpath('xmlns:fptr').map { |node| Fptr.new(node) }
33
+ end
34
+
35
+ def mptrs
36
+ xpath('xmlns:mptr').map { |node| Mptr.new(node) }
37
+ end
38
+
39
+ def <=>(other)
40
+ order.to_i <=> other.order.to_i
41
+ end
42
+
43
+ def dereferenced_hash
44
+ contents = []
45
+ contents.concat(divs.map { |div| div.dereferenced_hash }) unless divs.empty?
46
+ contents.concat(fptrs.map { |fptr| fptr.dereferenced_hash }) unless fptrs.empty?
47
+ contents.concat(mptrs.map { |mptr| mptr.dereferenced_hash }) unless mptrs.empty?
48
+ dh = { id: id, label: label, order: order, orderlabel: orderlabel, type: type }.compact
49
+ dh[:contents] = contents unless contents.empty?
50
+ dh
51
+ end
52
+
53
+ def self.build(args)
54
+ node = Nokogiri::XML::Node.new('div', args[:document])
55
+ node['ID'] = args[:id] if args[:id]
56
+ node['LABEL'] = args[:label] if args[:label]
57
+ node['ORDER'] = args[:order] if args[:order]
58
+ node['ORDERLABEL'] = args[:orderlabel] if args[:orderlabel]
59
+ node['TYPE'] = args[:type] if args[:type]
60
+ node
61
+ end
62
+
63
+ end
64
+ end