decidim-decidim_awesome 0.12.3 → 0.12.4

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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -1
  3. data/README.md +1 -1
  4. data/app/commands/concerns/decidim/decidim_awesome/admin/needs_constraint_helpers.rb +39 -5
  5. data/app/commands/decidim/decidim_awesome/admin/create_authorization_group.rb +42 -0
  6. data/app/commands/decidim/decidim_awesome/admin/create_custom_redirect.rb +10 -14
  7. data/app/commands/decidim/decidim_awesome/admin/create_menu_hack.rb +9 -8
  8. data/app/commands/decidim/decidim_awesome/admin/create_proposal_custom_field.rb +3 -8
  9. data/app/commands/decidim/decidim_awesome/admin/create_scoped_admin.rb +4 -8
  10. data/app/commands/decidim/decidim_awesome/admin/create_scoped_style.rb +3 -7
  11. data/app/commands/decidim/decidim_awesome/admin/destroy_authorization_group.rb +37 -0
  12. data/app/commands/decidim/decidim_awesome/admin/destroy_custom_redirect.rb +10 -9
  13. data/app/commands/decidim/decidim_awesome/admin/destroy_menu_hack.rb +8 -7
  14. data/app/commands/decidim/decidim_awesome/admin/destroy_proposal_custom_field.rb +7 -13
  15. data/app/commands/decidim/decidim_awesome/admin/destroy_scoped_admin.rb +7 -10
  16. data/app/commands/decidim/decidim_awesome/admin/destroy_scoped_style.rb +6 -11
  17. data/app/commands/decidim/decidim_awesome/admin/update_config.rb +12 -1
  18. data/app/commands/decidim/decidim_awesome/admin/update_custom_redirect.rb +11 -11
  19. data/app/commands/decidim/decidim_awesome/admin/update_menu_hack.rb +10 -8
  20. data/app/controllers/concerns/decidim/decidim_awesome/enforce_access_authorizations.rb +49 -0
  21. data/app/controllers/concerns/decidim/decidim_awesome/needs_hashcash.rb +7 -5
  22. data/app/controllers/decidim/decidim_awesome/admin/constraints_controller.rb +2 -0
  23. data/app/controllers/decidim/decidim_awesome/admin/force_authorizations_controller.rb +44 -0
  24. data/app/controllers/decidim/decidim_awesome/required_authorizations_controller.rb +51 -13
  25. data/app/forms/concerns/decidim/decidim_awesome/proposals/admin/proposal_form_customizations.rb +59 -0
  26. data/app/forms/concerns/decidim/decidim_awesome/proposals/proposal_form_customizations.rb +28 -28
  27. data/app/forms/concerns/decidim/decidim_awesome/proposals/proposal_form_customizations_base.rb +36 -0
  28. data/app/forms/decidim/decidim_awesome/admin/authorization_group_form.rb +66 -0
  29. data/app/forms/decidim/decidim_awesome/admin/config_form.rb +12 -26
  30. data/app/forms/decidim/decidim_awesome/admin/constraint_form.rb +2 -0
  31. data/app/helpers/concerns/decidim/decidim_awesome/amendments_helper_override.rb +2 -1
  32. data/app/helpers/decidim/decidim_awesome/admin/config_constraints_helpers.rb +20 -17
  33. data/app/overrides/decidim/assemblies/admin/assemblies/_form/add_visibility_callout.html.erb.deface +3 -0
  34. data/app/overrides/decidim/conferences/admin/conferences/_form/add_visibility_callout.html.erb.deface +3 -0
  35. data/app/overrides/decidim/participatory_processes/admin/participatory_process_groups/_form/add_visibility_callout.html.erb.deface +3 -0
  36. data/app/overrides/decidim/participatory_processes/admin/participatory_processes/_form/add_visibility_callout.html.erb.deface +3 -0
  37. data/app/overrides/decidim/shared/_login_modal/add_hashcash.html.erb.deface +3 -0
  38. data/app/packs/src/decidim/decidim_awesome/admin/auto_edit.js +15 -0
  39. data/app/packs/src/decidim/decidim_awesome/awesome_admin.js +0 -1
  40. data/app/packs/stylesheets/decidim/decidim_awesome/admin/codemirror.scss +6 -1
  41. data/app/packs/stylesheets/decidim/decidim_awesome/admin/constraints.scss +5 -0
  42. data/app/packs/stylesheets/decidim/decidim_awesome/admin/custom_fields.scss +1 -2
  43. data/app/queries/decidim/decidim_awesome/space_constraint_finder.rb +43 -0
  44. data/app/serializers/concerns/decidim/decidim_awesome/proposals/proposal_serializer_methods.rb +3 -2
  45. data/app/services/decidim/decidim_awesome/access_authorization_service.rb +79 -0
  46. data/app/types/concerns/decidim/decidim_awesome/add_proposal_type_custom_fields.rb +2 -1
  47. data/app/views/decidim/decidim_awesome/admin/config/_authorization_options_form.html.erb +19 -0
  48. data/app/views/decidim/decidim_awesome/admin/config/_form_verifications.html.erb +71 -9
  49. data/app/views/decidim/decidim_awesome/admin/constraints/_form.html.erb +5 -4
  50. data/app/views/decidim/decidim_awesome/admin/shared/_visibility_notice.html.erb +8 -0
  51. data/app/views/decidim/decidim_awesome/hashcash/_hidden_field.html.erb +0 -1
  52. data/app/views/decidim/decidim_awesome/required_authorizations/index.html.erb +14 -4
  53. data/config/i18n-tasks.yml +1 -0
  54. data/config/locales/ca.yml +31 -7
  55. data/config/locales/cs.yml +32 -7
  56. data/config/locales/de.yml +31 -7
  57. data/config/locales/en.yml +36 -12
  58. data/config/locales/es.yml +32 -7
  59. data/config/locales/eu.yml +3 -8
  60. data/config/locales/fr.yml +3 -8
  61. data/config/locales/ja.yml +70 -7
  62. data/config/locales/sv.yml +49 -0
  63. data/lib/decidim/decidim_awesome/admin_engine.rb +1 -0
  64. data/lib/decidim/decidim_awesome/{authorizator.rb → authorizer.rb} +1 -1
  65. data/lib/decidim/decidim_awesome/awesome.rb +5 -17
  66. data/lib/decidim/decidim_awesome/awesome_helpers.rb +14 -5
  67. data/lib/decidim/decidim_awesome/checksums.yml +11 -0
  68. data/lib/decidim/decidim_awesome/config.rb +18 -7
  69. data/lib/decidim/decidim_awesome/context_analyzers/request_analyzer.rb +1 -1
  70. data/lib/decidim/decidim_awesome/engine.rb +3 -1
  71. data/lib/decidim/decidim_awesome/menu.rb +1 -1
  72. data/lib/decidim/decidim_awesome/middleware/current_config.rb +5 -10
  73. data/lib/decidim/decidim_awesome/test/initializer.rb +1 -1
  74. data/lib/decidim/decidim_awesome/test/shared_examples/proposal_form_examples.rb +191 -0
  75. data/lib/decidim/decidim_awesome/test/shared_examples/summary_examples.rb +7 -3
  76. data/lib/decidim/decidim_awesome/version.rb +1 -1
  77. data/package.json +4 -4
  78. metadata +20 -5
  79. data/app/controllers/concerns/decidim/decidim_awesome/check_login_authorizations.rb +0 -60
  80. data/app/packs/src/decidim/decidim_awesome/admin/verification_selects.js +0 -21
