Class: Spree::Api::V3::Admin::ImportsController
- Inherits:
-
ResourceController
- Object
- ActionController::API
- BaseController
- ResourceController
- Spree::Api::V3::Admin::ImportsController
- Includes:
- ActiveStorage::SetCurrent
- Defined in:
- app/controllers/spree/api/v3/admin/imports_controller.rb
Overview
See docs/plans/5.6-admin-spa-csv-import.md.
There is no standalone imports scope: an import is a bulk write of
the records it creates, so every action — including reads, which
expose the uploaded data — maps to the write scope of the imported
resource (Spree::Imports::Customers => write_customers; see
Spree::Import.required_scope). The index is filtered to the types
the key can write.
Constant Summary
Constants inherited from BaseController
BaseController::RATE_LIMIT_RESPONSE
Constants included from Idempotent
Idempotent::IDEMPOTENCY_HEADER, Idempotent::IDEMPOTENCY_TTL, Idempotent::MAX_KEY_LENGTH, Idempotent::MUTATING_METHODS
Constants included from ErrorHandler
Constants included from JwtAuthentication
JwtAuthentication::JWT_AUDIENCE_ADMIN, JwtAuthentication::JWT_AUDIENCE_STORE, JwtAuthentication::JWT_ISSUER, JwtAuthentication::USER_TYPE_ADMIN, JwtAuthentication::USER_TYPE_CUSTOMER
Instance Method Summary collapse
-
#complete_mapping ⇒ Object
PATCH /api/v3/admin/imports/:id/complete_mapping.
-
#create ⇒ Object
POST /api/v3/admin/imports.
-
#download ⇒ Object
GET /api/v3/admin/imports/:id/download.
-
#retry_failed_rows ⇒ Object
PATCH /api/v3/admin/imports/:id/retry_failed_rows.
-
#template ⇒ Object
GET /api/v3/admin/imports/template?type=Spree::Imports::Products.
Methods inherited from ResourceController
#destroy, #index, #show, #update
Methods included from Spree::Api::V3::ApiKeyAuthentication
#authenticate_api_key!, #authenticate_secret_key!
Methods included from JwtAuthentication
#authenticate_user, #require_authentication!
Instance Method Details
#complete_mapping ⇒ Object
PATCH /api/v3/admin/imports/:id/complete_mapping
Applies the submitted mappings atomically, then transitions out of mapping (which enqueues row creation + processing). 422 when required schema fields remain unmapped or a file column is assigned twice.
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'app/controllers/spree/api/v3/admin/imports_controller.rb', line 60 def complete_mapping @resource = find_resource (@resource, :update) unless @resource.mapping? return render_error( code: Spree::Api::V3::ErrorHandler::ERROR_CODES[:validation_error], message: 'Import is not in the mapping state', status: :unprocessable_content ) end apply_mappings!(@resource) if @resource.mapping_done? @resource.complete_mapping! render json: serialize_resource(@resource) else missing = @resource.required_fields - @resource.mappings.mapped.pluck(:schema_field) render_error( code: Spree::Api::V3::ErrorHandler::ERROR_CODES[:validation_error], message: "Required fields are not mapped: #{missing.join(', ')}", status: :unprocessable_content, details: { missing_required_fields: missing } ) end rescue ActiveRecord::RecordInvalid => e render_validation_error(e.record.errors) end |
#create ⇒ Object
POST /api/v3/admin/imports
attachment is an ActiveStorage signed blob id obtained from
POST /api/v3/admin/direct_uploads. On success the import advances
straight into mapping (auto-assigning file columns from the CSV
headers), so the response already carries the mapping payload.
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'app/controllers/spree/api/v3/admin/imports_controller.rb', line 26 def create @resource = build_resource (@resource, :create) if @resource.save begin @resource.start_mapping! rescue ::CSV::MalformedCSVError, EncodingError => e @resource.update_columns(status: 'failed', processing_errors: e., updated_at: Time.current) return render_error( code: Spree::Api::V3::ErrorHandler::ERROR_CODES[:validation_error], message: "Could not parse CSV: #{e.}", status: :unprocessable_content ) end render json: serialize_resource(@resource), status: :created else render_errors(@resource.errors) end rescue ActiveSupport::MessageVerifier::InvalidSignature render_error( code: Spree::Api::V3::ErrorHandler::ERROR_CODES[:validation_error], message: 'Invalid attachment signed id', status: :unprocessable_content ) end |
#download ⇒ Object
GET /api/v3/admin/imports/:id/download
Streams the originally uploaded CSV — the audit trail for what
was actually imported. Same inline-streaming rationale as
ExportsController#download: a signed ActiveStorage URL neither
survives the SPA's /api/*-only dev proxy nor carries the JWT.
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'app/controllers/spree/api/v3/admin/imports_controller.rb', line 116 def download @resource = find_resource (@resource, :show) = @resource. unless .attached? return render_error( code: Spree::Api::V3::ErrorHandler::ERROR_CODES[:validation_error], message: 'Import has no attached file', status: :unprocessable_content ) end send_data( .download, filename: .filename.to_s, type: .content_type || 'text/csv', disposition: 'attachment' ) end |
#retry_failed_rows ⇒ Object
PATCH /api/v3/admin/imports/:id/retry_failed_rows
Re-dispatches processing over the rows still failed (the
dispatcher's pending_and_failed scope picks them up). 422 unless
the import is completed with failures.
95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'app/controllers/spree/api/v3/admin/imports_controller.rb', line 95 def retry_failed_rows @resource = find_resource (@resource, :update) if @resource.retry_failed_rows render json: serialize_resource(@resource) else render_error( code: Spree::Api::V3::ErrorHandler::ERROR_CODES[:validation_error], message: 'Import has no failed rows to retry', status: :unprocessable_content ) end end |
#template ⇒ Object
GET /api/v3/admin/imports/template?type=Spree::Imports::Products
CSV header row for the type's schema (including the metafield columns available for the model) — the "Download template" link in the admin dashboard.
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'app/controllers/spree/api/v3/admin/imports_controller.rb', line 142 def template klass = resolve_import_type(params[:type]) unless klass return render_error( code: Spree::Api::V3::ErrorHandler::ERROR_CODES[:validation_error], message: 'Unknown import type', status: :unprocessable_content ) end headers = klass.new.schema_fields.map { |field| field[:name] } send_data ::CSV.generate_line(headers), filename: "#{klass.name.demodulize.underscore}_import_template.csv", type: 'text/csv', disposition: 'attachment' end |