curation_concerns 1.6.3 → 1.7.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (236) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -0
  3. data/.travis.yml +2 -8
  4. data/README.md +27 -1
  5. data/app/actors/curation_concerns/actors/base_actor.rb +2 -3
  6. data/app/actors/curation_concerns/actors/file_set_actor.rb +1 -1
  7. data/app/actors/curation_concerns/actors/grant_edit_to_depositor_actor.rb +19 -0
  8. data/app/actors/curation_concerns/actors/initialize_workflow_actor.rb +19 -0
  9. data/app/assets/javascripts/curation_concerns/charts.js +47 -0
  10. data/app/assets/javascripts/curation_concerns/curation_concerns.js +2 -0
  11. data/app/assets/javascripts/curation_concerns/workflow_actions_affix.js +11 -0
  12. data/app/assets/stylesheets/curation_concerns/_admin.scss +18 -0
  13. data/app/assets/stylesheets/curation_concerns/_curation_concerns.scss +1 -0
  14. data/app/assets/stylesheets/curation_concerns/_positioning.scss +11 -0
  15. data/app/controllers/concerns/curation_concerns/act_as_admin_controller.rb +25 -0
  16. data/app/controllers/concerns/curation_concerns/admin_controller_behavior.rb +38 -0
  17. data/app/controllers/concerns/curation_concerns/admin_page.rb +18 -0
  18. data/app/controllers/concerns/curation_concerns/collections_controller_behavior.rb +3 -2
  19. data/app/controllers/concerns/curation_concerns/curation_concern_controller.rb +158 -159
  20. data/app/controllers/concerns/curation_concerns/embargoes_controller_behavior.rb +4 -6
  21. data/app/controllers/concerns/curation_concerns/file_sets_controller_behavior.rb +2 -1
  22. data/app/controllers/concerns/curation_concerns/leases_controller_behavior.rb +4 -6
  23. data/app/controllers/concerns/curation_concerns/single_use_links_viewer_controller_behavior.rb +2 -1
  24. data/app/controllers/curation_concerns/admin/workflow_roles_controller.rb +36 -0
  25. data/app/controllers/curation_concerns/workflow_actions_controller.rb +25 -0
  26. data/app/conversions/power_converters/polymorphic_type.rb +7 -0
  27. data/app/conversions/power_converters/sipity_action.rb +9 -0
  28. data/app/conversions/power_converters/sipity_action_name.rb +8 -0
  29. data/app/conversions/power_converters/sipity_agent.rb +6 -0
  30. data/app/conversions/power_converters/sipity_entity.rb +12 -0
  31. data/app/conversions/power_converters/sipity_role.rb +8 -0
  32. data/app/conversions/power_converters/sipity_workflow_id.rb +16 -0
  33. data/app/conversions/power_converters/sipity_workflow_state.rb +10 -0
  34. data/app/conversions/power_converters.rb +6 -0
  35. data/app/forms/curation_concerns/forms/workflow_action_form.rb +62 -0
  36. data/app/forms/curation_concerns/forms/workflow_responsibility_form.rb +42 -0
  37. data/app/helpers/curation_concerns/charts_helper.rb +23 -0
  38. data/app/helpers/curation_concerns/main_app_helpers.rb +1 -0
  39. data/app/helpers/curation_concerns/url_helper.rb +2 -5
  40. data/app/indexers/curation_concerns/indexes_workflow.rb +44 -0
  41. data/app/indexers/curation_concerns/work_indexer.rb +1 -2
  42. data/app/jobs/import_export_job.rb +46 -0
  43. data/app/models/concerns/curation_concerns/ability.rb +2 -0
  44. data/app/models/concerns/curation_concerns/permissions/writable.rb +7 -8
  45. data/app/models/concerns/curation_concerns/publishable.rb +6 -0
  46. data/app/models/concerns/curation_concerns/solr_document_behavior.rb +8 -0
  47. data/app/models/concerns/curation_concerns/user.rb +5 -0
  48. data/app/models/curation_concerns/group.rb +23 -0
  49. data/app/models/curation_concerns/workflow_action_info.rb +13 -0
  50. data/app/models/sipity/agent.rb +21 -0
  51. data/app/models/sipity/comment.rb +13 -0
  52. data/app/models/sipity/entity.rb +32 -0
  53. data/app/models/sipity/entity_specific_responsibility.rb +21 -0
  54. data/app/models/sipity/method.rb +5 -0
  55. data/app/models/sipity/notifiable_context.rb +26 -0
  56. data/app/models/sipity/notification.rb +28 -0
  57. data/app/models/sipity/notification_recipient.rb +17 -0
  58. data/app/models/sipity/role.rb +43 -0
  59. data/app/models/sipity/workflow.rb +19 -0
  60. data/app/models/sipity/workflow_action.rb +25 -0
  61. data/app/models/sipity/workflow_responsibility.rb +23 -0
  62. data/app/models/sipity/workflow_role.rb +13 -0
  63. data/app/models/sipity/workflow_state.rb +26 -0
  64. data/app/models/sipity/workflow_state_action.rb +9 -0
  65. data/app/models/sipity/workflow_state_action_permission.rb +8 -0
  66. data/app/models/vocab/fedora_resource_status.rb +4 -1
  67. data/app/presenters/curation_concerns/admin/workflow_role_presenter.rb +40 -0
  68. data/app/presenters/curation_concerns/work_show_presenter.rb +4 -0
  69. data/app/presenters/curation_concerns/workflow_presenter.rb +43 -0
  70. data/app/renderers/curation_concerns/renderers/rights_attribute_renderer.rb +1 -1
  71. data/app/search_builders/curation_concerns/search_filters.rb +0 -1
  72. data/app/services/curation_concerns/actors/actor_factory.rb +3 -1
  73. data/app/services/curation_concerns/admin_set_service.rb +13 -4
  74. data/app/services/curation_concerns/work_form_service.rb +11 -0
  75. data/app/services/curation_concerns/workflow/action_taken_service.rb +57 -0
  76. data/app/services/curation_concerns/workflow/activate_object.rb +9 -0
  77. data/app/services/curation_concerns/workflow/deactivate_object.rb +11 -0
  78. data/app/services/curation_concerns/workflow/default_workflow_strategy.rb +13 -0
  79. data/app/services/curation_concerns/workflow/method_generator.rb +55 -0
  80. data/app/services/curation_concerns/workflow/notification_configuration_parameter.rb +42 -0
  81. data/app/services/curation_concerns/workflow/notification_generator.rb +64 -0
  82. data/app/services/curation_concerns/workflow/notification_service.rb +66 -0
  83. data/app/services/curation_concerns/workflow/permission_generator.rb +95 -0
  84. data/app/services/curation_concerns/workflow/permission_query.rb +432 -0
  85. data/app/services/curation_concerns/workflow/remove_depositor_permissions.rb +11 -0
  86. data/app/services/curation_concerns/workflow/sipity_actions_generator.rb +49 -0
  87. data/app/services/curation_concerns/workflow/state_machine_generator.rb +102 -0
  88. data/app/services/curation_concerns/workflow/status_list_service.rb +52 -0
  89. data/app/services/curation_concerns/workflow/workflow_action_service.rb +56 -0
  90. data/app/services/curation_concerns/workflow/workflow_by_model_name_strategy.rb +14 -0
  91. data/app/services/curation_concerns/workflow/workflow_factory.rb +64 -0
  92. data/app/services/curation_concerns/workflow/workflow_importer.rb +103 -0
  93. data/app/services/curation_concerns/workflow/workflow_permissions_generator.rb +49 -0
  94. data/app/services/curation_concerns/workflow/workflow_schema.rb +56 -0
  95. data/app/services/rights_service.rb +1 -1
  96. data/app/services/sipity.rb +2 -0
  97. data/app/sources/curation_concerns/resource_statistics_source.rb +101 -0
  98. data/app/values/curation_concerns/chart_data.rb +61 -0
  99. data/app/views/curation_concerns/admin/_admin_menu.html.erb +5 -0
  100. data/app/views/curation_concerns/admin/_resource_stats.html.erb +43 -0
  101. data/app/views/curation_concerns/admin/_sidebar.html.erb +3 -0
  102. data/app/views/curation_concerns/admin/_total_embargo_visibility.html.erb +21 -0
  103. data/app/views/curation_concerns/admin/_total_objects.html.erb +1 -0
  104. data/app/views/curation_concerns/admin/_total_objects_charts.html.erb +12 -0
  105. data/app/views/curation_concerns/admin/index.html.erb +11 -0
  106. data/app/views/curation_concerns/admin/widgets/_pie.html.erb +1 -0
  107. data/app/views/curation_concerns/admin/workflow.html.erb +31 -0
  108. data/app/views/curation_concerns/admin/workflow_roles/index.html.erb +45 -0
  109. data/app/views/curation_concerns/base/_form_rights.html.erb +1 -1
  110. data/app/views/curation_concerns/base/_workflow_actions.html.erb +39 -0
  111. data/app/views/curation_concerns/base/show.html.erb +2 -0
  112. data/app/views/curation_concerns/file_sets/media_display/_office_document.html.erb +0 -1
  113. data/app/views/layouts/_head_tag_content.html.erb +13 -0
  114. data/app/views/layouts/admin.html.erb +10 -0
  115. data/app/views/shared/_my_actions.html.erb +4 -1
  116. data/config/initializers/precompile_assets.rb +1 -0
  117. data/config/locales/curation_concerns.en.yml +97 -56
  118. data/config/routes.rb +7 -0
  119. data/curation_concerns.gemspec +9 -3
  120. data/db/migrate/20160919151348_create_sipity.rb +163 -0
  121. data/db/migrate/20161012182404_create_sipity_workflow_methods.rb +10 -0
  122. data/lib/curation_concerns/configuration.rb +68 -0
  123. data/lib/curation_concerns/engine.rb +9 -1
  124. data/lib/curation_concerns/rails/routes.rb +1 -0
  125. data/lib/curation_concerns/version.rb +1 -1
  126. data/lib/curation_concerns.rb +1 -1
  127. data/lib/generators/curation_concerns/admin_dashboard_generator.rb +15 -0
  128. data/lib/generators/curation_concerns/install_generator.rb +7 -0
  129. data/lib/generators/curation_concerns/sample_data_generator.rb +12 -0
  130. data/lib/generators/curation_concerns/templates/app/controllers/curation_concerns/admin_controller.rb +61 -0
  131. data/lib/generators/curation_concerns/templates/catalog_controller.rb +1 -3
  132. data/lib/generators/curation_concerns/templates/config/curation_concerns.rb +39 -0
  133. data/lib/generators/curation_concerns/templates/db/seeds.rb +94 -0
  134. data/lib/generators/curation_concerns/templates/spec/models/collection_spec.rb +1 -1
  135. data/lib/generators/curation_concerns/templates/spec/models/file_set_spec.rb +1 -1
  136. data/lib/generators/curation_concerns/templates/workflow.json.erb +19 -0
  137. data/lib/generators/curation_concerns/work/USAGE +1 -0
  138. data/lib/generators/curation_concerns/work/templates/actor_spec.rb.erb +1 -1
  139. data/lib/generators/curation_concerns/work/templates/controller_spec.rb.erb +1 -1
  140. data/lib/generators/curation_concerns/work/templates/feature_spec.rb.erb +1 -1
  141. data/lib/generators/curation_concerns/work/templates/form_spec.rb.erb +1 -1
  142. data/lib/generators/curation_concerns/work/templates/model_spec.rb.erb +1 -1
  143. data/spec/abilities/admin_ability_spec.rb +15 -0
  144. data/spec/actors/curation_concerns/file_set_actor_spec.rb +24 -0
  145. data/spec/actors/curation_concerns/grant_edit_to_depositor_actor_spec.rb +32 -0
  146. data/spec/actors/curation_concerns/initialize_workflow_actor_spec.rb +33 -0
  147. data/spec/actors/curation_concerns/interpret_visibility_actor_spec.rb +1 -0
  148. data/spec/actors/curation_concerns/work_actor_spec.rb +10 -5
  149. data/spec/controllers/curation_concerns/acts_as_admin_controller_spec.rb +22 -0
  150. data/spec/controllers/curation_concerns/admin/workflow_roles_controller_spec.rb +26 -0
  151. data/spec/controllers/curation_concerns/admin_controller_spec.rb +64 -0
  152. data/spec/controllers/curation_concerns/generic_works_controller_json_spec.rb +11 -3
  153. data/spec/controllers/curation_concerns/generic_works_controller_spec.rb +4 -4
  154. data/spec/controllers/curation_concerns/workflow_actions_controller_spec.rb +36 -0
  155. data/spec/conversions/power_converters/polymorphic_type_spec.rb +22 -0
  156. data/spec/conversions/power_converters/sipity_action_name_spec.rb +32 -0
  157. data/spec/conversions/power_converters/sipity_action_spec.rb +43 -0
  158. data/spec/conversions/power_converters/sipity_agent_spec.rb +20 -0
  159. data/spec/conversions/power_converters/sipity_entity_spec.rb +46 -0
  160. data/spec/conversions/power_converters/sipity_role_spec.rb +33 -0
  161. data/spec/conversions/power_converters/sipity_workflow_id_spec.rb +28 -0
  162. data/spec/conversions/power_converters/sipity_workflow_state_spec.rb +22 -0
  163. data/spec/factories/generic_works.rb +19 -6
  164. data/spec/factories/sipity_entities.rb +7 -0
  165. data/spec/factories/workflow_actions.rb +6 -0
  166. data/spec/factories/workflow_states.rb +6 -0
  167. data/spec/factories/workflows.rb +5 -0
  168. data/spec/features/admin_spec.rb +14 -0
  169. data/spec/features/create_child_work_spec.rb +1 -1
  170. data/spec/features/create_work_spec.rb +1 -1
  171. data/spec/features/embargo_spec.rb +1 -1
  172. data/spec/features/lease_spec.rb +1 -1
  173. data/spec/features/work_generator_spec.rb +2 -2
  174. data/spec/features/workflow_roles_spec.rb +48 -0
  175. data/spec/forms/curation_concerns/forms/workflow_action_form_spec.rb +111 -0
  176. data/spec/forms/curation_concerns/forms/workflow_responsibility_form_spec.rb +33 -0
  177. data/spec/helpers/curation_concerns/charts_helper_spec.rb +62 -0
  178. data/spec/helpers/url_helper_spec.rb +11 -11
  179. data/spec/indexers/work_indexer_spec.rb +13 -1
  180. data/spec/javascripts/charts_spec.coffee +10 -0
  181. data/spec/javascripts/fixtures/chart_example.html +1 -0
  182. data/spec/jobs/import_export_job_spec.rb +28 -0
  183. data/spec/models/curation_concerns/group_spec.rb +15 -0
  184. data/spec/models/file_set_spec.rb +6 -2
  185. data/spec/models/generic_work_spec.rb +12 -0
  186. data/spec/models/sipity/agent_spec.rb +9 -0
  187. data/spec/models/sipity/comment_spec.rb +16 -0
  188. data/spec/models/sipity/entity_spec.rb +27 -0
  189. data/spec/models/sipity/entity_specific_responsibility_spec.rb +8 -0
  190. data/spec/models/sipity/notifiable_context_spec.rb +8 -0
  191. data/spec/models/sipity/notification_recipient_spec.rb +10 -0
  192. data/spec/models/sipity/notification_spec.rb +15 -0
  193. data/spec/models/sipity/role_spec.rb +30 -0
  194. data/spec/models/sipity/workflow_action_spec.rb +10 -0
  195. data/spec/models/sipity/workflow_responsibility_spec.rb +7 -0
  196. data/spec/models/sipity/workflow_role_spec.rb +7 -0
  197. data/spec/models/sipity/workflow_spec.rb +15 -0
  198. data/spec/models/sipity/workflow_state_action_permission_spec.rb +7 -0
  199. data/spec/models/sipity/workflow_state_action_spec.rb +7 -0
  200. data/spec/models/sipity/workflow_state_spec.rb +7 -0
  201. data/spec/models/user_spec.rb +12 -1
  202. data/spec/presenters/curation_concerns/work_show_presenter_spec.rb +12 -1
  203. data/spec/presenters/curation_concerns/workflow_presenter_spec.rb +39 -0
  204. data/spec/routing/route_spec.rb +13 -0
  205. data/spec/services/curation_concerns/admin_set_service_spec.rb +13 -0
  206. data/spec/services/curation_concerns/qa_select_service_spec.rb +75 -0
  207. data/spec/services/curation_concerns/workflow/action_taken_service_spec.rb +76 -0
  208. data/spec/services/curation_concerns/workflow/activate_object_spec.rb +20 -0
  209. data/spec/services/curation_concerns/workflow/deactivate_object_spec.rb +20 -0
  210. data/spec/services/curation_concerns/workflow/method_generator_spec.rb +43 -0
  211. data/spec/services/curation_concerns/workflow/notification_configuration_parameter_spec.rb +25 -0
  212. data/spec/services/curation_concerns/workflow/notification_generator_spec.rb +27 -0
  213. data/spec/services/curation_concerns/workflow/notification_service_spec.rb +81 -0
  214. data/spec/services/curation_concerns/workflow/permission_generator_spec.rb +52 -0
  215. data/spec/services/curation_concerns/workflow/permission_query_spec.rb +179 -0
  216. data/spec/services/curation_concerns/workflow/remove_depositor_permissions_spec.rb +21 -0
  217. data/spec/services/curation_concerns/workflow/sipity_actions_generator_spec.rb +30 -0
  218. data/spec/services/curation_concerns/workflow/state_machine_generator_spec.rb +46 -0
  219. data/spec/services/curation_concerns/workflow/status_list_service_spec.rb +46 -0
  220. data/spec/services/curation_concerns/workflow/workflow_importer_spec.rb +50 -0
  221. data/spec/services/curation_concerns/workflow/workflow_permissions_generator_spec.rb +37 -0
  222. data/spec/services/curation_concerns/workflow/workflow_schema_spec.rb +85 -0
  223. data/spec/sources/curation_concerns/resource_statistics_source_spec.rb +137 -0
  224. data/spec/spec_helper.rb +8 -1
  225. data/spec/test_app_templates/lib/generators/test_app_generator.rb +11 -0
  226. data/spec/views/curation_concerns/admin/_admin_menu.html.erb_spec.rb +23 -0
  227. data/spec/views/curation_concerns/admin/_resource_stats.html.erb_spec.rb +33 -0
  228. data/spec/views/curation_concerns/admin/_total_objects_charts.html.erb_spec.rb +28 -0
  229. data/spec/views/curation_concerns/admin/index.html.erb_spec.rb +26 -0
  230. data/spec/views/curation_concerns/admin/widgets/_pie.html.erb_spec.rb +17 -0
  231. data/spec/views/curation_concerns/base/file_manager.html.erb_spec.rb +1 -1
  232. data/spec/views/curation_concerns/base/show.html.erb_spec.rb +33 -0
  233. data/spec/views/curation_concerns/permissions/confirm.html.erb_spec.rb +1 -1
  234. data/spec/views/shared/_my_actions.html.erb_spec.rb +1 -0
  235. data/tasks/workflow.rake +8 -0
  236. metadata +335 -21
