educoder/app/controllers/shixuns_controller.rb

506 lines
20 KiB
Ruby
Raw Normal View History

2017-04-07 10:16:13 +08:00
# encoding: utf-8
# REDO: 创建版本库权限控制
class ShixunsController < ApplicationController
layout 'base_shixun'
before_filter :require_login
2017-06-11 15:45:54 +08:00
before_filter :check_authentication
before_filter :find_shixun, :except => [ :index, :new, :create, :index, :search ]
2017-04-07 10:16:13 +08:00
before_filter :shixun_view_allow, :only => [:show]
2017-05-19 17:30:30 +08:00
before_filter :require_manager, :only => [ :settings, :add_script, :publish, :collaborators_delete, :shixun_members_added, :add_collaborators]
2017-06-23 08:57:56 +08:00
#skip_before_filter :verify_authenticity_token, :only => :update_propaedeutics
2017-04-07 10:16:13 +08:00
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
2017-04-07 10:16:13 +08:00
2017-05-02 17:18:34 +08:00
def statistics
@challenges = @shixun.challenges
@top_students = @shixun.myshixuns.where(:status => 1)
2017-05-02 17:18:34 +08:00
myshixuns = @shixun.myshixuns.includes(:games)
@latest_myshixuns = myshixuns.order("created_at desc").limit(4)
end
2017-06-06 14:17:07 +08:00
def autocompletion
end
2017-04-24 14:42:54 +08:00
def index
# @type = params[:type]
# @status = params[:status]
# @search = params[:search]
# if @type == 1 || @type.nil?
# case @status
# when 1, nil # 所有进展
# @shixuns = Shixun.where(:authentication => 1).where("name like ?", "%#{@search}%")
# when 2 # 我已创建
# @shixuns = Shixun.where(:authentication => 1, :user_id => User.current).where("name like ?", "%#{@search}%")
# when 3 # 我未挑战
# @shixuns = Shixun.find_by_sql("select * from shixuns where id not in (SELECT shixun_id FROM `myshixuns` where shixun_id in (SELECT id FROM `shixuns` where authentication=1) and user_id=#{User.current.id})and name like %#{@search}%;")
# when 4 # 我未通关
# @shixuns = Shixun.find_by_sql("select * from shixuns where id in (SELECT shixun_id FROM `myshixuns` where shixun_id in (SELECT id FROM `shixuns` where authentication=1) and user_id=#{User.current.id} and status=0) and name like %#{@search}%;")
# when 5 # 我已通关
# @shixuns = Shixun.find_by_sql("select * from shixuns where id in (SELECT shixun_id FROM `myshixuns` where shixun_id in (SELECT id FROM `shixuns` where authentication=1) and user_id=#{User.current.id} and status=1) and name like %#{@search}%;")
# end
# else
# @shixuns = User.current.shixuns
# end
@shixuns = Shixun.where(:authentication => 1)
@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
2017-04-24 17:29:38 +08:00
@shixuns_count = @shixuns.count
2017-06-02 19:21:09 +08:00
@limit = 16
@is_remote = true
@shixun_pages = Paginator.new @shixuns_count, @limit, params['page'] || 1
@offset ||= @shixun_pages.offset
@shixuns = paginateHelper @shixuns, @limit
2017-04-24 14:42:54 +08:00
render :layout => "base_edu"
end
def propaedeutics
respond_to do |format|
format.html
end
end
2017-06-23 08:57:56 +08:00
def update_propaedeutics
@shixun = Shixun.where(:identifier => params[:id]).first
@shixun.update_attribute("propaedeutics", params[:shixun][:propaedeutics])
redirect_to propaedeutics_shixun_path(@shixun)
end
2017-05-19 16:56:09 +08:00
def collaborators
@collaborators = @shixun.collaborators
end
2017-05-19 17:14:15 +08:00
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
2017-05-19 16:56:09 +08:00
# 已存在的成员不添加
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
2017-04-27 10:18:15 +08:00
def search
2017-04-25 14:18:52 +08:00
# 确定 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
2017-06-02 15:17:13 +08:00
@language = params[:language]
2017-06-01 15:20:12 +08:00
@status = params[:status].to_i
@search = params[:search]
if @language.nil?
case @status
2017-06-01 15:20:12 +08:00
when 1, 0 # 所有进展
@shixuns = Shixun.where(:authentication => 1).where("name like ?", "%#{@search}%").reorder(@order)
when 2 # 我已创建
@shixuns = Shixun.where(:authentication => 1, :user_id => User.current).where("name like ?", "%#{@search}%").reorder(@order)
when 3 # 我未挑战
@shixuns = Shixun.find_by_sql("select * from shixuns where id not in (SELECT shixun_id FROM `myshixuns` where shixun_id in (SELECT id FROM `shixuns` where authentication=1) and user_id=#{User.current.id})and name like '%#{@search}%' and authentication=1 order by #{@order};")
when 4 # 我未通关
2017-06-02 15:17:13 +08:00
@shixuns = Shixun.find_by_sql("select * from shixuns where id in (SELECT shixun_id FROM `myshixuns` where shixun_id in (SELECT id FROM `shixuns` where authentication=1) and user_id=#{User.current.id} and status=0) and name like '%#{@search}%' order by #{@order};")
when 5 # 我已通关
2017-06-02 15:17:13 +08:00
@shixuns = Shixun.find_by_sql("select * from shixuns where id in (SELECT shixun_id FROM `myshixuns` where shixun_id in (SELECT id FROM `shixuns` where authentication=1) and user_id=#{User.current.id} and status=1) and name like '%#{@search}%' order by #{@order};")
end
else
2017-06-02 15:17:13 +08:00
case @status
when 1, 0 # 所有进展
@shixuns = Shixun.where(:authentication => 1, :language => @language).where("name like ?", "%#{@search}%").reorder(@order)
when 2 # 我已创建
@shixuns = Shixun.where(:authentication => 1, :user_id => User.current, :language => @language).where("name like ?", "%#{@search}%").reorder(@order)
when 3 # 我未挑战
@shixuns = Shixun.find_by_sql("select * from shixuns where id not in (SELECT shixun_id FROM `myshixuns` where shixun_id in (SELECT id FROM `shixuns` where authentication=1) and user_id=#{User.current.id})and name like '%#{@search}%' and language='#{@language}' and authentication=1 order by #{@order};")
2017-06-02 15:17:13 +08:00
when 4 # 我未通关
@shixuns = Shixun.find_by_sql("select * from shixuns where id in (SELECT shixun_id FROM `myshixuns` where shixun_id in (SELECT id FROM `shixuns` where authentication=1 and language='#{@language}') and user_id=#{User.current.id} and status=0) and name like '%#{@search}%' order by #{@order};")
when 5 # 我已通关
@shixuns = Shixun.find_by_sql("select * from shixuns where id in (SELECT shixun_id FROM `myshixuns` where shixun_id in (SELECT id FROM `shixuns` where authentication=1 and language='#{@language}') and user_id=#{User.current.id} and status=1) and name like '%#{@search}%' order by #{@order};")
end
end
# @shixuns = Shixun.where(:authentication => 1).reorder(order)
@shixuns_count = @shixuns.count
2017-06-02 19:21:09 +08:00
@limit = 16
@is_remote = true
@shixun_pages = Paginator.new @shixuns_count, @limit, params['page'] || 1
@offset ||= @shixun_pages.offset
@shixuns = paginateHelper @shixuns, @limit
respond_to do |format|
format.js
end
2017-04-25 14:18:52 +08:00
end
# jenkins回调脚本
2017-04-16 17:20:47 +08:00
# gameID 及实训ID
def publish
jenkins_shixuns = Redmine::Configuration['jenkins_shixuns']
begin
2017-06-20 11:34:46 +08:00
gameInfo = @shixun.gameInfo
2017-04-16 17:20:47 +08:00
uri = URI("#{jenkins_shixuns}/jenkins-exec/game/publishGame")
2017-06-20 11:34:46 +08:00
logger.info(gameInfo)
params = {gameInfo:gameInfo}
logger.info(params)
2017-04-17 10:11:17 +08:00
res = uri_exec uri, params
2017-06-22 17:37:27 +08:00
if res && res['code'].to_i == 0
2017-06-20 16:09:48 +08:00
@shixun.update_attributes(:status => 1, :is_updated => 1)
apply = ApplyAction.where(:container_type => "ApplyShixun", :container_id => @shixun.id).last
if apply && apply.status == 0
@status = 0
else
ApplyAction.create(:container_type => "ApplyShixun", :container_id => @shixun.id, :user_id => User.current.id, :status => 0)
notes = User.current.show_name.to_s + " 申请发布实训:<a href='#{shixun_path(@shixun)}'>#{@shixun.name}</a>"
JournalsForMessage.create(:jour_id => 1, :jour_type => 'Principal', :user_id => User.current.id, :notes => notes, :private => 1, :reply_id => 0)
@status = 1
end
shixun_modify_status_without_publish(@shixun, 1)
2017-04-17 15:30:31 +08:00
else
logger.error("res['code'] is #{res['code']}, res['msg'] is #{res['code']}")
@jenkin_error = true
end
rescue Exception => e
2017-06-19 17:27:11 +08:00
@jenkin_error = true
logger.error("pushlish game #{e}")
respond_to do |format|
format.js
end
2017-04-07 10:16:13 +08:00
end
end
2017-06-21 17:26:49 +08:00
def apply_publish
apply = ApplyAction.where(:container_type => "ApplyShixun", :container_id => @shixun.id).last
if apply && apply.status == 0
@status = 0
else
ApplyAction.create(:container_type => "ApplyShixun", :container_id => @shixun.id, :user_id => User.current.id, :status => 0)
notes = User.current.show_name.to_s + " 申请发布实训:<a href='#{shixun_path(@shixun)}'>#{@shixun.name}</a>"
JournalsForMessage.create(:jour_id => 1, :jour_type => 'Principal', :user_id => User.current.id, :notes => notes, :private => 1, :reply_id => 0)
@shixun.update_column('status', 1)
@status = 1
end
end
def cancel_publish
apply = ApplyAction.where(:container_type => "ApplyShixun", :container_id => @shixun.id).last
if apply && apply.status == 0
apply.update_attributes(:status => 3)
@shixun.update_column('status', 0)
end
redirect_to shixun_path(@shixun)
end
def close
@shixun.update_column('status', 3)
redirect_to shixun_path(@shixun)
end
2017-04-07 10:16:13 +08:00
# copy_shixun复制一个新的实训模块包括版本库
# copy_myshixun自动创建系列game,game中只包含状态等信息公共信息从Challeges中读取
# 开启过实训的则直接跳入my实训页面
2017-04-07 10:16:13 +08:00
def shixun_exec
unless allow_shixun_exec(@shixun) && (User.current.manager_of_shixun?(@shixun) || @shixun.status > 0)
2017-04-07 10:16:13 +08:00
render_403
return
2017-04-07 10:16:13 +08:00
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}")
2017-06-23 15:13:45 +08:00
redirect_to myshixun_game_path(myshixun.current_task, :myshixun_id => myshixun)
return
end
2017-06-23 15:13:45 +08:00
repository = @shixun.repository
2017-04-07 10:16:13 +08:00
ActiveRecord::Base.transaction do
begin
2017-06-23 15:13:45 +08:00
@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))
2017-06-23 15:13:45 +08:00
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 =Game.create!(:challenge_id => challenge.id, :myshixun_id => myshixun.id, :status => status, :user_id => myshixun.user_id, :open_time => Time.now, :identifier => code)
# 记录刚开始时默认代开文件原始代码
# 刚开始fork的一段时间是获取不了content内容的
game_passed_code(game.try(:id), challenge.try(:path), myshixun.try(:gpid), 0)
end
if params[:type] == "1" # 重置过来的请求
shixun_mod = ShixunModify.where(:shixun_id => myshixun.try(:shixun_id), :myshixun_id => myshixun.try(:id)).first
if shixun_mod.nil?
ShixunModify.create(:shixun_id => myshixun.shixun_id, :myshixun_id => myshixun.id, :status => 0)
else
shixun_mod.update_attributes(:status => 0)
end
end
2017-06-23 15:13:45 +08:00
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)
2017-04-07 10:16:13 +08:00
rescue Exception => e
flash[:error] = e.message
logger.info("failed to exec shixun: current task id is #{e}")
2017-04-07 10:16:13 +08:00
@g.delete_project(gshixun.id) if !gshixun.id.nil?
redirect_to shixun_challenges_path(@shixun)
2017-04-07 10:16:13 +08:00
raise ActiveRecord::Rollback
end
end
end
def new
@shixun = Shixun.new
respond_to do |format|
2017-05-17 17:19:16 +08:00
format.html{render :layout => 'base_edu'}
2017-04-07 10:16:13 +08:00
format.json
end
end
2017-04-25 17:15:37 +08:00
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)
2017-04-07 10:16:13 +08:00
def create
2017-04-25 17:15:37 +08:00
identifier = generate_identifier
2017-04-07 10:16:13 +08:00
@shixun = Shixun.new(params[:shixun])
@shixun.user_id = User.current.id
@shixun.language = params[:language]
2017-04-25 17:15:37 +08:00
@shixun.identifier = identifier
2017-04-07 10:16:13 +08:00
(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
2017-05-08 15:28:35 +08:00
# 自动构建版本库
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 && @repository.id
@repository.destroy
end
end
end
end
2017-04-25 17:15:37 +08:00
format.html { redirect_to shixun_path @shixun, notice: l(:notice_successful_create) }
2017-04-07 10:16:13 +08:00
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
2017-04-25 17:15:37 +08:00
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
2017-04-07 10:16:13 +08:00
def edit
end
def update
if @shixun.status == 0
language = @shixun.language
@shixun.attributes = params[:shixun]
@shixun.language = params[:language]
params[:shixun][:is_public] == "on" ? @shixun.is_public = 1 : @shixun.is_public = 0
if @shixun.save
# 实训语言更改了会影响后续的评测所以需要更新is_updated
if language != params[:language]
add_shixun_modify_status(@shixun, 1)
end
2017-06-22 16:21:47 +08:00
end
else
@error = "该实训已申请发布了,暂不能编辑"
2017-06-20 16:09:48 +08:00
end
2017-04-07 10:16:13 +08:00
respond_to do |format|
format.html{redirect_to settings_shixun_url(@shixun)}
format.js
2017-04-07 10:16:13 +08:00
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)
2017-04-07 10:16:13 +08:00
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
2017-04-25 17:15:37 +08:00
@shixun = Shixun.find_by_identifier(params[:id])
render_404 if @shixun.nil?
2017-04-07 10:16:13 +08:00
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
2017-06-23 15:13:45 +08:00
# 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)
2017-06-29 15:51:49 +08:00
rep_url = Base64.encode64(git_shixun_url_ip shixun, login)
2017-06-23 15:13:45 +08:00
uri = URI("#{jenkins_shixuns}/jenkins-exec/game/openGameInstance")
pipeLine = "#{shixun.script}"
params = {jobNameForInstance: "myshixun_#{myshixun.id}", gameInfo: shixun.gameInfo, instanceGitURL:rep_url}
logger.info("openGameInstance params is #{params}")
res = uri_exec uri, params
if (res && res['code'].to_i != 0)
raise("实训云平台繁忙繁忙等级83")
end
return myshixun
end
end
2017-04-07 10:16:13 +08:00
def training_shixun_notice res
if res['code'] == 0
@notice = "实训开启成功"
else
@notice = res['msg'].nil? ? "实训开启失败" : res['msg']
end
end
# 权限控制
def shixun_view_allow
2017-06-23 10:38:40 +08:00
render_403 if (@shixun.status == 0 && !(User.current.manager_of_shixun?(@shixun) || User.current.admin?))
2017-04-07 10:16:13 +08:00
end
# 实训管理员或者超级管理员
def require_manager
2017-04-17 15:39:01 +08:00
render_403 unless (User.current.manager_of_shixun?(@shixun) || User.current.admin?)
2017-04-07 10:16:13 +08:00
end
end