stash-merritt 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +193 -0
  3. data/.rubocop.yml +32 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +12 -0
  6. data/Gemfile +6 -0
  7. data/Gemfile.lock +326 -0
  8. data/LICENSE.md +22 -0
  9. data/README.md +53 -0
  10. data/Rakefile +49 -0
  11. data/lib/datacite/mapping/datacite_xml_factory.rb +212 -0
  12. data/lib/stash/merritt/ezid_helper.rb +50 -0
  13. data/lib/stash/merritt/module_info.rb +12 -0
  14. data/lib/stash/merritt/repository.rb +17 -0
  15. data/lib/stash/merritt/submission_job.rb +90 -0
  16. data/lib/stash/merritt/submission_package/data_one_manifest_builder.rb +41 -0
  17. data/lib/stash/merritt/submission_package/merritt_datacite_builder.rb +22 -0
  18. data/lib/stash/merritt/submission_package/merritt_delete_builder.rb +25 -0
  19. data/lib/stash/merritt/submission_package/merritt_oaidc_builder.rb +130 -0
  20. data/lib/stash/merritt/submission_package/stash_wrapper_builder.rb +59 -0
  21. data/lib/stash/merritt/submission_package.rb +125 -0
  22. data/lib/stash/merritt/sword_helper.rb +58 -0
  23. data/lib/stash/merritt.rb +5 -0
  24. data/lib/stash.rb +5 -0
  25. data/spec/.rubocop.yml +10 -0
  26. data/spec/config/app_config.yml +3 -0
  27. data/spec/config/database.yml +7 -0
  28. data/spec/config/licenses.yml +18 -0
  29. data/spec/data/archive/mrt-datacite.xml +121 -0
  30. data/spec/data/archive/mrt-dataone-manifest.txt +32 -0
  31. data/spec/data/archive/mrt-oaidc.xml +38 -0
  32. data/spec/data/archive/stash-wrapper.xml +213 -0
  33. data/spec/data/archive.zip +0 -0
  34. data/spec/data/dc4-with-funding-references.xml +123 -0
  35. data/spec/db/datacite/mapping/datacite_xml_factory_spec.rb +56 -0
  36. data/spec/db/stash/merritt/merritt_oaidc_builder_spec.rb +72 -0
  37. data/spec/db/stash/merritt/submission_package_spec.rb +174 -0
  38. data/spec/db/stash/merritt/sword_helper_spec.rb +162 -0
  39. data/spec/db_spec_helper.rb +31 -0
  40. data/spec/rspec_custom_matchers.rb +92 -0
  41. data/spec/spec_helper.rb +86 -0
  42. data/spec/unit/stash/merritt/ezid_helper_spec.rb +88 -0
  43. data/spec/unit/stash/merritt/repository_spec.rb +19 -0
  44. data/spec/unit/stash/merritt/submission_job_spec.rb +127 -0
  45. data/spec/util/resource_builder.rb +333 -0
  46. data/stash-merritt.gemspec +48 -0
  47. data/stash-merritt.iml +147 -0
  48. data/stash-merritt.ipr +127 -0
  49. data/travis-local-deps.sh +43 -0
  50. metadata +337 -0