@@ -0,0 +1,56 @@
1
+ module CurationConcerns
2
+ module Workflow
3
+ class WorkflowActionService
4
+ def self.run(subject:, action:, comment: nil)
5
+ new(subject: subject, action: action, comment: comment).run
6
+ end
7
+
8
+ def initialize(subject:, action:, comment:)
9
+ @subject = subject
10
+ @action = action
11
+ @comment_text = comment
12
+ end
13
+
14
+ attr_reader :subject, :action, :comment_text
15
+
16
+ def run
17
+ update_sipity_workflow_state
18
+ comment = create_sipity_comment
19
+ handle_sipity_notifications(comment: comment)
20
+ handle_additional_sipity_workflow_action_processing(comment: comment)
21
+ subject.work.update_index # So that the new actions and state are written into solr.
22
+ end
23
+
24
+ protected
25
+
26
+ def update_sipity_workflow_state
27
+ return true unless action.resulting_workflow_state_id.present?
28
+ subject.entity.update_attribute(:workflow_state_id, action.resulting_workflow_state_id)
29
+ end
30
+
31
+ def create_sipity_comment
32
+ return true unless comment_text.present?
33
+ Sipity::Comment.create!(entity: subject.entity, agent: subject.agent, comment: comment_text)
34
+ end
35
+
36
+ def handle_sipity_notifications(comment:)
37
+ CurationConcerns::Workflow::NotificationService.deliver_on_action_taken(
38
+ entity: subject.entity,
39
+ comment: comment,
40
+ action: action,
41
+ user: subject.user
42
+ )
43
+ end
44
+
45
+ # Run any configured custom methods
46
+ def handle_additional_sipity_workflow_action_processing(comment:)
47
+ CurationConcerns::Workflow::ActionTakenService.handle_action_taken(
48
+ entity: subject.entity,
49
+ comment: comment,
50
+ action: action,
51
+ user: subject.user
52
+ )
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,14 @@
1
+ module CurationConcerns
2
+ module Workflow
3
+ class WorkflowByModelNameStrategy
4
+ def initialize(work, _attributes)
5
+ @work = work
6
+ end
7
+
8
+ # @return [String] The name of the workflow to use
9
+ def workflow_name
10
+ 'default'
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,64 @@
1
+ module CurationConcerns
2
+ module Workflow
3
+ class WorkflowFactory
4
+ class_attribute :workflow_strategy
5
+ self.workflow_strategy = DefaultWorkflowStrategy
6
+
7
+ # @param work [#to_global_id]
8
+ # @param attributes [Hash]
9
+ # @param strategy [#name] strategy for finding which workflow to use. Defaults to an instance of WorkflowByModelNameStrategy
10
+ # @return [TrueClass]
11
+ def self.create(work, attributes, user, strategy = nil)
12
+ strategy ||= workflow_strategy.new(work, attributes)
13
+ new(work, attributes, user, strategy).create
14
+ end
15
+
16
+ # @param work [#to_global_id]
17
+ # @param attributes [Hash]
18
+ # @param strategy [#name] strategy for finding which workflow to use
19
+ def initialize(work, attributes, user, strategy)
20
+ @work = work
21
+ @attributes = attributes
22
+ @user = user
23
+ @strategy = strategy
24
+ end
25
+
26
+ attr_reader :work, :attributes, :user, :strategy
27
+ private :work, :attributes, :strategy
28
+
29
+ # Creates a Sipity::Entity for the work.
30
+ # The Sipity::Entity acts as a proxy to a work within a workflow
31
+ # @return [TrueClass]
32
+ def create
33
+ Sipity::Entity.create!(proxy_for_global_id: work.to_global_id.to_s,
34
+ workflow: workflow,
35
+ workflow_state: nil)
36
+
37
+ subject = WorkflowActionInfo.new(work, user)
38
+ Workflow::WorkflowActionService.run(subject: subject,
39
+ action: find_deposit_action)
40
+ true
41
+ end
42
+
43
+ # This tells us which workflow to use. If no workflow is found with the expected name
44
+ # then load the workflows in config/workflows/*.json and try again.
45
+ # @return [Sipity::Workflow]
46
+ def workflow
47
+ @workflow ||= Sipity::Workflow.find_by(name: workflow_name) ||
48
+ (CurationConcerns::Workflow::WorkflowImporter.load_workflows &&
49
+ Sipity::Workflow.find_by!(name: workflow_name))
50
+ end
51
+
52
+ delegate :workflow_name, to: :strategy
53
+
54
+ # Find an action that has no starting state. This is the deposit action.
55
+ # # @return [Sipity::WorkflowAction]
56
+ def find_deposit_action
57
+ actions_that_lead_to_states = Sipity::WorkflowStateAction.all.pluck(:workflow_action_id)
58
+ relation = Sipity::WorkflowAction.where(workflow: workflow)
59
+ relation = relation.where('id NOT IN (?)', actions_that_lead_to_states) if actions_that_lead_to_states.any?
60
+ relation.first!
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,103 @@
1
+ module CurationConcerns
2
+ module Workflow
3
+ class WorkflowImporter
4
+ # @api public
5
+ #
6
+ # Load all the workflows in config/workflows/*.json
7
+ # @return [TrueClass]
8
+ def self.load_workflows
9
+ Dir.glob(Rails.root + "config/workflows/*.json") do |config|
10
+ Rails.logger.info "Loading workflow: #{config}"
11
+ generate_from_json_file(path: config)
12
+ end
13
+ true
14
+ end
15
+
16
+ # @api public
17
+ #
18
+ # Responsible for generating the work type and corresponding processing entries based on given pathname or JSON document.
19
+ #
20
+ # @return [Array<Sipity::Workflow>]
21
+ def self.generate_from_json_file(path:, **keywords)
22
+ contents = path.respond_to?(:read) ? path.read : File.read(path)
23
+ data = JSON.parse(contents)
24
+ new(data: data, **keywords).call
25
+ end
26
+
27
+ # @param data [#deep_symbolize_keys] the configuration information from which we will generate all the data entries
28
+ # @param schema [#call] The schema in which you will validate the data
29
+ # @param validator [#call] The validation service for the given data and schema
30
+ def initialize(data:, schema: default_schema, validator: default_validator)
31
+ self.data = data
32
+ self.schema = schema
33
+ self.validator = validator
34
+ validate!
35
+ end
36
+
37
+ private
38
+
39
+ attr_reader :data
40
+
41
+ def data=(input)
42
+ @data = input.deep_symbolize_keys
43
+ end
44
+
45
+ attr_accessor :validator
46
+
47
+ def default_validator
48
+ SchemaValidator.method(:call)
49
+ end
50
+
51
+ attr_accessor :schema
52
+
53
+ def default_schema
54
+ CurationConcerns::Workflow::WorkflowSchema
55
+ end
56
+
57
+ def validate!
58
+ validator.call(data: data, schema: schema)
59
+ end
60
+
61
+ public
62
+
63
+ def call
64
+ Array.wrap(data.fetch(:workflows)).map do |configuration|
65
+ find_or_create_from(configuration: configuration)
66
+ end
67
+ end
68
+
69
+ private
70
+
71
+ def find_or_create_from(configuration:)
72
+ workflow = Sipity::Workflow.find_or_initialize_by(name: configuration.fetch(:name)) do |wf|
73
+ wf.label = configuration.fetch(:label, nil)
74
+ wf.description = configuration.fetch(:description, nil)
75
+ wf.save!
76
+ end
77
+
78
+ find_or_create_workflow_permissions!(
79
+ workflow: workflow, workflow_permissions_configuration: configuration.fetch(:workflow_permissions, [])
80
+ )
81
+ generate_state_diagram(workflow: workflow, actions_configuration: configuration.fetch(:actions))
82
+ workflow
83
+ end
84
+
85
+ extend Forwardable
86
+ def_delegator WorkflowPermissionsGenerator, :call, :find_or_create_workflow_permissions!
87
+ def_delegator SipityActionsGenerator, :call, :generate_state_diagram
88
+
89
+ module SchemaValidator
90
+ # @param data [Hash]
91
+ # @param schema [#call]
92
+ #
93
+ # @return true if the data validates from the schema
94
+ # @raise Exceptions::InvalidSchemaError if the data does not validate against the schema
95
+ def self.call(data:, schema:)
96
+ validation = schema.call(data)
97
+ return true unless validation.messages.present?
98
+ raise validation.messages.inspect
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,49 @@
1
+ module CurationConcerns
2
+ module Workflow
3
+ # Responsible for creating database entries for the given workflow's permissions
4
+ class WorkflowPermissionsGenerator
5
+ # @api public
6
+ #
7
+ # Responsible for creating database entries for the given workflow's permissions
8
+ #
9
+ # @param workflow [Sipity::Workflow]
10
+ # @param workflow_permissions_configuration [Hash] as defined in CurationConcerns::Workflow::WorkflowSchema
11
+ # @return [Sipity::Workflow]
12
+ def self.call(workflow:, workflow_permissions_configuration:)
13
+ new(workflow: workflow, workflow_permissions_configuration: workflow_permissions_configuration).call
14
+ end
15
+
16
+ def initialize(workflow:, workflow_permissions_configuration:)
17
+ self.workflow = workflow
18
+ self.workflow_permissions_configuration = workflow_permissions_configuration
19
+ end
20
+
21
+ private
22
+
23
+ attr_accessor :workflow
24
+ attr_reader :workflow_permissions_configuration
25
+
26
+ def workflow_permissions_configuration=(input)
27
+ @workflow_permissions_configuration = Array.wrap(input)
28
+ end
29
+
30
+ public
31
+
32
+ def call
33
+ find_or_create_workflow_permissions!
34
+ workflow
35
+ end
36
+
37
+ private
38
+
39
+ def find_or_create_workflow_permissions!
40
+ # In Sipity application, Agents were assigned in the configuration file.
41
+ # However this is something assigned via a UI component for a given role.
42
+ default_agents = []
43
+ workflow_permissions_configuration.each do |configuration|
44
+ PermissionGenerator.call(agents: default_agents, roles: configuration.fetch(:role), workflow: workflow)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,56 @@
1
+ module CurationConcerns
2
+ module Workflow
3
+ # Responsible for describing the JSON schema for a Workflow.
4
+ #
5
+ # The `workflows name` defines the name of the Sipity::Workflow.
6
+ # The `workflows actions` defines the actions that can be taken in the given states (e.g. :from_states) by the given :roles.
7
+ # The `workflows actions transition_to` defines the state to which we transition when the action is taken.
8
+ # The `workflows actions notifications` defines the notifications that should be sent when the action is taken.
9
+ #
10
+ # @see Sipity::Workflow
11
+ # @see Sipity::WorkflowAction
12
+ # @see Sipity::WorkflowState
13
+ # @see Sipity::Role
14
+ # @see Sipity::Notification
15
+ # @see Sipity::Method
16
+ # @see ./lib/generators/curation_concerns/work/templates/workflow.json.erb
17
+ WorkflowSchema = Dry::Validation.Schema do
18
+ configure do
19
+ def self.messages
20
+ Dry::Validation::Messages.default.merge(
21
+ en: { errors: { constant_name?: 'must be an initialized Ruby constant' } }
22
+ )
23
+ end
24
+
25
+ def constant_name?(value)
26
+ value.constantize
27
+ true
28
+ rescue NameError
29
+ false
30
+ end
31
+ end
32
+
33
+ required(:workflows).each do
34
+ required(:name).filled(:str?) # Sipity::Workflow#name
35
+ optional(:label).filled(:str?) # Sipity::Workflow#label
36
+ optional(:description).filled(:str?) # Sipity::Workflow#description
37
+ required(:actions).each do
38
+ required(:name).filled(:str?) # Sipity::WorkflowAction#name
39
+ required(:from_states).each do
40
+ required(:names) { array? { each(:str?) } } # Sipity::WorkflowState#name
41
+ required(:roles) { array? { each(:str?) } } # Sipity::Role#name
42
+ end
43
+ optional(:transition_to).filled(:str?) # Sipity::WorkflowState#name
44
+ optional(:notifications).each do
45
+ required(:name).value(:constant_name?) # Sipity::Notification#name
46
+ required(:notification_type).value(included_in?: Sipity::Notification.valid_notification_types)
47
+ required(:to) { array? { each(:str?) } }
48
+ optional(:cc) { array? { each(:str?) } }
49
+ optional(:bcc) { array? { each(:str?) } }
50
+ end
51
+ optional(:methods) { array? { each(:str?) } }
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -9,7 +9,7 @@ module RightsService
9
9
  end
