diff --git a/Dockerfile b/Dockerfile index 23ee1f4b..969084aa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,7 @@ RUN apk --no-cache add fontforge wget && \ wget https://github.com/Maxattax97/gnu-freefont/raw/master/ttf/FreeSans.ttf && \ wget https://github.com/impallari/DancingScript/raw/master/OFL.txt && \ wget -O /model.onnx "https://github.com/docusealco/fields-detection/releases/download/2.0.0/model_704_int8.onnx" && \ - wget -O pdfium-linux.tgz "https://github.com/docusealco/pdfium-binaries/releases/latest/download/pdfium-linux-$(uname -m | sed 's/x86_64/x64/;s/aarch64/arm64/').tgz" && \ + wget -O pdfium-linux.tgz "https://github.com/bblanchon/pdfium-binaries/releases/latest/download/pdfium-linux-musl-$(uname -m | sed 's/x86_64/x64/;s/aarch64/arm64/').tgz" && \ mkdir -p /pdfium-linux && \ tar -xzf pdfium-linux.tgz -C /pdfium-linux @@ -47,13 +47,11 @@ FROM ruby:4.0.1-alpine AS app ENV RAILS_ENV=production ENV BUNDLE_WITHOUT="development:test" -ENV LD_PRELOAD=/lib/libgcompat.so.0 ENV OPENSSL_CONF=/etc/openssl_legacy.cnf -ENV VIPS_MAX_COORD=15000 WORKDIR /app -RUN apk add --no-cache sqlite-dev libpq-dev vips-dev yaml-dev redis libheif vips-heif gcompat ttf-freefont onnxruntime && mkdir /fonts && rm /usr/share/fonts/freefont/FreeSans.otf +RUN apk add --no-cache libpq vips redis vips-heif ttf-freefont onnxruntime && mkdir /fonts && rm /usr/share/fonts/freefont/FreeSans.otf RUN addgroup -g 2000 docuseal && adduser -u 2000 -G docuseal -s /bin/sh -D -h /home/docuseal docuseal @@ -71,7 +69,7 @@ activate = 1' >> /etc/openssl_legacy.cnf COPY --chown=docuseal:docuseal ./Gemfile ./Gemfile.lock ./ -RUN apk add --no-cache build-base git && bundle install && apk del --no-cache build-base git && rm -rf ~/.bundle /usr/local/bundle/cache && ruby -e "puts Dir['/usr/local/bundle/**/{spec,rdoc,resources/shared,resources/collation,resources/locales}']" | xargs rm -rf && ln -sf /usr/lib/libonnxruntime.so.1 $(ruby -e "print Dir[Gem::Specification.find_by_name('onnxruntime').gem_dir + '/vendor/*.so'].first") +RUN apk add --no-cache build-base git libpq-dev yaml-dev && bundle install && apk del --no-cache build-base git libpq-dev yaml-dev && rm -rf ~/.bundle /usr/local/bundle/cache && ruby -e "puts Dir['/usr/local/bundle/**/{spec,rdoc,resources/shared,resources/collation,resources/locales,resources/unicode_data/properties}'] + Dir['/usr/local/bundle/gems/*/{test,tests,examples,sample,misc,doc,docs}'] + Dir['/usr/local/bundle/gems/*/ext/**/*.{c,h,o,S}']" | xargs rm -rf && ln -sf /usr/lib/libonnxruntime.so.1 $(ruby -e "print Dir[Gem::Specification.find_by_name('onnxruntime').gem_dir + '/vendor/*.so'].first") COPY --chown=docuseal:docuseal ./bin ./bin COPY --chown=docuseal:docuseal ./app ./app @@ -98,6 +96,7 @@ RUN ln -s /fonts /app/public/fonts && \ WORKDIR /data/docuseal ENV HOME=/home/docuseal ENV WORKDIR=/data/docuseal +ENV VIPS_MAX_COORD=17000 EXPOSE 3000 CMD ["/app/bin/bundle", "exec", "puma", "-C", "/app/config/puma.rb", "--dir", "/app"] diff --git a/Gemfile.lock b/Gemfile.lock index ce504fee..d97a7bc9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,31 +1,31 @@ GEM remote: https://rubygems.org/ specs: - action_text-trix (2.1.16) + action_text-trix (2.1.17) railties - actioncable (8.1.2) - actionpack (= 8.1.2) - activesupport (= 8.1.2) + actioncable (8.1.3) + actionpack (= 8.1.3) + activesupport (= 8.1.3) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (8.1.2) - actionpack (= 8.1.2) - activejob (= 8.1.2) - activerecord (= 8.1.2) - activestorage (= 8.1.2) - activesupport (= 8.1.2) + actionmailbox (8.1.3) + actionpack (= 8.1.3) + activejob (= 8.1.3) + activerecord (= 8.1.3) + activestorage (= 8.1.3) + activesupport (= 8.1.3) mail (>= 2.8.0) - actionmailer (8.1.2) - actionpack (= 8.1.2) - actionview (= 8.1.2) - activejob (= 8.1.2) - activesupport (= 8.1.2) + actionmailer (8.1.3) + actionpack (= 8.1.3) + actionview (= 8.1.3) + activejob (= 8.1.3) + activesupport (= 8.1.3) mail (>= 2.8.0) rails-dom-testing (~> 2.2) - actionpack (8.1.2) - actionview (= 8.1.2) - activesupport (= 8.1.2) + actionpack (8.1.3) + actionview (= 8.1.3) + activesupport (= 8.1.3) nokogiri (>= 1.8.5) rack (>= 2.2.4) rack-session (>= 1.0.1) @@ -33,36 +33,36 @@ GEM rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) useragent (~> 0.16) - actiontext (8.1.2) + actiontext (8.1.3) action_text-trix (~> 2.1.15) - actionpack (= 8.1.2) - activerecord (= 8.1.2) - activestorage (= 8.1.2) - activesupport (= 8.1.2) + actionpack (= 8.1.3) + activerecord (= 8.1.3) + activestorage (= 8.1.3) + activesupport (= 8.1.3) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (8.1.2) - activesupport (= 8.1.2) + actionview (8.1.3) + activesupport (= 8.1.3) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - activejob (8.1.2) - activesupport (= 8.1.2) + activejob (8.1.3) + activesupport (= 8.1.3) globalid (>= 0.3.6) - activemodel (8.1.2) - activesupport (= 8.1.2) - activerecord (8.1.2) - activemodel (= 8.1.2) - activesupport (= 8.1.2) + activemodel (8.1.3) + activesupport (= 8.1.3) + activerecord (8.1.3) + activemodel (= 8.1.3) + activesupport (= 8.1.3) timeout (>= 0.4.0) - activestorage (8.1.2) - actionpack (= 8.1.2) - activejob (= 8.1.2) - activerecord (= 8.1.2) - activesupport (= 8.1.2) + activestorage (8.1.3) + actionpack (= 8.1.3) + activejob (= 8.1.3) + activerecord (= 8.1.3) + activesupport (= 8.1.3) marcel (~> 1.0) - activesupport (8.1.2) + activesupport (8.1.3) base64 bigdecimal concurrent-ruby (~> 1.0, >= 1.3.1) @@ -318,7 +318,7 @@ GEM multi_json (1.19.1) net-http (0.9.1) uri (>= 0.11.1) - net-imap (0.6.2) + net-imap (0.6.3) date net-protocol net-pop (0.1.2) @@ -394,20 +394,20 @@ GEM rack (>= 1.3) rackup (2.3.1) rack (>= 3) - rails (8.1.2) - actioncable (= 8.1.2) - actionmailbox (= 8.1.2) - actionmailer (= 8.1.2) - actionpack (= 8.1.2) - actiontext (= 8.1.2) - actionview (= 8.1.2) - activejob (= 8.1.2) - activemodel (= 8.1.2) - activerecord (= 8.1.2) - activestorage (= 8.1.2) - activesupport (= 8.1.2) + rails (8.1.3) + actioncable (= 8.1.3) + actionmailbox (= 8.1.3) + actionmailer (= 8.1.3) + actionpack (= 8.1.3) + actiontext (= 8.1.3) + actionview (= 8.1.3) + activejob (= 8.1.3) + activemodel (= 8.1.3) + activerecord (= 8.1.3) + activestorage (= 8.1.3) + activesupport (= 8.1.3) bundler (>= 1.15.0) - railties (= 8.1.2) + railties (= 8.1.3) rails-dom-testing (2.3.0) activesupport (>= 5.0.0) minitest @@ -418,9 +418,9 @@ GEM rails-i18n (8.1.0) i18n (>= 0.7, < 2) railties (>= 8.0.0, < 9) - railties (8.1.2) - actionpack (= 8.1.2) - activesupport (= 8.1.2) + railties (8.1.3) + actionpack (= 8.1.3) + activesupport (= 8.1.3) irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) @@ -543,7 +543,7 @@ GEM activemodel (>= 3.0, < 9.0) strscan (3.1.7) thor (1.5.0) - timeout (0.6.0) + timeout (0.6.1) trailblazer-option (0.1.2) trilogy (2.10.0) bigdecimal diff --git a/app/controllers/account_configs_controller.rb b/app/controllers/account_configs_controller.rb index 66d0967b..079866d7 100644 --- a/app/controllers/account_configs_controller.rb +++ b/app/controllers/account_configs_controller.rb @@ -11,6 +11,7 @@ class AccountConfigsController < ApplicationController AccountConfig::FORCE_MFA, AccountConfig::ALLOW_TO_RESUBMIT, AccountConfig::ALLOW_TO_DECLINE_KEY, + AccountConfig::ALLOW_TO_DELEGATE_KEY, AccountConfig::FORM_PREFILL_SIGNATURE_KEY, AccountConfig::ESIGNING_PREFERENCE_KEY, AccountConfig::FORM_WITH_CONFETTI_KEY, @@ -36,7 +37,7 @@ class AccountConfigsController < ApplicationController end def destroy - raise InvalidKey unless ALLOWED_KEYS.include?(@account_config.key) + raise InvalidKey unless allowed_keys.include?(@account_config.key) @account_config.destroy! @@ -45,8 +46,12 @@ class AccountConfigsController < ApplicationController private + def allowed_keys + ALLOWED_KEYS + end + def load_account_config - raise InvalidKey unless ALLOWED_KEYS.include?(account_config_params[:key]) + raise InvalidKey unless allowed_keys.include?(account_config_params[:key]) @account_config = AccountConfig.find_or_initialize_by(account: current_account, key: account_config_params[:key]) diff --git a/app/controllers/errors_controller.rb b/app/controllers/errors_controller.rb index 0c9e3632..f6401243 100644 --- a/app/controllers/errors_controller.rb +++ b/app/controllers/errors_controller.rb @@ -40,7 +40,7 @@ class ErrorsController < ActionController::Base render json: { status: error_status_code, error: }.compact, status: error_status_code end - f.html { render error_status_code.to_s, status: error_status_code } + f.any { render error_status_code.to_s, status: error_status_code } end end @@ -51,7 +51,7 @@ class ErrorsController < ActionController::Base headers['Access-Control-Allow-Methods'] = 'POST, GET, PUT, PATCH, DELETE, OPTIONS' headers['Access-Control-Allow-Headers'] = '*' headers['Access-Control-Max-Age'] = '1728000' - headers['Access-Control-Allow-Credentials'] = true + headers['Access-Control-Allow-Credentials'] = 'true' end def error_status_code diff --git a/app/controllers/submission_events_controller.rb b/app/controllers/submission_events_controller.rb index 28011799..0dad2336 100644 --- a/app/controllers/submission_events_controller.rb +++ b/app/controllers/submission_events_controller.rb @@ -16,6 +16,7 @@ class SubmissionEventsController < ApplicationController 'email_verified' => 'email_check', 'click_sms' => 'hand_click', 'decline_form' => 'x', + 'delegate_form' => 'user_share', 'start_verification' => 'player_play', 'complete_verification' => 'check', 'invite_party' => 'user_plus' diff --git a/app/controllers/submit_form_controller.rb b/app/controllers/submit_form_controller.rb index 5a6a0ae5..4155b9f6 100644 --- a/app/controllers/submit_form_controller.rb +++ b/app/controllers/submit_form_controller.rb @@ -3,11 +3,12 @@ class SubmitFormController < ApplicationController layout 'form' - around_action :with_browser_locale, only: %i[show completed success] + around_action :with_browser_locale, only: %i[show completed success delegated] skip_before_action :authenticate_user! skip_authorization_check before_action :load_submitter, only: %i[show update completed] + before_action :maybe_redirect_delegated, only: %i[show completed] before_action :maybe_render_locked_page, only: :show before_action :maybe_require_link_2fa, only: %i[show] @@ -91,6 +92,12 @@ class SubmitFormController < ApplicationController def success; end + def delegated + submitter_version = SubmitterVersion.find_by!(slug: params[:slug] || params[:submit_form_slug]) + + @submitter = submitter_version.submitter + end + private def maybe_require_link_2fa @@ -108,8 +115,18 @@ class SubmitFormController < ApplicationController render :declined if @submitter.declined_at? end + def maybe_redirect_delegated + return if @submitter + + submitter_version = SubmitterVersion.find_by!(slug: params[:slug] || params[:submit_form_slug]) + + submitter_version.submitter.submission_events.find_by!(event_type: :delegate_form) + + redirect_to submit_form_delegated_path(submitter_version.slug) + end + def load_submitter - @submitter = Submitter.find_by!(slug: params[:slug] || params[:submit_form_slug]) + @submitter = Submitter.find_by(slug: params[:slug] || params[:submit_form_slug]) end def build_attachments_index(submission) diff --git a/app/controllers/submit_form_decline_controller.rb b/app/controllers/submit_form_decline_controller.rb index a8f969c3..a55590f1 100644 --- a/app/controllers/submit_form_decline_controller.rb +++ b/app/controllers/submit_form_decline_controller.rb @@ -4,31 +4,38 @@ class SubmitFormDeclineController < ApplicationController skip_before_action :authenticate_user! skip_authorization_check - def create - submitter = Submitter.find_by!(slug: params[:submit_form_slug]) + before_action :load_submitter - return redirect_to submit_form_path(submitter.slug) if submitter.declined_at? || - submitter.completed_at? || - submitter.submission.archived_at? || - submitter.submission.expired? || - submitter.submission.template&.archived_at? || - !Submitters::AuthorizedForForm.call(submitter, current_user, - request) + def create + return redirect_to submit_form_path(@submitter.slug) if @submitter.declined_at? || + @submitter.completed_at? || + @submitter.submission.archived_at? || + @submitter.submission.expired? || + @submitter.submission.template&.archived_at? || + !Submitters::AuthorizedForForm.call(@submitter, + current_user, + request) ApplicationRecord.transaction do - submitter.update!(declined_at: Time.current) + @submitter.update!(declined_at: Time.current) - SubmissionEvents.create_with_tracking_data(submitter, 'decline_form', request, { reason: params[:reason] }) + SubmissionEvents.create_with_tracking_data(@submitter, 'decline_form', request, { reason: params[:reason] }) end - user = submitter.submission.created_by_user || submitter.template.author + user = @submitter.submission.created_by_user || @submitter.template.author if user.user_configs.find_by(key: UserConfig::RECEIVE_DECLINED_EMAIL)&.value != false - SubmitterMailer.declined_email(submitter, user).deliver_later! + SubmitterMailer.declined_email(@submitter, user).deliver_later! end - WebhookUrls.enqueue_events(submitter, 'form.declined') + WebhookUrls.enqueue_events(@submitter, 'form.declined') + + redirect_to submit_form_path(@submitter.slug) + end + + private - redirect_to submit_form_path(submitter.slug) + def load_submitter + @submitter = Submitter.find_by!(slug: params[:submit_form_slug]) end end diff --git a/app/controllers/submit_form_delegate_controller.rb b/app/controllers/submit_form_delegate_controller.rb new file mode 100644 index 00000000..0a516509 --- /dev/null +++ b/app/controllers/submit_form_delegate_controller.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +class SubmitFormDelegateController < ApplicationController + skip_before_action :authenticate_user! + skip_authorization_check + + before_action :load_submitter + + def create + return redirect_to submit_form_path(@submitter.slug) if @submitter.declined_at? || + @submitter.completed_at? || + @submitter.submission.archived_at? || + @submitter.submission.expired? || + @submitter.submission.template&.archived_at? || + !Submitters::AuthorizedForForm.call(@submitter, + current_user, + request) + + @submitter.account.account_configs.find_by!(key: AccountConfig::ALLOW_TO_DELEGATE_KEY, value: true) + + email = Submissions.normalize_email(params[:email]) + + return redirect_to submit_form_path(@submitter.slug) if email.blank? + + old_slug = @submitter.slug + + ApplicationRecord.transaction do + @submitter.submitter_versions.create!(slug: old_slug, email: @submitter.email, + name: @submitter.name, phone: @submitter.phone) + + SubmissionEvents.create_with_tracking_data(@submitter, 'delegate_form', request, + { old_email: @submitter.email, email: }) + + @submitter.update!(email:, phone: nil, name: nil, slug: SecureRandom.base58(14)) + end + + SendSubmitterInvitationEmailJob.perform_async('submitter_id' => @submitter.id) + + redirect_to submit_form_delegated_path(old_slug) + end + + private + + def load_submitter + @submitter = Submitter.find_by!(slug: params[:submit_form_slug]) + end +end diff --git a/app/javascript/form.js b/app/javascript/form.js index 1fbd54c8..00ec8743 100644 --- a/app/javascript/form.js +++ b/app/javascript/form.js @@ -36,7 +36,7 @@ safeRegisterElement('submission-form', class extends HTMLElement { expand: ['true', 'false'].includes(this.dataset.expand) ? this.dataset.expand === 'true' : null, withSignatureId: this.dataset.withSignatureId === 'true', requireSigningReason: this.dataset.requireSigningReason === 'true', - withConfetti: this.dataset.withConfetti !== 'false', + withConfetti: this.dataset.withConfetti === 'true', withFieldLabels: this.dataset.withFieldLabels !== 'false', withDisclosure: this.dataset.withDisclosure === 'true', reuseSignature: this.dataset.reuseSignature !== 'false', diff --git a/app/models/account_config.rb b/app/models/account_config.rb index 7781e293..8d41bca4 100644 --- a/app/models/account_config.rb +++ b/app/models/account_config.rb @@ -30,6 +30,7 @@ class AccountConfig < ApplicationRecord ALLOW_TYPED_SIGNATURE = 'allow_typed_signature' ALLOW_TO_RESUBMIT = 'allow_to_resubmit' ALLOW_TO_DECLINE_KEY = 'allow_to_decline' + ALLOW_TO_DELEGATE_KEY = 'allow_to_delegate' ALLOW_TO_PARTIAL_DOWNLOAD_KEY = 'allow_to_partial_download' SUBMITTER_REMINDERS = 'submitter_reminders' ENFORCE_SIGNING_ORDER_KEY = 'enforce_signing_order' diff --git a/app/models/submission_event.rb b/app/models/submission_event.rb index 8aece806..e88d192f 100644 --- a/app/models/submission_event.rb +++ b/app/models/submission_event.rb @@ -64,6 +64,7 @@ class SubmissionEvent < ApplicationRecord invite_party: 'invite_party', complete_form: 'complete_form', decline_form: 'decline_form', + delegate_form: 'delegate_form', api_complete_form: 'api_complete_form' }, scope: false diff --git a/app/models/submitter.rb b/app/models/submitter.rb index 205a3b0c..0e4bc6c2 100644 --- a/app/models/submitter.rb +++ b/app/models/submitter.rb @@ -44,6 +44,7 @@ class Submitter < ApplicationRecord belongs_to :account has_one :template, through: :submission has_one :search_entry, as: :record, inverse_of: :record, dependent: :destroy if SearchEntry.table_exists? + has_many :submitter_versions, dependent: :destroy attribute :values, :string, default: -> { {} } attribute :preferences, :string, default: -> { {} } diff --git a/app/models/submitter_version.rb b/app/models/submitter_version.rb new file mode 100644 index 00000000..ea67a745 --- /dev/null +++ b/app/models/submitter_version.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +# == Schema Information +# +# Table name: submitter_versions +# +# id :bigint not null, primary key +# email :string +# name :string +# phone :string +# slug :string not null +# created_at :datetime not null +# updated_at :datetime not null +# submitter_id :bigint not null +# +# Indexes +# +# index_submitter_versions_on_slug (slug) +# index_submitter_versions_on_submitter_id (submitter_id) +# +# Foreign Keys +# +# fk_rails_... (submitter_id => submitters.id) +# +class SubmitterVersion < ApplicationRecord + belongs_to :submitter +end diff --git a/app/views/accounts/show.html.erb b/app/views/accounts/show.html.erb index 8ee0e45f..ba9a9c49 100644 --- a/app/views/accounts/show.html.erb +++ b/app/views/accounts/show.html.erb @@ -131,23 +131,50 @@ <% end %> <% end %> - <% if !Docuseal.multitenant? || can?(:manage, :disable_decline) %> - <% account_config = AccountConfig.find_or_initialize_by(account: current_account, key: AccountConfig::ALLOW_TO_DECLINE_KEY) %> - <% if can?(:manage, account_config) %> - <%= form_for account_config, url: account_configs_path, method: :post do |f| %> - <%= f.hidden_field :key %> -
-
- <%= t('allow_to_decline_documents') %> - - <%= svg_icon('info_circle', class: 'hidden md:inline-block w-4 h-4 shrink-0') %> - -
+ <% account_config = AccountConfig.find_or_initialize_by(account: current_account, key: AccountConfig::ALLOW_TO_DECLINE_KEY) %> + <% if can?(:manage, account_config) %> + <%= form_for account_config, url: account_configs_path, method: :post do |f| %> + <%= f.hidden_field :key %> +
+
+ <%= t('allow_to_decline_documents') %> + + <%= svg_icon('info_circle', class: 'hidden md:inline-block w-4 h-4 shrink-0') %> + +
+ <% if !Docuseal.multitenant? || can?(:manage, :disable_decline) %> <%= f.check_box :value, class: 'toggle', checked: account_config.value != false %> + <% else %> + " data-turbo="false" data-tip="<%= I18n.t('unlock_with_docuseal_pro') %>" data-on="change" class="flex tooltip"> + <%= f.check_box :value, class: 'toggle pointer-events-none', checked: account_config.value != false, disabled: true %> + + <% end %> +
+ <% end %> + <% end %> + <% account_config = AccountConfig.find_or_initialize_by(account: current_account, key: AccountConfig::ALLOW_TO_DELEGATE_KEY) %> + <% if can?(:manage, account_config) %> + <%= form_for account_config, url: account_configs_path, method: :post do |f| %> + <%= f.hidden_field :key %> +
+
+ <%= t('allow_to_delegate_documents') %> + + <%= svg_icon('info_circle', class: 'hidden md:inline-block w-4 h-4 shrink-0') %> +
- <% end %> + <% if !Docuseal.multitenant? || can?(:manage, :delegate_form) %> + + <%= f.check_box :value, class: 'toggle', checked: account_config.value == true %> + + <% else %> + " data-turbo="false" data-tip="<%= I18n.t('unlock_with_docuseal_pro') %>" class="flex tooltip"> + <%= f.check_box :value, class: 'toggle pointer-events-none', checked: account_config.value == true, disabled: true %> + + <% end %> +
<% end %> <% end %> <% account_config = AccountConfig.find_or_initialize_by(account: current_account, key: AccountConfig::FORM_PREFILL_SIGNATURE_KEY) %> diff --git a/app/views/icons/_user_share.html.erb b/app/views/icons/_user_share.html.erb new file mode 100644 index 00000000..ecb37945 --- /dev/null +++ b/app/views/icons/_user_share.html.erb @@ -0,0 +1 @@ + diff --git a/app/views/personalization_settings/_form_toggle_options.html.erb b/app/views/personalization_settings/_form_toggle_options.html.erb index f57dbee8..195ef0f1 100644 --- a/app/views/personalization_settings/_form_toggle_options.html.erb +++ b/app/views/personalization_settings/_form_toggle_options.html.erb @@ -1,4 +1,4 @@ -<% account_config = AccountConfig.where(account: current_account, key: AccountConfig::FORM_WITH_CONFETTI_KEY).first_or_initialize(value: true) %> +<% account_config = AccountConfig.where(account: current_account, key: AccountConfig::FORM_WITH_CONFETTI_KEY).first_or_initialize(value: false) %> <% if can?(:manage, account_config) %>
<%= form_for account_config, url: account_configs_path, method: :post do |f| %> @@ -8,7 +8,7 @@ <%= t('show_confetti_on_successful_completion') %> - <%= f.check_box :value, { class: 'toggle', checked: account_config.value != false }, '1', '0' %> + <%= f.check_box :value, { class: 'toggle', checked: account_config.value == true }, '1', '0' %>
<% end %> diff --git a/app/views/submission_events/index.html.erb b/app/views/submission_events/index.html.erb index 8dec75f3..1ce6c8c0 100644 --- a/app/views/submission_events/index.html.erb +++ b/app/views/submission_events/index.html.erb @@ -20,10 +20,13 @@ <% end %>

