class ChallengesController < ApplicationController before_action :require_login, :check_auth, except: [:index] before_action :find_shixun, only: [:new, :create, :index] skip_before_action :verify_authenticity_token, only: [:create, :update, :create_choose_question, :crud_answer] before_action :find_challenge, only: [:edit, :show, :update, :create_choose_question, :index_down, :index_up, :edit_choose_question, :show_choose_question, :destroy_challenge_choose, :update_choose_question, :destroy, :crud_answer, :answer] # 关卡更新和操作的权限控制 before_action :update_allowed, except: [:index] # 关卡访问的权限控制 before_action :shixun_access_allowed, only: [:index] include ChallengesHelper # 新建实践题 def new @position = @shixun.challenges.count + 1 @st = params[:st].to_i @task_pass_default = PlatformSample.find_by(samples_type: "taskPass").try(:contents) end # params # challenge:{"subject": "标题", "task_pass": "过关任务", # "diffculty": "关卡难度", "score": "关卡分数", "st": "关卡类型"} 关卡相关信息 # challenge_tag: 关卡标签 # def create ActiveRecord::Base.transaction do begin @challenge = Challenge.new(challenge_params) @challenge.position = @shixun.challenges.count + 1 @challenge.shixun_id = @shixun.id @challenge.user_id = current_user.id @challenge.modify_time = Time.now @challenge.save! # 实训是否需要重置, 非实践任务创建第一个阶段调用, 避免不包含实践任务的实训进行模拟实战报错 todo: 新建实训需要重置TPI # shixun_modify_status_without_publish(@shixun, 1) if @challenge.position != 1 tags = params[:challenge_tag] if tags.present? tags.each do |tag| # TODO 创建tag的时候为什么一直报challenge choose必须存在?? ChallengeTag.create!(name: tag, challenge_id: @challenge.id) end end rescue Exception => e uid_logger_error("create challenge failed #{e}") end end end # 创建选择题 def create_choose_question ActiveRecord::Base.transaction do begin @challenge_choose = ChallengeChoose.new(chooce_params) @challenge_choose.position = @challenge.challenge_chooses.count + 1 @challenge_choose.category = @challenge_choose.standard_answer.length == 1 ? 1 : 2 @challenge_choose.challenge_id = @challenge.id if @challenge_choose.save! # 创建选项 params[:question][:cnt].each_with_index do |test, index| answer = params[:choice][:answer][index] ChallengeQuestion.create(:option_name => test, :challenge_choose_id => @challenge_choose.id, :position => index, :right_key => answer) end # 创建单选多选的技能标签 if params[:challenge_tag].present? params[:challenge_tag].each do |tag| ChallengeTag.create(:name => tag, :challenge_choose_id => @challenge_choose.id, :challenge_id => @challenge.id) end end @challenge.update_column(:score, @challenge.challenge_chooses.sum(:score)) end rescue Exception => e raise ActiveRecord::Rollback end end end # 选择题详情页面 def show_choose_question @challenge_choose = ChallengeChoose.find params[:choose_id] end # 选择题更新页面 def update_choose_question @challenge_choose = ChallengeChoose.find(params[:choose_id]) ActiveRecord::Base.transaction do if params[:standard_answer] != @challenge_choose.standard_answer @challenge.update_column(:modify_time, Time.now) end @challenge_choose.update_attributes(chooce_params) @challenge.update_column(:score, @challenge.challenge_chooses.sum(:score)) # 单选多选题的更新 category = @challenge_choose.standard_answer.length > 1 ? 2 : 1 @challenge_choose.update_column(:category, category) begin @challenge_choose.challenge_questions.delete_all params[:question][:cnt].each_with_index do |test, index| answer = params[:choice][:answer][index] ChallengeQuestion.create(:option_name => test, :challenge_choose_id => @challenge_choose.id, :position => index, :right_key => answer) end @challenge_choose.challenge_tags.delete_all unless @challenge_choose.challenge_tags.blank? if params[:challenge_tag].present? params[:challenge_tag].each do |tag| ChallengeTag.create(:name => tag, :challenge_choose_id => @challenge_choose.id, :challenge_id => @challenge.id) end end @challenge_choose = ChallengeChoose.find params[:choose_id] rescue Exception => e raise ActiveRecord::Rollback end end end # 选择题的编辑 def edit_choose_question @challenge_choose = ChallengeChoose.find params[:choose_id] end def destroy_challenge_choose ActiveRecord::Base.transaction do @challenge_choose = ChallengeChoose.where(:id => params[:choose_id]).first pos = @challenge_choose.position @challenge.challenge_chooses.where("position > ?", pos).update_all("position = position - 1") @challenge_choose.destroy @status = 1 # 发起重置请求 TODO: 重置实训需要后续做 # shixun_modify_status_without_publish(@shixun, 1) end end # 编辑模式 # tab 0,nil 过关任务, 1 评测设置, 2 参考答案 def edit @tab = params[:tab].to_i @power = @shixun.status == 0 challenge_num = Challenge.where(:shixun_id => @shixun).count @position = @challenge.position @chooses = @challenge.challenge_chooses if @position < challenge_num @next_challenge = Challenge.where(:shixun_id => @shixun, :position => @position + 1).first end @prev_challenge = Challenge.where(:shixun_id => @shixun, :position => @position - 1).first if @position - 1 > 0 end def index uid_logger("identifier: #{params}") @challenges = @shixun.challenges.fields_for_list @editable = @shixun.status == 0 # before_action:有判断权限,如果没发布,则肯定是管理人员 @user = current_user @shixun.increment!(:visits) end def show @tab = params[:tab].nil? ? 1 : params[:tab].to_i challenge_num = @shixun.challenges_count @power = @shixun.status == 0 # 之前验证走过了是不是管理员,因此这里只用判断是否发布 @position = @challenge.position if @position < challenge_num @next_challenge = Challenge.where(:shixun_id => @shixun, :position => @position + 1).first end @prev_challenge = Challenge.where(:shixun_id => @shixun, :position => @position - 1).first if @position - 1 > 0 end # tab 0:过关任务的更新; 1:评测设置的更新; 2:表示参考答案的更新; def update begin ActiveRecord::Base.transaction do tab = params[:tab].to_i @challenge.update_attributes!(challenge_params) if tab == 0 && @challenge.st == 0 @challenge.challenge_tags.delete_all if params[:challenge_tag].present? params[:challenge_tag].each do |input| ChallengeTag.create!(:name => input, :challenge_id => @challenge.id) end end elsif tab == 1 path = @challenge.path exec_path = @challenge.exec_path test_set = @challenge.test_sets sets_output = test_set.map(&:output) sets_input = test_set.map(&:input) sets_open = test_set.map(&:is_public) set_score = test_set.map(&:score) set_match_rule = test_set.map(&:match_rule) params_hidden = params[:test_set].map{|set| set[:hidden].to_i == 0} params_output = params[:test_set].map{|set| set[:output] } params_input = params[:test_set].map{|set| set[:input] } params_score = params[:test_set].map{|set| set[:score]} params_test_set = params[:test_set].map{|set| set[:match_rule]} # 测试集变化则需要更新(输入、 输出、 是否隐藏) if sets_output != params_output || sets_open != params_hidden || sets_input != params_input || set_score != params_score || params_test_set != set_match_rule test_set.delete_all unless test_set.blank? params[:test_set].each_with_index do |set, index| # last: 末尾匹配, full: 全完匹配 logger.info("set: #{set}; match_rule : #{set[:match_rule]}") match_rule = set[:match_rule] == 'last' ? 'last' : 'full' TestSet.create!(:challenge_id => @challenge.id, :input => "#{set[:input]}", :output => "#{set[:output]}", :is_public => params_hidden[index], :score => set[:score], :match_rule => "#{match_rule}", :position => (index + 1)) end @challenge.update_column(:modify_time, Time.now) # 测试集的 @shixun.myshixuns.update_all(:system_tip => 0) end if params[:challenge][:show_type].to_i == -1 @challenge.update_attributes(picture_path: nil, web_route: nil, expect_picture_path: nil, original_picture_path: nil) end # 关卡评测执行文件如果被修改,需要修改脚本内容 logger.info("############shixun_publiced:#{@shixun.public == 0}") if @shixun.public == 0 script = modify_shixun_script @shixun, @shixun.evaluate_script @shixun.shixun_info.update_column(:evaluate_script, script) end # TODO: # if path != params[:challenge][:path] # shixun_modify_status_without_publish(@shixun, 1) # end #Attachment.attach_files(@challenge, params[:attachments]) end end rescue Exception => e logger.error("##update_challenges: ##{e.message}") tip_exception("#{e.message}") end end # 参考答案的'增,删,改' # POST: /shixuns/:id/challenges/:id/crud_answer # {'challenge_answer': [ # {'name': 'name', contents: 'contents', score: 10}, # {...}, # {...}, ...] #} def crud_answer if @challenge.challenge_answers && params[:challenge_answer].blank? @challenge.challenge_answers.destroy_all else raise '参考答案不能为空' if params[:challenge_answer].empty? raise '占比之和必须为100%' if params[:challenge_answer].map{|a| a[:score]}.sum != 100 ActiveRecord::Base.transaction do @challenge.challenge_answers.destroy_all if @challenge.challenge_answers params[:challenge_answer].each_with_index do |answer, index| # 内容为空不保存 next if answer[:contents].blank? ChallengeAnswer.create!(name: answer[:name], contents: answer[:contents], level: index+1, score: answer[:score], challenge_id: @challenge.id) end end end end # 查看参考答案接口 def answer @answers = @challenge.challenge_answers end def index_down next_challenge = @challenge.next_challenge position = @challenge.position @challenge.update_attribute(:position, (position + 1)) next_challenge.update_attribute(:position, next_challenge.position - 1) # 关卡位置被修改,需要修改脚本 script = modify_shixun_script @shixun, @shixun.evaluate_script @shixun.shixun_info.update_column(:evaluate_script, script) end def index_up position = @challenge.position last_challenge = @challenge.last_challenge @challenge.update_attribute(:position, (position - 1)) last_challenge.update_attribute(:position, last_challenge.position + 1) # 关卡位置被修改,需要修改脚本 script = modify_shixun_script @shixun, @shixun.evaluate_script @shixun.shixun_info.update_column(:evaluate_script, script) end def destroy next_challenges = @shixun.challenges.where("position > #{@challenge.position}") next_challenges.update_all("position = position - 1") # Todo: 实训修改后,关卡需要重置 # shixun_modify_status_without_publish(@shixun, 1) @challenge.destroy # 关卡位置被删除,需要修改脚本 script = modify_shixun_script @shixun, @shixun.evaluate_script @shixun.shixun_info.update_column(:evaluate_script, script) end private def find_shixun @shixun = Shixun.find_by_identifier(params[:shixun_identifier]) end # 通用接口 def find_challenge @challenge = Challenge.find params[:id] @shixun = Shixun.find_by!(identifier: params[:shixun_identifier]) end def challenge_params tip_exception("评测时间不能超过300秒") if params[:challenge][:exec_time].to_i > 300 params.require(:challenge).permit(:subject, :task_pass, :difficulty, :score, :st, :modify_time, :test_set_average, :path, :exec_path, :show_type, :original_picture_path, :test_set_score, :expect_picture_path, :picture_path, :web_route, :answer, :exec_time) end def chooce_params params.require(:challenge_choose).permit(:subject, :answer, :standard_answer, :score, :difficult) end def update_allowed unless current_user.manager_of_shixun?(@shixun) raise Educoder::TipException.new(403, "..") end end end