@@ -0,0 +1,212 @@
1
+ require 'datacite/mapping'
2
+
3
+ module Datacite
4
+ module Mapping
5
+ class DataciteXMLFactory # rubocop:disable Metrics/ClassLength
6
+ attr_reader :doi_value
7
+ attr_reader :se_resource_id
8
+ attr_reader :total_size_bytes
9
+ attr_reader :version
10
+
11
+ def initialize(doi_value:, se_resource_id:, total_size_bytes:, version:)
12
+ @doi_value = doi_value
13
+ @se_resource_id = se_resource_id
14
+ @total_size_bytes = total_size_bytes
15
+ @version = version && version.to_s
16
+ end
17
+
18
+ def build_datacite_xml(datacite_3: false)
19
+ dcs_resource = build_resource(datacite_3: datacite_3)
20
+
21
+ return dcs_resource.write_xml(mapping: :datacite_3) if datacite_3
22
+ dcs_resource.write_xml
23
+ end
24
+
25
+ def build_resource(datacite_3: false) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
26
+ pub_year = se_resource.publication_years[0] # TODO: make this has_one instead of has_many
27
+
28
+ dcs_resource = Resource.new(
29
+ identifier: Identifier.from_doi(doi_value),
30
+ creators: se_resource.creators.map do |c|
31
+ Creator.new(
32
+ name: c.creator_full_name,
33
+ identifier: to_dcs_identifier(c.name_identifier),
34
+ affiliations: c.affiliations.map(&:smart_name)
35
+ )
36
+ end,
37
+ titles: se_resource.titles.map { |t| Title.new(value: t.title, type: t.title_type_mapping_obj) },
38
+ publisher: to_dcs_publisher(se_resource.publisher),
39
+ publication_year: to_dcs_pub_year(pub_year)
40
+ )
41
+
42
+ dcs_resource.language = 'en'
43
+ dcs_resource.resource_type = to_dcs_type(se_resource.resource_type)
44
+ dcs_resource.sizes = ["#{total_size_bytes} bytes"]
45
+ dcs_resource.formats = se_resource.formats.map(&:format)
46
+ dcs_resource.version = version
47
+
48
+ add_subjects(dcs_resource)
49
+ add_contributors(dcs_resource)
50
+ add_dates(dcs_resource)
51
+ add_alt_ids(dcs_resource)
52
+ add_related_ids(dcs_resource)
53
+ add_rights(dcs_resource)
54
+ add_descriptions(dcs_resource)
55
+ add_locations(dcs_resource)
56
+ add_funding(dcs_resource, datacite_3: datacite_3)
57
+
58
+ dcs_resource
59
+ end
60
+
61
+ private
62
+
63
+ def se_resource
64
+ @se_resource ||= StashEngine::Resource.find(se_resource_id)
65
+ end
66
+
67
+ def to_dcs_type(sd_resource_type)
68
+ ResourceType.new(resource_type_general: sd_resource_type.resource_type_general_mapping_obj,
69
+ value: sd_resource_type.resource_type)
70
+ end
71
+
72
+ def add_locations(dcs_resource)
73
+ dcs_resource.geo_locations = se_resource.geolocations.map do |l|
74
+ GeoLocation.new(
75
+ place: l.datacite_mapping_place,
76
+ point: l.datacite_mapping_point,
77
+ box: l.datacite_mapping_box
78
+ )
79
+ end
80
+ end
81
+
82
+ def add_descriptions(dcs_resource)
83
+ se_resource.descriptions.where.not(description: nil).each do |d|
84
+ next if d.description.blank?
85
+ dcs_resource.descriptions << Description.new(
86
+ value: d.description,
87
+ type: d.description_type_mapping_obj
88
+ )
89
+ end
90
+ end
91
+
92
+ def add_rights(dcs_resource)
93
+ dcs_resource.rights_list = se_resource.rights.map do |r|
94
+ Rights.new(
95
+ value: r.rights,
96
+ uri: to_uri(r.rights_uri)
97
+ )
98
+ end
99
+ end
100
+
101
+ def add_related_ids(dcs_resource)
102
+ dcs_resource.related_identifiers = se_resource.related_identifiers.completed.map do |id|
103
+ RelatedIdentifier.new(
104
+ relation_type: id.relation_type_mapping_obj,
105
+ value: id.related_identifier,
106
+ identifier_type: id.related_identifier_type_mapping_obj,
107
+ related_metadata_scheme: id.related_metadata_scheme,
108
+ scheme_uri: to_uri(id.scheme_URI),
109
+ scheme_type: id.scheme_type
110
+ )
111
+ end
112
+ end
113
+
114
+ def add_alt_ids(dcs_resource)
115
+ dcs_resource.alternate_identifiers = se_resource.alternate_identifiers.map do |id|
116
+ AlternateIdentifier.new(
117
+ value: id.alternate_identifier,
118
+ type: id.alternate_identifier_type
119
+ )
120
+ end
121
+ end
122
+
123
+ def add_dates(dcs_resource)
124
+ dcs_resource.dates = se_resource.datacite_dates.where.not(date: nil).map do |d|
125
+ sd_date = d.date
126
+ Date.new(
127
+ type: d.date_type_mapping_obj,
128
+ value: sd_date
129
+ )
130
+ end
131
+ end
132
+
133
+ def add_subjects(dcs_resource)
134
+ dcs_resource.subjects = se_resource.subjects.map { |s| Subject.new(value: s.subject) }
135
+ end
136
+
137
+ def add_contributors(dcs_resource)
138
+ se_resource.contributors.completed.where.not(contributor_type: 'funder').each do |c|
139
+ dcs_resource.contributors << Contributor.new(
140
+ name: c.contributor_name,
141
+ identifier: to_dcs_identifier(c.name_identifier),
142
+ type: c.contributor_type_mapping_obj,
143
+ affiliations: c.affiliations.map(&:long_name)
144
+ )
145
+ end
146
+ end
147
+
148
+ def add_funding(dcs_resource, datacite_3: false)
149
+ datacite_3 ? add_dc3_funders(dcs_resource) : add_funding_references(dcs_resource)
150
+ end
151
+
152
+ def sd_funder_contribs
153
+ se_resource.contributors.completed.where(contributor_type: 'funder')
154
+ end
155
+
156
+ def add_dc3_funders(dcs_resource)
157
+ sd_funder_contribs.each do |contrib|
158
+ dcs_resource.descriptions << to_funding_desc(contrib)
159
+ dcs_resource.contributors << to_dcs_funder(contrib)
160
+ end
161
+ end
162
+
163
+ def add_funding_references(dcs_resource)
164
+ dcs_resource.funding_references = sd_funder_contribs.map do |c|
165
+ FundingReference.new(
166
+ name: c.contributor_name,
167
+ award_number: c.award_number
168
+ )
169
+ end
170
+ end
171
+
172
+ def to_dcs_funder(contrib)
173
+ Contributor.new(
174
+ name: contrib.contributor_name,
175
+ identifier: to_dcs_identifier(contrib.name_identifier),
176
+ type: ContributorType::FUNDER
177
+ )
178
+ end
179
+
180
+ def to_funding_desc(contrib)
181
+ award_num = contrib.award_number
182
+ desc_text = "Data were created with funding from #{contrib.contributor_name}"
183
+ desc_text << " under grant(s) #{award_num}." if award_num
184
+ Description.new(type: DescriptionType::OTHER, value: desc_text)
185
+ end
186
+
187
+ def to_dcs_identifier(sd_name_ident)
188
+ return unless sd_name_ident
189
+ sd_scheme_uri = sd_name_ident.scheme_URI
190
+ NameIdentifier.new(
191
+ scheme: sd_name_ident.name_identifier_scheme,
192
+ scheme_uri: sd_scheme_uri && to_uri(sd_scheme_uri),
193
+ value: sd_name_ident.name_identifier
194
+ )
195
+ end
196
+
197
+ def to_dcs_publisher(sd_publisher)
198
+ return 'unknown' unless sd_publisher
199
+ sd_publisher.publisher
200
+ end
201
+
202
+ def to_dcs_pub_year(sd_pub_year)
203
+ return ::Date.today.year unless sd_pub_year
204
+ sd_pub_year.publication_year
205
+ end
206
+
207
+ def to_uri(uri_or_str)
208
+ ::XML::MappingExtensions.to_uri(uri_or_str)
209
+ end
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,50 @@
1
+ require 'stash_ezid/client'
2
+
3
+ module Stash
4
+ module Merritt
5
+ class EzidHelper
6
+ attr_reader :resource
7
+ attr_reader :url_helpers
8
+
9
+ def initialize(resource:, url_helpers:)
10
+ @resource = resource
11
+ @url_helpers = url_helpers
12
+ end
13
+
14
+ # @return [String] the identifier (DOI, ARK, or URN)
15
+ def ensure_identifier
16
+ identifier_str = resource.identifier_str
17
+ return identifier_str if identifier_str
18
+
19
+ new_identifier_str = ezid_client.mint_id
20
+ resource.ensure_identifier(new_identifier_str)
21
+ new_identifier_str
22
+ end
23
+
24
+ def update_metadata(dc3_xml:)
25
+ identifier_str = resource.identifier_str
26
+ landing_page_url = url_helpers.show_path(identifier_str)
27
+ ezid_client.update_metadata(identifier_str, dc3_xml, landing_page_url)
28
+ end
29
+
30
+ private
31
+
32
+ def tenant
33
+ resource.tenant
34
+ end
35
+
36
+ def ezid_client
37
+ @ezid_client ||= begin
38
+ id_params = tenant.identifier_service
39
+ StashEzid::Client.new(
40
+ shoulder: id_params.shoulder,
41
+ account: id_params.account,
42
+ password: id_params.password,
43
+ owner: id_params.owner,
44
+ id_scheme: id_params.scheme
45
+ )
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,12 @@
1
+ module Stash
2
+ module Merritt
3
+ # The name of this gem
4
+ NAME = 'stash-merritt'.freeze
5
+
6
+ # The version of this gem
7
+ VERSION = '0.0.1'.freeze
8
+
9
+ # The copyright notice for this gem
10
+ COPYRIGHT = 'Copyright (c) 2017 The Regents of the University of California'.freeze
11
+ end
12
+ end
@@ -0,0 +1,17 @@
1
+ require 'stash/repo'
2
+ require 'stash/merritt/submission_job'
3
+
4
+ module Stash
5
+ module Merritt
6
+ class Repository < Stash::Repo::Repository
7
+
8
+ def initialize(url_helpers:)
9
+ super
10
+ end
11
+
12
+ def create_submission_job(resource_id:)
13
+ SubmissionJob.new(resource_id: resource_id, url_helpers: url_helpers)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,90 @@
1
+ require 'stash/repo'
2
+ require 'stash/merritt/ezid_helper'
3
+ require 'stash/merritt/submission_package'
4
+ require 'stash/merritt/sword_helper'
5
+
6
+ module Stash
7
+ module Merritt
8
+ class SubmissionJob < Stash::Repo::SubmissionJob
9
+ attr_reader :resource_id
10
+ attr_reader :url_helpers
11
+
12
+ def initialize(resource_id:, url_helpers:)
13
+ @resource_id = resource_id
14
+ @url_helpers = url_helpers
15
+ end
16
+
17
+ def submit!
18
+ log.info("#{Time.now.xmlschema} #{description}")
19
+ do_submit!
20
+ rescue => e
21
+ Stash::Repo::SubmissionResult.failure(resource_id: resource_id, request_desc: description, error: e)
22
+ end
23
+
24
+ def description
25
+ @description ||= begin
26
+ resource = StashEngine::Resource.find(resource_id)
27
+ description_for(resource)
28
+ rescue => e
29
+ log.error("Can't find resource #{resource_id}: #{e}\n#{e.backtrace.join("\n")}")
30
+ "#{self.class} for missing resource #{resource_id}"
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def do_submit!
37
+ package = create_package
38
+ submit(package)
39
+ update_metadata(package.dc3_xml)
40
+ cleanup(package)
41
+ Stash::Repo::SubmissionResult.success(resource_id: resource_id, request_desc: description, message: 'Success')
42
+ end
43
+
44
+ def resource
45
+ @resource ||= StashEngine::Resource.find(resource_id)
46
+ end
47
+
48
+ def ezid_helper
49
+ @ezid_helper ||= EzidHelper.new(resource: resource, url_helpers: url_helpers)
50
+ end
51
+
52
+ def ensure_identifier
53
+ log.info("#{Time.now.xmlschema} #{self.class}: ensuring identifier for resource #{resource_id} (#{resource.identifier_str})")
54
+ ezid_helper.ensure_identifier
55
+ end
56
+
57
+ def create_package
58
+ ensure_identifier
59
+ log.info("#{Time.now.xmlschema} #{self.class}: creating package for resource #{resource_id} (#{resource.identifier_str})")
60
+ SubmissionPackage.new(resource: resource)
61
+ end
62
+
63
+ def submit(package)
64
+ log.info("#{Time.now.xmlschema} #{self.class}: submitting resource #{resource_id} (#{resource.identifier_str})")
65
+ sword_helper = SwordHelper.new(package: package, logger: log)
66
+ sword_helper.submit!
67
+ end
68
+
69
+ def update_metadata(dc3_xml)
70
+ log.info("#{Time.now.xmlschema} #{self.class}: updating identifier metadata for resource #{resource_id} (#{resource.identifier_str})")
71
+ ezid_helper.update_metadata(dc3_xml: dc3_xml)
72
+ end
73
+
74
+ def cleanup(package)
75
+ log.info("#{Time.now.xmlschema} #{self.class}: cleaning up temporary files for resource #{resource_id} (#{resource.identifier_str})")
76
+ package.cleanup!
77
+ end
78
+
79
+ def description_for(resource)
80
+ msg = "#{self.class} for resource #{resource_id} (#{resource.identifier_str}): "
81
+ msg << if (update_uri = resource.update_uri)
82
+ "posting update to #{update_uri}"
83
+ else
84
+ "posting new object to #{resource.tenant.sword_params[:collection_uri]}"
85
+ end
86
+ msg << " (tenant: #{resource.tenant_id})"
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,41 @@
1
+ require 'stash/repo/file_builder'
2
+
3
+ module Stash
4
+ module Merritt
5
+ class SubmissionPackage
6
+ class DataONEManifestBuilder < Stash::Repo::FileBuilder
7
+ HEADER = [
8
+ '#%dataonem_0.1',
9
+ '#%profile | http://uc3.cdlib.org/registry/ingest/manifest/mrt-dataone-manifest',
10
+ '#%prefix | dom: | http://uc3.cdlib.org/ontology/dataonem',
11
+ '#%prefix | mrt: | http://uc3.cdlib.org/ontology/mom',
12
+ '#%fields | dom:scienceMetadataFile | dom:scienceMetadataFormat | dom:scienceDataFile | mrt:mimeType'
13
+ ].join("\n").freeze
14
+
15
+ METADATA_FILES = {
16
+ 'mrt-datacite.xml' => 'http://datacite.org/schema/kernel-3.1',
17
+ 'mrt-oaidc.xml' => 'http://dublincore.org/schemas/xmls/qdc/2008/02/11/qualifieddc.xsd'
18
+ }.freeze
19
+
20
+ attr_reader :uploads
21
+
22
+ # @param uploads [Array[StashEngine::FileUpload]] a list of file uploads
23
+ def initialize(uploads)
24
+ super(file_name: 'mrt-dataone-manifest.txt')
25
+ @uploads = uploads
26
+ end
27
+
28
+ def contents
29
+ content = [HEADER]
30
+ uploads.each do |upload|
31
+ METADATA_FILES.each do |md_filename, md_schema|
32
+ content << "#{md_filename} | #{md_schema} | #{upload.upload_file_name} | #{upload.upload_content_type}"
33
+ end
34
+ end
35
+ content << "#%eof\n"
36
+ content.join("\n")
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,22 @@
1
+ require 'datacite/mapping/datacite_xml_factory'
2
+ require 'stash/repo/file_builder'
3
+
4
+ module Stash
5
+ module Merritt
6
+ class SubmissionPackage
7
+ class MerrittDataciteBuilder < Stash::Repo::FileBuilder
8
+ attr_reader :factory
9
+
10
+ # @param factory [DataciteXMLFactory] the Datacite XML factory
11
+ def initialize(factory)
12
+ super(file_name: 'mrt-datacite.xml')
13
+ @factory = factory
14
+ end
15
+
16
+ def contents
17
+ factory.build_datacite_xml(datacite_3: true)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,25 @@
1
+ require 'stash/repo/file_builder'
2
+
3
+ module Stash
4
+ module Merritt
5
+ class SubmissionPackage
6
+ class MerrittDeleteBuilder < Stash::Repo::FileBuilder
7
+ attr_reader :resource_id
8
+
9
+ def initialize(resource_id:)
10
+ super(file_name: 'mrt-delete.txt')
11
+ @resource_id = resource_id
12
+ end
13
+
14
+ def resource
15
+ @resource ||= StashEngine::Resource.find(resource_id)
16
+ end
17
+
18
+ def contents
19
+ del_files = resource.file_uploads.deleted
20
+ del_files.blank? ? nil : del_files.map(&:upload_file_name).join("\n")
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,130 @@
1
+ require 'stash/repo/file_builder'
2
+
3
+ module Stash
4
+ module Merritt
5
+ class SubmissionPackage
6
+ class MerrittOAIDCBuilder < Stash::Repo::FileBuilder
7
+ ROOT_ATTRIBUTES = {
8
+ 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
9
+ 'xsi:noNamespaceSchemaLocation' => 'http://dublincore.org/schemas/xmls/qdc/2008/02/11/qualifieddc.xsd',
10
+ 'xmlns:dc' => 'http://purl.org/dc/elements/1.1/',
11
+ 'xmlns:dcterms' => 'http://purl.org/dc/terms/'
12
+ }.freeze
13
+
14
+ DC_RELATION_TYPES = {
15
+ 'cites' => 'references',
16
+ 'iscitedby' => 'isReferencedBy',
17
+ 'isnewversionof' => 'isVersionOf',
18
+ 'ispreviousversionof' => 'hasVersion',
19
+ 'ispartof' => 'isPartOf',
20
+ 'haspart' => 'hasPart'
21
+ }.freeze
22
+
23
+ attr_reader :resource_id
24
+
25
+ def initialize(resource_id:)
26
+ super(file_name: 'mrt-oaidc.xml')
27
+ @resource_id = resource_id
28
+ end
29
+
30
+ def contents # rubocop:disable Metrics/MethodLength
31
+ Nokogiri::XML::Builder.new do |xml|
32
+ xml.qualifieddc(ROOT_ATTRIBUTES) do
33
+ add_creators(xml)
34
+ add_contributors(xml)
35
+ add_title(xml)
36
+ add_publisher(xml)
37
+ add_pub_year(xml)
38
+ add_subjects(xml)
39
+ add_resource_type(xml)
40
+ add_rights(xml)
41
+ add_descriptions(xml)
42
+ add_related_identifiers(xml)
43
+ end
44
+ end.to_xml.to_s
45
+ end
46
+
47
+ private
48
+
49
+ def resource
50
+ @resource ||= StashEngine::Resource.find(resource_id)
51
+ end
52
+
53
+ def tenant
54
+ resource.tenant
55
+ end
56
+
57
+ def add_creators(xml)
58
+ resource.creators.each { |c| xml.send(:'dc:creator', c.creator_full_name.delete("\r").to_s) }
59
+ end
60
+
61
+ def add_pub_year(xml)
62
+ pub_year = resource.publication_years.first
63
+ xml.send(:'dc:date', pub_year.publication_year) if pub_year
64
+ end
65
+
66
+ def add_publisher(xml)
67
+ xml.send(:'dc:publisher', (tenant.short_name || tenant.long_name || 'unknown').to_s)
68
+ end
69
+
70
+ def add_title(xml)
71
+ xml.send(:'dc:title', resource.titles.where(title_type: nil).first.title.to_s)
72
+ end
73
+
74
+ def add_contributors(xml)
75
+ # Funder contributors are handled under 'add_descriptions' below
76
+ resource.contributors.where.not(contributor_type: 'funder').each do |c|
77
+ if (contrib_name = c.contributor_name) && !contrib_name.blank?
78
+ xml.send(:'dc:contributor', contrib_name.strip)
79
+ end
80
+ end
81
+ end
82
+
83
+ def add_subjects(xml)
84
+ resource.subjects.each { |s| xml.send(:'dc:subject', s.subject.delete("\r").to_s) }
85
+ end
86
+
87
+ def add_resource_type(xml)
88
+ resource_type = (rt = resource.resource_type) && rt.resource_type_general
89
+ xml.send(:'dc:type', resource_type.strip) unless resource_type.blank?
90
+ end
91
+
92
+ def add_rights(xml)
93
+ resource.rights.each do |r|
94
+ xml.send(:'dc:rights', r.rights.to_s)
95
+ xml.send(:'dcterms:license', r.rights_uri.to_s, 'xsi:type' => 'dcterms:URI')
96
+ end
97
+ end
98
+
99
+ def add_descriptions(xml)
100
+ strip_desc_linefeeds(xml)
101
+ resource.contributors.where(contributor_type: 'funder').each do |c|
102
+ xml.send(:'dc:description', to_dc_description(c))
103
+ end
104
+ end
105
+
106
+ def to_dc_description(contributor)
107
+ contrib_name = contributor.contributor_name
108
+ award_num = contributor.award_number
109
+ desc_text = 'Data were created'
110
+ desc_text << " with funding from #{contrib_name}" unless contrib_name.blank?
111
+ desc_text << " under grant(s) #{award_num}" unless award_num.blank?
112
+ end
113
+
114
+ def strip_desc_linefeeds(xml)
115
+ resource.descriptions.each do |d|
116
+ desc_text = d.description.to_s.delete("\r")
117
+ xml.send(:'dc:description', desc_text.to_s) unless desc_text.blank?
118
+ end
119
+ end
120
+
121
+ def add_related_identifiers(xml)
122
+ resource.related_identifiers.each do |r|
123
+ dc_relation_type = DC_RELATION_TYPES[r.relation_type] || 'relation'
124
+ xml.send(:"dcterms:#{dc_relation_type}", "#{r.related_identifier_type_friendly}: #{r.related_identifier}")
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,59 @@
1
+ require 'stash/wrapper'
2
+ require 'stash/repo/file_builder'
3
+
4
+ module Stash
5
+ module Merritt
6
+ class SubmissionPackage
7
+ class StashWrapperBuilder < Stash::Repo::FileBuilder
8
+ include Stash::Wrapper
9
+ attr_reader :dcs_resource
10
+ attr_reader :uploads
11
+ attr_reader :version_number
12
+
13
+ def initialize(dcs_resource:, version_number:, uploads:)
14
+ super(file_name: 'stash-wrapper.xml')
15
+ @dcs_resource = dcs_resource
16
+ @version_number = version_number
17
+ @uploads = uploads
18
+ end
19
+
20
+ def contents
21
+ StashWrapper.new(
22
+ identifier: to_sw_identifier(dcs_resource.identifier),
23
+ version: Version.new(number: version_number, date: Date.today),
24
+ license: to_sw_license(dcs_resource.rights_list),
25
+ inventory: to_sw_inventory(uploads),
26
+ descriptive_elements: [dcs_resource.save_to_xml]
27
+ ).write_xml
28
+ end
29
+
30
+ private
31
+
32
+ def to_sw_identifier(dcs_identifier)
33
+ return unless dcs_identifier
34
+ raise "Invalid identifier type; expected DOI, was #{dcs_identifier.identifier_type}" unless dcs_identifier.identifier_type == 'DOI'
35
+ Identifier.new(type: IdentifierType::DOI, value: dcs_identifier.value)
36
+ end
37
+
38
+ def to_sw_license(dcs_rights_list)
39
+ return unless dcs_rights_list && !dcs_rights_list.empty?
40
+ dcs_rights = dcs_rights_list[0]
41
+ License.new(name: dcs_rights.value, uri: dcs_rights.uri)
42
+ end
43
+
44
+ def to_sw_inventory(uploads)
45
+ return unless uploads
46
+ Inventory.new(files: uploads.map { |upload| to_stash_file(upload) })
47
+ end
48
+
49
+ def to_stash_file(upload)
50
+ StashFile.new(
51
+ pathname: upload.upload_file_name,
52
+ size_bytes: upload.upload_file_size,
53
+ mime_type: upload.upload_content_type
54
+ )
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end