Skip to content

Commit

Permalink
refactor xml_id_path to use array
Browse files Browse the repository at this point in the history
  • Loading branch information
kkoehn committed Nov 19, 2024
1 parent 9347d76 commit 6b8c04b
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 24 deletions.
13 changes: 7 additions & 6 deletions app/services/proforma_service/convert_exercise_to_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def create_task

def proglang
regex = %r{^openhpi/co_execenv_(?<language>[^:]*):(?<version>[^-]*)(?>-.*)?$}
match = regex.match @exercise.execution_environment.docker_image
match = regex.match @exercise&.execution_environment&.docker_image
match ? {name: match[:language], version: match[:version]} : nil
end

Expand Down Expand Up @@ -105,18 +105,19 @@ def tests
end

def xml_id_from_file(file)
xml_id_path = file.xml_id_path || []
return xml_id_path if xml_id_path&.any?

type = if file.teacher_defined_assessment?
'test'
elsif file.reference_implementation?
'ms'
else
'file'
end
xml_id_path_parts = file.xml_id_path&.split('/')
xml_id_path = []

xml_id_path << (xml_id_path_parts&.first || "co-#{type}-#{file.id}") unless type == 'file'
xml_id_path << (xml_id_path_parts&.last || file.id)
xml_id_path << "co-#{type}-#{file.id}" unless type == 'file'
xml_id_path << file.id.to_s

xml_id_path
end
Expand Down Expand Up @@ -190,7 +191,7 @@ def task_files
end

def task_file(file)
file.update(xml_id_path: xml_id_from_file(file).join('/')) if file.xml_id_path.blank?
file.update(xml_id_path: xml_id_from_file(file)) if file.xml_id_path.blank?

xml_id = xml_id_from_file(file).last
task_file = ProformaXML::TaskFile.new(
Expand Down
9 changes: 5 additions & 4 deletions app/services/proforma_service/convert_task_to_exercise.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def import_task

def extract_meta_data(meta_data, *path)
current_level = meta_data
path.each {|attribute| current_level = current_level&.dig("CodeOcean:#{attribute}") }
path.each {|attribute| current_level = current_level.is_a?(Hash) ? current_level&.dig("CodeOcean:#{attribute}") : current_level&.find {|entry| entry['@id'] == attribute } } # || current_level
current_level&.dig('$1')
end

Expand Down Expand Up @@ -81,6 +81,7 @@ def model_solution_files
model_solution.files.map do |task_file|
codeocean_file_from_task_file(task_file, model_solution).tap do |file|
file.role ||= 'reference_implementation'
file.feedback_message = nil
end
end
end
Expand All @@ -90,14 +91,14 @@ def task_files
@task.files.reject {|file| file.id == 'ms-placeholder-file' }.map do |task_file|
codeocean_file_from_task_file(task_file).tap do |file|
file.role ||= 'regular_file'
file.feedback_message = nil
end
end
end

def codeocean_file_from_task_file(file, parent_object = nil)
extension = File.extname(file.filename)

codeocean_file = CodeOcean::File.where(context: @exercise).where('xml_id_path = ? OR xml_id_path LIKE ?', file.id, "%/#{file.id}").first_or_initialize(context: @exercise)
codeocean_file = @exercise.files.where('array_length(xml_id_path, 1) IS NOT NULL AND xml_id_path[array_length(xml_id_path, 1)] = ?', file.id).first_or_initialize
codeocean_file.assign_attributes(
context: @exercise,
file_type: file_type(extension),
Expand All @@ -106,7 +107,7 @@ def codeocean_file_from_task_file(file, parent_object = nil)
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),
xml_id_path: (parent_object.nil? ? '' : "#{parent_object.id}/") + file.id.to_s
xml_id_path: (parent_object.nil? ? [file.id] : [parent_object.id, file.id]).map(&:to_s)
)
if file.binary
codeocean_file.native_file = FileIO.new(file.content.dup.force_encoding('UTF-8'), File.basename(file.filename))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

