#coding=utf-8 class GamesController < ApplicationController layout "base_myshixun" skip_before_filter :verify_authenticity_token, :only => [:file_update] before_filter :find_myshixun, :only => [:index] before_filter :find_game, :only => [:show, :game_build, :entry,:next_step, :prev_step,:outputs_show, :file_edit, :file_update, :get_waiting_time, :web_display, :check_test_sets, :game_status, :change_status, :answer, :minus_score, :refresh_game_list, :reset_original_code, :reset_new_code, :evaluating_choice, :sync_codes, :myshixun_repair, :system_update, :enter_game, :get_repository_contents, :sync_modify_time, :challenges] before_filter :find_repository, :only => [:entry, :file_edit, :file_update, :reset_original_code, :reset_new_code, :html_show, :get_repository_contents] before_filter :allowd_manager, :except => [:show] # before_filter :allowd_view, :only => [:show] before_filter :find__shixun_language, :only => [:entry] include ApplicationHelper include GamesHelper CODES = %W(1 2 3 4 5 6 7 8 9 A B C D E F G H J K L N M O P Q R S T U V W X Y Z) require 'open3' # 同步更新最新代码 # 同步完成后,需要更新myshixun的commit_id为实训的commit最新值 # -------------------------- # 新思路,有冲突则则重置,没有冲突直接pull # identifier为password--- # -------------------------- def sync_codes g = Gitlab.client shixun_tomcat = Redmine::Configuration['shixun_tomcat'] begin shixun_new_commit = g.commits(@myshixun.shixun.try(:gpid)).first.try(:id) if @myshixun.commit_id != shixun_new_commit if @myshixun.reset_time != @myshixun.shixun.try(:reset_time) flag = 2 else flag = 0 end else flag = 1 end git_myshixun_url = gitlab_url @myshixun login = @myshixun.shixun.try(:git_login) # 如果educoder不是当前项目的成员,则需要把educoder设置成管理员,为了便于权限验证 # REDO:如果用educoder的话,可能其他成员也可以推代码 educoder_gid = Redmine::Configuration['educoder_gid'] Gitlab.client.add_team_member(@myshixun.gpid, educoder_gid, 40) git_shixun_url = gitlab_url @myshixun.shixun git_myshixun_url = Base64.urlsafe_encode64(git_myshixun_url) git_shixun_url = Base64.urlsafe_encode64(git_shixun_url) params = {tpiID: "#{@myshixun.try(:id)}", :tpiGitURL => "#{git_myshixun_url}", :tpmGitURL => "#{git_shixun_url}", :identifier => "xinhu1ji2qu3"} uri = "#{shixun_tomcat}/bridge/game/resetTpmRepository" res = uri_exec uri, params if (res && res['code'] != 0) render :json => {:status => -1, :message => "实训云平台繁忙(繁忙等级:95)"} return end shixun_new_commit = g.commits(@myshixun.shixun.try(:gpid)).first.try(:id) Rails.logger.info("#######Game -- myshixun") @myshixun.update_attributes!(:commit_id => shixun_new_commit, :reset_time => @myshixun.shixun.try(:reset_time)) if @game.challenge.st == 0 && @game.challenge.path.present? paths = @game.challenge.path.split(";") paths.each do |path| game_code_init @game.id, path.try(:strip) end end render :json => {:status => 1, :message => "success", :path => @game.challenge.path} rescue Exception => e @message = e.try(:message) logger.error(e) respond_to do |format| format.js end end end def enter_game if @game.status == 3 @game.update_attributes(:status => 0, :open_time => Time.now) redirect_to myshixun_game_path( @game, :myshixun_id => @myshixun) end end # 出现代码不存在、脚本异常等自动修复 # 88错误的修复等 def myshixun_repair shixun_tomcat = Redmine::Configuration['shixun_tomcat'] begin git_myshixun_url = gitlab_url @myshixun git_myshixun_url = Base64.urlsafe_encode64(git_myshixun_url) params = {tpiID: "#{@myshixun.try(:id)}", :tpiGitURL => "#{git_myshixun_url}", :tpmID => "#{@myshixun.shixun.try(:id)}"} uri = "#{shixun_tomcat}/bridge/game/solveProblems" res = uri_exec uri, params if (res && res['code'] != 0) @message = "实训云平台繁忙(繁忙等级:96)" raise("实训云平台繁忙(繁忙等级:96)") end respond_to do |format| format.js{ redirect_to myshixun_game_path(@game, :myshixun_id => @myshixun)} end rescue Exception => e @message = e.try(:message) logger.error(e) respond_to do |format| format.js end end end def index @games = @myshixun.games.includes(:challenge) @games_count = @games.count respond_to do |format| format.html format.js end end # mushixun的版本库必须创建时就创建 # 首次进入版本库自动打开文件 # path:"" && path: @game.path # @praise 判断是否点赞 # @tread 判断是否踩 # git_repository_url @myshixun, "Myshixun" # @st 0 实践任务 1 选择题任务 # begin表示用户从实训tpm列表点击进入 def show # 该参数是为了判断是否需要加载loading @is_subject = params[:is_subject] redirect_to "/tasks/#{@game.identifier}" return # 验证版本库 gitUrl = gitlab_url @myshixun gitUrl = Base64.urlsafe_encode64(gitUrl) shixun_tomcat = Redmine::Configuration['shixun_tomcat'] params = {:tpiID => "#{@myshixun.id}", :tpiGitURL => "#{gitUrl}"} # 监测版本库HEAD是否存在,不存在则取最新的HEAD uri = "#{shixun_tomcat}/bridge/game/check" res = uri_exec uri, params if (res && res['code'] != 0) logger.error("Verify the repository exception") end # end @is_subject = params[:is_subject] # 防止页面ajax数据还没获取就关闭 @game.update_attribute(:status, 0) if @game.status == 1 @game_challenge = @game.challenge @position = @game_challenge.position @challenges = Challenge.where(:shixun_id => @myshixun.shixun_id).includes(:games).where("games.user_id = #{@myshixun.user_id}") @shixun = @myshixun.shixun # 判断tpm是否修改了 @tpm_modified = repository_is_modified(@myshixun, @shixun.try(:gpid)) unless (@shixun.modify_time.blank? || @myshixun.modify_time.blank? || @shixun.reset_time.blank? || @myshixun.reset_time.blank?) @tpm_script_modified = (@shixun.reset_time > @myshixun.reset_time ? true : false) end if (@game_challenge.modify_time.present? || @game.modify_time.present?) @tpm_cases_modified = (@game_challenge.modify_time != @game.modify_time ? true : false) end # end @praise_count = PraiseTread.where(:praise_tread_object_id => @game_challenge.id, :praise_tread_object_type => "Challenge", :praise_or_tread => 1).count @tread_count = PraiseTread.where(:praise_tread_object_id => @game_challenge.id, :praise_tread_object_type => "Challenge", :praise_or_tread => 0).count # st:判断是选择类型还是实训类型 @st = @game_challenge.st @had_done = @game.had_done @praise = PraiseTread.where("praise_tread_object_id=? and praise_tread_object_type=? and praise_or_tread=? and user_id=?", @game_challenge.id, @game_challenge.class.to_s, 1, User.current.id).first @tread = PraiseTread.where("praise_tread_object_id=? and praise_tread_object_type=? and praise_or_tread=? and user_id=?", @game_challenge.id, @game_challenge.class.to_s, 0, User.current.id).first @rev = @rev.nil? ? "master" : @rev @type = @_params['type'] challenge_path = @game_challenge.path @discusses_count = @shixun.discusses.count @arr_path = challenge_path.present? ? challenge_path.split(";") : [] # 默认打开文件 logger.info("repository id is #{@repository.try(:id)}, repository's shixun_id =#{@repository.try(:myshixun_id)} shixun_id =#{@repository.try(:shixun_id)}, project_id => #{@repository.try(:project_id)}") # 验证challenge文件名的合法性 # 获取文件content内容,如果内容不存在则说明是目录,否则则认为是文件 if (@g.files(@myshixun.gpid, @path, @rev).try(:message).present? && !@path.present? && @_params['type'] != "root" ) @path = @arr_path.reject(&:blank?)[0].try(:strip) # 多文件(以';'形式隔开),默认打开第一个文件 file_content = @g.files(@myshixun.gpid, @path, @rev).content if file_content.blank? # gitlab缺陷:forked完成,短暂时间内取不了内容的,所以做一个小轮询,间隔0.1秒 # 超过2秒则失败,需通过页面刷新 for i in 0..20 do sleep(0.1) file_content = @g.files(@myshixun.gpid, @path, @rev).content unless file_content.blank? logger.info("start: file_content is####{file_content.first(6)}") break end end end @content = tran_base64_decode64(file_content) end if @content.nil? || @_params['type'] == "root" @entries = @repository.entries(@path, @rev) end # 页面前后端分离数据转换 # test_sets = @game_challenge.test_sets max_query_index = @game.outputs.first.try(:query_index) if max_query_index.present? test_sets = TestSet.find_by_sql("SELECT o.actual_output, o.result, o.test_set_position, o.query_index,t.is_public,t.input, t.output, g.id as game_id, c.id as challenge_id FROM outputs o,games g ,challenges c,test_sets t where g.id=#{@game.id} and o.query_index=#{max_query_index} and g.id = o.game_id and c.id= g.challenge_id and t.challenge_id = c.id and t.position =o.test_set_position order by o.query_index ") else test_sets = TestSet.find_by_sql("SELECT t.is_public,t.input, t.output,t.position FROM games g ,challenges c,test_sets t where g.id=#{@game.id} and c.id= g.challenge_id and t.challenge_id = c.id ") end unless test_sets.blank? @test_sets = test_set_static_data(test_sets) end @test_sets_count = test_sets.count @test_sets_hidden_count = test_sets.blank? ? 0 :test_sets.select{|test_set| test_set.is_public == false}.count @test_sets_public_count = @test_sets_count - @test_sets_hidden_count had_test = Output.where(:game_id => @game.id, :query_index => (@game.query_index - 1)) @had_test_count = had_test.count @had_passed_testsests_error_count = had_test.blank? ? 0 : had_test.select{|had_test| had_test.result == false}.count @had_passed_testsests_error_count = @had_test_count - @had_passed_testsests_error_count @had_passed_testsests_hidden_count = had_test.blank? ? 0 : had_test.select{|had_test| had_test.result == true && had_test.is_public == false}.count @had_passed_testsests_public_count = had_test.blank? ? 0 : had_test.select{|had_test| had_test.result == true && had_test.is_public == true}.count @mirror_name = @myshixun.mirror_name @final_score = ((@shixun.status <= 1) ? 0 : @game.final_score.to_i) if @myshixun.shixun.status <= 1 || (@game.final_score != 0 && @game.answer_open?) @gold = 0 else if @game.answer_open? && @game.final_score ==0 @gold = -@game_challenge.score.to_i else @gold = @game.final_score.to_i end end #@gold = @myshixun.shixun.status <= 1 ? 0 : ((@game.answer_open? && @game.final_score == 0 && @game.status == 2) ? -@game_challenge.score.to_i : @game.final_score.to_i) @had_done = @game.had_done @language = @game_challenge.shixun.language @mirror_name = @myshixun.mirror_name error_position = had_test.blank? ? nil : had_test.select{|had_test| had_test.result == false}.last logger.info("latest output id is #{error_position.id unless error_position.blank?}") @latest_output = error_position.try(:out_put).gsub(/\n/, '
').gsub(/\t/, '        ').to_json unless error_position.try(:out_put).blank? logger.info(@latest_output) @power = (User.current.manager_of_shixun?(@shixun) || (User.current.try(:professional_certification) && User.current.user_extensions.try(:identity) == 0) || @game.test_sets_view ) ? true : false @record = EvaluateRecord.where(:game_id => @game.id).first.try(:consume_time) respond_to do |format| format.html format.js end rescue Exception => e logger.error("game error##############{e.message}") flash[:error] = e.message end def get_repository_contents @rev = @rev.nil? ? "master" : @rev @path = params[:path].try(:strip) # 多文件(以';'形式隔开),默认打开第一个文件 file_content = @g.files(@myshixun.gpid, @path, @rev).content @content = tran_base64_decode64(file_content) end # 代码预览 def entry # entry_and_raw(false) @arr_path = @game.challenge.path.split(";") file_content = @g.files(@myshixun.gpid, @path, @rev).content @content =tran_base64_decode64(file_content) # @content = @repository.cat(@path, @rev) end def file_edit # entry_and_raw(false) # @content = @repository.cat(@path, @rev).strip # # respond_to do |format| # # format.js # end end def sync_modify_time @game.update_column(:modify_time, @game.challenge.try(:modify_time)) # return {:status => 1, :message => "success"} render :json => {:status => 1, :message => "success"} end def file_update # render :json => {:success => "success", :resubmit => '11111'} logger.info("file_update start#1**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") ActiveRecord::Base.transaction do if params[:evaluate].present? # 创建评测记录 record = EvaluateRecord.create!(:user_id => User.current.id, :shixun_id => @myshixun.shixun.id, :game_id => @game.id) logger.info("file_update start#2**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") # @myshixun.student_works.update_all(:update_time => Time.now) if !@myshixun.student_works.blank? student_work_time = format("%.3f", (Time.now.to_f - record.created_at.to_f)).to_f record.update_attributes!(:student_work => student_work_time) end logger.info("file_update start#3**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") @g = Gitlab.client last_content = @g.files(@myshixun.gpid, @path, "master").try(:content) logger.info("file_update start#4**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") last_content = tran_base64_decode64(last_content) content = if (@myshixun.mirror_name.include?('Python2.7') || @myshixun.mirror_name.include?('Python3.6') || @myshixun.mirror_name.include?('MachineLearning')) && params[:content].present? params[:content].gsub(/\t/, ' ') else params[:content] end logger.info("file_update start#5**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") if content != last_content code_file = @g.edit_file(@myshixun.gpid, User.current.login, :content => content, :file_path => @path, :branch_name => @rev, :commit_message => "shixun exec") end if record.present? consume_time = format("%.3f", (Time.now.to_f - record.created_at.to_f)).to_f record.update_attributes!(:file_update => consume_time) end logger.info("file_update start#6**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") # status为2说明是重新评测 if @game.status == 2 code = CODES.sample(8).join resubmit = "#{code}_#{@myshixun.id}" end if content != last_content && code_file.blank? raise("update file failed") else render :json => {:success => "success", :resubmit => resubmit} end end rescue Exception => e render :json => {:success => "fail", :contents => "实训云平台繁忙(繁忙等级:81),请稍后刷新并重试", :position => @game.challenge.position, :had_done => @game.had_done} end # json调用,显示左边的隐藏具体详情@game 字段 msg # 刷新右边的输出结果 @game out_put def outputs_show @output = Output.find(params[:game_output_id]) respond_to do |format| format.js end end # 获取评测的等待的时间 # res['waitNum'] 评测等待人数 # res['waitingTime'] 评测等待时间 # res['ableToCreate'] 0 表示在等待中 1 表示可执行 -1 表示超过最大等待人数 def get_waiting_time shixun_tomcat = Redmine::Configuration['shixun_tomcat'] uri = "#{shixun_tomcat}/bridge/game/getWaitingTime" params = {:tpiID => "#{@myshixun.id}", :first => @_params[:first].to_i} res = uri_exec uri, params logger.info("############ res: #{res}") if (res && res['code'] != 0) @message = "实训云平台繁忙(繁忙等级:94)" raise("实训云平台繁忙(繁忙等级:94)") end logger.info("########### get_waiting_time: #{params}") logger.info("########### ableToCreate : #{res['ableToCreate']}") render :json => {:result => "success", :ableToCreate => res['ableToCreate'], :waitNum => res['waitNum'], :waitingTime => res['waitingTime'], :position => @game.challenge.position} #render :json => {:result => "success", :ableToCreate => 1, :waitNum => 10, :waitingTime => 1324 } rescue Exception => e render :json => {:result => "fail", :contents => '实训云平台繁忙(繁忙等级:94),请稍后刷新并重试', :position => @game.challenge.position} end # status 0: 未提交测评或者提交测评失败后报错;1:中间状态还没返回值;2:返回值并成功 # resubmit 唯一随机码,为了区分每一次重新评测结果 def game_build #render :json => {:result => "success", :ableToCreate => 1, :waitNum => 13, :port => 41222 } # 更新时间是为了TPM端显示的更新,退出实训及访问实训的时候会更新 logger.info("game_build start#1**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") @myshixun.update_column(:updated_at, Time.now) game_challenge = @game.challenge shixun = @myshixun.shixun gitUrl = gitlab_url @myshixun gitUrl = Base64.urlsafe_encode64(gitUrl) taskId = @game.id #code = CODES.sample(8).join # status为2说明是重新评测 if @game.status == 2 resubmit = @_params[:resubmit] else # 重新评测不影响已通关的实训状态 if @_params[:first].to_i == 1 @game.update_attributes!(:status => 1) end end shixun_tomcat = Redmine::Configuration['shixun_tomcat'] step = game_challenge.try(:position) logger.info("game_build start#2**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") testSet = [] game_challenge.test_sets.each do |test_set| input = test_set.input.nil? ? "" : test_set.input.gsub("\r\n", "\n") output = test_set.output.nil? ? "" : test_set.output.gsub("\r\n", "\n") test_cases = {:input => input, :output => output} testSet << test_cases end logger.info("game_build start#3**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") testCases = Base64.urlsafe_encode64(testSet.to_json) unless testSet.blank? mirror_repository = shixun.mirror_repositories.where(:main_type => 1).first resource_limit = "echo 'ulimit -f #{mirror_repository.resource_limit}' >> /root/.bashrc ; source /root/.bashrc\n" tpmScript = shixun.evaluate_script.nil? ? "" : Base64.urlsafe_encode64((resource_limit + shixun.evaluate_script).gsub("\r\n", "\n")) # 注意:这个地方的参数写的时候不能换行 params = {:tpiID => "#{@myshixun.id}", :tpiGitURL => "#{gitUrl}", :buildID => "#{taskId}",:instanceChallenge => "#{step}", :testCases => "#{testCases}", :resubmit => "#{resubmit}", :times => @_params[:first].to_i, :podType => shixun.webssh, :containers => "#{Base64.urlsafe_encode64(container_limit(shixun.mirror_repositories))}", :tpmScript => "#{tpmScript}", :timeLimit => "#{shixun.main_mirror.try(:time_limit)}"} # 评测有文件输出的需要特殊传字段 path:表示文件存储的位置 params['file'] = Base64.urlsafe_encode64({:path => "#{game_challenge.picture_path}"}.to_json) if game_challenge.picture_path.present? # needPortMapping: web类型需要pod端口映射 params[:needPortMapping] = 8080 if @myshixun.mirror_name.include?("Web") # uri = URI("#{shixun_tomcat}/bridge/game/gameEvaluate") logger.info("game_build start#4**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") uri = "#{shixun_tomcat}/bridge/game/gameEvaluate" res = uri_exec uri, params if (res && res['code'] != 0) @message = "实训云平台繁忙(繁忙等级:86)" raise("实训云平台繁忙(繁忙等级:86)") end logger.info("game_build start#5****** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") render :json => {:result => "success", :resubmit => resubmit, :ableToCreate => res['ableToCreate'], :waitNum => res['waitNum'], :waitingTime => res['waitingTime'], :position => @game.challenge.position, :port => res['port'], :had_done => @game.had_done } logger.info("game_build start#6****** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") rescue Exception => e if resubmit.nil? @game.update_attributes!(:status => 0) end logger.error("###################" + e.message) render :json => {:result => 'fail', :contents =>"实训云平台繁忙(繁忙等级:86),请稍后刷新并重试", :position => game_challenge.position, :had_done => @game.had_done} end # @myshixun -status 1:完成实训 # 全部通关奖励1000分 # retry_status 评测的唯一标识,重新评测对以前已产生的结果不造成影响 # params[:resubmit] 不为空表示已通过该关后重新评测, 重新评测必须是通过该关后才能执行 # @had_done 1 通关所有关 # port: PHP/Web会有端口号,其他语言返回-1 # params[:time_out] 超时 def game_status logger.info("game_status start#1**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") if (params[:time_out] == "false") && ((params[:resubmit].blank? && @game.status != 2 && @game.status != 0) || (params[:resubmit].present? && (params[:resubmit] != @game.resubmit_identifier))) render :json => {:status => 1} return end game_challenge = @game.challenge had_done = @game.had_done resubmit_identifier = @game.resubmit_identifier shixun = @myshixun.shixun port = params[:port] score = 0 user_gold = 0 #用户奖励金币 tag_count = 0 logger.info("##### resubmit_identifier is #{resubmit_identifier}") logger.info("game_status start#2**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") if params[:resubmit].blank? # 非重新评测 # 通过当前一关 if @game.status == 2 if !@game.answer_open && shixun.status > 1 score = game_challenge.score user_gold = game_challenge.score tag_count = game_challenge.challenge_tags.count elsif shixun.status > 1 && @game.answer_open score = -game_challenge.score.to_i tag_count = 0 else score = "+0" tag_count = 0 end end game_status = @game.status else # 重新评测 if params[:resubmit] == resubmit_identifier # 本次重新评测结果已经返回并存入数据库 game_status = (@game.retry_status == 2 ? 2 : 0) # retry_status 2:成功 1: 失败 if game_status == 2 && had_done == 1 # 重新评测如果评测成功 had_done =1 else had_done = 0 end else # game_status 在前端有行为判断,2表示通关;0表示失败;1表示评测中的中间状态 game_status = 1 had_done = 0 end end logger.info("game_status start#3**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") max_query_index = @game.outputs.first.try(:query_index) if max_query_index.present? test_sets = TestSet.find_by_sql("SELECT o.actual_output, o.result, o.test_set_position, o.query_index,t.is_public,t.input, t.output, g.id as game_id, c.id as challenge_id FROM outputs o,games g ,challenges c,test_sets t where g.id=#{@game.id} and o.query_index=#{max_query_index} and g.id = o.game_id and c.id= g.challenge_id and t.challenge_id = c.id and t.position =o.test_set_position order by o.query_index ") else test_sets = TestSet.find_by_sql("SELECT t.is_public,t.input, t.output,t.position FROM games g ,challenges c,test_sets t where g.id=#{@game.id} and c.id= g.challenge_id and t.challenge_id = c.id ") end logger.info("game_status start#4**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") unless test_sets.blank? total_test_sets = test_set_static_data(test_sets) end logger.info("#################################{@public_test_sets}") @test_sets_count = test_sets.count @test_sets_hidden_count = test_sets.blank? ? 0 :test_sets.select{|test_set| test_set.is_public == false}.count @test_sets_public_count = @test_sets_count - @test_sets_hidden_count had_test = Output.where(:game_id => @game.id, :query_index => (@game.query_index - 1)) @had_test_count = had_test.count @had_passed_testsests_error_count = had_test.blank? ? 0 : had_test.select{|had_test| had_test.result == false}.count @had_passed_testsests_error_count = @had_test_count - @had_passed_testsests_error_count @had_passed_testsests_hidden_count = had_test.blank? ? 0 : had_test.select{|had_test| had_test.result == true && had_test.is_public == false}.count @had_passed_testsests_public_count = had_test.blank? ? 0 : had_test.select{|had_test| had_test.result == true && had_test.is_public == true}.count @final_score = (( shixun.try(:status).to_i <= 1) ? 0 : @game.try(:final_score).to_i) picture = (@game.picture_path.nil? ? 0 : @game.id) if @myshixun.shixun.try(:status) <= 1 || (@game.try(:final_score).to_i != 0 && @game.answer_open?) @gold = 0 else if @game.answer_open? && @game.try(:final_score).to_i ==0 @gold = -game_challenge.try(:score).to_i else @gold = @game.try(:final_score).to_i end end #@gold = @myshixun.shixun.status <= 1 ? 0 : (@game.answer_open? && @game.final_score.to_i == 0 && @game.status == 2 ? -game_challenge.score.to_i : @game.final_score.to_i) error_position = had_test.blank? ? nil : had_test.select{|had_test| had_test.result == false}.last @latest_output = error_position.try(:out_put).gsub(/\n/, '
').gsub(/\t/, '        ') unless error_position.try(:out_put).blank? logger.info("@compile_success###################{@compile_success}") @language = game_challenge.shixun.language @mirror_name = @myshixun.mirror_name power = (User.current.manager_of_shixun?(shixun) || (User.current.try(:professional_certification) && User.current.user_extensions.try(:identity) == 0)) ? true : false logger.info("game_status start#5**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") # 更新用户时间 if game_status == 0 || game_status == 2 record = EvaluateRecord.where(:game_id => @game.id).first if record front_js = format("%.3f", (Time.now.to_f - record.try(:updated_at).to_f)).to_f consume_time = format("%.3f", (Time.now - record.created_at)).to_f record.update_attributes(:consume_time => consume_time, :front_js => front_js) end end # 记录前端总耗时 record = EvaluateRecord.where(:game_id => @game.id).first.try(:consume_time) logger.info("game_status start#6**#{@game.id}**** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") render :json => {test_sets: total_test_sets, test_sets_count: @test_sets_count, test_sets_hidden_count: @test_sets_hidden_count, test_sets_public_count: @test_sets_public_count, had_test_count: @had_test_count, had_passed_testsests_error_count: @had_passed_testsests_error_count, had_passed_testsests_hidden_count: @had_passed_testsests_hidden_count, had_passed_testsests_public_count: @had_passed_testsests_public_count, final_score: @final_score, gold: @gold, latest_output: @latest_output, status: game_status, had_done: had_done, language: @language, score: score, user_gold: user_gold, tag_count: tag_count, position: game_challenge.position, port: port, power: power, record:record, mirror_name:@mirror_name, picture:picture } end # 选择题评测(选择题不需要重新评测) # score 获得金币数 tag_count 技能数 right用户是否全对 answer_right全部选择题的正确性 def evaluating_choice @game_challenge = @game.challenge @challenges = Challenge.where(:shixun_id => @myshixun.shixun_id) @shixun = @myshixun.shixun score = 0 tag_count = 0 @right = true answer_right = [] @game_challenge.challenge_chooses.each_with_index do |choose, index| correct = (params[:answer][index] == choose.standard_answer) ? true : false Output.create(:game_id => @game.id, :test_set_position => choose.position, :actual_output => params[:answer][index], :result => correct, :query_index => @game.query_index) if @shixun.status > 1 && !@game.answer_open if correct score += choose.score tag_count += choose.challenge_tags.count end elsif @shixun.status > 1 && @game.answer_open score -= choose.score end unless correct @right = false end answer_right << correct end @had_done = @game.had_done if @right && @game.status != 2 @game.update_attributes(:status => 2, :end_time => Time.now) # 选择题最后一关,更新status if @had_done @myshixun.update_attribute(:status, 1) end if @shixun.status > 1 && !@game.answer_open reward_grade(@game.user, @game.id, 'Game', @game_challenge.choose_score) reward_experience(@game.user, @game.id, 'Game', @game_challenge.choose_score) @game.update_attribute(:final_score, @game_challenge.choose_score) end end respond_to do |format| format.js{redirect_to myshixun_game_path(@game, :myshixun_id => @myshixun, :choose => @right)} end end def change_status @game.update_attribute(:status, 0) outputs = @game.outputs if outputs.count == 0 outputs = "" else outputs = outputs.map{|result| [result.code, result.id]} end render :json => {status: @game.status, output: "服务器网络异常", results: outputs, had_done: 0} end # 获取等待的任务数 # 如果没有等待任务页面上将不显示 # msg: -1 不存在等待的任务 # 如果该方法异常则直接返回0,跳过等待 def waiting_info begin shixun_tomcat = Redmine::Configuration['shixun_tomcat'] params = {:buildID => "#{@game.id}"} uri = URI("#{shixun_tomcat}/jenkins-exec/api/getWaitingTime") res = uri_exec uri, params if (res && res['code'] != 0) raise("获取等待任务数异常") end task_count = res['msg'].to_i task_count > 0 ? task_count : 0 render :json => {task_count: task_count} rescue render :json => {task_count: 0} end end # 自动推送下一个任务 # 从waiting_time发的请求则有type def next_step #unless show_next_stage?(@game, @myshixun.shixun.try(:status)) # render_403 #end next_game = @game.next_game next_game.update_attributes(:status => 0, :open_time => Time.now) if next_game.status == 3 respond_to do |format| format.js{ redirect_to myshixun_game_path(next_game, :myshixun_id => @myshixun)} format.html{redirect_to myshixun_game_path(next_game, :myshixun_id => @myshixun)} end end def prev_step prev_game = @game.prev_game respond_to do |format| format.js{ redirect_to myshixun_game_path(prev_game, :myshixun_id => @myshixun)} format.html{ redirect_to myshixun_game_path(prev_game, :myshixun_id => @myshixun)} end end # 获取答案,第一次查看需扣掉该关卡的积分 # 如果已看过,下次可以免费查看 # viewed 1: 直接查看 2:弹框提示将要扣除积分,确定后显示内容 3:弹框提示分数不够 def answer challenge = @game.challenge @challenge_score = challenge.score.to_i @answer = "" # 已经开启过 @score = User.current.grade.to_i - @challenge_score if(params[:choose] == "true") challenge.challenge_chooses.each_with_index do |choose, index| @answer += "第"+ ((index + 1).to_s) +"题:
" @answer += (choose.answer.blank? ? choose.standard_answer : choose.answer) @answer += "


