decidim-system 0.28.1 → 0.29.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/app/cells/decidim/system/system_checks/show.erb +13 -0
  4. data/app/cells/decidim/system/system_checks_cell.rb +48 -0
  5. data/app/commands/decidim/system/create_default_content_blocks.rb +0 -3
  6. data/app/commands/decidim/system/{populate_help.rb → create_default_help_pages.rb} +14 -7
  7. data/app/commands/decidim/system/create_default_pages.rb +0 -1
  8. data/app/commands/decidim/system/{register_organization.rb → create_organization.rb} +11 -10
  9. data/app/controllers/decidim/system/dashboard_controller.rb +2 -0
  10. data/app/controllers/decidim/system/organizations_controller.rb +7 -1
  11. data/app/forms/decidim/system/base_organization_form.rb +127 -0
  12. data/app/forms/decidim/system/register_organization_form.rb +23 -3
  13. data/app/forms/decidim/system/update_organization_form.rb +18 -88
  14. data/app/models/decidim/system/admin.rb +2 -2
  15. data/app/packs/stylesheets/decidim/system/application.scss +57 -0
  16. data/app/views/decidim/system/dashboard/show.html.erb +4 -0
  17. data/app/views/decidim/system/oauth_applications/_form.html.erb +1 -1
  18. data/app/views/decidim/system/oauth_applications/index.html.erb +2 -2
  19. data/app/views/decidim/system/organizations/edit.html.erb +5 -3
  20. data/app/views/decidim/system/shared/_admins_list.html.erb +2 -2
  21. data/app/views/decidim/system/shared/_organizations_list.html.erb +3 -3
  22. data/app/views/layouts/decidim/system/_js_configuration.html.erb +1 -1
  23. data/app/views/layouts/decidim/system/login.html.erb +1 -1
  24. data/config/locales/ar.yml +0 -1
  25. data/config/locales/bg.yml +22 -4
  26. data/config/locales/ca.yml +18 -4
  27. data/config/locales/cs.yml +5 -3
  28. data/config/locales/de.yml +16 -4
  29. data/config/locales/el.yml +0 -4
  30. data/config/locales/en.yml +18 -4
  31. data/config/locales/es-MX.yml +18 -4
  32. data/config/locales/es-PY.yml +18 -4
  33. data/config/locales/es.yml +18 -4
  34. data/config/locales/eu.yml +18 -4
  35. data/config/locales/fi-plain.yml +18 -4
  36. data/config/locales/fi.yml +18 -4
  37. data/config/locales/fr-CA.yml +18 -4
  38. data/config/locales/fr.yml +18 -4
  39. data/config/locales/gl.yml +0 -1
  40. data/config/locales/hu.yml +0 -2
  41. data/config/locales/id-ID.yml +0 -1
  42. data/config/locales/it.yml +1 -1
  43. data/config/locales/ja.yml +18 -4
  44. data/config/locales/lt.yml +0 -4
  45. data/config/locales/lv.yml +0 -1
  46. data/config/locales/nl.yml +0 -1
  47. data/config/locales/no.yml +0 -1
  48. data/config/locales/pl.yml +120 -1
  49. data/config/locales/pt-BR.yml +0 -2
  50. data/config/locales/pt.yml +0 -1
  51. data/config/locales/ro-RO.yml +0 -1
  52. data/config/locales/ru.yml +0 -1
  53. data/config/locales/sk.yml +0 -1
  54. data/config/locales/sv.yml +0 -1
  55. data/config/locales/tr-TR.yml +22 -1
  56. data/config/locales/zh-CN.yml +0 -1
  57. data/config/locales/zh-TW.yml +0 -4
  58. data/db/seeds.rb +1 -1
  59. data/decidim-system.gemspec +1 -1
  60. data/lib/decidim/system/engine.rb +4 -0
  61. data/lib/decidim/system/version.rb +1 -1
  62. data/lib/tasks/decidim_system.rake +1 -1
  63. metadata +18 -16
  64. data/app/mailers/decidim/system/application_mailer.rb +0 -12
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a35646cb8914a3d098676b0ed5ca18bc5d77a3112d96e483287a99fae05362c
4
- data.tar.gz: 3e57b2bbefb5309281431d8960af134285e3926cf351add494969511c773e0d2
3
+ metadata.gz: 947a58b195365e516146ac29a1b1ccf623416523defcc0fe31ae44e3fd697a36
4
+ data.tar.gz: 713c800019aebcf933159515236a8c5c4dd5c79543f2822e1ac75059b0ddf293
5
5
  SHA512:
