# encoding: utf-8 class ChallengesController < ApplicationController layout "base_shixun" # 如要添加或修改before_filter时,请将handle_openi_request这个before_filter放至第一位 # before_filter :handle_openi_request, if: -> { user_login_and_from_openi? }, only: [:index] before_filter :check_authentication, :except => [:index] before_filter :find_shixun, :only => [:index, :new, :create, :destroy, :challenge_build, :update_evaluation, :add_choose_question, :new_choose_question, :choose_type_show, :edit_choose_question, :update_choose_question, :destroy_challenge_choose] before_filter :find_challenge, :only => [:show, :edit, :update, :challenge_build, :index_up, :index_down, :destroy, :update_evaluation, :add_choose_question, :show_choose_question, :create_choose_question, :create_choice_question, :new_choose_question, :choose_type_show, :edit_choose_question, :update_choose_question, :destroy_challenge_choose] before_filter :build_challege_from_params, :only => [:new, :create] before_filter :tpi_manager_allowed, :only => [:challenge_build, :destroy, :edit, :new, :create] before_filter :allowed_view, :only => [:show] before_filter :query_challeges, :only => [:show, :edit, :update, :update_evaluation] skip_before_filter :verify_authenticity_token, :only => [:create_choose_question, :update_choose_question] #before_filter :find_shixun_language, :only => [:show, :new, :edit] before_filter :base_index, :only => [:index, :index_down, :index_up, :destroy] before_filter :view_allow, :only => [:show] include ApplicationHelper ##{ # @url: 判断新建与编辑提交的url} def new # 顶部导航 @challenge = Challenge.new @st = params[:st].to_i @challenge.st = @st @url = shixun_challenges_path(@shixun, :st => @st) @method = "post" @project_menu_type = 11 @task_pass_sample = PlatformSample.where(:samples_type => 'taskPass').first.try(:contents) respond_to do |format| format.html { render :action => 'new', :layout => 'base_shixun' } end end def create ActiveRecord::Base.transaction do begin challenge_count = @shixun.challenges.count @challenge = Challenge.new(params[:challenge]) @challenge.position = challenge_count + 1 @challenge.shixun = @shixun @challenge.user = User.current @challenge.st = params[:st].to_i @challenge.modify_time = Time.now # 实训是否需要重启 # 非实践任务创建第一个阶段时调用 publishGame, 避免不包含实践任务的实训进行模拟实战时报错 shixun_modify_status_without_publish(@shixun, 1) if @challenge.position != 1 @challenge.save! if params[:challenge_tag].present? params[:challenge_tag].each do |input| ChallengeTag.create!(:name => input, :challenge_id => @challenge.id) end end redirect_to shixun_challenge_path(@challenge, :shixun_id => @shixun) rescue Exception => e flash[:error] = "#{e.message}" redirect_to new_shixun_challenge_path(:shixun_id => @shixun) raise ActiveRecord::Rollback end end end # 处理新建challenge返回的pipeline片段 def fragment_from_jenkins end def index base_index respond_to do |format| format.js format.html end rescue ActiveRecord::RecordNotFound render_404 end def show @tab = params[:tab].nil? ? 1 : params[:tab].to_i challenge_num = Challenge.where(:shixun_id => @shixun).count challenge_pos = @challenge.position if challenge_pos < challenge_num @next_challenge = Challenge.where(:shixun_id => @shixun, :position => challenge_pos + 1).first end @prev_challenge = Challenge.where(:shixun_id => @shixun, :position => challenge_pos - 1).first if challenge_pos - 1 > 0 respond_to do |format| format.html format.js end end ##{ # @action: 判断新建与编辑提交的url} def edit @tab = params[:tab].blank? ? 1 : params[:tab].to_i @url = shixun_challenge_path(@challenge, :shixun_id => @shixun, :tab => @tab) @method= "put" respond_to do |format| format.html format.js end end def update ActiveRecord::Base.transaction do tab = params[:tab].to_i @challenge.update_attributes(params[:challenge]) if tab == 1 @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 == 2 path = @challenge.path exec_path = @challenge.exec_path sets_output = @test_sets.map(&:output) sets_input = @test_sets.map(&:input) sets_open = @test_sets.map(&:is_public) params_hidden = params[:test_set][:hidden].map{|hidden| hidden.to_i == 0} # 测试集变化则需要更新(输入、 输出、 是否隐藏) if sets_output != params[:test_set][:output] || sets_open != params_hidden || sets_input != params[:test_set][:input] @test_sets.delete_all unless @test_sets.blank? if params[:test_set][:hidden].length > 0 params[:test_set][:input].each_with_index do |input, index| unless (input[index] == params[:test_set][:output][index] && input[index].nil?) TestSet.create(:challenge_id => @challenge.id, :input => "#{input}", :output => "#{params[:test_set][:output][index]}", :is_public => params_hidden[index], :position => (index + 1)) end end end @challenge.update_column(:modify_time, Time.now) # 测试集的 @shixun.myshixuns.update_all(:system_tip => 0) end # 关卡评测执行文件如果被修改,需要修改脚本内容 script = modify_shixun_script @shixun, @shixun.evaluate_script @shixun.update_column(:evaluate_script, script) if path != params[:challenge][:path] shixun_modify_status_without_publish(@shixun, 1) end Attachment.attach_files(@challenge, params[:attachments]) end redirect_to shixun_challenge_path(@challenge, :shixun_id => @shixun, :tab => tab) end end def new_choose_question @challenge_choose = ChallengeChoose.new @url = "#{create_choose_question_shixun_challenge_path(@challenge, :shixun_id => @shixun)}" respond_to do |format| format.js end end def create_choose_question ActiveRecord::Base.transaction do begin @challenge_choose = ChallengeChoose.new @challenge_choose.challenge_id = @challenge.id @challenge_choose.subject = params[:choose][:subject] @challenge_choose.answer = params[:choose][:answer] @challenge_choose.standard_answer = params[:standard_answer] @challenge_choose.score = params[:challenge][:score].to_i @challenge_choose.difficult = params[:challenge][:difficulty].to_i @challenge_choose.position = @challenge.challenge_chooses.count + 1 @challenge_choose.category = @challenge_choose.standard_answer.length == 1 ? 1 : 2 if @challenge_choose.save! # 创建选项 params[:question][:cnt].each_with_index do |test, index| answer = params[:choice][:answer][index] == "0" ? false : true 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 end rescue Exception => e flash[:error] = "#{e.message}" raise ActiveRecord::Rollback end end end def show_choose_question @challenge_choose = ChallengeChoose.find params[:choose_id] respond_to do |format| format.js end end def update_choose_question @challenge_choose = ChallengeChoose.where(:id => params[:choose_id]).first ActiveRecord::Base.transaction do if params[:standard_answer] != @challenge_choose.standard_answer @challenge.update_column(:modify_time, Time.now) end category = params[:standard_answer].length > 1 ? 2 : 1 score = params[:challenge] ? params[:challenge][:score].to_i : @challenge_choose.score difficult = params[:challenge] ? params[:challenge][:difficulty].to_i : @challenge_choose.difficult @challenge_choose.update_attributes(:subject => params[:choose][:subject], :answer => params[:choose][:answer], :standard_answer => params[:standard_answer], :score => score, :difficult => difficult, :category => category) begin @challenge_choose.challenge_questions.delete_all params[:question][:cnt].each_with_index do |test, index| answer = params[:choice][:answer][index] == "0" ? false : true 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 flash[:error] = "#{e.message}" raise ActiveRecord::Rollback end end end def edit_choose_question @challenge_choose = ChallengeChoose.find params[:choose_id] @url = "#{update_choose_question_shixun_challenge_path(@challenge, :shixun_id => @shixun, :choose_id => params[:choose_id])}" respond_to do |format| format.js end end def choose_type_show @challenge_choose = ChallengeChoose.where(:id => params[:choose_id]).first @index = params[:index].to_i respond_to do |format| format.js end 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 # 发起重置请求 shixun_modify_status_without_publish(@shixun, 1) redirect_to shixun_challenge_path(@challenge, :shixun_id => @shixun) end end def add_choose_question @category = params[:category].to_i @position = params[:position].to_i #@challenge_choose = @challenge.challenge_chooses respond_to do |format| format.js end end def destroy next_challenges = @shixun.challenges.where("position > #{@challenge.position}") next_challenges.update_all("position = position - 1") shixun_modify_status_without_publish(@shixun, 1) @challenge.destroy # 关卡位置被删除,需要修改脚本 script = modify_shixun_script @shixun, @shixun.evaluate_script @shixun.update_column(:evaluate_script, script) base_index respond_to do |format| format.js format.html{redirect_to shixun_challenges_path(@shixun)} end end def update_evaluation ActiveRecord::Base.transaction do path = @challenge.path exec_path = @challenge.exec_path @challenge.update_attributes(params[:challenge]) begin if params[:tab].to_i == 2 sets_output = @test_sets.map(&:output) sets_input = @test_sets.map(&:input) sets_open = @test_sets.map(&:is_public) params_hidden = params[:test_set][:hidden].map{|hidden| hidden.to_i == 0} # 测试集变化则需要更新(输入、 输出、 是否隐藏) if sets_output != params[:test_set][:output] || sets_open != params_hidden || sets_input != params[:test_set][:input] @test_sets.delete_all unless @test_sets.blank? if params[:test_set][:hidden].length > 0 params[:test_set][:input].each_with_index do |input, index| unless (input[index] == params[:test_set][:output][index] && input[index].nil?) TestSet.create(:challenge_id => @challenge.id, :input => input, :output => params[:test_set][:output][index], :is_public => params_hidden[index], :position => (index + 1)) end end end @challenge.update_column(:modify_time, Time.now) # 测试集的 @shixun.myshixuns.update_all(:system_tip => 0) end # 关卡评测执行文件如果被修改,需要修改脚本内容 if exec_path != params[:challenge][:exec_path] script = modify_shixun_script @shixun, @shixun.evaluate_script @shixun.update_column(:evaluate_script, script) end # 学员任务文件路径更新不需要重置 # if path != params[:challenge][:path] # shixun_modify_status_without_publish(@shixun, 1) # end Attachment.attach_files(@challenge, params[:attachments]) elsif params[:tab].to_i == 5 @challenge_tags.delete_all unless @challenge_tags.blank? unless params[:knowledge].blank? params[:knowledge][:input].each do |input| ChallengeTag.create!(:name => input, :challenge_id => @challenge.id) end end end if params[:tab].to_i == 5 respond_to do |format| format.js{redirect_to edit_shixun_challenge_path(@challenge, :shixun_id => @shixun, :tab => params[:tab])} end else redirect_to edit_shixun_challenge_path(@challenge, :shixun_id => @shixun, :tab => params[:tab]) end rescue Exception => e flash[:error] = "#{e.message}" redirect_to edit_shixun_challenge_path(@challenge, :shixun_id => @shixun, :tab => params[:tab]) raise ActiveRecord::Rollback end end 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.update_column(:evaluate_script, script) base_index 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.update_column(:evaluate_script, script) base_index end # build job 只负责发送请求 def challenge_build gitUrl = gitlab_url@shixun gitUrl = Base64.urlsafe_encode64(gitUrl) taskId = params[:id] jobName = @shixun.forked_form step = @challenge.position jenkins_shixuns = Redmine::Configuration['jenkins_shixuns'] if @challenge.status == 0 params = {:jobName => "#{jobName}", :taskId => "#{taskId}", :step => "#{step}", :gitUrl => "#{gitUrl}"} uri = URI("#{jenkins_shixuns}/jenkins-exec/api/buildJob") res = uri_exec uri, params # @challenge.update_attribute(:status, 1) end respond_to do |format| format.js end end private # 过滤掉对指定单位公开的用户(超级管理员和实训管理者除外) def view_allow shixun_view_allow @shixun end def count_input input, output if input.length == 0 && output.length == 0 result = 0 else if input.length > output.length end end end def tpi_manager_allowed unless User.current.manager_of_shixun?(@shixun) render_403 end end def allowed_view unless (allow_to_view_challenge(@challenge, @shixun) || User.current.manager_of_shixun?(@shixun)) render_403 end end def build_challege_from_params if params[:id].blank? @challenge = Challenge.new @challenge.shixun = @shixun if params[:st].to_i == 0 @challenge.st = 1 end else @challenge = @shixun.challenges.find(params[:id]) end @challenge.shixun = @shixun @challenge.user ||= User.current end def query_challeges @test_sets = @challenge.test_sets @challenge_tags = @challenge.challenge_tags end # index/index_down/index_up/destroy等方法公共部分 def base_index @manager = User.current.manager_of_shixun?(@shixun) # 当前用户开启的实训 @current_myshixun = @shixun.myshixuns.where(:user_id => User.current).first if @current_myshixun.present? @challenges = Challenge.select([:id, :subject, :user_id, :shixun_id, :position, :st, :score]).where(:shixun_id => @shixun) @current_modify = ShixunModify.where(:myshixun_id => @current_myshixun.id, :shixun_id => @shixun.try(:id), :status => 1).first else @challenges = @shixun.challenges end end def find_challenge @challenge = Challenge.find(params[:id]) @shixun = @challenge.shixun rescue ActiveRecord::RecordNotFound render_404 end # Find project of id params[:id] def find_shixun shixun_id = params[:shixun_id] || (params[:challenge] && params[:challenge][:shixun_id]) @shixun = Shixun.find_by_identifier(shixun_id) if @shixun.nil? render_404 return else logger.info("operable: ##{@shixun.operable?}") logger.info("@shixun.status: ##{@shixun.status}") if (@shixun.status == 0 && !User.current.manager_of_shixun?(@shixun)) || (!@shixun.operable? && !User.current.admin?) render_403 return end end rescue ActiveRecord::RecordNotFound render_404 end def find_shixun_language language = @shixun.language @language = language_switch language end def default_format_js response.headers['content--type'] = 'text/javascript' request.format = 'js' end end