decidim-decidim_awesome 0.12.0 → 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 (184) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +45 -0
  3. data/README.md +25 -15
  4. data/Rakefile +12 -0
  5. data/app/cells/concerns/decidim/decidim_awesome/global_menu_cell_override.rb +14 -2
  6. data/app/cells/concerns/decidim/decidim_awesome/proposal_l_cell_override.rb +5 -4
  7. data/app/cells/decidim/decidim_awesome/voting/voting_cards_proposal/show.erb +3 -3
  8. data/app/cells/decidim/decidim_awesome/voting/voting_cards_proposal/vote_block_for.erb +1 -1
  9. data/app/commands/concerns/decidim/decidim_awesome/admin/needs_constraint_helpers.rb +39 -5
  10. data/app/commands/decidim/decidim_awesome/admin/create_authorization_group.rb +42 -0
  11. data/app/commands/decidim/decidim_awesome/admin/create_custom_redirect.rb +10 -14
  12. data/app/commands/decidim/decidim_awesome/admin/create_menu_hack.rb +9 -8
  13. data/app/commands/decidim/decidim_awesome/admin/create_proposal_custom_field.rb +3 -8
  14. data/app/commands/decidim/decidim_awesome/admin/create_scoped_admin.rb +4 -8
  15. data/app/commands/decidim/decidim_awesome/admin/create_scoped_style.rb +3 -7
  16. data/app/commands/decidim/decidim_awesome/admin/destroy_authorization_group.rb +37 -0
  17. data/app/commands/decidim/decidim_awesome/admin/destroy_custom_redirect.rb +10 -9
  18. data/app/commands/decidim/decidim_awesome/admin/destroy_menu_hack.rb +8 -7
  19. data/app/commands/decidim/decidim_awesome/admin/destroy_proposal_custom_field.rb +7 -13
  20. data/app/commands/decidim/decidim_awesome/admin/destroy_scoped_admin.rb +7 -10
  21. data/app/commands/decidim/decidim_awesome/admin/destroy_scoped_style.rb +6 -11
  22. data/app/commands/decidim/decidim_awesome/admin/update_config.rb +12 -1
  23. data/app/commands/decidim/decidim_awesome/admin/update_custom_redirect.rb +11 -11
  24. data/app/commands/decidim/decidim_awesome/admin/update_menu_hack.rb +10 -8
  25. data/app/controllers/concerns/decidim/decidim_awesome/admin/maintenance_context.rb +0 -28
  26. data/app/controllers/concerns/decidim/decidim_awesome/enforce_access_authorizations.rb +49 -0
  27. data/app/controllers/concerns/decidim/decidim_awesome/needs_hashcash.rb +43 -0
  28. data/app/controllers/concerns/decidim/decidim_awesome/not_found_redirect.rb +2 -2
  29. data/app/controllers/decidim/decidim_awesome/admin/admin_authorizations_controller.rb +2 -2
  30. data/app/controllers/decidim/decidim_awesome/admin/checks_controller.rb +0 -4
  31. data/app/controllers/decidim/decidim_awesome/admin/config_controller.rb +2 -1
  32. data/app/controllers/decidim/decidim_awesome/admin/constraints_controller.rb +2 -0
  33. data/app/controllers/decidim/decidim_awesome/admin/custom_redirects_controller.rb +1 -2
  34. data/app/controllers/decidim/decidim_awesome/admin/force_authorizations_controller.rb +44 -0
  35. data/app/controllers/decidim/decidim_awesome/admin/hashcash_controller.rb +39 -0
  36. data/app/controllers/decidim/decidim_awesome/admin/menu_hacks_controller.rb +1 -1
  37. data/app/controllers/decidim/decidim_awesome/admin/{maintenance_controller.rb → private_data_controller.rb} +9 -9
  38. data/app/controllers/decidim/decidim_awesome/required_authorizations_controller.rb +51 -13
  39. data/app/controllers/decidim/decidim_awesome/utils_controller.rb +17 -0
  40. data/app/forms/concerns/decidim/decidim_awesome/proposals/admin/proposal_form_customizations.rb +59 -0
  41. data/app/forms/concerns/decidim/decidim_awesome/proposals/proposal_form_customizations.rb +28 -28
  42. data/app/forms/concerns/decidim/decidim_awesome/proposals/proposal_form_customizations_base.rb +36 -0
  43. data/app/forms/concerns/decidim/decidim_awesome/proposals/proposal_form_override.rb +7 -1
  44. data/app/forms/decidim/decidim_awesome/admin/authorization_group_form.rb +66 -0
  45. data/app/forms/decidim/decidim_awesome/admin/config_form.rb +23 -24
  46. data/app/forms/decidim/decidim_awesome/admin/constraint_form.rb +2 -0
  47. data/app/helpers/concerns/decidim/decidim_awesome/amendments_helper_override.rb +2 -1
  48. data/app/helpers/decidim/decidim_awesome/admin/config_constraints_helpers.rb +21 -18
  49. data/app/helpers/decidim/decidim_awesome/map_helper.rb +4 -2
  50. data/app/models/decidim/decidim_awesome/paper_trail_version.rb +1 -1
  51. data/app/overrides/decidim/assemblies/admin/assemblies/_form/add_visibility_callout.html.erb.deface +3 -0
  52. data/app/overrides/decidim/conferences/admin/conferences/_form/add_visibility_callout.html.erb.deface +3 -0
  53. data/app/overrides/decidim/devise/registrations/new/add_hashcash.html.erb.deface +3 -0
  54. data/app/overrides/decidim/devise/sessions/new/add_hashcash.html.erb.deface +3 -0
  55. data/app/overrides/decidim/participatory_processes/admin/participatory_process_groups/_form/add_visibility_callout.html.erb.deface +3 -0
  56. data/app/overrides/decidim/participatory_processes/admin/participatory_processes/_form/add_visibility_callout.html.erb.deface +3 -0
  57. data/app/overrides/decidim/shared/_login_modal/add_hashcash.html.erb.deface +3 -0
  58. data/app/overrides/layouts/decidim/_head/add_awesome_custom_styles.html.erb.deface +3 -0
  59. data/app/overrides/layouts/decidim/_head/add_awesome_tags.html.erb.deface +0 -2
  60. data/app/packs/entrypoints/decidim_decidim_awesome_hashcash.js +4 -0
  61. data/app/packs/src/decidim/decidim_awesome/admin/auto_edit.js +25 -6
  62. data/app/packs/src/decidim/decidim_awesome/admin/custom_fields_builder.js +4 -2
  63. data/app/packs/src/decidim/decidim_awesome/admin/verifications.js +6 -3
  64. data/app/packs/src/decidim/decidim_awesome/awesome_admin.js +0 -1
  65. data/app/packs/src/decidim/decidim_awesome/awesome_map/api/proposals_fetcher.js +1 -1
  66. data/app/packs/src/decidim/decidim_awesome/awesome_map/controllers/controller.js +1 -1
  67. data/app/packs/src/decidim/decidim_awesome/awesome_map/controllers/proposals_controller.js +1 -1
  68. data/app/packs/src/decidim/decidim_awesome/awesome_map/controls_ui.js +6 -6
  69. data/app/packs/src/decidim/decidim_awesome/awesome_map/load_map.js +1 -1
  70. data/app/packs/src/decidim/decidim_awesome/forms/autosave.js +3 -3
  71. data/app/packs/src/decidim/decidim_awesome/forms/custom_fields_renderer.js +1 -113
  72. data/app/packs/src/decidim/decidim_awesome/proposals/images.js +1 -1
  73. data/app/packs/src/vendor/form_builder_langs/ar-SA.lang +111 -0
  74. data/app/packs/src/vendor/form_builder_langs/ar-TN.lang +94 -0
  75. data/app/packs/src/vendor/form_builder_langs/ca-ES.lang +110 -0
  76. data/app/packs/src/vendor/form_builder_langs/cs-CZ.lang +105 -0
  77. data/app/packs/src/vendor/form_builder_langs/da-DK.lang +110 -0
  78. data/app/packs/src/vendor/form_builder_langs/de-DE.lang +109 -0
  79. data/app/packs/src/vendor/form_builder_langs/el-GR.lang +110 -0
  80. data/app/packs/src/vendor/form_builder_langs/en-US.lang +117 -0
  81. data/app/packs/src/vendor/form_builder_langs/es-ES.lang +103 -0
  82. data/app/packs/src/vendor/form_builder_langs/fa-IR.lang +108 -0
  83. data/app/packs/src/vendor/form_builder_langs/fi-FI.lang +107 -0
  84. data/app/packs/src/vendor/form_builder_langs/fr-FR.lang +117 -0
  85. data/app/packs/src/vendor/form_builder_langs/he-IL.lang +108 -0
  86. data/app/packs/src/vendor/form_builder_langs/hi-IN.lang +110 -0
  87. data/app/packs/src/vendor/form_builder_langs/hu-HU.lang +108 -0
  88. data/app/packs/src/vendor/form_builder_langs/id-ID.lang +110 -0
  89. data/app/packs/src/vendor/form_builder_langs/it-IT.lang +107 -0
  90. data/app/packs/src/vendor/form_builder_langs/ja-JP.lang +108 -0
  91. data/app/packs/src/vendor/form_builder_langs/my-MM.lang +108 -0
  92. data/app/packs/src/vendor/form_builder_langs/nb-NO.lang +94 -0
  93. data/app/packs/src/vendor/form_builder_langs/nl-NL.lang +94 -0
  94. data/app/packs/src/vendor/form_builder_langs/pl-PL.lang +122 -0
  95. data/app/packs/src/vendor/form_builder_langs/pt-BR.lang +110 -0
  96. data/app/packs/src/vendor/form_builder_langs/pu-IN.lang +110 -0
  97. data/app/packs/src/vendor/form_builder_langs/qz-MM.lang +108 -0
  98. data/app/packs/src/vendor/form_builder_langs/ro-RO.lang +94 -0
  99. data/app/packs/src/vendor/form_builder_langs/ru-RU.lang +110 -0
  100. data/app/packs/src/vendor/form_builder_langs/sl-SI.lang +110 -0
  101. data/app/packs/src/vendor/form_builder_langs/th-TH.lang +111 -0
  102. data/app/packs/src/vendor/form_builder_langs/tr-TR.lang +115 -0
  103. data/app/packs/src/vendor/form_builder_langs/uk-UA.lang +108 -0
  104. data/app/packs/src/vendor/form_builder_langs/vi-VN.lang +94 -0
  105. data/app/packs/src/vendor/form_builder_langs/zh-CN.lang +100 -0
  106. data/app/packs/src/vendor/form_builder_langs/zh-TW.lang +94 -0
  107. data/app/packs/src/vendor/hashcash.js +83 -0
  108. data/app/packs/src/vendor/sha1.js +143 -0
  109. data/app/packs/src/vendor/stamp.js +50 -0
  110. data/app/packs/stylesheets/decidim/decidim_awesome/admin/codemirror.scss +6 -1
  111. data/app/packs/stylesheets/decidim/decidim_awesome/admin/constraints.scss +5 -0
  112. data/app/packs/stylesheets/decidim/decidim_awesome/admin/custom_fields.scss +1 -2
  113. data/app/packs/stylesheets/decidim/decidim_awesome/forms/autosave.scss +2 -12
  114. data/app/presenters/decidim/decidim_awesome/private_data_presenter.rb +2 -2
  115. data/app/queries/decidim/decidim_awesome/space_constraint_finder.rb +43 -0
  116. data/app/serializers/concerns/decidim/decidim_awesome/proposals/proposal_serializer_methods.rb +3 -2
  117. data/app/services/decidim/decidim_awesome/access_authorization_service.rb +79 -0
  118. data/app/types/concerns/decidim/decidim_awesome/add_proposal_type_custom_fields.rb +2 -1
  119. data/app/views/decidim/decidim_awesome/admin/admin_accountability/index.html.erb +4 -4
  120. data/app/views/decidim/decidim_awesome/admin/admin_authorizations/callout.html.erb +2 -2
  121. data/app/views/decidim/decidim_awesome/admin/admin_authorizations/conflict.html.erb +4 -4
  122. data/app/views/decidim/decidim_awesome/admin/admin_authorizations/edit.html.erb +6 -5
  123. data/app/views/decidim/decidim_awesome/admin/checks/index.html.erb +6 -6
  124. data/app/views/decidim/decidim_awesome/admin/config/_authorization_options_form.html.erb +19 -0
  125. data/app/views/decidim/decidim_awesome/admin/config/_autoedit_box_label.html.erb +2 -2
  126. data/app/views/decidim/decidim_awesome/admin/config/_constraints.html.erb +3 -3
  127. data/app/views/decidim/decidim_awesome/admin/config/_form_admins.html.erb +4 -3
  128. data/app/views/decidim/decidim_awesome/admin/config/_form_editors.html.erb +1 -1
  129. data/app/views/decidim/decidim_awesome/admin/config/_form_proposal_custom_fields.html.erb +4 -4
  130. data/app/views/decidim/decidim_awesome/admin/config/_form_scoped_styles.html.erb +3 -3
  131. data/app/views/decidim/decidim_awesome/admin/config/_form_surveys.html.erb +40 -2
  132. data/app/views/decidim/decidim_awesome/admin/config/_form_verifications.html.erb +71 -9
  133. data/app/views/decidim/decidim_awesome/admin/constraints/_form.html.erb +5 -4
  134. data/app/views/decidim/decidim_awesome/admin/hashcash/_filters.html.erb +55 -0
  135. data/app/views/decidim/decidim_awesome/admin/hashcash/index.html.erb +33 -0
  136. data/app/views/decidim/decidim_awesome/admin/hashcash/ip_addresses.html.erb +29 -0
  137. data/app/views/decidim/decidim_awesome/admin/hashcash/show.html.erb +42 -0
  138. data/app/views/decidim/decidim_awesome/admin/menu_hacks/index.html.erb +2 -2
  139. data/app/views/decidim/decidim_awesome/admin/{maintenance → private_data}/_private_data.html.erb +2 -2
  140. data/app/views/decidim/decidim_awesome/admin/{maintenance/show.html.erb → private_data/index.html.erb} +2 -3
  141. data/app/views/decidim/decidim_awesome/admin/proposals/_private_body.html.erb +1 -1
  142. data/app/views/decidim/decidim_awesome/admin/shared/_visibility_notice.html.erb +8 -0
  143. data/app/views/decidim/decidim_awesome/amendments/_modal.html.erb +2 -2
  144. data/app/views/decidim/decidim_awesome/hashcash/_hidden_field.html.erb +4 -0
  145. data/app/views/decidim/decidim_awesome/required_authorizations/index.html.erb +14 -4
  146. data/app/views/layouts/decidim/decidim_awesome/_awesome_config.html.erb +2 -2
  147. data/app/views/layouts/decidim/decidim_awesome/admin/maintenance.html.erb +2 -11
  148. data/config/assets.rb +1 -0
  149. data/config/i18n-tasks.yml +2 -0
  150. data/config/locales/ca.yml +100 -37
  151. data/config/locales/cs.yml +100 -36
  152. data/config/locales/de.yml +98 -35
  153. data/config/locales/en.yml +117 -44
  154. data/config/locales/es.yml +100 -36
  155. data/config/locales/eu.yml +34 -39
  156. data/config/locales/fr.yml +77 -31
  157. data/config/locales/ja.yml +99 -36
  158. data/config/locales/sv.yml +49 -0
  159. data/lib/decidim/decidim_awesome/admin_engine.rb +9 -5
  160. data/lib/decidim/decidim_awesome/{authorizator.rb → authorizer.rb} +1 -1
  161. data/lib/decidim/decidim_awesome/awesome.rb +34 -24
  162. data/lib/decidim/decidim_awesome/awesome_helpers.rb +14 -5
  163. data/lib/decidim/decidim_awesome/checksums.yml +26 -40
  164. data/lib/decidim/decidim_awesome/config.rb +18 -7
  165. data/lib/decidim/decidim_awesome/context_analyzers/request_analyzer.rb +1 -1
  166. data/lib/decidim/decidim_awesome/engine.rb +14 -3
  167. data/lib/decidim/decidim_awesome/menu.rb +151 -138
  168. data/lib/decidim/decidim_awesome/middleware/current_config.rb +5 -10
  169. data/lib/decidim/decidim_awesome/test/initializer.rb +5 -2
  170. data/lib/decidim/decidim_awesome/test/shared_examples/config_examples.rb +1 -3
  171. data/lib/decidim/decidim_awesome/test/shared_examples/editor_examples.rb +2 -1
  172. data/lib/decidim/decidim_awesome/test/shared_examples/proposal_form_examples.rb +191 -0
  173. data/lib/decidim/decidim_awesome/test/shared_examples/summary_examples.rb +15 -4
  174. data/lib/decidim/decidim_awesome/version.rb +1 -1
  175. data/lib/tasks/decidim_awesome_upgrade_tasks.rake +4 -1
  176. data/package.json +7 -8
  177. metadata +86 -13
  178. data/app/controllers/concerns/decidim/decidim_awesome/check_login_authorizations.rb +0 -60
  179. data/app/packs/src/decidim/decidim_awesome/admin/verification_selects.js +0 -21
  180. data/config/rubocop/disabled.yml +0 -11
  181. data/config/rubocop/faker.yml +0 -480
  182. data/config/rubocop/rails.yml +0 -88
  183. data/config/rubocop/rspec.yml +0 -65
  184. data/config/rubocop/ruby.yml +0 -1210