6
- metadata.gz: 3ffa69136fa5dad543b2ae62b60938ed0f7d50bdb9592c8abc0326d99dd0fec08942a8069c4797ee008601bc4141a8c3fe418edd5d990714c052617ea29a2b0d
7
- data.tar.gz: d04818e42d0651f8b70933a7758122cb13de4ae3b5c267a4fea821d6a037c49c9e438818ac60fc8a95cb539c5ac46c81164d1c4a8d1bd063efdb8bc645c7e8ae
6
+ metadata.gz: f88a26f5fdd1527aafaaadf95c4a6e450e08846d2852277a17c4fac539cd55b5311d7d8d5d71b6399b225194d7668bd2cb6d1993df265e86aec9fc29ba2e19c1
7
+ data.tar.gz: 675c8a7bf6cd5eb07ef01aba70ba8423673c5c4e4a624d49bc3b6dbe6548444e3c690b27b4afc8f96fcb3e597334947d3f1e85432dd7f9503be4b5008063748f
data/README.md CHANGED
@@ -49,7 +49,7 @@ bin/rails decidim_system:create_admin
49
49
  You will be asked for an email and a password. For security, the password will not get displayed back at you and you will need to confirm it.
50
50
 
51
51
  Once you have created your first admin you can access the system dashboard at `/system`. For instance, if you have Decidim running at `https://example.org`, this URL would be `https://example.org/system`.
52
- You will be able to login with your newly created user.
52
+ You will be able to log in with your newly created user.
53
53
 
54
54
  From the system dashboard you can add new admins.
55
55
 
@@ -73,11 +73,11 @@ system_admin.save
73
73
 
74
74
  ## Managing organizations
75
75
 
76
- Once you have your system admin setup you can also start managing the organizations in your deploy. To do it, login at the system dashboard and create a new organization
76
+ Once you have your system admin setup you can also start managing the organizations in your deploy. To do it, log in at the system dashboard and create a new organization
77
77
  following the form instructions. After creating it, a new admin user will be created and invited to start managing it.
78
78
 
79
79
  Remember that System admins and regular Admins are completely different users (they do not even share the same database table), so you cannot use your
80
- system user to login in as an organization admin.
80
+ system user to log in in as an organization admin.
81
81
 
82
82
  ## Contributing
83
83
 
