diff --git a/Gemfile b/Gemfile index 55030971d..55478816f 100644 --- a/Gemfile +++ b/Gemfile @@ -103,3 +103,6 @@ gem 'diffy' # oauth2 gem 'omniauth', '~> 1.9.0' gem 'omniauth-oauth2', '~> 1.6.0' + +# global var +gem 'request_store' diff --git a/app/controllers/admins/shixuns_controller.rb b/app/controllers/admins/shixuns_controller.rb index e2d2830ad..6593f27c2 100644 --- a/app/controllers/admins/shixuns_controller.rb +++ b/app/controllers/admins/shixuns_controller.rb @@ -8,6 +8,9 @@ class Admins::ShixunsController < Admins::BaseController @pending_shixuns = shixuns.where(status:1).size @processed_shixuns = shixuns.where(status:2).size @closed_shixuns = shixuns.where(status:3).size + @none_public_shixuns = shixuns.where(public:0).size + @pending_public_shixuns = shixuns.where(public:1).size + @processed_pubic_shixuns = shixuns.where(public:2).size @shixuns_type_check = MirrorRepository.pluck(:type_name,:id) @params_page = params[:page] || 1 @shixuns = paginate shixuns.preload(:user,:challenges) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 3ec8ad0f7..b3a0e123a 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -303,7 +303,7 @@ class ApplicationController < ActionController::Base current_domain_session = session[:"#{default_yun_session}"] if current_domain_session # existing session - (User.active.find(current_domain_session) rescue nil) + User.current = (User.active.find(current_domain_session) rescue nil) elsif autologin_user = try_to_autologin autologin_user elsif params[:format] == 'atom' && params[:key] && request.get? && accept_rss_auth? diff --git a/app/controllers/challenges_controller.rb b/app/controllers/challenges_controller.rb index 0b5140743..4528b7b90 100644 --- a/app/controllers/challenges_controller.rb +++ b/app/controllers/challenges_controller.rb @@ -173,64 +173,70 @@ class ChallengesController < ApplicationController # tab 0:过关任务的更新; 1:评测设置的更新; 2:表示参考答案的更新; def update - ActiveRecord::Base.transaction do - tab = params[:tab].to_i - @challenge.update_attributes(challenge_params) - if tab == 0 && @challenge.st == 0 - @challenge.challenge_tags.delete_all - if params[:challenge_tag].present? - params[:challenge_tag].each do |input| - ChallengeTag.create!(:name => input, :challenge_id => @challenge.id) + begin + ActiveRecord::Base.transaction do + tab = params[:tab].to_i + @challenge.update_attributes(challenge_params) + if tab == 0 && @challenge.st == 0 + @challenge.challenge_tags.delete_all + if params[:challenge_tag].present? + params[:challenge_tag].each do |input| + ChallengeTag.create!(:name => input, :challenge_id => @challenge.id) + end end - end - elsif tab == 1 - path = @challenge.path - exec_path = @challenge.exec_path - test_set = @challenge.test_sets - sets_output = test_set.map(&:output) - sets_input = test_set.map(&:input) - sets_open = test_set.map(&:is_public) - set_score = test_set.map(&:score) - set_match_rule = test_set.map(&:match_rule) - params_hidden = params[:test_set].map{|set| set[:hidden].to_i == 0} - params_output = params[:test_set].map{|set| set[:output] } - params_input = params[:test_set].map{|set| set[:input] } - params_score = params[:test_set].map{|set| set[:score]} - params_test_set = params[:test_set].map{|set| set[:match_rule]} - # 测试集变化则需要更新(输入、 输出、 是否隐藏) - if sets_output != params_output || sets_open != params_hidden || sets_input != params_input || - set_score != params_score || params_test_set != set_match_rule - test_set.delete_all unless test_set.blank? - params[:test_set].each_with_index do |set, index| - # last: 末尾匹配, full: 全完匹配 - logger.info("set: #{set}; match_rule : #{set[:match_rule]}") - match_rule = set[:match_rule] == 'last' ? 'last' : 'full' - TestSet.create(:challenge_id => @challenge.id, - :input => "#{set[:input]}", - :output => "#{set[:output]}", - :is_public => params_hidden[index], - :score => set[:score], - :match_rule => "#{match_rule}", - :position => (index + 1)) + elsif tab == 1 + path = @challenge.path + exec_path = @challenge.exec_path + test_set = @challenge.test_sets + sets_output = test_set.map(&:output) + sets_input = test_set.map(&:input) + sets_open = test_set.map(&:is_public) + set_score = test_set.map(&:score) + set_match_rule = test_set.map(&:match_rule) + params_hidden = params[:test_set].map{|set| set[:hidden].to_i == 0} + params_output = params[:test_set].map{|set| set[:output] } + params_input = params[:test_set].map{|set| set[:input] } + params_score = params[:test_set].map{|set| set[:score]} + params_test_set = params[:test_set].map{|set| set[:match_rule]} + # 测试集变化则需要更新(输入、 输出、 是否隐藏) + if sets_output != params_output || sets_open != params_hidden || sets_input != params_input || + set_score != params_score || params_test_set != set_match_rule + test_set.delete_all unless test_set.blank? + params[:test_set].each_with_index do |set, index| + # last: 末尾匹配, full: 全完匹配 + logger.info("set: #{set}; match_rule : #{set[:match_rule]}") + match_rule = set[:match_rule] == 'last' ? 'last' : 'full' + TestSet.create(:challenge_id => @challenge.id, + :input => "#{set[:input]}", + :output => "#{set[:output]}", + :is_public => params_hidden[index], + :score => set[:score], + :match_rule => "#{match_rule}", + :position => (index + 1)) + end + @challenge.update_column(:modify_time, Time.now) + # 测试集的 + @shixun.myshixuns.update_all(:system_tip => 0) end - @challenge.update_column(:modify_time, Time.now) - # 测试集的 - @shixun.myshixuns.update_all(:system_tip => 0) - end - if params[:challenge][:show_type].to_i == -1 - @challenge.update_attributes(picture_path: nil, web_route: nil, expect_picture_path: nil, original_picture_path: nil) + if params[:challenge][:show_type].to_i == -1 + @challenge.update_attributes(picture_path: nil, web_route: nil, expect_picture_path: nil, original_picture_path: nil) + end + # 关卡评测执行文件如果被修改,需要修改脚本内容 + script = modify_shixun_script @shixun, @shixun.evaluate_script + @shixun.shixun_info.update_column(:evaluate_script, script) + # TODO: + # if path != params[:challenge][:path] + # shixun_modify_status_without_publish(@shixun, 1) + # end + #Attachment.attach_files(@challenge, params[:attachments]) end - # 关卡评测执行文件如果被修改,需要修改脚本内容 - script = modify_shixun_script @shixun, @shixun.evaluate_script - @shixun.shixun_info.update_column(:evaluate_script, script) - # TODO: - # if path != params[:challenge][:path] - # shixun_modify_status_without_publish(@shixun, 1) - # end - #Attachment.attach_files(@challenge, params[:attachments]) - end + end + rescue => e + logger_error("##update_challenges: ##{e.message}") + tip_exception("更新失败!") end + end # 参考答案的'增,删,改' diff --git a/app/controllers/courses_controller.rb b/app/controllers/courses_controller.rb index b08ba2dbd..52911e905 100644 --- a/app/controllers/courses_controller.rb +++ b/app/controllers/courses_controller.rb @@ -29,7 +29,7 @@ class CoursesController < ApplicationController :informs, :update_informs, :online_learning, :update_task_position, :tasks_list, :join_excellent_course, :export_couser_info, :export_member_act_score, :new_informs, :delete_informs, :change_member_role, :course_groups, :join_course_group, :statistics, - :work_score, :act_score] + :work_score, :act_score, :calculate_all_shixun_scores] before_action :user_course_identity, except: [:join_excellent_course, :index, :create, :new, :apply_to_join_course, :search_course_list, :get_historical_course_students, :mine, :search_slim, :board_list] before_action :teacher_allowed, only: [:update, :destroy, :settings, :search_teacher_candidate, @@ -48,7 +48,7 @@ class CoursesController < ApplicationController before_action :validate_page_size, only: :mine before_action :course_tasks, only: [:tasks_list, :update_task_position] before_action :validate_inform_params, only: [:update_informs, :new_informs] - before_action :course_member_allowed, only: [:statistics, :work_score, :act_score] + before_action :course_member_allowed, only: [:statistics, :work_score, :act_score, :calculate_all_shixun_scores] if RUBY_PLATFORM =~ /linux/ require 'simple_xlsx_reader' @@ -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, @@ -1334,6 +1334,16 @@ class CoursesController < ApplicationController end end + # 计算课堂所有已发布的实训作业成绩 + def calculate_all_shixun_scores + tip_exception(-1, "课堂已结束") if @course.is_end + shixun_homeworks = @course.homework_commons.homework_published.where(homework_type: 4) + shixun_homeworks.includes(:homework_challenge_settings, :published_settings, :homework_commons_shixun).each do |homework| + homework.update_homework_work_score + end + normal_status(0, "更新成功") + end + def search_slim courses = current_user.manage_courses.not_deleted.processing diff --git a/app/controllers/hacks_controller.rb b/app/controllers/hacks_controller.rb index 657ad0f2a..cab952a04 100644 --- a/app/controllers/hacks_controller.rb +++ b/app/controllers/hacks_controller.rb @@ -1,8 +1,8 @@ class HacksController < ApplicationController before_action :require_login, except: [:index] - before_action :find_hack, only: [:edit, :update, :publish, :start, :update_set, :delete_set, :destroy] + before_action :find_hack, only: [:edit, :update, :publish, :start, :update_set, :delete_set, :destroy, :cancel_publish] before_action :require_teacher_identity, only: [:create] - before_action :require_auth_identity, only: [:update, :edit, :publish, :update_set, :delete_set, :destroy] + before_action :require_auth_identity, only: [:update, :edit, :publish, :update_set, :delete_set, :destroy, :cancel_publish] # 开启编程,如果第一次开启,创建一条记录,如果已经开启过的话,直接返回标识即可 @@ -99,6 +99,12 @@ class HacksController < ApplicationController render_ok end + # 取消发布 + def cancel_publish + @hack.update_attribute(:status, 0) + render_ok + end + # 发布列表 def unpulished_list limit = params[:limit] || 16 diff --git a/app/controllers/myshixuns_controller.rb b/app/controllers/myshixuns_controller.rb index b5c8af1f3..1325d1423 100644 --- a/app/controllers/myshixuns_controller.rb +++ b/app/controllers/myshixuns_controller.rb @@ -1,385 +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的position,passed: 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是查看答案的扣分比例 - # status:0表示评测成功 - 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参数表示在有文件生成的实训是在本地生成,还是在其他云端生成评测文件 - params = {tpiID:@myshixun.id, podType:@myshixun.shixun.try(:webssh), local: @myshixun.shixun.show_type != -1, - 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/, "") - 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/, "") - 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的position,passed: 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是查看答案的扣分比例 + # status:0表示评测成功 + 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/, "") + 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/, "") + 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 diff --git a/app/controllers/shixuns_controller.rb b/app/controllers/shixuns_controller.rb index 03fdbf97f..caa716f16 100644 --- a/app/controllers/shixuns_controller.rb +++ b/app/controllers/shixuns_controller.rb @@ -17,16 +17,16 @@ class ShixunsController < ApplicationController :get_mirror_script, :download_file, :shixun_list, :batch_send_to_course] before_action :find_repo_name, only: [:repository, :commits, :file_content, :update_file, :shixun_exec, :copy, :add_file] - before_action :allowed, only: [:update, :close, :update_propaedeutics, :settings, :publish, + before_action :allowed, only: [:update, :close, :update_propaedeutics, :settings, :publish, :apply_public, :shixun_members_added, :change_manager, :collaborators_delete, - :cancel_publish, :add_collaborators, :add_file] + :cancel_apply_public, :cancel_publish, :add_collaborators, :add_file] before_action :portion_allowed, only: [:copy] before_action :special_allowed, only: [:send_to_course, :search_user_courses] ## 获取课程列表 def index - @shixuns = current_laboratory.shixuns.unhidden + @shixuns = current_laboratory.shixuns.unhidden.publiced ## 方向 if params[:tag_level].present? && params[:tag_id].present? @@ -818,44 +818,48 @@ class ShixunsController < ApplicationController @status = 0 @position = [] begin - if @shixun.challenges.count == 0 - @status = 4 - else - @shixun.challenges.each do |challenge| - if challenge.challenge_tags.count == 0 - @status = 3 - @position << challenge.position + unless @shixun.is_jupyter? + if @shixun.challenges.count == 0 + @status = 4 + else + @shixun.challenges.each do |challenge| + if challenge.challenge_tags.count == 0 + @status = 3 + @position << challenge.position + end end - end - unfinish_challenge = @shixun.challenges.where(:st => 0, :path => nil) - if unfinish_challenge.count > 0 && !@shixun.is_choice_type? - @status = 2 - @pos = [] - unfinish_challenge.each do |challenge| - @pos << challenge.position + unfinish_challenge = @shixun.challenges.where(:st => 0, :path => nil) + if unfinish_challenge.count > 0 && !@shixun.is_choice_type? + @status = 2 + @pos = [] + unfinish_challenge.each do |challenge| + @pos << challenge.position + end end end end if @status == 0 - @shixun.update_attributes!(:status => 1) - apply = ApplyAction.where(:container_type => "ApplyShixun", :container_id => @shixun.id).order("created_at desc").first - if apply && apply.status == 0 - @status = 0 - else - ApplyAction.create(:container_type => "ApplyShixun", :container_id => @shixun.id, :user_id => current_user.id, :status => 0) - #begin - # status = Trustie::Sms.send(mobile: '18711011226', send_type:'publish_shixun' , name: '管理员') - #rescue => e - # Rails.logger.error "发送验证码出错: #{e}" - #end - @status = 1 - end + @shixun.update_attributes!(:status => 2) end rescue Exception => e logger.error("pushlish game #{e}") end end + def apply_public + tip_exception(-1, "请先发布实训再申请公开") if @shixun.status != 2 + ActiveRecord::Base.transaction do + @shixun.update_attributes!(public: 1) + apply = ApplyAction.where(:container_type => "ApplyShixun", :container_id => @shixun.id).order("created_at desc").first + if apply && apply.status == 0 + @status = 0 + else + ApplyAction.create(:container_type => "ApplyShixun", :container_id => @shixun.id, :user_id => current_user.id, :status => 0) + end + end + normal_status(0, "申请成功") + end + # 设置私密版本库的在tpm中的目录 def set_secret_dir raise("设置路径不能为空") if params[:secret_dir_path].blank? @@ -993,14 +997,24 @@ class ShixunsController < ApplicationController :disposition => 'attachment' #inline can open in browser end + # 撤销申请公开 + def cancel_apply_public + tip_exception("实训已经公开,无法撤销") if @shixun.public == 2 + ActiveRecord::Base.transaction do + apply = ApplyAction.where(:container_type => "ApplyShixun", :container_id => @shixun.id).order("created_at desc").first + if apply && apply.status == 0 + apply.update_attributes!(status: 3) + apply.tidings&.destroy_all + end + @shixun.update_column(:public, 0) + end + normal_status(0, "成功撤销申请") + end + # 撤销发布 def cancel_publish - tip_exception("实训已经发布,无法撤销") if @shixun.status == 2 - apply = ApplyAction.where(:container_type => "ApplyShixun", :container_id => @shixun.id).order("created_at desc").first - if apply && apply.status == 0 - apply.update_attribute(:status, 3) - apply.tidings.destroy_all - end + tip_exception("请先撤销申请公开,再撤销发布") if @shixun.public == 1 + tip_exception("实训已经公开,无法撤销") if @shixun.public == 2 @shixun.update_column(:status, 0) end diff --git a/app/controllers/student_works_controller.rb b/app/controllers/student_works_controller.rb index 637155a1a..dfdce7bd2 100644 --- a/app/controllers/student_works_controller.rb +++ b/app/controllers/student_works_controller.rb @@ -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,"正在下载中") diff --git a/app/helpers/export_helper.rb b/app/helpers/export_helper.rb index 31e1ecf45..ef6f3255c 100644 --- a/app/helpers/export_helper.rb +++ b/app/helpers/export_helper.rb @@ -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) diff --git a/app/helpers/shixuns_helper.rb b/app/helpers/shixuns_helper.rb index b41750bed..655a7ed04 100644 --- a/app/helpers/shixuns_helper.rb +++ b/app/helpers/shixuns_helper.rb @@ -27,6 +27,17 @@ module ShixunsHelper end end + def shixun_public_status shixun + case shixun.try(:public) + when 0,nil + "未公开" + when 1 + "待审核" + when 2 + "已公开" + end + end + # 已完成实训所获得的经验值 def myshixun_exp myshixun score = 0 diff --git a/app/jobs/sync_trustie_job.rb b/app/jobs/sync_trustie_job.rb index 33df5b529..dec09debc 100644 --- a/app/jobs/sync_trustie_job.rb +++ b/app/jobs/sync_trustie_job.rb @@ -17,10 +17,17 @@ class SyncTrustieJob < ApplicationJob "number": count } uri = URI.parse(url) + # http = Net::HTTP.new(uri.hostname, uri.port) + if api_host http = Net::HTTP.new(uri.hostname, uri.port) - http.send_request('PUT', uri.path, sync_json.to_json, {'Content-Type' => 'application/json'}) - Rails.logger.info("#######_________response__sync__end_____#########") + + if api_host.include?("https://") + http.use_ssl = true + end + + response = http.send_request('PUT', uri.path, sync_json.to_json, {'Content-Type' => 'application/json'}) + Rails.logger.info("#######_________response__sync__end_____#########{response.body}") end end end diff --git a/app/models/game.rb b/app/models/game.rb index d82392a59..ca7339352 100644 --- a/app/models/game.rb +++ b/app/models/game.rb @@ -119,6 +119,12 @@ class Game < ApplicationRecord # self.outputs.pluck(:query_index).first #end + # 是否查看了答案(通关的是否在通关前看的答案) + def view_answer + answer_exists = Grade.exists?("container_type = 'Answer' and container_id = #{id} and created_at < '#{end_time}'") + answer_open != 0 ? (status == 2 ? answer_exists : true) : false + end + # 用户关卡得分 def get_user_final_score diff --git a/app/models/laboratory.rb b/app/models/laboratory.rb index 2ba86ed90..dab2f6f39 100644 --- a/app/models/laboratory.rb +++ b/app/models/laboratory.rb @@ -38,12 +38,20 @@ class Laboratory < ApplicationRecord find_by_identifier(subdomain) end - def self.current=(laboratory) - Thread.current[:current_laboratory] = laboratory + # def self.current=(laboratory) + # Thread.current[:current_laboratory] = laboratory + # end + # + # def self.current + # Thread.current[:current_laboratory] ||= Laboratory.find(1) + # end + + def self.current=(user) + RequestStore.store[:current_laboratory] = user end def self.current - Thread.current[:current_laboratory] ||= Laboratory.find(1) + RequestStore.store[:current_laboratory] ||= User.anonymous end def shixuns diff --git a/app/models/myshixun.rb b/app/models/myshixun.rb index 54dcf9011..9b824c0d8 100644 --- a/app/models/myshixun.rb +++ b/app/models/myshixun.rb @@ -83,9 +83,10 @@ class Myshixun < ApplicationRecord self.games.select{|game| game.status == 2}.size end - # 查看答案的关卡数 + # 查看答案的关卡数,只统计通关前看的关卡 def view_answer_count - self.games.select{|game| game.status == 2 && game.answer_open != 0}.size + answer_ids = user.grades.joins("join games on grades.container_id = games.id").where("container_type = 'Answer' and games.status=2 and games.end_time > grades.created_at").pluck(:container_id) + self.games.select{|game| game.status == 2 && game.answer_open != 0 && answer_ids.include?(game.id)}.size end # 通关时间 diff --git a/app/models/shixun.rb b/app/models/shixun.rb index 0f9842739..dc5348450 100644 --- a/app/models/shixun.rb +++ b/app/models/shixun.rb @@ -3,6 +3,7 @@ class Shixun < ApplicationRecord attr_accessor :page_no #管理员页面 实训配置更新状态时,需要接受page_no参数 # status: 0:编辑 1:申请发布 2:正式发布 3:关闭 -1:软删除 + # public: 0:未公开 1:申请公开 2:公开 # hide_code: 隐藏代码窗口 # code_hidden: 隐藏代码目录 # task_pass: 跳关 @@ -76,6 +77,7 @@ class Shixun < ApplicationRecord scope :published_closed, lambda{ where(status: [2, 3]) } scope :none_closed, lambda{ where(status: [0, 1, 2]) } scope :unhidden, lambda{ where(hidden: 0, status: 2) } + scope :publiced, lambda{ where(public: 2) } scope :field_for_recommend, lambda{ select([:id, :name, :identifier, :myshixuns_count]) } scope :find_by_ids,lambda{|k| where(id:k)} diff --git a/app/models/user.rb b/app/models/user.rb index eb3ece0a4..a9b2f0b3a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -540,12 +540,20 @@ class User < ApplicationRecord mail.present? end + # def self.current=(user) + # Thread.current[:current_user] = user + # end + # + # def self.current + # Thread.current[:current_user] ||= User.anonymous + # end + def self.current=(user) - Thread.current[:current_user] = user + RequestStore.store[:current_user] = user end def self.current - Thread.current[:current_user] ||= User.anonymous + RequestStore.store[:current_user] ||= User.anonymous end def self.anonymous diff --git a/app/queries/admins/shixun_query.rb b/app/queries/admins/shixun_query.rb index 0d726f267..0f8523599 100644 --- a/app/queries/admins/shixun_query.rb +++ b/app/queries/admins/shixun_query.rb @@ -21,7 +21,17 @@ class Admins::ShixunQuery < ApplicationQuery [0,1,2,3] end + public = + case params[:public] + when "editing" then [0] + when "pending" then [1] + when "processed" then [2] + else + [0,1,2] + end + all_shixuns = all_shixuns.where(status: status) if status.present? + all_shixuns = all_shixuns.where(public: public) if public.present? if params[:tag].present? all_shixuns = all_shixuns.joins(:mirror_repositories).where("mirror_repositories.id = ?",params[:tag].to_i) diff --git a/app/services/admins/shixun_auths/agree_apply_service.rb b/app/services/admins/shixun_auths/agree_apply_service.rb index 4734e03bb..b8875cf09 100644 --- a/app/services/admins/shixun_auths/agree_apply_service.rb +++ b/app/services/admins/shixun_auths/agree_apply_service.rb @@ -10,7 +10,7 @@ class Admins::ShixunAuths::AgreeApplyService < ApplicationService def call ActiveRecord::Base.transaction do apply.update!(status: 1, dealer_id: user.id) - shixun.update!(status: 2, publish_time: Time.now) + shixun.update!(public: 2, publish_time: Time.now) # 奖励金币、经验 reward_grade_and_experience! diff --git a/app/services/admins/shixun_auths/refuse_apply_service.rb b/app/services/admins/shixun_auths/refuse_apply_service.rb index 49416a2b0..76d420e53 100644 --- a/app/services/admins/shixun_auths/refuse_apply_service.rb +++ b/app/services/admins/shixun_auths/refuse_apply_service.rb @@ -10,7 +10,7 @@ class Admins::ShixunAuths::RefuseApplyService < ApplicationService def call ActiveRecord::Base.transaction do - shixun.update!(status: 0) + shixun.update!(public: 0) apply.update!(status: 2, reason: reason, dealer_id: user.id) deal_tiding! diff --git a/app/services/search_service.rb b/app/services/search_service.rb index 5eb11f398..a45875e07 100644 --- a/app/services/search_service.rb +++ b/app/services/search_service.rb @@ -30,7 +30,6 @@ class SearchService < ApplicationService model_options = { includes: modal_name.searchable_includes } - model_options.deep_merge!(where: { status: 2 }) if modal_name == Shixun model_options.deep_merge!(extra_options) model_options.deep_merge!(default_options) @@ -40,7 +39,7 @@ class SearchService < ApplicationService def extra_options case params[:type].to_s.strip when 'shixun' then - { where: { id: Laboratory.current.shixuns.pluck(:id) } } + { where: { id: Laboratory.current.shixuns.where(public: 2, status: 2, fork_from: nil).or(Laboratory.current.shixuns.where(status: 2, id: User.current.shixuns)).pluck(:id) } } when 'subject' then { where: { id: Laboratory.current.subjects.pluck(:id) } } when 'course' then diff --git a/app/services/shixun_search_service.rb b/app/services/shixun_search_service.rb index 580208dfe..fce8a2fd5 100644 --- a/app/services/shixun_search_service.rb +++ b/app/services/shixun_search_service.rb @@ -25,7 +25,7 @@ class ShixunSearchService < ApplicationService else none_shixun_ids = ShixunSchool.where("school_id != #{User.current.school_id}").pluck(:shixun_id) - @shixuns = @shixuns.where.not(id: none_shixun_ids).where(hidden: 0) + @shixuns = @shixuns.where.not(id: none_shixun_ids).where(hidden: 0, status: 2, public: 2).or(@shixuns.where(id: User.current.shixuns)) end end diff --git a/app/views/admins/shixuns/index.html.erb b/app/views/admins/shixuns/index.html.erb index d9f8086d8..d04257927 100644 --- a/app/views/admins/shixuns/index.html.erb +++ b/app/views/admins/shixuns/index.html.erb @@ -4,25 +4,31 @@
筛选:
+this.belongto("all")}>全部实训
+this.belongto("mine")}>普通实训
+难度:
+this.DropdownClick(0)}>全部
+this.DropdownClick(1)}>初级
+this.DropdownClick(2)}>中级
+this.DropdownClick(3)}>高级
+this.DropdownClick(4)}>顶级
+实践课程
TRAINING COURSE
实训项目
DEVELOPMENT COMMUNITY