#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/, '
').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>/, '/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