decidim-admin 0.18.1 → 0.19.0

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.

Potentially problematic release.


This version of decidim-admin might be problematic. Click here for more details.

Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/decidim/admin/form.js.es6 +24 -8
  3. data/app/assets/stylesheets/decidim/admin/modules/_forms.scss +8 -0
  4. data/app/assets/stylesheets/decidim/admin/modules/_modules.scss +1 -0
  5. data/app/commands/decidim/admin/create_component.rb +4 -7
  6. data/app/commands/decidim/admin/create_participatory_space_private_user.rb +4 -2
  7. data/app/commands/decidim/admin/destroy_newsletter.rb +1 -0
  8. data/app/commands/decidim/admin/process_participatory_space_private_user_import_csv.rb +41 -0
  9. data/app/commands/decidim/admin/process_user_group_verification_csv.rb +1 -0
  10. data/app/commands/decidim/admin/reject_user_group.rb +1 -0
  11. data/app/commands/decidim/admin/remove_admin.rb +1 -1
  12. data/app/commands/decidim/admin/update_component_permissions.rb +1 -1
  13. data/app/commands/decidim/admin/update_organization.rb +1 -0
  14. data/app/commands/decidim/admin/verify_user_group.rb +1 -0
  15. data/app/controllers/decidim/admin/areas_controller.rb +1 -0
  16. data/app/controllers/decidim/admin/components_controller.rb +29 -5
  17. data/app/controllers/decidim/admin/concerns/has_private_users_csv_import.rb +58 -0
  18. data/app/controllers/decidim/admin/impersonations_controller.rb +19 -2
  19. data/app/controllers/decidim/admin/resource_permissions_controller.rb +4 -1
  20. data/app/controllers/decidim/admin/scopes_controller.rb +2 -0
  21. data/app/forms/decidim/admin/component_form.rb +41 -16
  22. data/app/forms/decidim/admin/managed_user_promotion_form.rb +1 -0
  23. data/app/forms/decidim/admin/participatory_space_private_user_csv_import_form.rb +13 -0
  24. data/app/forms/decidim/admin/selective_newsletter_form.rb +1 -0
  25. data/app/helpers/decidim/admin/application_helper.rb +1 -1
  26. data/app/helpers/decidim/admin/attributes_display_helper.rb +2 -0
  27. data/app/helpers/decidim/admin/newsletters_helper.rb +6 -0
  28. data/app/helpers/decidim/admin/resource_permissions_helper.rb +1 -1
  29. data/app/helpers/decidim/admin/settings_helper.rb +52 -10
  30. data/app/jobs/decidim/admin/expire_impersonation_job.rb +1 -0
  31. data/app/jobs/decidim/admin/import_participatory_space_private_user_csv_job.rb +27 -0
  32. data/app/jobs/decidim/admin/newsletter_job.rb +1 -0
  33. data/app/jobs/decidim/admin/verify_user_group_from_csv_job.rb +1 -0
  34. data/app/permissions/decidim/admin/permissions.rb +4 -0
  35. data/app/permissions/decidim/admin/user_manager_permissions.rb +2 -0
  36. data/app/queries/decidim/admin/newsletter_recipients.rb +3 -0
  37. data/app/queries/decidim/admin/user_filter.rb +1 -0
  38. data/app/queries/decidim/admin/user_groups_evaluation.rb +1 -0
  39. data/app/views/decidim/admin/attachment_collections/index.html.erb +1 -1
  40. data/app/views/decidim/admin/attachment_collections/show.html.erb +1 -1
  41. data/app/views/decidim/admin/attachments/index.html.erb +1 -1
  42. data/app/views/decidim/admin/attachments/show.html.erb +1 -1
  43. data/app/views/decidim/admin/categories/index.html.erb +2 -2
  44. data/app/views/decidim/admin/categories/show.html.erb +1 -1
  45. data/app/views/decidim/admin/components/_form.html.erb +6 -6
  46. data/app/views/decidim/admin/components/_settings_fields.html.erb +6 -5
  47. data/app/views/decidim/admin/impersonations/_form.html.erb +1 -3
  48. data/app/views/decidim/admin/newsletters/select_recipients_to_deliver.html.erb +1 -1
  49. data/app/views/decidim/admin/organization_appearance/_form.html.erb +0 -7
  50. data/app/views/decidim/admin/participatory_space_private_users/index.html.erb +4 -3
  51. data/app/views/decidim/admin/participatory_space_private_users_csv_imports/new.html.erb +19 -0
  52. data/app/views/decidim/admin/resource_permissions/edit.html.erb +1 -1
  53. data/app/views/decidim/admin/static_pages/_topic.html.erb +1 -1
  54. data/app/views/decidim/admin/static_pages/show.html.erb +1 -1
  55. data/app/views/layouts/decidim/admin/_application.html.erb +6 -6
  56. data/app/views/layouts/decidim/admin/_header.html.erb +1 -1
  57. data/config/locales/ar.yml +7 -1
  58. data/config/locales/ca.yml +23 -11
  59. data/config/locales/cs.yml +13 -2
  60. data/config/locales/de.yml +9 -0
  61. data/config/locales/en.yml +14 -2
  62. data/config/locales/es-MX.yml +13 -2
  63. data/config/locales/es-PY.yml +13 -2
  64. data/config/locales/es.yml +13 -1
  65. data/config/locales/fi-plain.yml +13 -2
  66. data/config/locales/fi.yml +14 -2
  67. data/config/locales/fr.yml +13 -2
  68. data/config/locales/hu.yml +13 -1
  69. data/config/locales/it.yml +12 -2
  70. data/config/locales/nl.yml +13 -1
  71. data/config/locales/sv.yml +0 -1
  72. data/config/locales/tr-TR.yml +0 -2
  73. data/lib/decidim/admin/test/manage_attachments_examples.rb +1 -1
  74. data/lib/decidim/admin/version.rb +1 -1
  75. metadata +14 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3e1bb0a468fe74558d68a3e069223c66f93216b5d0b6a982ca573c79b9e5133a
