diff --git a/Dockerfile b/Dockerfile index b1341fcf..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 @@ -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 diff --git a/app/controllers/submissions_export_controller.rb b/app/controllers/submissions_export_controller.rb index bfbb7359..d199e585 100644 --- a/app/controllers/submissions_export_controller.rb +++ b/app/controllers/submissions_export_controller.rb @@ -5,10 +5,11 @@ class SubmissionsExportController < ApplicationController load_and_authorize_resource :submission, through: :template, parent: false, only: :index def index - submissions = @submissions.active - .preload(submitters: { documents_attachments: :blob, - attachments_attachments: :blob }) - .order(id: :asc) + submissions = params[:archived] == 'true' ? @submissions.archived : @submissions.active + + submissions = submissions.preload(submitters: { documents_attachments: :blob, + attachments_attachments: :blob }) + .order(id: :asc) submissions = Submissions.search(current_user, submissions, params[:q], search_values: true) submissions = Submissions::Filter.call(submissions, current_user, params) diff --git a/app/controllers/submitters_autocomplete_controller.rb b/app/controllers/submitters_autocomplete_controller.rb index efbb110a..22599e58 100644 --- a/app/controllers/submitters_autocomplete_controller.rb +++ b/app/controllers/submitters_autocomplete_controller.rb @@ -7,25 +7,34 @@ class SubmittersAutocompleteController < ApplicationController LIMIT = 100 def index - submitters = search_submitters(@submitters) + field = SELECT_COLUMNS.find { |c| c == params[:field] } + + submitters = search_submitters(@submitters, field) arel_columns = SELECT_COLUMNS.map { |col| Submitter.arel_table[col] } - values = submitters.limit(LIMIT).group(arel_columns).pluck(arel_columns) + + values = + if field + max_ids = submitters.group(field).limit(LIMIT).select(Submitter.arel_table[:id].maximum) + + submitters.where(id: max_ids).order(id: :desc).pluck(arel_columns) + else + submitters.limit(LIMIT).group(arel_columns).pluck(arel_columns) + end attrs = values.map { |row| SELECT_COLUMNS.zip(row).to_h } - attrs = attrs.uniq { |e| e[params[:field]] } if params[:field].present? render json: attrs end private - def search_submitters(submitters) - if SELECT_COLUMNS.include?(params[:field]) + def search_submitters(submitters, field) + if field if Docuseal.fulltext_search? - Submitters.fulltext_search_field(current_user, submitters, params[:q], params[:field]) + Submitters.fulltext_search_field(current_user, submitters, params[:q], field) else - column = Submitter.arel_table[params[:field].to_sym] + column = Submitter.arel_table[field.to_sym] term = "#{params[:q].downcase}%" 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 diff --git a/app/javascript/application.js b/app/javascript/application.js index 8889609f..fe53cc5b 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -155,12 +155,15 @@ safeRegisterElement('template-builder', class extends HTMLElement { this.appElem.classList.add('md:h-screen') + const template = reactive(JSON.parse(this.dataset.template)) + this.app = createApp(TemplateBuilder, { - template: reactive(JSON.parse(this.dataset.template)), + template, customFields: reactive(JSON.parse(this.dataset.customFields || '[]')), backgroundColor: '#faf7f5', locale: this.dataset.locale, withPhone: this.dataset.withPhone === 'true', + withPrefillable: template.fields?.some((f) => f.prefillable), withVerification: ['true', 'false'].includes(this.dataset.withVerification) ? this.dataset.withVerification === 'true' : null, withKba: ['true', 'false'].includes(this.dataset.withKba) ? this.dataset.withKba === 'true' : null, withLogo: this.dataset.withLogo !== 'false', 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/javascript/template_builder/builder.vue b/app/javascript/template_builder/builder.vue index be19c2d4..969304e7 100644 --- a/app/javascript/template_builder/builder.vue +++ b/app/javascript/template_builder/builder.vue @@ -720,6 +720,11 @@ export default { required: false, default: false }, + withPrefillable: { + type: Boolean, + required: false, + default: false + }, customFields: { type: Array, required: false, @@ -948,13 +953,6 @@ export default { !submitter.email }) }, - withPrefillable () { - if (this.template.fields) { - return this.template.fields.some((f) => f.prefillable) - } else { - return false - } - }, isInlineSize () { return CSS.supports('container-type: size') }, diff --git a/app/javascript/template_builder/field.vue b/app/javascript/template_builder/field.vue index d7e04166..00f6d5d7 100644 --- a/app/javascript/template_builder/field.vue +++ b/app/javascript/template_builder/field.vue @@ -1,6 +1,7 @@