Merge from docusealco/wip

master 2.2.6
Alex Turchyn 1 day ago committed by GitHub
commit ae891932c5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -1,27 +1,14 @@
name: Build Docker Images name: Build Docker Images
on: on:
workflow_dispatch: push:
inputs: tags:
version: - "*.*.*"
description: Version
type: string
required: true
image:
description: QEMU image
type: string
required: false
default: tonistiigi/binfmt:latest
os:
description: OS
type: string
required: false
default: ubuntu-24.04-arm
jobs: jobs:
build: build:
runs-on: ${{ inputs.os }} runs-on: ubuntu-24.04-arm
timeout-minutes: 20 timeout-minutes: 30
steps: steps:
- name: Checkout code - name: Checkout code
@ -34,18 +21,16 @@ jobs:
uses: docker/metadata-action@v4 uses: docker/metadata-action@v4
with: with:
images: docuseal/docuseal images: docuseal/docuseal
tags: latest,${{ inputs.version }} tags: type=semver,pattern={{version}}
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v3 uses: docker/setup-qemu-action@v3
with:
image: ${{ inputs.image }}
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
- name: Create .version file - name: Create .version file
run: echo ${{ inputs.version }} > .version run: echo ${{ github.ref_name }} > .version
- name: Login to Docker Hub - name: Login to Docker Hub
uses: docker/login-action@v3 uses: docker/login-action@v3

