Skip to content

Commit 650e853

Browse files
authored
Add direct download of proforma zip (#2834)
add direct download of proforma zip
1 parent f6d4f03 commit 650e853

File tree

8 files changed

+66
-2
lines changed

8 files changed

+66
-2
lines changed

app/controllers/exercises_controller.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class ExercisesController < ApplicationController
1212
before_action :set_exercise_and_authorize,
1313
only: MEMBER_ACTIONS + %i[clone implement working_times intervention statistics reload feedback
1414
study_group_dashboard export_external_check export_external_confirm
15-
external_user_statistics]
15+
external_user_statistics download_proforma]
1616
before_action :collect_set_and_unset_exercise_tags, only: MEMBER_ACTIONS
1717
before_action :set_external_user_and_authorize, only: [:external_user_statistics]
1818
before_action :set_file_types, only: %i[create edit new update]
@@ -181,6 +181,13 @@ def import_task
181181
render json: t('exercises.import_codeharbor.import_errors.internal_error'), status: :internal_server_error
182182
end
183183

184+
def download_proforma
185+
zip_file = ProformaService::ExportTask.call(exercise: @exercise)
186+
send_data(zip_file.string, type: 'application/zip', filename: "exercise_#{@exercise.id}.zip", disposition: 'attachment')
187+
rescue ProformaXML::PostGenerateValidationError => e
188+
redirect_to :root, danger: JSON.parse(e.message).join('<br>')
189+
end
190+
184191
def user_from_api_key
185192
authorization_header = request.headers['Authorization']
186193
api_key = authorization_header&.split&.second

app/policies/exercise_policy.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ def batch_update?
55
admin?
66
end
77

8-
%i[show? feedback? statistics? external_user_statistics? rfcs_for_exercise?].each do |action|
8+
%i[show? feedback? statistics? external_user_statistics? rfcs_for_exercise? download_proforma?].each do |action|
99
define_method(action) { admin? || teacher_in_study_group? || (teacher? && @record.public?) || author? }
1010
end
1111

app/views/exercises/index.html.slim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ h1 = Exercise.model_name.human(count: :other)
5454
li = link_to(t('shared.destroy'), exercise, data: {confirm: t('shared.confirm_destroy')}, method: :delete, class: 'dropdown-item') if policy(exercise).destroy?
5555
li = link_to(t('.clone'), clone_exercise_path(exercise), data: {confirm: t('shared.confirm_destroy')}, method: :post, class: 'dropdown-item') if policy(exercise).clone?
5656
li = link_to(t('exercises.export_codeharbor.label'), '', class: 'dropdown-item export-start', data: {'exercise-id': exercise.id}) if policy(exercise).export_external_confirm?
57+
li = link_to(t('exercises.download_proforma.label'), download_proforma_exercise_path(exercise), class: 'dropdown-item', target: '_blank', rel: 'noopener noreferrer') if policy(exercise).download_proforma?
5758

5859
= render('shared/pagination', collection: @exercises)
5960
p = render('shared/new_button', model: Exercise)

app/views/exercises/show.html.slim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ h1.d-inline-block
2323
li = link_to(t('shared.destroy'), @exercise, data: {confirm: t('shared.confirm_destroy')}, method: :delete, class: 'dropdown-item') if policy(@exercise).destroy?
2424
li = link_to(t('exercises.index.clone'), clone_exercise_path(@exercise), data: {confirm: t('shared.confirm_destroy')}, method: :post, class: 'dropdown-item') if policy(@exercise).clone?
2525
li = link_to(t('exercises.export_codeharbor.label'), '', class: 'dropdown-item export-start', data: {'exercise-id': @exercise.id}) if policy(@exercise).export_external_confirm?
26+
li = link_to(t('exercises.download_proforma.label'), download_proforma_exercise_path(@exercise), class: 'dropdown-item', target: '_blank', rel: 'noopener noreferrer') if policy(@exercise).download_proforma?
2627

2728
= row(label: 'exercise.title', value: @exercise.title)
2829
= row(label: 'exercise.internal_title', value: @exercise.internal_title)

config/locales/de/exercise.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ de:
3737
download_file_tree:
3838
file_root: Erstellte Dateien
3939
gone: Die angeforderte Datei konnte nicht abgerufen werden. Erstellte Dateien werden nur kurzzeitig vorgehalten und dann gelöscht. Bitte führen Sie den Code erneut aus und versuchen Sie dann wieder den Download der Datei.
40+
download_proforma:
41+
label: ProformaXML ZIP herunterladen
4042
editor:
4143
collapse_action_sidebar: Aktions-Leiste Einklappen
4244
collapse_output_sidebar: Ausgabe-Leiste Einklappen

config/locales/en/exercise.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ en:
3737
download_file_tree:
3838
file_root: Generated Files
3939
gone: The requested file could not be retrieved. Generated files are only held for a short time and are then deleted. Please run the code again and then try downloading the file a second time.
40+
download_proforma:
41+
label: Download ProformaXML ZIP
4042
editor:
4143
collapse_action_sidebar: Collapse Action Sidebar
4244
collapse_output_sidebar: Collapse Output Sidebar

config/routes.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
get 'study_group_dashboard/:study_group_id', to: 'exercises#study_group_dashboard'
9292
post :export_external_check
9393
post :export_external_confirm
94+
get :download_proforma
9495
end
9596

9697
resources :programming_groups

spec/controllers/exercises_controller_spec.rb

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,4 +534,54 @@
534534
end
535535
end
536536
end
537+
538+
describe 'GET #download_proforma' do
539+
subject(:get_request) { get :download_proforma, params: {id: exercise.id} }
540+
541+
let(:zip) { instance_double(StringIO, string: 'dummy') }
542+
543+
context 'when export is successful' do
544+
before do
545+
allow(ProformaService::ExportTask).to receive(:call).with(exercise:).and_return(zip)
546+
end
547+
548+
it 'calls the ExportTask service' do
549+
get_request
550+
expect(ProformaService::ExportTask).to have_received(:call)
551+
end
552+
553+
it 'sends the correct data' do
554+
get_request
555+
expect(response.body).to eql 'dummy'
556+
end
557+
558+
it 'sets the correct Content-Type header' do
559+
get_request
560+
expect(response.header['Content-Type']).to eql 'application/zip'
561+
end
562+
563+
it 'sets the correct Content-Disposition header' do
564+
get_request
565+
expect(response.header['Content-Disposition']).to include "attachment; filename=\"exercise_#{exercise.id}.zip\""
566+
end
567+
end
568+
569+
context 'when export fails with PostGenerateValidationError' do
570+
let(:error_message) { '["Error 1", "Error 2"]' }
571+
572+
before do
573+
allow(ProformaService::ExportTask).to receive(:call).with(exercise:).and_raise(ProformaXML::PostGenerateValidationError.new(error_message))
574+
end
575+
576+
it 'redirects to root' do
577+
get_request
578+
expect(response).to redirect_to(:root)
579+
end
580+
581+
it 'sets a danger flash message' do
582+
get_request
583+
expect(flash[:danger]).to eq('Error 1<br>Error 2')
584+
end
585+
end
586+
end
537587
end

0 commit comments

Comments
 (0)