@@ -4,11 +4,13 @@ module Decidim
4
4
  module DecidimAwesome
5
5
  module Admin
6
6
  class UpdateMenuHack < Command
7
+ include NeedsConstraintHelpers
7
8
  # Public: Initializes the command.
8
9
  #
9
10
  def initialize(form, menu_name)
10
11
  @form = form
11
- @menu = AwesomeConfig.find_or_initialize_by(var: menu_name, organization: form.current_organization)
12
+ @config_var = menu_name
13
+ @organization = form.current_organization
12
14
  end
13
15
 
14
16
  # Executes the command. Broadcasts these events:
@@ -20,10 +22,10 @@ module Decidim
20
22
  def call
21
23
  return broadcast(:invalid) if form.invalid?
22
24
 
23
- menu.value = [] unless menu.value.is_a? Array
24
- menu.value = menu.value.filter { |i| i.is_a? Hash }
25
+ find_var.value = [] unless find_var.value.is_a? Array
26
+ find_var.value = find_var.value.filter { |i| i.is_a? Hash }
25
27
  found = false
26
- menu.value.map! do |item|
28
+ find_var.value.map! do |item|
27
29
  if item["url"] == form.url
28
30
  found = true
29
31
  form.to_params
@@ -31,16 +33,16 @@ module Decidim
31
33
  item
