diff --git a/app/controllers/export_controller.rb b/app/controllers/export_controller.rb index cfa94cf4..bcde4d7e 100644 --- a/app/controllers/export_controller.rb +++ b/app/controllers/export_controller.rb @@ -32,6 +32,30 @@ class ExportController < ApplicationController head :internal_server_error end + def export_submission + submission = Submission.find(params[:id]) + export_location = ExportLocation.default_location + + unless export_location&.submissions_endpoint.present? + redirect_to submission, alert: 'Export failed: Submission export endpoint is not configured.' + return + end + + payload = { + submission_id: submission.id, + template_name: submission.template&.name, + events: submission.submission_events.order(updated_at: :desc).limit(1) + } + + response = post_to_api(payload, export_location.submissions_endpoint, export_location.extra_params) + + if response&.success? + redirect_to submission, notice: "Submission ##{submission.id} events exported successfully." + else + redirect_to submission, alert: "Failed to export submission ##{submission.id} events." + end + end + private def api_connection diff --git a/app/models/document_generation_event.rb b/app/models/document_generation_event.rb index 24d71ba3..f4e0a701 100644 --- a/app/models/document_generation_event.rb +++ b/app/models/document_generation_event.rb @@ -13,7 +13,7 @@ # Indexes # # index_document_generation_events_on_submitter_id (submitter_id) -# index_document_generation_events_on_submitter_id_and_event_name (submitter_id,event_name) UNIQUE WHERE ((event_name)::text = ANY (ARRAY[('start'::character varying)::text, ('complete'::character varying)::text])) +# index_document_generation_events_on_submitter_id_and_event_name (submitter_id,event_name) UNIQUE WHERE ((event_name)::text = ANY ((ARRAY['start'::character varying, 'complete'::character varying])::text[])) # # Foreign Keys # diff --git a/app/models/email_event.rb b/app/models/email_event.rb index 3aaa5db9..3c6aac61 100644 --- a/app/models/email_event.rb +++ b/app/models/email_event.rb @@ -20,7 +20,7 @@ # # index_email_events_on_account_id_and_event_datetime (account_id,event_datetime) # index_email_events_on_email (email) -# index_email_events_on_email_event_types (email) WHERE ((event_type)::text = ANY (ARRAY[('bounce'::character varying)::text, ('soft_bounce'::character varying)::text, ('complaint'::character varying)::text, ('soft_complaint'::character varying)::text])) +# index_email_events_on_email_event_types (email) WHERE ((event_type)::text = ANY ((ARRAY['bounce'::character varying, 'soft_bounce'::character varying, 'complaint'::character varying, 'soft_complaint'::character varying])::text[])) # index_email_events_on_emailable (emailable_type,emailable_id) # index_email_events_on_message_id (message_id) # diff --git a/app/models/export_location.rb b/app/models/export_location.rb index a211c0a3..0be6dfb3 100644 --- a/app/models/export_location.rb +++ b/app/models/export_location.rb @@ -2,15 +2,16 @@ # # Table name: export_locations # -# id :bigint not null, primary key -# api_base_url :string not null -# authorization_token :string -# default_location :boolean default(FALSE), not null -# extra_params :jsonb not null -# name :string not null -# templates_endpoint :string -# created_at :datetime not null -# updated_at :datetime not null +# id :bigint not null, primary key +# api_base_url :string not null +# authorization_token :string +# default_location :boolean default(FALSE), not null +# extra_params :jsonb not null +# name :string not null +# submissions_endpoint :string +# templates_endpoint :string +# created_at :datetime not null +# updated_at :datetime not null # class ExportLocation < ApplicationRecord validates :name, presence: true diff --git a/app/views/templates/_submission.html.erb b/app/views/templates/_submission.html.erb index cfa7f936..fc4804b1 100644 --- a/app/views/templates/_submission.html.erb +++ b/app/views/templates/_submission.html.erb @@ -101,6 +101,9 @@ <%= t('view') %> + + <%= button_to button_title(title: nil, icon: svg_icon('upload', class: 'w-6 h-6')), export_submission_path(submission), class: 'btn btn-outline btn-sm w-full md:w-fit', form: { class: 'flex' }, title: t('export'), method: :post %> + <% if !submission.archived_at? && !template&.archived_at? && can?(:destroy, submission) %> <%= button_to button_title(title: nil, disabled_with: t(:archive).first(4), icon: svg_icon('archive', class: 'w-6 h-6')), submission_path(submission), class: 'btn btn-outline btn-sm w-full md:w-fit', form: { class: 'flex' }, title: t('archive'), method: :delete %> diff --git a/config/routes.rb b/config/routes.rb index 7fc306c2..18390c8a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -81,6 +81,8 @@ Rails.application.routes.draw do resources :submissions_archived, only: %i[index], path: 'submissions/archived' resources :submissions, only: %i[index], controller: 'submissions_dashboard' resources :submissions, only: %i[show destroy] do + post :export, on: :member, to: 'export#export_submission' + resources :unarchive, only: %i[create], controller: 'submissions_unarchive' resources :events, only: %i[index], controller: 'submission_events' end diff --git a/db/migrate/20250708172115_add_submissions_endpoint_to_export_locations.rb b/db/migrate/20250708172115_add_submissions_endpoint_to_export_locations.rb new file mode 100644 index 00000000..2f3a31f8 --- /dev/null +++ b/db/migrate/20250708172115_add_submissions_endpoint_to_export_locations.rb @@ -0,0 +1,5 @@ +class AddSubmissionsEndpointToExportLocations < ActiveRecord::Migration[8.0] + def change + add_column :export_locations, :submissions_endpoint, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 9a97cf4f..326eb62d 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.0].define(version: 2025_07_03_143236) do +ActiveRecord::Schema[8.0].define(version: 2025_07_08_172115) do # These are extensions that must be enabled in order to support this database enable_extension "btree_gin" enable_extension "pg_catalog.plpgsql" @@ -160,7 +160,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_07_03_143236) do t.string "event_name", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.index ["submitter_id", "event_name"], name: "index_document_generation_events_on_submitter_id_and_event_name", unique: true, where: "((event_name)::text = ANY (ARRAY[('start'::character varying)::text, ('complete'::character varying)::text]))" + t.index ["submitter_id", "event_name"], name: "index_document_generation_events_on_submitter_id_and_event_name", unique: true, where: "((event_name)::text = ANY ((ARRAY['start'::character varying, 'complete'::character varying])::text[]))" t.index ["submitter_id"], name: "index_document_generation_events_on_submitter_id" end @@ -177,7 +177,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_07_03_143236) do t.datetime "created_at", null: false t.index ["account_id", "event_datetime"], name: "index_email_events_on_account_id_and_event_datetime" t.index ["email"], name: "index_email_events_on_email" - t.index ["email"], name: "index_email_events_on_email_event_types", where: "((event_type)::text = ANY (ARRAY[('bounce'::character varying)::text, ('soft_bounce'::character varying)::text, ('complaint'::character varying)::text, ('soft_complaint'::character varying)::text]))" + t.index ["email"], name: "index_email_events_on_email_event_types", where: "((event_type)::text = ANY ((ARRAY['bounce'::character varying, 'soft_bounce'::character varying, 'complaint'::character varying, 'soft_complaint'::character varying])::text[]))" t.index ["emailable_type", "emailable_id"], name: "index_email_events_on_emailable" t.index ["message_id"], name: "index_email_events_on_message_id" end @@ -225,6 +225,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_07_03_143236) do t.datetime "created_at", null: false t.datetime "updated_at", null: false t.jsonb "extra_params", default: {}, null: false + t.string "submissions_endpoint" end create_table "oauth_access_grants", force: :cascade do |t|