diff --git a/Gemfile b/Gemfile index 661419ff..16d1261f 100644 --- a/Gemfile +++ b/Gemfile @@ -109,4 +109,7 @@ end gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] gem 'hirb' +# signing verification +gem 'pdf-reader' + gem "rails-controller-testing", "~> 1.0" diff --git a/Gemfile.lock b/Gemfile.lock index b98bce40..577ecff1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,6 +1,7 @@ GEM remote: https://rubygems.org/ specs: + Ascii85 (1.1.0) actioncable (6.1.7.3) actionpack (= 6.1.7.3) activesupport (= 6.1.7.3) @@ -62,6 +63,7 @@ GEM zeitwerk (~> 2.3) addressable (2.8.5) public_suffix (>= 2.0.2, < 6.0) + afm (0.2.2) aws-eventstream (1.2.0) aws-partitions (1.734.0) aws-record (2.10.1) @@ -164,6 +166,7 @@ GEM activerecord (>= 4.0.0) globalid (1.1.0) activesupport (>= 5.0) + hashery (2.1.2) hashie (5.0.0) hirb (0.7.3) htmlentities (4.3.4) @@ -270,6 +273,12 @@ GEM omniauth-rails_csrf_protection (1.0.1) actionpack (>= 4.2) omniauth (~> 2.0) + pdf-reader (2.11.0) + Ascii85 (~> 1.0) + afm (~> 0.2.1) + hashery (~> 2.0) + ruby-rc4 + ttfunk pg (1.4.6) pg_search (2.3.6) activerecord (>= 5.2) @@ -366,6 +375,7 @@ GEM rspec-support (3.12.0) rspec_junit_formatter (0.6.0) rspec-core (>= 2, < 4, != 2.12.0) + ruby-rc4 (0.1.5) ruby2_keywords (0.0.5) rubyzip (2.3.2) sass-rails (6.0.0) @@ -418,6 +428,7 @@ GEM thor (1.2.1) tilt (2.1.0) timeout (0.3.2) + ttfunk (1.7.0) turbolinks (5.2.1) turbolinks-source (~> 5.2) turbolinks-source (5.2.0) @@ -486,6 +497,7 @@ DEPENDENCIES omniauth omniauth-google-oauth2 omniauth-rails_csrf_protection + pdf-reader pg pg_search premailer-rails diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index fba004e1..2cf362c0 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -14,6 +14,7 @@ *= require static *= require navody-frontend-fixes *= require or-sr + *= require spinner *= require_self */ diff --git a/app/assets/stylesheets/or-sr.scss b/app/assets/stylesheets/or-sr.scss index c78c17fa..4c458190 100644 --- a/app/assets/stylesheets/or-sr.scss +++ b/app/assets/stylesheets/or-sr.scss @@ -83,28 +83,6 @@ div#or-sr-identifiers, div#acts-submission { min-height: 40px; } - @keyframes spinner { - to {transform: rotate(360deg);} - } - - .spinner { - position: absolute; - top: 25%; - left: 50%; - } - - .spinner:before { - content: ''; - box-sizing: border-box; - position: absolute; - width: 20px; - height: 20px; - border-radius: 50%; - border: 2px solid #ccc; - border-top-color: #000; - animation: spinner .6s linear infinite; - } - #identifiers-sr input, #identifiers-foreign input { width: 100%; diff --git a/app/assets/stylesheets/spinner.scss b/app/assets/stylesheets/spinner.scss new file mode 100644 index 00000000..a3b1ab68 --- /dev/null +++ b/app/assets/stylesheets/spinner.scss @@ -0,0 +1,26 @@ +@keyframes spinner { + to {transform: rotate(360deg);} +} + +.spinner { + position: absolute; + top: 25%; + left: 50%; +} + +.spinner:before { + content: ''; + box-sizing: border-box; + position: absolute; + width: 20px; + height: 20px; + border-radius: 50%; + border: 2px solid #ccc; + border-top-color: #000; + animation: spinner .6s linear infinite; +} + +.spinner.spinner-lg:before { + width: 60px; + height: 60px; +} diff --git a/app/controllers/apps/acts_or_sr_app/acts_submissions_controller.rb b/app/controllers/apps/acts_or_sr_app/acts_submissions_controller.rb index 9f0afaf2..332170e7 100644 --- a/app/controllers/apps/acts_or_sr_app/acts_submissions_controller.rb +++ b/app/controllers/apps/acts_or_sr_app/acts_submissions_controller.rb @@ -85,8 +85,7 @@ def form_check # generates XML to be submitted def create - xml_form = UpvsSubmissions::FormBuilders::ApplicationForDocumentCopyFormBuilder.build_form(@application_form) - render xml: xml_form.to_xml + render json: { id: UpvsSubmissions::Forms::ApplicationForDocumentCopy.create_form_attachment(@application_form) }.to_json end def callback diff --git a/app/controllers/apps/general_agenda_app/general_agenda_controller.rb b/app/controllers/apps/general_agenda_app/general_agenda_controller.rb new file mode 100644 index 00000000..18d95cb5 --- /dev/null +++ b/app/controllers/apps/general_agenda_app/general_agenda_controller.rb @@ -0,0 +1,55 @@ +module Apps + module GeneralAgendaApp + class GeneralAgendaController < ApplicationController + skip_forgery_protection only: [:index] + + def index + # Configuration of the form - as API + attributes = { + title: params[:title].presence || 'Všeobecná agenda', + description: params[:description].presence || 'Formulár pre odoslanie podania pre všeobecnú agendu', + subject: params[:subject_placeholder], + text: params[:text_placeholder], + signed_required: params[:signed_required], + attachments_template: params[:attachments_template], + }.with_indifferent_access + + # Appending whatever user submitted into recipient, subject, text and attachments + # + remembers the form configuration between submits + attributes.merge!(general_agenda_params || {}) + + @application_form = Apps::GeneralAgendaApp::GeneralAgenda::ApplicationForm.new(attributes) + + return render :invalid_template unless @application_form.valid_template? + + redirect_to_upvs_submission if @application_form.is_submitted && @application_form.valid? + end + + def callback + end + + private + + def redirect_to_upvs_submission + @submission_form = UpvsSubmissions::Forms::GeneralAgenda.new(@application_form) + + render :redirect_to_upvs_submission + end + + def general_agenda_params + params[:apps_general_agenda_app_general_agenda_application_form]&.permit( + :title, + :description, + :subject, + :text, + :signed_required, + :recipient_name, + :recipient_uri, + :is_submitted, + attachments: {}, + attachments_template: [:name, :description, :required, :signed_required] + ) + end + end + end +end diff --git a/app/controllers/datahub/upvs/public_authority_edesks_controller.rb b/app/controllers/datahub/upvs/public_authority_edesks_controller.rb index fcf56499..3ab11c89 100644 --- a/app/controllers/datahub/upvs/public_authority_edesks_controller.rb +++ b/app/controllers/datahub/upvs/public_authority_edesks_controller.rb @@ -1,8 +1,9 @@ -module Datahub::Upvs - class PublicAuthorityEdesksController < ApplicationController - - def search - render json: PublicAuthorityEdesk.search(params[:q]) +module Datahub + module Upvs + class PublicAuthorityEdesksController < ApplicationController + def search + render json: PublicAuthorityEdesk.search(params[:q]) + end end end end diff --git a/app/controllers/datahub/upvs/services_with_forms_controller.rb b/app/controllers/datahub/upvs/services_with_forms_controller.rb new file mode 100644 index 00000000..7b02b94f --- /dev/null +++ b/app/controllers/datahub/upvs/services_with_forms_controller.rb @@ -0,0 +1,26 @@ +module Datahub + module Upvs + class ServicesWithFormsController < ApplicationController + def search_recipient + result = if testing? + # Datahub::Upvs::ServicesWithForms.search(params[:q]) + [{ name: 'Testing - ico://sk/83369507', uri: 'ico://sk/83369507' }] + else + Datahub::Upvs::ServicesWithForms.search(params[:q]) + end + render json: { result: result } + end + + private + + # Testing is determined based on the content of 'SLOVENSKO_SK_API_URL' which looks like e.g.: + # - https://localhost:4000 + # - https://fix.slovensko-sk-api.staging.slovensko.digital + # + # If you need to see production list of recipients, change the `SLOVENSKO_SK_API_URL` ENV to something else + def testing? + ['staging.', 'localhost'].any? { |e| ENV['SLOVENSKO_SK_API_URL'].to_s.include?(e) } + end + end + end +end diff --git a/app/controllers/upvs/submissions_controller.rb b/app/controllers/upvs/submissions_controller.rb index af6b9232..2dce0219 100644 --- a/app/controllers/upvs/submissions_controller.rb +++ b/app/controllers/upvs/submissions_controller.rb @@ -3,7 +3,8 @@ class Upvs::SubmissionsController < ApplicationController before_action :set_metadata before_action :build_upvs_submission, only: :create - before_action :load_upvs_submission, only: [:show, :submit, :finish] + before_action :load_upvs_submission, only: [:show, :submit, :finish, :signing_data, :update_blob_after_signature] + before_action :load_blob, only: [:signing_data, :update_blob_after_signature] rescue_from Upvs::Submission::SkApiError, :with => :handle_error @@ -52,8 +53,54 @@ def finish def submission_error end + def signing_data + response = { + file_name: @blob.filename, + mime_type: @blob.content_type, + content: Base64.strict_encode64(@blob.download) + } + + # This mime type is set in `UpvsSubmissions::Forms::GeneralAgenda#create_form_attachment` + if @blob.content_type == 'application/x-eform-xml' + form_template = Upvs::FormTemplateRelatedDocument.find_by!(message_type: 'App.GeneralAgenda') + + response.merge!({ + identifier: form_template.identifier, + container_xmlns: 'http://data.gov.sk/def/container/xmldatacontainer+xml/1.1', + schema: Base64.strict_encode64(form_template.xsd_schema), + transformation: Base64.strict_encode64(form_template.xslt_transformation) + }) + end + + render json: response + end + + def update_blob_after_signature + render_partial = params[:render_partial].in?(['signed_badge', 'blob_row_content']) ? params[:render_partial] : 'signed_badge' + new_blob = ActiveStorage::Blob.create_and_upload!( + io: StringIO.new(Base64.decode64(params[:content])), + filename: params[:name], + content_type: params[:mimetype], + metadata: { signed: true, signed_required: @blob.metadata[:signed_required] }.compact + ) + + @blob.signed_blob.attach(new_blob) # 'signed_blob' is defined in `config/initializers/active_storage.rb` + + render json: { + success: true, + old_blob_id: @blob.id, + html: render_to_string(partial: "upvs/submissions/#{render_partial}", locals: { blob: @blob }) + } + rescue StandardError, ScriptError => e + render json: { success: false, error: "Nastala chyba pri podpisovaní. [#{e.class}]: #{e.message}" } + end + private + def load_blob + @blob = ActiveStorage::Blob.find_signed!(params[:signed_blob_id]) # This is only 'hashed blob ID', not signed blob object nor file + end + def load_upvs_submission @upvs_submission = current_user.find_upvs_submission!(params[:id] || params[:submission_id]) end @@ -87,9 +134,10 @@ def submission_params :sender_business_reference, :recipient_business_reference, :message_subject, - :form, + :form_blob_id, :attachments, - :callback_url + :callback_url, + attachments_ids: [] ).except(:authenticity_token) end diff --git a/app/helpers/app_form_builder.rb b/app/helpers/app_form_builder.rb index 375d57da..9b5eaf83 100644 --- a/app/helpers/app_form_builder.rb +++ b/app/helpers/app_form_builder.rb @@ -30,6 +30,36 @@ def text_field(method, options = {}) end end + def text_area(method, options = {}) + group_classes = ['govuk-form-group'] + field_classes = ['govuk-textarea', options[:class]] + described_by = [] + + label = options.delete(:label) + label = label(method, label, class: 'govuk-label') if label + + hint = options.delete(:hint) + if hint + hint = @template.content_tag(:span, hint, id: hint_id(method), class: 'govuk-hint') + described_by << hint_id(method) + end + + if @object.errors[method].present? + group_classes << 'govuk-form-group--error' + field_classes << 'govuk-input--error' + described_by << error_id(method) + end + + options = options.merge({'aria-describedby': described_by.join(' ')}) unless described_by.empty? + + @template.content_tag(:div, class: group_classes) do + @template.concat label + @template.concat hint + @template.concat error_message(method) + @template.concat super(method, objectify_options(options.merge({class: field_classes}))) + end + end + def select(method, values, options = {}, html_options = {}, &block) group_classes = ['govuk-form-group'] field_classes = ['govuk-select', html_options[:class]] diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 76d78d9e..022e948c 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -18,4 +18,10 @@ def sanitize_description(description, length: 500) def dont_show_small_search_bar? current_page?(root_path) || current_page?(search_path) end + + def localize_boolean(value) + value.to_s.in?(['1', 'true']) ? 'Áno' : 'Nie' + end + + alias :lb :localize_boolean end diff --git a/app/jobs/remove_stale_blobs_job.rb b/app/jobs/remove_stale_blobs_job.rb new file mode 100644 index 00000000..568771bd --- /dev/null +++ b/app/jobs/remove_stale_blobs_job.rb @@ -0,0 +1,11 @@ +class RemoveStaleBlobs < ApplicationJob + queue_as :default + + # TODO: Setup this as a cron job and run once a week + def perform + # In `GeneralAgenda` user can upload a file which creates an `ActiveStorage::Blob` + # if this form is not converted into `Uvps::Submission`, the file remains uploaded, but not attached anywhere + # These files should be regularly purged + ActiveStorage::Blob.unattached.where('created_at < ?', 3.days.ago).each(&:purge_later) + end +end diff --git a/app/lib/analyzers/signed_pdf_analyzer.rb b/app/lib/analyzers/signed_pdf_analyzer.rb new file mode 100644 index 00000000..8693ce88 --- /dev/null +++ b/app/lib/analyzers/signed_pdf_analyzer.rb @@ -0,0 +1,21 @@ +module Analyzers + class SignedPdfAnalyzer < ActiveStorage::Analyzer + def self.accept?(blob) + ['application/pdf'].include? blob.content_type + end + + def metadata + { is_signed: is_signed? } + end + + def is_signed? + begin + reader = PDF::Reader.new(blob.download) + rescue StandardError + return false # NOTE: if pdf reading fails it is not signed + end + + reader.objects.to_a.flatten.select { |o| o.is_a?(Hash) }.select { |o| o[:Type] == :Sig }.first.present? + end + end +end diff --git a/app/lib/analyzers/signed_x_analyzer.rb b/app/lib/analyzers/signed_x_analyzer.rb new file mode 100644 index 00000000..d70647c5 --- /dev/null +++ b/app/lib/analyzers/signed_x_analyzer.rb @@ -0,0 +1,15 @@ +module Analyzers + class SignedXAnalyzer < ActiveStorage::Analyzer + def self.accept?(blob) + ['application/vnd.etsi.asic-e+zip'].include? blob.content_type + end + + def metadata + { is_signed: is_signed? } + end + + def is_signed? + true # NOTE: this content type is always signed + end + end +end diff --git a/app/lib/upvs_submissions/form_builders/general_agenda_form_builder.rb b/app/lib/upvs_submissions/form_builders/general_agenda_form_builder.rb new file mode 100644 index 00000000..1675ac76 --- /dev/null +++ b/app/lib/upvs_submissions/form_builders/general_agenda_form_builder.rb @@ -0,0 +1,17 @@ +module UpvsSubmissions + module FormBuilders + class GeneralAgendaFormBuilder + def self.build_form(form) + xml_form = Nokogiri::XML::Builder.new do |doc| + doc.GeneralAgenda('xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', + 'xmlns' => 'http://schemas.gov.sk/form/App.GeneralAgenda/1.9') do + doc.subject form.subject + doc.text_ form.text + end + end + + xml_form.doc.root + end + end + end +end diff --git a/app/lib/upvs_submissions/forms/application_for_document_copy.rb b/app/lib/upvs_submissions/forms/application_for_document_copy.rb index 7843c671..9f680274 100644 --- a/app/lib/upvs_submissions/forms/application_for_document_copy.rb +++ b/app/lib/upvs_submissions/forms/application_for_document_copy.rb @@ -3,7 +3,7 @@ module Forms class ApplicationForDocumentCopy include ActiveModel::Model - attr_accessor :sender_uri, :recipient_uri, :sender_business_reference, :recipient_business_reference, :form, :attachments + attr_accessor :sender_uri, :recipient_uri, :sender_business_reference, :recipient_business_reference, :form_blob_id, :attachments class << self delegate :uuid, to: SecureRandom @@ -14,10 +14,22 @@ def initialize(recipient_uri: nil, sender_uri: nil, sender_business_reference: n @recipient_uri = recipient_uri || default_recipient_uri @sender_business_reference = sender_business_reference @recipient_business_reference = recipient_business_reference - @form = form_params ? build_form(form_params) : nil @attachments = [] end + def self.create_form_attachment(application_form) + document_xml = UpvsSubmissions::FormBuilders::ApplicationForDocumentCopyFormBuilder.build_form(application_form) + + blob = ActiveStorage::Blob.create_and_upload!( + io: StringIO.new(document_xml.to_xml), + filename: 'Dokument.xml', # This is how the XML is called in slovensko.sk + content_type: 'application/x-eform-xml', # Mandatory content type for the Autogram and UPVS app. See `Upvs::SubmissionsController#signing_data` + metadata: { signed_required: false } + ) + + blob.id + end + def posp_id "00166073.MSSR_ORSR_Poziadanie_o_vyhotovenie_kopie_listiny_ulozenej_v_zbierke_listin.sk" end diff --git a/app/lib/upvs_submissions/forms/general_agenda.rb b/app/lib/upvs_submissions/forms/general_agenda.rb new file mode 100644 index 00000000..4d4e858d --- /dev/null +++ b/app/lib/upvs_submissions/forms/general_agenda.rb @@ -0,0 +1,66 @@ +module UpvsSubmissions + module Forms + class GeneralAgenda + include ActiveModel::Model + + attr_accessor :application_form, :form_blob_id, :attachments + + delegate :recipient_uri, to: :application_form + + class << self + delegate :uuid, to: SecureRandom + end + + def initialize(application_form) + @application_form = application_form + @form_blob_id = create_form_attachment + @attachments = [] + end + + def posp_id + "App.GeneralAgenda" + end + + def posp_version + "1.9" + end + + def message_type + "App.GeneralAgenda" + end + + def message_subject + "Všeobecná agenda" + end + + def message_id + @message_id ||= uuid + end + + def correlation_id + @correlation_id ||= uuid + end + + def attachments_blob_ids + application_form.attachments.to_h.values.map(&:to_i) + end + + private + + def create_form_attachment + document_xml = UpvsSubmissions::FormBuilders::GeneralAgendaFormBuilder.build_form(application_form) + + blob = ActiveStorage::Blob.create_and_upload!( + io: StringIO.new(document_xml.to_xml), + filename: 'Dokument.xml', # This is how the XML is called in slovensko.sk + content_type: 'application/x-eform-xml', # Mandatory content type for the Autogram and UPVS app. See `Upvs::SubmissionsController#signing_data` + metadata: { signed_required: application_form.signed_required? } + ) + + blob.id + end + + delegate :uuid, to: self + end + end +end diff --git a/app/lib/upvs_submissions/sktalk_message_builder.rb b/app/lib/upvs_submissions/sktalk_message_builder.rb index 5e766f07..9bed139a 100644 --- a/app/lib/upvs_submissions/sktalk_message_builder.rb +++ b/app/lib/upvs_submissions/sktalk_message_builder.rb @@ -5,7 +5,6 @@ class << self XML_ENTITIES = HTMLEntities.new(:expanded) - # TODO add #{build_attachment_objects(egov_application.attachments)} when attachments added to upvs_submission def build_sktalk_message(egov_application, eid_token) <<~SKTALK @@ -27,7 +26,7 @@ def build_sktalk_message(egov_application, eid_token) #{egov_application.recipient_uri} #{egov_application.message_type} #{sanitize(egov_application.message_subject)} - #{build_business_references(egov_application) if references_present?(egov_application)}#{build_form_object(egov_application.form)} + #{build_business_references(egov_application) if references_present?(egov_application)}#{build_form_object(egov_application.form)}#{build_attachment_objects(egov_application.attachments)} @@ -47,16 +46,16 @@ def build_business_references(egov_application) end def build_form_object(form) - build_object(content: format_xml_form(form), object_class: 'FORM') + build_object(name: form.blob.filename.to_s, signed: form.signed?, mime_type: form.blob.content_type, content: format_xml_form(form.blob_for_upvs.download), object_class: 'FORM') end def build_attachment_objects(attachments = []) separator = "\n " - (separator + attachments.map { |attachment| build_object(attachment) }.join(separator)) if attachments.present? + (separator + attachments.map { |attachment| build_object(name: attachment.blob.filename.to_s, signed: attachment.signed?, mime_type: attachment.blob.content_type, content: attachment.blob_for_upvs.download) }.join(separator)) if attachments.present? end - def build_object(id: uuid, name: 'Formulár.xml', description: nil, signed: false, mime_type: 'application/x-eform-xml', encoding: 'XML', content: nil, object_class: 'ATTACHMENT') - %Q{#{content}} + def build_object(id: uuid, name: 'Dokument.xml', description: nil, signed: false, mime_type: 'application/x-eform-xml', encoding: 'Base64', content: nil, object_class: 'ATTACHMENT') + %Q{#{Base64.strict_encode64(content)}} end def format_xml_form(form) diff --git a/app/models/anonymous_user.rb b/app/models/anonymous_user.rb index 1bfebe42..e17c8c0f 100644 --- a/app/models/anonymous_user.rb +++ b/app/models/anonymous_user.rb @@ -27,7 +27,9 @@ def find_submission!(uuid) end def build_upvs_submission(params, callback_step:) - upvs_submission = Upvs::Submission.new(params) + upvs_submission = Upvs::Submission.new(params.except(:form_blob_id, :attachments_ids)) + upvs_submission.form.attach(ActiveStorage::Blob.find_by(id: params[:form_blob_id])) + upvs_submission.attachments = ActiveStorage::Blob.where(id: params[:attachments_ids]) if params[:attachments_ids].present? upvs_submission.anonymous_user_uuid = @uuid upvs_submission.current_user = self upvs_submission.callback_step = callback_step diff --git a/app/models/apps/general_agenda_app/general_agenda/application_form.rb b/app/models/apps/general_agenda_app/general_agenda/application_form.rb new file mode 100644 index 00000000..bd942dc4 --- /dev/null +++ b/app/models/apps/general_agenda_app/general_agenda/application_form.rb @@ -0,0 +1,139 @@ +module Apps + module GeneralAgendaApp + module GeneralAgenda + class ApplicationForm + include ActiveModel::Model + include ActiveModel::Validations + + validate :validate_recipient_present + validate :validate_subject + validate :validate_text + validate :validate_attachments + + attr_accessor( + # Static/template attributes + :title, + :description, + :attachments_template, + + # Submitted through form + :recipient_name, + :recipient_uri, + :subject, + :text, + :signed_required, + :attachments, + + :is_submitted # Whether the form is submitted internally via the submit button or just open from POST request from external site (API functionality) + ) + + # `signed_required` is stored as string and this method converts it into boolean + def signed_required? + UtilityService.yes?(signed_required) + end + + def template_errors + @template_errors || [] + end + + def valid_template? + @template_errors = [] + + if attachments_template.present? && !attachments_template.is_a?(Array) + @template_errors << 'Premenná "attachments_template" musí byť pole súborov.' + elsif attachments_template.is_a?(Array) + attachments_template.each_with_index do |attachment_template, index| + @template_errors << "Hodnota \"name\" pre #{index + 1} attachments_template musí byť povinne text." if attachment_template[:name].blank? || !attachment_template[:name].is_a?(String) + @template_errors << "Hodnota \"description\" pre #{index + 1} attachments_template má byť text." if attachment_template[:description].present? && !attachment_template[:description].is_a?(String) + @template_errors << "Hodnota \"required\" pre #{index + 1} attachments_template musí byť 1 alebo 0." unless attachment_template[:required].in?(['1', '0', nil, '']) + @template_errors << "Hodnota \"signed_required\" pre #{index + 1} attachments_template musí byť 1 alebo 0." unless attachment_template[:signed_required].in?(['1', '0', nil, '']) + end + end + + @template_errors << "Hodnota \"signed_required\" musí byť 1 alebo 0." unless signed_required.in?(['1', '0', nil, '']) + + @template_errors.blank? + end + + # Process uploaded files and store them as blobs + def attachments=(value) + @attachments = {} + + value&.each do |index, value| + index = index.to_i # Index submitted from form like `name="something[0]"` is treated as string + + # Check if the value is directly a blob's integer and then just use it + if value.is_a?(Integer) || (value.is_a?(String) && /\A\d+\z/.match?(value)) + @attachments[index] = value + elsif value.is_a?(ActionDispatch::Http::UploadedFile) # Upload the file and use the blob's ID + attachment_template = attachments_template.try(:[], index) + signed_required = UtilityService.yes?(attachment_template.try(:[], 'signed_required')) + + blob = ActiveStorage::Blob.create_and_upload!( + io: value.tempfile, + filename: value.original_filename, + metadata: { + original_template_name: attachment_template.try(:[], :name), + signed_required: signed_required + } + ) + + @attachments[index] = blob.id + end + end + end + + # attachments contains index->blob_id mapping like `{ 1 => 123, 2 => 456 }` + # index represents index in the `attachments_template` + # + # This method returns actual `ActiveStorage::Blob` objects instead of IDs like: + # { 1 => , 2 => } + def attachment_blobs + return @attachment_blobs unless @attachment_blobs.nil? + + blobs = ActiveStorage::Blob.where(id: attachments&.values).index_by(&:id) + + @attachment_blobs = attachments.to_h.transform_values { |blob_id| blobs[blob_id.to_i] } + end + + private + + def validate_recipient_present + errors.add(:recipient_name, 'Zvoľte prijímateľa') if recipient_name.blank? || recipient_uri.blank? + end + + def validate_subject + errors.add(:subject, 'Predmet je povinná položka') if subject.blank? + + validate_placeholders(:subject) + end + + def validate_text + errors.add(:text, 'Text je povinná položka') if text.blank? + + validate_placeholders(:text) + end + + def validate_placeholders(attribute) + pattern = /\{[^{}\s]+}/ # Define a regex pattern to match {PLACEHOLDER} without spaces within the text + value = send(attribute) + + # Check if the text contains any placeholders + if pattern.match(value.to_s) + placeholders = value.to_s.scan(pattern).uniq + + errors.add(attribute, "Prosím nahraďte #{placeholders.join(', ')} za skutočnú hodnotu.") + end + end + + def validate_attachments + attachments_template&.each_with_index do |attachment_template, index| + if UtilityService.yes?(attachment_template[:required]) && attachments.to_h[index].blank? + errors.add(:base, "Nahrajte povinnú prílohu pre '#{attachment_template[:name]}'") + end + end + end + end + end + end +end diff --git a/app/models/datahub/upvs/public_authority_edesk.rb b/app/models/datahub/upvs/public_authority_edesk.rb index e15804a9..0ab7f657 100644 --- a/app/models/datahub/upvs/public_authority_edesk.rb +++ b/app/models/datahub/upvs/public_authority_edesk.rb @@ -1,15 +1,21 @@ -class Datahub::Upvs::PublicAuthorityEdesk < DatahubRecord - ICO_REGEXP = /\d+/ - - def self.search(query) - if query.match(ICO_REGEXP) - where('cin::varchar ilike ?', "#{query}%").limit(15) - else - where('unaccent(name) ilike unaccent(?)', "%#{query}%").order('LENGTH(name) ASC').limit(15) # TODO make this better - end - end +module Datahub + module Upvs + class PublicAuthorityEdesk < DatahubRecord + + ICO_REGEXP = /\d+/ - def serializable_hash(options = nil) - super(options).merge(cin: cin.to_s.rjust(8, '0')) + def self.search(query) + if query.match(ICO_REGEXP) + where('cin::varchar ilike ?', "#{query}%").limit(15) + else + where('unaccent(name) ilike unaccent(?)', "%#{query}%").order('LENGTH(name) ASC').limit(15) # TODO make this better + end + end + + def serializable_hash(options = nil) + super(options).merge(cin: cin.to_s.rjust(8, '0')) + end + end end end + diff --git a/app/models/datahub/upvs/services_with_forms.rb b/app/models/datahub/upvs/services_with_forms.rb new file mode 100644 index 00000000..21187064 --- /dev/null +++ b/app/models/datahub/upvs/services_with_forms.rb @@ -0,0 +1,17 @@ +module Datahub + module Upvs + class ServicesWithForms < DatahubRecord + def self.search(query) + select(:institution_name, :institution_uri).where('unaccent(institution_name) ilike unaccent(?)', "%#{query}%") + .is_valid.order(:institution_name).distinct.limit(15).pluck(:institution_name, :institution_uri) + .collect { |i| { name: i.first, uri: i.second } } + end + + def self.is_valid + # is it localized ? or PG time is ok + where('(valid_from < Now() OR valid_from IS NULL) AND (valid_to > Now() OR valid_to IS NULL) ') + end + end + end +end + diff --git a/app/models/upvs/form_template_related_document.rb b/app/models/upvs/form_template_related_document.rb index 9141fd70..75714850 100644 --- a/app/models/upvs/form_template_related_document.rb +++ b/app/models/upvs/form_template_related_document.rb @@ -14,4 +14,8 @@ class Upvs::FormTemplateRelatedDocument < ApplicationRecord self.table_name = "upvs.form_template_related_documents" + + def identifier + "http://schemas.gov.sk/form/#{posp_id}/#{posp_version}" + end end diff --git a/app/models/upvs/submission.rb b/app/models/upvs/submission.rb index eadf849e..f01a8ee0 100644 --- a/app/models/upvs/submission.rb +++ b/app/models/upvs/submission.rb @@ -14,7 +14,7 @@ # recipient_uri :string not null # sender_business_reference :string # recipient_business_reference :string -# form :text not null +# form :text # callback_url :string # callback_step_id :string # callback_step_status :string @@ -23,27 +23,41 @@ # updated_at :datetime not null # -class Upvs::Submission < ApplicationRecord +class Upvs::Submission < ApplicationRecord + self.ignored_columns += [:form] # TODO: drop + belongs_to :user, optional: true belongs_to :callback_step, optional: true, class_name: 'Step' attr_accessor :subscription_types, :raw_extra, :skip_subscribe, :current_user, :callback_step_path + # form_id: 123 + # signed_required: true + + # attachments + # signed_required + # [ + # { blob_id: 1, signed_required: false }, + # { blob_id: 2, signed_required: true } + # ] + + # blob_id: 1 | signed: false | signed_required: true + + has_one_attached :form + has_many_attached :attachments + before_create { self.uuid = SecureRandom.uuid } # TODO ensure unique in loop before_create { set_new_expiration_time } validates_presence_of :posp_id, :posp_version, :message_type, :recipient_uri, :message_subject, :form, on: :create validate :recipient_uri_allowed?, if: -> { Rails.env.production? }, on: :create validate :egov_application_allowed?, if: -> { Rails.env.production? }, on: :create - validate :valid_xml_form?, on: :create scope :expired, -> { where('expires_at < ?', Time.zone.now) } self.table_name = "upvs.submissions" def recipient_name - return recipient_uri if Rails.env.development? - - @recipient_name ||= Datahub::Upvs::PublicAuthorityEdesk.where(uri: recipient_uri).pluck(:name).first + @recipient_name ||= Datahub::Upvs::PublicAuthorityEdesk.where(uri: recipient_uri).pluck(:name).first || recipient_uri end def message_id @@ -89,8 +103,8 @@ def validate def submit_to_sk_api(client, url, eid_token) begin - headers = { "Content-Type": "application/json" } - data = { message: UpvsSubmissions::SktalkMessageBuilder.new.build_sktalk_message(self, eid_token) }.to_json + headers = { "Content-Type": "application/json" } + data = { message: UpvsSubmissions::SktalkMessageBuilder.new.build_sktalk_message(self, eid_token) }.to_json client.post(url, data, headers) rescue Exception @@ -122,7 +136,11 @@ def xslt_transformation xslt_template = Nokogiri::XSLT(form_related_document.xslt_transformation) - xslt_template.transform(Nokogiri::XML(form)).to_s.gsub('"', '\'') + doc = form.open do |temp_file| + Nokogiri::XML(temp_file) + end + + xslt_template.transform(doc).to_s.gsub('"', '\'') end def recipient_uri_allowed? diff --git a/app/models/user.rb b/app/models/user.rb index c95f78f3..a9ad1479 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -32,7 +32,9 @@ def find_submission!(uuid) end def build_upvs_submission(params, callback_step:) - upvs_submission = upvs_submissions.build(params) + upvs_submission = upvs_submissions.build(params.except(:form_blob_id, :attachments_ids)) + upvs_submission.form.attach(ActiveStorage::Blob.find_by(id: params[:form_blob_id])) + upvs_submission.attachments = ActiveStorage::Blob.where(id: params[:attachments_ids]) if params[:attachments_ids].present? upvs_submission.current_user = self upvs_submission.callback_step = callback_step upvs_submission diff --git a/app/services/utility_service.rb b/app/services/utility_service.rb new file mode 100644 index 00000000..fd9a6756 --- /dev/null +++ b/app/services/utility_service.rb @@ -0,0 +1,7 @@ +module UtilityService + module_function + + def yes?(value) + value.to_s.in?(['1', 'true']) + end +end diff --git a/app/views/apps/acts_or_sr_app/acts_submissions/email.html.erb b/app/views/apps/acts_or_sr_app/acts_submissions/email.html.erb index 09431053..f0293f99 100644 --- a/app/views/apps/acts_or_sr_app/acts_submissions/email.html.erb +++ b/app/views/apps/acts_or_sr_app/acts_submissions/email.html.erb @@ -37,7 +37,7 @@ <%= form_with model: @submission_form, url: upvs_submissions_path, scope: 'upvs_submission', html: { id: 'new_upvs_submissions_forms_application_for_document_copy' } do |f| %> <%= f.hidden_field :title, value: 'Podanie žiadosti vyhotovenia kópie listín z ORSR' %> - <%= f.hidden_field :form, value: nil %> + <%= f.hidden_field :form_blob_id, value: nil %> <%= f.hidden_field :callback_url, value: callback_apps_acts_or_sr_app_acts_submissions_url %> <%= f.hidden_field :recipient_uri %> <%= f.hidden_field :posp_version %> @@ -68,7 +68,7 @@ let at = document.getElementById('authenticity-token').getAttribute('content') - document.getElementById('upvs_submission_form').value = await post('/aplikacie/or-sr-listiny', + document.getElementById('upvs_submission_form_blob_id').value = await post('/aplikacie/or-sr-listiny', { authenticity_token: at, apps_or_sr_app_acts_submission_application_form: { @@ -82,7 +82,7 @@ acts: acts, } } - ).then(res => res.text()) + ).then(res => res.json()).then(body => body.id) const validation_response = await post('/aplikacie/or-sr-listiny/form_check', { diff --git a/app/views/apps/general_agenda_app/general_agenda/_header.html.erb b/app/views/apps/general_agenda_app/general_agenda/_header.html.erb new file mode 100644 index 00000000..23c0d3f0 --- /dev/null +++ b/app/views/apps/general_agenda_app/general_agenda/_header.html.erb @@ -0,0 +1,3 @@ +<%= content_for(:headerline, 'Všeobecná agenda') %> + + diff --git a/app/views/apps/general_agenda_app/general_agenda/callback.erb b/app/views/apps/general_agenda_app/general_agenda/callback.erb new file mode 100644 index 00000000..2993fd51 --- /dev/null +++ b/app/views/apps/general_agenda_app/general_agenda/callback.erb @@ -0,0 +1,19 @@ +<%= render partial: 'header' %> + +
+
+
+

