educoder/app/controllers/shixuns_controller.rb

393 lines
13 KiB
Ruby
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# encoding: utf-8
# REDO: 创建版本库权限控制
class ShixunsController < ApplicationController
layout 'base_shixun'
before_filter :require_login
before_filter :find_shixun, :except => [ :index, :new, :create, :index, :search ]
before_filter :shixun_view_allow, :only => [:show]
before_filter :require_manager, :only => [ :settings, :add_script, :publish, :collaborators_delete, :shixun_members_added, :add_collaborators]
include ApplicationHelper
def shixun_monitor
# monitor_filter
# if @had_exec
# @tpm = Myshixun.where(:user_id => User.current, :shixun_id => @shixun).first
# end
#
# respond_to do |format|
# format.js
# end
end
def statistics
@challenges = @shixun.challenges
@top_students = @shixun.myshixuns.where(:status => 1)
myshixuns = @shixun.myshixuns.includes(:games)
@latest_myshixuns = myshixuns.order("created_at desc").limit(4)
end
def index
@shixuns = Shixun.where(:authentication => 1).order('updated_at desc')
@shixun_my_score = Game.find_by_sql("select sum(final_score) as score from games where myshixun_id in (select id from myshixuns where status =1
and user_id=#{User.current.id} and shixun_id in (SELECT id FROM `shixuns` where authentication=1))").first.try(:score).to_i
@current_user_had_passed = Myshixun.find_by_sql("select count(*) as had_passed from myshixuns where status =1 and user_id=#{User.current.id}
and shixun_id in (SELECT id FROM `shixuns` where authentication=1)").first.try(:had_passed).to_i
@shixuns_count = @shixuns.count
render :layout => "base_edu"
end
def propaedeutics
respond_to do |format|
format.html
end
end
def collaborators
@collaborators = @shixun.collaborators
end
def collaborators_delete
user_id = params[:c_id]
shixun_member = ShixunMember.where(:user_id => user_id, :shixun_id => @shixun.id, :role => 2).first
shixun_member.delete
@collaborators = @shixun.collaborators
respond_to do |format|
format.js
end
end
# 已存在的成员不添加
def add_collaborators
if !params[:search].nil?
# members = searchTeacherAndAssistant @course
member_ids = "(" + @shixun.shixun_members.map(&:user_id).join(',') + ")"
condition = "%#{params[:search].strip}%".gsub(" ","")
@users = User.where("id not in #{member_ids} and status = 1 and LOWER(concat(lastname, firstname)) LIKE '#{condition}'").includes(:user_extensions)
end
respond_to do |format|
format.js
end
end
def shixun_members_added
unless params[:membership][:user_ids].blank?
memberships = params[:membership][:user_ids]
memberships.each do |member|
ShixunMember.create(:user_id => member, :shixun_id => @shixun.id, :role => 2)
end
@collaborators = @shixun.collaborators
end
respond_to do |format|
format.js
end
end
def search
# 确定 sort 1升序 2 降序
if params[:time_reorder]
order = "#{Shixun.table_name}.created_at #{params[:time_reorder]}"
elsif params[:hot_reorder]
order = "myshixun_count #{params[:hot_reorder]}, #{Shixun.table_name}.updated_at #{params[:hot_reorder]}"
else
order = "#{Shixun.table_name}.created_at desc"
end
@shixuns = Shixun.where(:authentication => 1).reorder(order)
respond_to do |format|
format.js
end
end
# jenkins回调脚本
# gameID 及实训ID
def publish
jenkins_shixuns = Redmine::Configuration['jenkins_shixuns']
fragments = []
testSet = []
testCases = []
begin
challenges = @shixun.challenges.includes(:test_sets)
challenges.each do |challenge|
pipeline_script = challenge.try(:pipeline_script)
challenge_script = {:challengeStage => "#{challenge.position}", :challengePipeline => "#{pipeline_script}"}
fragments << challenge_script
# 每一关所有的测试集
challenge.test_sets.each do |test_set|
test_cases = {:caseId => test_set.id.to_s, :input => test_set.input, :output => test_set.output, :isPublic => (test_set.is_public ? "1" : "0")}
testSet << test_cases
end
test_sets_list = {:challengeStage => challenge.position.to_s, :challengeTestCases => testSet}
testCases << test_sets_list
testSet = []
end
gameInfo = {:trainingID => @shixun.id.to_s, :operationEnvironment => @shixun.language, :challengePipelines => fragments, :testCases => testCases}
fragments = fragments.to_json
uri = URI("#{jenkins_shixuns}/jenkins-exec/game/publishGame")
params = {gameInfo:gameInfo.to_json}
res = uri_exec uri, params
if res['code'] == 0
@shixun.update_attribute(:status, 1)
@shixun.update_attribute(:script, res["msg"])
else
logger.error("res['code'] is #{res['code']}, res['msg'] is #{res['code']}")
@jenkin_error = true
end
rescue Exception => e
logger.error("pushlish game #{e}")
respond_to do |format|
format.js
end
end
end
# copy_shixun复制一个新的实训模块包括版本库
# copy_myshixun自动创建系列game,game中只包含状态等信息公共信息从Challeges中读取
# 开启过实训的则直接跳入my实训页面
def shixun_exec
unless allow_shixun_exec(@shixun)
render_403
end
myshixun = Myshixun.where(:user_id => User.current.id, :shixun_id => @shixun.id).first
unless myshixun.blank?
logger.info("current task id is #{myshixun.current_task}")
redirect_to myshixun_game_path(myshixun.current_task, :myshixun_id => myshixun)
return
end
repository = @shixun.repository
ActiveRecord::Base.transaction do
begin
@g = Gitlab.client
if User.current.gid.nil?
s = Trustie::Gitlab::Sync.new
s.sync_user(User.current)
end
gshixun = @g.fork(@shixun.gpid, User.current.gid)
logger.info("#############gshixun is #{gshixun}")
if !gshixun.id.nil?
myshixun = copy_myshixun(@shixun, gshixun)
@shixun.update_attribute(:myshixun_count, (@shixun.myshixun_count + 1))
challenges = @shixun.challenges
# 之所以增加user_id是为了方便统计查询性能
challenges.each_with_index do |challenge, index|
status = (index == 0 ? 0 : 3)
code = CODES.sample(12).join
code = CODES.sample(12).join if Game.where(identifier: code).present?
Game.create!(:challenge_id => challenge.id, :myshixun_id => myshixun.id, :status => status, :user_id => myshixun.user_id, :open_time => Time.now, :identifier => code)
end
else
raise("实训云平台繁忙繁忙等级81")
end
logger.info("myshixun id si #{myshixun.id} and current_task id is#{myshixun.current_task.id}")
redirect_to myshixun_game_path(myshixun.current_task, :myshixun_id => myshixun)
rescue Exception => e
flash[:error] = e.message
logger.info("failed to exec shixun: current task id is #{e}")
@g.delete_project(gshixun.id) if !gshixun.id.nil?
redirect_to shixun_challenges_path(@shixun)
raise ActiveRecord::Rollback
end
end
end
def new
@shixun = Shixun.new
respond_to do |format|
format.html{render :layout => 'base_edu'}
format.json
end
end
CODES = %W(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)
def create
identifier = generate_identifier
@shixun = Shixun.new(params[:shixun])
@shixun.user_id = User.current.id
@shixun.language = params[:language]
@shixun.identifier = identifier
(params[:shixun][:is_public] == "1" ? @shixun.is_public = true : @shixun.is_public = false)
respond_to do |format|
if @shixun.save
m = ShixunMember.new(:user_id => User.current.id, :role => 1)
@shixun.shixun_members << m
# 自动构建版本库
repository = Repository.new
repository.shixun = @shixun
repository.type = 'Repository::Gitlab'
repository.identifier = @shixun.identifier.downcase
repository.project_id = -1
ActiveRecord::Base.transaction do
if repository.save
begin
s = Trustie::Gitlab::Sync.new
gproject = s.create_shixun(@shixun, repository)
raise "sync failed" if @shixun.gpid.blank?
rescue Exception => e
@shixun.update_attribute(:gpid, nil)
if @repository.id
@repository.destroy
end
end
end
end
format.html { redirect_to shixun_path @shixun, notice: l(:notice_successful_create) }
format.js
else
format.html { render action: "new" }
format.js
end
end
end
def show
respond_to do |format|
format.html{redirect_to shixun_challenges_path(@shixun)}
end
end
CODES = %W(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)
def generate_identifier
code = CODES.sample(8).join
return generate_identifier if Shixun.where(identifier: code).present?
code
end
def edit
end
def update
@shixun.attributes = params[:shixun]
@shixun.language = params[:language]
params[:shixun][:is_public] == "on" ? @shixun.is_public = 1 : @shixun.is_public = 0
@shixun.save
respond_to do |format|
format.html{redirect_to settings_shixun_url(@shixun)}
end
end
def destroy
end
def settings
@repository = Repository.where(:shixun_id => @shixun, :type => "Repository::Gitlab").first
unless @repository.nil?
gitlab_address = Redmine::Configuration['gitlab_address']
login = User.find_by_mail("educoder@163.com").try(:login)
@repos_url = git_shixun_url(@shixun, login)
end
end
# 添加实训脚本
def add_script
if @shixun.update_attribute(:script, params[:shixun_script])
@notice = "脚本添加成功"
else
@notice = "脚本添加失败"
end
end
# 创建实训job
def shixun_job_create
if @shixun.challenges.count == 0
@notice = "实训开启失败:请先发布实训任务"
return
elsif Repository.where(:shixun_id => @shixun.id, :type => "Repository::Gitlab").count == 0
@notice = "实训开启失败:请先创建版本库"
return
end
@shixun.update_attribute(:status, 1)
end
# 更新实训job
def shixun_job_update
# jobName = "#{@shixun.id}"
# pipeLine = "#{Base64.encode64(@shixun.script)}"
# uri = URI("http://123.59.135.74:9999/jenkins-exec/api/updateJob")
# params = {jobName: jobName, pipeLine: pipeLine}
# res = uri_exec uri, params
training_shixun_notice res
if res['code'] == 0
@shixun.update_attribute(:status, 1)
end
end
# Find shixun of id params[:id]
def find_shixun
@shixun = Shixun.find_by_identifier(params[:id])
render_404 if @shixun.nil?
rescue ActiveRecord::RecordNotFound
render_404
end
def monitor_filter
if User.current.id == @shixun.user_id
@notice = l(:label_shixun_mine)
else
if has_exec_cur_shixun(@shixun)
@notice = l(:label_shixun_had_forked)
@had_exec = true
else
@notice = l(:label_shixun_exec)
@had_exec = false
end
end
end
private
# REDO: 新增类型copy的时候
# 复制项目
# gshixun --> gitlab project
CODES = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z)
def copy_myshixun shixun, gshixun
myshixun = Myshixun.new
myshixun.attributes = shixun.attributes.dup.except("id","user_id","visits","gpid","status", "identifier","propaedeutics")
myshixun.shixun_id = shixun.id
myshixun.user_id = User.current.id
myshixun.gpid = gshixun.id
jenkins_shixuns = Redmine::Configuration['jenkins_shixuns']
if myshixun.save!
code = CODES.sample(10).join
code = CODES.sample(10).join if Myshixun.where(identifier: code).present?
myshixun.update_attribute(:identifier, code)
MyshixunMember.create!(:myshixun_id => myshixun.id, :user_id => User.current.id, :role => 1)
rep = Repository.new(:myshixun_id => myshixun.id, :identifier => gshixun.name,:project_id => -1, :shixun_id => -2)
rep.type = "Repository::Gitlab"
rep.save!
login = User.find_by_mail("educoder@163.com").try(:login)
rep_url = Base64.encode64(git_shixun_url shixun, login)
uri = URI("#{jenkins_shixuns}/jenkins-exec/game/openGameInstance")
pipeLine = "#{shixun.script}"
params = {jobNameForInstance: "myshixun_#{myshixun.id}", gamePipelineScript: pipeLine, instanceGitURL:rep_url}
res = uri_exec uri, params
if (res && res['code'] != 0)
raise("实训云平台繁忙繁忙等级83")
end
return myshixun
end
end
def training_shixun_notice res
if res['code'] == 0
@notice = "实训开启成功"
else
@notice = res['msg'].nil? ? "实训开启失败" : res['msg']
end
end
# 权限控制
def shixun_view_allow
if @shixun.is_public?
true
else
User.current.member_of?(@shixun) ? true : false
end
end
# 实训管理员或者超级管理员
def require_manager
render_403 unless (User.current.manager_of_shixun?(@shixun) || User.current.admin?)
end
end