stash-merritt 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +193 -0
- data/.rubocop.yml +32 -0
- data/.ruby-version +1 -0
- data/.travis.yml +12 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +326 -0
- data/LICENSE.md +22 -0
- data/README.md +53 -0
- data/Rakefile +49 -0
- data/lib/datacite/mapping/datacite_xml_factory.rb +212 -0
- data/lib/stash/merritt/ezid_helper.rb +50 -0
- data/lib/stash/merritt/module_info.rb +12 -0
- data/lib/stash/merritt/repository.rb +17 -0
- data/lib/stash/merritt/submission_job.rb +90 -0
- data/lib/stash/merritt/submission_package/data_one_manifest_builder.rb +41 -0
- data/lib/stash/merritt/submission_package/merritt_datacite_builder.rb +22 -0
- data/lib/stash/merritt/submission_package/merritt_delete_builder.rb +25 -0
- data/lib/stash/merritt/submission_package/merritt_oaidc_builder.rb +130 -0
- data/lib/stash/merritt/submission_package/stash_wrapper_builder.rb +59 -0
- data/lib/stash/merritt/submission_package.rb +125 -0
- data/lib/stash/merritt/sword_helper.rb +58 -0
- data/lib/stash/merritt.rb +5 -0
- data/lib/stash.rb +5 -0
- data/spec/.rubocop.yml +10 -0
- data/spec/config/app_config.yml +3 -0
- data/spec/config/database.yml +7 -0
- data/spec/config/licenses.yml +18 -0
- data/spec/data/archive/mrt-datacite.xml +121 -0
- data/spec/data/archive/mrt-dataone-manifest.txt +32 -0
- data/spec/data/archive/mrt-oaidc.xml +38 -0
- data/spec/data/archive/stash-wrapper.xml +213 -0
- data/spec/data/archive.zip +0 -0
- data/spec/data/dc4-with-funding-references.xml +123 -0
- data/spec/db/datacite/mapping/datacite_xml_factory_spec.rb +56 -0
- data/spec/db/stash/merritt/merritt_oaidc_builder_spec.rb +72 -0
- data/spec/db/stash/merritt/submission_package_spec.rb +174 -0
- data/spec/db/stash/merritt/sword_helper_spec.rb +162 -0
- data/spec/db_spec_helper.rb +31 -0
- data/spec/rspec_custom_matchers.rb +92 -0
- data/spec/spec_helper.rb +86 -0
- data/spec/unit/stash/merritt/ezid_helper_spec.rb +88 -0
- data/spec/unit/stash/merritt/repository_spec.rb +19 -0
- data/spec/unit/stash/merritt/submission_job_spec.rb +127 -0
- data/spec/util/resource_builder.rb +333 -0
- data/stash-merritt.gemspec +48 -0
- data/stash-merritt.iml +147 -0
- data/stash-merritt.ipr +127 -0
- data/travis-local-deps.sh +43 -0
- 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
|