Skip to content

Commit 641fe1c

Browse files
committed
migrate exercise show and update to ActiveStorage
1 parent e37cbc8 commit 641fe1c

File tree

15 files changed

+74
-76
lines changed

15 files changed

+74
-76
lines changed

app/controllers/code_ocean/files_controller.rb

Lines changed: 35 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ class FilesController < ApplicationController
66
include FileParameters
77

88
before_action :set_content_type_nosniff
9-
# Overwrite the CSP header and some default actions for the :render_protected_upload action
109
content_security_policy false, only: :render_protected_upload
1110
skip_before_action :deny_access_from_render_host, only: :render_protected_upload
1211
skip_before_action :verify_authenticity_token, only: :render_protected_upload
@@ -25,54 +24,54 @@ def show_protected_upload
2524
@file = CodeOcean::File.find(params[:id])
2625
authorize!
2726
# The `@file.name_with_extension` is assembled based on the user-selected file type, not on the actual file name stored on disk.
28-
raise Pundit::NotAuthorizedError if @embed_options[:disable_download] || @file.filepath != params[:filename] || @file.native_file.blank?
27+
raise Pundit::NotAuthorizedError if @embed_options[:disable_download] || @file.filepath != params[:filename] || @file.attachment.blank?
2928

30-
real_location = Pathname(@file.native_file.current_path).realpath
31-
send_file(real_location, type: 'application/octet-stream', filename: @file.name_with_extension, disposition: 'attachment')
29+
url = rails_blob_path(@file.attachment, disposition: 'attachment', expires_in: 5.minutes)
30+
redirect_to url, allow_other_host: true
3231
end
3332

3433
def render_protected_upload
3534
# Set @current_user with a new *learner* for Pundit checks
3635
@current_user = ExternalUser.new
3736

3837
@file = authorize AuthenticatedUrlHelper.retrieve!(CodeOcean::File, request)
39-
4038
# The `@file.name_with_extension` is assembled based on the user-selected file type, not on the actual file name stored on disk.
41-
raise Pundit::NotAuthorizedError unless @file.filepath == params[:filename] || @file.native_file.present?
39+
raise Pundit::NotAuthorizedError unless @file.filepath == params[:filename] || @file.attachment.present?
4240

43-
real_location = Pathname(@file.native_file.current_path).realpath
44-
send_file(real_location, type: @file.native_file.content_type, filename: @file.name_with_extension)
45-
end
41+
url = rails_blob_path(@file.attachment, disposition: 'inline', expires_in: 5.minutes)
4642

47-
def create
48-
@file = CodeOcean::File.new(file_params)
49-
if @file.file_template_id
50-
content = FileTemplate.find(@file.file_template_id).content
51-
content.sub! '{{file_name}}', @file.name
52-
@file.content = content
53-
end
54-
authorize!
55-
create_and_respond(object: @file, path: proc { implement_exercise_path(@file.context.exercise) })
43+
redirect_to url, allow_other_host: true
5644
end
5745

58-
def create_and_respond(options = {})
59-
@object = options[:object]
60-
respond_to do |format|
61-
if @object.save
62-
yield if block_given?
63-
path = options[:path].try(:call) || @object
64-
respond_with_valid_object(format, notice: t('shared.object_created', model: @object.class.model_name.human),
65-
path:, status: :created)
66-
else
67-
filename = "#{@object.path || ''}/#{@object.name || ''}#{@object.file_type.try(:file_extension) || ''}"
68-
format.html do
69-
flash[:danger] = t('code_ocean/files.error.filename', name: filename)
70-
redirect_to options[:path], status: :see_other
71-
end
72-
format.json { render json: @object.errors, status: :unprocessable_content }
73-
end
74-
end
75-
end
46+
# def create
47+
# @file = CodeOcean::File.new(file_params)
48+
# if @file.file_template_id
49+
# content = FileTemplate.find(@file.file_template_id).content
50+
# content.sub! '{{file_name}}', @file.name
51+
# @file.content = content
52+
# end
53+
# authorize!
54+
# create_and_respond(object: @file, path: proc { implement_exercise_path(@file.context.exercise) })
55+
# end
56+
#
57+
# def create_and_respond(options = {})
58+
# @object = options[:object]
59+
# respond_to do |format|
60+
# if @object.save
61+
# yield if block_given?
62+
# path = options[:path].try(:call) || @object
63+
# respond_with_valid_object(format, notice: t('shared.object_created', model: @object.class.model_name.human),
64+
# path:, status: :created)
65+
# else
66+
# filename = "#{@object.path || ''}/#{@object.name || ''}#{@object.file_type.try(:file_extension) || ''}"
67+
# format.html do
68+
# flash[:danger] = t('code_ocean/files.error.filename', name: filename)
69+
# redirect_to options[:path], status: :see_other
70+
# end
71+
# format.json { render json: @object.errors, status: :unprocessable_content }
72+
# end
73+
# end
74+
# end
7675

