decidim-toggle 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.erb-lint.yml +2134 -0
- data/.github/workflows/website.yml +57 -0
- data/.gitignore +13 -0
- data/.gitlab-ci.yml +165 -0
- data/.node-version +1 -0
- data/.rspec +1 -0
- data/.rubocop.yml +2 -0
- data/.ruby-version +1 -0
- data/.simplecov +18 -0
- data/CONTRIBUTING.md +17 -0
- data/Gemfile +33 -0
- data/Gemfile.lock +843 -0
- data/LICENSE.md +661 -0
- data/README.md +90 -0
- data/Rakefile +38 -0
- data/app/commands/decidim/toggle/update_authorizations_command.rb +31 -0
- data/app/commands/decidim/toggle/update_emails_command.rb +30 -0
- data/app/commands/decidim/toggle/update_file_upload_settings_command.rb +31 -0
- data/app/commands/decidim/toggle/update_locale_command.rb +47 -0
- data/app/commands/decidim/toggle/update_module_config_command.rb +31 -0
- data/app/commands/decidim/toggle/update_name_command.rb +31 -0
- data/app/commands/decidim/toggle/update_omniauth_command.rb +30 -0
- data/app/commands/decidim/toggle/update_security_command.rb +31 -0
- data/app/controllers/decidim_toggle/system/settings_tab_controller.rb +64 -0
- data/app/forms/decidim/toggle/update_authorizations_form.rb +54 -0
- data/app/forms/decidim/toggle/update_emails_form.rb +28 -0
- data/app/forms/decidim/toggle/update_file_upload_settings_form.rb +26 -0
- data/app/forms/decidim/toggle/update_locale_form.rb +116 -0
- data/app/forms/decidim/toggle/update_name_form.rb +63 -0
- data/app/forms/decidim/toggle/update_omniauth_form.rb +37 -0
- data/app/forms/decidim/toggle/update_security_form.rb +65 -0
- data/app/helpers/decidim/toggle/javascript_config_helper.rb +11 -0
- data/app/helpers/decidim/toggle/system_settings_tab_helper.rb +59 -0
- data/app/models/decidim/toggle/organization_module_config.rb +15 -0
- data/app/overrides/add_toggle_javascript_admin.rb +11 -0
- data/app/overrides/add_toggle_javascript_public.rb +11 -0
- data/app/packs/entrypoints/decidim_toggle.js +3 -0
- data/app/packs/src/decidim/toggle/organization_settings_tabs.js +114 -0
- data/app/packs/stylesheets/decidim/toggle/organization_settings.scss +160 -0
- data/app/views/decidim/system/organizations/edit.html.erb +20 -0
- data/app/views/decidim_toggle/system/organizations/_default_form_tab.html.erb +5 -0
- data/app/views/decidim_toggle/system/organizations/_encryption_not_configured_callout.html.erb +6 -0
- data/app/views/decidim_toggle/system/organizations/_settings_tab_active_tab_field.html.erb +1 -0
- data/app/views/decidim_toggle/system/organizations/_settings_tab_submit.html.erb +4 -0
- data/app/views/decidim_toggle/system/organizations/_settings_tabs.html.erb +31 -0
- data/app/views/decidim_toggle/system/organizations/tabs/_authorizations_tab.html.erb +9 -0
- data/app/views/decidim_toggle/system/organizations/tabs/_emails_tab.html.erb +5 -0
- data/app/views/decidim_toggle/system/organizations/tabs/_file_upload_tab.html.erb +5 -0
- data/app/views/decidim_toggle/system/organizations/tabs/_language_tab.html.erb +35 -0
- data/app/views/decidim_toggle/system/organizations/tabs/_omniauth_tab.html.erb +5 -0
- data/app/views/decidim_toggle/system/organizations/tabs/_security_tab.html.erb +20 -0
- data/app/views/layouts/decidim/toggle/_javascript_config.html.erb +3 -0
- data/bin/check +10 -0
- data/bin/i18n-tasks +27 -0
- data/bin/postversion +14 -0
- data/config/assets.rb +8 -0
- data/config/locales/decidim_toggle_en.yml +58 -0
- data/crowdin.yml +15 -0
- data/db/migrate/20260321120000_create_decidim_toggle_organization_module_configs.rb +20 -0
- data/decidim-toggle.gemspec +35 -0
- data/docker-compose.yml +41 -0
- data/lib/decidim/toggle/engine.rb +62 -0
- data/lib/decidim/toggle/expose_attributes_to_js.rb +26 -0
- data/lib/decidim/toggle/expose_attributes_to_js_validator.rb +32 -0
- data/lib/decidim/toggle/gem_registry.rb +15 -0
- data/lib/decidim/toggle/informative_callouts.rb +76 -0
- data/lib/decidim/toggle/javascript_config.rb +87 -0
- data/lib/decidim/toggle/module_config.rb +64 -0
- data/lib/decidim/toggle/module_config_form.rb +41 -0
- data/lib/decidim/toggle/module_config_i18n.rb +44 -0
- data/lib/decidim/toggle/module_configuration_presenter.rb +55 -0
- data/lib/decidim/toggle/organization_settings_tabs.rb +69 -0
- data/lib/decidim/toggle/settings_form_builder.rb +200 -0
- data/lib/decidim/toggle/settings_tab_item.rb +37 -0
- data/lib/decidim/toggle/settings_tab_registry.rb +109 -0
- data/lib/decidim/toggle/settings_tabs.rb +56 -0
- data/lib/decidim/toggle/tab_form.rb +20 -0
- data/lib/decidim/toggle/version.rb +14 -0
- data/lib/decidim/toggle.rb +36 -0
- data/lib/tasks/decidim/toggle/toggle_upgrade.rake +13 -0
- data/lib/tasks/decidim/toggle/toggle_webpacker.rake +60 -0
- data/log/.gitignore +2 -0
- data/package.json +18 -0
- data/prettier.config.js +15 -0
- data/spec/commands/decidim/toggle/update_authorizations_command_spec.rb +41 -0
- data/spec/commands/decidim/toggle/update_emails_command_spec.rb +84 -0
- data/spec/commands/decidim/toggle/update_file_upload_settings_command_spec.rb +28 -0
- data/spec/commands/decidim/toggle/update_locale_command_spec.rb +53 -0
- data/spec/commands/decidim/toggle/update_module_config_command_spec.rb +38 -0
- data/spec/commands/decidim/toggle/update_name_command_spec.rb +49 -0
- data/spec/commands/decidim/toggle/update_omniauth_command_spec.rb +80 -0
- data/spec/commands/decidim/toggle/update_security_command_spec.rb +25 -0
- data/spec/decidim/toggle/settings_tab_item_spec.rb +34 -0
- data/spec/decidim/toggle/settings_tab_registry_spec.rb +66 -0
- data/spec/decidim/toggle/settings_tabs_spec.rb +60 -0
- data/spec/forms/concerns/decidim/toggle/informative_callouts_spec.rb +48 -0
- data/spec/forms/decidim/toggle/update_authorizations_form_spec.rb +40 -0
- data/spec/forms/decidim/toggle/update_emails_form_spec.rb +35 -0
- data/spec/forms/decidim/toggle/update_file_upload_settings_form_spec.rb +20 -0
- data/spec/forms/decidim/toggle/update_locale_form_spec.rb +64 -0
- data/spec/forms/decidim/toggle/update_name_form_spec.rb +57 -0
- data/spec/forms/decidim/toggle/update_omniauth_form_spec.rb +56 -0
- data/spec/forms/decidim/toggle/update_security_form_spec.rb +32 -0
- data/spec/helpers/decidim/toggle/system_settings_tab_helper_spec.rb +99 -0
- data/spec/lib/decidim/toggle/expose_attributes_to_js_spec.rb +31 -0
- data/spec/lib/decidim/toggle/expose_attributes_to_js_validator_spec.rb +30 -0
- data/spec/lib/decidim/toggle/gem_registry_spec.rb +30 -0
- data/spec/lib/decidim/toggle/javascript_config_spec.rb +169 -0
- data/spec/lib/decidim/toggle/module_config_form_spec.rb +45 -0
- data/spec/lib/decidim/toggle/module_config_spec.rb +74 -0
- data/spec/lib/decidim/toggle/module_configuration_presenter_spec.rb +53 -0
- data/spec/lib/decidim/toggle/settings_form_builder_spec.rb +115 -0
- data/spec/requests/decidim_toggle/system/settings_tab_spec.rb +144 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/support/decidim_factories.rb +3 -0
- data/spec/support/devise.rb +5 -0
- data/spec/system/decidim_toggle/javascript_config_spec.rb +56 -0
- data/website/.gitignore +4 -0
- data/website/docs/developer/_category_.json +8 -0
- data/website/docs/developer/code-of-conduct.md +99 -0
- data/website/docs/developer/contribute.md +50 -0
- data/website/docs/developer/deface-usage.md +37 -0
- data/website/docs/developer/documentation.md +58 -0
- data/website/docs/developer/error-handling.md +51 -0
- data/website/docs/developer/tab-registry.md +51 -0
- data/website/docs/developer/view-customization.md +49 -0
- data/website/docs/index.md +80 -0
- data/website/docs/integrate/_category_.json +8 -0
- data/website/docs/integrate/attributes.md +121 -0
- data/website/docs/integrate/customize-views.md +62 -0
- data/website/docs/integrate/index.md +38 -0
- data/website/docs/integrate/informative_callout.md +80 -0
- data/website/docs/integrate/javascript.md +84 -0
- data/website/docs/integrate/labels.md +91 -0
- data/website/docs/integrate/quickstart.md +77 -0
- data/website/docusaurus.config.ts +100 -0
- data/website/package.json +31 -0
- data/website/sidebars.ts +7 -0
- data/website/src/css/custom.css +37 -0
- data/website/static/img/logo.svg +1 -0
- data/website/static/img/schema_overview.png +0 -0
- data/website/static/img/screenshot_informative_callouts.png +0 -0
- data/website/static/img/screenshot_saved_flash.png +0 -0
- data/website/static/img/screenshots_locale_tab.png +0 -0
- data/website/static/img/screenshots_name_tab.png +0 -0
- data/website/static/img/screenshots_security_tab.png +0 -0
- data/website/tsconfig.json +6 -0
- data/website/yarn.lock +8336 -0
- data/yarn.lock +13 -0
- metadata +249 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
module Decidim
|
|
6
|
+
module Toggle
|
|
7
|
+
describe SettingsTabRegistry do
|
|
8
|
+
after do
|
|
9
|
+
described_class.destroy(:test_registry)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe ".register" do
|
|
13
|
+
it "creates registry and stores configuration blocks" do
|
|
14
|
+
described_class.register(:test_registry) { |_tabs| nil }
|
|
15
|
+
described_class.register(:test_registry) { |_tabs| nil }
|
|
16
|
+
reg = described_class.find(:test_registry)
|
|
17
|
+
expect(reg.configurations.length).to eq(2)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe ".find / .create" do
|
|
22
|
+
it "returns nil when missing" do
|
|
23
|
+
expect(described_class.find(:missing)).to be_nil
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "create stores a new registry" do
|
|
27
|
+
r = described_class.create(:test_registry)
|
|
28
|
+
expect(described_class.find(:test_registry)).to eq(r)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
describe "#register_form_tab and #form_tab" do
|
|
33
|
+
it "stores form/command mapping" do
|
|
34
|
+
reg = described_class.create(:test_registry)
|
|
35
|
+
reg.register_form_tab(:foo, String, Integer)
|
|
36
|
+
expect(reg.form_tab(:foo)).to eq(form: String, command: Integer)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "stores module_name for #form_tab_for_module" do
|
|
40
|
+
reg = described_class.create(:test_registry)
|
|
41
|
+
reg.register_form_tab(:foo, String, Integer, module_name: :decidim_geo)
|
|
42
|
+
expect(reg.form_tab_for_module(:decidim_geo)).to eq(
|
|
43
|
+
form: String,
|
|
44
|
+
command: Integer,
|
|
45
|
+
tab_identifier: :foo
|
|
46
|
+
)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "drops module mapping when the same tab is re-registered without module_name" do
|
|
50
|
+
reg = described_class.create(:test_registry)
|
|
51
|
+
reg.register_form_tab(:foo, String, Integer, module_name: :decidim_geo)
|
|
52
|
+
reg.register_form_tab(:foo, String, Integer)
|
|
53
|
+
expect(reg.form_tab_for_module(:decidim_geo)).to be_nil
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "raises when the same tab id is re-registered with a different form in test" do
|
|
57
|
+
reg = described_class.create(:test_registry)
|
|
58
|
+
reg.register_form_tab(:foo, String, Integer)
|
|
59
|
+
expect do
|
|
60
|
+
reg.register_form_tab(:foo, Array, Integer)
|
|
61
|
+
end.to raise_error(Decidim::Toggle::DuplicateTabRegistrationError, /:foo/)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
module Decidim
|
|
6
|
+
module Toggle
|
|
7
|
+
describe SettingsTabs do
|
|
8
|
+
after do
|
|
9
|
+
SettingsTabRegistry.destroy(:tabs_spec)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "raises when registry is missing" do
|
|
13
|
+
expect do
|
|
14
|
+
described_class.new(:tabs_spec).build_for(Object.new)
|
|
15
|
+
end.to raise_error(RuntimeError, /not registered/)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "builds items from registered blocks" do
|
|
19
|
+
SettingsTabRegistry.register(:tabs_spec) do |tabs|
|
|
20
|
+
tabs.add_tab :one, "One", form: String, command: Integer, position: 1, module_name: :demo_mod
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
ctx = Object.new
|
|
24
|
+
list = described_class.new(:tabs_spec)
|
|
25
|
+
list.build_for(ctx)
|
|
26
|
+
expect(list.items.size).to eq(1)
|
|
27
|
+
expect(list.items.first.identifier).to eq(:one)
|
|
28
|
+
expect(list.items.first.module_name).to eq(:demo_mod)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "add_tab supports form_layout_partial" do
|
|
32
|
+
SettingsTabRegistry.register(:tabs_spec) do |tabs|
|
|
33
|
+
tabs.add_tab :x,
|
|
34
|
+
"X",
|
|
35
|
+
form: String,
|
|
36
|
+
command: Integer,
|
|
37
|
+
form_layout_partial: "decidim/foo/tab",
|
|
38
|
+
position: 2
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
list = described_class.new(:tabs_spec)
|
|
42
|
+
list.build_for(Object.new)
|
|
43
|
+
expect(list.items.first.form_layout_partial).to eq("decidim/foo/tab")
|
|
44
|
+
expect(list.items.first.form_tab?).to be(true)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "remove_tab filters items" do
|
|
48
|
+
SettingsTabRegistry.register(:tabs_spec) do |tabs|
|
|
49
|
+
tabs.add_tab :a, "A", form: String, command: Integer
|
|
50
|
+
tabs.add_tab :b, "B", form: String, command: Integer
|
|
51
|
+
tabs.remove_tab(:a)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
list = described_class.new(:tabs_spec)
|
|
55
|
+
list.build_for(Object.new)
|
|
56
|
+
expect(list.items.map(&:identifier)).to eq([:b])
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
module Decidim
|
|
6
|
+
module Toggle
|
|
7
|
+
describe InformativeCallouts do
|
|
8
|
+
let(:form_class) do
|
|
9
|
+
Class.new(Decidim::Form) do
|
|
10
|
+
include InformativeCallouts
|
|
11
|
+
|
|
12
|
+
mimic :organization
|
|
13
|
+
|
|
14
|
+
info :always_visible_message
|
|
15
|
+
warning :conditional_message, if_predicate: ->(form) { form.show_warning? }
|
|
16
|
+
|
|
17
|
+
def always_visible_message
|
|
18
|
+
"Always visible"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def conditional_message
|
|
22
|
+
"Conditional"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def show_warning?
|
|
26
|
+
@show_warning
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
attr_writer :show_warning
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "registers informative entries on the form class" do
|
|
34
|
+
expect(form_class.informative_callouts.map(&:type)).to eq([:info, :warning])
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "filters entries with visible_informative_callouts" do
|
|
38
|
+
form = form_class.from_params({})
|
|
39
|
+
form.show_warning = false
|
|
40
|
+
|
|
41
|
+
expect(form.visible_informative_callouts.map { |entry| entry.message_for(form) }).to eq(["Always visible"])
|
|
42
|
+
|
|
43
|
+
form.show_warning = true
|
|
44
|
+
expect(form.visible_informative_callouts.map { |entry| entry.message_for(form) }).to eq(["Always visible", "Conditional"])
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
module Decidim
|
|
6
|
+
module Toggle
|
|
7
|
+
describe UpdateAuthorizationsForm do
|
|
8
|
+
let(:organization) { create(:organization, available_authorizations: []) }
|
|
9
|
+
|
|
10
|
+
describe ".from_model" do
|
|
11
|
+
it "loads workflow names as strings" do
|
|
12
|
+
org = create(:organization, available_authorizations: %w(dummy_authorization_handler))
|
|
13
|
+
|
|
14
|
+
form = described_class.from_model(org)
|
|
15
|
+
|
|
16
|
+
expect(form.available_authorizations).to eq(%w(dummy_authorization_handler))
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe ".from_params" do
|
|
21
|
+
it "defaults missing available_authorizations to an empty array" do
|
|
22
|
+
form = described_class.from_params(organization: {}).with_context(current_organization: organization)
|
|
23
|
+
|
|
24
|
+
expect(form.available_authorizations).to eq([])
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe "validations" do
|
|
29
|
+
it "rejects authorization names that are not registered workflows" do
|
|
30
|
+
form = described_class.from_params(
|
|
31
|
+
organization: { available_authorizations: %w(unknown_handler) }
|
|
32
|
+
).with_context(current_organization: organization)
|
|
33
|
+
|
|
34
|
+
expect(form).not_to be_valid
|
|
35
|
+
expect(form.errors[:available_authorizations]).to be_present
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
module Decidim
|
|
6
|
+
module Toggle
|
|
7
|
+
describe UpdateEmailsForm do
|
|
8
|
+
let(:organization) { create(:organization) }
|
|
9
|
+
|
|
10
|
+
it "exposes host and users_registration_mode from the organization" do
|
|
11
|
+
form = described_class.from_model(organization)
|
|
12
|
+
|
|
13
|
+
expect(form.host).to eq(organization.host)
|
|
14
|
+
expect(form.users_registration_mode).to eq(organization.users_registration_mode)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "extracts host/users_registration_mode from params[:organization]" do
|
|
18
|
+
organization.update!(host: "current-host.example.org")
|
|
19
|
+
|
|
20
|
+
params_host = "params-host.example.org"
|
|
21
|
+
params = {
|
|
22
|
+
organization: {
|
|
23
|
+
host: params_host,
|
|
24
|
+
users_registration_mode: organization.users_registration_mode
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
form = described_class.from_params(params).with_context(current_organization: organization)
|
|
29
|
+
|
|
30
|
+
expect(form.host).to eq(params_host)
|
|
31
|
+
expect(form.users_registration_mode).to eq(organization.users_registration_mode)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
module Decidim
|
|
6
|
+
module Toggle
|
|
7
|
+
describe UpdateFileUploadSettingsForm do
|
|
8
|
+
let(:organization) { create(:organization) }
|
|
9
|
+
|
|
10
|
+
describe ".from_model" do
|
|
11
|
+
it "wraps the organization file_upload_settings for editing" do
|
|
12
|
+
form = described_class.from_model(organization)
|
|
13
|
+
|
|
14
|
+
expect(form.file_upload_settings).to be_a(Decidim::System::FileUploadSettingsForm)
|
|
15
|
+
expect(form.file_upload_settings.maximum_file_size).to be_present
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
module Decidim
|
|
6
|
+
module Toggle
|
|
7
|
+
describe UpdateLocaleForm do
|
|
8
|
+
let(:organization) { create(:organization) }
|
|
9
|
+
|
|
10
|
+
describe ".from_model" do
|
|
11
|
+
it "normalizes available_locales and default_locale to strings" do
|
|
12
|
+
org = Struct.new(:available_locales, :default_locale, :enable_machine_translations, :machine_translation_display_priority).new(
|
|
13
|
+
[:en, :ca, :es], :en, false, "original"
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
form = described_class.from_model(org)
|
|
17
|
+
|
|
18
|
+
expect(form.available_locales).to eq(%w(en ca es))
|
|
19
|
+
expect(form.default_locale).to eq("en")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "loads locales from the Organization record when the source only has id (e.g. system UpdateOrganizationForm)" do
|
|
23
|
+
org = create(:organization, available_locales: %w(en ca), default_locale: "ca")
|
|
24
|
+
form_like = Struct.new(:id, :enable_machine_translations, :machine_translation_display_priority).new(
|
|
25
|
+
org.id, false, "original"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
form = described_class.from_model(form_like)
|
|
29
|
+
|
|
30
|
+
expect(form.available_locales).to eq(%w(en ca))
|
|
31
|
+
expect(form.default_locale).to eq("ca")
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
describe ".from_params with hash available_locales" do
|
|
36
|
+
it "maps checked keys to array" do
|
|
37
|
+
form = described_class.from_params(
|
|
38
|
+
organization: { available_locales: { "en" => "1", "ca" => "1" }, default_locale: "en" }
|
|
39
|
+
).with_context(current_organization: organization)
|
|
40
|
+
|
|
41
|
+
expect(form.available_locales).to include("en", "ca")
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
describe "validations" do
|
|
46
|
+
it "rejects default_locale not in available_locales" do
|
|
47
|
+
form = described_class.from_params(
|
|
48
|
+
organization: { available_locales: %w(en), default_locale: "ca" }
|
|
49
|
+
).with_context(current_organization: organization)
|
|
50
|
+
|
|
51
|
+
expect(form).not_to be_valid
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "rejects available_locales outside I18n" do
|
|
55
|
+
form = described_class.from_params(
|
|
56
|
+
organization: { available_locales: %w(zz), default_locale: "zz" }
|
|
57
|
+
).with_context(current_organization: organization)
|
|
58
|
+
|
|
59
|
+
expect(form).not_to be_valid
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
module Decidim
|
|
6
|
+
module Toggle
|
|
7
|
+
describe UpdateNameForm do
|
|
8
|
+
let(:organization) { create(:organization) }
|
|
9
|
+
|
|
10
|
+
describe ".from_params with name_* keys" do
|
|
11
|
+
it "maps name_en into nested name hash" do
|
|
12
|
+
form = described_class.from_params(
|
|
13
|
+
organization: { "name_en" => "Hello", :host => "x.lvh.me" }
|
|
14
|
+
).with_context(current_organization: organization)
|
|
15
|
+
|
|
16
|
+
expect(form.name["en"]).to eq("Hello")
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe ".from_model" do
|
|
21
|
+
it "joins array secondary hosts with newlines" do
|
|
22
|
+
organization.update!(secondary_hosts: %w(a.example.org b.example.org))
|
|
23
|
+
|
|
24
|
+
form = described_class.from_model(organization)
|
|
25
|
+
|
|
26
|
+
expect(form.secondary_hosts).to eq("a.example.org\nb.example.org")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "preserves string secondary hosts" do
|
|
30
|
+
allow(organization).to receive(:secondary_hosts).and_return("legacy.example.org")
|
|
31
|
+
|
|
32
|
+
form = described_class.from_model(organization)
|
|
33
|
+
|
|
34
|
+
expect(form.secondary_hosts).to eq("legacy.example.org")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "defaults secondary hosts to an empty string for unexpected values" do
|
|
38
|
+
allow(organization).to receive(:secondary_hosts).and_return(nil)
|
|
39
|
+
|
|
40
|
+
form = described_class.from_model(organization)
|
|
41
|
+
|
|
42
|
+
expect(form.secondary_hosts).to eq("")
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
describe "#clean_secondary_hosts" do
|
|
47
|
+
it "splits lines and drops blanks" do
|
|
48
|
+
form = described_class.from_params(
|
|
49
|
+
organization: { host: organization.host, secondary_hosts: "a.com\n\nb.com" }
|
|
50
|
+
).with_context(current_organization: organization)
|
|
51
|
+
|
|
52
|
+
expect(form.clean_secondary_hosts).to eq(%w(a.com b.com))
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
module Decidim
|
|
6
|
+
module Toggle
|
|
7
|
+
describe UpdateOmniauthForm do
|
|
8
|
+
let(:organization) { create(:organization) }
|
|
9
|
+
|
|
10
|
+
it "exposes host and users_registration_mode from the organization" do
|
|
11
|
+
form = described_class.from_model(organization)
|
|
12
|
+
|
|
13
|
+
expect(form.host).to eq(organization.host)
|
|
14
|
+
expect(form.users_registration_mode).to eq(organization.users_registration_mode)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "builds omniauth encrypted settings from params[:organization]" do
|
|
18
|
+
provider = Decidim::OmniauthProvider.available.keys.first
|
|
19
|
+
omniauth_secrets = Rails.application.secrets.dig(:omniauth, provider) || {}
|
|
20
|
+
|
|
21
|
+
# Pick the first setting other than :enabled. For `developer` this is typically :icon.
|
|
22
|
+
setting_key = (omniauth_secrets.keys.map(&:to_sym) - [:enabled]).first
|
|
23
|
+
skip "No omniauth provider settings found in secrets" if provider.blank? || setting_key.blank?
|
|
24
|
+
|
|
25
|
+
params = {
|
|
26
|
+
organization: {
|
|
27
|
+
:host => organization.host,
|
|
28
|
+
:users_registration_mode => organization.users_registration_mode,
|
|
29
|
+
"omniauth_settings_#{provider}_enabled" => true,
|
|
30
|
+
"omniauth_settings_#{provider}_#{setting_key}" => "foo-#{setting_key}"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
form = described_class.from_params(params).with_context(current_organization: organization)
|
|
35
|
+
|
|
36
|
+
expect(form.omniauth_settings).to include(
|
|
37
|
+
"omniauth_settings_#{provider}_enabled" => true,
|
|
38
|
+
"omniauth_settings_#{provider}_#{setting_key}" => "foo-#{setting_key}"
|
|
39
|
+
)
|
|
40
|
+
expect(form.encrypted_omniauth_settings).to include("omniauth_settings_#{provider}_#{setting_key}")
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "registers space page info callout only when decidim-space_page is in the bundle" do
|
|
44
|
+
form = described_class.from_params({})
|
|
45
|
+
entries = form.visible_informative_callouts
|
|
46
|
+
|
|
47
|
+
if Decidim::Toggle.gem_present?("decidim-space_page")
|
|
48
|
+
expect(entries.map(&:type)).to eq([:info])
|
|
49
|
+
expect(entries.first.message_for(form)).to include("decidim space page")
|
|
50
|
+
else
|
|
51
|
+
expect(entries).to be_empty
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
module Decidim
|
|
6
|
+
module Toggle
|
|
7
|
+
describe UpdateSecurityForm do
|
|
8
|
+
let(:organization) { create(:organization) }
|
|
9
|
+
|
|
10
|
+
describe "#content_security_policy" do
|
|
11
|
+
it "compacts blank directive values" do
|
|
12
|
+
form = described_class.from_model(organization)
|
|
13
|
+
form.send(:"default-src=", "'self'")
|
|
14
|
+
form.send(:"img-src=", nil)
|
|
15
|
+
|
|
16
|
+
csp = form.content_security_policy
|
|
17
|
+
expect(csp["default-src"]).to eq("'self'")
|
|
18
|
+
expect(csp).not_to have_key("img-src")
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe "validations" do
|
|
23
|
+
it "rejects invalid users_registration_mode" do
|
|
24
|
+
form = described_class.from_model(organization)
|
|
25
|
+
form.users_registration_mode = "invalid_mode"
|
|
26
|
+
|
|
27
|
+
expect(form).not_to be_valid
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
module Decidim
|
|
6
|
+
module Toggle
|
|
7
|
+
describe SystemSettingsTabHelper do
|
|
8
|
+
describe "#decidim_toggle_update_settings_tab_organization_path" do
|
|
9
|
+
let(:helper_host) do
|
|
10
|
+
Class.new do
|
|
11
|
+
include Decidim::Toggle::SystemSettingsTabHelper
|
|
12
|
+
end.new
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "prefixes engine path with /decidim_toggle once" do
|
|
16
|
+
org = create(:organization)
|
|
17
|
+
path = helper_host.decidim_toggle_update_settings_tab_organization_path(org, tab_id: "name")
|
|
18
|
+
expect(path).to start_with("/decidim_toggle")
|
|
19
|
+
expect(path).to include("settings_tab")
|
|
20
|
+
expect(path).not_to include("/decidim_toggle/decidim_toggle")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe "#decidim_toggle_settings_tab_form" do
|
|
25
|
+
let(:helper_host) do
|
|
26
|
+
Class.new do
|
|
27
|
+
include Decidim::Toggle::SystemSettingsTabHelper
|
|
28
|
+
include ActionView::Helpers::FormHelper
|
|
29
|
+
include ActionView::Helpers::FormTagHelper
|
|
30
|
+
include ActionView::Helpers::OutputSafetyHelper
|
|
31
|
+
include ActionView::Context
|
|
32
|
+
|
|
33
|
+
def flash
|
|
34
|
+
@flash ||= {}
|
|
35
|
+
end
|
|
36
|
+
end.new
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
let(:tab) do
|
|
40
|
+
SettingsTabItem.new(
|
|
41
|
+
:security,
|
|
42
|
+
"Security",
|
|
43
|
+
form_class: UpdateSecurityForm,
|
|
44
|
+
command_class: UpdateSecurityCommand
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
let(:form) { UpdateSecurityForm.from_params(organization: { host: "example.org", users_registration_mode: "enabled" }) }
|
|
48
|
+
let(:organization) { instance_double(Decidim::Organization, id: 1) }
|
|
49
|
+
|
|
50
|
+
before do
|
|
51
|
+
allow(UpdateSecurityForm).to receive(:from_model).with(organization).and_return(form)
|
|
52
|
+
allow(helper_host).to receive(:render).and_return("".html_safe)
|
|
53
|
+
allow(helper_host).to receive(:decidim_toggle_update_settings_tab_organization_path)
|
|
54
|
+
.with(organization, tab_id: :security)
|
|
55
|
+
.and_return("/decidim_toggle/system/organizations/1/settings_tab/security")
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "renders form shell markup" do
|
|
59
|
+
html = helper_host.decidim_toggle_settings_tab_form(organization, tab) { |_tf| "body" }
|
|
60
|
+
expect(html).to include("settings_tab_form_security")
|
|
61
|
+
expect(html).to include('action="/decidim_toggle/system/organizations/1/settings_tab/security"')
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
describe "#encryption_configured?" do
|
|
66
|
+
let(:helper_host) do
|
|
67
|
+
Class.new do
|
|
68
|
+
include Decidim::Toggle::SystemSettingsTabHelper
|
|
69
|
+
end.new
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
around do |example|
|
|
73
|
+
Decidim::AttributeEncryptor.remove_instance_variable(:@cryptor) if Decidim::AttributeEncryptor.instance_variable_defined?(:@cryptor)
|
|
74
|
+
example.run
|
|
75
|
+
Decidim::AttributeEncryptor.remove_instance_variable(:@cryptor) if Decidim::AttributeEncryptor.instance_variable_defined?(:@cryptor)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it "returns true when encryption round-trips" do
|
|
79
|
+
allow(Rails.application).to receive(:secret_key_base).and_return(SecureRandom.hex(64))
|
|
80
|
+
|
|
81
|
+
expect(helper_host.encryption_configured?).to be(true)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it "returns false when secret_key_base is missing" do
|
|
85
|
+
allow(Rails.application).to receive(:secret_key_base).and_return(nil)
|
|
86
|
+
|
|
87
|
+
expect(helper_host.encryption_configured?).to be(false)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it "returns false when encryption fails" do
|
|
91
|
+
allow(Rails.application).to receive(:secret_key_base).and_return("too-short")
|
|
92
|
+
allow(Decidim::AttributeEncryptor).to receive(:encrypt).and_raise(ArgumentError)
|
|
93
|
+
|
|
94
|
+
expect(helper_host.encryption_configured?).to be(false)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
module Decidim
|
|
6
|
+
module Toggle
|
|
7
|
+
describe ExposeAttributesToJs do
|
|
8
|
+
let(:form_class) do
|
|
9
|
+
Class.new(Decidim::Form) do
|
|
10
|
+
include ExposeAttributesToJs
|
|
11
|
+
|
|
12
|
+
mimic :organization
|
|
13
|
+
attribute :enabled, :boolean
|
|
14
|
+
attribute :search_bar, :boolean
|
|
15
|
+
attribute :secret, :string
|
|
16
|
+
|
|
17
|
+
expose_to_javascript :enabled, :search_bar
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "registers attributes via expose_to_javascript" do
|
|
22
|
+
expect(form_class.javascript_exposed_attribute_names).to contain_exactly("enabled", "search_bar")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "deduplicates exposed attribute names" do
|
|
26
|
+
form_class.expose_to_javascript(:enabled)
|
|
27
|
+
expect(form_class.javascript_exposed_attribute_names).to contain_exactly("enabled", "search_bar")
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
module Decidim
|
|
6
|
+
module Toggle
|
|
7
|
+
describe ExposeAttributesToJsValidator do
|
|
8
|
+
it "warns when an exposed attribute is not declared on the form" do
|
|
9
|
+
form_class = Class.new(Decidim::Form) do
|
|
10
|
+
include ExposeAttributesToJs
|
|
11
|
+
|
|
12
|
+
mimic :organization
|
|
13
|
+
attribute :enabled, :boolean
|
|
14
|
+
|
|
15
|
+
expose_to_javascript :missing_flag
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
expect(Rails.logger).to receive(:warn).with(
|
|
19
|
+
/decidim-toggle.*missing_flag/
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
described_class.validate_form!(form_class)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "validates every registered organization settings form without error" do
|
|
26
|
+
expect { described_class.validate! }.not_to raise_error
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
module Decidim
|
|
6
|
+
module Toggle
|
|
7
|
+
describe GemRegistry do
|
|
8
|
+
describe ".present?" do
|
|
9
|
+
it "returns true when the gem is in the bundle" do
|
|
10
|
+
expect(described_class.present?("decidim-core")).to be(true)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "returns false when the gem is not in the bundle" do
|
|
14
|
+
expect(described_class.present?("decidim-space_page")).to be(false)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "returns false for blank names" do
|
|
18
|
+
expect(described_class.present?("")).to be(false)
|
|
19
|
+
expect(described_class.present?(nil)).to be(false)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe "Decidim::Toggle.gem_present?" do
|
|
25
|
+
it "returns true for gems in the bundle" do
|
|
26
|
+
expect(Decidim::Toggle.gem_present?("decidim-core")).to be(true)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|