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,17 @@
1
+ module CurationConcerns
2
+ module Naming
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ # Override of ActiveModel::Model name that allows us to use our custom name class
7
+ def model_name
8
+ @_model_name ||= begin
9
+ namespace = parents.detect do |n|
10
+ n.respond_to?(:use_relative_model_naming?) && n.use_relative_model_naming?
11
+ end
12
+ CurationConcerns::Name.new(self, namespace)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ module CurationConcerns
2
+ module Permissions
3
+ module Readable
4
+ extend ActiveSupport::Concern
5
+ def public?
6
+ read_groups.include?('public')
7
+ end
8
+
9
+ def registered?
10
+ read_groups.include?('registered')
11
+ end
12
+
13
+ def private?
14
+ !(public? || registered?)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,34 @@
1
+ module CurationConcerns
2
+ module Permissions
3
+ module Writable
4
+ extend ActiveSupport::Concern
5
+
6
+ # we're overriding the permissions= method which is in Hydra::AccessControls::Permissions
7
+ include Hydra::AccessControls::Permissions
8
+ include Hydra::AccessControls::Visibility
9
+
10
+ included do
11
+ validate :paranoid_permissions
12
+ end
13
+
14
+ def paranoid_permissions
15
+ valid = true
16
+ paranoid_edit_permissions.each do |validation|
17
+ next unless validation[:condition].call(self)
18
+ errors[validation[:key]] ||= []
19
+ errors[validation[:key]] << validation[:message]
20
+ valid = false
21
+ end
22
+ valid
23
+ end
24
+
25
+ def paranoid_edit_permissions
26
+ [
27
+ { key: :edit_users, message: 'Depositor must have edit access', condition: ->(obj) { !obj.edit_users.include?(obj.depositor) } },
28
+ { key: :edit_groups, message: 'Public cannot have edit access', condition: ->(obj) { obj.edit_groups.include?('public') } },
29
+ { key: :edit_groups, message: 'Registered cannot have edit access', condition: ->(obj) { obj.edit_groups.include?('registered') } }
30
+ ]
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,7 @@
1
+ module CurationConcerns
2
+ module Permissions
3
+ extend ActiveSupport::Concern
4
+ include CurationConcerns::Permissions::Writable
5
+ include CurationConcerns::Permissions::Readable
6
+ end
7
+ end
@@ -0,0 +1,30 @@
1
+ module CurationConcerns
2
+ module RequiredMetadata
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ property :depositor, predicate: ::RDF::URI.new('http://id.loc.gov/vocabulary/relators/dpt'), multiple: false do |index|
7
+ index.as :symbol, :stored_searchable
8
+ end
9
+
10
+ property :title, predicate: ::RDF::Vocab::DC.title do |index|
11
+ index.as :stored_searchable, :facetable
12
+ end
13
+
14
+ # We reserve date_uploaded for the original creation date of the record.
15
+ # For example, when migrating data from a fedora3 repo to fedora4,
16
+ # fedora's system created date will reflect the date when the record
17
+ # was created in fedora4, but the date_uploaded will preserve the
18
+ # original creation date from the old repository.
19
+ property :date_uploaded, predicate: ::RDF::Vocab::DC.dateSubmitted, multiple: false do |index|
20
+ index.type :date
21
+ index.as :stored_sortable
22
+ end
23
+
24
+ property :date_modified, predicate: ::RDF::Vocab::DC.modified, multiple: false do |index|
25
+ index.type :date
26
+ index.as :stored_sortable
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,13 @@
1
+ module CurationConcerns
2
+ module Serializers
3
+ def to_s
4
+ if title.present?
5
+ Array(title).join(' | ')
6
+ elsif label.present?
7
+ Array(label).join(' | ')
8
+ else
9
+ 'No Title'
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,147 @@
1
+ module CurationConcerns
2
+ module SolrDocumentBehavior
3
+ extend ActiveSupport::Concern
4
+ include Hydra::Works::MimeTypes
5
+
6
+ def title_or_label
7
+ title || label
8
+ end
9
+
10
+ def to_param
11
+ id
12
+ end
13
+
14
+ def to_s
15
+ title_or_label
16
+ end
17
+
18
+ ##
19
+ # Offer the source (ActiveFedora-based) model to Rails for some of the
20
+ # Rails methods (e.g. link_to).
21
+ # @example
22
+ # link_to '...', SolrDocument(:id => 'bXXXXXX5').new => <a href="/dams_object/bXXXXXX5">...</a>
23
+ def to_model
24
+ @model ||= begin
25
+ m = ActiveFedora::Base.load_instance_from_solr(id, self)
26
+ m.class == ActiveFedora::Base ? self : m
27
+ end
28
+ end
29
+
30
+ def collection?
31
+ hydra_model == 'Collection'
32
+ end
33
+
34
+ # Method to return the ActiveFedora model
35
+ def hydra_model
36
+ self[Solrizer.solr_name('active_fedora_model', Solrizer::Descriptor.new(:string, :stored, :indexed))]
37
+ end
38
+
39
+ def human_readable_type
40
+ Array(self[Solrizer.solr_name('human_readable_type', :stored_searchable)]).first
41
+ end
42
+
43
+ def representative_id
44
+ fetch(Solrizer.solr_name('hasRelatedMediaFragment', :symbol), []).first
45
+ end
46
+
47
+ # Date created is indexed as a string. This allows users to enter values like: 'Circa 1840-1844'
48
+ def date_created
49
+ fetch(Solrizer.solr_name("date_created"), []).first
50
+ end
51
+
52
+ def date_modified
53
+ date_field('date_modified')
54
+ end
55
+
56
+ def date_uploaded
57
+ date_field('date_uploaded')
58
+ end
59
+
60
+ def depositor(default = '')
61
+ val = Array(self[Solrizer.solr_name('depositor')]).first
62
+ val.present? ? val : default
63
+ end
64
+
65
+ def title
66
+ Array(self[Solrizer.solr_name('title')]).first
67
+ end
68
+
69
+ def description
70
+ Array(self[Solrizer.solr_name('description')]).first
71
+ end
72
+
73
+ def label
74
+ Array(self[Solrizer.solr_name('label')]).first
75
+ end
76
+
77
+ def file_format
78
+ Array(self[Solrizer.solr_name('file_format')]).first
79
+ end
80
+
81
+ def creator
82
+ fetch(Solrizer.solr_name('creator'), [])
83
+ end
84
+
85
+ def contributor
86
+ fetch(Solrizer.solr_name('contributor'), [])
87
+ end
88
+
89
+ def subject
90
+ fetch(Solrizer.solr_name('subject'), [])
91
+ end
92
+
93
+ def publisher
94
+ fetch(Solrizer.solr_name('publisher'), [])
95
+ end
96
+
97
+ def language
98
+ fetch(Solrizer.solr_name('language'), [])
99
+ end
100
+
101
+ def tags
102
+ fetch(Solrizer.solr_name('tag'), [])
103
+ end
104
+
105
+ def embargo_release_date
106
+ self[Hydra.config.permissions.embargo.release_date]
107
+ end
108
+
109
+ def lease_expiration_date
110
+ self[Hydra.config.permissions.lease.expiration_date]
111
+ end
112
+
113
+ def rights
114
+ self[Solrizer.solr_name('rights')]
115
+ end
116
+
117
+ def mime_type
118
+ self[Solrizer.solr_name('mime_type', :stored_sortable)]
119
+ end
120
+
121
+ def read_groups
122
+ fetch(Hydra.config.permissions.read.group, [])
123
+ end
124
+
125
+ def visibility
126
+ @visibility ||= if read_groups.include? Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_PUBLIC
127
+ Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PUBLIC
128
+ elsif read_groups.include? Hydra::AccessControls::AccessRight::PERMISSION_TEXT_VALUE_AUTHENTICATED
129
+ Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_AUTHENTICATED
130
+ else
131
+ Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PRIVATE
132
+ end
133
+ end
134
+
135
+ private
136
+
137
+ def date_field(field_name)
138
+ field = self[Solrizer.solr_name(field_name, :stored_sortable, type: :date)]
139
+ return unless field.present?
140
+ begin
141
+ Date.parse(field).to_formatted_s(:standard)
142
+ rescue
143
+ Rails.logger.info "Unable to parse date: #{field.first.inspect} for #{self['id']}"
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,18 @@
1
+ module CurationConcerns::User
2
+ extend ActiveSupport::Concern
3
+ included do
4
+ delegate :can?, :cannot?, to: :ability
5
+ end
6
+
7
+ # Redefine this for more intuitive keys in Redis
8
+ def to_param
9
+ # HACK: because rails doesn't like periods in urls.
10
+ user_key.gsub(/\./, '-dot-')
11
+ end
12
+
13
+ private
14
+
15
+ def ability
16
+ @ability ||= ::Ability.new(self)
17
+ end
18
+ end
@@ -0,0 +1,37 @@
1
+ # Copied from Curate
2
+ module CurationConcerns
3
+ module WithFileSets
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ # The file_sets association and its accessor methods comes from Hydra::Works::AggregatesFileSets
8
+ before_destroy :cleanup_file_sets
9
+ end
10
+
11
+ # Stopgap unil ActiveFedora ContainerAssociation includes an *_ids accessor.
12
+ # At the moment, this is no more efficient than calling file_sets, but hopefully that will change in the future.
13
+ def file_set_ids
14
+ file_sets.map(&:id)
15
+ end
16
+
17
+ def cleanup_file_sets
18
+ # Destroy the list source first. This prevents each file_set from attemping to
19
+ # remove itself individually from the work. If hundreds of files are attached,
20
+ # this would take too long.
21
+
22
+ # Get list of member file_sets from Solr
23
+ fs = file_sets
24
+ list_source.destroy
25
+ # Remove Work from Solr after it was removed from Fedora
26
+ ActiveFedora::SolrService.delete(id)
27
+ fs.each(&:destroy)
28
+ end
29
+
30
+ def copy_visibility_to_files
31
+ file_sets.each do |fs|
32
+ fs.visibility = visibility
33
+ fs.save!
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,45 @@
1
+ module CurationConcerns::WorkBehavior
2
+ extend ActiveSupport::Concern
3
+
4
+ include Hydra::Works::WorkBehavior
5
+ include CurationConcerns::HumanReadableType
6
+ include CurationConcerns::Noid
7
+ include CurationConcerns::Permissions
8
+ include CurationConcerns::Serializers
9
+ include Hydra::WithDepositor
10
+ include Solrizer::Common
11
+ include CurationConcerns::HasRepresentative
12
+ include CurationConcerns::WithFileSets
13
+ include CurationConcerns::Naming
14
+ include CurationConcerns::RequiredMetadata
15
+ include Hydra::AccessControls::Embargoable
16
+ include GlobalID::Identification
17
+
18
+ included do
19
+ property :owner, predicate: RDF::URI.new('http://opaquenamespace.org/ns/hydra/owner'), multiple: false
20
+ class_attribute :human_readable_short_description
21
+ end
22
+
23
+ module ClassMethods
24
+ def indexer
25
+ CurationConcerns::WorkIndexer
26
+ end
27
+
28
+ # This governs which partial to draw when you render this type of object
29
+ def _to_partial_path #:nodoc:
30
+ @_to_partial_path ||= begin
31
+ element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(name))
32
+ collection = ActiveSupport::Inflector.tableize(name)
33
+ "curation_concerns/#{collection}/#{element}".freeze
34
+ end
35
+ end
36
+ end
37
+
38
+ def to_s
39
+ if title.present?
40
+ Array(title).join(' | ')
41
+ else
42
+ 'No Title'
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,49 @@
1
+ require 'active_attr'
2
+ module CurationConcerns
3
+ class ClassifyConcern
4
+ include ActiveAttr::Model
5
+ attribute :curation_concern_type
6
+
7
+ validates(
8
+ :curation_concern_type,
9
+ presence: true,
10
+ inclusion: { in: ->(record) { record.registered_curation_concern_types } }
11
+ )
12
+
13
+ def all_curation_concern_classes
14
+ registered_curation_concern_types.sort.map { |c| self.class.to_class(c) }
15
+ end
16
+
17
+ def registered_curation_concern_types
18
+ CurationConcerns.config.registered_curation_concern_types
19
+ end
20
+
21
+ def possible_curation_concern_types
22
+ registered_curation_concern_types.collect do |concern|
23
+ [self.class.to_class(concern).human_readable_type, concern]
24
+ end
25
+ end
26
+
27
+ def curation_concern_class
28
+ if possible_curation_concern_types.detect do |_name, class_name|
29
+ class_name == curation_concern_type
30
+ end
31
+ self.class.to_class(curation_concern_type)
32
+ else
33
+ fail 'Invalid :curation_concern_type'
34
+ end
35
+ end
36
+
37
+ # @option [String] type name of the model
38
+ # @return [Class] the model class
39
+ def self.to_class(type)
40
+ # TODO: we may want to allow a different (or nil) namespace
41
+ type.camelize.constantize
42
+ # begin
43
+ # "::#{type.camelize}".constantize
44
+ # rescue NameError
45
+ # "CurationConcerns::#{type}".constantize
46
+ # end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,38 @@
1
+ module CurationConcerns
2
+ class QuickClassificationQuery
3
+ attr_reader :user
4
+
5
+ # @param [User] user the current user
6
+ # @param [Hash] options
7
+ # @option options [#call] :concern_name_normalizer (ClassifyConcern.to_class) a proc that translates names to classes
8
+ # @option options [Array<String>] :models the options to display, defaults to everything.
9
+ def initialize(user, options = {})
10
+ @user = user
11
+ @concern_name_normalizer = options.fetch(:concern_name_normalizer, ClassifyConcern.method(:to_class))
12
+ @models = options.fetch(:models, CurationConcerns.config.registered_curation_concern_types)
13
+ end
14
+
15
+ def each(&block)
16
+ authorized_models.each(&block)
17
+ end
18
+
19
+ # @return true if the requested concerns is same as all avaliable concerns
20
+ def all?
21
+ models == CurationConcerns.config.registered_curation_concern_types
22
+ end
23
+
24
+ # @return [Array] a list of all the requested concerns that the user can create
25
+ def authorized_models
26
+ normalized_model_names.select { |klass| user.can?(:create, klass) }
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :concern_name_normalizer, :models
32
+
33
+ # Transform the list of requested model names into a list of class names
34
+ def normalized_model_names
35
+ models.map { |name| concern_name_normalizer.call(name) }
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,34 @@
1
+ class SingleUseLink < ActiveRecord::Base
2
+ validate :expiration_date_cannot_be_in_the_past
3
+ validate :cannot_be_destroyed
4
+
5
+ after_initialize :set_defaults
6
+
7
+ def create_for_path(path)
8
+ self.class.create(itemId: itemId, path: path)
9
+ end
10
+
11
+ def expired?
12
+ DateTime.now > expires
13
+ end
14
+
15
+ def to_param
16
+ downloadKey
17
+ end
18
+
19
+ protected
20
+
21
+ def expiration_date_cannot_be_in_the_past
22
+ errors.add(:expires, "can't be in the past") if expired?
23
+ end
24
+
25
+ def cannot_be_destroyed
26
+ errors[:base] << "Single Use Link has already been used" if destroyed?
27
+ end
28
+
29
+ def set_defaults
30
+ return unless new_record?
31
+ self.expires ||= DateTime.now.advance(hours: 24)
32
+ self.downloadKey ||= (Digest::SHA2.new << rand(1_000_000_000).to_s).to_s
33
+ end
34
+ end
@@ -0,0 +1,2 @@
1
+ class VersionCommitter < ActiveRecord::Base
2
+ end
@@ -1,5 +1,5 @@
1
1
  module CurationConcerns