7776
def destroy
7877
@file = CodeOcean::File.find(params[:id])

app/controllers/concerns/file_parameters.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ def reject_illegal_file_attributes(exercise, params)
3333
private :reject_illegal_file_attributes
3434

3535
def file_attributes
36-
%w[content context_id feedback_message file_id file_type_id hidden id name native_file path read_only role weight
37-
file_template_id hidden_feedback]
36+
%w[content context_id feedback_message file_id file_type_id hidden id name path read_only role weight
37+
file_template_id hidden_feedback attachment]
3838
end
3939
private :file_attributes
4040
end

app/controllers/exercises_controller.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,12 +304,12 @@ def exercise_params_with_tags
304304
def handle_file_uploads
305305
if exercise_params
306306
exercise_params[:files_attributes].try(:each) do |_index, file_attributes|
307-
if file_attributes[:content].respond_to?(:read)
307+
if file_attributes[:attachment].respond_to?(:read)
308308
if FileType.find_by(id: file_attributes[:file_type_id]).try(:binary?)
309-
file_attributes[:native_file] = file_attributes[:content]
310309
file_attributes[:content] = nil
311310
else
312-
file_attributes[:content] = file_attributes[:content].read.detect_encoding!.encode.delete("\x00")
311+
file_attributes[:content] = file_attributes[:attachment].read.detect_encoding!.encode.delete("\x00")
312+
file_attributes[:attachment] = nil
313313
end
314314
end
315315
end

app/controllers/submissions_controller.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def download
6565
def download_file
6666
raise Pundit::NotAuthorizedError if @embed_options[:disable_download]
6767

68-
if @file.native_file?
68+
if @file.attachment.attached?
6969
redirect_to protected_upload_path(id: @file.id, filename: @file.filepath), status: :see_other
7070
else
7171
response.set_header('Content-Length', @file.size)
@@ -96,7 +96,7 @@ def render_file
9696
end
9797

9898
# Finally grant access and send the file
99-
if @file.native_file?
99+
if @file.attachment.attached?
100100
url = render_protected_upload_url(id: @file.id, filename: @file.filepath)
101101
redirect_to AuthenticatedUrlHelper.sign(url, @file), status: :see_other
102102
else

app/models/code_ocean/file.rb

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class File < ApplicationRecord
3636
has_many :events_synchronized_editor, class_name: 'Event::SynchronizedEditor'
3737
alias descendants files
3838

39-
mount_uploader :native_file, FileUploader
39+
has_one_attached :attachment
4040

4141
scope :editable, -> { where(read_only: false) }
4242
scope :visible, -> { where(hidden: false) }
@@ -73,21 +73,13 @@ class File < ApplicationRecord
7373
end
7474

7575
def read
76-
if native_file?
77-
return nil unless native_file_location_valid?
78-
79-
native_file.read
76+
if attachment.attached?
77+
attachment.download
8078
else
8179
content
8280
end
8381
end
8482

85-
def native_file_location_valid?
86-
real_location = Pathname(native_file.current_path).realpath
87-
upload_location = Pathname(::File.join(native_file.root, 'uploads')).realpath
88-
real_location.fnmatch? ::File.join(upload_location.to_s, '**')
89-
end
90-
9183
def ancestor_id
9284
file_id || id
9385
end
@@ -102,7 +94,7 @@ def teacher_defined_assessment?
10294
end
10395

