chromesetting
杨树林 5 years ago
commit f68820832d

@ -1318,7 +1318,7 @@ class CoursesController < ApplicationController
@c_tasks = @course.graduation_tasks.task_published.order("graduation_tasks.publish_time asc, graduation_tasks.created_at asc")
set_export_cookies
member_to_xlsx(@course, @all_members, @c_homeworks, @c_exercises, @c_tasks)
member_to_xlsx(@course, @all_members.includes(user: :user_extension), @c_homeworks, @c_exercises, @c_tasks)
filename_ = "#{current_user.real_name}_#{@course.name}_总成绩_#{Time.now.strftime('%Y%m%d_%H%M%S')}"
render xlsx: "#{format_sheet_name filename_.strip}",template: "courses/export_member_scores_excel.xlsx.axlsx",
locals: {course_scores:@course_user_scores,shixun_works:@shixun_work_arrays,

@ -1,386 +1,386 @@
class MyshixunsController < ApplicationController
before_action :require_login, :check_auth, :except => [:training_task_status, :code_runinng_message]
before_action :find_myshixun, :except => [:training_task_status, :code_runinng_message]
before_action :find_repo_name, :except => [:training_task_status, :code_runinng_message]
skip_before_action :verify_authenticity_token, :only => [:html_content]
## TPI关卡列表
def challenges
# @challenges = Challenge.where(shixun_id: params[:shixun_id])
@shixun = @myshixun.shixun
@games = @myshixun.games.includes(:challenge).reorder("challenges.position")
@identity = current_user.game_identity(@games.first)
end
# For Admin
# 强制重置实训
# 前段需要按照操作过程提示
def reset_my_game
unless (current_user.admin? || current_user.id == @myshixun.user_id)
tip_exception("403", "")
end
begin
ActiveRecord::Base.transaction do
begin
@shixun = Shixun.select(:id, :identifier, :challenges_count).find(@myshixun.shixun_id)
@myshixun.destroy!
StudentWork.where(:myshixun_id => @myshixun.id).update_all(myshixun_id: 0, work_status: 0, work_score: nil,
final_score: nil, efficiency: 0, eff_score: 0, calculation_time: nil, cost_time: 0, compelete_status: 0)
rescue Exception => e
logger.error("######reset_my_game_failed:#{e.message}")
raise("ActiveRecord::RecordInvalid")
end
end
# 删除版本库
GitService.delete_repository(repo_path: @repo_path) unless @shixun.is_choice_type?
rescue Exception => e
if e.message != "ActiveRecord::RecordInvalid"
logger.error("######delete_repository_error-:#{e.message}")
end
raise "delete_repository_error:#{e.message}"
end
end
# 代码运行中的信息接口
# 这个方法是中间层主动调用的点击评测后中间层会发送参数过来告诉目前Pod的启动情况一次评测会调用两次请求
def code_runinng_message
begin
jsonTestDetails = JSON.parse(params[:jsonTestDetails])
game_id = jsonTestDetails['buildID']
message = jsonTestDetails['textMsg']
if game_id.present? && message.present?
game = Game.find game_id
msg = game.run_code_message
# 只有评测中的game才会创建和更新代码评测中的信息
if game.status == 1 || game.status == 2
if msg.blank?
RunCodeMessage.create!(:game_id => game_id, :status => 1, :message => message)
else
msg.update_attributes(:status => (msg.status + 1), :message => message)
end
end
render :json => {:data => "success"}
end
rescue Exception => e
render :json => {:data => "failed, exception_message: #{e}"}
end
end
# 中间层评测接口
# taskId 即返回的game id
# 返回结果params [:stauts] 0 表示成功,其它则失败
# msg 错误信息
# output 为测试用户编译输出结果
# myshixun:status 1为完成实训
# @jenkins: caseId对应test_set的positionpassed: 1表示成功0表示失败
# resubmit 1表示已通关后重新评测0表示非重新评测
# retry_status 0初始值1重新评测失败2重新评测成功
# tpiRepoPath 中间层图片的workspace路径
# params[:jsonTestDetails] = '{"buildID":"19284","compileSuccess":"1",
# "msg":[{"caseId":"1","expectedOutput":"MSAyIDMNCg","input":"MiAzIDE","output":"MSAyIDMNCg","passed":"1"},
# {"caseId":"2","expectedOutput":"LTMgMSA2DQo","input":"LTMgNiAx","output":"LTMgMSA2DQo","passed":"1"},
# {"caseId":"3","expectedOutput":"LTcgLTUgLTMNCg","input":"LTcgLTMgLTU","output":"LTcgLTUgLTMNCg","passed":"1"}],
# "outPut":"Y29tcGlsZSBzdWNjZXNzZnVsbHk","resubmit":"","status":"0"}'
# params[:timeCost] = '{"evaluateEnd":"2017-11-24 11:04:37","pull":"0.086",
# "createPod":"1.610","evaluateAllTime":2820,"evaluateStart":"2017-11-24 11:04:35","execute":"0.294"}'
# params[:pics] = "a.png,b.png,c.png"
def training_task_status
ActiveRecord::Base.transaction do
begin
t1 = Time.now
uid_logger_dubug("@@@222222#{params[:jsonTestDetails]}")
jsonTestDetails = JSON.parse(params[:jsonTestDetails])
timeCost = JSON.parse(params[:timeCost])
brige_end_time = Time.parse(timeCost['evaluateEnd']) if timeCost['evaluateEnd'].present?
return_back_time = format("%.3f", ( t1.to_f - brige_end_time.to_f)).to_f
status = jsonTestDetails['status']
game_id = jsonTestDetails['buildID']
sec_key = jsonTestDetails['sec_key']
uid_logger_dubug("training_task_status start-#{game_id}-1#{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
resubmit = jsonTestDetails['resubmit']
outPut = tran_base64_decode64(jsonTestDetails['outPut'])
jenkins_testsets = jsonTestDetails['msg']
compile_success = jsonTestDetails['compileSuccess']
# message = Base64.decode64(params[:msg]) unless params[:msg].blank?
game = Game.find(game_id)
myshixun = game.myshixun
challenge = game.challenge
# test_sets = challenge.test_sets
if challenge.picture_path.present?
#pics = params[:files]
pics = params[:tpiRepoPath]
game.update_column(:picture_path, pics)
end
max_query_index = game.outputs ? (game.outputs.first.try(:query_index).to_i + 1) : 1
test_set_score = 0
unless jenkins_testsets.blank?
jenkins_testsets.each_with_index do |j_test_set, i|
actual_output = tran_base64_decode64(j_test_set['output'])
#ts_time += j_test_set['testSetTime'].to_i
# is_public = test_sets.where(:position => j_test_set['caseId']).first.try(:is_public)
ts_time = format("%.2f", j_test_set['testSetTime'].to_f/1000000000).to_f if j_test_set['testSetTime']
ts_mem = format("%.2f", j_test_set['testSetMem'].to_f/1024/1024).to_f if j_test_set['testSetMem']
Output.create!(:code => status, :game_id => game_id, :out_put => outPut, :test_set_position => j_test_set['caseId'],
:actual_output => actual_output, :result => j_test_set['passed'].to_i, :query_index => max_query_index,
:compile_success => compile_success.to_i, :sec_key => sec_key, :ts_time => ts_time, :ts_mem => ts_mem)
# 如果设置了按测试集给分,则需要统计测试集的分值
if challenge.test_set_score && j_test_set['passed'].to_i == 1
test_set_score += challenge.test_sets.where(:position => j_test_set['caseId']).pluck(:score).first
end
end
end
record = EvaluateRecord.where(:identifier => sec_key).first
answer_deduction_percentage = (100 - game.answer_deduction) / 100.to_f # 查看答案后剩余分数的百分比.
# answer_deduction是查看答案的扣分比例
# status0表示评测成功
if status == "0"
if resubmit.present?
game.update_attributes!(:retry_status => 2, :resubmit_identifier => resubmit)
challenge.path.split("").each do |path|
game_passed_code(path.try(:strip), myshixun, game_id)
end
else
game.update_attributes!(:status => 2,
:end_time => Time.now,
:accuracy => format("%.4f", 1.0 / game.query_index))
myshixun.update_attributes!(:status => 1) if game.had_done == 1
challenge.path.split("").each do |path|
game_passed_code(path.try(:strip), myshixun, game_id)
end
# 如果是已经发布的实训,则需要给出相应的奖励
if challenge.shixun.try(:status) > 1
score = (challenge.score * answer_deduction_percentage).to_i
if score > 0
reward_attrs = { container_id: game.id, container_type: 'Game', score: score }
RewardGradeService.call(game.user, reward_attrs)
RewardExperienceService.call(game.user, reward_attrs)
end
# 需要扣除查看答案的分数
game.update_attributes!(:final_score => score)
end
# 更新实训关联的作品分数 TODO: 更新作品分数
# HomeworksService.new.update_myshixun_work_score myshixun
end
# 如果过关了下一关的状态是3为开启则需要把状态改成1已开启
# next_game = game.next_game
next_game = game.next_game(myshixun.shixun_id, game.myshixun_id, challenge.position)
next_game.update_column(:status, 0) if next_game.present? && next_game.status == 3
# status == "-1" 表示返回结果错误
else
if resubmit.present?
game.update_attributes!(:retry_status => 1, :resubmit_identifier => resubmit)
else
# 评测没通关则,测试集对的个数给分,并且还要扣除用户是否查看答案的值
test_set_percentage = test_set_score / 100.to_f # 测试集得分比
score = (challenge.score * test_set_percentage * answer_deduction_percentage).to_i
# 如果分数比上次多,则更新成绩
game_update =
if game.final_score < score
{final_score: score, status: 0}
else
{status: 0}
end
game.update_attributes!(game_update)
end
end
test_cases_time = format("%.3f", (Time.now.to_f - t1.to_f)).to_f
if record.present?
consume_time = format("%.3f", (Time.now - record.created_at)).to_f
record.update_attributes!(:consume_time => consume_time, :git_pull => timeCost['pull'] , :create_pod => timeCost['createPod'],
:pod_execute => timeCost['execute'], :test_cases => test_cases_time,
:brige => timeCost['evaluateAllTime'], :return_back => return_back_time)
end
sucess_status
# rescue Exception => e
# tip_exception(e.message)
# uid_logger_error("training_task_status error: #{e}")
# raise ActiveRecord::Rollback
end
end
end
# 连接webssh
def open_webssh
username = edu_setting('webssh_username')
password = edu_setting('webssh_password')
old_time = Time.now.to_i
begin
shixun_tomcat = edu_setting('tomcat_webssh')
uri = "#{shixun_tomcat}/bridge/webssh/getConnectInfo"
# 由于中间层采用混合云的方式因为local参数表示在有文件生成的实训是在本地生成还是在其他云端生成评测文件
local = @myshixun.shixun.challenges.where.not(show_type: -1).count == 0
params = {tpiID:@myshixun.id, podType:@myshixun.shixun.try(:webssh), local: local,
containers:(Base64.urlsafe_encode64(shixun_container_limit @myshixun.shixun))}
res = uri_post uri, params
if res && res['code'].to_i != 0
tip_exception("实训云平台繁忙繁忙等级92")
end
render :json => {:host => res['address'],
:port => res['port'],
:ws_url => res['ws_address'],
:username => username,
:password => password,
:game_id => @myshixun.id,
:webssh_url => "#{shixun_tomcat}/bridge"}
rescue Exception => e
logger.error(e)
render :json => {:error => e.try(:message)}
ensure
use_time = Time.now.to_i - old_time
logger.info "open_webssh tpiID #{@myshixun.id} use time #{use_time}"
end
end
include GitCommon
# -----Repository
# TODO: 之类需要一个resubmit参数,但是是关于games.
def update_file
begin
@hide_code = Shixun.where(id: @myshixun.shixun_id).pluck(:hide_code).first
tip_exception("技术平台为空!") if @myshixun.mirror_name.blank?
path = params[:path].strip unless params[:path].blank?
game_id = params[:game_id]
game = Game.find(game_id)
@content_modified = 0
# params[:evaluate] 实训评测时更新必须给的参数,需要依据该参数做性能统计,其它类型的更新可以跳过
# 自动保存的时候evaluate为0点评测的时候为1
if params[:evaluate] == 1
exec_time = game.challenge.try(:exec_time)
@sec_key = generate_identifier(EvaluateRecord, 12)
record = EvaluateRecord.create!(:user_id => current_user.id, :shixun_id => @myshixun.shixun_id, :game_id => game_id,
:identifier => @sec_key, :exec_time => exec_time)
uid_logger_dubug("-- game build: file update #{@sec_key}, record id is #{record.id}, time is **** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
end
# 隐藏代码文件 和 VNC的都不需要走版本库
unless @hide_code || (@myshixun.shixun&.vnc_evaluate && params[:evaluate].present?)
# 远程版本库文件内容
last_content = GitService.file_content(repo_path: @repo_path, path: path)["content"]
content =
if python_file?(path)
params[:content].gsub(/\t/, ' ').gsub(/ /, ' ')
else
params[:content]
end
uid_logger_dubug("###11222333####{content}")
uid_logger_dubug("###222333####{last_content}")
if content != last_content
@content_modified = 1
author_name = current_user.real_name
author_email = current_user.git_mail
message = params[:evaluate] == 0 ? "System automatically submitted" : "User submitted"
uid_logger_dubug("112233#{author_name}")
uid_logger_dubug("112233#{author_email}")
@content = GitService.update_file(repo_path: @repo_path,
file_path: path,
message: message,
content: content,
author_name: author_name,
author_email: author_email)
end
end
if game.status == 2
@resubmit = Time.now.to_i
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
rescue Exception => e
uid_logger_error(e.message)
tip_exception("文件内容更新异常,请稍后重试")
end
end
# 渲染实训代码
# educodercss: 字符串以 分隔存储的是版本库css的路径
# educoderscript: 字符串以 分隔存储的是版本库js的路径
# contents html实训的整体内容
def html_content
@contents = params[:contents] || ""
edu_css = params[:educodercss]
edu_js = params[:educoderscript]
if @contents.present?
@contents = @contents.gsub("w3equalsign", "=").gsub("w3scrw3ipttag", "script").gsub("edulink", "link").html_safe
end
# css
if edu_css.present?
css_path = edu_css.split(",")
css_path.each do |path|
file_content = git_fle_content(@repo_path, path)["content"]
file_content = tran_base64_decode64(file_content) unless file_content.blank?
@contents = @contents.sub(/EDUCODERCSS/, "<style>#{file_content}</style>")
end
end
# js
if edu_js.present?
js_path = edu_js.split(",")
js_path.each do |path|
file_content = git_fle_content(@repo_path, path)["content"]
file_content = tran_base64_decode64(file_content) unless file_content.blank?
@contents = @contents.sub(/EDUCODERJS/, "<script>#{file_content}</script>")
end
end
respond_to do |format|
format.json
format.html{render :layout => false}
end
end
# 最新可以用的并发测试接口
def sigle_mul_test
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)
begin
identifiers = Myshixun.where(:shixun_id => params[:shixun_id].split(",")).pluck(:identifier)
ide = identifiers[rand(identifiers.length)]
myshixun = Myshixun.where(:identifier => ide).first
game = myshixun.games.last
logger.warn("###2mul test game_build start ")
identifier = game.try(:identifier)
if game.status == 2
code = codes.sample(8).join
resubmit = "#{code}_#{myshixun.id}"
end
logger.warn("###3mul test game_build start ...")
EvaluateRecord.create!(:user_id => myshixun.user_id, :shixun_id => myshixun.shixun.id, :game_id => game.id)
redirect_to "/api/games/#{identifier}/game_build?resubmit=#{resubmit}&content_modified=0&first=1"
rescue Exception => e
logger.error("mul test failed ===> #{e.message}")
end
end
# -----End
private
def find_myshixun
@myshixun = Myshixun.find_by!(identifier: params[:identifier])
end
def find_repo_name
@repo_path = @myshixun.try(:repo_path)
@path = params[:path]
end
def python_file?(path)
false if path.blank?
path.to_s.split(".").last.downcase == "py"
end
end
class MyshixunsController < ApplicationController
before_action :require_login, :check_auth, :except => [:training_task_status, :code_runinng_message]
before_action :find_myshixun, :except => [:training_task_status, :code_runinng_message]
before_action :find_repo_name, :except => [:training_task_status, :code_runinng_message]
skip_before_action :verify_authenticity_token, :only => [:html_content]
## TPI关卡列表
def challenges
# @challenges = Challenge.where(shixun_id: params[:shixun_id])
@shixun = @myshixun.shixun
@games = @myshixun.games.includes(:challenge).reorder("challenges.position")
@identity = current_user.game_identity(@games.first)
end
# For Admin
# 强制重置实训
# 前段需要按照操作过程提示
def reset_my_game
unless (current_user.admin? || current_user.id == @myshixun.user_id)
tip_exception("403", "")
end
begin
ActiveRecord::Base.transaction do
begin
@shixun = Shixun.select(:id, :identifier, :challenges_count).find(@myshixun.shixun_id)
@myshixun.destroy!
StudentWork.where(:myshixun_id => @myshixun.id).update_all(myshixun_id: 0, work_status: 0, work_score: nil,
final_score: nil, efficiency: 0, eff_score: 0, calculation_time: nil, cost_time: 0, compelete_status: 0)
rescue Exception => e
logger.error("######reset_my_game_failed:#{e.message}")
raise("ActiveRecord::RecordInvalid")
end
end
# 删除版本库
GitService.delete_repository(repo_path: @repo_path) unless @shixun.is_choice_type?
rescue Exception => e
if e.message != "ActiveRecord::RecordInvalid"
logger.error("######delete_repository_error-:#{e.message}")
end
raise "delete_repository_error:#{e.message}"
end
end
# 代码运行中的信息接口
# 这个方法是中间层主动调用的点击评测后中间层会发送参数过来告诉目前Pod的启动情况一次评测会调用两次请求
def code_runinng_message
begin
jsonTestDetails = JSON.parse(params[:jsonTestDetails])
game_id = jsonTestDetails['buildID']
message = jsonTestDetails['textMsg']
if game_id.present? && message.present?
game = Game.find game_id
msg = game.run_code_message
# 只有评测中的game才会创建和更新代码评测中的信息
if game.status == 1 || game.status == 2
if msg.blank?
RunCodeMessage.create!(:game_id => game_id, :status => 1, :message => message)
else
msg.update_attributes(:status => (msg.status + 1), :message => message)
end
end
render :json => {:data => "success"}
end
rescue Exception => e
render :json => {:data => "failed, exception_message: #{e}"}
end
end
# 中间层评测接口
# taskId 即返回的game id
# 返回结果params [:stauts] 0 表示成功,其它则失败
# msg 错误信息
# output 为测试用户编译输出结果
# myshixun:status 1为完成实训
# @jenkins: caseId对应test_set的positionpassed: 1表示成功0表示失败
# resubmit 1表示已通关后重新评测0表示非重新评测
# retry_status 0初始值1重新评测失败2重新评测成功
# tpiRepoPath 中间层图片的workspace路径
# params[:jsonTestDetails] = '{"buildID":"19284","compileSuccess":"1",
# "msg":[{"caseId":"1","expectedOutput":"MSAyIDMNCg","input":"MiAzIDE","output":"MSAyIDMNCg","passed":"1"},
# {"caseId":"2","expectedOutput":"LTMgMSA2DQo","input":"LTMgNiAx","output":"LTMgMSA2DQo","passed":"1"},
# {"caseId":"3","expectedOutput":"LTcgLTUgLTMNCg","input":"LTcgLTMgLTU","output":"LTcgLTUgLTMNCg","passed":"1"}],
# "outPut":"Y29tcGlsZSBzdWNjZXNzZnVsbHk","resubmit":"","status":"0"}'
# params[:timeCost] = '{"evaluateEnd":"2017-11-24 11:04:37","pull":"0.086",
# "createPod":"1.610","evaluateAllTime":2820,"evaluateStart":"2017-11-24 11:04:35","execute":"0.294"}'
# params[:pics] = "a.png,b.png,c.png"
def training_task_status
ActiveRecord::Base.transaction do
begin
t1 = Time.now
uid_logger_dubug("@@@222222#{params[:jsonTestDetails]}")
jsonTestDetails = JSON.parse(params[:jsonTestDetails])
timeCost = JSON.parse(params[:timeCost])
brige_end_time = Time.parse(timeCost['evaluateEnd']) if timeCost['evaluateEnd'].present?
return_back_time = format("%.3f", ( t1.to_f - brige_end_time.to_f)).to_f
status = jsonTestDetails['status']
game_id = jsonTestDetails['buildID']
sec_key = jsonTestDetails['sec_key']
uid_logger_dubug("training_task_status start-#{game_id}-1#{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
resubmit = jsonTestDetails['resubmit']
outPut = tran_base64_decode64(jsonTestDetails['outPut'])
jenkins_testsets = jsonTestDetails['msg']
compile_success = jsonTestDetails['compileSuccess']
# message = Base64.decode64(params[:msg]) unless params[:msg].blank?
game = Game.find(game_id)
myshixun = game.myshixun
challenge = game.challenge
# test_sets = challenge.test_sets
if challenge.picture_path.present?
#pics = params[:files]
pics = params[:tpiRepoPath]
game.update_column(:picture_path, pics)
end
max_query_index = game.outputs ? (game.outputs.first.try(:query_index).to_i + 1) : 1
test_set_score = 0
unless jenkins_testsets.blank?
jenkins_testsets.each_with_index do |j_test_set, i|
actual_output = tran_base64_decode64(j_test_set['output'])
#ts_time += j_test_set['testSetTime'].to_i
# is_public = test_sets.where(:position => j_test_set['caseId']).first.try(:is_public)
ts_time = format("%.2f", j_test_set['testSetTime'].to_f/1000000000).to_f if j_test_set['testSetTime']
ts_mem = format("%.2f", j_test_set['testSetMem'].to_f/1024/1024).to_f if j_test_set['testSetMem']
Output.create!(:code => status, :game_id => game_id, :out_put => outPut, :test_set_position => j_test_set['caseId'],
:actual_output => actual_output, :result => j_test_set['passed'].to_i, :query_index => max_query_index,
:compile_success => compile_success.to_i, :sec_key => sec_key, :ts_time => ts_time, :ts_mem => ts_mem)
# 如果设置了按测试集给分,则需要统计测试集的分值
if challenge.test_set_score && j_test_set['passed'].to_i == 1
test_set_score += challenge.test_sets.where(:position => j_test_set['caseId']).pluck(:score).first
end
end
end
record = EvaluateRecord.where(:identifier => sec_key).first
answer_deduction_percentage = (100 - game.answer_deduction) / 100.to_f # 查看答案后剩余分数的百分比.
# answer_deduction是查看答案的扣分比例
# status0表示评测成功
if status == "0"
if resubmit.present?
game.update_attributes!(:retry_status => 2, :resubmit_identifier => resubmit)
challenge.path.split("").each do |path|
game_passed_code(path.try(:strip), myshixun, game_id)
end
else
game.update_attributes!(:status => 2,
:end_time => Time.now,
:accuracy => format("%.4f", 1.0 / game.query_index))
myshixun.update_attributes!(:status => 1) if game.had_done == 1
challenge.path.split("").each do |path|
game_passed_code(path.try(:strip), myshixun, game_id)
end
# 如果是已经发布的实训,则需要给出相应的奖励
if challenge.shixun.try(:status) > 1
score = (challenge.score * answer_deduction_percentage).to_i
if score > 0
reward_attrs = { container_id: game.id, container_type: 'Game', score: score }
RewardGradeService.call(game.user, reward_attrs)
RewardExperienceService.call(game.user, reward_attrs)
end
# 需要扣除查看答案的分数
game.update_attributes!(:final_score => score)
end
# 更新实训关联的作品分数 TODO: 更新作品分数
# HomeworksService.new.update_myshixun_work_score myshixun
end
# 如果过关了下一关的状态是3为开启则需要把状态改成1已开启
# next_game = game.next_game
next_game = game.next_game(myshixun.shixun_id, game.myshixun_id, challenge.position)
next_game.update_column(:status, 0) if next_game.present? && next_game.status == 3
# status == "-1" 表示返回结果错误
else
if resubmit.present?
game.update_attributes!(:retry_status => 1, :resubmit_identifier => resubmit)
else
# 评测没通关则,测试集对的个数给分,并且还要扣除用户是否查看答案的值
test_set_percentage = test_set_score / 100.to_f # 测试集得分比
score = (challenge.score * test_set_percentage * answer_deduction_percentage).to_i
# 如果分数比上次多,则更新成绩
game_update =
if game.final_score < score
{final_score: score, status: 0}
else
{status: 0}
end
game.update_attributes!(game_update)
end
end
test_cases_time = format("%.3f", (Time.now.to_f - t1.to_f)).to_f
if record.present?
consume_time = format("%.3f", (Time.now - record.created_at)).to_f
record.update_attributes!(:consume_time => consume_time, :git_pull => timeCost['pull'] , :create_pod => timeCost['createPod'],
:pod_execute => timeCost['execute'], :test_cases => test_cases_time,
:brige => timeCost['evaluateAllTime'], :return_back => return_back_time)
end
sucess_status
# rescue Exception => e
# tip_exception(e.message)
# uid_logger_error("training_task_status error: #{e}")
# raise ActiveRecord::Rollback
end
end
end
# 连接webssh
def open_webssh
username = edu_setting('webssh_username')
password = edu_setting('webssh_password')
old_time = Time.now.to_i
begin
shixun_tomcat = edu_setting('tomcat_webssh')
uri = "#{shixun_tomcat}/bridge/webssh/getConnectInfo"
# 由于中间层采用混合云的方式因为local参数表示在有文件生成的实训是在本地生成还是在其他云端生成评测文件
local = @myshixun.shixun.challenges.where.not(show_type: -1).count == 0
params = {tpiID:@myshixun.id, podType:@myshixun.shixun.try(:webssh), local: local,
containers:(Base64.urlsafe_encode64(shixun_container_limit @myshixun.shixun))}
res = uri_post uri, params
if res && res['code'].to_i != 0
tip_exception("实训云平台繁忙繁忙等级92")
end
render :json => {:host => res['address'],
:port => res['port'],
:ws_url => res['ws_address'],
:username => username,
:password => password,
:game_id => @myshixun.id,
:webssh_url => "#{shixun_tomcat}/bridge"}
rescue Exception => e
logger.error(e)
render :json => {:error => e.try(:message)}
ensure
use_time = Time.now.to_i - old_time
logger.info "open_webssh tpiID #{@myshixun.id} use time #{use_time}"
end
end
include GitCommon
# -----Repository
# TODO: 之类需要一个resubmit参数,但是是关于games.
def update_file
begin
@hide_code = Shixun.where(id: @myshixun.shixun_id).pluck(:hide_code).first
tip_exception("技术平台为空!") if @myshixun.mirror_name.blank?
path = params[:path].strip unless params[:path].blank?
game_id = params[:game_id]
game = Game.find(game_id)
@content_modified = 0
# params[:evaluate] 实训评测时更新必须给的参数,需要依据该参数做性能统计,其它类型的更新可以跳过
# 自动保存的时候evaluate为0点评测的时候为1
if params[:evaluate] == 1
exec_time = game.challenge.try(:exec_time)
@sec_key = generate_identifier(EvaluateRecord, 12)
record = EvaluateRecord.create!(:user_id => current_user.id, :shixun_id => @myshixun.shixun_id, :game_id => game_id,
:identifier => @sec_key, :exec_time => exec_time)
uid_logger_dubug("-- game build: file update #{@sec_key}, record id is #{record.id}, time is **** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
end
# 隐藏代码文件 和 VNC的都不需要走版本库
unless @hide_code || (@myshixun.shixun&.vnc_evaluate && params[:evaluate].present?)
# 远程版本库文件内容
last_content = GitService.file_content(repo_path: @repo_path, path: path)["content"]
content =
if python_file?(path)
params[:content].gsub(/\t/, ' ').gsub(/ /, ' ')
else
params[:content]
end
uid_logger_dubug("###11222333####{content}")
uid_logger_dubug("###222333####{last_content}")
if content != last_content
@content_modified = 1
author_name = current_user.real_name
author_email = current_user.git_mail
message = params[:evaluate] == 0 ? "System automatically submitted" : "User submitted"
uid_logger_dubug("112233#{author_name}")
uid_logger_dubug("112233#{author_email}")
@content = GitService.update_file(repo_path: @repo_path,
file_path: path,
message: message,
content: content,
author_name: author_name,
author_email: author_email)
end
end
if game.status == 2
@resubmit = Time.now.to_i
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
rescue Exception => e
uid_logger_error(e.message)
tip_exception("文件内容更新异常,请稍后重试")
end
end
# 渲染实训代码
# educodercss: 字符串以 分隔存储的是版本库css的路径
# educoderscript: 字符串以 分隔存储的是版本库js的路径
# contents html实训的整体内容
def html_content
@contents = params[:contents] || ""
edu_css = params[:educodercss]
edu_js = params[:educoderscript]
if @contents.present?
@contents = @contents.gsub("w3equalsign", "=").gsub("w3scrw3ipttag", "script").gsub("edulink", "link").html_safe
end
# css
if edu_css.present?
css_path = edu_css.split(",")
css_path.each do |path|
file_content = git_fle_content(@repo_path, path)["content"]
file_content = tran_base64_decode64(file_content) unless file_content.blank?
@contents = @contents.sub(/EDUCODERCSS/, "<style>#{file_content}</style>")
end
end
# js
if edu_js.present?
js_path = edu_js.split(",")
js_path.each do |path|
file_content = git_fle_content(@repo_path, path)["content"]
file_content = tran_base64_decode64(file_content) unless file_content.blank?
@contents = @contents.sub(/EDUCODERJS/, "<script>#{file_content}</script>")
end
end
respond_to do |format|
format.json
format.html{render :layout => false}
end
end
# 最新可以用的并发测试接口
def sigle_mul_test
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)
begin
identifiers = Myshixun.where(:shixun_id => params[:shixun_id].split(",")).pluck(:identifier)
ide = identifiers[rand(identifiers.length)]
myshixun = Myshixun.where(:identifier => ide).first
game = myshixun.games.last
logger.warn("###2mul test game_build start ")
identifier = game.try(:identifier)
if game.status == 2
code = codes.sample(8).join
resubmit = "#{code}_#{myshixun.id}"
end
logger.warn("###3mul test game_build start ...")
EvaluateRecord.create!(:user_id => myshixun.user_id, :shixun_id => myshixun.shixun.id, :game_id => game.id)
redirect_to "/api/games/#{identifier}/game_build?resubmit=#{resubmit}&content_modified=0&first=1"
rescue Exception => e
logger.error("mul test failed ===> #{e.message}")
end
end
# -----End
private
def find_myshixun
@myshixun = Myshixun.find_by!(identifier: params[:identifier])
end
def find_repo_name
@repo_path = @myshixun.try(:repo_path)
@path = params[:path]
end
def python_file?(path)
false if path.blank?
path.to_s.split(".").last.downcase == "py"
end
end

@ -529,8 +529,8 @@ class StudentWorksController < ApplicationController
@echart_data = student_efficiency(@homework, @work)
@myself_eff = @echart_data[:efficiency_list].find { |item| item.last == @user.id }
@myself_consume = @echart_data[:consume_list].find { |item| item.last == @user.id }
filename_ = "#{@use&.student_id}_#{@use&.real_name}_#{@shixun&.name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}"
filename = Base64.urlsafe_encode64(filename_.strip)
filename_ = "#{@use&.student_id}_#{@use&.real_name}_#{@shixun&.name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}.pdf"
filename = filename_.strip.tr("+/", "-_")
stylesheets = %w(shixun_work/shixun_work.css shared/codemirror.css)
if params[:export].present? && params[:export]
normal_status(0,"正在下载中")

@ -22,21 +22,21 @@ module ExportHelper
end
end
shixun_homeworks = shixun_homeworks&.includes(score_student_works: :user)
shixun_homeworks = shixun_homeworks&.includes(:score_student_works)
common_homeworks = homeworks.search_homework_type(1) #全部普通作业
common_titles = common_homeworks.pluck(:name)+ ["总得分"]
common_homeworks = common_homeworks&.includes(score_student_works: :user)
common_homeworks = common_homeworks&.includes(:score_student_works)
group_homeworks = homeworks.search_homework_type(3) #全部分组作业
group_titles = group_homeworks.pluck(:name)+ ["总得分"]
group_homeworks = group_homeworks&.includes(score_student_works: :user)
group_homeworks = group_homeworks&.includes(:score_student_works)
task_titles = tasks.pluck(:name) + ["总得分"]
tasks = tasks&.includes(user: :user_extension, score_graduation_works: :user)
tasks = tasks&.includes(:score_graduation_works)
exercise_titles = exercises.pluck(:exercise_name) + ["总得分"]
exercises = exercises&.includes(user: :user_extension, score_exercise_users: :user)
exercises = exercises&.includes(:score_exercise_users)
total_user_score_array = [] #学生总成绩集合
@ -163,9 +163,12 @@ module ExportHelper
count_2 = common_homeworks.size
count_3 = group_homeworks.size
count_4 = tasks.size
all_user_ids = all_members.pluck(:user_id)
#实训作业
shixun_homeworks.each_with_index do |s,index|
all_student_works = s.score_student_works #该实训题的全部用户回答
all_student_works = s.score_student_works.where(user_id: all_user_ids) #该实训题的全部用户回答
title_no = index.to_i + 1
student_work_to_xlsx(all_student_works,s)
shixun_work_display_name = format_sheet_name (title_no.to_s + "." + s.name).strip.first(30)
@ -175,7 +178,7 @@ module ExportHelper
#普通作业
common_homeworks.each_with_index do |c,index|
all_student_works = c.score_student_works #当前用户的对该作业的回答
all_student_works = c.score_student_works.where(user_id: all_user_ids) #当前用户的对该作业的回答
title_no = count_1 + index.to_i + 1
student_work_to_xlsx(all_student_works,c)
@ -187,7 +190,7 @@ module ExportHelper
#分组作业
group_homeworks.each_with_index do |c,index|
all_student_works = c.score_student_works #当前用户的对该作业的回答
all_student_works = c.score_student_works.where(user_id: all_user_ids) #当前用户的对该作业的回答
title_no = count_1 + count_2 + index.to_i + 1
student_work_to_xlsx(all_student_works,c)
work_name = format_sheet_name (title_no.to_s + "." + c.name).strip.first(30)
@ -197,7 +200,7 @@ module ExportHelper
#毕设任务
tasks.each_with_index do |c,index|
all_student_works = c.score_graduation_works #当前用户的对该作业的回答
all_student_works = c.score_graduation_works.where(user_id: all_user_ids) #当前用户的对该作业的回答
title_no = count_1 + count_2 + count_3 + index.to_i + 1
graduation_work_to_xlsx(all_student_works,c,current_user)
work_name = format_sheet_name (title_no.to_s + "." + c.name).strip.first(30)
@ -207,7 +210,7 @@ module ExportHelper
#试卷的导出
exercises.each_with_index do |c,index|
all_student_works = c.score_exercise_users #当前用户的对该作业的回答
all_student_works = c.score_exercise_users.where(user_id: all_user_ids) #当前用户的对该作业的回答
title_no = count_1 + count_2 + count_3 + count_4 + index.to_i + 1
get_export_users(c,course,all_student_works)
work_name = format_sheet_name (title_no.to_s + "." + c.exercise_name).strip.first(30)

@ -756,7 +756,7 @@ class Fileslists extends Component{
Savesname={this.state.Savesname}
Cancel={this.state.Cancel}
Saves={this.state.Saves}
course_groups={this.state.course_groups}
// course_groups={this.state.course_groups}
/>:""}
{/*发送*/}

@ -428,6 +428,9 @@ class NewShixunModel extends Component{
.ant-drawer-body {
padding:15px 24px 24px 0px;
}
.ant-dropdown {
z-index:11000
}
`
}
</style>

@ -492,13 +492,13 @@ class YslDetailCards extends Component{
:<i className="iconfont icon-bofang progressRing-part font-18 mt10"></i>
}
</span>
<span className={this.props.current_user&&this.props.current_user.admin===false&&line.shixun_status==="暂未公开"?"paragraph_name color204":"paragraph_name color-grey3"}>
<span className={this.props.current_user&&this.props.current_user.admin===false&&this.props.current_user&&this.props.current_user.business===false&&line.shixun_status==="暂未公开"?"paragraph_name color204":"paragraph_name color-grey3"}>
<span className="subject_stage_shixun_index">{key+1}</span>-{index+1}&nbsp;&nbsp;{line.shixun_name}
</span>
</li>
{
this.props.current_user&&this.props.current_user.admin===false&&line.shixun_status==="暂未公开"?
this.props.current_user&&this.props.current_user.admin===false&&this.props.current_user&&this.props.current_user.business===false&&line.shixun_status==="暂未公开"?
<li className="fr status_li"><span className="fr color204">暂未公开</span></li>
:
<li className={showparagraph===false?"none":"fr status_li"}>
@ -512,7 +512,7 @@ class YslDetailCards extends Component{
</li>
}
{this.props.current_user&&this.props.current_user.admin===false&&line.shixun_status==="暂未公开"?"": <li className={showparagraph===false?"fr status_li":"fr status_li"}>
{this.props.current_user&&this.props.current_user.admin===false&&this.props.current_user&&this.props.current_user.business===false&&line.shixun_status==="暂未公开"?"": <li className={showparagraph===false?"fr status_li":"fr status_li"}>
{
showparagraphkey === key && showparagraphindex === index ? "" :
<span className="fr color204">实验任务 <span

@ -159,7 +159,7 @@ class ShixunsHome extends Component {
}
</style>
<div className="clearfix edu-back-white pb40 pt30 mb20 banners" id="index-top" onMouseMove={this.bannaronmousemove} onMouseOut={this.bannaronmouseout}>
<div className="educontent pr educontentSlider">
<div className="educontent pr educontentSlider" style={{"width":'1200px'}}>
{homedatalist===undefined?"":
<Slider
nextArrow={<CustomNextArrow />}
@ -240,7 +240,7 @@ class ShixunsHome extends Component {
<p className="color-dark edu-txt-center font-24" style={{lineHeight: '30px'}}>实践课程</p>
<p className="color-grey-cd font-12">TRAINING COURSE</p>
</div>
<Link to={"/paths"} className="moreitem">更多<i className="fa fa-angle-right ml5"></i></Link>
<Link to={"/paths"} className="moreitem mr18">更多<i className="fa fa-angle-right ml5"></i></Link>
<div className="square-list clearfix" style={{'width':'100%','padding-left':'25px'}}>
@ -319,7 +319,7 @@ class ShixunsHome extends Component {
<p className="color-dark edu-txt-center font-24" style={{lineHeight: '30px'}}>实训项目</p>
<p className="color-grey-cd font-12">DEVELOPMENT COMMUNITY</p>
</div>
<Link to={"/shixuns"} className="moreitem">更多<i className="fa fa-angle-right ml5"></i></Link>
<Link to={"/shixuns"} className="moreitem mr18">更多<i className="fa fa-angle-right ml5"></i></Link>
<div className="square-list clearfix" style={{'width':'100%','padding-left':'25px'}}>
<style>

@ -38,9 +38,9 @@ class VNCContainer extends Component {
}
shouldComponentUpdate () {
return false;
}
// shouldComponentUpdate () {
// return false;
// }
getSecondDrawerWidth = () => {
return $('#game_right_contents').width() - firstDrawerWidth
@ -337,11 +337,11 @@ class VNCContainer extends Component {
width={firstDrawerWidth}
closable={false}
onClose={this.onBottomDrawerClose}
visible={this.state.bottomDrawer}
visible={this.state.bottomDrawer===undefined?false:this.state.bottomDrawer}
className={'codeEvaluateDrawer'}
placement="bottom"
getContainer={false}
style={{ position: 'absolute', bottom: '25px', zIndex: 1 }}
style={{ position: 'absolute', bottom: '-25px', zIndex: 1 }}
afterVisibleChange={(visible) => {
if (visible) {
const canvas = $('.vncDisply canvas')[0]

Loading…
Cancel
Save