curation_concerns 0.12.0.pre1 → 0.12.0.pre2

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.
Files changed (212) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +24 -16
  3. data/Gemfile +0 -4
  4. data/README.md +14 -0
  5. data/RELEASING.md +2 -2
  6. data/Rakefile +2 -0
  7. data/app/actors/concerns/curation_concerns/manages_embargoes_actor.rb +28 -0
  8. data/app/actors/curation_concerns/abstract_actor.rb +28 -0
  9. data/app/actors/curation_concerns/add_to_collection_actor.rb +38 -0
  10. data/app/actors/curation_concerns/apply_order_actor.rb +24 -0
  11. data/app/actors/curation_concerns/assign_identifier_actor.rb +7 -0
  12. data/app/actors/curation_concerns/assign_representative_actor.rb +18 -0
  13. data/app/actors/curation_concerns/attach_files_actor.rb +39 -0
  14. data/app/actors/curation_concerns/base_actor.rb +71 -0
  15. data/app/actors/curation_concerns/embargo_actor.rb +19 -0
  16. data/app/actors/curation_concerns/file_actor.rb +79 -0
  17. data/app/actors/curation_concerns/file_set_actor.rb +146 -0
  18. data/app/actors/curation_concerns/interpret_visibility_actor.rb +123 -0
  19. data/app/actors/curation_concerns/lease_actor.rb +19 -0
  20. data/app/actors/curation_concerns/root_actor.rb +17 -0
  21. data/app/actors/curation_concerns/work_actor_behavior.rb +8 -0
  22. data/app/assets/javascripts/curation_concerns/batch_select.js +42 -0
  23. data/app/assets/javascripts/curation_concerns/collections.js +13 -0
  24. data/app/assets/javascripts/curation_concerns/curation_concerns.js +2 -0
  25. data/app/assets/stylesheets/curation_concerns/_curation_concerns.scss +0 -3
  26. data/app/assets/stylesheets/curation_concerns/_modules.scss +1 -1
  27. data/app/assets/stylesheets/curation_concerns/_positioning.scss +3 -6
  28. data/app/assets/stylesheets/curation_concerns/_theme.scss +0 -39
  29. data/app/assets/stylesheets/curation_concerns/_typography.scss +0 -69
  30. data/app/assets/stylesheets/curation_concerns/modules/classify_work.scss +0 -2
  31. data/app/assets/stylesheets/curation_concerns/modules/collections.scss +4 -0
  32. data/app/assets/stylesheets/curation_concerns/modules/forms.scss +0 -4
  33. data/app/assets/stylesheets/curation_concerns/modules/site_actions.scss +34 -29
  34. data/app/assets/stylesheets/curation_concerns/modules/site_search.scss +0 -46
  35. data/app/assets/stylesheets/curation_concerns.scss +4 -0
  36. data/app/controllers/concerns/curation_concerns/collections_controller_behavior.rb +166 -21
  37. data/app/controllers/concerns/curation_concerns/embargoes_controller_behavior.rb +1 -1
  38. data/app/controllers/concerns/curation_concerns/leases_controller_behavior.rb +1 -1
  39. data/app/controllers/concerns/curation_concerns/selects_collections.rb +65 -0
  40. data/app/forms/curation_concerns/forms/collection_edit_form.rb +0 -29
  41. data/app/forms/curation_concerns/forms/work_form.rb +2 -1
  42. data/app/helpers/batch_select_helper.rb +23 -0
  43. data/app/helpers/collections_helper.rb +4 -0
  44. data/app/helpers/curation_concerns/collections_helper.rb +2 -2
  45. data/app/helpers/curation_concerns/collections_helper_behavior.rb +56 -0
  46. data/app/helpers/curation_concerns/render_constraints_helper.rb +14 -35
  47. data/app/helpers/curation_concerns/title_helper.rb +4 -0
  48. data/app/indexers/curation_concerns/collection_indexer.rb +16 -0
  49. data/app/indexers/curation_concerns/file_set_indexer.rb +46 -0
  50. data/app/indexers/curation_concerns/work_indexer.rb +15 -0
  51. data/app/jobs/audit_job.rb +49 -0
  52. data/app/jobs/characterize_job.rb +11 -0
  53. data/app/jobs/create_derivatives_job.rb +21 -0
  54. data/app/jobs/import_url_job.rb +48 -0
  55. data/app/jobs/ingest_file_job.rb +30 -0
  56. data/app/jobs/ingest_local_file_job.rb +20 -0
  57. data/app/jobs/resolrize_job.rb +7 -0
  58. data/app/models/checksum_audit_log.rb +20 -0
  59. data/app/models/collection.rb +6 -0
  60. data/app/models/concerns/curation_concerns/ability.rb +49 -0
  61. data/app/models/concerns/curation_concerns/basic_metadata.rb +64 -0
  62. data/app/models/concerns/curation_concerns/collection.rb +16 -0
  63. data/app/models/concerns/curation_concerns/collection_behavior.rb +62 -0
  64. data/app/models/concerns/curation_concerns/file_set/belongs_to_works.rb +47 -0
  65. data/app/models/concerns/curation_concerns/file_set/derivatives.rb +65 -0
  66. data/app/models/concerns/curation_concerns/file_set/full_text_indexing.rb +11 -0
  67. data/app/models/concerns/curation_concerns/file_set/indexing.rb +14 -0
  68. data/app/models/concerns/curation_concerns/file_set/querying.rb +17 -0
  69. data/app/models/concerns/curation_concerns/file_set_behavior.rb +36 -0
  70. data/app/models/concerns/curation_concerns/has_representative.rb +13 -0
  71. data/app/models/concerns/curation_concerns/human_readable_type.rb +17 -0
  72. data/app/models/concerns/curation_concerns/naming.rb +17 -0
  73. data/app/models/concerns/curation_concerns/permissions/readable.rb +18 -0
  74. data/app/models/concerns/curation_concerns/permissions/writable.rb +34 -0
  75. data/app/models/concerns/curation_concerns/permissions.rb +7 -0
  76. data/app/models/concerns/curation_concerns/required_metadata.rb +30 -0
  77. data/app/models/concerns/curation_concerns/serializers.rb +13 -0
  78. data/app/models/concerns/curation_concerns/solr_document_behavior.rb +147 -0
  79. data/app/models/concerns/curation_concerns/user.rb +18 -0
  80. data/app/models/concerns/curation_concerns/with_file_sets.rb +37 -0
  81. data/app/models/concerns/curation_concerns/work_behavior.rb +45 -0
  82. data/app/models/curation_concerns/classify_concern.rb +49 -0
  83. data/app/models/curation_concerns/quick_classification_query.rb +38 -0
  84. data/app/models/single_use_link.rb +34 -0
  85. data/app/models/version_committer.rb +2 -0
  86. data/app/search_builders/curation_concerns/collection_member_search_builder.rb +1 -1
  87. data/app/search_builders/curation_concerns/collection_search_builder.rb +33 -0
  88. data/app/search_builders/curation_concerns/member_search_builder.rb +17 -0
  89. data/app/services/curation_concerns/derivative_path.rb +49 -0
  90. data/app/services/curation_concerns/file_set_audit_service.rb +105 -0
  91. data/app/services/curation_concerns/indexes_thumbnails.rb +30 -0
  92. data/app/services/curation_concerns/local_file_service.rb +10 -0
  93. data/app/services/curation_concerns/lock_manager.rb +39 -0
  94. data/app/services/curation_concerns/lockable.rb +16 -0
  95. data/app/services/curation_concerns/noid.rb +23 -0
  96. data/app/services/curation_concerns/persist_derivatives.rb +33 -0
  97. data/app/services/curation_concerns/persist_directly_contained_output_file_service.rb +26 -0
  98. data/app/services/curation_concerns/repository_audit_service.rb +7 -0
  99. data/app/services/curation_concerns/thumbnail_path_service.rb +46 -0
  100. data/app/services/curation_concerns/time_service.rb +7 -0
  101. data/app/services/curation_concerns/versioning_service.rb +26 -0
  102. data/app/validators/has_one_title_validator.rb +8 -0
  103. data/app/views/batch_select/_add_button.html.erb +3 -0
  104. data/app/views/batch_select/_check_all.html.erb +4 -0
  105. data/app/views/batch_select/_tools.html.erb +10 -0
  106. data/app/views/catalog/_action_menu_partials/_collection.html.erb +3 -3
  107. data/app/views/catalog/_action_menu_partials/_default.html.erb +1 -1
  108. data/app/views/catalog/_document_list.html.erb +1 -1
  109. data/app/views/collections/_bookmark_control.html.erb +2 -0
  110. data/app/views/collections/_button_create_collection.html.erb +2 -0
  111. data/app/views/collections/_button_for_creating_empty_collection.html.erb +1 -1
  112. data/app/views/collections/_button_for_delete_collection.html.erb +4 -0
  113. data/app/views/collections/_button_for_remove_selected_from_collection.html.erb +8 -0
  114. data/app/views/collections/_button_for_update_collection.html.erb +4 -0
  115. data/app/views/collections/_button_remove_from_collection.html.erb +4 -0
  116. data/app/views/collections/_document_header.html.erb +9 -0
  117. data/app/views/collections/_edit_actions.html.erb +1 -1
  118. data/app/views/collections/_edit_descriptions.html.erb +1 -1
  119. data/app/views/collections/_form.html.erb +2 -2
  120. data/app/views/collections/_form_for_select_destination_collection.html.erb +21 -0
  121. data/app/views/collections/_form_to_add_member.html.erb +1 -1
  122. data/app/views/collections/_index_default.html.erb +2 -0
  123. data/app/views/collections/_index_header_default.html.erb +2 -0
  124. data/app/views/collections/_media_display.html.erb +1 -1
  125. data/app/views/collections/_paginate.html.erb +1 -1
  126. data/app/views/collections/_paginate_compact.html.erb +1 -0
  127. data/app/views/collections/_results_pagination.html.erb +9 -0
  128. data/app/views/collections/_search_collection_dashboard_form.html.erb +1 -1
  129. data/app/views/collections/_search_form.html.erb +1 -1
  130. data/app/views/collections/_search_results.html.erb +23 -0
  131. data/app/views/collections/_show_actions.html.erb +1 -1
  132. data/app/views/collections/_sort_and_per_page.html.erb +1 -1
  133. data/app/views/collections/_view_type_group.html.erb +1 -1
  134. data/app/views/collections/index.html.erb +9 -0
  135. data/app/views/collections/new.html.erb +3 -0
  136. data/app/views/curation_concerns/base/_form_permission.html.erb +10 -11
  137. data/app/views/curation_concerns/base/_form_permission_embargo.html.erb +1 -1
  138. data/app/views/curation_concerns/base/_form_permission_lease.html.erb +1 -1
  139. data/app/views/curation_concerns/base/_legally_binding_text.html.erb +7 -7
  140. data/app/views/curation_concerns/base/_related_files.html.erb +1 -1
  141. data/app/views/curation_concerns/base/_visibility.html.erb +2 -2
  142. data/app/views/curation_concerns/file_sets/_actions.html.erb +1 -1
  143. data/app/views/embargoes/_list_expired_active_embargoes.html.erb +1 -1
  144. data/app/views/error/single_use_error.html.erb +1 -1
  145. data/app/views/shared/_add_content.html.erb +17 -15
  146. data/app/views/shared/_brand_bar.html.erb +19 -10
  147. data/app/views/shared/_header.html.erb +2 -6
  148. data/app/views/shared/_my_actions.html.erb +28 -27
  149. data/app/views/shared/_site_actions.html.erb +5 -1
  150. data/app/views/shared/_site_search.html.erb +3 -2
  151. data/app/views/shared/_title_bar.html.erb +7 -16
  152. data/app/views/welcome/index.html.erb +2 -2
  153. data/config/locales/curation_concerns.en.yml +25 -1
  154. data/curation_concerns.gemspec +21 -5
  155. data/lib/curation_concerns/collections/accepts_batches.rb +53 -0
  156. data/lib/curation_concerns/collections/search_service.rb +57 -0
  157. data/lib/curation_concerns/collections.rb +10 -0
  158. data/lib/curation_concerns/configuration.rb +167 -0
  159. data/lib/curation_concerns/engine.rb +22 -1
  160. data/lib/curation_concerns/messages.rb +68 -0
  161. data/lib/curation_concerns/models.rb +42 -0
  162. data/lib/curation_concerns/name.rb +20 -0
  163. data/lib/curation_concerns/null_logger.rb +10 -0
  164. data/lib/curation_concerns/rails/routes.rb +1 -3
  165. data/lib/curation_concerns/version.rb +1 -1
  166. data/lib/curation_concerns.rb +2 -0
  167. data/lib/generators/curation_concerns/abstract_migration_generator.rb +31 -0
  168. data/lib/generators/curation_concerns/clamav_generator.rb +19 -0
  169. data/lib/generators/curation_concerns/collection_generator.rb +15 -0
  170. data/lib/generators/curation_concerns/install_generator.rb +1 -2
  171. data/lib/generators/curation_concerns/models_generator.rb +62 -0
  172. data/lib/generators/curation_concerns/templates/app/models/collection.rb +6 -0
  173. data/lib/generators/curation_concerns/templates/app/models/file_set.rb +4 -0
  174. data/lib/generators/curation_concerns/templates/config/clamav.rb +1 -0
  175. data/lib/generators/curation_concerns/templates/config/curation_concerns.rb +61 -0
  176. data/lib/generators/curation_concerns/templates/config/mime_types.rb +6 -0
  177. data/lib/generators/curation_concerns/templates/config/redis.yml +9 -0
  178. data/lib/generators/curation_concerns/templates/config/redis_config.rb +29 -0
  179. data/lib/generators/curation_concerns/templates/config/resque-pool.yml +1 -0
  180. data/lib/generators/curation_concerns/templates/config/resque_config.rb +6 -0
  181. data/lib/generators/curation_concerns/templates/curation_concerns.scss +3 -2
  182. data/lib/generators/curation_concerns/templates/migrations/create_checksum_audit_logs.rb +19 -0
  183. data/lib/generators/curation_concerns/templates/migrations/create_single_use_links.rb +12 -0
  184. data/lib/generators/curation_concerns/templates/migrations/create_version_committers.rb +15 -0
  185. data/lib/tasks/migrate.rake +11 -0
  186. data/lib/tasks/resque.rake +14 -0
  187. data/lib/tasks/solr_reindex.rake +8 -0
  188. data/spec/actors/curation_concerns/file_set_actor_spec.rb +31 -0
  189. data/spec/controllers/accepts_batches_controller_spec.rb +65 -0
  190. data/spec/controllers/collections_controller_spec.rb +272 -0
  191. data/spec/controllers/curation_concerns/collections_controller_spec.rb +1 -2
  192. data/spec/controllers/selects_collections_controller_spec.rb +109 -0
  193. data/spec/features/create_work_spec.rb +1 -1
  194. data/spec/features/work_generator_spec.rb +1 -1
  195. data/spec/forms/collection_edit_form_spec.rb +2 -9
  196. data/spec/forms/work_form_spec.rb +5 -0
  197. data/spec/helpers/collections_helper_spec.rb +129 -0
  198. data/spec/helpers/curation_concerns/collections_helper_spec.rb +2 -2
  199. data/spec/helpers/render_constraints_helper_spec.rb +23 -1
  200. data/spec/lib/curation_concerns/collections/search_service_spec.rb +33 -0
  201. data/spec/models/collection_spec.rb +165 -0
  202. data/spec/tasks/rake_spec.rb +1 -1
  203. data/spec/test_app_templates/lib/generators/test_app_generator.rb +1 -1
  204. data/spec/views/curation_concerns/base/_form_permission.html.erb_spec.rb +4 -1
  205. data/spec/views/curation_concerns/file_sets/show.html.erb_spec.rb +1 -0
  206. data/spec/views/shared/_add_content.html.erb_spec.rb +3 -3
  207. metadata +341 -24
  208. data/VERSION +0 -1
  209. data/app/assets/stylesheets/curation_concerns/_global-variables.scss +0 -5
  210. data/app/assets/stylesheets/curation_concerns/modules/multi_value_fields.scss +0 -52
  211. data/app/views/collections/_form_required_information.html.erb +0 -11
  212. data/tasks/release.rake +0 -93
