diff --git a/Gemfile.lock b/Gemfile.lock index 8a83f4cb3..6b12f2ead 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,29 +3,29 @@ GEM specs: action_text-trix (2.1.19) railties - actioncable (8.1.3.1) - actionpack (= 8.1.3.1) - activesupport (= 8.1.3.1) + actioncable (8.1.4) + actionpack (= 8.1.4) + activesupport (= 8.1.4) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (8.1.3.1) - actionpack (= 8.1.3.1) - activejob (= 8.1.3.1) - activerecord (= 8.1.3.1) - activestorage (= 8.1.3.1) - activesupport (= 8.1.3.1) + actionmailbox (8.1.4) + actionpack (= 8.1.4) + activejob (= 8.1.4) + activerecord (= 8.1.4) + activestorage (= 8.1.4) + activesupport (= 8.1.4) mail (>= 2.8.0) - actionmailer (8.1.3.1) - actionpack (= 8.1.3.1) - actionview (= 8.1.3.1) - activejob (= 8.1.3.1) - activesupport (= 8.1.3.1) + actionmailer (8.1.4) + actionpack (= 8.1.4) + actionview (= 8.1.4) + activejob (= 8.1.4) + activesupport (= 8.1.4) mail (>= 2.8.0) rails-dom-testing (~> 2.2) - actionpack (8.1.3.1) - actionview (= 8.1.3.1) - activesupport (= 8.1.3.1) + actionpack (8.1.4) + actionview (= 8.1.4) + activesupport (= 8.1.4) 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.3.1) + actiontext (8.1.4) action_text-trix (~> 2.1.15) - actionpack (= 8.1.3.1) - activerecord (= 8.1.3.1) - activestorage (= 8.1.3.1) - activesupport (= 8.1.3.1) + actionpack (= 8.1.4) + activerecord (= 8.1.4) + activestorage (= 8.1.4) + activesupport (= 8.1.4) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (8.1.3.1) - activesupport (= 8.1.3.1) + actionview (8.1.4) + activesupport (= 8.1.4) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - activejob (8.1.3.1) - activesupport (= 8.1.3.1) + activejob (8.1.4) + activesupport (= 8.1.4) globalid (>= 0.3.6) - activemodel (8.1.3.1) - activesupport (= 8.1.3.1) - activerecord (8.1.3.1) - activemodel (= 8.1.3.1) - activesupport (= 8.1.3.1) + activemodel (8.1.4) + activesupport (= 8.1.4) + activerecord (8.1.4) + activemodel (= 8.1.4) + activesupport (= 8.1.4) timeout (>= 0.4.0) - activestorage (8.1.3.1) - actionpack (= 8.1.3.1) - activejob (= 8.1.3.1) - activerecord (= 8.1.3.1) - activesupport (= 8.1.3.1) + activestorage (8.1.4) + actionpack (= 8.1.4) + activejob (= 8.1.4) + activerecord (= 8.1.4) + activesupport (= 8.1.4) marcel (~> 1.0) - activesupport (8.1.3.1) + activesupport (8.1.4) base64 bigdecimal concurrent-ruby (~> 1.0, >= 1.3.1) @@ -116,7 +116,7 @@ GEM erubi (~> 1.4) parser (>= 2.4) smart_properties - bigdecimal (4.1.2) + bigdecimal (4.1.3) bindex (0.8.1) bootsnap (1.23.0) msgpack (~> 1.2) @@ -149,14 +149,14 @@ GEM crack (1.0.1) bigdecimal rexml - crass (1.0.7) + crass (1.0.8) csv (3.3.5) csv-safe (3.3.1) csv (~> 3.0) cuprite (0.17) capybara (~> 3.0) ferrum (~> 0.17.0) - date (3.5.1) + date (3.6.0) debug (1.11.1) irb (~> 1.10) reline (>= 0.3.8) @@ -179,7 +179,7 @@ GEM dotenv (3.2.0) drb (2.2.3) email_typo (0.2.3) - erb (6.0.6) + erb (6.0.7) erb_lint (0.9.0) activesupport better_html (>= 2.0.1) @@ -195,8 +195,8 @@ GEM railties (>= 6.1.0) faker (3.6.1) i18n (>= 1.8.11, < 2) - faraday (2.14.3) - faraday-net_http (>= 2.0, < 3.5) + faraday (2.15.1) + faraday-net_http (>= 2.0, < 3.6) json logger faraday-follow_redirects (0.5.0) @@ -264,14 +264,14 @@ GEM strscan (>= 3.1.2) i18n (1.15.2) concurrent-ruby (~> 1.0) - io-console (0.8.2) + io-console (0.9.5) irb (1.18.0) pp (>= 0.6.0) prism (>= 1.3.0) rdoc (>= 4.0.0) reline (>= 0.4.2) jmespath (1.6.2) - json (2.21.2) + json (3.1.0) jwt (3.2.0) base64 language_server-protocol (3.17.0.5) @@ -310,17 +310,17 @@ GEM drb (~> 2.0) prism (~> 1.5) msgpack (1.8.4) - multi_json (1.19.1) + multi_json (1.21.2) net-http (0.9.1) uri (>= 0.11.1) - net-imap (0.6.6) + net-imap (0.6.8) date net-protocol net-pop (0.1.2) net-protocol - net-protocol (0.2.2) + net-protocol (0.4.0) timeout - net-smtp (0.5.1) + net-smtp (0.5.2) net-protocol nio4r (2.7.5) nokogiri (1.19.4-aarch64-linux-gnu) @@ -361,7 +361,7 @@ GEM prettyprint pretender (1.0.0) actionpack (>= 7.2) - prettyprint (0.2.0) + prettyprint (0.2.1) prism (1.9.0) pry (0.16.0) coderay (~> 1.1) @@ -373,30 +373,30 @@ GEM puma (8.0.2) nio4r (~> 2.0) racc (1.8.1) - rack (3.2.6) + rack (3.2.7) rack-proxy (0.7.7) rack rack-session (2.1.2) base64 (>= 0.1.0) rack (>= 3.0.0) - rack-test (2.2.0) + rack-test (2.3.0) rack (>= 1.3) rackup (2.3.1) rack (>= 3) - rails (8.1.3.1) - actioncable (= 8.1.3.1) - actionmailbox (= 8.1.3.1) - actionmailer (= 8.1.3.1) - actionpack (= 8.1.3.1) - actiontext (= 8.1.3.1) - actionview (= 8.1.3.1) - activejob (= 8.1.3.1) - activemodel (= 8.1.3.1) - activerecord (= 8.1.3.1) - activestorage (= 8.1.3.1) - activesupport (= 8.1.3.1) + rails (8.1.4) + actioncable (= 8.1.4) + actionmailbox (= 8.1.4) + actionmailer (= 8.1.4) + actionpack (= 8.1.4) + actiontext (= 8.1.4) + actionview (= 8.1.4) + activejob (= 8.1.4) + activemodel (= 8.1.4) + activerecord (= 8.1.4) + activestorage (= 8.1.4) + activesupport (= 8.1.4) bundler (>= 1.15.0) - railties (= 8.1.3.1) + railties (= 8.1.4) rails-dom-testing (2.3.0) activesupport (>= 5.0.0) minitest @@ -407,9 +407,9 @@ GEM rails-i18n (8.1.0) i18n (>= 0.7, < 2) railties (>= 8.0.0, < 9) - railties (8.1.3.1) - actionpack (= 8.1.3.1) - activesupport (= 8.1.3.1) + railties (8.1.4) + actionpack (= 8.1.4) + activesupport (= 8.1.4) irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) @@ -418,11 +418,11 @@ GEM zeitwerk (~> 2.6) rainbow (3.1.1) rake (13.4.2) - rbs (4.1.0) + rbs (4.2.0) logger prism (>= 1.6.0) tsort - rdoc (8.0.0) + rdoc (8.1.0) erb prism (>= 1.6.0) rbs (>= 4.0.0) @@ -430,7 +430,7 @@ GEM redis-client (0.29.0) connection_pool regexp_parser (2.11.3) - reline (0.6.3) + reline (0.7.0) io-console (~> 0.5) representable (3.2.0) declarative (< 0.1.0) @@ -466,14 +466,14 @@ GEM rspec-mocks (>= 3.13.0, < 5.0.0) rspec-support (>= 3.13.0, < 5.0.0) rspec-support (3.13.7) - rubocop (1.86.0) - json (~> 2.3) + rubocop (1.92.1) + json (>= 2.3) language_server-protocol (~> 3.17.0.2) lint_roller (~> 1.1.0) - parallel (~> 1.10) + parallel (>= 1.10) parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 2.9.3, < 3.0) + regexp_parser (>= 2.11.3, < 3.0) rubocop-ast (>= 1.49.0, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 4.0) @@ -555,7 +555,7 @@ GEM unicode-emoji (~> 4.1) unicode-emoji (4.2.0) uniform_notifier (1.18.0) - uri (1.1.1) + uri (1.1.2) useragent (0.16.11) warden (1.2.9) rack (>= 2.0.9) @@ -587,7 +587,7 @@ GEM xpath (3.2.0) nokogiri (~> 1.8) yaml (0.4.0) - zeitwerk (2.8.2) + zeitwerk (2.8.3) zip_kit (6.3.4) PLATFORMS diff --git a/SECURITY.md b/SECURITY.md index b1692488c..c61204cc4 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -9,6 +9,7 @@ Out of scope vulnerabilities: - CSRF - DNSSEC, CAA, CSP headers - DNS or email security related +- SSRF - Rate Limiting Note: We reserve the right to classify any reported vulnerability as out of scope for the bug bounty program. diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 37591527e..949cea168 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -54,14 +54,13 @@ class AccountsController < ApplicationController email: true_user.email.sub('@', '+removed@')) true_user.account.update!(archived_at: Time.current) - # rubocop:disable Layout/LineLength + # rubocop:disable-next Layout/LineLength render turbo_stream: turbo_stream.replace( :account_delete_button, html: helpers.tag.p(I18n.t('your_account_will_be_permanently_deleted_within_2_months_please_contact_us_if_you_want_to_keep_your_account')) + helpers.tag.br + helpers.tag.p(I18n.t('your_email_address_has_been_released_immediately_you_can_now_be_added_to_your_company_team_without_waiting_for_the_deletion_period_to_end')) ) - # rubocop:enable Layout/LineLength end private diff --git a/app/controllers/api/active_storage_blobs_proxy_controller.rb b/app/controllers/api/active_storage_blobs_proxy_controller.rb index 0cddd9949..e55c1cb3d 100644 --- a/app/controllers/api/active_storage_blobs_proxy_controller.rb +++ b/app/controllers/api/active_storage_blobs_proxy_controller.rb @@ -11,7 +11,7 @@ module Api before_action :set_noindex_headers before_action :set_security_headers - # rubocop:disable Metrics + # rubocop:disable-next Metrics def show blob_uuid, purp, exp = ApplicationRecord.signed_id_verifier.verified(params[:signed_uuid]) @@ -53,7 +53,6 @@ module Api end end end - # rubocop:enable Metrics private 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 diff --git a/app/controllers/api/submitters_controller.rb b/app/controllers/api/submitters_controller.rb index a547ba75a..eee1e835c 100644 --- a/app/controllers/api/submitters_controller.rb +++ b/app/controllers/api/submitters_controller.rb @@ -36,7 +36,7 @@ module Api render json: Submitters::SerializeForApi.call(@submitter, with_template: true, with_events: true, params:) end - # rubocop:disable Metrics/MethodLength + # rubocop:disable-next Metrics/MethodLength def update submission = @submitter.submission role = submission.template_submitters.find { |e| e['uuid'] == @submitter.uuid }['name'] @@ -84,7 +84,6 @@ module Api render json: { error: e.message }, status: :unprocessable_content end - # rubocop:enable Metrics/MethodLength def submitter_params submitter_params = params.key?(:submitter) ? params.require(:submitter) : params @@ -179,11 +178,29 @@ 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) if params[:template_id].present? maybe_filter_by_completed_at(submitters, params) end + 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: params[:template_id]) + + return submitters.none if template.nil? || !can?(:read, template) + + 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) + .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) diff --git a/app/controllers/mcp/create_template_controller.rb b/app/controllers/mcp/create_template_controller.rb index 2f54ce716..3d91686d6 100644 --- a/app/controllers/mcp/create_template_controller.rb +++ b/app/controllers/mcp/create_template_controller.rb @@ -30,7 +30,7 @@ module Mcp } }.freeze - # rubocop:disable Metrics/AbcSize, Metrics/MethodLength + # rubocop:disable-next Metrics/AbcSize, Metrics/MethodLength def call account = current_user.account @@ -87,6 +87,5 @@ module Mcp edit_url: edit_template_url(@template) ) end - # rubocop:enable Metrics/AbcSize, Metrics/MethodLength end end diff --git a/app/controllers/mcp/send_documents_controller.rb b/app/controllers/mcp/send_documents_controller.rb index 7fadc8a17..a4c5a7125 100644 --- a/app/controllers/mcp/send_documents_controller.rb +++ b/app/controllers/mcp/send_documents_controller.rb @@ -66,7 +66,7 @@ module Mcp } }.freeze - # rubocop:disable Metrics + # rubocop:disable-next Metrics def call @template = Template.accessible_by(current_ability).find(mcp_params['template_id']) @@ -115,6 +115,5 @@ module Mcp rescue Submissions::CreateFromSubmitters::BaseError => e render_tool_error(e.message) end - # rubocop:enable Metrics end end diff --git a/app/controllers/passwords_controller.rb b/app/controllers/passwords_controller.rb index e166da35a..12240d65f 100644 --- a/app/controllers/passwords_controller.rb +++ b/app/controllers/passwords_controller.rb @@ -1,9 +1,8 @@ # frozen_string_literal: true class PasswordsController < Devise::PasswordsController - # rubocop:disable Rails/LexicallyScopedActionFilter + # rubocop:disable-next Rails/LexicallyScopedActionFilter skip_before_action :require_no_authentication, only: %i[edit update] - # rubocop:enable Rails/LexicallyScopedActionFilter around_action :with_browser_locale diff --git a/app/controllers/preview_document_page_controller.rb b/app/controllers/preview_document_page_controller.rb index f43265904..ce4e02df0 100644 --- a/app/controllers/preview_document_page_controller.rb +++ b/app/controllers/preview_document_page_controller.rb @@ -53,7 +53,7 @@ class PreviewDocumentPageController < ActionController::API File.open(file_path, File::RDWR | File::CREAT, 0o644) do |file| file.flock(File::LOCK_EX) - # rubocop:disable Style/ZeroLengthPredicate + # rubocop:disable-next Style/ZeroLengthPredicate if file.size.zero? cleanup_stale_tempfiles @@ -63,7 +63,6 @@ class PreviewDocumentPageController < ActionController::API else FileUtils.touch(file_path) end - # rubocop:enable Style/ZeroLengthPredicate file.flock(File::LOCK_UN) diff --git a/app/controllers/send_submission_email_controller.rb b/app/controllers/send_submission_email_controller.rb index 13bd5f161..5cb82a034 100644 --- a/app/controllers/send_submission_email_controller.rb +++ b/app/controllers/send_submission_email_controller.rb @@ -14,7 +14,7 @@ class SendSubmissionEmailController < ApplicationController template = Template.find_by!(slug: params[:template_slug]) @submitter = - Submitter.completed.where(submission: template.submissions).find_by(email: params[:email].to_s.downcase) + Submitter.completed.where(template_id: template.id).find_by(email: params[:email].to_s.downcase) elsif params[:submission_slug] submission = Submission.find_by!(slug: params[:submission_slug]) diff --git a/app/controllers/start_form_controller.rb b/app/controllers/start_form_controller.rb index 86471d381..530b3b7be 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 @@ -80,7 +80,7 @@ class StartFormController < ApplicationController raise ActionController::RoutingError, I18n.t('not_found') if required_params.any? { |_, v| v.blank? } || required_params.except('name').compact_blank.blank? - @submitter = Submitter.where(submission: @template.submissions) + @submitter = Submitter.where(template_id: @template.id) .where.not(completed_at: nil) .find_by!(required_params.except('name')) 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,14 @@ 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 + + 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 0787ab468..cb942bd55 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 @@ -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/submissions_export_controller.rb b/app/controllers/submissions_export_controller.rb index d199e5850..7a42d6a5c 100644 --- a/app/controllers/submissions_export_controller.rb +++ b/app/controllers/submissions_export_controller.rb @@ -25,5 +25,7 @@ class SubmissionsExportController < ApplicationController end end - def new; end + def new + render layout: turbo_native_android? ? 'plain' : true + end end 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/controllers/submit_form_controller.rb b/app/controllers/submit_form_controller.rb index 2f3ab0cb2..f2d95e713 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 @@ -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 6f95e7544..6c73112b8 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,19 +38,24 @@ 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 @submitter = Submitter.find_by!(slug: params[:submitter_slug]) end + + def lang + params[:lang].presence + end end diff --git a/app/controllers/template_folders_controller.rb b/app/controllers/template_folders_controller.rb index 17fbc806f..8b24d2020 100644 --- a/app/controllers/template_folders_controller.rb +++ b/app/controllers/template_folders_controller.rb @@ -41,7 +41,9 @@ class TemplateFoldersController < ApplicationController render_infinite_scroll(@pagy, @templates, @template_folders) if turbo_infinite_scroll? end - def edit; end + def edit + render layout: turbo_native_android? ? 'plain' : true + end def update if @template_folder != current_account.default_template_folder && diff --git a/app/controllers/templates_clone_controller.rb b/app/controllers/templates_clone_controller.rb index d001087ff..8d5f62546 100644 --- a/app/controllers/templates_clone_controller.rb +++ b/app/controllers/templates_clone_controller.rb @@ -7,6 +7,8 @@ class TemplatesCloneController < ApplicationController authorize!(:create, Template) @template = Template.new(name: "#{@base_template.name} (#{I18n.t('clone')})") + + render layout: turbo_native_android? ? 'plain' : true end def create diff --git a/app/controllers/templates_folders_controller.rb b/app/controllers/templates_folders_controller.rb index 05ee62d84..6f22669b0 100644 --- a/app/controllers/templates_folders_controller.rb +++ b/app/controllers/templates_folders_controller.rb @@ -3,7 +3,9 @@ class TemplatesFoldersController < ApplicationController load_and_authorize_resource :template - def edit; end + def edit + render layout: turbo_native_android? ? 'plain' : true + end def update authorize!(:update, @template) diff --git a/app/controllers/user_initials_controller.rb b/app/controllers/user_initials_controller.rb index 29562e642..1306444cc 100644 --- a/app/controllers/user_initials_controller.rb +++ b/app/controllers/user_initials_controller.rb @@ -4,7 +4,9 @@ class UserInitialsController < ApplicationController before_action :load_user_config authorize_resource :user_config - def edit; end + def edit + render layout: turbo_native_android? ? 'plain' : true + end def update file = params[:file] diff --git a/app/controllers/user_signatures_controller.rb b/app/controllers/user_signatures_controller.rb index da2974eae..353e26092 100644 --- a/app/controllers/user_signatures_controller.rb +++ b/app/controllers/user_signatures_controller.rb @@ -4,7 +4,9 @@ class UserSignaturesController < ApplicationController before_action :load_user_config authorize_resource :user_config - def edit; end + def edit + render layout: turbo_native_android? ? 'plain' : true + end def update file = params[:file] diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index d2371aa55..6298c0815 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -31,9 +31,13 @@ class UsersController < ApplicationController end end - def new; end + def new + render layout: turbo_native_android? ? 'plain' : true + end - def edit; end + def edit + render layout: turbo_native_android? ? 'plain' : true + end def create existing_user = User.accessible_by(current_ability).find_by(email: @user.email) 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/javascript/elements/signature_form.js b/app/javascript/elements/signature_form.js index 845a6b6cf..f3129167e 100644 --- a/app/javascript/elements/signature_form.js +++ b/app/javascript/elements/signature_form.js @@ -55,7 +55,7 @@ export default targetable(class extends HTMLElement { this.input.files = dataTransfer.files - if (this.input.webkitEntries.length) { + if (this.input.webkitEntries?.length) { this.input.dataset.file = `${dataTransfer.files[0].name}` } 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" > -
+
{{ t('available_in_pro') }}
-
+
export default { name: 'ConditionModal', - inject: ['t', 'template', 'withConditions'], + inject: ['t', 'template', 'withConditions', 'nativePlatform'], props: { item: { type: Object, diff --git a/app/javascript/template_builder/description_modal.vue b/app/javascript/template_builder/description_modal.vue index 14bd31c57..bea1a78f5 100644 --- a/app/javascript/template_builder/description_modal.vue +++ b/app/javascript/template_builder/description_modal.vue @@ -7,7 +7,7 @@ class="absolute top-0 bottom-0 right-0 left-0" @click.prevent="$emit('close')" /> -
+
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/submission_events/index.html.erb b/app/views/submission_events/index.html.erb index 96a1b8326..821b54a98 100644 --- a/app/views/submission_events/index.html.erb +++ b/app/views/submission_events/index.html.erb @@ -43,7 +43,8 @@

<% if event.event_type == 'complete_verification' %> - <%= t('submission_event_names.complete_verification_by_html', provider: event.data['method'], submitter_name:) %> + <% identity_name = [event.data['firstname'], event.data['lastname']].compact_blank.join(' ') %> + <%= t('submission_event_names.complete_verification_by_html', provider: event.data['method'], submitter_name: identity_name.presence || 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' %> 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..c869745d4 100644 --- a/app/views/submissions/new.html.erb +++ b/app/views/submissions/new.html.erb @@ -6,14 +6,14 @@ <% 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 %> <% options = [only_detailed ? nil : [t('via_email'), 'email'], only_detailed || !with_phone ? nil : [t('via_phone'), 'phone'], [t('detailed'), 'detailed'], with_list ? [t('upload_list'), 'list'] : nil].compact %> <% if options.size > 1 %> - +
<% options.each_with_index do |(label, value), index| %> <%= content_tag(value == 'list' ? 'span' : 'toggle-cookies', data: { value:, key: 'add_recipients_tab' }) do %> diff --git a/app/views/submissions_export/new.html.erb b/app/views/submissions_export/new.html.erb index 38121609a..52e25fdd1 100644 --- a/app/views/submissions_export/new.html.erb +++ b/app/views/submissions_export/new.html.erb @@ -1,6 +1,6 @@ <% filter_params = params.permit(:q, :archived, *Submissions::Filter::ALLOWED_PARAMS) %> <%= render 'shared/turbo_modal', title: t('export'), close_after_submit: false do %> -
+
<%= button_to template_submissions_export_index_path(@template), params: { format: :xlsx, **filter_params }, method: :get, data: { turbo_frame: :_top } do %>
diff --git a/app/views/submissions_filters/_filter_modal.html.erb b/app/views/submissions_filters/_filter_modal.html.erb index a74c20f4a..b7d45e168 100644 --- a/app/views/submissions_filters/_filter_modal.html.erb +++ b/app/views/submissions_filters/_filter_modal.html.erb @@ -1,7 +1,7 @@ <% path_uri = Addressable::URI.parse(params[:path].to_s) %> <% path = url_for(**Rails.application.routes.recognize_path(path_uri.path, method: :get)) %> <%= render 'shared/turbo_modal', title: local_assigns[:title] do %> - <%= form_for '', url: path, method: :get, data: { turbo_frame: :_top }, html: { autocomplete: :off } do |f| %> + <%= form_for '', url: path, method: :get, data: { turbo_frame: :_top }, html: { autocomplete: :off, class: ('px-4' if turbo_native_android?) } do |f| %> <%= hidden_field_tag :q, params[:q] if params[:q].present? %> <%= hidden_field_tag :scope, params[:scope] if params[:scope].present? %> <%= hidden_field_tag :archived, params[:archived] if params[:archived].present? %> diff --git a/app/views/submissions_filters/completed_at.html.erb b/app/views/submissions_filters/completed_at.html.erb index 0a0b6b6fe..b69ac97b6 100644 --- a/app/views/submissions_filters/completed_at.html.erb +++ b/app/views/submissions_filters/completed_at.html.erb @@ -3,11 +3,11 @@
<%= label_tag 'completed_at_from', t('from'), for: 'date_from', class: 'label text-sm' %> - <%= date_field_tag 'completed_at_from', params[:completed_at_from], id: 'date_from', class: 'base-input !h-10', autocomplete: 'off' %> + <%= date_field_tag 'completed_at_from', params[:completed_at_from], id: 'date_from', class: "base-input !h-10 #{'w-full' if turbo_native_android?}", autocomplete: 'off' %>
<%= label_tag 'completed_at_to', t('to'), for: 'date_to', class: 'label text-sm' %> - <%= date_field_tag 'completed_at_to', params[:completed_at_to], id: 'date_to', class: 'base-input !h-10', autocomplete: 'off' %> + <%= date_field_tag 'completed_at_to', params[:completed_at_to], id: 'date_to', class: "base-input !h-10 #{'w-full' if turbo_native_android?}", autocomplete: 'off' %>
<%= render 'date_buttons' %> diff --git a/app/views/submissions_filters/created_at.html.erb b/app/views/submissions_filters/created_at.html.erb index 2f0894645..059c3dce6 100644 --- a/app/views/submissions_filters/created_at.html.erb +++ b/app/views/submissions_filters/created_at.html.erb @@ -3,11 +3,11 @@
<%= label_tag 'created_at_from', t('from'), for: 'date_from', class: 'label text-sm' %> - <%= date_field_tag 'created_at_from', params[:created_at_from], id: 'date_from', class: 'base-input !h-10', autocomplete: 'off' %> + <%= date_field_tag 'created_at_from', params[:created_at_from], id: 'date_from', class: "base-input !h-10 #{'w-full' if turbo_native_android?}", autocomplete: 'off' %>
<%= label_tag 'created_at_to', t('to'), for: 'date_to', class: 'label text-sm' %> - <%= date_field_tag 'created_at_to', params[:created_at_to], id: 'date_to', class: 'base-input !h-10', autocomplete: 'off' %> + <%= date_field_tag 'created_at_to', params[:created_at_to], id: 'date_to', class: "base-input !h-10 #{'w-full' if turbo_native_android?}", autocomplete: 'off' %>
<%= render 'date_buttons' %> 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 %> diff --git a/app/views/template_folders/edit.html.erb b/app/views/template_folders/edit.html.erb index 5ecb3a0d3..4b8cbbf5d 100644 --- a/app/views/template_folders/edit.html.erb +++ b/app/views/template_folders/edit.html.erb @@ -1,6 +1,6 @@ <%= render 'shared/turbo_modal', title: t('rename_folder') do %> - <%= form_for @template_folder, url: folder_path(@template_folder), data: { turbo_frame: :_top }, html: { autocomplete: :off } do |f| %> -
+ <%= form_for @template_folder, url: folder_path(@template_folder), data: { turbo_frame: :_top }, html: { autocomplete: :off, class: ('px-4' if turbo_native_android?) } do |f| %> +
<%= f.text_field :name, required: true, placeholder: "#{t('folder_name')}...", class: 'base-input w-full', autofocus: true, dir: 'auto' %>
diff --git a/app/views/templates/show.html.erb b/app/views/templates/show.html.erb index 7ee8567cb..bb95bb554 100644 --- a/app/views/templates/show.html.erb +++ b/app/views/templates/show.html.erb @@ -5,7 +5,9 @@ <% is_show_header = submissions_count != 0 || params[:q].present? || params[:status].present? || filter_params.present? %> <%= render 'title', template: @template, with_export: is_show_header %> <% if turbo_native_app? %> - + <% if !turbo_native_android? || submissions_count >= 5 || params[:q].present? || params[:status].present? || filter_params.present? %> + + <% end %> <% if !@template.archived_at? && can?(:create, Submission) %> diff --git a/app/views/templates_clone/_form.html.erb b/app/views/templates_clone/_form.html.erb index b2fb88b50..ebb320584 100644 --- a/app/views/templates_clone/_form.html.erb +++ b/app/views/templates_clone/_form.html.erb @@ -1,11 +1,12 @@ -<%= form_for @template, url: template_clone_index_path(@base_template), data: { turbo_frame: :_top }, html: { autocomplete: :off } do |f| %> +<%= form_for @template, url: template_clone_index_path(@base_template), data: { turbo_frame: :_top }, html: { autocomplete: :off, class: ('px-4' if turbo_native_android?) } do |f| %> <% accounts = Account.accessible_by(true_ability).where.not(id: true_user.account.testing_accounts).where(User.where(User.arel_table[:account_id].eq(Account.arel_table[:id])).arel.exists).active %> - <% if (can?(:manage, :tenants) || true_user != current_user) && accounts.where.not(id: current_account.id).exists? %> -
+ <% with_accounts = (can?(:manage, :tenants) || true_user != current_user) && accounts.where.not(id: current_account.id).exists? %> + <% if with_accounts %> +
<%= select_tag :account_id, options_for_select([current_account, *accounts.order(:name)].uniq.map { |e| [e.name, e.id] }, current_account.id), required: true, class: 'base-select' %>
<% end %> -
+
<%= f.text_field :name, required: true, placeholder: t('document_name'), class: 'base-input', dir: 'auto' %>
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/templates_folders/edit.html.erb b/app/views/templates_folders/edit.html.erb index c28da2ac4..26bd1643f 100644 --- a/app/views/templates_folders/edit.html.erb +++ b/app/views/templates_folders/edit.html.erb @@ -1,7 +1,7 @@ <% with_subfolder = @template.folder.name != TemplateFolder::DEFAULT_NAME && params[:subfolder] != 'false' %> <%= render 'shared/turbo_modal', title: t('move_into_folder') do %> <% if with_subfolder %> - <%= form_for '', url: template_folder_path(@template), method: :put, data: { turbo_frame: :_top }, html: { id: 'subfolder_form', autocomplete: :off } do |f| %> + <%= form_for '', url: template_folder_path(@template), method: :put, data: { turbo_frame: :_top }, html: { id: 'subfolder_form', autocomplete: :off, class: ('px-4' if turbo_native_android?) } do |f| %> <%= f.hidden_field :parent_name, value: @template.folder.parent_folder&.name || @template.folder.name %>
@@ -25,7 +25,7 @@
<% end %> <% end %> - <%= form_for '', url: template_folder_path(@template), method: :put, data: { turbo_frame: :_top }, html: { id: 'folder_form', autocomplete: :off, class: "mt-6 #{'hidden' if with_subfolder}" } do |f| %> + <%= form_for '', url: template_folder_path(@template), method: :put, data: { turbo_frame: :_top }, html: { id: 'folder_form', autocomplete: :off, class: "#{turbo_native_android? ? 'mt-1.5 px-4' : 'mt-6'} #{'hidden' if with_subfolder}" } do |f| %>
<%= f.text_field :name, required: true, placeholder: "#{t('new_folder_name')}...", class: 'base-input w-full', autofocus: true %> diff --git a/app/views/templates_preferences/show.html.erb b/app/views/templates_preferences/show.html.erb index f6df9d583..404355d4f 100644 --- a/app/views/templates_preferences/show.html.erb +++ b/app/views/templates_preferences/show.html.erb @@ -5,7 +5,7 @@ <% options << [t('recipients'), 'recipients'] if show_recipients %> <% options << [safe_join([tag.span('API', class: 'md:hidden'), tag.span(t('api_and_embedding'), class: 'hidden md:inline')]), 'api'] if show_api %> <% if options.size > 1 %> - +
<% options.each_with_index do |(label, value), index| %> diff --git a/app/views/templates_share_link/show.html.erb b/app/views/templates_share_link/show.html.erb index 71cec53f5..b4712eedc 100644 --- a/app/views/templates_share_link/show.html.erb +++ b/app/views/templates_share_link/show.html.erb @@ -1,21 +1,21 @@ <% multiple_submitters = @template.submitters.to_a.length > 1 %> <% enough_defined_submitters = Templates.filter_undefined_submitters(@template.submitters).size < 2 %> <%= render 'shared/turbo_modal_large', title: t('share_link') do %> -
+
<% if @template.variables_schema.present? %>
<%= svg_icon('info_circle', class: 'stroke-current shrink-0 h-6 w-6') %>
<%= t('dynamic_template_with_variables_cannot_be_used_via_shared_link') %>
<% end %> - <%= form_for @template, url: template_share_link_path(@template), method: :post, html: { id: 'shared_link_form', autocomplete: 'off', class: 'mt-3' }, data: { close_on_submit: false } do |f| %> + <%= form_for @template, url: template_share_link_path(@template), method: :post, html: { id: 'shared_link_form', autocomplete: 'off', class: turbo_native_android? ? 'mt-1' : 'mt-3' }, data: { close_on_submit: false } do |f| %> <% if @template.preferences&.dig('require_email_2fa') || @template.preferences&.dig('require_phone_2fa') %> -
diff --git a/app/views/user_initials/edit.html.erb b/app/views/user_initials/edit.html.erb index feef01891..ee693fb3b 100644 --- a/app/views/user_initials/edit.html.erb +++ b/app/views/user_initials/edit.html.erb @@ -1,6 +1,6 @@ <%= render 'shared/turbo_modal', title: t('update_initials') do %> <% options = [[t('draw'), 'draw'], [t('upload'), 'upload']] %> - +
<% options.each_with_index do |(label, value), index| %> @@ -12,7 +12,7 @@ <% end %>
-
+
<%= form_for @user_config, url: user_initials_path, method: :put, data: { turbo_frame: :_top }, html: { autocomplete: :off, enctype: 'multipart/form-data' } do |f| %> <%= t('clear') %> @@ -24,7 +24,7 @@ <% end %>
-