32
34
  end
33
35
  end
34
- menu.value << form.to_params unless found
35
- menu.save!
36
- broadcast(:ok, menu)
36
+ find_var.value << form.to_params unless found
37
+ find_var.save!
38
+ broadcast(:ok, find_var)
37
39
  rescue StandardError => e
38
40
  broadcast(:invalid, e.message)
39
41
  end
40
42
 
41
43
  private
42
44
 
43
- attr_reader :form, :menu
45
+ attr_reader :form
44
46
  end
45
47
  end
46
48
  end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module DecidimAwesome
5
+ module EnforceAccessAuthorizations
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ include ::Decidim::DecidimAwesome::NeedsAwesomeConfig
10
+ before_action :enforce_authorizations
11
+ end
12
+
13
+ private
14
+
15
+ def enforce_authorizations
16
+ return if skip_enforcement_for_current_request?
17
+
18
+ unless service.granted?
19
+ flash[:alert] = I18n.t("decidim.decidim_awesome.session.authorization_is_required",
20
+ authorizations: service.adapters.map(&:fullname).join(", "))
21
+ redirect_to decidim_decidim_awesome.required_authorizations_path(redirect_url: request.fullpath)
22
+ end
23
+ end
24
+
25
+ def service
26
+ @service ||= Decidim::DecidimAwesome::AccessAuthorizationService.new(current_user, current_organization, required_authorization_groups)
27
+ end
28
+
29
+ def required_authorization_groups
30
+ return unless awesome_force_authorizations.is_a?(Array)
31
+
32
+ @required_authorization_groups ||= awesome_force_authorizations.pluck("authorization_handlers").compact_blank
33
+ end
34
+
35
+ def skip_enforcement_for_current_request?
36
+ # skip unconfirmed and blocked as other decidim mechanisms kick in
37
+ return true if user_signed_in? && (!current_user.confirmed? || current_user.blocked?)
38
+ return true if allowed_controllers.include?(controller_name.to_s)
39
+
40
+ # Only apply it if the context requires it
41
+ awesome_force_authorizations.blank?
42
+ end
43
+
44
+ def allowed_controllers
45
+ %w(required_authorizations authorizations upload_validations timeouts editor_images locales pages tos) + awesome_config[:force_authorization_allowed_controller_names].to_a
46
+ end
47
+ end
48
+ end
49
+ end
@@ -30,11 +30,13 @@ module Decidim
30
30
 
31
31
  # Dynamically configures the gem https://github.com/BaseSecrete/active_hashcash
32
32
  def set_hashcash_bits
33
- if controller_name == "sessions"
34
- ActiveHashcash.bits = awesome_hashcash_bits(:login)
35
- elsif controller_name == "registrations"
36
- ActiveHashcash.bits = awesome_hashcash_bits(:signup)
37
- end
33
+ return if user_signed_in?
34
+
35
+ ActiveHashcash.bits = if controller_name == "registrations"
36
+ awesome_hashcash_bits(:signup)
37
+ else
38
+ awesome_hashcash_bits(:login)
39
+ end
38
40
  end
39
41
  end
40
42
  end
@@ -138,6 +138,8 @@ module Decidim
138
138
  :proposal_custom_fields
139
139
  when /^proposal_private_custom_field_/
140
140
  :proposal_private_custom_fields
141
+ when /^force_authorization_/
142
+ :force_authorizations
141
143
  else
142
144
  key
143
145
  end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module DecidimAwesome