@@ -0,0 +1,13 @@
1
+ <ul>
2
+ <% checks.each do |key, check| %>
3
+ <li>
4
+ <% if check[:check_method] %>
5
+ <%= icon "checkbox-circle-line", class: "fill-success inline" %>
6
+ <%= t("#{key}.success", scope: "decidim.system.system_checks") %>
7
+ <% else %>
8
+ <%= icon "close-circle-line", class: "fill-alert inline" %>
9
+ <%= t("#{key}.error", scope: "decidim.system.system_checks", error_extra: check[:error_extra]) %>
10
+ <% end %>
11
+ </li>
12
+ <% end %>
13
+ </ul>
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module System
5
+ class SystemChecksCell < Decidim::ViewModel
6
+ def show
7
+ render
8
+ end
9
+
10
+ private
11
+
12
+ def checks
13
+ {
14
+ secret_key: {
15
+ check_method: correct_secret_key_base?,
16
+ error_extra: generated_secret_key
17
+ },
18
+ active_job_queue: {
19
+ check_method: correct_active_job_queue?,
20
+ error_extra: active_job_queue_link
21
+ }
22
+ }
23
+ end
24
+
25
+ def correct_secret_key_base?
26
+ Rails.application.secrets.secret_key_base&.length == 128
27
+ end
28
+
29
+ def generated_secret_key
30
+ SecureRandom.hex(64)
31
+ end
32
+
33
+ def correct_active_job_queue?
34
+ # The default ActiveJob queue is not recommended for production environments,
35
+ # as it can lose jobs when restarting
36
+ Rails.application.config.active_job.queue_adapter != :async
37
+ end
38
+
39
+ def active_job_queue_link
40
+ link_to(t("active_job_queue.decidim_documentation", scope: "decidim.system.system_checks"),
41
+ "https://docs.decidim.org/en/develop/services/activejob",
42
+ class: "underline text-primary",
43
+ target: "_blank",
44
+ rel: "nofollow noopener noreferrer")
45
+ end
46
+ end
47
+ end
48
+ end
@@ -5,9 +5,6 @@ module Decidim
5
5
  # A command with all the business logic to create the default content blocks
6
6
  # for a newly-created organization.
7
7
  class CreateDefaultContentBlocks < Decidim::Command
8
- DEFAULT_CONTENT_BLOCKS =
9
- [:hero, :sub_hero, :highlighted_content_banner, :how_to_participate, :stats, :metrics, :footer_sub_hero].freeze
10
-
11
8
  # Public: Initializes the command.
12
9
  #
13
10
  # form - A form object with the params.
@@ -3,7 +3,9 @@
3
3
  module Decidim
4
4
  module System
5
5
  # A command that will create default help pages for an organization.
6
- class PopulateHelp < Decidim::Command
6
+ class CreateDefaultHelpPages < Decidim::Command
7
+ include Decidim::TranslatableAttributes
8
+
7
9
  # Public: Initializes the command.
8
10
  #
9
11
  # organization - An organization
@@ -17,16 +19,17 @@ module Decidim
17
19
  def call
18
20
  ActiveRecord::Base.transaction do
19
21
  topic = Decidim::StaticPageTopic.create!(
20
- title: multi_translation("decidim.help.main_topic.title", organization: @organization.name),
21
- description: multi_translation("decidim.help.main_topic.description", organization: @organization.name),
22
+ title: multi_translation("decidim.help.main_topic.title", organization: organization_name),
23
+ description: multi_translation("decidim.help.main_topic.description", organization: organization_name),
22
24
  organization: @organization,
25
+ show_in_footer: true,
23
26
  weight: 0
24
27
  )
25
28
 
