zizia 1.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 +15 -0
- data/.rubocop.yml +65 -0
- data/.rubocop_todo.yml +21 -0
- data/.solr_wrapper +8 -0
- data/.travis.yml +11 -0
- data/Gemfile +12 -0
- data/README.md +77 -0
- data/Rakefile +34 -0
- data/docs/_config.yml +1 -0
- data/docs/index.md +98 -0
- data/lib/zizia/always_invalid_validator.rb +17 -0
- data/lib/zizia/hash_mapper.rb +44 -0
- data/lib/zizia/hyrax_basic_metadata_mapper.rb +149 -0
- data/lib/zizia/hyrax_record_importer.rb +261 -0
- data/lib/zizia/importer.rb +61 -0
- data/lib/zizia/input_record.rb +65 -0
- data/lib/zizia/log_stream.rb +43 -0
- data/lib/zizia/metadata_mapper.rb +83 -0
- data/lib/zizia/metadata_only_stack.rb +70 -0
- data/lib/zizia/parser.rb +132 -0
- data/lib/zizia/parsers/csv_parser.rb +45 -0
- data/lib/zizia/record_importer.rb +57 -0
- data/lib/zizia/spec/fakes/fake_parser.rb +22 -0
- data/lib/zizia/spec/shared_examples/a_mapper.rb +32 -0
- data/lib/zizia/spec/shared_examples/a_message_stream.rb +11 -0
- data/lib/zizia/spec/shared_examples/a_parser.rb +73 -0
- data/lib/zizia/spec/shared_examples/a_validator.rb +46 -0
- data/lib/zizia/spec.rb +15 -0
- data/lib/zizia/streams/formatted_message_stream.rb +70 -0
- data/lib/zizia/validator.rb +117 -0
- data/lib/zizia/validators/csv_format_validator.rb +26 -0
- data/lib/zizia/validators/title_validator.rb +30 -0
- data/lib/zizia/version.rb +5 -0
- data/lib/zizia.rb +73 -0
- data/log/.keep +0 -0
- data/spec/fixtures/bad_example.csv +2 -0
- data/spec/fixtures/example.csv +4 -0
- data/spec/fixtures/hyrax/example.csv +3 -0
- data/spec/fixtures/images/animals/cat.png +0 -0
- data/spec/fixtures/images/zizia.png +0 -0
- data/spec/fixtures/zizia.png +0 -0
- data/spec/integration/import_csv_spec.rb +28 -0
- data/spec/integration/import_hyrax_csv.rb +71 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/stdout_stream_spec.rb +9 -0
- data/spec/support/hyrax/basic_metadata.rb +30 -0
- data/spec/support/hyrax/core_metadata.rb +15 -0
- data/spec/support/shared_contexts/with_work_type.rb +101 -0
- data/spec/zizia/csv_format_validator_spec.rb +38 -0
- data/spec/zizia/csv_parser_spec.rb +73 -0
- data/spec/zizia/formatted_message_stream_spec.rb +35 -0
- data/spec/zizia/hash_mapper_spec.rb +8 -0
- data/spec/zizia/hyrax_basic_metadata_mapper_spec.rb +190 -0
- data/spec/zizia/hyrax_record_importer_spec.rb +178 -0
- data/spec/zizia/importer_spec.rb +46 -0
- data/spec/zizia/input_record_spec.rb +71 -0
- data/spec/zizia/parser_spec.rb +47 -0
- data/spec/zizia/record_importer_spec.rb +70 -0
- data/spec/zizia/title_validator_spec.rb +23 -0
- data/spec/zizia/validator_spec.rb +9 -0
- data/spec/zizia/version_spec.rb +7 -0
- data/spec/zizia_spec.rb +19 -0
- data/zizia.gemspec +34 -0
- metadata +246 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 488d9a3f2c71f53ed2134084ed2c9acb446b1eae14f4ce9c0a8959557297a733
|
4
|
+
data.tar.gz: c4bc95f1c51e4f619329ad287cdbe15234501bdf0695d8beb42f0d9c99355339
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5e53b4a49325cab2f77a6fd714e73b9de8c269fff9960daf211897ecad7cd40c81d75ad92ef68a8d8d7bf6bf822b1044e4969888c887bb7e21d4b8198ab2d4e0
|
7
|
+
data.tar.gz: 010b019094941db98acbe9bfd2a92df88f150a45d9cd1de23337dcf74b0525c4f1430715a9c0a87a01dea9b8bf5bc3dac714fb9be4df7fca64ab1e8161fe84d7
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
inherit_from: .rubocop_todo.yml
|
2
|
+
|
3
|
+
inherit_gem:
|
4
|
+
bixby: bixby_default.yml
|
5
|
+
|
6
|
+
AllCops:
|
7
|
+
TargetRubyVersion: 2.3
|
8
|
+
|
9
|
+
Lint/HandleExceptions:
|
10
|
+
Exclude:
|
11
|
+
- 'spec/**/*'
|
12
|
+
- 'lib/zizia/spec/**/*'
|
13
|
+
|
14
|
+
Metrics/AbcSize:
|
15
|
+
Exclude:
|
16
|
+
- 'spec/support/hyrax/basic_metadata.rb'
|
17
|
+
- 'lib/zizia/hyrax_record_importer.rb'
|
18
|
+
|
19
|
+
Metrics/BlockLength:
|
20
|
+
Exclude:
|
21
|
+
- 'spec/**/*'
|
22
|
+
- 'lib/zizia/spec/**/*'
|
23
|
+
|
24
|
+
Metrics/ClassLength:
|
25
|
+
Enabled: false
|
26
|
+
|
27
|
+
Metrics/CyclomaticComplexity:
|
28
|
+
Exclude:
|
29
|
+
- lib/zizia/hyrax_basic_metadata_mapper.rb
|
30
|
+
- lib/zizia/hyrax_record_importer.rb
|
31
|
+
|
32
|
+
Metrics/LineLength:
|
33
|
+
Enabled: false
|
34
|
+
|
35
|
+
Metrics/MethodLength:
|
36
|
+
Exclude:
|
37
|
+
- 'spec/support/hyrax/basic_metadata.rb'
|
38
|
+
- 'lib/zizia/hyrax_basic_metadata_mapper.rb'
|
39
|
+
- lib/zizia/hyrax_record_importer.rb
|
40
|
+
|
41
|
+
Metrics/PerceivedComplexity:
|
42
|
+
Exclude:
|
43
|
+
- lib/zizia/hyrax_record_importer.rb
|
44
|
+
|
45
|
+
Naming/AccessorMethodName:
|
46
|
+
Exclude:
|
47
|
+
- lib/zizia/hyrax_record_importer.rb
|
48
|
+
|
49
|
+
RSpec/DescribeClass:
|
50
|
+
Exclude:
|
51
|
+
- 'spec/integration/**/*'
|
52
|
+
- 'spec/*_spec.rb'
|
53
|
+
|
54
|
+
RSpec/ExampleLength:
|
55
|
+
Exclude:
|
56
|
+
- 'spec/zizia/hyrax_basic_metadata_mapper_spec.rb'
|
57
|
+
- 'spec/integration/import_hyrax_csv.rb'
|
58
|
+
|
59
|
+
RSpec/MultipleExpectations:
|
60
|
+
Exclude:
|
61
|
+
- 'spec/zizia/hyrax_basic_metadata_mapper_spec.rb'
|
62
|
+
- 'spec/integration/import_hyrax_csv.rb'
|
63
|
+
|
64
|
+
Style/StructInheritance:
|
65
|
+
Enabled: false
|
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config`
|
3
|
+
# on 2019-02-21 09:32:03 -0500 using RuboCop version 0.52.1.
|
4
|
+
# The point is for the user to remove these configuration records
|
5
|
+
# one by one as the offenses are removed from the code base.
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
8
|
+
|
9
|
+
# Offense count: 1
|
10
|
+
Metrics/CyclomaticComplexity:
|
11
|
+
Max: 7
|
12
|
+
|
13
|
+
# Offense count: 1
|
14
|
+
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
|
15
|
+
# URISchemes: http, https
|
16
|
+
Metrics/LineLength:
|
17
|
+
Max: 228
|
18
|
+
|
19
|
+
# Offense count: 1
|
20
|
+
Metrics/PerceivedComplexity:
|
21
|
+
Max: 8
|
data/.solr_wrapper
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
# Zizia
|
2
|
+
|
3
|
+
<table width="100%">
|
4
|
+
<tr><td>
|
5
|
+
<img alt="Zizia image" src="https://camo.githubusercontent.com/87eafa4a5b6a84802eab583e532bb33881b8a7ab/68747470733a2f2f7777772e706572766572646f6e6b2e636f6d2f77696c64253230666c6f776572732f506172736e69702f476f6c64656e253230416c6578616e646572732f323030383038253230476f6c64656e253230416c6578616e646572253230285a697a69612532306175726561292532302d2532304e47532532302d253230746865253230426f6f6b2532306f6625323057696c64253230466c6f776572732e6a7067" width="500px">
|
6
|
+
</td><td>
|
7
|
+
Object import for Hyrax. See the <a href="https://www.rubydoc.info/gems/zizia">API documentation</a> for more
|
8
|
+
information. See the <a href="https://curationexperts.github.io/zizia/">Getting Started</a> guide for a gentle introduction.
|
9
|
+
<br/><br/>
|
10
|
+
|
11
|
+
|
12
|
+
[![Gem Version](https://badge.fury.io/rb/zizia.svg)](https://badge.fury.io/rb/zizia)
|
13
|
+
[![Build Status](https://travis-ci.org/curationexperts/zizia.svg?branch=master)](https://travis-ci.org/curationexperts/zizia)
|
14
|
+
[![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://www.rubydoc.info/gems/zizia)
|
15
|
+
|
16
|
+
</td></tr>
|
17
|
+
</table>
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
In your project's `Gemfile`, add: `gem 'zizia'`, then run `bundle install`.
|
22
|
+
|
23
|
+
To do a basic Hyrax import, first ensure that a [work type is registered](http://www.rubydoc.info/github/samvera/hyrax/Hyrax/Configuration#register_curation_concern-instance_method)
|
24
|
+
with your `Hyrax` application. Then write a class like this:
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
require 'zizia'
|
28
|
+
|
29
|
+
class MyImporter
|
30
|
+
def initialize(csv_file)
|
31
|
+
@csv_file = csv_file
|
32
|
+
raise "Cannot find expected input file #{csv_file}" unless File.exist?(csv_file)
|
33
|
+
end
|
34
|
+
|
35
|
+
def import
|
36
|
+
attrs = {
|
37
|
+
collection_id: collection_id, # pass a collection id to the record importer and all records will be added to that collection
|
38
|
+
depositor_id: depositor_id, # pass a Hyrax user_key here and that Hyrax user will own all objects created during this import
|
39
|
+
deduplication_field: 'identifier' # pass a field with a persistent identifier (e.g., ARK) and it will check to see if a record with that identifier already
|
40
|
+
} # exists, update its metadata if so, and only if it doesn't find a record with that identifier will it make a new object.
|
41
|
+
|
42
|
+
file = File.open(@csv_file)
|
43
|
+
parser = Zizia::CsvParser.new(file: file)
|
44
|
+
record_importer = Zizia::HyraxRecordImporter.new(attributes: attrs)
|
45
|
+
Zizia::Importer.new(parser: parser, record_importer: record_importer).import
|
46
|
+
file.close # unless a block is passed to File.open, the file must be explicitly closed
|
47
|
+
end
|
48
|
+
end
|
49
|
+
```
|
50
|
+
|
51
|
+
You can find [an example csv file for import to Hyrax](https://github.com/curationexperts/zizia/blob/master/spec/fixtures/hyrax/example.csv) in the fixtures directory. Files for attachment should have the filename in a column
|
52
|
+
with a heading of `files`, and the location of the files should be specified via an
|
53
|
+
environment variables called `IMPORT_PATH`. If `IMPORT_PATH` is not set, `HyraxRecordImporter` will look in `/opt/data` by default.
|
54
|
+
|
55
|
+
## Customizing
|
56
|
+
To input any kind of file other than CSV, you need to provide a `Parser` (out of the box, we support simple CSV import with `CsvParser`). We will be writing guides about
|
57
|
+
how to support custom mappers (for metadata outside of Hyrax's core and basic metadata fields).
|
58
|
+
|
59
|
+
This software is primarily intended for use in a [Hyrax](https://github.com/samvera/hyrax) project.
|
60
|
+
However, its dependency on `hyrax` is kept strictly optional so most of its code can be reused to
|
61
|
+
good effect elsewhere. Note: As of release 2.0, `HyraxBasicMetadataMapper` will be the default mapper.
|
62
|
+
|
63
|
+
## Development
|
64
|
+
|
65
|
+
```sh
|
66
|
+
git clone https://github.com/curationexperts/zizia
|
67
|
+
cd zizia
|
68
|
+
|
69
|
+
bundle install
|
70
|
+
bundle exec rake ci
|
71
|
+
```
|
72
|
+
|
73
|
+
### RSpec Support
|
74
|
+
|
75
|
+
This gem ships with RSpec shared examples and other support tools intended to ease testing and ensure
|
76
|
+
interoperability of client code. These can be included by adding `require 'zizia/spec'` to a
|
77
|
+
`spec_helper.rb` or `rails_helper.rb` file in your application's test suite.
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'bundler/setup'
|
5
|
+
rescue LoadError
|
6
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'fcrepo_wrapper'
|
10
|
+
require 'solr_wrapper'
|
11
|
+
require 'active_fedora/rake_support'
|
12
|
+
|
13
|
+
require 'rspec/core/rake_task'
|
14
|
+
require 'rubocop/rake_task'
|
15
|
+
|
16
|
+
Bundler::GemHelper.install_tasks
|
17
|
+
|
18
|
+
desc 'Run style checker'
|
19
|
+
RuboCop::RakeTask.new(:rubocop) do |task|
|
20
|
+
task.fail_on_error = true
|
21
|
+
end
|
22
|
+
|
23
|
+
desc 'Run specs'
|
24
|
+
RSpec::Core::RakeTask.new(:spec)
|
25
|
+
|
26
|
+
desc 'Run specs with Fedora & Solr servers'
|
27
|
+
task :spec_with_server do
|
28
|
+
with_test_server { Rake::Task['spec'].invoke }
|
29
|
+
end
|
30
|
+
|
31
|
+
desc 'Check style and run specs'
|
32
|
+
task ci: %w[rubocop spec_with_server]
|
33
|
+
|
34
|
+
task default: :ci
|
data/docs/_config.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
theme: jekyll-theme-minimal
|
data/docs/index.md
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
# Importing to Hyrax with Zizia
|
2
|
+
|
3
|
+
## Getting Started
|
4
|
+
The simplest use case is importing content that matches [Hyrax's core and basic metadata fields](http://samvera.github.io/metadata_application_profile.html), plus a few extra fields that let Hyrax know how to display the content properly. At a very high level we're going to:
|
5
|
+
1. Write a simple import test first
|
6
|
+
1. Get the test passing
|
7
|
+
1. Write a rake task to run your import with real data
|
8
|
+
|
9
|
+
**Note:** This guide assumes that you already have a working Hyrax instance with at least one work type. If you need help doing that, see [the Hyrax documentation](https://github.com/samvera/hyrax#creating-a-hyrax-based-app). This guide is going to assume we're using an `Image` work type and attaching image files, but should be applicable to any work type or kind of attachment.
|
10
|
+
|
11
|
+
### 1. Write a simple import test
|
12
|
+
1. Make a directory for your importer: `mkdir app/importers`
|
13
|
+
1. Make a directory for your importer tests: `mkdir spec/importers`
|
14
|
+
1. Make a directory for your fixture files: `mkdir spec/fixtures/images`
|
15
|
+
1. Put three small images in `spec/fixtures/images` In this guide, we're using copyright free images from https://www.pexels.com/, `birds.jpg`, `cat.jpg`, and `dog.jpg`.
|
16
|
+
1. Make a directory for your CSV fixture files: `mkdir spec/fixtures/csv_import`
|
17
|
+
1. Put a file like this in `spec/fixtures/csv_import`:
|
18
|
+
```
|
19
|
+
title,source,visibility
|
20
|
+
"A Cute Dog",https://www.pexels.com/photo/animal-blur-canine-close-up-551628/,open
|
21
|
+
"An Interesting Cat",https://www.pexels.com/photo/person-holding-white-cat-1383397/,open
|
22
|
+
"A Flock of Birds",https://www.pexels.com/photo/animal-avian-beak-birds-203088/,open
|
23
|
+
```
|
24
|
+
1. Make a file called `spec/importers/modular_importer_spec.rb` that contains this:
|
25
|
+
```ruby
|
26
|
+
# frozen_string_literal: true
|
27
|
+
|
28
|
+
require 'rails_helper'
|
29
|
+
require 'active_fedora/cleaner'
|
30
|
+
|
31
|
+
RSpec.describe ModularImporter do
|
32
|
+
let(:modular_csv) { 'spec/fixtures/csv_import/modular_input.csv' }
|
33
|
+
let(:user) { ::User.batch_user }
|
34
|
+
|
35
|
+
before do
|
36
|
+
DatabaseCleaner.clean
|
37
|
+
ActiveFedora::Cleaner.clean!
|
38
|
+
end
|
39
|
+
|
40
|
+
it "imports a csv" do
|
41
|
+
expect { ModularImporter.new(modular_csv).import }.to change { Work.count }.by 3
|
42
|
+
end
|
43
|
+
end
|
44
|
+
```
|
45
|
+
1. Make a file called `app/importers/modular_importer.rb` that contains just enough of an importer class that your test can run and give a meaningful error:
|
46
|
+
```ruby
|
47
|
+
class ModularImporter
|
48
|
+
def initialize(csv_file)
|
49
|
+
@csv_file = csv_file
|
50
|
+
raise "Cannot find expected input file #{csv_file}" unless File.exist?(csv_file)
|
51
|
+
end
|
52
|
+
|
53
|
+
def import
|
54
|
+
end
|
55
|
+
end
|
56
|
+
```
|
57
|
+
1. Run your test:
|
58
|
+
```
|
59
|
+
bundle exec rspec spec/importers/modular_importer_spec.rb
|
60
|
+
```
|
61
|
+
It should fail with a message like
|
62
|
+
```
|
63
|
+
expected `Work.count` to have changed by 3, but was changed by 0
|
64
|
+
```
|
65
|
+
|
66
|
+
So, at this point, your test is running, but the importer isn't yet creating any records.
|
67
|
+
|
68
|
+
### 2. Get the test passing
|
69
|
+
1. Add the zizia gem to your `Gemfile` and run bundle update:
|
70
|
+
```
|
71
|
+
gem `zizia`
|
72
|
+
```
|
73
|
+
2. Edit `app/importer/modular_importer.rb` so it looks like this:
|
74
|
+
```ruby
|
75
|
+
require 'zizia'
|
76
|
+
|
77
|
+
class ModularImporter
|
78
|
+
def initialize(csv_file)
|
79
|
+
@csv_file = csv_file
|
80
|
+
raise "Cannot find expected input file #{csv_file}" unless File.exist?(csv_file)
|
81
|
+
end
|
82
|
+
|
83
|
+
def import
|
84
|
+
file = File.open(@csv_file)
|
85
|
+
Zizia::Importer.new(parser: Zizia::CsvParser.new(file: file), record_importer: Zizia::HyraxRecordImporter.new).import
|
86
|
+
file.close # Note that we must close any files we open.
|
87
|
+
end
|
88
|
+
end
|
89
|
+
```
|
90
|
+
3. Now your test should pass with output something like this:
|
91
|
+
|
92
|
+
```
|
93
|
+
ModularImporter
|
94
|
+
Creating record: ["A Cute Dog"].Record created at: jw827b648Record created at: jw827b648Creating record: ["An Interesting Cat"].Record created at: 3n203z084Record created at: 3n203z084Creating record: ["A Flock of Birds"].Record created at: wm117n96bRecord created at: wm117n96b imports a csv
|
95
|
+
|
96
|
+
Finished in 7.56 seconds (files took 9.06 seconds to load)
|
97
|
+
1 example, 0 failures
|
98
|
+
```
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zizia
|
4
|
+
##
|
5
|
+
# A Validator that always gives an error named `:everytime`.
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# validator = AlwaysInvalidValidator.new
|
9
|
+
# validator.validate(:anything, :at, :all) # => [Error<#...>]
|
10
|
+
class AlwaysInvalidValidator < Validator
|
11
|
+
##
|
12
|
+
# @return [Array<Validator::Error>]
|
13
|
+
def validate(*)
|
14
|
+
[Error.new(self, :everytime)]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zizia
|
4
|
+
##
|
5
|
+
# A generic metadata mapper for input records
|
6
|
+
#
|
7
|
+
# Maps from hash accessor syntax (`['title']`) to method call dot syntax (`.title`)
|
8
|
+
#
|
9
|
+
# The fields provided by this mapper are dynamically determined by the fields
|
10
|
+
# available in the provided metadata hash.
|
11
|
+
#
|
12
|
+
# All field values are given as multi-valued arrays.
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# mapper = HashMapper.new
|
16
|
+
# mapper.fields # => []
|
17
|
+
#
|
18
|
+
# mapper.metadata = { title: 'Comet in Moominland', author: 'Tove Jansson' }
|
19
|
+
# mapper.fields # => [:title, :author]
|
20
|
+
# mapper.title # => ['Comet in Moominland']
|
21
|
+
# mapper.author # => ['Tove Jansson']
|
22
|
+
#
|
23
|
+
class HashMapper < MetadataMapper
|
24
|
+
##
|
25
|
+
# @param meta [#to_h]
|
26
|
+
# @return [Hash<String, String>]
|
27
|
+
def metadata=(meta)
|
28
|
+
@metadata = meta.to_h
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# @return [Enumerable<Symbol>] The fields the mapper can process
|
33
|
+
def fields
|
34
|
+
return [] if metadata.nil?
|
35
|
+
metadata.keys.map(&:to_sym)
|
36
|
+
end
|
37
|
+
|
38
|
+
##
|
39
|
+
# @see MetadataMapper#map_field
|
40
|
+
def map_field(name)
|
41
|
+
Array(metadata[name.to_s])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
module Zizia
|
5
|
+
##
|
6
|
+
# A mapper for Hyrax metadata.
|
7
|
+
#
|
8
|
+
# Maps from hash accessor syntax (`['title']`) to method call dot syntax (`.title`).
|
9
|
+
#
|
10
|
+
# The fields provided by this mapper are the same as the properties defined in `Hyrax::CoreMetadata` and `Hyrax::BasicMetadata`.
|
11
|
+
#
|
12
|
+
# @note This mapper allows you to set values for all the Hyrax fields, but depending on how you create the records, some of the values might get clobbered. For example, if you use Hyrax's actor stack to create records, it might overwrite fields like `date_modified` or `depositor`.
|
13
|
+
#
|
14
|
+
# @see HashMapper Parent class for more info and examples.
|
15
|
+
class HyraxBasicMetadataMapper < HashMapper
|
16
|
+
# If your CSV headers don't exactly match the
|
17
|
+
# the method name for the property's setter
|
18
|
+
# method, add a mapping here.
|
19
|
+
# Example: the method name is work.resource_type,
|
20
|
+
# but in the CSV file, the header is
|
21
|
+
# 'resource type' (without the underscore).
|
22
|
+
CSV_HEADERS = {
|
23
|
+
resource_type: 'resource type',
|
24
|
+
description: 'abstract or summary',
|
25
|
+
rights_statement: 'rights statement',
|
26
|
+
date_created: 'date created',
|
27
|
+
based_near: 'location',
|
28
|
+
related_url: 'related url'
|
29
|
+
}.freeze
|
30
|
+
|
31
|
+
##
|
32
|
+
# @return [Enumerable<Symbol>] The fields the mapper can process.
|
33
|
+
def fields
|
34
|
+
core_fields + basic_fields + [:visibility]
|
35
|
+
end
|
36
|
+
|
37
|
+
# Properties defined with `multiple: false` in
|
38
|
+
# Hyrax should return a single value instead of
|
39
|
+
# an Array of values.
|
40
|
+
def depositor
|
41
|
+
single_value('depositor')
|
42
|
+
end
|
43
|
+
|
44
|
+
def date_modified
|
45
|
+
single_value('date_modified')
|
46
|
+
end
|
47
|
+
|
48
|
+
def label
|
49
|
+
single_value('label')
|
50
|
+
end
|
51
|
+
|
52
|
+
def relative_path
|
53
|
+
single_value('relative_path')
|
54
|
+
end
|
55
|
+
|
56
|
+
def import_url
|
57
|
+
single_value('import_url')
|
58
|
+
end
|
59
|
+
|
60
|
+
# We should accept visibility values that match the UI and transform them into
|
61
|
+
# the controlled vocabulary term expected by Hyrax
|
62
|
+
def visibility
|
63
|
+
case metadata[matching_header('visibility')]&.downcase&.gsub(/\s+/, "")
|
64
|
+
when 'public'
|
65
|
+
'open'
|
66
|
+
when 'open'
|
67
|
+
'open'
|
68
|
+
when 'registered'
|
69
|
+
'authenticated'
|
70
|
+
when "authenticated"
|
71
|
+
'authenticated'
|
72
|
+
when ::Hyrax::Institution.name&.downcase&.gsub(/\s+/, "")
|
73
|
+
'authenticated'
|
74
|
+
when ::Hyrax::Institution.name_full&.downcase&.gsub(/\s+/, "")
|
75
|
+
'authenticated'
|
76
|
+
when 'private'
|
77
|
+
'restricted'
|
78
|
+
when 'restricted'
|
79
|
+
'restricted'
|
80
|
+
else
|
81
|
+
'restricted' # This is the default if nothing else matches
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def files
|
86
|
+
map_field('files')
|
87
|
+
end
|
88
|
+
|
89
|
+
##
|
90
|
+
# @return [String] The delimiter that will be used to split a metadata field into separate values.
|
91
|
+
# @example
|
92
|
+
# mapper = HyraxBasicMetadataMapper.new
|
93
|
+
# mapper.metadata = { 'language' => 'English|~|French|~|Japanese' }
|
94
|
+
# mapper.language = ['English', 'French', 'Japanese']
|
95
|
+
#
|
96
|
+
def delimiter
|
97
|
+
@delimiter ||= '|~|'
|
98
|
+
end
|
99
|
+
attr_writer :delimiter
|
100
|
+
|
101
|
+
##
|
102
|
+
# @see MetadataMapper#map_field
|
103
|
+
def map_field(name)
|
104
|
+
method_name = name.to_s
|
105
|
+
method_name = CSV_HEADERS[name] if CSV_HEADERS.keys.include?(name)
|
106
|
+
key = matching_header(method_name)
|
107
|
+
Array(metadata[key]&.split(delimiter))
|
108
|
+
end
|
109
|
+
|
110
|
+
protected
|
111
|
+
|
112
|
+
# Some fields should have single values instead
|
113
|
+
# of array values.
|
114
|
+
def single_value(field_name)
|
115
|
+
metadata[matching_header(field_name)]
|
116
|
+
end
|
117
|
+
|
118
|
+
# Lenient matching for headers.
|
119
|
+
# If the user has headers like:
|
120
|
+
# 'Title' or 'TITLE' or 'Title '
|
121
|
+
# it should match the :title field.
|
122
|
+
def matching_header(field_name)
|
123
|
+
metadata.keys.find do |key|
|
124
|
+
next unless key
|
125
|
+
key.downcase.strip == field_name
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# Properties defined in Hyrax::CoreMetadata
|
130
|
+
# Note that date_uploaded is NOT set here, even though it is defined in
|
131
|
+
# Hyrax::CoreMetadata. Hyrax expects to set date_uploaded itself, and
|
132
|
+
# sending a metadata value for that field interferes with Hyrax expected
|
133
|
+
# behavior.
|
134
|
+
def core_fields
|
135
|
+
[:depositor, :title, :date_modified]
|
136
|
+
end
|
137
|
+
|
138
|
+
# Properties defined in Hyrax::BasicMetadata
|
139
|
+
def basic_fields
|
140
|
+
[:label, :relative_path, :import_url,
|
141
|
+
:resource_type, :creator, :contributor,
|
142
|
+
:description, :keyword, :license,
|
143
|
+
:rights_statement, :publisher, :date_created,
|
144
|
+
:subject, :language, :identifier,
|
145
|
+
:based_near, :related_url,
|
146
|
+
:bibliographic_citation, :source]
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|