diff --git a/app/controllers/account_configs_controller.rb b/app/controllers/account_configs_controller.rb index bb8399db6..6f96a9341 100644 --- a/app/controllers/account_configs_controller.rb +++ b/app/controllers/account_configs_controller.rb @@ -8,6 +8,7 @@ class AccountConfigsController < ApplicationController AccountConfig::ALLOW_TYPED_SIGNATURE, AccountConfig::FORCE_MFA, AccountConfig::ALLOW_TO_RESUBMIT, + AccountConfig::FORM_PREFILL_SIGNATURE_KEY, AccountConfig::ESIGNING_PREFERENCE_KEY, AccountConfig::FORM_WITH_CONFETTI_KEY, AccountConfig::DOWNLOAD_LINKS_AUTH_KEY, diff --git a/app/controllers/api/attachments_controller.rb b/app/controllers/api/attachments_controller.rb index 7ff46fe73..49a7b06d8 100644 --- a/app/controllers/api/attachments_controller.rb +++ b/app/controllers/api/attachments_controller.rb @@ -1,16 +1,37 @@ # frozen_string_literal: true module Api - class AttachmentsController < ApiBaseController - skip_before_action :authenticate_user! - skip_authorization_check + class AttachmentsController < ActionController::API + include ActionController::Cookies + include ActiveStorage::SetCurrent + + COOKIE_STORE_LIMIT = 10 def create submitter = Submitter.find_by!(slug: params[:submitter_slug]) attachment = Submitters.create_attachment!(submitter, params) + if params[:remember_signature] == 'true' && submitter.email.present? + cookies.encrypted[:signature_uuids] = build_new_cookie_signatures_json(submitter, attachment) + end + render json: attachment.as_json(only: %i[uuid], methods: %i[url filename content_type]) end + + def build_new_cookie_signatures_json(submitter, attachment) + values = + begin + JSON.parse(cookies.encrypted[:signature_uuids].presence || '{}') + rescue JSON::ParserError + {} + end + + values[submitter.email] = attachment.uuid + + values = values.to_a.last(COOKIE_STORE_LIMIT).to_h if values.size > COOKIE_STORE_LIMIT + + values.to_json + end end end diff --git a/app/controllers/submit_form_controller.rb b/app/controllers/submit_form_controller.rb index a07b202e0..c3e3c7440 100644 --- a/app/controllers/submit_form_controller.rb +++ b/app/controllers/submit_form_controller.rb @@ -7,12 +7,14 @@ class SubmitFormController < ApplicationController skip_before_action :authenticate_user! skip_authorization_check + CONFIG_KEYS = [].freeze PRELOAD_ALL_PAGES_AMOUNT = 200 def show @submitter = Submitter.find_by!(slug: params[:slug]) return redirect_to submit_form_completed_path(@submitter.slug) if @submitter.completed_at? + return render :archived if @submitter.submission.template.archived_at? || @submitter.submission.archived_at? ActiveRecord::Associations::Preloader.new( records: [@submitter], @@ -34,11 +36,14 @@ def show @attachments_index = ActiveStorage::Attachment.where(record: @submitter.submission.submitters, name: :attachments) .preload(:blob).index_by(&:uuid) - unless Docuseal.multitenant? - @signature_attachment = Submitters::MaybeAssignDefaultSignature.call(@submitter, params, @attachments_index) - end + @form_configs = Submitters::FormConfigs.call(@submitter, CONFIG_KEYS) + + return unless @form_configs[:prefill_signature] + + @signature_attachment = + Submitters::MaybeAssignDefaultBrowserSignature.call(@submitter, params, cookies, @attachments_index.values) - render(@submitter.submission.template.archived_at? || @submitter.submission.archived_at? ? :archived : :show) + @attachments_index[@signature_attachment.uuid] = @signature_attachment if @signature_attachment end def update diff --git a/app/javascript/draw.js b/app/javascript/draw.js index 40e5d31e6..81ceccf52 100644 --- a/app/javascript/draw.js +++ b/app/javascript/draw.js @@ -70,6 +70,7 @@ window.customElements.define('draw-signature', class extends HTMLElement { formData.append('file', file) formData.append('submitter_slug', this.dataset.slug) formData.append('name', 'attachments') + formData.append('remember_signature', 'true') return fetch('/api/attachments', { method: 'POST', diff --git a/app/javascript/form.js b/app/javascript/form.js index a63b28469..4d4d62a1a 100644 --- a/app/javascript/form.js +++ b/app/javascript/form.js @@ -23,6 +23,7 @@ safeRegisterElement('submission-form', class extends HTMLElement { withDisclosure: this.dataset.withDisclosure === 'true', withTypedSignature: this.dataset.withTypedSignature !== 'false', authenticityToken: document.querySelector('meta[name="csrf-token"]')?.content, + rememberSignature: this.dataset.rememberSignature === 'true', values: reactive(JSON.parse(this.dataset.values)), completedButton: JSON.parse(this.dataset.completedButton || '{}'), withQrButton: true, diff --git a/app/javascript/submission_form/form.vue b/app/javascript/submission_form/form.vue index 2179806ef..aded89730 100644 --- a/app/javascript/submission_form/form.vue +++ b/app/javascript/submission_form/form.vue @@ -323,11 +323,12 @@ :field="currentField" :previous-value="previousSignatureValueFor(currentField) || previousSignatureValue" :with-typed-signature="withTypedSignature" + :remember-signature="rememberSignature" :attachments-index="attachmentsIndex" :button-text="buttonText" :with-disclosure="withDisclosure" :with-qr-button="withQrButton" - :submitter-slug="submitterSlug" + :submitter="submitter" :show-field-names="showFieldNames" @attached="attachments.push($event)" @start="scrollIntoField(currentField)" @@ -549,6 +550,11 @@ export default { required: false, default: null }, + rememberSignature: { + type: Boolean, + required: false, + default: false + }, minimize: { type: Boolean, required: false, diff --git a/app/javascript/submission_form/signature_step.vue b/app/javascript/submission_form/signature_step.vue index 44ce5069c..c861ae24d 100644 --- a/app/javascript/submission_form/signature_step.vue +++ b/app/javascript/submission_form/signature_step.vue @@ -255,8 +255,8 @@ export default { type: Object, required: true }, - submitterSlug: { - type: String, + submitter: { + type: Object, required: true }, showFieldNames: { @@ -284,6 +284,11 @@ export default { required: false, default: true }, + rememberSignature: { + type: Boolean, + required: false, + default: false + }, attachmentsIndex: { type: Object, required: false, @@ -311,6 +316,9 @@ export default { } }, computed: { + submitterSlug () { + return this.submitter.slug + }, computedPreviousValue () { if (this.isUsePreviousValue) { return this.previousValue @@ -521,6 +529,27 @@ export default { this.uploadImageInputKey = Math.random().toString() } }, + maybeSetSignedUuid (signedUuid) { + try { + if (window.localStorage && signedUuid && this.rememberSignature) { + const values = window.localStorage.getItem('signed_signature_uuids') + + let data + + if (values) { + data = JSON.parse(values) + } else { + data = {} + } + + data[this.submitter.email] = signedUuid + + window.localStorage.setItem('signed_signature_uuids', JSON.stringify(data)) + } + } catch (e) { + console.error(e) + } + }, async submit () { if (this.modelValue || this.computedPreviousValue) { if (this.computedPreviousValue) { @@ -539,6 +568,7 @@ export default { formData.append('file', file) formData.append('submitter_slug', this.submitterSlug) formData.append('name', 'attachments') + formData.append('remember_signature', this.rememberSignature) return fetch(this.baseUrl + '/api/attachments', { method: 'POST', @@ -547,6 +577,8 @@ export default { this.$emit('attached', attachment) this.$emit('update:model-value', attachment.uuid) + this.maybeSetSignedUuid(attachment.signed_uuid) + return resolve(attachment) }) }).catch((error) => { diff --git a/app/models/account_config.rb b/app/models/account_config.rb index cd4320ef2..4e3451703 100644 --- a/app/models/account_config.rb +++ b/app/models/account_config.rb @@ -32,6 +32,7 @@ class AccountConfig < ApplicationRecord FORM_COMPLETED_BUTTON_KEY = 'form_completed_button' FORM_COMPLETED_MESSAGE_KEY = 'form_completed_message' FORM_WITH_CONFETTI_KEY = 'form_with_confetti' + FORM_PREFILL_SIGNATURE_KEY = 'form_prefill_signature' ESIGNING_PREFERENCE_KEY = 'esigning_preference' WEBHOOK_PREFERENCES_KEY = 'webhook_preferences' DOWNLOAD_LINKS_AUTH_KEY = 'download_links_auth' diff --git a/app/views/accounts/show.html.erb b/app/views/accounts/show.html.erb index 692c3f95a..9e27a4c99 100644 --- a/app/views/accounts/show.html.erb +++ b/app/views/accounts/show.html.erb @@ -75,6 +75,18 @@ <% end %> <% end %> + <% account_config = AccountConfig.find_or_initialize_by(account: current_account, key: AccountConfig::FORM_PREFILL_SIGNATURE_KEY) %> + <% if can?(:manage, account_config) %> + <%= form_for account_config, url: account_configs_path, method: :post do |f| %> + <%= f.hidden_field :key %> +