class CountsExportsController < ApplicationController wrap_parameters false def create_job locale = resolve_locale! payload = request.request_parameters.merge(request.query_parameters) session[:counts_export_owner] ||= SecureRandom.hex(32) job = CountsExportJobs.start(payload, session[:counts_export_owner], locale.language_code) response.headers['Cache-Control'] = 'private, no-store' render json: { job: }, status: :accepted rescue CountsExportDownload::Busy head :too_many_requests rescue ArgumentError, TypeError, KeyError, JSON::ParserError head :bad_request end def job_status job_state(cancel: false) end def cancel_job job_state(cancel: true) end def prepare locale = resolve_locale! payload = request.request_parameters.merge(request.query_parameters) exporter = CountsExporter.new(payload, language_code: locale.language_code) session[:counts_export_owner] ||= SecureRandom.hex(32) token = CountsExportDownload.prepare(exporter, session[:counts_export_owner]) response.headers['Cache-Control'] = 'private, no-store' render json: { token: } rescue CountsExportDownload::Busy head :too_many_requests rescue CountsExportDownload::TooLarge head 413 rescue CountsExportDownload::TimedOut head :gateway_timeout rescue CountsExportDownload::StorageFull, Errno::ENOSPC head :insufficient_storage rescue ArgumentError, TypeError, KeyError, JSON::ParserError head :bad_request end def download file = CountsExportDownload.find(params[:token], session[:counts_export_owner]) return head :not_found unless file response.headers['Cache-Control'] = 'private, no-store' send_file file.fetch('path'), filename: "counts-#{ file.fetch('resource') }.#{ file.fetch('format') }", type: file['format'] == 'json' ? 'application/json' : 'text/csv', disposition: 'attachment' end def job_state(cancel:) result = CountsExportJobs.status(params[:token], session[:counts_export_owner], cancel:) return head :not_found unless result response.headers['Cache-Control'] = 'private, no-store' render json: result end private :job_state def index locale = resolve_locale! payload = request.request_parameters.except('authenticity_token') .merge(request.query_parameters) exporter = CountsExporter.new(payload, language_code: locale.language_code) response.headers['Content-Type'] = exporter.format == 'json' ? 'application/json; charset=utf-8' : 'text/csv; charset=utf-8' response.headers['Content-Disposition'] = "attachment; filename=\"counts-#{ exporter.resource }.#{ exporter.format }\"" response.headers['Cache-Control'] = 'private, no-store' response.headers['X-Accel-Buffering'] = 'no' # Rack::ETag otherwise materialises the response to calculate a digest. response.headers['Last-Modified'] = Time.current.httpdate self.response_body = exporter.body rescue ArgumentError, TypeError, KeyError, JSON::ParserError head :bad_request end end