@ -182,13 +182,13 @@ module Api
def submissions_params def submissions_params
permitted_attrs = [ permitted_attrs = [
:send_email, :send_sms, :bcc_completed, :completed_redirect_url, :reply_to, :go_to_last, :send_email, :send_sms, :bcc_completed, :completed_redirect_url, :reply_to, :go_to_last,
:require_phone_2fa, :expire_at, :name, :require_phone_2fa, :require_email_2fa, :expire_at, :name,
{ {
variables: {}, variables: {},
message: %i[subject body], message: %i[subject body],
submitters: [[:send_email, :send_sms, :completed_redirect_url, :uuid, :name, :email, :role, submitters: [[:send_email, :send_sms, :completed_redirect_url, :uuid, :name, :email, :role,
:completed, :phone, :application_key, :external_id, :reply_to, :go_to_last, :completed, :phone, :application_key, :external_id, :reply_to, :go_to_last,
:require_phone_2fa, :order, :require_phone_2fa, :require_email_2fa, :order, :invite_by,
{ metadata: {}, values: {}, roles: [], readonly_fields: [], message: %i[subject body], { metadata: {}, values: {}, roles: [], readonly_fields: [], message: %i[subject body],
fields: [:name, :uuid, :default_value, :value, :title, :description, fields: [:name, :uuid, :default_value, :value, :title, :description,
:readonly, :required, :validation_pattern, :invalid_message, :readonly, :required, :validation_pattern, :invalid_message,

@ -84,7 +84,7 @@ module Api
submitter_params.permit( submitter_params.permit(
:send_email, :send_sms, :reply_to, :completed_redirect_url, :uuid, :name, :email, :role, :send_email, :send_sms, :reply_to, :completed_redirect_url, :uuid, :name, :email, :role,
:completed, :phone, :application_key, :external_id, :go_to_last, :require_phone_2fa, :completed, :phone, :application_key, :external_id, :go_to_last, :require_phone_2fa, :require_email_2fa,
{ metadata: {}, values: {}, readonly_fields: [], message: %i[subject body], { metadata: {}, values: {}, readonly_fields: [], message: %i[subject body],
fields: [[:name, :uuid, :default_value, :value, :required, fields: [[:name, :uuid, :default_value, :value, :required,
:readonly, :validation_pattern, :invalid_message, :readonly, :validation_pattern, :invalid_message,

@ -12,6 +12,14 @@ class SubmissionsController < ApplicationController
authorize!(:create, Submission) authorize!(:create, Submission)
end end
FIELD_ICONS = {
'text' => 'text_size', 'signature' => 'writing_sign', 'date' => 'calendar_event',
'number' => 'square_number_1', 'image' => 'photo', 'initials' => 'letter_case_upper',
'file' => 'paperclip', 'select' => 'select', 'checkbox' => 'checkbox', 'radio' => 'circle_dot',
'stamp' => 'rubber_stamp', 'cells' => 'columns_3', 'multiple' => 'checks', 'phone' => 'phone_check',
'payment' => 'credit_card', 'verification' => 'id'
}.freeze
def show def show
@submission = Submissions.preload_with_pages(@submission) @submission = Submissions.preload_with_pages(@submission)

@ -537,7 +537,7 @@
/> />
<div <div
v-if="stepFields.length < 80" v-if="stepFields.length < 80"
class="flex justify-center mt-3 sm:mt-4 mb-0 sm:mb-1" class="flex justify-center mt-3 sm:mt-4 mb-0 sm:mb-1 select-none"
> >
<div class="flex items-center flex-wrap steps-progress"> <div class="flex items-center flex-wrap steps-progress">
<a <a

@ -13,7 +13,7 @@ const en = {
esignature_disclosure: 'eSignature Disclosure', esignature_disclosure: 'eSignature Disclosure',
signature: 'Signature', signature: 'Signature',
initials: 'Initials', initials: 'Initials',
drawn_signature_on_a_touchscreen_device: 'Drawn signature on a touchscreen device', sign_on_the_touchscreen: 'Sign on the touchscreen',
approved: 'Approved', approved: 'Approved',
reviewed: 'Reviewed', reviewed: 'Reviewed',
other: 'Other', other: 'Other',
@ -120,7 +120,7 @@ const es = {
select_a_reason: 'Selecciona una razón', select_a_reason: 'Selecciona una razón',
value_is_invalid: 'El valor no es válido', value_is_invalid: 'El valor no es válido',
verification_code_is_invalid: 'El código de verificación no es válido', verification_code_is_invalid: 'El código de verificación no es válido',
drawn_signature_on_a_touchscreen_device: 'Firma dibujada en un dispositivo con pantalla táctil', sign_on_the_touchscreen: 'Firmar en pantalla táctil',
scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: 'Escanea el código QR con la aplicación de la cámara para abrir el formulario en el móvil y dibujar tu firma', scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: 'Escanea el código QR con la aplicación de la cámara para abrir el formulario en el móvil y dibujar tu firma',
by_clicking_you_agree_to_the: 'Al hacer clic en "{button}", usted acepta el', by_clicking_you_agree_to_the: 'Al hacer clic en "{button}", usted acepta el',
electronic_signature_disclosure: 'Divulgación de Firma Electrónica', electronic_signature_disclosure: 'Divulgación de Firma Electrónica',
@ -221,7 +221,7 @@ const it = {
select_a_reason: 'Seleziona una ragione', select_a_reason: 'Seleziona una ragione',
value_is_invalid: 'Il valore non è valido', value_is_invalid: 'Il valore non è valido',
verification_code_is_invalid: 'Il codice di verifica non è valido', verification_code_is_invalid: 'Il codice di verifica non è valido',
drawn_signature_on_a_touchscreen_device: 'Firma disegnata su un dispositivo con schermo tattile', sign_on_the_touchscreen: 'Firma su schermo tattile',
scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: "Scansiona il codice QR con l'app della fotocamera per aprire il modulo sul cellulare e disegnare la tua firma", scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: "Scansiona il codice QR con l'app della fotocamera per aprire il modulo sul cellulare e disegnare la tua firma",
by_clicking_you_agree_to_the: 'Cliccando su "{button}", accetti il', by_clicking_you_agree_to_the: 'Cliccando su "{button}", accetti il',
electronic_signature_disclosure: 'Divulgazione della Firma Elettronica', electronic_signature_disclosure: 'Divulgazione della Firma Elettronica',
@ -316,7 +316,7 @@ const de = {
esignature_disclosure: 'Hinweis zur eSignatur', esignature_disclosure: 'Hinweis zur eSignatur',
signature: 'Unterschrift', signature: 'Unterschrift',
initials: 'Initialen', initials: 'Initialen',
drawn_signature_on_a_touchscreen_device: 'Auf einem Touchscreen-Gerät gezeichnete Unterschrift', sign_on_the_touchscreen: 'Auf Touchscreen signieren',
approved: 'Genehmigt', approved: 'Genehmigt',
reviewed: 'Geprüft', reviewed: 'Geprüft',
other: 'Sonstiges', other: 'Sonstiges',
@ -417,7 +417,7 @@ const fr = {
esignature_disclosure: 'Déclaration eSignature', esignature_disclosure: 'Déclaration eSignature',
signature: 'Signature', signature: 'Signature',
initials: 'Initiales', initials: 'Initiales',
drawn_signature_on_a_touchscreen_device: 'Signature dessinée sur un appareil à écran tactile', sign_on_the_touchscreen: 'Signer sur écran tactile',
approved: 'Approuvé', approved: 'Approuvé',
reviewed: 'Révisé', reviewed: 'Révisé',
other: 'Autre', other: 'Autre',
@ -524,7 +524,7 @@ const pl = {
select_a_reason: 'Wybierz powód', select_a_reason: 'Wybierz powód',
value_is_invalid: 'Wartość jest nieprawidłowa', value_is_invalid: 'Wartość jest nieprawidłowa',
verification_code_is_invalid: 'Kod weryfikacyjny jest nieprawidłowy', verification_code_is_invalid: 'Kod weryfikacyjny jest nieprawidłowy',
drawn_signature_on_a_touchscreen_device: 'Podpis odręczny na urządzeniu z ekranem dotykowym', sign_on_the_touchscreen: 'Podpisz na ekranie dotykowym',
scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: 'Zeskanuj kod QR za pomocą aplikacji aparatu, aby otworzyć formularz na telefonie i narysować swój podpis', scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: 'Zeskanuj kod QR za pomocą aplikacji aparatu, aby otworzyć formularz na telefonie i narysować swój podpis',
by_clicking_you_agree_to_the: 'Klikając na "{button}", zgadzasz się na', by_clicking_you_agree_to_the: 'Klikając na "{button}", zgadzasz się na',
electronic_signature_disclosure: 'Ujawnienie Elektronicznej Sygnatury', electronic_signature_disclosure: 'Ujawnienie Elektronicznej Sygnatury',
@ -625,7 +625,7 @@ const uk = {
select_a_reason: 'Виберіть причину', select_a_reason: 'Виберіть причину',
value_is_invalid: 'Значення є неправильним', value_is_invalid: 'Значення є неправильним',
verification_code_is_invalid: 'Код підтвердження є неправильним', verification_code_is_invalid: 'Код підтвердження є неправильним',
drawn_signature_on_a_touchscreen_device: 'Підпис на сенсорному пристрої', sign_on_the_touchscreen: 'Підписати на сенсорному екрані',
scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: 'Скануйте QR-код за допомогою програми камери, щоб відкрити форму на мобільному пристрої та намалювати свій підпис', scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: 'Скануйте QR-код за допомогою програми камери, щоб відкрити форму на мобільному пристрої та намалювати свій підпис',
by_clicking_you_agree_to_the: 'Натиснувши на "{button}", ви погоджуєтеся з', by_clicking_you_agree_to_the: 'Натиснувши на "{button}", ви погоджуєтеся з',
electronic_signature_disclosure: 'Розголошення Електронного Підпису', electronic_signature_disclosure: 'Розголошення Електронного Підпису',
@ -726,7 +726,7 @@ const cs = {
select_a_reason: 'Vyberte důvod', select_a_reason: 'Vyberte důvod',
value_is_invalid: 'Hodnota je neplatná', value_is_invalid: 'Hodnota je neplatná',
verification_code_is_invalid: 'Ověřovací kód je neplatný', verification_code_is_invalid: 'Ověřovací kód je neplatný',
drawn_signature_on_a_touchscreen_device: 'Namalovaný podpis na dotykovém zařízení', sign_on_the_touchscreen: 'Podepsat na dotykové obrazovce',
scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: 'Naskenujte QR kód pomocí aplikace fotoaparátu, abyste otevřeli formulář na mobilním zařízení a nakreslili svůj podpis', scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: 'Naskenujte QR kód pomocí aplikace fotoaparátu, abyste otevřeli formulář na mobilním zařízení a nakreslili svůj podpis',
by_clicking_you_agree_to_the: 'Kliknutím na "{button}" souhlasíte s', by_clicking_you_agree_to_the: 'Kliknutím na "{button}" souhlasíte s',
electronic_signature_disclosure: 'Zveřejněním Elektronického Podpisu', electronic_signature_disclosure: 'Zveřejněním Elektronického Podpisu',
@ -827,7 +827,7 @@ const pt = {
select_a_reason: 'Selecione um motivo', select_a_reason: 'Selecione um motivo',
value_is_invalid: 'Valor é inválido', value_is_invalid: 'Valor é inválido',
verification_code_is_invalid: 'Código de verificação é inválido', verification_code_is_invalid: 'Código de verificação é inválido',
drawn_signature_on_a_touchscreen_device: 'Assinatura desenhada em um dispositivo com tela sensível ao toque', sign_on_the_touchscreen: 'Assinar na tela sensível',
scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: 'Escaneie o código QR com o aplicativo da câmera para abrir o formulário no celular e desenhar sua assinatura', scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: 'Escaneie o código QR com o aplicativo da câmera para abrir o formulário no celular e desenhar sua assinatura',
by_clicking_you_agree_to_the: 'Ao clicar em "{button}", você concorda com o', by_clicking_you_agree_to_the: 'Ao clicar em "{button}", você concorda com o',
electronic_signature_disclosure: 'Divulgação de Assinatura Eletrônica', electronic_signature_disclosure: 'Divulgação de Assinatura Eletrônica',
@ -928,7 +928,7 @@ const he = {
select_a_reason: 'בחר סיבה', select_a_reason: 'בחר סיבה',
value_is_invalid: 'ערך לא תקין', value_is_invalid: 'ערך לא תקין',
verification_code_is_invalid: 'קוד האימות אינו תקין', verification_code_is_invalid: 'קוד האימות אינו תקין',
drawn_signature_on_a_touchscreen_device: 'חתימה שנוצרה במכשיר עם מסך מגע', sign_on_the_touchscreen: 'חתום על מסך המגע',
scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: 'סרוק את קוד ה-QR באמצעות אפליקציית המצלמה כדי לפתוח את הטופס במובייל ולצייר את החתימה שלך', scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: 'סרוק את קוד ה-QR באמצעות אפליקציית המצלמה כדי לפתוח את הטופס במובייל ולצייר את החתימה שלך',
by_clicking_you_agree_to_the: 'על ידי לחיצה על "{button}", אתה מסכים ל', by_clicking_you_agree_to_the: 'על ידי לחיצה על "{button}", אתה מסכים ל',
electronic_signature_disclosure: 'חשיפת חתימה אלקטרונית', electronic_signature_disclosure: 'חשיפת חתימה אלקטרונית',
@ -1029,7 +1029,7 @@ const nl = {
select_a_reason: 'Selecteer een reden', select_a_reason: 'Selecteer een reden',
value_is_invalid: 'Waarde is ongeldig', value_is_invalid: 'Waarde is ongeldig',
verification_code_is_invalid: 'Verificatiecode is ongeldig', verification_code_is_invalid: 'Verificatiecode is ongeldig',
drawn_signature_on_a_touchscreen_device: 'Getekende handtekening op een apparaat met een touchscreen', sign_on_the_touchscreen: 'Onderteken op touchscreen',
scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: 'Scan de QR-code met de camera-app om het formulier op mobiel te openen en uw handtekening te tekenen', scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: 'Scan de QR-code met de camera-app om het formulier op mobiel te openen en uw handtekening te tekenen',
by_clicking_you_agree_to_the: 'Door op "{button}" te klikken, gaat u akkoord met de', by_clicking_you_agree_to_the: 'Door op "{button}" te klikken, gaat u akkoord met de',
electronic_signature_disclosure: 'Openbaarmaking van Elektronische Handtekening', electronic_signature_disclosure: 'Openbaarmaking van Elektronische Handtekening',
@ -1131,7 +1131,7 @@ const ar = {
value_is_invalid: 'القيمة غير صالحة', value_is_invalid: 'القيمة غير صالحة',
verification_code_is_invalid: 'رمز التحقق غير صالح', verification_code_is_invalid: 'رمز التحقق غير صالح',
already_paid: 'تم الدفع بالفعل', already_paid: 'تم الدفع بالفعل',
drawn_signature_on_a_touchscreen_device: 'توقيع مرسوم على جهاز بشاشة تعمل باللمس', sign_on_the_touchscreen: 'وقع على شاشة اللمس',
scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: 'امسح رمز الاستجابة السريعة باستخدام تطبيق الكاميرا لفتح النموذج على الهاتف المحمول ورسم توقيعك', scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: 'امسح رمز الاستجابة السريعة باستخدام تطبيق الكاميرا لفتح النموذج على الهاتف المحمول ورسم توقيعك',
by_clicking_you_agree_to_the: 'بالنقر فوق "{button}"، أنت توافق على', by_clicking_you_agree_to_the: 'بالنقر فوق "{button}"، أنت توافق على',
electronic_signature_disclosure: 'كشف التوقيع الإلكتروني', electronic_signature_disclosure: 'كشف التوقيع الإلكتروني',
@ -1229,7 +1229,7 @@ const ko = {
reviewed_by: '검토자', reviewed_by: '검토자',
authored_by: '작성자', authored_by: '작성자',
select_a_reason: '이유 선택', select_a_reason: '이유 선택',
drawn_signature_on_a_touchscreen_device: '터치스크린 장치에서 그린 서명', sign_on_the_touchscreen: '터치스크린에서 서명',
scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: '카메라 앱으로 QR 코드를 스캔하여 모바일에서 양식을 열고 서명을 그리세요', scan_the_qr_code_with_the_camera_app_to_open_the_form_on_mobile_and_draw_your_signature: '카메라 앱으로 QR 코드를 스캔하여 모바일에서 양식을 열고 서명을 그리세요',
by_clicking_you_agree_to_the: '"{button}"를 클릭함으로써, 다음에 동의하게 됩니다', by_clicking_you_agree_to_the: '"{button}"를 클릭함으로써, 다음에 동의하게 됩니다',
electronic_signature_disclosure: '전자 서명 공개', electronic_signature_disclosure: '전자 서명 공개',
@ -1326,7 +1326,7 @@ const ja = {
esignature_disclosure: '電子署名開示', esignature_disclosure: '電子署名開示',
signature: '署名', signature: '署名',
initials: 'イニシャル', initials: 'イニシャル',
drawn_signature_on_a_touchscreen_device: 'タッチスクリーンデバイスで描かれた署名', sign_on_the_touchscreen: 'タッチスクリーンで署名',
approved: '承認済み', approved: '承認済み',
reviewed: '確認済み', reviewed: '確認済み',
other: 'その他', other: 'その他',

@ -19,7 +19,7 @@
<div class="space-x-2 flex flex-none"> <div class="space-x-2 flex flex-none">
<span <span
v-if="isDrawInitials" v-if="isDrawInitials"
class="tooltip" class="md:tooltip"
:data-tip="t('type_initial')" :data-tip="t('type_initial')"
> >
<a <a
@ -36,7 +36,7 @@
</span> </span>
<span <span
v-else v-else
class="tooltip ml-2" class="md:tooltip ml-2"
:data-tip="t('draw_initials')" :data-tip="t('draw_initials')"
> >
<a <a
@ -52,7 +52,7 @@
</a> </a>
</span> </span>
<span <span
class="tooltip" class="md:tooltip"
:data-tip="t('click_to_upload')" :data-tip="t('click_to_upload')"
> >
<label class="btn btn-outline btn-sm font-medium inline-flex flex-nowrap upload-image-button"> <label class="btn btn-outline btn-sm font-medium inline-flex flex-nowrap upload-image-button">

@ -22,7 +22,7 @@
<div class="space-x-2 flex flex-none"> <div class="space-x-2 flex flex-none">
<span <span
v-if="isTextSignature && format !== 'typed_or_upload' && format !== 'typed' && format !== 'upload'" v-if="isTextSignature && format !== 'typed_or_upload' && format !== 'typed' && format !== 'upload'"
class="tooltip" class="md:tooltip"
:data-tip="t('draw_signature')" :data-tip="t('draw_signature')"
> >
<a <a
@ -39,7 +39,7 @@
</span> </span>
<span <span
v-else-if="withTypedSignature && format !== 'drawn_or_upload' && format !== 'typed_or_upload' && format !== 'typed' && format !== 'drawn' && format !== 'upload'" v-else-if="withTypedSignature && format !== 'drawn_or_upload' && format !== 'typed_or_upload' && format !== 'typed' && format !== 'drawn' && format !== 'upload'"
class="tooltip ml-2" class="md:tooltip ml-2"
:class="{ 'hidden sm:inline': modelValue || computedPreviousValue }" :class="{ 'hidden sm:inline': modelValue || computedPreviousValue }"
:data-tip="t('type_text')" :data-tip="t('type_text')"
> >
@ -57,7 +57,7 @@
</span> </span>
<span <span
v-if="format !== 'typed' && format !== 'drawn' && format !== 'upload' && format !== 'drawn_or_typed'" v-if="format !== 'typed' && format !== 'drawn' && format !== 'upload' && format !== 'drawn_or_typed'"
class="tooltip" class="md:tooltip"
:class="{ 'hidden sm:inline': modelValue || computedPreviousValue }" :class="{ 'hidden sm:inline': modelValue || computedPreviousValue }"
:data-tip="t('take_photo')" :data-tip="t('take_photo')"
> >
@ -86,8 +86,8 @@
</a> </a>
<span <span
v-if="withQrButton && !modelValue && !computedPreviousValue && format !== 'typed_or_upload' && format !== 'typed' && format !== 'upload'" v-if="withQrButton && !modelValue && !computedPreviousValue && format !== 'typed_or_upload' && format !== 'typed' && format !== 'upload'"
class="tooltip before:translate-x-[-90%]" class="md:tooltip before:translate-x-[-90%]"
:data-tip="t('drawn_signature_on_a_touchscreen_device')" :data-tip="t('sign_on_the_touchscreen')"
> >
<a <a
href="#" href="#"
@ -142,7 +142,7 @@
/> />
<div <div
v-else v-else
class="relative" class="relative select-none"
> >
<div <div
v-if="!modelValue && !computedPreviousValue && !isShowQr && !isTextSignature && isSignatureStarted" v-if="!modelValue && !computedPreviousValue && !isShowQr && !isTextSignature && isSignatureStarted"
@ -176,7 +176,7 @@
class="top-0 bottom-0 right-0 left-0 absolute bg-base-content/10 rounded-2xl" class="top-0 bottom-0 right-0 left-0 absolute bg-base-content/10 rounded-2xl"
> >
<div <div
class="absolute top-1.5 right-1.5 tooltip" class="absolute top-1.5 right-1.5 md:tooltip"
> >
<a <a
href="#" href="#"
@ -281,7 +281,7 @@
<div <div
v-else-if="withDisclosure" v-else-if="withDisclosure"
dir="auto" dir="auto"
class="text-base-content/60 text-xs text-center w-full mt-1" class="text-base-content/60 text-xs text-center w-full mt-1 select-none"
> >
{{ t('by_clicking_you_agree_to_the').replace('{button}', buttonText.charAt(0).toUpperCase() + buttonText.slice(1)) }} <a {{ t('by_clicking_you_agree_to_the').replace('{button}', buttonText.charAt(0).toUpperCase() + buttonText.slice(1)) }} <a
href="https://www.docuseal.com/esign-disclosure" href="https://www.docuseal.com/esign-disclosure"

@ -6,7 +6,9 @@ class SendSubmitterVerificationEmailJob
def perform(params = {}) def perform(params = {})
submitter = Submitter.find(params['submitter_id']) submitter = Submitter.find(params['submitter_id'])
SubmitterMailer.otp_verification_email(submitter).deliver_now! locale = params['locale'].presence || submitter.account.locale
SubmitterMailer.otp_verification_email(submitter, locale:).deliver_now!
SubmissionEvent.create!(submitter_id: params['submitter_id'], SubmissionEvent.create!(submitter_id: params['submitter_id'],
event_type: 'send_2fa_email', event_type: 'send_2fa_email',

@ -144,13 +144,13 @@ class SubmitterMailer < ApplicationMailer
end end
end end
def otp_verification_email(submitter) def otp_verification_email(submitter, locale: nil)
@submitter = submitter @submitter = submitter
@otp_code = EmailVerificationCodes.generate([submitter.email.downcase.strip, submitter.slug].join(':')) @otp_code = EmailVerificationCodes.generate([submitter.email.downcase.strip, submitter.slug].join(':'))
assign_message_metadata('otp_verification_email', submitter) assign_message_metadata('otp_verification_email', submitter)
I18n.with_locale(submitter.account.locale) do I18n.with_locale(locale || submitter.account.locale) do
mail(to: submitter.email, subject: I18n.t('email_verification')) mail(to: submitter.email, subject: I18n.t('email_verification'))
end end
end end

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M4 5m0 2a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2z"></path>
<path d="M16 3l0 4"></path>
<path d="M8 3l0 4"></path>
<path d="M4 11l16 0"></path>
<path d="M8 15h2v2h-2z"></path>
</svg>

After

Width:  |  Height:  |  Size: 450 B

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M9 11l3 3l8 -8"></path>
<path d="M20 12v6a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2h9"></path>
</svg>

After

Width:  |  Height:  |  Size: 346 B

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M7 12l5 5l10 -10"></path>
<path d="M2 12l5 5m5 -5l5 -5"></path>
</svg>

After

Width:  |  Height:  |  Size: 303 B

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 3m0 1a1 1 0 0 1 1 -1h16a1 1 0 0 1 1 1v16a1 1 0 0 1 -1 1h-16a1 1 0 0 1 -1 -1zm6 -1v18m6 -18v18"></path>
</svg>

After

Width:  |  Height:  |  Size: 343 B

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 5m0 3a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v8a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3z"></path>
<path d="M3 10l18 0"></path>
<path d="M7 15l.01 0"></path>
<path d="M11 15l2 0"></path>
</svg>

After

Width:  |  Height:  |  Size: 419 B

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 4m0 3a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v10a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3z"></path>
<path d="M9 10m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0"></path>
<path d="M15 8l2 0"></path>
<path d="M15 12l2 0"></path>
<path d="M7 16l10 0"></path>
</svg>

After

Width:  |  Height:  |  Size: 478 B

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 19v-10.5a3.5 3.5 0 0 1 7 0v10.5"></path>
<path d="M3 13h7"></path>
<path d="M14 19v-10.5a3.5 3.5 0 0 1 7 0v10.5"></path>
<path d="M14 13h7"></path>
</svg>

After

Width:  |  Height:  |  Size: 394 B

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M15 8h.01"></path>
<path d="M3 6a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v12a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3v-12z"></path>
<path d="M3 16l5 -5c.928 -.893 2.072 -.893 3 0l5 5"></path>
<path d="M14 14l1 -1c.928 -.893 2.072 -.893 3 0l3 3"></path>
</svg>

After

Width:  |  Height:  |  Size: 481 B

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 17.85h-18c0 -4.05 1.421 -4.05 3.79 -4.05c5.21 0 1.21 -4.59 1.21 -6.8a4 4 0 1 1 8 0c0 2.21 -4 6.8 1.21 6.8c2.369 0 3.79 0 3.79 4.05z"></path>
<path d="M5 21h14"></path>
</svg>

After

Width:  |  Height:  |  Size: 411 B

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 3m0 2a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v14a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2z"></path>
<path d="M9 11l3 3l3 -3"></path>
</svg>

After

Width:  |  Height:  |  Size: 361 B

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="44" height="44" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 3m0 2a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v14a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2z"></path>
<path d="M10 10l2 -2v8"></path>
</svg>

After

Width:  |  Height:  |  Size: 360 B

@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" class="<%= local_assigns[:class] %>" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 7v-2h13v2"></path>
<path d="M10 5v14"></path>
<path d="M12 19h-4"></path>
<path d="M15 13v-1h6v1"></path>
<path d="M18 12v7"></path>
<path d="M17 19h2"></path>
</svg>

After

Width:  |  Height:  |  Size: 410 B

@ -1,6 +1,6 @@
<a target="_blank" href="<%= Docuseal::GITHUB_URL %>" rel="noopener noreferrer nofollow" class="relative flex items-center rounded-full px-2 py-0.5 text-xs leading-4 mt-1 text-base-content border border-base-300 tooltip tooltip-bottom" data-tip="Give a star on GitHub"> <a target="_blank" href="<%= Docuseal::GITHUB_URL %>" rel="noopener noreferrer nofollow" class="relative flex items-center rounded-full px-2 py-0.5 text-xs leading-4 mt-1 text-base-content border border-base-300 tooltip tooltip-bottom" data-tip="Give a star on GitHub">
<span class="flex items-center justify-between space-x-0.5 font-medium"> <span class="flex items-center justify-between space-x-0.5 font-medium">
<%= svg_icon('start', class: 'h-3 w-3') %> <%= svg_icon('start', class: 'h-3 w-3') %>
<span>10k</span> <span>11k</span>
</span> </span>
</a> </a>

@ -50,12 +50,13 @@
<%= svg_icon('check', class: "aspect-square #{area['w'] > area['h'] ? '!w-auto !h-full' : '!w-full !h-auto'}") %> <%= svg_icon('check', class: "aspect-square #{area['w'] > area['h'] ? '!w-auto !h-full' : '!w-full !h-auto'}") %>
</div> </div>
<% elsif field['type'].in?(%w[multiple radio]) && area['option_uuid'] %> <% elsif field['type'].in?(%w[multiple radio]) && area['option_uuid'] %>
<% option = field['options']&.find { |o| o['uuid'] == area['option_uuid'] } %> <% if (option = field['options']&.find { |o| o['uuid'] == area['option_uuid'] }) %>
<% option_name = option['value'].presence || "Option #{field['options'].index(option) + 1}" %> <% option_name = option['value'].presence || "Option #{field['options'].index(option) + 1}" %>
<% if option && Array.wrap(value).include?(option_name) %> <% if Array.wrap(value).include?(option_name) %>
<div class="w-full flex items-center justify-center"> <div class="w-full flex items-center justify-center">
<%= svg_icon('check', class: "aspect-square #{area['w'] > area['h'] ? '!w-auto !h-full' : '!w-full !h-auto'}") %> <%= svg_icon('check', class: "aspect-square #{area['w'] > area['h'] ? '!w-auto !h-full' : '!w-full !h-auto'}") %>
</div> </div>
<% end %>
<% end %> <% end %>
<% elsif field['type'] == 'cells' && area['cell_w'].to_f > 0.0 %> <% elsif field['type'] == 'cells' && area['cell_w'].to_f > 0.0 %>
<% cell_width = area['cell_w'] / area['w'] * 100 %> <% cell_width = area['cell_w'] / area['w'] * 100 %>

@ -4,7 +4,7 @@
<% font_scale = 1040.0 / PdfUtils::US_LETTER_W %> <% font_scale = 1040.0 / PdfUtils::US_LETTER_W %>
<% configs = AccountConfig.where(account_id: @submission.account_id, key: [AccountConfig::COMBINE_PDF_RESULT_KEY, AccountConfig::WITH_SIGNATURE_ID, AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY, AccountConfig::WITH_SIGNATURE_ID_REASON_KEY]) %> <% configs = AccountConfig.where(account_id: @submission.account_id, key: [AccountConfig::COMBINE_PDF_RESULT_KEY, AccountConfig::WITH_SIGNATURE_ID, AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY, AccountConfig::WITH_SIGNATURE_ID_REASON_KEY]) %>
<% with_signature_id = configs.find { |e| e.key == AccountConfig::WITH_SIGNATURE_ID }&.value == true %> <% with_signature_id = configs.find { |e| e.key == AccountConfig::WITH_SIGNATURE_ID }&.value == true %>
<% is_combined_enabled = configs.find { |e| e.key == AccountConfig::COMBINE_PDF_RESULT_KEY }&.value == true %> <% is_combined_enabled = configs.find { |e| e.key == AccountConfig::COMBINE_PDF_RESULT_KEY }&.value == true && !@submission.template_fields&.any? { |f| f['type'] == 'verification' } %>
<% with_submitter_timezone = configs.find { |e| e.key == AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY }&.value == true %> <% with_submitter_timezone = configs.find { |e| e.key == AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY }&.value == true %>
<% with_signature_id_reason = configs.find { |e| e.key == AccountConfig::WITH_SIGNATURE_ID_REASON_KEY }&.value != false %> <% with_signature_id_reason = configs.find { |e| e.key == AccountConfig::WITH_SIGNATURE_ID_REASON_KEY }&.value != false %>
<div style="max-width: 1600px" class="mx-auto pl-4"> <div style="max-width: 1600px" class="mx-auto pl-4">
@ -93,8 +93,10 @@
<div class="pr-3.5 pl-0.5"> <div class="pr-3.5 pl-0.5">
<% fields_index = Templates.build_field_areas_index(@submission.template_fields || @submission.template.fields) %> <% fields_index = Templates.build_field_areas_index(@submission.template_fields || @submission.template.fields) %>
<% submitters_index = @submission.submitters.index_by(&:uuid) %> <% submitters_index = @submission.submitters.index_by(&:uuid) %>
<% submitters_order_index = nil %>
<% attachments_index = ActiveStorage::Attachment.where(record: @submission.submitters, name: :attachments).preload(:blob).index_by(&:uuid) %> <% attachments_index = ActiveStorage::Attachment.where(record: @submission.submitters, name: :attachments).preload(:blob).index_by(&:uuid) %>
<% page_blob_struct = Struct.new(:url, :metadata, keyword_init: true) %> <% page_blob_struct = Struct.new(:url, :metadata, keyword_init: true) %>
<% bg_classes = %w[bg-red-100 bg-sky-100 bg-emerald-100 bg-yellow-100 bg-purple-100 bg-pink-100 bg-cyan-100 bg-orange-100 bg-lime-100 bg-indigo-100] %>
<% schema.each do |item| %> <% schema.each do |item| %>
<% document = @submission.schema_documents.find { |e| e.uuid == item['attachment_uuid'] } %> <% document = @submission.schema_documents.find { |e| e.uuid == item['attachment_uuid'] } %>
<% document_annots_index = document.metadata.dig('pdf', 'annotations')&.group_by { |e| e['page'] } || {} %> <% document_annots_index = document.metadata.dig('pdf', 'annotations')&.group_by { |e| e['page'] } || {} %>
@ -111,19 +113,29 @@
<% fields_index.dig(document.uuid, index)&.each do |(area, field)| %> <% fields_index.dig(document.uuid, index)&.each do |(area, field)| %>
<% value = values[field['uuid']].presence || (field['default_value'] != '{{date}}' && field['readonly'] == true && field['conditions'].blank? && field['default_value'].present? ? Submitters::SubmitValues.template_default_value_for_submitter(field['default_value'], @submission.submitters.find { |e| e.uuid == field['submitter_uuid'] }, with_time: false) : nil) %> <% value = values[field['uuid']].presence || (field['default_value'] != '{{date}}' && field['readonly'] == true && field['conditions'].blank? && field['default_value'].present? ? Submitters::SubmitValues.template_default_value_for_submitter(field['default_value'], @submission.submitters.find { |e| e.uuid == field['submitter_uuid'] }, with_time: false) : nil) %>
<% value ||= field['default_value'] if field['type'] == 'heading' %> <% value ||= field['default_value'] if field['type'] == 'heading' %>
<% next if value.blank? %>
<% submitter = submitters_index[field['submitter_uuid']] %> <% submitter = submitters_index[field['submitter_uuid']] %>
<% if (mask = field.dig('preferences', 'mask').presence) && signed_in? && can?(:read, @submission) %> <% if value.present? %>
<span class="group"> <% if (mask = field.dig('preferences', 'mask').presence) && signed_in? && can?(:read, @submission) %>
<span class="hidden group-hover:inline"> <span class="group">
<%= render 'submissions/value', font_scale:, area:, field:, attachments_index:, value:, locale: @submission.account.locale, timezone: @submission.account.timezone, submitter:, with_signature_id: %> <span class="hidden group-hover:inline">
</span> <%= render 'submissions/value', font_scale:, area:, field:, attachments_index:, value:, locale: @submission.account.locale, timezone: @submission.account.timezone, submitter:, with_signature_id: %>
<span class="group-hover:hidden"> </span>
<%= render 'submissions/value', font_scale:, area:, field:, attachments_index:, value: Array.wrap(value).map { |e| TextUtils.mask_value(e, mask) }.join(', '), locale: @submission.account.locale, timezone: @submission.account.timezone, submitter:, with_signature_id: %> <span class="group-hover:hidden">
<%= render 'submissions/value', font_scale:, area:, field:, attachments_index:, value: Array.wrap(value).map { |e| TextUtils.mask_value(e, mask) }.join(', '), locale: @submission.account.locale, timezone: @submission.account.timezone, submitter:, with_signature_id: %>
</span>
</span> </span>
</span> <% else %>
<% else %> <%= render 'submissions/value', page_width: width, page_height: height, font_scale:, area:, field:, attachments_index:, value: mask.present? ? Array.wrap(value).map { |e| TextUtils.mask_value(e, mask) }.join(', ') : value, locale: @submission.account.locale, timezone: @submission.account.timezone, submitter:, with_signature_id:, with_submitter_timezone:, with_signature_id_reason: %>
<%= render 'submissions/value', page_width: width, page_height: height, font_scale:, area:, field:, attachments_index:, value: mask.present? ? Array.wrap(value).map { |e| TextUtils.mask_value(e, mask) }.join(', ') : value, locale: @submission.account.locale, timezone: @submission.account.timezone, submitter:, with_signature_id:, with_submitter_timezone:, with_signature_id_reason: %> <% end %>
<% elsif field['readonly'] != true && submitter && !submitter.completed_at? %>
<% submitters_order_index ||= (@submission.template_submitters || @submission.template.submitters).each_with_index.to_h { |s, i| [s['uuid'], i] } %>
<% submitter_index = submitters_order_index[submitter.uuid] %>
<% bg_class = bg_classes[submitter_index % bg_classes.size] %>
<div class="absolute overflow-visible" style="width: <%= area['w'] * 100 %>%; height: <%= area['h'] * 100 %>%; left: <%= area['x'] * 100 %>%; top: <%= area['y'] * 100 %>%;">
<div class="flex h-full w-full bg-opacity-80 justify-center items-center <%= bg_class %>">
<%= svg_icon(SubmissionsController::FIELD_ICONS[field['type']], class: 'max-h-10 w-full h-full stroke-2 opacity-50') %>
</div>
</div>
<% end %> <% end %>
<% end %> <% end %>
</div> </div>

@ -1,7 +1,7 @@
{ {
"ignored_warnings": [ "ignored_warnings": [
{ {
"fingerprint": "bbd1bdad94998e53a48921859065e06cd1595502d4dc40362afcaa90307b591a", "fingerprint": "de39648cd3f79d51e95e45f05fc77da49b0ad68bf80458061151016c0ef78208",
"note": "Permitted parameters are necessary for creating submitters via API" "note": "Permitted parameters are necessary for creating submitters via API"
}, },
{ {

@ -876,6 +876,7 @@ en: &en
you_requested_to_reset_your_password_use_the_link_below_to_continue: You requested to reset your password. Use the link below to continue you_requested_to_reset_your_password_use_the_link_below_to_continue: You requested to reset your password. Use the link below to continue
if_you_didnt_request_this_you_can_ignore_this_email: "If you didn't request this, please ignore this email." if_you_didnt_request_this_you_can_ignore_this_email: "If you didn't request this, please ignore this email."
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Your password won't change until you open the link above and set a new one." your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Your password won't change until you open the link above and set a new one."
too_many_requests_try_again_later: Too many requests, try again later.
devise: devise:
confirmations: confirmations:
confirmed: Your email address has been successfully confirmed. confirmed: Your email address has been successfully confirmed.
@ -1847,6 +1848,7 @@ es: &es
you_requested_to_reset_your_password_use_the_link_below_to_continue: Solicitaste restablecer tu contraseña. Usa el enlace a continuación para continuar. you_requested_to_reset_your_password_use_the_link_below_to_continue: Solicitaste restablecer tu contraseña. Usa el enlace a continuación para continuar.
if_you_didnt_request_this_you_can_ignore_this_email: "Si no solicitaste esto, puedes ignorar este correo electrónico." if_you_didnt_request_this_you_can_ignore_this_email: "Si no solicitaste esto, puedes ignorar este correo electrónico."
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Tu contraseña no cambiará hasta que abras el enlace anterior y establezcas una nueva." your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Tu contraseña no cambiará hasta que abras el enlace anterior y establezcas una nueva."
too_many_requests_try_again_later: Demasiadas solicitudes. Intenta de nuevo más tarde.
devise: devise:
confirmations: confirmations:
confirmed: Tu dirección de correo electrónico ha sido confirmada correctamente. confirmed: Tu dirección de correo electrónico ha sido confirmada correctamente.
@ -2819,6 +2821,7 @@ it: &it
you_requested_to_reset_your_password_use_the_link_below_to_continue: Hai richiesto di reimpostare la tua password. Usa il link qui sotto per continuare. you_requested_to_reset_your_password_use_the_link_below_to_continue: Hai richiesto di reimpostare la tua password. Usa il link qui sotto per continuare.
if_you_didnt_request_this_you_can_ignore_this_email: "Se non hai richiesto questo, puoi ignorare questa email." if_you_didnt_request_this_you_can_ignore_this_email: "Se non hai richiesto questo, puoi ignorare questa email."
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "La tua password non cambierà finché non apri il link sopra e ne imposti una nuova." your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "La tua password non cambierà finché non apri il link sopra e ne imposti una nuova."
too_many_requests_try_again_later: Troppe richieste. Riprova più tardi.
devise: devise:
confirmations: confirmations:
confirmed: Il tuo indirizzo email è stato confermato con successo. confirmed: Il tuo indirizzo email è stato confermato con successo.
@ -3787,6 +3790,7 @@ fr: &fr
you_requested_to_reset_your_password_use_the_link_below_to_continue: Vous avez demandé à réinitialiser votre mot de passe. Utilisez le lien ci-dessous pour continuer. you_requested_to_reset_your_password_use_the_link_below_to_continue: Vous avez demandé à réinitialiser votre mot de passe. Utilisez le lien ci-dessous pour continuer.
if_you_didnt_request_this_you_can_ignore_this_email: "Si vous n'avez pas fait cette demande, veuillez ignorer cet e-mail." if_you_didnt_request_this_you_can_ignore_this_email: "Si vous n'avez pas fait cette demande, veuillez ignorer cet e-mail."
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Votre mot de passe ne changera pas tant que vous naurez pas ouvert le lien ci-dessus et défini un nouveau mot de passe." your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Votre mot de passe ne changera pas tant que vous naurez pas ouvert le lien ci-dessus et défini un nouveau mot de passe."
too_many_requests_try_again_later: Trop de demandes. Réessayez plus tard.
devise: devise:
confirmations: confirmations:
confirmed: Votre adresse e-mail a été confirmée avec succès. confirmed: Votre adresse e-mail a été confirmée avec succès.
@ -4758,6 +4762,7 @@ pt: &pt
you_requested_to_reset_your_password_use_the_link_below_to_continue: Você solicitou a redefinição da sua senha. Use o link abaixo para continuar. you_requested_to_reset_your_password_use_the_link_below_to_continue: Você solicitou a redefinição da sua senha. Use o link abaixo para continuar.
if_you_didnt_request_this_you_can_ignore_this_email: "Se você não solicitou isso, pode ignorar este e-mail." if_you_didnt_request_this_you_can_ignore_this_email: "Se você não solicitou isso, pode ignorar este e-mail."
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Sua senha não será alterada até que você abra o link acima e defina uma nova." your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Sua senha não será alterada até que você abra o link acima e defina uma nova."
too_many_requests_try_again_later: Muitas solicitações. Tente novamente mais tarde.
devise: devise:
confirmations: confirmations:
confirmed: Seu endereço de e-mail foi confirmado com sucesso. confirmed: Seu endereço de e-mail foi confirmado com sucesso.
@ -5729,6 +5734,7 @@ de: &de
you_requested_to_reset_your_password_use_the_link_below_to_continue: Sie haben angefordert, Ihr Passwort zurückzusetzen. Verwenden Sie den untenstehenden Link, um fortzufahren. you_requested_to_reset_your_password_use_the_link_below_to_continue: Sie haben angefordert, Ihr Passwort zurückzusetzen. Verwenden Sie den untenstehenden Link, um fortzufahren.
if_you_didnt_request_this_you_can_ignore_this_email: "Wenn Sie dies nicht angefordert haben, können Sie diese E-Mail ignorieren." if_you_didnt_request_this_you_can_ignore_this_email: "Wenn Sie dies nicht angefordert haben, können Sie diese E-Mail ignorieren."
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Ihr Passwort wird erst geändert, wenn Sie den obigen Link öffnen und ein neues festlegen." your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Ihr Passwort wird erst geändert, wenn Sie den obigen Link öffnen und ein neues festlegen."
too_many_requests_try_again_later: Zu viele Anfragen. Versuchen Sie es später erneut.
devise: devise:
confirmations: confirmations:
confirmed: Ihre E-Mail-Adresse wurde erfolgreich bestätigt. confirmed: Ihre E-Mail-Adresse wurde erfolgreich bestätigt.
@ -5938,6 +5944,7 @@ pl:
the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: Nadawca zażądał uwierzytelniania dwuskładnikowego za pośrednictwem hasła jednorazowego wysłanego na Twój adres e-mail <b>%{email}</b>. the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: Nadawca zażądał uwierzytelniania dwuskładnikowego za pośrednictwem hasła jednorazowego wysłanego na Twój adres e-mail <b>%{email}</b>.
please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: Skontaktuj się z nadawcą, aby podać swój adres e-mail do uwierzytelniania dwuskładnikowego. please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: Skontaktuj się z nadawcą, aby podać swój adres e-mail do uwierzytelniania dwuskładnikowego.
rate_limit_exceeded: Przekroczono limit rate_limit_exceeded: Przekroczono limit
too_many_requests_try_again_later: Zbyt wiele żądań. Spróbuj ponownie później.
uk: uk:
require_phone_2fa_to_open: Вимагати двофакторну автентифікацію через телефон для відкриття require_phone_2fa_to_open: Вимагати двофакторну автентифікацію через телефон для відкриття
@ -6034,6 +6041,7 @@ uk:
the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: Відправник запросив двофакторну автентифікацію за допомогою одноразового пароля, відправленого на вашу електронну пошту <b>%{email}</b>. the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: Відправник запросив двофакторну автентифікацію за допомогою одноразового пароля, відправленого на вашу електронну пошту <b>%{email}</b>.
please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: Будь ласка, зв'яжіться з відправником, щоб вказати вашу електронну пошту для двофакторної автентифікації. please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: Будь ласка, зв'яжіться з відправником, щоб вказати вашу електронну пошту для двофакторної автентифікації.
rate_limit_exceeded: Перевищено ліміт rate_limit_exceeded: Перевищено ліміт
too_many_requests_try_again_later: Забагато запитів. Спробуйте пізніше.
cs: cs:
require_phone_2fa_to_open: Vyžadovat otevření pomocí telefonního 2FA require_phone_2fa_to_open: Vyžadovat otevření pomocí telefonního 2FA
@ -6130,6 +6138,7 @@ cs:
the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: Odesílatel požádal o dvoufaktorové ověření pomocí jednorázového hesla odeslaného na vaši e-mailovou adresu <b>%{email}</b>. the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: Odesílatel požádal o dvoufaktorové ověření pomocí jednorázového hesla odeslaného na vaši e-mailovou adresu <b>%{email}</b>.
please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: Prosím kontaktujte odesílatele a uveďte svůj e-mail pro dvoufaktorové ověření. please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: Prosím kontaktujte odesílatele a uveďte svůj e-mail pro dvoufaktorové ověření.
rate_limit_exceeded: Překročena hranice rate_limit_exceeded: Překročena hranice
too_many_requests_try_again_later: Příliš mnoho požadavků. Zkuste to později.
he: he:
require_phone_2fa_to_open: דרוש אימות דו-שלבי באמצעות טלפון לפתיחה require_phone_2fa_to_open: דרוש אימות דו-שלבי באמצעות טלפון לפתיחה
@ -6226,6 +6235,7 @@ he:
the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: השולח ביקש אימות דו-שלבי באמצעות סיסמה חד-פעמית שנשלחה לכתובת הדוא"ל שלך <b>%{email}</b>. the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: השולח ביקש אימות דו-שלבי באמצעות סיסמה חד-פעמית שנשלחה לכתובת הדוא"ל שלך <b>%{email}</b>.
please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: אנא פנה לשולח וציין את כתובת הדוא"ל שלך לאימות דו-שלבי. please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: אנא פנה לשולח וציין את כתובת הדוא"ל שלך לאימות דו-שלבי.
rate_limit_exceeded: חריגה ממגבלת rate_limit_exceeded: חריגה ממגבלת
too_many_requests_try_again_later: יותר מדי בקשות. נסה שוב מאוחר יותר.
nl: &nl nl: &nl
templates_that_require_email_or_phone_2fa_cannot_be_used_via_a_shared_link: Sjablonen waarvoor e-mail- of telefoon-2FA vereist is, kunnen niet via een gedeelde link worden gebruikt. templates_that_require_email_or_phone_2fa_cannot_be_used_via_a_shared_link: Sjablonen waarvoor e-mail- of telefoon-2FA vereist is, kunnen niet via een gedeelde link worden gebruikt.
@ -7081,6 +7091,7 @@ nl: &nl
you_requested_to_reset_your_password_use_the_link_below_to_continue: Je hebt gevraagd je wachtwoord te resetten. Gebruik de onderstaande link om verder te gaan. you_requested_to_reset_your_password_use_the_link_below_to_continue: Je hebt gevraagd je wachtwoord te resetten. Gebruik de onderstaande link om verder te gaan.
if_you_didnt_request_this_you_can_ignore_this_email: "Als je dit niet hebt aangevraagd, kun je deze e-mail negeren." if_you_didnt_request_this_you_can_ignore_this_email: "Als je dit niet hebt aangevraagd, kun je deze e-mail negeren."
your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Je wachtwoord wordt niet gewijzigd totdat je de bovenstaande link opent en een nieuw wachtwoord instelt." your_password_wont_change_until_you_open_the_link_above_and_set_a_new_one: "Je wachtwoord wordt niet gewijzigd totdat je de bovenstaande link opent en een nieuw wachtwoord instelt."
too_many_requests_try_again_later: Te veel verzoeken. Probeer het later opnieuw.
devise: devise:
confirmations: confirmations:
confirmed: Je e-mailadres is succesvol bevestigd. confirmed: Je e-mailadres is succesvol bevestigd.
@ -7290,6 +7301,7 @@ ar:
the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: طلب المرسل المصادقة الثنائية عبر كلمة مرور لمرة واحدة مرسلة إلى عنوان بريدك الإلكتروني <b>%{email}</b>. the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: طلب المرسل المصادقة الثنائية عبر كلمة مرور لمرة واحدة مرسلة إلى عنوان بريدك الإلكتروني <b>%{email}</b>.
please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: يرجى الاتصال بالمرسل لتحديد عنوان بريدك الإلكتروني للمصادقة الثنائية. please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: يرجى الاتصال بالمرسل لتحديد عنوان بريدك الإلكتروني للمصادقة الثنائية.
rate_limit_exceeded: تم تجاوز الحد المسموح به rate_limit_exceeded: تم تجاوز الحد المسموح به
too_many_requests_try_again_later: طلبات كثيرة جدًا. حاول مرة أخرى لاحقًا.
ko: ko:
require_phone_2fa_to_open: 휴대폰 2FA를 열 때 요구함 require_phone_2fa_to_open: 휴대폰 2FA를 열 때 요구함
@ -7386,6 +7398,7 @@ ko:
the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: 발신자가 <b>%{email}</b> 이메일 주소로 전송된 일회용 비밀번호를 통해 2단계 인증을 요청했습니다. the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: 발신자가 <b>%{email}</b> 이메일 주소로 전송된 일회용 비밀번호를 통해 2단계 인증을 요청했습니다.
please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: 2단계 인증을 위해 이메일 주소를 지정하려면 발신자에게 문의하세요. please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: 2단계 인증을 위해 이메일 주소를 지정하려면 발신자에게 문의하세요.
rate_limit_exceeded: 속도 제한 초과 rate_limit_exceeded: 속도 제한 초과
too_many_requests_try_again_later: 요청이 너무 많습니다. 나중에 다시 시도하세요.
ja: ja:
require_phone_2fa_to_open: 電話による2段階認証が必要です require_phone_2fa_to_open: 電話による2段階認証が必要です
@ -7482,6 +7495,7 @@ ja:
the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: 送信者は、<b>%{email}</b> メールアドレスに送信されたワンタイムパスワードによる2段階認証を要求しました。 the_sender_has_requested_a_two_factor_authentication_via_one_time_password_sent_to_your_email_html: 送信者は、<b>%{email}</b> メールアドレスに送信されたワンタイムパスワードによる2段階認証を要求しました。
please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: 2段階認証用にメールアドレスを指定するために、送信者にお問い合わせください。 please_contact_the_requester_to_specify_your_email_for_two_factor_authentication: 2段階認証用にメールアドレスを指定するために、送信者にお問い合わせください。
rate_limit_exceeded: レート制限を超えました rate_limit_exceeded: レート制限を超えました
too_many_requests_try_again_later: リクエストが多すぎます。後でもう一度お試しください。
en-US: en-US:
<<: *en <<: *en

@ -9,6 +9,8 @@ class AddIsFirstToCompletedSubmitters < ActiveRecord::Migration[8.0]
add_index :completed_submitters, %i[account_id completed_at], add_index :completed_submitters, %i[account_id completed_at],
where: 'is_first = TRUE', where: 'is_first = TRUE',
name: 'index_completed_submitters_account_id_completed_at_is_first' name: 'index_completed_submitters_account_id_completed_at_is_first'
add_index :completed_submitters, :submission_id, unique: true, where: 'is_first = TRUE'
add_index :completed_submitters, :submission_id, unique: adapter_name != 'Mysql2',
where: 'is_first = TRUE'
end end
end end

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -151,7 +151,8 @@ const token = jwt.sign({
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"drawFieldType": { "drawFieldType": {
@ -194,7 +195,8 @@ const token = jwt.sign({
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"role": { "role": {
@ -321,7 +323,8 @@ const token = jwt.sign({
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"role": { "role": {
@ -444,6 +447,12 @@ const token = jwt.sign({
"default": true, "default": true,
"description": "Set `false` to now show the fields list on the right. Fields list is displayed by default." "description": "Set `false` to now show the fields list on the right. Fields list is displayed by default."
}, },
"withFieldsDetection": {
"type": "boolean",
"required": false,
"default": false,
"description": "Display a button to automatically detect and add fields to the document with AI."
},
"withFieldPlaceholder": { "withFieldPlaceholder": {
"type": "boolean", "type": "boolean",
"required": false, "required": false,
@ -483,7 +492,7 @@ const token = jwt.sign({
"type": "string", "type": "string",
"required": false, "required": false,
"default": "en", "default": "en",
"description": "UI language, 'en', 'es', 'de', 'fr', 'pt', 'he', 'ar' languages are available." "description": "UI language, 'en', 'es', 'de', 'fr', 'pt', 'nl', 'he', 'ar' languages are available."
}, },
"i18n": { "i18n": {
"type": "object", "type": "object",

@ -118,7 +118,8 @@
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"role": { "role": {
@ -249,7 +250,8 @@
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"role": { "role": {
@ -336,7 +338,8 @@
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"data-draw-field-type": { "data-draw-field-type": {
@ -408,6 +411,12 @@
"default": true, "default": true,
"description": "Set `false` to now show the fields list on the right. Fields list is displayed by default." "description": "Set `false` to now show the fields list on the right. Fields list is displayed by default."
}, },
"data-with-fields-detection": {
"type": "boolean",
"required": false,
"default": false,
"description": "Display a button to automatically detect and add fields to the document with AI."
},
"data-with-field-placeholder": { "data-with-field-placeholder": {
"type": "boolean", "type": "boolean",
"required": false, "required": false,
@ -453,7 +462,7 @@
"type": "string", "type": "string",
"required": false, "required": false,
"default": "en", "default": "en",
"description": "UI language, 'en', 'es', 'de', 'fr', 'pt', 'he', 'ar' languages are available." "description": "UI language, 'en', 'es', 'de', 'fr', 'pt', 'nl', 'he', 'ar' languages are available."
}, },
"data-background-color": { "data-background-color": {
"type": "string", "type": "string",

@ -142,7 +142,8 @@ const token = jwt.sign({
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"drawFieldType": { "drawFieldType": {
@ -185,7 +186,8 @@ const token = jwt.sign({
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"role": { "role": {
@ -312,7 +314,8 @@ const token = jwt.sign({
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"role": { "role": {
@ -435,6 +438,12 @@ const token = jwt.sign({
"default": true, "default": true,
"description": "Set `false` to now show the fields list on the right. Fields list is displayed by default." "description": "Set `false` to now show the fields list on the right. Fields list is displayed by default."
}, },
"withFieldsDetection": {
"type": "boolean",
"required": false,
"default": false,
"description": "Display a button to automatically detect and add fields to the document with AI."
},
"withFieldPlaceholder": { "withFieldPlaceholder": {
"type": "boolean", "type": "boolean",
"required": false, "required": false,
@ -474,7 +483,7 @@ const token = jwt.sign({
"type": "string", "type": "string",
"required": false, "required": false,
"default": "en", "default": "en",
"description": "UI language, 'en', 'es', 'de', 'fr', 'pt', 'he', 'ar' languages are available." "description": "UI language, 'en', 'es', 'de', 'fr', 'pt', 'nl', 'he', 'ar' languages are available."
}, },
"i18n": { "i18n": {
"type": "object", "type": "object",

@ -163,7 +163,8 @@ const token = jwt.sign({
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"draw-field-type": { "draw-field-type": {
@ -206,7 +207,8 @@ const token = jwt.sign({
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"role": { "role": {
@ -333,7 +335,8 @@ const token = jwt.sign({
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"role": { "role": {
@ -450,6 +453,12 @@ const token = jwt.sign({
"default": true, "default": true,
"description": "Set `false` to now show the fields list on the right. Fields list is displayed by default." "description": "Set `false` to now show the fields list on the right. Fields list is displayed by default."
}, },
"with-fields-detection": {
"type": "boolean",
"required": false,
"default": false,
"description": "Display a button to automatically detect and add fields to the document with AI."
},
"with-field-placeholder": { "with-field-placeholder": {
"type": "boolean", "type": "boolean",
"required": false, "required": false,
@ -483,7 +492,7 @@ const token = jwt.sign({
"type": "string", "type": "string",
"required": false, "required": false,
"default": "en", "default": "en",
"description": "UI language, 'en', 'es', 'de', 'fr', 'pt', 'he', 'ar' languages are available." "description": "UI language, 'en', 'es', 'de', 'fr', 'pt', 'nl', 'he', 'ar' languages are available."
}, },
"i18n": { "i18n": {
"type": "object", "type": "object",

@ -30,7 +30,7 @@ export class AppComponent {}
"src": { "src": {
"type": "string", "type": "string",
"required": true, "required": true,
"description": "Public URL of the document signing form. There are two types of URLs: <li><code>/d/{slug}</code> - template form signing URL can be copied from the template page in the admin dashboard. Also template \"slug\" key can be obtained via the <code>/templates</code> API.</li><li><code>/s/{slug}</code> - individual signer URL. Signer \"slug\" key can be obtained via the <code>/submissions</code> API which is used to initiate signature requests for a template form with recipients.</li>" "description": "Public URL of the document signing form. There are two types of URLs: <ul class=\"list-inside list-disc\"><li><code>/d/{slug}</code> - template form signing URL can be copied from the template page in the admin dashboard. Also template \"slug\" key can be obtained via the <code>/templates</code> API.</li><li><code>/s/{slug}</code> - individual signer URL. Signer \"slug\" key can be obtained via the <code>/submissions</code> API which is used to initiate signature requests for a template form with recipients.</li></ul>"
}, },
"email": { "email": {
"type": "string", "type": "string",

@ -26,7 +26,7 @@
"data-src": { "data-src": {
"type": "string", "type": "string",
"required": true, "required": true,
"description": "Public URL of the document signing form. There are two types of URLs: <li><code>/d/{slug}</code> - template form signing URL can be copied from the template page in the admin dashboard. Also template \"slug\" key can be obtained via the <code>/templates</code> API.</li><li><code>/s/{slug}</code> - individual signer URL. Signer \"slug\" key can be obtained via the <code>/submissions</code> API which is used to initiate signature requests for a template form with recipients.</li>" "description": "Public URL of the document signing form. There are two types of URLs: <ul class=\"list-inside list-disc\"><li><code>/d/{slug}</code> - template form signing URL can be copied from the template page in the admin dashboard. Also template \"slug\" key can be obtained via the <code>/templates</code> API.</li><li><code>/s/{slug}</code> - individual signer URL. Signer \"slug\" key can be obtained via the <code>/submissions</code> API which is used to initiate signature requests for a template form with recipients.</li></ul>"
}, },
"data-email": { "data-email": {
"type": "string", "type": "string",

@ -27,7 +27,7 @@ export function App() {
"src": { "src": {
"type": "string", "type": "string",
"required": true, "required": true,
"description": "Public URL of the document signing form. There are two types of URLs: <li><code>/d/{slug}</code> - template form signing URL can be copied from the template page in the admin dashboard. Also template \"slug\" key can be obtained via the <code>/templates</code> API.</li><li><code>/s/{slug}</code> - individual signer URL. Signer \"slug\" key can be obtained via the <code>/submissions</code> API which is used to initiate signature requests for a template form with recipients.</li>" "description": "Public URL of the document signing form. There are two types of URLs: <ul class=\"list-inside list-disc\"><li><code>/d/{slug}</code> - template form signing URL can be copied from the template page in the admin dashboard. Also template \"slug\" key can be obtained via the <code>/templates</code> API.</li><li><code>/s/{slug}</code> - individual signer URL. Signer \"slug\" key can be obtained via the <code>/submissions</code> API which is used to initiate signature requests for a template form with recipients.</li></ul>"
}, },
"email": { "email": {
"type": "string", "type": "string",

@ -36,7 +36,7 @@ export default {
"src": { "src": {
"type": "string", "type": "string",
"required": true, "required": true,
"description": "Public URL of the document signing form. There are two types of URLs: <li><code>/d/{slug}</code> - template form signing URL can be copied from the template page in the admin dashboard. Also template \"slug\" key can be obtained via the <code>/templates</code> API.</li><li><code>/s/{slug}</code> - individual signer URL. Signer \"slug\" key can be obtained via the <code>/submissions</code> API which is used to initiate signature requests for a template form with recipients.</li>" "description": "Public URL of the document signing form. There are two types of URLs: <ul class=\"list-inside list-disc\"><li><code>/d/{slug}</code> - template form signing URL can be copied from the template page in the admin dashboard. Also template \"slug\" key can be obtained via the <code>/templates</code> API.</li><li><code>/s/{slug}</code> - individual signer URL. Signer \"slug\" key can be obtained via the <code>/submissions</code> API which is used to initiate signature requests for a template form with recipients.</li></ul>"
}, },
"email": { "email": {
"type": "string", "type": "string",

@ -251,7 +251,8 @@
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"required": { "required": {
@ -277,6 +278,10 @@
"type": "string", "type": "string",
"description": "Font color of the field value." "description": "Font color of the field value."
}, },
"background": {
"type": "string",
"description": "Field box background color."
},
"align": { "align": {
"type": "string", "type": "string",
"description": "Horizontal alignment of the field text value." "description": "Horizontal alignment of the field text value."
@ -300,6 +305,13 @@
"mask": { "mask": {
"type": "boolean", "type": "boolean",
"description": "Indicates if the field is masked on the document." "description": "Indicates if the field is masked on the document."
},
"reasons": {
"description": "An array of signature reasons to choose from.",
"type": "array",
"items": {
"type": "string"
}
} }
} }
}, },
@ -714,7 +726,8 @@
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"required": { "required": {
@ -740,6 +753,10 @@
"type": "string", "type": "string",
"description": "Font color of the field value." "description": "Font color of the field value."
}, },
"background": {
"type": "string",
"description": "Field box background color."
},
"align": { "align": {
"type": "string", "type": "string",
"description": "Horizontal alignment of the field text value." "description": "Horizontal alignment of the field text value."
@ -763,6 +780,13 @@
"mask": { "mask": {
"type": "boolean", "type": "boolean",
"description": "Indicates if the field is masked on the document." "description": "Indicates if the field is masked on the document."
},
"reasons": {
"description": "An array of signature reasons to choose from.",
"type": "array",
"items": {
"type": "string"
}
} }
} }
}, },
@ -1782,6 +1806,11 @@
"description": "Set to `true` to require phone 2FA verification via a one-time code sent to the phone number in order to access the documents.", "description": "Set to `true` to require phone 2FA verification via a one-time code sent to the phone number in order to access the documents.",
"default": false "default": false
}, },
"require_email_2fa": {
"type": "boolean",
"description": "Set to `true` to require email 2FA verification via a one-time code sent to the email address in order to access the documents.",
"default": false
},
"message": { "message": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -1933,6 +1962,15 @@
], ],
"default": "black" "default": "black"
}, },
"background": {
"type": "string",
"description": "Field box background color.",
"enum": [
"black",
"white",
"blue"
]
},
"align": { "align": {
"type": "string", "type": "string",
"description": "Horizontal alignment of the field text value.", "description": "Horizontal alignment of the field text value.",
@ -1986,6 +2024,13 @@
} }
], ],
"default": false "default": false
},
"reasons": {
"description": "An array of signature reasons to choose from.",
"type": "array",
"items": {
"type": "string"
}
} }
} }
} }
@ -2622,6 +2667,10 @@
"event_timestamp": { "event_timestamp": {
"type": "string", "type": "string",
"description": "Date and time when the event was triggered." "description": "Date and time when the event was triggered."
},
"data": {
"type": "object",
"description": "Additional event details object."
} }
} }
} }
@ -2733,7 +2782,8 @@
"id": 1, "id": 1,
"submitter_id": 2, "submitter_id": 2,
"event_type": "view_form", "event_type": "view_form",
"event_timestamp": "2023-12-14T15:47:24.566Z" "event_timestamp": "2023-12-14T15:47:24.566Z",
"data": {}
} }
], ],
"documents": [ "documents": [
@ -3318,7 +3368,8 @@
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"role": { "role": {
@ -3471,6 +3522,15 @@
"description": "Set to `true` to require phone 2FA verification via a one-time code sent to the phone number in order to access the documents.", "description": "Set to `true` to require phone 2FA verification via a one-time code sent to the phone number in order to access the documents.",
"default": false "default": false
}, },
"require_email_2fa": {
"type": "boolean",
"description": "Set to `true` to require email 2FA verification via a one-time code sent to the email address in order to access the documents.",
"default": false
},
"invite_by": {
"type": "string",
"description": "Set the role name of the previous party that should invite this party via email."
},
"fields": { "fields": {
"type": "array", "type": "array",
"description": "A list of configurations for document form fields.", "description": "A list of configurations for document form fields.",
@ -3609,6 +3669,15 @@
], ],
"default": "black" "default": "black"
}, },
"background": {
"type": "string",
"description": "Field box background color.",
"enum": [
"black",
"white",
"blue"
]
},
"align": { "align": {
"type": "string", "type": "string",
"description": "Horizontal alignment of the field text value.", "description": "Horizontal alignment of the field text value.",
@ -3662,6 +3731,13 @@
} }
], ],
"default": false "default": false
},
"reasons": {
"description": "An array of signature reasons to choose from.",
"type": "array",
"items": {
"type": "string"
}
} }
} }
} }
@ -3744,7 +3820,6 @@
"type": "object", "type": "object",
"required": [ "required": [
"id", "id",
"submission_id",
"uuid", "uuid",
"email", "email",
"slug", "slug",
@ -3833,6 +3908,53 @@
"awaiting" "awaiting"
] ]
}, },
"values": {
"type": "array",
"description": "An array of pre-filled values for the submitter.",
"items": {
"type": "object",
"required": [
"field",
"value"
],
"properties": {
"field": {
"type": "string",
"description": "Document template field name."
},
"value": {
"oneOf": [
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
},
{
"type": "array",
"items": {
"oneOf": [
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
}
]
}
}
],
"description": "Pre-filled value of the field."
}
}
}
},
"role": { "role": {
"type": "string", "type": "string",
"description": "The role of the submitter." "description": "The role of the submitter."
@ -3944,7 +4066,8 @@
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"required": { "required": {
@ -3970,6 +4093,10 @@
"type": "string", "type": "string",
"description": "Font color of the field value." "description": "Font color of the field value."
}, },
"background": {
"type": "string",
"description": "Field box background color."
},
"align": { "align": {
"type": "string", "type": "string",
"description": "Horizontal alignment of the field text value." "description": "Horizontal alignment of the field text value."
@ -3993,6 +4120,13 @@
"mask": { "mask": {
"type": "boolean", "type": "boolean",
"description": "Indicates if the field is masked on the document." "description": "Indicates if the field is masked on the document."
},
"reasons": {
"description": "An array of signature reasons to choose from.",
"type": "array",
"items": {
"type": "string"
}
} }
} }
}, },
@ -4040,27 +4174,6 @@
} }
} }
}, },
"documents": {
"type": "array",
"description": "List of documents attached to the one-off submission.",
"items": {
"type": "object",
"required": [
"attachment_uuid",
"name"
],
"properties": {
"attachment_uuid": {
"type": "string",
"description": "Unique indentifier of attached document to the one-off submission."
},
"name": {
"type": "string",
"description": "Name of the attached document to the one-off submission."
}
}
}
},
"expire_at": { "expire_at": {
"type": "string", "type": "string",
"description": "Specify the expiration date and time after which the submission becomes unavailable for signature.", "description": "Specify the expiration date and time after which the submission becomes unavailable for signature.",
@ -4158,7 +4271,7 @@
"Submissions" "Submissions"
], ],
"summary": "Create a submission from DOCX", "summary": "Create a submission from DOCX",
"description": "The API endpoint provides functionality to create a one-off submission request from a DOCX file with dynamic content variables. Use <code>[[variable_name]]</code> text tags to define dynamic content variables in the document. See <a href=\"https://www.docuseal.com/examples/demo_template.docx\" target=\"_blank\" class=\"link font-bold\">https://www.docuseal.com/examples/demo_template.docx</a> for the specific text variable syntax, including dynamic content tables and list. You can also use the <code>{{signature}}</code> fillable field syntax to define fillable fields, as in a PDF.<br><b>Related Guides</b><br><a href=\"https://www.docuseal.com/guides/use-embedded-text-field-tags-in-the-pdf-to-create-a-fillable-form\" class=\"link\">Use embedded text field tags to create a fillable form</a>", "description": "The API endpoint provides functionality to create a one-off submission request from a DOCX file with dynamic content variables. Use <code>[[variable_name]]</code> text tags to define dynamic content variables in the document. See <a href=\"https://www.docuseal.com/examples/demo_template.docx\" target=\"_blank\" class=\"link font-bold\">https://www.docuseal.com/examples/demo_template.docx</a> for the specific text variable syntax, including dynamic content tables and list. You can also use the <code>{{signature}}</code> field syntax to define fillable fields, as in a PDF.<br><b>Related Guides</b><br><a href=\"https://www.docuseal.com/guides/use-dynamic-content-variables-in-docx-to-create-personalized-documents\" class=\"link\">Use dynamic content variables in DOCX to create personalized documents</a>",
"operationId": "createSubmissionFromDocx", "operationId": "createSubmissionFromDocx",
"parameters": [], "parameters": [],
"requestBody": { "requestBody": {
@ -4189,7 +4302,7 @@
}, },
"variables": { "variables": {
"type": "object", "type": "object",
"description": "Dynamic content variables object", "description": "Dynamic content variables object. Variable values can be strings, numbers, arrays, objects, or HTML content used to generate styled text, paragraphs, and tables in DOCX.",
"example": { "example": {
"variable_name": "value" "variable_name": "value"
} }
@ -4327,6 +4440,15 @@
"description": "Set to `true` to require phone 2FA verification via a one-time code sent to the phone number in order to access the documents.", "description": "Set to `true` to require phone 2FA verification via a one-time code sent to the phone number in order to access the documents.",
"default": false "default": false
}, },
"require_email_2fa": {
"type": "boolean",
"description": "Set to `true` to require email 2FA verification via a one-time code sent to the email address in order to access the documents.",
"default": false
},
"invite_by": {
"type": "string",
"description": "Set the role name of the previous party that should invite this party via email."
},
"fields": { "fields": {
"type": "array", "type": "array",
"description": "A list of configurations for document form fields.", "description": "A list of configurations for document form fields.",
@ -4465,6 +4587,15 @@
], ],
"default": "black" "default": "black"
}, },
"background": {
"type": "string",
"description": "Field box background color.",
"enum": [
"black",
"white",
"blue"
]
},
"align": { "align": {
"type": "string", "type": "string",
"description": "Horizontal alignment of the field text value.", "description": "Horizontal alignment of the field text value.",
@ -4518,6 +4649,13 @@
} }
], ],
"default": false "default": false
},
"reasons": {
"description": "An array of signature reasons to choose from.",
"type": "array",
"items": {
"type": "string"
}
} }
} }
} }
@ -4595,7 +4733,6 @@
"type": "object", "type": "object",
"required": [ "required": [
"id", "id",
"submission_id",
"uuid", "uuid",
"email", "email",
"slug", "slug",
@ -4684,6 +4821,53 @@
"awaiting" "awaiting"
] ]
}, },
"values": {
"type": "array",
"description": "An array of pre-filled values for the submitter.",
"items": {
"type": "object",
"required": [
"field",
"value"
],
"properties": {
"field": {
"type": "string",
"description": "Document template field name."
},
"value": {
"oneOf": [
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
},
{
"type": "array",
"items": {
"oneOf": [
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
}
]
}
}
],
"description": "Pre-filled value of the field."
}
}
}
},
"role": { "role": {
"type": "string", "type": "string",
"description": "The role of the submitter." "description": "The role of the submitter."
@ -4795,7 +4979,8 @@
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"required": { "required": {
@ -4821,6 +5006,10 @@
"type": "string", "type": "string",
"description": "Font color of the field value." "description": "Font color of the field value."
}, },
"background": {
"type": "string",
"description": "Field box background color."
},
"align": { "align": {
"type": "string", "type": "string",
"description": "Horizontal alignment of the field text value." "description": "Horizontal alignment of the field text value."
@ -4844,6 +5033,13 @@
"mask": { "mask": {
"type": "boolean", "type": "boolean",
"description": "Indicates if the field is masked on the document." "description": "Indicates if the field is masked on the document."
},
"reasons": {
"description": "An array of signature reasons to choose from.",
"type": "array",
"items": {
"type": "string"
}
} }
} }
}, },
@ -4891,27 +5087,6 @@
} }
} }
}, },
"documents": {
"type": "array",
"description": "List of documents attached to the one-off submission.",
"items": {
"type": "object",
"required": [
"attachment_uuid",
"name"
],
"properties": {
"attachment_uuid": {
"type": "string",
"description": "Unique indentifier of attached document to the one-off submission."
},
"name": {
"type": "string",
"description": "Name of the attached document to the one-off submission."
}
}
}
},
"expire_at": { "expire_at": {
"type": "string", "type": "string",
"description": "Specify the expiration date and time after which the submission becomes unavailable for signature.", "description": "Specify the expiration date and time after which the submission becomes unavailable for signature.",
@ -5198,6 +5373,15 @@
"description": "Set to `true` to require phone 2FA verification via a one-time code sent to the phone number in order to access the documents.", "description": "Set to `true` to require phone 2FA verification via a one-time code sent to the phone number in order to access the documents.",
"default": false "default": false
}, },
"require_email_2fa": {
"type": "boolean",
"description": "Set to `true` to require email 2FA verification via a one-time code sent to the email address in order to access the documents.",
"default": false
},
"invite_by": {
"type": "string",
"description": "Set the role name of the previous party that should invite this party via email."
},
"fields": { "fields": {
"type": "array", "type": "array",
"description": "A list of configurations for document form fields.", "description": "A list of configurations for document form fields.",
@ -5336,6 +5520,15 @@
], ],
"default": "black" "default": "black"
}, },
"background": {
"type": "string",
"description": "Field box background color.",
"enum": [
"black",
"white",
"blue"
]
},
"align": { "align": {
"type": "string", "type": "string",
"description": "Horizontal alignment of the field text value.", "description": "Horizontal alignment of the field text value.",
@ -5389,6 +5582,13 @@
} }
], ],
"default": false "default": false
},
"reasons": {
"description": "An array of signature reasons to choose from.",
"type": "array",
"items": {
"type": "string"
}
} }
} }
} }
@ -5461,7 +5661,6 @@
"type": "object", "type": "object",
"required": [ "required": [
"id", "id",
"submission_id",
"uuid", "uuid",
"email", "email",
"slug", "slug",
@ -5550,6 +5749,53 @@
"awaiting" "awaiting"
] ]
}, },
"values": {
"type": "array",
"description": "An array of pre-filled values for the submitter.",
"items": {
"type": "object",
"required": [
"field",
"value"
],
"properties": {
"field": {
"type": "string",
"description": "Document template field name."
},
"value": {
"oneOf": [
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
},
{
"type": "array",
"items": {
"oneOf": [
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
}
]
}
}
],
"description": "Pre-filled value of the field."
}
}
}
},
"role": { "role": {
"type": "string", "type": "string",
"description": "The role of the submitter." "description": "The role of the submitter."
@ -5661,7 +5907,8 @@
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"required": { "required": {
@ -5687,6 +5934,10 @@
"type": "string", "type": "string",
"description": "Font color of the field value." "description": "Font color of the field value."
}, },
"background": {
"type": "string",
"description": "Field box background color."
},
"align": { "align": {
"type": "string", "type": "string",
"description": "Horizontal alignment of the field text value." "description": "Horizontal alignment of the field text value."
@ -5710,6 +5961,13 @@
"mask": { "mask": {
"type": "boolean", "type": "boolean",
"description": "Indicates if the field is masked on the document." "description": "Indicates if the field is masked on the document."
},
"reasons": {
"description": "An array of signature reasons to choose from.",
"type": "array",
"items": {
"type": "string"
}
} }
} }
}, },
@ -5757,27 +6015,6 @@
} }
} }
}, },
"documents": {
"type": "array",
"description": "List of documents attached to the one-off submission.",
"items": {
"type": "object",
"required": [
"attachment_uuid",
"name"
],
"properties": {
"attachment_uuid": {
"type": "string",
"description": "Unique indentifier of attached document to the one-off submission."
},
"name": {
"type": "string",
"description": "Name of the attached document to the one-off submission."
}
}
}
},
"expire_at": { "expire_at": {
"type": "string", "type": "string",
"description": "Specify the expiration date and time after which the submission becomes unavailable for signature.", "description": "Specify the expiration date and time after which the submission becomes unavailable for signature.",
@ -6078,6 +6315,10 @@
"event_timestamp": { "event_timestamp": {
"type": "string", "type": "string",
"description": "Date and time when the event was triggered." "description": "Date and time when the event was triggered."
},
"data": {
"type": "object",
"description": "Additional event details object."
} }
} }
} }
@ -6185,7 +6426,8 @@
"id": 12, "id": 12,
"submitter_id": 7, "submitter_id": 7,
"event_type": "view_form", "event_type": "view_form",
"event_timestamp": "2023-12-14T15:47:17.351Z" "event_timestamp": "2023-12-14T15:47:17.351Z",
"data": {}
} }
], ],
"values": [ "values": [
@ -6435,6 +6677,15 @@
], ],
"default": "black" "default": "black"
}, },
"background": {
"type": "string",
"description": "Field box background color.",
"enum": [
"black",
"white",
"blue"
]
},
"align": { "align": {
"type": "string", "type": "string",
"description": "Horizontal alignment of the field text value.", "description": "Horizontal alignment of the field text value.",
@ -6488,6 +6739,13 @@
} }
], ],
"default": false "default": false
},
"reasons": {
"description": "An array of signature reasons to choose from.",
"type": "array",
"items": {
"type": "string"
}
} }
} }
} }
@ -6990,6 +7248,10 @@
"event_timestamp": { "event_timestamp": {
"type": "string", "type": "string",
"description": "Date and time when the event was triggered." "description": "Date and time when the event was triggered."
},
"data": {
"type": "object",
"description": "Additional event details object."
} }
} }
} }
@ -7126,7 +7388,8 @@
"id": 12, "id": 12,
"submitter_id": 7, "submitter_id": 7,
"event_type": "view_form", "event_type": "view_form",
"event_timestamp": "2023-12-14T15:48:17.351Z" "event_timestamp": "2023-12-14T15:48:17.351Z",
"data": {}
} }
], ],
"values": [ "values": [
@ -7346,7 +7609,8 @@
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"required": { "required": {
@ -7372,6 +7636,10 @@
"type": "string", "type": "string",
"description": "Font color of the field value." "description": "Font color of the field value."
}, },
"background": {
"type": "string",
"description": "Field box background color."
},
"align": { "align": {
"type": "string", "type": "string",
"description": "Horizontal alignment of the field text value." "description": "Horizontal alignment of the field text value."
@ -7395,6 +7663,13 @@
"mask": { "mask": {
"type": "boolean", "type": "boolean",
"description": "Indicates if the field is masked on the document." "description": "Indicates if the field is masked on the document."
},
"reasons": {
"description": "An array of signature reasons to choose from.",
"type": "array",
"items": {
"type": "string"
}
} }
} }
}, },
@ -7793,7 +8068,8 @@
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"required": { "required": {
@ -7819,6 +8095,10 @@
"type": "string", "type": "string",
"description": "Font color of the field value." "description": "Font color of the field value."
}, },
"background": {
"type": "string",
"description": "Field box background color."
},
"align": { "align": {
"type": "string", "type": "string",
"description": "Horizontal alignment of the field text value." "description": "Horizontal alignment of the field text value."
@ -7842,6 +8122,13 @@
"mask": { "mask": {
"type": "boolean", "type": "boolean",
"description": "Indicates if the field is masked on the document." "description": "Indicates if the field is masked on the document."
},
"reasons": {
"description": "An array of signature reasons to choose from.",
"type": "array",
"items": {
"type": "string"
}
} }
} }
}, },
@ -8294,7 +8581,8 @@
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"required": { "required": {
@ -8320,6 +8608,10 @@
"type": "string", "type": "string",
"description": "Font color of the field value." "description": "Font color of the field value."
}, },
"background": {
"type": "string",
"description": "Field box background color."
},
"align": { "align": {
"type": "string", "type": "string",
"description": "Horizontal alignment of the field text value." "description": "Horizontal alignment of the field text value."
@ -8343,6 +8635,13 @@
"mask": { "mask": {
"type": "boolean", "type": "boolean",
"description": "Indicates if the field is masked on the document." "description": "Indicates if the field is masked on the document."
},
"reasons": {
"description": "An array of signature reasons to choose from.",
"type": "array",
"items": {
"type": "string"
}
} }
} }
}, },
@ -8674,7 +8973,8 @@
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"role": { "role": {
@ -8812,6 +9112,15 @@
], ],
"default": "black" "default": "black"
}, },
"background": {
"type": "string",
"description": "Field box background color.",
"enum": [
"black",
"white",
"blue"
]
},
"align": { "align": {
"type": "string", "type": "string",
"description": "Horizontal alignment of the field text value.", "description": "Horizontal alignment of the field text value.",
@ -8865,6 +9174,13 @@
} }
], ],
"default": false "default": false
},
"reasons": {
"description": "An array of signature reasons to choose from.",
"type": "array",
"items": {
"type": "string"
}
} }
} }
} }
@ -8989,7 +9305,8 @@
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"required": { "required": {
@ -9015,6 +9332,10 @@
"type": "string", "type": "string",
"description": "Font color of the field value." "description": "Font color of the field value."
}, },
"background": {
"type": "string",
"description": "Field box background color."
},
"align": { "align": {
"type": "string", "type": "string",
"description": "Horizontal alignment of the field text value." "description": "Horizontal alignment of the field text value."
@ -9038,6 +9359,13 @@
"mask": { "mask": {
"type": "boolean", "type": "boolean",
"description": "Indicates if the field is masked on the document." "description": "Indicates if the field is masked on the document."
},
"reasons": {
"description": "An array of signature reasons to choose from.",
"type": "array",
"items": {
"type": "string"
}
} }
} }
}, },
@ -9369,7 +9697,8 @@
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"role": { "role": {
@ -9515,6 +9844,15 @@
], ],
"default": "black" "default": "black"
}, },
"background": {
"type": "string",
"description": "Field box background color.",
"enum": [
"black",
"white",
"blue"
]
},
"align": { "align": {
"type": "string", "type": "string",
"description": "Horizontal alignment of the field text value.", "description": "Horizontal alignment of the field text value.",
@ -9568,6 +9906,13 @@
} }
], ],
"default": false "default": false
},
"reasons": {
"description": "An array of signature reasons to choose from.",
"type": "array",
"items": {
"type": "string"
}
} }
} }
} }
@ -9702,7 +10047,8 @@
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"required": { "required": {
@ -9728,6 +10074,10 @@
"type": "string", "type": "string",
"description": "Font color of the field value." "description": "Font color of the field value."
}, },
"background": {
"type": "string",
"description": "Field box background color."
},
"align": { "align": {
"type": "string", "type": "string",
"description": "Horizontal alignment of the field text value." "description": "Horizontal alignment of the field text value."
@ -9751,6 +10101,13 @@
"mask": { "mask": {
"type": "boolean", "type": "boolean",
"description": "Indicates if the field is masked on the document." "description": "Indicates if the field is masked on the document."
},
"reasons": {
"description": "An array of signature reasons to choose from.",
"type": "array",
"items": {
"type": "string"
}
} }
} }
}, },
@ -10169,7 +10526,8 @@
"stamp", "stamp",
"payment", "payment",
"phone", "phone",
"verification" "verification",
"strikethrough"
] ]
}, },
"required": { "required": {
@ -10195,6 +10553,10 @@
"type": "string", "type": "string",
"description": "Font color of the field value." "description": "Font color of the field value."
}, },
"background": {
"type": "string",
"description": "Field box background color."
},
"align": { "align": {
"type": "string", "type": "string",
"description": "Horizontal alignment of the field text value." "description": "Horizontal alignment of the field text value."
@ -10218,6 +10580,13 @@
"mask": { "mask": {
"type": "boolean", "type": "boolean",
"description": "Indicates if the field is masked on the document." "description": "Indicates if the field is masked on the document."
},
"reasons": {
"description": "An array of signature reasons to choose from.",
"type": "array",
"items": {
"type": "string"
}
} }
} }
}, },