@@ -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,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module DecidimAwesome
5
+ # Abstract component class for components without any admin controllers (only settings)
6
+ class UtilsController < DecidimAwesome::ApplicationController
7
+ def form_builder_i18n
8
+ lang = I18n.locale
9
+ folder = "app/packs/src/vendor/form_builder_langs/"
10
+ file = Decidim::DecidimAwesome::Engine.root.join(folder, "#{lang}.lang")
11
+ file = Dir[Decidim::DecidimAwesome::Engine.root.join(folder, "#{lang}-*.lang")].first unless File.exist?(file)
12
+ file = Decidim::DecidimAwesome::Engine.root.join(folder, "en-US.lang") unless file && File.exist?(file)
13
+ render plain: File.read(file)
14
+ end
15
+ end
16
+ end
17
+ 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
@@ -8,7 +8,13 @@ module Decidim
8
8
 
9
9
  included do
10
10
  alias_method :decidim_original_map_model, :map_model
11
- attribute :private_body, String
11
+ attribute :private_body, Decidim::Attributes::RichText
12
+
13
+ if name == "Decidim::Proposals::ProposalForm"
14
+ # the original decidim uses CleanString, as no images are allowed for non admins
15
+ # The RichText attribute transforms signed_id blobs to ObjectIDs
16
+ attribute :body, Decidim::Attributes::RichText
17
+ end
12
18
 