" end else @answer = challenge.answer end if challenge.shixun.status < 2 || User.current.manager_of_shixun?(challenge.shixun) || @game.answer_open || (challenge.st != 0 && @game.status == 2) @viewed = 1 else if @score >= 0 @viewed = 2 else @viewed = 3 end end respond_to do |format| format.js format.html end end # web渲染 def web_display path = @game.challenge.path.strip port = (50000 + @game.myshixun_id).to_s # 测试 #path = "src/step1/Helloworld.php" #port = (50000+4116).to_s @url = "http://106.75.96.108:" + port + '/' + path respond_to do |format| format.html{render :layout => false} end end def minus_score @game_challenge = @game.challenge @position = @game_challenge.position user = User.current challenge_score = @game_challenge.score.to_i @answer = "" if @game.challenge.st == 0 @answer = @game_challenge.answer else @game_challenge.challenge_chooses.each_with_index do |choose, index| @answer += "第"+ ((index + 1).to_s) +"题:
" @answer += (choose.answer.blank? ? choose.standard_answer : choose.answer) @answer += "


" end end unless @game.answer_open # 最终得分可能是负分 final_score = @game.final_score - challenge_score @game.update_attributes!(:answer_open => true, :final_score => final_score) # 积分消耗情况统计 reward_grade(user, @game.id, 'Answer', -challenge_score) @grades = final_score end end def refresh_game_list myshixun_id = params[:myshixun_id] @myshixun = Myshixun.find_by_identifier(myshixun_id) # @challenges = Challenge.where(:shixun_id => @myshixun.shixun_id) @challenges = Challenge.where(:shixun_id => @myshixun.shixun_id).includes(:games).where("games.user_id = #{@myshixun.user_id}") respond_to do |format| format.js end end def check_test_sets user_grade = User.current.grade @minus_grade = @game.challenge.score * 5 if user_grade >= @minus_grade User.current.update_attribute(:grade, user_grade - @minus_grade) @game.update_attribute(:test_sets_view, true) # 扣分记录 Grade.create(:user_id => User.current.id, :container_id => @game.id, :score => -@minus_grade, :container_type => "testSet") respond_to do |format| format.js{redirect_to myshixun_game_path(@game, :myshixun_id => @myshixun, :test_sets_view => true)} end else respond_to do |format| format.js end end end def reset_original_code @g = Gitlab.client begin @shixun = @myshixun.shixun @path = params[:path].try(:strip) game_code = GameCode.where(:game_id => @game.id, :path => @path).first GameCode.create(:game_id => @game.id, :path => @path) if game_code.blank? content = game_code.try(:original_code) @arr_path = @game.challenge.path.split(";") @rev = @rev.nil? ? "master" : @rev content = @g.files(@shixun.gpid, @path, @rev).try(:content) content = tran_base64_decode64(content) update_gitlab_file(content, @path, @rev, "file reset") file_content = @g.files(@myshixun.gpid, @path, @rev).content @content = tran_base64_decode64(file_content) if @content.nil? raise("初始代码为空,代码重置失败") end rescue Exception => e @error_messages = e.message end respond_to do |format| format.js end end def system_update @myshixun.update_attribute(:system_tip, true) render :json => {:status => 1, :message => "success"} end def reset_new_code begin @shixun = @myshixun.shixun @g = Gitlab.client @arr_path = params[:path] @path = @arr_path[0].try(:strip) @rev = @rev.nil? ? "master" : @rev message = "file reset" @arr_path.each do |path| game_code = GameCode.where(:game_id => @game.id, :path => path).first content = game_code.try(:new_code) if content.nil? raise("示例代码为空,代码重置失败") end update_gitlab_file(content, path, @rev, message) end file_content = @g.files(@myshixun.gpid, @path, @rev).content @content = tran_base64_decode64(file_content) if @content.nil? raise("示例代码为空,代码重置失败") # @entries = @repository.entries(@path, @rev) end respond_to do |format| format.js end rescue Exception => e @error_messages = e.message end end private def update_gitlab_file content, path, rev, message code_file = @g.edit_file(@myshixun.gpid, User.current.login, :content => content, :file_path => path, :branch_name => rev, :commit_message => "#{message}") if code_file.nil? raise("网络异常,文件更新失败") end end def test_set_static_data test_sets test_result = [] unless test_sets.blank? test_sets.each do |test_set| actual_output = test_set.attributes.count > 4 ? test_set.try(:actual_output) : nil result = test_set.attributes.count > 4 ? test_set.try(:result) : nil #actual_output = Base64.encode64(actual_output) compile_success = (actual_output.blank? || actual_output.downcase.match(/error/).present?) ? 0 : 1 public_result = {:is_public => (test_set.is_public ? 1 : 0), :result => result, :input => test_set.input, :actual_output => actual_output, :output => test_set.output, :compile_success => compile_success} test_result << public_result.to_json end end test_result = test_result.blank? ? test_result : test_result.join(",") return test_result.gsub(/<\/script>/, '') end def entry_and_raw(is_raw) @entry = @repository.entry(@path, @rev) (show_error_not_found; return) unless @entry # If the entry is a dir, show the browser (show; return) if @entry.is_dir? @content = @repository.cat(@path, @rev) (show_error_not_found; return) unless @content if is_raw || (@content.size && @content.size > Setting.file_max_size_displayed.to_i.kilobyte) || !is_entry_text_data?(@content, @path) # Force the download send_opt = { :filename => filename_for_content_disposition(@path.split('/').last) } send_type = Redmine::MimeType.of(@path) send_opt[:type] = send_type.to_s if send_type send_opt[:disposition] = (Redmine::MimeType.is_type?('image', @path) && !is_raw ? 'inline' : 'attachment') send_data @content, send_opt else # Prevent empty lines when displaying a file with Windows style eol # TODO: UTF-16 # Is this needs? AttachmentsController reads file simply. @content.gsub!("\r\n", "\n") @changeset = @repository.find_changeset_by_name(@rev) end end def is_entry_text_data?(ent, path) # UTF-16 contains "\x00". # It is very strict that file contains less than 30% of ascii symbols # in non Western Europe. return true if Redmine::MimeType.is_type?('text', path) # Ruby 1.8.6 has a bug of integer divisions. # http://apidock.com/ruby/v1_8_6_287/String/is_binary_data%3F return false if ent.is_binary_data? true end def find_repository @repository = @myshixun.repository render_404 if @myshixun.gpid.nil? @path = params[:path].is_a?(Array) ? params[:path].join('/') : params[:path].to_s @g = Gitlab.client @g_project = @g.project(@myshixun.gpid) @g_default_branch = @g_project.default_branch # gitlab端获取默认分支 @rev = params[:rev].blank? ? @g_default_branch : params[:rev].to_s.strip rescue ActiveRecord::RecordNotFound render_404 end def allowd_manager render_403 unless (User.current.manager_of_myshixun?(@myshixun) || User.current.admin? || User.current.id == @myshixun.shixun.try(:user_id)) end # 判断成员是否允许查看 def allowd_view if @myshixun.shixun.try(:status) == 2 && @game.status == 3 && User.current.id != @myshixun.shixun.try(:user_id) render_403 end # render_403 if (@game.status == 3 && User.current.id != @myshixun.shixun.try(:user_id)) end def find__shixun_language language = @myshixun.shixun.try(:language) @language = language_switch(language) end # Find myshixun of id params[:id] def find_myshixun myshixun_id = params[:myshixun_id] || (params[:game] && params[:game][:myshixun_id]) @myshixun = Myshixun.find_by_identifier(myshixun_id) if @myshixun.nil? render_404 return end rescue ActiveRecord::RecordNotFound render_404 end def find_game # myshixun_id = params[:myshixun_id] @game = Game.find_by_identifier(params[:id]) if @game.nil? render_404 return end @myshixun = @game.myshixun rescue ActiveRecord::RecordNotFound render_404 end end