+ Vaša správa bola odoslaná +

+
+ Vaša správa bola podpísaná a odoslaná. +
+
+ + <%= render_notification_subscription_component(%w[NewsletterSubscription CompanyNewsletterSubscription]) do %> +

Čo ďalej?

+

Ak sa Vám táto služba páčila, prihláste sa na odber noviniek Návody.Digital. Posielame ich len sem-tam, žiadny spam. Sľubujeme, že to bude užitočné.

+ <% end %> +
+
diff --git a/app/views/apps/general_agenda_app/general_agenda/index.html.erb b/app/views/apps/general_agenda_app/general_agenda/index.html.erb new file mode 100644 index 00000000..3c838da8 --- /dev/null +++ b/app/views/apps/general_agenda_app/general_agenda/index.html.erb @@ -0,0 +1,270 @@ +<%= render partial: 'header' %> + +
+
+ +

<%= @application_form.title %>

+
+
+ + <%= form_for @application_form, builder: AppFormBuilder, url: apps_general_agenda_app_general_agenda_path do |f| %> +

<%= @application_form.description %>

+
+ + <%= render 'components/error_summary', form: @application_form %> + + <%= f.hidden_field :title %> + <%= f.hidden_field :description %> + <%= f.hidden_field :signed_required %> + + <% @application_form.attachments_template.to_a.each do |attachment_template| %> + <% # Rails will wrap this as `name="apps_general_agenda_app_general_agenda_application_form[attachments_template][][name]"` %> + + <%= f.hidden_field "attachments_template][][name", value: attachment_template[:name] %> + <%= f.hidden_field "attachments_template][][description", value: attachment_template[:description] %> + <%= f.hidden_field "attachments_template][][required", value: attachment_template[:required] %> + <%= f.hidden_field "attachments_template][][signed_required", value: attachment_template[:signed_required] %> + <% end %> + + <%= f.hidden_field :recipient_name %> + <%= f.hidden_field :recipient_uri %> + + <%= f.hidden_field :is_submitted, value: 1 %> + +

