2017-04-07 10:16:13 +08:00
#coding=utf-8
class GamesController < ApplicationController
layout " base_myshixun "
skip_before_filter :verify_authenticity_token , :only = > [ :file_update ]
before_filter :find_myshixun , :only = > [ :index ]
2017-05-25 10:09:53 +08:00
before_filter :find_game , :only = > [ :show , :game_build , :entry , :next_step , :outputs_show , :file_edit , :file_update , :game_status , :change_status , :answer , :minus_score , :refresh_game_list ]
2017-04-07 10:16:13 +08:00
before_filter :find_repository , :only = > [ :show , :entry , :file_edit , :file_update ]
before_filter :allowd_manager
before_filter :allowd_view , :only = > [ :show ]
before_filter :find__shixun_language , :only = > [ :show , :entry ]
include ApplicationHelper
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
2017-04-14 15:47:20 +08:00
# @praise 判断是否点赞
2017-05-24 20:45:39 +08:00
# @tread 判断是否踩
2017-05-22 17:47:30 +08:00
# git_repository_url @myshixun, "Myshixun"
2017-04-07 10:16:13 +08:00
def show
2017-04-25 10:11:41 +08:00
# 展示全部实训
2017-04-28 23:35:27 +08:00
if @game . status == 1
# 放置页面ajax数据还没获取就关闭
@game . update_attribute ( :status , 0 )
end
2017-05-18 11:26:35 +08:00
# logger.info("#################%%%%%%#{@game.outputs.first.out_put}")
2017-05-15 17:00:52 +08:00
# @games = @myshixun.games.includes(:challenge)
2017-05-16 10:19:16 +08:00
@challenges = Challenge . where ( :shixun_id = > @myshixun . shixun_id )
2017-05-18 14:50:39 +08:00
@shixun = @myshixun . shixun
2017-05-15 17:00:52 +08:00
# @games_count = @games.count
2017-04-07 10:16:13 +08:00
@game_challenge = @game . challenge
2017-05-14 15:28:18 +08:00
@had_done = @game . had_done
2017-04-14 15:47:20 +08:00
@praise = PraiseTread . where ( " praise_tread_object_id=? and praise_tread_object_type=? and user_id=? " , @game_challenge . id , @game_challenge . class . to_s , User . current . id ) . first
@tread = PraiseTread . where ( " praise_tread_object_id=? and praise_tread_object_type=? and user_id=? " , @game_challenge . id , " ChallengeTread " , User . current . id ) . first
2017-04-07 10:16:13 +08:00
@rev = @rev . nil? ? " master " : @rev
@type = params [ :type ]
2017-04-21 19:34:57 +08:00
challenge_path = @game_challenge . path
2017-04-07 10:16:13 +08:00
# 默认打开文件
2017-05-14 15:28:18 +08:00
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 ) } " )
2017-04-21 19:34:57 +08:00
# 验证challenge文件名的合法性
2017-04-21 20:21:52 +08:00
if @path . blank? && ! challenge_path . blank? && challenge_path . include? ( " . " ) && @type != " root "
2017-04-21 19:34:57 +08:00
@path = challenge_path . strip
2017-04-20 14:10:59 +08:00
file_content = @g . files ( @myshixun . gpid , @path , @rev ) . content
2017-04-21 19:34:57 +08:00
if file_content . blank?
# gitlab缺陷: forked完成, 短暂时间内取不了内容的, 所以做一个小轮询, 间隔0.1秒
# 超过2秒则失败, 需通过页面刷新
2017-04-21 20:21:52 +08:00
for i in 0 .. 20 do
2017-04-21 19:34:57 +08:00
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
2017-04-21 16:10:46 +08:00
end
2017-04-28 20:24:33 +08:00
@content = Base64 . urlsafe_decode64 ( file_content ) unless file_content . blank?
2017-04-20 09:47:56 +08:00
end
2017-04-21 19:34:57 +08:00
if @content . nil?
2017-04-07 10:16:13 +08:00
@entries = @repository . entries ( @path , @rev )
end
2017-04-18 14:09:08 +08:00
# 页面前后端分离数据转换
test_sets = @game_challenge . test_sets
unless test_sets . blank?
2017-04-20 17:19:18 +08:00
@test_sets = test_set_static_data ( test_sets )
2017-04-07 10:16:13 +08:00
end
2017-04-18 16:14:11 +08:00
2017-04-18 14:09:08 +08:00
logger . info ( " # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #{ @public_test_sets } " )
2017-04-18 17:55:15 +08:00
@test_sets_count = test_sets . count
2017-05-05 16:14:35 +08:00
@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 = @game . outputs
@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_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
2017-06-02 15:50:07 +08:00
@final_score = ( @game . answer_open == 1 ? 0 : @game . final_score . to_i )
2017-05-12 21:48:06 +08:00
@had_done = ( ( @myshixun . games . where ( :status = > 2 ) . count == @myshixun . games . count && @game_challenge . position == @myshixun . games . count ) ? 1 : 0 )
2017-05-05 16:14:35 +08:00
error_position = had_test . blank? ? nil : had_test . select { | had_test | had_test . result == false } . last
2017-05-12 16:19:38 +08:00
logger . info ( " latest output id is #{ error_position . id unless error_position . blank? } " )
2017-05-18 15:55:12 +08:00
@latest_output = error_position . try ( :out_put ) . gsub ( / \ n / , '<br />' ) . gsub ( / \ t / , ' ' ) . to_json unless error_position . try ( :out_put ) . blank?
2017-05-18 11:26:35 +08:00
logger . info ( @latest_output )
2017-04-07 10:16:13 +08:00
respond_to do | format |
2017-04-18 16:14:11 +08:00
format . html
2017-04-07 10:16:13 +08:00
format . js
end
rescue Exception = > e
2017-04-21 19:34:57 +08:00
logger . error ( " game error # # # # # # # # # # # # # #{ e . message } " )
2017-04-07 10:16:13 +08:00
flash [ :error ] = e . message
end
# 代码预览
def entry
2017-04-21 19:34:57 +08:00
# entry_and_raw(false)
file_content = @g . files ( @myshixun . gpid , @path , @rev ) . content
2017-04-28 20:24:33 +08:00
@content = Base64 . urlsafe_decode64 ( file_content ) unless file_content . blank?
2017-04-21 19:34:57 +08:00
# @content = @repository.cat(@path, @rev)
2017-04-07 10:16:13 +08:00
end
def file_edit
# entry_and_raw(false)
# @content = @repository.cat(@path, @rev).strip
# # respond_to do |format|
# # format.js
# end
end
def file_update
@g = Gitlab . client
content = params [ :content ] . strip
2017-05-08 16:44:51 +08:00
code_file = @g . edit_file ( @myshixun . gpid , :content = > params [ :content ] , :file_path = > @path , :branch_name = > @rev , :commit_message = > " shixun exec " )
unless code_file . blank?
render :json = > { :success = > " success " }
end
2017-04-21 16:57:59 +08:00
= begin
2017-04-07 10:16:13 +08:00
respond_to do | format |
2017-04-21 16:57:59 +08:00
format . js
2017-04-07 10:16:13 +08:00
end
rescue Exception = > e
puts e . message
2017-04-21 16:57:59 +08:00
= end
2017-04-07 10:16:13 +08:00
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
# status 0: 未提交测评或者提交测评失败后报错; 1: 中间状态还没返回值; 2: 返回值并成功
2017-05-15 16:37:46 +08:00
# resubmit 唯一随机码,为了区分每一次重新评测结果
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 )
2017-04-07 10:16:13 +08:00
def game_build
game_challenge = @game . challenge
gitUrl = git_repository_url ( @myshixun , " Myshixun " )
gitUrl = Base64 . encode64 ( gitUrl )
2017-04-26 17:01:25 +08:00
taskId = @game . id
2017-04-07 10:16:13 +08:00
jobName = " myshixun_ #{ @myshixun . id } "
2017-05-15 16:37:46 +08:00
code = CODES . sample ( 8 ) . join
if @game . status == 2
resubmit = " #{ code } _ #{ @myshixun . id } "
end
2017-05-12 19:33:26 +08:00
# 过关后重评不更新状态
2017-05-15 16:37:46 +08:00
if resubmit . nil?
2017-05-12 19:33:26 +08:00
@game . update_attributes! ( :status = > 1 )
end
jenkins_shixuns = Redmine :: Configuration [ 'jenkins_shixuns' ]
step = game_challenge . try ( :position )
2017-05-14 15:28:18 +08:00
params = { :jobNameForInstance = > " #{ jobName } " , :buildID = > " #{ taskId } " , :step = > " #{ step } " , :instanceGitURL = > " #{ gitUrl } " , :instanceChallenge = > " #{ step } " , :resubmit = > resubmit }
2017-05-12 19:33:26 +08:00
uri = URI ( " #{ jenkins_shixuns } /jenkins-exec/api/buildJobForInstance " )
res = uri_exec uri , params
logger . info ( " # # # # # # # # # # # # # # # # # # # # # buildJobForInstance result is #{ res } " )
if ( res && res [ 'code' ] != 0 )
2017-05-23 21:26:42 +08:00
@message = " 实训云平台繁忙( 繁忙等级: 86) "
raise ( " 实训云平台繁忙( 繁忙等级: 86) " )
2017-04-07 10:16:13 +08:00
end
2017-05-15 16:37:46 +08:00
render :json = > { :result = > " success " , :resubmit = > resubmit }
2017-04-07 10:16:13 +08:00
rescue
2017-05-15 16:37:46 +08:00
if resubmit . nil?
2017-05-14 15:28:18 +08:00
@game . update_attributes! ( :status = > 0 )
end
2017-04-18 10:49:52 +08:00
#REDO Jenkins服务异常弹框抛出
2017-05-12 19:33:26 +08:00
render :json = > { :result = > " failed " }
2017-04-07 10:16:13 +08:00
end
2017-05-04 17:29:00 +08:00
# @myshixun -status 1:完成实训
2017-05-10 10:43:23 +08:00
# 全部通关奖励1000分
2017-05-15 16:37:46 +08:00
# retry_status 评测的唯一标识,重新评测对以前已产生的结果不造成影响
# params[:resubmit] 不为空表示已通过该关后重新评测, 重新评测必须是通过该关后才能执行
2017-05-14 15:28:18 +08:00
# @had_done 1 通关所有关
2017-04-07 10:16:13 +08:00
def game_status
game_challenge = @game . challenge
2017-05-14 15:28:18 +08:00
had_done = @game . had_done
2017-05-15 16:37:46 +08:00
resubmit_identifier = @game . resubmit_identifier
logger . info ( " # # # # # resubmit_identifier is #{ resubmit_identifier } " )
if params [ :resubmit ] . blank? # 非重新评测
if had_done == 1 # 通过最后一关,即所有关卡
2017-05-10 10:43:23 +08:00
@myshixun . update_attribute ( :status , 1 )
2017-05-15 16:37:46 +08:00
else # 通过当前一关
2017-05-10 10:43:23 +08:00
if @game . status == 2
@game . next_game . update_attribute ( :status , 0 )
2017-05-25 17:41:28 +08:00
unless @game . answer_open == true
2017-05-25 15:49:25 +08:00
reward_grade ( @game . user , @game . id , @game . class , game_challenge . score )
end
2017-05-10 10:43:23 +08:00
end
2017-05-04 17:29:00 +08:00
end
2017-05-12 21:48:06 +08:00
game_status = @game . status
2017-05-15 16:37:46 +08:00
else # 重新评测
if params [ :resubmit ] == resubmit_identifier # 本次重新评测结果已经返回并存入数据库
game_status = ( @game . retry_status == 2 ? 2 : 0 ) # retry_status 2: 成功 1: 失败
2017-05-26 09:48:06 +08:00
if game_status == 2 && had_done == 1 # 重新评测如果评测成功
had_done = 1
else
had_done = 0
end
2017-05-15 16:37:46 +08:00
else
# game_status 在前端有行为判断, 2表示通关; 0表示失败; 1表示评测中的中间状态
game_status = 1
had_done = 0
end
2017-04-07 10:16:13 +08:00
end
2017-04-18 14:09:08 +08:00
test_sets = game_challenge . test_sets
unless test_sets . blank?
2017-04-20 17:19:18 +08:00
total_test_sets = test_set_static_data ( test_sets )
2017-04-18 14:09:08 +08:00
end
2017-05-05 16:14:35 +08:00
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 = @game . outputs
@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_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
2017-06-02 15:50:07 +08:00
@final_score = ( @game . answer_open == 1 ? 0 : @game . final_score . to_i )
2017-05-05 16:14:35 +08:00
error_position = had_test . blank? ? nil : had_test . select { | had_test | had_test . result == false } . last
2017-05-21 15:26:43 +08:00
@latest_output = error_position . try ( :out_put ) . gsub ( / \ n / , '<br />' ) . gsub ( / \ t / , ' ' ) unless error_position . try ( :out_put ) . blank?
2017-05-05 16:14:35 +08:00
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 ,
latest_output : @latest_output ,
2017-05-12 21:48:06 +08:00
status : game_status ,
2017-05-05 16:14:35 +08:00
had_done : had_done }
2017-04-07 10:16:13 +08:00
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
# 自动推送下一个任务
def next_step
render_403 if @game . status != 2
next_game = @game . next_game
2017-04-14 10:58:25 +08:00
next_game . update_attributes ( :status = > 0 , :open_time = > Time . now ) if next_game . status == 3
2017-04-28 16:01:38 +08:00
respond_to do | format |
format . js { redirect_to myshixun_game_path ( next_game , :myshixun_id = > @myshixun ) }
end
2017-04-07 10:16:13 +08:00
end
2017-05-04 14:47:19 +08:00
# 获取答案,第一次查看需扣掉该关卡的积分
# 如果已看过,下次可以免费查看
# viewed 1: 直接查看 2: 弹框提示将要扣除积分, 确定后显示内容 3: 弹框提示分数不够
def answer
challenge = @game . challenge
2017-05-05 14:57:58 +08:00
@challenge_score = challenge . score . to_i
2017-05-04 14:47:19 +08:00
# 已经开启过
2017-05-25 16:52:08 +08:00
@score = User . current . grade . to_i - @challenge_score
2017-05-05 14:57:58 +08:00
@answer = challenge . answer
2017-05-04 14:47:19 +08:00
if @game . answer_open
2017-05-05 14:57:58 +08:00
@viewed = 1
2017-05-04 14:47:19 +08:00
else
2017-05-05 14:57:58 +08:00
if @score > = 0
@viewed = 2
2017-05-04 14:47:19 +08:00
else
2017-05-05 14:57:58 +08:00
@viewed = 3
2017-05-04 14:47:19 +08:00
end
end
2017-05-05 14:57:58 +08:00
respond_to do | format |
format . js
2017-05-21 15:00:24 +08:00
format . html
2017-05-05 14:57:58 +08:00
end
end
def minus_score
2017-05-24 17:39:36 +08:00
@game_challenge = @game . challenge
2017-05-05 14:57:58 +08:00
user = User . current
2017-05-24 17:39:36 +08:00
challenge_score = @game_challenge . score . to_i
2017-05-25 15:49:25 +08:00
reward_grade ( user , @game . id , 'Answer' , - challenge_score )
2017-05-24 17:39:36 +08:00
@answer = @game_challenge . answer
2017-05-05 14:57:58 +08:00
@game . update_column ( :answer_open , true )
respond_to do | format |
format . js
end
2017-05-04 14:47:19 +08:00
end
2017-05-25 10:09:53 +08:00
def refresh_game_list
myshixun_id = params [ :myshixun_id ]
@myshixun = Myshixun . find_by_identifier ( myshixun_id )
@challenges = Challenge . where ( :shixun_id = > @myshixun . shixun_id )
respond_to do | format |
format . js
end
end
2017-04-07 10:16:13 +08:00
private
2017-04-18 10:49:52 +08:00
def test_set_static_data test_sets
2017-04-20 17:19:18 +08:00
test_result = [ ]
2017-04-18 10:49:52 +08:00
unless test_sets . blank?
test_sets . each do | test_set |
2017-04-20 17:19:18 +08:00
output = Output . where ( :game_id = > @game . id , :test_set_position = > test_set . position ) . first
2017-05-18 15:55:12 +08:00
actual_output = ( output . try ( :actual_output ) . gsub ( / \ n / , '<br />' ) . gsub ( / \ t / , ' ' ) unless output . try ( :actual_output ) . blank? )
2017-04-20 17:19:18 +08:00
result = output . try ( :result )
public_result = { :is_public = > ( test_set . is_public ? 1 : 0 ) , :result = > result , :input = > test_set . input ,
2017-04-19 20:16:02 +08:00
:actual_output = > actual_output , :output = > test_set . output }
2017-04-20 15:12:33 +08:00
logger . info ( " 1111 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #{ public_result . to_json } " )
2017-04-20 17:19:18 +08:00
test_result << public_result . to_json
2017-04-18 10:49:52 +08:00
end
end
2017-04-20 17:19:18 +08:00
test_result = test_result . blank? ? test_result : test_result . join ( " , " )
logger . info ( " 222 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #{ test_result } " )
return test_result
2017-04-18 10:49:52 +08:00
end
2017-04-07 10:16:13 +08:00
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
2017-04-21 15:57:08 +08:00
render_403 if ( @game . status == 3 && User . current . id != @myshixun . shixun . try ( :user_id ) )
2017-04-07 10:16:13 +08:00
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 ] )
2017-04-26 16:03:05 +08:00
@myshixun = Myshixun . find_by_identifier ( myshixun_id )
if @myshixun . nil?
render_404
return
end
2017-04-07 10:16:13 +08:00
rescue ActiveRecord :: RecordNotFound
render_404
end
def find_game
2017-04-26 14:20:07 +08:00
# myshixun_id = params[:myshixun_id]
@game = Game . find_by_identifier ( params [ :id ] )
if @game . nil?
render_404
return
end
2017-04-07 10:16:13 +08:00
@myshixun = @game . myshixun
rescue ActiveRecord :: RecordNotFound
render_404
end
end