diff --git a/app/controllers/account_configs_controller.rb b/app/controllers/account_configs_controller.rb new file mode 100644 index 00000000..cfa46a14 --- /dev/null +++ b/app/controllers/account_configs_controller.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +class AccountConfigsController < ApplicationController + before_action :load_account_config + authorize_resource :account_config + + ALLOWED_KEYS = [ + AccountConfig::ALLOW_TYPED_SIGNATURE, + AccountConfig::FORCE_MFA + ].freeze + + def create + @account_config.update!(account_config_params) + + head :ok + end + + private + + def load_account_config + return head :not_found unless ALLOWED_KEYS.include?(account_config_params[:key]) + + @account_config = + AccountConfig.find_or_initialize_by(account: current_account, key: account_config_params[:key]) + end + + def account_config_params + params.required(:account_config).permit!.tap do |attrs| + attrs[:value] = attrs[:value] == '1' if attrs[:value].in?(%w[1 0]) + end + end +end diff --git a/app/controllers/mfa_force_controller.rb b/app/controllers/mfa_force_controller.rb deleted file mode 100644 index 1be78147..00000000 --- a/app/controllers/mfa_force_controller.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -class MfaForceController < ApplicationController - before_action :load_account_config - authorize_resource :account_config - - def create - @account_config.update!(value: !@account_config.value) - - redirect_back fallback_location: settings_users_path, - notice: "Force 2FA has been #{@account_config.value ? 'enabled' : 'disabled'}." - end - - private - - def load_account_config - @account_config = - AccountConfig.find_or_initialize_by(account: current_account, key: AccountConfig::FORCE_MFA) - end -end diff --git a/app/javascript/form.js b/app/javascript/form.js index ebdcea17..f0023ecf 100644 --- a/app/javascript/form.js +++ b/app/javascript/form.js @@ -17,6 +17,7 @@ window.customElements.define('submission-form', class extends HTMLElement { isDemo: this.dataset.isDemo === 'true', attribution: this.dataset.attribution !== 'false', withConfetti: true, + withTypedSignature: this.dataset.withTypedSignature !== 'false', values: reactive(JSON.parse(this.dataset.values)), completedButton: JSON.parse(this.dataset.completedButton), attachments: reactive(JSON.parse(this.dataset.attachments)), diff --git a/app/javascript/submission_form/form.vue b/app/javascript/submission_form/form.vue index cc38f228..e549b5fc 100644 --- a/app/javascript/submission_form/form.vue +++ b/app/javascript/submission_form/form.vue @@ -223,6 +223,7 @@ :field="currentField" :previous-value="previousSignatureValue" :is-direct-upload="isDirectUpload" + :with-typed-signature="withTypedSignature" :attachments-index="attachmentsIndex" :submitter-slug="submitterSlug" @attached="attachments.push($event)" @@ -386,6 +387,11 @@ export default { required: false, default: false }, + withTypedSignature: { + type: Boolean, + required: false, + default: true + }, baseUrl: { type: String, required: false, diff --git a/app/javascript/submission_form/signature_step.vue b/app/javascript/submission_form/signature_step.vue index 4157133d..a4c90958 100644 --- a/app/javascript/submission_form/signature_step.vue +++ b/app/javascript/submission_form/signature_step.vue @@ -23,7 +23,7 @@ @@ -149,6 +149,11 @@ export default { required: true, default: false }, + withTypedSignature: { + type: Boolean, + required: false, + default: true + }, attachmentsIndex: { type: Object, required: false, diff --git a/app/models/account_config.rb b/app/models/account_config.rb index 56410a89..0c435e0e 100644 --- a/app/models/account_config.rb +++ b/app/models/account_config.rb @@ -26,6 +26,7 @@ class AccountConfig < ApplicationRecord SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY = 'submitter_documents_copy_email' BCC_EMAILS = 'bcc_emails' FORCE_MFA = 'force_mfa' + ALLOW_TYPED_SIGNATURE = 'allow_typed_signature' SUBMITTER_REMAILERS = 'submitter_reminders' FORM_COMPLETED_BUTTON_KEY = 'form_completed_button' diff --git a/app/views/accounts/show.html.erb b/app/views/accounts/show.html.erb index 5734e240..4682fafd 100644 --- a/app/views/accounts/show.html.erb +++ b/app/views/accounts/show.html.erb @@ -36,6 +36,35 @@ <% end %> <% end %> + <% if can?(:manage, AccountConfig) %> +
+

Preferences

+ <% account_config = AccountConfig.find_or_initialize_by(account: current_account, key: AccountConfig::FORCE_MFA) %> + <% if can?(:manage, account_config) %> + <%= form_for account_config, url: account_configs_path, method: :post do |f| %> + <%= f.hidden_field :key %> +
+ + Force 2FA with Authenticator App + + <%= f.check_box :value, class: 'toggle', checked: account_config.value, onchange: 'this.form.requestSubmit()' %> +
+ <% end %> + <% end %> + <% account_config = AccountConfig.find_or_initialize_by(account: current_account, key: AccountConfig::ALLOW_TYPED_SIGNATURE) %> + <% if can?(:manage, account_config) %> + <%= form_for account_config, url: account_configs_path, method: :post do |f| %> + <%= f.hidden_field :key %> +
+ + Allow typed text signatures + + <%= f.check_box :value, class: 'toggle', checked: account_config.value != false, onchange: 'this.form.requestSubmit()' %> +
+ <% end %> + <% end %> +
+ <% end %>
diff --git a/app/views/mfa_setup/_form.html.erb b/app/views/mfa_setup/_form.html.erb index c5060c22..5b59d451 100644 --- a/app/views/mfa_setup/_form.html.erb +++ b/app/views/mfa_setup/_form.html.erb @@ -1,4 +1,4 @@ -<%= form_for '', url: mfa_setup_path, data: { turbo_frame: :_top }, html: { id: 'mfa_form'} do |f| %> +<%= form_for '', url: mfa_setup_path, data: { turbo_frame: :_top }, html: { id: 'mfa_form' } do |f| %>

Use an authenticator mobile app like Google Authenticator or 1Password to scan the QR code below.

diff --git a/app/views/submit_form/_submission_form.html.erb b/app/views/submit_form/_submission_form.html.erb index fcbe8116..d931c127 100644 --- a/app/views/submit_form/_submission_form.html.erb +++ b/app/views/submit_form/_submission_form.html.erb @@ -1,4 +1,4 @@ <% data_attachments = attachments_index.values.select { |e| e.record_id == submitter.id }.to_json(only: %i[uuid], methods: %i[url filename content_type]) %> <% data_fields = (submitter.submission.template_fields || submitter.submission.template.fields).select { |f| f['submitter_uuid'] == submitter.uuid }.to_json %> -<% completed_button_params = submitter.submission.template.account.account_configs.find_by(key: AccountConfig::FORM_COMPLETED_BUTTON_KEY)&.value || {} %> - +<% configs = Submitters::FormConfigs.call(submitter) %> + diff --git a/app/views/users/index.html.erb b/app/views/users/index.html.erb index c38ce8c2..27dee367 100644 --- a/app/views/users/index.html.erb +++ b/app/views/users/index.html.erb @@ -4,19 +4,6 @@

Team

- <% if !Docuseal.multitenant? %> - <% account_config = AccountConfig.find_or_initialize_by(account: current_account, key: AccountConfig::FORCE_MFA) %> - <% if can?(:manage, account_config) %> - <%= form_for :force_mfa, url: mfa_force_path do |f| %> - - <% end %> - <% end %> - <% end %> <% if can?(:create, User.new(account: current_account)) %> <%= link_to new_user_path, class: 'btn btn-primary btn-md gap-2', data: { turbo_frame: 'modal' } do %> <%= svg_icon('plus', class: 'w-6 h-6') %> diff --git a/config/routes.rb b/config/routes.rb index 830f8e3e..0d90dd88 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -49,7 +49,7 @@ Rails.application.routes.draw do resources :verify_pdf_signature, only: %i[create] resource :mfa_setup, only: %i[show new edit create destroy], controller: 'mfa_setup' - resource :mfa_force, only: %i[create], controller: 'mfa_force' + resources :account_configs, only: %i[create] resources :dashboard, only: %i[index] resources :setup, only: %i[index create] resource :newsletter, only: %i[show update] diff --git a/lib/submitters/form_configs.rb b/lib/submitters/form_configs.rb new file mode 100644 index 00000000..d5f69e7b --- /dev/null +++ b/lib/submitters/form_configs.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Submitters + module FormConfigs + module_function + + def call(submitter) + configs = submitter.submission.template.account.account_configs + .where(key: [AccountConfig::FORM_COMPLETED_BUTTON_KEY, + AccountConfig::ALLOW_TYPED_SIGNATURE]) + + completed_button = configs.find { |e| e.key == AccountConfig::FORM_COMPLETED_BUTTON_KEY }&.value || {} + + with_typed_signature = configs.find { |e| e.key == AccountConfig::ALLOW_TYPED_SIGNATURE }&.value != false + + { completed_button:, with_typed_signature: } + end + end +end