10
10
 
11
11
  def self.select_all_options
12
- Deprecation.warn(RightsService, "RightsService is deprecated. Use CurationConcerns::LicenseService instead. This will be removed in curation_concerns 2.0")
12
+ Deprecation.warn(RightsService, "RightsService is deprecated. Use CurationConcerns.config.license_service_class instead. This will be removed in curation_concerns 2.0")
13
13
  authority.all.map do |element|
14
14
  [element[:label], element[:id]]
15
15
  end
@@ -0,0 +1,2 @@
1
+ module Sipity
2
+ end
@@ -0,0 +1,101 @@
1
+ module CurationConcerns
2
+ class ResourceStatisticsSource
3
+ attr_accessor :search_builder, :repository
4
+ def initialize(search_builder: ::CurationConcerns::AdminController.new.search_builder, repository: ::CurationConcerns::AdminController.new.repository)
5
+ # Remove gated discovery.
6
+ @search_builder = search_builder.except(:add_access_controls_to_solr_params)
7
+ @repository = repository
8
+ solr_arguments[:fq] ||= []
9
+ solr_arguments[:rows] = 0
10
+ end
11
+
12
+ def open_concerns_count
13
+ results_count(public_read_group)
14
+ end
15
+
16
+ def authenticated_concerns_count
17
+ results_count(registered_read_group)
18
+ end
19
+
20
+ def restricted_concerns_count
21
+ results_count([not_registered_read_group, not_public_read_group])
22
+ end
23
+
24
+ def expired_embargo_now_authenticated_concerns_count
25
+ results_count([registered_read_group, embargo_history_query])
26
+ end
27
+
28
+ def expired_embargo_now_open_concerns_count
29
+ results_count([public_read_group, embargo_history_query])
30
+ end
31
+
32
+ def active_embargo_now_authenticated_concerns_count
33
+ results_count([registered_read_group, active_embargo])
34
+ end
35
+
36
+ def active_embargo_now_restricted_concerns_count
37
+ results_count([not_registered_read_group, not_public_read_group, active_embargo])
38
+ end
39
+
40
+ def expired_lease_now_authenticated_concerns_count
41
+ results_count([registered_read_group, lease_history_query])
42
+ end
43
+
44
+ def expired_lease_now_restricted_concerns_count
45
+ results_count([not_registered_read_group, not_public_read_group, lease_history_query])
46
+ end
47
+
48
+ def active_lease_now_authenticated_concerns_count
49
+ results_count([registered_read_group, active_lease])
50
+ end
51
+
52
+ def active_lease_now_open_concerns_count
53
+ results_count([public_read_group, active_lease])
54
+ end
55
+
56
+ private
57
+
58
+ def solr_arguments
59
+ @solr_arguments ||= search_builder.to_h
60
+ end
61
+
62
+ def results_count(query)
63
+ q = { fq: Array.wrap(query) }
64
+ repository.search(solr_arguments.merge(q) do |_key, v1, v2|
65
+ v1 + v2
66
+ end)["response"]["numFound"]
67
+ end
68
+
69
+ def active_lease
70
+ "lease_expiration_date_dtsi:[NOW TO *]"
71
+ end
72
+
73
+ def active_embargo
74
+ "embargo_release_date_dtsi:[NOW TO *]"
75
+ end
76
+
77
+ def lease_history_query
78
+ "lease_history_ssim:*"
79
+ end
80
+
81
+ def embargo_history_query
82
+ "embargo_history_ssim:*"
83
+ end
84
+
85
+ def registered_read_group
86
+ "#{Hydra.config.permissions.read.group}:registered"
87
+ end
88
+
89
+ def not_registered_read_group
90
+ "-#{registered_read_group}"
91
+ end
92
+
93
+ def public_read_group
94
+ "#{Hydra.config.permissions.read.group}:public"
95
+ end
96
+
97
+ def not_public_read_group
98
+ "-#{public_read_group}"
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,61 @@
1
+ module CurationConcerns
2
+ class ChartData
3
+ attr_reader :data
4
+ def initialize(data)
5
+ @data = data
6
+ end
7
+
8
+ def drilldown
9
+ data.each_with_object([]) do |(k, v), arr|
10
+ arr << Value.new(k, v).drilldown_value
11
+ end.compact
12
+ end
13
+
14
+ def series
15
+ data.each_with_object([]) do |(k, v), arr|
16
+ arr << Value.new(k, v).series_value
17
+ end
18
+ end
19
+
20
+ class Value
21
+ def initialize(key, value)
22
+ @key = key
23
+ @value = value
24
+ end
25
+
26
+ def series_value
27
+ if @value.is_a?(Hash)
28
+ drilldown_hash
29
+ else
30
+ series_hash
31
+ end
32
+ end
33
+
34
+ def drilldown_value
35
+ return nil unless @value.is_a?(Hash)
36
+ {
37
+ name: @key,
38
+ id: @key,
39
+ data: @value.to_a
40
+ }
41
+ end
42
+
43
+ private
44
+
45
+ def drilldown_hash
46
+ {
47
+ name: @key,
48
+ y: @value.values.inject(&:+),
49
+ drilldown: @key
50
+ }
51
+ end
52
+
53
+ def series_hash
54
+ {
55
+ name: @key,
56
+ y: @value
57
+ }
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,5 @@
1
+ <% configuration[:menu].each do |key, config| %>
2
+ <%= content_tag :li, class: (action_name == key ? 'active' : '') do %>
3
+ <%= link_to t("curation_concerns.dashboard.menu.#{key}"), polymorphic_path([curation_concerns, :admin, key])%>
4
+ <% end %>
5
+ <% end %>
@@ -0,0 +1,43 @@
1
+ <div class="panel-heading">
2
+ <h4 class="panel-title">Totals by Visibility</h4>
3
+ </div>
4
+
5
+ <table class="table table-striped">
6
+ <tr>
7
+ <th>Visibility</th>
8
+ <th>Count</th>
9
+ </tr>
10
+ <tr>
11
+ <td><%= t("curation_concerns.visibility.open.text") %></td><td><span class="count"><%= resource_stats.open_concerns_count %></span></td>
12
+ </tr>
13
+ <tr>
14
+ <td><%= t("curation_concerns.visibility.authenticated.text") %></td><td><span class="count"><%= resource_stats.authenticated_concerns_count %></span></td>
15
+ </tr>
16
+ <tr>
17
+ <td><%= t("curation_concerns.visibility.restricted.text") %></td><td><span class="count"><%= resource_stats.restricted_concerns_count %></span></td>
18
+ </tr>
19
+ <tr>
20
+ <td><%= t("curation_concerns.visibility.embargo.expired.authenticated.text") %></td><td><span class="count"><%= resource_stats.expired_embargo_now_authenticated_concerns_count %></span></td>
21
+ </tr>
22
+ <tr>
23
+ <td><%= t("curation_concerns.visibility.embargo.expired.open.text") %></td><td><span class="count"><%= resource_stats.expired_embargo_now_open_concerns_count %></span></td>
24
+ </tr>
25
+ <tr>
26
+ <td><%= t("curation_concerns.visibility.embargo.active.authenticated.text") %></td><td><span class="count"><%= resource_stats.active_embargo_now_authenticated_concerns_count %></span></td>
27
+ </tr>
28
+ <tr>
29
+ <td><%= t("curation_concerns.visibility.embargo.active.restricted.text") %></td><td><span class="count"><%= resource_stats.active_embargo_now_restricted_concerns_count %></span></td>
30
+ </tr>
31
+ <tr>
32
+ <td><%= t("curation_concerns.visibility.lease.expired.restricted.text") %></td><td><span class="count"><%= resource_stats.expired_lease_now_restricted_concerns_count %></span></td>
33
+ </tr>
34
+ <tr>
35
+ <td><%= t("curation_concerns.visibility.lease.expired.authenticated.text") %></td><td><span class="count"><%= resource_stats.expired_lease_now_authenticated_concerns_count %></span></td>
36
+ </tr>
37
+ <tr>
38
+ <td><%= t("curation_concerns.visibility.lease.active.authenticated.text") %></td><td><span class="count"><%= resource_stats.active_lease_now_authenticated_concerns_count %></span></td>
39
+ </tr>
40
+ <tr>
41
+ <td><%= t("curation_concerns.visibility.lease.active.open.text") %></td><td><span class="count"><%= resource_stats.active_lease_now_open_concerns_count %></span></td>
42
+ </tr>
43
+ </table>
@@ -0,0 +1,3 @@
1
+ <ul class="nav nav-pills nav-stacked">
2
+ <%= render "/curation_concerns/admin/admin_menu", configuration: @configuration %>
3
+ </ul>
@@ -0,0 +1,21 @@
1
+ <div class="panel-heading">
2
+ <h4 class="panel-title">Embargos &amp; Leases</h4>
3
+ </div>
4
+
5
+ <div class="panel-body">
6
+ <%= render "curation_concerns/admin/widgets/pie", label: "embargo",
7
+ data: {
8
+ t("curation_concerns.visibility.embargo.text") => {
9
+ t("curation_concerns.visibility.embargo.expired.authenticated.text") => @resource_statistics.expired_embargo_now_authenticated_concerns_count,
10
+ t("curation_concerns.visibility.embargo.expired.open.text") => @resource_statistics.expired_embargo_now_open_concerns_count,
11
+ t("curation_concerns.visibility.embargo.active.authenticated.text") => @resource_statistics.active_embargo_now_authenticated_concerns_count,
12
+ t("curation_concerns.visibility.embargo.active.restricted.text") => @resource_statistics.active_embargo_now_restricted_concerns_count
13
+ },
14
+ t("curation_concerns.visibility.lease.text") => {
15
+ t("curation_concerns.visibility.lease.active.authenticated.text") => @resource_statistics.active_lease_now_authenticated_concerns_count,
16
+ t("curation_concerns.visibility.lease.expired.restricted.text") => @resource_statistics.expired_lease_now_restricted_concerns_count,
17
+ t("curation_concerns.visibility.lease.expired.authenticated.text") => @resource_statistics.expired_lease_now_authenticated_concerns_count,
18
+ t("curation_concerns.visibility.lease.active.open.text") => @resource_statistics.active_lease_now_open_concerns_count,
19
+ }
20
+ } %>
21
+ </div>
@@ -0,0 +1 @@
1
+ <%= render "resource_stats", resource_stats: @resource_statistics %>
@@ -0,0 +1,12 @@
1
+ <div class="panel-heading">
2
+ <h4 class="panel-title">Visibility</h4>
3
+ </div>
4
+
5
+ <div class="panel-body">
6
+ <%= render "curation_concerns/admin/widgets/pie", label: "visibility",
7
+ data: {
8
+ t("curation_concerns.visibility.open.text") => @resource_statistics.open_concerns_count,
9
+ t("curation_concerns.visibility.authenticated.text") => @resource_statistics.authenticated_concerns_count,
10
+ t("curation_concerns.visibility.restricted.text") => @resource_statistics.restricted_concerns_count
11
+ } %>
12
+ </div>
@@ -0,0 +1,11 @@
1
+ <div class="<%= "dashboard-#{action_name}" %>">
2
+ <div class="wrapper">
3
+ <% @configuration[:actions][action_name][:partials].each do |partial_name| %>
4
+ <div class="<%= "partial-#{partial_name}" %>">
5
+ <div class="partial-wrapper">
6
+ <%= render partial_name %>
7
+ </div>
8
+ </div>
9
+ <% end %>
10
+ </div>
11
+ </div>
@@ -0,0 +1 @@
1
+ <%= content_tag :div, '', id: "#{label}-stats-pie", class: "stats-pie", data: { label: "#{label}_data", series: hash_to_chart(data) }, style: "height: 300px;" %>
@@ -0,0 +1,31 @@
1
+ <div class="panel panel-default">
2
+ <div class="panel-heading">
3
+ <h3 class="panel-title">Review and comment</h3>
4
+ </div>
5
+ <div class="panel-body panel-body-table">
6
+
7
+ <div class="table-responsive">
8
+ <table class="table table-condensed table-bordered table-striped">
9
+ <thead>
10
+ <tr>
11
+ <th width="60%">Title</th>
12
+ <th width="20%">Status</th>
13
+ </tr>
14
+ </thead>
15
+ <tbody>
16
+ <% @status_list.each do |document| %>
17
+ <tr>
18
+ <td>
19
+ <%= link_to document, [main_app, document] %>
20
+ </td>
21
+ <td>
22
+ <span class="state state-pending"><%= document.workflow_state %></span>
23
+ </td>
24
+ </tr>
25
+ <% end %>
26
+ </tbody>
27
+ </table>
28
+ </div>
29
+
30
+ </div>
31
+ </div>