2
- class CollectionMemberSearchBuilder < Hydra::Collections::MemberSearchBuilder
2
+ class CollectionMemberSearchBuilder < CurationConcerns::MemberSearchBuilder
3
3
  include CurationConcerns::FilterByType
4
4
  end
5
5
  end
@@ -0,0 +1,33 @@
1
+ module CurationConcerns
2
+ class CollectionSearchBuilder < ::SearchBuilder
3
+ # Defines which search_params_logic should be used when searching for Collections
4
+ self.default_processor_chain = [:default_solr_parameters, :add_query_to_solr,
5
+ :add_access_controls_to_solr_params, :add_collection_filter, :some_rows, :sort_by_title]
6
+
7
+ def some_rows(solr_parameters)
8
+ solr_parameters[:rows] = '100'
9
+ end
10
+
11
+ def add_collection_filter(solr_parameters)
12
+ solr_parameters[:fq] ||= []
13
+ solr_parameters[:fq] << ActiveFedora::SolrQueryBuilder.construct_query_for_rel(has_model: ::Collection.to_class_uri)
14
+ end
15
+
16
+ # Sort results by title if no query was supplied.
17
+ # This overrides the default 'relevance' sort.
18
+ def sort_by_title(solr_parameters)
19
+ return if solr_parameters[:q]
20
+ solr_parameters[:sort] ||= "#{sort_field} asc"
21
+ end
22
+
23
+ attr_writer :discovery_perms
24
+
25
+ def discovery_permissions
26
+ @discovery_perms || super
27
+ end
28
+
29
+ def sort_field
30
+ Solrizer.solr_name('title', :sortable)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,17 @@
1
+ module CurationConcerns
2
+ class MemberSearchBuilder < ::SearchBuilder
3
+ class_attribute :from_field
4
+ self.from_field = 'member_ids_ssim'
5
+
6
+ # Defines which search_params_logic should be used when searching for Collection members
7
+ self.default_processor_chain += [:include_collection_ids]
8
+
9
+ delegate :collection, to: :scope
10
+
11
+ # include filters into the query to only include the collection memebers
12
+ def include_collection_ids(solr_parameters)
13
+ solr_parameters[:fq] ||= []
14
+ solr_parameters[:fq] << "{!join from=#{from_field} to=id}id:#{collection.id}"
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,49 @@
1
+ module CurationConcerns
2
+ class DerivativePath
3
+ class << self
4
+ # Path on file system where derivative file is stored
5
+ def derivative_path_for_reference(object, destination_name)
6
+ destination_name = destination_name.gsub(/^original_file_/, '')
7
+ derivative_path(object, extension_for(destination_name), destination_name)
8
+ end
9
+
10
+ # @return [Array<String>] Array of paths to derivatives for this object.
11
+ def derivatives_for_reference(object)
12
+ Dir.glob(root_path(object).join("*")).select do |path|
13
+ path.start_with?(path_prefix(object).to_s)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ # @param [#id] object Object whose ID is used to generate root path
20
+ # @return [String] Returns the root path where derivatives will be generated into.
21
+ def root_path(object)
22
+ Pathname.new(derivative_path(object, "", "")).dirname
23
+ end
24
+
25
+ # @return <Pathname> Full prefix of the path for object.
26
+ def path_prefix(object)
27
+ Pathname.new(CurationConcerns.config.derivatives_path).join(pair_path(object.id))
28
+ end
29
+
30
+ def derivative_path(object, extension, destination_name)
31
+ file_name = destination_name + extension
32
+ "#{path_prefix(object)}-#{file_name}"
33
+ end
34
+
35
+ def pair_path(id)
36
+ id.split('').each_slice(2).map(&:join).join('/')
37
+ end
38
+
39
+ def extension_for(destination_name)
40
+ case destination_name
41
+ when 'thumbnail'
42
+ ".#{MIME::Types.type_for('jpg').first.extensions.first}"
43
+ else
44
+ ".#{destination_name}"
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end