Skip to content

Commit ccf63fe

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

File tree

22 files changed

+81
-110
lines changed

22 files changed

+81
-110
lines changed

app/controllers/code_ocean/files_controller.rb

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,23 @@ def show_protected_upload
2525
@file = CodeOcean::File.find(params[:id])
2626
authorize!
2727
# 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?
28+
raise Pundit::NotAuthorizedError if @embed_options[:disable_download] || @file.filepath != params[:filename] || @file.attachment.blank?
2929

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')
30+
url = rails_blob_path(@file.attachment, disposition: 'attachment', expires_in: 5.minutes)
31+
redirect_to url, allow_other_host: true
3232
end
3333

3434
def render_protected_upload
3535
# Set @current_user with a new *learner* for Pundit checks
3636
@current_user = ExternalUser.new
3737

3838
@file = authorize AuthenticatedUrlHelper.retrieve!(CodeOcean::File, request)
39-
4039
# 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?
40+
raise Pundit::NotAuthorizedError unless @file.filepath == params[:filename] || @file.attachment.present?
41+
42+
url = rails_blob_path(@file.attachment, disposition: 'inline', expires_in: 5.minutes)
4243

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)
44+
redirect_to url, allow_other_host: true
4545
end
4646

4747
def create

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: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ class File < ApplicationRecord
1616

1717
after_initialize :set_default_values
1818
before_validation :clear_weight, unless: :teacher_defined_assessment?
19-
before_validation :hash_content, if: :content_present?
2019
before_validation :set_ancestor_values, if: :incomplete_descendent?
2120

2221
attr_writer :size
@@ -36,7 +35,7 @@ class File < ApplicationRecord
3635
has_many :events_synchronized_editor, class_name: 'Event::SynchronizedEditor'
3736
alias descendants files
3837

39-
mount_uploader :native_file, FileUploader
38+
has_one_attached :attachment
4039

4140
scope :editable, -> { where(read_only: false) }
4241
scope :visible, -> { where(hidden: false) }
@@ -50,7 +49,6 @@ class File < ApplicationRecord
5049

5150
validates :feedback_message, if: :teacher_defined_assessment?, presence: true
5251
validates :feedback_message, absence: true, unless: :teacher_defined_assessment?
53-
validates :hashed_content, if: :content_present?, presence: true
5452
validates :hidden, inclusion: [true, false]
5553
validates :hidden_feedback, inclusion: [true, false]
5654
validates :name, presence: true
@@ -73,21 +71,13 @@ class File < ApplicationRecord
7371
end
7472

7573
def read
76-
if native_file?
77-
return nil unless native_file_location_valid?
78-
79-
native_file.read
74+
if attachment.attached?
75+
attachment.download
8076
else
8177
content
8278
end
8379
end
8480

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-
9181
def ancestor_id
9282
file_id || id
9383
end
@@ -102,7 +92,7 @@ def teacher_defined_assessment?
10292
end
10393

10494
def content_present?
105-
content? || native_file?
95+
content? || attachment.attached?
10696
end
10797
private :content_present?
10898

@@ -122,11 +112,6 @@ def filepath_without_extension
122112
end
123113
end
124114

125-
def hash_content
126-
self.hashed_content = Digest::MD5.new.hexdigest(read || '')
127-
end
128-
private :hash_content
129-
130115
def incomplete_descendent?
131116
file_id.present? && file_type_id.blank?
132117
end
@@ -158,8 +143,8 @@ def visible?
158143
end
159144

160145
def size
161-
@size ||= if native_file?
162-
native_file.size
146+
@size ||= if attachment.attached?
147+
attachment.byte_size
163148
else
164149
content.size
165150
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)