decidim-system 0.28.2 → 0.29.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -3
- data/app/cells/decidim/system/system_checks/show.erb +13 -0
- data/app/cells/decidim/system/system_checks_cell.rb +48 -0
- data/app/commands/decidim/system/create_default_content_blocks.rb +0 -3
- data/app/commands/decidim/system/{populate_help.rb → create_default_help_pages.rb} +14 -7
- data/app/commands/decidim/system/create_default_pages.rb +0 -1
- data/app/commands/decidim/system/{register_organization.rb → create_organization.rb} +5 -7
- data/app/controllers/decidim/system/dashboard_controller.rb +2 -0
- data/app/controllers/decidim/system/organizations_controller.rb +2 -1
- data/app/forms/decidim/system/base_organization_form.rb +127 -0
- data/app/forms/decidim/system/register_organization_form.rb +23 -3
- data/app/forms/decidim/system/update_organization_form.rb +18 -103
- data/app/models/decidim/system/admin.rb +2 -2
- data/app/packs/stylesheets/decidim/system/application.scss +57 -0
- data/app/views/decidim/system/dashboard/show.html.erb +4 -0
- data/app/views/decidim/system/oauth_applications/_form.html.erb +1 -1
- data/app/views/decidim/system/oauth_applications/index.html.erb +2 -2
- data/app/views/decidim/system/organizations/edit.html.erb +4 -2
- data/app/views/decidim/system/shared/_admins_list.html.erb +2 -2
- data/app/views/decidim/system/shared/_organizations_list.html.erb +3 -3
- data/app/views/layouts/decidim/system/_js_configuration.html.erb +1 -1
- data/app/views/layouts/decidim/system/login.html.erb +1 -1
- data/config/locales/ar.yml +0 -1
- data/config/locales/bg.yml +9 -3
- data/config/locales/ca.yml +12 -3
- data/config/locales/cs.yml +5 -3
- data/config/locales/de.yml +12 -3
- data/config/locales/el.yml +0 -2
- data/config/locales/en.yml +12 -3
- data/config/locales/es-MX.yml +12 -3
- data/config/locales/es-PY.yml +12 -3
- data/config/locales/es.yml +12 -3
- data/config/locales/eu.yml +12 -3
- data/config/locales/fi-plain.yml +12 -3
- data/config/locales/fi.yml +12 -3
- data/config/locales/fr-CA.yml +12 -3
- data/config/locales/fr.yml +12 -3
- data/config/locales/gl.yml +0 -1
- data/config/locales/hu.yml +0 -2
- data/config/locales/id-ID.yml +0 -1
- data/config/locales/it.yml +0 -1
- data/config/locales/ja.yml +12 -3
- data/config/locales/lt.yml +0 -2
- data/config/locales/lv.yml +0 -1
- data/config/locales/nl.yml +0 -1
- data/config/locales/no.yml +0 -1
- data/config/locales/pl.yml +11 -2
- data/config/locales/pt-BR.yml +0 -2
- data/config/locales/pt.yml +0 -1
- data/config/locales/ro-RO.yml +0 -1
- data/config/locales/ru.yml +0 -1
- data/config/locales/sk.yml +0 -1
- data/config/locales/sv.yml +0 -1
- data/config/locales/tr-TR.yml +0 -1
- data/config/locales/zh-CN.yml +0 -1
- data/config/locales/zh-TW.yml +0 -2
- data/db/seeds.rb +1 -1
- data/decidim-system.gemspec +1 -1
- data/lib/decidim/system/engine.rb +4 -0
- data/lib/decidim/system/version.rb +1 -1
- data/lib/tasks/decidim_system.rake +1 -1
- metadata +14 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 277b3e36b9c0b77055703a370f9c81a59c9e33e08c4f2b63c8b79b01e4ee26d7
|
4
|
+
data.tar.gz: aa8b44e92b184232ac44516239eeed136f060dd32ea8af5c2e3fe691669c9f49
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 64b7713b089990c91a8ee8c9bb74ccabb1e7413cfaf99492e7d04f8bd0c838c77446e21233df40ebfe1904decedd56d8df4a73e58a448635dc01431e84e702ae
|
7
|
+
data.tar.gz: 9aab23d7e0889ac7946c3884bf431f275692f652527c77c04f2ed2459bfbb56e4c6da8c0542c669304aec5ab79eaaf06a9844b02a2c0d96e4553b69ec0c71225
|
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
|
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,
|
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
|
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
|
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:
|
21
|
-
description: multi_translation("decidim.help.main_topic.description", organization:
|
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:
|
29
|
-
content: multi_translation("decidim.help.main_topic.default_page.content", organization:
|
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, **
|
53
|
-
Decidim::TranslationsHelper.multi_translation(key, @organization.available_locales, **
|
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
|
|
@@ -8,7 +8,8 @@ module Decidim
|
|
8
8
|
# A command with all the business logic when creating a new organization in
|
9
9
|
# the system. It creates the organization and invites the admin to the
|
10
10
|
# system.
|
11
|
-
|
11
|
+
|
12
|
+
class CreateOrganization < Decidim::Command
|
12
13
|
# Public: Initializes the command.
|
13
14
|
#
|
14
15
|
# form - A form object with the params.
|
@@ -31,7 +32,7 @@ module Decidim
|
|
31
32
|
transaction do
|
32
33
|
@organization = create_organization
|
33
34
|
CreateDefaultPages.call(@organization)
|
34
|
-
|
35
|
+
CreateDefaultHelpPages.call(@organization)
|
35
36
|
CreateDefaultContentBlocks.call(@organization)
|
36
37
|
invite_form = invite_user_form(@organization)
|
37
38
|
raise InvitationFailedError if invite_form.invalid?
|
@@ -52,13 +53,13 @@ module Decidim
|
|
52
53
|
|
53
54
|
def create_organization
|
54
55
|
Decidim::Organization.create!(
|
55
|
-
name: form.name,
|
56
|
+
name: { form.default_locale => form.name },
|
56
57
|
host: form.host,
|
57
58
|
secondary_hosts: form.clean_secondary_hosts,
|
58
59
|
reference_prefix: form.reference_prefix,
|
59
60
|
available_locales: form.available_locales,
|
60
61
|
available_authorizations: form.clean_available_authorizations,
|
61
|
-
|
62
|
+
external_domain_allowlist: ["decidim.org", "github.com"],
|
62
63
|
users_registration_mode: form.users_registration_mode,
|
63
64
|
force_users_to_authenticate_before_access_organization: form.force_users_to_authenticate_before_access_organization,
|
64
65
|
badges_enabled: true,
|
@@ -75,10 +76,7 @@ module Decidim
|
|
75
76
|
|
76
77
|
def default_colors
|
77
78
|
{
|
78
|
-
alert: "#ec5840",
|
79
79
|
primary: "#53bf40",
|
80
|
-
success: "#57d685",
|
81
|
-
warning: "#ffae00",
|
82
80
|
tertiary: "#bf4053",
|
83
81
|
secondary: "#4053bf"
|
84
82
|
}
|
@@ -16,7 +16,7 @@ module Decidim
|
|
16
16
|
def create
|
17
17
|
@form = form(RegisterOrganizationForm).from_params(params)
|
18
18
|
|
19
|
-
|
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
|
@@ -44,6 +44,7 @@ module Decidim
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def update
|
47
|
+
@organization = Organization.find(params[:id])
|
47
48
|
@form = form(UpdateOrganizationForm).from_params(params)
|
48
49
|
|
49
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 <
|
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, :
|
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
|
-
|
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,123 +6,38 @@ module Decidim
|
|
6
6
|
module System
|
7
7
|
# A form object used to update organizations from the system dashboard.
|
8
8
|
#
|
9
|
-
class UpdateOrganizationForm <
|
10
|
-
|
11
|
-
include JsonbAttributes
|
9
|
+
class UpdateOrganizationForm < BaseOrganizationForm
|
10
|
+
translatable_attribute :name, String
|
12
11
|
|
13
|
-
|
12
|
+
validate :validate_organization_name_presence
|
14
13
|
|
15
|
-
|
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
|
-
validate :validate_secret_key_base_for_encryption
|
62
|
-
validates :users_registration_mode, inclusion: { in: Decidim::Organization.users_registration_modes }
|
63
|
-
|
64
|
-
def map_model(model)
|
65
|
-
self.secondary_hosts = model.secondary_hosts.join("\n")
|
66
|
-
self.omniauth_settings = (model.omniauth_settings || {}).transform_values do |v|
|
67
|
-
Decidim::OmniauthProvider.value_defined?(v) ? Decidim::AttributeEncryptor.decrypt(v) : v
|
68
|
-
end
|
69
|
-
self.file_upload_settings = FileUploadSettingsForm.from_model(model.file_upload_settings)
|
70
|
-
end
|
71
|
-
|
72
|
-
def clean_secondary_hosts
|
73
|
-
return unless secondary_hosts
|
74
|
-
|
75
|
-
secondary_hosts.split("\n").map(&:chomp).select(&:present?)
|
76
|
-
end
|
77
|
-
|
78
|
-
def clean_available_authorizations
|
79
|
-
return unless available_authorizations
|
80
|
-
|
81
|
-
available_authorizations.select(&:present?)
|
82
|
-
end
|
14
|
+
private
|
83
15
|
|
84
|
-
def
|
85
|
-
|
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?
|
86
19
|
end
|
87
20
|
|
88
|
-
def
|
89
|
-
|
21
|
+
def validate_organization_uniqueness
|
22
|
+
base_query = persisted? ? Decidim::Organization.where.not(id:).all : Decidim::Organization.all
|
90
23
|
|
91
|
-
|
24
|
+
organization_names = []
|
92
25
|
|
93
|
-
|
94
|
-
|
95
|
-
|
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
|
96
30
|
|
97
|
-
|
98
|
-
return from_email if from_label.blank?
|
31
|
+
organization_names = organization_names.map(&:downcase).compact_blank
|
99
32
|
|
100
|
-
|
101
|
-
|
33
|
+
name.each do |language, value|
|
34
|
+
next if value.is_a?(Hash)
|
102
35
|
|
103
|
-
|
104
|
-
encrypted = omniauth_settings.transform_values do |v|
|
105
|
-
Decidim::OmniauthProvider.value_defined?(v) ? Decidim::AttributeEncryptor.encrypt(v) : v
|
36
|
+
errors.add("name_#{language}", :taken) if organization_names.include?(value.downcase)
|
106
37
|
end
|
107
38
|
|
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
|
-
def validate_organization_uniqueness
|
115
|
-
errors.add(:name, :taken) if Decidim::Organization.where(name:).where.not(id:).exists?
|
116
39
|
errors.add(:host, :taken) if Decidim::Organization.where(host:).where.not(id:).exists?
|
117
40
|
end
|
118
|
-
|
119
|
-
# We need a valid secret key base for encrypting the SMTP password with it
|
120
|
-
# It is also necessary for other things in Rails (like Cookies encryption)
|
121
|
-
def validate_secret_key_base_for_encryption
|
122
|
-
return if Rails.application.secrets.secret_key_base&.length == 128
|
123
|
-
|
124
|
-
errors.add(:password, I18n.t("activemodel.errors.models.organization.attributes.password.secret_key"))
|
125
|
-
end
|
126
41
|
end
|
127
42
|
end
|
128
43
|
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, *
|
17
|
-
devise_mailer.send(notification, self, *
|
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.
|
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 %>
|
@@ -13,7 +13,7 @@
|
|
13
13
|
<th><%= t("models.oauth_application.fields.name", scope: "decidim.system") %></th>
|
14
14
|
<th><%= t("models.oauth_application.fields.organization_name", scope: "decidim.system") %></th>
|
15
15
|
<th><%= t("models.oauth_application.fields.created_at", scope: "decidim.system") %></th>
|
16
|
-
<th
|
16
|
+
<th><%= t("actions.title", scope: "decidim.system") %></th>
|
17
17
|
</tr>
|
18
18
|
</thead>
|
19
19
|
<tbody>
|
@@ -31,7 +31,7 @@
|
|
31
31
|
<td>
|
32
32
|
<%= l oauth_application.created_at, format: :short %>
|
33
33
|
</td>
|
34
|
-
<td
|
34
|
+
<td>
|
35
35
|
<%= link_to t("actions.edit", scope: "decidim.system"), [:edit, oauth_application] %>
|
36
36
|
<%= link_to t("actions.destroy", scope: "decidim.system"), oauth_application, method: :delete, data: { confirm: t(".confirm_delete") } %>
|
37
37
|
</td>
|