10496
def content_present?
105-
content? || native_file?
97+
content? || attachment.attached?
10698
end
10799
private :content_present?
108100

@@ -123,7 +115,7 @@ def filepath_without_extension
123115
end
124116

125117
def hash_content
126-
self.hashed_content = Digest::MD5.new.hexdigest(read || '')
118+
self.hashed_content = Digest::MD5.new.hexdigest(read || '') # fix this!
127119
end
128120
private :hash_content
129121

@@ -158,8 +150,8 @@ def visible?
158150
end
159151

160152
def size
161-
@size ||= if native_file?
162-
native_file.size
153+
@size ||= if attachment.attached?
154+
attachment.byte_size
163155
else
164156
content.size
165157
end

app/policies/code_ocean/file_policy.rb

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ def author?
77
end
88

99
def show?
10-
return no_one if @record.native_file? && !@record.native_file_location_valid?
11-
1210
if @record.context.is_a?(Exercise)
1311
admin? || author? || !@record.hidden
1412
else
@@ -17,8 +15,6 @@ def show?
1715
end
1816

1917
def show_protected_upload?
20-
return no_one if @record.native_file? && !@record.native_file_location_valid?
21-
2218
if @record.context.is_a?(Exercise)
2319
admin? || author? || (!@record.context.unpublished && !@record.hidden)
2420
else
@@ -27,7 +23,6 @@ def show_protected_upload?
2723
end
2824

2925
def render_protected_upload?
30-
return no_one if @record.native_file? && !@record.native_file_location_valid?
3126
return no_one if @record.context.is_a?(Exercise) && (@record.context.unpublished || @record.hidden)
3227

3328
# The AuthenticatedUrlHelper will check for more details, but we cannot determine a specific user

app/services/proforma_service/convert_exercise_to_task.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ def filename(file)
211211
end
212212

213213
def add_content_to_task_file(file, task_file)
214-
if file.native_file.present?
214+
if file.attachment.attached?
215215
file_content = file.read
216216
task_file.content = file_content
217217
task_file.used_by_grader = false

app/services/proforma_service/convert_task_to_exercise.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ def codeocean_file_from_task_file(file, parent_object = nil)
119119
xml_id_path: (parent_object.nil? ? [file.id] : [parent_object.id, file.id]).map(&:to_s)
120120
)
121121
if file.binary
122-
codeocean_file.native_file = FileIO.new(file.content.dup.force_encoding('UTF-8'), File.basename(file.filename))
122+
codeocean_file.attachment.attach(io: StringIO.new(file.content.dup.force_encoding('UTF-8')), filename: file.filename)
123123
else
124124
codeocean_file.content = file.content
125125
end

app/views/exercises/_code_field.html.slim

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.mb-3
2-
= form.label(attribute, class: 'form-label')
3-
= form.text_area(attribute, class: 'code-field form-control', rows: 16, style: 'display:none;')
2+
= form.label('content', class: 'form-label')
3+
= form.text_area('content', class: 'code-field form-control', rows: 16, style: 'display:none;')
44
= render(partial: 'editor_edit', locals: {exercise: @exercise})
55
.card.border-warning.p-2.my-2
66
= form.file_field(attribute, class: 'form-control', style: 'display: inline-block;')

app/views/exercises/_editor_frame.html.slim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ div class=(defined?(own_solution) ? 'own-frame' : 'frame') data-executable=file.
1010
- elsif file.file_type.video?
1111
= video_tag(file_path, controls: true)
1212
- else
13-
= link_to(file.native_file.file.filename, file_path)
13+
= link_to(file.attachment.filename, file_path)
1414
- else
1515
.editor-content.d-none data-file-id=file.ancestor_id = file.content
1616
div class=(defined?(own_solution) ? 'own-editor' : 'editor') data-file-id=file.ancestor_id data-indent-size=file.file_type.indent_size data-mode=file.file_type.editor_mode data-allow-auto-completion=exercise.allow_auto_completion.to_s data-id=file.id

0 commit comments

Comments
 (0)