5
+ module Admin
6
+ class ForceAuthorizationsController < DecidimAwesome::Admin::ConfigController
7
+ def create
8
+ CreateAuthorizationGroup.call(current_organization, config_var) do
9
+ on(:ok) do |key|
10
+ flash[:notice] = I18n.t("config.create_force_authorization.success", key:, scope: "decidim.decidim_awesome.admin")
11
+ end
12
+
13
+ on(:invalid) do |message|
14
+ flash[:alert] = I18n.t("config.create_force_authorization.error", error: message, scope: "decidim.decidim_awesome.admin")
15
+ end
16
+ end
17
+
18
+ redirect_to decidim_admin_decidim_awesome.config_path(:verifications)
19
+ end
20
+
21
+ def destroy
22
+ DestroyAuthorizationGroup.call(params[:key], current_organization, config_var) do
23
+ on(:ok) do |key|
24
+ flash[:notice] = I18n.t("config.destroy_force_authorization.success", key:, scope: "decidim.decidim_awesome.admin")
25
+ end
26
+
27
+ on(:invalid) do |message|
28
+ flash[:alert] = I18n.t("config.destroy_force_authorization.error", error: message, scope: "decidim.decidim_awesome.admin")
29
+ end
30
+ end
31
+
32
+ redirect_to decidim_admin_decidim_awesome.config_path(:verifications)
33
+ end
34
+
35
+ private
36
+
37
+ # maybe in the future we want to restrict the admin as well
38
+ def config_var
39
+ :force_authorizations
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -2,14 +2,17 @@
2
2
 
3
3
  module Decidim
4
4
  module DecidimAwesome
5
- # This controller handles image uploads for the Tiptap editor
5
+ # Lists the authorizations required for the current user/context and helps
6
6
  class RequiredAuthorizationsController < DecidimAwesome::ApplicationController
7
+ include ActionView::Helpers::SanitizeHelper
7
8
  layout "layouts/decidim/authorizations"
8
- helper_method :granted_authorizations, :pending_authorizations, :missing_authorizations, :redirect_url
9
+ helper_method :granted_authorizations, :pending_authorizations, :missing_authorizations, :redirect_url, :authorization_help_text, :service
9
10
 
10
11
  before_action do
11
- redirect_to redirect_url unless user_signed_in?
12
- redirect_to redirect_url if user_is_authorized?
12
+ # If the user is already authorized for the required handlers, send them
13
+ # back to the original destination (or root). This avoids loops because
14
+ # redirect_url defaults to decidim.root_path when it points back here.
15
+ redirect_to redirect_url if user_signed_in? && service.granted? && request.path != redirect_url
13
16
  end
14
17
 
15
18
  def redirect_url
@@ -23,35 +26,70 @@ module Decidim
23
26
  end
24
27
  end
25
28
 
26
- def index
27
- enforce_permission_to :read, :required_authorizations, user_is_authorized: user_is_authorized?
28
- end
29
-
30
29
  private
31
30
 
31
+ delegate :authorization_handlers, :adapters, to: :service
32
+
33
+ def current_authorizations
34
+ @current_authorizations ||= Decidim::Verifications::Authorizations.new(
35
+ organization: current_organization,
36
+ user: current_user,
37
+ name: authorization_handlers,
38
+ granted: true
39
+ )
40
+ end
41
+
32
42
  def missing_authorizations
33
- @missing_authorizations ||= required_authorizations.filter do |manifest|
43
+ @missing_authorizations ||= adapters.filter do |manifest|
34
44
  Decidim::Verifications::Authorizations.new(
35
45
  organization: current_organization,
36
46
  user: current_user,
37
- name: required_authorizations.map(&:name)
47
+ name: authorization_handlers
38
48
  ).pluck(:name).exclude?(manifest.name)
39
49
  end
40
50
  end
41
51
 
42
52
  def pending_authorizations
43
- @pending_authorizations ||= required_authorizations.filter do |manifest|
53
+ @pending_authorizations ||= adapters.filter do |manifest|
44
54
  Decidim::Verifications::Authorizations.new(
45
55
  organization: current_organization,
46
56
  user: current_user,
47
- name: required_authorizations.map(&:name),
57
+ name: authorization_handlers,
48
58
  granted: false
49
59
  ).pluck(:name).include?(manifest.name)
50
60
  end
51
61
  end
52
62
 
