diff options
| -rw-r--r-- | app/controllers/api/v1/netex_imports_controller.rb | 5 | ||||
| -rw-r--r-- | app/controllers/support/error_format.rb | 15 | ||||
| -rw-r--r-- | app/models/concerns/error_format.rb | 25 | ||||
| -rw-r--r-- | app/services/http_service.rb | 15 | ||||
| -rw-r--r-- | app/services/retry_service.rb | 13 | ||||
| -rw-r--r-- | app/workers/workbench_import_worker.rb | 21 | ||||
| -rw-r--r-- | spec/models/concerns/error_format_spec.rb | 35 | 
7 files changed, 107 insertions, 22 deletions
| diff --git a/app/controllers/api/v1/netex_imports_controller.rb b/app/controllers/api/v1/netex_imports_controller.rb index ba7777654..7dc18a7be 100644 --- a/app/controllers/api/v1/netex_imports_controller.rb +++ b/app/controllers/api/v1/netex_imports_controller.rb @@ -44,7 +44,10 @@ module Api          ReferentialMetadataKludge.make_metadata_from_name! netex_import_params['name'], referential_id: @new_referential.id          #  <<< REMOVE ME !!!!        rescue ActiveRecord::RecordInvalid -        render json: {errors: @new_referential.errors}, status: 406 +        require 'pry' +        binding.pry +        # render json: {errors: @new_referential.errors}, status: 406 +        render json: {errors: ErrorFormat.detailed(@new_referential)}, status: 406          finish_action!        end diff --git a/app/controllers/support/error_format.rb b/app/controllers/support/error_format.rb new file mode 100644 index 000000000..567eece80 --- /dev/null +++ b/app/controllers/support/error_format.rb @@ -0,0 +1,15 @@ +module Support +  module ErrorFormat extend self + +    def detailed error_object +      error_object.errors.each do +      end +    end + + +    private +    def detailed_messages errors +    end +     +  end +end diff --git a/app/models/concerns/error_format.rb b/app/models/concerns/error_format.rb new file mode 100644 index 000000000..d7d15894c --- /dev/null +++ b/app/models/concerns/error_format.rb @@ -0,0 +1,25 @@ +module ErrorFormat extend self + +    def details error_object +      error_object.errors.messages.map(&partial(:detail, error_object)) +    end + + +    private +    def detail error_object, error +      { +        error.first => { +          error: error.last.first, +          value: error_object[error.first] +        } +      } +    end +     + +    def partial name, *partial_args +      -> *lazy_args do +        send(name, *(partial_args + lazy_args)) +      end +    end +   +end diff --git a/app/services/http_service.rb b/app/services/http_service.rb index ae7d0e413..6cf8ef93b 100644 --- a/app/services/http_service.rb +++ b/app/services/http_service.rb @@ -20,7 +20,6 @@ module HTTPService extend self        raise "Error on api request status : #{resp.status} => #{resp.body}"      end    end -    # host: 'http://localhost:3000',    # path: '/api/v1/netex_imports.json',    # token: '13-74009c36638f587c9eafb1ce46e95585', @@ -32,14 +31,14 @@ module HTTPService extend self        c.request :multipart        c.request :url_encoded        c.adapter Faraday.default_adapter - -      if upload -        name = upload.keys.first -        value, mime_type, as_name = upload.values.first -        params.update( name => Faraday::UploadIO.new(value, mime_type, as_name ) ) -      end - +        require 'pry' +        binding.pry        return c.post path, params      end    end + +  # Expose this in order to make the service replaceable +  def upload(*triple) +    Faraday::UploadIO.new(*triple) +  end  end diff --git a/app/services/retry_service.rb b/app/services/retry_service.rb index 21b1def36..245dd32df 100644 --- a/app/services/retry_service.rb +++ b/app/services/retry_service.rb @@ -16,8 +16,9 @@ class RetryService    # @param@ block:    # This optional code is excuted before each retry, it is passed the result of the failed attempt, thus    # an `Exception` and the number of execution already tried. -  def initialize( delays: [], rescue_from: [], &blk ) +  def initialize( delays: [], rescue_from: [], logger: nil, &blk )      @intervals             = delays +    @logger                = logger      @registered_exceptions = Array(rescue_from) << Retry      @failure_callback      = blk    end @@ -31,6 +32,7 @@ class RetryService      result = execute_protected blk      return result if result.ok?      @intervals.each_with_index do | interval, retry_count | +      warn "retry #{retry_count + 1 }; sleeping #{interval}; cause: #{result.value.inspect}"        sleep interval        @failure_callback.try(:call, result.value, retry_count + 1)        result = execute_protected blk @@ -43,7 +45,9 @@ class RetryService    private    def execute_protected blk -    Result.ok(blk.()) +    result = blk.() +    return result if Result === result +    Result.ok(result)    rescue Exception => e      if @registered_exceptions.any?{ |re| e.is_a? re }        Result.error(e) @@ -51,4 +55,9 @@ class RetryService        raise      end    end + +  def warn message +    return unless @logger +    @logger.try :warn, message +  end  end diff --git a/app/workers/workbench_import_worker.rb b/app/workers/workbench_import_worker.rb index f91093806..d06d4607c 100644 --- a/app/workers/workbench_import_worker.rb +++ b/app/workers/workbench_import_worker.rb @@ -31,23 +31,17 @@ class WorkbenchImportWorker        host: export_host,        path: export_path,        token: token(eg_name), -      params: params, -      upload: {file: [eg_file, 'application/zip', eg_name]}) +      params: params(eg_file, eg_name))    end    def log_failure reason, count      logger.warn "HTTP POST failed with #{reason}, count = #{count}, response=#{@response}"    end -  def try_again -    raise RetryService::Retry -  end -    def try_upload_entry_group eg_name, eg_file      result = execute_post eg_name, eg_file -    return result if result && result.status < 400 -    @response = result.body -    try_again +    return Result.ok(result) if result && result.status < 400 +    Result.error(JSON.parse result.body)    end    def upload zip_service @@ -63,6 +57,7 @@ class WorkbenchImportWorker      retry_service = RetryService.new(        delays: RETRY_DELAYS,        rescue_from: [HTTPService::Timeout], +      logger: logger,        &method(:log_failure))       status = retry_service.execute(&upload_entry_group_proc(entry_pair))      raise StopIteration unless status.ok? @@ -116,7 +111,11 @@ class WorkbenchImportWorker      @__import_url__ ||= File.join(import_host, import_path)    end -  def params -    @__params__ ||= { netex_import: { referential_id: @workbench_import.referential_id, workbench_id: @workbench_import.workbench_id } } +  def params file, name +    { netex_import: +      { referential_id: @workbench_import.referential_id, +        workbench_id: @workbench_import.workbench_id, +        name: name, +        file: HTTPService.upload(file, 'application/zip', name) } }    end  end diff --git a/spec/models/concerns/error_format_spec.rb b/spec/models/concerns/error_format_spec.rb new file mode 100644 index 000000000..7f7df22b6 --- /dev/null +++ b/spec/models/concerns/error_format_spec.rb @@ -0,0 +1,35 @@ +RSpec.describe ErrorFormat do +   +  context '#details' do  +    context 'are empty' do  +      it 'if no errors are present' do +        expect( described_class.details(create :referential) ).to be_empty +      end + +      it 'if no validation has been carried out' do +        invalid = build :referential, name: nil +        expect( described_class.details(invalid) ).to be_empty +      end +    end + +    context 'are not empty' do  +      it 'if an error is present and validation has been carried out' do +        invalid = build :referential, name: nil +        expect( invalid ).not_to be_valid +        expect( described_class.details(invalid) ).to eq([ +          {name: {error: 'doit ĂȘtre rempli(e)', value: nil}} +        ]) +      end + +      it 'and can even hold many errors' do +        create :referential, name: 'hello' +        invalid = build :referential, name: 'hello', slug: 'hello world' +        expect( invalid ).not_to be_valid +        expect( described_class.details(invalid) ).to eq([ +          {name: {error: "n'est pas disponible", value: 'hello'}}, +          {slug: {error: "n'est pas valide", value: 'hello world'}} +        ]) +      end +    end +  end +end | 
