# frozen_string_literal: true require 'mimemagic' module ProformaService class ConvertExerciseToTask < ServiceBase DEFAULT_LANGUAGE = 'de' def initialize(exercise: nil) super() @exercise = exercise end def execute create_task end private def create_task ProformaXML::Task.new( { title: @exercise.title, description: @exercise.description, internal_description: nil, proglang:, files: task_files, tests:, uuid:, language: DEFAULT_LANGUAGE, model_solutions:, meta_data: { '@@order' => %w[meta-data], 'meta-data' => { '@@order' => %w[CodeOcean:public CodeOcean:hide_file_tree CodeOcean:allow_file_creation CodeOcean:allow_auto_completion CodeOcean:expected_difficulty CodeOcean:execution_environment_id CodeOcean:files], '@xmlns' => {'CodeOcean' => 'codeocean.openhpi.de'}, 'CodeOcean:public' => { '@@order' => %w[$1], '$1' => @exercise.public, }, 'CodeOcean:hide_file_tree' => { '@@order' => %w[$1], '$1' => @exercise.hide_file_tree, }, 'CodeOcean:allow_file_creation' => { '@@order' => %w[$1], '$1' => @exercise.allow_file_creation, }, 'CodeOcean:allow_auto_completion' => { '@@order' => %w[$1], '$1' => @exercise.allow_auto_completion, }, 'CodeOcean:expected_difficulty' => { '@@order' => %w[$1], '$1' => @exercise.expected_difficulty, }, 'CodeOcean:execution_environment_id' => { '@@order' => %w[$1], '$1' => @exercise.execution_environment_id, }, 'CodeOcean:files' => task_files_meta_data, }, }, }.compact ) end def proglang regex = %r{^openhpi/co_execenv_(?[^:]*):(?[^-]*)(?>-.*)?$} match = regex.match @exercise.execution_environment.docker_image match ? {name: match[:language], version: match[:version]} : nil end def uuid @exercise.update(uuid: SecureRandom.uuid) if @exercise.uuid.nil? @exercise.uuid end def model_solutions @exercise.files.filter {|file| file.role == 'reference_implementation' }.map do |file| ProformaXML::ModelSolution.new( id: "ms-#{file.id}", files: model_solution_file(file) ) end end def model_solution_file(file) [ task_file(file).tap do |ms_file| ms_file.used_by_grader = false ms_file.usage_by_lms = 'display' end, ] end def tests @exercise.files.filter(&:teacher_defined_assessment?).map do |file| ProformaXML::Test.new( id: file.id, title: file.name, files: test_file(file), meta_data: test_meta_data(file) ) end end def test_meta_data(file) { '@@order' => %w[test-meta-data], 'test-meta-data' => { '@@order' => %w[CodeOcean:feedback-message CodeOcean:weight CodeOcean:hidden-feedback], '@xmlns' => {'CodeOcean' => 'codeocean.openhpi.de'}, 'CodeOcean:feedback-message' => { '@@order' => %w[$1], '$1' => file.feedback_message, }, 'CodeOcean:weight' => { '@@order' => %w[$1], '$1' => file.weight, }, 'CodeOcean:hidden-feedback' => { '@@order' => %w[$1], '$1' => file.hidden_feedback, }, }, } end def test_file(file) [ task_file(file).tap do |t_file| t_file.used_by_grader = true end, ] end def exercise_files @exercise.files.filter do |file| !file.role.in? %w[reference_implementation teacher_defined_test teacher_defined_linter] end end def task_files_meta_data task_files_hash = { '@@order' => [], } exercise_files.each do |file| task_files_hash['@@order'] << "CodeOcean:CO-#{file.id}" task_files_hash["CodeOcean:CO-#{file.id}"] = { '@@order' => ['CodeOcean:role'], 'CodeOcean:role' => { '@@order' => ['$1'], '$1' => file.role, }, } end task_files_hash end def task_files exercise_files.map do |file| task_file(file) end end def task_file(file) task_file = ProformaXML::TaskFile.new( id: file.id, filename: filename(file), usage_by_lms: file.read_only ? 'display' : 'edit', visible: file.hidden ? 'no' : 'yes' ) add_content_to_task_file(file, task_file) task_file end def filename(file) if file.path.present? && file.path != '.' ::File.join(file.path, file.name_with_extension) else file.name_with_extension end end def add_content_to_task_file(file, task_file) if file.native_file.present? file_content = file.read task_file.content = file_content task_file.used_by_grader = false task_file.binary = true task_file.mimetype = MimeMagic.by_magic(file_content).type else task_file.content = file.content task_file.used_by_grader = true task_file.binary = false end end end end