From b7103cf010dc5a45c4e7c362402111090105f568 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Mon, 26 Oct 2026 16:33:55 +0200 Subject: [PATCH 01/21] cleanup --- ...e_storage_blobs_proxy_legacy_controller.rb | 53 ------------------- 1 file changed, 53 deletions(-) delete mode 100644 app/controllers/api/active_storage_blobs_proxy_legacy_controller.rb diff --git a/app/controllers/api/active_storage_blobs_proxy_legacy_controller.rb b/app/controllers/api/active_storage_blobs_proxy_legacy_controller.rb deleted file mode 100644 index 3df2dae27..000000000 --- a/app/controllers/api/active_storage_blobs_proxy_legacy_controller.rb +++ /dev/null @@ -1,53 +0,0 @@ -# frozen_string_literal: true - -module Api - class ActiveStorageBlobsProxyLegacyController < ApiBaseController - include ActiveStorage::Streaming - - skip_before_action :authenticate_user! - skip_authorization_check - - before_action :set_cors_headers - before_action :set_noindex_headers - before_action :set_security_headers - - # rubocop:disable Metrics - def show - Rollbar.info('Blob legacy') if defined?(Rollbar) - - blob = ActiveStorage::Blob.find_signed(params[:signed_blob_id] || params[:signed_id]) - - return head :not_found unless blob - - if FilenameUtils.dangerous_extension(blob.filename) - Rollbar.error('Dangerous extension') if defined?(Rollbar) - - return head :unprocessable_content - end - - is_permitted = blob.attachments.any? do |a| - (current_user && a.record.account.id == current_user.account_id) || - a.record.account.account_configs.any? { |e| e.key == 'legacy_blob_proxy' } || - a.name == 'logo' - end - - unless is_permitted - Rollbar.error("Blob account not found: #{blob.id}") if defined?(Rollbar) - - return render json: { error: 'Not authenticated' }, status: :unauthorized - end - - if request.headers['Range'].present? - send_blob_byte_range_data blob, request.headers['Range'] - else - http_cache_forever public: true do - response.headers['Accept-Ranges'] = 'bytes' - response.headers['Content-Length'] = blob.byte_size.to_s - - send_blob_stream blob, disposition: params[:disposition] - end - end - end - # rubocop:enable Metrics - end -end From af4672084d0a32dc0e79cfa2993dda8e4ade724b Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Mon, 26 Oct 2026 17:14:45 +0200 Subject: [PATCH 02/21] optimize query --- app/controllers/api/submitters_controller.rb | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/submitters_controller.rb b/app/controllers/api/submitters_controller.rb index a547ba75a..86361ec7d 100644 --- a/app/controllers/api/submitters_controller.rb +++ b/app/controllers/api/submitters_controller.rb @@ -179,11 +179,28 @@ module Api submitters = submitters.where(external_id: params[:external_id]) if params[:external_id].present? submitters = submitters.where(slug: params[:slug]) if params[:slug].present? submitters = submitters.where(submission_id: params[:submission_id]) if params[:submission_id].present? - submitters = submitters.where(template_id: params[:template_id]) if params[:template_id].present? + submitters = filter_submitters_by_template_id(submitters, params[:template_id]) if params[:template_id].present? maybe_filter_by_completed_at(submitters, params) end + def filter_submitters_by_template_id(submitters, template_id) + return submitters.where(template_id:) if template_id.is_a?(Array) + + template = Template.find_by(id: template_id) + + return submitters.none if template.nil? || !can?(:read, template) + + if template.account_id == current_user.account_id + account_id_bind = Submitter.predicate_builder.build_bind_attribute('account_id', current_user.account_id) + + submitters = submitters.unscope(where: :account_id) + .where((Submitter.arel_table[:account_id] + 0).eq(account_id_bind)) + end + + submitters.where(template_id: template.id) + end + def assign_external_id(submitter, attrs) submitter.external_id = attrs[:application_key] if attrs.key?(:application_key) submitter.external_id = attrs[:external_id] if attrs.key?(:external_id) From d3c92cecfa27fe64551fdaf60178190e9a726c5c Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Mon, 26 Oct 2026 17:57:03 +0200 Subject: [PATCH 03/21] carry lang param --- app/controllers/application_controller.rb | 4 ++++ app/controllers/start_form_controller.rb | 10 +++++----- .../start_form_email_2fa_send_controller.rb | 6 +++--- app/controllers/submit_form_controller.rb | 6 +++--- .../submit_form_email_2fas_controller.rb | 15 ++++++++------- app/views/start_form/email_verification.html.erb | 4 ++-- app/views/start_form/show.html.erb | 2 +- app/views/submit_form/email_2fa.html.erb | 5 +++-- 8 files changed, 29 insertions(+), 23 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 33257be89..21300338f 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -99,6 +99,10 @@ class ApplicationController < ActionController::Base I18n.with_locale(locale, &) end + def lang + params[:lang].presence + end + def with_browser_locale(&) return yield if I18n.locale != :'en-US' && I18n.locale != :en diff --git a/app/controllers/start_form_controller.rb b/app/controllers/start_form_controller.rb index 86471d381..4431c3073 100644 --- a/app/controllers/start_form_controller.rb +++ b/app/controllers/start_form_controller.rb @@ -34,7 +34,7 @@ class StartFormController < ApplicationController @submitter = find_or_initialize_submitter(@template, submitter_params) if @submitter.completed_at? - redirect_to start_form_completed_path(@template.slug, submitter_params.compact_blank) + redirect_to start_form_completed_path(@template.slug, submitter_params.compact_blank.merge(lang:)) else if Templates.filter_undefined_submitters(@template.submitters).size > 1 && @submitter.new_record? @error_message = multiple_submitters_error_message @@ -59,7 +59,7 @@ class StartFormController < ApplicationController Submitters::StartForm.assign_start_form_cookie(@submitter, request) - redirect_to submit_form_path(@submitter.slug) + redirect_to submit_form_path(@submitter.slug, lang:) else render :show, status: :unprocessable_content end @@ -150,7 +150,7 @@ class StartFormController < ApplicationController return render :show, status: :unprocessable_content if submitter.errors.present? if Submitters::StartForm.verify_2fa_and_save_submitter(submitter, request, is_new_record: submitter.new_record?) - redirect_to submit_form_path(submitter.slug) + redirect_to submit_form_path(submitter.slug, lang:) else if defined?(Rollbar) && template.preferences['shared_link_2fa'] != true Rollbar.info("2FA link requested: #{submitter.id}") @@ -167,10 +167,10 @@ class StartFormController < ApplicationController render :error, status: :unprocessable_content rescue Submitters::UnableToSendCode, Submitters::InvalidOtp => e - redirect_to start_form_path(template.slug, params: submitter_params.merge(email_verification: true)), + redirect_to start_form_path(template.slug, lang:, params: submitter_params.merge(email_verification: true)), alert: e.message rescue RateLimit::LimitApproached - redirect_to start_form_path(template.slug, params: submitter_params.merge(email_verification: true)), + redirect_to start_form_path(template.slug, lang:, params: submitter_params.merge(email_verification: true)), alert: I18n.t(:too_many_attempts) end end diff --git a/app/controllers/start_form_email_2fa_send_controller.rb b/app/controllers/start_form_email_2fa_send_controller.rb index 0787ab468..389baa59a 100644 --- a/app/controllers/start_form_email_2fa_send_controller.rb +++ b/app/controllers/start_form_email_2fa_send_controller.rb @@ -16,21 +16,21 @@ class StartFormEmail2faSendController < ApplicationController .submitters.new(**submitter_params, account_id: @template.account_id) if @submitter.email.blank? - return redirect_to start_form_path(@template.slug), alert: I18n.t(:provide_your_email_to_start) + return redirect_to start_form_path(@template.slug, lang:), alert: I18n.t(:provide_your_email_to_start) end Submitters.send_shared_link_email_verification_code(@submitter, request:) redir_params = { notice: I18n.t(:code_has_been_resent) } if params[:resend] - redirect_to start_form_path(@template.slug, params: submitter_params.merge(email_verification: true)), + redirect_to start_form_path(@template.slug, lang:, params: submitter_params.merge(email_verification: true)), **redir_params rescue Submitters::BouncedEmail => e @error_message = e.message render 'start_form/error', status: :unprocessable_content rescue Submitters::UnableToSendCode => e - redirect_to start_form_path(@template.slug, params: submitter_params.merge(email_verification: true)), + redirect_to start_form_path(@template.slug, lang:, params: submitter_params.merge(email_verification: true)), alert: e.message end diff --git a/app/controllers/submit_form_controller.rb b/app/controllers/submit_form_controller.rb index 2f3ab0cb2..06eb475ec 100644 --- a/app/controllers/submit_form_controller.rb +++ b/app/controllers/submit_form_controller.rb @@ -20,7 +20,7 @@ class SubmitFormController < ApplicationController return render :email_2fa unless Submitters::AuthorizedForForm.pass_email_2fa?(@submitter, request) if @submitter.completed_at? || submission.completed_at? - return redirect_to submit_form_completed_path(@submitter.slug) + return redirect_to submit_form_completed_path(@submitter.slug, lang:) end @form_configs = Submitters::FormConfigs.call(@submitter, CONFIG_KEYS) @@ -96,7 +96,7 @@ class SubmitFormController < ApplicationController return if Submitters::AuthorizedForForm.call(@submitter, current_user, request) - redirect_to submit_form_path(params[:submit_form_slug]) + redirect_to submit_form_path(params[:submit_form_slug], lang:) end def success; end @@ -114,7 +114,7 @@ class SubmitFormController < ApplicationController def maybe_require_link_2fa return if Submitters::AuthorizedForForm.pass_link_2fa?(@submitter, current_user, request) - redirect_to start_form_path(@submitter.submission.template.slug) + redirect_to start_form_path(@submitter.submission.template.slug, lang:) end def maybe_render_locked_page diff --git a/app/controllers/submit_form_email_2fas_controller.rb b/app/controllers/submit_form_email_2fas_controller.rb index 6f95e7544..6c6ad52eb 100644 --- a/app/controllers/submit_form_email_2fas_controller.rb +++ b/app/controllers/submit_form_email_2fas_controller.rb @@ -20,17 +20,17 @@ class SubmitFormEmail2fasController < ApplicationController { value: @submitter.slug, expires: Submitters::StartForm::COOKIES_TTL.from_now, **Submitters::StartForm::COOKIES_DEFAULTS } - redirect_to submit_form_path(@submitter.slug) + redirect_to submit_form_path(@submitter.slug, lang:) else - redirect_to submit_form_path(@submitter.slug, status: :error), alert: I18n.t(:invalid_code) + redirect_to submit_form_path(@submitter.slug, status: :error, lang:), alert: I18n.t(:invalid_code) end rescue RateLimit::LimitApproached - redirect_to submit_form_path(@submitter.slug, status: :error), alert: I18n.t(:too_many_attempts) + redirect_to submit_form_path(@submitter.slug, status: :error, lang:), alert: I18n.t(:too_many_attempts) end def update if @submitter.submission_events.where(event_type: 'send_2fa_email').exists?(created_at: 15.seconds.ago..) - return redirect_to submit_form_path(@submitter.slug, status: :error), alert: I18n.t(:rate_limit_exceeded) + return redirect_to submit_form_path(@submitter.slug, status: :error, lang:), alert: I18n.t(:rate_limit_exceeded) end RateLimit.call("send-email-code-#{@submitter.id}", limit: 2, ttl: 45.seconds, enabled: true) @@ -38,16 +38,17 @@ class SubmitFormEmail2fasController < ApplicationController if Docuseal.multitenant? && Submitters.email_bounced_recently?(@submitter.email) Rollbar.warning("Bounced OTP email for submitter: #{@submitter.id}") if defined?(Rollbar) - return redirect_to submit_form_path(@submitter.slug, status: :error), alert: I18n.t(:verification_email_bounced) + return redirect_to submit_form_path(@submitter.slug, status: :error, lang:), + alert: I18n.t(:verification_email_bounced) end SendSubmitterVerificationEmailJob.perform_async('submitter_id' => @submitter.id, 'locale' => I18n.locale.to_s) redir_params = params[:resend] ? { alert: I18n.t(:code_has_been_resent) } : {} - redirect_to submit_form_path(@submitter.slug, status: :sent), **redir_params + redirect_to submit_form_path(@submitter.slug, status: :sent, lang:), **redir_params rescue RateLimit::LimitApproached - redirect_to submit_form_path(@submitter.slug, status: :error), alert: I18n.t(:too_many_attempts) + redirect_to submit_form_path(@submitter.slug, status: :error, lang:), alert: I18n.t(:too_many_attempts) end def load_submitter diff --git a/app/views/start_form/email_verification.html.erb b/app/views/start_form/email_verification.html.erb index 383d8c9f6..8bf7db481 100644 --- a/app/views/start_form/email_verification.html.erb +++ b/app/views/start_form/email_verification.html.erb @@ -23,7 +23,7 @@
<%= t('we_sent_a_one_time_verification_code_to_your_email_address_please_enter_the_code_below_to_continue') %>
- <%= form_for '', url: @resubmit_submitter ? resubmit_form_path : start_form_path(@template.slug), method: :put, html: { class: 'space-y-4', id: 'code_form' } do |f| %> + <%= form_for '', url: @resubmit_submitter ? resubmit_form_path : start_form_path(@template.slug, lang: params[:lang].presence), method: :put, html: { class: 'space-y-4', id: 'code_form' } do |f| %>
<%= f.hidden_field 'resubmit', value: params[:resubmit] %> <%= f.hidden_field 'submitter[name]', value: params[:name] || params.dig(:submitter, :name) %> @@ -52,7 +52,7 @@ <% if @resubmit_submitter %> <%= button_to t(:re_send_email), resubmit_form_path, params: { resubmit: @resubmit_submitter.slug }, method: :put, id: 'resend_code', class: 'hidden' %> <% else %> - <%= button_to t(:re_send_email), start_form_email_2fa_send_index_path, params: { slug: @template.slug, resend: true, submitter: { name: params[:name] || params.dig(:submitter, :name), email: params[:email] || params.dig(:submitter, :email), phone: params[:phone] || params.dig(:submitter, :phone) } }.compact, method: :post, id: 'resend_code', class: 'hidden' %> + <%= button_to t(:re_send_email), start_form_email_2fa_send_index_path, params: { slug: @template.slug, resend: true, submitter: { name: params[:name] || params.dig(:submitter, :name), email: params[:email] || params.dig(:submitter, :email), phone: params[:phone] || params.dig(:submitter, :phone) }, lang: params[:lang] }.compact, method: :post, id: 'resend_code', class: 'hidden' %> <% end %>
diff --git a/app/views/start_form/show.html.erb b/app/views/start_form/show.html.erb index dfe336914..e6c431db4 100644 --- a/app/views/start_form/show.html.erb +++ b/app/views/start_form/show.html.erb @@ -28,7 +28,7 @@ <% if !@template.archived_at? && !@template.account.archived_at? %> - <%= form_for @submitter, url: @resubmit_submitter ? resubmit_form_path : start_form_path(@template.slug), data: { turbo_frame: :_top }, method: :put, html: { class: 'space-y-4' } do |f| %> + <%= form_for @submitter, url: @resubmit_submitter ? resubmit_form_path : start_form_path(@template.slug, lang: params[:lang].presence), data: { turbo_frame: :_top }, method: :put, html: { class: 'space-y-4' } do |f| %> <%= hidden_field_tag :resubmit, @resubmit_submitter.slug if @resubmit_submitter %> <% if @error_message %>
diff --git a/app/views/submit_form/email_2fa.html.erb b/app/views/submit_form/email_2fa.html.erb index 878bad01a..70382ad2f 100644 --- a/app/views/submit_form/email_2fa.html.erb +++ b/app/views/submit_form/email_2fa.html.erb @@ -34,6 +34,7 @@ <%= form_for '', url: submit_form_email_2fa_path, method: :post, html: { class: 'space-y-4', id: 'code_form' } do |f| %>
<%= f.hidden_field :submitter_slug, value: @submitter.slug %> + <%= f.hidden_field :lang, value: params[:lang] if params[:lang].present? %> <%= f.text_field :one_time_code, required: true, inputmode: 'numeric', class: 'base-input text-center', placeholder: 'XXXXXX' %>
@@ -55,7 +56,7 @@ <%= f.button button_title(title: t('submit')), class: 'base-button' %> <% end %> - <%= button_to t(:re_send_email), submit_form_email_2fa_path, params: { submitter_slug: @submitter.slug, resend: true }, method: :put, form: { id: 'resend_code_form', class: 'hidden' } %> + <%= button_to t(:re_send_email), submit_form_email_2fa_path, params: { submitter_slug: @submitter.slug, resend: true, lang: params[:lang] }.compact_blank, method: :put, form: { id: 'resend_code_form', class: 'hidden' } %> <% else %> <% if params[:t] %> @@ -63,7 +64,7 @@ <% end %> - <%= button_to button_title(title: t('send_verification_code')), submit_form_email_2fa_path, params: { submitter_slug: @submitter.slug }, method: :put, class: 'base-button w-full' %> + <%= button_to button_title(title: t('send_verification_code')), submit_form_email_2fa_path, params: { submitter_slug: @submitter.slug, lang: params[:lang] }.compact_blank, method: :put, class: 'base-button w-full' %> <% end %> <% else %> From e22a3d9ef3df0ec16077b8859bc9a58bd4d29c1b Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Tue, 27 Oct 2026 11:24:42 +0200 Subject: [PATCH 04/21] use uuid v7 --- app/controllers/webhook_settings_controller.rb | 2 +- app/jobs/process_submitter_completion_job.rb | 4 ++-- app/models/webhook_event.rb | 2 +- lib/webhook_urls.rb | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/controllers/webhook_settings_controller.rb b/app/controllers/webhook_settings_controller.rb index 77fa22bff..6b6cf9140 100644 --- a/app/controllers/webhook_settings_controller.rb +++ b/app/controllers/webhook_settings_controller.rb @@ -66,7 +66,7 @@ class WebhookSettingsController < ApplicationController SendTestWebhookRequestJob.perform_async( 'submitter_id' => submitter.id, - 'event_uuid' => SecureRandom.uuid, + 'event_uuid' => SecureRandom.uuid_v7, 'webhook_url_id' => @webhook_url.id ) diff --git a/app/jobs/process_submitter_completion_job.rb b/app/jobs/process_submitter_completion_job.rb index 1dc1da132..da4f5b03a 100644 --- a/app/jobs/process_submitter_completion_job.rb +++ b/app/jobs/process_submitter_completion_job.rb @@ -100,7 +100,7 @@ class ProcessSubmitterCompletionJob WebhookUrls.for_account_id(submitter.account_id, %w[form.completed submission.completed]).each do |webhook| if webhook.events.include?('form.completed') - event_uuids['form.completed'] ||= SecureRandom.uuid + event_uuids['form.completed'] ||= SecureRandom.uuid_v7 SendFormCompletedWebhookRequestJob.perform_async('submitter_id' => submitter.id, 'event_uuid' => event_uuids['form.completed'], @@ -109,7 +109,7 @@ class ProcessSubmitterCompletionJob next unless webhook.events.include?('submission.completed') && is_last - event_uuids['submission.completed'] ||= SecureRandom.uuid + event_uuids['submission.completed'] ||= SecureRandom.uuid_v7 SendSubmissionCompletedWebhookRequestJob.perform_async('submission_id' => submitter.submission_id, 'event_uuid' => event_uuids['submission.completed'], diff --git a/app/models/webhook_event.rb b/app/models/webhook_event.rb index 885a16b19..d5bdb6246 100644 --- a/app/models/webhook_event.rb +++ b/app/models/webhook_event.rb @@ -22,7 +22,7 @@ # index_webhook_events_on_webhook_url_id_and_id (webhook_url_id,id) # class WebhookEvent < ApplicationRecord - attribute :uuid, :string, default: -> { SecureRandom.uuid } + attribute :uuid, :string, default: -> { SecureRandom.uuid_v7 } belongs_to :webhook_url, optional: true belongs_to :account, optional: true diff --git a/lib/webhook_urls.rb b/lib/webhook_urls.rb index 242c274cf..5544499a6 100644 --- a/lib/webhook_urls.rb +++ b/lib/webhook_urls.rb @@ -54,7 +54,7 @@ module WebhookUrls webhook_urls = for_account_id(account_id, event_type) account_records.each do |record| - event_uuid = SecureRandom.uuid + event_uuid = SecureRandom.uuid_v7 webhook_urls.each do |webhook_url| next unless webhook_url.events.include?(event_type) From 2af09afc66c20637ccd3d496c23fa53ba175cc33 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Tue, 27 Oct 2026 15:31:15 +0200 Subject: [PATCH 05/21] add lang --- app/controllers/application_controller.rb | 4 ---- app/controllers/start_form_controller.rb | 4 ++++ app/controllers/start_form_email_2fa_send_controller.rb | 4 ++++ app/controllers/submit_form_controller.rb | 4 ++++ app/controllers/submit_form_email_2fas_controller.rb | 4 ++++ 5 files changed, 16 insertions(+), 4 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 21300338f..33257be89 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -99,10 +99,6 @@ class ApplicationController < ActionController::Base I18n.with_locale(locale, &) end - def lang - params[:lang].presence - end - def with_browser_locale(&) return yield if I18n.locale != :'en-US' && I18n.locale != :en diff --git a/app/controllers/start_form_controller.rb b/app/controllers/start_form_controller.rb index 4431c3073..7227bd93a 100644 --- a/app/controllers/start_form_controller.rb +++ b/app/controllers/start_form_controller.rb @@ -173,4 +173,8 @@ class StartFormController < ApplicationController redirect_to start_form_path(template.slug, lang:, params: submitter_params.merge(email_verification: true)), alert: I18n.t(:too_many_attempts) end + + def lang + params[:lang].presence + end end diff --git a/app/controllers/start_form_email_2fa_send_controller.rb b/app/controllers/start_form_email_2fa_send_controller.rb index 389baa59a..cb942bd55 100644 --- a/app/controllers/start_form_email_2fa_send_controller.rb +++ b/app/controllers/start_form_email_2fa_send_controller.rb @@ -66,4 +66,8 @@ class StartFormEmail2faSendController < ApplicationController attrs[:email] = Submissions.normalize_email(attrs[:email]) end end + + def lang + params[:lang].presence + end end diff --git a/app/controllers/submit_form_controller.rb b/app/controllers/submit_form_controller.rb index 06eb475ec..f2d95e713 100644 --- a/app/controllers/submit_form_controller.rb +++ b/app/controllers/submit_form_controller.rb @@ -144,4 +144,8 @@ class SubmitFormController < ApplicationController ActiveStorage::Attachment.where(record: submission.submitters, name: :attachments) .preload(:blob).index_by(&:uuid) end + + def lang + params[:lang].presence + end end diff --git a/app/controllers/submit_form_email_2fas_controller.rb b/app/controllers/submit_form_email_2fas_controller.rb index 6c6ad52eb..6c73112b8 100644 --- a/app/controllers/submit_form_email_2fas_controller.rb +++ b/app/controllers/submit_form_email_2fas_controller.rb @@ -54,4 +54,8 @@ class SubmitFormEmail2fasController < ApplicationController def load_submitter @submitter = Submitter.find_by!(slug: params[:submitter_slug]) end + + def lang + params[:lang].presence + end end From 349c0b0537a30244697f4800f83d02bed30b5906 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Tue, 27 Oct 2026 15:41:12 +0200 Subject: [PATCH 06/21] optimize query --- app/controllers/api/submitters_controller.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/controllers/api/submitters_controller.rb b/app/controllers/api/submitters_controller.rb index 86361ec7d..4fc595ec8 100644 --- a/app/controllers/api/submitters_controller.rb +++ b/app/controllers/api/submitters_controller.rb @@ -179,19 +179,20 @@ module Api submitters = submitters.where(external_id: params[:external_id]) if params[:external_id].present? submitters = submitters.where(slug: params[:slug]) if params[:slug].present? submitters = submitters.where(submission_id: params[:submission_id]) if params[:submission_id].present? - submitters = filter_submitters_by_template_id(submitters, params[:template_id]) if params[:template_id].present? + submitters = filter_submitters_by_template_id(submitters, params) if params[:template_id].present? maybe_filter_by_completed_at(submitters, params) end - def filter_submitters_by_template_id(submitters, template_id) - return submitters.where(template_id:) if template_id.is_a?(Array) + def filter_submitters_by_template_id(submitters, params) + return submitters.where(template_id: params[:template_id]) if params[:template_id].is_a?(Array) - template = Template.find_by(id: template_id) + template = Template.find_by(id: params[:template_id]) return submitters.none if template.nil? || !can?(:read, template) - if template.account_id == current_user.account_id + if template.account_id == current_user.account_id && + params[:completed_after].blank? && params[:completed_before].blank? account_id_bind = Submitter.predicate_builder.build_bind_attribute('account_id', current_user.account_id) submitters = submitters.unscope(where: :account_id) From 8334b612a80fac8379201b4482f0a60c1a006035 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Wed, 28 Oct 2026 09:33:46 +0200 Subject: [PATCH 07/21] fix enable shared link --- app/views/templates_share_link_qr/disabled.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/templates_share_link_qr/disabled.html.erb b/app/views/templates_share_link_qr/disabled.html.erb index ef1f929ce..a3d36114a 100644 --- a/app/views/templates_share_link_qr/disabled.html.erb +++ b/app/views/templates_share_link_qr/disabled.html.erb @@ -4,7 +4,7 @@

<% if can?(:update, @template) %> - <%= button_to button_title(title: t('enable_shared_link'), icon: svg_icon('lock_open', class: 'w-6 h-6')), template_share_link_path(@template), params: { template: { shared_link: true }, redir: template_share_link_qr_path(@template) }, method: :post, data: { turbo: false }, class: 'base-button w-full' %> + <%= button_to button_title(title: t('enable_shared_link'), icon: svg_icon('lock_open', class: 'w-6 h-6')), template_share_link_path(@template), params: { template: { shared_link: true }, redir: template_share_link_qr_path(@template) }, method: :post, class: 'base-button w-full' %> <% end %>
From a0ecc8e823f525e5d421faeaf28a357df730cba2 Mon Sep 17 00:00:00 2001 From: Alex Turchyn Date: Sat, 24 Oct 2026 20:08:26 +0300 Subject: [PATCH 08/21] support the android app --- .../template_builder/documents_editor_modal.vue | 12 ++++++------ .../template_builder/field_context_menu.vue | 4 ++-- app/javascript/template_builder/field_settings.vue | 4 ++-- app/javascript/template_builder/fields.vue | 2 +- app/javascript/template_builder/payment_settings.vue | 4 ++-- .../template_builder/selection_context_menu.vue | 2 +- app/views/accounts/show.html.erb | 4 ++-- .../esign_settings/_default_signature_row.html.erb | 2 +- app/views/notifications_settings/index.html.erb | 2 +- app/views/personalization_settings/show.html.erb | 2 +- app/views/shared/_settings_nav.html.erb | 6 +++--- app/views/submissions/_send_sms.html.erb | 2 +- app/views/submissions/_send_sms_button.html.erb | 2 +- app/views/submissions/new.html.erb | 4 ++-- app/views/templates_code_modal/_placeholder.html.erb | 2 +- app/views/users/_role_select.html.erb | 2 +- 16 files changed, 28 insertions(+), 28 deletions(-) diff --git a/app/javascript/template_builder/documents_editor_modal.vue b/app/javascript/template_builder/documents_editor_modal.vue index 6d243032b..d90247f34 100644 --- a/app/javascript/template_builder/documents_editor_modal.vue +++ b/app/javascript/template_builder/documents_editor_modal.vue @@ -36,7 +36,7 @@
  • <% end %> - <% if can?(:read, EncryptedConfig.new(key: 'submitter_invitation_sms', account: current_account)) && true_user == current_user && (!turbo_native_ios? || can?(:manage, :sms_verification)) %> + <% if can?(:read, EncryptedConfig.new(key: 'submitter_invitation_sms', account: current_account)) && true_user == current_user && (!turbo_native_app? || can?(:manage, :sms_verification)) %>
  • <%= link_to 'SMS', settings_sms_path, class: 'text-base hover:bg-base-300', data: nav_link_data %>
  • @@ -84,7 +84,7 @@ <% end %> <% end %> - <% if !Docuseal.demo? && !turbo_native_ios? && can?(:manage, EncryptedConfig) && (current_user != true_user || !current_account.linked_account_account) %> + <% if !Docuseal.demo? && !turbo_native_app? && can?(:manage, EncryptedConfig) && (current_user != true_user || !current_account.linked_account_account) %>
  • <%= content_for(:pro_link) || link_to(Docuseal.multitenant? ? console_redirect_index_path(redir: "#{Docuseal::CONSOLE_URL}/plans") : "#{Docuseal::CLOUD_URL}/sign_up?#{{ redir: "#{Docuseal::CONSOLE_URL}/on_premises" }.to_query}", class: 'text-base hover:bg-base-300', data: { turbo: false }) do %> <%= t('plans') %> @@ -107,7 +107,7 @@ <% end %>
  • <% end %> - <% if (!Docuseal.multitenant? || can?(:manage, :saml_sso)) && can?(:read, EncryptedConfig.new(key: 'saml_configs', account: current_account)) && true_user == current_user && (!turbo_native_ios? || can?(:manage, :saml_sso)) %> + <% if (!Docuseal.multitenant? || can?(:manage, :saml_sso)) && can?(:read, EncryptedConfig.new(key: 'saml_configs', account: current_account)) && true_user == current_user && (!turbo_native_app? || can?(:manage, :saml_sso)) %>
  • <%= link_to 'SSO', settings_sso_index_path, class: 'text-base hover:bg-base-300', data: nav_link_data %>
  • diff --git a/app/views/submissions/_send_sms.html.erb b/app/views/submissions/_send_sms.html.erb index 598b3a887..fa24b59cd 100644 --- a/app/views/submissions/_send_sms.html.erb +++ b/app/views/submissions/_send_sms.html.erb @@ -1,4 +1,4 @@ -<% unless turbo_native_ios? %> +<% unless turbo_native_app? %>
    <%= render 'sms_settings/placeholder' %> diff --git a/app/views/submissions/_send_sms_button.html.erb b/app/views/submissions/_send_sms_button.html.erb index 26d90f80b..7e18fed02 100644 --- a/app/views/submissions/_send_sms_button.html.erb +++ b/app/views/submissions/_send_sms_button.html.erb @@ -1,4 +1,4 @@ -<% unless turbo_native_ios? %> +<% unless turbo_native_app? %>
    <%= link_to submitter.sent_at? ? t('re_send_sms') : t('send_sms'), Docuseal.multitenant? ? console_redirect_index_path(redir: "#{Docuseal::CONSOLE_URL}/plans") : "#{Docuseal::CLOUD_URL}/sign_up?#{{ redir: "#{Docuseal::CONSOLE_URL}/on_premises" }.to_query}", class: 'btn btn-sm btn-primary text-gray-400 w-full' %> diff --git a/app/views/submissions/new.html.erb b/app/views/submissions/new.html.erb index 7821f1d2e..53296bc85 100644 --- a/app/views/submissions/new.html.erb +++ b/app/views/submissions/new.html.erb @@ -6,8 +6,8 @@ <% recipient_form_fields = Accounts.load_recipient_form_fields(current_account) if prefillable_fields.blank? %> <% can_send_emails = Accounts.can_send_emails?(current_account) %> <% only_detailed = require_phone_2fa || require_email_2fa || prefillable_fields.present? || recipient_form_fields.present? %> -<% with_list = @template.variables_schema.blank? && (!turbo_native_ios? || can?(:manage, :bulk_send)) %> -<% with_phone = !turbo_native_ios? || can?(:manage, :sms_verification) %> +<% with_list = @template.variables_schema.blank? && (!turbo_native_app? || can?(:manage, :bulk_send)) %> +<% with_phone = !turbo_native_app? || can?(:manage, :sms_verification) %> <% default_tab = 'email' if default_tab == 'phone' && !with_phone %> <% variables_form = render 'variables_form', schema: @template.variables_schema if @template.variables_schema.present? && @template.variables_schema.any? { |_, v| !v['disabled'] } %> <%= render 'shared/turbo_modal_large', title: params[:selfsign] ? t('add_recipients') : t('add_new_recipients') do %> diff --git a/app/views/templates_code_modal/_placeholder.html.erb b/app/views/templates_code_modal/_placeholder.html.erb index b5c69ac27..9e24d2a93 100644 --- a/app/views/templates_code_modal/_placeholder.html.erb +++ b/app/views/templates_code_modal/_placeholder.html.erb @@ -1,4 +1,4 @@ -<% unless turbo_native_ios? %> +<% unless turbo_native_app? %>
    <%= svg_icon('info_circle', class: 'w-6 h-6') %>
    diff --git a/app/views/users/_role_select.html.erb b/app/views/users/_role_select.html.erb index dde2cacca..d3fa10290 100644 --- a/app/views/users/_role_select.html.erb +++ b/app/views/users/_role_select.html.erb @@ -12,7 +12,7 @@ <% end %> - <% unless turbo_native_ios? %> + <% unless turbo_native_app? %> "> <%= svg_icon('info_circle', class: 'w-4 h-4 inline align-text-bottom') %> <%= t('unlock_more_user_roles_with_docuseal_pro') %> From 4ecd830587b4261a3d7c5d97f40e13c6e17fdd9c Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Wed, 28 Oct 2026 15:30:04 +0200 Subject: [PATCH 09/21] android fixes --- .../submissions_filters_controller.rb | 2 +- app/javascript/template_builder/builder.vue | 4 ++-- .../template_builder/documents_editor_modal.vue | 2 +- app/views/layouts/_native_styles.html.erb | 17 +++++++++++++++++ app/views/shared/_native_navbar.html.erb | 14 ++++++++------ app/views/shared/_turbo_modal.html.erb | 2 +- app/views/submissions/new.html.erb | 2 +- .../submissions_filters/_filter_modal.html.erb | 2 +- .../submissions_filters/completed_at.html.erb | 4 ++-- .../submissions_filters/created_at.html.erb | 4 ++-- app/views/templates/show.html.erb | 4 +++- app/views/templates_preferences/show.html.erb | 2 +- app/views/templates_share_link/show.html.erb | 8 ++++---- 13 files changed, 44 insertions(+), 23 deletions(-) diff --git a/app/controllers/submissions_filters_controller.rb b/app/controllers/submissions_filters_controller.rb index 8c08bb1d6..ecebfefca 100644 --- a/app/controllers/submissions_filters_controller.rb +++ b/app/controllers/submissions_filters_controller.rb @@ -14,6 +14,6 @@ class SubmissionsFiltersController < ApplicationController def show return head :not_found unless ALLOWED_NAMES.include?(params[:name]) - render params[:name] + render params[:name], layout: turbo_native_android? ? 'plain' : true end end diff --git a/app/javascript/template_builder/builder.vue b/app/javascript/template_builder/builder.vue index 620ab845a..7da438e5d 100644 --- a/app/javascript/template_builder/builder.vue +++ b/app/javascript/template_builder/builder.vue @@ -772,7 +772,7 @@ class="sticky bottom-0 z-20" >