store multiple submitter results
This commit is contained in:
@@ -39,6 +39,12 @@ Metrics/PerceivedComplexity:
|
||||
Metrics/AbcSize:
|
||||
Max: 35
|
||||
|
||||
Metrics/ModuleLength:
|
||||
Max: 500
|
||||
|
||||
Metrics/ClassLength:
|
||||
Max: 500
|
||||
|
||||
RSpec/NestedGroups:
|
||||
Max: 6
|
||||
|
||||
|
||||
@@ -5,14 +5,14 @@ module Api
|
||||
skip_before_action :authenticate_user!
|
||||
|
||||
def create
|
||||
submission = Submission.find_by!(slug: params[:submission_slug]) unless current_account
|
||||
submitter = Submitter.find_by!(slug: params[:submitter_slug]) unless current_account
|
||||
|
||||
blob = ActiveStorage::Blob.find_signed(params[:blob_signed_id])
|
||||
|
||||
attachment = ActiveStorage::Attachment.create!(
|
||||
blob:,
|
||||
name: params[:name],
|
||||
record: submission || current_account
|
||||
record: submitter || current_account
|
||||
)
|
||||
|
||||
render json: attachment.as_json(only: %i[uuid], methods: %i[url filename content_type])
|
||||
|
||||
@@ -9,14 +9,15 @@ class SendSubmissionEmailController < ApplicationController
|
||||
def success; end
|
||||
|
||||
def create
|
||||
@submission =
|
||||
@submitter =
|
||||
if params[:template_slug]
|
||||
Submission.joins(:template).find_by!(email: params[:email], template: { slug: params[:template_slug] })
|
||||
Submitter.joins(submission: :template).find_by!(email: params[:email],
|
||||
template: { slug: params[:template_slug] })
|
||||
else
|
||||
Submission.find_by!(slug: params[:submission_slug])
|
||||
Submitter.find_by!(slug: params[:submitter_slug])
|
||||
end
|
||||
|
||||
SubmissionMailer.copy_to_submitter(@submission).deliver_later!
|
||||
SubmitterMailer.copy_to_submitter(@submitter).deliver_later!
|
||||
|
||||
respond_to do |f|
|
||||
f.html { redirect_to success_send_submission_email_index_path }
|
||||
|
||||
@@ -8,25 +8,27 @@ class StartFormController < ApplicationController
|
||||
before_action :load_template
|
||||
|
||||
def show
|
||||
@submission = @template.submissions.new
|
||||
@submitter = @template.submissions.new.submitters.new(uuid: @template.submitters.first['uuid'])
|
||||
end
|
||||
|
||||
def update
|
||||
@submission = @template.submissions.find_or_initialize_by(
|
||||
deleted_at: nil, **submission_params
|
||||
)
|
||||
@submitter = Submitter.where(submission: @template.submissions.where(submission: { deleted_at: nil }))
|
||||
.find_or_initialize_by(**submitter_params)
|
||||
|
||||
if @submission.completed_at?
|
||||
if @submitter.completed_at?
|
||||
redirect_to start_form_completed_path(@template.slug, email: submission_params[:email])
|
||||
else
|
||||
@submission.assign_attributes(
|
||||
@submitter.assign_attributes(
|
||||
uuid: @template.submitters.first['uuid'],
|
||||
opened_at: Time.current,
|
||||
ip: request.remote_ip,
|
||||
ua: request.user_agent
|
||||
)
|
||||
|
||||
if @submission.save
|
||||
redirect_to submit_form_path(@submission.slug)
|
||||
@submitter.build_submission(template: @template)
|
||||
|
||||
if @submitter.save
|
||||
redirect_to submit_form_path(@submitter.slug)
|
||||
else
|
||||
render :show
|
||||
end
|
||||
@@ -34,13 +36,13 @@ class StartFormController < ApplicationController
|
||||
end
|
||||
|
||||
def completed
|
||||
@submission = @template.submissions.find_by(email: params[:email])
|
||||
@submitter = Submitter.where(submission: @template.submitters).find_by(email: params[:email])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def submission_params
|
||||
params.require(:submission).permit(:email)
|
||||
def submitter_params
|
||||
params.require(:submitter).permit(:email)
|
||||
end
|
||||
|
||||
def load_template
|
||||
|
||||
@@ -17,19 +17,19 @@ class SubmissionsController < ApplicationController
|
||||
def new; end
|
||||
|
||||
def create
|
||||
emails = params[:emails].to_s.scan(User::EMAIL_REGEXP)
|
||||
|
||||
submissions =
|
||||
emails.map do |email|
|
||||
submission = @template.submissions.create!(email:, sent_at: params[:send_email] == '1' ? Time.current : nil)
|
||||
|
||||
if params[:send_email] == '1'
|
||||
SubmissionMailer.invitation_email(submission, message: params[:message]).deliver_later!
|
||||
end
|
||||
|
||||
submission
|
||||
if params[:emails].present?
|
||||
create_submissions_from_emails
|
||||
else
|
||||
create_submissions_from_submitters
|
||||
end
|
||||
|
||||
if params[:send_email] == '1'
|
||||
submissions.flat_map(&:submitters).each do |submitter|
|
||||
SubmitterMailer.invitation_email(submitter, message: params[:message]).deliver_later!
|
||||
end
|
||||
end
|
||||
|
||||
redirect_to template_submissions_path(@template), notice: "#{submissions.size} recepients added"
|
||||
end
|
||||
|
||||
@@ -44,6 +44,34 @@ class SubmissionsController < ApplicationController
|
||||
|
||||
private
|
||||
|
||||
def create_submissions_from_emails
|
||||
emails = params[:emails].to_s.scan(User::EMAIL_REGEXP)
|
||||
|
||||
emails.map do |email|
|
||||
submission = @template.submissions.new
|
||||
submission.submitters.new(email:, uuid: @template.submitters.first['uuid'],
|
||||
sent_at: params[:send_email] == '1' ? Time.current : nil)
|
||||
|
||||
submission.tap(&:save!)
|
||||
end
|
||||
end
|
||||
|
||||
def create_submissions_from_submitters
|
||||
submissions_params.map do |attrs|
|
||||
submission = @template.submissions.new
|
||||
|
||||
attrs[:submitters].each do |submitter_attrs|
|
||||
submission.submitters.new(**submitter_attrs, sent_at: params[:send_email] == '1' ? Time.current : nil)
|
||||
end
|
||||
|
||||
submission.tap(&:save!)
|
||||
end
|
||||
end
|
||||
|
||||
def submissions_params
|
||||
params.require(:submission).map { |param| param.permit(submitters: [%i[uuid email]]) }
|
||||
end
|
||||
|
||||
def load_template
|
||||
@template = current_account.templates.find(params[:template_id])
|
||||
end
|
||||
|
||||
@@ -6,16 +6,16 @@ class SubmissionsDebugController < ApplicationController
|
||||
skip_before_action :authenticate_user!
|
||||
|
||||
def index
|
||||
@submission = Submission.preload({ attachments_attachments: :blob },
|
||||
template: { documents_attachments: :blob })
|
||||
.find_by(slug: params[:submission_slug])
|
||||
@submitter = Submitter.preload({ attachments_attachments: :blob },
|
||||
submission: { template: { documents_attachments: :blob } })
|
||||
.find_by(slug: params[:submitter_slug])
|
||||
|
||||
respond_to do |f|
|
||||
f.html do
|
||||
render 'submit_template/show'
|
||||
end
|
||||
f.pdf do
|
||||
Submissions::GenerateResultAttachments.call(@submission)
|
||||
Submissions::GenerateResultAttachments.call(@submitter.submission)
|
||||
|
||||
send_data ActiveStorage::Attachment.where(name: :documents).last.download,
|
||||
filename: 'debug.pdf',
|
||||
|
||||
@@ -4,10 +4,10 @@ class SubmissionsDownloadController < ApplicationController
|
||||
skip_before_action :authenticate_user!
|
||||
|
||||
def index
|
||||
submission = Submission.find_by(slug: params[:submission_slug])
|
||||
submitter = Submitter.find_by(slug: params[:submitter_slug])
|
||||
|
||||
Submissions::GenerateResultAttachments.call(submission)
|
||||
Submissions::GenerateResultAttachments.call(submitter)
|
||||
|
||||
redirect_to submission.archive.url, allow_other_host: true
|
||||
redirect_to submitter.archive.url, allow_other_host: true
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,24 +6,25 @@ class SubmitFormController < ApplicationController
|
||||
skip_before_action :authenticate_user!
|
||||
|
||||
def show
|
||||
@submission = Submission.preload(template: { documents_attachments: { preview_images_attachments: :blob } })
|
||||
.find_by!(slug: params[:slug])
|
||||
@submitter =
|
||||
Submitter.preload(submission: { template: { documents_attachments: { preview_images_attachments: :blob } } })
|
||||
.find_by!(slug: params[:slug])
|
||||
|
||||
return redirect_to submit_form_completed_path(@submission.slug) if @submission.completed_at?
|
||||
return redirect_to submit_form_completed_path(@submitter.slug) if @submitter.completed_at?
|
||||
end
|
||||
|
||||
def update
|
||||
submission = Submission.find_by!(slug: params[:slug])
|
||||
submission.values.merge!(normalized_values)
|
||||
submission.completed_at = Time.current if params[:completed] == 'true'
|
||||
submitter = Submitter.find_by!(slug: params[:slug])
|
||||
submitter.values.merge!(normalized_values)
|
||||
submitter.completed_at = Time.current if params[:completed] == 'true'
|
||||
|
||||
submission.save
|
||||
submitter.save
|
||||
|
||||
head :ok
|
||||
end
|
||||
|
||||
def completed
|
||||
@submission = Submission.find_by!(slug: params[:submit_form_slug])
|
||||
@submitter = Submitter.find_by!(slug: params[:submit_form_slug])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -62,7 +62,7 @@ export default actionable(targetable(class extends HTMLElement {
|
||||
body: JSON.stringify({
|
||||
name: this.dataset.name,
|
||||
blob_signed_id: blob.signed_id,
|
||||
submission_slug: this.dataset.submissionSlug
|
||||
submitter_slug: this.dataset.submitterSlug
|
||||
}),
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
}).then(resp => resp.json()).then((data) => {
|
||||
|
||||
@@ -7,7 +7,8 @@ window.customElements.define('submission-form', class extends HTMLElement {
|
||||
this.appElem = document.createElement('div')
|
||||
|
||||
this.app = createApp(Form, {
|
||||
submissionSlug: this.dataset.submissionSlug,
|
||||
submitterSlug: this.dataset.submitterSlug,
|
||||
submitterUuid: this.dataset.submitterUuid,
|
||||
authenticityToken: this.dataset.authenticityToken,
|
||||
values: reactive(JSON.parse(this.dataset.values)),
|
||||
attachments: reactive(JSON.parse(this.dataset.attachments)),
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
</template>
|
||||
<FileDropzone
|
||||
:message="'Attachments'"
|
||||
:submission-slug="submissionSlug"
|
||||
:submitter-slug="submitterSlug"
|
||||
@upload="onUpload"
|
||||
/>
|
||||
</div>
|
||||
@@ -52,7 +52,7 @@ export default {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
submissionSlug: {
|
||||
submitterSlug: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
export default {
|
||||
name: 'FormCompleted',
|
||||
props: {
|
||||
submissionSlug: {
|
||||
submitterSlug: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
@@ -41,7 +41,7 @@ export default {
|
||||
sendCopyToEmail () {
|
||||
this.isSendingCopy = true
|
||||
|
||||
fetch(`/send_submission_email.json?submission_slug=${this.submissionSlug}`, {
|
||||
fetch(`/send_submission_email.json?submitter_slug=${this.submitterSlug}`, {
|
||||
method: 'POST'
|
||||
}).finally(() => {
|
||||
this.isSendingCopy = false
|
||||
@@ -50,7 +50,7 @@ export default {
|
||||
download () {
|
||||
this.isDownloading = true
|
||||
|
||||
fetch(`/submissions/${this.submissionSlug}/download`).then(async (response) => {
|
||||
fetch(`/submitters/${this.submitterSlug}/download`).then(async (response) => {
|
||||
const blob = new Blob([await response.text()], { type: `${response.headers.get('content-type')};charset=utf-8;` })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const link = document.createElement('a')
|
||||
|
||||
@@ -33,7 +33,7 @@ export default {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
submissionSlug: {
|
||||
submitterSlug: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
@@ -97,7 +97,7 @@ export default {
|
||||
body: JSON.stringify({
|
||||
name: 'attachments',
|
||||
blob_signed_id: blob.signed_id,
|
||||
submission_slug: this.submissionSlug
|
||||
submitter_slug: this.submitterSlug
|
||||
}),
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
}).then(resp => resp.json()).then((data) => {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<FieldAreas
|
||||
ref="areas"
|
||||
:fields="fields"
|
||||
:fields="submitterFields"
|
||||
:values="values"
|
||||
:attachments-index="attachmentsIndex"
|
||||
@focus-field="goToField"
|
||||
/>
|
||||
<button
|
||||
v-if="currentStep !== 0"
|
||||
@click="goToField(fields[currentStep - 1], true)"
|
||||
@click="goToField(submitterFields[currentStep - 1], true)"
|
||||
>
|
||||
Back
|
||||
</button>
|
||||
@@ -26,7 +26,7 @@
|
||||
:value="authenticityToken"
|
||||
>
|
||||
<input
|
||||
v-if="currentStep === fields.length - 1"
|
||||
v-if="currentStep === submitterFields.length - 1"
|
||||
type="hidden"
|
||||
name="completed"
|
||||
value="true"
|
||||
@@ -117,7 +117,7 @@
|
||||
v-model="values[currentField.uuid]"
|
||||
:field="currentField"
|
||||
:attachments-index="attachmentsIndex"
|
||||
:submission-slug="submissionSlug"
|
||||
:submitter-slug="submitterSlug"
|
||||
@attached="attachments.push($event)"
|
||||
/>
|
||||
<SignatureStep
|
||||
@@ -126,7 +126,7 @@
|
||||
v-model="values[currentField.uuid]"
|
||||
:field="currentField"
|
||||
:attachments-index="attachmentsIndex"
|
||||
:submission-slug="submissionSlug"
|
||||
:submitter-slug="submitterSlug"
|
||||
@attached="attachments.push($event)"
|
||||
/>
|
||||
<AttachmentStep
|
||||
@@ -134,7 +134,7 @@
|
||||
v-model="values[currentField.uuid]"
|
||||
:field="currentField"
|
||||
:attachments-index="attachmentsIndex"
|
||||
:submission-slug="submissionSlug"
|
||||
:submitter-slug="submitterSlug"
|
||||
@attached="attachments.push($event)"
|
||||
/>
|
||||
</div>
|
||||
@@ -151,7 +151,7 @@
|
||||
</form>
|
||||
<FormCompleted
|
||||
v-else
|
||||
:submission-slug="submissionSlug"
|
||||
:submitter-slug="submitterSlug"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -174,7 +174,11 @@ export default {
|
||||
FormCompleted
|
||||
},
|
||||
props: {
|
||||
submissionSlug: {
|
||||
submitterSlug: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
submitterUuid: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
@@ -207,7 +211,10 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
currentField () {
|
||||
return this.fields[this.currentStep]
|
||||
return this.submitterFields[this.currentStep]
|
||||
},
|
||||
submitterFields () {
|
||||
return this.fields.filter((f) => f.submitter_uuid === this.submitterUuid)
|
||||
},
|
||||
attachmentsIndex () {
|
||||
return this.attachments.reduce((acc, a) => {
|
||||
@@ -217,18 +224,18 @@ export default {
|
||||
}, {})
|
||||
},
|
||||
submitPath () {
|
||||
return `/l/${this.submissionSlug}`
|
||||
return `/s/${this.submitterSlug}`
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.currentStep = Math.min(
|
||||
this.fields.indexOf([...this.fields].reverse().find((field) => !!this.values[field.uuid])) + 1,
|
||||
this.fields.length - 1
|
||||
this.submitterFields.indexOf([...this.submitterFields].reverse().find((field) => !!this.values[field.uuid])) + 1,
|
||||
this.submitterFields.length - 1
|
||||
)
|
||||
},
|
||||
methods: {
|
||||
goToField (field, scrollToArea = false) {
|
||||
this.currentStep = this.fields.indexOf(field)
|
||||
this.currentStep = this.submitterFields.indexOf(field)
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (scrollToArea) {
|
||||
@@ -251,10 +258,10 @@ export default {
|
||||
method: 'POST',
|
||||
body: new FormData(this.$refs.form)
|
||||
}).then(response => {
|
||||
const nextField = this.fields[this.currentStep + 1]
|
||||
const nextField = this.submitterFields[this.currentStep + 1]
|
||||
|
||||
if (nextField) {
|
||||
this.goToField(this.fields[this.currentStep + 1], true)
|
||||
this.goToField(this.submitterFields[this.currentStep + 1], true)
|
||||
} else {
|
||||
this.isCompleted = true
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
>
|
||||
<FileDropzone
|
||||
:message="'Image'"
|
||||
:submission-slug="submissionSlug"
|
||||
:submitter-slug="submitterSlug"
|
||||
:accept="'image/*'"
|
||||
@upload="onImageUpload"
|
||||
/>
|
||||
@@ -37,7 +37,7 @@ export default {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
submissionSlug: {
|
||||
submitterSlug: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
|
||||
@@ -39,7 +39,7 @@ export default {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
submissionSlug: {
|
||||
submitterSlug: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
@@ -81,7 +81,7 @@ export default {
|
||||
fetch('/api/attachments', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
submission_slug: this.submissionSlug,
|
||||
submitter_slug: this.submitterSlug,
|
||||
blob_signed_id: data.signed_id,
|
||||
name: 'attachments'
|
||||
}),
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class SubmissionMailer < ApplicationMailer
|
||||
DEFAULT_MESSAGE = "You've been invited to submit documents."
|
||||
|
||||
def invitation_email(submission, message: DEFAULT_MESSAGE)
|
||||
@submission = submission
|
||||
@message = message
|
||||
|
||||
mail(to: @submission.email,
|
||||
subject: 'You have been invited to submit forms')
|
||||
end
|
||||
|
||||
def copy_to_submitter(submission)
|
||||
@submission = submission
|
||||
|
||||
mail(to: submission.email, subject: 'Here is your copy')
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,19 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class SubmitterMailer < ApplicationMailer
|
||||
DEFAULT_MESSAGE = "You've been invited to submit documents."
|
||||
|
||||
def invitation_email(submitter, message: DEFAULT_MESSAGE)
|
||||
@submitter = submitter
|
||||
@message = message
|
||||
|
||||
mail(to: @submitter.email,
|
||||
subject: 'You have been invited to submit forms')
|
||||
end
|
||||
|
||||
def copy_to_submitter(submitter)
|
||||
@submitter = submitter
|
||||
|
||||
mail(to: submitter.email, subject: 'Here is your copy')
|
||||
end
|
||||
end
|
||||
@@ -4,24 +4,14 @@
|
||||
#
|
||||
# Table name: submissions
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# completed_at :datetime
|
||||
# deleted_at :datetime
|
||||
# email :string not null
|
||||
# ip :string
|
||||
# opened_at :datetime
|
||||
# sent_at :datetime
|
||||
# slug :string not null
|
||||
# ua :string
|
||||
# values :string not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# template_id :bigint not null
|
||||
# id :bigint not null, primary key
|
||||
# deleted_at :datetime
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# template_id :bigint not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_submissions_on_email (email)
|
||||
# index_submissions_on_slug (slug) UNIQUE
|
||||
# index_submissions_on_template_id (template_id)
|
||||
#
|
||||
# Foreign Keys
|
||||
@@ -31,27 +21,7 @@
|
||||
class Submission < ApplicationRecord
|
||||
belongs_to :template
|
||||
|
||||
attribute :values, :string, default: -> { {} }
|
||||
attribute :slug, :string, default: -> { SecureRandom.base58(8) }
|
||||
|
||||
serialize :values, JSON
|
||||
|
||||
has_one_attached :archive
|
||||
has_many_attached :documents
|
||||
|
||||
has_many_attached :attachments
|
||||
has_many :submitters, dependent: :destroy
|
||||
|
||||
scope :active, -> { where(deleted_at: nil) }
|
||||
|
||||
def status
|
||||
if completed_at?
|
||||
'completed'
|
||||
elsif opened_at?
|
||||
'opened'
|
||||
elsif sent_at?
|
||||
'sent'
|
||||
else
|
||||
'awaiting'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: submitters
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# completed_at :datetime
|
||||
# email :string not null
|
||||
# ip :string
|
||||
# opened_at :datetime
|
||||
# sent_at :datetime
|
||||
# slug :string not null
|
||||
# ua :string
|
||||
# uuid :string not null
|
||||
# values :string not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# submission_id :bigint not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_submitters_on_email (email)
|
||||
# index_submitters_on_slug (slug) UNIQUE
|
||||
# index_submitters_on_submission_id (submission_id)
|
||||
#
|
||||
# Foreign Keys
|
||||
#
|
||||
# fk_rails_... (submission_id => submissions.id)
|
||||
#
|
||||
class Submitter < ApplicationRecord
|
||||
belongs_to :submission
|
||||
|
||||
attribute :values, :string, default: -> { {} }
|
||||
attribute :slug, :string, default: -> { SecureRandom.base58(8) }
|
||||
|
||||
serialize :values, JSON
|
||||
|
||||
has_one_attached :archive
|
||||
has_many_attached :documents
|
||||
|
||||
has_many_attached :attachments
|
||||
|
||||
def status
|
||||
if completed_at?
|
||||
'completed'
|
||||
elsif opened_at?
|
||||
'opened'
|
||||
elsif sent_at?
|
||||
'sent'
|
||||
else
|
||||
'awaiting'
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,5 +1,5 @@
|
||||
You have been invited to submit template <%= @template.name %>
|
||||
<%= form_for @submission, url: start_form_path(@template.slug), data: { turbo_frame: :_top }, method: :put do |f| %>
|
||||
<%= form_for @submitter, url: start_form_path(@template.slug), data: { turbo_frame: :_top }, method: :put do |f| %>
|
||||
Provide youe email to start
|
||||
<div>
|
||||
<%= f.label :email %>
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<p>Hi</a>
|
||||
<%= @submission.values %>
|
||||
<%= link_to 'Download', submission_download_index_url(@submission.slug) %>
|
||||
@@ -4,16 +4,18 @@
|
||||
<%= @template.name %>
|
||||
<%= link_to 'Edit', template_path(@template), class: 'btn btn-outline btn-sm' %>
|
||||
</h2>
|
||||
<div class="join w-full">
|
||||
<buttun class="btn bg-neutral btn-disabled text-white join-item">
|
||||
Share link
|
||||
</buttun>
|
||||
<input id="share-link-input" autocomplete="off" type="text" class="input input-bordered w-full join-item" value="<%= start_form_url(slug: @template.slug) %>" disabled>
|
||||
<clipboard-copy class="btn btn-neutral btn-square join-item text-white font-bold swap swap-active" for="share-link-input">
|
||||
<%= svg_icon('clipboard', class: 'w-6 h-6 swap-on text-white') %>
|
||||
<%= svg_icon('clipboard_copy', class: 'w-6 h-6 swap-off text-white') %>
|
||||
</clipboard-copy>
|
||||
</div>
|
||||
<% if @template.submitters.size == 1 %>
|
||||
<div class="join w-full">
|
||||
<buttun class="btn bg-neutral btn-disabled text-white join-item">
|
||||
Share link
|
||||
</buttun>
|
||||
<input id="share-link-input" autocomplete="off" type="text" class="input input-bordered w-full join-item" value="<%= start_form_url(slug: @template.slug) %>" disabled>
|
||||
<clipboard-copy class="btn btn-neutral btn-square join-item text-white font-bold swap swap-active" for="share-link-input">
|
||||
<%= svg_icon('clipboard', class: 'w-6 h-6 swap-on text-white') %>
|
||||
<%= svg_icon('clipboard_copy', class: 'w-6 h-6 swap-off text-white') %>
|
||||
</clipboard-copy>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between mb-4">
|
||||
@@ -42,15 +44,22 @@
|
||||
<% @submissions.each do |submission| %>
|
||||
<tr>
|
||||
<td>
|
||||
<%= submission.email %>
|
||||
<% submission.submitters.each do |submitter| %>
|
||||
<%= submitter.email %>
|
||||
<% end %>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge badge-info badge-outline">
|
||||
<%= submission.status.humanize %>
|
||||
</span>
|
||||
<% submission.submitters.each do |submitter| %>
|
||||
<div>
|
||||
<span class="badge badge-info badge-outline">
|
||||
<%= submitter.status %>
|
||||
</span>
|
||||
<%= link_to 'Copy', submit_form_url(slug: submitter.slug), title: 'Copy', class: 'btn btn-outline btn-xs' %>
|
||||
</div>
|
||||
<% end %>
|
||||
</td>
|
||||
<td class="flex items-center space-x-2 justify-end">
|
||||
<%= link_to 'View', submission_path(@template), title: 'View', class: 'btn btn-outline btn-xs' %>
|
||||
<%= link_to 'View', submission_path(submission), title: 'View', class: 'btn btn-outline btn-xs' %>
|
||||
<%= button_to 'Remove', submission_path(submission), class: 'btn btn-outline btn-error btn-xs', title: 'Delete', method: :delete, data: { turbo_confirm: 'Are you sure?' } %>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -1,9 +1,41 @@
|
||||
<%= render 'shared/turbo_modal', title: 'New Recepients' do %>
|
||||
<%= form_for '', url: template_submissions_path(@template), html: { class: 'space-y-4' }, data: { turbo_frame: :_top } do |f| %>
|
||||
<div class="form-control">
|
||||
<%= f.label :emails, class: 'label' %>
|
||||
<%= f.text_area :emails, required: true, class: 'base-textarea' %>
|
||||
</div>
|
||||
<% if @template.submitters.size == 1 %>
|
||||
<div class="form-control">
|
||||
<%= f.label :emails, class: 'label' %>
|
||||
<%= f.text_area :emails, required: true, class: 'base-textarea' %>
|
||||
</div>
|
||||
<% else %>
|
||||
<table class="">
|
||||
<thead>
|
||||
<tr>
|
||||
<% @template.submitters.each do |item| %>
|
||||
<th class="w-1/2 text-left">
|
||||
<%= item['name'] %>
|
||||
</th>
|
||||
<% end %>
|
||||
<th>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<% @template.submitters.each do |item| %>
|
||||
<td>
|
||||
<input type="hidden" name="submission[][submitters][][uuid]" value="<%= item['uuid'] %>" >
|
||||
<input type="email" name="submission[][submitters][][email]" value="<%= item['email'] %>" required>
|
||||
</td>
|
||||
<% end %>
|
||||
<td>
|
||||
×
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<button>
|
||||
+ Add new
|
||||
</button>
|
||||
<% end %>
|
||||
<div class="form-control">
|
||||
<%= f.label :send_email, class: 'flex items-center cursor-pointer' do %>
|
||||
<%= f.check_box :send_email, class: 'base-checkbox', onchange: "message_field.classList.toggle('hidden', !event.currentTarget.checked)" %>
|
||||
@@ -12,23 +44,18 @@
|
||||
</div>
|
||||
<div id="message_field" class="card card-compact bg-base-200 hidden">
|
||||
<div class="card-body">
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text">Hi There,</span>
|
||||
</label>
|
||||
<%= f.text_area :message, value: SubmissionMailer::DEFAULT_MESSAGE, required: true, class: 'base-textarea !rounded-lg' %>
|
||||
<label class="label">
|
||||
<span class="label-text">
|
||||
Thanks,
|
||||
</br>
|
||||
<%= current_account.name %>
|
||||
</span>
|
||||
</label>
|
||||
<div class="form-control space-y-2">
|
||||
<span class="label-text">Hi there,</span>
|
||||
<%= f.text_area :message, value: SubmitterMailer::DEFAULT_MESSAGE, required: true, class: 'base-textarea !rounded-lg' %>
|
||||
<span class="label-text">
|
||||
Thanks,
|
||||
</br>
|
||||
<%= current_account.name %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<%= f.button button_title(title: 'Confirm', disabled_with: 'Processing'), class: 'base-button' %>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="form-control">
|
||||
<%= f.button button_title(title: 'Confirm', disabled_with: 'Processing'), class: 'base-button' %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
@@ -12,18 +12,6 @@
|
||||
<%= link_to @submission.template.name, template_submissions_path(@submission.template), class: 'link link-hover' %>
|
||||
</dd>
|
||||
</div>
|
||||
<div class="py-6 sm:grid sm:grid-cols-3 sm:gap-4">
|
||||
<dt class="text-sm font-medium leading-6 text-gray-900">URL</dt>
|
||||
<dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
|
||||
<%= link_to submit_form_url(slug: @submission.slug), submit_form_url(slug: @submission.slug), class: 'link link-hover' %>
|
||||
</dd>
|
||||
</div>
|
||||
<div class="py-6 sm:grid sm:grid-cols-3 sm:gap-4">
|
||||
<dt class="text-sm font-medium leading-6 text-gray-900">Email address</dt>
|
||||
<dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
|
||||
<%= mail_to @submission.email %>
|
||||
</dd>
|
||||
</div>
|
||||
<%- if @submission.completed_at.present? %>
|
||||
<div class="py-6 sm:grid sm:grid-cols-3 sm:gap-4">
|
||||
<dt class="text-sm font-medium leading-6 text-gray-900">Completed at</dt>
|
||||
@@ -40,35 +28,41 @@
|
||||
<dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
|
||||
<% if ['image', 'signature'].include?(field['type']) %>
|
||||
<ul role="list" class="divide-y divide-gray-100 rounded-md border border-gray-200">
|
||||
<% Array.wrap(@submission.values[field['uuid']]).each do |uuid| %>
|
||||
<li class="py-4 pl-4 pr-5 text-sm leading-6">
|
||||
<div class="flex w-0 flex-1 items-center">
|
||||
<%= image_tag ActiveStorage::Attachment.find_by(uuid:).url %>
|
||||
</div>
|
||||
</li>
|
||||
<% @submission.submitters.each do |submitter| %>
|
||||
<% Array.wrap(submitter.values[field['uuid']]).each do |uuid| %>
|
||||
<li class="py-4 pl-4 pr-5 text-sm leading-6">
|
||||
<div class="flex w-0 flex-1 items-center">
|
||||
<%= image_tag ActiveStorage::Attachment.find_by(uuid:).url %>
|
||||
</div>
|
||||
</li>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% elsif ['attachment'].include?(field['type']) %>
|
||||
<ul role="list" class="divide-y divide-gray-100 rounded-md border border-gray-200">
|
||||
<% Array.wrap(@submission.values[field['uuid']]).each do |uuid| %>
|
||||
<% attachment = ActiveStorage::Attachment.find_by(uuid:) %>
|
||||
<li class="flex items-center justify-between py-4 pl-4 pr-5 text-sm leading-6">
|
||||
<div class="flex w-0 flex-1 items-center">
|
||||
<%= svg_icon('paperclip', class: 'h-5 w-5 flex-shrink-0 text-gray-300') %>
|
||||
<div class="ml-4 flex min-w-0 flex-1 gap-2">
|
||||
<span class="truncate font-medium">
|
||||
<%= attachment.filename %>
|
||||
</span>
|
||||
<% @submission.submitters.each do |submitter| %>
|
||||
<% Array.wrap(submitter.values[field['uuid']]).each do |uuid| %>
|
||||
<% attachment = ActiveStorage::Attachment.find_by(uuid:) %>
|
||||
<li class="flex items-center justify-between py-4 pl-4 pr-5 text-sm leading-6">
|
||||
<div class="flex w-0 flex-1 items-center">
|
||||
<%= svg_icon('paperclip', class: 'h-5 w-5 flex-shrink-0 text-gray-300') %>
|
||||
<div class="ml-4 flex min-w-0 flex-1 gap-2">
|
||||
<span class="truncate font-medium">
|
||||
<%= attachment.filename %>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml-4 flex-shrink-0">
|
||||
<%= link_to 'Download', attachment.url, class: "font-medium text-indigo-600 hover:text-indigo-500" %>
|
||||
</div>
|
||||
</li>
|
||||
<div class="ml-4 flex-shrink-0">
|
||||
<%= link_to 'Download', attachment.url, class: "font-medium text-indigo-600 hover:text-indigo-500" %>
|
||||
</div>
|
||||
</li>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% else %>
|
||||
<%= @submission.values[field['uuid']] %>
|
||||
<% @submission.submitters.each do |submitter| %>
|
||||
<%= submitter.values[field['uuid']] %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</dt>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<p>
|
||||
Form completed - thanks!
|
||||
</p>
|
||||
<%= button_to button_title(title: 'Send copy to Email', disabled_with: 'Sending'), send_submission_email_index_path, params: { submission_slug: @submission.slug }, form: { onsubmit: 'event.submitter.disabled = true' } %>
|
||||
<%= button_to button_title(title: 'Download documents', disabled_with: 'Downloading'), submission_download_index_path(@submission.slug), method: :get, form: { onsubmit: 'event.submitter.disabled = true' } %>
|
||||
<%= button_to button_title(title: 'Send copy to Email', disabled_with: 'Sending'), send_submission_email_index_path, params: { submitter_slug: @submitter.slug }, form: { onsubmit: 'event.submitter.disabled = true' } %>
|
||||
<%= button_to button_title(title: 'Download documents', disabled_with: 'Downloading'), submitter_download_index_path(@submitter.slug), method: :get, form: { onsubmit: 'event.submitter.disabled = true' } %>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<% attachment_field_uuids = @submission.template.fields.select { |f| f['type'].in?(%w[image signature attachment]) }.pluck('uuid') %>
|
||||
<% attachments = ActiveStorage::Attachment.where(uuid: @submission.values.values_at(*attachment_field_uuids).flatten).preload(:blob) %>
|
||||
<% attachment_field_uuids = @submitter.submission.template.fields.select { |f| f['type'].in?(%w[image signature attachment]) }.pluck('uuid') %>
|
||||
<% attachments = ActiveStorage::Attachment.where(uuid: @submitter.values.values_at(*attachment_field_uuids).flatten).preload(:blob) %>
|
||||
<div class="mx-auto block" style="max-width: 1000px">
|
||||
<% @submission.template.schema.each do |item| %>
|
||||
<% document = @submission.template.documents.find { |a| a.uuid == item['attachment_uuid'] } %>
|
||||
<% @submitter.submission.template.schema.each do |item| %>
|
||||
<% document = @submitter.submission.template.documents.find { |a| a.uuid == item['attachment_uuid'] } %>
|
||||
<% document.preview_images.sort_by { |a| a.filename.base.to_i }.each_with_index do |page, index| %>
|
||||
<div class="relative">
|
||||
<img src="<%= page.url %>" width="<%= page.metadata['width'] %>" height="<%= page.metadata['height'] %>" loading="lazy">
|
||||
@@ -12,7 +12,7 @@
|
||||
<% end %>
|
||||
<div class="sticky bottom-8 w-full">
|
||||
<div class="bg-white mx-8 md:mx-32 border p-4 rounded">
|
||||
<submission-form data-submission-slug="<%= @submission.slug %>" data-attachments="<%= attachments.to_json(only: %i[uuid], methods: %i[url filename content_type]) %>" data-fields="<%= @submission.template.fields.to_json %>" data-values="<%= @submission.values.to_json %>" data-authenticity-token="<%= form_authenticity_token %>"></submission-form>
|
||||
<submission-form data-submitter-uuid="<%= @submitter.uuid %>" data-submitter-slug="<%= @submitter.slug %>" data-attachments="<%= attachments.to_json(only: %i[uuid], methods: %i[url filename content_type]) %>" data-fields="<%= @submitter.submission.template.fields.to_json %>" data-values="<%= @submitter.values.to_json %>" data-authenticity-token="<%= form_authenticity_token %>"></submission-form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<p>Hi</a>
|
||||
<%= @submitter.values %>
|
||||
<%= link_to 'Download', submitter_download_index_url(@submitter.slug) %>
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
<p>Hi there</p>
|
||||
<p>Hi there,</p>
|
||||
<p>You have been invited to submit a form:</p>
|
||||
<p><%= link_to 'Submit', submit_form_index_url(slug: @submission.slug) %></p>
|
||||
<p><%= link_to 'Submit', submit_form_url(slug: @submitter.slug) %></p>
|
||||
<p>If you didn't request this, please ignore this email.</p>
|
||||
@@ -13,7 +13,7 @@ Rails.configuration.to_prepare do
|
||||
|
||||
LoadActiveStorageConfigs.call
|
||||
rescue StandardError => e
|
||||
Rails.logger.debug(e)
|
||||
Rails.logger.error(e)
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
@@ -10,10 +10,16 @@ ActionView::Base.field_error_proc = proc do |html_tag, instance|
|
||||
|
||||
parsed_html_tag = Nokogiri::HTML::DocumentFragment.parse(html_tag)
|
||||
parsed_html_tag.children.add_class 'input-error'
|
||||
# rubocop:disable Rails/OutputSafety
|
||||
html_tag = parsed_html_tag.to_s.html_safe
|
||||
# rubocop:enable Rails/OutputSafety
|
||||
|
||||
result = html_tag
|
||||
result += ApplicationController.helpers.tag.label(ApplicationController.render(partial: 'shared/field_error', locals: { message: "#{field_name} #{errors}" }), class: 'label') if errors.present?
|
||||
|
||||
if errors.present?
|
||||
result +=
|
||||
ApplicationController.render(partial: 'shared/field_error', locals: { message: "#{field_name} #{errors}" })
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
+3
-3
@@ -34,11 +34,11 @@ Rails.application.routes.draw do
|
||||
resources :submissions, only: %i[index new create]
|
||||
end
|
||||
|
||||
resources :start_form, only: %i[show update], path: 'f', param: 'slug' do
|
||||
resources :start_form, only: %i[show update], path: 't', param: 'slug' do
|
||||
get :completed
|
||||
end
|
||||
|
||||
resources :submit_form, only: %i[show update], path: 'l', param: 'slug' do
|
||||
resources :submit_form, only: %i[show update], path: 's', param: 'slug' do
|
||||
get :completed
|
||||
end
|
||||
|
||||
@@ -46,7 +46,7 @@ Rails.application.routes.draw do
|
||||
get :success, on: :collection
|
||||
end
|
||||
|
||||
resources :submissions, only: %i[], param: 'slug' do
|
||||
resources :submitters, only: %i[], param: 'slug' do
|
||||
resources :download, only: %i[index], controller: 'submissions_download'
|
||||
resources :debug, only: %i[index], controller: 'submissions_debug'
|
||||
end
|
||||
|
||||
@@ -3,16 +3,8 @@
|
||||
class CreateSubmissions < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
create_table :submissions do |t|
|
||||
t.string :email, null: false, index: true
|
||||
t.string :slug, null: false, index: { unique: true }
|
||||
t.references :template, null: false, foreign_key: true, index: true
|
||||
t.string :values, null: false
|
||||
t.string :ua
|
||||
t.string :ip
|
||||
|
||||
t.datetime :sent_at
|
||||
t.datetime :opened_at
|
||||
t.datetime :completed_at
|
||||
t.datetime :deleted_at
|
||||
|
||||
t.timestamps
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class CreateSubmitters < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
create_table :submitters do |t|
|
||||
t.references :submission, null: false, foreign_key: true, index: true
|
||||
|
||||
t.string :uuid, null: false
|
||||
t.string :email, null: false, index: true
|
||||
t.string :slug, null: false, index: { unique: true }
|
||||
t.string :values, null: false
|
||||
t.string :ua
|
||||
t.string :ip
|
||||
|
||||
t.datetime :sent_at
|
||||
t.datetime :opened_at
|
||||
t.datetime :completed_at
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
||||
+15
-6
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[7.0].define(version: 2023_05_19_144036) do
|
||||
ActiveRecord::Schema[7.0].define(version: 2023_06_12_182744) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
||||
@@ -61,21 +61,29 @@ ActiveRecord::Schema[7.0].define(version: 2023_05_19_144036) do
|
||||
end
|
||||
|
||||
create_table "submissions", force: :cascade do |t|
|
||||
t.bigint "template_id", null: false
|
||||
t.datetime "deleted_at"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["template_id"], name: "index_submissions_on_template_id"
|
||||
end
|
||||
|
||||
create_table "submitters", force: :cascade do |t|
|
||||
t.bigint "submission_id", null: false
|
||||
t.string "uuid", null: false
|
||||
t.string "email", null: false
|
||||
t.string "slug", null: false
|
||||
t.bigint "template_id", null: false
|
||||
t.string "values", null: false
|
||||
t.string "ua"
|
||||
t.string "ip"
|
||||
t.datetime "sent_at"
|
||||
t.datetime "opened_at"
|
||||
t.datetime "completed_at"
|
||||
t.datetime "deleted_at"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["email"], name: "index_submissions_on_email"
|
||||
t.index ["slug"], name: "index_submissions_on_slug", unique: true
|
||||
t.index ["template_id"], name: "index_submissions_on_template_id"
|
||||
t.index ["email"], name: "index_submitters_on_email"
|
||||
t.index ["slug"], name: "index_submitters_on_slug", unique: true
|
||||
t.index ["submission_id"], name: "index_submitters_on_submission_id"
|
||||
end
|
||||
|
||||
create_table "templates", force: :cascade do |t|
|
||||
@@ -125,6 +133,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_05_19_144036) do
|
||||
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
|
||||
add_foreign_key "encrypted_configs", "accounts"
|
||||
add_foreign_key "submissions", "templates"
|
||||
add_foreign_key "submitters", "submissions"
|
||||
add_foreign_key "templates", "accounts"
|
||||
add_foreign_key "templates", "users", column: "author_id"
|
||||
add_foreign_key "users", "accounts"
|
||||
|
||||
@@ -8,19 +8,18 @@ module Submissions
|
||||
module_function
|
||||
|
||||
# rubocop:disable Metrics
|
||||
def call(submission)
|
||||
cert = submission.template.account.encrypted_configs
|
||||
.find_by(key: EncryptedConfig::ESIGN_CERTS_KEY).value
|
||||
def call(submitter)
|
||||
template = submitter.submission.template
|
||||
|
||||
cert = submitter.submission.template.account.encrypted_configs
|
||||
.find_by(key: EncryptedConfig::ESIGN_CERTS_KEY).value
|
||||
|
||||
zip_file = Tempfile.new
|
||||
zip_stream = Zip::ZipOutputStream.open(zip_file)
|
||||
|
||||
pdfs_index =
|
||||
submission.template.documents.to_h do |attachment|
|
||||
[attachment.uuid, HexaPDF::Document.new(io: StringIO.new(attachment.download))]
|
||||
end
|
||||
pdfs_index = build_pdfs_index(submitter)
|
||||
|
||||
submission.template.fields.each do |field|
|
||||
template.fields.each do |field|
|
||||
field.fetch('areas', []).each do |area|
|
||||
pdf = pdfs_index[area['attachment_uuid']]
|
||||
|
||||
@@ -29,7 +28,7 @@ module Submissions
|
||||
width = page.box.width
|
||||
height = page.box.height
|
||||
|
||||
value = submission.values[field['uuid']]
|
||||
value = submitter.values[field['uuid']]
|
||||
|
||||
canvas = page.canvas(type: :overlay)
|
||||
|
||||
@@ -88,7 +87,8 @@ module Submissions
|
||||
end
|
||||
when 'date'
|
||||
canvas.font(FONT_NAME, size: FONT_SIZE)
|
||||
canvas.text(I18n.l(Date.parse(value)), at: [area['x'] * width, height - ((area['y'] * height) + FONT_SIZE)])
|
||||
canvas.text(I18n.l(Date.parse(value)),
|
||||
at: [area['x'] * width, height - ((area['y'] * height) + FONT_SIZE)])
|
||||
else
|
||||
canvas.font(FONT_NAME, size: FONT_SIZE)
|
||||
canvas.text(value.to_s, at: [area['x'] * width, height - ((area['y'] * height) + FONT_SIZE)])
|
||||
@@ -96,14 +96,14 @@ module Submissions
|
||||
end
|
||||
end
|
||||
|
||||
submission.template.schema.map do |item|
|
||||
document = submission.template.documents.find { |a| a.uuid == item['attachment_uuid'] }
|
||||
template.schema.map do |item|
|
||||
template.documents.find { |a| a.uuid == item['attachment_uuid'] }
|
||||
|
||||
io = StringIO.new
|
||||
|
||||
pdf = pdfs_index[item['attachment_uuid']]
|
||||
|
||||
pdf.sign(io, reason: "Signed by #{submission.email}",
|
||||
pdf.sign(io, reason: "Signed by #{submitter.email}",
|
||||
# doc_mdp_permissions: :no_changes,
|
||||
certificate: OpenSSL::X509::Certificate.new(cert['cert']),
|
||||
key: OpenSSL::PKey::RSA.new(cert['key']),
|
||||
@@ -113,13 +113,33 @@ module Submissions
|
||||
zip_stream.put_next_entry("#{item['name']}.pdf")
|
||||
zip_stream.write(io.string)
|
||||
|
||||
submission.documents.attach(io: StringIO.new(io.string), filename: document.filename)
|
||||
ActiveStorage::Attachment.create!(
|
||||
uuid: item['attachment_uuid'],
|
||||
blob: ActiveStorage::Blob.create_and_upload!(
|
||||
io: StringIO.new(io.string), filename: "#{item['name']}.pdf"
|
||||
),
|
||||
name: 'documents',
|
||||
record: submitter
|
||||
)
|
||||
end
|
||||
|
||||
zip_stream.close
|
||||
|
||||
submission.archive.attach(io: zip_file, filename: "#{submission.template.name}.zip")
|
||||
submitter.archive.attach(io: zip_file, filename: "#{template.name}.zip")
|
||||
end
|
||||
# rubocop:enable Metrics
|
||||
|
||||
def build_pdfs_index(submitter)
|
||||
latest_submitter = submitter.submission.submitters
|
||||
.select { |e| e.id != submitter.id && e.completed_at? }
|
||||
.max_by(&:completed_at)
|
||||
|
||||
documents = latest_submitter&.documents.to_a.presence
|
||||
documents ||= submitter.submission.template.documents
|
||||
|
||||
documents.to_h do |attachment|
|
||||
[attachment.uuid, HexaPDF::Document.new(io: StringIO.new(attachment.download))]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user