53
63
  def granted_authorizations
54
- @granted_authorizations ||= required_authorizations.filter { |manifest| current_authorizations.pluck(:name).include?(manifest.name) }
64
+ @granted_authorizations ||= adapters.filter { |manifest| current_authorizations.pluck(:name).include?(manifest.name) }
65
+ end
66
+
67
+ def service
68
+ @service ||= Decidim::DecidimAwesome::AccessAuthorizationService.new(current_user, current_organization, context_authorizations)
69
+ end
70
+
71
+ # we need to detect the context from the redirect_url passed
72
+ def context_force_authorizations
73
+ @context_force_authorizations ||= begin
74
+ config = Config.new(current_organization)
75
+ config.context_from_request!(redirect_url)
76
+ config.application_context!(current_user:)
77
+ config.collect_sub_configs_values("force_authorization")
78
+ end
79
+ end
80
+
81
+ def context_authorizations
82
+ @context_authorizations ||= (context_force_authorizations.pluck("authorization_handlers").compact_blank if context_force_authorizations.is_a?(Array))
83
+ end
84
+
85
+ # show the first help text available
86
+ def authorization_help_text
87
+ return unless context_force_authorizations.is_a?(Array)
88
+
89
+ context_force_authorizations.pluck("force_authorization_help_text").find do |text|
90
+ text = translated_attribute(text)
91
+ strip_tags(text).strip.present? ? text : nil
92
+ end
55
93
  end
56
94
  end
57
95
  end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Recreate validations to take into account custom fields and ignore the length limit in proposals
4
+ module Decidim
5
+ module DecidimAwesome
6
+ module Proposals
7
+ module Admin
8
+ module ProposalFormCustomizations
9
+ extend ActiveSupport::Concern
10
+
11
+ include ProposalFormCustomizationsBase
12
+
13
+ class_methods do
14
+ def overridden_validators
15
+ _validators.filter do |attribute, _validators|
16
+ attribute.to_s.start_with?("title") || attribute.to_s.start_with?("body")
17
+ end
18
+ end
19
+
20
+ def overridden_validate_callbacks
21
+ _validate_callbacks.filter do |callback|
22
+ filter = callback.filter
23
+ if filter.is_a?(ActiveModel::Validations::LengthValidator) ||
24
+ filter.is_a?(ActiveModel::Validations::PresenceValidator) ||
25
+ filter.is_a?(TranslatablePresenceValidator)
26
+
27
+ filter.attributes.any? { |attr| attr.to_s.start_with?("title") || attr.to_s.start_with?("body") }
28
+ end
29
+ end
30
+ end
31
+
32
+ # remove presence, length and etiquette validators from :title and :body
33
+ def clear_overridden_validators!
34
+ overridden_validators.keys.each do |attribute|
35
+ _validators.delete(attribute)
36
+ end
37
+ overridden_validate_callbacks.each do |callback|
38
+ _validate_callbacks.delete(callback)
39
+ end
40
+ end
41
+ end
42
+
43
+ included do
44
+ clear_overridden_validators!
45
+
46
+ translatable_attribute :title, String do |field, _locale|
47
+ validates field, proposal_length: {
48
+ minimum: ->(form) { form.minimum_title_length },
49
+ maximum: 150
50
+ }, if: proc { |resource| resource.send(field).present? }
51
+ end
52
+
53
+ validates :title, :body, translatable_presence: true, unless: ->(form) { form.override_validations? }
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -7,8 +7,35 @@ module Decidim
7
7
  module ProposalFormCustomizations
8
8
  extend ActiveSupport::Concern
9
9
 
10
+ include ProposalFormCustomizationsBase
11
+
12
+ class_methods do
13
+ def overridden_validate_callbacks
14
+ _validate_callbacks.filter do |callback|
15
+ filter = callback.filter
16
+
17
+ case filter
18
+ when EtiquetteValidator, ActiveModel::Validations::LengthValidator, ProposalLengthValidator, ActiveModel::Validations::PresenceValidator
19
+ filter.attributes.include?(:title) || filter.attributes.include?(:body)
20
+ when :body_is_not_bare_template
21
+ true
22
+ end
23
+ end
24
+ end
25
+
26
+ # remove presence, length and etiquette validators from :title and :body
27
+ def clear_overridden_validators!
28
+ _validators.delete(:title)
29
+ _validators.delete(:body)
30
+
31
+ overridden_validate_callbacks.each do |callback|
32
+ _validate_callbacks.delete(callback)
33
+ end
34
+ end
35
+ end
36
+
10
37
  included do
