class ShixunsController < ApplicationController
include ShixunsHelper
include ApplicationHelper
before_action :require_login , :check_auth , except : [ :download_file , :index , :menus , :show , :show_right , :ranking_list ,
:discusses , :collaborators , :fork_list , :propaedeutics ]
before_action :check_account , only : [ :new , :create , :shixun_exec ]
before_action :find_shixun , :shixun_access_allowed , except : [ :index , :new , :create , :menus , :get_recommend_shixuns ,
:propaedeutics , :departments , :apply_shixun_mirror ,
:get_mirror_script , :download_file ]
before_action :find_repo_name , only : [ :repository , :commits , :file_content , :update_file , :shixun_exec , :copy ]
before_action :allowed , only : [ :update , :close , :update_propaedeutics , :settings , :publish ,
:shixun_members_added , :change_manager , :collaborators_delete ,
:cancel_publish , :add_collaborators ]
before_action :portion_allowed , only : [ :copy ]
before_action :special_allowed , only : [ :send_to_course , :search_user_courses ]
## 获取课程列表
def index
## 我的实训
@shixuns =
if params [ :order_by ] == 'mine'
tip_exception ( 401 , " .. " ) unless current_user . logged?
current_user . my_shixuns
else
Shixun . unhidden
end
## 方向
if params [ :tag_level ] . present? && params [ :tag_id ] . present?
@shixuns = @shixuns . filter_tag ( params [ :tag_level ] . to_i , params [ :tag_id ] . to_i )
case params [ :tag_level ] . to_i
when 1 #大类
@search_tags = Repertoire . find ( params [ :tag_id ] . to_i ) . name
when 2 #子类
@search_tags = SubRepertoire . find ( params [ :tag_id ] . to_i ) . name
when 3 #tag
tag = TagRepertoire . find ( params [ :tag_id ] . to_i )
@search_tags = " #{ tag . sub_repertoire . name } / #{ tag . name } "
end
end
## 搜索关键字 匹配关卡名, 用户名, 实训名 和 空格多搜索
if params [ :keyword ] . present?
keyword = params [ :keyword ] . strip
@shixuns = @shixuns . joins ( :user , challenges : :challenge_tags ) .
where ( " challenge_tags.name like :keyword
or challenges . subject like :keyword
or concat ( lastname , firstname ) like :keyword
or shixuns . name like :name " ,
keyword : " % #{ keyword } % " , name : " % #{ keyword . split ( " " ) . join ( " % " ) } % " ) . distinct
end
## 筛选 状态
if params [ :status ] . present? && params [ :status ] . to_i != 0
params [ :status ] = [ 0 , 1 ] if params [ :status ] . to_i == 1
@shixuns = @shixuns . where ( status : params [ :status ] )
end
## 筛选 难度
if params [ :diff ] . present? && params [ :diff ] . to_i != 0
@shixuns = @shixuns . where ( trainee : params [ :diff ] )
end
## 排序参数
bsort = params [ :sort ] || 'desc'
case params [ :order_by ] || 'publish_time'
when 'new'
@shixuns = @shixuns . order ( " shixuns.status = 2 desc, shixuns.created_at #{ bsort } " )
when 'hot'
@shixuns = @shixuns . order ( " shixuns.status = 2 desc, shixuns.myshixuns_count #{ bsort } " )
when 'mine'
@shixuns = @shixuns . order ( " shixuns.created_at #{ bsort } " )
else
@shixuns = @shixuns . order ( " shixuns.status = 2 desc, shixuns.publish_time #{ bsort } " )
end
# 用id计数会快10+MS左右,对于搜索的内容随着数据的增加,性能会提升一些。
@total_count = @shixuns . count ( " shixuns.id " )
## 分页参数
page = params [ :page ] || 1
limit = params [ :limit ] || 16
@shixuns = @shixuns . includes ( :tag_repertoires , :challenges ) . page ( page ) . per ( limit )
@tag_name_map = TagRepertoire . joins ( :shixun_tag_repertoires )
. where ( shixun_tag_repertoires : { shixun_id : @shixuns . map ( & :id ) } )
. group ( 'shixun_tag_repertoires.shixun_id' )
. select ( 'shixun_id, tag_repertoires.name' )
. each_with_object ( { } ) { | r , obj | obj [ r . shixun_id ] = r . name }
end
## 获取顶部菜单
def menus
@repertoires = Repertoire . includes ( sub_repertoires : [ :tag_repertoires ] ) . order ( " updated_at asc " )
# respond_with @repertoires
render_json
end
## 实训详情
def show
# 当前用户开启的实训
can_fork = current_user . is_certification_teacher || current_user . admin?
unless can_fork
@can_fork = { can_fork : " 已经职业认证的教师才能fork实训 " ,
certi_url : edu_setting ( 'old_edu_host' ) + " /account/professional_certification " }
end
@current_myshixun = @shixun . current_myshixun ( current_user )
if @shixun . fork_from
fork_shixun = Shixun . select ( :id , :user_id , :name , :identifier ) . where ( id : @shixun . fork_from ) . first
@fork_from = { name : fork_shixun . name , username : fork_shixun . owner . try ( :full_name ) ,
fork_identifier : fork_shixun . identifier } if fork_shixun
end
@power = current_user . manager_of_shixun? ( @shixun )
# 更新是为了首页的排序, myshixun的动静需要在实训中展现出来
if @current_myshixun && params [ :exit ] && ! current_user . admin?
@current_myshixun . update_column ( :updated_at , Time . now )
end
end
def show_right
owner = @shixun . owner
#@fans_count = owner.fan_count
#@followed_count = owner.follow_count
@user_own_shixuns = owner . shixuns . published . count
end
# 排行榜
def ranking_list
if @shixun . status == 2
sql = "
select m . user_id , u . login , u . lastname , m . updated_at ,
( select sum ( cost_time ) from games g where g . myshixun_id = m . id ) as time ,
( select sum ( final_score ) from games g where g . myshixun_id = m . id ) as score
from ( users u left join myshixuns m on m . user_id = u . id ) where m . shixun_id = #{@shixun.id} and m.status = 1
order by score desc , time asc limit 10
"
@myshixuns = Myshixun . find_by_sql ( sql )
end
end
#评论
def discusses
new_params = params . merge ( container_id : @shixun . id , container_type : 'Shixun' )
discusses = ShixunsService . new . shixun_discuss new_params , current_user
if discusses . present?
@children_list = discusses [ :children_list ]
else
@children_list = [ ]
end
end
def copy
ActiveRecord :: Base . transaction do
begin
@new_shixun = Shixun . new
@new_shixun . attributes = @shixun . attributes . dup . except ( " id " , " user_id " , " visits " , " gpid " , " status " , " identifier " , " averge_star " ,
" homepage_show " , " repo_name " , " myshixuns_count " , " challenges_count " ,
" can_copy " , " created_at " , " updated_at " )
@new_shixun . user_id = User . current . id
@new_shixun . averge_star = 5
@new_shixun . identifier = generate_identifier Shixun , 8
@new_shixun . fork_from = @shixun . id
@new_shixun . save!
# 同步shixun_info的信息
if @shixun . shixun_info . present?
ShixunInfo . create! ( shixun_id : @new_shixun . id ,
description : @shixun . description ,
evaluate_script : @shixun . evaluate_script )
end
# 同步镜像
if @shixun . mirror_repositories . present?
@shixun . mirror_repositories . each do | mirror |
ShixunMirrorRepository . create! ( :shixun_id = > @new_shixun . id , :mirror_repository_id = > mirror . id )
end
end
# 同步技术标签
@shixun . shixun_tag_repertoires . each do | str |
ShixunTagRepertoire . create! ( :tag_repertoire_id = > str . tag_repertoire_id , :shixun_id = > @new_shixun . id )
end
# 同步配置
logger . info ( " # # # # # # # # -shixun_service_configs_count: #{ @shixun . shixun_service_configs . pluck ( :id , :shixun_id ) } " )
@shixun . shixun_service_configs . each do | config |
ShixunServiceConfig . create! ( :shixun_id = > @new_shixun . id ,
:cpu_limit = > config . cpu_limit ,
:lower_cpu_limit = > config . lower_cpu_limit ,
:memory_limit = > config . memory_limit ,
:request_limit = > config . request_limit ,
:mirror_repository_id = > config . mirror_repository_id )
end
# fork版本库
logger . info ( " # # # # # # # # # # # fork_repo_path: # # # # # #{ @repo_path } " )
project_fork ( @new_shixun , @repo_path , current_user . login )
ShixunMember . create! ( :user_id = > User . current . id , :shixun_id = > @new_shixun . try ( :id ) , :role = > 1 )
# 同步复制关卡
if @shixun . challenges . present?
@shixun . challenges . each do | challenge |
new_challenge = Challenge . new
new_challenge . attributes = challenge . attributes . dup . except ( " id " , " shixun_id " , " user_id " , " challenge_tags_count " )
new_challenge . user_id = User . current . id
new_challenge . shixun_id = @new_shixun . id
new_challenge . save!
# 同步参考答案
challenge . challenge_answers . each do | answer |
new_answer = ChallengeAnswer . new
new_answer . attributes = answer . attributes . dup . except ( " id " , " challenge_id " )
new_answer . challenge_id = new_challenge . id
new_answer . save!
end
if challenge . st == 0 # 评测题
# 同步测试集
if challenge . test_sets . present?
challenge . test_sets . each do | test_set |
new_test_set = TestSet . new
new_test_set . attributes = test_set . attributes . dup . except ( " id " , " challenge_id " )
new_test_set . challenge_id = new_challenge . id
new_test_set . save!
end
end
# 同步关卡标签
challenge_tags = ChallengeTag . where ( " challenge_id =? and challenge_choose_id is null " , challenge . id )
if challenge_tags . present?
challenge_tags . each do | challenge_tag |
ChallengeTag . create! ( :challenge_id = > new_challenge . id , :name = > challenge_tag . try ( :name ) )
end
end
elsif challenge . st == 1 # 选择题
if challenge . challenge_chooses . present?
challenge . challenge_chooses . each do | challenge_choose |
new_challenge_choose = ChallengeChoose . new
new_challenge_choose . attributes = challenge_choose . attributes . dup . except ( " id " , " challenge_id " )
new_challenge_choose . challenge_id = new_challenge . id
new_challenge_choose . save!
# 每一题的选项
if challenge_choose . challenge_questions . present?
challenge_choose . challenge_questions . each do | challenge_question |
new_challenge_question = ChallengeQuestion . new
new_challenge_question . attributes = challenge_question . attributes . dup . except ( " id " , " challenge_choose_id " )
new_challenge_question . challenge_choose_id = new_challenge_choose . id
new_challenge_question . save!
end
end
# 每一题的知识标签
st_challenge_tags = ChallengeTag . where ( :challenge_id = > challenge . id , :challenge_choose_id = > challenge_choose . id )
if st_challenge_tags . present?
st_challenge_tags . each do | st_challenge_tag |
ChallengeTag . create! ( :challenge_id = > new_challenge . id , :name = > st_challenge_tag . try ( :name ) , :challenge_choose_id = > new_challenge_choose . id )
end
end
end
end
end
end
end
rescue Exception = > e
uid_logger_error ( " copy shixun failed # #{ e . message } " )
g . delete_project ( gshixungshixun . id ) if gshixun . try ( :id ) . present? # 异常后,如果已经创建了版本库需要删除该版本库
tip_exception ( " 实训Fork失败 " )
raise ActiveRecord :: Rollback
end
end
end
#合作者
def collaborators
@user = current_user
@members = @shixun . shixun_members . includes ( :user )
end
def fork_list
@shixuns = Shixun . where ( :fork_from = > @shixun . id )
@shixuns_count = @shixuns . count
## 分页参数
page = params [ :page ] || 1
limit = params [ :limit ] || 20
@shixuns = @shixuns . page ( page ) . per ( limit )
end
def new
@introduction_sample = PlatformSample . where ( samples_type : [ 'introduction' , 'knowledge' ] ) . pluck ( [ :samples_type , :contents ] )
@main_type = shixun_main_type
@small_type = shixun_small_type
end
def create
# 评测脚本的一些操作
main_type , sub_type = params [ :main_type ] , params [ :small_type ]
mirror = MirrorScript . where ( :mirror_repository_id = > main_type )
identifier = generate_identifier Shixun , 8
@shixun = Shixun . new ( shixun_params )
@shixun . identifier = identifier
@shixun . user_id = current_user . id
@shixun . reset_time , @shixun . modify_time = Time . now , Time . now
if sub_type . blank?
shixun_script = mirror . first . try ( :script )
else
main_mirror = MirrorRepository . find ( main_type ) . type_name
sub_mirror = MirrorRepository . where ( id : sub_type ) . pluck ( :type_name )
if main_mirror == " Java " && sub_mirror . include? ( " Mysql " )
shixun_script = mirror . last . try ( :script )
else
shixun_script = mirror . first . try ( :script )
shixun_script = modify_shixun_script @shixun , shixun_script
end
end
ActiveRecord :: Base . transaction do
begin
@shixun . save!
# shixun_info关联ß
ShixunInfo . create! ( shixun_id : @shixun . id , evaluate_script : shixun_script , description : params [ :description ] )
# 实训的公开范围
if params [ :scope_partment ] . present?
arr = [ ]
ids = School . where ( :name = > params [ :scope_partment ] ) . pluck ( :id ) . uniq
ids . each do | id |
arr << { :school_id = > id , :shixun_id = > @shixun . id }
end
ShixunSchool . create! ( arr )
end
# 实训合作者
@shixun . shixun_members . create! ( user_id : current_user . id , role : 1 )
# 镜像-实训关联表
ShixunMirrorRepository . create! ( :shixun_id = > @shixun . id , :mirror_repository_id = > main_type . to_i ) if main_type . present?
# 实训主镜像服务配置
ShixunServiceConfig . create! ( :shixun_id = > @shixun . id , :mirror_repository_id = > main_type . to_i )
if sub_type . present?
sub_type . each do | mirror |
ShixunMirrorRepository . create! ( :shixun_id = > @shixun . id , :mirror_repository_id = > mirror )
# 实训子镜像服务配置
ShixunServiceConfig . create! ( :shixun_id = > @shixun . id , :mirror_repository_id = > mirror )
end
end
# 创建版本库
repo_path = repo_namespace ( User . current . login , @shixun . identifier )
GitService . add_repository ( repo_path : repo_path )
# todo: 为什么保存的时候要去除后面的.git呢??
@shixun . update_column ( :repo_name , repo_path . split ( " . " ) [ 0 ] )
rescue Exception = > e
uid_logger_error ( e . message )
tip_exception ( " 实训创建失败 " )
raise ActiveRecord :: Rollback
end
end
end
def apply_shixun_mirror
form_params = params . permit ( * % i [ language runtime run_method attachment_id ] )
form = ApplyShixunMirrorForm . new ( form_params )
form . validate!
tiding = Tiding . new (
user_id : 1 ,
trigger_user_id : current_user . id ,
container_type : 'SendMessage' ,
viewed : 0 ,
tiding_type : 'Apply' ,
extra : form . to_json
)
ActiveRecord :: Base . transaction do
# TODO: 由于tiding是多态,而SendMessage却没有对应的model,因此,如果不跳过验证会报 container must exist的错.
tiding . save ( validate : false )
form . attachment . update! ( container : tiding )
end
sucess_status
rescue ActiveModel :: ValidationError = > ex
tip_exception ( ex . message )
rescue Exception = > e
uid_logger_error ( e . message )
tip_exception ( " 申请失败 " )
end
def update
ActiveRecord :: Base . transaction do
begin
@shixun . shixun_mirror_repositories . destroy_all
if params [ :main_type ] . present?
ShixunMirrorRepository . create ( :shixun_id = > @shixun . id , :mirror_repository_id = > params [ :main_type ] . to_i )
end
if params [ :small_type ] . present?
params [ :small_type ] . each do | mirror |
ShixunMirrorRepository . create ( :shixun_id = > @shixun . id , :mirror_repository_id = > mirror )
end
end
@shixun . update_attributes ( shixun_params )
logger . info ( " # # # # # # # # # # shixun_info_params: #{ shixun_info_params } " )
logger . info ( " # # # # # # # # # # params[:shixun_info][:evaluate_script]: #{ params [ :shixun_info ] [ :evaluate_script ] } " )
@shixun . shixun_info . update_attributes ( shixun_info_params )
@shixun . shixun_schools . delete_all
# scope_partment: 高校的名称
if params [ :scope_partment ] . present?
arr = [ ]
ids = School . where ( :name = > params [ :scope_partment ] ) . pluck ( :id ) . uniq
ids . each do | id |
arr << { :school_id = > id , :shixun_id = > @shixun . id }
end
ShixunSchool . create! ( arr )
end
# 超级管理员和运营人员才能保存 中间层服务器pod信息的配置
if current_user . admin? || current_user . business?
@shixun . shixun_service_configs . destroy_all
@shixun . shixun_service_configs . create! ( service_config_params [ :shixun_service_configs ] )
end
rescue Exception = > e
uid_logger_error ( e . message )
tip_exception ( " 实训保存失败 " )
raise ActiveRecord :: Rollback
end
end
end
# 永久关闭实训
def close
@shixun . update_attributes ( status : 3 , closer_id : current_user . id , end_time : Time . now )
sucess_status
end
def propaedeutics
@content = Shixun . find_by_identifier! ( params [ :identifier ] ) . propaedeutics
end
# 更新背景知识
def update_propaedeutics
@shixun . shixun_info . update_column ( :propaedeutics , params [ :content ] )
end
# 获取推荐实训接口 2个热门实训 + 2个最新实训
def get_recommend_shixuns
hot_shixuns = Shixun . field_for_recommend . published . order ( " myshixuns_count desc " ) . limit ( 2 )
newest_shixuns = Shixun . field_for_recommend . published . order ( " created_at desc " ) . limit ( 2 )
@recommend_shixuns = hot_shixuns + newest_shixuns
end
def settings
@choice_main_type = @shixun . main_mirror_id
@choice_small_type = @shixun . small_mirror_id
@main_type = shixun_main_type
@small_type = shixun_small_type
@configs = @shixun . shixun_service_configs
#@mirror_script = MirrorScript.select([:id, :script_type]).find(@shixun.mirror_script_id).attributes if @shixun.mirror_script_id && @shixun.mirror_script_id != 0
# @shixun_main_mirror = @shixun.show_shixun_mirror
# @script_type = @shixun.script_tag.try(:script_type) || "无"
# @evaluate_scirpt = @shixun.evaluate_script || "无"
end
# 获取脚本内容
def get_script_contents
mirrir_script = MirrorScript . find ( params [ :script_id ] )
script = mirrir_script . try ( :script )
@description = mirrir_script . try ( :description )
@script = modify_shixun_script @shixun , script
end
def get_custom_script
shixun_script = PlatformSample . where ( :samples_type = > " script " ) . first . try ( :contents )
compile = params [ :compile ]
execute = params [ :executive ]
if shixun_script
shixun_script = compile . blank? ? shixun_script . gsub ( " COMPILEFUNCTION " , " " ) . gsub ( " CHALLENGEFIELPATH " , " " ) :
shixun_script . gsub ( " COMPILEFUNCTION " , " #{ compile_command } " ) . gsub ( " COMPILECOMMAND " , " #{ compile } " )
shixun_script = execute . blank? ? shixun_script . gsub ( " EXECUTEFUNCTION " , " " ) : shixun_script . gsub ( " EXECUTECOMMAND " , " #{ execute } " )
shixun_script = modify_shixun_script @shixun , shixun_script
end
@shixun_script = shixun_script
end
def departments
@scope = [ ]
q = params [ :q ]
if q && q . strip . present?
@scope = School . where ( " name like ? " , " % #{ q . strip } % " ) . pluck ( :name )
end
end
def get_mirror_script
mirror = MirrorRepository . find ( params [ :mirror_id ] )
@script = mirror . mirror_scripts
end
# TODO: 目前实训只做软删除.
def destroy
apply_records = ApplyAction . where ( container_id : @shixun . id , container_type : " ApplyShixun " )
apply_records . delete_all if apply_records
# HomeworkCommonShixuns.where(shixun_id: @shixun).delete_all
# @shixun.destroy
@shixun . update_column ( :status , - 1 )
end
# 开启挑战
# 以前在开启挑战的时候检测实训是否更新, 更新则重置, 觉得应该放在TPI更好
# 中间需要一个过渡动画
# TODO: 第一次开启实训都会去判断是否是纯选择题类型,感觉做成在创建关卡的时候就判断该实训是否是纯选择题更加合适
def shixun_exec
if is_shixun_opening?
tip_show_exception ( - 3 , " #{ @shixun . opening_time . strftime ( '%Y-%m-%d %H:%M:%S' ) } " )
end
current_myshixun = @shixun . current_myshixun ( current_user . id )
min_challenges = @shixun . challenges . pluck ( :id , :st )
Rails . logger . info ( " 11111111112 #{ current_myshixun . try ( :id ) } " )
Rails . logger . info ( " 111111111102 #{ params [ :reset ] != 1 } " )
# 因为读写分离有延迟, 所以如果是重置来的请求可以先跳过, 重置过来的params[:reset]为1
if current_myshixun && params [ :reset ] != " 1 "
games = current_myshixun . games
# 如果TPM和TPI的管卡数不相等或者关卡顺序错了, 说明实训被极大的改动, 需要重置,实训发布前打过的实训都需要重置
if is_shixun_reset? ( games , min_challenges , current_myshixun )
# 这里页面弹框要收到 当前用户myshixun的identifier.
tip_show_exception ( " /myshixuns/ #{ current_myshixun . try ( :identifier ) } /reset_my_game " )
end
# 如果存在实训,则直接进入实训
# 如果实训允许跳关, 传参params[:challenge_id]跳入具体的关卡
@current_task =
if params [ :challenge_id ]
game = games . where ( challenge_id : params [ :challenge_id ] ) . take
if @shixun . task_pass || game . status != 3
game
else
current_myshixun . current_task ( games )
end
else
current_myshixun . current_task ( games )
end
else
# 如果未创建关卡一定不能开启实训, 否则TPI没法找到当前的关卡
if @shixun . challenges_count == 0
tip_exception ( " 开启实战前请先创建实训关卡 " )
end
# 判断实训是否全为选择题
is_choice_type = ( min_challenges . size == min_challenges . select { | challenge | challenge . last == 1 } . count )
if ! is_choice_type
commit = GitService . commits ( repo_path : @repo_path ) . try ( :first )
uid_logger ( " First comit # # # # # # # #{ commit } " )
tip_exception ( " 开启实战前请先在版本库中提交代码 " ) if commit . blank?
commit_id = commit [ " id " ]
end
# 如果该实训是金课中的实训,则将当前用户加入到当期开课的课堂
# if StageShixun.exists?(shixun_id: @shixun.id, subject_id: Subject.where(excellent: 1))
# subject = Subject.where(excellent: 1, id: StageShixun.where(shixun_id: @shixun.id).pluck(:subject_id)).take
# course = subject.courses.where("start_date is not null and start_date <= '#{Date.today}' and end_date is not null and end_date >= '#{Date.today}'").take
# if course.present? && !CourseMember.exists?(course_id: course.id, user_id: current_user.id)
# # 为了不影响后续操作, 用create而不是create!
# CourseMember.create(course_id: course.id, user_id: current_user.id, role: 4)
# CourseAddStudentCreateWorksJob.perform_later(course.id, [current_user.id])
# end
# end
ActiveRecord :: Base . transaction do
begin
cloud_bridge = edu_setting ( 'cloud_bridge' )
myshixun_identifier = generate_identifier Myshixun , 10
myshixun = @shixun . myshixuns . create! ( user_id : current_user . id , identifier : myshixun_identifier ,
modify_time : @shixun . modify_time , reset_time : @shixun . reset_time ,
onclick_time : Time . now , commit_id : commit_id , repo_name : ( is_choice_type ? " -1 " : nil ) )
uid_logger ( " myshixun_id is #{ myshixun . id } " )
# 其它创建关卡等操作
challenges = @shixun . challenges
# 之所以增加user_id是为了方便统计查询性能
game_attrs = % i [ challenge_id myshixun_id status user_id open_time identifier modify_time created_at updated_at ]
Game . bulk_insert ( * game_attrs ) do | worker |
base_attr = { myshixun_id : myshixun . id , user_id : myshixun . user_id }
challenges . each_with_index do | challenge , index |
status = ( index == 0 ? 0 : 3 )
game_identifier = generate_identifier ( Game , 12 )
worker . add ( base_attr . merge ( challenge_id : challenge . id , status : status , open_time : Time . now ,
identifier : game_identifier , modify_time : challenge . modify_time ) )
end
end
# 如果实训是纯选择题, 则不需要去fork仓库以及中间层的相关操作了
unless is_choice_type
# fork仓库
project_fork ( myshixun , @repo_path , current_user . login )
rep_url = Base64 . urlsafe_encode64 ( repo_ip_url @repo_path )
uid_logger ( " start openGameInstance " )
uri = " #{ cloud_bridge } /bridge/game/openGameInstance "
logger . info ( " end openGameInstance " )
params = { tpiID : " #{ myshixun . id } " , tpmGitURL : rep_url , tpiRepoName : myshixun . repo_name . split ( " / " ) . last }
uid_logger ( " openGameInstance params is #{ params } " )
interface_post uri , params , 83 , " 实训云平台繁忙( 繁忙等级: 83) "
end
@current_task = myshixun . current_task ( myshixun . games )
uid_logger ( " # # shixun exec: myshixun id is #{ myshixun . id } " )
rescue Exception = > e
uid_logger_error ( e . message )
tip_exception ( " 实训云平台繁忙( 繁忙等级: 81) " )
raise ActiveRecord :: Rollback
end
end
end
end
# def shixun_exec
# if is_shixun_opening?
# tip_show_exception(-3, "#{@shixun.opening_time.strftime('%Y-%m-%d %H:%M:%S')}")
# end
# current_myshixun = @shixun.current_myshixun(current_user.id)
#
# min_challenges = @shixun.challenges.pluck(:id , :st)
# # 因为读写分离有延迟, 所以如果是重置来的请求可以先跳过, 重置过来的params[:reset]为1
# if current_myshixun && params[:reset] != "1"
# games = current_myshixun.games
# # 如果TPM和TPI的管卡数不相等或者关卡顺序错了, 说明实训被极大的改动, 需要重置,实训发布前打过的实训都需要重置
# if is_shixun_reset?(games, min_challenges, current_myshixun)
# # 这里页面弹框要收到 当前用户myshixun的identifier.
# tip_show_exception("/myshixuns/#{current_myshixun.try(:identifier)}/reset_my_game")
# end
#
#
# if current_myshixun.repo_name.nil?
# g = Gitlab.client
# repo_name = g.project(current_myshixun.gpid).try(:path_with_namespace)
# current_myshixun.update_column(:repo_name, repo_name)
# end
#
# # 如果存在实训,则直接进入实训
# # 如果实训允许跳关, 传参params[:challenge_id]跳入具体的关卡
# @current_task =
# if params[:challenge_id]
# game = games.where(challenge_id: params[:challenge_id]).take
# if @shixun.task_pass || game.status != 3
# game
# else
# current_myshixun.current_task(games)
# end
# else
# current_myshixun.current_task(games)
# end
# else
# # 如果未创建关卡一定不能开启实训, 否则TPI没法找到当前的关卡
# if @shixun.challenges_count == 0
# tip_exception("开启实战前请先创建实训关卡")
# end
#
# # 判断实训是否全为选择题
# is_choice_type = (min_challenges.size == min_challenges.select{|challenge| challenge.last == 1}.count)
# if !is_choice_type
# commit = GitService.commits(repo_path: @repo_path).try(:first)
# uid_logger("First comit########{commit}")
# tip_exception("开启实战前请先在版本库中提交代码") if commit.blank?
# commit_id = commit["id"]
# end
#
# begin
# ActiveRecord::Base.transaction do
# begin
# myshixun_identifier = generate_identifier Myshixun, 10
# myshixun_params = {user_id: current_user.id, identifier: myshixun_identifier,
# modify_time: @shixun.modify_time, reset_time: @shixun.reset_time,
# onclick_time: Time.now, commit_id: commit_id}
# @myshixun = @shixun.myshixuns.create!(myshixun_params)
# # 其它创建关卡等操作
# challenges = @shixun.challenges
# # 之所以增加user_id是为了方便统计查询性能
# game_attrs = %i[challenge_id myshixun_id status user_id open_time identifier modify_time created_at updated_at]
# Game.bulk_insert(*game_attrs) do |worker|
# base_attr = {myshixun_id: @myshixun.id, user_id: @myshixun.user_id}
# challenges.each_with_index do |challenge, index|
# status = (index == 0 ? 0 : 3)
# game_identifier = generate_identifier(Game, 12)
# worker.add(base_attr.merge(challenge_id: challenge.id, status: status, open_time: Time.now,
# identifier: game_identifier, modify_time: challenge.modify_time))
# end
# end
# @current_task = @myshixun.current_task(@myshixun.games)
# rescue Exception => e
# logger.error("------ActiveRecord::RecordInvalid: #{e.message}")
# raise("ActiveRecord::RecordInvalid")
# end
# end
# # 如果实训是纯选择题, 则不需要去fork仓库以及中间层的相关操作了
# ActiveRecord::Base.transaction do
# unless is_choice_type
# # fork仓库
# cloud_bridge = edu_setting('cloud_bridge')
# project_fork(@myshixun, @repo_path, current_user.login)
# rep_url = Base64.urlsafe_encode64(repo_ip_url @repo_path)
# uid_logger("start openGameInstance")
# uri = "#{cloud_bridge}/bridge/game/openGameInstance"
# logger.info("end openGameInstance")
# params = {tpiID: "#{@myshixun.id}", tpmGitURL: rep_url, tpiRepoName: @myshixun.repo_name.split("/").last}
# uid_logger("openGameInstance params is #{params}")
# interface_post uri, params, 83, "实训云平台繁忙( 繁忙等级: 83) "
# end
# end
# rescue Exception => e
# logger.info("shixun_exec error: #{e.message}")
# if e.message != "ActiveRecord::RecordInvalid"
# logger.error("##########project_fork error #{e.message}")
# @myshixun.destroy!
# end
# raise "实训云平台繁忙( 繁忙等级: 81) "
# end
# end
# end
# gameID 及实训ID
# status: 0 , 1 申请过, 2, 实训关卡路径未填, 3 实训标签未填, 4 实训未创建关卡
def publish
@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
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
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
end
rescue Exception = > e
logger . error ( " pushlish game #{ e } " )
end
end
include GitCommon
def update_file
content = params [ :content ]
author_name = current_user . real_name
author_email = current_user . git_mail
@content = update_file_content content , @repo_path , @path , author_email , author_name , " Edit by browser "
end
def add_collaborators
member_ids = " ( " + @shixun . shixun_members . map ( & :user_id ) . join ( ',' ) + " ) "
user_name = " % #{ params [ :user_name ] . to_s . strip } % "
school_name = " % #{ params [ :school_name ] . to_s . strip } % "
if user_name . present? || school_name . present?
@users = User . joins ( user_extension : :school ) . where ( " users.id not in #{ member_ids } AND users.status = 1 AND
( LOWER ( concat ( users . lastname , users . firstname ) ) LIKE ? or users . phone like ?)
AND LOWER ( schools . name ) LIKE ?" , user_name , user_name , school_name )
else
@users = User . none
end
page = params [ :page ] || 1
limit = params [ :limit ] || 20
@user_count = @users . count
@users = @users . page ( page ) . per ( limit )
end
def shixun_members_added
raise ( " user_ids 不能为空! " ) if params [ :user_ids ] . blank?
memberships = params [ :user_ids ]
memberships . each do | member |
ShixunMember . create! ( :user_id = > member , :shixun_id = > @shixun . id , :role = > 2 )
end
end
def change_manager
# 搜索成员
if request . get?
@collaborators = @shixun . shixun_members . where ( " user_id != #{ @shixun . user_id } " )
else
if params [ :user_id ]
man_member = ShixunMember . where ( :shixun_id = > @shixun . id , :user_id = > @shixun . user_id ) . first
cha_member = ShixunMember . where ( :user_id = > params [ :user_id ] , :shixun_id = > @shixun . id ) . first
if man_member && cha_member
man_member . update_attribute ( :role , 2 )
cha_member . update_attribute ( :role , 1 )
@shixun . update_attribute ( :user_id , cha_member . user_id )
end
end
end
end
# 刪除合作者
def collaborators_delete
raise ( " user_id不能为空 " ) if params [ :user_id ] . blank?
shixun_member = ShixunMember . where ( :user_id = > params [ :user_id ] , :shixun_id = > @shixun . id , :role = > 2 ) . first
shixun_member . delete
end
# 实训的发送至课堂:搜索课堂
def search_user_courses
## 分页参数
page = params [ :page ] || 1
limit = params [ :limit ] || 20
if params [ :search ]
search = " % #{ params [ :search ] . to_s . strip . downcase } % "
course_ids = Course . find_by_sql ( " SELECT c.id FROM courses c, course_members m
WHERE m . course_id = c . id AND m . role in ( 1 , 2 , 3 )
AND m . user_id = #{current_user.id} AND c.is_delete = 0 AND c.is_end = 0
AND c . name like '#{search}' " ).map(&:id)
else
course_ids = Course . find_by_sql ( " SELECT c.id, c.name FROM courses c, course_members m
WHERE m . course_id = c . id AND m . role in ( 1 , 2 , 3 )
AND m . user_id = #{current_user.id} AND c.is_delete = 0 AND c.is_end = 0").map(&:id)
end
@course_count = course_ids . length
@courses = Course . where ( :id = > course_ids ) . page ( page ) . per ( limit )
end
# 将实训发送到课程
def send_to_course
@course = Course . find ( params [ :course_id ] )
homework = HomeworksService . new . create_homework @shixun , @course , nil , current_user
end
# 二维码扫描下载
def download_file
file_path = params [ :file_name ]
send_file " #{ Rails . root } / #{ file_path } " , :filename = > " #{ file_path } " ,
:type = > 'shixun' ,
:disposition = > 'attachment' #inline can open in browser
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
@shixun . update_column ( :status , 0 )
end
private
def shixun_params
raise ( " 实训名称不能为空 " ) if params [ :shixun ] [ :name ] . blank?
params . require ( :shixun ) . permit ( :name , :trainee , :webssh , :can_copy , :use_scope , :vnc , :test_set_permission ,
:task_pass , :multi_webssh , :opening_time , :mirror_script_id , :code_hidden ,
:hide_code , :forbid_copy )
end
def shixun_info_params
raise ( " 实训描述不能为空 " ) if params [ :shixun_info ] [ :description ] . blank?
raise ( " 评测脚本不能为空 " ) if params [ :shixun_info ] [ :evaluate_script ] . blank?
params . require ( :shixun_info ) . permit ( :description , :evaluate_script )
end
def service_config_params
params . permit ( shixun_service_configs : [ :cpu_limit , :lower_cpu_limit , :memory_limit , :request_limit , :mirror_repository_id ] )
end
def find_shixun
@shixun = Shixun . find_by_identifier ( params [ :identifier ] )
if @shixun . blank?
normal_status ( 404 , " ... " )
return
end
end
def find_repo_name
@repo_path = @shixun . try ( :repo_path )
@path = params [ :path ]
end
def allowed
unless current_user . manager_of_shixun? ( @shixun )
tip_exception ( 403 , " .. " )
end
end
def portion_allowed
if current_user . shixun_identity ( @shixun ) > User :: EDU_CERTIFICATION_TEACHER
raise Educoder :: TipException . new ( 403 , " .. " )
end
end
def special_allowed
if @shixun . status != 2
tip_exception ( 403 , " .. " )
end
end
# 实训是否需要开启
def is_shixun_opening?
@shixun . opening_time . present? &&
@shixun . opening_time > Time . now &&
current_user . shixun_identity ( @shixun ) > User :: EDU_SHIXUN_MEMBER
end
# 实训是否需要重置
def is_shixun_reset? ( games , min_challenges , current_myshixun )
# 用户在申请发布之前,是否玩过实训 TODO: 重置的字段应该迁移到myshixuns表比较合适
modify_shixun = ShixunModify . exists? ( :myshixun_id = > current_myshixun . id , :shixun_id = > @shixun . id , :status = > 1 )
games . size != min_challenges . size || modify_shixun
end
end