@ -281,6 +281,10 @@ Get submission creation, completion, expiration, and archiving notifications usi
"event_timestamp": { "event_timestamp": {
"type": "string", "type": "string",
"description": "Date and time when the event was triggered." "description": "Date and time when the event was triggered."
},
"data": {
"type": "object",
"description": "Additional event details object."
} }
} }
} }

@ -1,7 +1,35 @@
# frozen_string_literal: true # frozen_string_literal: true
module DownloadUtils module DownloadUtils
LOCALHOSTS = %w[0.0.0.0 127.0.0.1 localhost].freeze LOCALHOSTS = Set[
'0.0.0.0',
'127.0.0.1',
'127.0.1.1',
'localhost',
'localhost.localdomain',
'::1',
'[::1]',
'ip6-localhost',
'ip6-loopback',
'127.0.0.0',
'127.255.255.255',
'::',
'0:0:0:0:0:0:0:1',
'[0:0:0:0:0:0:0:1]',
'0000:0000:0000:0000:0000:0000:0000:0001',
'[0000:0000:0000:0000:0000:0000:0000:0001]',
'::0',
'0::0',
'::ffff:127.0.0.1',
'[::ffff:127.0.0.1]',
'::ffff:7f00:1',
'[::ffff:7f00:1]',
'local',
'localhost.local',
'ip6-localnet',
'ip6-allnodes',
'ip6-allrouters'
].freeze
UnableToDownload = Class.new(StandardError) UnableToDownload = Class.new(StandardError)
@ -14,10 +42,7 @@ module DownloadUtils
Addressable::URI.parse(url).normalize Addressable::URI.parse(url).normalize
end end
if Docuseal.multitenant? validate_uri!(uri) if Docuseal.multitenant?
raise UnableToDownload, "Error loading: #{uri}. Only HTTPS is allowed." if uri.scheme != 'https'
raise UnableToDownload, "Error loading: #{uri}. Can't download from localhost." if uri.host.in?(LOCALHOSTS)
end
resp = conn.get(uri) resp = conn.get(uri)
@ -26,9 +51,16 @@ module DownloadUtils
resp resp
end end
def validate_uri!(uri)
raise UnableToDownload, "Error loading: #{uri}. Only HTTPS is allowed." if uri.scheme != 'https'
raise UnableToDownload, "Error loading: #{uri}. Can't download from localhost." if uri.host.in?(LOCALHOSTS)
end
def conn def conn
Faraday.new do |faraday| Faraday.new do |faraday|
faraday.response :follow_redirects faraday.response :follow_redirects, callback: lambda { |_, new_env|
validate_uri!(new_env[:url]) if Docuseal.multitenant?
}
end end
end end
end end