@@ -0,0 +1,61 @@
1
+ CurationConcerns.configure do |config|
2
+ # Should schema.org microdata be displayed?
3
+ # config.display_microdata = true
4
+
5
+ # What default microdata type should be used if a more appropriate
6
+ # type can not be found in the locale file?
7
+ # config.microdata_default_type = 'http://schema.org/CreativeWork'
8
+
9
+ # How frequently should a file be audited.
10
+ # Note: In CurationConcerns you must trigger the FileSetAuditService manually.
11
+ # config.max_days_between_audits = 7
12
+
13
+ # Enable displaying usage statistics in the UI
14
+ # Requires a Google Analytics id and OAuth2 keyfile. See README for more info
15
+ # config.analytics = false
16
+
17
+ # Specify a Google Analytics tracking ID to gather usage statistics
18
+ # config.google_analytics_id = 'UA-99999999-1'
19
+
20
+ # Specify a date you wish to start collecting Google Analytic statistics for.
21
+ # config.analytic_start_date = DateTime.new(2014,9,10)
22
+
23
+ # Where to store tempfiles, leave blank for the system temp directory (e.g. /tmp)
24
+ # config.temp_file_base = '/home/developer1'
25
+
26
+ # Location on local file system where derivatives will be stored.
27
+ # If you use a multi-server architecture, this MUST be a shared volume.
28
+ # config.derivatives_path = File.join(Rails.root, 'tmp', 'derivatives')
29
+
30
+ # Location on local file system where uploaded files will be staged
31
+ # prior to being ingested into the repository or having derivatives generated.
32
+ # If you use a multi-server architecture, this MUST be a shared volume.
33
+ # config.working_path = File.join(Rails.root, 'tmp', 'uploads')
34
+
35
+ # If you have ffmpeg installed and want to transcode audio and video uncomment this line
36
+ # config.enable_ffmpeg = true
37
+
38
+ # CurationConcerns uses NOIDs for files and collections instead of Fedora UUIDs
39
+ # where NOID = 10-character string and UUID = 32-character string w/ hyphens
40
+ # config.enable_noids = true
41
+
42
+ # Specify a different template for your repository's NOID IDs
43
+ # config.noid_template = ".reeddeeddk"
44
+
45
+ # Store identifier minter's state in a file for later replayability
46
+ # If you use a multi-server architecture, this MUST be on a shared volume.
47
+ # config.minter_statefile = '/tmp/minter-state'
48
+
49
+ # Specify the prefix for Redis keys:
50
+ # config.redis_namespace = "curation_concerns"
51
+
52
+ # Specify the path to the file characterization tool:
53
+ # config.fits_path = "fits.sh"
54
+
55
+ # Specify a date you wish to start collecting Google Analytic statistics for.
56
+ # Leaving it blank will set the start date to when ever the file was uploaded by
57
+ # NOTE: if you have always sent analytics to GA for downloads and page views leave this commented out
58
+ # config.analytic_start_date = DateTime.new(2014,9,10)
59
+ end
60
+
61
+ Date::DATE_FORMATS[:standard] = '%m/%d/%Y'
@@ -0,0 +1,6 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Add new mime types for use in respond_to blocks:
4
+ # Mime::Type.register "text/richtext", :rtf
5
+ # Mime::Type.register_alias "text/html", :iphone
6
+ Mime::Type.register 'application/x-endnote-refer', :endnote
@@ -0,0 +1,9 @@
1
+ development:
2
+ host: localhost
3
+ port: 6379
4
+ test:
5
+ host: localhost
6
+ port: 6379
7
+ production:
8
+ host: localhost
9
+ port: 6379
@@ -0,0 +1,29 @@
1
+ if defined?(PhusionPassenger)
2
+ PhusionPassenger.on_event(:starting_worker_process) do |forked|
3
+ # We're in smart spawning mode.
4
+ if forked
5
+ # Re-establish redis connection
6
+ require 'redis'
7
+ config = YAML.load(ERB.new(IO.read(File.join(Rails.root, 'config', 'redis.yml'))).result)[Rails.env].with_indifferent_access
8
+
9
+ # The important two lines
10
+ Redis.current.disconnect!
11
+ Redis.current = begin
12
+ Redis.new(config.merge(thread_safe: true))
13
+ rescue
14
+ nil
15
+ end
16
+ Resque.redis = Redis.current
17
+ Resque.redis.namespace = "#{CurationConcerns.config.redis_namespace}:#{Rails.env}"
18
+ Resque.redis.client.reconnect if Resque.redis
19
+ end
20
+ end
21
+ else
22
+ config = YAML.load(ERB.new(IO.read(File.join(Rails.root, 'config', 'redis.yml'))).result)[Rails.env].with_indifferent_access
23
+ require 'redis'
24
+ Redis.current = begin
25
+ Redis.new(config.merge(thread_safe: true))
26
+ rescue
27
+ nil
28
+ end
29
+ end
@@ -0,0 +1,6 @@
1
+ require 'resque'
2
+ config = YAML.load(ERB.new(IO.read(File.join(Rails.root, 'config', 'redis.yml'))).result)[Rails.env].with_indifferent_access
3
+ Resque.redis = Redis.new(host: config[:host], port: config[:port], thread_safe: true)
4
+
5
+ Resque.inline = Rails.env.test?
6
+ Resque.redis.namespace = "#{CurationConcerns.config.redis_namespace}:#{Rails.env}"
@@ -1,3 +1,4 @@
1
- //@import 'blacklight/blacklight';
2
- @import 'curation_concerns/curation_concerns';
1
+ @import 'bootstrap-sprockets';
2
+ @import 'bootstrap';
3
3
 
