From d035525c7a6b320707dbade8682eb392aecc3e82 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Sat, 21 Feb 2026 08:26:09 +0200 Subject: [PATCH 01/13] additional terms --- Dockerfile | 2 +- LICENSE_ADDITIONAL_TERMS | 5 +++++ README.md | 4 ++-- 3 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 LICENSE_ADDITIONAL_TERMS diff --git a/Dockerfile b/Dockerfile index b1341fcf..68a2bee1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -80,7 +80,7 @@ COPY --chown=docuseal:docuseal ./log ./log COPY --chown=docuseal:docuseal ./lib ./lib COPY --chown=docuseal:docuseal ./public ./public COPY --chown=docuseal:docuseal ./tmp ./tmp -COPY --chown=docuseal:docuseal LICENSE README.md Rakefile config.ru .version ./ +COPY --chown=docuseal:docuseal LICENSE LICENSE_ADDITIONAL_TERMS README.md Rakefile config.ru .version ./ COPY --chown=docuseal:docuseal .version ./public/version COPY --chown=docuseal:docuseal --from=download /fonts/GoNotoKurrent-Regular.ttf /fonts/GoNotoKurrent-Bold.ttf /fonts/DancingScript-Regular.otf /fonts/OFL.txt /fonts diff --git a/LICENSE_ADDITIONAL_TERMS b/LICENSE_ADDITIONAL_TERMS new file mode 100644 index 00000000..cac2a50b --- /dev/null +++ b/LICENSE_ADDITIONAL_TERMS @@ -0,0 +1,5 @@ +Additional Terms + +In accordance with Section 7(b) of the GNU Affero General Public License, +a covered work must retain the original DocuSeal attribution in interactive +user interfaces. diff --git a/README.md b/README.md index fc1273d5..d97620c0 100644 --- a/README.md +++ b/README.md @@ -97,8 +97,8 @@ At DocuSeal we have expertise and technologies to make documents creation, filli ## License -Distributed under the AGPLv3 License. See [LICENSE](https://github.com/docusealco/docuseal/blob/master/LICENSE) for more information. -Unless otherwise noted, all files © 2023 DocuSeal LLC. +Distributed under the AGPLv3 License with Section 7(b) Additional Terms. See [LICENSE](https://github.com/docusealco/docuseal/blob/master/LICENSE) and [LICENSE_ADDITIONAL_TERMS](https://github.com/docusealco/docuseal/blob/master/LICENSE_ADDITIONAL_TERMS) for more information. +Unless otherwise noted, all files © 2023-2026 DocuSeal LLC. ## Tools From a5716cd5181eeaf9e9b5110f65a3481cb85c28de Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Tue, 24 Feb 2026 11:29:32 +0200 Subject: [PATCH 02/13] show html textarea --- app/javascript/elements/markdown_editor.js | 13 +- .../_markdown_editor.html.erb | 136 +++++++++--------- 2 files changed, 76 insertions(+), 73 deletions(-) diff --git a/app/javascript/elements/markdown_editor.js b/app/javascript/elements/markdown_editor.js index 17431277..b9937598 100644 --- a/app/javascript/elements/markdown_editor.js +++ b/app/javascript/elements/markdown_editor.js @@ -36,15 +36,11 @@ function loadTiptap () { } class LinkTooltip { - constructor (container, editor) { + constructor (container, editor, templateEl) { this.container = container this.editor = editor - const template = document.createElement('template') - - template.innerHTML = container.dataset.linkTooltipHtml - - this.tooltip = template.content.firstElementChild + this.tooltip = templateEl.content.firstElementChild.cloneNode(true) this.input = this.tooltip.querySelector('input') this.saveButton = this.tooltip.querySelector('[data-role="link-save"]') @@ -140,7 +136,8 @@ export default actionable(targetable(class extends HTMLElement { 'boldButton', 'italicButton', 'underlineButton', - 'linkButton' + 'linkButton', + 'linkTooltipTemplate' ] async connectedCallback () { @@ -256,7 +253,7 @@ export default actionable(targetable(class extends HTMLElement { } }) - this.linkTooltip = new LinkTooltip(this, this.editor) + this.linkTooltip = new LinkTooltip(this, this.editor, this.linkTooltipTemplate) } adjustShortcutsForPlatform () { diff --git a/app/views/personalization_settings/_markdown_editor.html.erb b/app/views/personalization_settings/_markdown_editor.html.erb index b870fffc..5e43e5cb 100644 --- a/app/views/personalization_settings/_markdown_editor.html.erb +++ b/app/views/personalization_settings/_markdown_editor.html.erb @@ -1,70 +1,76 @@ -<% link_tooltip_html = capture do %> - -<% end %> - -
-
-
-
- -
-
- -
-
- -
-
- -
+<% if value.to_s.start_with?(' + + <%= text_area_tag name, value, required: true, class: 'base-input w-full py-2 !rounded-2xl', dir: 'auto', style: 'max-height: 400px' %> + +<% else %> + + +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
-
- <% if local_assigns[:variables]&.any? %> - <% variable_labels = { 'account.name' => t('variables.account_name'), 'submitter.link' => t('variables.submitter_link'), 'template.name' => t('variables.template_name'), 'submission.submitters' => t('variables.submission_submitters'), 'submission.link' => t('variables.submission_link'), 'documents.link' => t('variables.documents_link') } %> - -
-
- <%= hidden_field_tag name, value, required: true, data: { target: 'markdown-editor.textarea' } %> -
+ <%= hidden_field_tag name, value, required: true, data: { target: 'markdown-editor.textarea' } %> + +<% end %> From 4f2830a34d66936658814d3cc129dc83cb4c769c Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Tue, 24 Feb 2026 11:46:55 +0200 Subject: [PATCH 03/13] increase image resolution --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 68a2bee1..52531940 100644 --- a/Dockerfile +++ b/Dockerfile @@ -48,7 +48,7 @@ ENV RAILS_ENV=production ENV BUNDLE_WITHOUT="development:test" ENV LD_PRELOAD=/lib/libgcompat.so.0 ENV OPENSSL_CONF=/etc/openssl_legacy.cnf -ENV VIPS_MAX_COORD=10000 +ENV VIPS_MAX_COORD=15000 WORKDIR /app From bd28a761d06b9f7890277c2dd14969550547dbae Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Tue, 24 Feb 2026 11:58:10 +0200 Subject: [PATCH 04/13] adjust bmp loader --- lib/load_bmp.rb | 97 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 78 insertions(+), 19 deletions(-) diff --git a/lib/load_bmp.rb b/lib/load_bmp.rb index 2dc3269e..9b99d964 100644 --- a/lib/load_bmp.rb +++ b/lib/load_bmp.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true module LoadBmp + BPPS = [1, 4, 8, 24, 32].freeze + module_function # rubocop:disable Metrics @@ -16,18 +18,25 @@ module LoadBmp header_data[:height] ) - final_pixel_data = prepare_unpadded_pixel_data_string( - raw_pixel_data_from_file, - header_data[:bpp], - header_data[:width], - header_data[:height], - header_data[:bmp_stride] - ) - - bands = header_data[:bpp] / 8 - - unless header_data[:bpp] == 24 || header_data[:bpp] == 32 - raise ArgumentError, "Conversion for #{header_data[:bpp]}-bpp BMP not implemented." + if header_data[:bpp] <= 8 + final_pixel_data = decode_indexed_pixel_data( + raw_pixel_data_from_file, + header_data[:bpp], + header_data[:width], + header_data[:height], + header_data[:bmp_stride], + header_data[:color_table] + ) + bands = 3 + else + final_pixel_data = prepare_unpadded_pixel_data_string( + raw_pixel_data_from_file, + header_data[:bpp], + header_data[:width], + header_data[:height], + header_data[:bmp_stride] + ) + bands = header_data[:bpp] / 8 end image = Vips::Image.new_from_memory(final_pixel_data, header_data[:width], header_data[:height], bands, :uchar) @@ -35,7 +44,9 @@ module LoadBmp image = image.flip(:vertical) if header_data[:orientation] == -1 image_rgb = - if bands == 3 + if header_data[:bpp] <= 8 + image + elsif bands == 3 image.recomb(band3_recomb) elsif bands == 4 image.recomb(band4_recomb) @@ -93,15 +104,31 @@ module LoadBmp "Unsupported BMP compression type: #{compression}. Only uncompressed (0) is supported." end - unless [24, 32].include?(bpp) - raise ArgumentError, "Unsupported BMP bits per pixel: #{bpp}. Only 24-bit and 32-bit are supported." + if BPPS.exclude?(bpp) + raise ArgumentError, "Unsupported BMP bits per pixel: #{bpp}. Only 1, 4, 8, 24, and 32-bit are supported." end raise ArgumentError, "Unsupported BMP planes: #{planes}. Expected 1." if planes != 1 - bytes_per_pixel = bpp / 8 - row_size_unpadded = width * bytes_per_pixel - bmp_stride = (row_size_unpadded + 3) & ~3 + bmp_stride = (((width * bpp) + 31) / 32) * 4 + + color_table = nil + + if bpp <= 8 + num_colors = 1 << bpp + color_table_offset = 14 + info_header_size + color_table_size = num_colors * 4 + + if bmp_bytes.bytesize < color_table_offset + color_table_size + raise ArgumentError, 'BMP data too short for color table.' + end + + color_table = Array.new(num_colors) do |i| + offset = color_table_offset + (i * 4) + b, g, r = bmp_bytes.unpack("@#{offset}CCC") + [r, g, b] + end + end { width:, @@ -109,7 +136,8 @@ module LoadBmp bpp:, pixel_data_offset:, bmp_stride:, - orientation: + orientation:, + color_table: } end @@ -163,6 +191,37 @@ module LoadBmp unpadded_rows.join end + def decode_indexed_pixel_data(raw_data, bpp, width, height, bmp_stride, color_table) + palette = color_table.map { |r, g, b| [r, g, b].pack('CCC') } + + output = String.new(capacity: width * height * 3) + + height.times do |y| + row_offset = y * bmp_stride + + case bpp + when 1 + width.times do |x| + byte_val = raw_data.getbyte(row_offset + (x >> 3)) + index = (byte_val >> (7 - (x & 7))) & 0x01 + output << palette[index] + end + when 4 + width.times do |x| + byte_val = raw_data.getbyte(row_offset + (x >> 1)) + index = x.even? ? (byte_val >> 4) & 0x0F : byte_val & 0x0F + output << palette[index] + end + when 8 + width.times do |x| + output << palette[raw_data.getbyte(row_offset + x)] + end + end + end + + output + end + def band3_recomb @band3_recomb ||= Vips::Image.new_from_array( From db3b80c96c925da2a3e6dd72e3b4b0bb344b8825 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Wed, 25 Feb 2026 00:12:37 +0200 Subject: [PATCH 05/13] fix clone --- app/controllers/templates_clone_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/templates_clone_controller.rb b/app/controllers/templates_clone_controller.rb index 802a97e0..51a4de28 100644 --- a/app/controllers/templates_clone_controller.rb +++ b/app/controllers/templates_clone_controller.rb @@ -21,7 +21,7 @@ class TemplatesCloneController < ApplicationController authorize!(:create, @template) - if params[:account_id].present? && true_ability.authorize!(:manage, Account.find(params[:account_id])) + if params[:account_id].present? && true_ability.can?(:manage, Account.find(params[:account_id])) @template.account_id = params[:account_id] @template.author = true_user if true_user.account_id == @template.account_id @template.folder = @template.account.default_template_folder if @template.account_id != current_account.id From 5a31df40d83c6e29421e01d94c204ec124ccfdb6 Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Wed, 25 Feb 2026 10:15:41 +0200 Subject: [PATCH 06/13] add field settings classes --- .../template_builder/field_context_menu.vue | 40 +++++++------ .../template_builder/field_settings.vue | 57 +++++++++++++------ .../template_builder/payment_settings.vue | 17 +++--- 3 files changed, 74 insertions(+), 40 deletions(-) diff --git a/app/javascript/template_builder/field_context_menu.vue b/app/javascript/template_builder/field_context_menu.vue index 26384fa7..9635f189 100644 --- a/app/javascript/template_builder/field_context_menu.vue +++ b/app/javascript/template_builder/field_context_menu.vue @@ -11,7 +11,7 @@ >