13
19
  def map_model(model)
14
20
  decidim_original_map_model(model)
@@ -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,9 +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
23
- translatable_attribute :force_authorization_help_text, String
21
+ attribute :force_authorizations, Hash, default: {}
22
+ attribute :hashcash_signup, Boolean
23
+ attribute :hashcash_signup_bits, Integer, default: Decidim::DecidimAwesome.hashcash_signup_bits
24
+ attribute :hashcash_login, Boolean
25
+ attribute :hashcash_login_bits, Integer, default: Decidim::DecidimAwesome.hashcash_login_bits
24
26
  attribute :scoped_admins, Hash
25
27
  attribute :menu, [MenuForm]
26
28
  attribute :intergram_for_admins, Boolean
@@ -49,27 +51,29 @@ module Decidim
49
51
  validates :validate_body_min_length, presence: true, numericality: { greater_than_or_equal_to: 0 }
50
52
  validates :validate_body_max_caps_percent, presence: true, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 100 }
51
53
  validates :validate_body_max_marks_together, presence: true, numericality: { greater_than_or_equal_to: 1 }
52
- validate :force_authorization_after_login_is_valid
54
+ validates :hashcash_signup_bits, presence: true, numericality: { greater_than_or_equal_to: 10, less_than_or_equal_to: 50 }
55
+ validates :hashcash_login_bits, presence: true, numericality: { greater_than_or_equal_to: 10, less_than_or_equal_to: 50 }
53
56
  # TODO: validate non general admins are here