@ -71,7 +71,11 @@ module Params
end end
def validate_submitter(submitter_params) def validate_submitter(submitter_params)
required(submitter_params, %i[email phone name]) if submitter_params['invite_by'].present?
required(submitter_params, :role)
else
required(submitter_params, %i[email phone name])
end
type(submitter_params, :name, String) type(submitter_params, :name, String)
type(submitter_params, :reply_to, String) type(submitter_params, :reply_to, String)

@ -81,7 +81,7 @@ module Submissions
next if submission.submitters.blank? next if submission.submitters.blank?
maybe_add_invite_submitters(submission, template) maybe_add_invite_submitters(submission, template, attrs[:submitters])
submission.template = nil unless with_template submission.template = nil unless with_template
@ -102,8 +102,16 @@ module Submissions
end end
end end
def maybe_add_invite_submitters(submission, template) def maybe_add_invite_submitters(submission, template, submitter_attrs)
template.submitters.each_with_index do |item, index| template.submitters.each_with_index do |item, index|
submitter_attr = submitter_attrs.find { |e| e['role'].to_s.casecmp?(item['name'].to_s) }
if submitter_attr && submitter_attr['invite_by'].present?
invite_by_uuid = template.submitters.find { |s| s['name'] == submitter_attr['invite_by'] }&.dig('uuid')
item = item.merge('invite_by_uuid' => invite_by_uuid) if invite_by_uuid
end
next if item['invite_by_uuid'].blank? && item['optional_invite_by_uuid'].blank? next if item['invite_by_uuid'].blank? && item['optional_invite_by_uuid'].blank?
next if submission.template_submitters.any? { |e| e['uuid'] == item['uuid'] } next if submission.template_submitters.any? { |e| e['uuid'] == item['uuid'] }

