diff --git a/app/services/exercise_service/push_external.rb b/app/services/exercise_service/push_external.rb
index d8ed09fbf..61f48a218 100644
--- a/app/services/exercise_service/push_external.rb
+++ b/app/services/exercise_service/push_external.rb
@@ -17,11 +17,22 @@ def execute
request.headers['Authorization'] = "Bearer #{@codeharbor_link.api_key}"
request.body = body
end
+ return nil if response.success?
+ return I18n.t('exercises.export_codeharbor.not_authorized') if response.status == 401
- response.success? ? nil : response.body
+ handle_error(message: response.body)
+ rescue Faraday::ServerError => e
+ handle_error(error: e, message: I18n.t('exercises.export_codeharbor.server_error'))
rescue StandardError => e
- e.message
+ handle_error(error: e, message: I18n.t('exercises.export_codeharbor.generic_error'))
end
end
+
+ private
+
+ def handle_error(message:, error: nil)
+ Sentry.capture_exception(error) if error.present?
+ ERB::Util.html_escape(message)
+ end
end
end
diff --git a/config/locales/de/exercise.yml b/config/locales/de/exercise.yml
index 97b144bfb..5e7f06eb0 100644
--- a/config/locales/de/exercise.yml
+++ b/config/locales/de/exercise.yml
@@ -101,7 +101,10 @@ de:
dialogtitle: Zu CodeHarbor exportieren
error: Es ist ein Fehler bei der Kommunikation mit CodeHarbor aufgetreten.
export_failed: 'Export ist fehlgeschlagen.
ID: %{id}
Title: %{title}
Error: %{error}'
+ generic_error: Ein unbekannter Fehler ist beim exportieren der Aufgabe aufgetreten.
label: Zu CodeHarbor exportieren
+ not_authorized: Die Autorisierung mit CodeHarbor konnte nicht hergestellt werden. Ist der API-Schlüssel korrekt?
+ server_error: Verbindung zu CodeHarbor fehlgeschlagen. Gegenseite nicht erreichbar.
successfully_exported: 'Aufgabe wurde erfolgreich exportiert.
ID: %{id}
Title: %{title}'
external_users:
statistics:
diff --git a/config/locales/en/exercise.yml b/config/locales/en/exercise.yml
index 3f9e04b15..149529fad 100644
--- a/config/locales/en/exercise.yml
+++ b/config/locales/en/exercise.yml
@@ -101,7 +101,10 @@ en:
dialogtitle: Export to CodeHarbor
error: An error occurred while contacting CodeHarbor
export_failed: 'Export has failed.
ID: %{id}
Title: %{title}
Error: %{error}'
+ generic_error: An unknown error has occurred while exporting the exercise.
label: Export to CodeHarbor
+ not_authorized: Authorization with could not be established with CodeHarbor. Is the API Key correct?
+ server_error: Connection to CodeHarbor failed. Remote host unreachable.
successfully_exported: 'Exercise has been successfully exported.
ID: %{id}
Title: %{title}'
external_users:
statistics:
diff --git a/spec/services/exercise_service/push_external_spec.rb b/spec/services/exercise_service/push_external_spec.rb
index 24e428b50..33071023a 100644
--- a/spec/services/exercise_service/push_external_spec.rb
+++ b/spec/services/exercise_service/push_external_spec.rb
@@ -26,7 +26,11 @@
let(:status) { 200 }
let(:response) { '' }
- before { stub_request(:post, codeharbor_link.push_url).to_return(status:, body: response) }
+ before do
+ # Un-memoize the connection to force a reconnection for each example
+ described_class.instance_variable_set(:@connection, nil)
+ stub_request(:post, codeharbor_link.push_url).to_return(status:, body: response)
+ end
it 'calls the correct url' do
expect(push_external).to have_requested(:post, codeharbor_link.push_url)
@@ -49,16 +53,45 @@
context 'when response status is 500' do
let(:status) { 500 }
- let(:response) { 'an error occured' }
+ let(:response) { 'an error occurred' }
+
+ 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
+
+ context 'when faraday throws an error' do
+ let(:connection) { instance_double(Faraday::Connection) }
+ let(:error) { Faraday::ServerError }
+
+ before do
+ allow(Faraday).to receive(:new).and_return(connection)
+ allow(connection).to receive(:post).and_raise(error)
+ end
+
+ it { is_expected.to eql I18n.t('exercises.export_codeharbor.server_error') }
+
+ context 'when another error occurs' do
+ let(:error) { 'another error' }
+
+ it { is_expected.to eql I18n.t('exercises.export_codeharbor.generic_error') }
+ end
+ end
+ end
+
+ context 'when response status is 401' do
+ let(:status) { 401 }
+ let(:response) { I18n.t('exercises.export_codeharbor.not_authorized') }
- it { is_expected.to be response }
+ it { is_expected.to eql response }
end
end
context 'when an error occurs' do
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)
end