54
57
 
55
58
  def self.from_params(params, additional_params = {})
56
59
  instance = super(params, additional_params)
57
- instance.force_authorization_after_login = instance.force_authorization_after_login.compact_blank if instance.force_authorization_after_login.present?
58
- 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)
59
62
  instance.sanitize_labels!
63
+ instance.sanitize_arrays!
60
64
  instance
61
65
  end
62
66
 
63
- def self.extract_valid_keys_from_params(params)
64
- keys = []
65
- params.each do |key, _value|
66
- keys << if key.to_s.starts_with?("force_authorization_help_text_")
67
- :force_authorization_help_text if keys.exclude?(:force_authorization_help_text)
68
- else
69
- key.to_sym
70
- 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)
71
70
  end
72
- 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)
73
77
  end
74
78
 
75
79
  def additional_proposal_sorting_labels
@@ -135,15 +139,10 @@ module Decidim
135
139
  end
136
140
  end
137
141
 
138
- private
139
-
140
- def force_authorization_after_login_is_valid
141
- return if force_authorization_after_login.blank?
142
-
143
- invalid = force_authorization_after_login - (current_organization.available_authorizations & Decidim.authorization_workflows.map(&:name))
144
- return if invalid.empty?
145
-
146
- errors.add(:force_authorization_after_login, :invalid)
142
+ def sanitize_arrays!
143
+ scoped_admins.transform_values! do |code|
144
+ code.is_a?(Array) ? code.compact_blank : code
145
+ end
147
146
  end
