scholarsphere-client 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.circleci/config.yml +40 -0
- data/.gitignore +1 -1
- data/.rubocop.yml +3 -0
- data/Gemfile.lock +204 -0
- data/README.md +55 -3
- data/lib/scholarsphere/client.rb +10 -0
- data/lib/scholarsphere/client/config.rb +8 -3
- data/lib/scholarsphere/client/ingest.rb +92 -9
- data/lib/scholarsphere/client/upload.rb +52 -0
- data/lib/scholarsphere/client/version.rb +1 -1
- data/lib/scholarsphere/s3/uploaded_file.rb +27 -35
- data/lib/scholarsphere/s3/uploader.rb +30 -30
- data/scholarsphere-client.gemspec +6 -2
- metadata +37 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8ab004f36213538c0e74821396c0499a52f08a24c8a8d7f450b3c224a0b71a8d
|
|
4
|
+
data.tar.gz: 84788832717be95ff66b8def2433633fc41a82aa85e4b204d1750814b8fa4bb4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 45c9c56b6f2db7ed715a595b9d5533ddba125b0a63d7b2d694669105c50b65e19c66b70814add3921b1d1fc83ef1ebc6592488641206c1eef1ef21c331d9649c
|
|
7
|
+
data.tar.gz: c7d927e3d027ecdf2b204f350b0758b353d0b161e285b795111174deca41951c2ca8f5642cc6461852b831cd6a1c890febb5083730b08b3360358fbbf902c574
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
version: 2.1
|
|
2
|
+
orbs:
|
|
3
|
+
ruby: circleci/ruby@0.1.2
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
build:
|
|
7
|
+
docker:
|
|
8
|
+
- image: circleci/ruby:2.6.3-stretch-node
|
|
9
|
+
executor: ruby/default
|
|
10
|
+
steps:
|
|
11
|
+
- checkout
|
|
12
|
+
- run:
|
|
13
|
+
name: "Install Dependencides"
|
|
14
|
+
command: gem install bundler:2.1.4 && bundle install
|
|
15
|
+
- run:
|
|
16
|
+
name: "Rubocop"
|
|
17
|
+
command: bundle exec rubocop
|
|
18
|
+
- run:
|
|
19
|
+
name: "RSpec"
|
|
20
|
+
command: bundle exec rspec
|
|
21
|
+
environment:
|
|
22
|
+
SS4_ENDPOINT: "https://scholarsphere.test/api/v1"
|
|
23
|
+
- run:
|
|
24
|
+
name: "Copy VCR Logs"
|
|
25
|
+
when: on_fail
|
|
26
|
+
command: cp vcr.log /tmp/vcr.log
|
|
27
|
+
- run:
|
|
28
|
+
name: "Upload Coverage"
|
|
29
|
+
when: on_success
|
|
30
|
+
command: |
|
|
31
|
+
wget -q https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 -O cc-test-reporter
|
|
32
|
+
chmod 755 cc-test-reporter
|
|
33
|
+
export TAG=${CIRCLE_SHA1}
|
|
34
|
+
export GIT_COMMIT_SHA=$CIRCLE_SHA1
|
|
35
|
+
export GIT_BRANCH=$CIRCLE_BRANCH
|
|
36
|
+
export GIT_COMMITED_AT=$(git log -1 --date=short --pretty=format:%ct)
|
|
37
|
+
./cc-test-reporter after-build -d
|
|
38
|
+
- store_artifacts:
|
|
39
|
+
path: /tmp/vcr.log
|
|
40
|
+
destination: VCR
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
scholarsphere-client (0.2.0)
|
|
5
|
+
aws-sdk-s3 (~> 1.49)
|
|
6
|
+
faraday (> 0.12)
|
|
7
|
+
marcel (~> 0.3)
|
|
8
|
+
|
|
9
|
+
GEM
|
|
10
|
+
remote: https://rubygems.org/
|
|
11
|
+
specs:
|
|
12
|
+
actionview (6.1.1)
|
|
13
|
+
activesupport (= 6.1.1)
|
|
14
|
+
builder (~> 3.1)
|
|
15
|
+
erubi (~> 1.4)
|
|
16
|
+
rails-dom-testing (~> 2.0)
|
|
17
|
+
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
|
18
|
+
activesupport (6.1.1)
|
|
19
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
20
|
+
i18n (>= 1.6, < 2)
|
|
21
|
+
minitest (>= 5.1)
|
|
22
|
+
tzinfo (~> 2.0)
|
|
23
|
+
zeitwerk (~> 2.3)
|
|
24
|
+
addressable (2.7.0)
|
|
25
|
+
public_suffix (>= 2.0.2, < 5.0)
|
|
26
|
+
ast (2.4.1)
|
|
27
|
+
aws-eventstream (1.1.0)
|
|
28
|
+
aws-partitions (1.322.0)
|
|
29
|
+
aws-sdk-core (3.97.0)
|
|
30
|
+
aws-eventstream (~> 1, >= 1.0.2)
|
|
31
|
+
aws-partitions (~> 1, >= 1.239.0)
|
|
32
|
+
aws-sigv4 (~> 1.1)
|
|
33
|
+
jmespath (~> 1.0)
|
|
34
|
+
aws-sdk-kms (1.32.0)
|
|
35
|
+
aws-sdk-core (~> 3, >= 3.71.0)
|
|
36
|
+
aws-sigv4 (~> 1.1)
|
|
37
|
+
aws-sdk-s3 (1.67.0)
|
|
38
|
+
aws-sdk-core (~> 3, >= 3.96.1)
|
|
39
|
+
aws-sdk-kms (~> 1)
|
|
40
|
+
aws-sigv4 (~> 1.1)
|
|
41
|
+
aws-sigv4 (1.1.4)
|
|
42
|
+
aws-eventstream (~> 1.0, >= 1.0.2)
|
|
43
|
+
better_html (1.0.15)
|
|
44
|
+
actionview (>= 4.0)
|
|
45
|
+
activesupport (>= 4.0)
|
|
46
|
+
ast (~> 2.0)
|
|
47
|
+
erubi (~> 1.4)
|
|
48
|
+
html_tokenizer (~> 0.0.6)
|
|
49
|
+
parser (>= 2.4)
|
|
50
|
+
smart_properties
|
|
51
|
+
builder (3.2.4)
|
|
52
|
+
byebug (11.1.3)
|
|
53
|
+
coderay (1.1.3)
|
|
54
|
+
colorize (0.8.1)
|
|
55
|
+
concurrent-ruby (1.1.7)
|
|
56
|
+
crack (0.4.5)
|
|
57
|
+
rexml
|
|
58
|
+
crass (1.0.6)
|
|
59
|
+
diff-lcs (1.3)
|
|
60
|
+
docile (1.3.5)
|
|
61
|
+
erb_lint (0.0.37)
|
|
62
|
+
activesupport
|
|
63
|
+
better_html (~> 1.0.7)
|
|
64
|
+
html_tokenizer
|
|
65
|
+
parser (>= 2.7.1.4)
|
|
66
|
+
rainbow
|
|
67
|
+
rubocop
|
|
68
|
+
smart_properties
|
|
69
|
+
erubi (1.10.0)
|
|
70
|
+
faraday (1.0.1)
|
|
71
|
+
multipart-post (>= 1.2, < 3)
|
|
72
|
+
ffi (1.14.2)
|
|
73
|
+
hashdiff (1.0.1)
|
|
74
|
+
html_tokenizer (0.0.7)
|
|
75
|
+
i18n (1.8.7)
|
|
76
|
+
concurrent-ruby (~> 1.0)
|
|
77
|
+
jmespath (1.4.0)
|
|
78
|
+
json (2.5.1)
|
|
79
|
+
loofah (2.8.0)
|
|
80
|
+
crass (~> 1.0.2)
|
|
81
|
+
nokogiri (>= 1.5.9)
|
|
82
|
+
marcel (0.3.3)
|
|
83
|
+
mimemagic (~> 0.3.2)
|
|
84
|
+
method_source (1.0.0)
|
|
85
|
+
mimemagic (0.3.5)
|
|
86
|
+
mini_portile2 (2.5.0)
|
|
87
|
+
minitest (5.14.3)
|
|
88
|
+
multipart-post (2.1.1)
|
|
89
|
+
niftany (0.8.0)
|
|
90
|
+
colorize (~> 0.8.1)
|
|
91
|
+
erb_lint (~> 0.0.22)
|
|
92
|
+
rubocop (~> 0.79)
|
|
93
|
+
rubocop-performance (~> 1.1)
|
|
94
|
+
rubocop-rails (~> 2.3)
|
|
95
|
+
rubocop-rspec (~> 1.3)
|
|
96
|
+
scss_lint (~> 0.55)
|
|
97
|
+
nokogiri (1.11.1)
|
|
98
|
+
mini_portile2 (~> 2.5.0)
|
|
99
|
+
racc (~> 1.4)
|
|
100
|
+
parallel (1.20.1)
|
|
101
|
+
parser (3.0.0.0)
|
|
102
|
+
ast (~> 2.4.1)
|
|
103
|
+
pry (0.13.1)
|
|
104
|
+
coderay (~> 1.1)
|
|
105
|
+
method_source (~> 1.0)
|
|
106
|
+
pry-byebug (3.9.0)
|
|
107
|
+
byebug (~> 11.0)
|
|
108
|
+
pry (~> 0.13.0)
|
|
109
|
+
public_suffix (4.0.6)
|
|
110
|
+
racc (1.5.2)
|
|
111
|
+
rack (2.2.3)
|
|
112
|
+
rails-dom-testing (2.0.3)
|
|
113
|
+
activesupport (>= 4.2.0)
|
|
114
|
+
nokogiri (>= 1.6)
|
|
115
|
+
rails-html-sanitizer (1.3.0)
|
|
116
|
+
loofah (~> 2.3)
|
|
117
|
+
rainbow (3.0.0)
|
|
118
|
+
rake (13.0.1)
|
|
119
|
+
rb-fsevent (0.10.4)
|
|
120
|
+
rb-inotify (0.10.1)
|
|
121
|
+
ffi (~> 1.0)
|
|
122
|
+
regexp_parser (2.0.3)
|
|
123
|
+
rexml (3.2.4)
|
|
124
|
+
rspec (3.9.0)
|
|
125
|
+
rspec-core (~> 3.9.0)
|
|
126
|
+
rspec-expectations (~> 3.9.0)
|
|
127
|
+
rspec-mocks (~> 3.9.0)
|
|
128
|
+
rspec-core (3.9.2)
|
|
129
|
+
rspec-support (~> 3.9.3)
|
|
130
|
+
rspec-expectations (3.9.2)
|
|
131
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
132
|
+
rspec-support (~> 3.9.0)
|
|
133
|
+
rspec-its (1.3.0)
|
|
134
|
+
rspec-core (>= 3.0.0)
|
|
135
|
+
rspec-expectations (>= 3.0.0)
|
|
136
|
+
rspec-mocks (3.9.1)
|
|
137
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
138
|
+
rspec-support (~> 3.9.0)
|
|
139
|
+
rspec-support (3.9.3)
|
|
140
|
+
rubocop (0.93.1)
|
|
141
|
+
parallel (~> 1.10)
|
|
142
|
+
parser (>= 2.7.1.5)
|
|
143
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
144
|
+
regexp_parser (>= 1.8)
|
|
145
|
+
rexml
|
|
146
|
+
rubocop-ast (>= 0.6.0)
|
|
147
|
+
ruby-progressbar (~> 1.7)
|
|
148
|
+
unicode-display_width (>= 1.4.0, < 2.0)
|
|
149
|
+
rubocop-ast (1.4.0)
|
|
150
|
+
parser (>= 2.7.1.5)
|
|
151
|
+
rubocop-performance (1.9.2)
|
|
152
|
+
rubocop (>= 0.90.0, < 2.0)
|
|
153
|
+
rubocop-ast (>= 0.4.0)
|
|
154
|
+
rubocop-rails (2.9.1)
|
|
155
|
+
activesupport (>= 4.2.0)
|
|
156
|
+
rack (>= 1.1)
|
|
157
|
+
rubocop (>= 0.90.0, < 2.0)
|
|
158
|
+
rubocop-rspec (1.44.1)
|
|
159
|
+
rubocop (~> 0.87)
|
|
160
|
+
rubocop-ast (>= 0.7.1)
|
|
161
|
+
ruby-progressbar (1.11.0)
|
|
162
|
+
sass (3.7.4)
|
|
163
|
+
sass-listen (~> 4.0.0)
|
|
164
|
+
sass-listen (4.0.0)
|
|
165
|
+
rb-fsevent (~> 0.9, >= 0.9.4)
|
|
166
|
+
rb-inotify (~> 0.9, >= 0.9.7)
|
|
167
|
+
scss_lint (0.59.0)
|
|
168
|
+
sass (~> 3.5, >= 3.5.5)
|
|
169
|
+
simplecov (0.17.1)
|
|
170
|
+
docile (~> 1.1)
|
|
171
|
+
json (>= 1.8, < 3)
|
|
172
|
+
simplecov-html (~> 0.10.0)
|
|
173
|
+
simplecov-html (0.10.2)
|
|
174
|
+
smart_properties (1.15.0)
|
|
175
|
+
tzinfo (2.0.4)
|
|
176
|
+
concurrent-ruby (~> 1.0)
|
|
177
|
+
unicode-display_width (1.7.0)
|
|
178
|
+
vcr (6.0.0)
|
|
179
|
+
webmock (3.11.1)
|
|
180
|
+
addressable (>= 2.3.6)
|
|
181
|
+
crack (>= 0.3.2)
|
|
182
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
|
183
|
+
yard (0.9.26)
|
|
184
|
+
zeitwerk (2.4.2)
|
|
185
|
+
|
|
186
|
+
PLATFORMS
|
|
187
|
+
ruby
|
|
188
|
+
|
|
189
|
+
DEPENDENCIES
|
|
190
|
+
bundler (~> 2.0)
|
|
191
|
+
niftany (~> 0.6)
|
|
192
|
+
pry (~> 0.12)
|
|
193
|
+
pry-byebug (~> 3.9)
|
|
194
|
+
rake (>= 12.3.3)
|
|
195
|
+
rspec (~> 3.0)
|
|
196
|
+
rspec-its (~> 1.3)
|
|
197
|
+
scholarsphere-client!
|
|
198
|
+
simplecov (< 0.18)
|
|
199
|
+
vcr (~> 6.0)
|
|
200
|
+
webmock (~> 3.11)
|
|
201
|
+
yard (< 1.0)
|
|
202
|
+
|
|
203
|
+
BUNDLED WITH
|
|
204
|
+
2.1.4
|
data/README.md
CHANGED
|
@@ -20,8 +20,60 @@ Or install it yourself as:
|
|
|
20
20
|
|
|
21
21
|
## Usage
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
### Authentication
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
Obtain an api key, and save it to `config/scholarsphere-client.yml`
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
SS4_ENDPOINT: "http://scholarsphere/api/v1"
|
|
28
|
+
SS_CLIENT_KEY: "[key]"
|
|
29
|
+
|
|
30
|
+
If you are using a testing instance, you'll need to disable ssl verification:
|
|
31
|
+
|
|
32
|
+
SS_CLIENT_SSL: "false"
|
|
33
|
+
|
|
34
|
+
### Ingesting
|
|
35
|
+
|
|
36
|
+
To publish a work:
|
|
37
|
+
|
|
38
|
+
metadata = {
|
|
39
|
+
title: "My Awesome Work",
|
|
40
|
+
creators_attributes: [
|
|
41
|
+
{
|
|
42
|
+
display_name: 'Dr. Pat Researcher',
|
|
43
|
+
actor_attributes: {
|
|
44
|
+
psu_id: 'pxr123',
|
|
45
|
+
surname: 'Researcher',
|
|
46
|
+
given_name: 'Pat',
|
|
47
|
+
email: 'pxr123@psu.edu'
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
files = [ File.new('path/to/file') ]
|
|
54
|
+
|
|
55
|
+
depositor = {
|
|
56
|
+
psu_id: 'pxr123',
|
|
57
|
+
surname: 'Researcher',
|
|
58
|
+
given_name: 'Pat',
|
|
59
|
+
email: 'pxr123@psu.edu'
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
ingest = Scholarsphere::Client::Ingest.new(
|
|
63
|
+
metadata: metadata,
|
|
64
|
+
files: files,
|
|
65
|
+
depositor: depositor
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
response = ingest.publish
|
|
69
|
+
|
|
70
|
+
puts response.body
|
|
71
|
+
|
|
72
|
+
{
|
|
73
|
+
"message": "Work was successfully created",
|
|
74
|
+
"url": "/resources/0797e99c-7d4f-4e05-8bf6-86aea1029a6a"
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
## Documentation
|
|
78
|
+
|
|
79
|
+
You can read the [ruby docs](https://www.rubydoc.info/github/psu-stewardship/scholarsphere-client/main) for the latest features.
|
data/lib/scholarsphere/client.rb
CHANGED
|
@@ -7,6 +7,7 @@ require 'scholarsphere/s3'
|
|
|
7
7
|
require 'scholarsphere/client/config'
|
|
8
8
|
require 'scholarsphere/client/ingest'
|
|
9
9
|
require 'scholarsphere/client/collection'
|
|
10
|
+
require 'scholarsphere/client/upload'
|
|
10
11
|
require 'scholarsphere/client/version'
|
|
11
12
|
|
|
12
13
|
module Scholarsphere
|
|
@@ -16,6 +17,7 @@ module Scholarsphere
|
|
|
16
17
|
Config.load_defaults
|
|
17
18
|
|
|
18
19
|
class << self
|
|
20
|
+
# @return [Faraday::Connection] A cached connection to the Scholarsphere API with the provided credentials.
|
|
19
21
|
def connection
|
|
20
22
|
@connection ||= Faraday::Connection.new(
|
|
21
23
|
url: ENV['SS4_ENDPOINT'],
|
|
@@ -27,10 +29,18 @@ module Scholarsphere
|
|
|
27
29
|
)
|
|
28
30
|
end
|
|
29
31
|
|
|
32
|
+
# @return [nil] Resets the client connection when needed.
|
|
33
|
+
def reset
|
|
34
|
+
@connection = nil
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @return [TrueClass, FalseClass] If set to 'false', Faraday will not verify the SSL certificate. This is mostly
|
|
38
|
+
# used for testing. Default is 'true'.
|
|
30
39
|
def verify_ssl?
|
|
31
40
|
ENV['SS_CLIENT_SSL'] != 'false'
|
|
32
41
|
end
|
|
33
42
|
|
|
43
|
+
# @return [String] Alphanumeric API key that grants access to the API.
|
|
34
44
|
def api_key
|
|
35
45
|
ENV['SS_CLIENT_KEY']
|
|
36
46
|
end
|
|
@@ -7,11 +7,16 @@ module Scholarsphere
|
|
|
7
7
|
# Loads the yaml configuration file for the client. The default location is `config/scholarsphere-client.yml` and
|
|
8
8
|
# the client will load this file automatically whenever it is invoked.
|
|
9
9
|
#
|
|
10
|
-
# The configuration file should contain the endpoint of the Scholarsphere API.
|
|
10
|
+
# The configuration file should contain the endpoint of the Scholarsphere API and the API key.
|
|
11
11
|
#
|
|
12
|
-
#
|
|
12
|
+
# ## Required
|
|
13
13
|
#
|
|
14
|
-
# SS4_ENDPOINT:
|
|
14
|
+
# SS4_ENDPOINT: "https://scholarsphere.psu.edu/api/v1"
|
|
15
|
+
# SS_CLIENT_KEY: "[key]"
|
|
16
|
+
#
|
|
17
|
+
# ## Optional
|
|
18
|
+
#
|
|
19
|
+
# SS_CLIENT_SSL: "false"
|
|
15
20
|
#
|
|
16
21
|
class Config
|
|
17
22
|
# @private
|
|
@@ -2,12 +2,98 @@
|
|
|
2
2
|
|
|
3
3
|
module Scholarsphere
|
|
4
4
|
module Client
|
|
5
|
+
##
|
|
6
|
+
#
|
|
7
|
+
# Uploads a complete work into Scholarsphere. If successful, the work will be published and made
|
|
8
|
+
# publicly available.
|
|
9
|
+
#
|
|
10
|
+
# ## Publishing a New Work
|
|
11
|
+
#
|
|
12
|
+
# The most common use case is uploading a single file with the required metadata:
|
|
13
|
+
#
|
|
14
|
+
# ingest = Scholarsphere::Client::Ingest.new(
|
|
15
|
+
# metadata: metadata,
|
|
16
|
+
# files: files,
|
|
17
|
+
# depositor: depositor
|
|
18
|
+
# )
|
|
19
|
+
# response = ingest.publish
|
|
20
|
+
#
|
|
21
|
+
# If the response is successful, the application returns 200 OK with JSON:
|
|
22
|
+
#
|
|
23
|
+
# puts response.body
|
|
24
|
+
# {
|
|
25
|
+
# "message": "Work was successfully created",
|
|
26
|
+
# "url": "/resources/0797e99c-7d4f-4e05-8bf6-86aea1029a6a"
|
|
27
|
+
# }
|
|
28
|
+
#
|
|
29
|
+
# Other possible outcomes include:
|
|
30
|
+
#
|
|
31
|
+
# * work was created, but not successfully published because of missing attributes (201 Created)
|
|
32
|
+
# * work could not be created due to insufficient parameters (422 Unprocessable Entity)
|
|
33
|
+
# * there was an error with the application (500 Internal Server Error)
|
|
34
|
+
#
|
|
35
|
+
# If possible, the response will include additional information about which errors occurred and which attributes are
|
|
36
|
+
# required or are incorrect.
|
|
37
|
+
#
|
|
38
|
+
# ## Metadata
|
|
39
|
+
#
|
|
40
|
+
# A hash of descriptive metadata about the work. The minimal amount required in order to publish would be:
|
|
41
|
+
#
|
|
42
|
+
# {
|
|
43
|
+
# title: "[descriptive title of the work]",
|
|
44
|
+
# creators_attributes: [
|
|
45
|
+
# {
|
|
46
|
+
# display_name: '[Penn State Person]',
|
|
47
|
+
# actor_attributes: {
|
|
48
|
+
# psu_id: 'abc123',
|
|
49
|
+
# surname: '[family name]',
|
|
50
|
+
# given_name: '[given name]',
|
|
51
|
+
# email: 'abc123@psu.edu'
|
|
52
|
+
# }
|
|
53
|
+
# }
|
|
54
|
+
# ]
|
|
55
|
+
# }
|
|
56
|
+
#
|
|
57
|
+
# For a complete listing of all the possible metadata values, see the OpenAPI docs for
|
|
58
|
+
# Scholarsphere.
|
|
59
|
+
#
|
|
60
|
+
# ## Files
|
|
61
|
+
#
|
|
62
|
+
# [
|
|
63
|
+
# Pathname.new('MyPaper.pdf'),
|
|
64
|
+
# Pathname.new('dataset.dat')
|
|
65
|
+
# ]
|
|
66
|
+
#
|
|
67
|
+
# One or more files are required in order for the work be published. The simplest method is an array of `IO`
|
|
68
|
+
# objects. The client then uploads them into S3.
|
|
69
|
+
#
|
|
70
|
+
# *Note: All filenames must have an extension!*
|
|
71
|
+
#
|
|
72
|
+
# ## Depositor
|
|
73
|
+
#
|
|
74
|
+
# {
|
|
75
|
+
# psu_id: '[Penn State Person]',
|
|
76
|
+
# surname: '[family name]',
|
|
77
|
+
# given_name: '[given name]',
|
|
78
|
+
# email: 'abc123@psu.edu'
|
|
79
|
+
# }
|
|
80
|
+
#
|
|
81
|
+
# Currently, the person identified as the depositor must have an active access account at Penn State. In most cases,
|
|
82
|
+
# the depositor will be the same person as the creator specified in the metadata; although, this is not always the
|
|
83
|
+
# case. The depositor may be someone who is uploading on behalf of the creator and is not affiliated with the
|
|
84
|
+
# creation of the work. The depositor is *not* the client itself, either. The client is identified separately via
|
|
85
|
+
# the API token.
|
|
86
|
+
#
|
|
87
|
+
# Note that the fields are the same for both `creators_attributes` and `depositor`, so if the depositor is the same
|
|
88
|
+
# as the creator, all the values will need to be duplicated.
|
|
89
|
+
#
|
|
90
|
+
#
|
|
5
91
|
class Ingest
|
|
6
92
|
attr_reader :content, :metadata, :depositor, :permissions
|
|
7
93
|
|
|
8
94
|
# @param metadata [Hash] Metadata attributes
|
|
9
95
|
# @param files [Array<File,IO,Pathnme>,Hash] An array of File or IO objects, or a hash with a :file param
|
|
10
|
-
# @param depositor [
|
|
96
|
+
# @param depositor [Hash] The name and access id of the depositor
|
|
11
97
|
# @param permissions [Hash] (optional) Additional permissions to apply to the resource
|
|
12
98
|
def initialize(metadata:, files:, depositor:, permissions: {})
|
|
13
99
|
@content = build_content_hash(files)
|
|
@@ -16,6 +102,7 @@ module Scholarsphere
|
|
|
16
102
|
@permissions = permissions
|
|
17
103
|
end
|
|
18
104
|
|
|
105
|
+
# @return [Faraday::Response] The response from the Scholarsphere application.
|
|
19
106
|
def publish
|
|
20
107
|
upload_files
|
|
21
108
|
connection.post do |req|
|
|
@@ -29,24 +116,20 @@ module Scholarsphere
|
|
|
29
116
|
def build_content_hash(files)
|
|
30
117
|
files.map do |file|
|
|
31
118
|
if file.is_a?(Hash)
|
|
32
|
-
file.merge(file: S3::UploadedFile.new(file.fetch(:file)))
|
|
119
|
+
file.merge(file: S3::UploadedFile.new(source: file.fetch(:file)))
|
|
33
120
|
else
|
|
34
|
-
{ file: S3::UploadedFile.new(file) }
|
|
121
|
+
{ file: S3::UploadedFile.new(source: file) }
|
|
35
122
|
end
|
|
36
123
|
end
|
|
37
124
|
end
|
|
38
125
|
|
|
39
126
|
def upload_files
|
|
40
127
|
content.map do |file_parameters|
|
|
41
|
-
|
|
42
|
-
file_parameters[:file] = file_parameters[:file].
|
|
128
|
+
S3::Uploader.new(file: file_parameters.fetch(:file)).upload
|
|
129
|
+
file_parameters[:file] = file_parameters[:file].to_param.to_json
|
|
43
130
|
end
|
|
44
131
|
end
|
|
45
132
|
|
|
46
|
-
def uploader
|
|
47
|
-
@uploader ||= S3::Uploader.new
|
|
48
|
-
end
|
|
49
|
-
|
|
50
133
|
def connection
|
|
51
134
|
Scholarsphere::Client.connection
|
|
52
135
|
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Scholarsphere
|
|
4
|
+
module Client
|
|
5
|
+
##
|
|
6
|
+
#
|
|
7
|
+
# Requests a pre-signed url, id, and prefix from Scholarsphere for uploading a given file. In order to generate a
|
|
8
|
+
# correct path, the file's extension name is required for the request. The url is used to upload the file's binary
|
|
9
|
+
# content into Scholarsphere, while the id and key are used when adding the file to a work.
|
|
10
|
+
#
|
|
11
|
+
class Upload
|
|
12
|
+
# @param extname [String] Extension of the file to be uploaded, without the period, such as 'pdf'
|
|
13
|
+
def initialize(extname:)
|
|
14
|
+
@extname = extname
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# @return [String] Prefix where the file is stored in the S3 bucket.
|
|
18
|
+
def prefix
|
|
19
|
+
data['prefix']
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @return [String] URL for uploading the file into AWS.
|
|
23
|
+
def url
|
|
24
|
+
data['url']
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# @return [String] A unique identifier for the file which will serve as its name in S3.
|
|
28
|
+
def id
|
|
29
|
+
data['id']
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
attr_reader :extname
|
|
35
|
+
|
|
36
|
+
def request
|
|
37
|
+
@request ||= Scholarsphere::Client.connection.post do |req|
|
|
38
|
+
req.url 'uploads'
|
|
39
|
+
req.body = { extension: extname }.to_json
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def data
|
|
44
|
+
@data ||= begin
|
|
45
|
+
raise Client::Error unless request.success?
|
|
46
|
+
|
|
47
|
+
JSON.parse(request.body)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -4,10 +4,10 @@ module Scholarsphere
|
|
|
4
4
|
module S3
|
|
5
5
|
##
|
|
6
6
|
#
|
|
7
|
-
# Represents a file on the client's file system
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# to
|
|
7
|
+
# Represents a file on the client's file system to be uploaded into Scholarsphere. The object is constructed using a
|
|
8
|
+
# pathname for the file, and an optional checksum. Once initialized, the object is used by the client to make
|
|
9
|
+
# additional calls to the application, including uploading the file into S3, and adding the resulting uploaded file
|
|
10
|
+
# to a work in Scholarsphere.
|
|
11
11
|
#
|
|
12
12
|
# ## Examples
|
|
13
13
|
#
|
|
@@ -16,46 +16,38 @@ module Scholarsphere
|
|
|
16
16
|
# pathname = Pathname.new('path/to/your/file')
|
|
17
17
|
# uploaded_file = UploadedFile.new(pathname)
|
|
18
18
|
#
|
|
19
|
-
# If the file is large, then calculating a checksum could be time-intensive. Providing one can avoid that
|
|
19
|
+
# If the file is large, then calculating a checksum could be time-intensive. Providing one can avoid that, or, if
|
|
20
20
|
# you already have a checksum from a trusted source, you can pass that along for the client to use:
|
|
21
21
|
#
|
|
22
22
|
# uploaded_file = UploadedFile.new(pathname, checksum: '[md5 checksum hash]')
|
|
23
23
|
#
|
|
24
|
+
# ## Checksum Verification
|
|
25
|
+
#
|
|
26
|
+
# Checksums are always used. If you don't provide one, the client will calculate one for you and use it when
|
|
27
|
+
# uploading the file, such as with S3::Uploader. AWS uses the provided checksum to verify the file's integrity, and
|
|
28
|
+
# if that check fails, an exception is raised. This avoids the prospect that the file could be corrupted during its
|
|
29
|
+
# transfer from the local client's filesystem into S3.
|
|
30
|
+
#
|
|
24
31
|
class UploadedFile
|
|
25
|
-
# @return [Pathname] The
|
|
32
|
+
# @return [Pathname] The file to be uploaded on the client's filesystem
|
|
26
33
|
attr_reader :source
|
|
27
34
|
|
|
28
|
-
# @param source [Pathname]
|
|
29
|
-
# @param
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
@source = source
|
|
34
|
-
@checksum = options[:checksum]
|
|
35
|
+
# @param source [Pathname, File, IO, String] Object or path to the file
|
|
36
|
+
# @param checksum [String] Optional md5 checksum of the file
|
|
37
|
+
def initialize(source:, checksum: nil)
|
|
38
|
+
@source = Pathname.new(source)
|
|
39
|
+
@checksum = checksum
|
|
35
40
|
end
|
|
36
41
|
|
|
37
|
-
# @return [Hash]
|
|
38
|
-
|
|
39
|
-
def to_shrine
|
|
42
|
+
# @return [Hash] Parameters required to add the file to a work in Scholarsphere
|
|
43
|
+
def to_param
|
|
40
44
|
{
|
|
41
|
-
id: id,
|
|
42
|
-
storage:
|
|
45
|
+
id: upload.id,
|
|
46
|
+
storage: upload.prefix,
|
|
43
47
|
metadata: metadata
|
|
44
48
|
}
|
|
45
49
|
end
|
|
46
50
|
|
|
47
|
-
# @return [String] A unique, randomly-generated UUID
|
|
48
|
-
# @note This serves as the name of the file in the S3 bucket. However, this original name of the file is kept as
|
|
49
|
-
# metadata within the application so that it can be downloaded.
|
|
50
|
-
def id
|
|
51
|
-
@id ||= "#{SecureRandom.uuid}#{source.extname}"
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# @return [String] Path of the file relative to the bucket in S3
|
|
55
|
-
def key
|
|
56
|
-
"#{prefix}/#{id}"
|
|
57
|
-
end
|
|
58
|
-
|
|
59
51
|
# @return [String] The md5 checksum encoded in base64. If you provided a checksum at initialization, that one will
|
|
60
52
|
# be encoded, if not, a checksum will be calculated and then encoded.
|
|
61
53
|
# @note When sending the checksum to verify the file's integrity, Amazon requires that the value be base64
|
|
@@ -70,9 +62,9 @@ module Scholarsphere
|
|
|
70
62
|
end
|
|
71
63
|
end
|
|
72
64
|
|
|
73
|
-
# @return [String]
|
|
74
|
-
def
|
|
75
|
-
|
|
65
|
+
# @return [String] Pre-signed url used to upload the file into Scholarsphere's S3 instance.
|
|
66
|
+
def presigned_url
|
|
67
|
+
upload.url
|
|
76
68
|
end
|
|
77
69
|
|
|
78
70
|
private
|
|
@@ -87,8 +79,8 @@ module Scholarsphere
|
|
|
87
79
|
}
|
|
88
80
|
end
|
|
89
81
|
|
|
90
|
-
def
|
|
91
|
-
|
|
82
|
+
def upload
|
|
83
|
+
@upload ||= Client::Upload.new(extname: source.extname)
|
|
92
84
|
end
|
|
93
85
|
end
|
|
94
86
|
end
|
|
@@ -2,43 +2,43 @@
|
|
|
2
2
|
|
|
3
3
|
module Scholarsphere
|
|
4
4
|
module S3
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
5
|
+
##
|
|
6
|
+
#
|
|
7
|
+
# Uploads a file to Scholarsphere's AWS S3 instance. When upload is invoked, a pre-signed URL is requested from
|
|
8
|
+
# Scholarsphere, and if successful, the file is then uploaded to Scholarsphere using the url.
|
|
9
|
+
#
|
|
10
|
+
# An md5 hash is calculated for the file at initialization to ensure the file is transferred successfully.
|
|
11
|
+
#
|
|
12
|
+
# # Example
|
|
13
|
+
#
|
|
14
|
+
# uploaded_file = Scholarsphere::S3::UploadedFile.new('path/to/file')
|
|
15
|
+
# uploader = Scholarsphere::S3::Uploader(file: uploaded_file)
|
|
16
|
+
# response = uploader.upload
|
|
17
|
+
#
|
|
18
|
+
class Uploader
|
|
19
|
+
# @param file [UploadedFile]
|
|
20
|
+
def initialize(file:)
|
|
21
|
+
@file = file
|
|
22
|
+
@content_md5 = file.content_md5
|
|
16
23
|
end
|
|
17
24
|
|
|
18
|
-
# @
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def upload(uploaded_file, options = {})
|
|
24
|
-
options[:bucket] = ENV['AWS_BUCKET']
|
|
25
|
-
options[:key] = uploaded_file.key
|
|
26
|
-
if uploaded_file.size < multipart_threshold
|
|
27
|
-
options[:content_md5] = uploaded_file.content_md5
|
|
25
|
+
# @return [Faraday::Response] The response from Scholarsphere to the upload request.
|
|
26
|
+
def upload
|
|
27
|
+
connection(file.presigned_url).put do |req|
|
|
28
|
+
req.body = file.source.read
|
|
29
|
+
req.headers['Content-MD5'] = file.content_md5
|
|
28
30
|
end
|
|
29
|
-
super(uploaded_file.source, options)
|
|
30
31
|
end
|
|
31
32
|
|
|
32
33
|
private
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
35
|
+
attr_reader :file, :content_md5
|
|
36
|
+
|
|
37
|
+
def connection(url)
|
|
38
|
+
Faraday::Connection.new(
|
|
39
|
+
url: url,
|
|
40
|
+
ssl: { verify: Scholarsphere::Client.verify_ssl? }
|
|
41
|
+
)
|
|
42
42
|
end
|
|
43
43
|
end
|
|
44
44
|
end
|
|
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
|
|
|
17
17
|
spec.metadata = {
|
|
18
18
|
'homepage_uri' => spec.homepage,
|
|
19
19
|
'source_code_uri' => spec.homepage,
|
|
20
|
-
'
|
|
20
|
+
'documentation_uri' => 'https://www.rubydoc.info/github/psu-stewardship/scholarsphere-client/main',
|
|
21
21
|
'allowed_push_host' => 'https://rubygems.org'
|
|
22
22
|
}
|
|
23
23
|
|
|
@@ -41,6 +41,10 @@ Gem::Specification.new do |spec|
|
|
|
41
41
|
spec.add_development_dependency 'rake', '>= 12.3.3'
|
|
42
42
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
|
43
43
|
spec.add_development_dependency 'rspec-its', '~> 1.3'
|
|
44
|
-
spec.add_development_dependency '
|
|
44
|
+
spec.add_development_dependency 'vcr', '~> 6.0'
|
|
45
|
+
spec.add_development_dependency 'webmock', '~> 3.11'
|
|
45
46
|
spec.add_development_dependency 'yard', '< 1.0'
|
|
47
|
+
|
|
48
|
+
# Latest version of simplecov is not compatible with Code Climate
|
|
49
|
+
spec.add_development_dependency 'simplecov', '< 0.18'
|
|
46
50
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: scholarsphere-client
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Adam Wead
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2021-
|
|
11
|
+
date: 2021-03-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: aws-sdk-s3
|
|
@@ -151,19 +151,33 @@ dependencies:
|
|
|
151
151
|
- !ruby/object:Gem::Version
|
|
152
152
|
version: '1.3'
|
|
153
153
|
- !ruby/object:Gem::Dependency
|
|
154
|
-
name:
|
|
154
|
+
name: vcr
|
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
|
156
156
|
requirements:
|
|
157
157
|
- - "~>"
|
|
158
158
|
- !ruby/object:Gem::Version
|
|
159
|
-
version: '0
|
|
159
|
+
version: '6.0'
|
|
160
160
|
type: :development
|
|
161
161
|
prerelease: false
|
|
162
162
|
version_requirements: !ruby/object:Gem::Requirement
|
|
163
163
|
requirements:
|
|
164
164
|
- - "~>"
|
|
165
165
|
- !ruby/object:Gem::Version
|
|
166
|
-
version: '0
|
|
166
|
+
version: '6.0'
|
|
167
|
+
- !ruby/object:Gem::Dependency
|
|
168
|
+
name: webmock
|
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
|
170
|
+
requirements:
|
|
171
|
+
- - "~>"
|
|
172
|
+
- !ruby/object:Gem::Version
|
|
173
|
+
version: '3.11'
|
|
174
|
+
type: :development
|
|
175
|
+
prerelease: false
|
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
177
|
+
requirements:
|
|
178
|
+
- - "~>"
|
|
179
|
+
- !ruby/object:Gem::Version
|
|
180
|
+
version: '3.11'
|
|
167
181
|
- !ruby/object:Gem::Dependency
|
|
168
182
|
name: yard
|
|
169
183
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -178,6 +192,20 @@ dependencies:
|
|
|
178
192
|
- - "<"
|
|
179
193
|
- !ruby/object:Gem::Version
|
|
180
194
|
version: '1.0'
|
|
195
|
+
- !ruby/object:Gem::Dependency
|
|
196
|
+
name: simplecov
|
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
|
198
|
+
requirements:
|
|
199
|
+
- - "<"
|
|
200
|
+
- !ruby/object:Gem::Version
|
|
201
|
+
version: '0.18'
|
|
202
|
+
type: :development
|
|
203
|
+
prerelease: false
|
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
205
|
+
requirements:
|
|
206
|
+
- - "<"
|
|
207
|
+
- !ruby/object:Gem::Version
|
|
208
|
+
version: '0.18'
|
|
181
209
|
description: Client software to create new content for the Scholarsphere repository
|
|
182
210
|
at Penn State.
|
|
183
211
|
email:
|
|
@@ -186,11 +214,13 @@ executables: []
|
|
|
186
214
|
extensions: []
|
|
187
215
|
extra_rdoc_files: []
|
|
188
216
|
files:
|
|
217
|
+
- ".circleci/config.yml"
|
|
189
218
|
- ".gitignore"
|
|
190
219
|
- ".rspec"
|
|
191
220
|
- ".rubocop.yml"
|
|
192
221
|
- ".yardopts"
|
|
193
222
|
- Gemfile
|
|
223
|
+
- Gemfile.lock
|
|
194
224
|
- README.md
|
|
195
225
|
- Rakefile
|
|
196
226
|
- bin/console
|
|
@@ -200,6 +230,7 @@ files:
|
|
|
200
230
|
- lib/scholarsphere/client/collection.rb
|
|
201
231
|
- lib/scholarsphere/client/config.rb
|
|
202
232
|
- lib/scholarsphere/client/ingest.rb
|
|
233
|
+
- lib/scholarsphere/client/upload.rb
|
|
203
234
|
- lib/scholarsphere/client/version.rb
|
|
204
235
|
- lib/scholarsphere/s3.rb
|
|
205
236
|
- lib/scholarsphere/s3/uploaded_file.rb
|
|
@@ -210,7 +241,7 @@ licenses: []
|
|
|
210
241
|
metadata:
|
|
211
242
|
homepage_uri: https://github.com/psu-stewardship/scholarsphere-client
|
|
212
243
|
source_code_uri: https://github.com/psu-stewardship/scholarsphere-client
|
|
213
|
-
|
|
244
|
+
documentation_uri: https://www.rubydoc.info/github/psu-stewardship/scholarsphere-client/main
|
|
214
245
|
allowed_push_host: https://rubygems.org
|
|
215
246
|
post_install_message:
|
|
216
247
|
rdoc_options: []
|