11
- clear_validators!
38
+ clear_overridden_validators!
12
39
 
13
40
  validates :title, presence: true, etiquette: true
14
41
  validates :title, proposal_length: {
@@ -22,34 +49,7 @@ module Decidim
22
49
  minimum: ->(form) { form.minimum_body_length },
23
50
  maximum: ->(form) { form.override_validations? ? 0 : form.component.settings.proposal_length }
24
51
  }
25
-
26
52
  validate :body_is_not_bare_template, unless: ->(form) { form.override_validations? }
27
-
28
- def override_validations?
29
- return false if context.current_component.settings.participatory_texts_enabled
30
-
31
- custom_fields.present?
32
- end
33
-
34
- def minimum_title_length
35
- awesome_config.config[:validate_title_min_length].to_i
36
- end
37
-
38
- def minimum_body_length
39
- awesome_config.config[:validate_body_min_length].to_i
40
- end
41
-
42
- def custom_fields
43
- @custom_fields ||= awesome_config.collect_sub_configs_values("proposal_custom_field")
44
- end
45
-
46
- def awesome_config
47
- @awesome_config ||= begin
48
- conf = Decidim::DecidimAwesome::Config.new(context.current_organization)
49
- conf.context_from_component(context.current_component)
50
- conf
51
- end
52
- end
53
53
  end
54
54
  end
55
55
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module DecidimAwesome
5
+ module Proposals
6
+ module ProposalFormCustomizationsBase
7
+ def override_validations?
8
+ return false if context.current_component.settings.participatory_texts_enabled
9
+
10
+ custom_fields.present?
11
+ end
12
+
13
+ def minimum_title_length
14
+ awesome_config.config[:validate_title_min_length].to_i
15
+ end
16
+
17
+ def minimum_body_length
18
+ awesome_config.config[:validate_body_min_length].to_i
19
+ end
20
+
21
+ def custom_fields
22
+ @custom_fields ||= awesome_config.collect_sub_configs_values("proposal_custom_field")
23
+ end
24
+
25
+ def awesome_config
26
+ @awesome_config ||= begin
27
+ conf = Decidim::DecidimAwesome::Config.new(context.current_organization)
28
+ conf.context_from_component!(context.current_component)
29
+ conf.application_context!(current_user: context.current_user)
30
+ conf
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module DecidimAwesome
5
+ module Admin
6
+ class AuthorizationGroupForm < Decidim::Form
7
+ include TranslatableAttributes
8
+
9
+ attribute :authorization_handlers, { String => Object }
10
+ attribute :authorization_handlers_names, Array[String]
11
+ attribute :authorization_handlers_options, { String => Object }
12
+ translatable_attribute :force_authorization_help_text, String, default: {}
13
+
14
+ def verification_settings
15
+ {
16
+ authorization_handlers: parsed_authorization_handlers,
17
+ force_authorization_help_text: force_authorization_help_text || {}
18
+ }
19
+ end
20
+
21
+ def parsed_authorization_handlers
22
+ authorization_handlers_names.filter_map do |name|
23
+ next if name.blank?
24
+
25
+ [
26
+ name,
27
+ { options: authorization_handler_options(name) }
28
+ ]
29
+ end.to_h
30
+ end
31
+
32
+ def options_schema(handler_name)
33
+ options_manifest(handler_name).schema.new(authorization_handler_options(handler_name))
34
+ end
35
+
36
+ def authorization_handlers_names
37
+ super.presence || authorization_handlers.keys.map(&:to_s)
38
+ end
39
+
40
+ def authorization_handler_options(handler_name)
41
+ authorization_handlers_options&.dig(handler_name.to_s) || authorization_handlers&.dig(handler_name, "options").presence || {}
42
+ end
43
+
44
+ def options_attributes(handler_name)
45
+ manifest = options_manifest(handler_name)
46
+ manifest ? manifest.attributes : []
47
+ end
48
+
49
+ def manifest(handler_name)
50
+ Decidim::Verifications.find_workflow_manifest(handler_name)
51
+ end
52
+
53
+ def options_manifest(handler_name)
54
+ manifest(handler_name).options
55
+ end
56
+
57
+ # Helper for the view, at this point, ephemeral authorizations are not supported yet
58
+ def available_authorizations
59
+ Decidim.authorization_workflows.filter do |workflow|
60
+ current_organization.available_authorizations.include?(workflow.name) && !workflow.ephemeral?
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -18,13 +18,11 @@ module Decidim
18
18
  attribute :proposal_custom_fields, Hash
