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
data/README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Decidim Toggle
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="website/static/img/logo.svg" alt="Decidim Toggle" width="120" />
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
[](https://git.octree.ch/decidim/vocacity/decidim-modules/decidim-toggle/-/commits/main)
|
|
8
|
+
[](LICENSE.md)
|
|
9
|
+
[](https://octree-gva.github.io/decidim-toggle/)
|
|
10
|
+
|
|
11
|
+
Register organization settings tabs for Decidim modules—one form, one command, one read API per gem.
|
|
12
|
+
|
|
13
|
+
## Contents
|
|
14
|
+
|
|
15
|
+
- [Quick start](#quick-start)
|
|
16
|
+
- [Host app install](#host-app-install)
|
|
17
|
+
- [Documentation](#documentation)
|
|
18
|
+
- [Development](#development-this-gem)
|
|
19
|
+
- [Support](#support)
|
|
20
|
+
- [Contributing](#contributing)
|
|
21
|
+
- [License](#license)
|
|
22
|
+
|
|
23
|
+
## Quick start
|
|
24
|
+
|
|
25
|
+
Add a settings tab in three steps:
|
|
26
|
+
|
|
27
|
+
1. **Form** — include `Decidim::Toggle::ModuleConfigForm`, set `module_config_name`, declare attributes.
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
module MyModule
|
|
31
|
+
class AdminConfigForm < Decidim::Form
|
|
32
|
+
include Decidim::Toggle::ModuleConfigForm
|
|
33
|
+
|
|
34
|
+
self.module_config_name = "my_module"
|
|
35
|
+
mimic :organization
|
|
36
|
+
attribute :enabled, :boolean
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
2. **Register** — in your engine, after `decidim_toggle.organization_settings_tabs`:
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
initializer "decidim_my_module.organization_settings_tab", after: "decidim_toggle.organization_settings_tabs" do
|
|
45
|
+
Decidim::Toggle.settings_tabs :organization_settings do |tabs|
|
|
46
|
+
tabs.add_tab :my_module, "My module",
|
|
47
|
+
form: MyModule::AdminConfigForm,
|
|
48
|
+
command: Decidim::Toggle::UpdateModuleConfigCommand,
|
|
49
|
+
module_name: :my_module
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
3. **Read** — `Decidim::Toggle.config_for(organization, :my_module)`.
|
|
55
|
+
|
|
56
|
+
Optional view partial: `form_layout_partial:` on `add_tab` — see [Customize views](https://octree-gva.github.io/decidim-toggle/integrate/customize-views).
|
|
57
|
+
|
|
58
|
+
Full walkthrough: [Add a settings tab](https://octree-gva.github.io/decidim-toggle/integrate/quickstart).
|
|
59
|
+
|
|
60
|
+
## Host app install
|
|
61
|
+
|
|
62
|
+
```ruby
|
|
63
|
+
gem "decidim-toggle"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
bundle install
|
|
68
|
+
rails decidim_toggle:install:migrations
|
|
69
|
+
rails db:migrate
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Documentation
|
|
73
|
+
|
|
74
|
+
[octree-gva.github.io/decidim-toggle](https://octree-gva.github.io/decidim-toggle/) — integrator guides (registration, views, storage) and contributor docs.
|
|
75
|
+
|
|
76
|
+
## Development (this gem)
|
|
77
|
+
|
|
78
|
+
Docker + `./bin/check` (RuboCop, erblint, RSpec) — see [CONTRIBUTING.md](CONTRIBUTING.md) and [Contribute](https://octree-gva.github.io/decidim-toggle/contributing).
|
|
79
|
+
|
|
80
|
+
## Support
|
|
81
|
+
|
|
82
|
+
[GitLab issues](https://git.octree.ch/decidim/vocacity/decidim-modules/decidim-toggle/-/issues) for bugs and integration questions.
|
|
83
|
+
|
|
84
|
+
## Contributing
|
|
85
|
+
|
|
86
|
+
Pull requests welcome. Read [CONTRIBUTING.md](CONTRIBUTING.md) before opening a merge request.
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
[AGPL-3.0](LICENSE.md).
|
data/Rakefile
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "decidim/dev/common_rake"
|
|
4
|
+
|
|
5
|
+
def install_deps(path)
|
|
6
|
+
Dir.chdir(path) do
|
|
7
|
+
system("bundle exec rails decidim:update")
|
|
8
|
+
system("bundle exec rake db:migrate")
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def seed_db(path)
|
|
13
|
+
Dir.chdir(path) do
|
|
14
|
+
system("bundle exec rake db:seed")
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
desc "Generates a dummy app for testing"
|
|
19
|
+
task test_app: "decidim:generate_external_test_app"
|
|
20
|
+
|
|
21
|
+
desc "Generates a development app."
|
|
22
|
+
task :development_app do
|
|
23
|
+
Bundler.with_original_env do
|
|
24
|
+
generate_decidim_app(
|
|
25
|
+
"development_app",
|
|
26
|
+
"--app_name",
|
|
27
|
+
"#{base_app_name}_development_app",
|
|
28
|
+
"--path",
|
|
29
|
+
"..",
|
|
30
|
+
"--recreate_db",
|
|
31
|
+
"--demo",
|
|
32
|
+
"--locales",
|
|
33
|
+
"en,ca,es,fr"
|
|
34
|
+
)
|
|
35
|
+
end
|
|
36
|
+
install_deps("development_app")
|
|
37
|
+
seed_db("development_app")
|
|
38
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Toggle
|
|
5
|
+
class UpdateAuthorizationsCommand < Decidim::Command
|
|
6
|
+
def initialize(organization, form)
|
|
7
|
+
@organization = organization
|
|
8
|
+
@form = form
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def call
|
|
12
|
+
return broadcast(:invalid) if form.invalid?
|
|
13
|
+
|
|
14
|
+
transaction do
|
|
15
|
+
organization.available_authorizations = form.clean_available_authorizations
|
|
16
|
+
organization.save!
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
Decidim::OrganizationSettings.reload(organization) if defined?(Decidim::OrganizationSettings)
|
|
20
|
+
|
|
21
|
+
broadcast(:ok)
|
|
22
|
+
rescue ActiveRecord::RecordInvalid
|
|
23
|
+
broadcast(:invalid)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
attr_reader :organization, :form
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Toggle
|
|
5
|
+
class UpdateEmailsCommand < Decidim::Command
|
|
6
|
+
def initialize(organization, form)
|
|
7
|
+
@organization = organization
|
|
8
|
+
@form = form
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def call
|
|
12
|
+
return broadcast(:invalid) if form.invalid?
|
|
13
|
+
|
|
14
|
+
transaction do
|
|
15
|
+
organization.smtp_settings = form.encrypted_smtp_settings
|
|
16
|
+
organization.save!
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
Decidim::OrganizationSettings.reload(organization) if defined?(Decidim::OrganizationSettings)
|
|
20
|
+
broadcast(:ok)
|
|
21
|
+
rescue ActiveRecord::RecordInvalid
|
|
22
|
+
broadcast(:invalid)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
attr_reader :organization, :form
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Toggle
|
|
5
|
+
class UpdateFileUploadSettingsCommand < Decidim::Command
|
|
6
|
+
def initialize(organization, form)
|
|
7
|
+
@organization = organization
|
|
8
|
+
@form = form
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def call
|
|
12
|
+
return broadcast(:invalid) if form.invalid?
|
|
13
|
+
|
|
14
|
+
transaction do
|
|
15
|
+
organization.file_upload_settings = form.file_upload_settings.final
|
|
16
|
+
organization.save!
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
Decidim::OrganizationSettings.reload(organization) if defined?(Decidim::OrganizationSettings)
|
|
20
|
+
|
|
21
|
+
broadcast(:ok)
|
|
22
|
+
rescue ActiveRecord::RecordInvalid
|
|
23
|
+
broadcast(:invalid)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
attr_reader :organization, :form
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rake"
|
|
4
|
+
|
|
5
|
+
module Decidim
|
|
6
|
+
module Toggle
|
|
7
|
+
class UpdateLocaleCommand < Decidim::Command
|
|
8
|
+
def initialize(organization, form)
|
|
9
|
+
@organization = organization
|
|
10
|
+
@form = form
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def call
|
|
14
|
+
return broadcast(:invalid) if form.invalid?
|
|
15
|
+
|
|
16
|
+
transaction do
|
|
17
|
+
update_organization_locales
|
|
18
|
+
rebuild_search_index
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
broadcast(:ok)
|
|
22
|
+
rescue ActiveRecord::RecordInvalid
|
|
23
|
+
broadcast(:invalid)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
attr_reader :organization, :form
|
|
29
|
+
|
|
30
|
+
def update_organization_locales
|
|
31
|
+
organization.available_locales = form.clean_available_locales
|
|
32
|
+
organization.default_locale = form.default_locale
|
|
33
|
+
if organization.respond_to?(:enable_machine_translations=)
|
|
34
|
+
organization.enable_machine_translations = form.enable_machine_translations
|
|
35
|
+
organization.machine_translation_display_priority = form.machine_translation_display_priority || "original"
|
|
36
|
+
end
|
|
37
|
+
organization.save!
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def rebuild_search_index
|
|
41
|
+
Rails.application.load_tasks
|
|
42
|
+
Rake::Task["decidim:locales:rebuild_search"].reenable
|
|
43
|
+
Rake::Task["decidim:locales:rebuild_search"].invoke
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Toggle
|
|
5
|
+
# Persists a form that includes {ModuleConfigForm} into {OrganizationModuleConfig#config}.
|
|
6
|
+
class UpdateModuleConfigCommand < Decidim::Command
|
|
7
|
+
def initialize(organization, form)
|
|
8
|
+
@organization = organization
|
|
9
|
+
@form = form
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def call
|
|
13
|
+
return broadcast(:invalid) if form.class.module_config_name.blank?
|
|
14
|
+
return broadcast(:invalid) if form.invalid?
|
|
15
|
+
|
|
16
|
+
Decidim::Toggle.save_config!(
|
|
17
|
+
organization,
|
|
18
|
+
form.class.module_config_name,
|
|
19
|
+
form.to_h
|
|
20
|
+
)
|
|
21
|
+
broadcast(:ok)
|
|
22
|
+
rescue ActiveRecord::RecordInvalid
|
|
23
|
+
broadcast(:invalid)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
attr_reader :organization, :form
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Toggle
|
|
5
|
+
class UpdateNameCommand < Decidim::Command
|
|
6
|
+
def initialize(organization, form)
|
|
7
|
+
@organization = organization
|
|
8
|
+
@form = form
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def call
|
|
12
|
+
return broadcast(:invalid) if form.invalid?
|
|
13
|
+
|
|
14
|
+
transaction do
|
|
15
|
+
organization.name = form.name
|
|
16
|
+
organization.host = form.host
|
|
17
|
+
organization.secondary_hosts = form.clean_secondary_hosts
|
|
18
|
+
organization.save!
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
broadcast(:ok)
|
|
22
|
+
rescue ActiveRecord::RecordInvalid
|
|
23
|
+
broadcast(:invalid)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
attr_reader :organization, :form
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Toggle
|
|
5
|
+
class UpdateOmniauthCommand < Decidim::Command
|
|
6
|
+
def initialize(organization, form)
|
|
7
|
+
@organization = organization
|
|
8
|
+
@form = form
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def call
|
|
12
|
+
return broadcast(:invalid) if form.invalid?
|
|
13
|
+
|
|
14
|
+
transaction do
|
|
15
|
+
organization.omniauth_settings = form.encrypted_omniauth_settings
|
|
16
|
+
organization.save!
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
Decidim::OrganizationSettings.reload(organization) if defined?(Decidim::OrganizationSettings)
|
|
20
|
+
broadcast(:ok)
|
|
21
|
+
rescue ActiveRecord::RecordInvalid
|
|
22
|
+
broadcast(:invalid)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
attr_reader :organization, :form
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Toggle
|
|
5
|
+
class UpdateSecurityCommand < Decidim::Command
|
|
6
|
+
def initialize(organization, form)
|
|
7
|
+
@organization = organization
|
|
8
|
+
@form = form
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def call
|
|
12
|
+
return broadcast(:invalid) if form.invalid?
|
|
13
|
+
|
|
14
|
+
transaction do
|
|
15
|
+
organization.force_users_to_authenticate_before_access_organization = form.force_users_to_authenticate_before_access_organization
|
|
16
|
+
organization.users_registration_mode = form.users_registration_mode
|
|
17
|
+
organization.content_security_policy = form.content_security_policy
|
|
18
|
+
organization.save!
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
broadcast(:ok)
|
|
22
|
+
rescue ActiveRecord::RecordInvalid
|
|
23
|
+
broadcast(:invalid)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
attr_reader :organization, :form
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DecidimToggle
|
|
4
|
+
module System
|
|
5
|
+
class SettingsTabController < Decidim::System::ApplicationController
|
|
6
|
+
def update
|
|
7
|
+
build_tabs_registry
|
|
8
|
+
config = registry.form_tab(params[:tab_id])
|
|
9
|
+
return head :not_found unless config
|
|
10
|
+
|
|
11
|
+
@organization = Decidim::Organization.find(params[:organization_id])
|
|
12
|
+
form_class = config[:form]
|
|
13
|
+
command_class = config[:command]
|
|
14
|
+
@form = form(form_class).from_params(params.permit!).with_context(current_organization: @organization)
|
|
15
|
+
|
|
16
|
+
command_class.call(@organization, @form) do
|
|
17
|
+
on(:ok) do
|
|
18
|
+
flash[:notice] = t("decidim_toggle.system.organizations.form_tab.success")
|
|
19
|
+
redirect_to settings_tab_redirect_target
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
on(:invalid) do
|
|
23
|
+
flash[:decidim_toggle_invalid_settings_tab] = {
|
|
24
|
+
organization_id: @organization.id,
|
|
25
|
+
tab_id: params[:tab_id].to_s,
|
|
26
|
+
params: params.fetch(:organization, {}).permit!.to_h,
|
|
27
|
+
errors: @form.errors.messages.transform_keys(&:to_s).transform_values { |messages| messages.map(&:to_s) }
|
|
28
|
+
}
|
|
29
|
+
redirect_to settings_tab_redirect_target
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def build_tabs_registry
|
|
37
|
+
tabs = Decidim::Toggle::SettingsTabs.new(:organization_settings)
|
|
38
|
+
tabs.build_for(self)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def registry
|
|
42
|
+
Decidim::Toggle::SettingsTabRegistry.find(:organization_settings)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def settings_tab_redirect_target
|
|
46
|
+
anchor = tab_anchor_fragment
|
|
47
|
+
return decidim_system.edit_organization_path(@organization) if anchor.blank?
|
|
48
|
+
|
|
49
|
+
decidim_system.edit_organization_path(@organization, anchor:)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def tab_anchor_fragment
|
|
53
|
+
tab_id = params[:decidim_toggle_active_tab].presence
|
|
54
|
+
return nil unless tab_id
|
|
55
|
+
|
|
56
|
+
tabs = Decidim::Toggle::SettingsTabs.new(:organization_settings)
|
|
57
|
+
tabs.build_for(self)
|
|
58
|
+
return nil unless tabs.items.any? { |item| item.identifier.to_s == tab_id.to_s }
|
|
59
|
+
|
|
60
|
+
"panel-toggle-#{tab_id}"
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Toggle
|
|
5
|
+
# Vanilla Decidim: `available_authorizations` is a string array of workflow names.
|
|
6
|
+
# Other gems may replace this tab (same identifier `:authorizations`); see
|
|
7
|
+
# {Decidim::Toggle::OrganizationSettingsTabs}.
|
|
8
|
+
class UpdateAuthorizationsForm < Decidim::Form
|
|
9
|
+
mimic :organization
|
|
10
|
+
|
|
11
|
+
attribute :available_authorizations, [String]
|
|
12
|
+
|
|
13
|
+
validate :available_authorizations_subset_of_workflows
|
|
14
|
+
|
|
15
|
+
def self.from_model(organization)
|
|
16
|
+
from_params(organization: { available_authorizations: Array(organization.available_authorizations).map(&:to_s) })
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.collection_for_available_authorizations
|
|
20
|
+
Decidim.authorization_workflows.map { |w| [w.name, w.description] }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.from_params(params, additional_params = {})
|
|
24
|
+
params = params.to_h.with_indifferent_access if params.respond_to?(:to_h)
|
|
25
|
+
attrs = params[:organization] || params
|
|
26
|
+
if attrs[:available_authorizations].nil?
|
|
27
|
+
params = params.dup
|
|
28
|
+
params[:organization] = (params[:organization] || {}).merge(available_authorizations: [])
|
|
29
|
+
end
|
|
30
|
+
super(params, additional_params)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def clean_available_authorizations
|
|
34
|
+
@clean_available_authorizations ||= if available_authorizations.blank?
|
|
35
|
+
[]
|
|
36
|
+
else
|
|
37
|
+
available_authorizations.map(&:to_s).select(&:present?)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def available_authorizations_subset_of_workflows
|
|
44
|
+
return if clean_available_authorizations.blank?
|
|
45
|
+
|
|
46
|
+
allowed = Decidim.authorization_workflows.to_set(&:name)
|
|
47
|
+
invalid = Array(clean_available_authorizations).map(&:to_s).reject { |a| allowed.include?(a) }
|
|
48
|
+
return if invalid.empty?
|
|
49
|
+
|
|
50
|
+
errors.add(:available_authorizations, :invalid)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Toggle
|
|
5
|
+
class UpdateEmailsForm < Decidim::System::BaseOrganizationForm
|
|
6
|
+
mimic :organization
|
|
7
|
+
|
|
8
|
+
# These tabs only update a small JSONB slice (SMTP settings).
|
|
9
|
+
# The generic system form validates presence of `host` and
|
|
10
|
+
# `users_registration_mode`, so fall back to the current organization when
|
|
11
|
+
# those attributes aren't part of the tab payload.
|
|
12
|
+
def host
|
|
13
|
+
super.presence || current_organization&.host
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def users_registration_mode
|
|
17
|
+
super.presence || current_organization&.users_registration_mode
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
# No-op: this tab doesn't touch organization identity/uniqueness.
|
|
23
|
+
def validate_organization_uniqueness
|
|
24
|
+
# intentionally blank
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Toggle
|
|
5
|
+
# Wraps {Decidim::System::FileUploadSettingsForm} for the settings-tab endpoint
|
|
6
|
+
# so file upload settings can be saved without submitting the full organization form.
|
|
7
|
+
class UpdateFileUploadSettingsForm < Decidim::Form
|
|
8
|
+
mimic :organization
|
|
9
|
+
|
|
10
|
+
attribute :file_upload_settings, Decidim::System::FileUploadSettingsForm
|
|
11
|
+
|
|
12
|
+
def self.from_model(organization)
|
|
13
|
+
from_params(
|
|
14
|
+
organization: {
|
|
15
|
+
file_upload_settings: Decidim::System::FileUploadSettingsForm.from_model(organization.file_upload_settings)
|
|
16
|
+
}
|
|
17
|
+
)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.from_params(params, additional_params = {})
|
|
21
|
+
params = params.to_h.with_indifferent_access if params.respond_to?(:to_h)
|
|
22
|
+
super(params, additional_params)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Toggle
|
|
5
|
+
class UpdateLocaleForm < Decidim::Form
|
|
6
|
+
mimic :organization
|
|
7
|
+
|
|
8
|
+
attribute :available_locales, Array
|
|
9
|
+
attribute :default_locale, String
|
|
10
|
+
attribute :enable_machine_translations, Boolean
|
|
11
|
+
attribute :machine_translation_display_priority, String
|
|
12
|
+
|
|
13
|
+
# Decidim::Form delegates :available_locales to current_organization; this form is often
|
|
14
|
+
# built without context (e.g. system settings tabs), so prefer the attribute value.
|
|
15
|
+
def available_locales
|
|
16
|
+
attributes["available_locales"]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
validates :available_locales, presence: true
|
|
20
|
+
validates :default_locale, presence: true
|
|
21
|
+
validates :machine_translation_display_priority,
|
|
22
|
+
inclusion: { in: %w(original translation) },
|
|
23
|
+
if: -> { defined?(Decidim::Organization::AVAILABLE_MACHINE_TRANSLATION_DISPLAY_PRIORITIES) && enable_machine_translations }
|
|
24
|
+
validate :available_locales_subset_of_i18n
|
|
25
|
+
validate :default_locale_in_available_locales
|
|
26
|
+
validate :default_locale_in_i18n
|
|
27
|
+
|
|
28
|
+
def self.from_model(organization)
|
|
29
|
+
attrs = locale_attrs_from(organization)
|
|
30
|
+
attrs[:enable_machine_translations] = organization.enable_machine_translations if organization.respond_to?(:enable_machine_translations)
|
|
31
|
+
attrs[:machine_translation_display_priority] = organization.machine_translation_display_priority if organization.respond_to?(:machine_translation_display_priority)
|
|
32
|
+
from_params(attrs)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.locale_attrs_from(organization)
|
|
36
|
+
record =
|
|
37
|
+
if organization.is_a?(Decidim::Organization)
|
|
38
|
+
organization
|
|
39
|
+
elsif organization.respond_to?(:id) && organization.id.present?
|
|
40
|
+
Decidim::Organization.find_by(id: organization.id)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
source = record || organization
|
|
44
|
+
|
|
45
|
+
{
|
|
46
|
+
available_locales: Array(source.try(:available_locales)).map(&:to_s),
|
|
47
|
+
default_locale: source.try(:default_locale)&.to_s
|
|
48
|
+
}
|
|
49
|
+
end
|
|
50
|
+
private_class_method :locale_attrs_from
|
|
51
|
+
|
|
52
|
+
def self.collection_for_machine_translation_display_priority
|
|
53
|
+
return [] unless defined?(Decidim::Organization::AVAILABLE_MACHINE_TRANSLATION_DISPLAY_PRIORITIES)
|
|
54
|
+
|
|
55
|
+
Decidim::Organization::AVAILABLE_MACHINE_TRANSLATION_DISPLAY_PRIORITIES.map do |priority|
|
|
56
|
+
[
|
|
57
|
+
priority,
|
|
58
|
+
I18n.t("activemodel.attributes.organization.machine_translation_display_priority_#{priority}", default: priority)
|
|
59
|
+
]
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def self.collection_for_available_locales
|
|
64
|
+
I18n.available_locales.map { |l| [l.to_s, l.to_s] }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def self.collection_for_default_locale
|
|
68
|
+
I18n.available_locales.map { |l| [l.to_s, l.to_s] }
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def self.from_params(params, additional_params = {})
|
|
72
|
+
params = params.to_h.with_indifferent_access if params.respond_to?(:to_h)
|
|
73
|
+
attrs = params[:organization] || params
|
|
74
|
+
if attrs[:available_locales].is_a?(Hash)
|
|
75
|
+
params = params.dup
|
|
76
|
+
params[:organization] = (params[:organization] || {}).merge(available_locales: attrs[:available_locales].keys.compact_blank)
|
|
77
|
+
end
|
|
78
|
+
super(params, additional_params)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def clean_available_locales
|
|
82
|
+
return [] if available_locales.blank?
|
|
83
|
+
|
|
84
|
+
allowed = i18n_available_locales_set
|
|
85
|
+
Array(available_locales).map(&:to_s).select { |l| allowed.include?(l) }
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
def i18n_available_locales_set
|
|
91
|
+
@i18n_available_locales_set ||= I18n.available_locales.to_set(&:to_s)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def available_locales_subset_of_i18n
|
|
95
|
+
return if available_locales.blank?
|
|
96
|
+
|
|
97
|
+
invalid = Array(available_locales).map(&:to_s) - i18n_available_locales_set.to_a
|
|
98
|
+
return if invalid.empty?
|
|
99
|
+
|
|
100
|
+
errors.add(:available_locales, :inclusion)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def default_locale_in_available_locales
|
|
104
|
+
return if default_locale.blank?
|
|
105
|
+
|
|
106
|
+
errors.add(:default_locale, :inclusion) unless Array(available_locales).map(&:to_s).include?(default_locale.to_s)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def default_locale_in_i18n
|
|
110
|
+
return if default_locale.blank?
|
|
111
|
+
|
|
112
|
+
errors.add(:default_locale, :inclusion) unless i18n_available_locales_set.include?(default_locale.to_s)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|