148
147
  end
149
148
  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,10 +5,11 @@ 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
 
11
- delegate :menus, :config_enabled?, to: "Decidim::DecidimAwesome::Menu"
12
+ delegate :menus, :main_path_for, :config_enabled?, to: "Decidim::DecidimAwesome::Menu"
12
13
 
13
14
  def check(status)
14
15
  content_tag(:span, icon(status ? "check-line" : "close-line", class: "inline-block", aria_label: status, role: "img"), class: "fill-#{status ? "success" : "alert"}")
@@ -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)
@@ -10,7 +10,7 @@ module Decidim
10
10
  end
11
11
 
12
12
  # rubocop:disable Metrics/CyclomaticComplexity
13
- # rubocop:disable Metrics/PerceivedComplexity:
13
+ # rubocop:disable Metrics/PerceivedComplexity
14
14
  def awesome_map_for(components, &)
15
15
  return unless map_utility_dynamic
16
16
 
@@ -57,7 +57,7 @@ module Decidim
57
57
  end
58
58
  end
59
59
  # rubocop:enable Metrics/CyclomaticComplexity
60
- # rubocop:enable Metrics/PerceivedComplexity:
60
+ # rubocop:enable Metrics/PerceivedComplexity
61
61
 
62
62
  def step_settings
63
63
  settings_source.try(:current_settings)
