dev_forge
Jasder 5 years ago
commit 72b4563830

11
.gitignore vendored

@ -6,6 +6,7 @@
# Ignore bundler config. # Ignore bundler config.
/.bundle /.bundle
/bundle
# Ignore lock config file # Ignore lock config file
*.lock *.lock
@ -71,3 +72,13 @@ vendor/bundle/
/workspace /workspace
/log /log
/public/admin /public/admin
/mysql_data
.generators
.rakeTasks
db/bak/
docker/
educoder.sql
redis_data/
Dockerfile

@ -108,3 +108,6 @@ gem 'diffy'
# oauth2 # oauth2
gem 'omniauth', '~> 1.9.0' gem 'omniauth', '~> 1.9.0'
gem 'omniauth-oauth2', '~> 1.6.0' gem 'omniauth-oauth2', '~> 1.6.0'
# global var
gem 'request_store'

@ -26,6 +26,15 @@ $(document).on('turbolinks:load', function() {
}); });
}); });
// 清空
searchForm.on('click', '.clear-btn', function () {
searchForm.find('select[name="status"]').val('');
searchForm.find('.school-select').val('').trigger('change');
searchForm.find('input[name="keyword"]').val('');
searchForm.find('#homepage_show').attr('checked', false);
searchForm.find('input[type="submit"]').trigger('click');
});
// ************** 学校选择 ************* // ************** 学校选择 *************
searchForm.find('.school-select').select2({ searchForm.find('.school-select').select2({
theme: 'bootstrap4', theme: 'bootstrap4',

@ -0,0 +1,11 @@
$(document).on('turbolinks:load', function () {
if ($('body.admins-projects-index-page').length > 0) {
var $form = $('.search-form');
// 清空
$form.on('click', '.clear-btn', function () {
$form.find('input[name="search"]').val('');
$form.find('input[type="submit"]').trigger('click');
});
}
});

@ -1,12 +1,14 @@
$(document).on('turbolinks:load', function(){ $(document).on('turbolinks:load', function(){
if ($('body.admins-shixun-feedback-messages-index-page').length > 0) { if ($('body.admins-shixun-feedback-messages-index-page').length > 0) {
$(".content-img img").addClass("w-20").addClass("preview-image");
var baseOptions = { var baseOptions = {
autoclose: true, autoclose: true,
language: 'zh-CN', language: 'zh-CN',
format: 'yyyy-mm-dd 00:00:00', format: 'yyyy-mm-dd 00:00:00',
startDate: '2017-04-01' startDate: '2017-04-01'
} };
var defineDateRangeSelect = function(element){ var defineDateRangeSelect = function(element){
var options = $.extend({inputs: $(element).find('.start-date, .end-date')}, baseOptions); var options = $.extend({inputs: $(element).find('.start-date, .end-date')}, baseOptions);
@ -14,9 +16,9 @@ $(document).on('turbolinks:load', function(){
$(element).find('.start-date').datepicker().on('changeDate', function(e){ $(element).find('.start-date').datepicker().on('changeDate', function(e){
$(element).find('.end-date').datepicker('setStartDate', e.date); $(element).find('.end-date').datepicker('setStartDate', e.date);
}) });
}; };
defineDateRangeSelect('.grow-date-input-daterange'); defineDateRangeSelect('.grow-date-input-daterange');
} }
}) });

@ -0,0 +1,12 @@
$(document).on('turbolinks:load', function () {
if ($('body.admins-shixun-modify-records-index-page').length > 0) {
var $form = $('.search-form');
// 清空
$form.on('click', '.clear-btn', function () {
$form.find('select[name="date"]').val('weekly');
$form.find('input[name="user_name"]').val('');
$form.find('input[type="submit"]').trigger('click');
});
}
});

@ -0,0 +1,14 @@
.diff{overflow:auto;}
.diff ul{background:#fff;overflow:auto;font-size:13px;list-style:none;margin:0;padding:0 1rem;display:table;width:100%;}
.diff del, .diff ins{display:block;text-decoration:none;}
.diff li{padding:0; display:table-row;margin: 0;height:1em;}
.diff li.ins{background:#dfd; color:#080}
.diff li.del{background:#fee; color:#b00}
.diff li:hover{background:#ffc}
/* try 'whitespace:pre;' if you don't want lines to wrap */
.diff del, .diff ins, .diff span{white-space:pre-wrap;font-family:courier;}
.diff del strong{font-weight:normal;background:#fcc;}
.diff ins strong{font-weight:normal;background:#9f9;}
.diff li.diff-comment { display: none; }
.diff li.diff-block-info { background: none repeat scroll 0 0 gray; }

@ -0,0 +1,7 @@
.admins-shixun-feedback-messages-index-page {
.content-img {
img {
height: 60px;
}
}
}

@ -1,7 +1,8 @@
class AdminConstraint class AdminConstraint
def matches?(request) def matches?(request)
return false unless request.session[:user_id] laboratory = Laboratory.first
user = User.find request.session[:user_id] return false unless request.session[:"#{laboratory.try(:identifier).split('.').first}_user_id"]
user = User.find request.session[:"#{laboratory.try(:identifier).split('.').first}_user_id"]
user && user.admin? user && user.admin?
end end
end end

@ -69,6 +69,8 @@ class AccountsController < ApplicationController
return normal_status(-2, "验证码已失效") if !verifi_code&.effective? return normal_status(-2, "验证码已失效") if !verifi_code&.effective?
end end
return normal_status(-1, "8~16位密码支持字母数字和符号") unless params[:password] =~ CustomRegexp::PASSWORD
code = generate_identifier User, 8, pre code = generate_identifier User, 8, pre
login = pre + code login = pre + code
@user = User.new(admin: false, login: login, mail: email, phone: phone, type: "User") @user = User.new(admin: false, login: login, mail: email, phone: phone, type: "User")
@ -145,6 +147,7 @@ class AccountsController < ApplicationController
end end
return normal_status(-2, "验证码不正确") if verifi_code.try(:code) != code.strip return normal_status(-2, "验证码不正确") if verifi_code.try(:code) != code.strip
return normal_status(-2, "验证码已失效") if !verifi_code&.effective? return normal_status(-2, "验证码已失效") if !verifi_code&.effective?
return normal_status(-1, "8~16位密码支持字母数字和符号") unless params[:new_password] =~ CustomRegexp::PASSWORD
user.password, user.password_confirmation = params[:new_password], params[:new_password_confirmation] user.password, user.password_confirmation = params[:new_password], params[:new_password_confirmation]
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
@ -154,7 +157,7 @@ class AccountsController < ApplicationController
sucess_status sucess_status
rescue Exception => e rescue Exception => e
uid_logger_error(e.message) uid_logger_error(e.message)
tip_exception("密码重置失败") tip_exception(e.message)
end end
end end

@ -6,6 +6,7 @@ class Admins::DailySchoolStatisticsController < Admins::BaseController
total_count, statistics = Admins::SchoolDailyStatisticService.call(params) total_count, statistics = Admins::SchoolDailyStatisticService.call(params)
@statistics = paginate statistics, total_count: total_count @statistics = paginate statistics, total_count: total_count
@params_page = params[:page] || 1
respond_to do |format| respond_to do |format|
format.html { load_statistic_total } format.html { load_statistic_total }

@ -6,6 +6,7 @@ class Admins::MyshixunsController < Admins::BaseController
myshixuns = Admins::MyshixunQuery.call(params) myshixuns = Admins::MyshixunQuery.call(params)
@myshixuns = paginate myshixuns.includes(:last_executable_task, :last_task, shixun: :user, user: { user_extension: :school }) @myshixuns = paginate myshixuns.includes(:last_executable_task, :last_task, shixun: :user, user: { user_extension: :school })
@params_page = params[:page] || 1
myshixun_ids = @myshixuns.map(&:id) myshixun_ids = @myshixuns.map(&:id)
@finish_game_count = Game.where(myshixun_id: myshixun_ids, status: 2).group(:myshixun_id).count @finish_game_count = Game.where(myshixun_id: myshixun_ids, status: 2).group(:myshixun_id).count

@ -10,6 +10,7 @@ class Admins::SchoolStatisticsController < Admins::BaseController
@grow_summary = service.grow_summary @grow_summary = service.grow_summary
total_count, statistics = service.call total_count, statistics = service.call
@params_page = params[:page] || 1
@statistics = paginate statistics, total_count: total_count @statistics = paginate statistics, total_count: total_count
end end

@ -5,7 +5,7 @@ class Admins::SchoolsController < Admins::BaseController
schools = Admins::SchoolQuery.call(params) schools = Admins::SchoolQuery.call(params)
@schools = paginate schools.includes(:user_extensions) @schools = paginate schools
school_ids = @schools.map(&:id) school_ids = @schools.map(&:id)
@department_count = Department.where(school_id: school_ids).group(:school_id).count @department_count = Department.where(school_id: school_ids).group(:school_id).count

@ -0,0 +1,9 @@
class Admins::ShixunModifyRecordsController < Admins::BaseController
def index
records = Admins::ShixunModifyRecordQuery.call(params)
@records = paginate records.includes(:diff_record_content)
end
end

@ -15,7 +15,8 @@ class Admins::ShixunSettingsController < Admins::BaseController
hidden: params[:hidden].present? ? params[:hidden] : false, hidden: params[:hidden].present? ? params[:hidden] : false,
homepage_show: params[:homepage_show].present? ? params[:homepage_show] : false, homepage_show: params[:homepage_show].present? ? params[:homepage_show] : false,
task_pass: params[:task_pass].present? ? params[:task_pass] : false, task_pass: params[:task_pass].present? ? params[:task_pass] : false,
code_hidden: params[:code_hidden].present? ? params[:code_hidden] : false code_hidden: params[:code_hidden].present? ? params[:code_hidden] : false,
vip: params[:vip].present? ? params[:vip] : false
} }
@shixuns_type_check = MirrorRepository.pluck(:type_name,:id) @shixuns_type_check = MirrorRepository.pluck(:type_name,:id)
@ -126,6 +127,6 @@ class Admins::ShixunSettingsController < Admins::BaseController
end end
def setting_params def setting_params
params.permit(:use_scope,:excute_time,:close,:status,:can_copy,:webssh,:hidden,:homepage_show,:task_pass,:code_hidden,:page_no, :id,tag_repertoires:[]) params.permit(:use_scope,:excute_time,:close,:status,:can_copy,:webssh,:hidden,:homepage_show,:task_pass,:code_hidden,:vip,:page_no,:id,tag_repertoires:[])
end end
end end

@ -8,6 +8,9 @@ class Admins::ShixunsController < Admins::BaseController
@pending_shixuns = shixuns.where(status:1).size @pending_shixuns = shixuns.where(status:1).size
@processed_shixuns = shixuns.where(status:2).size @processed_shixuns = shixuns.where(status:2).size
@closed_shixuns = shixuns.where(status:3).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) @shixuns_type_check = MirrorRepository.pluck(:type_name,:id)
@params_page = params[:page] || 1 @params_page = params[:page] || 1
@shixuns = paginate shixuns.preload(:user,:challenges) @shixuns = paginate shixuns.preload(:user,:challenges)

@ -283,7 +283,7 @@ class ApplicationController < ActionController::Base
# 测试版前端需求 # 测试版前端需求
logger.info("subdomain:#{request.subdomain}") logger.info("subdomain:#{request.subdomain}")
if request.subdomain == "test-newweb" if request.subdomain != "www"
if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除 if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除
User.current = User.find 81403 User.current = User.find 81403
elsif params[:debug] == 'student' elsif params[:debug] == 'student'
@ -303,7 +303,7 @@ class ApplicationController < ActionController::Base
current_domain_session = session[:"#{default_yun_session}"] current_domain_session = session[:"#{default_yun_session}"]
if current_domain_session if current_domain_session
# existing 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 elsif autologin_user = try_to_autologin
autologin_user autologin_user
elsif params[:format] == 'atom' && params[:key] && request.get? && accept_rss_auth? elsif params[:format] == 'atom' && params[:key] && request.get? && accept_rss_auth?
@ -465,9 +465,9 @@ class ApplicationController < ActionController::Base
# 实训主类别列表,自带描述 # 实训主类别列表,自带描述
def shixun_main_type def shixun_main_type
list = [] list = []
mirrors = MirrorRepository.select([:id, :type_name, :description]).published_main_mirror mirrors = MirrorRepository.select([:id, :type_name, :description, :name]).published_main_mirror
mirrors.try(:each) do |mirror| mirrors.try(:each) do |mirror|
list << {id: mirror.id, type_name: mirror.type_name, description: mirror.try(:description)} list << {id: mirror.id, type_name: mirror.type_name, description: mirror.try(:description), mirror_name: mirror.name}
end end
list list
end end
@ -475,9 +475,9 @@ class ApplicationController < ActionController::Base
# 小类别列表 # 小类别列表
def shixun_small_type def shixun_small_type
list = [] list = []
mirrors = MirrorRepository.select([:id, :type_name, :description]).published_small_mirror mirrors = MirrorRepository.select([:id, :type_name, :description, :name]).published_small_mirror
mirrors.try(:each) do |mirror| mirrors.try(:each) do |mirror|
list << {id: mirror.id, type_name: mirror.type_name, description: mirror.description} list << {id: mirror.id, type_name: mirror.type_name, description: mirror.description, mirror_name: mirror.name}
end end
list list
end end

@ -18,9 +18,9 @@ class AttachmentsController < ApplicationController
pdf_attachment = params[:disposition] || "attachment" pdf_attachment = params[:disposition] || "attachment"
if pdf_attachment == "inline" if pdf_attachment == "inline"
send_file absolute_path(local_path(@file)),filename: @file.filename, disposition: 'inline',type: 'application/pdf' send_file absolute_path(local_path(@file)),filename: @file.title, disposition: 'inline',type: 'application/pdf'
else else
send_file(absolute_path(local_path(@file)), filename: @file.filename,stream:false, type: @file.content_type.presence || 'application/octet-stream') send_file(absolute_path(local_path(@file)), filename: @file.title,stream:false, type: @file.content_type.presence || 'application/octet-stream')
end end
update_downloads(@file) update_downloads(@file)
end end
@ -28,6 +28,7 @@ class AttachmentsController < ApplicationController
def create def create
# 1. 本地存储 # 1. 本地存储
# 2. 上传到云 # 2. 上传到云
begin
upload_file = params["file"] || params["#{params[:file_param_name]}"] # 这里的file_param_name是为了方便其他插件名称 upload_file = params["file"] || params["#{params[:file_param_name]}"] # 这里的file_param_name是为了方便其他插件名称
uid_logger("#########################file_params####{params["#{params[:file_param_name]}"]}") uid_logger("#########################file_params####{params["#{params[:file_param_name]}"]}")
raise "未上传文件" unless upload_file raise "未上传文件" unless upload_file
@ -57,7 +58,6 @@ class AttachmentsController < ApplicationController
@attachment = Attachment.where(disk_filename: disk_filename, @attachment = Attachment.where(disk_filename: disk_filename,
author_id: current_user.id, author_id: current_user.id,
cloud_url: remote_path).first cloud_url: remote_path).first
if @attachment.blank? if @attachment.blank?
@attachment = Attachment.new @attachment = Attachment.new
@attachment.filename = upload_file.original_filename @attachment.filename = upload_file.original_filename
@ -74,6 +74,10 @@ class AttachmentsController < ApplicationController
end end
render_json render_json
rescue => e
uid_logger_error(e.message)
tip_exception(e.message)
end
end end
def destroy def destroy
@ -196,4 +200,5 @@ class AttachmentsController < ApplicationController
end end
end end
end end
end end

@ -13,6 +13,9 @@ class ChallengesController < ApplicationController
include ShixunsHelper include ShixunsHelper
include ChallengesHelper include ChallengesHelper
# 新建实践题 # 新建实践题
def new def new
@position = @shixun.challenges.count + 1 @position = @shixun.challenges.count + 1
@ -160,6 +163,8 @@ class ChallengesController < ApplicationController
@shixun.increment!(:visits) @shixun.increment!(:visits)
end end
def show def show
@tab = params[:tab].nil? ? 1 : params[:tab].to_i @tab = params[:tab].nil? ? 1 : params[:tab].to_i
challenge_num = @shixun.challenges_count challenge_num = @shixun.challenges_count
@ -173,6 +178,7 @@ class ChallengesController < ApplicationController
# tab 0:过关任务的更新; 1:评测设置的更新; 2:表示参考答案的更新; # tab 0:过关任务的更新; 1:评测设置的更新; 2:表示参考答案的更新;
def update def update
begin
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
tab = params[:tab].to_i tab = params[:tab].to_i
@challenge.update_attributes(challenge_params) @challenge.update_attributes(challenge_params)
@ -231,6 +237,11 @@ class ChallengesController < ApplicationController
end end
end end
rescue => e
logger_error("##update_challenges: ##{e.message}")
tip_exception("更新失败!")
end
end end
# 参考答案的'增,删,改' # 参考答案的'增,删,改'

@ -0,0 +1,175 @@
class CollegesController < ApplicationController
include PaginateHelper
# layout 'college'
before_action :require_login
before_action :check_college_present!
before_action :check_manage_permission!
helper_method :current_school, :current_college
def statistics
# 教师、学生总数
count_statistic = UserExtension.where(school_id: current_school.id)
.select('SUM(IF(identity=0, 1, 0)) AS teachers_count, SUM(IF(identity=1, 1, 0)) AS students_count').first
@teachers_count = count_statistic['teachers_count']
@students_count = count_statistic['students_count']
# 课堂总数
@courses_count = Course.where(school_id: current_school.id, is_delete: 0).where.not(id: 1309).count
# 实训总数
@shixuns_count = Shixun.visible.joins('left join user_extensions on user_extensions.user_id = shixuns.user_id')
.where(user_extensions: { school_id: current_school.id }).count
render json: { teachers_count: @teachers_count, students_count: @students_count, courses_count: @courses_count, shixuns_count: @shixuns_count, school: current_school.name }
end
def shixun_time
time_sum = Game.joins('left join user_extensions on user_extensions.user_id = games.user_id')
.where(user_extensions: { school_id: current_school.id }).sum(:cost_time)
shixun_time_sum = (time_sum / (24 * 60 * 60.0)).ceil
render json: { shixun_time: shixun_time_sum }
end
def shixun_report_count
shixun_report_count = StudentWork.where(work_status: [1, 2]).where('myshixun_id != 0')
.joins('left join user_extensions on user_extensions.user_id = student_works.user_id')
.where(user_extensions: { school_id: current_school.id }).count
render json: { shixun_report_count: shixun_report_count }
end
def teachers
@teachers = User.find_by_sql("SELECT users.id, users.login, users.lastname, users.firstname, users.nickname, IFNULL((SELECT count(shixuns.id) FROM shixuns where shixuns.user_id =users.id group by shixuns.user_id), 0) AS publish_shixun_count,
(SELECT count(c.id) FROM courses c, course_members m WHERE c.id != 1309 and m.course_id = c.id AND m.user_id=users.id AND m.role in (1,2,3) and c.school_id = #{current_school.id} AND c.is_delete = 0) as course_count
FROM `users`, user_extensions ue where ue.school_id=#{current_school.id} and users.id=ue.user_id and ue.identity=0 ORDER BY publish_shixun_count desc, course_count desc, id desc LIMIT 10")
# ).order("publish_shixun_count desc, experience desc").limit(10)
# @teacher_count = UserExtension.where(school_id: current_school.id)
# .select('SUM(IF(identity=0, 1, 0)) AS teachers_count').first.teachers_count
@teachers =
@teachers.map do |teacher|
course_ids = Course.find_by_sql("SELECT c.id FROM courses c, course_members m WHERE c.id != 1309 and m.course_id = c.id AND m.role in (1,2,3) AND m.user_id=#{teacher.id} AND c.is_delete = 0 and c.school_id = #{current_school.id}")
course_count = course_ids.size
homeworks = HomeworkCommon.where(:homework_type => 4, :course_id => course_ids.map(&:id))
un_shixun_work_count = homeworks.where("publish_time > '#{Time.now}' or publish_time is null").count
shixun_work_count = homeworks.size - un_shixun_work_count
student_count = StudentsForCourse.where(:course_id => course_ids.map(&:id)).count
myshixun_ids = StudentWork.select("myshixun_id").where("homework_common_id in (#{homeworks.map(&:id).join(',').strip == "" ? -1 : homeworks.map(&:id).join(',')}) and myshixun_id is not null")
complete_myshixun = Myshixun.select("id").where(:status => 1, :id => myshixun_ids.map(&:myshixun_id)).size
all_myshixun = Myshixun.select("id").where(:id => myshixun_ids.map(&:myshixun_id)).size
complete_rate = all_myshixun == 0 ? 0 : ((complete_myshixun * 100) / all_myshixun).try(:round, 2).to_f
real_name = teacher.show_real_name
teacher = teacher.attributes.dup.merge({
real_name: real_name,
course_count: course_count,
shixun_work_count: shixun_work_count,
un_shixun_work_count: un_shixun_work_count,
student_count: student_count,
complete_rate: complete_rate
}).to_json
JSON.parse(teacher)
end
end
def shixun_chart_data
shixun_ids = HomeworkCommonsShixun.joins(homework_common: :course).where(courses: {school_id: current_school.id, is_delete: 0}).where('courses.id != 1309').pluck('distinct shixun_id')
shixun_count_map = ShixunTagRepertoire.joins(:tag_repertoire).where(shixun_id: shixun_ids).group('tag_repertoires.name').order('count_shixun_id desc').count(:shixun_id)
names = []
data = []
shixun_count_map.each do |name, count|
break if names.size == 9
names << name
data << { value: count, name: name }
end
if shixun_count_map.keys.size > 9
other_count = shixun_count_map.values[9..-1].reduce(:+)
names << 'Others'
data << { name: 'Others', value: other_count }
end
render json: { names: names, data: data }
end
# 在线课堂
def course_statistics
courses = Course.where(school_id: current_school.id, is_delete: 0).where.not(id: 1309)
@course_count = courses.size
courses = courses.left_joins(practice_homeworks: { student_works: { myshixun: :games } })
.select('courses.id, courses.name, courses.is_end, IFNULL(sum(games.evaluate_count), 0) evaluating_count')
.group('courses.id').order('is_end asc, evaluating_count desc')
@courses = paginate courses
course_ids = @courses.map(&:id)
@student_count = StudentsForCourse.where(course_id: course_ids).group(:course_id).count
@shixun_work_count = HomeworkCommon.where(homework_type: 4, course_id: course_ids).group(:course_id).count
@attachment_count = Attachment.where(container_id: course_ids, container_type: 'Course').group(:container_id).count
@message_count = Message.joins(:board).where(boards: { parent_id: 0, course_id: course_ids }).group('boards.course_id').count
@active_time = CourseActivity.where(course_id: course_ids).group(:course_id).maximum(:created_at)
@exercise_count = Exercise.where(course_id: course_ids).group(:course_id).count
@poll_count = Poll.where(course_id: course_ids).group(:course_id).count
@other_work_count = HomeworkCommon.where(homework_type: [1,3], course_id: course_ids).group(:course_id).count
end
# 学生实训
def student_shixun
# @student_count = User.joins(:user_extension).where(user_extensions: { school_id: current_school.id, identity: 1 }).count
@students = User.joins(:user_extension).where(user_extensions: { school_id: current_school.id, identity: 1 }).includes(:user_extension).order('experience desc').limit(10)
student_ids = @students.map(&:id)
@shixun_count = Myshixun.where(user_id: student_ids).group(:user_id).count
@study_shixun_count = Myshixun.where(user_id: student_ids, status: 0).group(:user_id).count
end
def student_hot_evaluations
games = Game.joins(:myshixun).joins('join shixun_tag_repertoires str on str.shixun_id = myshixuns.shixun_id')
games = games.joins('join tag_repertoires tr on tr.id = str.tag_repertoire_id')
games = games.joins("join user_extensions ue on ue.user_id = myshixuns.user_id and ue.school_id = #{current_school.id}")
evaluate_count_map = games.group('tr.name').reorder('sum_games_evaluate_count desc').limit(10).sum('games.evaluate_count')
render json: { names: evaluate_count_map.keys, values: evaluate_count_map.values }
end
private
def require_login
return if User.current.logged?
redirect_to "/login?back_url=#{CGI::escape(request.fullpath)}"
end
def check_college_present!
return if current_college.present?
redirect_to '/404'
end
def check_manage_permission!
return if can_manage_college?
redirect_to '/403'
end
def can_manage_college?
return true if current_user.admin_or_business? # 超级管理员|运营
return true if current_college.is_a?(Department) && current_college.member?(current_user) # 部门管理员
return true if current_user.is_teacher? && current_user.school_id == current_school.id # 学校老师
# return true if current_school.customers.exists? && current_user.partner&.partner_customers&.exists?(customer_id: current_school.customer_id)
false
end
def current_school
current_college.is_a?(School) ? current_college : current_college.school
end
def current_college
@_current_college ||= begin
Department.find_by(identifier: params[:id]) || School.find_by(id: params[:id])
end
end
end

@ -29,7 +29,7 @@ class CoursesController < ApplicationController
:informs, :update_informs, :online_learning, :update_task_position, :tasks_list, :informs, :update_informs, :online_learning, :update_task_position, :tasks_list,
:join_excellent_course, :export_couser_info, :export_member_act_score, :new_informs, :join_excellent_course, :export_couser_info, :export_member_act_score, :new_informs,
:delete_informs, :change_member_role, :course_groups, :join_course_group, :statistics, :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, 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] :search_course_list, :get_historical_course_students, :mine, :search_slim, :board_list]
before_action :teacher_allowed, only: [:update, :destroy, :settings, :search_teacher_candidate, 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 :validate_page_size, only: :mine
before_action :course_tasks, only: [:tasks_list, :update_task_position] before_action :course_tasks, only: [:tasks_list, :update_task_position]
before_action :validate_inform_params, only: [:update_informs, :new_informs] 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/ if RUBY_PLATFORM =~ /linux/
require 'simple_xlsx_reader' require 'simple_xlsx_reader'
@ -1299,8 +1299,10 @@ class CoursesController < ApplicationController
begin begin
@all_members = @course.students @all_members = @course.students
search = params[:search] ? "#{params[:search].strip}" : "" #用户名或学生学号id搜索 search = params[:search] ? "#{params[:search].strip}" : "" #用户名或学生学号id搜索
group_id = params[:group_id] #分班的班级id if params[:group_id].present?
@all_members = @all_members.where(course_group_id: group_id.map(&:to_i)) unless group_id.blank? group_ids = params[:group_id].is_a?(String) ? [params[:group_id].to_i] : params[:group_id].map(&:to_i)
@all_members = @all_members.where(course_group_id: group_ids)
end
unless search.blank? unless search.blank?
@all_members = @all_members.joins(user: [:user_extension]).where('concat(users.lastname, users.firstname) like ? or user_extensions.student_id like ?',"%#{search}%","%#{search}%") @all_members = @all_members.joins(user: [:user_extension]).where('concat(users.lastname, users.firstname) like ? or user_extensions.student_id like ?',"%#{search}%","%#{search}%")
end end
@ -1316,7 +1318,7 @@ class CoursesController < ApplicationController
@c_tasks = @course.graduation_tasks.task_published.order("graduation_tasks.publish_time asc, graduation_tasks.created_at asc") @c_tasks = @course.graduation_tasks.task_published.order("graduation_tasks.publish_time asc, graduation_tasks.created_at asc")
set_export_cookies 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')}" 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", 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, locals: {course_scores:@course_user_scores,shixun_works:@shixun_work_arrays,
@ -1332,6 +1334,16 @@ class CoursesController < ApplicationController
end end
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 def search_slim
courses = current_user.manage_courses.not_deleted.processing courses = current_user.manage_courses.not_deleted.processing

@ -47,26 +47,26 @@ class FilesController < ApplicationController
def bulk_publish def bulk_publish
return normal_status(403, "您没有权限进行操作") if current_user.course_identity(@course) >= 5 return normal_status(403, "您没有权限进行操作") if current_user.course_identity(@course) >= 5
tip_exception("请至少选择一个分班") if params[:group_ids].blank? && @course.course_groups.size != 0 # tip_exception("请至少选择一个分班") if params[:group_ids].blank? && @course.course_groups.size != 0
attachments = @course.attachments.by_ids(@attachment_ids) attachments = @course.attachments.by_ids(@attachment_ids)
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
# 有分班设置时 # 有分班设置时
if @course.course_group_module? && @course.course_groups_count != 0 && params[:group_ids] # if @course.course_group_module? && @course.course_groups_count != 0 && params[:group_ids]
group_ids = params[:group_ids]&.reject(&:blank?) # group_ids = params[:group_ids]&.reject(&:blank?)
charge_group_ids = @course.charge_group_ids(current_user) # charge_group_ids = @course.charge_group_ids(current_user)
publish_groups = charge_group_ids & group_ids if group_ids # publish_groups = charge_group_ids & group_ids if group_ids
#
attachments.each do |atta| # attachments.each do |atta|
if atta.published? && !atta.unified_setting || !atta.published? # if atta.published? && !atta.unified_setting || !atta.published?
create_atta_group_settings atta # create_atta_group_settings atta
atta.update_all(unified_setting: 0) if atta.unified_setting # atta.update_attributes!(unified_setting: 0) if atta.unified_setting
none_publish_settings = atta.attachment_group_settings.where(course_group_id: publish_groups).none_published # none_publish_settings = atta.attachment_group_settings.where(course_group_id: publish_groups).none_published
none_publish_settings.update_all(publish_time: Time.now) # none_publish_settings.update_all(publish_time: Time.now)
end # end
end # end
end # end
# 未发布的资源更新状态 # 未发布的资源更新状态
attachments.where(is_publish: 0).update_all(is_publish: 1, publish_time: Time.now) attachments.where(is_publish: 0).update_all(is_publish: 1, publish_time: Time.now)
@ -140,7 +140,7 @@ class FilesController < ApplicationController
def public_with_course_and_project def public_with_course_and_project
@attachments = Attachment.publiced.simple_columns @attachments = Attachment.publiced.simple_columns
.contains_course_and_project .contains_course_and_project
.includes(:author => :user_extension) .includes(:container, author: :user_extension)
.by_filename_or_user_name(params[:search]) .by_filename_or_user_name(params[:search])
.ordered(sort: 0, sort_type: 'created_on') .ordered(sort: 0, sort_type: 'created_on')
@ -361,15 +361,16 @@ class FilesController < ApplicationController
def publish_params def publish_params
tip_exception("缺少发布参数") if params[:delay_publish].blank? tip_exception("缺少发布参数") if params[:delay_publish].blank?
@unified_setting = 1 @unified_setting = 1
if params[:delay_publish].to_i == 1 && @course.course_group_module? && @course.course_groups_count != 0 # if params[:delay_publish].to_i == 1 && @course.course_group_module? && @course.course_groups_count != 0
tip_exception("分班发布设置不能为空") if params[:group_settings].blank? # tip_exception("分班发布设置不能为空") if params[:group_settings].blank?
min_publish_time = params[:group_settings].pluck(:publish_time).reject(&:blank?).min # min_publish_time = params[:group_settings].pluck(:publish_time).reject(&:blank?).min
max_publish_time = params[:group_settings].pluck(:publish_time).reject(&:blank?).max # max_publish_time = params[:group_settings].pluck(:publish_time).reject(&:blank?).max
tip_exception("分班发布设置不能为空") if min_publish_time.blank? # tip_exception("分班发布设置不能为空") if min_publish_time.blank?
#
# 分班设置中的时间一样且包含所有分班 则按统一设置处理,否则是非统一设置 # # 分班设置中的时间一样且包含所有分班 则按统一设置处理,否则是非统一设置
@unified_setting = 0 unless min_publish_time == max_publish_time && params[:group_settings].pluck(:group_id).flatten.sort == @course.course_groups.pluck(:id).sort # @unified_setting = 0 unless min_publish_time == max_publish_time && params[:group_settings].pluck(:group_id).flatten.sort == @course.course_groups.pluck(:id).sort
elsif params[:delay_publish].to_i == 1 # els
if params[:delay_publish].to_i == 1
tip_exception("缺少延期发布的时间参数") if params[:publish_time].blank? tip_exception("缺少延期发布的时间参数") if params[:publish_time].blank?
min_publish_time = params[:publish_time] min_publish_time = params[:publish_time]
end end

@ -1,15 +1,18 @@
class GamesController < ApplicationController class GamesController < ApplicationController
before_action :require_login, :check_auth before_action :require_login, :check_auth
before_action :find_game before_action :find_game, except: [:jupyter]
before_action :find_shixun, only: [:show, :answer, :rep_content, :choose_build, :game_build, :game_status] before_action :find_shixun, only: [:show, :answer, :rep_content, :choose_build, :game_build, :game_status]
before_action :allowed before_action :allowed, except: [:jupyter]
#require 'iconv' #require 'iconv'
include GamesHelper include GamesHelper
include ApplicationHelper include ApplicationHelper
def show def show
uid_logger("--games show start") uid_logger("--games show start")
# 防止评测中途ajaxE被取消;3改成0是为了处理首次进入下一关的问题 # 防止评测中途ajaxE被取消;3改成0是为了处理首次进入下一关的问题
@ -88,6 +91,22 @@ class GamesController < ApplicationController
end end
end end
def jupyter
# Jupyter没有challenge
@myshixun = Myshixun.find_by_identifier params[:identifier]
unless current_user.id == @myshixun.user_id || current_user.admin_or_business?
raise Educoder::TipException.new(403, "..")
end
@shixun = @myshixun.shixun
# 判断tpm是否修改了
begin
@tpm_modified = @myshixun.repository_is_modified(@shixun.repo_path) # 判断TPM和TPI的版本库是否被改了
rescue
uid_logger("实训平台繁忙繁忙等级81")
end
end
def reset_vnc_link def reset_vnc_link
begin begin
# 删除vnc的pod # 删除vnc的pod

@ -1,13 +1,14 @@
class HackUserLastestCodesController < ApplicationController class HackUserLastestCodesController < ApplicationController
before_action :require_login, except: [:listen_result] before_action :require_login, except: [:listen_result]
before_action :find_my_hack, only: [:show, :code_debug, :code_submit, :update_code, before_action :find_my_hack, only: [:show, :code_debug, :code_submit, :update_code, :sync_code,
:listen_result, :result, :submit_records, :restore_initial_code] :listen_result, :result, :submit_records, :restore_initial_code]
before_action :update_user_hack_status, only: [:code_debug, :code_submit] before_action :update_user_hack_status, only: [:code_debug, :code_submit]
before_action :require_auth_identity, only: [:update_code, :restore_initial_code] before_action :require_auth_identity, only: [:update_code, :restore_initial_code, :sync_code]
before_action :require_manager_identity, only: [:update_code] before_action :require_manager_identity, only: [:update_code]
def show def show
@my_hack.update_attribute(:submit_status, 0) if @my_hack.submit_status == 1 @my_hack.update_attribute(:submit_status, 0) if @my_hack.submit_status == 1
@modify = @my_hack.modify_time.to_i < @hack.hack_codes.first.modify_time.to_i
end end
def update_code def update_code
@ -20,6 +21,11 @@ class HackUserLastestCodesController < ApplicationController
@my_hack.update_attribute(:code, @hack.code) @my_hack.update_attribute(:code, @hack.code)
end end
# 同步代码
def sync_code
@my_hack.update_attributes(code: @hack.code, modify_time: Time.now)
end
# 调试代码 # 调试代码
def code_debug def code_debug
exec_mode = "debug" exec_mode = "debug"
@ -62,6 +68,7 @@ class HackUserLastestCodesController < ApplicationController
# 提交记录详情 # 提交记录详情
def record_detail def record_detail
@hack_user = HackUserCode.find params[:id] @hack_user = HackUserCode.find params[:id]
@my_hack = @hack_user.hack_user_lastest_code
end end
# 接收中间件返回结果接口 # 接收中间件返回结果接口

@ -1,21 +1,23 @@
class HacksController < ApplicationController class HacksController < ApplicationController
before_action :require_login, except: [:index] before_action :require_login, except: [:index]
before_action :find_hack, only: [:edit, :update, :publish, :start, :update_set, :delete_set] before_action :find_hack, only: [:edit, :update, :publish, :start, :update_set, :delete_set, :destroy, :cancel_publish]
before_action :require_teacher_identity, only: [:create, :update_set] before_action :require_teacher_identity, only: [:create]
before_action :require_auth_identity, only: [:update, :edit, :publish, :update_set, :delete_set] before_action :require_auth_identity, only: [:update, :edit, :publish, :update_set, :delete_set, :destroy, :cancel_publish]
# 开启编程,如果第一次开启,创建一条记录,如果已经开启过的话,直接返回标识即可 # 开启编程,如果第一次开启,创建一条记录,如果已经开启过的话,直接返回标识即可
def start def start
# 未发布的编程题,只能作者、或管理员访问 # 未发布的编程题,只能作者、或管理员访问
start_hack_auth start_hack_auth
user_hack = @hack.hack_user_lastest_codes.mine(current_user.id) user_hack = @hack.hack_user_lastest_codes.where(user_id: current_user.id).first
logger.info("#user_hack: #{user_hack}")
identifier = identifier =
if user_hack.present? if user_hack.present?
logger.info("#####user_hack_id:#{user_hack.id}")
user_hack.identifier user_hack.identifier
else else
user_identifier = generate_identifier HackUserLastestCode, 12 user_identifier = generate_identifier HackUserLastestCode, 12
user_code = {user_id: current_user.id, code: @hack.code, user_code = {user_id: current_user.id, code: @hack.code, modify_time: Time.now,
identifier: user_identifier, language: @hack.language} identifier: user_identifier, language: @hack.language}
@hack.hack_user_lastest_codes.create!(user_code) @hack.hack_user_lastest_codes.create!(user_code)
user_identifier user_identifier
@ -47,10 +49,10 @@ class HacksController < ApplicationController
hack.identifier = generate_identifier Hack, 8 hack.identifier = generate_identifier Hack, 8
hack.save! hack.save!
# 创建测试集与代码 # 创建测试集与代码
logger.info("hack_sets_params:#{hack_sets_params}")
logger.info("hack_code_params:#{hack_code_params}")
hack.hack_sets.create!(hack_sets_params) hack.hack_sets.create!(hack_sets_params)
hack.hack_codes.create!(hack_code_params) hack_codes = hack.hack_codes.new(hack_code_params)
hack_codes.modify_time = Time.now
hack_codes.save!
end end
render_ok({identifier: hack.identifier}) render_ok({identifier: hack.identifier})
rescue Exception => e rescue Exception => e
@ -69,7 +71,8 @@ class HacksController < ApplicationController
# 新建 # 新建
@hack.hack_sets.create!(hack_sets_params) @hack.hack_sets.create!(hack_sets_params)
# 更新代码 # 更新代码
@hack.hack_codes.create!(hack_code_params) code_params = params[:hack_codes][:code] != @hack.code ? hack_code_params.merge(modify_time: Time.now) : hack_code_params
@hack.hack_codes.first.update_attributes!(code_params)
end end
render_ok render_ok
rescue Exception => e rescue Exception => e
@ -98,6 +101,12 @@ class HacksController < ApplicationController
render_ok render_ok
end end
# 取消发布
def cancel_publish
@hack.update_attribute(:status, 0)
render_ok
end
# 发布列表 # 发布列表
def unpulished_list def unpulished_list
limit = params[:limit] || 16 limit = params[:limit] || 16
@ -109,6 +118,13 @@ class HacksController < ApplicationController
def edit;end def edit;end
def new;end
def destroy
@hack.destroy
render_ok
end
private private
# 实名认证老师,管理员与运营人员权限 # 实名认证老师,管理员与运营人员权限
def require_teacher_identity def require_teacher_identity

@ -78,7 +78,7 @@ class HomeworkCommonsController < ApplicationController
when '4' when '4'
sql_str = %Q((homework_detail_manuals.comment_status = #{order} and homework_detail_manuals.appeal_time > '#{Time.now}')) sql_str = %Q((homework_detail_manuals.comment_status = #{order} and homework_detail_manuals.appeal_time > '#{Time.now}'))
when '5' when '5'
sql_str = %Q((homework_detail_manuals.comment_status = #{order} or (anonymous_comment = 0 and homework_commons.end_time <= '#{Time.now}'))) sql_str = %Q((anonymous_comment = 0 or (anonymous_comment = 1 and homework_detail_manuals.comment_status = #{order})) and ((allow_late= 0 and homework_commons.end_time <= '#{Time.now}') or (allow_late= 1 and late_time <= '#{Time.now}')))
else else
sql_str = %Q(homework_detail_manuals.comment_status = #{order}) sql_str = %Q(homework_detail_manuals.comment_status = #{order})
end end
@ -167,11 +167,11 @@ class HomeworkCommonsController < ApplicationController
if params[:work_status].present? if params[:work_status].present?
params_work_status = params[:work_status] params_work_status = params[:work_status]
work_status = params_work_status.map{|status| status.to_i} work_status = params_work_status.map{|status| status.to_i}
all_student_works = @student_works.left_joins(:myshixun) if @homework.homework_type == "practice"
@student_works = all_student_works.where(work_status: work_status) @student_works = @student_works.where(compelete_status: work_status)
else
@student_works = @student_works.or(all_student_works.where(work_status: 0)).or(all_student_works.where(myshixuns: {status: 0})) if work_status.include?(3) @student_works = @student_works.where(work_status: work_status)
@student_works = @student_works.or(all_student_works.where(myshixuns: {status: 1})) if work_status.include?(4) end
end end
# 分班情况 # 分班情况
@ -198,7 +198,6 @@ class HomeworkCommonsController < ApplicationController
end end
@work_count = @student_works.size @work_count = @student_works.size
@work_excel = @student_works.where("work_status > 0")
# 排序 # 排序
rorder = params[:order].blank? ? "update_time" : params[:order] rorder = params[:order].blank? ? "update_time" : params[:order]
@ -208,6 +207,7 @@ class HomeworkCommonsController < ApplicationController
elsif rorder == "student_id" elsif rorder == "student_id"
@student_works = @student_works.joins(user: :user_extension).order("user_extensions.#{rorder} #{b_order}") @student_works = @student_works.joins(user: :user_extension).order("user_extensions.#{rorder} #{b_order}")
end end
@work_excel = @student_works
# 分页参数 # 分页参数
page = params[:page] || 1 page = params[:page] || 1
@ -453,7 +453,7 @@ class HomeworkCommonsController < ApplicationController
# 课堂结束后不能再更新 # 课堂结束后不能再更新
unless @course.is_end unless @course.is_end
UpdateHomeworkSettingService.call(@homework, publish_params) UpdateHomeworkPublishSettingService.call(@homework, publish_params)
# 作业未发布时unified_setting参数不能为空 # 作业未发布时unified_setting参数不能为空
=begin =begin
if @homework.publish_time.nil? || @homework.publish_time > Time.now if @homework.publish_time.nil? || @homework.publish_time > Time.now
@ -585,8 +585,8 @@ class HomeworkCommonsController < ApplicationController
tip_exception("缺少answer_open_evaluation参数") if params[:answer_open_evaluation].nil? tip_exception("缺少answer_open_evaluation参数") if params[:answer_open_evaluation].nil?
tip_exception("缺少work_efficiency参数") if params[:work_efficiency].nil? tip_exception("缺少work_efficiency参数") if params[:work_efficiency].nil?
tip_exception("缺少eff_score参数") if params[:work_efficiency] && params[:eff_score].blank? tip_exception("缺少eff_score参数") if params[:work_efficiency] && params[:eff_score].blank?
tip_exception("效率分不能小于等于0") if params[:eff_score] && params[:eff_score].to_f <= 0 tip_exception("效率分不能小于等于0") if params[:work_efficiency] && params[:eff_score] && params[:eff_score].to_f <= 0
tip_exception("效率分不能大于总分值") if params[:eff_score] && params[:eff_score].to_f.round(2) > params[:total_score].to_f.round(2) tip_exception("效率分不能大于总分值") if params[:work_efficiency] && params[:eff_score] && params[:eff_score].to_f.round(2) > params[:total_score].to_f.round(2)
tip_exception("缺少shixun_evaluation参数") if params[:shixun_evaluation].blank? tip_exception("缺少shixun_evaluation参数") if params[:shixun_evaluation].blank?
tip_exception("缺少challenge_settings参数") if params[:challenge_settings].blank? tip_exception("缺少challenge_settings参数") if params[:challenge_settings].blank?
# tip_exception("缺少challenge_id参数") if params[:challenge_settings][:challenge_id].blank? # tip_exception("缺少challenge_id参数") if params[:challenge_settings][:challenge_id].blank?
@ -1501,8 +1501,12 @@ class HomeworkCommonsController < ApplicationController
@user = @student_work.user @user = @student_work.user
tip_exception("当前用户无作品可以显示") if @student_work.nil? tip_exception("当前用户无作品可以显示") if @student_work.nil?
# 查询最新一次的查重标识query_id # 查询最新一次的查重标识query_id
group_id = @course.course_members.where(user_id: params[:user_id]).pluck(:course_group_id).first group_id = @course.students.where(user_id: params[:user_id]).pluck(:course_group_id).first
query_id = @homework.homework_group_reviews.where(:course_group_id => group_id).last.try(:query_id) homework_group_review = @homework.homework_group_reviews.where(:course_group_id => group_id).last || @homework.homework_group_reviews.last
query_id = homework_group_review.try(:query_id)
Rails.logger.info("##################------query_id: #{query_id}")
tip_exception(-1, "query_id有误") unless query_id.present?
results = ReviewService.query_result({user_id: params[:user_id], query_id: query_id}) results = ReviewService.query_result({user_id: params[:user_id], query_id: query_id})
@shixun = @homework.shixuns.take @shixun = @homework.shixuns.take
if results.status == 0 if results.status == 0
@ -1652,7 +1656,7 @@ class HomeworkCommonsController < ApplicationController
end end
def publish_params def publish_params
params.permit(:unified_setting, :publish_time, :end_time, group_settings: []) params.permit(:unified_setting, :publish_time, :end_time, group_settings: [:publish_time, :end_time, group_id: []])
end end
end end

@ -0,0 +1,14 @@
class LibrariesController < ApplicationController
include PaginateHelper
def index
default_sort('updated_at', 'desc')
@items = ItemBankQuery.call(params)
@items = paginate courses.includes(:school, :students, :attachments, :homework_commons, teacher: :user_extension)
end
def create
end
end

@ -0,0 +1,46 @@
class JupytersController < ApplicationController
include JupyterService
before_action :shixun, only: [:open, :open1, :test, :save]
def save_with_tpi
myshixun = Myshixun.find_by(identifier: params[:identifier])
jupyter_save_with_game(myshixun, params[:jupyter_port])
render json: {status: 0}
end
def save_with_tpm
shixun = Shixun.find_by(identifier: params[:identifier])
jupyter_save_with_shixun(shixun, params[:jupyter_port])
render json: {status: 0}
end
def get_info_with_tpi
myshixun = Myshixun.find_by(identifier: params[:identifier])
url = jupyter_url_with_game(myshixun)
port = jupyter_port_with_game(myshixun)
render json: {status: 0, url: url, port: port}
end
def get_info_with_tpm
shixun = Shixun.find_by(identifier: params[:identifier])
url = jupyter_url_with_shixun(shixun)
port = jupyter_port_with_shixun(shixun)
render json: {status: 0, url: url, port: port}
end
def reset_with_tpi
myshixun = Myshixun.find_by(identifier: params[:identifier])
info = jupyter_tpi_reset(myshixun)
render json: {status: 0, url: info[:url], port: info[:port]}
end
def reset_with_tpm
shixun = Shixun.find_by(identifier: params[:identifier])
info = jupyter_tpm_reset(shixun)
render json: {status: 0, url: info[:url], port: info[:port]}
end
end

@ -216,7 +216,9 @@ class MyshixunsController < ApplicationController
begin begin
shixun_tomcat = edu_setting('tomcat_webssh') shixun_tomcat = edu_setting('tomcat_webssh')
uri = "#{shixun_tomcat}/bridge/webssh/getConnectInfo" uri = "#{shixun_tomcat}/bridge/webssh/getConnectInfo"
params = {tpiID:@myshixun.id, podType:@myshixun.shixun.try(:webssh), # 由于中间层采用混合云的方式因为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))} containers:(Base64.urlsafe_encode64(shixun_container_limit @myshixun.shixun))}
res = uri_post uri, params res = uri_post uri, params
if res && res['code'].to_i != 0 if res && res['code'].to_i != 0
@ -245,7 +247,7 @@ class MyshixunsController < ApplicationController
def update_file def update_file
begin begin
@hide_code = Shixun.where(id: @myshixun.shixun_id).pluck(:hide_code).first @hide_code = Shixun.where(id: @myshixun.shixun_id).pluck(:hide_code).first
tip_exception("技术平台为空!") if @myshixun.mirror_name.blank? tip_exception("实验环境不能为空,请查看实训模板的环境配置项是否正确!") if (@myshixun.mirror_name.blank? || @myshixun.mirror_name.first.to_s == "-1")
path = params[:path].strip unless params[:path].blank? path = params[:path].strip unless params[:path].blank?
game_id = params[:game_id] game_id = params[:game_id]
game = Game.find(game_id) game = Game.find(game_id)
@ -364,6 +366,31 @@ class MyshixunsController < ApplicationController
end end
end end
def sync_code
shixun_tomcat = edu_setting('cloud_bridge')
begin
git_myshixun_url = repo_ip_url @myshixun.repo_path
git_shixun_url = repo_ip_url @myshixun.shixun.try(:repo_path)
git_myshixun_url = Base64.urlsafe_encode64(git_myshixun_url)
git_shixun_url = Base64.urlsafe_encode64(git_shixun_url)
# todo: identifier 是以前的密码,用来验证的,新版如果不需要,和中间层协调更改.
params = {tpiID: "#{@myshixun.try(:id)}", tpiGitURL: "#{git_myshixun_url}", tpmGitURL: "#{git_shixun_url}",
identifier: "xinhu1ji2qu3"}
uri = "#{shixun_tomcat}/bridge/game/resetTpmRepository"
res = uri_post uri, params
if (res && res['code'] != 0)
tip_exception("实训云平台繁忙繁忙等级95")
end
shixun_new_commit = GitService.commits(repo_path: @myshixun.shixun.repo_path).first["id"]
@myshixun.update_attributes!(commit_id: shixun_new_commit, reset_time: @myshixun.shixun.try(:reset_time))
# 更新完成后,弹框则隐藏不再提示
@myshixun.update_column(:system_tip, false)
render_ok
rescue Exception => e
tip_exception("立即更新代码失败!#{e.message}")
end
end
# -----End # -----End

@ -1409,16 +1409,21 @@ class PollsController < ApplicationController
poll_questions.each do |q| poll_questions.each do |q|
user_poll_votes = u_user.poll_votes.find_current_vote("poll_question_id",q.id) user_poll_votes = u_user.poll_votes.find_current_vote("poll_question_id",q.id)
if user_poll_votes.present? if user_poll_votes.present?
if q.question_type < 3
user_poll_answer_ids = user_poll_votes.pluck(:poll_answer_id).reject(&:blank?) user_poll_answer_ids = user_poll_votes.pluck(:poll_answer_id).reject(&:blank?)
user_poll_vote_texts = user_poll_votes.pluck(:vote_text).reject(&:blank?)
if user_poll_answer_ids.count > 0 if user_poll_answer_ids.count > 0
answer_content = q.poll_answers.find_answer_by_custom("id",user_poll_answer_ids) answer_content = q.poll_answers.find_answer_by_custom("id",user_poll_answer_ids)
if user_poll_answer_ids.count >1 if user_poll_answer_ids.count >1
u_answer = answer_content.pluck(:answer_text).join(";") u_answer = answer_content.pluck(:answer_text).join(";")
else else
u_answer = answer_content.first.answer_text u_answer = answer_content.first&.answer_text
end
else
u_answer = "--"
end end
elsif user_poll_vote_texts.count > 0 else
user_poll_vote_texts = user_poll_votes.pluck(:vote_text).reject(&:blank?)
if user_poll_vote_texts.count > 0
if user_poll_vote_texts.count > 1 if user_poll_vote_texts.count > 1
u_answer = user_poll_vote_texts.join(";") u_answer = user_poll_vote_texts.join(";")
else else
@ -1427,6 +1432,7 @@ class PollsController < ApplicationController
else else
u_answer = "--" u_answer = "--"
end end
end
else else
u_answer = "--" u_answer = "--"
end end

@ -6,27 +6,28 @@ class ShixunsController < ApplicationController
before_action :require_login, :check_auth, except: [:download_file, :index, :menus, :show, :show_right, :ranking_list, before_action :require_login, :check_auth, except: [:download_file, :index, :menus, :show, :show_right, :ranking_list,
:discusses, :collaborators, :fork_list, :propaedeutics] :discusses, :collaborators, :fork_list, :propaedeutics]
before_action :check_account, only: [:new, :create, :shixun_exec] before_action :check_account, only: [:new, :create, :shixun_exec, :jupyter_exec]
before_action :find_shixun, except: [:index, :new, :create, :menus, :get_recommend_shixuns, before_action :find_shixun, except: [:index, :new, :create, :menus, :get_recommend_shixuns,
:propaedeutics, :departments, :apply_shixun_mirror, :propaedeutics, :departments, :apply_shixun_mirror,
:get_mirror_script, :download_file, :shixun_list, :batch_send_to_course] :get_mirror_script, :download_file, :shixun_list, :batch_send_to_course]
before_action :shixun_access_allowed, except: [:index, :new, :create, :menus, :get_recommend_shixuns, before_action :shixun_access_allowed, except: [:index, :new, :create, :menus, :get_recommend_shixuns,
:propaedeutics, :departments, :apply_shixun_mirror, :propaedeutics, :departments, :apply_shixun_mirror, :jupyter_exec,
:get_mirror_script, :download_file, :shixun_list, :batch_send_to_course] :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 :find_repo_name, only: [:repository, :commits, :file_content, :update_file, :shixun_exec, :copy,
:add_file, :jupyter_exec]
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, :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 :portion_allowed, only: [:copy]
before_action :special_allowed, only: [:send_to_course, :search_user_courses] before_action :special_allowed, only: [:send_to_course, :search_user_courses]
## 获取课程列表 ## 获取课程列表
def index def index
@shixuns = current_laboratory.shixuns.unhidden @shixuns = current_laboratory.shixuns.unhidden.publiced
## 方向 ## 方向
if params[:tag_level].present? && params[:tag_id].present? if params[:tag_level].present? && params[:tag_id].present?
@ -66,15 +67,11 @@ class ShixunsController < ApplicationController
## 排序参数 ## 排序参数
bsort = params[:sort] || 'desc' bsort = params[:sort] || 'desc'
case params[:order_by] || 'publish_time' case params[:order_by] || 'new'
when 'new'
@shixuns = @shixuns.order("shixuns.status = 2 desc, shixuns.created_at #{bsort}")
when 'hot' when 'hot'
@shixuns = @shixuns.order("shixuns.status = 2 desc, shixuns.myshixuns_count #{bsort}") @shixuns = @shixuns.order("shixuns.public = 2 desc, shixuns.myshixuns_count #{bsort}")
when 'mine'
@shixuns = @shixuns.order("shixuns.created_at #{bsort}")
else else
@shixuns = @shixuns.order("shixuns.status = 2 desc, shixuns.publish_time #{bsort}") @shixuns = @shixuns.order("shixuns.public = 2 desc, shixuns.publish_time #{bsort}")
end end
# 用id计数会快10+MS左右,对于搜索的内容随着数据的增加,性能会提升一些。 # 用id计数会快10+MS左右,对于搜索的内容随着数据的增加,性能会提升一些。
@ -168,9 +165,10 @@ class ShixunsController < ApplicationController
def show_right def show_right
owner = @shixun.owner owner = @shixun.owner
#@fans_count = owner.fan_count
#@followed_count = owner.follow_count
@user_own_shixuns = owner.shixuns.published.count @user_own_shixuns = owner.shixuns.published.count
@user_tags = @shixun.user_tags_name(current_user)
@shixun_tags = @shixun.challenge_tags_name
@myshixun = @shixun.myshixuns.find_by(user_id: current_user.id)
end end
# 排行榜 # 排行榜
@ -206,7 +204,7 @@ class ShixunsController < ApplicationController
@new_shixun = Shixun.new @new_shixun = Shixun.new
@new_shixun.attributes = @shixun.attributes.dup.except("id","user_id","visits","gpid","status", "identifier", "averge_star", @new_shixun.attributes = @shixun.attributes.dup.except("id","user_id","visits","gpid","status", "identifier", "averge_star",
"homepage_show","repo_name", "myshixuns_count", "challenges_count", "homepage_show","repo_name", "myshixuns_count", "challenges_count",
"can_copy", "created_at", "updated_at") "can_copy", "created_at", "updated_at", "public")
@new_shixun.user_id = User.current.id @new_shixun.user_id = User.current.id
@new_shixun.averge_star = 5 @new_shixun.averge_star = 5
@new_shixun.identifier = generate_identifier Shixun, 8 @new_shixun.identifier = generate_identifier Shixun, 8
@ -264,7 +262,12 @@ class ShixunsController < ApplicationController
project_fork(@new_shixun, @repo_path, current_user.login) project_fork(@new_shixun, @repo_path, current_user.login)
ShixunMember.create!(:user_id => User.current.id, :shixun_id => @new_shixun.try(:id), :role => 1) ShixunMember.create!(:user_id => User.current.id, :shixun_id => @new_shixun.try(:id), :role => 1)
# 如果是jupyter先创建一个目录,为了挂载(因为后续数据集开启Pod后环境在没销毁前你上传数据集是挂载不上目录的因此要先创建目录方便中间层挂载)
if @new_shixun.is_jupyter?
folder = EduSetting.get('shixun_folder')
path = "#{folder}/#{@new_shixun.identifier}"
FileUtils.mkdir_p(path, :mode => 0777) unless File.directory?(path)
end
# 同步复制关卡 # 同步复制关卡
if @shixun.challenges.present? if @shixun.challenges.present?
@shixun.challenges.each do |challenge| @shixun.challenges.each do |challenge|
@ -343,7 +346,11 @@ class ShixunsController < ApplicationController
#合作者 #合作者
def collaborators def collaborators
@user = current_user @user = current_user
@members = @shixun.shixun_members.includes(:user) ## 分页参数
page = params[:page] || 1
limit = params[:limit] || 10
@member_count = @shixun.shixun_members.count
@members = @shixun.shixun_members.includes(:user).page(page).per(limit)
end end
def fork_list def fork_list
@ -364,73 +371,162 @@ class ShixunsController < ApplicationController
end end
def create def create
# 评测脚本的一些操作 @shixun = CreateShixunService.call(current_user, shixun_params, params)
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
# 保存jupyter到版本库
def update_jupyter
jupyter_save_with_shixun(@shixun, params[:jupyter_port])
end end
ActiveRecord::Base.transaction do def update
# 镜像方面
mirror_ids = MirrorRepository.where(id: params[:main_type])
.or( MirrorRepository.where(id: params[:sub_type])).pluck(:id).uniq
old_mirror_ids = @shixun.shixun_mirror_repositories
.where(mirror_repository_id: params[:main_type])
.or(@shixun.shixun_mirror_repositories.where(mirror_repository_id: params[:sub_type]))
.pluck(:mirror_repository_id).uniq
new_mirror_id = (mirror_ids - old_mirror_ids).map{|id| {mirror_repository_id: id}} # 转换成数组hash方便操作
logger.info("##########new_mirror_id: #{new_mirror_id}")
logger.info("##########old_mirror_ids: #{old_mirror_ids}")
logger.info("##########mirror_ids: #{mirror_ids}")
# 服务配置方面
service_create_params = service_config_params[:shixun_service_configs]
.select{|config| !old_mirror_ids.include?(config[:mirror_repository_id]) &&
MirrorRepository.find(config[:mirror_repository_id]).name.present?}
service_update_params = service_config_params[:shixun_service_configs]
.select{|config| old_mirror_ids.include?(config[:mirror_repository_id])}
logger.info("#########service_create_params: #{service_create_params}")
logger.info("#########service_update_params: #{service_update_params}")
begin begin
@shixun.save! ActiveRecord::Base.transaction do
# shixun_info关联ß @shixun.update_attributes(shixun_params)
ShixunInfo.create!(shixun_id: @shixun.id, evaluate_script: shixun_script, description: params[:description]) @shixun.shixun_info.update_attributes(shixun_info_params)
# 实训的公开范围 # 镜像变动
if params[:scope_partment].present? @shixun.shixun_mirror_repositories.where.not(mirror_repository_id: old_mirror_ids).destroy_all
arr = [] @shixun.shixun_mirror_repositories.create!(new_mirror_id) if new_mirror_id.present?
ids = School.where(:name => params[:scope_partment]).pluck(:id).uniq # 镜像变动要更换服务配置
ids.each do |id| @shixun.shixun_service_configs.where.not(mirror_repository_id: old_mirror_ids).destroy_all
arr << { :school_id => id, :shixun_id => @shixun.id } @shixun.shixun_service_configs.create!(service_create_params) if service_create_params.present?
service_update_params&.map do |service|
smr = @shixun.shixun_service_configs.find_by(mirror_repository_id: service[:mirror_repository_id])
logger.info("########smr: #{smr}")
smr.update_attributes(service) if smr.present?
end
# 添加第二仓库(管理员权限)
if params[:is_secret_repository]
add_secret_repository if @shixun.shixun_secret_repository.blank?
else
# 如果有仓库,就要删
if @shixun.shixun_secret_repository&.repo_name
@shixun.shixun_secret_repository.lock!
GitService.delete_repository(repo_path: @shixun.shixun_secret_repository.repo_path)
@shixun.shixun_secret_repository.destroy
end
end
end
rescue => e
uid_logger_error(e.message)
tip_exception("基本信息更新失败:#{e.message}")
end end
ShixunSchool.create!(arr)
end end
# 实训合作者 # 实训权限设置
@shixun.shixun_members.create!(user_id: current_user.id, role: 1) def update_permission_setting
# 查找需要增删的高校id
school_id = School.where(:name => params[:scope_partment]).pluck(:id)
old_school_ids = @shixun.shixun_schools.pluck(:school_id)
school_params = (school_id - old_school_ids).map{|id| {school_id: id}}
begin
ActiveRecord::Base.transaction do
@shixun.update_attributes!(shixun_params)
@shixun.shixun_schools.where.not(school_id: school_id).destroy_all if school_id.present?
@shixun.shixun_schools.create!(school_params)
end
rescue => e
uid_logger_error("实训权限设置失败--------#{e.message}")
tip_exception("实训权限设置失败")
end
end
# 镜像-实训关联表 # 实训学习页面设置
ShixunMirrorRepository.create!(:shixun_id => @shixun.id, :mirror_repository_id => main_type.to_i) if main_type.present? def update_learn_setting
# 实训主镜像服务配置 begin
ShixunServiceConfig.create!(:shixun_id => @shixun.id, :mirror_repository_id => main_type.to_i) ActiveRecord::Base.transaction do
if sub_type.present? @shixun.update_attributes!(shixun_params)
sub_type.each do |mirror| end
ShixunMirrorRepository.create!(:shixun_id => @shixun.id, :mirror_repository_id => mirror) rescue => e
# 实训子镜像服务配置 uid_logger_error("实训学习页面设置失败--------#{e.message}")
name = MirrorRepository.find_by(id: mirror).try(:name) #查看镜像是否有名称,如果没有名称就不用服务配置 tip_exception("实训学习页面设置失败")
ShixunServiceConfig.create!(:shixun_id => @shixun.id, :mirror_repository_id => mirror) if name.present?
end end
end end
# 创建版本库 # Jupyter数据集
repo_path = repo_namespace(User.current.login, @shixun.identifier) def get_data_sets
GitService.add_repository(repo_path: repo_path) page = params[:page] || 1
# todo: 为什么保存的时候要去除后面的.git呢?? limit = params[:limit] || 10
@shixun.update_column(:repo_name, repo_path.split(".")[0]) data_sets = @shixun.data_sets
@data_count = data_sets.count
@data_sets= data_sets.order("created_on desc").page(page).per(limit)
@absolute_folder = edu_setting('shixun_folder')
end
# 将实训标志为该云上实验室建立 # 实训测试集附件
Laboratory.current.laboratory_shixuns.create!(shixun: @shixun, ownership: true) def upload_data_sets
rescue Exception => e begin
upload_file = params["file"]
raise "未上传文件" unless upload_file
folder = edu_setting('shixun_folder')
raise "存储目录未定义" unless folder.present?
rep_name = @shixun.data_sets.pluck(:filename).include?(upload_file.original_filename)
raise "文件名已经存在\"#{upload_file.original_filename}\", 请删除后再上传" if rep_name
tpm_folder = params[:identifier] # 这个是实训的identifier
save_path = File.join(folder, tpm_folder)
ext = file_ext(upload_file.original_filename)
local_path, digest = file_save_to_local(save_path, upload_file.tempfile, ext)
content_type = upload_file.content_type.presence || 'application/octet-stream'
disk_filename = local_path[save_path.size + 1, local_path.size]
@attachment = Attachment.where(disk_filename: disk_filename,
author_id: current_user.id).first
if @attachment.blank?
@attachment = Attachment.new
@attachment.filename = upload_file.original_filename
@attachment.disk_filename = local_path[save_path.size + 1, local_path.size]
@attachment.filesize = upload_file.tempfile.size
@attachment.content_type = content_type
@attachment.digest = digest
@attachment.author_id = current_user.id
@attachment.disk_directory = tpm_folder
@attachment.container_id = @shixun.id
@attachment.container_type = @shixun.class.name
@attachment.attachtype = 2
@attachment.save!
else
logger.info "文件已存在id = #{@attachment.id}, filename = #{@attachment.filename}"
end
render_ok
rescue => e
uid_logger_error(e.message) uid_logger_error(e.message)
tip_exception("实训创建失败") tip_exception(e.message)
raise ActiveRecord::Rollback end
end
# 多文件删除
def destroy_data_sets
files = Attachment.where(id: params[:id])
shixun_folder= edu_setting("shixun_folder")
begin
files.each do |file|
file_path = "#{shixun_folder}/#{file.relative_path_filename}"
delete_file(file_path)
end end
files.destroy_all
render_ok
rescue => e
uid_logger_error(e.message)
tip_exception(e.message)
end end
end end
@ -462,61 +558,6 @@ class ShixunsController < ApplicationController
tip_exception("申请失败") tip_exception("申请失败")
end 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)
@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信息的配置
# 如果镜像改动了,则也需要更改
mirror = @shixun.shixun_service_configs.map(&:mirror_repository_id).sort
new_mirror = params[:shixun_service_configs].map{|c| c[:mirror_repository_id]}.sort
if current_user.admin? || current_user.business? || (mirror != new_mirror)
@shixun.shixun_service_configs.destroy_all
service_config_params[:shixun_service_configs].each do |config|
name = MirrorRepository.find_by_id(config[:mirror_repository_id])&.name
# 不保存没有镜像的配置
@shixun.shixun_service_configs.create!(config) if name.present?
end
end
# 添加第二仓库
if params[:is_secret_repository]
add_secret_repository if @shixun.shixun_secret_repository.blank?
else
# 如果有仓库,就要删
if @shixun.shixun_secret_repository&.repo_name
@shixun.shixun_secret_repository.lock!
GitService.delete_repository(repo_path: @shixun.shixun_secret_repository.repo_path)
@shixun.shixun_secret_repository.destroy
end
end
rescue Exception => e
uid_logger_error("实训保存失败--------#{e.message}")
tip_exception("实训保存失败")
raise ActiveRecord::Rollback
end
end
end
# 永久关闭实训 # 永久关闭实训
def close def close
@ -552,6 +593,8 @@ class ShixunsController < ApplicationController
# @evaluate_scirpt = @shixun.evaluate_script || "无" # @evaluate_scirpt = @shixun.evaluate_script || "无"
end end
# 获取脚本内容 # 获取脚本内容
def get_script_contents def get_script_contents
mirrir_script = MirrorScript.find(params[:script_id]) mirrir_script = MirrorScript.find(params[:script_id])
@ -708,116 +751,45 @@ class ShixunsController < ApplicationController
end end
end end
# def shixun_exec # jupyter开启挑战
# if is_shixun_opening? def jupyter_exec
# tip_show_exception(-3, "#{@shixun.opening_time.strftime('%Y-%m-%d %H:%M:%S')}") begin
# end if is_shixun_opening?
# current_myshixun = @shixun.current_myshixun(current_user.id) tip_show_exception(-3, "#{@shixun.opening_time.strftime('%Y-%m-%d %H:%M:%S')}")
# end
# min_challenges = @shixun.challenges.pluck(:id , :st) current_myshixun = @shixun.current_myshixun(current_user.id)
# # 因为读写分离有延迟所以如果是重置来的请求可以先跳过重置过来的params[:reset]为1 if current_myshixun
# if current_myshixun && params[:reset] != "1" @myshixun = current_myshixun
# games = current_myshixun.games else
# # 如果TPM和TPI的管卡数不相等或者关卡顺序错了说明实训被极大的改动需要重置,实训发布前打过的实训都需要重置 commit = GitService.commits(repo_path: @repo_path).try(:first)
# if is_shixun_reset?(games, min_challenges, current_myshixun) uid_logger("First comit########{commit}")
# # 这里页面弹框要收到 当前用户myshixun的identifier. tip_exception("开启挑战前请先在Jupyter中填写内容") if commit.blank?
# tip_show_exception("/myshixuns/#{current_myshixun.try(:identifier)}/reset_my_game") commit_id = commit["id"]
# end cloud_bridge = edu_setting('cloud_bridge')
# myshixun_identifier = generate_identifier Myshixun, 10
# ActiveRecord::Base.transaction do
# if current_myshixun.repo_name.nil? @myshixun = @shixun.myshixuns.create!(user_id: current_user.id, identifier: myshixun_identifier,
# g = Gitlab.client modify_time: @shixun.modify_time, reset_time: @shixun.reset_time,
# repo_name = g.project(current_myshixun.gpid).try(:path_with_namespace) onclick_time: Time.now, commit_id: commit_id)
# current_myshixun.update_column(:repo_name, repo_name) # fork仓库
# end project_fork(@myshixun, @repo_path, current_user.login)
# rep_url = Base64.urlsafe_encode64(repo_ip_url @repo_path)
# # 如果存在实训,则直接进入实训 uri = "#{cloud_bridge}/bridge/game/openGameInstance"
# # 如果实训允许跳关传参params[:challenge_id]跳入具体的关卡 params = {tpiID: "#{@myshixun.id}", tpmGitURL: rep_url, tpiRepoName: @myshixun.repo_name.split("/").last}
# @current_task = interface_post uri, params, 83, "实训云平台繁忙繁忙等级83"
# if params[:challenge_id] end
# game = games.where(challenge_id: params[:challenge_id]).take end
# if @shixun.task_pass || game.status != 3 rescue => e
# game uid_logger_error(e.message)
# else tip_exception("#{e.message}")
# current_myshixun.current_task(games) end
# end 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 def publish
@status = 0 @status = 0
@position = [] @position = []
begin begin
unless @shixun.is_jupyter?
if @shixun.challenges.count == 0 if @shixun.challenges.count == 0
@status = 4 @status = 4
else else
@ -836,24 +808,27 @@ class ShixunsController < ApplicationController
end end
end end
end end
end
if @status == 0 if @status == 0
@shixun.update_attributes!(:status => 1) @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 apply = ApplyAction.where(:container_type => "ApplyShixun", :container_id => @shixun.id).order("created_at desc").first
if apply && apply.status == 0 if apply && apply.status == 0
@status = 0 @status = 0
else else
ApplyAction.create(:container_type => "ApplyShixun", :container_id => @shixun.id, :user_id => current_user.id, :status => 0) 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
end end
rescue Exception => e normal_status(0, "申请成功")
logger.error("pushlish game #{e}")
end
end end
# 设置私密版本库的在tpm中的目录 # 设置私密版本库的在tpm中的目录
@ -993,14 +968,24 @@ class ShixunsController < ApplicationController
:disposition => 'attachment' #inline can open in browser :disposition => 'attachment' #inline can open in browser
end end
# 撤销发布 # 撤销申请公开
def cancel_publish def cancel_apply_public
tip_exception("实训已经发布,无法撤销") if @shixun.status == 2 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 apply = ApplyAction.where(:container_type => "ApplyShixun", :container_id => @shixun.id).order("created_at desc").first
if apply && apply.status == 0 if apply && apply.status == 0
apply.update_attribute(:status, 3) apply.update_attributes!(status: 3)
apply.tidings.destroy_all apply.tidings&.destroy_all
end end
@shixun.update_column(:public, 0)
end
normal_status(0, "成功撤销申请")
end
# 撤销发布
def cancel_publish
tip_exception("请先撤销申请公开,再撤销发布") if @shixun.public == 1
tip_exception("实训已经公开,无法撤销") if @shixun.public == 2
@shixun.update_column(:status, 0) @shixun.update_column(:status, 0)
end end
@ -1021,10 +1006,9 @@ class ShixunsController < ApplicationController
private private
def shixun_params def shixun_params
raise("实训名称不能为空") if params[:shixun][:name].blank?
params.require(:shixun).permit(:name, :trainee, :webssh, :can_copy, :use_scope, :vnc, :test_set_permission, 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, :task_pass, :multi_webssh, :opening_time, :mirror_script_id, :code_hidden,
:hide_code, :forbid_copy, :vnc_evaluate, :code_edit_permission) :hide_code, :forbid_copy, :vnc_evaluate, :code_edit_permission, :is_jupyter)
end end
def validate_review_shixun_params def validate_review_shixun_params
@ -1033,8 +1017,6 @@ private
end end
def shixun_info_params 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) params.require(:shixun_info).permit(:description, :evaluate_script)
end end
@ -1102,4 +1084,47 @@ private
ShixunSecretRepository.create!(repo_name: repo_path.split(".")[0], shixun_id: @shixun.id) ShixunSecretRepository.create!(repo_name: repo_path.split(".")[0], shixun_id: @shixun.id)
end end
def file_save_to_local(save_path, temp_file, ext)
unless Dir.exists?(save_path)
FileUtils.mkdir_p(save_path) ##不成功这里会抛异常
end
digest = md5_file(temp_file)
digest = "#{digest}_#{(Time.now.to_f * 1000).to_i}"
local_file_path = File.join(save_path, digest) + ext
save_temp_file(temp_file, local_file_path)
[local_file_path, digest]
end
def save_temp_file(temp_file, save_file_path)
File.open(save_file_path, 'wb') do |f|
temp_file.rewind
while (buffer = temp_file.read(8192))
f.write(buffer)
end
end
end
def file_ext(file_name)
ext = ''
exts = file_name.split(".")
if exts.size > 1
ext = ".#{exts.last}"
end
ext
end
def delete_file(file_path)
File.delete(file_path) if File.exist?(file_path)
end
def md5_file(temp_file)
md5 = Digest::MD5.new
temp_file.rewind
while (buffer = temp_file.read(8192))
md5.update(buffer)
end
md5.hexdigest
end
end end

@ -529,8 +529,8 @@ class StudentWorksController < ApplicationController
@echart_data = student_efficiency(@homework, @work) @echart_data = student_efficiency(@homework, @work)
@myself_eff = @echart_data[:efficiency_list].find { |item| item.last == @user.id } @myself_eff = @echart_data[:efficiency_list].find { |item| item.last == @user.id }
@myself_consume = @echart_data[:consume_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_ = "#{@user&.student_id}_#{@user&.real_name}_#{@shixun&.name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}.pdf"
filename = Base64.urlsafe_encode64(filename_.strip) filename = filename_.strip.tr("+/", "-_")
stylesheets = %w(shixun_work/shixun_work.css shared/codemirror.css) stylesheets = %w(shixun_work/shixun_work.css shared/codemirror.css)
if params[:export].present? && params[:export] if params[:export].present? && params[:export]
normal_status(0,"正在下载中") normal_status(0,"正在下载中")
@ -559,6 +559,7 @@ class StudentWorksController < ApplicationController
if @work.work_status == 0 if @work.work_status == 0
@work.work_status = 1 @work.work_status = 1
@work.commit_time = Time.now @work.commit_time = Time.now
@work.compelete_status = 1 if @homework.homework_type == "practice"
# 分组作业更新分组id # 分组作业更新分组id
@work.group_id = @homework.max_group_id if @homework.homework_type == "group" @work.group_id = @homework.max_group_id if @homework.homework_type == "group"
end end
@ -739,7 +740,8 @@ class StudentWorksController < ApplicationController
comment: comment) comment: comment)
challenge_score.create_tiding current_user.id challenge_score.create_tiding current_user.id
if @work.work_status != 0 && @work.myshixun if @work.work_status != 0 && @work.myshixun
HomeworksService.new.update_myshixun_work_score @work, @work.myshixun, @work.myshixun&.games, @homework, @homework.homework_challenge_settings games = @work.myshixun.games.where(challenge_id: @homework.homework_challenge_settings.pluck(:challenge_id))
HomeworksService.new.update_myshixun_work_score @work, @work.myshixun, games, @homework, @homework.homework_challenge_settings
else else
update_none_commit_work @work, @homework update_none_commit_work @work, @homework
end end
@ -877,6 +879,7 @@ class StudentWorksController < ApplicationController
def update_none_commit_work work, homework def update_none_commit_work work, homework
if work.work_status == 0 if work.work_status == 0
work.work_status = 1 work.work_status = 1
work.compelete_status = 1
work.commit_time = homework.end_time work.commit_time = homework.end_time
work.update_time = Time.now work.update_time = Time.now
end end

@ -204,7 +204,7 @@ class SubjectsController < ApplicationController
def add_shixun_to_stage def add_shixun_to_stage
identifier = generate_identifier Shixun, 8 identifier = generate_identifier Shixun, 8
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
@shixun = Shixun.create!(name: params[:name], user_id: current_user.id, identifier: identifier) @shixun = Shixun.create!(name: params[:name], user_id: current_user.id, identifier: identifier, is_jupyter: params[:is_jupyter])
# 添加合作者 # 添加合作者
@shixun.shixun_members.create!(user_id: current_user.id, role: 1) @shixun.shixun_members.create!(user_id: current_user.id, role: 1)
# 创建长字段 # 创建长字段

@ -1,5 +1,6 @@
class Users::AuthenticationAppliesController < Users::BaseAccountController class Users::AuthenticationAppliesController < Users::BaseAccountController
before_action :private_user_resources! before_action :private_user_resources!
before_action :check_account, only: [:create]
def create def create
Users::ApplyAuthenticationService.call(observed_user, create_params) Users::ApplyAuthenticationService.call(observed_user, create_params)

@ -1,5 +1,6 @@
class Users::ProfessionalAuthAppliesController < Users::BaseAccountController class Users::ProfessionalAuthAppliesController < Users::BaseAccountController
before_action :private_user_resources! before_action :private_user_resources!
before_action :check_account, only: [:create]
def create def create
Users::ApplyProfessionalAuthService.call(observed_user, create_params) Users::ApplyProfessionalAuthService.call(observed_user, create_params)

@ -6,7 +6,7 @@ class Weapps::CoursesController < Weapps::BaseController
before_action :teacher_or_admin_allowed, only: [:change_member_roles, :delete_course_teachers] before_action :teacher_or_admin_allowed, only: [:change_member_roles, :delete_course_teachers]
def create def create
return render_error("只有老师身份才能创建课堂") unless current_user.is_teacher? # return render_error("只有老师身份才能创建课堂") unless current_user.is_teacher?
course = Course.new(tea_id: current_user.id) course = Course.new(tea_id: current_user.id)
Weapps::CreateCourseService.call(course, course_params) Weapps::CreateCourseService.call(course, course_params)
render_ok render_ok
@ -93,8 +93,8 @@ class Weapps::CoursesController < Weapps::BaseController
end end
if course_group_id.present? if course_group_id.present?
course_group = CourseGroup.find(course_group_id) if course_group_id != 0 @course_group = CourseGroup.find(course_group_id) if course_group_id != 0
@students = @students.where(course_group_id: course_group&.id.to_i) @students = @students.where(course_group_id: @course_group&.id.to_i)
end end
@students_count = @students.size @students_count = @students.size
@ -107,7 +107,7 @@ class Weapps::CoursesController < Weapps::BaseController
# 批量修改角色 # 批量修改角色
def change_member_roles def change_member_roles
@course = current_course @course = current_course
tip_exception("请至少选择一个角色") if params[:roles].blank? tip_exception("请至少选择一个角色") if params[:roles].reject(&:blank?).blank?
tip_exception("不能具有老师、助教两种角色") if params[:roles].include?("PROFESSOR") && params[:roles].include?("ASSISTANT_PROFESSOR") tip_exception("不能具有老师、助教两种角色") if params[:roles].include?("PROFESSOR") && params[:roles].include?("ASSISTANT_PROFESSOR")
params[:user_ids].each do |user_id| params[:user_ids].each do |user_id|
@ -150,13 +150,13 @@ class Weapps::CoursesController < Weapps::BaseController
new_student.is_active = 0 if correspond_teacher_exist new_student.is_active = 0 if correspond_teacher_exist
new_student.save! new_student.save!
CourseAddStudentCreateWorksJob.perform_later(@course.id, user_id) CourseAddStudentCreateWorksJob.perform_later(@course.id, [user_id])
# StudentJoinCourseNotifyJob.perform_later(current_user.id, course.id) # StudentJoinCourseNotifyJob.perform_later(current_user.id, course.id)
elsif !params[:roles].include?("STUDENT") && student_member.present? elsif !params[:roles].include?("STUDENT") && student_member.present?
# 删除学生身份时激活老师身份 # 删除学生身份时激活老师身份
teacher_member.update_attributes!(is_active: 1) if student_member.is_active && teacher_member.present? teacher_member.update_attributes!(is_active: 1) if student_member.is_active && teacher_member.present?
student_member.destroy! student_member.destroy!
CourseDeleteStudentDeleteWorksJob.perform_later(@course.id, user_id) CourseDeleteStudentDeleteWorksJob.perform_later(@course.id, [user_id])
# CourseDeleteStudentNotifyJob.perform_later(@course.id, [params[:user_id]], current_user.id) # CourseDeleteStudentNotifyJob.perform_later(@course.id, [params[:user_id]], current_user.id)
elsif params[:roles].include?("STUDENT") && student_member.present? && !params[:roles].include?("PROFESSOR") && !params[:roles].include?("ASSISTANT_PROFESSOR") elsif params[:roles].include?("STUDENT") && student_member.present? && !params[:roles].include?("PROFESSOR") && !params[:roles].include?("ASSISTANT_PROFESSOR")
# 学生身份存在且学生没有教师身份时更新is_active # 学生身份存在且学生没有教师身份时更新is_active
@ -167,6 +167,15 @@ class Weapps::CoursesController < Weapps::BaseController
normal_status(0, "修改成功") normal_status(0, "修改成功")
end end
# 分班列表
def course_groups
@course_groups = @course.course_groups
@course_groups = @course_groups.where("name like ?", "%#{params[:search]}%") unless params[:search].blank?
@all_group_count = @course_groups.size
@teachers = @course.teachers.includes(:user, :teacher_course_groups) if @user_course_identity < Course::NORMAL
@current_group_id = @course.students.where(user_id: current_user.id).take&.course_group_id if @user_course_identity == Course::STUDENT
end
private private
def course_params def course_params

@ -6,8 +6,9 @@ class Weapps::HomeworkCommonsController < Weapps::BaseController
def update_settings def update_settings
begin begin
# 课堂结束后不能再更新 # 课堂结束后不能再更新
if @course.is_end unless @course.is_end
UpdateHomeworkSettingService.call(@homework, publish_params) UpdateHomeworkPublishSettingService.call(@homework, publish_params)
render_ok
else else
tip_exception("课堂已结束不能再更新") tip_exception("课堂已结束不能再更新")
end end
@ -31,7 +32,7 @@ class Weapps::HomeworkCommonsController < Weapps::BaseController
end end
def publish_params def publish_params
params.permit(:unified_setting, :publish_time, :end_time, group_settings: []) params.permit(:unified_setting, :publish_time, :end_time, group_settings: [:publish_time, :end_time, group_id: []])
end end
end end

@ -3,5 +3,5 @@ class Users::UpdatePasswordForm
attr_accessor :password, :old_password attr_accessor :password, :old_password
validates :password, presence: true validates :password, presence: true, length: { minimum: 8, maximum: 16 }, format: { with: CustomRegexp::PASSWORD, message: "8~16位密码支持字母数字和符号" }
end end

@ -210,7 +210,7 @@ module ApplicationHelper
# 普通/分组 作业作品状态数组 # 普通/分组 作业作品状态数组
def student_work_status homework, user_id, course, work def student_work_status homework, user_id, course, work
status = [] status = []
homework_setting = homework.homework_group_setting user_id homework_setting = homework.homework_group_setting user_id, true
work = work || StudentWork.create(homework_common_id: homework.id, user_id: user_id) work = work || StudentWork.create(homework_common_id: homework.id, user_id: user_id)
late_time = homework.late_time || course.end_date late_time = homework.late_time || course.end_date

@ -4,4 +4,7 @@ module ChallengesHelper
str.gsub(/\A\r/, "\r\r") str.gsub(/\A\r/, "\r\r")
end end
end end

@ -22,21 +22,21 @@ module ExportHelper
end end
end end
shixun_homeworks = shixun_homeworks&.includes(score_student_works: :user) shixun_homeworks = shixun_homeworks&.includes(:student_works)
common_homeworks = homeworks.search_homework_type(1) #全部普通作业 common_homeworks = homeworks.search_homework_type(1) #全部普通作业
common_titles = common_homeworks.pluck(:name)+ ["总得分"] common_titles = common_homeworks.pluck(:name)+ ["总得分"]
common_homeworks = common_homeworks&.includes(score_student_works: :user) common_homeworks = common_homeworks&.includes(:student_works)
group_homeworks = homeworks.search_homework_type(3) #全部分组作业 group_homeworks = homeworks.search_homework_type(3) #全部分组作业
group_titles = group_homeworks.pluck(:name)+ ["总得分"] group_titles = group_homeworks.pluck(:name)+ ["总得分"]
group_homeworks = group_homeworks&.includes(score_student_works: :user) group_homeworks = group_homeworks&.includes(:student_works)
task_titles = tasks.pluck(:name) + ["总得分"] task_titles = tasks.pluck(:name) + ["总得分"]
tasks = tasks&.includes(user: :user_extension, score_graduation_works: :user) tasks = tasks&.includes(:graduation_works)
exercise_titles = exercises.pluck(:exercise_name) + ["总得分"] exercise_titles = exercises.pluck(:exercise_name) + ["总得分"]
exercises = exercises&.includes(user: :user_extension, score_exercise_users: :user) exercises = exercises&.includes(:exercise_users)
total_user_score_array = [] #学生总成绩集合 total_user_score_array = [] #学生总成绩集合
@ -67,7 +67,7 @@ module ExportHelper
#实训作业 #实训作业
if shixun_homeworks.size > 0 if shixun_homeworks.size > 0
shixun_homeworks.each do |s| shixun_homeworks.each do |s|
user_student_work = s.score_student_works.select{|work| work.user_id == user.id}.first #当前用户的对该作业的回答 user_student_work = s.student_works.select{|work| work.user_id == user.id}.first #当前用户的对该作业的回答
if user_student_work.nil? if user_student_work.nil?
h_score = 0.0 #该作业的得分为0 h_score = 0.0 #该作业的得分为0
else else
@ -82,7 +82,7 @@ module ExportHelper
#普通作业 #普通作业
if common_homeworks.size > 0 if common_homeworks.size > 0
common_homeworks.each do |c| common_homeworks.each do |c|
user_student_work_1 = c.score_student_works.select{|work| work.user_id == user.id}.first #当前用户的对该作业的回答 user_student_work_1 = c.student_works.select{|work| work.user_id == user.id}.first #当前用户的对该作业的回答
if user_student_work_1.nil? if user_student_work_1.nil?
h_score_1 = 0.0 #该作业的得分为0 h_score_1 = 0.0 #该作业的得分为0
else else
@ -97,7 +97,7 @@ module ExportHelper
#分组作业 #分组作业
if group_homeworks.size > 0 if group_homeworks.size > 0
group_homeworks.each do |g| group_homeworks.each do |g|
user_student_work_3 = g.score_student_works.select{|work| work.user_id == user.id}.first #当前用户的对该作业的回答 user_student_work_3 = g.student_works.select{|work| work.user_id == user.id}.first #当前用户的对该作业的回答
if user_student_work_3.nil? if user_student_work_3.nil?
h_score_3 = 0.0 #该作业的得分为0 h_score_3 = 0.0 #该作业的得分为0
else else
@ -112,7 +112,7 @@ module ExportHelper
#毕设作业 #毕设作业
if tasks.size > 0 if tasks.size > 0
tasks.each do |task| tasks.each do |task|
graduation_work = task.score_graduation_works.select{|work| work.user_id == user.id}.first graduation_work = task.graduation_works.select{|work| work.user_id == user.id}.first
if graduation_work.nil? if graduation_work.nil?
t_score = 0.0 t_score = 0.0
else else
@ -127,7 +127,7 @@ module ExportHelper
#试卷 #试卷
if exercises.size > 0 if exercises.size > 0
exercises.each do |ex| exercises.each do |ex|
exercise_work = ex.score_exercise_users.select{|work| work.user_id == user.id}.first exercise_work = ex.exercise_users.select{|work| work.user_id == user.id}.first
if exercise_work.nil? if exercise_work.nil?
e_score = 0.0 e_score = 0.0
else else
@ -163,9 +163,12 @@ module ExportHelper
count_2 = common_homeworks.size count_2 = common_homeworks.size
count_3 = group_homeworks.size count_3 = group_homeworks.size
count_4 = tasks.size count_4 = tasks.size
all_user_ids = all_members.pluck(:user_id)
#实训作业 #实训作业
shixun_homeworks.each_with_index do |s,index| shixun_homeworks.each_with_index do |s,index|
all_student_works = s.score_student_works #该实训题的全部用户回答 all_student_works = s.student_works.where(user_id: all_user_ids) #该实训题的全部用户回答
title_no = index.to_i + 1 title_no = index.to_i + 1
student_work_to_xlsx(all_student_works,s) student_work_to_xlsx(all_student_works,s)
shixun_work_display_name = format_sheet_name (title_no.to_s + "." + s.name).strip.first(30) 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| common_homeworks.each_with_index do |c,index|
all_student_works = c.score_student_works #当前用户的对该作业的回答 all_student_works = c.student_works.where(user_id: all_user_ids) #当前用户的对该作业的回答
title_no = count_1 + index.to_i + 1 title_no = count_1 + index.to_i + 1
student_work_to_xlsx(all_student_works,c) student_work_to_xlsx(all_student_works,c)
@ -187,7 +190,7 @@ module ExportHelper
#分组作业 #分组作业
group_homeworks.each_with_index do |c,index| group_homeworks.each_with_index do |c,index|
all_student_works = c.score_student_works #当前用户的对该作业的回答 all_student_works = c.student_works.where(user_id: all_user_ids) #当前用户的对该作业的回答
title_no = count_1 + count_2 + index.to_i + 1 title_no = count_1 + count_2 + index.to_i + 1
student_work_to_xlsx(all_student_works,c) student_work_to_xlsx(all_student_works,c)
work_name = format_sheet_name (title_no.to_s + "." + c.name).strip.first(30) 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| tasks.each_with_index do |c,index|
all_student_works = c.score_graduation_works #当前用户的对该作业的回答 all_student_works = c.graduation_works.where(user_id: all_user_ids) #当前用户的对该作业的回答
title_no = count_1 + count_2 + count_3 + index.to_i + 1 title_no = count_1 + count_2 + count_3 + index.to_i + 1
graduation_work_to_xlsx(all_student_works,c,current_user) graduation_work_to_xlsx(all_student_works,c,current_user)
work_name = format_sheet_name (title_no.to_s + "." + c.name).strip.first(30) 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| exercises.each_with_index do |c,index|
all_student_works = c.score_exercise_users #当前用户的对该作业的回答 all_student_works = c.exercise_users.where(user_id: all_user_ids) #当前用户的对该作业的回答
title_no = count_1 + count_2 + count_3 + count_4 + index.to_i + 1 title_no = count_1 + count_2 + count_3 + count_4 + index.to_i + 1
get_export_users(c,course,all_student_works) get_export_users(c,course,all_student_works)
work_name = format_sheet_name (title_no.to_s + "." + c.exercise_name).strip.first(30) work_name = format_sheet_name (title_no.to_s + "." + c.exercise_name).strip.first(30)
@ -426,7 +429,7 @@ module ExportHelper
end end
else #实训题 else #实训题
shixun = homework.shixuns.take shixun = homework.shixuns.take
shixun_head_cells = %w(完成情况 通关时间 学员在EduCoder做实训花费的时间 总评测次数 获得经验值 关卡得分) shixun_head_cells = %w(截止前完成关卡 通关时间 学员在EduCoder做实训花费的时间 总评测次数 获得经验值 关卡得分)
eff_boolean = homework.work_efficiency eff_boolean = homework.work_efficiency
if eff_boolean if eff_boolean
eff_score_cell = ["效率分"] eff_score_cell = ["效率分"]
@ -452,16 +455,18 @@ module ExportHelper
course_name = course.students.find_by(user_id: w.user_id).try(:course_group_name) course_name = course.students.find_by(user_id: w.user_id).try(:course_group_name)
w_5 = course_name.present? ? course_name : "--" w_5 = course_name.present? ? course_name : "--"
#0 未提交, 1 按时提交, 2 延迟提交 #0 未提交, 1 按时提交, 2 延迟提交
if w.work_status == 0 if w.compelete_status == 0
w_6 = "未提交" w_6 = "未开启"
elsif w.work_status == 1 elsif w.compelete_status == 1
w_6 = "按时提交" w_6 = "未通关"
elsif w.work_status == 2 elsif w.compelete_status == 2
w_6 = "延迟提交" w_6 = "按时通关"
elsif w.compelete_status == 3
w_6 = "迟交通关"
else else
w_6 = "--" w_6 = "--"
end end
w_7 = w.work_status == 0 ? '--' : myshixun.try(:passed_count).to_s+"/"+shixun.challenges_count.to_s w_7 = myshixun&.time_passed_count(homework.homework_group_setting(w.user_id)&.end_time).to_i.to_s+"/"+shixun.challenges_count.to_s
w_8 = myshixun ? myshixun.try(:passed_time).to_s == "--" ? "--" : format_time(myshixun.try(:passed_time)) : "--" # 通关时间 w_8 = myshixun ? myshixun.try(:passed_time).to_s == "--" ? "--" : format_time(myshixun.try(:passed_time)) : "--" # 通关时间
w_9 = myshixun ? (myshixun.try(:passed_count).to_i > 0 ? myshixun.total_spend_time : '--') : "--" #总耗时 w_9 = myshixun ? (myshixun.try(:passed_count).to_i > 0 ? myshixun.total_spend_time : '--') : "--" #总耗时
w_10 = myshixun ? myshixun.output_times : 0 #评测次数 w_10 = myshixun ? myshixun.output_times : 0 #评测次数
@ -478,7 +483,7 @@ module ExportHelper
w_14 = nil w_14 = nil
end end
w_15 = w.work_score.nil? ? "--" : w.work_score.round(1) w_15 = w.work_score.nil? ? "--" : w.work_score.round(1)
w_16 = w.update_time ? format_time(w.update_time) : "--" "更新时间" w_16 = w.update_time ? format_time(w.update_time) : "--"
myshixun_complete = myshixun && myshixun.status == 1 myshixun_complete = myshixun && myshixun.status == 1
w_17 = myshixun_complete && w.cost_time ? (game_spend_time w.cost_time) : "未完成" w_17 = myshixun_complete && w.cost_time ? (game_spend_time w.cost_time) : "未完成"
teacher_comment = w.shixun_work_comments.select{|comment| comment.challenge_id == 0}.first teacher_comment = w.shixun_work_comments.select{|comment| comment.challenge_id == 0}.first

@ -24,20 +24,22 @@ module HomeworkCommonsHelper
time = course.end_date.strftime("%Y-%m-%d") time = course.end_date.strftime("%Y-%m-%d")
time_status = 6 time_status = 6
else else
ho_detail_manual = homework_common.homework_detail_manual
if ho_detail_manual
# 作业状态大于“提交”状态时,不用考虑分班权限
if ho_detail_manual.comment_status > 1
if homework_common.end_time && homework_common.end_time < Time.now && homework_common.allow_late && if homework_common.end_time && homework_common.end_time < Time.now && homework_common.allow_late &&
(homework_common.late_time.nil? || homework_common.late_time > Time.now) (homework_common.late_time.nil? || homework_common.late_time > Time.now)
status << "补交中" status << "补交中"
time = "补交剩余时间:" + how_much_time(homework_common.late_time)
time_status = 2
end end
ho_detail_manual = homework_common.homework_detail_manual
if ho_detail_manual
# 作业状态大于“提交”状态时,不用考虑分班权限
if ho_detail_manual.comment_status > 1
case ho_detail_manual.comment_status case ho_detail_manual.comment_status
when 3 when 3
if ho_detail_manual.evaluation_end && ho_detail_manual.evaluation_end > Time.now if ho_detail_manual.evaluation_end && ho_detail_manual.evaluation_end > Time.now
status << "匿评中" status << "匿评中"
time = "提交剩余时间:" + how_much_time(ho_detail_manual.evaluation_end) time = "匿评剩余时间:" + how_much_time(ho_detail_manual.evaluation_end)
time_status = 3 time_status = 3
end end
when 4 when 4
@ -46,17 +48,12 @@ module HomeworkCommonsHelper
time = "申诉剩余时间:" + how_much_time(ho_detail_manual.appeal_time) time = "申诉剩余时间:" + how_much_time(ho_detail_manual.appeal_time)
time_status = 4 time_status = 4
end end
when 2, 5, 6 else
status << "评阅中" if status.blank?
status << "已截止"
time = course.end_date.present? ? ("评阅剩余时间:" + how_much_time(course.end_date.end_of_day)) : "" time = course.end_date.present? ? ("评阅剩余时间:" + how_much_time(course.end_date.end_of_day)) : ""
time_status = 5 time_status = 5
end end
# 如果还在补交阶段则显示补交结束时间
if homework_common.end_time && homework_common.end_time < Time.now && homework_common.allow_late &&
homework_common.late_time && homework_common.late_time > Time.now
time = "补交剩余时间:" + how_much_time(homework_common.late_time)
time_status = 2
end end
else else
# member = course.course_members.find_by(user_id: user.id, is_active: 1) # member = course.course_members.find_by(user_id: user.id, is_active: 1)
@ -77,12 +74,15 @@ module HomeworkCommonsHelper
time = "提交剩余时间:" + how_much_time(homework_common.end_time) time = "提交剩余时间:" + how_much_time(homework_common.end_time)
time_status = 1 time_status = 1
elsif homework_common.end_time && homework_common.end_time < Time.now elsif homework_common.end_time && homework_common.end_time < Time.now
time_status = 5
if homework_common.allow_late && (homework_common.late_time.nil? || homework_common.late_time >= Time.now) if homework_common.allow_late && (homework_common.late_time.nil? || homework_common.late_time >= Time.now)
status << "补交中"
time = "补交剩余时间:" + how_much_time(homework_common.late_time) time = "补交剩余时间:" + how_much_time(homework_common.late_time)
time_status = 2 time_status = 2
else
status << "已截止"
time = course.end_date.present? ? ("评阅剩余时间:" + how_much_time(course.end_date.end_of_day)) : ""
time_status = 5
end end
status << "评阅中"
end end
end end
else else
@ -116,24 +116,22 @@ module HomeworkCommonsHelper
status << "提交中" status << "提交中"
time = "提交剩余时间:" + how_much_time(max_end_time) time = "提交剩余时间:" + how_much_time(max_end_time)
time_status = 1 time_status = 1
elsif homework_common.allow_late && (homework_common.late_time.nil? || homework_common.late_time >= Time.now)
status << "评阅中"
time = "补交剩余时间:" + how_much_time(homework_common.late_time)
time_status = 2
else else
status << "评阅中" status << "已截止"
time = "" time = course.end_date.present? ? ("评阅剩余时间:" + how_much_time(course.end_date.end_of_day)) : ""
time_status = 5 time_status = 5
end end
end end
end end
status << "未开启补交" if !homework_common.allow_late && time_status != 0 status << "未开启补交" if !homework_common.allow_late && time_status == 1
end end
end end
end end
# 如果作业状态都没有的话,在课堂结束前,都显示评阅中 # 如果作业状态都没有的话,在课堂结束前,都显示已截止
if status.blank? if status.blank?
status << "评阅中" status << "已截止"
time = course.end_date.present? ? ("评阅剩余时间:" + how_much_time(course.end_date.end_of_day)) : ""
time_status = 5
end end
result[:status] = status result[:status] = status
result[:time] = time result[:time] = time
@ -144,7 +142,7 @@ module HomeworkCommonsHelper
# 阶段剩余时间 # 阶段剩余时间
def left_time homework, user_id def left_time homework, user_id
setting = homework.homework_group_setting(user_id) setting = homework.homework_group_setting(user_id, true)
if setting.publish_time && setting.publish_time < Time.now if setting.publish_time && setting.publish_time < Time.now
if setting.end_time > Time.now if setting.end_time > Time.now
status = "剩余提交时间" status = "剩余提交时间"
@ -224,10 +222,10 @@ module HomeworkCommonsHelper
# 作品状态 # 作品状态
def practice_homework_status homework, member def practice_homework_status homework, member
[{id: 3, name: "未通关", count: homework.un_complete_count(member)}, [{id: 0, name: "未开启", count: homework.compelete_status_count(member, 0)},
{id: 4, name: "通关", count: homework.complete_count(member)}, {id: 1, name: "通关", count: homework.compelete_status_count(member, 1)},
{id: 1, name: "按时完成", count: homework.finished_count(member)}, {id: 2, name: "按时通关", count: homework.compelete_status_count(member, 2)},
{id: 2, name: "延时完成", count: homework.delay_finished_count(member)}] {id: 3, name: "迟交通关", count: homework.compelete_status_count(member, 3)}]
end end
# 作品状态 # 作品状态

@ -27,6 +27,17 @@ module ShixunsHelper
end end
end end
def shixun_public_status shixun
case shixun.try(:public)
when 0,nil
"未公开"
when 1
"待审核"
when 2
"已公开"
end
end
# 已完成实训所获得的经验值 # 已完成实训所获得的经验值
def myshixun_exp myshixun def myshixun_exp myshixun
score = 0 score = 0

@ -17,10 +17,17 @@ class SyncTrustieJob < ApplicationJob
"number": count "number": count
} }
uri = URI.parse(url) uri = URI.parse(url)
# http = Net::HTTP.new(uri.hostname, uri.port)
if api_host if api_host
http = Net::HTTP.new(uri.hostname, uri.port) 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 end
end end

@ -3,4 +3,5 @@ module CustomRegexp
EMAIL = /\A[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+\z/ EMAIL = /\A[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+\z/
LASTNAME = /\A[a-zA-Z0-9\u4e00-\u9fa5]+\z/ LASTNAME = /\A[a-zA-Z0-9\u4e00-\u9fa5]+\z/
NICKNAME = /\A[\u4e00-\u9fa5_a-zA-Z0-9]+\z/ NICKNAME = /\A[\u4e00-\u9fa5_a-zA-Z0-9]+\z/
PASSWORD = /\A[a-z_A-Z0-9\-\.!@#\$%\\\^&\*\)\(\+=\{\}\[\]\/",'_<>~\·`\?:;|]{8,16}\z/
end end

@ -21,18 +21,31 @@ class Attachment < ApplicationRecord
scope :contains_only_project, -> { where(container_type: 'Project') } scope :contains_only_project, -> { where(container_type: 'Project') }
scope :contains_course_and_project, -> { contains_only_course.or(contains_only_project) } scope :contains_course_and_project, -> { contains_only_course.or(contains_only_project) }
scope :mine, -> (author_id) { where(author_id: author_id) } scope :mine, -> (author_id) { where(author_id: author_id) }
scope :simple_columns, -> { select(:id, :filename, :filesize, :created_on, :cloud_url, :author_id, :content_type) } scope :simple_columns, -> { select(:id, :filename, :filesize, :created_on, :cloud_url, :author_id, :content_type, :container_type, :container_id) }
scope :search_by_container, -> (ids) {where(container_id: ids)} scope :search_by_container, -> (ids) {where(container_id: ids)}
scope :unified_setting, -> {where("unified_setting = ? ", 1)} scope :unified_setting, -> {where("unified_setting = ? ", 1)}
validates_length_of :description, maximum: 100 validates_length_of :description, maximum: 100
DCODES = %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 diskfile def diskfile
File.join(File.join(Rails.root, "files"), disk_directory.to_s, disk_filename.to_s) File.join(File.join(Rails.root, "files"), disk_directory.to_s, disk_filename.to_s)
end end
def relative_path_filename
File.join(disk_directory.to_s, disk_filename.to_s)
end
def title def title
filename title = filename
if container && container.is_a?(StudentWork) && author_id != User.current.id
course = container&.homework_common&.course
unless User.current.teacher_of_course?(course)
title = "#{Time.now.strftime('%Y%m%d%H%M%S')}_#{DCODES.sample(8).join}" + File.extname(filename)
end
end
title
end end
def downloads_count def downloads_count

@ -165,7 +165,7 @@ class Competition < ApplicationRecord
def get_module_name type def get_module_name type
case type case type
when 'home' then '首页' when 'home' then '赛制介绍'
when 'enroll' then '报名' when 'enroll' then '报名'
when 'inform' then '通知公告' when 'inform' then '通知公告'
when 'chart' then '排行榜' when 'chart' then '排行榜'

@ -119,6 +119,12 @@ class Game < ApplicationRecord
# self.outputs.pluck(:query_index).first # self.outputs.pluck(:query_index).first
#end #end
# 是否查看了答案(通关的是否在通关前看的答案)
def view_answer
answer_exists = Grade.where("container_type = 'Answer' and container_id = #{self.id} and created_at < '#{self.end_time}'").exists?
answer_open != 0 ? (status == 2 ? answer_exists : true) : false
end
# 用户关卡得分 # 用户关卡得分
def get_user_final_score def get_user_final_score

@ -3,6 +3,8 @@ class Hack < ApplicationRecord
# diffcult: 难度 1简单2中等 3困难 # diffcult: 难度 1简单2中等 3困难
# 编程题 # 编程题
validates_length_of :name, maximum: 60 validates_length_of :name, maximum: 60
validates :description, presence: { message: "描述不能为空" }
validates :name, presence: { message: "名称不能为空" }
# 测试集 # 测试集
has_many :hack_sets, ->{order("position asc")}, :dependent => :destroy has_many :hack_sets, ->{order("position asc")}, :dependent => :destroy
# 代码 # 代码
@ -39,4 +41,9 @@ class Hack < ApplicationRecord
hack_sets.first&.input hack_sets.first&.input
end end
# 管理员
def manager?(user)
user_id == user.id || user.admin_or_business?
end
end end

@ -1,6 +1,7 @@
class HackSet < ApplicationRecord class HackSet < ApplicationRecord
validates :input, presence: { message: "测试集输入不能为空" } #validates :input, presence: { message: "测试集输入不能为空" }
validates :output, presence: { message: "测试集输出不能为空" } validates :output, presence: { message: "测试集输出不能为空" }
validates_uniqueness_of :input, scope: [:hack_id, :input], message: "多个测试集的输入不能相同"
# 编程题测试集 # 编程题测试集
belongs_to :hack belongs_to :hack
end end

@ -1,6 +1,7 @@
class HackUserCode < ApplicationRecord class HackUserCode < ApplicationRecord
# 用户编程题的信息 # 用户编程题的信息
belongs_to :hack belongs_to :hack
belongs_to :hack_user_lastest_code
scope :created_order, ->{ order("created_at desc")} scope :created_order, ->{ order("created_at desc")}
end end

@ -8,7 +8,7 @@ class HackUserLastestCode < ApplicationRecord
belongs_to :user belongs_to :user
has_many :hack_user_codes, dependent: :destroy has_many :hack_user_codes, dependent: :destroy
has_one :hack_user_debug has_one :hack_user_debug
scope :mine, ->(author_id){ find_by(user_id: author_id) } scope :mine, ->(author_id){ where(user_id: author_id).first }
scope :mine_hack, ->(author_id){ where(user_id: author_id) } scope :mine_hack, ->(author_id){ where(user_id: author_id) }
scope :passed, -> {where(status: 1)} scope :passed, -> {where(status: 1)}

@ -108,7 +108,7 @@ class HomeworkCommon < ApplicationRecord
# 是否在补交阶段内 # 是否在补交阶段内
def late_duration def late_duration
homework_setting = self.homework_group_setting(User.current.id) homework_setting = self.homework_group_setting(User.current.id, true)
!course.is_end && self.publish_time && self.publish_time < Time.now && homework_setting.end_time && !course.is_end && self.publish_time && self.publish_time < Time.now && homework_setting.end_time &&
homework_setting.end_time < Time.now && self.allow_late && (self.late_time.nil? || self.late_time > Time.now) homework_setting.end_time < Time.now && self.allow_late && (self.late_time.nil? || self.late_time > Time.now)
end end
@ -119,7 +119,7 @@ class HomeworkCommon < ApplicationRecord
if self.course.is_end || (self.allow_late && self.late_time && self.late_time < Time.now) if self.course.is_end || (self.allow_late && self.late_time && self.late_time < Time.now)
status = true status = true
elsif !self.allow_late elsif !self.allow_late
homework_setting = self.homework_group_setting(User.current.id) homework_setting = self.homework_group_setting(User.current.id, true)
status = homework_setting.end_time && homework_setting.end_time < Time.now status = homework_setting.end_time && homework_setting.end_time < Time.now
end end
status status
@ -241,14 +241,8 @@ class HomeworkCommon < ApplicationRecord
self.teacher_works(member).delay_finished.count self.teacher_works(member).delay_finished.count
end end
# 未通关数 def compelete_status_count member, status
def un_complete_count member teacher_works(member).where(compelete_status: status).count
teacher_works(member).count - complete_count(member)
end
# 通关数
def complete_count member
Myshixun.where(id: self.teacher_works(member).pluck(:myshixun_id), status: 1).count
end end
# 分组作业的最大分组id # 分组作业的最大分组id
@ -257,12 +251,13 @@ class HomeworkCommon < ApplicationRecord
end end
# 作业的分班设置时间 # 作业的分班设置时间
def homework_group_setting user_id def homework_group_setting user_id, current_user=false
if unified_setting if unified_setting
homework_setting = self homework_setting = self
else else
member = course.course_member(user_id) # 当前用户是从course_member中取否则是从学生中取双重身份的原因
group_setting = self.homework_group_settings.find_by_course_group_id(member.try(:course_group_id)) member = current_user ? course.course_member(user_id) : course.students.find_by(user_id: user_id)
group_setting = self.homework_group_settings.select{ |setting| setting.course_group_id == member.try(:course_group_id)}.first
homework_setting = group_setting.present? ? group_setting : self homework_setting = group_setting.present? ? group_setting : self
end end
homework_setting homework_setting

@ -0,0 +1,3 @@
class ItemAnalysis < ApplicationRecord
belongs_to :item_bank
end

@ -0,0 +1,11 @@
class ItemBank < ApplicationRecord
# difficulty: 1 简单 2 适中 3 困难
# item_type: 0 单选 1 多选 2 判断 3 填空 4 简答 5 实训 6 编程
enum item_type: { SINGLE: 0, MULTIPLE: 1, JUDGMENT: 2, COMPLETION: 3, SUBJECTIVE: 4, PRACTICAL: 5, PROGRAM: 6 }
belongs_to :user
has_one :item_analysis, dependent: :destroy
has_many :item_choices, dependent: :destroy
has_many :item_baskets, dependent: :destroy
end

@ -0,0 +1,4 @@
class ItemBasket < ApplicationRecord
belongs_to :item_bank
belongs_to :user
end

@ -0,0 +1,3 @@
class ItemChoice < ApplicationRecord
belongs_to :item_bank
end

@ -38,12 +38,20 @@ class Laboratory < ApplicationRecord
find_by_identifier(subdomain) find_by_identifier(subdomain)
end end
def self.current=(laboratory) # def self.current=(laboratory)
Thread.current[:current_laboratory] = 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 end
def self.current def self.current
Thread.current[:current_laboratory] ||= Laboratory.find(1) RequestStore.store[:current_laboratory] ||= User.anonymous
end end
def shixuns def shixuns

@ -67,6 +67,7 @@ class LaboratorySetting < ApplicationRecord
{ 'name' => '在线竞赛', 'link' => '/competitions', 'hidden' => false }, { 'name' => '在线竞赛', 'link' => '/competitions', 'hidden' => false },
{ 'name' => '教学案例', 'link' => '/moop_cases', 'hidden' => false }, { 'name' => '教学案例', 'link' => '/moop_cases', 'hidden' => false },
{ 'name' => '交流问答', 'link' => '/forums', 'hidden' => false }, { 'name' => '交流问答', 'link' => '/forums', 'hidden' => false },
{ 'name' => '开发者社区', 'link' => '/problems', 'hidden' => false },
], ],
footer: nil footer: nil
} }

@ -28,6 +28,11 @@ class Myshixun < ApplicationRecord
"#{self.repo_name}.git" "#{self.repo_name}.git"
end end
def repo_save_path
self.repo_name.split('/').last
end
def is_complete? def is_complete?
self.status == 1 self.status == 1
end end
@ -83,9 +88,15 @@ class Myshixun < ApplicationRecord
self.games.select{|game| game.status == 2}.size self.games.select{|game| game.status == 2}.size
end end
# 查看答案的关卡数 # 指定时间前完成的关卡数
def time_passed_count time
time.present? ? self.games.select{|game| game.status == 2 && game.end_time < time}.size : 0
end
# 查看答案的关卡数,只统计通关前看的关卡
def view_answer_count 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 end
# 通关时间 # 通关时间

@ -52,7 +52,8 @@ module Searchable::Shixun
challenges_count: challenges_count, challenges_count: challenges_count,
study_count: myshixuns_count, study_count: myshixuns_count,
star: averge_star, star: averge_star,
level: shixun_level level: shixun_level,
is_jupyter: is_jupyter
} }
end end

@ -3,12 +3,14 @@ class Shixun < ApplicationRecord
attr_accessor :page_no #管理员页面 实训配置更新状态时需要接受page_no参数 attr_accessor :page_no #管理员页面 实训配置更新状态时需要接受page_no参数
# status: 0编辑 1申请发布 2正式发布 3关闭 -1软删除 # status: 0编辑 1申请发布 2正式发布 3关闭 -1软删除
# public: 0未公开 1申请公开 2公开
# hide_code 隐藏代码窗口 # hide_code 隐藏代码窗口
# code_hidden: 隐藏代码目录 # code_hidden: 隐藏代码目录
# task_pass: 跳关 # task_pass: 跳关
# webssh 0不开启webssh1开启练习模式; 2开启评测模式 # webssh 0不开启webssh1开启练习模式; 2开启评测模式
# trainee 实训的难度 # trainee 实训的难度
# vnc: VCN实训是否用于评测 # vnc: VCN实训是否用于评测
validates_presence_of :name, message: "实训名称不能为空"
has_many :challenges, -> {order("challenges.position asc")}, dependent: :destroy has_many :challenges, -> {order("challenges.position asc")}, dependent: :destroy
has_many :challenge_tags, through: :challenges has_many :challenge_tags, through: :challenges
has_many :myshixuns, :dependent => :destroy has_many :myshixuns, :dependent => :destroy
@ -54,6 +56,8 @@ class Shixun < ApplicationRecord
has_many :laboratory_shixuns, dependent: :destroy has_many :laboratory_shixuns, dependent: :destroy
belongs_to :laboratory, optional: true belongs_to :laboratory, optional: true
# Jupyter数据集,附件
has_many :data_sets, ->{where(attachtype: 2)}, class_name: 'Attachment', as: :container, dependent: :destroy
scope :search_by_name, ->(keyword) { where("name like ? or description like ? ", scope :search_by_name, ->(keyword) { where("name like ? or description like ? ",
"%#{keyword}%", "%#{keyword}%") } "%#{keyword}%", "%#{keyword}%") }
@ -76,6 +80,7 @@ class Shixun < ApplicationRecord
scope :published_closed, lambda{ where(status: [2, 3]) } scope :published_closed, lambda{ where(status: [2, 3]) }
scope :none_closed, lambda{ where(status: [0, 1, 2]) } scope :none_closed, lambda{ where(status: [0, 1, 2]) }
scope :unhidden, lambda{ where(hidden: 0, status: 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 :field_for_recommend, lambda{ select([:id, :name, :identifier, :myshixuns_count]) }
scope :find_by_ids,lambda{|k| where(id:k)} scope :find_by_ids,lambda{|k| where(id:k)}
@ -280,7 +285,7 @@ class Shixun < ApplicationRecord
end end
def has_manager?(user) def has_manager?(user)
return true if user.admin? return true if user.admin? || user.business?
shixun_members.where(role: [1, 2]).exists?(user_id: user.id) shixun_members.where(role: [1, 2]).exists?(user_id: user.id)
end end

@ -1,8 +1,6 @@
class ShixunInfo < ApplicationRecord class ShixunInfo < ApplicationRecord
belongs_to :shixun belongs_to :shixun
validates_uniqueness_of :shixun_id validates_uniqueness_of :shixun_id
validates_presence_of :shixun_id
after_commit :create_diff_record after_commit :create_diff_record
private private

@ -2,4 +2,5 @@ class ShixunMirrorRepository < ApplicationRecord
belongs_to :shixun belongs_to :shixun
belongs_to :mirror_repository belongs_to :mirror_repository
validates_uniqueness_of :shixun_id, :scope => :mirror_repository_id validates_uniqueness_of :shixun_id, :scope => :mirror_repository_id
validates_presence_of :shixun_id, :mirror_repository_id
end end

@ -1,4 +1,6 @@
class ShixunServiceConfig < ApplicationRecord class ShixunServiceConfig < ApplicationRecord
belongs_to :shixun belongs_to :shixun
belongs_to :mirror_repository belongs_to :mirror_repository
validates_presence_of :shixun_id, :mirror_repository_id
end end

@ -123,6 +123,26 @@ class StudentWork < ApplicationRecord
end end
end end
# 实训作业的作品状态 0未提交1未通关2按时通关(提交截止前通关)3迟交通关提交截止-补交截止间通关)
def real_work_status
status = work_status
if status > 0 && myshixun
if myshixun.status != 1
status = 1
else
homework_end_time = homework_common.homework_group_setting(user_id)&.end_time
if homework_end_time.present? && homework_end_time > myshixun.passed_time
status = 2
elsif homework_end_time.present? && homework_common.allow_late && homework_common.late_time > myshixun.passed_time
status = 3
else
status = 1
end
end
end
status
end
# 更新作品成绩 # 更新作品成绩
def set_work_score def set_work_score
if work_status > 0 && homework_common && !self.ultimate_score if work_status > 0 && homework_common && !self.ultimate_score

@ -546,12 +546,20 @@ class User < ApplicationRecord
mail.present? mail.present?
end 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) def self.current=(user)
Thread.current[:current_user] = user RequestStore.store[:current_user] = user
end end
def self.current def self.current
Thread.current[:current_user] ||= User.anonymous RequestStore.store[:current_user] ||= User.anonymous
end end
def self.anonymous def self.anonymous

@ -17,6 +17,7 @@ class Admins::SchoolQuery < ApplicationQuery
if keyword if keyword
schools = schools.where('schools.name LIKE ?', "%#{keyword}%") schools = schools.where('schools.name LIKE ?', "%#{keyword}%")
end end
schools = schools.left_joins(:user_extensions).select('schools.*, IFNULL(count(user_extensions.user_id),0) users_count').group('schools.id')
custom_sort schools, params[:sort_by], params[:sort_direction] custom_sort schools, params[:sort_by], params[:sort_direction]
end end
end end

@ -0,0 +1,33 @@
class Admins::ShixunModifyRecordQuery < ApplicationQuery
attr_reader :params
def initialize(params)
@params = params
end
def call
if params[:user_name].blank? || params[:date].blank?
records = DiffRecord.none
else
records = DiffRecord.joins(:user).where("concat(users.lastname, users.firstname) like ?", "%#{params[:user_name].strip}%")
if time_range.present?
records = records.where(created_at: time_range)
end
end
records.order("diff_records.created_at desc")
end
private
def time_range
@_time_range ||= begin
case params[:date]
when 'weekly' then 1.weeks.ago..Time.now
when 'monthly' then 1.months.ago..Time.now
when 'quarterly' then 3.months.ago..Time.now
when 'yearly' then 1.years.ago..Time.now
else ''
end
end
end
end

@ -21,7 +21,17 @@ class Admins::ShixunQuery < ApplicationQuery
[0,1,2,3] [0,1,2,3]
end 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(status: status) if status.present?
all_shixuns = all_shixuns.where(public: public) if public.present?
if params[:tag].present? if params[:tag].present?
all_shixuns = all_shixuns.joins(:mirror_repositories).where("mirror_repositories.id = ?",params[:tag].to_i) all_shixuns = all_shixuns.joins(:mirror_repositories).where("mirror_repositories.id = ?",params[:tag].to_i)

@ -51,6 +51,7 @@ class Admins::ShixunSettingsQuery < ApplicationQuery
all_shixuns = all_shixuns.where(homepage_show: params[:homepage_show]) if params[:homepage_show] all_shixuns = all_shixuns.where(homepage_show: params[:homepage_show]) if params[:homepage_show]
all_shixuns = all_shixuns.where(task_pass: params[:task_pass]) if params[:task_pass] all_shixuns = all_shixuns.where(task_pass: params[:task_pass]) if params[:task_pass]
all_shixuns = all_shixuns.where(code_hidden: params[:code_hidden]) if params[:code_hidden] all_shixuns = all_shixuns.where(code_hidden: params[:code_hidden]) if params[:code_hidden]
all_shixuns = all_shixuns.where(vip: params[:vip]) if params[:vip]
custom_sort(all_shixuns, params[:sort_by], params[:sort_direction]) custom_sort(all_shixuns, params[:sort_by], params[:sort_direction])
end end

@ -75,13 +75,12 @@ class Admins::CheckShixunMirrorsService < ApplicationService
def bridge_images def bridge_images
@_bridge_images ||= begin @_bridge_images ||= begin
url = EduSetting.get('cloud_bridge') url = "#{EduSetting.get('cloud_bridge')}/bridge/docker/images"
res = Faraday.get(url) res = Faraday.get(url)
res_body = JSON.parse(res.body) res = JSON.parse(res.body)
raise Error, '拉取镜像信息异常' if res && res['code'] != 0
raise Error, '拉取镜像信息异常' if res_body && res_body['code'].to_i != 0 res
res_body
rescue => e rescue => e
Rails.logger.error("get response failed ! #{e.message}") Rails.logger.error("get response failed ! #{e.message}")
raise Error, '实训云平台繁忙繁忙等级84' raise Error, '实训云平台繁忙繁忙等级84'

@ -10,7 +10,7 @@ class Admins::ShixunAuths::AgreeApplyService < ApplicationService
def call def call
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
apply.update!(status: 1, dealer_id: user.id) 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! reward_grade_and_experience!

@ -10,7 +10,7 @@ class Admins::ShixunAuths::RefuseApplyService < ApplicationService
def call def call
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
shixun.update!(status: 0) shixun.update!(public: 0)
apply.update!(status: 2, reason: reason, dealer_id: user.id) apply.update!(status: 2, reason: reason, dealer_id: user.id)
deal_tiding! deal_tiding!

@ -25,6 +25,7 @@ class CreateDiffRecordService < ApplicationService
index = 0 index = 0
fragment_size = 1 fragment_size = 1
Diffy::Diff.new(before, after).each do |line| Diffy::Diff.new(before, after).each do |line|
unless line.include?("\\ 文件尾没有 newline 字符")
unless line =~ /^[\+-]/ unless line =~ /^[\+-]/
if arr.empty? && index < fragment_size if arr.empty? && index < fragment_size
content += line content += line
@ -41,6 +42,7 @@ class CreateDiffRecordService < ApplicationService
content += line content += line
arr.clear arr.clear
end end
end
content content
end end
end end

@ -322,11 +322,16 @@ class HomeworksService
work.efficiency = format("%.2f", efficiency) work.efficiency = format("%.2f", efficiency)
if myshixun_endtime <= homework_end_or_late_time if myshixun_endtime <= homework_end_or_late_time
work.compelete_status = myshixun_endtime < setting_time.publish_time ? 2 : 1 # 2是按时通关 3是迟交通关
work.compelete_status = myshixun_endtime < setting_time.end_time ? 2 : 3
# 如果作业的最大效率值有变更则更新所有作品的效率分 # 如果作业的最大效率值有变更则更新所有作品的效率分
homework.update_column("max_efficiency", work.efficiency) if homework.work_efficiency && homework.max_efficiency < work.efficiency homework.update_column("max_efficiency", work.efficiency) if homework.work_efficiency && homework.max_efficiency < work.efficiency
else
work.compelete_status = 1 # 未通关
end end
else
work.compelete_status = 1 # 未通关
end end
work.late_penalty = work.work_status == 2 ? homework.late_penalty : 0 work.late_penalty = work.work_status == 2 ? homework.late_penalty : 0
@ -346,7 +351,7 @@ class HomeworksService
work.work_score = format("%.2f",(score < 0 ? 0 : score).to_f) unless work.ultimate_score work.work_score = format("%.2f",(score < 0 ? 0 : score).to_f) unless work.ultimate_score
#logger.info("#############work_score: #{score}") #logger.info("#############work_score: #{score}")
work.calculation_time = Time.now work.calculation_time = Time.now
work.save! work.save(validate: false)
end end
end end
end end

@ -0,0 +1,195 @@
#coding=utf-8
module JupyterService
def _open_shixun_jupyter(shixun)
if shixun.is_jupyter?
shixun_tomcat = edu_setting('cloud_bridge')
uri = "#{shixun_tomcat}/bridge/jupyter/get"
tpiID = "tpm#{shixun.id}"
mount = shixun.data_sets.present?
params = {tpiID: tpiID, identifier: shixun.identifier, needMount: mount,
:containers => "#{Base64.urlsafe_encode64(shixun_container_limit(shixun))}"}
logger.info "test_juypter: uri->#{uri}, params->#{params}"
res = uri_post uri, params
if res && res['code'].to_i != 0
raise("实训云平台繁忙繁忙等级99")
end
logger.info "test_juypter: #{res}"
@shixun_jupyter_port = res['port']
"#{jupyter_service(res['port'])}/notebooks/data/workspace/myshixun_#{tpiID}/01.ipynb"
end
end
def jupyter_url_with_shixun(shixun)
#打开tpm - juypter接口
_open_shixun_jupyter(shixun)
end
def jupyter_port_with_shixun(shixun)
if @shixun_jupyter_port.to_i <=0
_open_shixun_jupyter(shixun)
end
@shixun_jupyter_port
end
def _open_game_jupyter(myshixun)
## 打开tpi
shixun = myshixun.shixun
if shixun.is_jupyter?
shixun_tomcat = edu_setting('cloud_bridge')
uri = "#{shixun_tomcat}/bridge/jupyter/get"
tpiID = myshixun.id
mount = myshixun.shixun.data_sets.present?
params = {tpiID: tpiID, identifier: shixun.identifier, myshixunIdentifier: myshixun.identifier, needMount: mount,
:containers => "#{Base64.urlsafe_encode64(shixun_container_limit(shixun))}"}
res = uri_post uri, params
logger.info "test_juypter: #{res}"
if res && res['code'].to_i != 0
raise("实训云平台繁忙繁忙等级99")
end
@game_jupyter_port = res['port']
repo_save_path = myshixun.repo_save_path
"#{jupyter_service(res['port'])}/notebooks/data/workspace/myshixun_#{tpiID}/#{repo_save_path}/01.ipynb"
end
end
def jupyter_url_with_game(myshixun)
_open_game_jupyter(myshixun)
end
def jupyter_port_with_game(myshixun)
if @game_jupyter_port.to_i <=0
_open_game_jupyter(myshixun)
end
@game_jupyter_port
end
def jupyter_save_with_shixun(shixun,jupyter_port)
author_name = current_user.real_name
author_email = current_user.git_mail
message = "User submitted"
tpiID = "tpm#{shixun.id}"
src_url = "#{jupyter_service(jupyter_port)}/nbconvert/notebook/data/workspace/myshixun_#{tpiID}/01.ipynb?download=true"
response = Faraday.get(src_url)
if response.status.to_i != 200
raise("获取文件内容失败:#{response.status}")
end
content = response.body.force_encoding('utf-8')
c = GitService.update_file(repo_path: shixun.repo_path,
file_path: "01.ipynb",
message: message,
content: content,
author_name: author_name,
author_email: author_email)
return c.size
end
def jupyter_save_with_game(myshixun,jupyter_port)
author_name = current_user.real_name
author_email = current_user.git_mail
message = "User submitted"
tpiID = myshixun.id
repo_save_path = myshixun.repo_save_path
src_url = "#{jupyter_service(jupyter_port)}/nbconvert/notebook/data/workspace/myshixun_#{tpiID}/#{repo_save_path}/01.ipynb?download=true"
response = Faraday.get(src_url)
if response.status.to_i != 200
raise("获取文件内容失败:#{response.status}")
end
content = response.body.force_encoding('utf-8')
c = GitService.update_file(repo_path: myshixun.repo_path,
file_path: "01.ipynb",
message: message,
content: content,
author_name: author_name,
author_email: author_email)
return c.size
end
##重置jupyter环境
def jupyter_tpi_reset(myshixun)
jupyter_delete_tpi(myshixun)
url = jupyter_url_with_game(myshixun)
port = jupyter_port_with_game(myshixun)
{url: url, port: port}
end
## 重置tpm环境
def jupyter_tpm_reset(shixun)
jupyter_delete_tpm(shixun)
url = jupyter_url_with_shixun(shixun)
port = jupyter_port_with_shixun(shixun)
{url: url, port: port}
end
# 删除pod
def jupyter_delete_tpi(myshixun)
myshixun_id = myshixun.id
digest = myshixun.identifier + edu_setting('bridge_secret_key')
digest_key = Digest::SHA1.hexdigest("#{digest}")
begin
shixun_tomcat = edu_setting('cloud_bridge')
uri = "#{shixun_tomcat}/bridge/jupyter/delete"
Rails.logger.info("#{current_user} => cloese_jupyter digest is #{digest}")
params = {:tpiID => myshixun_id, :digestKey => digest_key, :identifier => myshixun.identifier}
res = uri_post uri, params
if res && res['code'].to_i != 0
raise("实训云平台繁忙繁忙等级110")
end
end
end
def jupyter_delete_tpm(shixun)
tpiID = "tpm#{shixun.id}"
digest = shixun.identifier + edu_setting('bridge_secret_key')
digest_key = Digest::SHA1.hexdigest("#{digest}")
begin
shixun_tomcat = edu_setting('cloud_bridge')
uri = "#{shixun_tomcat}/bridge/jupyter/delete"
Rails.logger.info("#{current_user} => cloese_jupyter digest is #{digest}")
params = {:tpiID => tpiID, :digestKey => digest_key, :identifier => shixun.identifier}
res = uri_post uri, params
if res && res['code'].to_i != 0
raise("实训云平台繁忙繁忙等级110")
end
end
end
def jupyter_service jupyter_port
edu_setting('jupyter_service').gsub("PORT", jupyter_port)
end
end

@ -30,7 +30,6 @@ class SearchService < ApplicationService
model_options = { model_options = {
includes: modal_name.searchable_includes 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!(extra_options)
model_options.deep_merge!(default_options) model_options.deep_merge!(default_options)
@ -40,7 +39,7 @@ class SearchService < ApplicationService
def extra_options def extra_options
case params[:type].to_s.strip case params[:type].to_s.strip
when 'shixun' then 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 when 'subject' then
{ where: { id: Laboratory.current.subjects.pluck(:id) } } { where: { id: Laboratory.current.subjects.pluck(:id) } }
when 'course' then when 'course' then

@ -25,7 +25,7 @@ class ShixunSearchService < ApplicationService
else else
none_shixun_ids = ShixunSchool.where("school_id != #{User.current.school_id}").pluck(:shixun_id) 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
end end
@ -38,6 +38,7 @@ class ShixunSearchService < ApplicationService
@shixuns = @shixuns.where(trainee: params[:diff]) @shixuns = @shixuns.where(trainee: params[:diff])
end end
Rails.logger.info("search_shixun_ids: #{@shixuns.pluck(:id)}")
Shixun.search(keyword, search_options) Shixun.search(keyword, search_options)
end end

@ -0,0 +1,115 @@
class CreateShixunService < ApplicationService
attr_reader :user, :params, :permit_params
def initialize(user, permit_params, params)
@user = user
@params = params
@permit_params = permit_params
end
def call
shixun = Shixun.new(permit_params)
identifier = Util::UUID.generate_identifier(Shixun, 8)
shixun.identifier= identifier
shixun.user_id = user.id
main_mirror = MirrorRepository.find params[:main_type]
sub_mirrors = MirrorRepository.where(id: params[:sub_type])
begin
ActiveRecord::Base.transaction do
shixun.save!
# 获取脚本内容
shixun_script = get_shixun_script(shixun, main_mirror, sub_mirrors)
# 创建额外信息
ShixunInfo.create!(shixun_id: shixun.id, evaluate_script: shixun_script, description: params[:description])
# 创建合作者
shixun.shixun_members.create!(user_id: user.id, role: 1)
# 创建镜像
ShixunMirrorRepository.create!(:shixun_id => shixun.id, :mirror_repository_id => main_mirror.id)
# 创建主服务配置
ShixunServiceConfig.create!(:shixun_id => shixun.id, :mirror_repository_id => main_mirror.id)
# 创建子镜像相关数据(实训镜像关联表,子镜像服务配置)
sub_mirrors.each do |sub|
ShixunMirrorRepository.create!(:shixun_id => shixun.id, :mirror_repository_id => sub.id)
# 实训子镜像服务配置
name = sub.name #查看镜像是否有名称,如果没有名称就不用服务配置
ShixunServiceConfig.create!(:shixun_id => shixun.id, :mirror_repository_id => sub.id) if name.present?
end
# 创建版本库
repo_path = repo_namespace(user.login, shixun.identifier)
GitService.add_repository(repo_path: repo_path)
shixun.update_column(:repo_name, repo_path.split(".")[0])
# 如果是云上实验室,创建相关记录
if !Laboratory.current.main_site?
Laboratory.current.laboratory_shixuns.create!(shixun: shixun, ownership: true)
end
# 如果是jupyter先创建一个目录,为了挂载(因为后续数据集开启Pod后环境在没销毁前你上传数据集是挂载不上目录的因此要先创建目录方便中间层挂载)
if shixun.is_jupyter?
folder = EduSetting.get('shixun_folder')
path = "#{folder}/#{identifier}"
FileUtils.mkdir_p(path, :mode => 0777) unless File.directory?(path)
end
return shixun
end
rescue => e
Rails.logger.error("shixun_create_error: #{e.message}")
raise("创建实训失败!")
end
end
private
def get_shixun_script shixun, main_mirror, sub_mirrors
if !shixun.is_jupyter?
mirror = main_mirror.mirror_scripts
if main_mirror.blank?
modify_shixun_script shixun, mirror.first&.(:script)
else
sub_name = sub_mirrors.pluck(:type_name)
if main_mirror.type_name == "Java" && sub_name.include?("Mysql")
mirror.last.try(:script)
else
shixun_script = mirror.first&.script
modify_shixun_script shixun, shixun_script
end
end
end
end
def modify_shixun_script shixun, script
if script.present?
source_class_name = []
challenge_program_name = []
shixun.challenges.map(&:exec_path).each do |exec_path|
challenge_program_name << "\"#{exec_path}\""
if shixun.main_mirror_name == "Java"
if exec_path.nil? || exec_path.split("src/")[1].nil?
source = "\"\""
else
source = "\"#{exec_path.split("src/")[1].split(".java")[0]}\""
end
logger.info("----source: #{source}")
source_class_name << source.gsub("/", ".") if source.present?
elsif shixun.main_mirror_name.try(:first) == "C#"
if exec_path.nil? || exec_path.split(".")[1].nil?
source = "\"\""
else
source = "\"#{exec_path.split(".")[0]}.exe\""
end
source_class_name << source if source.present?
end
end
script = if script.include?("sourceClassName") && script.include?("challengeProgramName")
script.gsub(/challengeProgramNames=\(.*\)/,"challengeProgramNames=\(#{challenge_program_name.reject(&:blank?).join(" ")}\)").gsub(/sourceClassNames=\(.*\)/, "sourceClassNames=\(#{source_class_name.reject(&:blank?).join(" ")}\)")
else
script.gsub(/challengeProgramNames=\(.*\)/,"challengeProgramNames=\(#{challenge_program_name.reject(&:blank?).join(" ")}\)").gsub(/sourceClassNames=\(.*\)/, "sourceClassNames=\(#{challenge_program_name.reject(&:blank?).join(" ")}\)")
end
end
return script
end
# 版本库目录空间
def repo_namespace(user, shixun_identifier)
"#{user}/#{shixun_identifier}.git"
end
end

@ -60,7 +60,7 @@ class Subjects::CopySubjectService < ApplicationService
shixun = stage_shixun.shixun shixun = stage_shixun.shixun
to_shixun = Shixun.new to_shixun = Shixun.new
to_shixun.attributes = shixun.attributes.dup.except('id', 'user_id', 'identifier', 'homepage_show', to_shixun.attributes = shixun.attributes.dup.except('id', 'user_id', 'identifier', 'homepage_show',
'use_scope', 'averge_star', 'myshixuns_count', 'challenges_count') 'use_scope', 'averge_star', 'myshixuns_count', 'challenges_count', "public")
to_shixun.identifier = Util::UUID.generate_identifier(Shixun, 8) to_shixun.identifier = Util::UUID.generate_identifier(Shixun, 8)
to_shixun.user_id = user.id to_shixun.user_id = user.id
if laboratory if laboratory

@ -1,4 +1,4 @@
class UpdateHomeworkSettingService < ApplicationService class UpdateHomeworkPublishSettingService < ApplicationService
attr_reader :homework, :params attr_reader :homework, :params
def initialize(homework, params) def initialize(homework, params)
@ -7,6 +7,7 @@ class UpdateHomeworkSettingService < ApplicationService
end end
def call def call
puts params
course = homework.course course = homework.course
# 作业未发布时unified_setting参数不能为空 # 作业未发布时unified_setting参数不能为空
if homework.publish_time.nil? || homework.publish_time > Time.now if homework.publish_time.nil? || homework.publish_time > Time.now
@ -37,9 +38,9 @@ class UpdateHomeworkSettingService < ApplicationService
tip_exception("分班id不能为空") if setting[:group_id].length == 0 tip_exception("分班id不能为空") if setting[:group_id].length == 0
tip_exception("发布时间不能为空") if setting[:publish_time].blank? tip_exception("发布时间不能为空") if setting[:publish_time].blank?
tip_exception("截止时间不能为空") if setting[:end_time].blank? tip_exception("截止时间不能为空") if setting[:end_time].blank?
tip_exception("发布时间不能早于当前时间") if setting[:publish_time] <= strf_time(Time.now) tip_exception("发布时间不能早于当前时间") if setting[:publish_time].to_time <= Time.now
tip_exception("截止时间不能早于当前时间") if setting[:end_time] <= strf_time(Time.now) tip_exception("截止时间不能早于当前时间") if setting[:end_time].to_time <= Time.now
tip_exception("截止时间不能早于发布时间") if setting[:publish_time] > setting[:end_time] tip_exception("截止时间不能早于发布时间") if setting[:publish_time].to_time > setting[:end_time].to_time
tip_exception("截止时间不能晚于课堂结束时间(#{course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if tip_exception("截止时间不能晚于课堂结束时间(#{course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if
course.end_date.present? && setting[:end_time] > course.end_date.end_of_day course.end_date.present? && setting[:end_time] > course.end_date.end_of_day
@ -74,15 +75,15 @@ class UpdateHomeworkSettingService < ApplicationService
else else
if homework.end_time > Time.now && homework.unified_setting if homework.end_time > Time.now && homework.unified_setting
tip_exception("截止时间不能为空") if params[:end_time].blank? tip_exception("截止时间不能为空") if params[:end_time].blank?
tip_exception("截止时间不能早于当前时间") if params[:end_time] <= strf_time(Time.now) tip_exception("截止时间不能早于当前时间") if params[:end_time].to_time <= Time.now
tip_exception("截止时间不能晚于课堂结束时间(#{course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if tip_exception("截止时间不能晚于课堂结束时间(#{course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if
course.end_date.present? && params[:end_time] > strf_time(course.end_date.end_of_day) course.end_date.present? && params[:end_time].to_time > course.end_date.end_of_day
homework.end_time = params[:end_time] homework.end_time = params[:end_time]
elsif !homework.unified_setting elsif !homework.unified_setting
homework.create_homework_group_settings homework.create_homework_group_settings
tip_exception("分班发布设置不能为空") if params[:group_settings].blank? tip_exception("分班发布设置不能为空") if params[:group_settings].reject(&:blank?).blank?
params[:group_settings].each do |setting| params[:group_settings].each do |setting|
group_settings = HomeworkGroupSetting.where(homework_common_id: homework.id, course_group_id: setting[:group_id]) group_settings = HomeworkGroupSetting.where(homework_common_id: homework.id, course_group_id: setting[:group_id])
@ -90,12 +91,12 @@ class UpdateHomeworkSettingService < ApplicationService
tip_exception("发布时间不能为空") if setting[:publish_time].blank? tip_exception("发布时间不能为空") if setting[:publish_time].blank?
tip_exception("截止时间不能为空") if setting[:end_time].blank? tip_exception("截止时间不能为空") if setting[:end_time].blank?
# 如果该发布规则 没有已发布的分班则需判断发布时间 # 如果该发布规则 没有已发布的分班则需判断发布时间
tip_exception("发布时间不能早于等于当前时间") if setting[:publish_time] <= strf_time(Time.now) && group_settings.group_published.count == 0 tip_exception("发布时间不能早于等于当前时间") if setting[:publish_time].to_time <= Time.now && group_settings.group_published.count == 0
tip_exception("截止时间不能早于等于当前时间") if setting[:end_time] <= strf_time(Time.now) && group_settings.none_end.count > 0 tip_exception("截止时间不能早于等于当前时间") if setting[:end_time].to_time <= Time.now && group_settings.none_end.count > 0
tip_exception("截止时间不能早于发布时间") if setting[:publish_time] > setting[:end_time] tip_exception("截止时间不能早于发布时间") if setting[:publish_time].to_time > setting[:end_time].to_time
tip_exception("截止时间不能晚于课堂结束时间(#{course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if tip_exception("截止时间不能晚于课堂结束时间(#{course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")}") if
course.end_date.present? && setting[:end_time] > strf_time(course.end_date.end_of_day) course.end_date.present? && setting[:end_time].to_time > course.end_date.end_of_day
group_settings.none_published.update_all(publish_time: setting[:publish_time]) group_settings.none_published.update_all(publish_time: setting[:publish_time])
group_settings.none_end.update_all(end_time: setting[:end_time]) group_settings.none_end.update_all(end_time: setting[:end_time])
@ -107,4 +108,9 @@ class UpdateHomeworkSettingService < ApplicationService
homework.save! homework.save!
HomeworkCommonPushNotifyJob.perform_later(homework.id, publish_group_ids) if send_tiding HomeworkCommonPushNotifyJob.perform_later(homework.id, publish_group_ids) if send_tiding
end end
private
def tip_exception(status = -1, message)
raise Educoder::TipException.new(status, message)
end
end end

@ -44,7 +44,7 @@ class Users::ShixunService
def user_policy_filter(relations) def user_policy_filter(relations)
# 只有自己或者管理员才有过滤筛选及查看全部状态下实训功能 # 只有自己或者管理员才有过滤筛选及查看全部状态下实训功能
if self_or_admin? if self_or_admin?
relations = relations.where.not(status: -1) relations = relations.where.not(status: -1).where(hidden: false)
status_filter(relations) status_filter(relations)
else else
relations.where(status: [2, 3], hidden: false) relations.where(status: [2, 3], hidden: false)

@ -35,7 +35,7 @@ class Users::SubjectService
def user_policy_filter(relations) def user_policy_filter(relations)
# 只有自己或者管理员才有过滤筛选及查看全部状态下实训功能 # 只有自己或者管理员才有过滤筛选及查看全部状态下实训功能
if self_or_admin? if self_or_admin?
status_filter(relations) status_filter(relations.unhidden)
else else
relations.where(status: 2, hidden: false) relations.where(status: 2, hidden: false)
end end

@ -557,7 +557,6 @@ a.user_orangebg_btn{background-color:#FF6800;color: #fff;}
a.user_greybg_btn{background-color:#747A7F;color: #fff;} a.user_greybg_btn{background-color:#747A7F;color: #fff;}
/*.user_white_btn{border: 1px solid #ffffff;color: #ffffff!important;}*/ /*.user_white_btn{border: 1px solid #ffffff;color: #ffffff!important;}*/
.pointer{cursor: pointer} .pointer{cursor: pointer}
.cdefault{cursor: default} .cdefault{cursor: default}

@ -1,30 +1,31 @@
<table class="table table-hover text-center subject-list-table"> <table class="table table-hover text-center subject-list-table">
<thead class="thead-light"> <thead class="thead-light">
<tr> <tr>
<th width="4%">序号</th>
<th width="4%">ID</th> <th width="4%">ID</th>
<th width="10%" class="text-left">课堂名称</th> <th width="10%" class="text-left">课堂名称</th>
<th width="6%">成员</th> <th width="5%">成员</th>
<th width="4%">资源</th> <th width="4%">资源</th>
<th width="4%">普通作业</th> <th width="4%">普通作业</th>
<th width="4%">分组作业</th> <th width="4%">分组作业</th>
<th width="4%">实训作业</th> <th width="4%">实训作业</th>
<th width="4%">试卷</th> <th width="4%">试卷</th>
<th width="7%">评测次数</th> <th width="6%">评测次数</th>
<th width="4%">私有</th> <th width="4%">私有</th>
<th width="6%">状态</th> <th width="6%">状态</th>
<th width="10%">单位</th> <th width="10%">单位</th>
<th width="7%">创建者</th> <th width="7%">创建者</th>
<th width="10%"><%= sort_tag('创建时间', name: 'created_at', path: admins_courses_path) %></th> <th width="10%"><%= sort_tag('创建时间', name: 'created_at', path: admins_courses_path) %></th>
<th width="4%">首页</th> <th width="4%">首页</th>
<th width="6%">邮件通知</th> <th width="5%">邮件通知</th>
<th width="6%">操作</th> <th width="5%">操作</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<% if courses.present? %> <% if courses.present? %>
<% courses.each do |course| %> <% courses.each_with_index do |course, index| %>
<tr class="course-item-<%= course.id %>"> <tr class="course-item-<%= course.id %>">
<%= render 'admins/courses/shared/td', course: course %> <%= render partial: 'admins/courses/shared/td', locals: {course: course, no: index} %>
</tr> </tr>
<% end %> <% end %>
<% else %> <% else %>

@ -1,3 +1,4 @@
<td><%= list_index_no((params[:page] || 1).to_i, no) %></td>
<td><%= course.id %></td> <td><%= course.id %></td>
<td class="text-left"> <td class="text-left">
<%= link_to(course.name, "/courses/#{course.id}", target: '_blank') %> <%= link_to(course.name, "/courses/#{course.id}", target: '_blank') %>

@ -1 +1,3 @@
$("#course-item-<%= @course.id %>").html("<%= j render partial: "admins/courses/shared/td",locals: {course: @course} %>") var index = $("#course-item-<%= @course.id %>").children(":first").html();
$("#course-item-<%= @course.id %>").html("<%= j render partial: "admins/courses/shared/td",locals: {course: @course, no: 1} %>");
$("#course-item-<%= @course.id %>").children(":first").html(index);

@ -1,15 +1,17 @@
<table class="table table-hover text-center customer-list-table"> <table class="table table-hover text-center customer-list-table">
<thead class="thead-light"> <thead class="thead-light">
<tr> <tr>
<th width="50%" class="text-left">客户名称</th> <th width="10%">序号</th>
<th width="40%" class="text-left">客户名称</th>
<th width="30%"><%= sort_tag('添加时间', name: 'created_at', path: admins_partner_customers_path(current_partner)) %></th> <th width="30%"><%= sort_tag('添加时间', name: 'created_at', path: admins_partner_customers_path(current_partner)) %></th>
<th width="20%">操作</th> <th width="20%">操作</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<% if customers.present? %> <% if customers.present? %>
<% customers.each do |customer| %> <% customers.each_with_index do |customer, index| %>
<tr class="customer-item-<%= customer.id %>"> <tr class="customer-item-<%= customer.id %>">
<td><%= list_index_no((params[:page] || 1).to_i, index) %></td>
<td class="text-left"><%= customer.school&.name %></td> <td class="text-left"><%= customer.school&.name %></td>
<td><%= customer.created_at&.strftime('%Y-%m-%d %H:%M') %></td> <td><%= customer.created_at&.strftime('%Y-%m-%d %H:%M') %></td>
<td> <td>

@ -1,8 +1,8 @@
<table class="table table-hover daily-school-statistic-list-table"> <table class="table table-hover daily-school-statistic-list-table">
<thead class="thead-light"> <thead class="thead-light">
<tr> <tr>
<th width="4%">序号</th>
<th width="12%" class="text-left">单位名称</th> <th width="12%" class="text-left">单位名称</th>
<th width="10%"><%= sort_tag('教师总数', name: 'teacher_count', path: admins_daily_school_statistics_path) %></th> <th width="10%"><%= sort_tag('教师总数', name: 'teacher_count', path: admins_daily_school_statistics_path) %></th>
<th width="10%"><%= sort_tag('学生总数', name: 'student_count', path: admins_daily_school_statistics_path) %></th> <th width="10%"><%= sort_tag('学生总数', name: 'student_count', path: admins_daily_school_statistics_path) %></th>
<th width="10%"><%= sort_tag('课堂总数', name: 'course_count', path: admins_daily_school_statistics_path) %></th> <th width="10%"><%= sort_tag('课堂总数', name: 'course_count', path: admins_daily_school_statistics_path) %></th>
@ -16,13 +16,14 @@
</th> </th>
<th width="11%"><%= sort_tag('实训作业总数', name: 'homework_count', path: admins_daily_school_statistics_path) %></th> <th width="11%"><%= sort_tag('实训作业总数', name: 'homework_count', path: admins_daily_school_statistics_path) %></th>
<th width="11%"><%= sort_tag('其它作业总数', name: 'other_homework_count', path: admins_daily_school_statistics_path) %></th> <th width="11%"><%= sort_tag('其它作业总数', name: 'other_homework_count', path: admins_daily_school_statistics_path) %></th>
<th width="13%"><%= sort_tag('动态时间', name: 'nearly_course_time', path: admins_daily_school_statistics_path) %></th> <th width="9%"><%= sort_tag('动态时间', name: 'nearly_course_time', path: admins_daily_school_statistics_path) %></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<% if statistics.present? %> <% if statistics.present? %>
<% statistics.each do |statistic| %> <% statistics.each_with_index do |statistic, index| %>
<tr> <tr>
<td><%= list_index_no(@params_page.to_i, index) %></td>
<td class="text-left"> <td class="text-left">
<%= link_to statistic[:name], "/colleges/#{statistic[:id]}/statistics", <%= link_to statistic[:name], "/colleges/#{statistic[:id]}/statistics",
target: '_blank', data: { toggle: 'tooltip', title: '点击查看学校统计概况' } %> target: '_blank', data: { toggle: 'tooltip', title: '点击查看学校统计概况' } %>

@ -1,18 +1,20 @@
<table class="table table-hover text-center department_applies-list-table"> <table class="table table-hover text-center department_applies-list-table">
<thead class="thead-light"> <thead class="thead-light">
<tr> <tr>
<th width="4%">序号</th>
<th width="8%">ID</th> <th width="8%">ID</th>
<th width="22%" class="text-left">部门名称</th> <th width="22%" class="text-left">部门名称</th>
<th width="20%" class="text-left">单位名称</th> <th width="20%" class="text-left">单位名称</th>
<th width="15%">创建者</th> <th width="11%">创建者</th>
<th width="15%"><%= sort_tag('创建于', name: 'created_at', path: admins_department_applies_path) %></th> <th width="15%"><%= sort_tag('创建于', name: 'created_at', path: admins_department_applies_path) %></th>
<th width="20%">操作</th> <th width="20%">操作</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<% if applies.present? %> <% if applies.present? %>
<% applies.each do |apply| %> <% applies.each_with_index do |apply, index| %>
<tr class="department-apply-<%= apply.id %>"> <tr class="department-apply-<%= apply.id %>">
<td><%= list_index_no((params[:page] || 1).to_i, index) %></td>
<td><%= apply.id %></td> <td><%= apply.id %></td>
<td class="text-left"> <%= apply.name %></td> <td class="text-left"> <%= apply.name %></td>
<td class="text-left"> <%= apply.school.try(:name) %></td> <td class="text-left"> <%= apply.school.try(:name) %></td>

@ -1,4 +1,6 @@
$('.modal.admin-add-department-member-modal').modal('hide'); $('.modal.admin-add-department-member-modal').modal('hide');
$.notify({ message: '操作成功' }); $.notify({ message: '操作成功' });
$('.department-list-table .department-item-<%= current_department.id %>').html("<%= j(render partial: 'admins/departments/shared/department_item', locals: { department: current_department }) %>") var index = $(".department-item-<%= current_department.id %>").children(":first").html();
$('.department-list-table .department-item-<%= current_department.id %>').html("<%= j(render partial: 'admins/departments/shared/department_item', locals: { department: current_department, index: 1 }) %>");
$(".department-item-<%= current_department.id %>").children(":first").html(index);

@ -1,3 +1,4 @@
<td><%= list_index_no((params[:page] || 1).to_i, index) %></td>
<% not_list = defined?(:users_count) %> <% not_list = defined?(:users_count) %>
<td class="text-left"><%= overflow_hidden_span department.name, width: 150 %></td> <td class="text-left"><%= overflow_hidden_span department.name, width: 150 %></td>

@ -1,10 +1,11 @@
<table class="table table-hover text-center department-list-table"> <table class="table table-hover text-center department-list-table">
<thead class="thead-light"> <thead class="thead-light">
<tr> <tr>
<th width="4%">序号</th>
<th width="14%" class="text-left">部门名称</th> <th width="14%" class="text-left">部门名称</th>
<th width="14%" class="text-left">单位名称</th> <th width="14%" class="text-left">单位名称</th>
<th width="6%">用户数</th> <th width="6%">用户数</th>
<th width="10%">已职业认证</th> <th width="6%">已职业认证</th>
<th width="20%">部门管理员</th> <th width="20%">部门管理员</th>
<th width="8%">统计链接</th> <th width="8%">统计链接</th>
<th width="8%">云主机数</th> <th width="8%">云主机数</th>
@ -14,9 +15,9 @@
</thead> </thead>
<tbody> <tbody>
<% if departments.present? %> <% if departments.present? %>
<% departments.each do |department| %> <% departments.each_with_index do |department, index| %>
<tr class="department-item-<%= department.id %>"> <tr class="department-item-<%= department.id %>">
<%= render 'admins/departments/shared/department_item', department: department %> <%= render partial: 'admins/departments/shared/department_item', locals: {department: department, index: index} %>
</tr> </tr>
<% end %> <% end %>
<% else %> <% else %>

@ -1,4 +1,6 @@
$('.modal.admin-edit-department-modal').modal('hide'); $('.modal.admin-edit-department-modal').modal('hide');
$.notify({ message: '操作成功' }); $.notify({ message: '操作成功' });
$('.department-list-table .department-item-<%= current_department.id %>').html("<%= j(render partial: 'admins/departments/shared/department_item', locals: { department: current_department }) %>") var index = $(".department-item-<%= current_department.id %>").children(":first").html();
$('.department-list-table .department-item-<%= current_department.id %>').html("<%= j(render partial: 'admins/departments/shared/department_item', locals: {department: current_department, index: 1}) %>");
$(".department-item-<%= current_department.id %>").children(":first").html(index);

@ -3,6 +3,7 @@
<table class="table table-hover text-center identity-authentication-list-table"> <table class="table table-hover text-center identity-authentication-list-table">
<thead class="thead-light"> <thead class="thead-light">
<tr> <tr>
<th width="4%">序号</th>
<% unless is_processed %> <% unless is_processed %>
<th width="4%"> <th width="4%">
<%= check_box_tag('all-check', 1, false, id: nil, class: 'batch-all-check-box', <%= check_box_tag('all-check', 1, false, id: nil, class: 'batch-all-check-box',
@ -13,7 +14,7 @@
<th width="10%">姓名</th> <th width="10%">姓名</th>
<th width="14%">身份证号</th> <th width="14%">身份证号</th>
<th width="20%">学校/单位</th> <th width="20%">学校/单位</th>
<th width="12%">职称</th> <th width="8%">职称</th>
<% unless is_processed %> <% unless is_processed %>
<th width="8%"> <th width="8%">
照片 照片
@ -33,9 +34,10 @@
</thead> </thead>
<tbody> <tbody>
<% if applies.present? %> <% if applies.present? %>
<% applies.each do |apply| %> <% applies.each_with_index do |apply, index| %>
<% user = apply.user %> <% user = apply.user %>
<tr class="identity-authentication-item identity-authentication-<%= apply.id %>"> <tr class="identity-authentication-item identity-authentication-<%= apply.id %>">
<td><%= list_index_no((params[:page] || 1).to_i, index) %></td>
<% unless is_processed %> <% unless is_processed %>
<td><%= check_box_tag('ids[]', apply.id, false, id: nil, class: 'batch-check-box') %></td> <td><%= check_box_tag('ids[]', apply.id, false, id: nil, class: 'batch-check-box') %></td>
<% end %> <% end %>

@ -1,4 +1,5 @@
<% school = laboratory.school %> <% school = laboratory.school %>
<td><%= list_index_no((params[:page] || 1).to_i, index) %></td>
<td class="text-left"><%= school&.name || 'EduCoder主站' %></td> <td class="text-left"><%= school&.name || 'EduCoder主站' %></td>
<td class="text-left"> <td class="text-left">
<% if laboratory.identifier %> <% if laboratory.identifier %>

@ -1,6 +1,7 @@
<table class="table table-hover text-center laboratory-list-table"> <table class="table table-hover text-center laboratory-list-table">
<thead class="thead-light"> <thead class="thead-light">
<tr> <tr>
<th width="4%">序号</th>
<th width="14%" class="text-left">单位名称</th> <th width="14%" class="text-left">单位名称</th>
<th width="16%" class="text-left">域名</th> <th width="16%" class="text-left">域名</th>
<th width="6%">统计链接</th> <th width="6%">统计链接</th>
@ -9,14 +10,14 @@
<th width="4%" title="同步显示主站下该单位的课堂">同步课堂</th> <th width="4%" title="同步显示主站下该单位的课堂">同步课堂</th>
<th width="4%" title="同步显示主站下该单位用户创建的实践课程">同步实践课程</th> <th width="4%" title="同步显示主站下该单位用户创建的实践课程">同步实践课程</th>
<th width="4%" title="同步显示主站下该单位用户创建的实训">同步实训</th> <th width="4%" title="同步显示主站下该单位用户创建的实训">同步实训</th>
<th width="20%">操作</th> <th width="16%">操作</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<% if laboratories.present? %> <% if laboratories.present? %>
<% laboratories.each do |laboratory| %> <% laboratories.each_with_index do |laboratory, index| %>
<tr class="laboratory-item laboratory-item-<%= laboratory.id %>"> <tr class="laboratory-item laboratory-item-<%= laboratory.id %>">
<%= render 'admins/laboratories/shared/laboratory_item', laboratory: laboratory %> <%= render partial: 'admins/laboratories/shared/laboratory_item', locals: {laboratory: laboratory, index: index} %>
</tr> </tr>
<% end %> <% end %>
<% else %> <% else %>

@ -1 +1,3 @@
$(".laboratory-item-<%= @laboratory.id %>").html("<%= j render partial: "admins/laboratories/shared/laboratory_item",locals: {laboratory: @laboratory} %>") var index = $(".laboratory-item-<%= @laboratory.id %>").children(":first").html();
$(".laboratory-item-<%= @laboratory.id %>").html("<%= j render partial: "admins/laboratories/shared/laboratory_item",locals: {laboratory: @laboratory, index: 1} %>");
$(".laboratory-item-<%= @laboratory.id %>").children(":first").html(index);

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save