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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -1
- data/README.md +1 -1
- data/app/commands/concerns/decidim/decidim_awesome/admin/needs_constraint_helpers.rb +39 -5
- data/app/commands/decidim/decidim_awesome/admin/create_authorization_group.rb +42 -0
- data/app/commands/decidim/decidim_awesome/admin/create_custom_redirect.rb +10 -14
- data/app/commands/decidim/decidim_awesome/admin/create_menu_hack.rb +9 -8
- data/app/commands/decidim/decidim_awesome/admin/create_proposal_custom_field.rb +3 -8
- data/app/commands/decidim/decidim_awesome/admin/create_scoped_admin.rb +4 -8
- data/app/commands/decidim/decidim_awesome/admin/create_scoped_style.rb +3 -7
- data/app/commands/decidim/decidim_awesome/admin/destroy_authorization_group.rb +37 -0
- data/app/commands/decidim/decidim_awesome/admin/destroy_custom_redirect.rb +10 -9
- data/app/commands/decidim/decidim_awesome/admin/destroy_menu_hack.rb +8 -7
- data/app/commands/decidim/decidim_awesome/admin/destroy_proposal_custom_field.rb +7 -13
- data/app/commands/decidim/decidim_awesome/admin/destroy_scoped_admin.rb +7 -10
- data/app/commands/decidim/decidim_awesome/admin/destroy_scoped_style.rb +6 -11
- data/app/commands/decidim/decidim_awesome/admin/update_config.rb +12 -1
- data/app/commands/decidim/decidim_awesome/admin/update_custom_redirect.rb +11 -11
- data/app/commands/decidim/decidim_awesome/admin/update_menu_hack.rb +10 -8
- data/app/controllers/concerns/decidim/decidim_awesome/enforce_access_authorizations.rb +49 -0
- data/app/controllers/concerns/decidim/decidim_awesome/needs_hashcash.rb +7 -5
- data/app/controllers/decidim/decidim_awesome/admin/constraints_controller.rb +2 -0
- data/app/controllers/decidim/decidim_awesome/admin/force_authorizations_controller.rb +44 -0
- data/app/controllers/decidim/decidim_awesome/required_authorizations_controller.rb +51 -13
- data/app/forms/concerns/decidim/decidim_awesome/proposals/admin/proposal_form_customizations.rb +59 -0
- data/app/forms/concerns/decidim/decidim_awesome/proposals/proposal_form_customizations.rb +28 -28
- data/app/forms/concerns/decidim/decidim_awesome/proposals/proposal_form_customizations_base.rb +36 -0
- data/app/forms/decidim/decidim_awesome/admin/authorization_group_form.rb +66 -0
- data/app/forms/decidim/decidim_awesome/admin/config_form.rb +12 -26
- data/app/forms/decidim/decidim_awesome/admin/constraint_form.rb +2 -0
- data/app/helpers/concerns/decidim/decidim_awesome/amendments_helper_override.rb +2 -1
- data/app/helpers/decidim/decidim_awesome/admin/config_constraints_helpers.rb +20 -17
- data/app/overrides/decidim/assemblies/admin/assemblies/_form/add_visibility_callout.html.erb.deface +3 -0
- data/app/overrides/decidim/conferences/admin/conferences/_form/add_visibility_callout.html.erb.deface +3 -0
- data/app/overrides/decidim/participatory_processes/admin/participatory_process_groups/_form/add_visibility_callout.html.erb.deface +3 -0
- data/app/overrides/decidim/participatory_processes/admin/participatory_processes/_form/add_visibility_callout.html.erb.deface +3 -0
- data/app/overrides/decidim/shared/_login_modal/add_hashcash.html.erb.deface +3 -0
- data/app/packs/src/decidim/decidim_awesome/admin/auto_edit.js +15 -0
- data/app/packs/src/decidim/decidim_awesome/awesome_admin.js +0 -1
- data/app/packs/stylesheets/decidim/decidim_awesome/admin/codemirror.scss +6 -1
- data/app/packs/stylesheets/decidim/decidim_awesome/admin/constraints.scss +5 -0
- data/app/packs/stylesheets/decidim/decidim_awesome/admin/custom_fields.scss +1 -2
- data/app/queries/decidim/decidim_awesome/space_constraint_finder.rb +43 -0
- data/app/serializers/concerns/decidim/decidim_awesome/proposals/proposal_serializer_methods.rb +3 -2
- data/app/services/decidim/decidim_awesome/access_authorization_service.rb +79 -0
- data/app/types/concerns/decidim/decidim_awesome/add_proposal_type_custom_fields.rb +2 -1
- data/app/views/decidim/decidim_awesome/admin/config/_authorization_options_form.html.erb +19 -0
- data/app/views/decidim/decidim_awesome/admin/config/_form_verifications.html.erb +71 -9
- data/app/views/decidim/decidim_awesome/admin/constraints/_form.html.erb +5 -4
- data/app/views/decidim/decidim_awesome/admin/shared/_visibility_notice.html.erb +8 -0
- data/app/views/decidim/decidim_awesome/hashcash/_hidden_field.html.erb +0 -1
- data/app/views/decidim/decidim_awesome/required_authorizations/index.html.erb +14 -4
- data/config/i18n-tasks.yml +1 -0
- data/config/locales/ca.yml +31 -7
- data/config/locales/cs.yml +32 -7
- data/config/locales/de.yml +31 -7
- data/config/locales/en.yml +36 -12
- data/config/locales/es.yml +32 -7
- data/config/locales/eu.yml +3 -8
- data/config/locales/fr.yml +3 -8
- data/config/locales/ja.yml +70 -7
- data/config/locales/sv.yml +49 -0
- data/lib/decidim/decidim_awesome/admin_engine.rb +1 -0
- data/lib/decidim/decidim_awesome/{authorizator.rb → authorizer.rb} +1 -1
- data/lib/decidim/decidim_awesome/awesome.rb +5 -17
- data/lib/decidim/decidim_awesome/awesome_helpers.rb +14 -5
- data/lib/decidim/decidim_awesome/checksums.yml +11 -0
- data/lib/decidim/decidim_awesome/config.rb +18 -7
- data/lib/decidim/decidim_awesome/context_analyzers/request_analyzer.rb +1 -1
- data/lib/decidim/decidim_awesome/engine.rb +3 -1
- data/lib/decidim/decidim_awesome/menu.rb +1 -1
- data/lib/decidim/decidim_awesome/middleware/current_config.rb +5 -10
- data/lib/decidim/decidim_awesome/test/initializer.rb +1 -1
- data/lib/decidim/decidim_awesome/test/shared_examples/proposal_form_examples.rb +191 -0
- data/lib/decidim/decidim_awesome/test/shared_examples/summary_examples.rb +7 -3
- data/lib/decidim/decidim_awesome/version.rb +1 -1
- data/package.json +4 -4
- metadata +20 -5
- data/app/controllers/concerns/decidim/decidim_awesome/check_login_authorizations.rb +0 -60
- 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
|
-
@
|
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
|
-
|
24
|
-
|
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
|
-
|
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
|
-
|
35
|
-
|
36
|
-
broadcast(:ok,
|
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
|
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
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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
|
@@ -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
|
-
#
|
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
|
-
|
12
|
-
|
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 ||=
|
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:
|
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 ||=
|
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:
|
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 ||=
|
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
|
data/app/forms/concerns/decidim/decidim_awesome/proposals/admin/proposal_form_customizations.rb
ADDED
@@ -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
|
-
|
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
|
data/app/forms/concerns/decidim/decidim_awesome/proposals/proposal_form_customizations_base.rb
ADDED
@@ -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 :
|
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.
|
64
|
-
instance.
|
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.
|
71
|
-
|
72
|
-
|
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
|
-
|
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
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
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)
|