19
19
  attribute :proposal_private_custom_fields, Hash
20
20
  attribute :user_timezone, Boolean
21
- attribute :force_authorization_after_login, Array
22
- attribute :force_authorization_with_any_method, Boolean
21
+ attribute :force_authorizations, Hash, default: {}
23
22
  attribute :hashcash_signup, Boolean
24
23
  attribute :hashcash_signup_bits, Integer, default: Decidim::DecidimAwesome.hashcash_signup_bits
25
24
  attribute :hashcash_login, Boolean
26
25
  attribute :hashcash_login_bits, Integer, default: Decidim::DecidimAwesome.hashcash_login_bits
27
- translatable_attribute :force_authorization_help_text, String
28
26
  attribute :scoped_admins, Hash
29
27
  attribute :menu, [MenuForm]
30
28
  attribute :intergram_for_admins, Boolean
@@ -55,28 +53,27 @@ module Decidim
55
53
  validates :validate_body_max_marks_together, presence: true, numericality: { greater_than_or_equal_to: 1 }
56
54
  validates :hashcash_signup_bits, presence: true, numericality: { greater_than_or_equal_to: 10, less_than_or_equal_to: 50 }
57
55
  validates :hashcash_login_bits, presence: true, numericality: { greater_than_or_equal_to: 10, less_than_or_equal_to: 50 }
58
- validate :force_authorization_after_login_is_valid
59
56
  # TODO: validate non general admins are here
60
57
 
61
58
  def self.from_params(params, additional_params = {})
62
59
  instance = super(params, additional_params)
63
- instance.force_authorization_after_login = instance.force_authorization_after_login.compact_blank if instance.force_authorization_after_login.present?
64
- instance.valid_keys = extract_valid_keys_from_params(params)
60
+ instance.valid_keys = params.keys.map(&:to_sym) || []
61
+ instance.force_authorizations = build_force_authorizations(instance.force_authorizations)
65
62
  instance.sanitize_labels!
66
63
  instance.sanitize_arrays!
67
64
  instance
68
65
  end
69
66
 
70
- def self.extract_valid_keys_from_params(params)
71
- keys = []
72
- params.each do |key, _value|
73
- keys << if key.to_s.starts_with?("force_authorization_help_text_")
74
- :force_authorization_help_text if keys.exclude?(:force_authorization_help_text)
75
- else
76
- key.to_sym
77
- end
67
+ def self.build_force_authorizations(raw_groups)
68
+ raw_groups.transform_values do |group_data|
69
+ group_data.is_a?(AuthorizationGroupForm) ? group_data : AuthorizationGroupForm.new(group_data)
78
70
  end
79
- keys
71
+ end
72
+
73
+ def force_authorizations_attributes
74
+ return {} unless force_authorizations.is_a?(Hash)
75
+
76
+ force_authorizations.transform_values(&:verification_settings)
80
77
  end
81
78
 
82
79
  def additional_proposal_sorting_labels
@@ -147,17 +144,6 @@ module Decidim
147
144
  code.is_a?(Array) ? code.compact_blank : code
148
145
  end
149
146
  end
150
-
151
- private
152
-
153
- def force_authorization_after_login_is_valid
154
- return if force_authorization_after_login.blank?
155
-
156
- invalid = force_authorization_after_login - (current_organization.available_authorizations & Decidim.authorization_workflows.map(&:name))
157
- return if invalid.empty?
158
-
159
- errors.add(:force_authorization_after_login, :invalid)
160
- end
161
147
  end
