diff --git a/Gemfile.lock b/Gemfile.lock index 467b245ea..5937319f1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -351,7 +351,7 @@ GEM responders (3.1.1) actionpack (>= 5.2) railties (>= 5.2) - rexml (3.3.3) + rexml (3.3.6) strscan rouge (4.2.0) rspec-core (3.12.2) diff --git a/app/controllers/assessment/handin.rb b/app/controllers/assessment/handin.rb index 2874ee253..d78886969 100755 --- a/app/controllers/assessment/handin.rb +++ b/app/controllers/assessment/handin.rb @@ -277,59 +277,6 @@ def log_submit ASSESSMENT_LOGGER.setAssessment(@assessment) ASSESSMENT_LOGGER.log("#{@user.email},0,#{@result}") - # Load up the lab.rb file - mod_name = @assessment.name + (@course.name).gsub(/[^A-Za-z0-9]/, "") - require(Rails.root.join("assessmentConfig", "#{@course.name}-#{@assessment.name}.rb")) - eval("extend #{mod_name.camelcase}") - - begin - # Call the parseAutoresult function defined in the lab.rb file. If - # the list of scores it returns is empty, then we the lab developer is - # asking us not to create an unofficial submission in the - # database. Simply return a successful status string to the client and - # exit. - scores = parseAutoresult(@result, false) - - render(plain: "OK", status: 200) && return if scores.keys.length == 0 - - # Try to find an existing submission (always version 0). - submission = @assessment.submissions.find_by(version: 0, course_user_datum_id: @cud.id) - if !submission - submission = @assessment.submissions.new( - version: 0, - autoresult: @result, - user_id: @cud.id, - submitted_by_id: 0, - ) - submission.save! - else - # update this one - submission.autoresult = @result - submission.created_at = Time.now - submission.save! - end - - # Update the scores in the db's unofficial submission using the list - # returned by the parseAutoresult function - scores.keys.each do |key| - problem = @assessment.problems.find_by(name: key) - score = submission.scores.find_or_initialize_by(problem_id: problem.id) - score.score = scores[key] - score.released = true - score.grader_id = 0 - score.save! - end - rescue StandardError => e - ExceptionNotifier.notify_exception(e, env: request.env, - data: { - user: current_user, - course: @course, - assessment: @assessment, - submission: submission, - }) - COURSE_LOGGER.log(e.to_s) - end - render(plain: "OK", status: 200) && return end diff --git a/app/models/assessment.rb b/app/models/assessment.rb index 13de87225..32dc35e3f 100755 --- a/app/models/assessment.rb +++ b/app/models/assessment.rb @@ -300,6 +300,36 @@ def dump_yaml File.open(asmt_yaml_path, "w") { |f| f.write(YAML.dump(sort_hash(serialize))) } end + # If the name field in a yaml for an assessment differs from the folder name + # then the name field for the assessment gets overridden, which then causes + # the yaml file to no longer be found, and then for cleanup to fail because + # the folder can no longer also be found. For example a folder with + # homework01 and a homework01.yml file but with a name field of homework02 + # would cause assessment.name = homework02 so then it would try to find + # homework02/homework02.yml. Instead we rename the name field to match the folder + # name. + # Similarly for a bunch of other fields in the yaml, if they are not provided, + # then we may run into issues loading the assessment + def validate_yaml(yaml_map) + unless yaml_map["general"] + raise "General section missing in yaml" + end + + if yaml_map["general"]["name"] != name + yaml_map["general"]["name"] = name + end + # ensure display name is present, otherwise fill in with name + if yaml_map["general"]["display_name"].blank? + yaml_map["general"]["display_name"] = name + end + if yaml_map["general"]["handin_directory"].blank? + yaml_map["general"]["handin_directory"] = "handin" + end + return if yaml_map["general"]["handin_filename"].present? + + yaml_map["general"]["handin_filename"] = "handin.c" + end + ## # reads from the properties of the YAML file and saves them to the assessment. # Will only run if the assessment has not been saved. @@ -308,6 +338,7 @@ def load_yaml return unless new_record? props = YAML.safe_load(File.open(asmt_yaml_path, "r", &:read)) + validate_yaml(props) backwards_compatibility(props) deserialize(props) end @@ -576,8 +607,11 @@ def deserialize(s) raise "General section missing in yaml" end - if s["dates"] && s["dates"]["start_at"] - if s["dates"]["due_at"] && s["dates"]["end_at"] + # ensure that if date fields are provided, they are + # valid, fill in dates based on whatever fields are provided + # or fill in automatically if no dates provided + if s["dates"] && s["dates"]["start_at"].present? + if s["dates"]["due_at"].present? && s["dates"]["end_at"].present? self.due_at = Time.zone.parse(s["dates"]["due_at"]) self.start_at = Time.zone.parse(s["dates"]["start_at"]) self.end_at = Time.zone.parse(s["dates"]["end_at"]) @@ -590,6 +624,7 @@ def deserialize(s) self.quiz = false self.quizData = "" + update!(s["general"]) Problem.deserialize_list(self, s["problems"]) if s["problems"]