rename to templates
This commit is contained in:
@@ -1,22 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Api
|
|
||||||
class FlowsController < ApiBaseController
|
|
||||||
def update
|
|
||||||
@flow = current_account.flows.find(params[:id])
|
|
||||||
|
|
||||||
@flow.update!(flow_params)
|
|
||||||
|
|
||||||
render :ok
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def flow_params
|
|
||||||
params.require(:flow).permit(:name,
|
|
||||||
schema: [%i[attachment_uuid name]],
|
|
||||||
fields: [[:uuid, :name, :type, :required,
|
|
||||||
{ options: [], areas: [%i[x y w h attachment_uuid page]] }]])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Api
|
||||||
|
class TemplatesController < ApiBaseController
|
||||||
|
def update
|
||||||
|
@template = current_account.templates.find(params[:id])
|
||||||
|
|
||||||
|
@template.update!(template_params)
|
||||||
|
|
||||||
|
render :ok
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def template_params
|
||||||
|
params.require(:template).permit(:name,
|
||||||
|
schema: [%i[attachment_uuid name]],
|
||||||
|
fields: [[:uuid, :name, :type, :required,
|
||||||
|
{ options: [], areas: [%i[x y w h attachment_uuid page]] }]])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
+4
-4
@@ -1,17 +1,17 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Api
|
module Api
|
||||||
class FlowsDocumentsController < ApiBaseController
|
class TemplatesDocumentsController < ApiBaseController
|
||||||
def create
|
def create
|
||||||
@flow = current_account.flows.find(params[:flow_id])
|
@template = current_account.templates.find(params[:template_id])
|
||||||
|
|
||||||
documents =
|
documents =
|
||||||
params[:blobs].map do |blob|
|
params[:blobs].map do |blob|
|
||||||
blob = ActiveStorage::Blob.find_signed(blob[:signed_id])
|
blob = ActiveStorage::Blob.find_signed(blob[:signed_id])
|
||||||
|
|
||||||
document = @flow.documents.create!(blob:)
|
document = @template.documents.create!(blob:)
|
||||||
|
|
||||||
Flows::ProcessDocument.call(document)
|
Templates::ProcessDocument.call(document)
|
||||||
end
|
end
|
||||||
|
|
||||||
schema = documents.map do |doc|
|
schema = documents.map do |doc|
|
||||||
@@ -2,6 +2,6 @@
|
|||||||
|
|
||||||
class DashboardController < ApplicationController
|
class DashboardController < ApplicationController
|
||||||
def index
|
def index
|
||||||
@flows = current_account.flows.active
|
@templates = current_account.templates.active
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class FlowsController < ApplicationController
|
|
||||||
layout false
|
|
||||||
|
|
||||||
def show
|
|
||||||
@flow = current_account.flows.preload(documents_attachments: { preview_images_attachments: :blob })
|
|
||||||
.find(params[:id])
|
|
||||||
end
|
|
||||||
|
|
||||||
def new
|
|
||||||
@flow = current_account.flows.new
|
|
||||||
end
|
|
||||||
|
|
||||||
def create
|
|
||||||
@flow = current_account.flows.new(flow_params)
|
|
||||||
@flow.author = current_user
|
|
||||||
|
|
||||||
if @flow.save
|
|
||||||
redirect_to flow_path(@flow)
|
|
||||||
else
|
|
||||||
render turbo_stream: turbo_stream.replace(:modal, template: 'flows/new'), status: :unprocessable_entity
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def destroy
|
|
||||||
@flow = current_account.flows.find(params[:id])
|
|
||||||
@flow.update!(deleted_at: Time.current)
|
|
||||||
|
|
||||||
redirect_to settings_users_path, notice: 'Flow has been archived.'
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def flow_params
|
|
||||||
params.require(:flow).permit(:name, :schema)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class SendSubmissionEmailController < ApplicationController
|
class SendSubmissionEmailController < ApplicationController
|
||||||
layout 'flow'
|
layout 'form'
|
||||||
|
|
||||||
skip_before_action :authenticate_user!
|
skip_before_action :authenticate_user!
|
||||||
skip_before_action :verify_authenticity_token
|
skip_before_action :verify_authenticity_token
|
||||||
@@ -10,8 +10,8 @@ class SendSubmissionEmailController < ApplicationController
|
|||||||
|
|
||||||
def create
|
def create
|
||||||
@submission =
|
@submission =
|
||||||
if params[:flow_slug]
|
if params[:template_slug]
|
||||||
Submission.joins(:flow).find_by!(email: params[:email], flow: { slug: params[:flow_slug] })
|
Submission.joins(:template).find_by!(email: params[:email], template: { slug: params[:template_slug] })
|
||||||
else
|
else
|
||||||
Submission.find_by!(slug: params[:submission_slug])
|
Submission.find_by!(slug: params[:submission_slug])
|
||||||
end
|
end
|
||||||
|
|||||||
+11
-11
@@ -1,23 +1,23 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class StartFlowController < ApplicationController
|
class StartFormController < ApplicationController
|
||||||
layout 'flow'
|
layout 'form'
|
||||||
|
|
||||||
skip_before_action :authenticate_user!
|
skip_before_action :authenticate_user!
|
||||||
|
|
||||||
before_action :load_flow
|
before_action :load_template
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@submission = @flow.submissions.new
|
@submission = @template.submissions.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@submission = @flow.submissions.find_or_initialize_by(
|
@submission = @template.submissions.find_or_initialize_by(
|
||||||
deleted_at: nil, **submission_params
|
deleted_at: nil, **submission_params
|
||||||
)
|
)
|
||||||
|
|
||||||
if @submission.completed_at?
|
if @submission.completed_at?
|
||||||
redirect_to start_flow_completed_path(@flow.slug, email: submission_params[:email])
|
redirect_to start_form_completed_path(@template.slug, email: submission_params[:email])
|
||||||
else
|
else
|
||||||
@submission.assign_attributes(
|
@submission.assign_attributes(
|
||||||
opened_at: Time.current,
|
opened_at: Time.current,
|
||||||
@@ -26,7 +26,7 @@ class StartFlowController < ApplicationController
|
|||||||
)
|
)
|
||||||
|
|
||||||
if @submission.save
|
if @submission.save
|
||||||
redirect_to submit_flow_path(@submission.slug)
|
redirect_to submit_form_path(@submission.slug)
|
||||||
else
|
else
|
||||||
render :show
|
render :show
|
||||||
end
|
end
|
||||||
@@ -34,7 +34,7 @@ class StartFlowController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def completed
|
def completed
|
||||||
@submission = @flow.submissions.find_by(email: params[:email])
|
@submission = @template.submissions.find_by(email: params[:email])
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
@@ -43,9 +43,9 @@ class StartFlowController < ApplicationController
|
|||||||
params.require(:submission).permit(:email)
|
params.require(:submission).permit(:email)
|
||||||
end
|
end
|
||||||
|
|
||||||
def load_flow
|
def load_template
|
||||||
slug = params[:slug] || params[:start_flow_slug]
|
slug = params[:slug] || params[:start_template_slug]
|
||||||
|
|
||||||
@flow = Flow.find_by!(slug:)
|
@template = Template.find_by!(slug:)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class SubmissionsController < ApplicationController
|
class SubmissionsController < ApplicationController
|
||||||
before_action :load_flow, only: %i[index new create]
|
before_action :load_template, only: %i[index new create]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@submissions = @flow.submissions.active
|
@submissions = @template.submissions.active
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@submission =
|
@submission =
|
||||||
Submission.joins(:flow).where(flow: { account_id: current_account.id })
|
Submission.joins(:template).where(template: { account_id: current_account.id })
|
||||||
.preload(flow: { documents_attachments: { preview_images_attachments: :blob } })
|
.preload(template: { documents_attachments: { preview_images_attachments: :blob } })
|
||||||
.find(params[:id])
|
.find(params[:id])
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ class SubmissionsController < ApplicationController
|
|||||||
|
|
||||||
submissions =
|
submissions =
|
||||||
emails.map do |email|
|
emails.map do |email|
|
||||||
submission = @flow.submissions.create!(email:, sent_at: params[:send_email] == '1' ? Time.current : nil)
|
submission = @template.submissions.create!(email:, sent_at: params[:send_email] == '1' ? Time.current : nil)
|
||||||
|
|
||||||
if params[:send_email] == '1'
|
if params[:send_email] == '1'
|
||||||
SubmissionMailer.invitation_email(submission, message: params[:message]).deliver_later!
|
SubmissionMailer.invitation_email(submission, message: params[:message]).deliver_later!
|
||||||
@@ -30,21 +30,21 @@ class SubmissionsController < ApplicationController
|
|||||||
submission
|
submission
|
||||||
end
|
end
|
||||||
|
|
||||||
redirect_to flow_submissions_path(@flow), notice: "#{submissions.size} recepients added"
|
redirect_to template_submissions_path(@template), notice: "#{submissions.size} recepients added"
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
submission = Submission.joins(:flow).where(flow: { account_id: current_account.id })
|
submission = Submission.joins(:template).where(template: { account_id: current_account.id })
|
||||||
.find(params[:id])
|
.find(params[:id])
|
||||||
|
|
||||||
submission.update!(deleted_at: Time.current)
|
submission.update!(deleted_at: Time.current)
|
||||||
|
|
||||||
redirect_to flow_submissions_path(submission.flow), notice: 'Submission has been archieved'
|
redirect_to template_submissions_path(submission.template), notice: 'Submission has been archieved'
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def load_flow
|
def load_template
|
||||||
@flow = current_account.flows.find(params[:flow_id])
|
@template = current_account.templates.find(params[:template_id])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class SubmissionsDebugController < ApplicationController
|
class SubmissionsDebugController < ApplicationController
|
||||||
layout 'flow'
|
layout 'form'
|
||||||
|
|
||||||
skip_before_action :authenticate_user!
|
skip_before_action :authenticate_user!
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@submission = Submission.preload({ attachments_attachments: :blob },
|
@submission = Submission.preload({ attachments_attachments: :blob },
|
||||||
flow: { documents_attachments: :blob })
|
template: { documents_attachments: :blob })
|
||||||
.find_by(slug: params[:submission_slug])
|
.find_by(slug: params[:submission_slug])
|
||||||
|
|
||||||
respond_to do |f|
|
respond_to do |f|
|
||||||
f.html do
|
f.html do
|
||||||
render 'submit_flow/show'
|
render 'submit_template/show'
|
||||||
end
|
end
|
||||||
f.pdf do
|
f.pdf do
|
||||||
Submissions::GenerateResultAttachments.call(@submission)
|
Submissions::GenerateResultAttachments.call(@submission)
|
||||||
|
|||||||
+5
-5
@@ -1,15 +1,15 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class SubmitFlowController < ApplicationController
|
class SubmitFormController < ApplicationController
|
||||||
layout 'flow'
|
layout 'form'
|
||||||
|
|
||||||
skip_before_action :authenticate_user!
|
skip_before_action :authenticate_user!
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@submission = Submission.preload(flow: { documents_attachments: { preview_images_attachments: :blob } })
|
@submission = Submission.preload(template: { documents_attachments: { preview_images_attachments: :blob } })
|
||||||
.find_by!(slug: params[:slug])
|
.find_by!(slug: params[:slug])
|
||||||
|
|
||||||
return redirect_to submit_flow_completed_path(@submission.slug) if @submission.completed_at?
|
return redirect_to submit_form_completed_path(@submission.slug) if @submission.completed_at?
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@@ -23,7 +23,7 @@ class SubmitFlowController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def completed
|
def completed
|
||||||
@submission = Submission.find_by!(slug: params[:submit_flow_slug])
|
@submission = Submission.find_by!(slug: params[:submit_form_slug])
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class TemplatesController < ApplicationController
|
||||||
|
layout false
|
||||||
|
|
||||||
|
def show
|
||||||
|
@template = current_account.templates.preload(documents_attachments: { preview_images_attachments: :blob })
|
||||||
|
.find(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def new
|
||||||
|
@template = current_account.templates.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@template = current_account.templates.new(template_params)
|
||||||
|
@template.author = current_user
|
||||||
|
|
||||||
|
if @template.save
|
||||||
|
redirect_to template_path(@template)
|
||||||
|
else
|
||||||
|
render turbo_stream: turbo_stream.replace(:modal, template: 'templates/new'), status: :unprocessable_entity
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
@template = current_account.templates.find(params[:id])
|
||||||
|
@template.update!(deleted_at: Time.current)
|
||||||
|
|
||||||
|
redirect_to settings_users_path, notice: 'template has been archived.'
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def template_params
|
||||||
|
params.require(:template).permit(:name, :schema)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -8,7 +8,7 @@ import TurboModal from './elements/turbo_modal'
|
|||||||
import FileDropzone from './elements/file_dropzone'
|
import FileDropzone from './elements/file_dropzone'
|
||||||
import MenuActive from './elements/menu_active'
|
import MenuActive from './elements/menu_active'
|
||||||
|
|
||||||
import FlowBuilder from './flow_builder/builder'
|
import TemplateBuilder from './template_builder/builder'
|
||||||
|
|
||||||
document.addEventListener('turbo:before-cache', () => {
|
document.addEventListener('turbo:before-cache', () => {
|
||||||
window.flash?.remove()
|
window.flash?.remove()
|
||||||
@@ -20,12 +20,12 @@ window.customElements.define('turbo-modal', TurboModal)
|
|||||||
window.customElements.define('file-dropzone', FileDropzone)
|
window.customElements.define('file-dropzone', FileDropzone)
|
||||||
window.customElements.define('menu-active', MenuActive)
|
window.customElements.define('menu-active', MenuActive)
|
||||||
|
|
||||||
window.customElements.define('flow-builder', class extends HTMLElement {
|
window.customElements.define('template-builder', class extends HTMLElement {
|
||||||
connectedCallback () {
|
connectedCallback () {
|
||||||
this.appElem = document.createElement('div')
|
this.appElem = document.createElement('div')
|
||||||
|
|
||||||
this.app = createApp(FlowBuilder, {
|
this.app = createApp(TemplateBuilder, {
|
||||||
flow: reactive(JSON.parse(this.dataset.flow))
|
template: reactive(JSON.parse(this.dataset.template))
|
||||||
})
|
})
|
||||||
|
|
||||||
this.app.mount(this.appElem)
|
this.app.mount(this.appElem)
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { createApp, reactive } from 'vue'
|
import { createApp, reactive } from 'vue'
|
||||||
|
|
||||||
import Flow from './flow_form/form'
|
import Form from './submission_form/form'
|
||||||
|
|
||||||
window.customElements.define('flow-form', class extends HTMLElement {
|
window.customElements.define('submission-form', class extends HTMLElement {
|
||||||
connectedCallback () {
|
connectedCallback () {
|
||||||
this.appElem = document.createElement('div')
|
this.appElem = document.createElement('div')
|
||||||
|
|
||||||
this.app = createApp(Flow, {
|
this.app = createApp(Form, {
|
||||||
submissionSlug: this.dataset.submissionSlug,
|
submissionSlug: this.dataset.submissionSlug,
|
||||||
authenticityToken: this.dataset.authenticityToken,
|
authenticityToken: this.dataset.authenticityToken,
|
||||||
values: reactive(JSON.parse(this.dataset.values)),
|
values: reactive(JSON.parse(this.dataset.values)),
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
@config "../../tailwind.flow.config.js";
|
@config "../../tailwind.form.config.js";
|
||||||
|
|
||||||
@import "tailwindcss/base";
|
@import "tailwindcss/base";
|
||||||
@import "tailwindcss/components";
|
@import "tailwindcss/components";
|
||||||
@@ -164,7 +164,7 @@ import CheckboxStep from './checkbox_step'
|
|||||||
import FormCompleted from './completed'
|
import FormCompleted from './completed'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'FlowForm',
|
name: 'SubmissionForm',
|
||||||
components: {
|
components: {
|
||||||
FieldAreas,
|
FieldAreas,
|
||||||
ImageStep,
|
ImageStep,
|
||||||
+23
-23
@@ -5,13 +5,13 @@
|
|||||||
>
|
>
|
||||||
<div class="flex justify-between py-1.5 items-center">
|
<div class="flex justify-between py-1.5 items-center">
|
||||||
<Contenteditable
|
<Contenteditable
|
||||||
:model-value="flow.name"
|
:model-value="template.name"
|
||||||
class="text-3xl focus:text-clip"
|
class="text-3xl focus:text-clip"
|
||||||
@update:model-value="updateName"
|
@update:model-value="updateName"
|
||||||
/>
|
/>
|
||||||
<div class="space-x-3 flex items-center">
|
<div class="space-x-3 flex items-center">
|
||||||
<a
|
<a
|
||||||
:href="`/flows/${flow.id}/submissions`"
|
:href="`/templates/${template.id}/submissions`"
|
||||||
class="btn btn-primary"
|
class="btn btn-primary"
|
||||||
>
|
>
|
||||||
<IconUsersPlus
|
<IconUsersPlus
|
||||||
@@ -40,9 +40,9 @@
|
|||||||
class="overflow-auto w-52 flex-none pr-4 mt-0.5 pt-0.5"
|
class="overflow-auto w-52 flex-none pr-4 mt-0.5 pt-0.5"
|
||||||
>
|
>
|
||||||
<DocumentPreview
|
<DocumentPreview
|
||||||
v-for="(item, index) in flow.schema"
|
v-for="(item, index) in template.schema"
|
||||||
:key="index"
|
:key="index"
|
||||||
:with-arrows="flow.schema.length > 1"
|
:with-arrows="template.schema.length > 1"
|
||||||
:item="item"
|
:item="item"
|
||||||
:document="sortedDocuments[index]"
|
:document="sortedDocuments[index]"
|
||||||
@scroll-to="scrollIntoDocument(item)"
|
@scroll-to="scrollIntoDocument(item)"
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
/>
|
/>
|
||||||
<div class="sticky bottom-0 bg-base-100 py-2">
|
<div class="sticky bottom-0 bg-base-100 py-2">
|
||||||
<Upload
|
<Upload
|
||||||
:flow-id="flow.id"
|
:template-id="template.id"
|
||||||
@success="updateFromUpload"
|
@success="updateFromUpload"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -90,7 +90,7 @@
|
|||||||
FIelds
|
FIelds
|
||||||
<Fields
|
<Fields
|
||||||
ref="fields"
|
ref="fields"
|
||||||
v-model:fields="flow.fields"
|
v-model:fields="template.fields"
|
||||||
@set-draw="drawField = $event"
|
@set-draw="drawField = $event"
|
||||||
@set-drag="dragFieldType = $event"
|
@set-drag="dragFieldType = $event"
|
||||||
@drag-end="dragFieldType = null"
|
@drag-end="dragFieldType = null"
|
||||||
@@ -110,7 +110,7 @@ import DocumentPreview from './preview'
|
|||||||
import { IconUsersPlus, IconDeviceFloppy } from '@tabler/icons-vue'
|
import { IconUsersPlus, IconDeviceFloppy } from '@tabler/icons-vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'FlowBuilder',
|
name: 'TemplateBuilder',
|
||||||
components: {
|
components: {
|
||||||
Upload,
|
Upload,
|
||||||
Document,
|
Document,
|
||||||
@@ -121,7 +121,7 @@ export default {
|
|||||||
IconDeviceFloppy
|
IconDeviceFloppy
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
flow: {
|
template: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
@@ -138,7 +138,7 @@ export default {
|
|||||||
fieldAreasIndex () {
|
fieldAreasIndex () {
|
||||||
const areas = {}
|
const areas = {}
|
||||||
|
|
||||||
this.flow.fields.forEach((f) => {
|
this.template.fields.forEach((f) => {
|
||||||
(f.areas || []).forEach((a) => {
|
(f.areas || []).forEach((a) => {
|
||||||
areas[a.attachment_uuid] ||= {}
|
areas[a.attachment_uuid] ||= {}
|
||||||
|
|
||||||
@@ -151,8 +151,8 @@ export default {
|
|||||||
return areas
|
return areas
|
||||||
},
|
},
|
||||||
sortedDocuments () {
|
sortedDocuments () {
|
||||||
return this.flow.schema.map((item) => {
|
return this.template.schema.map((item) => {
|
||||||
return this.flow.documents.find(doc => doc.uuid === item.attachment_uuid)
|
return this.template.documents.find(doc => doc.uuid === item.attachment_uuid)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -191,8 +191,8 @@ export default {
|
|||||||
this.$refs.fields.addField(this.dragFieldType, area)
|
this.$refs.fields.addField(this.dragFieldType, area)
|
||||||
},
|
},
|
||||||
updateFromUpload ({ schema, documents }) {
|
updateFromUpload ({ schema, documents }) {
|
||||||
this.flow.schema.push(...schema)
|
this.template.schema.push(...schema)
|
||||||
this.flow.documents.push(...documents)
|
this.template.documents.push(...documents)
|
||||||
|
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.$refs.previews.scrollTop = this.$refs.previews.scrollHeight
|
this.$refs.previews.scrollTop = this.$refs.previews.scrollHeight
|
||||||
@@ -203,28 +203,28 @@ export default {
|
|||||||
this.save()
|
this.save()
|
||||||
},
|
},
|
||||||
updateName (value) {
|
updateName (value) {
|
||||||
this.flow.name = value
|
this.template.name = value
|
||||||
|
|
||||||
this.save()
|
this.save()
|
||||||
},
|
},
|
||||||
onDocumentRemove (item) {
|
onDocumentRemove (item) {
|
||||||
if (window.confirm('Are you sure?')) {
|
if (window.confirm('Are you sure?')) {
|
||||||
this.flow.schema.splice(this.flow.schema.indexOf(item), 1)
|
this.template.schema.splice(this.template.schema.indexOf(item), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.save()
|
this.save()
|
||||||
},
|
},
|
||||||
moveDocument (item, direction) {
|
moveDocument (item, direction) {
|
||||||
const currentIndex = this.flow.schema.indexOf(item)
|
const currentIndex = this.template.schema.indexOf(item)
|
||||||
|
|
||||||
this.flow.schema.splice(currentIndex, 1)
|
this.template.schema.splice(currentIndex, 1)
|
||||||
|
|
||||||
if (currentIndex + direction > this.flow.schema.length) {
|
if (currentIndex + direction > this.template.schema.length) {
|
||||||
this.flow.schema.unshift(item)
|
this.template.schema.unshift(item)
|
||||||
} else if (currentIndex + direction < 0) {
|
} else if (currentIndex + direction < 0) {
|
||||||
this.flow.schema.push(item)
|
this.template.schema.push(item)
|
||||||
} else {
|
} else {
|
||||||
this.flow.schema.splice(currentIndex + direction, 0, item)
|
this.template.schema.splice(currentIndex + direction, 0, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.save()
|
this.save()
|
||||||
@@ -239,9 +239,9 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
save () {
|
save () {
|
||||||
return fetch(`/api/flows/${this.flow.id}`, {
|
return fetch(`/api/templates/${this.template.id}`, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
body: JSON.stringify({ flow: this.flow }),
|
body: JSON.stringify({ template: this.template }),
|
||||||
headers: { 'Content-Type': 'application/json' }
|
headers: { 'Content-Type': 'application/json' }
|
||||||
}).then((resp) => {
|
}).then((resp) => {
|
||||||
console.log(resp)
|
console.log(resp)
|
||||||
+1
-1
@@ -18,7 +18,7 @@
|
|||||||
import Page from './page'
|
import Page from './page'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'FlowDocument',
|
name: 'TemplateDocument',
|
||||||
components: {
|
components: {
|
||||||
Page
|
Page
|
||||||
},
|
},
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'FlowField',
|
name: 'TemplateField',
|
||||||
props: {
|
props: {
|
||||||
field: {
|
field: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@@ -49,7 +49,7 @@ import Field from './field'
|
|||||||
import { v4 } from 'uuid'
|
import { v4 } from 'uuid'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'FlowFields',
|
name: 'TemplateFields',
|
||||||
components: {
|
components: {
|
||||||
Field
|
Field
|
||||||
},
|
},
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
import FieldArea from './area'
|
import FieldArea from './area'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'FlowPage',
|
name: 'TemplatePage',
|
||||||
components: {
|
components: {
|
||||||
FieldArea
|
FieldArea
|
||||||
},
|
},
|
||||||
@@ -32,7 +32,7 @@ export default {
|
|||||||
IconUpload
|
IconUpload
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
flowId: {
|
templateId: {
|
||||||
type: [Number, String],
|
type: [Number, String],
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
@@ -76,7 +76,7 @@ export default {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
fetch(`/api/flows/${this.flowId}/documents`, {
|
fetch(`/api/templates/${this.templateId}/documents`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({ blobs }),
|
body: JSON.stringify({ blobs }),
|
||||||
headers: { 'Content-Type': 'application/json' }
|
headers: { 'Content-Type': 'application/json' }
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
class Account < ApplicationRecord
|
class Account < ApplicationRecord
|
||||||
has_many :users, dependent: :destroy
|
has_many :users, dependent: :destroy
|
||||||
has_many :encrypted_configs, dependent: :destroy
|
has_many :encrypted_configs, dependent: :destroy
|
||||||
has_many :flows, dependent: :destroy
|
has_many :templates, dependent: :destroy
|
||||||
has_many :active_users, -> { active }, dependent: :destroy,
|
has_many :active_users, -> { active }, dependent: :destroy,
|
||||||
inverse_of: :account, class_name: 'User'
|
inverse_of: :account, class_name: 'User'
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -16,20 +16,20 @@
|
|||||||
# values :string not null
|
# values :string not null
|
||||||
# created_at :datetime not null
|
# created_at :datetime not null
|
||||||
# updated_at :datetime not null
|
# updated_at :datetime not null
|
||||||
# flow_id :bigint not null
|
# template_id :bigint not null
|
||||||
#
|
#
|
||||||
# Indexes
|
# Indexes
|
||||||
#
|
#
|
||||||
# index_submissions_on_email (email)
|
# index_submissions_on_email (email)
|
||||||
# index_submissions_on_flow_id (flow_id)
|
# index_submissions_on_slug (slug) UNIQUE
|
||||||
# index_submissions_on_slug (slug) UNIQUE
|
# index_submissions_on_template_id (template_id)
|
||||||
#
|
#
|
||||||
# Foreign Keys
|
# Foreign Keys
|
||||||
#
|
#
|
||||||
# fk_rails_... (flow_id => flows.id)
|
# fk_rails_... (template_id => templates.id)
|
||||||
#
|
#
|
||||||
class Submission < ApplicationRecord
|
class Submission < ApplicationRecord
|
||||||
belongs_to :flow
|
belongs_to :template
|
||||||
|
|
||||||
attribute :values, :string, default: -> { {} }
|
attribute :values, :string, default: -> { {} }
|
||||||
attribute :slug, :string, default: -> { SecureRandom.base58(8) }
|
attribute :slug, :string, default: -> { SecureRandom.base58(8) }
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
#
|
#
|
||||||
# Table name: flows
|
# Table name: templates
|
||||||
#
|
#
|
||||||
# id :bigint not null, primary key
|
# id :bigint not null, primary key
|
||||||
# deleted_at :datetime
|
# deleted_at :datetime
|
||||||
@@ -17,16 +17,16 @@
|
|||||||
#
|
#
|
||||||
# Indexes
|
# Indexes
|
||||||
#
|
#
|
||||||
# index_flows_on_account_id (account_id)
|
# index_templates_on_account_id (account_id)
|
||||||
# index_flows_on_author_id (author_id)
|
# index_templates_on_author_id (author_id)
|
||||||
# index_flows_on_slug (slug) UNIQUE
|
# index_templates_on_slug (slug) UNIQUE
|
||||||
#
|
#
|
||||||
# Foreign Keys
|
# Foreign Keys
|
||||||
#
|
#
|
||||||
# fk_rails_... (account_id => accounts.id)
|
# fk_rails_... (account_id => accounts.id)
|
||||||
# fk_rails_... (author_id => users.id)
|
# fk_rails_... (author_id => users.id)
|
||||||
#
|
#
|
||||||
class Flow < ApplicationRecord
|
class Template < ApplicationRecord
|
||||||
belongs_to :author, class_name: 'User'
|
belongs_to :author, class_name: 'User'
|
||||||
belongs_to :account
|
belongs_to :account
|
||||||
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
<div class="max-w-6xl mx-auto px-2 py-3">
|
<div class="max-w-6xl mx-auto px-2 py-3">
|
||||||
<%= link_to 'Create Flow', new_flow_path, data: { turbo_frame: :modal } %>
|
<%= link_to 'Create Template', new_template_path, data: { turbo_frame: :modal } %>
|
||||||
<% @flows.each do |flow| %>
|
<% @templates.each do |template| %>
|
||||||
<div>
|
<div>
|
||||||
<%= flow.name %> |
|
<%= template.name %> |
|
||||||
<a href="<%= flow_path(flow) %>">edit</a> |
|
<a href="<%= template_path(template) %>">edit</a> |
|
||||||
<a href="<%= flow_submissions_path(flow) %>">submissions</a> |
|
<a href="<%= template_submissions_path(template) %>">submissions</a> |
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
<%= render 'shared/turbo_modal', title: 'New Flow' do %>
|
|
||||||
<%= form_for @flow, data: { turbo_frame: :_top } do |f| %>
|
|
||||||
<div class="form-control my-6">
|
|
||||||
<%= f.text_field :name, required: true, placeholder: 'Flow Name', class: 'base-input' %>
|
|
||||||
</div>
|
|
||||||
<div class="form-control mt-4">
|
|
||||||
<%= f.button button_title('Create'), class: 'base-button' %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
<% end %>
|
|
||||||
@@ -7,8 +7,8 @@
|
|||||||
<%= csrf_meta_tags %>
|
<%= csrf_meta_tags %>
|
||||||
<%= csp_meta_tag %>
|
<%= csp_meta_tag %>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<%= javascript_pack_tag 'flow', defer: true %>
|
<%= javascript_pack_tag 'form', defer: true %>
|
||||||
<%= stylesheet_pack_tag 'flow', media: 'all' %>
|
<%= stylesheet_pack_tag 'form', media: 'all' %>
|
||||||
<%= yield :head %>
|
<%= yield :head %>
|
||||||
</head>
|
</head>
|
||||||
<body class="font-sans antialiased font-normal leading-normal bg-white text-gray-700">
|
<body class="font-sans antialiased font-normal leading-normal bg-white text-gray-700">
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
You have been invited to submit flow <%= @flow.name %>
|
|
||||||
<%= form_for @submission, url: start_flow_path(@flow.slug), data: { turbo_frame: :_top }, method: :put do |f| %>
|
|
||||||
Provide youe email to start
|
|
||||||
<div>
|
|
||||||
<%= f.label :email %>
|
|
||||||
<%= f.email_field :email, required: true %>
|
|
||||||
</div>
|
|
||||||
<%= f.button button_title %>
|
|
||||||
<% end %>
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<p>
|
<p>
|
||||||
Form has been submitted alredy by ypu - thanks!
|
Form has been submitted alredy by ypu - thanks!
|
||||||
</p>
|
</p>
|
||||||
<%= button_to button_title('Send copy to Email'), send_submission_email_index_path, params: { flow_slug: @flow.slug, email: params[:email] }, form: { onsubmit: 'event.submitter.disabled = true' } %>
|
<%= button_to button_title('Send copy to Email'), send_submission_email_index_path, params: { template_slug: @template.slug, email: params[:email] }, form: { onsubmit: 'event.submitter.disabled = true' } %>
|
||||||
<%# do not allow donwload for securetiy reaosn<a href="">Download documets</a> %>
|
<%# do not allow donwload for securetiy reaosn<a href="">Download documets</a> %>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
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| %>
|
||||||
|
Provide youe email to start
|
||||||
|
<div>
|
||||||
|
<%= f.label :email %>
|
||||||
|
<%= f.email_field :email, required: true %>
|
||||||
|
</div>
|
||||||
|
<%= f.button button_title %>
|
||||||
|
<% end %>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<p>Hi there</p>
|
<p>Hi there</p>
|
||||||
<p>You have been invited to submit a form:</p>
|
<p>You have been invited to submit a form:</p>
|
||||||
<p><%= link_to 'Submit', submit_flow_index_url(slug: @submission.slug) %></p>
|
<p><%= link_to 'Submit', submit_form_index_url(slug: @submission.slug) %></p>
|
||||||
<p>If you didn't request this, please ignore this email.</p>
|
<p>If you didn't request this, please ignore this email.</p>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
Submissions
|
Submissions
|
||||||
Flow <%= @flow.name %>
|
template <%= @template.name %>
|
||||||
Copy share link:
|
Copy share link:
|
||||||
<input autocomplete="off" type="text" class="w-full" value="<%= start_flow_url(slug: @flow.slug) %>" disabled>
|
<input autocomplete="off" type="text" class="w-full" value="<%= start_form_url(slug: @template.slug) %>" disabled>
|
||||||
<a href="<%= new_flow_submission_path(@flow) %>" class="bg-green-600" data-turbo-frame="modal">Add Recepients</a>
|
<a href="<%= new_template_submission_path(@template) %>" class="bg-green-600" data-turbo-frame="modal">Add Recepients</a>
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>
|
||||||
@@ -32,7 +32,7 @@ Copy share link:
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
copy link<br>
|
copy link<br>
|
||||||
<%= link_to 'View', submission_path(@flow) %>
|
<%= link_to 'View', submission_path(@template) %>
|
||||||
<%= button_to 'Remove', submission_path(submission), method: :delete, data: { turbo_confirm: 'Are you sure?' } %>
|
<%= button_to 'Remove', submission_path(submission), method: :delete, data: { turbo_confirm: 'Are you sure?' } %>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<%= render 'shared/turbo_modal' do %>
|
<%= render 'shared/turbo_modal' do %>
|
||||||
<%= form_for '', url: flow_submissions_path(@flow), data: { turbo_frame: :_top } do |f| %>
|
<%= form_for '', url: template_submissions_path(@template), data: { turbo_frame: :_top } do |f| %>
|
||||||
<div>
|
<div>
|
||||||
<%= f.label :emails %>
|
<%= f.label :emails %>
|
||||||
<%= f.text_area :emails, required: true %>
|
<%= f.text_area :emails, required: true %>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
Flow: <%= @submission.flow.name %>
|
template: <%= @submission.template.name %>
|
||||||
Sub: <%= @submission.slug %>
|
Sub: <%= @submission.slug %>
|
||||||
Copy share link:
|
Copy share link:
|
||||||
<input autocomplete="off" type="text" class="w-full" value="<%= submit_flow_url(slug: @submission.slug) %>" disabled>
|
<input autocomplete="off" type="text" class="w-full" value="<%= submit_form_url(slug: @submission.slug) %>" disabled>
|
||||||
<% @submission.flow.fields.each do |field| %>
|
<% @submission.template.fields.each do |field| %>
|
||||||
<div>
|
<div>
|
||||||
<%= field['name'] %>:
|
<%= field['name'] %>:
|
||||||
<% if ['image', 'signature'].include?(field['type']) %>
|
<% if ['image', 'signature'].include?(field['type']) %>
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
<% attachment_field_uuids = @submission.flow.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) %>
|
|
||||||
<flow-view class="mx-auto block" style="max-width: 1000px">
|
|
||||||
<% @submission.flow.schema.each do |item| %>
|
|
||||||
<% document = @submission.flow.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">
|
|
||||||
<div id="page-<%= [document.uuid, index].join('-') %>" class="top-0 bottom-0 left-0 right-0 absolute"></div>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
<% end %>
|
|
||||||
<div class="sticky bottom-8 w-full">
|
|
||||||
<div class="bg-white mx-8 md:mx-32 border p-4 rounded">
|
|
||||||
<flow-form data-submission-slug="<%= @submission.slug %>" data-attachments="<%= attachments.to_json(only: %i[uuid], methods: %i[url filename content_type]) %>" data-fields="<%= @submission.flow.fields.to_json %>" data-values="<%= @submission.values.to_json %>" data-authenticity-token="<%= form_authenticity_token %>"></flow-form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</flow-view>
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<% 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) %>
|
||||||
|
<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'] } %>
|
||||||
|
<% 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">
|
||||||
|
<div id="page-<%= [document.uuid, index].join('-') %>" class="top-0 bottom-0 left-0 right-0 absolute"></div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
<% 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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<%= render 'shared/turbo_modal', title: 'New Template' do %>
|
||||||
|
<%= form_for @template, data: { turbo_frame: :_top } do |f| %>
|
||||||
|
<div class="form-control my-6">
|
||||||
|
<%= f.text_field :name, required: true, placeholder: 'Template Name', class: 'base-input' %>
|
||||||
|
</div>
|
||||||
|
<div class="form-control mt-4">
|
||||||
|
<%= f.button button_title('Create'), class: 'base-button' %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
@@ -11,6 +11,6 @@
|
|||||||
<%= stylesheet_pack_tag 'application', media: 'all' %>
|
<%= stylesheet_pack_tag 'application', media: 'all' %>
|
||||||
</head>
|
</head>
|
||||||
<body class="h-full" data>
|
<body class="h-full" data>
|
||||||
<flow-builder data-flow="<%= @flow.to_json(include: { documents: { include: { preview_images: { methods: %i[url metadata filename] } } } }) %>"></flow-builder>
|
<template-builder data-template="<%= @template.to_json(include: { documents: { include: { preview_images: { methods: %i[url metadata filename] } } } }) %>"></template-builder>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
+5
-5
@@ -21,8 +21,8 @@ Rails.application.routes.draw do
|
|||||||
|
|
||||||
namespace :api do
|
namespace :api do
|
||||||
resources :attachments, only: %i[create]
|
resources :attachments, only: %i[create]
|
||||||
resources :flows, only: %i[update] do
|
resources :templates, only: %i[update] do
|
||||||
resources :documents, only: %i[create destroy], controller: 'flows_documents'
|
resources :documents, only: %i[create destroy], controller: 'templates_documents'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -30,15 +30,15 @@ Rails.application.routes.draw do
|
|||||||
resources :setup, only: %i[index create]
|
resources :setup, only: %i[index create]
|
||||||
resources :users, only: %i[new create edit update destroy]
|
resources :users, only: %i[new create edit update destroy]
|
||||||
resources :submissions, only: %i[show destroy]
|
resources :submissions, only: %i[show destroy]
|
||||||
resources :flows, only: %i[new create show destroy] do
|
resources :templates, only: %i[new create show destroy] do
|
||||||
resources :submissions, only: %i[index new create]
|
resources :submissions, only: %i[index new create]
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :start_flow, only: %i[show update], path: 'f', param: 'slug' do
|
resources :start_form, only: %i[show update], path: 'f', param: 'slug' do
|
||||||
get :completed
|
get :completed
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :submit_flow, only: %i[show update], path: 'l', param: 'slug' do
|
resources :submit_form, only: %i[show update], path: 'l', param: 'slug' do
|
||||||
get :completed
|
get :completed
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class CreateFlows < ActiveRecord::Migration[7.0]
|
class CreateTemplates < ActiveRecord::Migration[7.0]
|
||||||
def change
|
def change
|
||||||
create_table :flows do |t|
|
create_table :templates do |t|
|
||||||
t.string :slug, null: false, index: { unique: true }
|
t.string :slug, null: false, index: { unique: true }
|
||||||
t.string :name, null: false
|
t.string :name, null: false
|
||||||
t.string :schema, null: false
|
t.string :schema, null: false
|
||||||
@@ -5,7 +5,7 @@ class CreateSubmissions < ActiveRecord::Migration[7.0]
|
|||||||
create_table :submissions do |t|
|
create_table :submissions do |t|
|
||||||
t.string :email, null: false, index: true
|
t.string :email, null: false, index: true
|
||||||
t.string :slug, null: false, index: { unique: true }
|
t.string :slug, null: false, index: { unique: true }
|
||||||
t.references :flow, null: false, foreign_key: true, index: true
|
t.references :template, null: false, foreign_key: true, index: true
|
||||||
t.string :values, null: false
|
t.string :values, null: false
|
||||||
t.string :ua
|
t.string :ua
|
||||||
t.string :ip
|
t.string :ip
|
||||||
|
|||||||
+20
-20
@@ -60,25 +60,10 @@ ActiveRecord::Schema[7.0].define(version: 2023_05_19_144036) do
|
|||||||
t.index ["account_id"], name: "index_encrypted_configs_on_account_id"
|
t.index ["account_id"], name: "index_encrypted_configs_on_account_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "flows", force: :cascade do |t|
|
|
||||||
t.string "slug", null: false
|
|
||||||
t.string "name", null: false
|
|
||||||
t.string "schema", null: false
|
|
||||||
t.string "fields", null: false
|
|
||||||
t.bigint "author_id", null: false
|
|
||||||
t.bigint "account_id", null: false
|
|
||||||
t.datetime "deleted_at"
|
|
||||||
t.datetime "created_at", null: false
|
|
||||||
t.datetime "updated_at", null: false
|
|
||||||
t.index ["account_id"], name: "index_flows_on_account_id"
|
|
||||||
t.index ["author_id"], name: "index_flows_on_author_id"
|
|
||||||
t.index ["slug"], name: "index_flows_on_slug", unique: true
|
|
||||||
end
|
|
||||||
|
|
||||||
create_table "submissions", force: :cascade do |t|
|
create_table "submissions", force: :cascade do |t|
|
||||||
t.string "email", null: false
|
t.string "email", null: false
|
||||||
t.string "slug", null: false
|
t.string "slug", null: false
|
||||||
t.bigint "flow_id", null: false
|
t.bigint "template_id", null: false
|
||||||
t.string "values", null: false
|
t.string "values", null: false
|
||||||
t.string "ua"
|
t.string "ua"
|
||||||
t.string "ip"
|
t.string "ip"
|
||||||
@@ -89,8 +74,23 @@ ActiveRecord::Schema[7.0].define(version: 2023_05_19_144036) do
|
|||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
t.index ["email"], name: "index_submissions_on_email"
|
t.index ["email"], name: "index_submissions_on_email"
|
||||||
t.index ["flow_id"], name: "index_submissions_on_flow_id"
|
|
||||||
t.index ["slug"], name: "index_submissions_on_slug", unique: true
|
t.index ["slug"], name: "index_submissions_on_slug", unique: true
|
||||||
|
t.index ["template_id"], name: "index_submissions_on_template_id"
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "templates", force: :cascade do |t|
|
||||||
|
t.string "slug", null: false
|
||||||
|
t.string "name", null: false
|
||||||
|
t.string "schema", null: false
|
||||||
|
t.string "fields", null: false
|
||||||
|
t.bigint "author_id", null: false
|
||||||
|
t.bigint "account_id", null: false
|
||||||
|
t.datetime "deleted_at"
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
t.index ["account_id"], name: "index_templates_on_account_id"
|
||||||
|
t.index ["author_id"], name: "index_templates_on_author_id"
|
||||||
|
t.index ["slug"], name: "index_templates_on_slug", unique: true
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "users", force: :cascade do |t|
|
create_table "users", force: :cascade do |t|
|
||||||
@@ -123,8 +123,8 @@ ActiveRecord::Schema[7.0].define(version: 2023_05_19_144036) do
|
|||||||
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
|
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
|
||||||
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
|
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
|
||||||
add_foreign_key "encrypted_configs", "accounts"
|
add_foreign_key "encrypted_configs", "accounts"
|
||||||
add_foreign_key "flows", "accounts"
|
add_foreign_key "submissions", "templates"
|
||||||
add_foreign_key "flows", "users", column: "author_id"
|
add_foreign_key "templates", "accounts"
|
||||||
add_foreign_key "submissions", "flows"
|
add_foreign_key "templates", "users", column: "author_id"
|
||||||
add_foreign_key "users", "accounts"
|
add_foreign_key "users", "accounts"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Flows
|
|
||||||
module_function
|
|
||||||
|
|
||||||
def build_field_areas_index(flow)
|
|
||||||
hash = {}
|
|
||||||
|
|
||||||
flow.fields.each do |field|
|
|
||||||
(field['areas'] || []).each do |area|
|
|
||||||
hash[area['attachment_uuid']] ||= {}
|
|
||||||
acc = (hash[area['attachment_uuid']][area['page']] ||= [])
|
|
||||||
|
|
||||||
acc << { area:, field: }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
hash
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -9,18 +9,18 @@ module Submissions
|
|||||||
|
|
||||||
# rubocop:disable Metrics
|
# rubocop:disable Metrics
|
||||||
def call(submission)
|
def call(submission)
|
||||||
cert = submission.flow.account.encrypted_configs
|
cert = submission.template.account.encrypted_configs
|
||||||
.find_by(key: EncryptedConfig::ESIGN_CERTS_KEY).value
|
.find_by(key: EncryptedConfig::ESIGN_CERTS_KEY).value
|
||||||
|
|
||||||
zip_file = Tempfile.new
|
zip_file = Tempfile.new
|
||||||
zip_stream = Zip::ZipOutputStream.open(zip_file)
|
zip_stream = Zip::ZipOutputStream.open(zip_file)
|
||||||
|
|
||||||
pdfs_index =
|
pdfs_index =
|
||||||
submission.flow.documents.to_h do |attachment|
|
submission.template.documents.to_h do |attachment|
|
||||||
[attachment.uuid, HexaPDF::Document.new(io: StringIO.new(attachment.download))]
|
[attachment.uuid, HexaPDF::Document.new(io: StringIO.new(attachment.download))]
|
||||||
end
|
end
|
||||||
|
|
||||||
submission.flow.fields.each do |field|
|
submission.template.fields.each do |field|
|
||||||
field.fetch('areas', []).each do |area|
|
field.fetch('areas', []).each do |area|
|
||||||
pdf = pdfs_index[area['attachment_uuid']]
|
pdf = pdfs_index[area['attachment_uuid']]
|
||||||
|
|
||||||
@@ -96,29 +96,29 @@ module Submissions
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
submission.flow.schema.map do |item|
|
submission.template.schema.map do |item|
|
||||||
document = submission.flow.documents.find { |a| a.uuid == item['attachment_uuid'] }
|
document = submission.template.documents.find { |a| a.uuid == item['attachment_uuid'] }
|
||||||
|
|
||||||
io = StringIO.new
|
io = StringIO.new
|
||||||
|
|
||||||
zip_stream.put_next_entry("#{item['name']}.pdf")
|
|
||||||
zip_stream.write(io.string)
|
|
||||||
|
|
||||||
pdf = pdfs_index[item['attachment_uuid']]
|
pdf = pdfs_index[item['attachment_uuid']]
|
||||||
|
|
||||||
pdf.sign(io, reason: "Signed by #{submission.email}",
|
pdf.sign(io, reason: "Signed by #{submission.email}",
|
||||||
doc_mdp_permissions: :no_changes,
|
# doc_mdp_permissions: :no_changes,
|
||||||
certificate: OpenSSL::X509::Certificate.new(cert['cert']),
|
certificate: OpenSSL::X509::Certificate.new(cert['cert']),
|
||||||
key: OpenSSL::PKey::RSA.new(cert['key']),
|
key: OpenSSL::PKey::RSA.new(cert['key']),
|
||||||
certificate_chain: [OpenSSL::X509::Certificate.new(cert['sub_ca']),
|
certificate_chain: [OpenSSL::X509::Certificate.new(cert['sub_ca']),
|
||||||
OpenSSL::X509::Certificate.new(cert['root_ca'])])
|
OpenSSL::X509::Certificate.new(cert['root_ca'])])
|
||||||
|
|
||||||
|
zip_stream.put_next_entry("#{item['name']}.pdf")
|
||||||
|
zip_stream.write(io.string)
|
||||||
|
|
||||||
submission.documents.attach(io: StringIO.new(io.string), filename: document.filename)
|
submission.documents.attach(io: StringIO.new(io.string), filename: document.filename)
|
||||||
end
|
end
|
||||||
|
|
||||||
zip_stream.close
|
zip_stream.close
|
||||||
|
|
||||||
submission.archive.attach(io: zip_file, filename: "#{submission.flow.name}.zip")
|
submission.archive.attach(io: zip_file, filename: "#{submission.template.name}.zip")
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics
|
# rubocop:enable Metrics
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Templates
|
||||||
|
end
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Flows
|
module Templates
|
||||||
module ProcessDocument
|
module ProcessDocument
|
||||||
DPI = 200
|
DPI = 200
|
||||||
FORMAT = '.jpg'
|
FORMAT = '.jpg'
|
||||||
@@ -3,9 +3,9 @@ const baseConfigs = require('./tailwind.config.js')
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
...baseConfigs,
|
...baseConfigs,
|
||||||
content: [
|
content: [
|
||||||
'./app/javascript/flow_form/**/*.vue',
|
'./app/javascript/submission_form/**/*.vue',
|
||||||
'./app/views/submit_flow/**/*.erb',
|
'./app/views/submit_form/**/*.erb',
|
||||||
'./app/views/start_flow/**/*.erb',
|
'./app/views/start_form/**/*.erb',
|
||||||
'./app/views/send_submission_copy/**/*.erb'
|
'./app/views/send_submission_copy/**/*.erb'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user