@@ -71,6 +71,7 @@ module Decidim
71
71
  try(:current_component) || self
72
72
  end
73
73
 
74
+ # rubocop:disable Rails/HelperInstanceVariable
74
75
  def current_categories(categories)
75
76
  return @current_categories if @current_categories
76
77
 
@@ -114,6 +115,7 @@ module Decidim
114
115
  color: format("#%02x%02x%02x", r, g, b)
115
116
  )
116
117
  end
118
+ # rubocop:enable Rails/HelperInstanceVariable
117
119
 
118
120
  # HSV values in [0..1[
119
121
  # returns [r, g, b] values from 0 to 255
@@ -20,7 +20,7 @@ module Decidim
20
20
  # add users that might have been completly destroyed in any organization
21
21
  relevant_user_ids += user_ids_from_object_changes - Decidim::User.select("id").where(id: user_ids_from_object_changes).pluck(:id)
22
22
 
23
- role_changes.where("object_changes ~ ANY (array[?])", relevant_user_ids.map { |id| "decidim_user_id:\n- ?\n- #{id}" })
23
+ role_changes.where("object_changes ~ ANY (array[?])", relevant_user_ids.map { |id| "decidim_user_id:\n- ?\n- #{id}(?!\\d)" })
24
24
  }
25
25
 