+ Prijímateľ +

+ +
+
+ <%= f.inputs_set :recipient_name do %> +
+ <% end %> +
+
+ +

+ Predmet +

+ +
+
+ <%= f.text_field :subject %> +
+
+ +

+ Text +

+ +
+
+ <%= f.text_area :text, rows: 15 %> +
+
+ + <% if @application_form.signed_required? %> +
+ Tento typ správy bude vyžadovať váš podpis občianskym preukazom +
+ <% end %> + + <% if @application_form.attachments_template.present? %> +

+ Prílohy +

+ + + + + + + + + + + + <% @application_form.attachments_template.each_with_index do |attachment_template, index| %> + + + + + + + <% end %> + +
Požadovaný súborPovinnýVyžaduje podpis?Príloha
+ <%= attachment_template[:name] %>
+ <%= attachment_template[:description] %> +
<%= lb attachment_template[:required] %><%= lb attachment_template[:signed_required] %> + <% blob = @application_form.attachment_blobs[index] %> + + <% if blob %> + <%= link_to blob.filename, rails_blob_url(blob, disposition: :download), target: :_blank %> + <%= f.hidden_field "attachments][#{index}", value: blob.id %> + <% end %> + + <%= f.file_field "attachments][#{index}" %> +
+ <% end %> + +

