Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/controllers/api/submissions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def index
submissions = Submissions.search(current_user, @submissions, params[:q])
submissions = filter_submissions(submissions, params)

submissions = paginate(submissions.preload(:created_by_user, :submitters,
submissions = paginate(submissions.preload(:account, :created_by_user, :submitters,
template: :folder,
combined_document_attachment: :blob,
audit_trail_attachment: :blob))
Expand Down Expand Up @@ -167,7 +167,7 @@ def create_submissions(template, params)
template:,
user: current_user,
source: :api,
submitters_order: params[:submitters_order] || params[:order] || 'preserved',
submitters_order: params[:submitters_order] || params[:order] || template.effective_submitters_order,
submissions_attrs:,
params:
)
Expand Down
24 changes: 24 additions & 0 deletions app/controllers/concerns/template_webhooks.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

module TemplateWebhooks
def enqueue_template_created_webhooks(template)
WebhookUrls.for_template(template, 'template.created').each do |webhook_url|
SendTemplateCreatedWebhookRequestJob.perform_async('template_id' => template.id,
'webhook_url_id' => webhook_url.id)
end
end

def enqueue_template_updated_webhooks(template)
WebhookUrls.for_template(template, 'template.updated').each do |webhook_url|
SendTemplateUpdatedWebhookRequestJob.perform_async('template_id' => template.id,
'webhook_url_id' => webhook_url.id)
end
end

def enqueue_template_preferences_updated_webhooks(template)
WebhookUrls.for_template(template, 'template.preferences_updated').each do |webhook_url|
SendTemplatePreferencesUpdatedWebhookRequestJob.perform_async('template_id' => template.id,
'webhook_url_id' => webhook_url.id)
end
end
end
2 changes: 1 addition & 1 deletion app/controllers/submissions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def create
Submissions.create_from_submitters(template: @template,
user: current_user,
source: :invite,
submitters_order: params[:preserve_order] == '1' ? 'preserved' : 'random',
submitters_order: @template.effective_submitters_order,
submissions_attrs: submissions_params[:submission].to_h.values,
params: params.merge('send_completed_email' => true))
end
Expand Down
14 changes: 11 additions & 3 deletions app/controllers/submit_form_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,17 @@ def show

@form_configs = Submitters::FormConfigs.call(@submitter, CONFIG_KEYS)

return render :awaiting if (@form_configs[:enforce_signing_order] ||
submission.template&.preferences&.dig('submitters_order') == 'preserved') &&
!Submitters.current_submitter_order?(@submitter)
if @form_configs[:enforce_signing_order] ||
submission.template_signing_order.in?(%w[employee_then_manager manager_then_employee])
signing_order = Submitters.validate_submitter_order(@submitter)

if signing_order.nil?
flash.now[:alert] = I18n.t('user_id_did_not_match_please_try_again_or_contact_support')
return render :awaiting
end

return render :awaiting unless signing_order
end

Submissions.preload_with_pages(submission)

Expand Down
27 changes: 11 additions & 16 deletions app/controllers/templates_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ class TemplatesController < ApplicationController
include PrefillFieldsHelper
include IframeAuthentication
include PartnershipContext
include TemplateWebhooks

skip_before_action :verify_authenticity_token
skip_before_action :authenticate_via_token!, only: [:update]
Expand Down Expand Up @@ -99,8 +100,10 @@ def create
end

def update
@template.assign_attributes(template_params)
# Capture current submitters_order before any changes
old_submitters_order = @template.preferences['submitters_order']

@template.assign_attributes(template_params)
is_name_changed = @template.name_changed?

@template.save!
Expand All @@ -109,7 +112,13 @@ def update

enqueue_template_updated_webhooks(@template)

head :ok
# If submitters_order changed (e.g., fields removed making it single_sided), fire preferences webhook
new_submitters_order = @template.preferences['submitters_order']
if old_submitters_order != new_submitters_order && new_submitters_order.present?
enqueue_template_preferences_updated_webhooks(@template)
end

render json: { preferences: @template.preferences }
end

def destroy
Expand Down Expand Up @@ -159,20 +168,6 @@ def maybe_redirect_to_template(template)
end
end

def enqueue_template_created_webhooks(template)
WebhookUrls.for_template(template, 'template.created').each do |webhook_url|
SendTemplateCreatedWebhookRequestJob.perform_async('template_id' => template.id,
'webhook_url_id' => webhook_url.id)
end
end

def enqueue_template_updated_webhooks(template)
WebhookUrls.for_template(template, 'template.updated').each do |webhook_url|
SendTemplateUpdatedWebhookRequestJob.perform_async('template_id' => template.id,
'webhook_url_id' => webhook_url.id)
end
end

def handle_account_override
return unless authorized_clone_account_id?(params[:account_id])

Expand Down
24 changes: 24 additions & 0 deletions app/controllers/templates_preferences_controller.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,41 @@
# frozen_string_literal: true

class TemplatesPreferencesController < ApplicationController
include IframeAuthentication
include PartnershipContext
include TemplateWebhooks

# We use IframeAuthentication#authenticate_from_referer to authenticate the user.
# These are holdovers from legacy Docuseal that uses an actual login system
# and will be removed in a future ticket.
skip_before_action :verify_authenticity_token
skip_before_action :authenticate_via_token!
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should maybe add a comment explaining why we're skipping these

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a comment there, it's because of the IframeAuthentication concern, they used to use Devise, but we don't need that since we don't have them log into Docuseal.


before_action :authenticate_from_referer
load_and_authorize_resource :template

def show; end

def create
authorize!(:update, @template)

old_submitters_order = @template.preferences['submitters_order']
@template.preferences = @template.preferences.merge(template_params[:preferences])
@template.preferences = @template.preferences.reject { |_, v| (v.is_a?(String) || v.is_a?(Hash)) && v.blank? }

# Handle single_sided case (when template has < 2 unique submitters)
if @template.unique_submitter_uuids.size < 2 && @template.preferences['submitters_order'].present?
@template.preferences['submitters_order'] = 'single_sided'
end

@template.save!

# Enqueue webhook if submitters_order changed
new_submitters_order = @template.preferences['submitters_order']
if old_submitters_order != new_submitters_order && new_submitters_order.present?
enqueue_template_preferences_updated_webhooks(@template)
end

head :ok
end

Expand Down
9 changes: 2 additions & 7 deletions app/controllers/templates_uploads_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# frozen_string_literal: true

class TemplatesUploadsController < ApplicationController
include TemplateWebhooks

skip_before_action :verify_authenticity_token, only: [:create]

load_and_authorize_resource :template, parent: false
Expand Down Expand Up @@ -70,11 +72,4 @@ def create_file_params_from_url

{ files: [file] }
end

def enqueue_template_created_webhooks(template)
WebhookUrls.for_template(template, 'template.created').each do |webhook_url|
SendTemplateCreatedWebhookRequestJob.perform_async('template_id' => template.id,
'webhook_url_id' => webhook_url.id)
end
end
end
34 changes: 31 additions & 3 deletions app/javascript/template_builder/builder.vue
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@
name="buttons"
/>
<template v-else>
<button
v-if="hasMultipleSubmitterFields"
class="base-button"
@click.prevent="isShowSigningOrderModal = true"
>
<IconAdjustments class="w-6 h-6 flex-shrink-0" />
<span class="whitespace-nowrap">{{ t('signing_order') }}</span>
</button>
<a
:href="formPreviewUrl"
data-turbo="false"
Expand Down Expand Up @@ -331,6 +339,14 @@
id="docuseal_modal_container"
class="modal-container"
/>
<Teleport
v-if="isShowSigningOrderModal"
to="#docuseal_modal_container"
>
<SigningOrderModal
@close="isShowSigningOrderModal = false"
/>
</Teleport>
</div>
</template>

Expand All @@ -348,6 +364,7 @@ import DocumentPreview from './preview'
import DocumentControls from './controls'
import MobileFields from './mobile_fields'
import FieldSubmitter from './field_submitter'
import SigningOrderModal from './signing_order_modal'
import { IconPlus, IconUsersPlus, IconDeviceFloppy, IconChevronDown, IconEye, IconWritingSign, IconInnerShadowTop, IconInfoCircle, IconAdjustments } from '@tabler/icons-vue'
import { v4 } from 'uuid'
import { ref, computed, toRaw, watch } from 'vue'
Expand Down Expand Up @@ -376,7 +393,8 @@ export default {
IconChevronDown,
IconAdjustments,
IconEye,
IconDeviceFloppy
IconDeviceFloppy,
SigningOrderModal
},
provide () {
return {
Expand All @@ -387,6 +405,7 @@ export default {
currencies: this.currencies,
locale: this.locale,
baseFetch: this.baseFetch,
authenticityToken: this.authenticityToken,
fieldTypes: this.fieldTypes,
backgroundColor: this.backgroundColor,
withPhone: this.withPhone,
Expand Down Expand Up @@ -636,13 +655,18 @@ export default {
drawFieldType: null,
drawOption: null,
dragField: null,
isDragFile: false
isDragFile: false,
isShowSigningOrderModal: false
}
},
computed: {
submitterDefaultNames: FieldSubmitter.computed.names,
selectedAreaRef: () => ref(),
fieldsDragFieldRef: () => ref(),
hasMultipleSubmitterFields () {
const submitterUuids = new Set(this.template.fields.map((f) => f.submitter_uuid).filter(Boolean))
return submitterUuids.size >= 2
},
language () {
return this.locale.split('-')[0].toLowerCase()
},
Expand Down Expand Up @@ -1823,7 +1847,11 @@ export default {
}
}),
headers: { 'Content-Type': 'application/json' }
}).then(() => {
}).then((response) => response.json()).then((data) => {
if (data.preferences) {
this.template.preferences = data.preferences
}

if (this.onSave) {
this.onSave(this.template)
}
Expand Down
4 changes: 4 additions & 0 deletions app/javascript/template_builder/i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ const en = {
condition: 'Condition',
first_party: 'Employee',
second_party: 'Manager',
signing_order: 'Signing Order',
select_signing_order: 'Select Signing Order',
simultaneous_signing_description: 'Both parties may complete the form at the same time',
failed_to_save_signing_order_please_try_again_or_contact_support: 'Failed to save signing order. Please try again or contact support for assistance.',
draw: 'Draw',
add: 'Add',
or_add_field_without_drawing: 'Or add field without drawing',
Expand Down
Loading
Loading