stash-merritt 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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