162
148
  end
163
149
  end
@@ -9,11 +9,13 @@ module Decidim
9
9
  attribute :participatory_space_slug, String
10
10
  attribute :component_manifest, String
11
11
  attribute :component_id, Integer
12
+ attribute :application_context, String
12
13
 
13
14
  validates :component_manifest, absence: true, if: lambda { |form|
14
15
  form.component_id.present? || ConfigConstraintsHelpers::OTHER_MANIFESTS.include?(form.participatory_space_manifest&.to_sym)
15
16
  }
16
17
  validates :component_id, absence: true, if: ->(form) { form.component_manifest.present? }
18
+ validates :application_context, inclusion: { in: ConfigConstraintsHelpers::APPLICATION_CONTEXTS.map(&:to_s) }, allow_blank: true
17
19
  end
18
20
  end
19
21
  end
@@ -53,7 +53,8 @@ module Decidim
53
53
  return if component.settings.participatory_texts_enabled?
54
54
 
55
55
  awesome_config = Decidim::DecidimAwesome::Config.new(component.organization)
56
- awesome_config.context_from_component(component)
56
+ awesome_config.context_from_component!(component)
57
+ awesome_config.application_context!(current_user:)
57
58
 
58
59
  pub = awesome_config.collect_sub_configs_values("proposal_custom_field")
59
60
  priv = awesome_config.collect_sub_configs_values("proposal_private_custom_field")
@@ -5,6 +5,7 @@ module Decidim
5
5
  module Admin
6
6
  module ConfigConstraintsHelpers
7
7
  OTHER_MANIFESTS = [:none, :system, :process_groups].freeze
8
+ APPLICATION_CONTEXTS = [:user_logged_in, :anonymous].freeze
8
9
 
9
10
  include Decidim::TranslatableAttributes
10
11
 
@@ -50,30 +51,32 @@ module Decidim
50
51
  space = model_for_manifest(manifest)
51
52
  return {} unless space&.column_names&.include? "slug"
52
53
 
53
- components = Component.where(participatory_space: space.find_by(slug:))
54
+ components = Decidim::Component.where(participatory_space: space.find_by(slug:))
54
55
  components.to_h do |item|
55
56
  [item.id, "#{item.id}: #{translated_attribute(item.name)}"]
56
57
  end
57
58
  end
58
59
 
60
+ def contexts_list
61
+ ConfigConstraintsHelpers::APPLICATION_CONTEXTS.index_with { |c| I18n.t("decidim.decidim_awesome.admin.config.#{c}") }
62
+ end
63
+
59
64
  def translate_constraint_value(constraint, key)
60
65
  value = constraint.settings[key]
61
- case key.to_sym
62
- when :participatory_space_manifest
63
- participatory_space_manifests[value.to_sym] || value
64
- when :participatory_space_slug
65
- manifest = constraint.settings["participatory_space_manifest"]
66
- participatory_spaces_list(manifest)[value] || value
67
- when :component_manifest
68
- component_manifests[value.to_sym] || value
69
- when :component_id
70
- component = Component.find_by(id: value)
71
- return "#{component.id}: #{translated_attribute(component.name)}" if component
72
-
73
- value
74
- else
75
- value
76
- end
66
+ translation = case key.to_sym
67
+ when :participatory_space_manifest
68
+ participatory_space_manifests[value.to_sym]
69
+ when :participatory_space_slug
70
+ participatory_spaces_list(constraint.settings["participatory_space_manifest"])[value]
71
+ when :component_manifest
72
+ component_manifests[value.to_sym]
73
+ when :component_id
74
+ component = Decidim::Component.find_by(id: value)
75
+ "#{component.id}: #{translated_attribute(component.name)}" if component
76
+ when :application_context
77
+ I18n.t("decidim.decidim_awesome.admin.config.#{value}")
78
+ end
79
+ translation.presence || value
77
80
  end
78
81
 
79
82
  def md5(text)
@@ -0,0 +1,3 @@
1
+ <!-- insert_bottom "div#panel-visibility" -->
2
+
3
+ <%= render "decidim/decidim_awesome/admin/shared/visibility_notice", participatory_space: current_assembly %>