You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
pgfqe6ch8/app/controllers/games_controller.rb

938 lines
42 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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 > 0)
@gold = 0
else
if @game.answer_open > 0 && @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/, '<br/>').gsub(/\t/, '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;').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/, '<br/>').gsub(/\t/, '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;') 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) +"题:<br />"
@answer += (choose.answer.blank? ? choose.standard_answer : choose.answer)
@answer += "<br /><br /><br />"
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) +"题:<br />"
@answer += (choose.answer.blank? ? choose.standard_answer : choose.answer)
@answer += "<br /><br /><br />"
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>/, '<//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