media3-0/apki.org

View on GitHub
app/lib/course/course_checker.rb

Summary

Maintainability
A
2 hrs
Test Coverage
module Course
  class CourseChecker
    def self.validate_lesson(lesson, user_course)
      valid_lesson = true
      lesson.course_exercises.each { |exercise| valid_lesson = false unless user_course.exercises.key? exercise.id.to_s }
       valid_lesson = false unless user_course.quizzes.include? lesson.id.to_s
      valid_lesson
    end

    def self.check_quizes(lesson, data, json_response)
      json_response['quizzes'] = {}
      lesson_correct = true
      lesson.course_quizs.each do |quiz|
        lesson_correct = false unless check_quiz data, json_response, quiz
      end
      lesson_correct
    end

    def self.check_excercise(exercise, data, json_response, output)
      conn = Faraday.new(url: Rails.configuration.x.compile_api_host) do |faraday|
        faraday.request :url_encoded
        faraday.response :logger
        faraday.adapter Faraday.default_adapter
      end

      code = ''
      code << exercise.data['code_before']
      code << "\n"
      code << data['code']
      code << "\n"
      code << exercise.data['code_after']

      response = conn.post do |req|
        req.url '/compile'
        req.headers['Content-Type'] = 'application/json'
        req.body = { lang: exercise.data['lang'], code: code, user_input: data['user_input'] }.to_json
      end

      output.merge! JSON.parse(response.body.to_s)
      json_response['output'] = output

      check_compiled_code data['code'], exercise.data['expected_result_expr'], output['output'], data['user_input']
    end

    private

    def self.check_quiz(data, json_response, quiz)
      correct = true
      unless data['quizzes'].key? quiz.id.to_s
        json_response['quizzes'][quiz.id.to_s] = false
        correct = false
      end
      answer = data['quizzes'][quiz.id.to_s]
      if quiz.data['answer_idx'] == answer
        json_response['quizzes'][quiz.id.to_s] = true
      else
        json_response['quizzes'][quiz.id.to_s] = false
        correct = false
      end
      correct
    end

    def self.check_compiled_code(code, expected_result_expr, output, user_input)
      return false if expected_result_expr.empty?
      type = expected_result_expr[0]
      expression = expected_result_expr[1..-1]

      case type
        when 'c' # Kod dentaku
          begin
            int_input = Integer(user_input)
            int_output = Integer(output)
          rescue ArgumentError
            return false
          end
          calculator = Dentaku::Calculator.new
          calculator.store(input: int_input)
          calculator.store(output: int_output)
          return calculator.evaluate(expression)
        when 'r' # regexp
          regexp = /#{expression.gsub('{user_input}', Regexp.escape(user_input)).gsub('{code}', Regexp.escape(code))}/
          return (regexp =~ output) != nil
        when 's' # simple (zwykły oczekiwany output)
          return expression == output
        else # Nie rozpoznano wyrażenia
          fail Exceptions::ExpressionTypeNotRecognized
      end
    end

    # Przyznawanie achiementa
    def self.grant_achievement(json_response, user_course, id, id_type, lesson_achievement = false)
      query = Course::Achievement.where(id_type => id)
      json_response_key = 'achievement_granted'
      json_response_key = 'lesson_achievement_granted' if lesson_achievement
      if query.exists?
        # Przyznanie achievementa
        achievement = query.first
        if user_course.achievements.include? achievement.id.to_s
          json_response[json_response_key] = nil
        else
          user_course.achievements << achievement.id.to_s
          user_course.save!
          json_response[json_response_key] = achievement.to_json
        end
      else
        json_response[json_response_key] = nil
      end
    end

    def self.check_lesson(user_course, lesson, json_reponse)
      if lesson.course_quizs.empty? && !user_course.quizzes.include?(lesson.id.to_s)
        user_course.quizzes << lesson.id.to_s
        user_course.save!
      end
      if validate_lesson lesson, user_course
        unless user_course.lessons.include? lesson.id.to_s
          user_course.lessons << lesson.id.to_s
          user_course.save!
          grant_achievement json_reponse, user_course, lesson.id.to_s, :lesson_id, true
        end
        true
      else
        false
      end
    end

    def self.correct_exercise(id, data, output, lesson, user_course, json_response)
      user_course.exercises[id] = {} unless user_course.exercises.key? id
      user_course.exercises[id]['code'] = data['code']
      user_course.exercises[id]['user_input'] = data['user_input']
      user_course.exercises[id]['output'] = output

      json_response['is_correct'] = true

      grant_achievement json_response, user_course, id, :exercise_id
      check_lesson user_course, lesson, json_response
      user_course.save!
    end

    def self.correct_quizzes(id, lesson, user_course, json_response)
      user_course.quizzes << id unless user_course.quizzes.include? id
      json_response['is_correct'] = true
      check_lesson user_course, lesson, json_response
      user_course.save!
    end
  end
end