26
29
  Decidim::StaticPage.create!(
27
30
  slug: "help",
28
- title: multi_translation("decidim.help.main_topic.default_page.title", organization: @organization.name),
29
- content: multi_translation("decidim.help.main_topic.default_page.content", organization: @organization.name),
31
+ title: multi_translation("decidim.help.main_topic.default_page.title", organization: organization_name),
32
+ content: multi_translation("decidim.help.main_topic.default_page.content", organization: organization_name),
30
33
  topic:,
31
34
  organization: @organization,
32
35
  weight: 0
@@ -49,8 +52,12 @@ module Decidim
49
52
  end
50
53
  end
51
54
 
52
- def multi_translation(key, **arguments)
53
- Decidim::TranslationsHelper.multi_translation(key, @organization.available_locales, **arguments)
55
+ def multi_translation(key, **)
56
+ Decidim::TranslationsHelper.multi_translation(key, @organization.available_locales, **)
57
+ end
58
+
59
+ def organization_name
60
+ translated_attribute(@organization.name)
54
61
  end
55
62
  end
56
63
  end
@@ -23,7 +23,6 @@ module Decidim
23
23
  translated_slug = I18n.t(slug, scope: "decidim.system.default_pages")
24
24
  page.title = localized_attribute(translated_slug, :title)
25
25
  page.content = localized_attribute(translated_slug, :content)
26
- page.show_in_footer = true
27
26
  page.allow_public_access = true if slug == "terms-of-service"
28
27
  end
29
28
 
@@ -2,10 +2,14 @@
2
2
 
3
3
  module Decidim
4
4
  module System
5
+ class InvitationFailedError < ActiveRecord::RecordInvalid
6
+ end
7
+
5
8
  # A command with all the business logic when creating a new organization in
6
9
  # the system. It creates the organization and invites the admin to the
7
10
  # system.
8
- class RegisterOrganization < Decidim::Command
11
+
12
+ class CreateOrganization < Decidim::Command
9
13
  # Public: Initializes the command.
10
14
  #
11
15
  # form - A form object with the params.
@@ -24,21 +28,21 @@ module Decidim
24
28
 
25
29
  @organization = nil
26
30
  invite_form = nil
27
- invitation_failed = false
28
31
 
29
32
  transaction do
30
33
  @organization = create_organization
31
34
  CreateDefaultPages.call(@organization)
32
- PopulateHelp.call(@organization)
35
+ CreateDefaultHelpPages.call(@organization)
33
36
  CreateDefaultContentBlocks.call(@organization)
34
37
  invite_form = invite_user_form(@organization)
35
- invitation_failed = invite_form.invalid?
38
+ raise InvitationFailedError if invite_form.invalid?
36
39
  end
37
- return broadcast(:invalid) if invitation_failed
38
40
 
39
41
  Decidim::InviteUser.call(invite_form) if @organization && invite_form
40
42
 
41
43
  broadcast(:ok)
44
+ rescue InvitationFailedError
45
+ broadcast(:invalid_invitation)
42
46
  rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique
43
47
  broadcast(:invalid)
44
48
  end
@@ -49,13 +53,13 @@ module Decidim
49
53
 
50
54
  def create_organization
51
55
  Decidim::Organization.create!(
52
- name: form.name,
56
+ name: { form.default_locale => form.name },
53
57
  host: form.host,
54
58
  secondary_hosts: form.clean_secondary_hosts,
55
59
  reference_prefix: form.reference_prefix,
56
60
  available_locales: form.available_locales,
57
61
  available_authorizations: form.clean_available_authorizations,
58
- external_domain_whitelist: ["decidim.org", "github.com"],
62
+ external_domain_allowlist: ["decidim.org", "github.com"],
59
63
  users_registration_mode: form.users_registration_mode,
60
64
  force_users_to_authenticate_before_access_organization: form.force_users_to_authenticate_before_access_organization,
61
65
  badges_enabled: true,
@@ -72,10 +76,7 @@ module Decidim
72
76
 
73
77
  def default_colors
74
78
  {
75
- alert: "#ec5840",
76
79
  primary: "#53bf40",
77
- success: "#57d685",
78
- warning: "#ffae00",
79
80
  tertiary: "#bf4053",
80
81
  secondary: "#4053bf"
81
82
  }
@@ -10,6 +10,8 @@ module Decidim
10
10
  @admins = Admin.all
11
11
  end
12
12
 
13
+ private
14
+
13
15
  def check_organizations_presence
14
16
  return if Organization.exists?
15
17
 
@@ -16,12 +16,17 @@ module Decidim
16
16
  def create
17
17
  @form = form(RegisterOrganizationForm).from_params(params)
18
18
 
19
- RegisterOrganization.call(@form) do
19
+ CreateOrganization.call(@form) do
20
20
  on(:ok) do
21
21
  flash[:notice] = t("organizations.create.success_html", scope: "decidim.system", host: @form.host, email: @form.organization_admin_email)
22
22
  redirect_to organizations_path
23
23
  end
24
24
 
25
+ on(:invalid_invitation) do
26
+ flash.now[:alert] = t("organizations.create.error_invitation", scope: "decidim.system")
27
+ render :new
28
+ end
29
+
25
30
  on(:invalid) do
26
31
  flash.now[:alert] = t("organizations.create.error", scope: "decidim.system")
27
32
  render :new
@@ -39,6 +44,7 @@ module Decidim
39
44
  end
40
45
 
41
46
  def update
47
+ @organization = Organization.find(params[:id])
42
48
  @form = form(UpdateOrganizationForm).from_params(params)
43
49
 
44
50
  UpdateOrganization.call(params[:id], @form) do
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/translatable_attributes"
4
+
5
+ module Decidim
6
+ module System
7
+ # A form object to be inherited to create and update organizations from the system dashboard.
8
+ #
9
+ class BaseOrganizationForm < Form
10
+ include TranslatableAttributes
11
+ include JsonbAttributes
12
+
13
+ mimic :organization
14
+
15
+ attribute :host, String
16
+ attribute :secondary_hosts, String
17
+ attribute :force_users_to_authenticate_before_access_organization, Boolean
18
+ attribute :available_authorizations, Array[String]
19
+ attribute :users_registration_mode, String
20
+ attribute :default_locale, String
21
+
22
+ jsonb_attribute :smtp_settings, [
23
+ [:from, String],
24
+ [:from_email, String],
25
+ [:from_label, String],
26
+ [:user_name, String],
27
+ [:encrypted_password, String],
28
+ [:address, String],
29
+ [:port, Integer],
30
+ [:authentication, String],
31
+ [:enable_starttls_auto, Boolean]
32
+ ]
33
+
34
+ jsonb_attribute :content_security_policy, [
35
+ [:"default-src", String],
36
+ [:"img-src", String],
37
+ [:"media-src", String],
38
+ [:"script-src", String],
39
+ [:"style-src", String],
40
+ [:"frame-src", String],
41
+ [:"font-src", String],
42
+ [:"connect-src", String]
43
+ ]
44
+
45
+ attribute :password, String
46
+ attribute :file_upload_settings, FileUploadSettingsForm
47
+
48
+ OMNIATH_PROVIDERS_ATTRIBUTES = Decidim::OmniauthProvider.available.keys.map do |provider|
49
+ Rails.application.secrets.dig(:omniauth, provider).keys.map do |setting|
50
+ if setting == :enabled
51
+ ["omniauth_settings_#{provider}_enabled".to_sym, Boolean]
52
+ else
53
+ ["omniauth_settings_#{provider}_#{setting}".to_sym, String]
54
+ end
55
+ end
56
+ end.flatten(1)
57
+
58
+ jsonb_attribute :omniauth_settings, OMNIATH_PROVIDERS_ATTRIBUTES
59
+
60
+ validates :host, :users_registration_mode, presence: true
61
+ validate :validate_organization_uniqueness
62
+ validate :validate_secret_key_base_for_encryption
63
+ validates :users_registration_mode, inclusion: { in: Decidim::Organization.users_registration_modes }
64
+
65
+ def map_model(model)
66
+ self.default_locale = model.default_locale
67
+ self.secondary_hosts = model.secondary_hosts.join("\n")
68
+ self.omniauth_settings = (model.omniauth_settings || {}).transform_values do |v|
69
+ Decidim::OmniauthProvider.value_defined?(v) ? Decidim::AttributeEncryptor.decrypt(v) : v
70
+ end
71
+ self.file_upload_settings = FileUploadSettingsForm.from_model(model.file_upload_settings)
72
+ end
73
+
74
+ def clean_secondary_hosts
75
+ return unless secondary_hosts
76
+
77
+ secondary_hosts.split("\n").map(&:chomp).select(&:present?)
78
+ end
79
+
80
+ def clean_available_authorizations
81
+ return unless available_authorizations
82
+
83
+ available_authorizations.select(&:present?)
84
+ end
85
+
86
+ def password
87
+ encrypted_password.nil? ? super : Decidim::AttributeEncryptor.decrypt(encrypted_password)
88
+ end
89
+
90
+ def encrypted_smtp_settings
91
+ smtp_settings["from"] = set_from
92
+
93
+ encrypted = smtp_settings.merge(encrypted_password: Decidim::AttributeEncryptor.encrypt(password))
94
+ # if all are empty, nil is returned so it does not break ENV vars configuration
95
+ encrypted.values.all?(&:blank?) ? nil : encrypted
96
+ end
97
+
98
+ def set_from
99
+ return from_email if from_label.blank?
100
+
101
+ "#{from_label} <#{from_email}>"
102
+ end
103
+
104
+ def encrypted_omniauth_settings
105
+ encrypted = omniauth_settings.transform_values do |v|
106
+ Decidim::OmniauthProvider.value_defined?(v) ? Decidim::AttributeEncryptor.encrypt(v) : v
107
+ end
108
+ # if all are empty, nil is returned so it does not break ENV vars configuration
109
+ encrypted.values.all?(&:blank?) ? nil : encrypted
110
+ end
111
+
112
+ private
113
+
114
+ # We need a valid secret key base for encrypting the SMTP password with it
115
+ # It is also necessary for other things in Rails (like Cookies encryption)
116
+ def validate_secret_key_base_for_encryption
117
+ return if Rails.application.secrets.secret_key_base&.length == 128
118
+
119
+ errors.add(:password, I18n.t("activemodel.errors.models.organization.attributes.password.secret_key"))
120
+ end
121
+
122
+ def validate_organization_uniqueness
123
+ raise "#{self.class.name} is expected to implement #validate_organization_uniqueness"
124
+ end
125
+ end
126
+ end
127
+ end
@@ -6,10 +6,12 @@ module Decidim
6
6
  module System
7
7
  # A form object used to create organizations from the system dashboard.
8
8
  #
9
- class RegisterOrganizationForm < UpdateOrganizationForm
9
+ class RegisterOrganizationForm < BaseOrganizationForm
10
10
  include JsonbAttributes
11
11
  mimic :organization
12
12
 
13
+ attribute :name, String
14
+
13
15
  attribute :organization_admin_email, String
14
16
  attribute :organization_admin_name, String
15
17
  attribute :available_locales, Array
@@ -18,11 +20,29 @@ module Decidim
18
20
  attribute :users_registration_mode, String
19
21
  attribute :force_users_to_authenticate_before_access_organization, Boolean
20
22
 
21
- validates :organization_admin_email, :organization_admin_name, :name, :host, :reference_prefix, :users_registration_mode, presence: true
23
+ validates :organization_admin_email, :organization_admin_name, :name, :reference_prefix, presence: true
24
+ validates :name, presence: true
22
25
  validates :available_locales, presence: true
23
26
  validates :default_locale, presence: true
24
27
  validates :default_locale, inclusion: { in: :available_locales }
25
- validates :users_registration_mode, inclusion: { in: Decidim::Organization.users_registration_modes }
28
+
29
+ private
30
+
31
+ def validate_organization_uniqueness
32
+ base_query = Decidim::Organization.pluck(:name)
33
+
34
+ organization_names = []
35
+
36
+ base_query.each do |value|
37
+ organization_names += value.except("machine_translations").values
38
+ organization_names += value.fetch("machine_translations", {}).values
39
+ end
40
+
41
+ organization_names = organization_names.map(&:downcase)
42
+
43
+ errors.add(:name, :taken) if organization_names.include?(name&.downcase)
44
+ errors.add(:host, :taken) if Decidim::Organization.where(host:).where.not(id:).exists?
45
+ end
26
46
  end
27
47
  end
28
48
  end
@@ -6,106 +6,36 @@ module Decidim
6
6
  module System
7
7
  # A form object used to update organizations from the system dashboard.
8
8
  #
9
- class UpdateOrganizationForm < Form
10
- include TranslatableAttributes
11
- include JsonbAttributes
9
+ class UpdateOrganizationForm < BaseOrganizationForm
10
+ translatable_attribute :name, String
12
11
 
13
- mimic :organization
12
+ validate :validate_organization_name_presence
14
13
 
15
- attribute :name, String
16
- attribute :host, String
17
- attribute :secondary_hosts, String
18
- attribute :force_users_to_authenticate_before_access_organization, Boolean
19
- attribute :available_authorizations, Array[String]
20
- attribute :users_registration_mode, String
21
- jsonb_attribute :smtp_settings, [
22
- [:from, String],
23
- [:from_email, String],
24
- [:from_label, String],
25
- [:user_name, String],
26
- [:encrypted_password, String],
27
- [:address, String],
28
- [:port, Integer],
29
- [:authentication, String],
30
- [:enable_starttls_auto, Boolean]
31
- ]
32
-
33
- jsonb_attribute :content_security_policy, [
34
- [:"default-src", String],
35
- [:"img-src", String],
36
- [:"media-src", String],
37
- [:"script-src", String],
38
- [:"style-src", String],
39
- [:"frame-src", String],
40
- [:"font-src", String],
41
- [:"connect-src", String]
42
- ]
43
-
44
- attribute :password, String
45
- attribute :file_upload_settings, FileUploadSettingsForm
46
-
47
- OMNIATH_PROVIDERS_ATTRIBUTES = Decidim::OmniauthProvider.available.keys.map do |provider|
48
- Rails.application.secrets.dig(:omniauth, provider).keys.map do |setting|
49
- if setting == :enabled
50
- ["omniauth_settings_#{provider}_enabled".to_sym, Boolean]
51
- else
52
- ["omniauth_settings_#{provider}_#{setting}".to_sym, String]
53
- end
54
- end
55
- end.flatten(1)
56
-
57
- jsonb_attribute :omniauth_settings, OMNIATH_PROVIDERS_ATTRIBUTES
58
-
59
- validates :name, :host, :users_registration_mode, presence: true
60
- validate :validate_organization_uniqueness
61
- validates :users_registration_mode, inclusion: { in: Decidim::Organization.users_registration_modes }
62
-
63
- def map_model(model)
64
- self.secondary_hosts = model.secondary_hosts.join("\n")
65
- self.omniauth_settings = (model.omniauth_settings || {}).transform_values do |v|
66
- Decidim::OmniauthProvider.value_defined?(v) ? Decidim::AttributeEncryptor.decrypt(v) : v
67
- end
68
- self.file_upload_settings = FileUploadSettingsForm.from_model(model.file_upload_settings)
69
- end
70
-
71
- def clean_secondary_hosts
72
- return unless secondary_hosts
73
-
74
- secondary_hosts.split("\n").map(&:chomp).select(&:present?)
75
- end
76
-
77
- def clean_available_authorizations
78
- return unless available_authorizations
14
+ private
79
15
 
80
- available_authorizations.select(&:present?)
16
+ def validate_organization_name_presence
17
+ translated_attr = "name_#{current_organization.try(:default_locale) || Decidim.default_locale.to_s}".to_sym
18
+ errors.add(translated_attr, :blank) if send(translated_attr).blank?
81
19
  end
82
20
 
83
- def password
84
- encrypted_password.nil? ? super : Decidim::AttributeEncryptor.decrypt(encrypted_password)
85
- end
21
+ def validate_organization_uniqueness
22
+ base_query = persisted? ? Decidim::Organization.where.not(id:).all : Decidim::Organization.all
86
23
 
87
- def encrypted_smtp_settings
88
- smtp_settings["from"] = set_from
24
+ organization_names = []
89
25
 
90
- smtp_settings.merge(encrypted_password: Decidim::AttributeEncryptor.encrypt(password))
91
- end
26
+ base_query.pluck(:name).each do |value|
27
+ organization_names += value.except("machine_translations").values
28
+ organization_names += value.fetch("machine_translations", {}).values
29
+ end
92
30
 
93
- def set_from
94
- return from_email if from_label.blank?
31
+ organization_names = organization_names.map(&:downcase).compact_blank
95
32
 
96
- "#{from_label} <#{from_email}>"
97
- end
33
+ name.each do |language, value|
34
+ next if value.is_a?(Hash)
98
35
 
99
- def encrypted_omniauth_settings
100
- omniauth_settings.transform_values do |v|
101
- Decidim::OmniauthProvider.value_defined?(v) ? Decidim::AttributeEncryptor.encrypt(v) : v
36
+ errors.add("name_#{language}", :taken) if organization_names.include?(value.downcase)
102
37
  end
103
- end
104
38
 
105
- private
106
-
107
- def validate_organization_uniqueness
108
- errors.add(:name, :taken) if Decidim::Organization.where(name:).where.not(id:).exists?
109
39
  errors.add(:host, :taken) if Decidim::Organization.where(host:).where.not(id:).exists?
110
40
  end
111
41
  end
@@ -13,8 +13,8 @@ module Decidim
13
13
  private
14
14
 
15
15
  # Changes default Devise behaviour to use ActiveJob to send async emails.
16
- def send_devise_notification(notification, *args)
17
- devise_mailer.send(notification, self, *args).deliver_later
16
+ def send_devise_notification(notification, *)
17
+ devise_mailer.send(notification, self, *).deliver_later
18
18
  end
19
19
  end
20
20
  end
@@ -107,3 +107,60 @@ dl {
107
107
  .ts-dropdown {
108
108
  margin: 0;
109
109
  }
110
+
111
+ .tabs--lang {
112
+ @apply bg-transparent flex items-center gap-x-1;
113
+
114
+ li {
115
+ @apply p-0.5 rounded-t-sm text-secondary text-xs;
116
+
117
+ background-color: rgba(243, 244, 247, 1);
118
+
119
+ &.is-active,
120
+ &:hover {
121
+ @apply border-b border-secondary;
122
+ }
123
+
124
+ &:hover {
125
+ background-color: rgba(243, 244, 247, 1);
126
+ }
127
+ }
128
+
129
+ a {
130
+ @apply text-xs p-0;
131
+
132
+ &::before {
133
+ @apply content-[''] w-2 h-2 inline-block bg-white rounded-full mr-2 border;
134
+
135
+ border-color: rgba(116, 129, 144, 1);
136
+ }
137
+ }
138
+
139
+ .tabs-title > a[aria-selected="true"] {
140
+ @apply font-bold text-secondary;
141
+
142
+ background-color: rgba(243, 244, 247, 1);
143
+
144
+ &::before {
145
+ @apply border-white;
146
+
147
+ background-color: rgba(40, 167, 69, 1);
148
+ }
149
+ }
150
+
151
+ a.is-tab-error {
152
+ color: red;
153
+ }
154
+ }
155
+
156
+ .label--tabs {
157
+ @apply flex justify-between items-end;
158
+
159
+ label {
160
+ @apply inline-block;
161
+ }
162
+ }
163
+
164
+ .tabs-panel[aria-hidden="true"] {
165
+ @apply hidden;
166
+ }
@@ -4,6 +4,10 @@
4
4
  <h1 class="h1"><%= t("decidim.system.titles.dashboard") %></h1>
5
5
  <% end %>
6
6
 
7
+ <h2 class="h3"><%= t ".system_checks" %></h2>
8
+
9
+ <%= cell "decidim/system/system_checks", nil %>
10
+
7
11
  <h2 class="h3"><%= t ".current_organizations" %></h2>
8
12
 
9
13
  <%= link_to t("actions.new_organization", scope: "decidim.system"), [:new, :organization], class: "button button__sm md:button__lg button__primary" %>
@@ -2,7 +2,7 @@
2
2
  <%= form.text_field :name %>
3
3
  <%= form.text_field :redirect_uri %>
4
4
  <%= form.select :decidim_organization_id,
5
- Decidim::Organization.pluck(:name, :id),
5
+ Decidim::Organization.all.map { |o| [organization_name(o), o.id] },
6
6
  { include_blank: t(".select_organization") },
7
7
  { multiple: false } %>
8
8
  <%= form.text_field :organization_name %>