4
+ @import 'curation_concerns/curation_concerns';
@@ -0,0 +1,19 @@
1
+ class CreateChecksumAuditLogs < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :checksum_audit_logs do |t|
4
+ t.string :file_set_id
5
+ t.string :file_id
6
+ t.string :version
7
+ t.integer :pass
8
+ t.string :expected_result
9
+ t.string :actual_result
10
+ t.timestamps
11
+ end
12
+ add_index :checksum_audit_logs, [:file_set_id, :file_id], name: 'by_file_set_id_and_file_id', order: { created_at: 'DESC' }
13
+ end
14
+
15
+ def self.down
16
+ remove_index(:checksum_audit_logs, name: 'by_file_set_id_and_file_id')
17
+ drop_table :checksum_audit_logs
18
+ end
19
+ end
@@ -0,0 +1,12 @@
1
+ class CreateSingleUseLinks < ActiveRecord::Migration
2
+ def change
3
+ create_table :single_use_links do |t|
4
+ t.string :downloadKey
5
+ t.string :path
6
+ t.string :itemId
7
+ t.datetime :expires
8
+
9
+ t.timestamps
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ class CreateVersionCommitters < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :version_committers do |t|
4
+ t.string :obj_id
5
+ t.string :datastream_id
6
+ t.string :version_id
7
+ t.string :committer_login
8
+ t.timestamps
9
+ end
10
+ end
11
+
12
+ def self.down
13
+ drop_table :version_committers
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ namespace :curation_concerns do
2
+ namespace :migrate do
3
+ desc "Migrate audit logs"
4
+ task audit_logs: :environment do
5
+ ChecksumAuditLog.all.each do |cs|
6
+ cs.file_set_id = cs.file_set_id.delete "#{CurationConcerns.config.redis_namespace}:"
7
+ cs.save
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ require 'resque/pool/tasks'
2
+
3
+ # This provides access to the Rails env within all Resque workers
4
+ task 'resque:setup' => :environment
5
+
6
+ # Set up resque-pool
7
+ task 'resque:pool:setup' do
8
+ ActiveRecord::Base.connection.disconnect!
9
+ require 'resque/pool'
10
+ Resque::Pool.after_prefork do |job|
11
+ ActiveRecord::Base.establish_connection
12
+ Resque.redis.client.reconnect
13
+ end
14
+ end
@@ -0,0 +1,8 @@
1
+ namespace :curation_concerns do
2
+ namespace :solr do
3
+ desc "Enqueue a job to resolrize the repository objects"
4
+ task reindex: :environment do
5
+ ResolrizeJob.perform_later
6
+ end
7
+ end
8
+ end
@@ -253,4 +253,35 @@ describe CurationConcerns::FileSetActor do
253
253
  end
