diff --git a/app/controllers/api/templates_documents_controller.rb b/app/controllers/api/templates_documents_controller.rb index 04fdb12c..908b899d 100644 --- a/app/controllers/api/templates_documents_controller.rb +++ b/app/controllers/api/templates_documents_controller.rb @@ -22,6 +22,8 @@ module Api } ) } + rescue Templates::CreateAttachments::PdfEncrypted + render json: { error: 'PDF encrypted' }, status: :unprocessable_entity end end end diff --git a/app/controllers/templates_uploads_controller.rb b/app/controllers/templates_uploads_controller.rb index 8823eeac..acb2ed38 100644 --- a/app/controllers/templates_uploads_controller.rb +++ b/app/controllers/templates_uploads_controller.rb @@ -10,12 +10,7 @@ class TemplatesUploadsController < ApplicationController def create url_params = create_file_params_from_url if params[:url].present? - @template.account = current_account - @template.author = current_user - @template.folder = TemplateFolders.find_or_create_by_name(current_user, params[:folder_name]) - @template.name = File.basename((url_params || params)[:files].first.original_filename, '.*') - - @template.save! + save_template!(@template, url_params) documents = Templates::CreateAttachments.call(@template, url_params || params) @@ -24,6 +19,8 @@ class TemplatesUploadsController < ApplicationController @template.update!(schema:) redirect_to edit_template_path(@template) + rescue Templates::CreateAttachments::PdfEncrypted + render turbo_stream: turbo_stream.append(params[:form_id], html: helpers.tag.prompt_password) rescue StandardError => e Rollbar.error(e) if defined?(Rollbar) @@ -32,6 +29,17 @@ class TemplatesUploadsController < ApplicationController private + def save_template!(template, url_params) + template.account = current_account + template.author = current_user + template.folder = TemplateFolders.find_or_create_by_name(current_user, params[:folder_name]) + template.name = File.basename((url_params || params)[:files].first.original_filename, '.*') + + template.save! + + template + end + def create_file_params_from_url tempfile = Tempfile.new tempfile.binmode diff --git a/app/javascript/application.js b/app/javascript/application.js index c20f0718..9c23a4cf 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -19,6 +19,7 @@ import SubmittersAutocomplete from './elements/submitter_autocomplete' import FolderAutocomplete from './elements/folder_autocomplete' import SignatureForm from './elements/signature_form' import SubmitForm from './elements/submit_form' +import PromptPassword from './elements/prompt_password' import * as TurboInstantClick from './lib/turbo_instant_click' @@ -51,6 +52,7 @@ window.customElements.define('submitters-autocomplete', SubmittersAutocomplete) window.customElements.define('folder-autocomplete', FolderAutocomplete) window.customElements.define('signature-form', SignatureForm) window.customElements.define('submit-form', SubmitForm) +window.customElements.define('prompt-password', PromptPassword) document.addEventListener('turbo:before-fetch-request', encodeMethodIntoRequestBody) document.addEventListener('turbo:submit-end', async (event) => { diff --git a/app/javascript/elements/prompt_password.js b/app/javascript/elements/prompt_password.js new file mode 100644 index 00000000..48561962 --- /dev/null +++ b/app/javascript/elements/prompt_password.js @@ -0,0 +1,19 @@ +export default class extends HTMLElement { + connectedCallback () { + const input = document.createElement('input') + + input.type = 'hidden' + input.name = 'password' + input.value = prompt('Enter PDF password') + + this.form.append(input) + + this.form.requestSubmit() + + this.remove() + } + + get form () { + return this.closest('form') + } +} diff --git a/app/javascript/template_builder/upload.vue b/app/javascript/template_builder/upload.vue index b0293b6c..49da7762 100644 --- a/app/javascript/template_builder/upload.vue +++ b/app/javascript/template_builder/upload.vue @@ -123,9 +123,30 @@ export default { method: 'POST', body: JSON.stringify({ blobs }), headers: { 'Content-Type': 'application/json' } - }).then(resp => resp.json()).then((data) => { - this.$emit('success', data) - this.$refs.input.value = '' + }).then((resp) => { + if (resp.ok) { + resp.json().then((data) => { + this.$emit('success', data) + this.$refs.input.value = '' + }) + } else if (resp.status === 422) { + resp.json().then((data) => { + if (data.error === 'PDF encrypted') { + this.baseFetch(`/api/templates/${this.templateId}/documents`, { + method: 'POST', + body: JSON.stringify({ blobs, password: prompt('Enter PDF password') }), + headers: { 'Content-Type': 'application/json' } + }).then(async (resp) => { + if (resp.ok) { + this.$emit('success', await resp.json()) + this.$refs.input.value = '' + } else { + alert('Wrong password') + } + }) + } + }) + } }).finally(() => { this.isProcessing = false }) @@ -133,9 +154,33 @@ export default { this.baseFetch(`/api/templates/${this.templateId}/documents`, { method: 'POST', body: new FormData(this.$refs.form) - }).then(resp => resp.json()).then((data) => { - this.$emit('success', data) - this.$refs.input.value = '' + }).then((resp) => { + if (resp.ok) { + resp.json().then((data) => { + this.$emit('success', data) + this.$refs.input.value = '' + }) + } else if (resp.status === 422) { + resp.json().then((data) => { + if (data.error === 'PDF encrypted') { + const formData = new FormData(this.$refs.form) + + formData.append('password', prompt('Enter PDF password')) + + this.baseFetch(`/api/templates/${this.templateId}/documents`, { + method: 'POST', + body: formData + }).then(async (resp) => { + if (resp.ok) { + this.$emit('success', await resp.json()) + this.$refs.input.value = '' + } else { + alert('Wrong password') + } + }) + } + }) + } }).finally(() => { this.isLoading = false }) diff --git a/app/views/dashboard/index.html.erb b/app/views/dashboard/index.html.erb index 5dfbe091..9f1bde62 100644 --- a/app/views/dashboard/index.html.erb +++ b/app/views/dashboard/index.html.erb @@ -33,7 +33,8 @@ <% end %> <% if params[:q].blank? && @pagy.pages == 1 && ((@template_folders.size < 10 && @templates.size.zero?) || (@template_folders.size < 7 && @templates.size < 4) || (@template_folders.size < 4 && @templates.size < 7)) %> - <%= form_for '', url: templates_upload_path, method: :post, class: 'mt-8 block', html: { enctype: 'multipart/form-data' } do %> + <%= form_for '', url: templates_upload_path, id: form_id = SecureRandom.uuid, method: :post, class: 'mt-8 block', html: { enctype: 'multipart/form-data' } do %> +