4
- data.tar.gz: fbfd2c9a1b874ad641144ff67560e003cfeb4dac69ab83eddb8077d73b359784
3
+ metadata.gz: 3fe9da64e350f8f333b98343743715f137e5f48ed586e9c397bad527caff7738
4
+ data.tar.gz: 22ae4dbc9bdaf872065dd3b3ca4c4458b5e0d824bb1c7f6a8dc12db7926abed7
5
5
  SHA512:
6
- metadata.gz: 0e5c425a443047671cc90f357e4b43d183ac5a4c90703c6ca842257a985531f3f49a047bfae93106d4fe9d9823ba61c5a5db2c1d6e217e9ec5d07d0601d333c6
7
- data.tar.gz: f90542e7d01193e11ff18550dc1c4c4f51a71be5bb159cdae6e74fadfdcce4e43c56b71d1923a3fa6cb82766508f7896d02b6c519dbe4c92b49772752ec80b81
6
+ metadata.gz: 9459a7af134d40568c3f9d53b4edd9f45dbbab101a9d093597ae9ab81a82288876a574d23fe0ab05986c9d7f904bad4058e957eb8e159fa34f614f13a6619db2
7
+ data.tar.gz: 5188ed41e3f8cf190a64315add75292008af12766a0a1a33307d38f3b5404c2a667b2993ef94eb8738a54e3e76d9693867aefa5b4702585d80f15731334503af
@@ -1,17 +1,33 @@
1
- // Checks if the form contains a field with a special CSS class added in
2
- // Decidim::Admin::SettingsHelper. If so, prevents the checkbox from being clicked,
3
- // extracts the stored text and adds a new paragraph after the field.
1
+ // Checks if the form contains fields with special CSS classes added in
2
+ // Decidim::Admin::SettingsHelper and acts accordingly.
4
3
  $(() => {
5
- const $checkbox = $(".participatory_texts_disabled");
4
+ // Prevents checkbox with ".participatory_texts_disabled" class from being clicked.
5
+ const $participatoryTexts = $(".participatory_texts_disabled");
6
6
 
7
- $checkbox.click((event) => {
7
+ $participatoryTexts.click((event) => {
8
8
  event.preventDefault();
9
9
  return false;
10
10
  });
11
11
 
12
- if ($checkbox.length > 0) {
13
- const $text = $checkbox[0].dataset.text
12
+ // Target fields:
13
+ // - amendments_wizard_help_text
14
+ // - all fields with ".amendments_step_settings" class
15
+ // (1) Hides target fields if amendments_enabled component setting is NOT checked.
16
+ // (2) Toggles visibilty of target fields when amendments_enabled component setting is clicked.
17
+ const $amendmentsEnabled = $("input#component_settings_amendments_enabled");
14
18
 
15
- $checkbox.parent().after(`<p class="help-text">${$text}</p>`)
19
+ if ($amendmentsEnabled.length > 0) {
20
+ const $amendmentWizardHelpText = $("[id*='amendments_wizard_help_text']").parent();
21
+ const $amendmentStepSettings = $(".amendments_step_settings").parent();
22
+
23
+ if ($amendmentsEnabled.is(":not(:checked)")) {
24
+ $amendmentWizardHelpText.hide();
25
+ $amendmentStepSettings.hide().siblings(".help-text").hide();
26
+ }
27
+
28
+ $amendmentsEnabled.click(() => {
29
+ $amendmentWizardHelpText.toggle();
30
+ $amendmentStepSettings.toggle().siblings(".help-text").toggle();
31
+ });
16
32
  }
17
33
  });
@@ -134,3 +134,11 @@ textarea{
134
134
  cursor: not-allowed;
135
135
  opacity: .5;
136
136
  }
137
+
138
+ .edit_component .step-settings{
139
+ .card-section fieldset legend{
140
+ font-size: 24px;
141
+ font-weight: bold;
142
+ border-bottom: 1px solid grey;
143
+ }
144
+ }
@@ -34,3 +34,4 @@
34
34
  @import "decidim/modules/input-tags";
35
35
  @import "decidim/modules/input-mentions";
36
36
  @import "decidim/modules/input-hashtags";
37
+ @import "decidim/modules/input-gallery";
@@ -8,13 +8,10 @@ module Decidim
8
8
 
9
9
  # Public: Initializes the command.
10
10
  #
11
- # manifest - The component's manifest to create a component from.
12
- # form - The form from which the data in this component comes from.
13
- # participatory_space - The participatory space that will hold this component.
14
- def initialize(manifest, form, participatory_space)
15
- @manifest = manifest
11
+ # form - The form from which the data in this component comes from.
12
+ def initialize(form)
16
13
  @form = form
17
- @participatory_space = participatory_space
14
+ @manifest = form.manifest
18
15
  end
19
16
 
20
17
  # Public: Creates the Component.
@@ -39,7 +36,7 @@ module Decidim
39
36
  form.current_user,
40
37
  manifest_name: manifest.name,
41
38
  name: form.name,
42
- participatory_space: participatory_space,
39
+ participatory_space: form.participatory_space,
43
40
  weight: form.weight,
44
41
  settings: form.settings,
45
42
  default_step_settings: form.default_step_settings,
@@ -10,10 +10,11 @@ module Decidim
10
10
  # form - A form object with the params.
11
11
  # private_user_to - The private_user_to that will hold the
12
12
  # user role
13
- def initialize(form, current_user, private_user_to)
13
+ def initialize(form, current_user, private_user_to, via_csv = false)
14
14
  @form = form
15
15
  @current_user = current_user
16
16
  @private_user_to = private_user_to
17
+ @via_csv = via_csv
17
18
  end
18
19
 
19
20
  # Executes the command. Broadcasts these events:
@@ -41,8 +42,9 @@ module Decidim
41
42
  attr_reader :form, :private_user_to, :current_user, :user
42
43
 
43
44
  def create_private_user
45
+ action = @via_csv ? "create_via_csv" : "create"
44
46
  Decidim.traceability.perform_action!(
45
- :create,
47
+ action,
46
48
  Decidim::ParticipatorySpacePrivateUser,
47
49
  current_user,
48
50
  resource: {
@@ -17,6 +17,7 @@ module Decidim
17
17
  # Broadcasts :ok if it got destroyed
18
18
  def call
19
19
  return broadcast(:already_sent) if newsletter.sent?
20
+
20
21
  destroy_newsletter
21
22
  broadcast(:ok)
22
23
  end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "csv"
4
+
5
+ module Decidim
6
+ module Admin
7
+ class ProcessParticipatorySpacePrivateUserImportCsv < Rectify::Command
8
+ # Public: Initializes the command.
9
+ #
10
+ # form - the form object containing the uploaded file
11
+ # current_user - the user performing the action
12
+ # private_users_to - The private_users_to that will hold the user role
13
+ def initialize(form, current_user, private_users_to)
14
+ @form = form
15
+ @current_user = current_user
16
+ @private_users_to = private_users_to
17
+ end
18
+
19
+ # Executes the command. Broadcasts these events:
20
+ #
21
+ # - :ok when everything is valid.
22
+ # - :invalid if the form wasn't valid and we couldn't proceed.
23
+ #
24
+ # Returns nothing.
25
+ def call
26
+ return broadcast(:invalid) unless @form.valid?
27
+
28
+ process_csv
29
+ broadcast(:ok)
30
+ end
31
+
32
+ private
33
+
34
+ def process_csv
35
+ CSV.foreach(@form.file.path) do |email, user_name|
36
+ ImportParticipatorySpacePrivateUserCsvJob.perform_later(email, user_name, @private_users_to, @current_user) if email.present? && user_name.present?
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -22,6 +22,7 @@ module Decidim
22
22
  # Returns nothing.
23
23
  def call
24
24
  return broadcast(:invalid) unless @form.valid?
25
+
25
26
  process_csv
26
27
  broadcast(:ok)
27
28
  end
@@ -21,6 +21,7 @@ module Decidim
21
21
  # Returns nothing.
22
22
  def call
23
23
  return broadcast(:invalid) unless @user_group.valid?
24
+
24
25
  reject_user_group
25
26
  broadcast(:ok)
26
27
  end
@@ -35,7 +35,7 @@ module Decidim
35
35
  attr_reader :user, :current_user
36
36
 
37
37
  def user_role
38
- user.admin? ? :admin : user.roles
38
+ user.admin? ? :admin : user.roles.last
39
39
  end
40
40
  end
41
41
  end
@@ -75,7 +75,7 @@ module Decidim
75
75
  return permissions unless component.permissions
76
76
 
77
77
  permissions.deep_stringify_keys.reject do |action, config|
78
- HashDiff.diff(config, component.permissions[action]).empty?
78
+ Hashdiff.diff(config, component.permissions[action]).empty?
79
79
  end
80
80
  end
81
81
 
@@ -24,6 +24,7 @@ module Decidim
24
24
  return broadcast(:invalid) if form.invalid?
25
25
 
26
26
  return broadcast(:ok, @organization) if update_organization
27
+
27
28
  broadcast(:invalid)
28
29
  end
29
30
 
@@ -21,6 +21,7 @@ module Decidim
21
21
  # Returns nothing.
22
22
  def call
23
23
  return broadcast(:invalid) unless @user_group.valid?
24
+
24
25
  verify_user_group
25
26
  broadcast(:ok)
26
27
  end
@@ -79,6 +79,7 @@ module Decidim
79
79
 
80
80
  def area
81
81
  return @area if defined?(@area)
82
+
82
83
  @area = organization_areas.find_by(id: params[:id])
83
84
  end
84
85
  end
@@ -27,10 +27,10 @@ module Decidim
27
27
  end
28
28
 
29
29
  def create
30
- @form = form(ComponentForm).from_params(params)
30
+ @form = form(ComponentForm).from_params(form_params)
31
31
  enforce_permission_to :create, :component
32
32
 
33
- CreateComponent.call(manifest, @form, current_participatory_space) do
33
+ CreateComponent.call(@form) do
34
34
  on(:ok) do
35
35
  flash[:notice] = I18n.t("components.create.success", scope: "decidim.admin")
36
36
  redirect_to action: :index
@@ -52,7 +52,7 @@ module Decidim
52
52
 
53
53
  def update
54
54
  @component = query_scope.find(params[:id])
55
- @form = form(ComponentForm).from_params(params)
55
+ @form = form(ComponentForm).from_params(form_params)
56
56
  enforce_permission_to :update, :component, component: @component
57
57
 
58
58
  UpdateComponent.call(@form, @component) do
@@ -65,7 +65,7 @@ module Decidim
65
65
 
66
66
  on(:invalid) do
67
67
  flash[:alert] = I18n.t("components.update.error", scope: "decidim.admin")
68
- redirect_to action: :edit
68
+ render action: :edit
69
69
  end
70
70
  end
71
71
  end
@@ -113,12 +113,36 @@ module Decidim
113
113
 
114
114
  private
115
115
 
116
+ # Returns a Class with the attributes sanitized, coerced and filtered
117
+ # to the right type. See Decidim::SettingsManifest#schema.
118
+ def new_settings_schema(name, data)
119
+ manifest.settings(name).schema.new(data, current_organization.default_locale)
120
+ end
121
+
122
+ # Processes the component params so Decidim::Admin::ComponentForm
123
+ # can assign and validate the attributes when using #from_params.
124
+ def form_params
125
+ form_params = params[:component].permit!
126
+ form_params[:id] = params[:id]
127
+ form_params[:manifest] = manifest
128
+ form_params[:participatory_space] = current_participatory_space
129
+ form_params[:settings] = new_settings_schema(:global, form_params[:settings])
130
+ if form_params[:default_step_settings]
131
+ form_params[:default_step_settings] = new_settings_schema(:step, form_params[:default_step_settings])
132
+ else
133
+ form_params[:step_settings].each do |key, value|
134
+ form_params[:step_settings][key] = new_settings_schema(:step, value)
135
+ end
136
+ end
137
+ form_params
138
+ end
139
+
116
140
  def query_scope
117
141
  current_participatory_space.components
118
142
  end
119
143
 
120
144
  def manifest
121
- Decidim.find_component_manifest(params[:type])
145
+ @component&.manifest || Decidim.find_component_manifest(params[:type])
122
146
  end
123
147
 
124
148
  def default_name(manifest)
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Admin
5
+ module Concerns
6
+ # PrivateUsers can be related to any ParticipatorySpace, in order to
7
+ # import private users from csv for a given type, you should create a new
8
+ # controller and include this concern.
9
+ #
10
+ # The only requirement is to define a `privatable_to` method that
11
+ # returns an instance of the model to relate the private_user to.
12
+ module HasPrivateUsersCsvImport
13
+ extend ActiveSupport::Concern
14
+
15
+ included do
16
+ helper_method :privatable_to
17
+
18
+ def new
19
+ enforce_permission_to :csv_import, :space_private_user
20
+ @form = form(ParticipatorySpacePrivateUserCsvImportForm).from_params({}, privatable_to: privatable_to)
21
+ render template: "decidim/admin/participatory_space_private_users_csv_imports/new"
22
+ end
23
+
24
+ def create
25
+ enforce_permission_to :csv_import, :space_private_user
26
+ @form = form(ParticipatorySpacePrivateUserCsvImportForm).from_params(params, privatable_to: privatable_to)
27
+
28
+ ProcessParticipatorySpacePrivateUserImportCsv.call(@form, current_user, current_participatory_space) do
29
+ on(:ok) do
30
+ flash[:notice] = I18n.t("participatory_space_private_users_csv_imports.create.success", scope: "decidim.admin")
31
+ redirect_to after_import_path
32
+ end
33
+
34
+ on(:invalid) do
35
+ flash[:alert] = I18n.t("participatory_space_private_users_csv_imports.create.invalid", scope: "decidim.admin")
36
+ render template: "decidim/admin/participatory_space_private_users_csv_imports/new"
37
+ end
38
+ end
39
+ end
40
+
41
+ # Public: Returns a String or Object that will be passed to `redirect_to` after
42
+ # importing private users. By default it redirects to the privatable_to.
43
+ #
44
+ # It can be redefined at controller level if you need to redirect elsewhere.
45
+ def after_import_path
46
+ privatable_to
47
+ end
48
+
49
+ # Public: The only method to be implemented at the controller. You need to
50
+ # return the object where the attachment will be attached to.
51
+ def privatable_to
52
+ raise NotImplementedError
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -68,14 +68,31 @@ module Decidim
68
68
 
69
69
  def user
70
70
  @user ||= if creating_managed_user?
71
- new_managed_user
71
+ existing_managed_user || new_managed_user
72
72
  else
73
73
  current_organization.users.find(params[:impersonatable_user_id])
74
74
  end
75
75
  end
76
76
 
77
+ def existing_managed_user
78
+ handler = Decidim::AuthorizationHandler.handler_for(
79
+ handler_name,
80
+ params.dig(:impersonate_user, :authorization)
81
+ )
82
+ return nil unless handler.unique_id
83
+
84
+ existing_authorization = Authorization.find_by(
85
+ name: handler_name,
86
+ unique_id: handler.unique_id
87
+ )
88
+ return nil unless existing_authorization
89
+ return nil unless existing_authorization.user.managed?
90
+
91
+ existing_authorization.user
92
+ end
93
+
77
94
  def new_managed_user
78
- Decidim::User.find_or_initialize_by(
95
+ Decidim::User.new(
79
96
  organization: current_organization,
80
97
  managed: true,
81
98
  name: params.dig(:impersonate_user, :name)
@@ -75,7 +75,10 @@ module Decidim
75
75
  return if params[:resource_name].blank?
76
76
 
77
77
  resource_id = params["#{params[:resource_name]}_id"]
78
- @resource ||= Decidim.find_resource_manifest(params[:resource_name])&.model_class&.find_by(id: resource_id)
78
+ resource_slug = params["#{params[:resource_name]}_slug"]
79
+
80
+ find_by = resource_slug.present? ? { slug: resource_slug } : { id: resource_id }
81
+ @resource ||= Decidim.find_resource_manifest(params[:resource_name])&.model_class&.find_by(find_by)
79
82
  @resource if @resource&.allow_resource_permissions?
80
83
  end
81
84
 
@@ -75,11 +75,13 @@ module Decidim
75
75
 
76
76
  def parent_scope
77
77
  return @parent_scope if defined?(@parent_scope)
78
+
78
79
  @parent_scope = scope ? scope.parent : organization_scopes.find_by(id: params[:scope_id])
79
80
  end
80
81
 
81
82
  def scope
82
83
  return @scope if defined?(@scope)
84
+
83
85
  @scope = organization_scopes.find_by(id: params[:id])
84
86
  end
85
87
 
@@ -13,15 +13,18 @@ module Decidim
13
13
  translatable_attribute :name, String
14
14
  validates :name, translatable_presence: true
15
15
 
16
- attribute :settings, Object
17
- attribute :default_step_settings, Object
18
- attribute :manifest
19
16
  attribute :weight, Integer, default: 0
20
17
 
18
+ attribute :manifest, Object
19
+ attribute :participatory_space, Object
20
+ validates :manifest, :participatory_space, presence: true
21
+
22
+ attribute :settings, Object
23
+ attribute :default_step_settings, Object
21
24
  attribute :step_settings, Hash[String => Object]
22
- attribute :participatory_space
23
25
 
24
- validate :must_be_able_to_change_participatory_texts_setting, if: :proposal_component?
26
+ validate :must_be_able_to_change_participatory_texts_setting
27
+ validate :amendments_visibility_options_must_be_valid
25
28
 
26
29
  def settings?
27
30
  settings.manifest.attributes.any?
@@ -31,23 +34,45 @@ module Decidim
31
34
  default_step_settings.manifest.attributes.any?
32
35
  end
33
36
 
34
- def component
35
- @component ||= Component.find_by(id: id)
37
+ private
38
+
39
+ # Overwrites Rectify::Form#form_attributes_valid? to validate nested `step_settings` attributes.
40
+ def form_attributes_valid?
41
+ return false unless errors.empty? && settings_errors_empty? # Preserves errors from custom validation methods
42
+
43
+ attributes_that_respond_to(:valid?).concat(
44
+ step_settings.each_value.select { |attribute| attribute.respond_to?(:valid?) }
45
+ ).all?(&:valid?)
36
46
  end
37
47
 
38
- def proposal_component?
39
- component&.manifest_name == "proposals"
48
+ def settings_errors_empty?
49
+ validations = [settings.errors.empty?]
50
+ validations << if default_step_settings.present?
51
+ default_step_settings.errors.empty?
52
+ else
53
+ step_settings.each_value.map(&:errors).all?(&:empty?)
54
+ end
55
+ validations.all?
40
56
  end
41
57
 
42
- # Validation for `Proposals` components. Prevents changing the global
43
- # setting `participatory_texts_enabled` when there are proposals.
44
- # Does not add a custom error message as it would be unused, because
45
- # the setting's checkbox is automatically being disabled on the frontend.
58
+ # Validates setting `participatory_texts_enabled` is not changed when there are proposals for the component.
46
59
  def must_be_able_to_change_participatory_texts_setting
47
- form_setting_value = settings[:participatory_texts_enabled].to_i == 1 # Convert "1"/"0" to true/false
48
- return if form_setting_value == component.settings.participatory_texts_enabled
60
+ return unless manifest&.name == :proposals && (component = Component.find_by(id: id))
61
+ return unless settings.participatory_texts_enabled != component.settings.participatory_texts_enabled
62
+
63
+ settings.errors.add(:participatory_texts_enabled) if Decidim::Proposals::Proposal.where(component: component).any?
64
+ end
65
+
66
+ # Validates setting `amendments_visibility` is included in Decidim::Amendment::VisibilityStepSetting.options.
67
+ def amendments_visibility_options_must_be_valid
68
+ return unless manifest&.name == :proposals && settings.amendments_enabled
69
+
70
+ visibility_options = Decidim::Amendment::VisibilityStepSetting.options.map(&:last)
71
+ step_settings.each do |step, settings|
72
+ next unless visibility_options.exclude? settings[:amendments_visibility]
49
73
 
50
- errors.add(:settings) if Decidim::Proposals::Proposal.where(component: component).any?
74
+ step_settings[step].errors.add(:amendments_visibility, :inclusion)
75
+ end
51
76
  end
52
77
  end
53
78
  end