diff --git a/app/services/task_service/push_external.rb b/app/services/task_service/push_external.rb
index 972b70ad3..759ed3abf 100644
--- a/app/services/task_service/push_external.rb
+++ b/app/services/task_service/push_external.rb
@@ -9,17 +9,28 @@ def initialize(zip:, account_link:)
end
def execute
- body = @zip.string
- begin
- response = self.class.connection.post(@account_link.push_url) {|request| request_parameters(request, body) }
- response.success? ? nil : response.body
- rescue StandardError => e
- e
- end
+ response = self.class.connection.post(@account_link.push_url) {|request| request_parameters(request, @zip.string) }
+ handle_response(response)
+ rescue Faraday::ServerError => e
+ handle_error(error: e, message: I18n.t('tasks.export_external_confirm.server_error', account_link: @account_link.name))
+ rescue StandardError => e
+ handle_error(error: e, message: I18n.t('tasks.export_external_confirm.generic_error'))
end
private
+ def handle_response(response)
+ return nil if response.success?
+ return I18n.t('tasks.export_external_confirm.not_authorized', account_link: @account_link.name) if response.status == 401
+
+ handle_error(message: response.body)
+ end
+
+ def handle_error(message:, error: nil)
+ Sentry.capture_exception(error) if error.present?
+ ERB::Util.html_escape(message)
+ end
+
def request_parameters(request, body)
request.tap do |req|
req.headers['Content-Type'] = 'application/zip'
diff --git a/config/locales/de/controllers/tasks.yml b/config/locales/de/controllers/tasks.yml
index fe3b551c0..576cc0215 100644
--- a/config/locales/de/controllers/tasks.yml
+++ b/config/locales/de/controllers/tasks.yml
@@ -7,7 +7,10 @@ de:
duplicate:
error_alert: Die Aufgabe konnte nicht dupliziert werden.
export_external_confirm:
- error: 'Der Export der Aufgabe (%{title}) ist fehlgeschlagen.
Fehler: %{error}'
+ error: 'Der Export der Aufgabe (%{title}) ist fehlgeschlagen.
Fehler: %{error}'
+ generic_error: Ein unbekannter Fehler ist beim exportieren der Aufgabe aufgetreten.
+ not_authorized: Die Autorisierung mit "%{account_link}" konnte nicht hergestellt werden. Ist der API-Schlüssel korrekt?
+ server_error: Verbindung zu "%{account_link}" fehlgeschlagen. Gegenseite nicht erreichbar.
success: Aufgabe (%{title}) erfolgreich exportiert.
import:
internal_error: Beim Import dieser Aufgabe ist auf CodeHarbor ein interner Fehler aufgetreten.
diff --git a/config/locales/en/controllers/tasks.yml b/config/locales/en/controllers/tasks.yml
index b3dc07df5..1ebf823ec 100644
--- a/config/locales/en/controllers/tasks.yml
+++ b/config/locales/en/controllers/tasks.yml
@@ -7,7 +7,10 @@ en:
duplicate:
error_alert: Task could not be duplicated
export_external_confirm:
- error: 'Export of task (%{title}) failed.
Error: %{error}'
+ error: 'Export of task (%{title}) failed.
Error: %{error}'
+ generic_error: An unknown error has occurred while exporting the task.
+ not_authorized: Authorization with "%{account_link}" could not be established. Is the API key correct?
+ server_error: Connection to "%{account_link}" failed. Remote host unreachable.
success: Task (%{title}) successfully exported.
import:
internal_error: An internal error occurred on CodeHarbor while importing the exercise.
diff --git a/spec/services/task_service/push_external_spec.rb b/spec/services/task_service/push_external_spec.rb
index f913ff2a7..a511cda0f 100644
--- a/spec/services/task_service/push_external_spec.rb
+++ b/spec/services/task_service/push_external_spec.rb
@@ -51,18 +51,43 @@
let(:status) { 500 }
let(:response) { 'an error occurred' }
- it { is_expected.to be response }
+ it { is_expected.to eql response }
+
+ context 'when response contains problematic characters' do
+ let(:response) { 'an occurred' }
+
+ it { is_expected.to eql 'an <error> occurred' }
+ end
+ end
+
+ context 'when response status is 401' do
+ let(:status) { 401 }
+ let(:response) { I18n.t('tasks.export_external_confirm.not_authorized', account_link: account_link.name) }
+
+ it { is_expected.to eq response }
+ end
+
+ context 'when faraday throws an error' do
+ let(:connection) { instance_double(Faraday::Connection) }
+ let(:error) { Faraday::ServerError }
+
+ before do
+ allow(TaskService).to receive(:connection).and_return(connection)
+ allow(connection).to receive(:post).and_raise(error)
+ end
+
+ it { is_expected.to eql ERB::Util.html_escape(I18n.t('tasks.export_external_confirm.server_error', account_link: account_link.name)) }
end
end
context 'when an error occurs' do
+ let(:error) { StandardError.new('Standard error occurred') }
+
before do
- # Un-memoize the connection to force a reconnection
- described_class.instance_variable_set(:@connection, nil)
- allow(Faraday).to receive(:new).and_raise(StandardError)
+ allow(TaskService).to receive(:connection).and_raise(error)
end
- it { is_expected.not_to be_nil }
+ it { is_expected.to eql I18n.t('tasks.export_external_confirm.generic_error') }
end
end
end