Používaním tejto služby súhlasíte so spracovaním osobných údajov v rozsahu nevyhnutnom na odoslanie podania. Vaše údaje neukladáme, sú použité výlučne na vyplnenie podania.

+ + + <% end %> +
+
+ + diff --git a/app/views/apps/general_agenda_app/general_agenda/invalid_template.html.erb b/app/views/apps/general_agenda_app/general_agenda/invalid_template.html.erb new file mode 100644 index 00000000..a6317fe4 --- /dev/null +++ b/app/views/apps/general_agenda_app/general_agenda/invalid_template.html.erb @@ -0,0 +1,14 @@ +<%= render partial: 'header' %> + + diff --git a/app/views/apps/general_agenda_app/general_agenda/redirect_to_upvs_submission.erb b/app/views/apps/general_agenda_app/general_agenda/redirect_to_upvs_submission.erb new file mode 100644 index 00000000..a8a0a38f --- /dev/null +++ b/app/views/apps/general_agenda_app/general_agenda/redirect_to_upvs_submission.erb @@ -0,0 +1,26 @@ +<%= render partial: 'header' %> + +
+ + + +<%= form_with model: @submission_form, url: upvs_submissions_path, scope: 'upvs_submission', html: { id: 'upvs_submissions_form' } do |f| %> + <%= f.hidden_field :title, value: 'Podanie všeobecnej agendy' %> + <%= f.hidden_field :form_blob_id %> + <%= f.hidden_field :callback_url, value: callback_apps_general_agenda_app_general_agenda_path %> + <%= f.hidden_field :recipient_uri %> + <%= f.hidden_field :posp_version %> + <%= f.hidden_field :posp_id %> + <%= f.hidden_field :message_type %> + <%= f.hidden_field :message_subject %> + + <% @submission_form.attachments_blob_ids.each do |blob_id| %> + <%= f.hidden_field 'attachments_ids[', value: blob_id %> + <% end %> +<% end %> + + diff --git a/app/views/upvs/submissions/_blob_row_content.html.erb b/app/views/upvs/submissions/_blob_row_content.html.erb new file mode 100644 index 00000000..212d77b9 --- /dev/null +++ b/app/views/upvs/submissions/_blob_row_content.html.erb @@ -0,0 +1,17 @@ + + <%= blob.metadata[:original_template_name] %>
+ + + <%= link_to blob.filename, rails_blob_url(blob, disposition: :download), target: :_blank %> + + <% if blob.signed_blob.attached? %> +
+ + Podpísaný súbor: <%= link_to blob.signed_blob.filename, rails_blob_url(blob.signed_blob, disposition: :download), target: :_blank %> + + <% end %> + +<%= lb blob.metadata[:signed_required] %> + + <%= render 'upvs/submissions/blob_sign_button', blob: blob %> + diff --git a/app/views/upvs/submissions/_blob_sign_button.html.erb b/app/views/upvs/submissions/_blob_sign_button.html.erb new file mode 100644 index 00000000..369c423b --- /dev/null +++ b/app/views/upvs/submissions/_blob_sign_button.html.erb @@ -0,0 +1,5 @@ +<% if blob.signed? %> + <%= render 'upvs/submissions/signed_badge' %> +<% elsif blob.metadata[:signed_required] %> + +<% end %> diff --git a/app/views/upvs/submissions/_form.html.erb b/app/views/upvs/submissions/_form.html.erb index 6d19250d..5cb2dcf3 100644 --- a/app/views/upvs/submissions/_form.html.erb +++ b/app/views/upvs/submissions/_form.html.erb @@ -22,5 +22,177 @@ +
+ <%= render 'upvs/submissions/blob_sign_button', blob: @upvs_submission.form %> +
+ + <% if @upvs_submission.attachments.attached? %> + + + + + + + + + + + <% @upvs_submission.attachments.each do |blob| %> + + <%= render 'upvs/submissions/blob_row_content', blob: blob %> + + <% end %> + +
Požadovaný súborNázov súboruVyžaduje podpis?
+ <% end %> + <%= render partial: 'actions' %> <% end %> + + diff --git a/app/views/upvs/submissions/_signed_badge.html.erb b/app/views/upvs/submissions/_signed_badge.html.erb new file mode 100644 index 00000000..b38da56f --- /dev/null +++ b/app/views/upvs/submissions/_signed_badge.html.erb @@ -0,0 +1,3 @@ + + Podpísané + diff --git a/config/application.rb b/config/application.rb index ad4ec8cd..dc8da4f5 100644 --- a/config/application.rb +++ b/config/application.rb @@ -49,6 +49,11 @@ class Application < Rails::Application }, } } + + config.after_initialize do + config.active_storage.analyzers.prepend ::Analyzers::SignedPdfAnalyzer + config.active_storage.analyzers.prepend ::Analyzers::SignedXAnalyzer + end end end diff --git a/config/initializers/active_storage.rb b/config/initializers/active_storage.rb new file mode 100644 index 00000000..8bed4edb --- /dev/null +++ b/config/initializers/active_storage.rb @@ -0,0 +1,31 @@ +module ActiveStorageBlobInitializer + extend ActiveSupport::Concern + + included do + has_one_attached :signed_blob + + def signed? + metadata[:signed] || signed_blob.attached? + end + + # Returns either self if the current blob is signed, or the signed blob (if exists) + def get_signed_blob + if metadata[:signed] + self + elsif signed_blob.attached? + signed_blob + end + end + + # If the signature is required, return signed version of this blob, otherwise the blob itself + def blob_for_upvs + get_signed_blob || self + end + end +end + +ActiveSupport::Reloader.to_prepare do + ActiveSupport.on_load(:active_storage_blob) do + include ActiveStorageBlobInitializer + end +end diff --git a/config/routes.rb b/config/routes.rb index eaa97608..d1a584e2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -100,6 +100,13 @@ get :picking_up_protocol, to: 'picking_up_protocol#show', path: 'vyzdvihnutie-rodneho-listu' end + namespace :general_agenda_app, path: 'vseobecna-agenda' do + resource :general_agenda, controller: 'general_agenda', path: '' do + match :index, via: [:get, :post] + get :callback, path: 'odoslane' + end + end + namespace :acts_or_sr_app, path: 'or-sr-listiny' do resource :acts_submissions, path: '' do member do @@ -169,6 +176,9 @@ post :submit, path: 'odoslat' get :submission_error, path: 'chyba' get :finish, path: 'dokoncene' + + get 'signing_data/:submission_id/:signed_blob_id', action: :signing_data, as: :signing_data + patch 'signing_data/:submission_id/:signed_blob_id', action: :update_blob_after_signature end end @@ -176,7 +186,7 @@ namespace :datahub do namespace :upvs do resources :public_authority_edesks do - get :search, on: :collection + get :search_recipient, to: 'services_with_forms#search_recipient', defaults: { format: :json }, on: :collection end end end diff --git a/db/migrate/20231007115021_change_not_null_on_upvs_submissions.rb b/db/migrate/20231007115021_change_not_null_on_upvs_submissions.rb new file mode 100644 index 00000000..740cbf51 --- /dev/null +++ b/db/migrate/20231007115021_change_not_null_on_upvs_submissions.rb @@ -0,0 +1,5 @@ +class ChangeNotNullOnUpvsSubmissions < ActiveRecord::Migration[6.1] + def change + change_column_null 'upvs.submissions', :form, true + end +end diff --git a/db/migrate/20240427100139_drop_upvs_submissions_form_attribute.rb b/db/migrate/20240427100139_drop_upvs_submissions_form_attribute.rb new file mode 100644 index 00000000..984c8e08 --- /dev/null +++ b/db/migrate/20240427100139_drop_upvs_submissions_form_attribute.rb @@ -0,0 +1,5 @@ +class DropUpvsSubmissionsFormAttribute < ActiveRecord::Migration[6.1] + def up + remove_column 'upvs.submissions', :form + end +end diff --git a/db/structure.sql b/db/structure.sql index 22e99246..a6a91675 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -16,6 +16,13 @@ SET row_security = off; CREATE SCHEMA code_list; +-- +-- Name: public; Type: SCHEMA; Schema: -; Owner: - +-- + +-- *not* creating schema, since initdb creates it + + -- -- Name: upvs; Type: SCHEMA; Schema: -; Owner: - -- @@ -1375,7 +1382,6 @@ CREATE TABLE upvs.submissions ( recipient_uri character varying NOT NULL, sender_business_reference character varying, recipient_business_reference character varying, - form text NOT NULL, callback_url character varying, callback_step_id bigint, callback_step_status character varying, @@ -2486,6 +2492,8 @@ INSERT INTO "schema_migrations" (version) VALUES ('20221022143119'), ('20230325092744'), ('20230325095737'), -('20230325151049'); +('20230325151049'), +('20231007115021'), +('20240427100139'); diff --git a/lib/tasks/tasks.rake b/lib/tasks/tasks.rake index 862d3e45..95f6a0c9 100644 --- a/lib/tasks/tasks.rake +++ b/lib/tasks/tasks.rake @@ -3,6 +3,7 @@ namespace :navody do task cleanup: :environment do Submission.expired.destroy_all Upvs::Submission.expired.destroy_all + RemoveStaleBlobs.perform_later end task check_or_sr_identifiers_status: :environment do diff --git a/spec/models/upvs/submission_spec.rb b/spec/models/upvs/submission_spec.rb index 6d518fb2..85b80033 100644 --- a/spec/models/upvs/submission_spec.rb +++ b/spec/models/upvs/submission_spec.rb @@ -2,6 +2,14 @@ RSpec.describe Upvs::Submission, type: :model do context 'with valid attributes' do + let(:file) do + ActiveStorage::Blob.create_and_upload!( + io: StringIO.new('
9
'), + filename: 'test.xml', + content_type: 'application/xml' + ) + end + let(:valid_attributes) do { posp_id: 'posp_id', @@ -9,7 +17,7 @@ message_type: 'message_type', recipient_uri: 'recipient_uri', message_subject: 'message_subject', - form: '
', + form: file, title: 'title' } end @@ -26,9 +34,8 @@ let(:submission) { described_class.new(valid_attributes) } it 'is valid' do - response_dbl = instance_double('Faraday::Response') allow(Faraday).to receive(:post) - .and_return(OpenStruct.new(body: { "receive_result" => 0, "save_to_outbox_result" => 0 }.to_json, status: 200)) + .and_return(OpenStruct.new(body: { "receive_result" => 0, "save_to_outbox_result" => 0 }.to_json, status: 200)) allow_any_instance_of(EidToken).to receive(:subject_sub).and_return("subject_sub") expect(submission.submit(EidToken.new("eid_token", config: nil), client: Faraday, url: 'https://testing.stub.com/')).to be_truthy diff --git a/spec/requests/upvs/submissions_request_spec.rb b/spec/requests/upvs/submissions_request_spec.rb index cf958f1e..3cd8ac27 100644 --- a/spec/requests/upvs/submissions_request_spec.rb +++ b/spec/requests/upvs/submissions_request_spec.rb @@ -1,6 +1,13 @@ require 'rails_helper' RSpec.describe "Upvs::Submissions", type: :request do + let(:file) do + ActiveStorage::Blob.create_and_upload!( + io: StringIO.new('
9
'), + filename: 'test.xml', + content_type: 'application/xml' + ) + end let(:valid_attributes) do { posp_id: 'posp_id', @@ -8,7 +15,7 @@ message_type: 'message_type', recipient_uri: 'foo://bar', message_subject: 'message_subject', - form: '
9
', + form_blob_id: file.id, title: 'title' } end @@ -20,7 +27,6 @@ message_type: 'message_type', recipient_uri: '', message_subject: 'message_subject', - form: '
', title: 'title' } end @@ -106,7 +112,6 @@ end describe "POST submit" do - context "with valid params" do it "redirects to the callback url" do # stub valid eid_token