Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 78dd7ba

Browse files
committedMar 19, 2025·
add direct download of proforma zip
1 parent e3103d5 commit 78dd7ba

File tree

8 files changed

+46
-2
lines changed

8 files changed

+46
-2
lines changed
 

‎app/controllers/exercises_controller.rb

+8-1
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).map {|msg| t("proforma_errors.#{msg}", default: msg) }.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

+1-1
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

+1
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') 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

+1
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') 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

+2
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: Download Proforma Zip
4042
editor:
4143
collapse_action_sidebar: Aktions-Leiste Einklappen
4244
collapse_output_sidebar: Ausgabe-Leiste Einklappen

‎config/locales/en/exercise.yml

+2
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 Proforma Zip
4042
editor:
4143
collapse_action_sidebar: Collapse Action Sidebar
4244
collapse_output_sidebar: Collapse Output Sidebar

‎config/routes.rb

+1
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

+30
Original file line numberDiff line numberDiff line change
@@ -518,4 +518,34 @@
518518
end
519519
end
520520
end
521+
522+
describe 'GET #download_proforma' do
523+
subject(:get_request) { get :download_proforma, params: {id: exercise.id} }
524+
525+
let(:zip) { instance_double(StringIO, string: 'dummy') }
526+
527+
before do
528+
allow(ProformaService::ExportTask).to receive(:call).with(exercise:).and_return(zip)
529+
end
530+
531+
it 'calls the ExportTask service' do
532+
get_request
533+
expect(ProformaService::ExportTask).to have_received(:call)
534+
end
535+
536+
it 'sends the correct data' do
537+
get_request
538+
expect(response.body).to eql 'dummy'
539+
end
540+
541+
it 'sets the correct Content-Type header' do
542+
get_request
543+
expect(response.header['Content-Type']).to eql 'application/zip'
544+
end
545+
546+
it 'sets the correct Content-Disposition header' do
547+
get_request
548+
expect(response.header['Content-Disposition']).to include "attachment; filename=\"exercise_#{exercise.id}.zip\""
549+
end
550+
end
521551
end

0 commit comments

Comments
 (0)
Please sign in to comment.