+ <% submitter_versions_index = @submission.submitters.preload(:submitter_versions).each_with_object({}) { |s, h| h[s.id] = s.submitter_versions.to_a.sort_by(&:created_at) } %> <% @submission.submission_events.order(:event_timestamp).each do |event| %> <% submitter = @submission.submitters.find { |e| e.id == event.submitter_id } %> <% bg_class = event_colors[submitters_uuids.index(submitter.uuid) % event_colors.length] %> - <% submitter_name = event.event_type.include?('sms') || event.event_type.include?('phone') ? (event.data['phone'] || submitter.phone) : (submitter.name || submitter.email || submitter.phone) %> + <% versions = submitter_versions_index[submitter.id] || [] %> + <% active_version = versions.find { |v| v.created_at > event.event_timestamp } %> + <% submitter_name = event.event_type.include?('sms') || event.event_type.include?('phone') ? (event.data['phone'] || active_version&.phone || submitter.phone) : (active_version&.name || active_version&.email || active_version&.phone || submitter.name || submitter.email || submitter.phone) %>
  • <%= svg_icon(SubmissionEventsController::SUBMISSION_EVENT_ICONS.fetch(event.event_type, 'circle_dot'), class: 'w-4 h-4') %> @@ -43,6 +46,9 @@ <%= t('submission_event_names.complete_verification_by_html', provider: event.data['method'], submitter_name:) %> <% elsif event.event_type == 'invite_party' && (invited_submitter = @submission.submitters.find { |e| e.uuid == event.data['uuid'] }) && (name = @submission.template_submitters.find { |e| e['uuid'] == event.data['uuid'] }&.dig('name')) %> <%= t('submission_event_names.invite_party_by_html', invited_submitter_name: [invited_submitter.name || invited_submitter.email || invited_submitter.phone, name].join(' '), submitter_name:) %> + <% elsif event.event_type == 'delegate_form' %> + <% delegate_from = event.data['old_email'].presence || (versions.reverse.find { |v| v.created_at <= event.event_timestamp }&.then { |v| v.name || v.phone }) %> + <%= t('submission_event_names.delegate_form_by_html', from: delegate_from, to: event.data['email']) %> <% elsif event.event_type.include?('send_') %> <%= t("submission_event_names.#{event.event_type}_to_html", submitter_name:) %> <% elsif event.event_type.start_with?('bounce_') || event.event_type.start_with?('complaint_') %> diff --git a/app/views/submissions/_detailed_form.html.erb b/app/views/submissions/_detailed_form.html.erb index 62f756fd..e6759580 100644 --- a/app/views/submissions/_detailed_form.html.erb +++ b/app/views/submissions/_detailed_form.html.erb @@ -3,7 +3,7 @@ <% submitters = template.submitters.reject { |e| e['invite_by_uuid'].present? || e['optional_invite_by_uuid'].present? || e['invite_via_field_uuid'].present? } %>
    -
    +