254
254
  end
255
255
  end
256
+
257
+ describe "#file_actor_class" do
258
+ context "default" do
259
+ it "is a FileActor" do
260
+ expect(actor.file_actor_class).to eq(CurationConcerns::FileActor)
261
+ end
262
+ end
263
+
264
+ context "overridden" do
265
+ let(:actor) { CustomFileSetActor.new(file_set, user) }
266
+
267
+ before do
268
+ class CustomFileActor < CurationConcerns::FileActor
269
+ end
270
+ class CustomFileSetActor < CurationConcerns::FileSetActor
271
+ def file_actor_class
272
+ CustomFileActor
273
+ end
274
+ end
275
+ end
276
+
277
+ after do
278
+ Object.send(:remove_const, :CustomFileActor)
279
+ Object.send(:remove_const, :CustomFileSetActor)
280
+ end
281
+
282
+ it "is a custom class" do
283
+ expect(actor.file_actor_class).to eq(CustomFileActor)
284
+ end
285
+ end
286
+ end
256
287
  end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ class AcceptsBatchesController < ApplicationController
4
+ include CurationConcerns::Collections::AcceptsBatches
5
+ end
6
+
7
+ describe AcceptsBatchesController, type: :controller do
8
+ describe 'batch' do
9
+ it 'accepts batch from parameters' do
10
+ controller.params['batch_document_ids'] = %w(abc xyz)
11
+ expect(controller.batch).to eq(%w(abc xyz))
12
+ end
13
+ describe ':all' do
14
+ let(:current_user) { double(user_key: 'vanessa') }
15
+ before do
16
+ doc1 = double(id: 123)
17
+ doc2 = double(id: 456)
18
+ expect_any_instance_of(CurationConcerns::Collections::SearchService).to receive(:last_search_documents).and_return([doc1, doc2])
19
+ allow(controller).to receive(:current_user).and_return(current_user)
20
+ end
21
+ it 'adds every document in the current resultset to the batch' do
22
+ controller.params['batch_document_ids'] = 'all'
23
+ expect(controller.batch).to eq([123, 456])
24
+ end
25
+ end
26
+ end
27
+
28
+ describe 'should allow filtering for access' do
29
+ before do
30
+ @allowed = [1, 2, 3]
31
+ @disallowed = [5, 6, 7]
32
+ subject.batch = @allowed + @disallowed
33
+ end
34
+ it 'using filter_docs_with_access!' do
35
+ @allowed.each { |doc_id| expect(subject).to receive(:can?).with(:foo, doc_id).and_return(true) }
36
+ @disallowed.each { |doc_id| expect(subject).to receive(:can?).with(:foo, doc_id).and_return(false) }
37
+ subject.send(:filter_docs_with_access!, :foo)
38
+ expect(flash[:notice]).to eq("You do not have permission to edit the documents: #{@disallowed.join(', ')}")
39
+ end
40
+ it 'using filter_docs_with_edit_access!' do
41
+ @allowed.each { |doc_id| expect(subject).to receive(:can?).with(:edit, doc_id).and_return(true) }
42
+ @disallowed.each { |doc_id| expect(subject).to receive(:can?).with(:edit, doc_id).and_return(false) }
43
+ subject.send(:filter_docs_with_edit_access!)
44
+ expect(flash[:notice]).to eq("You do not have permission to edit the documents: #{@disallowed.join(', ')}")
45
+ end
46
+ it 'using filter_docs_with_read_access!' do
47
+ @allowed.each { |doc_id| expect(subject).to receive(:can?).with(:read, doc_id).and_return(true) }
48
+ @disallowed.each { |doc_id| expect(subject).to receive(:can?).with(:read, doc_id).and_return(false) }
49
+ subject.send(:filter_docs_with_read_access!)
50
+ expect(flash[:notice]).to eq("You do not have permission to edit the documents: #{@disallowed.join(', ')}")
51
+ end
52
+ it "and be sassy if you didn't select anything" do
53
+ subject.batch = []
54
+ subject.send(:filter_docs_with_read_access!)
55
+ expect(flash[:notice]).to eq('Select something first')
56
+ end
57
+ end
58
+
59
+ it 'checks for empty' do
60
+ controller.batch = %w(77826928 94120425)
61
+ expect(controller.check_for_empty_batch?).to eq(false)
62
+ controller.batch = []
63
+ expect(controller.check_for_empty_batch?).to eq(true)
64
+ end
65
+ end
@@ -0,0 +1,272 @@
1
+ require 'spec_helper'
2
+
3
+ describe CollectionsController, type: :controller do
4
+ let(:user) { FactoryGirl.create(:user) }
5
+
6
+ before do
7
+ allow(controller).to receive(:has_access?).and_return(true)
8
+
9
+ sign_in user
10
+ allow_any_instance_of(User).to receive(:groups).and_return([])
11
+ allow(controller).to receive(:clear_session_user) ## Don't clear out the authenticated session
12
+ end
13
+
14
+ describe '#index' do
15
+ let!(:collection1) { FactoryGirl.create(:collection, title: ['Beta'], user: user) }
16
+ let!(:collection2) { FactoryGirl.create(:collection, title: ['Alpha'], user: user) }
17
+ let!(:generic_file) { create(:generic_work, user: user) }
18
+
19
+ it 'shows a list of collections sorted alphabetically' do
20
+ get :index
21
+ expect(response).to be_successful
22
+ expect(assigns[:document_list].map(&:id)).not_to include generic_file.id
23
+ expect(assigns[:document_list].map(&:id)).to match_array [collection2.id, collection1.id]
24
+ end
25
+ end
26
+
27
+ describe '#new' do
28
+ it 'assigns @collection' do
29
+ get :new
30
+ expect(assigns(:collection)).to be_kind_of(Collection)
31
+ end
32
+ end
33
+
34
+ describe '#create' do
35
+ it 'creates a Collection' do
36
+ expect do
37
+ post :create, collection: { title: ['My First Collection'],
38
+ description: ["The Description\r\n\r\nand more"] }
39
+ end.to change { Collection.count }.by(1)
40
+ expect(assigns[:collection].title).to eq ['My First Collection']
41
+ expect(assigns[:collection].description).to eq ["The Description\r\n\r\nand more"]
42
+ expect(assigns[:collection].depositor).to eq(user.user_key)
43
+ expect(response).to redirect_to collection_path(assigns[:collection])
44
+ end
45
+
46
+ it 'adds docs to collection if batch ids provided' do
47
+ @asset1 = create(:generic_work, user: user)
48
+ @asset2 = create(:generic_work, user: user)
49
+ post :create, batch_document_ids: [@asset1, @asset2],
50
+ collection: { title: ['My Secong Collection'],
51
+ description: ["The Description\r\n\r\nand more"] }
52
+ expect(assigns[:collection].members).to eq [@asset1, @asset2]
53
+ end
54
+
55
+ it 'calls after_create' do
56
+ expect(controller).to receive(:after_create).and_call_original
57
+ post :create, collection: { title: ['My First Collection'],
58
+ description: ["The Description\r\n\r\nand more"] }
59
+ end
60
+
61
+ it 'adds one doc to collection if batch ids provided and add the collection id to the document in the colledction' do
62
+ @asset1 = create(:generic_work, user: user)
63
+ post :create, batch_document_ids: [@asset1],
64
+ collection: { title: ['My Second Collection'],
65
+ description: ["The Description\r\n\r\nand more"] }
66
+ expect(assigns[:collection].members).to eq [@asset1]
67
+ asset_results = ActiveFedora::SolrService.instance.conn.get 'select', params: { fq: ["id:\"#{@asset1.id}\""], fl: ['id', Solrizer.solr_name(:collection)] }
68
+ expect(asset_results['response']['numFound']).to eq(1)
69
+ doc = asset_results['response']['docs'].first
70
+ expect(doc['id']).to eq @asset1.id
71
+ afterupdate = GenericWork.find(@asset1.id)
72
+ expect(doc[Solrizer.solr_name(:collection)]).to eq(afterupdate.to_solr[Solrizer.solr_name(:collection)])
73
+ end
74
+
75
+ it 'adds docs to collection if batch ids provided and add the collection id to the documents int he colledction' do
76
+ @asset1 = create(:generic_work, user: user)
77
+ @asset2 = create(:generic_work, user: user)
78
+ post :create, batch_document_ids: [@asset1, @asset2],
79
+ collection: { title: ['My Secong Collection'],
80
+ description: ["The Description\r\n\r\nand more"] }
81
+ expect(assigns[:collection].members).to eq [@asset1, @asset2]
82
+ asset_results = ActiveFedora::SolrService.instance.conn.get 'select', params: { fq: ["id:\"#{@asset1.id}\""], fl: ['id', Solrizer.solr_name(:collection)] }
83
+ expect(asset_results['response']['numFound']).to eq(1)
84
+ doc = asset_results['response']['docs'].first
85
+ expect(doc['id']).to eq(@asset1.id)
86
+ afterupdate = GenericWork.find(@asset1.id)
87
+ expect(doc[Solrizer.solr_name(:collection)]).to eq(afterupdate.to_solr[Solrizer.solr_name(:collection)])
88
+ end
89
+ end
90
+
91
+ describe '#update' do
92
+ let(:collection) { FactoryGirl.create(:collection, user: user) }
93
+ before do
94
+ @asset1 = create(:generic_work, user: user)
95
+ @asset2 = create(:generic_work, user: user)
96
+ @asset3 = create(:generic_work, user: user)
97
+ end
98
+
99
+ it 'updates collection metadata' do
100
+ put :update, id: collection.id, collection: { title: ['New Title'], description: ['New Description'] }
101
+ expect(response).to redirect_to collection_path(collection)
102
+ expect(assigns[:collection].title).to eq(['New Title'])
103
+ expect(assigns[:collection].description).to eq(['New Description'])
104
+ end
105
+
106
+ it 'calls after_update' do
107
+ expect(controller).to receive(:after_update).and_call_original
108
+ put :update, id: collection.id, collection: { title: ['New Title'], description: ['New Description'] }
109
+ end
110
+
111
+ context 'when updating fails' do
112
+ before do
113
+ allow_any_instance_of(Collection).to receive(:save).and_return(false)
114
+ end
115
+ it 'renders edit succesfully' do
116
+ put :update, id: collection.id, collection: { title: ['New Title'] }
117
+ expect(response).to render_template 'edit'
118
+ end
119
+ end
120
+
121
+ context 'when there are existing members in the collection' do
122
+ it 'supports adding batches of members' do
123
+ collection.members << @asset1
124
+ collection.save!
125
+ put :update, id: collection, collection: { members: 'add' }, batch_document_ids: [@asset2, @asset3]
126
+ expect(response).to redirect_to collection_path(collection)
127
+ expect(assigns[:collection].members).to match_array [@asset2, @asset3, @asset1]
128
+ end
129
+
130
+ it 'supports removing batches of members' do
131
+ collection.members = [@asset1, @asset2, @asset3]
132
+ collection.save!
133
+ put :update, id: collection, collection: { members: 'remove' }, batch_document_ids: [@asset1, @asset3]
134
+ expect(response).to redirect_to collection_path(collection)
135
+ expect(assigns[:collection].members).to eq([@asset2])
136
+ end
137
+ end
138
+
139
+ it 'supports setting members array' do
140
+ put :update, id: collection, collection: { members: 'add' }, batch_document_ids: [@asset2, @asset3, @asset1]
141
+ expect(response).to redirect_to collection_path(collection)
142
+ expect(assigns[:collection].members).to match_array [@asset2, @asset3, @asset1]
143
+ end
144
+
145
+ it 'set/un-sets collection on members' do
146
+ # Add to collection (sets collection on members)
147
+ put :update, id: collection, collection: { members: 'add' }, batch_document_ids: [@asset2, @asset3]
148
+ expect(assigns[:collection].members).to match_array [@asset2, @asset3]
149
+
150
+ # Remove from collection (un-sets collection on members)
151
+ put :update, id: collection, collection: { members: 'remove' }, batch_document_ids: [@asset2]
152
+ expect(assigns[:collection].members).not_to include(@asset2)
153
+ end
154
+
155
+ context 'when moving members between collections' do
156
+ before do
157
+ collection.members = [@asset1, @asset2, @asset3]
158
+ collection.save!
159
+ end
160
+ let(:collection2) do
161
+ Collection.create(title: ['Some Collection']) do |col|
162
+ col.apply_depositor_metadata(user.user_key)
163
+ end
164
+ end
165
+
166
+ it 'moves the members' do
167
+ put :update, id: collection, collection: { members: 'move' },
168
+ destination_collection_id: collection2, batch_document_ids: [@asset2, @asset3]
169
+ expect(collection.reload.members).to eq [@asset1]
170
+ expect(collection2.reload.members).to match_array [@asset2, @asset3]
171
+ end
172
+ end
173
+ end
174
+
175
+ describe '#destroy' do
176
+ describe 'valid collection' do
177
+ let!(:collection) { FactoryGirl.create(:collection, user: user) }
178
+ before do
179
+ expect(controller).to receive(:authorize!).and_return(true)
180
+ end
181
+
182
+ it 'deletes the collection' do
183
+ delete :destroy, id: collection
184
+ expect(response).to redirect_to Rails.application.routes.url_helpers.search_catalog_path
185
+ expect(flash[:notice]).to eq('Collection was successfully deleted.')
186
+ end
187
+
188
+ it 'calls after_destroy' do
189
+ expect(controller).to receive(:after_destroy).and_call_original
190
+ delete :destroy, id: collection
191
+ end
192
+
193
+ it 'updates members' do
194
+ asset1 = create(:generic_work, user: user)
195
+ collection.members << asset1
196
+ collection.save!
197
+ expect(asset1.in_collections).to eq [collection]
198
+
199
+ delete :destroy, id: collection
200
+ expect(asset1.in_collections).to eq []
201
+ end
202
+ end
203
+
204
+ it 'does not delete an invalid collection' do
205
+ expect { delete :destroy, id: 'zz:-1' }.to raise_error
206
+ end
207
+ end
208
+
209
+ describe '#show' do
210
+ context 'when there are no assets in the collection' do
211
+ let(:collection) { FactoryGirl.create(:collection, user: user) }
212
+ it 'shows no assets' do
213
+ get :show, id: collection
214
+ expect(response).to be_successful
215
+ expect(assigns[:presenter].id).to eq collection.id
216
+ expect(assigns[:member_docs]).to be_empty
217
+ end
218
+ end
219
+
220
+ context 'with a number of assets' do
221
+ let(:asset1) { create(:generic_work, title: ['First of the Assets'], read_users: [user.user_key]) }
222
+ let(:asset2) { create(:generic_work, title: ['Second of the Assets'], read_users: [user.user_key]) }
223
+ let(:asset3) { create(:generic_work, title: ['Third of the Assets'], read_users: [user.user_key]) }
224
+ let!(:collection) do
225
+ FactoryGirl.create(:collection, members: [asset1, asset2, asset3], user: user)
226
+ end
227
+
228
+ it 'queries the collections' do
229
+ get :show, id: collection, cq: 'First'
230
+ expect(assigns[:presenter].id).to eq collection.id
231
+ expect(assigns[:member_docs].map(&:id)).to match_array [asset1.id]
232
+ end
233
+
234
+ it 'returns the specified number of rows' do
235
+ get :show, id: collection, rows: '2'
236
+ expect(assigns[:presenter].id).to eq collection.id
237
+ expect(assigns[:member_docs].size).to eq 2
238
+ end
239
+
240
+ describe 'additional collections' do
241
+ let(:asset4) { create(:generic_work, user: user, title: [asset1.id.to_s], read_users: [user.user_key]) }
242
+ let!(:collection2) do
243
+ FactoryGirl.create(:collection, members: [asset4], user: user)
244
+ end
245
+ it 'shows only the collections assets' do
246
+ get :show, id: collection
247
+ expect(assigns[:presenter].id).to eq collection.id
248
+ expect(assigns[:member_docs].map(&:id)).to match_array [asset1.id, asset2.id, asset3.id]
249
+ end
250
+
251
+ it 'shows only the other collections assets' do
252
+ get :show, id: collection2
253
+ expect(assigns[:presenter].id).to eq collection2.id
254
+ expect(assigns[:member_docs].map(&:id)).to match_array [asset4.id]
255
+ end
256
+ end
257
+
258
+ context 'When there are search matches that are not in the collection' do
259
+ let!(:bad_asset1) { create(:generic_work, user: user, title: ["#{asset1.id} #{asset1.title.first}"]) }
260
+ let!(:bad_asset2) { create(:generic_work, user: user, title: ["#{asset1.id} #{asset1.title.first}"]) }
261
+
262
+ # NOTE: This test depends on title_tesim being in the qf in solrconfig.xml
263
+ it 'only shows the collection assets' do
264
+ get :show, id: collection, cq: "\"#{asset1.title.first}\""
265
+ expect(assigns[:presenter].id).to eq collection.id
266
+ expect(assigns[:member_docs].map(&:id)).not_to include bad_asset1.id, bad_asset2.id
267
+ expect(assigns[:member_docs].map(&:id)).to match_array [asset1.id]
268
+ end
269
+ end
270
+ end
271
+ end
272
+ end
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe CollectionsController do
4
- routes { Hydra::Collections::Engine.routes }
5
4
  before do
6
5
  allow_any_instance_of(User).to receive(:groups).and_return([])
7
6
  end
@@ -20,7 +19,7 @@ describe CollectionsController do
20
19
  title: ['Bogus Asset'],
21
20
  depositor: 'abc') }
22
21
  let(:collection_attrs) do
23
- { title: 'My First Collection', description: "The Description\r\n\r\nand more" }
22
+ { title: ['My First Collection'], description: ["The Description\r\n\r\nand more"] }
24
23
  end
25
24
 
26
25
  let(:collection) { create(:collection, title: ['Collection Title'], user: user) }