class AddXmlPathToFiles < ActiveRecord::Migration[7.1]
def change
add_column :files, :xml_id_path, :string, null: true, default: nil
add_column :files, :xml_id_path, :string, array: true, default: [], null: true
end
end
4 changes: 2 additions & 2 deletions db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 17 additions & 6 deletions spec/services/proforma_service/convert_exercise_to_task_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@
execution_environment:,
instructions: 'instruction',
uuid: SecureRandom.uuid,
files: files + tests)
files: files + tests,
unpublished:)
end
let(:unpublished) { false }
let(:files) { [] }
let(:tests) { [] }
let(:execution_environment) { create(:java) }
Expand Down Expand Up @@ -77,6 +79,15 @@
end
end

context 'when exercise has no execution_environment' do
let(:execution_environment) { nil }
let(:unpublished) { true }

it 'creates a task with the correct proglang attribute' do
expect(task).to have_attributes(proglang: nil)
end
end

context 'when exercise has a mainfile' do
let(:files) { [file] }
let(:file) { create(:file) }
Expand Down Expand Up @@ -111,13 +122,13 @@
end

it 'sets xml_id_path to default' do
expect { convert_to_task.execute }.to change(file.reload, :xml_id_path).from(nil).to(file.id.to_s)
expect { convert_to_task.execute }.to change(file.reload, :xml_id_path).from([]).to([file.id.to_s])
end

context 'when xml_id_path is set for file' do
let(:file) { create(:file, xml_id_path: 'foobar') }
let(:file) { create(:file, xml_id_path: ['foobar']) }

it 'does not change xml_path_id' do
it 'does not change xml_id_path' do
expect { convert_to_task.execute }.not_to change(file.reload, :xml_id_path)
end
end
Expand Down Expand Up @@ -224,7 +235,7 @@
end

context 'when reference_implementations belong to the same proforma model_solution' do
let(:files) { build_list(:file, 2, role: 'reference_implementation') {|file, i| file.xml_id_path = "proforma_ms/xml_id_#{i}" } }
let(:files) { build_list(:file, 2, role: 'reference_implementation') {|file, i| file.xml_id_path = ['proforma_ms', "xml_id_#{i}"] } }

it 'creates a task with one model-solution' do
expect(task.model_solutions).to have(1).items
Expand Down Expand Up @@ -294,7 +305,7 @@
end

context 'when test_files belong to the same proforma test' do
let(:tests) { build_list(:test_file, 2) {|file, i| file.xml_id_path = "proforma_test/xml_id_#{i}" } }
let(:tests) { build_list(:test_file, 2) {|file, i| file.xml_id_path = ['proforma_test', "xml_id_#{i}"] } }

it 'creates a test with two file' do
expect(task.tests.first).to have_attributes(
Expand Down
21 changes: 17 additions & 4 deletions spec/services/proforma_service/convert_task_to_exercise_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -558,21 +558,34 @@
context 'when the files with correct xml_id_paths already exist' do
let(:exercise) do
create(:dummy,
unpublished: true,
files: co_files,
title: 'exercise-title',
description: 'exercise-description')
end
let(:co_files) do
[create(:file, xml_id_path: 'id', role: 'regular_file'),
create(:file, xml_id_path: 'ms-id/ms-file-id', role: 'reference_implementation'),
create(:test_file, xml_id_path: 'test-id/test-file-id')]
[create(:file, xml_id_path: ['id'], role: 'regular_file'),
create(:file, xml_id_path: %w[ms-id ms-file-id], role: 'reference_implementation'),
create(:test_file, xml_id_path: %w[test-id test-file-id])]
end

it 'reuses existing file' do
convert_to_exercise_service

exercise.save!
expect(exercise.reload.files).to match_array(co_files)
end

context 'when files are move around' do
let(:files) { [test_file] }
let(:test_files) { [ms_file] }
let(:ms_files) { [file] }

it 'reuses existing file' do
convert_to_exercise_service
exercise.save!
expect(exercise.reload.files).to match_array(co_files)
end
end
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion spec/services/proforma_service/import_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@
end

context 'when exercise has multiple tests' do
let(:tests) { build_list(:test_file, 2) }
let(:tests) { [build(:test_file, xml_id_path: %w[test file1]), build(:test_file, xml_id_path: %w[test file2])] }

it { is_expected.to be_an_equal_exercise_as exercise }
end
Expand Down

0 comments on commit 6b8c04b

Please sign in to comment.