26
26
  scope :in_organization, lambda { |organization|
@@ -0,0 +1,3 @@
1
+ <!-- insert_bottom "div#panel-visibility" -->
2
+
3
+ <%= render "decidim/decidim_awesome/admin/shared/visibility_notice", participatory_space: current_assembly %>
@@ -0,0 +1,3 @@
1
+ <!-- insert_bottom "div#panel-title" -->
2
+
3
+ <%= render "decidim/decidim_awesome/admin/shared/visibility_notice", participatory_space: current_conference %>
@@ -0,0 +1,3 @@
1
+ <!-- insert_top ".login__links" -->
2
+
3
+ <%= render partial: "decidim/decidim_awesome/hashcash/hidden_field", locals: { zone: :signup } %>
@@ -0,0 +1,3 @@
1
+ <!-- insert_top ".login__links" -->
2
+
3
+ <%= render partial: "decidim/decidim_awesome/hashcash/hidden_field", locals: { zone: :login } %>
@@ -0,0 +1,3 @@
1
+ <!-- insert_bottom "div#panel-visibility" -->
2
+
3
+ <%= render "decidim/decidim_awesome/admin/shared/visibility_notice", participatory_space: participatory_process_group %>
@@ -0,0 +1,3 @@
1
+ <!-- insert_bottom "div#panel-visibility" -->
2
+
3
+ <%= render "decidim/decidim_awesome/admin/shared/visibility_notice", participatory_space: current_participatory_process %>
@@ -0,0 +1,3 @@
1
+ <!-- insert_top ".login__modal-links" -->
2
+
3
+ <%= render partial: "decidim/decidim_awesome/hashcash/hidden_field", locals: { zone: :login } %>
@@ -0,0 +1,3 @@
1
+ <!-- insert_after "erb[loud]:contains('content_for :header_snippets')" -->
2
+
3
+ <%= render(partial: "layouts/decidim/decidim_awesome/custom_styles") if awesome_scoped_styles.present? %>
@@ -1,7 +1,5 @@
1
1
  <!-- insert_after "erb[loud]:contains('append_stylesheet_pack_tag')" -->
2
2
 
3
3
  <% append_stylesheet_pack_tag "decidim_decidim_awesome", media: "all" %>
4
- <%= render(partial: "layouts/decidim/decidim_awesome/custom_styles") if awesome_scoped_styles.present? %>
5
-
6
4
  <% append_javascript_pack_tag "decidim_decidim_awesome", defer: false %>
7
5
  <% append_javascript_pack_tag("decidim_decidim_awesome_custom_fields") if Decidim::DecidimAwesome.enabled?(:proposal_custom_fields) %>
@@ -0,0 +1,4 @@
1
+ import Hashcash from "src/vendor/hashcash";
2
+
3
+ Hashcash.setup();
4
+