@ -522,10 +522,17 @@ module Submissions
if field['type'].in?(%w[multiple radio]) if field['type'].in?(%w[multiple radio])
option = field['options']&.find { |o| o['uuid'] == area['option_uuid'] } option = field['options']&.find { |o| o['uuid'] == area['option_uuid'] }
option_name = option['value'].presence value =
option_name ||= "#{I18n.t('option', locale: locale)} #{field['options'].index(option) + 1}" if option
option_name = option['value'].presence
option_name ||= "#{I18n.t('option', locale: locale)} #{field['options'].index(option) + 1}"
value = Array.wrap(value).include?(option_name) Array.wrap(value).include?(option_name)
else
Rollbar.error("Invalid option: #{field['uuid']}") if defined?(Rollbar)
false
end
end end
next unless value == true next unless value == true

@ -106,7 +106,8 @@ module Submitters
if AccountConfig.exists?(account_id: submitter.submission.account_id, if AccountConfig.exists?(account_id: submitter.submission.account_id,
key: AccountConfig::COMBINE_PDF_RESULT_KEY, key: AccountConfig::COMBINE_PDF_RESULT_KEY,
value: true) && value: true) &&
submitter.submission.submitters.all?(&:completed_at?) submitter.submission.submitters.all?(&:completed_at?) &&
submitter.submission.template_fields.none? { |f| f['type'] == 'verification' }
return [submitter.submission.combined_document_attachment || Submissions::EnsureCombinedGenerated.call(submitter)] return [submitter.submission.combined_document_attachment || Submissions::EnsureCombinedGenerated.call(submitter)]
end end
@ -157,6 +158,7 @@ module Submitters
preferences['send_email'] = params['send_email'].in?(TRUE_VALUES) if params.key?('send_email') preferences['send_email'] = params['send_email'].in?(TRUE_VALUES) if params.key?('send_email')
preferences['send_sms'] = params['send_sms'].in?(TRUE_VALUES) if params.key?('send_sms') preferences['send_sms'] = params['send_sms'].in?(TRUE_VALUES) if params.key?('send_sms')
preferences['require_phone_2fa'] = params['require_phone_2fa'].in?(TRUE_VALUES) if params.key?('require_phone_2fa') preferences['require_phone_2fa'] = params['require_phone_2fa'].in?(TRUE_VALUES) if params.key?('require_phone_2fa')
preferences['require_email_2fa'] = params['require_email_2fa'].in?(TRUE_VALUES) if params.key?('require_email_2fa')
preferences['bcc_completed'] = params['bcc_completed'] if params.key?('bcc_completed') preferences['bcc_completed'] = params['bcc_completed'] if params.key?('bcc_completed')
preferences['reply_to'] = params['reply_to'] if params.key?('reply_to') preferences['reply_to'] = params['reply_to'] if params.key?('reply_to')
preferences['go_to_last'] = params['go_to_last'] if params.key?('go_to_last') preferences['go_to_last'] = params['go_to_last'] if params.key?('go_to_last')

Loading…
Cancel
Save