hyrax 2.5.1 → 2.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +122 -162
- data/README.md +2 -6
- data/app/actors/hyrax/actors/add_to_work_actor.rb +23 -4
- data/app/actors/hyrax/actors/create_with_remote_files_actor.rb +2 -1
- data/app/forms/hyrax/forms/workflow_responsibility_form.rb +3 -3
- data/app/indexers/hyrax/file_set_indexer.rb +6 -0
- data/app/jobs/import_url_job.rb +9 -16
- data/app/jobs/ingest_local_file_job.rb +4 -0
- data/hyrax.gemspec +6 -6
- data/lib/generators/hyrax/install_generator.rb +1 -0
- data/lib/hyrax/configuration.rb +4 -1
- data/lib/hyrax/version.rb +1 -1
- data/spec/actors/hyrax/actors/create_with_remote_files_actor_spec.rb +14 -0
- data/spec/features/actor_stack_spec.rb +29 -0
- data/spec/indexers/hyrax/file_set_indexer_spec.rb +1 -0
- data/spec/jobs/import_url_job_spec.rb +49 -2
- data/spec/jobs/ingest_local_file_job_spec.rb +25 -1
- data/spec/lib/hyrax/configuration_spec.rb +7 -1
- data/spec/spec_helper.rb +8 -4
- data/spec/views/hyrax/file_sets/_versioning.html.erb_spec.rb +1 -0
- data/spec/views/hyrax/my/collections/_list_collections.html.erb_spec.rb +2 -2
- data/template.rb +1 -1
- metadata +23 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2d5150722f3ca96a6fafde49d7cb079bc12e74ec0a535ff26ae2fb1e3b4e6ef6
|
4
|
+
data.tar.gz: 2d4dd842e2d4d0f11889c3b31a9d38935942b102af52ee01b4912a9e13075ed5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e1aeac1be9a34b0d656baba6757285d70d44ab47a46a9a0ab86196098c5c5c8f0e8548295386c624de94d8fe0f359c1a303226ae9fbb7fd2add8604621b6125c
|
7
|
+
data.tar.gz: 9e2e93f81be52b0ea3c7fadab04046de5d5e8f1ec23d02f65f00d7f342f2a0f4881e6fb66e83888f1f81446cb7ac8961740456aecd4f7c5cde405acffa698b63
|
data/.circleci/config.yml
CHANGED
@@ -1,195 +1,155 @@
|
|
1
|
-
# Ruby CircleCI 2.0 configuration file
|
2
|
-
#
|
3
|
-
# Check https://circleci.com/docs/2.0/language-ruby/ for more details
|
4
|
-
#
|
5
1
|
version: 2.1
|
6
|
-
|
7
|
-
|
8
|
-
docker:
|
9
|
-
- image: circleci/ruby:2.5.3
|
10
|
-
working_directory: ~/hyrax
|
11
|
-
environment:
|
12
|
-
BUNDLE_PATH: vendor/bundle
|
13
|
-
BUNDLE_JOBS: 4
|
14
|
-
BUNDLE_RETRY: 3
|
15
|
-
|
2
|
+
orbs:
|
3
|
+
samvera: samvera/circleci-orb@0
|
16
4
|
jobs:
|
17
5
|
bundle:
|
18
|
-
|
6
|
+
parameters:
|
7
|
+
ruby_version:
|
8
|
+
type: string
|
9
|
+
default: 2.5.5
|
10
|
+
bundler_version:
|
11
|
+
type: string
|
12
|
+
default: 1.17.3
|
13
|
+
rails_version:
|
14
|
+
type: string
|
15
|
+
default: '5.2.2'
|
16
|
+
cache_version:
|
17
|
+
type: string
|
18
|
+
default: '1-2.x'
|
19
|
+
executor:
|
20
|
+
name: 'samvera/ruby'
|
21
|
+
ruby_version: << parameters.ruby_version >>
|
22
|
+
resource_class: medium+
|
23
|
+
environment:
|
24
|
+
RAILS_VERSION: << parameters.rails_version >>
|
25
|
+
NOKOGIRI_USE_SYSTEM_LIBRARIES: true
|
19
26
|
steps:
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
paths:
|
31
|
-
- ".git"
|
32
|
-
|
33
|
-
- restore_cache:
|
34
|
-
keys:
|
35
|
-
- v1-bundle-{{ checksum "Gemfile" }}--{{ checksum "hyrax.gemspec" }}
|
36
|
-
- v1-bundle
|
37
|
-
|
38
|
-
- run:
|
39
|
-
name: Install dependencies
|
40
|
-
command: bundle check || bundle install
|
41
|
-
|
42
|
-
- save_cache:
|
43
|
-
key: v1-bundle-{{ checksum "Gemfile.lock" }}--{{ checksum "hyrax.gemspec" }}
|
44
|
-
paths:
|
45
|
-
- ~/hyrax/vendor/bundle
|
46
|
-
|
47
|
-
- persist_to_workspace:
|
48
|
-
root: ~/
|
49
|
-
paths:
|
50
|
-
- hyrax/*
|
51
|
-
- hyrax/**/*
|
27
|
+
- samvera/cached_checkout
|
28
|
+
- samvera/bundle_for_gem:
|
29
|
+
ruby_version: << parameters.ruby_version >>
|
30
|
+
bundler_version: << parameters.bundler_version >>
|
31
|
+
project: hyrax
|
32
|
+
- persist_to_workspace:
|
33
|
+
root: ~/
|
34
|
+
paths:
|
35
|
+
- project/*
|
36
|
+
- project/**/*
|
52
37
|
|
53
38
|
lint:
|
54
|
-
|
39
|
+
parameters:
|
40
|
+
ruby_version:
|
41
|
+
type: string
|
42
|
+
default: 2.5.5
|
43
|
+
cache_version:
|
44
|
+
type: string
|
45
|
+
default: '1-2.x'
|
46
|
+
executor:
|
47
|
+
name: 'samvera/ruby'
|
48
|
+
ruby_version: << parameters.ruby_version >>
|
49
|
+
resource_class: medium+
|
55
50
|
steps:
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
- run:
|
60
|
-
name: Call Rubocop
|
61
|
-
command: bundle exec rubocop
|
51
|
+
- attach_workspace:
|
52
|
+
at: ~/
|
53
|
+
- samvera/rubocop
|
62
54
|
|
63
55
|
build:
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
56
|
+
parameters:
|
57
|
+
ruby_version:
|
58
|
+
type: string
|
59
|
+
default: 2.5.5
|
60
|
+
bundler_version:
|
61
|
+
type: string
|
62
|
+
default: 1.17.3
|
63
|
+
rails_version:
|
64
|
+
type: string
|
65
|
+
default: '5.2.2'
|
66
|
+
cache_version:
|
67
|
+
type: string
|
68
|
+
default: '1-2.x'
|
69
|
+
executor:
|
70
|
+
name: 'samvera/ruby'
|
71
|
+
ruby_version: << parameters.ruby_version >>
|
72
|
+
resource_class: medium+
|
69
73
|
environment:
|
70
|
-
|
71
|
-
BUNDLE_JOBS: 4
|
72
|
-
BUNDLE_RETRY: 3
|
73
|
-
RAILS_ENV: test
|
74
|
-
RACK_ENV: test
|
75
|
-
FCREPO_TEST_PORT: 8080/fcrepo
|
74
|
+
RAILS_VERSION: << parameters.rails_version >>
|
76
75
|
NOKOGIRI_USE_SYSTEM_LIBRARIES: true
|
77
76
|
ENGINE_CART_RAILS_OPTIONS: --skip-git --skip-bundle --skip-listen --skip-spring --skip-yarn --skip-keeps --skip-action-cable --skip-coffee --skip-puma --skip-test
|
78
|
-
SPEC_OPTS: --profile 10 --format RspecJunitFormatter --out /tmp/test-results/rspec.xml --format progress
|
79
|
-
COVERALLS_PARALLEL: true
|
80
|
-
|
81
77
|
steps:
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
command: bundle check || bundle install
|
97
|
-
|
98
|
-
- run:
|
99
|
-
name: Generate test app
|
100
|
-
command: (git diff --name-only master | grep -qG 'generators\/hyrax') || bundle exec rake engine_cart:generate
|
101
|
-
|
102
|
-
- run:
|
103
|
-
name: Ensure test app dependencies are installed
|
104
|
-
command: |
|
105
|
-
cd .internal_test_app
|
106
|
-
bundle check || bundle install
|
107
|
-
|
108
|
-
- save_cache:
|
109
|
-
key: v1-test-app-{{ checksum "template.rb" }}--{{ checksum "Gemfile.lock" }}
|
110
|
-
paths:
|
111
|
-
- ".internal_test_app"
|
112
|
-
|
113
|
-
- persist_to_workspace:
|
114
|
-
root: ~/
|
115
|
-
paths:
|
116
|
-
- hyrax/*
|
117
|
-
- hyrax/**/*
|
78
|
+
- attach_workspace:
|
79
|
+
at: ~/
|
80
|
+
- samvera/engine_cart_generate:
|
81
|
+
cache_key: v<< parameters.cache_version >>--internal-test-app-{{ checksum "hyrax.gemspec" }}-{{ checksum "spec/test_app_templates/lib/generators/test_app_generator.rb" }}-{{ checksum "lib/generators/hyrax/install_generator.rb" }}-<< parameters.rails_version >>-<< parameters.ruby_version >>
|
82
|
+
- samvera/bundle_for_gem:
|
83
|
+
ruby_version: << parameters.ruby_version >>
|
84
|
+
bundler_version: << parameters.bundler_version >>
|
85
|
+
cache_version: << parameters.cache_version >>
|
86
|
+
project: hyrax
|
87
|
+
- persist_to_workspace:
|
88
|
+
root: ~/
|
89
|
+
paths:
|
90
|
+
- project/*
|
91
|
+
- project/**/*
|
118
92
|
|
119
93
|
test:
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
94
|
+
parameters:
|
95
|
+
ruby_version:
|
96
|
+
type: string
|
97
|
+
default: 2.5.5
|
98
|
+
bundler_version:
|
99
|
+
type: string
|
100
|
+
default: 1.17.3
|
101
|
+
cache_version:
|
102
|
+
type: string
|
103
|
+
default: '1-2.x'
|
104
|
+
executor:
|
105
|
+
name: 'samvera/ruby_fcrepo_solr_redis'
|
106
|
+
ruby_version: << parameters.ruby_version >>
|
107
|
+
resource_class: medium+
|
108
|
+
parallelism: 10
|
132
109
|
environment:
|
133
|
-
BUNDLE_PATH: vendor/bundle
|
134
|
-
BUNDLE_JOBS: 4
|
135
|
-
BUNDLE_RETRY: 3
|
136
|
-
RAILS_ENV: test
|
137
|
-
RACK_ENV: test
|
138
|
-
FCREPO_TEST_PORT: 8080/fcrepo
|
139
|
-
NOKOGIRI_USE_SYSTEM_LIBRARIES: true
|
140
|
-
ENGINE_CART_RAILS_OPTIONS: --skip-git --skip-bundle --skip-listen --skip-spring --skip-yarn --skip-keeps --skip-action-cable --skip-coffee --skip-puma --skip-test
|
141
|
-
SPEC_OPTS: --profile 10 --format RspecJunitFormatter --out /tmp/test-results/rspec.xml --format progress
|
142
110
|
COVERALLS_PARALLEL: true
|
143
|
-
|
144
111
|
steps:
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
- run:
|
157
|
-
name: Install chromedriver Gems
|
158
|
-
command: gem install chromedriver-helper
|
159
|
-
|
160
|
-
- run:
|
161
|
-
name: Load config into solr
|
162
|
-
command: |
|
163
|
-
cd .internal_test_app/solr/config
|
164
|
-
zip -1 -r solr_hyrax_config.zip ./*
|
165
|
-
curl -H "Content-type:application/octet-stream" --data-binary @solr_hyrax_config.zip "http://localhost:8985/solr/admin/configs?action=UPLOAD&name=hyrax"
|
166
|
-
curl -H 'Content-type: application/json' http://localhost:8985/api/collections/ -d '{create: {name: hydra-test, config: hyrax, numShards: 1}}'
|
167
|
-
|
168
|
-
- run:
|
169
|
-
name: Run rspec in parallel
|
170
|
-
command: |
|
171
|
-
mkdir /tmp/test-results
|
172
|
-
bundle exec rspec $(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)
|
173
|
-
|
174
|
-
# collect reports
|
175
|
-
- store_test_results:
|
176
|
-
path: /tmp/test-results
|
177
|
-
- store_artifacts:
|
178
|
-
path: /tmp/test-results
|
179
|
-
destination: test-results
|
112
|
+
- attach_workspace:
|
113
|
+
at: ~/
|
114
|
+
- samvera/install_solr_core:
|
115
|
+
solr_config_path: .internal_test_app/solr/config
|
116
|
+
# Rerun bundler in case this is a different ruby version than bundle and build steps
|
117
|
+
- samvera/bundle_for_gem:
|
118
|
+
ruby_version: << parameters.ruby_version >>
|
119
|
+
bundler_version: << parameters.bundler_version >>
|
120
|
+
cache_version: << parameters.cache_version >>
|
121
|
+
project: hyrax
|
122
|
+
- samvera/parallel_rspec
|
180
123
|
|
181
124
|
workflows:
|
182
125
|
version: 2
|
183
126
|
ci:
|
184
127
|
jobs:
|
185
|
-
- bundle
|
128
|
+
- bundle:
|
129
|
+
ruby_version: "2.5.5"
|
130
|
+
rails_version: "5.1.7"
|
131
|
+
cache_version: "1-2.x"
|
186
132
|
- lint:
|
133
|
+
ruby_version: "2.5.5"
|
134
|
+
cache_version: "1-2.x"
|
187
135
|
requires:
|
188
136
|
- bundle
|
189
137
|
- build:
|
138
|
+
ruby_version: "2.5.5"
|
139
|
+
rails_version: "5.1.7"
|
140
|
+
cache_version: "1-2.x"
|
190
141
|
requires:
|
191
142
|
- bundle
|
192
143
|
- test:
|
144
|
+
name: "ruby2-5-5"
|
145
|
+
ruby_version: "2.5.5"
|
146
|
+
requires:
|
147
|
+
- build
|
148
|
+
- lint
|
149
|
+
- test:
|
150
|
+
name: "ruby2-6-2"
|
151
|
+
ruby_version: "2.6.2"
|
152
|
+
cache_version: "1-2.x"
|
193
153
|
requires:
|
194
154
|
- build
|
195
155
|
- lint
|
data/README.md
CHANGED
@@ -67,10 +67,6 @@ v2.5.0__. If you are looking for instructions on installing a different
|
|
67
67
|
version, be sure to select the appropriate branch or tag from the drop-down
|
68
68
|
menu above.
|
69
69
|
|
70
|
-
## Quickstart
|
71
|
-
|
72
|
-
If you're looking to spin up a vanilla Hyrax application very quickly for demonstration purposes, you may be interested in [the samvera-vagrant project](https://github.com/samvera-labs/samvera-vagrant) which may be used to "kick the tires" of Hyrax and [Hyku](https://github.com/samvera-labs/hyku). It requires VirtualBox and Vagrant.
|
73
|
-
|
74
70
|
## Prerequisites
|
75
71
|
|
76
72
|
Prerequisites are required for both creating a Hyrax\-based app and contributing new features to Hyrax. After installing the prerequisites...
|
@@ -118,7 +114,7 @@ Hyrax includes support for transcoding audio and video files with ffmpeg > 1.0 i
|
|
118
114
|
|
119
115
|
On OSX, you can use Homebrew to install ffmpeg:
|
120
116
|
|
121
|
-
`brew install
|
117
|
+
`brew install libvpx ffmpeg`
|
122
118
|
|
123
119
|
Otherwise, to compile ffmpeg yourself, see the [ffmpeg compilation guide](https://trac.ffmpeg.org/wiki/CompilationGuide).
|
124
120
|
|
@@ -162,7 +158,7 @@ NOTE: The steps need to be done in order to create a new Hyrax based app.
|
|
162
158
|
Generate a new Rails application using the template.
|
163
159
|
|
164
160
|
```
|
165
|
-
rails _5.1.6_ new my_app -m https://raw.githubusercontent.com/samvera/hyrax/v2.
|
161
|
+
rails _5.1.6_ new my_app -m https://raw.githubusercontent.com/samvera/hyrax/v2.6.0/template.rb
|
166
162
|
```
|
167
163
|
|
168
164
|
Generating a new Rails application using Hyrax's template above takes cares of a number of steps for you, including:
|
@@ -5,7 +5,8 @@ module Hyrax
|
|
5
5
|
# @return [Boolean] true if create was successful
|
6
6
|
def create(env)
|
7
7
|
work_ids = env.attributes.delete(:in_works_ids)
|
8
|
-
|
8
|
+
|
9
|
+
can_edit_works?(env, work_ids) && next_actor.create(env) && add_to_works(env, work_ids)
|
9
10
|
end
|
10
11
|
|
11
12
|
# @param [Hyrax::Actors::Environment] env
|
@@ -21,6 +22,15 @@ module Hyrax
|
|
21
22
|
env.current_ability.can?(:edit, work) && env.current_ability.can?(:edit, env.curation_concern)
|
22
23
|
end
|
23
24
|
|
25
|
+
def can_edit_works?(env, work_ids)
|
26
|
+
unless Array(work_ids).all? { |work_id| env.current_ability.can?(:edit, work_id) }
|
27
|
+
add_permissions_error(env.curation_concern)
|
28
|
+
return false
|
29
|
+
end
|
30
|
+
|
31
|
+
true
|
32
|
+
end
|
33
|
+
|
24
34
|
def add_to_works(env, new_work_ids)
|
25
35
|
return true if new_work_ids.nil?
|
26
36
|
cleanup_ids_to_remove_from_curation_concern(env, new_work_ids)
|
@@ -39,16 +49,25 @@ module Hyrax
|
|
39
49
|
|
40
50
|
def add_new_work_ids_not_already_in_curation_concern(env, new_work_ids)
|
41
51
|
# add to new so long as the depositor for the parent and child matches, otherwise inject an error
|
42
|
-
(new_work_ids
|
43
|
-
work = ::ActiveFedora::Base.find(work_id)
|
52
|
+
new_works_for(env, new_work_ids).each do |work|
|
44
53
|
if can_edit_both_works?(env, work)
|
45
54
|
work.ordered_members << env.curation_concern
|
46
55
|
work.save!
|
47
56
|
else
|
48
|
-
env.curation_concern
|
57
|
+
add_permissions_error(env.curation_concern)
|
49
58
|
end
|
50
59
|
end
|
51
60
|
end
|
61
|
+
|
62
|
+
def new_works_for(env, new_work_ids)
|
63
|
+
(new_work_ids - env.curation_concern.in_works_ids).map do |work_id|
|
64
|
+
::ActiveFedora::Base.find(work_id)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def add_permissions_error(work)
|
69
|
+
work.errors[:in_works_ids] << "Works can only be related to each other if user has ability to edit both."
|
70
|
+
end
|
52
71
|
end
|
53
72
|
end
|
54
73
|
end
|
@@ -64,7 +64,8 @@ module Hyrax
|
|
64
64
|
# Generic utility for creating FileSet from a URL
|
65
65
|
# Used in to import files using URLs from a file picker like browse_everything
|
66
66
|
def create_file_from_url(env, uri, file_name, auth_header = {})
|
67
|
-
|
67
|
+
import_url = URI.decode_www_form_component(uri.to_s)
|
68
|
+
::FileSet.new(import_url: import_url, label: file_name) do |fs|
|
68
69
|
actor = Hyrax::Actors::FileSetActor.new(fs, env.user)
|
69
70
|
actor.create_metadata(visibility: env.curation_concern.visibility)
|
70
71
|
actor.attach_to_work(env.curation_concern)
|
@@ -12,9 +12,9 @@ module Hyrax
|
|
12
12
|
@model ||= Sipity::WorkflowResponsibility.new
|
13
13
|
end
|
14
14
|
|
15
|
-
def to_model
|
16
|
-
|
17
|
-
end
|
15
|
+
# def to_model
|
16
|
+
# model_instance
|
17
|
+
# end
|
18
18
|
|
19
19
|
delegate :model_name, :to_key, :workflow_role_id, :persisted?, :save!, to: :model_instance
|
20
20
|
|
@@ -27,6 +27,7 @@ module Hyrax
|
|
27
27
|
solr_doc['duration_tesim'] = object.duration
|
28
28
|
solr_doc['sample_rate_tesim'] = object.sample_rate
|
29
29
|
solr_doc['original_checksum_tesim'] = object.original_checksum
|
30
|
+
solr_doc['original_file_id_ssi'] = original_file_id
|
30
31
|
end
|
31
32
|
end
|
32
33
|
|
@@ -37,6 +38,11 @@ module Hyrax
|
|
37
38
|
object.original_file.digest.first.to_s
|
38
39
|
end
|
39
40
|
|
41
|
+
def original_file_id
|
42
|
+
return unless object.original_file
|
43
|
+
object.original_file.id
|
44
|
+
end
|
45
|
+
|
40
46
|
def file_format
|
41
47
|
if object.mime_type.present? && object.format_label.present?
|
42
48
|
"#{object.mime_type.split('/').last} (#{object.format_label.join(', ')})"
|
data/app/jobs/import_url_job.rb
CHANGED
@@ -21,17 +21,19 @@ class ImportUrlJob < Hyrax::ApplicationJob
|
|
21
21
|
operation.performing!
|
22
22
|
user = User.find_by_user_key(file_set.depositor)
|
23
23
|
uri = URI(file_set.import_url)
|
24
|
+
name = file_set.label
|
25
|
+
|
24
26
|
@file_set = file_set
|
25
27
|
@operation = operation
|
26
28
|
|
27
|
-
unless can_retrieve?(uri)
|
29
|
+
unless BrowseEverything::Retriever.can_retrieve?(uri, headers)
|
28
30
|
send_error('Expired URL')
|
29
31
|
return false
|
30
32
|
end
|
31
33
|
|
32
34
|
# @todo Use Hydra::Works::AddExternalFileToFileSet instead of manually
|
33
35
|
# copying the file here. This will be gnarly.
|
34
|
-
copy_remote_file(uri, headers) do |f|
|
36
|
+
copy_remote_file(uri, name, headers) do |f|
|
35
37
|
# reload the FileSet once the data is copied since this is a long running task
|
36
38
|
file_set.reload
|
37
39
|
|
@@ -44,25 +46,16 @@ class ImportUrlJob < Hyrax::ApplicationJob
|
|
44
46
|
|
45
47
|
private
|
46
48
|
|
47
|
-
# The previous strategy of using only a HEAD request to check the validity of a
|
48
|
-
# remote URL fails for Amazon S3 pre-signed URLs. S3 URLs are generated for a single
|
49
|
-
# verb only (in this case, GET), and will return a 403 Forbidden response if any
|
50
|
-
# other verb is used. The workaround is to issue a GET request instead, with a
|
51
|
-
# Range: header requesting only the first byte. The successful response status
|
52
|
-
# code is 206 instead of 200, but that is enough to satisfy the #success? method.
|
53
|
-
# @param uri [URI] the uri of the file to be downloaded
|
54
|
-
def can_retrieve?(uri)
|
55
|
-
HTTParty.get(uri, headers: { Range: 'bytes=0-0' }).success?
|
56
|
-
end
|
57
|
-
|
58
49
|
# Download file from uri, yields a block with a file in a temporary directory.
|
59
50
|
# It is important that the file on disk has the same file name as the URL,
|
60
51
|
# because when the file in added into Fedora the file name will get persisted in the
|
61
52
|
# metadata.
|
62
53
|
# @param uri [URI] the uri of the file to download
|
54
|
+
# @param name [String] the human-readable name of the file
|
55
|
+
# @param headers [Hash] the HTTP headers for the GET request (these may contain an authentication token)
|
63
56
|
# @yield [IO] the stream to write to
|
64
|
-
def copy_remote_file(uri, headers = {})
|
65
|
-
filename = File.basename(
|
57
|
+
def copy_remote_file(uri, name, headers = {})
|
58
|
+
filename = File.basename(name)
|
66
59
|
dir = Dir.mktmpdir
|
67
60
|
Rails.logger.debug("ImportUrlJob: Copying <#{uri}> to #{dir}")
|
68
61
|
|
@@ -92,7 +85,7 @@ class ImportUrlJob < Hyrax::ApplicationJob
|
|
92
85
|
# @param f [IO] the stream to write to
|
93
86
|
def write_file(uri, f, headers)
|
94
87
|
retriever = BrowseEverything::Retriever.new
|
95
|
-
uri_spec =
|
88
|
+
uri_spec = ActiveSupport::HashWithIndifferentAccess.new(url: uri, headers: headers)
|
96
89
|
retriever.retrieve(uri_spec) do |chunk|
|
97
90
|
f.write(chunk)
|
98
91
|
end
|
@@ -14,5 +14,9 @@ class IngestLocalFileJob < Hyrax::ApplicationJob
|
|
14
14
|
else
|
15
15
|
Hyrax.config.callback.run(:after_import_local_file_failure, file_set, user, path)
|
16
16
|
end
|
17
|
+
rescue SystemCallError
|
18
|
+
# This is generic in order to handle Errno constants raised when accessing files
|
19
|
+
# @see https://ruby-doc.org/core-2.5.3/Errno.html
|
20
|
+
Hyrax.config.callback.run(:after_import_local_file_failure, file_set, user, path)
|
17
21
|
end
|
18
22
|
end
|
data/hyrax.gemspec
CHANGED
@@ -37,8 +37,7 @@ SUMMARY
|
|
37
37
|
spec.add_dependency 'blacklight', '~> 6.14'
|
38
38
|
spec.add_dependency 'blacklight-gallery', '~> 0.7'
|
39
39
|
spec.add_dependency 'breadcrumbs_on_rails', '~> 3.0'
|
40
|
-
|
41
|
-
spec.add_dependency 'browse-everything', '< 0.16'
|
40
|
+
spec.add_dependency 'browse-everything', '>= 0.16'
|
42
41
|
spec.add_dependency 'carrierwave', '~> 1.0'
|
43
42
|
spec.add_dependency 'clipboard-rails', '~> 1.5'
|
44
43
|
spec.add_dependency 'dry-equalizer', '~> 0.2'
|
@@ -50,7 +49,7 @@ SUMMARY
|
|
50
49
|
spec.add_dependency 'flot-rails', '~> 0.0.6'
|
51
50
|
spec.add_dependency 'font-awesome-rails', '~> 4.2'
|
52
51
|
spec.add_dependency 'hydra-derivatives', '~> 3.3'
|
53
|
-
spec.add_dependency 'hydra-editor', '>= 3.3', '<
|
52
|
+
spec.add_dependency 'hydra-editor', '>= 3.3', '< 6.0'
|
54
53
|
spec.add_dependency 'hydra-head', '>= 10.6.1'
|
55
54
|
spec.add_dependency 'hydra-works', '>= 0.16', '< 2.0'
|
56
55
|
spec.add_dependency 'iiif_manifest', '>= 0.3', '< 0.6'
|
@@ -105,12 +104,13 @@ SUMMARY
|
|
105
104
|
spec.add_development_dependency 'bixby', '~> 1.0.0'
|
106
105
|
spec.add_development_dependency 'shoulda-callback-matchers', '~> 1.1.1'
|
107
106
|
spec.add_development_dependency 'shoulda-matchers', '~> 3.1'
|
107
|
+
spec.add_development_dependency 'webdrivers', '~> 3.0'
|
108
108
|
spec.add_development_dependency 'webmock'
|
109
109
|
|
110
110
|
########################################################
|
111
111
|
# Temporarily pinned dependencies. INCLUDE EXPLANATIONS.
|
112
112
|
#
|
113
|
-
#
|
114
|
-
#
|
115
|
-
spec.add_dependency '
|
113
|
+
# Pin sass-rails to 5.x because rails 5.x apps have this same dependency in their generated Gemfiles
|
114
|
+
# See https://github.com/samvera/hyrax/issues/3919
|
115
|
+
spec.add_dependency 'sass-rails', '~> 5.0'
|
116
116
|
end
|
data/lib/hyrax/configuration.rb
CHANGED
@@ -189,7 +189,10 @@ module Hyrax
|
|
189
189
|
def whitelisted_ingest_dirs
|
190
190
|
@whitelisted_ingest_dirs ||= \
|
191
191
|
if defined? BrowseEverything
|
192
|
-
Array.wrap(BrowseEverything.config['file_system'].try(:[], :home)).compact
|
192
|
+
file_system_dirs = Array.wrap(BrowseEverything.config['file_system'].try(:[], :home)).compact
|
193
|
+
# Include the Rails tmp directory for cases where the BrowseEverything provider is required to download the file to a temporary directory first
|
194
|
+
tmp_dir = [Rails.root.join('tmp').to_s]
|
195
|
+
file_system_dirs + tmp_dir
|
193
196
|
else
|
194
197
|
[]
|
195
198
|
end
|
data/lib/hyrax/version.rb
CHANGED
@@ -44,6 +44,20 @@ RSpec.describe Hyrax::Actors::CreateWithRemoteFilesActor do
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
+
context "with source URIs that are remote and contain encoded parameters" do
|
48
|
+
let(:url1) { "https://dl.dropbox.com/fake/file?param1=%28example%29¶m2=%5Bexample2%5D" }
|
49
|
+
|
50
|
+
before do
|
51
|
+
allow(::FileSet).to receive(:new).and_call_original
|
52
|
+
end
|
53
|
+
|
54
|
+
it "preserves the encoded parameters in the URIs" do
|
55
|
+
expect(ImportUrlJob).to receive(:perform_later).with(FileSet, Hyrax::Operation, {}).twice
|
56
|
+
expect(actor.create(environment)).to be true
|
57
|
+
expect(::FileSet).to have_received(:new).with(import_url: "https://dl.dropbox.com/fake/file?param1=%28example%29¶m2=%5Bexample2%5D", label: "filepicker-demo.txt.txt")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
47
61
|
context "with source uris that are remote bearing auth headers" do
|
48
62
|
let(:remote_files) do
|
49
63
|
[{ url: url1,
|
@@ -26,6 +26,35 @@ RSpec.describe Hyrax::DefaultMiddlewareStack, :clean_repo do
|
|
26
26
|
.to true
|
27
27
|
end
|
28
28
|
|
29
|
+
context 'when adding to a work' do
|
30
|
+
let(:other_work) { FactoryBot.create(:work, user: user) }
|
31
|
+
let(:attributes) { { 'in_works_ids' => [other_work.id] } }
|
32
|
+
|
33
|
+
context 'when the user cannot edit the parent work' do
|
34
|
+
let(:other_work) { FactoryBot.create(:work, user: other_user) }
|
35
|
+
let(:other_user) { FactoryBot.create(:user) }
|
36
|
+
|
37
|
+
it 'fails' do
|
38
|
+
expect { actor.create(env) }
|
39
|
+
.not_to change { other_work.reload.members.to_a }
|
40
|
+
.from be_empty
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'does not create the work' do
|
44
|
+
expect { actor.create(env) }
|
45
|
+
.not_to change { work.persisted? }
|
46
|
+
.from false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'adds the work to the parent' do
|
51
|
+
expect { actor.create(env) }
|
52
|
+
.to change { other_work.reload.members.to_a }
|
53
|
+
.from(be_empty)
|
54
|
+
.to contain_exactly(work)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
29
58
|
context 'when failing on the way back up the actor stack' do
|
30
59
|
before { stack.insert_before(Hyrax::Actors::ModelActor, delayed_failure_actor) }
|
31
60
|
|
@@ -92,6 +92,7 @@ RSpec.describe Hyrax::FileSetIndexer do
|
|
92
92
|
expect(subject['file_title_tesim']).to eq ['title']
|
93
93
|
expect(subject['duration_tesim']).to eq ['0:1']
|
94
94
|
expect(subject['sample_rate_tesim']).to eq ['sample rate']
|
95
|
+
expect(subject['original_file_id_ssi']).to eq file_set.original_file.id
|
95
96
|
end
|
96
97
|
end
|
97
98
|
|
@@ -3,10 +3,11 @@ RSpec.describe ImportUrlJob do
|
|
3
3
|
|
4
4
|
let(:file_path) { fixture_path + '/world.png' }
|
5
5
|
let(:file_hash) { '/673467823498723948237462429793840923582' }
|
6
|
+
let(:label) { file_path }
|
6
7
|
|
7
8
|
let(:file_set) do
|
8
9
|
FileSet.new(import_url: "http://example.org#{file_hash}",
|
9
|
-
label:
|
10
|
+
label: label) do |f|
|
10
11
|
f.apply_depositor_metadata(user.user_key)
|
11
12
|
end
|
12
13
|
end
|
@@ -74,7 +75,21 @@ RSpec.describe ImportUrlJob do
|
|
74
75
|
|
75
76
|
it 'leaves the temp directory in place' do
|
76
77
|
described_class.perform_now(file_set, operation)
|
77
|
-
|
78
|
+
file_name = File.basename(file_set.label)
|
79
|
+
expect(File.exist?(File.join(tmpdir, file_name))).to be true
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'when the FileSet has an existing label' do
|
83
|
+
let(:label) { "example.tif" }
|
84
|
+
before do
|
85
|
+
allow(Rails.logger).to receive(:debug)
|
86
|
+
end
|
87
|
+
it 'uses the FileSet label' do
|
88
|
+
described_class.perform_now(file_set, operation)
|
89
|
+
tmp_file_path = Rails.root.join(tmpdir, label)
|
90
|
+
expect(Rails.logger).to have_received(:debug).with("ImportUrlJob: Closing #{tmp_file_path}")
|
91
|
+
expect(File.exist?(tmp_file_path.to_s)).to be true
|
92
|
+
end
|
78
93
|
end
|
79
94
|
end
|
80
95
|
|
@@ -130,4 +145,36 @@ RSpec.describe ImportUrlJob do
|
|
130
145
|
expect(last_message.body).to eq("Error: Timeout")
|
131
146
|
end
|
132
147
|
end
|
148
|
+
|
149
|
+
context 'when the URL to the remote file has headers' do
|
150
|
+
let(:import_url) { "http://example.org#{file_hash}" }
|
151
|
+
let(:headers) do
|
152
|
+
{
|
153
|
+
"Authorization" => "OAuth <ACCESS_TOKEN>"
|
154
|
+
}
|
155
|
+
end
|
156
|
+
let(:file_set) do
|
157
|
+
FileSet.new(import_url: import_url, label: file_path) do |f|
|
158
|
+
f.apply_depositor_metadata(user.user_key)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
let(:operation) { create(:operation) }
|
162
|
+
let(:import_uri) { URI(import_url) }
|
163
|
+
|
164
|
+
before do
|
165
|
+
allow(BrowseEverything::Retriever).to receive(:can_retrieve?).and_return(true)
|
166
|
+
described_class.perform_now(file_set, operation, headers)
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'submits a request to the cloud server with auth headers' do
|
170
|
+
expect(BrowseEverything::Retriever).to have_received(:can_retrieve?).with(import_uri, headers)
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'retrieves the cloud server resources with the auth headers' do
|
174
|
+
expect(mock_retriever).to have_received(:retrieve).with(
|
175
|
+
"url" => import_uri,
|
176
|
+
"headers" => headers
|
177
|
+
)
|
178
|
+
end
|
179
|
+
end
|
133
180
|
end
|
@@ -3,6 +3,9 @@ RSpec.describe IngestLocalFileJob do
|
|
3
3
|
|
4
4
|
let(:file_set) { FileSet.new }
|
5
5
|
let(:actor) { double }
|
6
|
+
let(:path) do
|
7
|
+
File.join(fixture_path, 'world.png')
|
8
|
+
end
|
6
9
|
|
7
10
|
before do
|
8
11
|
allow(Hyrax::Actors::FileSetActor).to receive(:new).with(file_set, user).and_return(actor)
|
@@ -11,6 +14,27 @@ RSpec.describe IngestLocalFileJob do
|
|
11
14
|
it 'has attached a file' do
|
12
15
|
expect(FileUtils).not_to receive(:rm)
|
13
16
|
expect(actor).to receive(:create_content).and_return(true)
|
14
|
-
described_class.perform_now(file_set,
|
17
|
+
described_class.perform_now(file_set, path, user)
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when an error is encountered when trying to save the file to disk' do
|
21
|
+
let(:callback) do
|
22
|
+
instance_double(Hyrax::Callbacks::Registry)
|
23
|
+
end
|
24
|
+
let(:config) do
|
25
|
+
instance_double(Hyrax::Configuration)
|
26
|
+
end
|
27
|
+
|
28
|
+
before do
|
29
|
+
allow(callback).to receive(:run)
|
30
|
+
allow(config).to receive(:callback).and_return(callback)
|
31
|
+
allow(Hyrax).to receive(:config).and_return(config)
|
32
|
+
allow(actor).to receive(:create_content).and_raise(SystemCallError, "example file system error")
|
33
|
+
described_class.perform_now(file_set, path, user)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "invokes the file failure callback" do
|
37
|
+
expect(callback).to have_received(:run).with(:after_import_local_file_failure, file_set, user, path)
|
38
|
+
end
|
15
39
|
end
|
16
40
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
RSpec.describe Hyrax::Configuration do
|
2
|
-
subject { described_class.new }
|
2
|
+
subject(:configuration) { described_class.new }
|
3
3
|
|
4
4
|
describe '#register_roles' do
|
5
5
|
it 'yields a RoleRegistry' do
|
@@ -82,4 +82,10 @@ RSpec.describe Hyrax::Configuration do
|
|
82
82
|
it { is_expected.to respond_to(:default_nested_relationship_reindexer) }
|
83
83
|
it { is_expected.to respond_to(:whitelisted_ingest_dirs) }
|
84
84
|
it { is_expected.to respond_to(:whitelisted_ingest_dirs=) }
|
85
|
+
|
86
|
+
describe "#whitelisted_ingest_dirs" do
|
87
|
+
it "provides the Rails tmp directory for temporary downloads for cloud files" do
|
88
|
+
expect(configuration.whitelisted_ingest_dirs).to include(Rails.root.join('tmp').to_s)
|
89
|
+
end
|
90
|
+
end
|
85
91
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -40,7 +40,7 @@ require 'rspec/active_model/mocks'
|
|
40
40
|
require 'capybara/rspec'
|
41
41
|
require 'capybara/rails'
|
42
42
|
require 'selenium-webdriver'
|
43
|
-
require '
|
43
|
+
require 'webdrivers'
|
44
44
|
require 'equivalent-xml'
|
45
45
|
require 'equivalent-xml/rspec_matchers'
|
46
46
|
require 'database_cleaner'
|
@@ -62,7 +62,7 @@ end
|
|
62
62
|
Dir[File.join(File.dirname(__FILE__), "support/**/*.rb")].each { |f| require f }
|
63
63
|
|
64
64
|
require 'webmock/rspec'
|
65
|
-
WebMock.disable_net_connect!(allow_localhost: true)
|
65
|
+
WebMock.disable_net_connect!(allow_localhost: true, allow: 'chromedriver.storage.googleapis.com')
|
66
66
|
|
67
67
|
require 'i18n/debug' if ENV['I18N_DEBUG']
|
68
68
|
require 'byebug' unless ci_build?
|
@@ -83,6 +83,10 @@ end
|
|
83
83
|
Capybara.default_driver = :rack_test # This is a faster driver
|
84
84
|
Capybara.javascript_driver = :selenium_chrome_headless_sandboxless # This is slower
|
85
85
|
|
86
|
+
# FIXME: Pin to older version of chromedriver to avoid issue with clicking
|
87
|
+
# non-visible elements
|
88
|
+
Webdrivers::Chromedriver.version = '72.0.3626.69'
|
89
|
+
|
86
90
|
ActiveJob::Base.queue_adapter = :test
|
87
91
|
|
88
92
|
# require 'http_logger'
|
@@ -192,11 +196,11 @@ RSpec.configure do |config|
|
|
192
196
|
|
193
197
|
config.before(:each, type: :view) do
|
194
198
|
initialize_controller_helpers(view)
|
195
|
-
WebMock.disable_net_connect!(allow_localhost: false)
|
199
|
+
WebMock.disable_net_connect!(allow_localhost: false, allow: 'chromedriver.storage.googleapis.com')
|
196
200
|
end
|
197
201
|
|
198
202
|
config.after(:each, type: :view) do
|
199
|
-
WebMock.disable_net_connect!(allow_localhost: true)
|
203
|
+
WebMock.disable_net_connect!(allow_localhost: true, allow: 'chromedriver.storage.googleapis.com')
|
200
204
|
end
|
201
205
|
|
202
206
|
config.before(:all, type: :feature) do
|
@@ -2,6 +2,7 @@ RSpec.describe 'hyrax/file_sets/_versioning.html.erb', type: :view do
|
|
2
2
|
let(:file_set) { stub_model(FileSet) }
|
3
3
|
|
4
4
|
before do
|
5
|
+
allow(file_set).to receive(:files).and_return([])
|
5
6
|
allow(view).to receive(:curation_concern).and_return(file_set)
|
6
7
|
assign(:version_list, [])
|
7
8
|
render
|
@@ -53,7 +53,7 @@ RSpec.describe 'hyrax/my/collections/_list_collections.html.erb', type: :view do
|
|
53
53
|
expect(rendered).to have_css '.collection_type', text: 'User Collection'
|
54
54
|
expect(rendered).to have_selector '.expanded-details', text: 'Collection Description'
|
55
55
|
expect(rendered).not_to have_selector 'span.fa-cubes'
|
56
|
-
expect(rendered).to have_selector '.thumbnail-wrapper > img
|
56
|
+
expect(rendered).to have_selector '.thumbnail-wrapper > img'
|
57
57
|
expect(rendered).to include Date.parse(modified_date).to_formatted_s(:standard)
|
58
58
|
end
|
59
59
|
end
|
@@ -102,7 +102,7 @@ RSpec.describe 'hyrax/my/collections/_list_collections.html.erb', type: :view do
|
|
102
102
|
expect(rendered).to have_css '.collection_type', text: 'Admin Set'
|
103
103
|
expect(rendered).to have_selector '.expanded-details', text: 'Admin Description'
|
104
104
|
expect(rendered).not_to have_selector 'span.fa-cubes'
|
105
|
-
expect(rendered).to have_selector '.thumbnail-wrapper > img
|
105
|
+
expect(rendered).to have_selector '.thumbnail-wrapper > img'
|
106
106
|
expect(rendered).to include Date.parse(modified_date).to_formatted_s(:standard)
|
107
107
|
end
|
108
108
|
end
|
data/template.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hyrax
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Coyne
|
@@ -14,7 +14,7 @@ authors:
|
|
14
14
|
autorequire:
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
|
-
date: 2019-
|
17
|
+
date: 2019-10-28 00:00:00.000000000 Z
|
18
18
|
dependencies:
|
19
19
|
- !ruby/object:Gem::Dependency
|
20
20
|
name: rails
|
@@ -124,14 +124,14 @@ dependencies:
|
|
124
124
|
name: browse-everything
|
125
125
|
requirement: !ruby/object:Gem::Requirement
|
126
126
|
requirements:
|
127
|
-
- - "
|
127
|
+
- - ">="
|
128
128
|
- !ruby/object:Gem::Version
|
129
129
|
version: '0.16'
|
130
130
|
type: :runtime
|
131
131
|
prerelease: false
|
132
132
|
version_requirements: !ruby/object:Gem::Requirement
|
133
133
|
requirements:
|
134
|
-
- - "
|
134
|
+
- - ">="
|
135
135
|
- !ruby/object:Gem::Version
|
136
136
|
version: '0.16'
|
137
137
|
- !ruby/object:Gem::Dependency
|
@@ -283,7 +283,7 @@ dependencies:
|
|
283
283
|
version: '3.3'
|
284
284
|
- - "<"
|
285
285
|
- !ruby/object:Gem::Version
|
286
|
-
version: '
|
286
|
+
version: '6.0'
|
287
287
|
type: :runtime
|
288
288
|
prerelease: false
|
289
289
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -293,7 +293,7 @@ dependencies:
|
|
293
293
|
version: '3.3'
|
294
294
|
- - "<"
|
295
295
|
- !ruby/object:Gem::Version
|
296
|
-
version: '
|
296
|
+
version: '6.0'
|
297
297
|
- !ruby/object:Gem::Dependency
|
298
298
|
name: hydra-head
|
299
299
|
requirement: !ruby/object:Gem::Requirement
|
@@ -1034,6 +1034,20 @@ dependencies:
|
|
1034
1034
|
- - "~>"
|
1035
1035
|
- !ruby/object:Gem::Version
|
1036
1036
|
version: '3.1'
|
1037
|
+
- !ruby/object:Gem::Dependency
|
1038
|
+
name: webdrivers
|
1039
|
+
requirement: !ruby/object:Gem::Requirement
|
1040
|
+
requirements:
|
1041
|
+
- - "~>"
|
1042
|
+
- !ruby/object:Gem::Version
|
1043
|
+
version: '3.0'
|
1044
|
+
type: :development
|
1045
|
+
prerelease: false
|
1046
|
+
version_requirements: !ruby/object:Gem::Requirement
|
1047
|
+
requirements:
|
1048
|
+
- - "~>"
|
1049
|
+
- !ruby/object:Gem::Version
|
1050
|
+
version: '3.0'
|
1037
1051
|
- !ruby/object:Gem::Dependency
|
1038
1052
|
name: webmock
|
1039
1053
|
requirement: !ruby/object:Gem::Requirement
|
@@ -1049,25 +1063,19 @@ dependencies:
|
|
1049
1063
|
- !ruby/object:Gem::Version
|
1050
1064
|
version: '0'
|
1051
1065
|
- !ruby/object:Gem::Dependency
|
1052
|
-
name:
|
1066
|
+
name: sass-rails
|
1053
1067
|
requirement: !ruby/object:Gem::Requirement
|
1054
1068
|
requirements:
|
1055
1069
|
- - "~>"
|
1056
1070
|
- !ruby/object:Gem::Version
|
1057
|
-
version: '
|
1058
|
-
- - "<="
|
1059
|
-
- !ruby/object:Gem::Version
|
1060
|
-
version: 3.5.0
|
1071
|
+
version: '5.0'
|
1061
1072
|
type: :runtime
|
1062
1073
|
prerelease: false
|
1063
1074
|
version_requirements: !ruby/object:Gem::Requirement
|
1064
1075
|
requirements:
|
1065
1076
|
- - "~>"
|
1066
1077
|
- !ruby/object:Gem::Version
|
1067
|
-
version: '
|
1068
|
-
- - "<="
|
1069
|
-
- !ruby/object:Gem::Version
|
1070
|
-
version: 3.5.0
|
1078
|
+
version: '5.0'
|
1071
1079
|
description: Hyrax is a featureful Samvera front-end based on the latest and greatest
|
1072
1080
|
Samvera software components.
|
1073
1081
|
email:
|