From 0c7f4e5b43995faa3d44e906f5d3452b3168d6e0 Mon Sep 17 00:00:00 2001 From: Alex Turchyn Date: Mon, 25 May 2026 21:08:03 +0300 Subject: [PATCH 01/27] fix sidekiq embedded redis connection --- lib/puma/plugin/sidekiq_embed.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/puma/plugin/sidekiq_embed.rb b/lib/puma/plugin/sidekiq_embed.rb index 42ea96db..921be32c 100644 --- a/lib/puma/plugin/sidekiq_embed.rb +++ b/lib/puma/plugin/sidekiq_embed.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require 'puma/plugin' +require 'redis_client' # rubocop:disable Metrics Puma::Plugin.create do @@ -68,7 +69,7 @@ Puma::Plugin.create do break rescue RedisClient::CannotConnectError - raise('Unable to connect to redis') if attempt > 10 + raise('Unable to connect to redis') if attempt > 30 end end end From 827de035793c4d38d63afc4c866771b3b5b57a42 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Tue, 26 May 2026 08:57:30 +0300 Subject: [PATCH 02/27] fix result generatrion --- lib/submissions/generate_result_attachments.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/submissions/generate_result_attachments.rb b/lib/submissions/generate_result_attachments.rb index a0b31c11..5eba4a63 100644 --- a/lib/submissions/generate_result_attachments.rb +++ b/lib/submissions/generate_result_attachments.rb @@ -759,12 +759,12 @@ module Submissions begin pdf.sign(io, write_options: { validate: false }, **sign_params) - rescue HexaPDF::Error, NoMethodError => e + rescue HexaPDF::Error, NoMethodError, TypeError => e Rollbar.error(e) if defined?(Rollbar) begin pdf.sign(io, write_options: { validate: false, incremental: false }, **sign_params) - rescue HexaPDF::Error + rescue HexaPDF::Error, TypeError pdf.validate(auto_correct: true) pdf.sign(io, write_options: { validate: false, incremental: false }, **sign_params) end From 369f4c0f08cc7004a33f940ae1c039250bc7a3e4 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Tue, 26 May 2026 09:18:32 +0300 Subject: [PATCH 03/27] sync prefillable field changes --- app/javascript/application.js | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/app/javascript/application.js b/app/javascript/application.js index bec3cc0b..38b58ad0 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -197,10 +197,35 @@ safeRegisterElement('template-builder', class extends HTMLElement { } onSubmit = (e) => { - if (e.detail.success && e.detail?.formSubmission?.formElement?.id === 'submitters_form') { - e.detail.fetchResponse.response.json().then((data) => { - this.component.template.submitters = data.submitters - }) + if (e.detail.success) { + if (e.detail?.formSubmission?.formElement?.id === 'submitters_form') { + e.detail.fetchResponse.response.json().then((data) => { + this.component.template.submitters = data.submitters + }) + } + + if (e.detail?.formSubmission?.formElement?.action?.endsWith('/prefillable_fields')) { + e.detail.fetchResponse.response.text().then((data) => { + const doc = new DOMParser().parseFromString(data, 'text/html') + const fragment = doc.querySelector('turbo-stream template').content + + const prefillableUuidsIndex = {} + + fragment.querySelectorAll('[name="field_uuid"]').forEach((field) => { + prefillableUuidsIndex[field.value] = true + }) + + this.component.template.fields.forEach((field) => { + if (prefillableUuidsIndex[field.uuid]) { + field.prefillable = true + field.readonly = true + } else if (field.prefillable) { + delete field.prefillable + delete field.readonly + } + }) + }) + } } } From b1dfcd62837674ca20e4a91562374e8e8f7bae2a Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Tue, 26 May 2026 10:30:29 +0300 Subject: [PATCH 04/27] fix email typo --- lib/submissions.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/submissions.rb b/lib/submissions.rb index 33081926..c7ba677b 100644 --- a/lib/submissions.rb +++ b/lib/submissions.rb @@ -162,7 +162,7 @@ module Submissions return email.downcase.sub(/@gmail?\z/i, '@gmail.com') if email.match?(/@gmail?\z/i) return email.downcase if email.include?(',') || - email.match?(/\.(?:gob|om|mm|cm|et|mo|nz|za|ie|ed\.jp)\z/i) || + email.match?(/\.(?:gob(?:\.\w+)?|om|mm|cm|et|mo|nz|za|ie|ed\.jp)\z/i) || email.exclude?('.') fixed_email = EmailTypo.call(email.delete_prefix('<')) @@ -175,7 +175,9 @@ module Submissions return email.downcase if domain == fixed_domain return email.downcase if fixed_domain.match?(/\Agmail\.(?!com\z)/i) - if DidYouMean::Levenshtein.distance(domain, fixed_domain) > 3 + threshold = fixed_domain.start_with?('hotmail.') ? 2 : 3 + + if DidYouMean::Levenshtein.distance(domain, fixed_domain) > threshold Rails.logger.info("Skipped email fix #{domain}") return email.downcase From 16808a7ec63f2708d7060dcc16cde21aaf1b633b Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Tue, 26 May 2026 11:42:13 +0300 Subject: [PATCH 05/27] use pngload_buffer --- lib/load_ico.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/load_ico.rb b/lib/load_ico.rb index a8c3061d..d956092c 100644 --- a/lib/load_ico.rb +++ b/lib/load_ico.rb @@ -43,7 +43,7 @@ module LoadIco raise ArgumentError, 'Unable to load' unless image_data_bytes && image_data_bytes.bytesize == best_entry[:size] - return Vips::Image.new_from_buffer(image_data_bytes, '') if image_data_bytes.start_with?(PNG_SIGNATURE) + return Vips::Image.pngload_buffer(image_data_bytes) if image_data_bytes.start_with?(PNG_SIGNATURE) image = load_image_entry(image_data_bytes, best_entry[:width], best_entry[:height]) From ae08d7abad0583c8c3986fded73d6d677c156f70 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Tue, 26 May 2026 11:48:52 +0300 Subject: [PATCH 06/27] adjust opacity_layer --- lib/submitters/create_stamp_attachment.rb | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/lib/submitters/create_stamp_attachment.rb b/lib/submitters/create_stamp_attachment.rb index d1e14088..4ae79b5b 100644 --- a/lib/submitters/create_stamp_attachment.rb +++ b/lib/submitters/create_stamp_attachment.rb @@ -6,12 +6,6 @@ module Submitters HEIGHT = 200 LRM = "\u200E" - TRANSPARENT_PIXEL = "\x89PNG\r\n\u001A\n\u0000\u0000\u0000\rIHDR\u0000" \ - "\u0000\u0000\u0001\u0000\u0000\u0000\u0001\b\u0004" \ - "\u0000\u0000\u0000\xB5\u001C\f\u0002\u0000\u0000\u0000" \ - "\vIDATx\xDAc\xFC_\u000F\u0000\u0002\x83\u0001\x804\xC3ڨ" \ - "\u0000\u0000\u0000\u0000IEND\xAEB`\x82" - module_function def call(submitter, with_logo: true) @@ -42,14 +36,14 @@ module Submitters if with_logo ImageUtils.load_vips(load_logo(submitter).read) else - Vips::Image.new_from_buffer(TRANSPARENT_PIXEL, '').resize(WIDTH) + Vips::Image.black(WIDTH, WIDTH, bands: 4).copy(interpretation: :srgb) end logo = logo.resize([WIDTH / logo.width.to_f, HEIGHT / logo.height.to_f].min) - base_layer = Vips::Image.black(WIDTH, HEIGHT).new_from_image([255, 255, 255]).copy(interpretation: :srgb) + base_layer = Vips::Image.black(WIDTH, HEIGHT).new_from_image([255, 255, 255, 255]).copy(interpretation: :srgb) - opacity_layer = Vips::Image.new_from_buffer(TRANSPARENT_PIXEL, '').resize(WIDTH) + opacity_layer = Vips::Image.black(WIDTH, HEIGHT).new_from_image([255, 255, 255, 127]).copy(interpretation: :srgb) text = build_text_image(submitter) From 9f3fcccb6123722d84c995b40ca7e05ccc66a045 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Tue, 26 May 2026 16:50:10 +0300 Subject: [PATCH 07/27] optimize build --- Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 3f6bb3c6..a4896f63 100644 --- a/Dockerfile +++ b/Dockerfile @@ -48,7 +48,8 @@ ENV OPENSSL_CONF=/etc/openssl_legacy.cnf WORKDIR /app -RUN apk add --no-cache libpq vips redis onnxruntime +RUN apk add --no-cache libpq vips redis onnxruntime && \ + rm -f /usr/bin/onnx_test_runner /usr/bin/onnxruntime_test RUN addgroup -g 2000 docuseal && adduser -u 2000 -G docuseal -s /bin/sh -D -h /home/docuseal docuseal From 2e6dd2867ecd00cbcc8ecd066fc432b01a02bbce Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Tue, 26 May 2026 21:49:04 +0300 Subject: [PATCH 08/27] file url ttl env var --- lib/accounts.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/accounts.rb b/lib/accounts.rb index 41b7d761..123747eb 100644 --- a/lib/accounts.rb +++ b/lib/accounts.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Accounts - LINK_EXPIRES_AT = 40.minutes + LINK_EXPIRES_AT = ENV.fetch('FILE_URLS_EXPIRE_MINUTES', '40').to_i.minutes module_function From 0741c879f1bb38c3931c691b7be8fbf36bde7094 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Wed, 27 May 2026 22:19:18 +0300 Subject: [PATCH 09/27] use expires_at with file links --- lib/submissions/generate_audit_trail.rb | 4 +++- lib/submissions/generate_preview_attachments.rb | 5 ++++- lib/submissions/generate_result_attachments.rb | 10 +++++++--- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/submissions/generate_audit_trail.rb b/lib/submissions/generate_audit_trail.rb index 2c16f044..d58a6c17 100644 --- a/lib/submissions/generate_audit_trail.rb +++ b/lib/submissions/generate_audit_trail.rb @@ -129,6 +129,8 @@ module Submissions with_submitter_timezone = configs.find { |c| c.key == AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY }&.value == true with_timestamp_seconds = configs.find { |c| c.key == AccountConfig::WITH_TIMESTAMP_SECONDS_KEY }&.value == true + file_links_expire_at = Accounts.link_expires_at(submission.account) if with_file_links + timezone = account.timezone timezone = last_submitter.timezone || account.timezone if with_submitter_timezone @@ -408,7 +410,7 @@ module Submissions link = if with_file_links - ActiveStorage::Blob.proxy_url(attachment.blob) + ActiveStorage::Blob.proxy_url(attachment.blob, expires_at: file_links_expire_at) else r.submissions_preview_url(submission.slug, **Docuseal.default_url_options) end diff --git a/lib/submissions/generate_preview_attachments.rb b/lib/submissions/generate_preview_attachments.rb index cbfa373d..9b712733 100644 --- a/lib/submissions/generate_preview_attachments.rb +++ b/lib/submissions/generate_preview_attachments.rb @@ -29,6 +29,8 @@ module Submissions with_signature_id_reason = configs.find { |c| c.key == AccountConfig::WITH_SIGNATURE_ID_REASON_KEY }&.value != false + file_links_expire_at = Accounts.link_expires_at(submission.account) if with_file_links + pdfs_index = GenerateResultAttachments.build_pdfs_index(submission, flatten: is_flatten, incremental: is_rotate_incremental) @@ -42,7 +44,8 @@ module Submissions GenerateResultAttachments.fill_submitter_fields(s, submission.account, pdfs_index, with_signature_id:, is_flatten:, with_headings: index.zero?, with_submitter_timezone:, with_file_links:, - with_signature_id_reason:, with_timestamp_seconds:) + file_links_expire_at:, with_signature_id_reason:, + with_timestamp_seconds:) end template = submission.template diff --git a/lib/submissions/generate_result_attachments.rb b/lib/submissions/generate_result_attachments.rb index 5eba4a63..93398455 100644 --- a/lib/submissions/generate_result_attachments.rb +++ b/lib/submissions/generate_result_attachments.rb @@ -151,6 +151,8 @@ module Submissions with_signature_id_reason = configs.find { |c| c.key == AccountConfig::WITH_SIGNATURE_ID_REASON_KEY }&.value != false + file_links_expire_at = Accounts.link_expires_at(submitter.account) if with_file_links + pdfs_index = build_pdfs_index(submitter.submission, submitter:, flatten: is_flatten, incremental: is_rotate_incremental) @@ -198,12 +200,14 @@ module Submissions with_submitter_timezone:, with_file_links:, with_timestamp_seconds:, - with_signature_id_reason:) + with_signature_id_reason:, + file_links_expire_at:) end def fill_submitter_fields(submitter, account, pdfs_index, with_signature_id:, is_flatten:, with_headings: nil, with_submitter_timezone: false, with_signature_id_reason: true, - with_timestamp_seconds: false, with_file_links: nil) + with_timestamp_seconds: false, with_file_links: nil, + file_links_expire_at: Accounts.link_expires_at(account)) cell_layouters = Hash.new do |hash, valign| hash[valign] = HexaPDF::Layout::TextLayouter.new(text_valign: valign.to_sym, text_align: :center) end @@ -516,7 +520,7 @@ module Submissions url = if with_file_links - ActiveStorage::Blob.proxy_url(attachment.blob) + ActiveStorage::Blob.proxy_url(attachment.blob, expires_at: file_links_expire_at) else r.submissions_preview_url(submission.slug, **Docuseal.default_url_options) end From 9558060bde3798ed8af545ed7ba7ed91f91a412e Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Wed, 27 May 2026 20:38:37 +0300 Subject: [PATCH 10/27] check resubmit config --- app/controllers/start_form_controller.rb | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/controllers/start_form_controller.rb b/app/controllers/start_form_controller.rb index ed9c2629..22fa4ffa 100644 --- a/app/controllers/start_form_controller.rb +++ b/app/controllers/start_form_controller.rb @@ -101,11 +101,18 @@ class StartFormController < ApplicationController def load_resubmit_submitter @resubmit_submitter = if params[:resubmit].present? && !params[:resubmit].in?([true, 'true']) - Submitter.find_by(slug: params[:resubmit]) + submitter = Submitter.find_by(slug: params[:resubmit]) + + submitter if submitter && can_resubmit?(submitter) end end + def can_resubmit?(submitter) + submitter.account.account_configs.find_or_initialize_by(key: AccountConfig::ALLOW_TO_RESUBMIT).value != false + end + def authorize_start! + return redirect_to submit_form_path(@resubmit_submitter.slug) if @resubmit_submitter && @template.archived_at? return redirect_to start_form_path(@template.slug) if @template.archived_at? return if @resubmit_submitter From b8ab01c46c119de64e45dc21e5a36e40ee99c8f8 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Wed, 27 May 2026 21:25:25 +0300 Subject: [PATCH 11/27] add dynamic documents to template response --- app/controllers/api/templates_controller.rb | 51 +++++++++++++++------ app/models/dynamic_document.rb | 6 +++ app/models/template.rb | 2 +- lib/templates/serialize_for_api.rb | 47 +++++++++++++------ 4 files changed, 77 insertions(+), 29 deletions(-) diff --git a/app/controllers/api/templates_controller.rb b/app/controllers/api/templates_controller.rb index 87b756ea..b3d05cec 100644 --- a/app/controllers/api/templates_controller.rb +++ b/app/controllers/api/templates_controller.rb @@ -9,20 +9,7 @@ module Api templates = paginate(templates.preload(:author, folder: :parent_folder)) - schema_documents = - ActiveStorage::Attachment.where(record_id: templates.map(&:id), - record_type: 'Template', - name: :documents, - uuid: templates.flat_map { |t| t.schema.pluck('attachment_uuid') }) - .preload(:blob) - - preview_image_attachments = - ActiveStorage::Attachment.joins(:blob) - .where(blob: { filename: ['0.png', '0.jpg'] }) - .where(record_id: schema_documents.map(&:id), - record_type: 'ActiveStorage::Attachment', - name: :preview_images) - .preload(:blob) + schema_documents, dynamic_documents, preview_image_attachments = preload_relations(templates) expires_at = Accounts.link_expires_at(current_account) @@ -30,6 +17,7 @@ module Api data: templates.map do |t| Templates::SerializeForApi.call(t, schema_documents: schema_documents.select { |e| e.record_id == t.id }, + dynamic_documents:, preview_image_attachments:, expires_at:) end, @@ -88,6 +76,41 @@ module Api private + def preload_relations(templates) + schema_documents = + ActiveStorage::Attachment.where(record_id: templates.map(&:id), + record_type: 'Template', + name: :documents, + uuid: templates.flat_map { |t| t.schema.pluck('attachment_uuid') }) + .preload(:blob) + + dynamic_document_uuids = + templates.flat_map { |t| t.schema.select { |item| item['dynamic'] }.pluck('attachment_uuid') } + + dynamic_documents = + if dynamic_document_uuids.present? + DynamicDocument.where(template: templates.map(&:id)) + .where(uuid: dynamic_document_uuids) + .preload(current_version: { document_attachment: :blob }) + .select(:id, :uuid, :template_id, :sha1, :created_at, :updated_at) + else + DynamicDocument.none + end + + preview_attachment_ids = + schema_documents.map(&:id) + dynamic_documents.filter_map { |d| d.current_version&.document_attachment&.id } + + preview_image_attachments = + ActiveStorage::Attachment.joins(:blob) + .where(blob: { filename: ['0.png', '0.jpg'] }) + .where(record_id: preview_attachment_ids, + record_type: 'ActiveStorage::Attachment', + name: :preview_images) + .preload(:blob) + + [schema_documents, dynamic_documents, preview_image_attachments] + end + def filter_templates(templates, params) templates = Templates.search(current_user, templates, params[:q]) templates = params[:archived].in?(['true', true]) ? templates.archived : templates.active diff --git a/app/models/dynamic_document.rb b/app/models/dynamic_document.rb index 8d93ff9a..354b0005 100644 --- a/app/models/dynamic_document.rb +++ b/app/models/dynamic_document.rb @@ -28,6 +28,12 @@ class DynamicDocument < ApplicationRecord has_many :versions, class_name: 'DynamicDocumentVersion', dependent: :destroy + has_one :current_version, class_name: 'DynamicDocumentVersion', + primary_key: %i[id sha1], + foreign_key: %i[dynamic_document_id sha1], + dependent: :destroy, + inverse_of: :dynamic_document + attribute :fields, :json before_validation :set_sha1 diff --git a/app/models/template.rb b/app/models/template.rb index 3679c946..ca8b8d0f 100644 --- a/app/models/template.rb +++ b/app/models/template.rb @@ -75,7 +75,7 @@ class Template < ApplicationRecord has_many :dynamic_document_versions, through: :dynamic_documents, source: :versions has_many :schema_dynamic_documents, lambda { |e| - where(uuid: e.schema.select { |e| e['dynamic'] }.pluck('attachment_uuid')) + where(uuid: e.schema.select { |item| item['dynamic'] }.pluck('attachment_uuid')) }, class_name: 'DynamicDocument', dependent: :destroy, inverse_of: :template scope :active, -> { where(archived_at: nil) } diff --git a/lib/templates/serialize_for_api.rb b/lib/templates/serialize_for_api.rb index ec9cb628..64907f50 100644 --- a/lib/templates/serialize_for_api.rb +++ b/lib/templates/serialize_for_api.rb @@ -14,27 +14,25 @@ module Templates module_function - def call(template, schema_documents: template.schema_documents.preload(:blob), preview_image_attachments: nil, - expires_at: Accounts.link_expires_at(Account.new(id: template.account_id))) + def call(template, schema_documents: template.schema_documents.preload(:blob), dynamic_documents: nil, + preview_image_attachments: nil, expires_at: Accounts.link_expires_at(Account.new(id: template.account_id))) json = template.as_json(SERIALIZE_PARAMS) - preview_image_attachments ||= - ActiveStorage::Attachment.joins(:blob) - .where(blob: { filename: ['0.jpg', '0.png'] }) - .where(record_id: schema_documents.map(&:id), - record_type: 'ActiveStorage::Attachment', - name: :preview_images) - .preload(:blob) + dynamic_documents ||= preload_dynamic_documents(template) - json['documents'] = template.schema.filter_map do |item| - attachment = schema_documents.find { |e| e.uuid == item['attachment_uuid'] } + preview_image_attachments ||= preload_preview_image_attachments(schema_documents, dynamic_documents) - unless attachment - Rollbar.error("Documents missing: #{template.id}") if defined?(Rollbar) + json['documents'] = template.schema.filter_map do |item| + if item['dynamic'] + dynamic_document = dynamic_documents.find { |e| e.uuid == item['attachment_uuid'] } - next + attachment = dynamic_document.current_version&.document_attachment end + attachment ||= schema_documents.find { |e| e.uuid == item['attachment_uuid'] } + + next unless attachment + first_page_blob = preview_image_attachments.find { |e| e.record_id == attachment.id }&.blob first_page_blob ||= attachment.preview_images.joins(:blob).find_by(blob: { filename: ['0.jpg', '0.png'] })&.blob @@ -49,5 +47,26 @@ module Templates json end + + def preload_dynamic_documents(template) + return DynamicDocument.none if template.schema.none? { |item| item['dynamic'] } + + template.schema_dynamic_documents + .preload(current_version: { document_attachment: :blob }) + .select(:id, :uuid, :template_id, :sha1, :created_at, :updated_at) + end + + def preload_preview_image_attachments(schema_documents, dynamic_documents) + record_ids = + schema_documents.map(&:id) + + dynamic_documents.filter_map { |d| d.current_version&.document_attachment&.id } + + ActiveStorage::Attachment.joins(:blob) + .where(blob: { filename: ['0.jpg', '0.png'] }) + .where(record_id: record_ids, + record_type: 'ActiveStorage::Attachment', + name: :preview_images) + .preload(:blob) + end end end From c61e84d1b403100a32af0ab4fbe2c229492c4182 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Thu, 28 May 2026 08:40:05 +0300 Subject: [PATCH 12/27] adjust archive --- app/views/templates/_title.html.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/templates/_title.html.erb b/app/views/templates/_title.html.erb index b439fa7a..007e1be0 100644 --- a/app/views/templates/_title.html.erb +++ b/app/views/templates/_title.html.erb @@ -60,7 +60,7 @@
<% if !template.archived_at? && can?(:destroy, template) %> - <%= button_to button_title(title: t('archive'), disabled_with: t('archiving'), title_class: 'inline', icon: svg_icon('archive', class: 'w-6 h-6')), template_path(template), class: 'btn btn-outline btn-sm w-full', form_class: 'flex-1', method: :delete, data: { turbo_confirm: t('are_you_sure_') } %> + <%= button_to button_title(title: t('archive'), disabled_with: t('archiving')[..-4], title_class: 'inline', icon: svg_icon('archive', class: 'w-6 h-6')), template_path(template), class: 'btn btn-outline btn-sm w-full', form_class: 'flex-1', method: :delete %> <% end %> <% if can?(:create, current_account.templates.new(author: current_user)) %> <%= link_to new_template_clone_path(template), class: 'btn btn-outline btn-sm flex-1', data: { turbo_frame: :modal } do %> @@ -89,7 +89,7 @@ <% end %> <% if template.archived_at? %> <% if can?(:create, template) %> - <%= button_to button_title(title: t('restore'), disabled_with: t('restoring'), icon: svg_icon('rotate', class: 'w-6 h-6')), template_restore_index_path(template), class: 'btn btn-outline btn-sm flex-1' %> + <%= button_to button_title(title: t('restore'), disabled_with: t('restoring')[..-4], icon: svg_icon('rotate', class: 'w-6 h-6')), template_restore_index_path(template), class: 'btn btn-outline btn-sm flex-1' %> <% end %> <%= link_to template_preview_path(template), class: 'btn btn-outline btn-sm flex-1' do %> From 504c42646b1372cdfec8b161f5b18b5dbf99d779 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Thu, 28 May 2026 10:06:47 +0300 Subject: [PATCH 13/27] refactor template builder data --- app/controllers/templates_controller.rb | 18 +----------------- .../templates_preview_controller.rb | 13 +------------ app/views/templates/edit.html.erb | 2 +- app/views/templates_preview/show.html.erb | 2 +- lib/templates.rb | 16 ++++++++++++++++ 5 files changed, 20 insertions(+), 31 deletions(-) diff --git a/app/controllers/templates_controller.rb b/app/controllers/templates_controller.rb index f32e1e1e..ae54665a 100644 --- a/app/controllers/templates_controller.rb +++ b/app/controllers/templates_controller.rb @@ -1,10 +1,6 @@ # frozen_string_literal: true class TemplatesController < ApplicationController - TEMPLATE_FIELDS = %i[id author_id folder_id external_id name slug - schema fields submitters variables_schema preferences - shared_link source archived_at created_at updated_at].freeze - load_and_authorize_resource :template def show @@ -31,19 +27,7 @@ class TemplatesController < ApplicationController def new; end def edit - ActiveRecord::Associations::Preloader.new( - records: [@template], - associations: [{ schema_documents: [:blob, { preview_images_attachments: :blob }] }] - ).call - - @template_data = - @template.as_json(only: TEMPLATE_FIELDS).merge( - documents: @template.schema_documents.as_json( - only: %i[id uuid], - methods: %i[metadata signed_key], - include: { preview_images: { only: %i[id], methods: %i[url metadata filename] } } - ) - ).to_json + @template_data = Templates.serialize_for_builder(@template) render :edit, layout: 'plain' end diff --git a/app/controllers/templates_preview_controller.rb b/app/controllers/templates_preview_controller.rb index e132b131..602fc622 100644 --- a/app/controllers/templates_preview_controller.rb +++ b/app/controllers/templates_preview_controller.rb @@ -4,18 +4,7 @@ class TemplatesPreviewController < ApplicationController load_and_authorize_resource :template def show - ActiveRecord::Associations::Preloader.new( - records: [@template], - associations: [{ schema_documents: { preview_images_attachments: :blob } }] - ).call - - @template_data = - @template.as_json.merge( - documents: @template.schema_documents.as_json( - methods: %i[metadata signed_key], - include: { preview_images: { methods: %i[url metadata filename] } } - ) - ).to_json + @template_data = Templates.serialize_for_builder(@template) render :show, layout: 'plain' end diff --git a/app/views/templates/edit.html.erb b/app/views/templates/edit.html.erb index 3e7b9701..5ef4c41f 100644 --- a/app/views/templates/edit.html.erb +++ b/app/views/templates/edit.html.erb @@ -6,4 +6,4 @@ <%= button_to nil, user_configs_path, method: :post, params: { user_config: { key: UserConfig::SHOW_APP_TOUR, value: true } }, class: 'hidden', id: 'start_tour_button' %> <% end %> <% end %> - + diff --git a/app/views/templates_preview/show.html.erb b/app/views/templates_preview/show.html.erb index 01d4c932..79925471 100644 --- a/app/views/templates_preview/show.html.erb +++ b/app/views/templates_preview/show.html.erb @@ -1 +1 @@ - + diff --git a/lib/templates.rb b/lib/templates.rb index ad45a3fc..df015808 100644 --- a/lib/templates.rb +++ b/lib/templates.rb @@ -3,6 +3,10 @@ module Templates COLOR_REGEXP = /\A(#(?:[0-9a-f]{3}|[0-9a-f]{6})|[a-z]+)\z/i + TEMPLATE_BUILDER_FIELDS = %i[id author_id folder_id external_id name slug + schema fields submitters variables_schema preferences + shared_link source archived_at created_at updated_at].freeze + EXPIRATION_DURATIONS = { one_day: 1.day, two_days: 2.days, @@ -91,4 +95,16 @@ module Templates Time.current + EXPIRATION_DURATIONS[default_expire_at_duration] end end + + def serialize_for_builder(template) + data = template.as_json(only: TEMPLATE_BUILDER_FIELDS) + + data['documents'] = template.schema_documents.preload(:blob, { preview_images_attachments: :blob }).as_json( + only: %i[id uuid], + methods: %i[metadata signed_key], + include: { preview_images: { only: %i[id], methods: %i[url metadata filename] } } + ) + + data + end end From 51743f1359ebe3bd99eaeef1c5b183f801a07e79 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Thu, 28 May 2026 10:18:45 +0300 Subject: [PATCH 14/27] fix spec --- spec/system/template_spec.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/spec/system/template_spec.rb b/spec/system/template_spec.rb index 83aa0f8d..438a131d 100644 --- a/spec/system/template_spec.rb +++ b/spec/system/template_spec.rb @@ -42,9 +42,7 @@ RSpec.describe 'Template' do it 'archives a template' do expect do - accept_confirm('Are you sure?') do - click_button 'Archive' - end + click_button 'Archive' end.to change { Template.active.count }.by(-1) expect(page).to have_content('Template has been archived') From e8b36c2b6dc9d711da3b02417e8c9b0480e74bcd Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Thu, 28 May 2026 14:38:34 +0300 Subject: [PATCH 15/27] update gh stars --- app/views/shared/_github.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/shared/_github.html.erb b/app/views/shared/_github.html.erb index 7fa11f0b..51083118 100644 --- a/app/views/shared/_github.html.erb +++ b/app/views/shared/_github.html.erb @@ -1,6 +1,6 @@ <%= svg_icon('start', class: 'h-3 w-3') %> - 16k + 17k From cd6503c4c3d2873b2270a5191d17dd7f1f32fb79 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Thu, 28 May 2026 15:37:20 +0300 Subject: [PATCH 16/27] adjust image size --- app/views/profile/index.html.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/profile/index.html.erb b/app/views/profile/index.html.erb index 9f1ec645..c2211349 100644 --- a/app/views/profile/index.html.erb +++ b/app/views/profile/index.html.erb @@ -36,7 +36,7 @@ <% if signature %>
<%= button_to button_title(title: t('remove'), disabled_with: t('removing')), user_signature_path, method: :delete, class: 'right-0 top-0 absolute link' %> - +
<% end %> @@ -49,7 +49,7 @@ <% if initials %>
<%= button_to button_title(title: t('remove'), disabled_with: t('removing')), user_initials_path, method: :delete, class: 'right-0 top-0 absolute link' %> - +
<% end %>
From 58fd180ae0bea6e8ce087395772d2262e0c50e82 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Fri, 29 May 2026 08:04:53 +0300 Subject: [PATCH 17/27] update gem --- Gemfile.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 8d15dd29..b1167631 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -274,7 +274,7 @@ GEM rdoc (>= 4.0.0) reline (>= 0.4.2) jmespath (1.6.2) - json (2.19.5) + json (2.19.7) jwt (3.2.0) base64 language_server-protocol (3.17.0.5) @@ -434,7 +434,7 @@ GEM erb psych (>= 4.0.0) tsort - redis-client (0.28.0) + redis-client (0.29.0) connection_pool regexp_parser (2.11.3) reline (0.6.3) @@ -516,12 +516,12 @@ GEM rack-proxy (>= 0.6.1) railties (>= 5.2) semantic_range (>= 2.3.0) - sidekiq (8.1.2) + sidekiq (8.1.6) connection_pool (>= 3.0.0) json (>= 2.16.0) logger (>= 1.7.0) rack (>= 3.2.0) - redis-client (>= 0.26.0) + redis-client (>= 0.29.0) signet (0.21.0) addressable (~> 2.8) faraday (>= 0.17.5, < 3.a) From f65b6e2d767bfe88445615876fb69aabade9208c Mon Sep 17 00:00:00 2001 From: Alex Turchyn Date: Fri, 29 May 2026 09:29:21 +0300 Subject: [PATCH 18/27] add confirm prompt for template upload via URL --- .../templates_uploads_controller.rb | 4 +- app/javascript/application.js | 2 + app/javascript/elements/confirm_upload.js | 27 ++++++++++++ app/views/templates_uploads/show.html.erb | 44 ++++++++++++------- config/locales/i18n.yml | 21 +++++++++ spec/system/templates_upload_spec.rb | 40 +++++++++++++++++ 6 files changed, 121 insertions(+), 17 deletions(-) create mode 100644 app/javascript/elements/confirm_upload.js create mode 100644 spec/system/templates_upload_spec.rb diff --git a/app/controllers/templates_uploads_controller.rb b/app/controllers/templates_uploads_controller.rb index 7d8b1bae..ea4febf0 100644 --- a/app/controllers/templates_uploads_controller.rb +++ b/app/controllers/templates_uploads_controller.rb @@ -5,7 +5,9 @@ class TemplatesUploadsController < ApplicationController layout 'plain' - def show; end + def show + redirect_to root_path if params[:url].blank? + end def create url_params = create_file_params_from_url if params[:url].present? diff --git a/app/javascript/application.js b/app/javascript/application.js index 38b58ad0..6aa39fc8 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -54,6 +54,7 @@ import GoogleDriveFilePicker from './elements/google_drive_file_picker' import OpenModal from './elements/open_modal' import BarChart from './elements/bar_chart' import FieldCondition from './elements/field_condition' +import ConfirmUpload from './elements/confirm_upload' import * as TurboInstantClick from './lib/turbo_instant_click' @@ -146,6 +147,7 @@ safeRegisterElement('google-drive-file-picker', GoogleDriveFilePicker) safeRegisterElement('open-modal', OpenModal) safeRegisterElement('bar-chart', BarChart) safeRegisterElement('field-condition', FieldCondition) +safeRegisterElement('confirm-upload', ConfirmUpload) safeRegisterElement('template-builder', class extends HTMLElement { connectedCallback () { diff --git a/app/javascript/elements/confirm_upload.js b/app/javascript/elements/confirm_upload.js new file mode 100644 index 00000000..aa39601d --- /dev/null +++ b/app/javascript/elements/confirm_upload.js @@ -0,0 +1,27 @@ +import { target, targetable } from '@github/catalyst/lib/targetable' + +export default targetable(class extends HTMLElement { + static [target.static] = [ + 'prompt', + 'processing', + 'logo' + ] + + connectedCallback () { + this.form.addEventListener('submit', this.onSubmit) + } + + disconnectedCallback () { + this.form.removeEventListener('submit', this.onSubmit) + } + + onSubmit = () => { + this.prompt.classList.add('hidden') + this.processing.classList.remove('hidden') + this.logo.classList.add('animate-bounce') + } + + get form () { + return this.querySelector('form') + } +}) diff --git a/app/views/templates_uploads/show.html.erb b/app/views/templates_uploads/show.html.erb index 16ca71ab..cac1b7f5 100644 --- a/app/views/templates_uploads/show.html.erb +++ b/app/views/templates_uploads/show.html.erb @@ -1,18 +1,30 @@ -
-
- - - <%= form_for '', url: templates_upload_path, method: :post, class: 'hidden' do %> - - - - <% end %> - + diff --git a/config/locales/i18n.yml b/config/locales/i18n.yml index 0739846b..cb4c112b 100644 --- a/config/locales/i18n.yml +++ b/config/locales/i18n.yml @@ -937,6 +937,9 @@ en: &en your_email_address_has_been_changed: Your email address has been changed the_email_address_for_your_account_has_been_changed_to_new_email: The email address for your account has been changed to %{new_email}. if_you_did_not_make_this_change_please_contact_us_by_replying_to_this_email: If you did not make this change, please contact us by replying to this email. + open_file_from: 'Open file from' + cancel: Cancel + open: Open devise: confirmations: confirmed: Your email address has been successfully confirmed. @@ -1987,6 +1990,9 @@ es: &es your_email_address_has_been_changed: Tu dirección de correo electrónico ha sido cambiada the_email_address_for_your_account_has_been_changed_to_new_email: La dirección de correo electrónico de tu cuenta ha sido cambiada a %{new_email}. if_you_did_not_make_this_change_please_contact_us_by_replying_to_this_email: Si no realizaste este cambio, contáctanos respondiendo a este correo electrónico. + open_file_from: 'Abrir archivo desde' + cancel: Cancelar + open: Abrir devise: confirmations: confirmed: Tu dirección de correo electrónico ha sido confirmada correctamente. @@ -3037,6 +3043,9 @@ it: &it your_email_address_has_been_changed: Il tuo indirizzo email è stato modificato the_email_address_for_your_account_has_been_changed_to_new_email: L'indirizzo email del tuo account è stato modificato in %{new_email}. if_you_did_not_make_this_change_please_contact_us_by_replying_to_this_email: Se non hai effettuato questa modifica, contattaci rispondendo a questa email. + open_file_from: 'Aprire file da' + cancel: Annulla + open: Apri devise: confirmations: confirmed: Il tuo indirizzo email è stato confermato con successo. @@ -4084,6 +4093,9 @@ fr: &fr your_email_address_has_been_changed: Votre adresse e-mail a été modifiée the_email_address_for_your_account_has_been_changed_to_new_email: "L'adresse e-mail de votre compte a été modifiée en %{new_email}." if_you_did_not_make_this_change_please_contact_us_by_replying_to_this_email: Si vous n'avez pas effectué ce changement, veuillez nous contacter en répondant à cet e-mail. + open_file_from: 'Ouvrir le fichier depuis' + cancel: Annuler + open: Ouvrir devise: confirmations: confirmed: Votre adresse e-mail a été confirmée avec succès. @@ -5134,6 +5146,9 @@ pt: &pt your_email_address_has_been_changed: Seu endereço de e-mail foi alterado the_email_address_for_your_account_has_been_changed_to_new_email: O endereço de e-mail da sua conta foi alterado para %{new_email}. if_you_did_not_make_this_change_please_contact_us_by_replying_to_this_email: Se você não fez essa alteração, entre em contato conosco respondendo a este e-mail. + open_file_from: 'Abrir arquivo de' + cancel: Cancelar + open: Abrir devise: confirmations: confirmed: Seu endereço de e-mail foi confirmado com sucesso. @@ -6184,6 +6199,9 @@ de: &de your_email_address_has_been_changed: Ihre E-Mail-Adresse wurde geändert the_email_address_for_your_account_has_been_changed_to_new_email: Die E-Mail-Adresse Ihres Kontos wurde in %{new_email} geändert. if_you_did_not_make_this_change_please_contact_us_by_replying_to_this_email: Wenn Sie diese Änderung nicht vorgenommen haben, kontaktieren Sie uns bitte, indem Sie auf diese E-Mail antworten. + open_file_from: 'Datei öffnen von' + cancel: Abbrechen + open: Öffnen devise: confirmations: confirmed: Ihre E-Mail-Adresse wurde erfolgreich bestätigt. @@ -7635,6 +7653,9 @@ nl: &nl your_email_address_has_been_changed: Uw e-mailadres is gewijzigd the_email_address_for_your_account_has_been_changed_to_new_email: Het e-mailadres van uw account is gewijzigd naar %{new_email}. if_you_did_not_make_this_change_please_contact_us_by_replying_to_this_email: Als u deze wijziging niet hebt aangebracht, neem dan contact met ons op door op deze e-mail te antwoorden. + open_file_from: 'Bestand openen van' + cancel: Annuleren + open: Openen devise: confirmations: confirmed: Uw e-mailadres is succesvol bevestigd. diff --git a/spec/system/templates_upload_spec.rb b/spec/system/templates_upload_spec.rb new file mode 100644 index 00000000..84dbf6d9 --- /dev/null +++ b/spec/system/templates_upload_spec.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +RSpec.describe 'Templates Upload' do + let!(:account) { create(:account) } + let!(:user) { create(:user, account:) } + + before do + sign_in(user) + end + + context 'when url param is present' do + let(:file_url) { 'https://example.com/document.pdf' } + + before do + stub_request(:get, file_url).to_return( + body: Rails.root.join('spec/fixtures/sample-document.pdf').read, + headers: { 'Content-Type' => 'application/pdf' } + ) + end + + it 'shows a confirm page and creates template on submit' do + visit "/new?url=#{CGI.escape(file_url)}" + + expect(page).to have_text('Open file from') + expect(page).to have_link('example.com/document.pdf') + + click_button 'Open' + + expect(Template.last.name).to eq('document') + end + end + + context 'when url param is missing' do + it 'redirects to root' do + visit '/new' + + expect(page).to have_current_path(root_path) + end + end +end From ff57e5c6ae0e904f8d69c9629ef45a2d43b883bb Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Fri, 29 May 2026 15:31:32 +0300 Subject: [PATCH 19/27] fix pdfa --- lib/submissions/generate_result_attachments.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/submissions/generate_result_attachments.rb b/lib/submissions/generate_result_attachments.rb index 93398455..3b2260ff 100644 --- a/lib/submissions/generate_result_attachments.rb +++ b/lib/submissions/generate_result_attachments.rb @@ -747,7 +747,7 @@ module Submissions pdf.trailer.info[:Creator] = info_creator if Docuseal.pdf_format == 'pdf/a-3b' - pdf.task(:pdfa, level: '3b') + pdfa_listener = pdf.task(:pdfa, level: '3b') pdf.config['font.map'] = PDFA_FONT_MAP end @@ -766,6 +766,8 @@ module Submissions rescue HexaPDF::Error, NoMethodError, TypeError => e Rollbar.error(e) if defined?(Rollbar) + pdf.instance_variable_get(:@listeners)[:complete_objects].delete(pdfa_listener) if pdfa_listener + begin pdf.sign(io, write_options: { validate: false, incremental: false }, **sign_params) rescue HexaPDF::Error, TypeError From 5f069e7a402b7f40c684cf553a519c48c77b5be3 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Sat, 30 May 2026 07:49:40 +0300 Subject: [PATCH 20/27] use load vips --- lib/load_ico.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/load_ico.rb b/lib/load_ico.rb index d956092c..633bdbdf 100644 --- a/lib/load_ico.rb +++ b/lib/load_ico.rb @@ -43,7 +43,9 @@ module LoadIco raise ArgumentError, 'Unable to load' unless image_data_bytes && image_data_bytes.bytesize == best_entry[:size] - return Vips::Image.pngload_buffer(image_data_bytes) if image_data_bytes.start_with?(PNG_SIGNATURE) + if image_data_bytes.start_with?(PNG_SIGNATURE) + return ImageUtils.load_vips(image_data_bytes, content_type: 'image/png') + end image = load_image_entry(image_data_bytes, best_entry[:width], best_entry[:height]) From 46a6bd01081c561aa20b0d46e6842062d80b3333 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Sat, 30 May 2026 11:50:36 +0300 Subject: [PATCH 21/27] fix stamp --- lib/submitters/create_stamp_attachment.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/submitters/create_stamp_attachment.rb b/lib/submitters/create_stamp_attachment.rb index 4ae79b5b..9b922e35 100644 --- a/lib/submitters/create_stamp_attachment.rb +++ b/lib/submitters/create_stamp_attachment.rb @@ -40,6 +40,7 @@ module Submitters end logo = logo.resize([WIDTH / logo.width.to_f, HEIGHT / logo.height.to_f].min) + logo = logo.copy(interpretation: :srgb) if logo.interpretation == :multiband base_layer = Vips::Image.black(WIDTH, HEIGHT).new_from_image([255, 255, 255, 255]).copy(interpretation: :srgb) From a2c9ac170766571ae64da303b63752a279bc7e4a Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Sat, 30 May 2026 21:37:00 +0300 Subject: [PATCH 22/27] remove image_processing --- Gemfile | 1 - Gemfile.lock | 6 ------ 2 files changed, 7 deletions(-) diff --git a/Gemfile b/Gemfile index 7ed8fdeb..36783f0d 100644 --- a/Gemfile +++ b/Gemfile @@ -21,7 +21,6 @@ gem 'faraday' gem 'faraday-follow_redirects' gem 'google-cloud-storage', require: false gem 'hexapdf' -gem 'image_processing' gem 'jwt', require: false gem 'lograge' gem 'numo-narray-alt', require: false diff --git a/Gemfile.lock b/Gemfile.lock index b1167631..933cf9a8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -264,9 +264,6 @@ GEM strscan (>= 3.1.2) i18n (1.14.8) concurrent-ruby (~> 1.0) - image_processing (1.14.0) - mini_magick (>= 4.9.5, < 6) - ruby-vips (>= 2.0.17, < 3) io-console (0.8.2) irb (1.18.0) pp (>= 0.6.0) @@ -308,8 +305,6 @@ GEM marcel (1.1.0) matrix (0.4.3) method_source (1.1.0) - mini_magick (5.3.1) - logger mini_mime (1.1.5) minitest (6.0.6) drb (~> 2.0) @@ -624,7 +619,6 @@ DEPENDENCIES foreman google-cloud-storage hexapdf - image_processing jwt letter_opener_web lograge From b2d9948c30016a28cd2a4286a3c1c116c7f0194c Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Sat, 30 May 2026 22:37:39 +0300 Subject: [PATCH 23/27] remove active storage analyzers --- app/controllers/api/attachments_controller.rb | 6 +++--- app/views/profile/index.html.erb | 4 ++-- app/views/submissions/show.html.erb | 6 ++++-- config/application.rb | 2 ++ lib/submitters.rb | 5 +++-- lib/submitters/generate_font_image.rb | 4 +++- lib/submitters/normalize_values.rb | 6 ++++-- 7 files changed, 21 insertions(+), 12 deletions(-) diff --git a/app/controllers/api/attachments_controller.rb b/app/controllers/api/attachments_controller.rb index 1d24f8ca..2bb0db92 100644 --- a/app/controllers/api/attachments_controller.rb +++ b/app/controllers/api/attachments_controller.rb @@ -11,8 +11,6 @@ module Api @submitter = Submitter.find_by!(slug: params[:submitter_slug]) unless can_upload?(@submitter) - Rollbar.error("Can't upload: #{@submitter.id}") if defined?(Rollbar) - return render json: { error: I18n.t('form_has_been_archived') }, status: :unprocessable_content end @@ -33,9 +31,11 @@ module Api return render json: { error: "#{params[:type]} error, try to sign on another device" }, status: :unprocessable_content end + + metadata = { analyzed: true, identified: true, width: image.width, height: image.height } end - attachment = Submitters.create_attachment!(@submitter, file) + attachment = Submitters.create_attachment!(@submitter, file, metadata:) if params[:remember_signature] == 'true' && @submitter.email.present? cookies.encrypted[:signature_uuids] = build_new_cookie_signatures_json(@submitter, attachment) diff --git a/app/views/profile/index.html.erb b/app/views/profile/index.html.erb index c2211349..016f29ef 100644 --- a/app/views/profile/index.html.erb +++ b/app/views/profile/index.html.erb @@ -36,7 +36,7 @@ <% if signature %>
<%= button_to button_title(title: t('remove'), disabled_with: t('removing')), user_signature_path, method: :delete, class: 'right-0 top-0 absolute link' %> - +
<% end %>
@@ -49,7 +49,7 @@ <% if initials %>
<%= button_to button_title(title: t('remove'), disabled_with: t('removing')), user_initials_path, method: :delete, class: 'right-0 top-0 absolute link' %> - +
<% end %>
diff --git a/app/views/submissions/show.html.erb b/app/views/submissions/show.html.erb index 7922949c..3d23b90a 100644 --- a/app/views/submissions/show.html.erb +++ b/app/views/submissions/show.html.erb @@ -266,10 +266,12 @@
<% if field['type'].in?(%w[signature initials]) %>
- <%= field['name'] || field['title'] || field['type'] %> + <% img_height = attachments_index[value].metadata['height'] %> + <%= field['name'] || field['title'] || field['type'] %>
<% elsif field['type'].in?(['image', 'stamp', 'kba']) && attachments_index[value].image? %> - <%= field['name'] || field['title'] || field['type'] %> + <% img_height = attachments_index[value].metadata['height'] %> + <%= field['name'] || field['title'] || field['type'] %> <% elsif field['type'].in?(['file', 'payment', 'image']) %>
<% Array.wrap(value).each do |val| %> diff --git a/config/application.rb b/config/application.rb index b9131dc3..a44c39b0 100644 --- a/config/application.rb +++ b/config/application.rb @@ -25,6 +25,8 @@ module DocuSeal config.active_storage.draw_routes = ENV['MULTITENANT'] != 'true' + config.active_storage.analyzers = [] + config.active_storage.content_types_to_serve_as_binary += %w[ application/javascript text/javascript diff --git a/lib/submitters.rb b/lib/submitters.rb index cdb4ee43..97041550 100644 --- a/lib/submitters.rb +++ b/lib/submitters.rb @@ -122,7 +122,7 @@ module Submitters end end - def create_attachment!(submitter, file) + def create_attachment!(submitter, file, metadata: {}) raise ParamsError, 'file param is missing' if file.blank? extension = File.extname(file.original_filename).delete_prefix('.').downcase @@ -133,7 +133,8 @@ module Submitters blob = ActiveStorage::Blob.create_and_upload!(io: file.tap(&:rewind).open, filename: file.original_filename, - content_type: file.content_type) + content_type: file.content_type, + metadata:) ActiveStorage::Attachment.create!(blob:, name: 'attachments', record: submitter) end diff --git a/lib/submitters/generate_font_image.rb b/lib/submitters/generate_font_image.rb index b70d7450..0413355f 100644 --- a/lib/submitters/generate_font_image.rb +++ b/lib/submitters/generate_font_image.rb @@ -27,7 +27,9 @@ module Submitters text_mask = Vips::Image.black(text_image.width, text_image.height) - text_mask.bandjoin(text_image).copy(interpretation: :b_w).write_to_buffer('.png') + image = text_mask.bandjoin(text_image).copy(interpretation: :b_w) + + [image.write_to_buffer('.png'), image.width, image.height] end end end diff --git a/lib/submitters/normalize_values.rb b/lib/submitters/normalize_values.rb index fe9f2d02..54149f72 100644 --- a/lib/submitters/normalize_values.rb +++ b/lib/submitters/normalize_values.rb @@ -260,7 +260,7 @@ module Submitters end def find_or_create_blob_from_text(account, text, type) - data = Submitters::GenerateFontImage.call(text, font: type) + data, width, height = Submitters::GenerateFontImage.call(text, font: type) checksum = Digest::MD5.base64digest(data) @@ -268,7 +268,9 @@ module Submitters blob || ActiveStorage::Blob.create_and_upload!( io: StringIO.new(data), - filename: "#{type}.png" + filename: "#{type}.png", + content_type: 'image/png', + metadata: { analyzed: true, identified: true, width:, height: } ) end From 04cf36891e708c293a549b1d3b78e59f709a68dd Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Sun, 31 May 2026 09:09:57 +0300 Subject: [PATCH 24/27] fix complete button press enter --- app/javascript/submission_form/date_step.vue | 1 + app/javascript/submission_form/form.vue | 12 ++++++++++-- app/javascript/submission_form/image_step.vue | 1 + app/javascript/submission_form/kba_step.vue | 1 + app/javascript/submission_form/payment_step.vue | 2 ++ 5 files changed, 15 insertions(+), 2 deletions(-) diff --git a/app/javascript/submission_form/date_step.vue b/app/javascript/submission_form/date_step.vue index 245573da..f60fd6eb 100644 --- a/app/javascript/submission_form/date_step.vue +++ b/app/javascript/submission_form/date_step.vue @@ -27,6 +27,7 @@ +