sdr-client 0.71.0 → 0.72.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -0
- data/.rubocop_todo.yml +16 -5
- data/README.md +46 -19
- data/exe/sdr +2 -128
- data/lib/sdr_client/cli.rb +137 -76
- data/lib/sdr_client/deposit/file.rb +4 -4
- data/lib/sdr_client/deposit/request.rb +11 -11
- data/lib/sdr_client/deposit.rb +4 -4
- data/lib/sdr_client/login.rb +3 -1
- data/lib/sdr_client/update.rb +125 -10
- data/lib/sdr_client/version.rb +1 -1
- data/sdr-client.gemspec +2 -1
- metadata +21 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 899fec033d20f23ab887672fcfe7c706f9c6e5b02b7fd6975db5560be96b788c
|
4
|
+
data.tar.gz: cb68aa02ff81a59f50bdbc5003407765caa25d3e73d64f663e40c3990d1509df
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a53a001759ad7c941c1713999f1dfcd15a43c4200fff5644605dd277f2e8ce4c52497e8e1662a7b43fb896860f20dfc42380a8249fa47702e9106a5ecf4bf1c1
|
7
|
+
data.tar.gz: f1de6ce23106680288c2994e7ba085a9ef4aed3cbf2ecbbb315c8c4601a01aba134d5bcfd3b316fb7a242a99ebcad89cbf8f22929e2099cad3f001f62ac3c74a
|
data/.rubocop.yml
CHANGED
data/.rubocop_todo.yml
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# This configuration was generated by
|
2
2
|
# `rubocop --auto-gen-config --auto-gen-only-exclude`
|
3
|
-
# on 2022-03-
|
3
|
+
# on 2022-03-11 00:50:54 UTC using RuboCop version 1.25.1.
|
4
4
|
# The point is for the user to remove these configuration records
|
5
5
|
# one by one as the offenses are removed from the code base.
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
@@ -26,17 +26,19 @@ Lint/UnusedMethodArgument:
|
|
26
26
|
- 'lib/sdr_client/deposit/file_type_file_set_strategy.rb'
|
27
27
|
- 'lib/sdr_client/deposit/image_file_set_strategy.rb'
|
28
28
|
|
29
|
-
# Offense count:
|
29
|
+
# Offense count: 2
|
30
30
|
# Configuration parameters: IgnoredMethods, CountRepeatedAttributes, Max.
|
31
31
|
Metrics/AbcSize:
|
32
32
|
Exclude:
|
33
33
|
- 'lib/sdr_client/cli.rb'
|
34
|
+
- 'lib/sdr_client/update.rb'
|
34
35
|
|
35
|
-
# Offense count:
|
36
|
+
# Offense count: 2
|
36
37
|
# Configuration parameters: IgnoredMethods, Max.
|
37
38
|
Metrics/CyclomaticComplexity:
|
38
39
|
Exclude:
|
39
40
|
- 'lib/sdr_client/cli.rb'
|
41
|
+
- 'lib/sdr_client/update.rb'
|
40
42
|
|
41
43
|
# Offense count: 11
|
42
44
|
# Configuration parameters: CountComments, Max, CountAsOne, ExcludedMethods, IgnoredMethods.
|
@@ -50,12 +52,13 @@ Metrics/MethodLength:
|
|
50
52
|
- 'lib/sdr_client/login.rb'
|
51
53
|
- 'lib/sdr_client/update.rb'
|
52
54
|
|
53
|
-
# Offense count:
|
55
|
+
# Offense count: 10
|
54
56
|
# Configuration parameters: Max, CountAsOne.
|
55
57
|
RSpec/ExampleLength:
|
56
58
|
Exclude:
|
57
59
|
- 'spec/sdr_client/deposit_spec.rb'
|
58
60
|
- 'spec/sdr_client/model_deposit_spec.rb'
|
61
|
+
- 'spec/sdr_client/update_spec.rb'
|
59
62
|
|
60
63
|
# Offense count: 3
|
61
64
|
# Configuration parameters: Include, CustomTransform, IgnoreMethods, SpecSuffixOnly.
|
@@ -119,6 +122,12 @@ Style/KeywordParametersOrder:
|
|
119
122
|
- 'lib/sdr_client/deposit.rb'
|
120
123
|
- 'lib/sdr_client/deposit/request.rb'
|
121
124
|
|
125
|
+
# Offense count: 1
|
126
|
+
# Cop supports --auto-correct.
|
127
|
+
Style/MultilineTernaryOperator:
|
128
|
+
Exclude:
|
129
|
+
- 'lib/sdr_client/update.rb'
|
130
|
+
|
122
131
|
# Offense count: 2
|
123
132
|
# Cop supports --auto-correct-all.
|
124
133
|
# Configuration parameters: Mode.
|
@@ -127,12 +136,14 @@ Style/StringConcatenation:
|
|
127
136
|
- 'lib/sdr_client/deposit/create_resource.rb'
|
128
137
|
- 'spec/sdr_client/deposit_spec.rb'
|
129
138
|
|
130
|
-
# Offense count:
|
139
|
+
# Offense count: 19
|
131
140
|
# Cop supports --auto-correct.
|
132
141
|
# Configuration parameters: Max, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
|
133
142
|
# URISchemes: http, https
|
134
143
|
Layout/LineLength:
|
135
144
|
Exclude:
|
145
|
+
- 'lib/sdr_client/cli.rb'
|
136
146
|
- 'lib/sdr_client/deposit/model_process.rb'
|
147
|
+
- 'lib/sdr_client/update.rb'
|
137
148
|
- 'spec/sdr_client/deposit/model_process_spec.rb'
|
138
149
|
- 'spec/sdr_client/deposit/process_spec.rb'
|
data/README.md
CHANGED
@@ -17,55 +17,82 @@ We recommend using the latest 3.x release of Ruby.
|
|
17
17
|
|
18
18
|
## Usage
|
19
19
|
|
20
|
+
Get general help (e.g., list out commands):
|
21
|
+
```
|
22
|
+
sdr help
|
23
|
+
# or:
|
24
|
+
sdr -h
|
25
|
+
# or:
|
26
|
+
sdr --help
|
27
|
+
```
|
28
|
+
|
29
|
+
Get help for a specific command:
|
30
|
+
```
|
31
|
+
sdr help register
|
32
|
+
```
|
33
|
+
|
20
34
|
Log in:
|
21
35
|
```
|
22
|
-
sdr --
|
36
|
+
sdr login --url https://sdr-api-server:3000
|
37
|
+
```
|
38
|
+
|
39
|
+
Display version of sdr-client:
|
40
|
+
```
|
41
|
+
sdr version
|
23
42
|
```
|
24
43
|
|
25
44
|
Register a new object:
|
26
45
|
```
|
27
|
-
sdr --
|
46
|
+
sdr register file1.png file2.png --url https://sdr-api-server:3000 \
|
47
|
+
--label 'hey there' \
|
28
48
|
--admin-policy 'druid:bk123gh4567' \
|
29
49
|
--collection 'druid:gh456kw9876' \
|
30
|
-
--source-id 'googlebooks:stanford_12345'
|
50
|
+
--source-id 'googlebooks:stanford_12345'
|
31
51
|
```
|
32
52
|
|
33
53
|
Deposit (register + accession) a new object:
|
34
54
|
```
|
35
|
-
sdr --
|
55
|
+
sdr deposit file1.png file2.png --url https://sdr-api-server:3000 \
|
56
|
+
--label 'hey there' \
|
36
57
|
--admin-policy 'druid:bk123gh4567' \
|
37
58
|
--collection 'druid:gh456kw9876' \
|
38
|
-
--source-id 'googlebooks:stanford_12345'
|
59
|
+
--source-id 'googlebooks:stanford_12345'
|
39
60
|
```
|
40
61
|
|
41
62
|
Deposit a new object, providing metadata for files:
|
42
63
|
```
|
43
|
-
sdr --
|
64
|
+
sdr deposit image42.jp2 ocr.html --url https://sdr-api-server:3000 \
|
65
|
+
--label 'hey there' \
|
44
66
|
--files-metadata '{"image42.jp2":{"mime_type":"image/jp2"},"ocr.html":{"use":"transcription"}}'
|
45
67
|
--admin-policy 'druid:bk123gh4567' \
|
46
68
|
--collection 'druid:gh456kw9876' \
|
47
|
-
--source-id 'googlebooks:stanford_12345'
|
69
|
+
--source-id 'googlebooks:stanford_12345'
|
48
70
|
```
|
49
71
|
|
50
72
|
View the object:
|
51
73
|
```
|
52
|
-
sdr --
|
53
|
-
{"type":"
|
54
|
-
```
|
55
|
-
|
56
|
-
Display version of sdr-client:
|
57
|
-
```
|
58
|
-
sdr version
|
74
|
+
sdr get druid:bw581ng3176 --url https://sdr-api-server:3000
|
75
|
+
{"type":"https://cocina.sul.stanford.edu/models/document","externalIdentifier":"druid:bw581ng3176","label":"Something something better title","version":1,"access":{"view":"stanford","copyright":"This work is copyrighted by the creator.","download":"stanford","useAndReproductionStatement":"This document is available only to the Stanford faculty, staff and student community."},"administrative":{"hasAdminPolicy":"druid:zx485kb6348"},"description":{"title":[{"value":"Something something better title"}],"contributor":[{"name":[{"value":"Hodge, Amy"}],"type":"person","role":[{"value":"Author"},{"value":"author","uri":"http://id.loc.gov/vocabulary/relators/aut","source":{"code":"marcrelator","uri":"http://id.loc.gov/vocabulary/relators/"}},{"value":"Creator"}]}],"form":[{"structuredValue":[{"value":"Text","type":"type"},{"value":"Report","type":"subtype"}],"type":"resource type","source":{"value":"Stanford self-deposit resource types"}},{"value":"reports","type":"genre","uri":"http://vocab.getty.edu/aat/300027267","source":{"code":"aat"}},{"value":"text","type":"resource type","source":{"value":"MODS resource types"}}],"note":[{"value":";alkdfjlsadkjf;l","type":"summary"},{"value":"amyhodge@stanford.edu","type":"contact","displayLabel":"Contact"}],"subject":[{"value":"lkfj","type":"topic"},{"value":";kfj","type":"topic"},{"value":"fjwelkb","type":"topic"}]},"identification":{"sourceId":"hydrus:20"},"structural":{"contains":[{"type":"https://cocina.sul.stanford.edu/models/resources/file","externalIdentifier":"bw581ng3176_1","label":"Test file","version":1,"structural":{"contains":[{"type":"https://cocina.sul.stanford.edu/models/file","externalIdentifier":"druid:bw581ng3176/test.txt","label":"test.txt","filename":"test.txt","size":11,"version":1,"hasMimeType":"text/plain","hasMessageDigests":[{"type":"sha1","digest":"5d39343e4bb48abd97f759828282f5ebbac56c5e"},{"type":"md5","digest":"63b8812b0c05722a9d6c51cbd2bfb54b"}],"access":{"view":"world","download":"world"},"administrative":{"sdrPreserve":true,"shelve":true}}]}}]}}
|
59
76
|
```
|
60
77
|
|
61
|
-
Update an object
|
78
|
+
Update an object:
|
62
79
|
```
|
63
|
-
|
80
|
+
# Change admin policy object (APO)
|
81
|
+
sdr update druid:bb408qn5061 --url https://sdr-api-server:3000 --admin-policy druid:bx911tp9024
|
82
|
+
# Change collection
|
83
|
+
sdr update druid:bb408qn5061 --url https://sdr-api-server:3000 --collection druid:pb756dt1672
|
84
|
+
# Change copyright
|
85
|
+
sdr update druid:bb408qn5061 --url https://sdr-api-server:3000 --copyright "Here is a new copyright statement"
|
86
|
+
# Change use and reproduction statement
|
87
|
+
sdr update druid:bb408qn5061 --url https://sdr-api-server:3000 --use-and-reproduction "Here are the terms of use..."
|
88
|
+
# Change license
|
89
|
+
sdr update druid:bb408qn5061 --url https://sdr-api-server:3000 --license "https://www.apache.org/licenses/LICENSE-2.0"
|
90
|
+
# Change access controls
|
91
|
+
sdr update druid:bb408qn5061 --url https://sdr-api-server:3000 --view "location-based" --download "none" --location "music" --cdl false
|
64
92
|
```
|
65
93
|
|
66
|
-
|
67
94
|
## Testing
|
68
95
|
|
69
|
-
To test running sdr-client against the SDR API, which itself has dependencies on other SDR services, we tend to test against our running SDR QA environment. Make sure you are connected to VPN throughout your testing, and pass `https://sdr-api-qa.stanford.edu` as the value to the `--
|
96
|
+
To test running sdr-client against the SDR API, which itself has dependencies on other SDR services, we tend to test against our running SDR QA environment. Make sure you are connected to VPN throughout your testing, and pass `https://sdr-api-qa.stanford.edu` as the value to the `--url` flag for the commands above.
|
70
97
|
|
71
|
-
**WARNING**: if you omit the `--
|
98
|
+
**WARNING**: if you omit the `--url` flag, the sdr-client CLI by default operates against the production environment.
|
data/exe/sdr
CHANGED
@@ -2,133 +2,7 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
$LOAD_PATH.unshift 'lib'
|
5
|
-
require 'optparse'
|
6
|
-
require 'sdr_client'
|
7
|
-
|
8
|
-
options = {}
|
9
|
-
|
10
|
-
global = OptionParser.new do |opts|
|
11
|
-
opts.on('--service-url URL', 'Connect to the host at this URL') do |url|
|
12
|
-
options[:url] = url
|
13
|
-
end
|
14
|
-
opts.on('-h', '--help', 'Display this screen') do
|
15
|
-
SdrClient::CLI.help
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
global.order!
|
20
|
-
command = ARGV.shift
|
21
|
-
|
22
|
-
deposit_options = OptionParser.new do |opts|
|
23
|
-
opts.banner = "Usage: sdr #{command} [options]"
|
24
|
-
opts.on('--label LABEL', 'The object label') do |label|
|
25
|
-
options[:label] = label
|
26
|
-
end
|
27
|
-
|
28
|
-
opts.on('--admin-policy ADMIN_POLICY', 'The druid identifier of the admin policy object') do |apo|
|
29
|
-
options[:apo] = apo
|
30
|
-
end
|
31
|
-
|
32
|
-
opts.on('--type TYPE', 'The object type to create. ' \
|
33
|
-
'One of: "image", "book", "document", "map", "manuscript", "media", ' \
|
34
|
-
'"three_dimensional", "object", "collection", or "admin_policy"') do |type|
|
35
|
-
if %w[image book document map manuscript media three_dimensional object collection admin_policy].include?(type)
|
36
|
-
options[:type] = "http://cocina.sul.stanford.edu/models/#{type}.jsonld"
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
opts.on('--collection COLLECTION', 'The druid identifier of the collection object') do |collection|
|
41
|
-
options[:collection] = collection
|
42
|
-
end
|
43
|
-
|
44
|
-
opts.on('--catkey CATKEY', 'The catkey for this item') do |catkey|
|
45
|
-
options[:catkey] = catkey
|
46
|
-
end
|
47
|
-
|
48
|
-
opts.on('--source-id SOURCE_ID', 'The source id for this object') do |source_id|
|
49
|
-
options[:source_id] = source_id
|
50
|
-
end
|
51
|
-
|
52
|
-
opts.on('--copyright COPYRIGHT', 'The copyright statement') do |copyright|
|
53
|
-
options[:copyright] = copyright
|
54
|
-
end
|
55
|
-
|
56
|
-
opts.on('--use-statement STATEMENT', 'The use and reproduction statement') do |use_statement|
|
57
|
-
options[:use_statement] = use_statement
|
58
|
-
end
|
59
|
-
|
60
|
-
opts.on('--viewing-direction DIRECTION', 'The viewing direction (if a book). ' \
|
61
|
-
'Either "left-to-right" or "right-to-left"') do |viewing_direction|
|
62
|
-
options[:viewing_direction] = viewing_direction if %w[left-to-right right-to-left].include?(viewing_direction)
|
63
|
-
end
|
64
5
|
|
65
|
-
|
66
|
-
'Either "world", "stanford", "location-based", "citation-only" or "dark"') do |level|
|
67
|
-
options[:access] = level if %w[world stanford location-based citation-only dark].include?(level)
|
68
|
-
end
|
69
|
-
|
70
|
-
opts.on('--files-metadata FILES_METADATA', 'A JSON object representing per-file metadata') do |files_metadata|
|
71
|
-
options[:files_metadata] = JSON.parse(files_metadata)
|
72
|
-
end
|
73
|
-
|
74
|
-
opts.on('--strategy STRATEGY',
|
75
|
-
'The strategy to use for distributing files into filesets. Either "default" or "filename"') do |strategy|
|
76
|
-
strategy_class = case strategy
|
77
|
-
when 'filename'
|
78
|
-
SdrClient::Deposit::MatchingFileGroupingStrategy
|
79
|
-
when 'default'
|
80
|
-
SdrClient::Deposit::SingleFileGroupingStrategy
|
81
|
-
else
|
82
|
-
warn "Unknown strategy #{strategy}"
|
83
|
-
exit(1)
|
84
|
-
end
|
85
|
-
options[:grouping_strategy] = strategy_class
|
86
|
-
end
|
87
|
-
|
88
|
-
opts.on('-h', '--help', 'Display this screen') do
|
89
|
-
puts opts
|
90
|
-
exit
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
update_options = OptionParser.new do |opts|
|
95
|
-
opts.banner = "Usage: sdr #{command} [options]"
|
96
|
-
|
97
|
-
opts.on('--admin-policy ADMIN_POLICY', 'The druid identifier of the admin policy object') do |apo|
|
98
|
-
options[:apo] = apo
|
99
|
-
end
|
100
|
-
|
101
|
-
opts.on('-h', '--help', 'Display this screen') do
|
102
|
-
puts opts
|
103
|
-
exit
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
SdrClient::CLI.help unless command
|
108
|
-
|
109
|
-
subcommands = {
|
110
|
-
'deposit' => deposit_options,
|
111
|
-
'get' => OptionParser.new,
|
112
|
-
'login' => OptionParser.new,
|
113
|
-
'register' => deposit_options,
|
114
|
-
'update' => update_options,
|
115
|
-
'version' => OptionParser.new
|
116
|
-
}
|
117
|
-
|
118
|
-
unless subcommands.key?(command)
|
119
|
-
puts "unknown command '#{command}'"
|
120
|
-
SdrClient::CLI.help
|
121
|
-
end
|
122
|
-
|
123
|
-
subcommands[command].order!
|
124
|
-
|
125
|
-
options[:url] ||= 'https://sdr-api-prod.stanford.edu'
|
6
|
+
require 'sdr_client'
|
126
7
|
|
127
|
-
|
128
|
-
SdrClient::CLI.start(command, options, ARGV)
|
129
|
-
rescue StandardError => e
|
130
|
-
warn "There was a problem making your request:\n\n"
|
131
|
-
warn e.message
|
132
|
-
puts
|
133
|
-
puts subcommands[command].help
|
134
|
-
end
|
8
|
+
SdrClient::CLI.start(ARGV)
|
data/lib/sdr_client/cli.rb
CHANGED
@@ -1,111 +1,172 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
# The command line interface
|
5
|
-
module CLI
|
6
|
-
HELP = <<~HELP
|
7
|
-
DESCRIPTION:
|
8
|
-
The SDR Command Line Interface is a tool to interact with the Stanford Digital Repository.
|
9
|
-
|
10
|
-
SYNOPSIS:
|
11
|
-
sdr [options] <command>
|
12
|
-
|
13
|
-
To see help text for each command you can run:
|
14
|
-
|
15
|
-
sdr [options] <command> help
|
16
|
-
|
17
|
-
OPTIONS:
|
18
|
-
--service-url (string)
|
19
|
-
Override the command's default URL with the given URL. Default: https://sdr-api-prod.stanford.edu
|
20
|
-
|
21
|
-
-h, --help
|
22
|
-
Displays this screen
|
3
|
+
require 'thor'
|
23
4
|
|
5
|
+
module SdrClient
|
6
|
+
# The SDR command-line interface
|
7
|
+
class CLI < Thor
|
8
|
+
include Thor::Actions
|
9
|
+
|
10
|
+
# Make sure Thor commands preserve exit statuses
|
11
|
+
# @see https://github.com/rails/thor/wiki/Making-An-Executable
|
12
|
+
def self.exit_on_failure?
|
13
|
+
true
|
14
|
+
end
|
24
15
|
|
25
|
-
|
26
|
-
|
27
|
-
|
16
|
+
# Print out help and exit with error code if command not found
|
17
|
+
def self.handle_no_command_error(command)
|
18
|
+
puts "Command '#{command}' not found, displaying help:"
|
19
|
+
puts
|
20
|
+
puts help
|
21
|
+
exit(1)
|
22
|
+
end
|
28
23
|
|
29
|
-
|
30
|
-
|
24
|
+
def self.default_url
|
25
|
+
'https://sdr-api-prod.stanford.edu'
|
26
|
+
end
|
31
27
|
|
32
|
-
|
33
|
-
Create a draft object in the SDR and retrieve a Druid identifier
|
28
|
+
package_name 'sdr'
|
34
29
|
|
35
|
-
|
36
|
-
Update an object in the SDR
|
30
|
+
class_option :url, desc: 'URL of SDR API endpoint', type: :string, default: default_url
|
37
31
|
|
38
|
-
|
39
|
-
|
32
|
+
desc 'get DRUID', 'Retrieve an object from the SDR'
|
33
|
+
def get(druid)
|
34
|
+
say SdrClient::Find.run(druid, url: options[:url])
|
35
|
+
rescue SdrClient::Credentials::NoCredentialsError
|
36
|
+
say_error 'Log in first'
|
37
|
+
exit(1)
|
38
|
+
end
|
40
39
|
|
41
|
-
|
42
|
-
|
40
|
+
desc 'login', 'Prompt for email & password and create a login token (saved in ~/.sdr/token)'
|
41
|
+
def login
|
42
|
+
status = SdrClient::Login.run(
|
43
|
+
url: options[:url],
|
44
|
+
login_service: lambda do
|
45
|
+
{
|
46
|
+
email: ask('Email:'),
|
47
|
+
password: ask('Password:', echo: false)
|
48
|
+
}
|
49
|
+
end
|
50
|
+
)
|
51
|
+
return puts unless status.failure?
|
43
52
|
|
44
|
-
|
53
|
+
say_error status.failure
|
54
|
+
exit(1)
|
55
|
+
end
|
45
56
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
when 'deposit', 'register'
|
51
|
-
deposit(command, options, arguments)
|
52
|
-
when 'update'
|
53
|
-
if arguments.size != 1 || !arguments.first.is_a?(String)
|
54
|
-
raise "Expected a single druid argument, received #{arguments}"
|
55
|
-
end
|
57
|
+
desc 'version', 'Display the SDR CLI version'
|
58
|
+
def version
|
59
|
+
say SdrClient::VERSION
|
60
|
+
end
|
56
61
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
62
|
+
desc 'update DRUID', 'Update an object in the SDR'
|
63
|
+
option :skip_polling, type: :boolean, default: false, aliases: '-s', desc: 'Print out job ID instead of polling for result'
|
64
|
+
option :apo, desc: 'Druid identifier of the admin policy object', aliases: '--admin-policy'
|
65
|
+
option :collection, desc: 'Druid identifier of the collection object'
|
66
|
+
option :copyright, desc: 'Copyright statement'
|
67
|
+
option :use_and_reproduction, desc: 'Use and reproduction statement'
|
68
|
+
option :license, desc: 'License URI'
|
69
|
+
option :view, enum: %w[world stanford location-based citation-only dark], desc: 'Access view level for the object'
|
70
|
+
option :download, enum: %w[world stanford location-based none], desc: 'Access download level for the object'
|
71
|
+
option :location, enum: %w[spec music ars art hoover m&m], desc: 'Access location for the object'
|
72
|
+
option :cdl, type: :boolean, default: false
|
73
|
+
def update(druid)
|
74
|
+
validate_druid!(druid)
|
75
|
+
job_id = SdrClient::Update.run(druid, **options)
|
76
|
+
poll_for_job_complete(job_id: job_id, url: options[:url]) # TODO: add an option that skips this
|
67
77
|
rescue SdrClient::Credentials::NoCredentialsError
|
68
|
-
|
78
|
+
say_error 'Log in first'
|
69
79
|
exit(1)
|
70
80
|
end
|
71
81
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
82
|
+
desc 'deposit OPTIONAL_FILES', 'Deposit (accession) an object into the SDR'
|
83
|
+
option :skip_polling, type: :boolean, default: false, aliases: '-s', desc: 'Print out job ID instead of polling for result'
|
84
|
+
option :apo, required: true, desc: 'Druid identifier of the admin policy object', aliases: '--admin-policy'
|
85
|
+
option :source_id, required: true, desc: 'Source ID for this object'
|
86
|
+
option :label, desc: 'Object label'
|
87
|
+
option :type, enum: %w[image book document map manuscript media three_dimensional object collection admin_policy], desc: 'The object type'
|
88
|
+
option :collection, desc: 'Druid identifier of the collection object'
|
89
|
+
option :catkey, desc: 'Catkey for this item'
|
90
|
+
option :copyright, desc: 'Copyright statement'
|
91
|
+
option :use_and_reproduction, desc: 'Use and reproduction statement'
|
92
|
+
option :viewing_direction, enum: %w[left-to-right right-to-left], desc: 'Viewing direction (if a book)'
|
93
|
+
option :view, enum: %w[world stanford location-based citation-only dark], desc: 'Access view level for the object'
|
94
|
+
option :files_metadata, desc: 'JSON string representing per-file metadata'
|
95
|
+
option :grouping_strategy, enum: %w[default filename], desc: 'Strategy for grouping files into filesets'
|
96
|
+
def deposit(*files)
|
97
|
+
register_or_deposit(files: files, accession: true)
|
77
98
|
end
|
78
99
|
|
79
|
-
|
80
|
-
|
100
|
+
desc 'register OPTIONAL_FILES', 'Create a draft object in the SDR and retrieve a Druid identifier'
|
101
|
+
option :skip_polling, type: :boolean, default: false, aliases: '-s', desc: 'Print out job ID instead of polling for result'
|
102
|
+
option :apo, required: true, desc: 'Druid identifier of the admin policy object', aliases: '--admin-policy'
|
103
|
+
option :source_id, required: true, desc: 'Source ID for this object'
|
104
|
+
option :label, desc: 'Object label'
|
105
|
+
option :type, enum: %w[image book document map manuscript media three_dimensional object collection admin_policy], desc: 'The object type'
|
106
|
+
option :collection, desc: 'Druid identifier of the collection object'
|
107
|
+
option :catkey, desc: 'Catkey for this item'
|
108
|
+
option :copyright, desc: 'Copyright statement'
|
109
|
+
option :use_and_reproduction, desc: 'Use and reproduction statement'
|
110
|
+
option :viewing_direction, enum: %w[left-to-right right-to-left], desc: 'Viewing direction (if a book)'
|
111
|
+
option :view, enum: %w[world stanford location-based citation-only dark], desc: 'Access view level for the object'
|
112
|
+
option :files_metadata, desc: 'JSON string representing per-file metadata'
|
113
|
+
option :grouping_strategy, enum: %w[default filename], desc: 'Strategy for grouping files into filesets'
|
114
|
+
def register(*files)
|
115
|
+
register_or_deposit(files: files, accession: false)
|
116
|
+
end
|
81
117
|
|
82
|
-
|
118
|
+
private
|
119
|
+
|
120
|
+
def register_or_deposit(files:, accession:)
|
121
|
+
opts = munge_options(options, files)
|
122
|
+
skip_polling = opts.delete(:skip_polling)
|
123
|
+
job_id = SdrClient::Deposit.run(accession: accession, **opts)
|
124
|
+
return if skip_polling
|
125
|
+
|
126
|
+
poll_for_job_complete(job_id: job_id, url: opts[:url])
|
127
|
+
rescue SdrClient::Credentials::NoCredentialsError
|
128
|
+
say_error 'Log in first'
|
129
|
+
exit(1)
|
83
130
|
end
|
84
131
|
|
85
|
-
def
|
86
|
-
|
87
|
-
|
88
|
-
|
132
|
+
def munge_options(options, files)
|
133
|
+
options.to_h.symbolize_keys.tap do |opts|
|
134
|
+
opts[:files] = files if files.present?
|
135
|
+
opts[:type] = Cocina::Models::ObjectType.public_send(options[:type]) if options[:type]
|
136
|
+
opts[:files_metadata] = JSON.parse(options[:files_metadata]) if options[:files_metadata]
|
137
|
+
if options[:grouping_strategy]
|
138
|
+
opts[:grouping_strategy] = if options[:grouping_strategy] == 'filename'
|
139
|
+
SdrClient::Deposit::MatchingFileGroupingStrategy
|
140
|
+
else
|
141
|
+
SdrClient::Deposit::SingleFileGroupingStrategy
|
142
|
+
end
|
143
|
+
end
|
89
144
|
end
|
90
145
|
end
|
91
146
|
|
92
|
-
def
|
93
|
-
|
94
|
-
|
147
|
+
def validate_druid!(druid)
|
148
|
+
return if druid.present?
|
149
|
+
|
150
|
+
say_error "Not a valid druid: #{druid.inspect}"
|
151
|
+
exit(1)
|
95
152
|
end
|
96
153
|
|
97
|
-
def
|
154
|
+
def poll_for_job_complete(job_id:, url:)
|
155
|
+
# the extra args to `say` prevent appending a newline
|
156
|
+
say('SDR is processing your request', nil, false)
|
98
157
|
result = nil
|
99
|
-
1.upto(
|
158
|
+
(1).upto(60) do
|
100
159
|
result = SdrClient::BackgroundJobResults.show(url: url, job_id: job_id)
|
101
|
-
break unless %w[pending processing].include?
|
160
|
+
break unless %w[pending processing].include?(result['status'])
|
102
161
|
|
103
|
-
|
162
|
+
# the extra args to `say` prevent appending a newline
|
163
|
+
say('.', nil, false)
|
164
|
+
sleep 1
|
104
165
|
end
|
105
166
|
if result['status'] == 'complete'
|
106
|
-
|
167
|
+
say " success! (druid: #{result.dig('output', 'druid')})"
|
107
168
|
else
|
108
|
-
|
169
|
+
say_error "Job #{job_id} did not complete\n#{result.inspect}"
|
109
170
|
end
|
110
171
|
end
|
111
172
|
end
|
@@ -6,16 +6,16 @@ module SdrClient
|
|
6
6
|
class File
|
7
7
|
# rubocop:disable Metrics/ParameterLists
|
8
8
|
def initialize(external_identifier:, label:, filename:,
|
9
|
-
|
9
|
+
view: 'dark', download: 'none', preserve: true, shelve: true,
|
10
10
|
publish: true, mime_type: nil, md5: nil, sha1: nil,
|
11
11
|
use: nil)
|
12
12
|
@external_identifier = external_identifier
|
13
13
|
@label = label
|
14
14
|
@filename = filename
|
15
|
-
@
|
15
|
+
@view = view
|
16
16
|
@download = download
|
17
17
|
@preserve = preserve
|
18
|
-
@shelve =
|
18
|
+
@shelve = view == 'dark' ? false : shelve
|
19
19
|
@publish = publish
|
20
20
|
@mime_type = mime_type
|
21
21
|
@md5 = md5
|
@@ -31,7 +31,7 @@ module SdrClient
|
|
31
31
|
filename: @filename,
|
32
32
|
externalIdentifier: @external_identifier,
|
33
33
|
access: {
|
34
|
-
view: @
|
34
|
+
view: @view,
|
35
35
|
download: @download
|
36
36
|
},
|
37
37
|
administrative: {
|
@@ -13,9 +13,9 @@ module SdrClient
|
|
13
13
|
# Additional metadata includes access, preserve, shelve, publish, md5, sha1
|
14
14
|
# rubocop:disable Metrics/ParameterLists
|
15
15
|
def initialize(label: nil,
|
16
|
-
|
16
|
+
view: 'dark',
|
17
17
|
download: 'none',
|
18
|
-
|
18
|
+
use_and_reproduction: nil,
|
19
19
|
copyright: nil,
|
20
20
|
apo:,
|
21
21
|
collection: nil,
|
@@ -36,9 +36,9 @@ module SdrClient
|
|
36
36
|
@embargo_release_date = embargo_release_date
|
37
37
|
@embargo_access = embargo_access
|
38
38
|
@embargo_download = embargo_download
|
39
|
-
@
|
39
|
+
@view = view
|
40
40
|
@download = download
|
41
|
-
@
|
41
|
+
@use_and_reproduction = use_and_reproduction
|
42
42
|
@copyright = copyright
|
43
43
|
@apo = apo
|
44
44
|
@file_sets = file_sets
|
@@ -62,7 +62,7 @@ module SdrClient
|
|
62
62
|
# @return [Request] a clone of this request with the file_sets added
|
63
63
|
def with_file_sets(file_sets)
|
64
64
|
Request.new(label: label,
|
65
|
-
|
65
|
+
view: view,
|
66
66
|
download: download,
|
67
67
|
apo: apo,
|
68
68
|
collection: collection,
|
@@ -73,7 +73,7 @@ module SdrClient
|
|
73
73
|
embargo_access: embargo_access,
|
74
74
|
embargo_download: embargo_download,
|
75
75
|
type: type,
|
76
|
-
|
76
|
+
use_and_reproduction: use_and_reproduction,
|
77
77
|
viewing_direction: viewing_direction,
|
78
78
|
file_sets: file_sets,
|
79
79
|
files_metadata: files_metadata)
|
@@ -83,7 +83,7 @@ module SdrClient
|
|
83
83
|
# @return [Hash] the metadata for the file
|
84
84
|
def for(filename)
|
85
85
|
metadata = files_metadata.fetch(filename, {}).with_indifferent_access
|
86
|
-
metadata[:
|
86
|
+
metadata[:view] = view unless metadata.key?(:view)
|
87
87
|
metadata[:download] = download unless metadata.key?(:download)
|
88
88
|
metadata
|
89
89
|
end
|
@@ -92,9 +92,9 @@ module SdrClient
|
|
92
92
|
|
93
93
|
private
|
94
94
|
|
95
|
-
attr_reader :
|
95
|
+
attr_reader :view, :label, :file_sets, :source_id, :catkey, :apo, :collection,
|
96
96
|
:files_metadata, :embargo_release_date, :embargo_access, :embargo_download,
|
97
|
-
:viewing_direction, :
|
97
|
+
:viewing_direction, :use_and_reproduction, :copyright, :download
|
98
98
|
|
99
99
|
def administrative
|
100
100
|
{
|
@@ -118,10 +118,10 @@ module SdrClient
|
|
118
118
|
|
119
119
|
def access_struct
|
120
120
|
{
|
121
|
-
view:
|
121
|
+
view: view,
|
122
122
|
download: download
|
123
123
|
}.tap do |json|
|
124
|
-
json[:useAndReproductionStatement] =
|
124
|
+
json[:useAndReproductionStatement] = use_and_reproduction if use_and_reproduction
|
125
125
|
json[:copyright] = copyright if copyright
|
126
126
|
|
127
127
|
if embargo_release_date
|
data/lib/sdr_client/deposit.rb
CHANGED
@@ -12,9 +12,9 @@ module SdrClient
|
|
12
12
|
def self.run(label: nil,
|
13
13
|
type: BOOK_TYPE,
|
14
14
|
viewing_direction: nil,
|
15
|
-
|
15
|
+
view: 'dark',
|
16
16
|
download: 'none',
|
17
|
-
|
17
|
+
use_and_reproduction: nil,
|
18
18
|
copyright: nil,
|
19
19
|
apo:,
|
20
20
|
collection: nil,
|
@@ -33,10 +33,10 @@ module SdrClient
|
|
33
33
|
augmented_metadata = FileMetadataBuilder.build(files: files, files_metadata: files_metadata)
|
34
34
|
metadata = Request.new(label: label,
|
35
35
|
type: type,
|
36
|
-
|
36
|
+
view: view,
|
37
37
|
download: download,
|
38
38
|
apo: apo,
|
39
|
-
|
39
|
+
use_and_reproduction: use_and_reproduction,
|
40
40
|
copyright: copyright,
|
41
41
|
collection: collection,
|
42
42
|
source_id: source_id,
|
data/lib/sdr_client/login.rb
CHANGED
@@ -8,7 +8,9 @@ module SdrClient
|
|
8
8
|
|
9
9
|
# @return [Result] the status of the call
|
10
10
|
def self.run(url:, login_service: LoginPrompt, credential_store: Credentials)
|
11
|
-
request_json = JSON.generate(
|
11
|
+
request_json = JSON.generate(
|
12
|
+
login_service.respond_to?(:run) ? login_service.run : login_service.call
|
13
|
+
)
|
12
14
|
response = Faraday.post(url + LOGIN_PATH, request_json, 'Content-Type' => 'application/json')
|
13
15
|
case response.status
|
14
16
|
when 200
|
data/lib/sdr_client/update.rb
CHANGED
@@ -2,24 +2,139 @@
|
|
2
2
|
|
3
3
|
module SdrClient
|
4
4
|
# The namespace for the "update" command
|
5
|
-
|
5
|
+
class Update
|
6
6
|
# @return [String] job id for the background job result
|
7
|
-
def self.run(druid,
|
8
|
-
|
7
|
+
def self.run(druid, **options)
|
8
|
+
new(druid, **options).run
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(druid, **options)
|
12
|
+
@druid = druid
|
13
|
+
@url = options.fetch(:url)
|
14
|
+
@options = options
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [String] job id for the background job result
|
18
|
+
def run
|
19
|
+
SdrClient::Deposit::UpdateResource.run(
|
20
|
+
metadata: updated_cocina_item,
|
21
|
+
logger: options[:logger] || Logger.new($stdout),
|
22
|
+
connection: SdrClient::Connection.new(url: url)
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
attr_reader :druid, :logger, :options, :url
|
29
|
+
|
30
|
+
def updated_cocina_item
|
31
|
+
@updated_cocina_item ||=
|
32
|
+
original_cocina_item.then { |cocina_item| update_apo(cocina_item) }
|
33
|
+
.then { |cocina_item| update_collection(cocina_item) }
|
34
|
+
.then { |cocina_item| update_copyright(cocina_item) }
|
35
|
+
.then { |cocina_item| update_use_and_reproduction(cocina_item) }
|
36
|
+
.then { |cocina_item| update_license(cocina_item) }
|
37
|
+
.then { |cocina_item| update_access(cocina_item) }
|
38
|
+
end
|
39
|
+
|
40
|
+
def original_cocina_item
|
41
|
+
Cocina::Models.build(
|
9
42
|
JSON.parse(
|
10
43
|
SdrClient::Find.run(druid, url: url)
|
11
44
|
)
|
12
45
|
)
|
46
|
+
end
|
13
47
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
48
|
+
# Update the APO of a Cocina item if the options specify a new one, else return the original
|
49
|
+
def update_apo(cocina_item)
|
50
|
+
return cocina_item unless options[:apo]
|
51
|
+
|
52
|
+
cocina_item.new(
|
53
|
+
administrative: cocina_item.administrative.new(
|
54
|
+
hasAdminPolicy: options[:apo]
|
55
|
+
)
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Update the collection of a Cocina item if the options specify a new one, else return the original
|
60
|
+
def update_collection(cocina_item)
|
61
|
+
return cocina_item unless options[:collection]
|
62
|
+
|
63
|
+
cocina_item.new(
|
64
|
+
structural: cocina_item.structural.new(
|
65
|
+
isMemberOf: Array(options[:collection])
|
66
|
+
)
|
67
|
+
)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Update the copyright of a Cocina item if the options specify a new one, else return the original
|
71
|
+
def update_copyright(cocina_item)
|
72
|
+
return cocina_item unless options[:copyright]
|
73
|
+
|
74
|
+
cocina_item.new(
|
75
|
+
access: cocina_item.access.new(
|
76
|
+
copyright: options[:copyright]
|
77
|
+
)
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Update the use and reproduction statement of a Cocina item if the options specify a new one, else return the original
|
82
|
+
def update_use_and_reproduction(cocina_item)
|
83
|
+
return cocina_item unless options[:use_and_reproduction]
|
84
|
+
|
85
|
+
cocina_item.new(
|
86
|
+
access: cocina_item.access.new(
|
87
|
+
useAndReproductionStatement: options[:use_and_reproduction]
|
88
|
+
)
|
89
|
+
)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Update the license of a Cocina item if the options specify a new one, else return the original
|
93
|
+
def update_license(cocina_item)
|
94
|
+
return cocina_item unless options[:license]
|
95
|
+
|
96
|
+
cocina_item.new(
|
97
|
+
access: cocina_item.access.new(
|
98
|
+
license: options[:license]
|
99
|
+
)
|
100
|
+
)
|
101
|
+
end
|
102
|
+
|
103
|
+
# rubocop:disable Style/DoubleNegation
|
104
|
+
# Update the access of a Cocina item if the options specify a new one, else return the original
|
105
|
+
def update_access(cocina_item)
|
106
|
+
return cocina_item unless options[:view] || options[:download] || options[:location] || options[:cdl]
|
107
|
+
|
108
|
+
cocina_item.new(
|
109
|
+
access: cocina_item.access.new(
|
110
|
+
view: options[:view],
|
111
|
+
download: options[:download],
|
112
|
+
location: options[:location],
|
113
|
+
controlledDigitalLending: !!options[:cdl]
|
19
114
|
),
|
20
|
-
|
21
|
-
|
115
|
+
structural: cocina_item.structural.new(
|
116
|
+
contains: cocina_item.structural.contains.map do |file_set|
|
117
|
+
file_set.new(
|
118
|
+
structural: file_set.structural.new(
|
119
|
+
contains: file_set.structural.contains.map do |file|
|
120
|
+
file.new(
|
121
|
+
access: file.access.new(
|
122
|
+
view: options[:view],
|
123
|
+
download: options[:download],
|
124
|
+
location: options[:location],
|
125
|
+
controlledDigitalLending: !!options[:cdl]
|
126
|
+
),
|
127
|
+
administrative: options[:view] == 'dark' ?
|
128
|
+
{ publish: false, shelve: false, sdrPreserve: file.administrative.sdrPreserve } :
|
129
|
+
file.administrative
|
130
|
+
)
|
131
|
+
end
|
132
|
+
)
|
133
|
+
)
|
134
|
+
end
|
135
|
+
)
|
22
136
|
)
|
23
137
|
end
|
138
|
+
# rubocop:enable Style/DoubleNegation
|
24
139
|
end
|
25
140
|
end
|
data/lib/sdr_client/version.rb
CHANGED
data/sdr-client.gemspec
CHANGED
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.require_paths = ['lib']
|
29
29
|
|
30
30
|
spec.add_dependency 'activesupport'
|
31
|
-
spec.add_dependency 'cocina-models', '~> 0.
|
31
|
+
spec.add_dependency 'cocina-models', '~> 0.69.0'
|
32
32
|
spec.add_dependency 'dry-monads'
|
33
33
|
spec.add_dependency 'faraday', '>= 0.16'
|
34
34
|
|
@@ -39,6 +39,7 @@ Gem::Specification.new do |spec|
|
|
39
39
|
spec.add_development_dependency 'rubocop-rake'
|
40
40
|
spec.add_development_dependency 'rubocop-rspec', '~> 2.1'
|
41
41
|
spec.add_development_dependency 'simplecov'
|
42
|
+
spec.add_development_dependency 'thor'
|
42
43
|
spec.add_development_dependency 'webmock', '~> 3.7'
|
43
44
|
spec.metadata['rubygems_mfa_required'] = 'true'
|
44
45
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sdr-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.72.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Coyne
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-03-
|
11
|
+
date: 2022-03-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.
|
33
|
+
version: 0.69.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.
|
40
|
+
version: 0.69.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: dry-monads
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -164,6 +164,20 @@ dependencies:
|
|
164
164
|
- - ">="
|
165
165
|
- !ruby/object:Gem::Version
|
166
166
|
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: thor
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
167
181
|
- !ruby/object:Gem::Dependency
|
168
182
|
name: webmock
|
169
183
|
requirement: !ruby/object:Gem::Requirement
|
@@ -242,7 +256,7 @@ metadata:
|
|
242
256
|
source_code_uri: https://github.com/sul-dlss/sdr-client
|
243
257
|
changelog_uri: https://github.com/sul-dlss/sdr-client/releases
|
244
258
|
rubygems_mfa_required: 'true'
|
245
|
-
post_install_message:
|
259
|
+
post_install_message:
|
246
260
|
rdoc_options: []
|
247
261
|
require_paths:
|
248
262
|
- lib
|
@@ -258,7 +272,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
258
272
|
version: '0'
|
259
273
|
requirements: []
|
260
274
|
rubygems_version: 3.2.32
|
261
|
-
signing_key:
|
275
|
+
signing_key:
|
262
276
|
specification_version: 4
|
263
277
|
summary: The CLI for https://github.com/sul-dlss/sdr-api
|
264
278
|
test_files: []
|