Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/models/code_ocean/file.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ class File < ApplicationRecord
validates :weight, absence: true, unless: :teacher_defined_assessment?
validates :file, presence: true if :context.is_a?(Submission)
validates :context_type, inclusion: {in: ALLOWED_CONTEXT_TYPES}
validates :path, uniqueness: {scope: %I[name file_type context_id context_type role]}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we have records that have this issue right now? I am worried that this migration will suddenly stop teachers from editing the file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about any existing records, since I don't have access, but it would indeed be important to check before merging this PR.


# xml_id_path must be unique within the scope of an exercise.
# Initially, it may match the record’s id (set while exporting),
# but it can later diverge as long as uniqueness is preserved.
Expand Down
12 changes: 8 additions & 4 deletions app/services/proforma_service/convert_task_to_exercise.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def string_to_bool(str)
end

def files
model_solution_files + test_files + task_files
(model_solution_files + test_files + task_files).uniq {|f| [f.name, f.file_type_id, f.role, f.path] }
end

def test_files
Expand Down Expand Up @@ -106,16 +106,20 @@ def task_files

def codeocean_file_from_task_file(file, parent_object = nil)
extension = File.extname(file.filename)
path = File.dirname(file.filename).in?(['.', '']) ? nil : File.dirname(file.filename)
name = File.basename(file.filename, '.*')
role = extract_meta_data(@task.meta_data&.dig('meta-data'), 'files', "CO-#{file.id}", 'role')

# checking the last element of xml_id_path array for file.id
codeocean_file = @exercise.files.detect {|f| f.xml_id_path.last == file.id } || @exercise.files.new
codeocean_file.assign_attributes(
context: @exercise,
file_type: file_type(extension),
hidden: file.visible != 'yes', # hides 'delayed' and 'no'
name: File.basename(file.filename, '.*'),
name:,
read_only: file.usage_by_lms != 'edit',
role: extract_meta_data(@task.meta_data&.dig('meta-data'), 'files', "CO-#{file.id}", 'role'),
path: File.dirname(file.filename).in?(['.', '']) ? nil : File.dirname(file.filename),
role:,
path:,
xml_id_path: (parent_object.nil? ? [file.id] : [parent_object.id, file.id]).map(&:to_s)
)
if file.binary
Expand Down
14 changes: 14 additions & 0 deletions spec/models/code_ocean/file_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,18 @@
end
end
end

context 'when a file with same attributes (path, name file_type context_id context_type role) already exists' do
before do
create(:file, name: 'static', context: exercise)
file.validate
end

let(:exercise) { create(:dummy) }
let(:file) { build(:file, name: 'static', context: exercise) }

it 'has an error for path' do
expect(file.errors[:path]).to be_present
end
end
end
25 changes: 23 additions & 2 deletions spec/services/proforma_service/convert_task_to_exercise_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,27 @@
expect { convert_to_exercise_service.save! }.to change(Exercise, :count).by(1)
end

context 'with two files with similar contents' do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I apologize for my lack of understanding. Should we not ensure that the exported file has no duplicates? Won't we have the same issue in CodeHarbor after exporting the it from CodeHarbor and importing it again to CodeHarbor?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the duplicates some requirement in the ProformaXML spec?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be preferable to also fix the export of CodeHarbor, since I only addressed the import of tasks with multi-referenced files and not the export.

It would be even better to enable CodeHarbor to support the multi-referenced files directly (which would require a serious time investment).

let(:file_dup) do
ProformaXML::TaskFile.new(
id: 'id2',
content:,
filename:,
used_by_grader: 'used_by_grader',
visible: 'yes',
usage_by_lms:,
binary:,
mimetype:
)
end

let(:files) { [file, file_dup] }

it 'creates an exercises with only one file' do
expect(convert_to_exercise_service.files.length).to be 1
end
end

context 'when file is a Makefile' do
let(:filename) { "#{path}Makefile" }

Expand Down Expand Up @@ -346,7 +367,7 @@
ProformaXML::TaskFile.new(
id: 'ms-file-2',
content: 'content',
filename: 'filename.txt',
filename: 'filename2.txt',
used_by_grader: 'used_by_grader',
visible: 'yes',
usage_by_lms: 'display',
Expand Down Expand Up @@ -456,7 +477,7 @@
ProformaXML::TaskFile.new(
id: 'test_file_id2',
content: 'testfile-content',
filename: 'testfile.txt',
filename: 'testfile2.txt',
used_by_grader: 'yes',
visible: 'no',
usage_by_lms: 'display',
Expand Down