diff --git a/.gitignore b/.gitignore index ea08c700e..12dc596a6 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ # Ignore bundler config. /.bundle +/bundle # Ignore lock config file *.lock @@ -70,3 +71,13 @@ vendor/bundle/ /workspace /log /public/admin +/mysql_data + + +.generators +.rakeTasks +db/bak/ +docker/ +educoder.sql +redis_data/ +Dockerfile \ No newline at end of file diff --git a/Gemfile b/Gemfile index 55030971d..55478816f 100644 --- a/Gemfile +++ b/Gemfile @@ -103,3 +103,6 @@ gem 'diffy' # oauth2 gem 'omniauth', '~> 1.9.0' gem 'omniauth-oauth2', '~> 1.6.0' + +# global var +gem 'request_store' diff --git a/app/controllers/admins/base_controller.rb b/app/controllers/admins/base_controller.rb index f90c8a1ed..0451b77d1 100644 --- a/app/controllers/admins/base_controller.rb +++ b/app/controllers/admins/base_controller.rb @@ -6,10 +6,10 @@ class Admins::BaseController < ApplicationController layout 'admin' skip_before_action :verify_authenticity_token - before_action :require_login, :require_admin! after_action :rebind_event_if_ajax_render_partial + skip_before_action :check_sign private diff --git a/app/controllers/admins/customers_controller.rb b/app/controllers/admins/customers_controller.rb index 80b01757b..8235bdb80 100644 --- a/app/controllers/admins/customers_controller.rb +++ b/app/controllers/admins/customers_controller.rb @@ -1,4 +1,5 @@ class Admins::CustomersController < Admins::BaseController + # skip_before_action :check_sign helper_method :current_partner def index diff --git a/app/controllers/admins/schools_controller.rb b/app/controllers/admins/schools_controller.rb index 7e1626d98..8c4f1d59e 100644 --- a/app/controllers/admins/schools_controller.rb +++ b/app/controllers/admins/schools_controller.rb @@ -5,7 +5,7 @@ class Admins::SchoolsController < Admins::BaseController schools = Admins::SchoolQuery.call(params) - @schools = paginate schools.includes(:user_extensions) + @schools = paginate schools school_ids = @schools.map(&:id) @department_count = Department.where(school_id: school_ids).group(:school_id).count diff --git a/app/controllers/admins/shixun_settings_controller.rb b/app/controllers/admins/shixun_settings_controller.rb index 6dbbc077a..37ca45674 100644 --- a/app/controllers/admins/shixun_settings_controller.rb +++ b/app/controllers/admins/shixun_settings_controller.rb @@ -5,9 +5,10 @@ class Admins::ShixunSettingsController < Admins::BaseController shixun_settings = Admins::ShixunSettingsQuery.call(params) @editing_shixuns = shixun_settings.where(status:0).size - @pending_shixuns = shixun_settings.where(status:1).size - @processed_shixuns = shixun_settings.where(status:2).size + @processed_shixuns = shixun_settings.where(status:2, public: 0).size @closed_shixuns = shixun_settings.where(status:3).size + @pending_public_shixuns = shixun_settings.where(public:1).size + @processed_pubic_shixuns = shixun_settings.where(public:2).size @sort_json = { can_copy: params[:can_copy].present? ? params[:can_copy] : false, @@ -83,9 +84,9 @@ class Admins::ShixunSettingsController < Admins::BaseController sheet1[count_row, 6] = shixun.myshixuns_count sheet1[count_row, 7] = shixun.myshixuns.select{|m| m.status == 1}.size sheet1[count_row, 8] = shixun.shixun_status - sheet1[count_row, 9] = shixun.user.show_real_name - sheet1[count_row, 10] = shixun.user.school_name - sheet1[count_row, 11] = shixun.user.identity + sheet1[count_row, 9] = shixun.user&.show_real_name + sheet1[count_row, 10] = shixun.user&.school_name + sheet1[count_row, 11] = shixun.user&.identity shixun.challenges.each do |challenge| sheet1[count_row, 12] = "第#{challenge.position}关" sheet1[count_row, 13] = challenge.subject @@ -112,13 +113,16 @@ class Admins::ShixunSettingsController < Admins::BaseController sheet1[count_row, 2] = shixun.mirror_repositories.select{|mr| mr.main_type == "1"}.first&.type_name sheet1[count_row, 3] = shixun.fork_from sheet1[count_row, 4] = shixun.shixun_status - sheet1[count_row, 5] = shixun.user.show_real_name - sheet1[count_row, 6] = shixun.user.school_name - sheet1[count_row, 7] = shixun.user.identity - shixun.challenges.each do |challenge| + sheet1[count_row, 5] = shixun.user&.show_real_name + sheet1[count_row, 6] = shixun.user&.school_name + sheet1[count_row, 7] = shixun.user&.identity + challenge_count = shixun.challenges.count + shixun.challenges.each_with_index do |challenge, index| sheet1[count_row, 8] = "第#{challenge.position}关" sheet1[count_row, 9] = challenge.subject - count_row += 1 + if index + 1 != challenge_count + count_row += 1 + end end count_row += 1 end diff --git a/app/controllers/admins/shixuns_controller.rb b/app/controllers/admins/shixuns_controller.rb index e2d2830ad..86cb9b45f 100644 --- a/app/controllers/admins/shixuns_controller.rb +++ b/app/controllers/admins/shixuns_controller.rb @@ -5,9 +5,10 @@ class Admins::ShixunsController < Admins::BaseController params[:sort_direction] = params[:sort_direction].presence || 'desc' shixuns = Admins::ShixunQuery.call(params) @editing_shixuns = shixuns.where(status:0).size - @pending_shixuns = shixuns.where(status:1).size - @processed_shixuns = shixuns.where(status:2).size + @processed_shixuns = shixuns.where(status:2, public: 0).size @closed_shixuns = shixuns.where(status:3).size + @pending_public_shixuns = shixuns.where(public:1).size + @processed_pubic_shixuns = shixuns.where(public:2).size @shixuns_type_check = MirrorRepository.pluck(:type_name,:id) @params_page = params[:page] || 1 @shixuns = paginate shixuns.preload(:user,:challenges) diff --git a/app/controllers/admins/users_controller.rb b/app/controllers/admins/users_controller.rb index 9630394b4..b9a07ba1e 100644 --- a/app/controllers/admins/users_controller.rb +++ b/app/controllers/admins/users_controller.rb @@ -61,7 +61,7 @@ class Admins::UsersController < Admins::BaseController private def update_params - params.require(:user).permit(%i[lastname nickname gender identity technical_title student_id + params.require(:user).permit(%i[lastname nickname gender identity technical_title student_id is_shixun_marker mail phone location location_city school_id department_id admin business is_test password professional_certification authentication]) end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 3ec8ad0f7..254d04cfd 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -12,6 +12,7 @@ class ApplicationController < ActionController::Base protect_from_forgery prepend: true, unless: -> { request.format.json? } + before_action :check_sign before_action :user_setup #before_action :check_account @@ -20,12 +21,37 @@ class ApplicationController < ActionController::Base helper_method :current_user + # 所有请求必须合法签名 + def check_sign + Rails.logger.info("66666 #{params}") + suffix = request.url.split(".").last.split("?").first + suffix_arr = ["xls", "xlsx", "pdf"] # excel文件先注释 + unless suffix_arr.include?(suffix) + if params[:client_key].present? + randomcode = params[:randomcode] + # tip_exception(501, "请求不合理") unless (Time.now.to_i - randomcode.to_i).between?(0,5) + + sign = Digest::MD5.hexdigest("#{OPENKEY}#{randomcode}") + Rails.logger.info("2222 #{sign}") + tip_exception(501, "请求不合理") if sign != params[:client_key] + else + tip_exception(501, "请求不合理") + end + end + end + # 全局配置参数 # 返回name对应的value def edu_setting(name) EduSetting.get(name) end + def shixun_marker + unless current_user.is_shixun_marker? || current_user.admin_or_business? + tip_exception(403, "..") + end + end + # 实训的访问权限 def shixun_access_allowed if !current_user.shixun_permission(@shixun) @@ -256,9 +282,10 @@ class ApplicationController < ActionController::Base end def user_setup - # reacct静态资源加载不需要走这一步 + # # reacct静态资源加载不需要走这一步 return if params[:controller] == "main" # Find the current user + #Rails.logger.info("current_laboratory is #{current_laboratory} domain is #{request.subdomain}") User.current = find_current_user uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous")) @@ -283,7 +310,7 @@ class ApplicationController < ActionController::Base # 测试版前端需求 logger.info("subdomain:#{request.subdomain}") - if request.subdomain == "test-newweb" + if request.subdomain != "www" if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除 User.current = User.find 81403 elsif params[:debug] == 'student' @@ -303,7 +330,7 @@ class ApplicationController < ActionController::Base current_domain_session = session[:"#{default_yun_session}"] if current_domain_session # existing session - (User.active.find(current_domain_session) rescue nil) + User.current = (User.active.find(current_domain_session) rescue nil) elsif autologin_user = try_to_autologin autologin_user elsif params[:format] == 'atom' && params[:key] && request.get? && accept_rss_auth? @@ -400,7 +427,7 @@ class ApplicationController < ActionController::Base end rescue Exception => e uid_logger("--uri_exec: exception #{e.message}") - raise Educoder::TipException.new("实训平台繁忙(繁忙等级:84)") + raise Educoder::TipException.new(message) end end @@ -465,9 +492,9 @@ class ApplicationController < ActionController::Base # 实训主类别列表,自带描述 def shixun_main_type 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| - 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 list end @@ -475,9 +502,9 @@ class ApplicationController < ActionController::Base # 小类别列表 def shixun_small_type 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| - 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 list end @@ -603,7 +630,7 @@ class ApplicationController < ActionController::Base end def paginate(relation) - limit = params[:limit].to_i.zero? ? 20 : params[:limit].to_i + limit = (params[:limit].to_i.zero? || params[:limit].to_i > 20) ? 20 : params[:limit].to_i page = params[:page].to_i.zero? ? 1 : params[:page].to_i offset = (page - 1) * limit @@ -678,4 +705,5 @@ class ApplicationController < ActionController::Base HotSearchKeyword.add(keyword) end + end diff --git a/app/controllers/attachments_controller.rb b/app/controllers/attachments_controller.rb index f58fe12bf..e0dd71467 100644 --- a/app/controllers/attachments_controller.rb +++ b/app/controllers/attachments_controller.rb @@ -5,6 +5,7 @@ class AttachmentsController < ApplicationController before_action :require_login, :check_auth, except: [:show] before_action :find_file, only: %i[show destroy] before_action :attachment_candown, only: [:show] + skip_before_action :check_sign, only: [:show, :create] include ApplicationHelper @@ -28,55 +29,56 @@ class AttachmentsController < ApplicationController def create # 1. 本地存储 # 2. 上传到云 - upload_file = params["file"] || params["#{params[:file_param_name]}"] # 这里的file_param_name是为了方便其他插件名称 - uid_logger("#########################file_params####{params["#{params[:file_param_name]}"]}") - raise "未上传文件" unless upload_file - - folder = edu_setting('attachment_folder') - raise "存储目录未定义" unless folder.present? - - month_folder = current_month_folder - save_path = File.join(folder, month_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' - - # remote_path = file_save_to_ucloud(local_path[folder.size, local_path.size], local_path, content_type) - remote_path = nil # TODO 暂时本地上传,待域名配置后方可上传至云端 - - logger.info "local_path: #{local_path}" - logger.info "remote_path: #{remote_path}" - - - disk_filename = local_path[save_path.size + 1, local_path.size] - #存数据库 - # - @attachment = Attachment.where(disk_filename: disk_filename, - author_id: current_user.id, - cloud_url: remote_path).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 = month_folder - @attachment.cloud_url = remote_path - @attachment.container_id = conversion_container_id(params[:container_id], params[:container_type]) - @attachment.container_type = params[:container_type] - @attachment.attachtype = params[:attachtype] - @attachment.save! - else - logger.info "文件已存在,id = #{@attachment.id}, filename = #{@attachment.filename}" - end + begin + upload_file = params["file"] || params["#{params[:file_param_name]}"] # 这里的file_param_name是为了方便其他插件名称 + uid_logger("#########################file_params####{params["#{params[:file_param_name]}"]}") + raise "未上传文件" unless upload_file + + folder = edu_setting('attachment_folder') + raise "存储目录未定义" unless folder.present? + + month_folder = current_month_folder + save_path = File.join(folder, month_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' + + # remote_path = file_save_to_ucloud(local_path[folder.size, local_path.size], local_path, content_type) + remote_path = nil # TODO 暂时本地上传,待域名配置后方可上传至云端 + + logger.info "local_path: #{local_path}" + logger.info "remote_path: #{remote_path}" + + + disk_filename = local_path[save_path.size + 1, local_path.size] + #存数据库 + # + @attachment = Attachment.where(disk_filename: disk_filename, + author_id: current_user.id, + cloud_url: remote_path).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 = month_folder + @attachment.cloud_url = remote_path + @attachment.save! + else + logger.info "文件已存在,id = #{@attachment.id}, filename = #{@attachment.filename}" + end - render_json + render_json + rescue => e + uid_logger_error(e.message) + tip_exception(e.message) + end end def destroy @@ -94,22 +96,6 @@ class AttachmentsController < ApplicationController end end - # 多文件删除 - def destroy_files - files = Attachment.where(id: params[:id]) - begin - files.each do |file| - file_path = absolute_path(local_path(file)) - file.destroy! - delete_file(file_path) - end - render_ok - rescue => e - uid_logger_error(e.message) - tip_exception(e.message) - end - end - private def find_file @file = @@ -216,11 +202,4 @@ class AttachmentsController < ApplicationController end end - def conversion_container_id id, type - if id.is_a?(String) && type == 'Shixun' - Shixun.find_by_identifier(id).id - else - id - end - end end diff --git a/app/controllers/challenges_controller.rb b/app/controllers/challenges_controller.rb index 0b5140743..354d63f6d 100644 --- a/app/controllers/challenges_controller.rb +++ b/app/controllers/challenges_controller.rb @@ -13,6 +13,9 @@ class ChallengesController < ApplicationController include ShixunsHelper include ChallengesHelper + + + # 新建实践题 def new @position = @shixun.challenges.count + 1 @@ -160,6 +163,8 @@ class ChallengesController < ApplicationController @shixun.increment!(:visits) end + + def show @tab = params[:tab].nil? ? 1 : params[:tab].to_i challenge_num = @shixun.challenges_count @@ -173,64 +178,70 @@ class ChallengesController < ApplicationController # tab 0:过关任务的更新; 1:评测设置的更新; 2:表示参考答案的更新; def update - ActiveRecord::Base.transaction do - tab = params[:tab].to_i - @challenge.update_attributes(challenge_params) - if tab == 0 && @challenge.st == 0 - @challenge.challenge_tags.delete_all - if params[:challenge_tag].present? - params[:challenge_tag].each do |input| - ChallengeTag.create!(:name => input, :challenge_id => @challenge.id) + begin + ActiveRecord::Base.transaction do + tab = params[:tab].to_i + @challenge.update_attributes(challenge_params) + if tab == 0 && @challenge.st == 0 + @challenge.challenge_tags.delete_all + if params[:challenge_tag].present? + params[:challenge_tag].each do |input| + ChallengeTag.create!(:name => input, :challenge_id => @challenge.id) + end end - end - elsif tab == 1 - path = @challenge.path - exec_path = @challenge.exec_path - test_set = @challenge.test_sets - sets_output = test_set.map(&:output) - sets_input = test_set.map(&:input) - sets_open = test_set.map(&:is_public) - set_score = test_set.map(&:score) - set_match_rule = test_set.map(&:match_rule) - params_hidden = params[:test_set].map{|set| set[:hidden].to_i == 0} - params_output = params[:test_set].map{|set| set[:output] } - params_input = params[:test_set].map{|set| set[:input] } - params_score = params[:test_set].map{|set| set[:score]} - params_test_set = params[:test_set].map{|set| set[:match_rule]} - # 测试集变化则需要更新(输入、 输出、 是否隐藏) - if sets_output != params_output || sets_open != params_hidden || sets_input != params_input || - set_score != params_score || params_test_set != set_match_rule - test_set.delete_all unless test_set.blank? - params[:test_set].each_with_index do |set, index| - # last: 末尾匹配, full: 全完匹配 - logger.info("set: #{set}; match_rule : #{set[:match_rule]}") - match_rule = set[:match_rule] == 'last' ? 'last' : 'full' - TestSet.create(:challenge_id => @challenge.id, - :input => "#{set[:input]}", - :output => "#{set[:output]}", - :is_public => params_hidden[index], - :score => set[:score], - :match_rule => "#{match_rule}", - :position => (index + 1)) + elsif tab == 1 + path = @challenge.path + exec_path = @challenge.exec_path + test_set = @challenge.test_sets + sets_output = test_set.map(&:output) + sets_input = test_set.map(&:input) + sets_open = test_set.map(&:is_public) + set_score = test_set.map(&:score) + set_match_rule = test_set.map(&:match_rule) + params_hidden = params[:test_set].map{|set| set[:hidden].to_i == 0} + params_output = params[:test_set].map{|set| set[:output] } + params_input = params[:test_set].map{|set| set[:input] } + params_score = params[:test_set].map{|set| set[:score]} + params_test_set = params[:test_set].map{|set| set[:match_rule]} + # 测试集变化则需要更新(输入、 输出、 是否隐藏) + if sets_output != params_output || sets_open != params_hidden || sets_input != params_input || + set_score != params_score || params_test_set != set_match_rule + test_set.delete_all unless test_set.blank? + params[:test_set].each_with_index do |set, index| + # last: 末尾匹配, full: 全完匹配 + logger.info("set: #{set}; match_rule : #{set[:match_rule]}") + match_rule = set[:match_rule] == 'last' ? 'last' : 'full' + TestSet.create(:challenge_id => @challenge.id, + :input => "#{set[:input]}", + :output => "#{set[:output]}", + :is_public => params_hidden[index], + :score => set[:score], + :match_rule => "#{match_rule}", + :position => (index + 1)) + end + @challenge.update_column(:modify_time, Time.now) + # 测试集的 + @shixun.myshixuns.update_all(:system_tip => 0) end - @challenge.update_column(:modify_time, Time.now) - # 测试集的 - @shixun.myshixuns.update_all(:system_tip => 0) - end - if params[:challenge][:show_type].to_i == -1 - @challenge.update_attributes(picture_path: nil, web_route: nil, expect_picture_path: nil, original_picture_path: nil) + if params[:challenge][:show_type].to_i == -1 + @challenge.update_attributes(picture_path: nil, web_route: nil, expect_picture_path: nil, original_picture_path: nil) + end + # 关卡评测执行文件如果被修改,需要修改脚本内容 + script = modify_shixun_script @shixun, @shixun.evaluate_script + @shixun.shixun_info.update_column(:evaluate_script, script) + # TODO: + # if path != params[:challenge][:path] + # shixun_modify_status_without_publish(@shixun, 1) + # end + #Attachment.attach_files(@challenge, params[:attachments]) end - # 关卡评测执行文件如果被修改,需要修改脚本内容 - script = modify_shixun_script @shixun, @shixun.evaluate_script - @shixun.shixun_info.update_column(:evaluate_script, script) - # TODO: - # if path != params[:challenge][:path] - # shixun_modify_status_without_publish(@shixun, 1) - # end - #Attachment.attach_files(@challenge, params[:attachments]) - end + end + rescue => e + logger_error("##update_challenges: ##{e.message}") + tip_exception("更新失败!") end + end # 参考答案的'增,删,改' diff --git a/app/controllers/colleges_controller.rb b/app/controllers/colleges_controller.rb index 4c33ad5e5..707255866 100644 --- a/app/controllers/colleges_controller.rb +++ b/app/controllers/colleges_controller.rb @@ -1,7 +1,7 @@ class CollegesController < ApplicationController include PaginateHelper - layout 'college' + # layout 'college' before_action :require_login before_action :check_college_present! @@ -21,6 +21,7 @@ class CollegesController < ApplicationController # 实训总数 @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 @@ -43,6 +44,8 @@ class CollegesController < ApplicationController (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}") @@ -94,11 +97,11 @@ class CollegesController < ApplicationController 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, sum(games.evaluate_count) evaluating_count') + .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') - params[:per_page] = 8 @courses = paginate courses course_ids = @courses.map(&:id) @@ -114,6 +117,7 @@ class CollegesController < ApplicationController # 学生实训 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) @@ -154,7 +158,7 @@ class CollegesController < ApplicationController 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) + # return true if current_school.customers.exists? && current_user.partner&.partner_customers&.exists?(customer_id: current_school.customer_id) false end diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index 851567c92..c5d3082ba 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -22,7 +22,7 @@ class CommentsController < ApplicationController @discuss = @hack.discusses.new(reply_params) @discuss.hidden = false @discuss.user_id = current_user.id - @discuss.root_id = params[:parent_id] + @discuss.root_id = params[:comments][:parent_id] @discuss.save! rescue Exception => e uid_logger_error("reply discuss failed : #{e.message}") @@ -32,9 +32,14 @@ class CommentsController < ApplicationController # 列表 def index - disscusses = @hack.disscusses.where(:root_id => nil) - @disscuss_count = disscusses.count - @disscusses= paginate disscusses + discusses = + if current_user.admin_or_business? + @hack.discusses.where(root_id: nil) + else + @hack.discusses.where(root_id: nil, hidden: false) + end + @discusses_count = discusses.count + @discusses= paginate discusses end # 删除 @@ -43,10 +48,21 @@ class CommentsController < ApplicationController render_ok end + # 隐藏、取消隐藏 + def hidden + if current_user.admin_or_business? + @discuss = @hack.discusses.where(id: params[:id]).first + @discuss.update_attribute(:hidden, params[:hidden].to_i == 1) + sucess_status + else + Educoder::TipException(403, "..") + end + end + private def find_hack - @hack = Hack.find_by_identifier params[:identifier] + @hack = Hack.find_by_identifier(params[:hack_identifier]) end def comment_params diff --git a/app/controllers/concerns/git_helper.rb b/app/controllers/concerns/git_helper.rb index 085fec360..0d8604aac 100644 --- a/app/controllers/concerns/git_helper.rb +++ b/app/controllers/concerns/git_helper.rb @@ -45,6 +45,16 @@ module GitHelper content: content, author_name: username, author_email: mail) end + # 添加目录 + def git_add_folder(folder_path, author_name, author_email, message) + GitService.add_tree(file_path: folder_path, message: message, author_name: author_name, author_email: author_email) + end + + # 删除文件 + def git_delete_file(file_path, author_name, author_email, message) + GitService.delete_file(file_path: file_path, message: message, author_name: author_name, author_email: author_email) + end + # 版本库Fork功能 def project_fork(container, original_rep_path, username) raise Educoder::TipException.new("fork源路径为空,fork失败!") if original_rep_path.blank? diff --git a/app/controllers/cooperative/base_controller.rb b/app/controllers/cooperative/base_controller.rb index 51af05ed2..5d21598aa 100644 --- a/app/controllers/cooperative/base_controller.rb +++ b/app/controllers/cooperative/base_controller.rb @@ -10,13 +10,14 @@ class Cooperative::BaseController < ApplicationController before_action :laboratory_exist!, :require_login, :require_cooperative_manager! after_action :rebind_event_if_ajax_render_partial + skip_before_action :check_sign helper_method :current_laboratory, :current_setting_or_default private def current_laboratory - @_current_laboratory ||= Laboratory.find_by_subdomain(request.subdomain) + @_current_laboratory ||= (Laboratory.find_by_subdomain(request.subdomain) || Laboratory.first) # @_current_laboratory ||= Laboratory.find 1 end diff --git a/app/controllers/courses_controller.rb b/app/controllers/courses_controller.rb index b08ba2dbd..52911e905 100644 --- a/app/controllers/courses_controller.rb +++ b/app/controllers/courses_controller.rb @@ -29,7 +29,7 @@ class CoursesController < ApplicationController :informs, :update_informs, :online_learning, :update_task_position, :tasks_list, :join_excellent_course, :export_couser_info, :export_member_act_score, :new_informs, :delete_informs, :change_member_role, :course_groups, :join_course_group, :statistics, - :work_score, :act_score] + :work_score, :act_score, :calculate_all_shixun_scores] before_action :user_course_identity, except: [:join_excellent_course, :index, :create, :new, :apply_to_join_course, :search_course_list, :get_historical_course_students, :mine, :search_slim, :board_list] before_action :teacher_allowed, only: [:update, :destroy, :settings, :search_teacher_candidate, @@ -48,7 +48,7 @@ class CoursesController < ApplicationController before_action :validate_page_size, only: :mine before_action :course_tasks, only: [:tasks_list, :update_task_position] before_action :validate_inform_params, only: [:update_informs, :new_informs] - before_action :course_member_allowed, only: [:statistics, :work_score, :act_score] + before_action :course_member_allowed, only: [:statistics, :work_score, :act_score, :calculate_all_shixun_scores] if RUBY_PLATFORM =~ /linux/ require 'simple_xlsx_reader' @@ -1318,7 +1318,7 @@ class CoursesController < ApplicationController @c_tasks = @course.graduation_tasks.task_published.order("graduation_tasks.publish_time asc, graduation_tasks.created_at asc") set_export_cookies - member_to_xlsx(@course, @all_members, @c_homeworks, @c_exercises, @c_tasks) + member_to_xlsx(@course, @all_members.includes(user: :user_extension), @c_homeworks, @c_exercises, @c_tasks) filename_ = "#{current_user.real_name}_#{@course.name}_总成绩_#{Time.now.strftime('%Y%m%d_%H%M%S')}" render xlsx: "#{format_sheet_name filename_.strip}",template: "courses/export_member_scores_excel.xlsx.axlsx", locals: {course_scores:@course_user_scores,shixun_works:@shixun_work_arrays, @@ -1334,6 +1334,16 @@ class CoursesController < ApplicationController end end + # 计算课堂所有已发布的实训作业成绩 + def calculate_all_shixun_scores + tip_exception(-1, "课堂已结束") if @course.is_end + shixun_homeworks = @course.homework_commons.homework_published.where(homework_type: 4) + shixun_homeworks.includes(:homework_challenge_settings, :published_settings, :homework_commons_shixun).each do |homework| + homework.update_homework_work_score + end + normal_status(0, "更新成功") + end + def search_slim courses = current_user.manage_courses.not_deleted.processing diff --git a/app/controllers/departments_controller.rb b/app/controllers/departments_controller.rb index 5e82b2c51..73cb19156 100644 --- a/app/controllers/departments_controller.rb +++ b/app/controllers/departments_controller.rb @@ -1,4 +1,6 @@ class DepartmentsController < ApplicationController + skip_before_action :check_sign + def for_option render_ok(departments: current_school.departments.without_deleted.select(:id, :name).as_json) end diff --git a/app/controllers/discusses_controller.rb b/app/controllers/discusses_controller.rb index cbb19cb7f..c2cc8f933 100644 --- a/app/controllers/discusses_controller.rb +++ b/app/controllers/discusses_controller.rb @@ -14,14 +14,14 @@ class DiscussesController < ApplicationController @disscuss_count = Discuss.where(:dis_id => @container.id, :dis_type => @container.class.to_s, :root_id => nil).count disscusses = Discuss.where(:dis_id => @container.id, :dis_type => @container.class.to_s, :root_id => nil) - @discusses = disscusses.limit(LIMIT).joins("left join games on discusses.challenge_id = games.challenge_id and discusses.user_id = games.user_id") - .select("discusses.*, games.identifier").includes(:user, :praise_treads).offset(offset) + @discusses = disscusses.joins("left join games on discusses.challenge_id = games.challenge_id and discusses.user_id = games.user_id") + .select("discusses.*, games.identifier").includes(:user, :praise_treads).limit(LIMIT).offset(offset) else disscusses = Discuss.where("dis_id = :dis_id and dis_type = :dis_type and root_id is null and (discusses.hidden = :hidden or discusses.user_id = :user_id)", {dis_id: @container.id, dis_type: @container.class.to_s, hidden: false, user_id: current_user.id}) @disscuss_count = disscusses.count("discusses.id") - @discusses = disscusses.limit(LIMIT).includes(:user, :praise_treads).offset(offset) + @discusses = disscusses.includes(:user, :praise_treads).limit(LIMIT).offset(offset) end @current_user = current_user @@ -117,13 +117,13 @@ class DiscussesController < ApplicationController # 0 取消赞; def plus pt = PraiseTread.where(:praise_tread_object_id => params[:id], :praise_tread_object_type => params[:container_type], - :user_id => current_user, :praise_or_tread => 1).first + :user_id => current_user, :praise_or_tread => 1) # 如果当前用户已赞过,则不能重复赞 if params[:type] == 1 && pt.blank? PraiseTread.create!(:praise_tread_object_id => params[:id], :praise_tread_object_type => params[:container_type], - :user_id => current_user.id, :praise_or_tread => 1) if pt.blank? + :user_id => current_user.id, :praise_or_tread => 1) else - pt.destroy if pt.present? # 如果已赞过,则删掉这条赞(取消);如果没赞过,则为非法请求不处理 + pt.destroy_all if pt.present? # 如果已赞过,则删掉这条赞(取消);如果没赞过,则为非法请求不处理 end @praise_count = PraiseTread.where(:praise_tread_object_id => params[:id], :praise_tread_object_type => params[:container_type], diff --git a/app/controllers/edu_settings_controller.rb b/app/controllers/edu_settings_controller.rb index 6baf38e5b..d3b796da7 100644 --- a/app/controllers/edu_settings_controller.rb +++ b/app/controllers/edu_settings_controller.rb @@ -1,7 +1,7 @@ class EduSettingsController < ApplicationController before_action :require_admin before_action :set_edu_setting, only: [:show, :edit, :update, :destroy] - + skip_before_action :check_sign # GET /edu_settings # GET /edu_settings.json def index diff --git a/app/controllers/games_controller.rb b/app/controllers/games_controller.rb index f4a914673..938d42c2f 100644 --- a/app/controllers/games_controller.rb +++ b/app/controllers/games_controller.rb @@ -3,7 +3,7 @@ class GamesController < ApplicationController before_action :find_game, except: [:jupyter] 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' @@ -88,11 +88,19 @@ class GamesController < ApplicationController 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("服务器出现问题,请重置刷新页面") + end end def reset_vnc_link diff --git a/app/controllers/gits_controller.rb b/app/controllers/gits_controller.rb index bbb0e293e..0767eab02 100644 --- a/app/controllers/gits_controller.rb +++ b/app/controllers/gits_controller.rb @@ -1,5 +1,5 @@ class GitsController < ApplicationController - + skip_before_action :check_sign # 说明: # 以下Git认证只针对新版git,Gitlab的Git认证不走该控制器 # 思路: @@ -39,7 +39,7 @@ class GitsController < ApplicationController # 用户是否对对象拥有权限 system_user = User.find_by_login(input_username) || User.find_by_mail(input_username) || User.find_by_phone(input_username) # 如果用户名密码错误 - if system_user && !system_user.check_password?(input_password) + if system_user.blank? || system_user && !system_user.check_password?(input_password) uid_logger_error("git start: password is wrong") result = false else diff --git a/app/controllers/graduation_topics_controller.rb b/app/controllers/graduation_topics_controller.rb index 0e6135e8c..9b3021994 100644 --- a/app/controllers/graduation_topics_controller.rb +++ b/app/controllers/graduation_topics_controller.rb @@ -140,8 +140,8 @@ class GraduationTopicsController < ApplicationController update_graduation_topic_status # 拒绝后将该学生移动到未分班中 - student_member = @course.course_members.where(:user_id => student_graduation_topic.user_id).first - student_member.update_attributes(:course_group_id => 0) if student_member.present? + # student_member = @course.course_members.where(:user_id => student_graduation_topic.user_id).first + # student_member.update_attributes(:course_group_id => 0) if student_member.present? student_graduation_topic.tidings.update_all(:status => 1) Tiding.create(:user_id => student_graduation_topic.user_id, :trigger_user_id => current_user.id, @@ -170,14 +170,15 @@ class GraduationTopicsController < ApplicationController teacher_group = @course.teacher_course_groups.where(:user_id => @graduation_topic.tea_id, :id => params[:group_id]).first unless teacher_group.present? member = @course.course_members.where(:user_id => @graduation_topic.tea_id).first - tip_exception("分班名称不能为空") if params[:course_group_name].blank? - course_group = CourseGroup.create(:name => params[:course_group_name], :course_id => @course.id) - teacher_group = TeacherCourseGroup.create(:course_id => @course.id, :course_member_id => member.try(:id), - :user_id => @graduation_topic.tea_id, - :course_group_id => course_group.try(:id)) + if params[:course_group_name].present? + course_group = CourseGroup.find_or_create_by!(:name => params[:course_group_name], :course_id => @course.id) + teacher_group = TeacherCourseGroup.find_or_create_by!(:course_id => @course.id, :course_member_id => member.try(:id), + :user_id => @graduation_topic.tea_id, + :course_group_id => course_group.try(:id)) + student_member = @course.course_members.where(:user_id => student_graduation_topic.user_id).first + student_member.update_attributes(:course_group_id => teacher_group.course_group_id) if student_member.present? + end end - student_member = @course.course_members.where(:user_id => student_graduation_topic.user_id).first - student_member.update_attributes(:course_group_id => teacher_group.course_group_id) if student_member.present? student_graduation_topic.tidings.update_all(:status => 1) Tiding.create(:user_id => student_graduation_topic.user_id, :trigger_user_id => current_user.id, diff --git a/app/controllers/hack_user_lastest_codes_controller.rb b/app/controllers/hack_user_lastest_codes_controller.rb index b7ec6fb8e..353833ee2 100644 --- a/app/controllers/hack_user_lastest_codes_controller.rb +++ b/app/controllers/hack_user_lastest_codes_controller.rb @@ -1,10 +1,11 @@ class HackUserLastestCodesController < ApplicationController before_action :require_login, except: [:listen_result] - before_action :find_my_hack, only: [:show, :code_debug, :code_submit, :update_code, :sync_code, + before_action :find_my_hack, only: [:show, :code_debug, :code_submit, :update_code, :sync_code, :add_notes, :listen_result, :result, :submit_records, :restore_initial_code] before_action :update_user_hack_status, only: [:code_debug, :code_submit] - before_action :require_auth_identity, only: [:update_code, :restore_initial_code, :sync_code] - before_action :require_manager_identity, only: [:update_code] + before_action :require_auth_identity, only: [:add_notes] + before_action :require_manager_identity, only: [:show, :update_code, :restore_initial_code, :sync_code] + skip_before_action :check_sign, only: [:listen_result] def show @my_hack.update_attribute(:submit_status, 0) if @my_hack.submit_status == 1 @@ -23,7 +24,7 @@ class HackUserLastestCodesController < ApplicationController # 同步代码 def sync_code - @my_hack.update_attributes(code: @hack.code, modify_time: @hack.modify_time) + @my_hack.update_attributes(code: @hack.code, modify_time: Time.now) end # 调试代码 @@ -61,13 +62,18 @@ class HackUserLastestCodesController < ApplicationController # 提交记录 def submit_records - @records = @my_hack.hack_user_codes.created_order - end + records = @my_hack.hack_user_codes + @records_count = records.count + @records = paginate records.created_order + end # 提交记录详情 def record_detail @hack_user = HackUserCode.find params[:id] + set = HackSet.find_by(id: @hack_user.error_test_set_id) + @pass_set_count = set ? set.position - 1 : 0 + @set_count = @hack_user.hack.hack_sets.count @my_hack = @hack_user.hack_user_lastest_code end @@ -80,7 +86,7 @@ class HackUserLastestCodesController < ApplicationController testCase = ojEvaResult['testCase'] # 只有编译出错时,才正则匹配错误行数 error_line= - if params[:status] == "-4" + if ojEvaResult['status'] == "4" || ojEvaResult['status'] == "5" regular_match_error_line ojEvaResult['outPut'], @my_hack.hack.language end # debug 与submit 公用的参数 @@ -94,7 +100,8 @@ class HackUserLastestCodesController < ApplicationController if ojEvaResult['execMode'] == "debug" save_debug_data ds_params elsif ojEvaResult['execMode'] == "submit" - save_submit_data ds_params.merge(expected_output: testCase['expectedOutput']) + save_submit_data ds_params.merge(expected_output: testCase['expectedOutput'], + error_test_set_id: ojEvaResult['failCaseNum']) end # 评测完成后,还原评测中的状态 @my_hack.update_attribute(:submit_status, 0) @@ -106,6 +113,11 @@ class HackUserLastestCodesController < ApplicationController end + def add_notes + @my_hack.update_attribute(:notes, params[:notes]) + render_ok + end + private def find_my_hack @my_hack = HackUserLastestCode.find_by(identifier: params[:identifier]) @@ -137,11 +149,12 @@ class HackUserLastestCodesController < ApplicationController # 正则错误行数 def regular_match_error_line content, language content = Base64.decode64(content).force_encoding("utf-8") + logger.info("######content: #{content}") case language when 'Java' content.scan(/.java.\d+/).map{|s| s.match(/\d+/)[0].to_i}.min when 'C', 'C++' - content.scan(/\d:\d+: error/).map{|s| s.match(/\d+/)[0]}.min + content.scan(/\d:\d+:/).map{|s| s.match(/\d+/)[0].to_i}.min when 'Python' content.scan(/line \d+/).map{|s| s.match(/\d+/)[0].to_i}.min end @@ -163,12 +176,12 @@ class HackUserLastestCodesController < ApplicationController # 通关 if submit_params[:status] == "0" # 编程题已经发布,且之前未通关奖励积分 + @hack.increment!(:pass_num) if @hack.status == 1 && !@my_hack.passed? - reward_attrs = { container_id: game.id, container_type: 'Hack', score: @hack.score } + reward_attrs = { container_id: @hack.id, container_type: 'Hack', score: @hack.score } RewardGradeService.call(@my_hack.user, reward_attrs) RewardExperienceService.call(@my_hack.user, reward_attrs) # 评测完成更新通过数 - @hack.increment!(:pass_num) @my_hack.update_attributes(passed: true, passed_time: Time.now) end end diff --git a/app/controllers/hacks_controller.rb b/app/controllers/hacks_controller.rb index 657ad0f2a..3eaac0648 100644 --- a/app/controllers/hacks_controller.rb +++ b/app/controllers/hacks_controller.rb @@ -1,17 +1,19 @@ class HacksController < ApplicationController before_action :require_login, except: [:index] - before_action :find_hack, only: [:edit, :update, :publish, :start, :update_set, :delete_set, :destroy] + before_action :find_hack, only: [:edit, :update, :publish, :start, :update_set, :delete_set, :destroy, :cancel_publish] before_action :require_teacher_identity, only: [:create] - before_action :require_auth_identity, only: [:update, :edit, :publish, :update_set, :delete_set, :destroy] + before_action :require_auth_identity, only: [:update, :edit, :publish, :update_set, :delete_set, :destroy, :cancel_publish] # 开启编程,如果第一次开启,创建一条记录,如果已经开启过的话,直接返回标识即可 def start # 未发布的编程题,只能作者、或管理员访问 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 = if user_hack.present? + logger.info("#####user_hack_id:#{user_hack.id}") user_hack.identifier else user_identifier = generate_identifier HackUserLastestCode, 12 @@ -42,12 +44,13 @@ class HacksController < ApplicationController begin logger.info("##########{hack_params}") hack = Hack.new(hack_params) + hack.user_id = current_user.id + hack.identifier = generate_identifier Hack, 8 ActiveRecord::Base.transaction do - hack.user_id = current_user.id - hack.identifier = generate_identifier Hack, 8 hack.save! # 创建测试集与代码 hack.hack_sets.create!(hack_sets_params) + # 新建知识点 hack_codes = hack.hack_codes.new(hack_code_params) hack_codes.modify_time = Time.now hack_codes.save! @@ -96,6 +99,22 @@ class HacksController < ApplicationController # 发布功能 def publish @hack.update_attribute(:status, 1) + base_attrs = { + trigger_user_id: current_user.id, viewed: 0, tiding_type: 'System', user_id: @hack.user_id, + parent_container_type: "HackPublish", extra: @hack.identifier + } + @hack.tidings.create!(base_attrs) + render_ok + end + + # 取消发布 + def cancel_publish + @hack.update_attribute(:status, 0) + base_attrs = { + trigger_user_id: current_user.id, viewed: 0, tiding_type: 'System', user_id: @hack.user_id, + parent_container_type: "HackUnPublish", extra: @hack.identifier + } + @hack.tidings.create!(base_attrs) render_ok end @@ -113,8 +132,19 @@ class HacksController < ApplicationController def new;end def destroy - @hack.destroy - render_ok + begin + base_attrs = { + user_id: @hack.user_id, viewed: 0, tiding_type: 'System', trigger_user_id: current_user.id, + parent_container_type: "HackDelete", extra: "#{@hack.name}" + } + @hack.tidings.create!(base_attrs) + @hack.destroy + render_ok + rescue => e + logger.error("####hack_delete_error: #{e.message}") + render_error("删除失败") + end + end private @@ -159,10 +189,13 @@ class HacksController < ApplicationController def param_update_sets sets, all_sets_id delete_set_ids = all_sets_id - sets.map{|set|set[:id]} @hack.hack_sets.where(id: delete_set_ids).destroy_all + logger.info("#######sets:#{sets}") sets.each do |set| + logger.info("###set[:id]: #{set[:id]}") + logger.info("###all_sets: #{all_sets_id.include?(set[:id])}") if all_sets_id.include?(set[:id]) update_attrs = {input: set[:input], output: set[:output], position: set[:position]} - @hack.hack_sets.find_by!(id: set[:id]).update_attributes(update_attrs) + @hack.hack_sets.find_by!(id: set[:id]).update_attributes!(update_attrs) end end end @@ -200,6 +233,11 @@ class HacksController < ApplicationController hacks = hacks.where(category: params[:category]) end + # 语言 + if params[:language] + hacks = hacks.joins(:hack_codes).where(hack_codes: {language: params[:language]}) + end + # 排序 sort_by = params[:sort_by] || "hack_user_lastest_codes_count" sort_direction = params[:sort_direction] || "desc" diff --git a/app/controllers/homework_commons_controller.rb b/app/controllers/homework_commons_controller.rb index e11fefea1..f9931c370 100644 --- a/app/controllers/homework_commons_controller.rb +++ b/app/controllers/homework_commons_controller.rb @@ -11,7 +11,7 @@ class HomeworkCommonsController < ApplicationController before_action :find_homework, only: [:edit, :show, :update, :group_list, :homework_code_repeat, :code_review_results, :code_review_detail, :show_comment, :settings, :works_list, :update_settings, :reference_answer, :publish_groups, :end_groups, :alter_name, :update_explanation, - :update_score, :update_student_score] + :update_score, :update_student_score, :batch_comment] before_action :user_course_identity before_action :homework_publish, only: [:show, :works_list, :code_review_results, :show_comment, :settings, :reference_answer, :update_student_score] @@ -19,7 +19,7 @@ class HomeworkCommonsController < ApplicationController :publish_homework, :end_homework, :set_public, :choose_category, :move_to_category, :choose_category, :create_subject_homework, :multi_destroy, :group_list, :homework_code_repeat, :code_review_results, :code_review_detail, :update_explanation, :update_settings, - :add_to_homework_bank, :publish_groups, :end_groups] + :add_to_homework_bank, :publish_groups, :end_groups, :batch_comment] before_action :require_id_params, only: [:set_public, :multi_destroy, :publish_homework, :end_homework, :move_to_category, :add_to_homework_bank] before_action :course_manager, only: [:alter_name] @@ -78,7 +78,7 @@ class HomeworkCommonsController < ApplicationController when '4' sql_str = %Q((homework_detail_manuals.comment_status = #{order} and homework_detail_manuals.appeal_time > '#{Time.now}')) 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 sql_str = %Q(homework_detail_manuals.comment_status = #{order}) end @@ -167,11 +167,11 @@ class HomeworkCommonsController < ApplicationController if params[:work_status].present? params_work_status = params[:work_status] work_status = params_work_status.map{|status| status.to_i} - all_student_works = @student_works.left_joins(:myshixun) - @student_works = all_student_works.where(work_status: work_status) - - @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.or(all_student_works.where(myshixuns: {status: 1})) if work_status.include?(4) + if @homework.homework_type == "practice" + @student_works = @student_works.where(compelete_status: work_status) + else + @student_works = @student_works.where(work_status: work_status) + end end # 分班情况 @@ -194,11 +194,10 @@ class HomeworkCommonsController < ApplicationController # TODO user_extension 如果修改 请调整 unless params[:search].blank? @student_works = @student_works.joins(user: :user_extension).where("concat(lastname, firstname) like ? - or student_id like ?", "%#{params[:search]}%", "%#{params[:search]}%") + or student_id like ?", "%#{params[:search].strip}%", "%#{params[:search].strip}%") end @work_count = @student_works.size - @work_excel = @student_works.where("work_status > 0") # 排序 rorder = params[:order].blank? ? "update_time" : params[:order] @@ -208,13 +207,14 @@ class HomeworkCommonsController < ApplicationController elsif rorder == "student_id" @student_works = @student_works.joins(user: :user_extension).order("user_extensions.#{rorder} #{b_order}") end + @work_excel = @student_works # 分页参数 page = params[:page] || 1 limit = params[:limit] || 20 @student_works = @student_works.page(page).per(limit) if @homework.homework_type == "practice" - @student_works = @student_works.includes(:student_works_scores, user: :user_extension, myshixun: :games) + @student_works = @student_works.includes(:student_works_scores, :shixun_work_comments, user: :user_extension, myshixun: :games) else @student_works = @student_works.includes(:student_works_scores, :project, user: :user_extension) end @@ -453,105 +453,8 @@ class HomeworkCommonsController < ApplicationController # 课堂结束后不能再更新 unless @course.is_end + # 发布设置 UpdateHomeworkPublishSettingService.call(@homework, publish_params) - # 作业未发布时,unified_setting参数不能为空 -=begin - if @homework.publish_time.nil? || @homework.publish_time > Time.now - tip_exception("缺少统一设置的参数") if params[:unified_setting].nil? - if params[:unified_setting] || @course.course_groups_count == 0 - tip_exception("发布时间不能为空") if params[:publish_time].blank? - tip_exception("截止时间不能为空") if params[:end_time].blank? - tip_exception("发布时间不能早于当前时间") if params[:publish_time] <= Time.now.strftime("%Y-%m-%d %H:%M:%S") - tip_exception("截止时间不能早于当前时间") if params[:end_time] <= Time.now.strftime("%Y-%m-%d %H:%M:%S") - tip_exception("截止时间不能早于发布时间") if params[:publish_time] > params[:end_time] - tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")})") if - @course.end_date.present? && params[:end_time] > @course.end_date.end_of_day - - @homework.unified_setting = 1 - @homework.homework_group_settings.destroy_all - @homework.publish_time = params[:publish_time] - # 截止时间为空时取发布时间后一个月 - @homework.end_time = params[:end_time] - - else - tip_exception("分班发布设置不能为空") if params[:group_settings].blank? - # 创建作业的分班设置 - create_homework_group_settings @homework - - setting_group_ids = [] - - params[:group_settings].each do |setting| - tip_exception("分班id不能为空") if setting[:group_id].length == 0 - tip_exception("发布时间不能为空") if setting[:publish_time].blank? - tip_exception("截止时间不能为空") if setting[:end_time].blank? - tip_exception("发布时间不能早于当前时间") if setting[:publish_time] <= strf_time(Time.now) - tip_exception("截止时间不能早于当前时间") if setting[:end_time] <= strf_time(Time.now) - tip_exception("截止时间不能早于发布时间") if setting[:publish_time] > setting[:end_time] - 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 - - - publish_time = setting[:publish_time] == "" ? Time.now : setting[:publish_time] - # 截止时间为空时取发布时间后一个月 - end_time = setting[:end_time] - HomeworkGroupSetting.where(homework_common_id: @homework.id, course_group_id: setting[:group_id]). - update_all(publish_time: publish_time, end_time: end_time) - setting_group_ids << setting[:group_id] - end - - # 未设置的分班:发布时间和截止时间都为nil - HomeworkGroupSetting.where.not(course_group_id: setting_group_ids).where(homework_common_id: @homework.id). - update_all(publish_time: nil, end_time: nil) - - # 记录已发布需要发消息的分班 - publish_group_ids = HomeworkGroupSetting.where(homework_common_id: @homework.id).group_published.pluck(:course_group_id) - - @homework.unified_setting = 0 - @homework.publish_time = @homework.min_group_publish_time - @homework.end_time = @homework.max_group_end_time - end - - # 如果作业立即发布则更新状态、发消息 - if @homework.publish_time <= Time.now and @homework_detail_manual.comment_status == 0 - @homework_detail_manual.comment_status = 1 - send_tiding = true - end - - # 作业在"提交中"状态时 - else - if @homework.end_time > Time.now && @homework.unified_setting - tip_exception("截止时间不能为空") if params[:end_time].blank? - tip_exception("截止时间不能早于当前时间") if params[:end_time] <= strf_time(Time.now) - 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) - - @homework.end_time = params[:end_time] - - elsif !@homework.unified_setting - create_homework_group_settings @homework - tip_exception("分班发布设置不能为空") if params[:group_settings].blank? - params[:group_settings].each do |setting| - group_settings = HomeworkGroupSetting.where(homework_common_id: @homework.id, course_group_id: setting[:group_id]) - - tip_exception("分班id不能为空") if setting[:group_id].length == 0 - tip_exception("发布时间不能为空") if setting[:publish_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[:end_time] <= strf_time(Time.now) && group_settings.none_end.count > 0 - tip_exception("截止时间不能早于发布时间") if setting[:publish_time] > setting[:end_time] - 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) - - group_settings.none_published.update_all(publish_time: setting[:publish_time]) - group_settings.none_end.update_all(end_time: setting[:end_time]) - end - - @homework.end_time = @homework.max_group_end_time - end - end -=end # 补交设置 tip_exception("缺少allow_late参数") if params[:allow_late].nil? @@ -880,69 +783,6 @@ class HomeworkCommonsController < ApplicationController ## 分页参数 page = params[:page] || 1 @shixuns = @shixuns.reorder("shixuns.created_at desc").includes(:challenges, user: [user_extension: :school]).page(page).per(10) - - # 新版用下面的代码 - # ## 我的实训 - # @shixuns = - # if params[:order_by] == 'mine' - # current_user.my_shixuns.unhidden - # else - # if current_user.admin? - # Shixun.unhidden - # else - # none_shixun_ids = ShixunSchool.where("school_id != #{current_user.school_id}").pluck(:shixun_id) - # - # @shixuns = Shixun.where.not(id: none_shixun_ids).unhidden - # end - # end - # - # ## 方向 - # if params[:tag_level].present? && params[:tag_id].present? - # @shixuns = @shixuns.filter_tag(params[:tag_level].to_i, params[:tag_id].to_i) - # case params[:tag_level].to_i - # when 1 #大类 - # @search_tags = Repertoire.find(params[:tag_id].to_i).name - # when 2 #子类 - # @search_tags = SubRepertoire.find(params[:tag_id].to_i).name - # when 3 #tag - # tag = TagRepertoire.find(params[:tag_id].to_i) - # @search_tags = "#{tag.sub_repertoire.name} / #{tag.name}" - # end - # end - # - # ## 搜索关键字创建者、实训名称、院校名称 - # if params[:keyword].present? - # keyword = params[:keyword].strip - # @shixuns = @shixuns.joins(user: [user_extenison: :school]). - # where("schools.name like '%#{keyword}%' - # or concat(lastname, firstname) like '%#{keyword}%' - # or shixuns.name like '%#{keyword.split(" ").join("%")}%'").distinct - # end - # - # ## 筛选 难度 - # if params[:diff].present? && params[:diff].to_i != 0 - # @shixuns = @shixuns.where(trainee: params[:diff]) - # end - # - # ## 排序参数 - # bsort = params[:sort] || 'desc' - # case params[:order_by] || 'hot' - # when 'hot' - # @shixuns = @shixuns.order("myshixuns_count #{bsort}") - # when 'mine' - # @shixuns = @shixuns.order("shixuns.created_at #{bsort}") - # else - # @shixuns = @shixuns.order("myshixuns_count #{bsort}") - # end - # - # @total_count = @shixuns.count - # - # ## 分页参数 - # page = params[:page] || 1 - # limit = params[:limit] || 15 - # - # @shixuns = @shixuns.includes(:challenges, user: [user_extension: :school]).page(page).per(limit) - # end def create_shixun_homework @@ -1046,7 +886,7 @@ class HomeworkCommonsController < ApplicationController course_module_id: course_module.id, position: course_module.course_second_categories.count + 1) # 去掉不对当前用户的单位公开的实训,已发布的实训 - stage.shixuns.where.not(shixuns: {id: none_shixun_ids}).unhidden.each do |shixun| + stage.shixuns.no_jupyter.where.not(shixuns: {id: none_shixun_ids}).unhidden.each do |shixun| homework = HomeworksService.new.create_homework shixun, @course, category, current_user @homework_ids << homework.id CreateStudentWorkJob.perform_later(homework.id) @@ -1248,31 +1088,6 @@ class HomeworkCommonsController < ApplicationController # homework_challenge_settings = homework.homework_challenge_settings unless student_works.blank? student_works.joins(:myshixun).where("myshixuns.status != 1").update_all(late_penalty: homework.late_penalty) if homework.allow_late - -=begin - student_works.where("work_status != 0").includes(:myshixun).each do |student_work| - unless student_work.myshixun.is_complete? - student_work.update_attributes(work_status: 2, late_penalty: homework.late_penalty) - student_work.late_penalty = homework.late_penalty - end - HomeworksService.new.set_shixun_final_score student_work, student_work.myshixun, homework_detail_manual.answer_open_evaluation, - homework_challenge_settings - end - - student_works.where("work_status = 0").each do |student_work| - myshixun = Myshixun.where(shixun_id: shixun.id, user_id: student_work.user_id).first - if myshixun.present? - student_work.update_attributes(work_status: (myshixun.is_complete? ? 1 : 2), - late_penalty: myshixun.is_complete? ? 0 : homework.late_penalty, - commit_time: myshixun.created_at, myshixun_id: myshixun.id) - student_work.late_penalty = myshixun.is_complete? ? 0 : homework.late_penalty - HomeworksService.new.set_shixun_final_score student_work, myshixun, homework_detail_manual.answer_open_evaluation, - homework_challenge_settings - end - end -=end - - # 更新所有学生的效率分(重新取homework确保是更新后的) end end homework.save! @@ -1501,8 +1316,12 @@ class HomeworkCommonsController < ApplicationController @user = @student_work.user tip_exception("当前用户无作品可以显示") if @student_work.nil? # 查询最新一次的查重标识query_id - group_id = @course.course_members.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) + group_id = @course.students.where(user_id: params[:user_id]).pluck(:course_group_id).first + 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}) @shixun = @homework.shixuns.take if results.status == 0 @@ -1554,6 +1373,21 @@ class HomeworkCommonsController < ApplicationController end + def batch_comment + tip_exception(-1, "作业还未发布,不能评阅") if @homework_detail_manual.comment_status == 0 + tip_exception("请至少输入一个评阅") if params[:comment].blank? && params[:hidden_comment].blank? + ActiveRecord::Base.transaction do + work_ids = @homework.student_works.where(work_status: [1, 2], user_id: @course.teacher_group_user_ids(current_user.id)).pluck(:id) + has_comment_ids = ShixunWorkComment.where(challenge_id: 0, student_work_id: work_ids, batch_comment: 0).pluck(:student_work_id) + batch_comment_works = ShixunWorkComment.where(challenge_id: 0, student_work_id: work_ids, batch_comment: 1) + batch_comment_works.update_all(comment: params[:comment], hidden_comment: params[:hidden_comment]) + work_ids = work_ids - has_comment_ids - batch_comment_works.pluck(:student_work_id) + # @homework.student_works.where(work_status: 0, id: work_ids).update_all(work_status: 1, commit_time: @homework.end_time, update_time: Time.now, work_score: 0, final_score: 0) + HomeworkBatchCommentJob.perform_later(params[:comment], params[:hidden_comment], work_ids, @homework.id, current_user.id) + normal_status("评阅成功") + end + end + private def find_homework diff --git a/app/controllers/item_banks_controller.rb b/app/controllers/item_banks_controller.rb new file mode 100644 index 000000000..104851676 --- /dev/null +++ b/app/controllers/item_banks_controller.rb @@ -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 \ No newline at end of file diff --git a/app/controllers/jupyters_controller.rb b/app/controllers/jupyters_controller.rb new file mode 100644 index 000000000..ecb411b36 --- /dev/null +++ b/app/controllers/jupyters_controller.rb @@ -0,0 +1,96 @@ +require 'base64' + +class JupytersController < ApplicationController + include JupyterService + + before_action :shixun, only: [:open, :open1, :test, :save] + + + def import_with_tpm + shixun = Shixun.find_by(identifier: params[:identifier]) + + upload_file = params["file"] || params["#{params[:file_param_name]}"] # 这里的file_param_name是为了方便其他插件名称 + uid_logger("#########################file_params####{params["#{params[:file]}"]}") + raise "未上传文件" unless upload_file + + content = Base64.encode64(upload_file.tempfile.read) + + # upload to server + shixun_tomcat = edu_setting('cloud_bridge') + uri = "#{shixun_tomcat}/bridge/jupyter/update" + tpiID = "tpm#{shixun.id}" + params = {tpiID: tpiID, content: content} + + logger.info "test_juypter: uri->#{uri}, params->#{params}" + res = uri_post uri, params + if res && res['code'].to_i != 0 + raise("实训云平台繁忙(繁忙等级:100)") + end + + render json: {status: 0} + end + + 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 + + def active_with_tpm + shixun = Shixun.find_by(identifier: params[:identifier]) + jupyter_active_tpm(shixun) + render json: {status: 0} + end + + def active_with_tpi + myshixun = Myshixun.find_by(identifier: params[:identifier]) + jupyter_active_tpm(myshixun) + render json: {status: 0} + end + + def timeinfo_with_tpm + shixun = Shixun.find_by(identifier: params[:identifier]) + info = jupyter_timeinfo_tpm(shixun) + render json: {status: 0}.merge(info) + end + + def timeinfo_with_tpi + myshixun = Myshixun.find_by(identifier: params[:identifier]) + info = jupyter_timeinfo_tpi(myshixun) + render json: {status: 0}.merge(info) + end + + +end diff --git a/app/controllers/main_controller.rb b/app/controllers/main_controller.rb index 0e2628c3e..e8554300c 100644 --- a/app/controllers/main_controller.rb +++ b/app/controllers/main_controller.rb @@ -1,4 +1,10 @@ class MainController < ApplicationController + skip_before_action :check_sign + + def first_stamp + render :json => { status: 0, message: Time.now.to_i } + end + def index render file: 'public/react/build/index.html', :layout => false end diff --git a/app/controllers/myshixuns_controller.rb b/app/controllers/myshixuns_controller.rb index b5c8af1f3..67bec877b 100644 --- a/app/controllers/myshixuns_controller.rb +++ b/app/controllers/myshixuns_controller.rb @@ -1,385 +1,412 @@ -class MyshixunsController < ApplicationController - before_action :require_login, :check_auth, :except => [:training_task_status, :code_runinng_message] - before_action :find_myshixun, :except => [:training_task_status, :code_runinng_message] - before_action :find_repo_name, :except => [:training_task_status, :code_runinng_message] - skip_before_action :verify_authenticity_token, :only => [:html_content] - - ## TPI关卡列表 - def challenges - # @challenges = Challenge.where(shixun_id: params[:shixun_id]) - @shixun = @myshixun.shixun - @games = @myshixun.games.includes(:challenge).reorder("challenges.position") - @identity = current_user.game_identity(@games.first) - end - - - # For Admin - # 强制重置实训 - # 前段需要按照操作过程提示 - def reset_my_game - unless (current_user.admin? || current_user.id == @myshixun.user_id) - tip_exception("403", "") - end - begin - ActiveRecord::Base.transaction do - begin - @shixun = Shixun.select(:id, :identifier, :challenges_count).find(@myshixun.shixun_id) - @myshixun.destroy! - StudentWork.where(:myshixun_id => @myshixun.id).update_all(myshixun_id: 0, work_status: 0, work_score: nil, - final_score: nil, efficiency: 0, eff_score: 0, calculation_time: nil, cost_time: 0, compelete_status: 0) - rescue Exception => e - logger.error("######reset_my_game_failed:#{e.message}") - raise("ActiveRecord::RecordInvalid") - end - end - # 删除版本库 - GitService.delete_repository(repo_path: @repo_path) unless @shixun.is_choice_type? - rescue Exception => e - if e.message != "ActiveRecord::RecordInvalid" - logger.error("######delete_repository_error-:#{e.message}") - end - raise "delete_repository_error:#{e.message}" - end - end - - # 代码运行中的信息接口 - # 这个方法是中间层主动调用的,点击评测后,中间层会发送参数过来,告诉目前Pod的启动情况,一次评测会调用两次请求 - def code_runinng_message - begin - jsonTestDetails = JSON.parse(params[:jsonTestDetails]) - game_id = jsonTestDetails['buildID'] - message = jsonTestDetails['textMsg'] - if game_id.present? && message.present? - game = Game.find game_id - msg = game.run_code_message - # 只有评测中的game才会创建和更新代码评测中的信息 - if game.status == 1 || game.status == 2 - if msg.blank? - RunCodeMessage.create!(:game_id => game_id, :status => 1, :message => message) - else - msg.update_attributes(:status => (msg.status + 1), :message => message) - end - end - render :json => {:data => "success"} - end - rescue Exception => e - render :json => {:data => "failed, exception_message: #{e}"} - end - end - - # 中间层评测接口 - # taskId 即返回的game id - # 返回结果:params [:stauts] 0 表示成功,其它则失败 - # msg 错误信息 - # output 为测试用户编译输出结果 - # myshixun:status 1为完成实训 - # @jenkins: caseId对应test_set的position,passed: 1表示成功,0表示失败 - # resubmit 1:表示已通关后重新评测;0:表示非重新评测 - # retry_status 0:初始值;1:重新评测失败;2:重新评测成功 - # tpiRepoPath 中间层图片的workspace路径 - # params[:jsonTestDetails] = '{"buildID":"19284","compileSuccess":"1", - # "msg":[{"caseId":"1","expectedOutput":"MSAyIDMNCg","input":"MiAzIDE","output":"MSAyIDMNCg","passed":"1"}, - # {"caseId":"2","expectedOutput":"LTMgMSA2DQo","input":"LTMgNiAx","output":"LTMgMSA2DQo","passed":"1"}, - # {"caseId":"3","expectedOutput":"LTcgLTUgLTMNCg","input":"LTcgLTMgLTU","output":"LTcgLTUgLTMNCg","passed":"1"}], - # "outPut":"Y29tcGlsZSBzdWNjZXNzZnVsbHk","resubmit":"","status":"0"}' - # params[:timeCost] = '{"evaluateEnd":"2017-11-24 11:04:37","pull":"0.086", - # "createPod":"1.610","evaluateAllTime":2820,"evaluateStart":"2017-11-24 11:04:35","execute":"0.294"}' - # params[:pics] = "a.png,b.png,c.png" - def training_task_status - - ActiveRecord::Base.transaction do - begin - t1 = Time.now - uid_logger_dubug("@@@222222#{params[:jsonTestDetails]}") - jsonTestDetails = JSON.parse(params[:jsonTestDetails]) - timeCost = JSON.parse(params[:timeCost]) - brige_end_time = Time.parse(timeCost['evaluateEnd']) if timeCost['evaluateEnd'].present? - return_back_time = format("%.3f", ( t1.to_f - brige_end_time.to_f)).to_f - status = jsonTestDetails['status'] - game_id = jsonTestDetails['buildID'] - sec_key = jsonTestDetails['sec_key'] - - uid_logger_dubug("training_task_status start-#{game_id}-1#{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") - resubmit = jsonTestDetails['resubmit'] - outPut = tran_base64_decode64(jsonTestDetails['outPut']) - - jenkins_testsets = jsonTestDetails['msg'] - compile_success = jsonTestDetails['compileSuccess'] - # message = Base64.decode64(params[:msg]) unless params[:msg].blank? - - game = Game.find(game_id) - myshixun = game.myshixun - challenge = game.challenge - # test_sets = challenge.test_sets - if challenge.picture_path.present? - #pics = params[:files] - pics = params[:tpiRepoPath] - game.update_column(:picture_path, pics) - end - max_query_index = game.outputs ? (game.outputs.first.try(:query_index).to_i + 1) : 1 - test_set_score = 0 - unless jenkins_testsets.blank? - jenkins_testsets.each_with_index do |j_test_set, i| - actual_output = tran_base64_decode64(j_test_set['output']) - #ts_time += j_test_set['testSetTime'].to_i - - # is_public = test_sets.where(:position => j_test_set['caseId']).first.try(:is_public) - ts_time = format("%.2f", j_test_set['testSetTime'].to_f/1000000000).to_f if j_test_set['testSetTime'] - ts_mem = format("%.2f", j_test_set['testSetMem'].to_f/1024/1024).to_f if j_test_set['testSetMem'] - - Output.create!(:code => status, :game_id => game_id, :out_put => outPut, :test_set_position => j_test_set['caseId'], - :actual_output => actual_output, :result => j_test_set['passed'].to_i, :query_index => max_query_index, - :compile_success => compile_success.to_i, :sec_key => sec_key, :ts_time => ts_time, :ts_mem => ts_mem) - # 如果设置了按测试集给分,则需要统计测试集的分值 - if challenge.test_set_score && j_test_set['passed'].to_i == 1 - test_set_score += challenge.test_sets.where(:position => j_test_set['caseId']).pluck(:score).first - end - end - end - record = EvaluateRecord.where(:identifier => sec_key).first - answer_deduction_percentage = (100 - game.answer_deduction) / 100.to_f # 查看答案后剩余分数的百分比. - # answer_deduction是查看答案的扣分比例 - # status:0表示评测成功 - if status == "0" - if resubmit.present? - game.update_attributes!(:retry_status => 2, :resubmit_identifier => resubmit) - challenge.path.split(";").each do |path| - game_passed_code(path.try(:strip), myshixun, game_id) - end - else - game.update_attributes!(:status => 2, - :end_time => Time.now, - :accuracy => format("%.4f", 1.0 / game.query_index)) - myshixun.update_attributes!(:status => 1) if game.had_done == 1 - challenge.path.split(";").each do |path| - game_passed_code(path.try(:strip), myshixun, game_id) - end - # 如果是已经发布的实训,则需要给出相应的奖励 - if challenge.shixun.try(:status) > 1 - score = (challenge.score * answer_deduction_percentage).to_i - if score > 0 - reward_attrs = { container_id: game.id, container_type: 'Game', score: score } - RewardGradeService.call(game.user, reward_attrs) - RewardExperienceService.call(game.user, reward_attrs) - end - # 需要扣除查看答案的分数 - game.update_attributes!(:final_score => score) - end - - # 更新实训关联的作品分数 TODO: 更新作品分数 - # HomeworksService.new.update_myshixun_work_score myshixun - end - # 如果过关了,下一关的状态是3(为开启),则需要把状态改成1(已开启) - # next_game = game.next_game - next_game = game.next_game(myshixun.shixun_id, game.myshixun_id, challenge.position) - next_game.update_column(:status, 0) if next_game.present? && next_game.status == 3 - # status == "-1" 表示返回结果错误 - else - if resubmit.present? - game.update_attributes!(:retry_status => 1, :resubmit_identifier => resubmit) - else - # 评测没通关则,测试集对的个数给分,并且还要扣除用户是否查看答案的值 - test_set_percentage = test_set_score / 100.to_f # 测试集得分比 - score = (challenge.score * test_set_percentage * answer_deduction_percentage).to_i - # 如果分数比上次多,则更新成绩 - game_update = - if game.final_score < score - {final_score: score, status: 0} - else - {status: 0} - end - game.update_attributes!(game_update) - end - end - test_cases_time = format("%.3f", (Time.now.to_f - t1.to_f)).to_f - if record.present? - consume_time = format("%.3f", (Time.now - record.created_at)).to_f - - record.update_attributes!(:consume_time => consume_time, :git_pull => timeCost['pull'] , :create_pod => timeCost['createPod'], - :pod_execute => timeCost['execute'], :test_cases => test_cases_time, - :brige => timeCost['evaluateAllTime'], :return_back => return_back_time) - end - sucess_status - # rescue Exception => e - # tip_exception(e.message) - # uid_logger_error("training_task_status error: #{e}") - # raise ActiveRecord::Rollback - end - end - end - - # 连接webssh - def open_webssh - username = edu_setting('webssh_username') - password = edu_setting('webssh_password') - old_time = Time.now.to_i - begin - shixun_tomcat = edu_setting('tomcat_webssh') - uri = "#{shixun_tomcat}/bridge/webssh/getConnectInfo" - # 由于中间层采用混合云的方式,因为local参数表示在有文件生成的实训是在本地生成,还是在其他云端生成评测文件 - params = {tpiID:@myshixun.id, podType:@myshixun.shixun.try(:webssh), local: @myshixun.shixun.show_type != -1, - containers:(Base64.urlsafe_encode64(shixun_container_limit @myshixun.shixun))} - res = uri_post uri, params - if res && res['code'].to_i != 0 - tip_exception("实训云平台繁忙(繁忙等级:92)") - end - render :json => {:host => res['address'], - :port => res['port'], - :ws_url => res['ws_address'], - :username => username, - :password => password, - :game_id => @myshixun.id, - :webssh_url => "#{shixun_tomcat}/bridge"} - rescue Exception => e - logger.error(e) - render :json => {:error => e.try(:message)} - ensure - use_time = Time.now.to_i - old_time - logger.info "open_webssh tpiID #{@myshixun.id} use time #{use_time}" - end - end - - include GitCommon - - # -----Repository - # TODO: 之类需要一个resubmit参数,但是是关于games. - def update_file - begin - @hide_code = Shixun.where(id: @myshixun.shixun_id).pluck(:hide_code).first - tip_exception("技术平台为空!") if @myshixun.mirror_name.blank? - path = params[:path].strip unless params[:path].blank? - game_id = params[:game_id] - game = Game.find(game_id) - @content_modified = 0 - - # params[:evaluate] 实训评测时更新必须给的参数,需要依据该参数做性能统计,其它类型的更新可以跳过 - # 自动保存的时候evaluate为0;点评测的时候为1 - if params[:evaluate] == 1 - exec_time = game.challenge.try(:exec_time) - @sec_key = generate_identifier(EvaluateRecord, 12) - record = EvaluateRecord.create!(:user_id => current_user.id, :shixun_id => @myshixun.shixun_id, :game_id => game_id, - :identifier => @sec_key, :exec_time => exec_time) - uid_logger_dubug("-- game build: file update #{@sec_key}, record id is #{record.id}, time is **** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") - end - # 隐藏代码文件 和 VNC的都不需要走版本库 - unless @hide_code || (@myshixun.shixun&.vnc_evaluate && params[:evaluate].present?) - # 远程版本库文件内容 - last_content = GitService.file_content(repo_path: @repo_path, path: path)["content"] - - content = - if python_file?(path) - params[:content].gsub(/\t/, ' ').gsub(/ /, ' ') - else - params[:content] - end - uid_logger_dubug("###11222333####{content}") - uid_logger_dubug("###222333####{last_content}") - - if content != last_content - @content_modified = 1 - - author_name = current_user.real_name - author_email = current_user.git_mail - message = params[:evaluate] == 0 ? "System automatically submitted" : "User submitted" - uid_logger_dubug("112233#{author_name}") - uid_logger_dubug("112233#{author_email}") - @content = GitService.update_file(repo_path: @repo_path, - file_path: path, - message: message, - content: content, - author_name: author_name, - author_email: author_email) - end - end - - if game.status == 2 - @resubmit = Time.now.to_i - end - - # 评测时间记录 - if record.present? - consume_time = format("%.3f", (Time.now.to_f - record.created_at.to_f)).to_f - record.update_attributes!(:file_update => consume_time) - end - rescue Exception => e - uid_logger_error(e.message) - tip_exception("文件内容更新异常,请稍后重试") - end - end - - # 渲染实训代码 - # educodercss: 字符串以 ‘,’分隔,存储的是版本库css的路径 - # educoderscript: 字符串以 ‘,’分隔,存储的是版本库js的路径 - # contents: html实训的整体内容 - def html_content - @contents = params[:contents] || "" - edu_css = params[:educodercss] - edu_js = params[:educoderscript] - if @contents.present? - @contents = @contents.gsub("w3equalsign", "=").gsub("w3scrw3ipttag", "script").gsub("edulink", "link").html_safe - end - # css - if edu_css.present? - css_path = edu_css.split(",") - css_path.each do |path| - file_content = git_fle_content(@repo_path, path)["content"] - file_content = tran_base64_decode64(file_content) unless file_content.blank? - @contents = @contents.sub(/EDUCODERCSS/, "") - end - end - # js - if edu_js.present? - js_path = edu_js.split(",") - js_path.each do |path| - file_content = git_fle_content(@repo_path, path)["content"] - file_content = tran_base64_decode64(file_content) unless file_content.blank? - @contents = @contents.sub(/EDUCODERJS/, "") - end - end - respond_to do |format| - format.json - format.html{render :layout => false} - end - end - - # 最新可以用的并发测试接口 - def sigle_mul_test - codes = %W(1 2 3 4 5 6 7 8 9 A B C D E F G H J K L N M O P Q R S T U V W X Y Z) - begin - identifiers = Myshixun.where(:shixun_id => params[:shixun_id].split(",")).pluck(:identifier) - ide = identifiers[rand(identifiers.length)] - myshixun = Myshixun.where(:identifier => ide).first - - game = myshixun.games.last - logger.warn("###2mul test game_build start ") - identifier = game.try(:identifier) - if game.status == 2 - code = codes.sample(8).join - resubmit = "#{code}_#{myshixun.id}" - end - logger.warn("###3mul test game_build start ...") - EvaluateRecord.create!(:user_id => myshixun.user_id, :shixun_id => myshixun.shixun.id, :game_id => game.id) - redirect_to "/api/games/#{identifier}/game_build?resubmit=#{resubmit}&content_modified=0&first=1" - rescue Exception => e - logger.error("mul test failed ===> #{e.message}") - end - end - - - # -----End - - private - def find_myshixun - @myshixun = Myshixun.find_by!(identifier: params[:identifier]) - end - - def find_repo_name - @repo_path = @myshixun.try(:repo_path) - @path = params[:path] - end - - def python_file?(path) - false if path.blank? - path.to_s.split(".").last.downcase == "py" - end -end +class MyshixunsController < ApplicationController + before_action :require_login, :check_auth, :except => [:training_task_status, :code_runinng_message] + before_action :find_myshixun, :except => [:training_task_status, :code_runinng_message] + before_action :find_repo_name, :except => [:training_task_status, :code_runinng_message] + skip_before_action :verify_authenticity_token, :only => [:html_content] + skip_before_action :check_sign, only: [:training_task_status, :code_runinng_message] + + ## TPI关卡列表 + def challenges + # @challenges = Challenge.where(shixun_id: params[:shixun_id]) + @shixun = @myshixun.shixun + @games = @myshixun.games.includes(:challenge).reorder("challenges.position") + @identity = current_user.game_identity(@games.first) + end + + + # For Admin + # 强制重置实训 + # 前段需要按照操作过程提示 + def reset_my_game + unless (current_user.admin? || current_user.id == @myshixun.user_id) + tip_exception("403", "") + end + begin + ActiveRecord::Base.transaction do + begin + @shixun = Shixun.select(:id, :identifier, :challenges_count).find(@myshixun.shixun_id) + @myshixun.destroy! + StudentWork.where(:myshixun_id => @myshixun.id).update_all(myshixun_id: 0, work_status: 0, work_score: nil, + final_score: nil, efficiency: 0, eff_score: 0, calculation_time: nil, cost_time: 0, compelete_status: 0) + rescue Exception => e + logger.error("######reset_my_game_failed:#{e.message}") + raise("ActiveRecord::RecordInvalid") + end + end + # 删除版本库 + GitService.delete_repository(repo_path: @repo_path) unless @shixun.is_choice_type? + rescue Exception => e + if e.message != "ActiveRecord::RecordInvalid" + logger.error("######delete_repository_error-:#{e.message}") + end + raise "delete_repository_error:#{e.message}" + end + end + + # 代码运行中的信息接口 + # 这个方法是中间层主动调用的,点击评测后,中间层会发送参数过来,告诉目前Pod的启动情况,一次评测会调用两次请求 + def code_runinng_message + begin + jsonTestDetails = JSON.parse(params[:jsonTestDetails]) + game_id = jsonTestDetails['buildID'] + message = jsonTestDetails['textMsg'] + if game_id.present? && message.present? + game = Game.find game_id + msg = game.run_code_message + # 只有评测中的game才会创建和更新代码评测中的信息 + if game.status == 1 || game.status == 2 + if msg.blank? + RunCodeMessage.create!(:game_id => game_id, :status => 1, :message => message) + else + msg.update_attributes(:status => (msg.status + 1), :message => message) + end + end + render :json => {:data => "success"} + end + rescue Exception => e + render :json => {:data => "failed, exception_message: #{e}"} + end + end + + # 中间层评测接口 + # taskId 即返回的game id + # 返回结果:params [:stauts] 0 表示成功,其它则失败 + # msg 错误信息 + # output 为测试用户编译输出结果 + # myshixun:status 1为完成实训 + # @jenkins: caseId对应test_set的position,passed: 1表示成功,0表示失败 + # resubmit 1:表示已通关后重新评测;0:表示非重新评测 + # retry_status 0:初始值;1:重新评测失败;2:重新评测成功 + # tpiRepoPath 中间层图片的workspace路径 + # params[:jsonTestDetails] = '{"buildID":"19284","compileSuccess":"1", + # "msg":[{"caseId":"1","expectedOutput":"MSAyIDMNCg","input":"MiAzIDE","output":"MSAyIDMNCg","passed":"1"}, + # {"caseId":"2","expectedOutput":"LTMgMSA2DQo","input":"LTMgNiAx","output":"LTMgMSA2DQo","passed":"1"}, + # {"caseId":"3","expectedOutput":"LTcgLTUgLTMNCg","input":"LTcgLTMgLTU","output":"LTcgLTUgLTMNCg","passed":"1"}], + # "outPut":"Y29tcGlsZSBzdWNjZXNzZnVsbHk","resubmit":"","status":"0"}' + # params[:timeCost] = '{"evaluateEnd":"2017-11-24 11:04:37","pull":"0.086", + # "createPod":"1.610","evaluateAllTime":2820,"evaluateStart":"2017-11-24 11:04:35","execute":"0.294"}' + # params[:pics] = "a.png,b.png,c.png" + def training_task_status + + ActiveRecord::Base.transaction do + begin + t1 = Time.now + uid_logger_dubug("@@@222222#{params[:jsonTestDetails]}") + jsonTestDetails = JSON.parse(params[:jsonTestDetails]) + timeCost = JSON.parse(params[:timeCost]) + brige_end_time = Time.parse(timeCost['evaluateEnd']) if timeCost['evaluateEnd'].present? + return_back_time = format("%.3f", ( t1.to_f - brige_end_time.to_f)).to_f + status = jsonTestDetails['status'] + game_id = jsonTestDetails['buildID'] + sec_key = jsonTestDetails['sec_key'] + + uid_logger_dubug("training_task_status start-#{game_id}-1#{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") + resubmit = jsonTestDetails['resubmit'] + outPut = tran_base64_decode64(jsonTestDetails['outPut']) + + jenkins_testsets = jsonTestDetails['msg'] + compile_success = jsonTestDetails['compileSuccess'] + # message = Base64.decode64(params[:msg]) unless params[:msg].blank? + + game = Game.find(game_id) + myshixun = game.myshixun + challenge = game.challenge + # test_sets = challenge.test_sets + if challenge.picture_path.present? + #pics = params[:files] + pics = params[:tpiRepoPath] + game.update_column(:picture_path, pics) + end + max_query_index = game.outputs ? (game.outputs.first.try(:query_index).to_i + 1) : 1 + test_set_score = 0 + unless jenkins_testsets.blank? + jenkins_testsets.each_with_index do |j_test_set, i| + actual_output = tran_base64_decode64(j_test_set['output']) + #ts_time += j_test_set['testSetTime'].to_i + + # is_public = test_sets.where(:position => j_test_set['caseId']).first.try(:is_public) + ts_time = format("%.2f", j_test_set['testSetTime'].to_f/1000000000).to_f if j_test_set['testSetTime'] + ts_mem = format("%.2f", j_test_set['testSetMem'].to_f/1024/1024).to_f if j_test_set['testSetMem'] + + Output.create!(:code => status, :game_id => game_id, :out_put => outPut, :test_set_position => j_test_set['caseId'], + :actual_output => actual_output, :result => j_test_set['passed'].to_i, :query_index => max_query_index, + :compile_success => compile_success.to_i, :sec_key => sec_key, :ts_time => ts_time, :ts_mem => ts_mem) + # 如果设置了按测试集给分,则需要统计测试集的分值 + if challenge.test_set_score && j_test_set['passed'].to_i == 1 + test_set_score += challenge.test_sets.where(:position => j_test_set['caseId']).pluck(:score).first + end + end + end + record = EvaluateRecord.where(:identifier => sec_key).first + answer_deduction_percentage = (100 - game.answer_deduction) / 100.to_f # 查看答案后剩余分数的百分比. + # answer_deduction是查看答案的扣分比例 + # status:0表示评测成功 + if status == "0" + if resubmit.present? + game.update_attributes!(:retry_status => 2, :resubmit_identifier => resubmit) + challenge.path.split(";").each do |path| + game_passed_code(path.try(:strip), myshixun, game_id) + end + else + game.update_attributes!(:status => 2, + :end_time => Time.now, + :accuracy => format("%.4f", 1.0 / game.query_index)) + myshixun.update_attributes!(:status => 1) if game.had_done == 1 + challenge.path.split(";").each do |path| + game_passed_code(path.try(:strip), myshixun, game_id) + end + # 如果是已经发布的实训,则需要给出相应的奖励 + if challenge.shixun.try(:status) > 1 + score = (challenge.score * answer_deduction_percentage).to_i + if score > 0 + reward_attrs = { container_id: game.id, container_type: 'Game', score: score } + RewardGradeService.call(game.user, reward_attrs) + RewardExperienceService.call(game.user, reward_attrs) + end + # 需要扣除查看答案的分数 + game.update_attributes!(:final_score => score) + end + + # 更新实训关联的作品分数 TODO: 更新作品分数 + # HomeworksService.new.update_myshixun_work_score myshixun + end + # 如果过关了,下一关的状态是3(为开启),则需要把状态改成1(已开启) + # next_game = game.next_game + next_game = game.next_game(myshixun.shixun_id, game.myshixun_id, challenge.position) + next_game.update_column(:status, 0) if next_game.present? && next_game.status == 3 + # status == "-1" 表示返回结果错误 + else + if resubmit.present? + game.update_attributes!(:retry_status => 1, :resubmit_identifier => resubmit) + else + # 评测没通关则,测试集对的个数给分,并且还要扣除用户是否查看答案的值 + test_set_percentage = test_set_score / 100.to_f # 测试集得分比 + score = (challenge.score * test_set_percentage * answer_deduction_percentage).to_i + # 如果分数比上次多,则更新成绩 + game_update = + if game.final_score < score + {final_score: score, status: 0} + else + {status: 0} + end + game.update_attributes!(game_update) + end + end + test_cases_time = format("%.3f", (Time.now.to_f - t1.to_f)).to_f + if record.present? + consume_time = format("%.3f", (Time.now - record.created_at)).to_f + + record.update_attributes!(:consume_time => consume_time, :git_pull => timeCost['pull'] , :create_pod => timeCost['createPod'], + :pod_execute => timeCost['execute'], :test_cases => test_cases_time, + :brige => timeCost['evaluateAllTime'], :return_back => return_back_time) + end + sucess_status + # rescue Exception => e + # tip_exception(e.message) + # uid_logger_error("training_task_status error: #{e}") + # raise ActiveRecord::Rollback + end + end + end + + # 连接webssh + def open_webssh + username = edu_setting('webssh_username') + password = edu_setting('webssh_password') + old_time = Time.now.to_i + begin + shixun_tomcat = edu_setting('tomcat_webssh') + uri = "#{shixun_tomcat}/bridge/webssh/getConnectInfo" + # 由于中间层采用混合云的方式,因为local参数表示在有文件生成的实训是在本地生成,还是在其他云端生成评测文件 + local = @myshixun.shixun.challenges.where.not(show_type: -1).count == 0 + params = {tpiID:@myshixun.id, podType:@myshixun.shixun.try(:webssh), local: local, + containers:(Base64.urlsafe_encode64(shixun_container_limit @myshixun.shixun))} + res = uri_post uri, params + if res && res['code'].to_i != 0 + tip_exception("实训云平台繁忙(繁忙等级:92)") + end + render :json => {:host => res['address'], + :port => res['port'], + :ws_url => res['ws_address'], + :username => username, + :password => password, + :game_id => @myshixun.id, + :webssh_url => "#{shixun_tomcat}/bridge"} + rescue Exception => e + logger.error(e) + render :json => {:error => e.try(:message)} + ensure + use_time = Time.now.to_i - old_time + logger.info "open_webssh tpiID #{@myshixun.id} use time #{use_time}" + end + end + + include GitCommon + + # -----Repository + # TODO: 之类需要一个resubmit参数,但是是关于games. + def update_file + begin + @hide_code = Shixun.where(id: @myshixun.shixun_id).pluck(:hide_code).first + tip_exception("实验环境不能为空,请查看实训模板的环境配置项是否正确!") if (@myshixun.mirror_name.blank? || @myshixun.mirror_name.first.to_s == "-1") + path = params[:path].strip unless params[:path].blank? + game_id = params[:game_id] + game = Game.find(game_id) + @content_modified = 0 + + # params[:evaluate] 实训评测时更新必须给的参数,需要依据该参数做性能统计,其它类型的更新可以跳过 + # 自动保存的时候evaluate为0;点评测的时候为1 + if params[:evaluate] == 1 + exec_time = game.challenge.try(:exec_time) + @sec_key = generate_identifier(EvaluateRecord, 12) + record = EvaluateRecord.create!(:user_id => current_user.id, :shixun_id => @myshixun.shixun_id, :game_id => game_id, + :identifier => @sec_key, :exec_time => exec_time) + uid_logger_dubug("-- game build: file update #{@sec_key}, record id is #{record.id}, time is **** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") + end + # 隐藏代码文件 和 VNC的都不需要走版本库 + unless @hide_code || (@myshixun.shixun&.vnc_evaluate && params[:evaluate].present?) + # 远程版本库文件内容 + last_content = GitService.file_content(repo_path: @repo_path, path: path)["content"] + + content = + if python_file?(path) + params[:content].gsub(/\t/, ' ').gsub(/ /, ' ') + else + params[:content] + end + uid_logger_dubug("###11222333####{content}") + uid_logger_dubug("###222333####{last_content}") + + if content != last_content + @content_modified = 1 + + author_name = current_user.real_name + author_email = current_user.git_mail + message = params[:evaluate] == 0 ? "System automatically submitted" : "User submitted" + uid_logger_dubug("112233#{author_name}") + uid_logger_dubug("112233#{author_email}") + @content = GitService.update_file(repo_path: @repo_path, + file_path: path, + message: message, + content: content, + author_name: author_name, + author_email: author_email) + end + end + + if game.status == 2 + @resubmit = Time.now.to_i + end + + # 评测时间记录 + if record.present? + consume_time = format("%.3f", (Time.now.to_f - record.created_at.to_f)).to_f + record.update_attributes!(:file_update => consume_time) + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception("文件内容更新异常,请稍后重试") + end + end + + # 渲染实训代码 + # educodercss: 字符串以 ‘,’分隔,存储的是版本库css的路径 + # educoderscript: 字符串以 ‘,’分隔,存储的是版本库js的路径 + # contents: html实训的整体内容 + def html_content + @contents = params[:contents] || "" + edu_css = params[:educodercss] + edu_js = params[:educoderscript] + if @contents.present? + @contents = @contents.gsub("w3equalsign", "=").gsub("w3scrw3ipttag", "script").gsub("edulink", "link").html_safe + end + # css + if edu_css.present? + css_path = edu_css.split(",") + css_path.each do |path| + file_content = git_fle_content(@repo_path, path)["content"] + file_content = tran_base64_decode64(file_content) unless file_content.blank? + @contents = @contents.sub(/EDUCODERCSS/, "") + end + end + # js + if edu_js.present? + js_path = edu_js.split(",") + js_path.each do |path| + file_content = git_fle_content(@repo_path, path)["content"] + file_content = tran_base64_decode64(file_content) unless file_content.blank? + @contents = @contents.sub(/EDUCODERJS/, "") + end + end + respond_to do |format| + format.json + format.html{render :layout => false} + end + end + + # 最新可以用的并发测试接口 + def sigle_mul_test + codes = %W(1 2 3 4 5 6 7 8 9 A B C D E F G H J K L N M O P Q R S T U V W X Y Z) + begin + identifiers = Myshixun.where(:shixun_id => params[:shixun_id].split(",")).pluck(:identifier) + ide = identifiers[rand(identifiers.length)] + myshixun = Myshixun.where(:identifier => ide).first + + game = myshixun.games.last + logger.warn("###2mul test game_build start ") + identifier = game.try(:identifier) + if game.status == 2 + code = codes.sample(8).join + resubmit = "#{code}_#{myshixun.id}" + end + logger.warn("###3mul test game_build start ...") + EvaluateRecord.create!(:user_id => myshixun.user_id, :shixun_id => myshixun.shixun.id, :game_id => game.id) + redirect_to "/api/games/#{identifier}/game_build?resubmit=#{resubmit}&content_modified=0&first=1" + rescue Exception => e + logger.error("mul test failed ===> #{e.message}") + end + end + + 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/resetJupyterTpm" + 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 + + private + def find_myshixun + @myshixun = Myshixun.find_by!(identifier: params[:identifier]) + end + + def find_repo_name + @repo_path = @myshixun.try(:repo_path) + @path = params[:path] + end + + def python_file?(path) + false if path.blank? + path.to_s.split(".").last.downcase == "py" + end +end diff --git a/app/controllers/partners_controller.rb b/app/controllers/partners_controller.rb index 7875e1780..dfa1b2017 100644 --- a/app/controllers/partners_controller.rb +++ b/app/controllers/partners_controller.rb @@ -1,4 +1,5 @@ class PartnersController < ApplicationController + skip_before_action :check_sign include Base::PaginateHelper include Admins::RenderHelper diff --git a/app/controllers/polls_controller.rb b/app/controllers/polls_controller.rb index 0c442a613..3e6914dee 100644 --- a/app/controllers/polls_controller.rb +++ b/app/controllers/polls_controller.rb @@ -46,8 +46,8 @@ class PollsController < ApplicationController @polls = member_show_polls.size > 0 ? member_show_polls.public_or_unset : [] else #已分班级的成员,可以查看统一设置和单独设置(试卷是发布在该班级)试卷 # 已发布 当前用户班级分组的 试卷id - not_poll_ids = @course.poll_group_settings.poll_group_not_published.where("course_group_id = #{@member_group_id}").pluck(:poll_id) - @polls = member_show_polls.where.not(id: not_poll_ids) + publish_poll_ids = @course.poll_group_settings.poll_group_published.where("course_group_id = #{@member_group_id}").pluck(:poll_id) + @polls = member_show_polls.unified_setting.or(member_show_polls.where(id: publish_poll_ids)) end else #用户未登陆或不是该课堂成员,仅显示统一设置的(已发布的/已截止的),如有公开,则不显示锁,不公开,则显示锁 @is_teacher_or = 0 @@ -722,19 +722,16 @@ class PollsController < ApplicationController un_anonymous = params[:un_anonymous] ? true : false # 统一设置或者分班为0,则更新问卷,并删除问卷分组 if unified_setting || (course_group_ids.size == 0) - params_publish_time = params[:publish_time].present? ? params[:publish_time].to_time : nil - params_end_time = nil - if params[:end_time].blank? - if params_publish_time.present? - params_end_time = params_publish_time + 30.days - end - else - params_end_time = params[:end_time].to_time - end - # params_end_time = params[:end_time].present? ? params[:end_time].to_time : nil - if poll_status == 2 && @poll.publish_time != params_publish_time - normal_status(-1,"不允许修改发布时间") - elsif poll_status == 3 && (@poll.end_time != params_end_time || @poll.publish_time != params_publish_time) + tip_exception("发布时间不能为空") if params[:publish_time].blank? + tip_exception("截止时间不能为空") if params[:end_time].blank? + tip_exception("截止时间不能早于发布时间") if params[:publish_time].to_time > params[:end_time].to_time + tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")})") if + @course.end_date.present? && params[:end_time].to_time > @course.end_date.end_of_day + + params_publish_time = params[:publish_time].to_time + params_end_time = params[:end_time].to_time + + if poll_status != 1 && @poll.publish_time != params_publish_time normal_status(-1,"不允许修改发布时间") elsif params_publish_time.present? && params_end_time.present? && params_end_time < params_publish_time normal_status(-1,"截止时间不能小于发布时间") @@ -761,24 +758,25 @@ class PollsController < ApplicationController total_common_group = poll_groups_ids & total_common #传入的分班与问卷已存在的分班的交集 old_poll_groups = poll_groups_ids - total_common_group #后来传入的分班里,没有了的班级,即需要删除 params_times.each do |t| - course_id = t[:course_group_id] #为数组,可能会设置分班为各个班级id的数组 - poll_publish_time = t[:publish_time].present? ? t[:publish_time].to_time : nil - # poll_end_time = t[:end_time].present? ? t[:end_time].to_time : nil - poll_end_time = nil - if t[:end_time].blank? - if poll_publish_time.present? - poll_end_time = poll_publish_time + 30.days - end - else - poll_end_time = t[:end_time].to_time - end + tip_exception("发布时间不能为空") if t[:publish_time].blank? + tip_exception("截止时间不能为空") if t[:end_time].blank? + tip_exception("截止时间不能早于发布时间") if t[:publish_time].to_time > t[:end_time].to_time + tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")})") if + @course.end_date.present? && t[:end_time].to_time > @course.end_date.end_of_day + + course_id = t[:course_group_id] + poll_publish_time = t[:publish_time].to_time + poll_end_time = t[:end_time].to_time + poll_group = poll_groups.find_in_poll_group("course_group_id",course_id) #判断该分班是否存在 - if poll_group.present? && poll_group.first.end_time <= Time.now && (poll_end_time != poll_group.first.end_time || poll_publish_time != poll_group.first.publish_time) #已截止且时间改变的,则提示错误 + + if poll_group.present? && (poll_group.first.publish_time < Time.now) && (poll_publish_time != poll_group.first.publish_time) error_count += 1 end - if poll_group.present? && poll_group.first.publish_time < Time.now && poll_publish_time != poll_group.first.publish_time + if poll_group.present? && (poll_group.first.publish_time < Time.now && poll_group.first.end_time > Time.now) && (poll_end_time < Time.now) error_count += 1 end + if error_count == 0 common_group = poll_groups_ids & course_id #传入的班级与问卷已存在的班级的交集,即表示已有分班的 new_group_ids = course_id - common_group #新传入的班级id @@ -794,12 +792,12 @@ class PollsController < ApplicationController if the_group_setting_status == 2 poll_group_params = { :publish_time => the_group_setting.publish_time, - :end_time => poll_end_time + :end_time => poll_end_time < Time.now ? the_group_setting.end_time : poll_end_time } elsif the_group_setting_status == 3 poll_group_params = { :publish_time => the_group_setting.publish_time, - :end_time => the_group_setting.end_time + :end_time => poll_end_time } end the_group_setting.update_attributes(poll_group_params) diff --git a/app/controllers/schools_controller.rb b/app/controllers/schools_controller.rb index 99ca62b4c..ae0315cdd 100644 --- a/app/controllers/schools_controller.rb +++ b/app/controllers/schools_controller.rb @@ -1,4 +1,5 @@ class SchoolsController < ApplicationController + skip_before_action :check_sign def school_list schools = School.all @@ -14,7 +15,6 @@ class SchoolsController < ApplicationController schools = School.all keyword = params[:keyword].to_s.strip schools = schools.where('name LIKE ?', "%#{keyword}%") if keyword - render_ok(schools: schools.select(:id, :name).as_json) end diff --git a/app/controllers/shixun_lists_controller.rb b/app/controllers/shixun_lists_controller.rb index d0bfe3d88..c77da46e0 100644 --- a/app/controllers/shixun_lists_controller.rb +++ b/app/controllers/shixun_lists_controller.rb @@ -4,7 +4,8 @@ class ShixunListsController < ApplicationController end private + def search_params - params.permit(:keyword, :type, :page, :limit, :order, :status, :diff) + params.permit(:keyword, :type, :page, :limit, :order, :status, :diff, :sort, :no_jupyter) end end \ No newline at end of file diff --git a/app/controllers/shixuns_controller.rb b/app/controllers/shixuns_controller.rb index 61c549d9c..f86ade58f 100644 --- a/app/controllers/shixuns_controller.rb +++ b/app/controllers/shixuns_controller.rb @@ -18,16 +18,18 @@ class ShixunsController < ApplicationController 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, - :shixun_members_added, :change_manager, :collaborators_delete, - :cancel_publish, :add_collaborators, :add_file] + before_action :allowed, only: [:update, :close, :update_propaedeutics, :settings, :publish, :apply_public, :upload_git_folder, + :shixun_members_added, :change_manager, :collaborators_delete, :upload_git_file, + :cancel_apply_public, :cancel_publish, :add_collaborators, :add_file, :delete_git_file] before_action :portion_allowed, only: [:copy] before_action :special_allowed, only: [:send_to_course, :search_user_courses] + before_action :shixun_marker, only: [:new, :create] + skip_before_action :check_sign, only: [:download_file] ## 获取课程列表 def index - @shixuns = current_laboratory.shixuns.unhidden + @shixuns = current_laboratory.shixuns.unhidden.publiced ## 方向 if params[:tag_level].present? && params[:tag_id].present? @@ -67,15 +69,11 @@ class ShixunsController < ApplicationController ## 排序参数 bsort = params[:sort] || 'desc' - case params[:order_by] || 'publish_time' - when 'new' - @shixuns = @shixuns.order("shixuns.status = 2 desc, shixuns.created_at #{bsort}") + case params[:order_by] || 'new' when 'hot' - @shixuns = @shixuns.order("shixuns.status = 2 desc, shixuns.myshixuns_count #{bsort}") - when 'mine' - @shixuns = @shixuns.order("shixuns.created_at #{bsort}") + @shixuns = @shixuns.order("shixuns.public = 2 desc, shixuns.myshixuns_count #{bsort}") else - @shixuns = @shixuns.order("shixuns.status = 2 desc, shixuns.publish_time #{bsort}") + @shixuns = @shixuns.order("shixuns.public = 2 desc, shixuns.publish_time #{bsort}") end # 用id计数会快10+MS左右,对于搜索的内容随着数据的增加,性能会提升一些。 @@ -169,9 +167,10 @@ class ShixunsController < ApplicationController def show_right owner = @shixun.owner - #@fans_count = owner.fan_count - #@followed_count = owner.follow_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 # 排行榜 @@ -207,7 +206,7 @@ class ShixunsController < ApplicationController @new_shixun = Shixun.new @new_shixun.attributes = @shixun.attributes.dup.except("id","user_id","visits","gpid","status", "identifier", "averge_star", "homepage_show","repo_name", "myshixuns_count", "challenges_count", - "can_copy", "created_at", "updated_at") + "can_copy", "created_at", "updated_at", "public") @new_shixun.user_id = User.current.id @new_shixun.averge_star = 5 @new_shixun.identifier = generate_identifier Shixun, 8 @@ -218,7 +217,8 @@ class ShixunsController < ApplicationController if @shixun.shixun_info.present? ShixunInfo.create!(shixun_id: @new_shixun.id, description: @shixun.description, - evaluate_script: @shixun.evaluate_script) + evaluate_script: @shixun.evaluate_script, + fork_reason: params[:reason].to_s.strip) end # 同步私密版本库 @@ -265,7 +265,24 @@ class ShixunsController < ApplicationController project_fork(@new_shixun, @repo_path, current_user.login) 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') + raise "存储目录未定义" unless folder.present? + path = "#{folder}/#{@new_shixun.identifier}" + FileUtils.mkdir_p(path, :mode => 0777) unless File.directory?(path) + # 复制数据集 + save_path = File.join(folder, @shixun.identifier) + @shixun.data_sets.each do |set| + new_date_set = Attachment.new + new_date_set.attributes = set.attributes.dup.except("id", "container_id", "disk_directory") + new_date_set.container_id = @new_shixun.id + new_date_set.disk_directory = @new_shixun.identifier + new_date_set.save! + FileUtils.cp("#{save_path}/#{set.relative_path_filename}", path) + end + end # 同步复制关卡 if @shixun.challenges.present? @shixun.challenges.each do |challenge| @@ -344,7 +361,11 @@ class ShixunsController < ApplicationController #合作者 def collaborators @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.order("role = 1 desc, created_at asc").includes(:user).page(page).per(limit) end def fork_list @@ -365,12 +386,12 @@ class ShixunsController < ApplicationController end def create - begin - @shixun = CreateShixunService.call(current_user, shixun_params, params) - rescue => e - logger_error("shixun_create_error: #{e.message}") - tip_exception("创建实训失败!") - end + @shixun = CreateShixunService.call(current_user, shixun_params, params) + end + + # 保存jupyter到版本库 + def update_jupyter + jupyter_save_with_shixun(@shixun, params[:jupyter_port]) end def update @@ -399,25 +420,24 @@ class ShixunsController < ApplicationController @shixun.shixun_info.update_attributes(shixun_info_params) # 镜像变动 @shixun.shixun_mirror_repositories.where.not(mirror_repository_id: old_mirror_ids).destroy_all - @shixun.shixun_mirror_repositories.create!(new_mirror_id) + @shixun.shixun_mirror_repositories.create!(new_mirror_id) if new_mirror_id.present? # 镜像变动要更换服务配置 @shixun.shixun_service_configs.where.not(mirror_repository_id: old_mirror_ids).destroy_all - @shixun.shixun_service_configs.create!(service_create_params) + @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]) - smr.update_attributes(service) + logger.info("########smr: #{smr}") + smr.update_attributes(service) if smr.present? end # 添加第二仓库(管理员权限) - if current_user.admin_or_business? - 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 + 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 @@ -449,7 +469,13 @@ class ShixunsController < ApplicationController def update_learn_setting begin ActiveRecord::Base.transaction do - @shixun.update_attributes!(shixun_params) + update_params = + if params[:shixun][:vnc] + shixun_params.merge(vnc_evaluate: 1) + else + shixun_params + end + @shixun.update_attributes!(update_params) end rescue => e uid_logger_error("实训学习页面设置失败--------#{e.message}") @@ -458,12 +484,71 @@ class ShixunsController < ApplicationController end # Jupyter数据集 - def jupyter_data_sets + def get_data_sets page = params[:page] || 1 limit = params[:limit] || 10 - data_sets = @shixun.jupyter_data_sets + data_sets = @shixun.data_sets @data_count = data_sets.count - @data_sets= data_sets.page(page).per(limit) + @data_sets= data_sets.order("created_on desc").page(page).per(limit) + @absolute_folder = edu_setting('shixun_folder') + end + + # 实训测试集附件 + def upload_data_sets + 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) + tip_exception(e.message) + 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 + files.destroy_all + render_ok + rescue => e + uid_logger_error(e.message) + tip_exception(e.message) + end end def apply_shixun_mirror @@ -529,6 +614,8 @@ class ShixunsController < ApplicationController # @evaluate_scirpt = @shixun.evaluate_script || "无" end + + # 获取脚本内容 def get_script_contents mirrir_script = MirrorScript.find(params[:script_id]) @@ -687,7 +774,7 @@ class ShixunsController < ApplicationController # jupyter开启挑战 def jupyter_exec - begin + if is_shixun_opening? tip_show_exception(-3, "#{@shixun.opening_time.strftime('%Y-%m-%d %H:%M:%S')}") end @@ -697,70 +784,75 @@ class ShixunsController < ApplicationController else commit = GitService.commits(repo_path: @repo_path).try(:first) uid_logger("First comit########{commit}") - tip_exception("开启实战前请先在版本库中提交代码") if commit.blank? + tip_exception("开启挑战前,请先在Jupyter中填写内容并保存") if commit.blank? commit_id = commit["id"] cloud_bridge = edu_setting('cloud_bridge') myshixun_identifier = generate_identifier Myshixun, 10 - ActiveRecord::Base.transaction do - @myshixun = @shixun.myshixuns.create!(user_id: current_user.id, identifier: myshixun_identifier, - modify_time: @shixun.modify_time, reset_time: @shixun.reset_time, - onclick_time: Time.now, commit_id: commit_id) - # fork仓库 - 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 = {tpiID: "#{myshixun.id}", tpmGitURL: rep_url, tpiRepoName: myshixun.repo_name.split("/").last} - interface_post uri, params, 83, "实训云平台繁忙(繁忙等级:83)" + begin + ActiveRecord::Base.transaction do + @myshixun = @shixun.myshixuns.create!(user_id: current_user.id, identifier: myshixun_identifier, + modify_time: @shixun.modify_time, reset_time: @shixun.reset_time, + onclick_time: Time.now, commit_id: commit_id) + # fork仓库 + 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 = {tpiID: "#{@myshixun.id}", tpmGitURL: rep_url, tpiRepoName: @myshixun.repo_name.split("/").last} + interface_post uri, params, 83, "服务器出现问题,请重置环境" + end + rescue => e + uid_logger_error(e.message) + tip_exception("服务器出现问题,请重置环境") end end - rescue => e - uid_logger_error(e.message) - tip_exception("实训云平台繁忙(繁忙等级:81)") - end end def publish @status = 0 @position = [] begin - if @shixun.challenges.count == 0 - @status = 4 - else - @shixun.challenges.each do |challenge| - if challenge.challenge_tags.count == 0 - @status = 3 - @position << challenge.position + unless @shixun.is_jupyter? + if @shixun.challenges.count == 0 + @status = 4 + else + @shixun.challenges.each do |challenge| + if challenge.challenge_tags.count == 0 + @status = 3 + @position << challenge.position + end end - end - unfinish_challenge = @shixun.challenges.where(:st => 0, :path => nil) - if unfinish_challenge.count > 0 && !@shixun.is_choice_type? - @status = 2 - @pos = [] - unfinish_challenge.each do |challenge| - @pos << challenge.position + unfinish_challenge = @shixun.challenges.where(:st => 0, :path => nil) + if unfinish_challenge.count > 0 && !@shixun.is_choice_type? + @status = 2 + @pos = [] + unfinish_challenge.each do |challenge| + @pos << challenge.position + end end end end if @status == 0 - @shixun.update_attributes!(:status => 1) - apply = ApplyAction.where(:container_type => "ApplyShixun", :container_id => @shixun.id).order("created_at desc").first - if apply && apply.status == 0 - @status = 0 - else - ApplyAction.create(:container_type => "ApplyShixun", :container_id => @shixun.id, :user_id => current_user.id, :status => 0) - #begin - # status = Trustie::Sms.send(mobile: '18711011226', send_type:'publish_shixun' , name: '管理员') - #rescue => e - # Rails.logger.error "发送验证码出错: #{e}" - #end - @status = 1 - end + @shixun.update_attributes!(:status => 2) end rescue Exception => e logger.error("pushlish game #{e}") end end + def apply_public + tip_exception(-1, "请先发布实训再申请公开") if @shixun.status != 2 + ActiveRecord::Base.transaction do + @shixun.update_attributes!(public: 1) + apply = ApplyAction.where(:container_type => "ApplyShixun", :container_id => @shixun.id).order("created_at desc").first + if apply && apply.status == 0 + @status = 0 + else + ApplyAction.create(:container_type => "ApplyShixun", :container_id => @shixun.id, :user_id => current_user.id, :status => 0) + end + end + normal_status(0, "申请成功") + end + # 设置私密版本库的在tpm中的目录 def set_secret_dir raise("设置路径不能为空") if params[:secret_dir_path].blank? @@ -792,7 +884,36 @@ class ShixunsController < ApplicationController author_name = current_user.real_name author_email = current_user.git_mail @content = update_file_content content, @repo_path, @path, author_email, author_name, "Edit by browser" - end + end + + def upload_git_file + upload_file = params["file"] + uid_logger("#########################file_params####{params["#{params[:file]}"]}") + raise "未上传文件" unless upload_file + content = upload_file.tempfile.read + author_name = current_user.real_name + author_email = current_user.git_mail + message = params[:message] || "upload file by browser" + update_file_content(content, @repo_path, @path, author_email, author_name, message) + render_ok + end + + # 上传目录 + def upload_git_folder + author_name = current_user.real_name + author_email = current_user.git_mail + message = params[:message] || "upload folder by browser" + git_add_folder(@path, author_name, author_email, message) + render_ok + end + + def delete_git_file + author_name = current_user.real_name + author_email = current_user.git_mail + message = params[:message] || "delete file by browser" + git_delete_file(@path, author_name, author_email, message) + render_ok + end def add_collaborators member_ids = "(" + @shixun.shixun_members.map(&:user_id).join(',') + ")" @@ -826,16 +947,20 @@ class ShixunsController < ApplicationController # 搜索成员 if request.get? @collaborators = @shixun.shixun_members.where("user_id != #{@shixun.user_id}") - else - if params[:user_id] - man_member = ShixunMember.where(:shixun_id => @shixun.id, :user_id => @shixun.user_id).first - cha_member = ShixunMember.where(:user_id => params[:user_id], :shixun_id => @shixun.id).first - if man_member && cha_member - man_member.update_attribute(:role, 2) - cha_member.update_attribute(:role, 1) - @shixun.update_attribute(:user_id, cha_member.user_id) - end - end + else + begin + raise("请先选择成员") if params[:user_id].blank? + man_member = ShixunMember.where(:shixun_id => @shixun.id, :user_id => @shixun.user_id).first + cha_member = ShixunMember.where(:user_id => params[:user_id], :shixun_id => @shixun.id).first + if man_member && cha_member + man_member.update_attribute(:role, 2) + cha_member.update_attribute(:role, 1) + @shixun.update_attribute(:user_id, cha_member.user_id) + end + rescue => e + logger.error("######change_manager_error: #{e.message}") + render_error(e.message) + end end end @@ -898,14 +1023,24 @@ class ShixunsController < ApplicationController :disposition => 'attachment' #inline can open in browser end + # 撤销申请公开 + def cancel_apply_public + tip_exception("实训已经公开,无法撤销") if @shixun.public == 2 + ActiveRecord::Base.transaction do + apply = ApplyAction.where(:container_type => "ApplyShixun", :container_id => @shixun.id).order("created_at desc").first + if apply && apply.status == 0 + apply.update_attributes!(status: 3) + apply.tidings&.destroy_all + end + @shixun.update_column(:public, 0) + end + normal_status(0, "成功撤销申请") + end + # 撤销发布 def cancel_publish - tip_exception("实训已经发布,无法撤销") if @shixun.status == 2 - apply = ApplyAction.where(:container_type => "ApplyShixun", :container_id => @shixun.id).order("created_at desc").first - if apply && apply.status == 0 - apply.update_attribute(:status, 3) - apply.tidings.destroy_all - end + tip_exception("请先撤销申请公开,再撤销发布") if @shixun.public == 1 + tip_exception("实训已经公开,无法撤销") if @shixun.public == 2 @shixun.update_column(:status, 0) end @@ -1004,4 +1139,48 @@ private ShixunSecretRepository.create!(repo_name: repo_path.split(".")[0], shixun_id: @shixun.id) 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 diff --git a/app/controllers/student_works_controller.rb b/app/controllers/student_works_controller.rb index 637155a1a..d71ca8037 100644 --- a/app/controllers/student_works_controller.rb +++ b/app/controllers/student_works_controller.rb @@ -529,8 +529,8 @@ class StudentWorksController < ApplicationController @echart_data = student_efficiency(@homework, @work) @myself_eff = @echart_data[:efficiency_list].find { |item| item.last == @user.id } @myself_consume = @echart_data[:consume_list].find { |item| item.last == @user.id } - filename_ = "#{@use&.student_id}_#{@use&.real_name}_#{@shixun&.name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}" - filename = Base64.urlsafe_encode64(filename_.strip) + filename_ = "#{@user&.student_id}_#{@user&.real_name}_#{@shixun&.name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}.pdf" + filename = filename_.strip.tr("+/", "-_") stylesheets = %w(shixun_work/shixun_work.css shared/codemirror.css) if params[:export].present? && params[:export] normal_status(0,"正在下载中") @@ -559,6 +559,7 @@ class StudentWorksController < ApplicationController if @work.work_status == 0 @work.work_status = 1 @work.commit_time = Time.now + @work.compelete_status = 1 if @homework.homework_type == "practice" # 分组作业更新分组id @work.group_id = @homework.max_group_id if @homework.homework_type == "group" end @@ -739,7 +740,8 @@ class StudentWorksController < ApplicationController comment: comment) challenge_score.create_tiding current_user.id 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 update_none_commit_work @work, @homework end @@ -877,6 +879,7 @@ class StudentWorksController < ApplicationController def update_none_commit_work work, homework if work.work_status == 0 work.work_status = 1 + work.compelete_status = 1 work.commit_time = homework.end_time work.update_time = Time.now end diff --git a/app/controllers/subjects_controller.rb b/app/controllers/subjects_controller.rb index 6a9438a79..7df9aae89 100644 --- a/app/controllers/subjects_controller.rb +++ b/app/controllers/subjects_controller.rb @@ -7,6 +7,8 @@ class SubjectsController < ApplicationController :search_members, :add_subject_members, :statistics, :shixun_report, :school_report, :up_member_position, :down_member_position, :update_team_title] before_action :require_admin, only: [:copy_subject] + before_action :shixun_marker, only: [:new, :create, :add_shixun_to_stage] + include ApplicationHelper include SubjectsHelper @@ -214,7 +216,15 @@ class SubjectsController < ApplicationController GitService.add_repository(repo_path: repo_path) # todo: 为什么保存的时候要去除后面的.git呢?? @shixun.update_column(:repo_name, repo_path.split(".")[0]) - mirror_id = MirrorRepository.find_by(type_name: 'Python3.6')&.id + mirror_id = + if @shixun.is_jupyter? + folder = EduSetting.get('shixun_folder') + path = "#{folder}/#{identifier}" + FileUtils.mkdir_p(path, :mode => 0777) unless File.directory?(path) + MirrorRepository.where("type_name like '%Jupyter%'").first&.id + else + MirrorRepository.find_by(type_name: 'Python3.6')&.id + end if mirror_id ShixunMirrorRepository.create!(:shixun_id => @shixun.id, :mirror_repository_id => mirror_id) @shixun.shixun_service_configs.create!(:shixun_id => @shixun.id, :mirror_repository_id => mirror_id) @@ -247,7 +257,7 @@ class SubjectsController < ApplicationController CourseSecondCategory.create!(name: stage.name, course_id: @course.id, category_type: "shixun_homework", course_module_id: course_module.id, position: course_module.course_second_categories.count + 1) - stage.shixuns.where(id: params[:shixun_ids], status: 2).each do |shixun| + stage.shixuns.no_jupyter.where(id: params[:shixun_ids], status: 2).each do |shixun| homework = HomeworksService.new.create_homework shixun, @course, category, current_user homework_ids << homework.id end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index a1f6a5495..c6dd7830c 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -2,6 +2,7 @@ class UsersController < ApplicationController before_action :load_user, only: [:show, :homepage_info] before_action :check_user_exist, only: [:show, :homepage_info] + skip_before_action :check_sign, only: [:attachment_show] # 检查是否更新 def system_update diff --git a/app/controllers/weapps/courses_controller.rb b/app/controllers/weapps/courses_controller.rb index a30fdfa4c..cb3c195d6 100644 --- a/app/controllers/weapps/courses_controller.rb +++ b/app/controllers/weapps/courses_controller.rb @@ -93,8 +93,8 @@ class Weapps::CoursesController < Weapps::BaseController end if course_group_id.present? - course_group = CourseGroup.find(course_group_id) if course_group_id != 0 - @students = @students.where(course_group_id: course_group&.id.to_i) + @course_group = CourseGroup.find(course_group_id) if course_group_id != 0 + @students = @students.where(course_group_id: @course_group&.id.to_i) end @students_count = @students.size @@ -167,6 +167,15 @@ class Weapps::CoursesController < Weapps::BaseController normal_status(0, "修改成功") 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 def course_params diff --git a/app/decorators/grade_decorator.rb b/app/decorators/grade_decorator.rb index ffffa11c9..5e2b9deed 100644 --- a/app/decorators/grade_decorator.rb +++ b/app/decorators/grade_decorator.rb @@ -31,6 +31,9 @@ module GradeDecorator when 'check_ta_answer' then game = Game.find_by(id: container_id) game.present? ? "查看实训“#{game.challenge.shixun.name}”第#{game.challenge.position}关的TA人解答消耗的金币" : '' + when 'hack' then + hack = Hack.find_by(id: container_id) + hack.present? ? "完成了题目解答“#{hack.name}”,获得金币奖励:#{hack.score}" : '' end end end \ No newline at end of file diff --git a/app/decorators/tiding_decorator.rb b/app/decorators/tiding_decorator.rb index 130e7f4b8..58345b601 100644 --- a/app/decorators/tiding_decorator.rb +++ b/app/decorators/tiding_decorator.rb @@ -220,11 +220,14 @@ module TidingDecorator when 'Journal' then message = parent_container&.notes.present? ? ':' + message_content_helper(parent_container.notes) : '' I18n.t(locale_format(parent_container_type)) % message + when 'Hack' then + I18n.t(locale_format(parent_container_type)) % parent_container.name end end def discuss_content - I18n.t(locale_format(container.parent_id.present?)) % message_content_helper(container.content) + I18n.t(locale_format(parent_container_type, container.parent_id.present?)) % + (parent_container_type == 'Hack' ? container.content : message_content_helper(container.content)) end def grade_content @@ -250,6 +253,9 @@ module TidingDecorator when 'shixunPublish' then name = Shixun.find_by(id: parent_container_id)&.name || '---' I18n.t(locale_format(parent_container_type)) % [name, container.score] + when 'Hack' then + name = Hack.find_by(id: container_id)&.name || '---' + I18n.t(locale_format(parent_container_type)) % [name, container.score] else I18n.t(locale_format(parent_container_type)) % container.score end @@ -405,4 +411,8 @@ module TidingDecorator def subject_start_course_content I18n.t(locale_format) % belong_container&.name end + + def hack_content + I18n.t(locale_format(parent_container_type)) % (container&.name || extra) + end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index be633b2cc..40e6cb365 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -64,7 +64,7 @@ module ApplicationHelper shixun_id = shixun_id.blank? ? -1 : shixun_id.join(",") Shixun.select([:id, :name, :user_id, :challenges_count, :myshixuns_count, :trainee, :identifier]).where("id - in(#{shixun_id})").unhidden.order("homepage_show asc, myshixuns_count desc").limit(3) + in(#{shixun_id})").unhidden.publiced.order("homepage_show asc, myshixuns_count desc").limit(3) end @@ -210,7 +210,7 @@ module ApplicationHelper # 普通/分组 作业作品状态数组 def student_work_status homework, user_id, course, work 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) late_time = homework.late_time || course.end_date diff --git a/app/helpers/challenges_helper.rb b/app/helpers/challenges_helper.rb index c6d05817d..fc0101dff 100644 --- a/app/helpers/challenges_helper.rb +++ b/app/helpers/challenges_helper.rb @@ -4,4 +4,7 @@ module ChallengesHelper str.gsub(/\A\r/, "\r\r") end + + + end diff --git a/app/helpers/export_helper.rb b/app/helpers/export_helper.rb index 31e1ecf45..ca76ee953 100644 --- a/app/helpers/export_helper.rb +++ b/app/helpers/export_helper.rb @@ -22,21 +22,21 @@ module ExportHelper end end - shixun_homeworks = shixun_homeworks&.includes(score_student_works: :user) + shixun_homeworks = shixun_homeworks&.includes(:student_works) common_homeworks = homeworks.search_homework_type(1) #全部普通作业 common_titles = common_homeworks.pluck(:name)+ ["总得分"] - common_homeworks = common_homeworks&.includes(score_student_works: :user) + common_homeworks = common_homeworks&.includes(:student_works) group_homeworks = homeworks.search_homework_type(3) #全部分组作业 group_titles = group_homeworks.pluck(:name)+ ["总得分"] - group_homeworks = group_homeworks&.includes(score_student_works: :user) + group_homeworks = group_homeworks&.includes(:student_works) 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) + ["总得分"] - exercises = exercises&.includes(user: :user_extension, score_exercise_users: :user) + exercises = exercises&.includes(:exercise_users) total_user_score_array = [] #学生总成绩集合 @@ -67,7 +67,7 @@ module ExportHelper #实训作业 if shixun_homeworks.size > 0 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? h_score = 0.0 #该作业的得分为0 else @@ -82,7 +82,7 @@ module ExportHelper #普通作业 if common_homeworks.size > 0 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? h_score_1 = 0.0 #该作业的得分为0 else @@ -97,7 +97,7 @@ module ExportHelper #分组作业 if group_homeworks.size > 0 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? h_score_3 = 0.0 #该作业的得分为0 else @@ -112,7 +112,7 @@ module ExportHelper #毕设作业 if tasks.size > 0 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? t_score = 0.0 else @@ -127,7 +127,7 @@ module ExportHelper #试卷 if exercises.size > 0 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? e_score = 0.0 else @@ -163,9 +163,12 @@ module ExportHelper count_2 = common_homeworks.size count_3 = group_homeworks.size count_4 = tasks.size + + all_user_ids = all_members.pluck(:user_id) + #实训作业 shixun_homeworks.each_with_index do |s,index| - all_student_works = s.score_student_works #该实训题的全部用户回答 + all_student_works = s.student_works.where(user_id: all_user_ids) #该实训题的全部用户回答 title_no = index.to_i + 1 student_work_to_xlsx(all_student_works,s) shixun_work_display_name = format_sheet_name (title_no.to_s + "." + s.name).strip.first(30) @@ -175,7 +178,7 @@ module ExportHelper #普通作业 common_homeworks.each_with_index do |c,index| - all_student_works = c.score_student_works #当前用户的对该作业的回答 + all_student_works = c.student_works.where(user_id: all_user_ids) #当前用户的对该作业的回答 title_no = count_1 + index.to_i + 1 student_work_to_xlsx(all_student_works,c) @@ -187,7 +190,7 @@ module ExportHelper #分组作业 group_homeworks.each_with_index do |c,index| - all_student_works = c.score_student_works #当前用户的对该作业的回答 + all_student_works = c.student_works.where(user_id: all_user_ids) #当前用户的对该作业的回答 title_no = count_1 + count_2 + index.to_i + 1 student_work_to_xlsx(all_student_works,c) work_name = format_sheet_name (title_no.to_s + "." + c.name).strip.first(30) @@ -197,7 +200,7 @@ module ExportHelper #毕设任务 tasks.each_with_index do |c,index| - all_student_works = c.score_graduation_works #当前用户的对该作业的回答 + all_student_works = c.graduation_works.where(user_id: all_user_ids) #当前用户的对该作业的回答 title_no = count_1 + count_2 + count_3 + index.to_i + 1 graduation_work_to_xlsx(all_student_works,c,current_user) work_name = format_sheet_name (title_no.to_s + "." + c.name).strip.first(30) @@ -207,7 +210,7 @@ module ExportHelper #试卷的导出 exercises.each_with_index do |c,index| - all_student_works = c.score_exercise_users #当前用户的对该作业的回答 + all_student_works = c.exercise_users.where(user_id: all_user_ids) #当前用户的对该作业的回答 title_no = count_1 + count_2 + count_3 + count_4 + index.to_i + 1 get_export_users(c,course,all_student_works) work_name = format_sheet_name (title_no.to_s + "." + c.exercise_name).strip.first(30) @@ -426,7 +429,7 @@ module ExportHelper end else #实训题 shixun = homework.shixuns.take - shixun_head_cells = %w(完成情况 通关时间 学员在EduCoder做实训花费的时间 总评测次数 获得经验值 关卡得分) + shixun_head_cells = %w(截止前完成关卡 通关时间 学员在EduCoder做实训花费的时间 总评测次数 获得经验值 关卡得分) eff_boolean = homework.work_efficiency if eff_boolean eff_score_cell = ["效率分"] @@ -452,16 +455,18 @@ module ExportHelper course_name = course.students.find_by(user_id: w.user_id).try(:course_group_name) w_5 = course_name.present? ? course_name : "--" #0: 未提交, 1 按时提交, 2 延迟提交 - if w.work_status == 0 - w_6 = "未提交" - elsif w.work_status == 1 - w_6 = "按时提交" - elsif w.work_status == 2 - w_6 = "延迟提交" + if w.compelete_status == 0 + w_6 = "未开启" + elsif w.compelete_status == 1 + w_6 = "未通关" + elsif w.compelete_status == 2 + w_6 = "按时通关" + elsif w.compelete_status == 3 + w_6 = "迟交通关" else w_6 = "--" 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_9 = myshixun ? (myshixun.try(:passed_count).to_i > 0 ? myshixun.total_spend_time : '--') : "--" #总耗时 w_10 = myshixun ? myshixun.output_times : 0 #评测次数 @@ -478,7 +483,7 @@ module ExportHelper w_14 = nil end 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 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 diff --git a/app/helpers/homework_commons_helper.rb b/app/helpers/homework_commons_helper.rb index efc14dc5e..f962288eb 100644 --- a/app/helpers/homework_commons_helper.rb +++ b/app/helpers/homework_commons_helper.rb @@ -24,40 +24,37 @@ module HomeworkCommonsHelper time = course.end_date.strftime("%Y-%m-%d") time_status = 6 else - 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) - status << "补交中" - 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 - when 3 - if ho_detail_manual.evaluation_end && ho_detail_manual.evaluation_end > Time.now - status << "匿评中" - time = "提交剩余时间:" + how_much_time(ho_detail_manual.evaluation_end) - time_status = 3 - end - when 4 - if ho_detail_manual.appeal_time && ho_detail_manual.appeal_time > Time.now - status << "申诉中" - time = "申诉剩余时间:" + how_much_time(ho_detail_manual.appeal_time) - time_status = 4 - end - when 2, 5, 6 - status << "评阅中" - time = course.end_date.present? ? ("评阅剩余时间:" + how_much_time(course.end_date.end_of_day)) : "" - time_status = 5 - 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 + (homework_common.late_time.nil? || homework_common.late_time > Time.now) + status << "补交中" time = "补交剩余时间:" + how_much_time(homework_common.late_time) time_status = 2 end + + case ho_detail_manual.comment_status + when 3 + if ho_detail_manual.evaluation_end && ho_detail_manual.evaluation_end > Time.now + status << "匿评中" + time = "匿评剩余时间:" + how_much_time(ho_detail_manual.evaluation_end) + time_status = 3 + end + when 4 + if ho_detail_manual.appeal_time && ho_detail_manual.appeal_time > Time.now + status << "申诉中" + time = "申诉剩余时间:" + how_much_time(ho_detail_manual.appeal_time) + time_status = 4 + end + else + if status.blank? + status << "已截止" + time = course.end_date.present? ? ("评阅剩余时间:" + how_much_time(course.end_date.end_of_day)) : "" + time_status = 5 + end + end else # member = course.course_members.find_by(user_id: user.id, is_active: 1) # teacher_course_groups = member.try(:teacher_course_groups) @@ -65,25 +62,28 @@ module HomeworkCommonsHelper # 作业统一设置、游客身份、超级管理员、分班权限不限的老师身份 if homework_common.unified_setting || identity > Course::STUDENT || identity == Course::ADMIN || - (identity < Course::STUDENT && teacher_course_groups.blank?) + (identity < Course::STUDENT && teacher_course_groups.blank?) case ho_detail_manual.comment_status - when 0 - status << "未发布" - time = homework_common.publish_time.present? ? "将于 #{format_time(homework_common.publish_time)} 发布" : "创建于#{time_from_now(homework_common.created_at)}" - time_status = 0 - when 1 - if homework_common.end_time && homework_common.end_time >= Time.now - status << "提交中" - time = "提交剩余时间:" + how_much_time(homework_common.end_time) - time_status = 1 - elsif homework_common.end_time && homework_common.end_time < Time.now + when 0 + status << "未发布" + time = homework_common.publish_time.present? ? "将于 #{format_time(homework_common.publish_time)} 发布" : "创建于#{time_from_now(homework_common.created_at)}" + time_status = 0 + when 1 + if homework_common.end_time && homework_common.end_time >= Time.now + status << "提交中" + time = "提交剩余时间:" + how_much_time(homework_common.end_time) + time_status = 1 + elsif homework_common.end_time && homework_common.end_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_status = 2 + else + status << "已截止" + time = course.end_date.present? ? ("评阅剩余时间:" + how_much_time(course.end_date.end_of_day)) : "" time_status = 5 - if homework_common.allow_late && (homework_common.late_time.nil? || homework_common.late_time >= Time.now) - time = "补交剩余时间:" + how_much_time(homework_common.late_time) - time_status = 2 - end - status << "评阅中" end + end end else # 未分班的学生始终显示“未发布”(按理不会来到这个判断) @@ -99,9 +99,9 @@ module HomeworkCommonsHelper else # 多个分班权限的取最小publish_time,最大end_time min_publish_time = homework_common.homework_group_settings.where.not(publish_time: nil). - where(course_group_id: teacher_course_groups.pluck(:course_group_id)).pluck(:publish_time).min + where(course_group_id: teacher_course_groups.pluck(:course_group_id)).pluck(:publish_time).min max_end_time = homework_common.homework_group_settings.where.not(end_time: nil). - where(course_group_id: teacher_course_groups.pluck(:course_group_id)).pluck(:end_time).max + where(course_group_id: teacher_course_groups.pluck(:course_group_id)).pluck(:end_time).max end if min_publish_time.nil? @@ -116,24 +116,22 @@ module HomeworkCommonsHelper status << "提交中" time = "提交剩余时间:" + how_much_time(max_end_time) 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 - status << "评阅中" - time = "" + status << "已截止" + time = course.end_date.present? ? ("评阅剩余时间:" + how_much_time(course.end_date.end_of_day)) : "" time_status = 5 end end end - status << "未开启补交" if !homework_common.allow_late && time_status != 0 + status << "未开启补交" if !homework_common.allow_late && time_status == 1 end end end - # 如果作业状态都没有的话,在课堂结束前,都显示评阅中 + # 如果作业状态都没有的话,在课堂结束前,都显示已截止 if status.blank? - status << "评阅中" + status << "已截止" + time = course.end_date.present? ? ("评阅剩余时间:" + how_much_time(course.end_date.end_of_day)) : "" + time_status = 5 end result[:status] = status result[:time] = time @@ -144,7 +142,7 @@ module HomeworkCommonsHelper # 阶段剩余时间 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.end_time > Time.now status = "剩余提交时间" @@ -224,10 +222,10 @@ module HomeworkCommonsHelper # 作品状态 def practice_homework_status homework, member - [{id: 3, name: "未通关", count: homework.un_complete_count(member)}, - {id: 4, name: "已通关", count: homework.complete_count(member)}, - {id: 1, name: "按时完成", count: homework.finished_count(member)}, - {id: 2, name: "延时完成", count: homework.delay_finished_count(member)}] + [{id: 0, name: "未开启", count: homework.compelete_status_count(member, 0)}, + {id: 1, name: "未通关", count: homework.compelete_status_count(member, 1)}, + {id: 2, name: "按时通关", count: homework.compelete_status_count(member, 2)}, + {id: 3, name: "迟交通关", count: homework.compelete_status_count(member, 3)}] end # 作品状态 diff --git a/app/helpers/shixuns_helper.rb b/app/helpers/shixuns_helper.rb index b41750bed..655a7ed04 100644 --- a/app/helpers/shixuns_helper.rb +++ b/app/helpers/shixuns_helper.rb @@ -27,6 +27,17 @@ module ShixunsHelper end end + def shixun_public_status shixun + case shixun.try(:public) + when 0,nil + "未公开" + when 1 + "待审核" + when 2 + "已公开" + end + end + # 已完成实训所获得的经验值 def myshixun_exp myshixun score = 0 diff --git a/app/jobs/homework_batch_comment_job.rb b/app/jobs/homework_batch_comment_job.rb new file mode 100644 index 000000000..b9baa8557 --- /dev/null +++ b/app/jobs/homework_batch_comment_job.rb @@ -0,0 +1,20 @@ +# 作业的一键评阅 +class HomeworkBatchCommentJob < ApplicationJob + queue_as :default + + def perform(comment, hidden_comment, work_ids, homework_id, user_id) + # Do something later + homework = HomeworkCommon.find_by(id: homework_id) + return if homework.blank? + + attrs = %i[student_work_id challenge_id user_id comment hidden_comment batch_comment created_at updated_at] + + same_attrs = {challenge_id: 0, user_id: user_id, comment: comment, hidden_comment: hidden_comment, batch_comment: 1} + + ShixunWorkComment.bulk_insert(*attrs) do |worker| + work_ids.each do |work_id| + worker.add same_attrs.merge(student_work_id: work_id) + end + end + end +end diff --git a/app/jobs/sync_trustie_job.rb b/app/jobs/sync_trustie_job.rb index 33df5b529..dec09debc 100644 --- a/app/jobs/sync_trustie_job.rb +++ b/app/jobs/sync_trustie_job.rb @@ -17,10 +17,17 @@ class SyncTrustieJob < ApplicationJob "number": count } uri = URI.parse(url) + # http = Net::HTTP.new(uri.hostname, uri.port) + if api_host http = Net::HTTP.new(uri.hostname, uri.port) - http.send_request('PUT', uri.path, sync_json.to_json, {'Content-Type' => 'application/json'}) - Rails.logger.info("#######_________response__sync__end_____#########") + + if api_host.include?("https://") + http.use_ssl = true + end + + response = http.send_request('PUT', uri.path, sync_json.to_json, {'Content-Type' => 'application/json'}) + Rails.logger.info("#######_________response__sync__end_____#########{response.body}") end end end diff --git a/app/models/attachment.rb b/app/models/attachment.rb index f18d9cd2a..ac051428f 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -33,6 +33,10 @@ class Attachment < ApplicationRecord File.join(File.join(Rails.root, "files"), disk_directory.to_s, disk_filename.to_s) end + def relative_path_filename + File.join(disk_directory.to_s, disk_filename.to_s) + end + def title title = filename if container && container.is_a?(StudentWork) && author_id != User.current.id diff --git a/app/models/course_group.rb b/app/models/course_group.rb index d57edf497..9486c9043 100644 --- a/app/models/course_group.rb +++ b/app/models/course_group.rb @@ -2,13 +2,15 @@ class CourseGroup < ApplicationRecord default_scope { order("course_groups.position ASC") } belongs_to :course, counter_cache: true has_many :course_members - has_many :exercise_group_settings,:dependent => :destroy has_many :attachment_group_settings, :dependent => :destroy has_many :homework_group_reviews, :dependent => :destroy + has_many :teacher_course_groups, :dependent => :destroy + has_many :homework_group_settings, :dependent => :destroy scope :by_group_ids, lambda { |ids| where(id: ids)} validates :name, length: { maximum: 60 } + validates_uniqueness_of :name, scope: :course_id, message: "不能创建相同名称的分班" after_create :generate_invite_code diff --git a/app/models/discuss.rb b/app/models/discuss.rb index a50b18a6f..4e6cd617c 100644 --- a/app/models/discuss.rb +++ b/app/models/discuss.rb @@ -10,7 +10,7 @@ class Discuss < ApplicationRecord has_one :praise_tread_cache, as: :object, dependent: :destroy belongs_to :dis, polymorphic: true - belongs_to :challenge + belongs_to :challenge, optional: true after_create :send_tiding scope :children, -> (discuss_id){ where(parent_id: discuss_id).includes(:user).reorder(created_at: :asc) } @@ -52,11 +52,21 @@ class Discuss < ApplicationRecord private def send_tiding + if dis_type == 'Shixun' + send_user_id = has_parent? ? parent.user_id : Challenge.find(challenge_id).user_id + parent_container_type = 'Challenge' + challenge_id = challenge_id + extra = '' + elsif dis_type == 'Hack' + send_user_id = has_parent? ? parent.user_id : Hack.find(dis_id).user_id + parent_container_type = 'Hack' + challenge_id = dis_id + extra = HackUserLastestCode.where(user_id: user_id, hack_id: dis_id).first&.identifier + end base_attrs = { - trigger_user_id: user_id, parent_container_id: challenge_id, parent_container_type: 'Challenge', - belong_container_id: dis_id, belong_container_type: 'Shixun', viewed: 0, tiding_type: 'Comment' + trigger_user_id: user_id, parent_container_id: challenge_id, parent_container_type: parent_container_type, + belong_container_id: dis_id, belong_container_type: dis_type, viewed: 0, tiding_type: 'Comment', extra: extra } - user_id = has_parent? ? parent.user_id : Challenge.find(challenge_id).user_id - tidings.create!(base_attrs.merge(user_id: user_id)) + tidings.create!(base_attrs.merge(user_id: send_user_id)) end end diff --git a/app/models/game.rb b/app/models/game.rb index d82392a59..062ad15cc 100644 --- a/app/models/game.rb +++ b/app/models/game.rb @@ -119,6 +119,12 @@ class Game < ApplicationRecord # self.outputs.pluck(:query_index).first #end + # 是否查看了答案(通关的是否在通关前看的答案) + def view_answer + answer_exists = Grade.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 diff --git a/app/models/hack.rb b/app/models/hack.rb index 506cd4942..37e1f239d 100644 --- a/app/models/hack.rb +++ b/app/models/hack.rb @@ -11,6 +11,11 @@ class Hack < ApplicationRecord has_many :hack_codes, :dependent => :destroy has_many :hack_user_lastest_codes, :dependent => :destroy has_many :discusses, as: :dis, dependent: :destroy + # 点赞 + has_many :praise_treads, as: :praise_tread_object, dependent: :destroy + # 消息 + has_many :tidings, as: :container + belongs_to :user scope :published, -> { where(status: 1) } diff --git a/app/models/hack_set.rb b/app/models/hack_set.rb index 6afe05663..9e2186fb5 100644 --- a/app/models/hack_set.rb +++ b/app/models/hack_set.rb @@ -1,5 +1,5 @@ class HackSet < ApplicationRecord - #validates :input, presence: { message: "测试集输入不能为空" } + validates :input, presence: { message: "测试集输入不能为空" } validates :output, presence: { message: "测试集输出不能为空" } validates_uniqueness_of :input, scope: [:hack_id, :input], message: "多个测试集的输入不能相同" # 编程题测试集 diff --git a/app/models/hack_user_code.rb b/app/models/hack_user_code.rb index eee394e39..1e13f8bfb 100644 --- a/app/models/hack_user_code.rb +++ b/app/models/hack_user_code.rb @@ -1,4 +1,5 @@ class HackUserCode < ApplicationRecord + # error_test_set_id: 错误的测试集id # 用户编程题的信息 belongs_to :hack belongs_to :hack_user_lastest_code diff --git a/app/models/hack_user_lastest_code.rb b/app/models/hack_user_lastest_code.rb index b4a707603..99582af41 100644 --- a/app/models/hack_user_lastest_code.rb +++ b/app/models/hack_user_lastest_code.rb @@ -8,8 +8,10 @@ class HackUserLastestCode < ApplicationRecord belongs_to :user has_many :hack_user_codes, dependent: :destroy 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 :passed, -> {where(status: 1)} + validates_length_of :notes, maximum: 5000, message: "笔记不能超过5000个字" + end diff --git a/app/models/homework_common.rb b/app/models/homework_common.rb index d37650c37..58b52bdd2 100644 --- a/app/models/homework_common.rb +++ b/app/models/homework_common.rb @@ -108,7 +108,7 @@ class HomeworkCommon < ApplicationRecord # 是否在补交阶段内 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 && homework_setting.end_time < Time.now && self.allow_late && (self.late_time.nil? || self.late_time > Time.now) end @@ -119,7 +119,7 @@ class HomeworkCommon < ApplicationRecord if self.course.is_end || (self.allow_late && self.late_time && self.late_time < Time.now) status = true 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 end status @@ -241,14 +241,8 @@ class HomeworkCommon < ApplicationRecord self.teacher_works(member).delay_finished.count end - # 未通关数 - def un_complete_count member - 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 + def compelete_status_count member, status + teacher_works(member).where(compelete_status: status).count end # 分组作业的最大分组id @@ -257,12 +251,13 @@ class HomeworkCommon < ApplicationRecord end # 作业的分班设置时间 - def homework_group_setting user_id + def homework_group_setting user_id, current_user=false if unified_setting homework_setting = self else - member = course.course_member(user_id) - group_setting = self.homework_group_settings.find_by_course_group_id(member.try(:course_group_id)) + # 当前用户是从course_member中取,否则是从学生中取(双重身份的原因) + 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 end homework_setting diff --git a/app/models/item_analysis.rb b/app/models/item_analysis.rb new file mode 100644 index 000000000..8f6e71302 --- /dev/null +++ b/app/models/item_analysis.rb @@ -0,0 +1,3 @@ +class ItemAnalysis < ApplicationRecord + belongs_to :item_bank +end diff --git a/app/models/item_bank.rb b/app/models/item_bank.rb new file mode 100644 index 000000000..8078a55e0 --- /dev/null +++ b/app/models/item_bank.rb @@ -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 diff --git a/app/models/item_basket.rb b/app/models/item_basket.rb new file mode 100644 index 000000000..d736d9bc0 --- /dev/null +++ b/app/models/item_basket.rb @@ -0,0 +1,4 @@ +class ItemBasket < ApplicationRecord + belongs_to :item_bank + belongs_to :user +end diff --git a/app/models/item_choice.rb b/app/models/item_choice.rb new file mode 100644 index 000000000..ccc35698e --- /dev/null +++ b/app/models/item_choice.rb @@ -0,0 +1,3 @@ +class ItemChoice < ApplicationRecord + belongs_to :item_bank +end diff --git a/app/models/laboratory.rb b/app/models/laboratory.rb index 2ba86ed90..dab2f6f39 100644 --- a/app/models/laboratory.rb +++ b/app/models/laboratory.rb @@ -38,12 +38,20 @@ class Laboratory < ApplicationRecord find_by_identifier(subdomain) end - def self.current=(laboratory) - Thread.current[:current_laboratory] = laboratory + # def self.current=(laboratory) + # Thread.current[:current_laboratory] = laboratory + # end + # + # def self.current + # Thread.current[:current_laboratory] ||= Laboratory.find(1) + # end + + def self.current=(user) + RequestStore.store[:current_laboratory] = user end def self.current - Thread.current[:current_laboratory] ||= Laboratory.find(1) + RequestStore.store[:current_laboratory] ||= User.anonymous end def shixuns diff --git a/app/models/laboratory_setting.rb b/app/models/laboratory_setting.rb index 4eacaf460..e53b54cd3 100644 --- a/app/models/laboratory_setting.rb +++ b/app/models/laboratory_setting.rb @@ -67,6 +67,7 @@ class LaboratorySetting < ApplicationRecord { 'name' => '在线竞赛', 'link' => '/competitions', 'hidden' => false }, { 'name' => '教学案例', 'link' => '/moop_cases', 'hidden' => false }, { 'name' => '交流问答', 'link' => '/forums', 'hidden' => false }, + { 'name' => '开发者社区', 'link' => '/problems', 'hidden' => false }, ], footer: nil } diff --git a/app/models/myshixun.rb b/app/models/myshixun.rb index 54dcf9011..1a89c755e 100644 --- a/app/models/myshixun.rb +++ b/app/models/myshixun.rb @@ -28,6 +28,11 @@ class Myshixun < ApplicationRecord "#{self.repo_name}.git" end + + def repo_save_path + self.repo_name.split('/').last + end + def is_complete? self.status == 1 end @@ -83,9 +88,15 @@ class Myshixun < ApplicationRecord self.games.select{|game| game.status == 2}.size 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 - self.games.select{|game| game.status == 2 && game.answer_open != 0}.size + answer_ids = user.grades.joins("join games on grades.container_id = games.id").where("container_type = 'Answer' and games.status=2 and games.end_time > grades.created_at").pluck(:container_id) + self.games.select{|game| game.status == 2 && game.answer_open != 0 && answer_ids.include?(game.id)}.size end # 通关时间 diff --git a/app/models/poll.rb b/app/models/poll.rb index 5c1a9a64c..365e46008 100644 --- a/app/models/poll.rb +++ b/app/models/poll.rb @@ -19,6 +19,7 @@ class Poll < ApplicationRecord scope :poll_by_ids, lambda { |ids| where(id: ids) unless ids.blank? } scope :poll_by_status, lambda { |s| where(polls_status: s) unless s.blank? } scope :poll_group_ended, -> {where("end_time is NOT NULL AND end_time <= ?",Time.now)} + scope :unified_setting, -> { where("unified_setting = ?",true) } scope :poll_search, lambda { |keywords| where("polls_name LIKE ?", "%#{keywords}%") unless keywords.blank?} @@ -103,7 +104,7 @@ class Poll < ApplicationRecord if course.is_end status = 4 else - if user.present? && user.student_of_course?(course) + if user.present? && user.course_identity(course) == Course::STUDENT ex_time = get_poll_times(user.id,false) pb_time = ex_time[:publish_time] ed_time = ex_time[:end_time] diff --git a/app/models/praise_tread.rb b/app/models/praise_tread.rb index 58ec965b4..8e96b7d47 100644 --- a/app/models/praise_tread.rb +++ b/app/models/praise_tread.rb @@ -12,7 +12,7 @@ class PraiseTread < ApplicationRecord case self.praise_tread_object_type when "Memo","Message","Issue" self.tidings << Tiding.new(:trigger_user_id => self.user_id, :user_id => self.praise_tread_object.author_id, :parent_container_id => self.praise_tread_object_id, :parent_container_type => self.praise_tread_object_type, :viewed => 0, :tiding_type => "Praise") - when "Discuss","Challenge","HomeworkCommon","JournalsForMessage","Journal","GraduationTopic","GraduationTask" + when "Discuss","Challenge","HomeworkCommon","JournalsForMessage","Journal","GraduationTopic","GraduationTask", "Hack" self.tidings << Tiding.new(:trigger_user_id => self.user_id, :user_id => self.praise_tread_object.user_id, :parent_container_id => self.praise_tread_object_id, :parent_container_type => self.praise_tread_object_type, :viewed => 0, :tiding_type => "Praise") end end diff --git a/app/models/searchable/shixun.rb b/app/models/searchable/shixun.rb index 359b8b4dc..e01920490 100644 --- a/app/models/searchable/shixun.rb +++ b/app/models/searchable/shixun.rb @@ -16,7 +16,9 @@ module Searchable::Shixun name: name, description: Util.extract_content(description)[0..Searchable::MAXIMUM_LENGTH], status: status, - myshixuns_count: myshixuns_count + myshixuns_count: myshixuns_count, + created_at: created_at, + publish_time: publish_time }.merge!(searchable_user_data) .merge!(searchable_challenge_data) end diff --git a/app/models/shixun.rb b/app/models/shixun.rb index 770dd81f7..d8a41ba6a 100644 --- a/app/models/shixun.rb +++ b/app/models/shixun.rb @@ -3,6 +3,7 @@ class Shixun < ApplicationRecord attr_accessor :page_no #管理员页面 实训配置更新状态时,需要接受page_no参数 # status: 0:编辑 1:申请发布 2:正式发布 3:关闭 -1:软删除 + # public: 0:未公开 1:申请公开 2:公开 # hide_code: 隐藏代码窗口 # code_hidden: 隐藏代码目录 # task_pass: 跳关 @@ -56,7 +57,7 @@ class Shixun < ApplicationRecord has_many :laboratory_shixuns, dependent: :destroy belongs_to :laboratory, optional: true # Jupyter数据集,附件 - has_many :jupyter_data_sets, ->{where(attachtype: 2)}, class_name: 'Attachment', as: :container, dependent: :destroy + 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 ? ", "%#{keyword}%", "%#{keyword}%") } @@ -79,8 +80,10 @@ class Shixun < ApplicationRecord scope :published_closed, lambda{ where(status: [2, 3]) } scope :none_closed, lambda{ where(status: [0, 1, 2]) } scope :unhidden, lambda{ where(hidden: 0, status: 2) } + scope :publiced, lambda{ where(public: 2) } scope :field_for_recommend, lambda{ select([:id, :name, :identifier, :myshixuns_count]) } scope :find_by_ids,lambda{|k| where(id:k)} + scope :no_jupyter, -> { where(is_jupyter: false) } after_create :send_tiding #同步到trustie @@ -101,6 +104,19 @@ class Shixun < ApplicationRecord shixun_info.try(:evaluate_script) end + def fork_reason + case shixun_info.try(:fork_reason) + when 'Shixun' + '实训内容升级' + when 'Course' + '课堂教学使用' + when 'Subject' + '实践课程使用' + else + shixun_info.try(:fork_reason) + end + end + def fork_identifier self.fork_from.nil? ? "--" : fork_shixuns.first&.identifier end @@ -283,7 +299,7 @@ class Shixun < ApplicationRecord end 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) end diff --git a/app/models/shixun_info.rb b/app/models/shixun_info.rb index e16f16537..7f7aa364e 100644 --- a/app/models/shixun_info.rb +++ b/app/models/shixun_info.rb @@ -1,8 +1,7 @@ class ShixunInfo < ApplicationRecord belongs_to :shixun validates_uniqueness_of :shixun_id - validates_presence_of :shixun_id, :description - + validates_length_of :fork_reason, maximum: 60 after_commit :create_diff_record private diff --git a/app/models/student_work.rb b/app/models/student_work.rb index d4f372823..4da23a30f 100644 --- a/app/models/student_work.rb +++ b/app/models/student_work.rb @@ -123,6 +123,26 @@ class StudentWork < ApplicationRecord 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 if work_status > 0 && homework_common && !self.ultimate_score diff --git a/app/models/teacher_course_group.rb b/app/models/teacher_course_group.rb index fbf9849ac..769026366 100644 --- a/app/models/teacher_course_group.rb +++ b/app/models/teacher_course_group.rb @@ -8,6 +8,8 @@ class TeacherCourseGroup < ApplicationRecord scope :find_teacher_group_ids, lambda { |ids| where(course_group_id: ids) unless ids.blank?} scope :get_user_groups,lambda {|ids| where(user_id:ids)} + validates_uniqueness_of :course_group_id, scope: :course_member_id + def course_members self.course_group.course_members end diff --git a/app/models/user.rb b/app/models/user.rb index eb3ece0a4..a9b2f0b3a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -540,12 +540,20 @@ class User < ApplicationRecord mail.present? end + # def self.current=(user) + # Thread.current[:current_user] = user + # end + # + # def self.current + # Thread.current[:current_user] ||= User.anonymous + # end + def self.current=(user) - Thread.current[:current_user] = user + RequestStore.store[:current_user] = user end def self.current - Thread.current[:current_user] ||= User.anonymous + RequestStore.store[:current_user] ||= User.anonymous end def self.anonymous diff --git a/app/queries/admins/school_query.rb b/app/queries/admins/school_query.rb index 888cded97..3206f0858 100644 --- a/app/queries/admins/school_query.rb +++ b/app/queries/admins/school_query.rb @@ -17,6 +17,7 @@ class Admins::SchoolQuery < ApplicationQuery if keyword schools = schools.where('schools.name LIKE ?', "%#{keyword}%") 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] end end \ No newline at end of file diff --git a/app/queries/admins/shixun_query.rb b/app/queries/admins/shixun_query.rb index 0d726f267..29e087332 100644 --- a/app/queries/admins/shixun_query.rb +++ b/app/queries/admins/shixun_query.rb @@ -13,15 +13,24 @@ class Admins::ShixunQuery < ApplicationQuery all_shixuns = Shixun.all status = case params[:status] - when "editing" then [0] - when "pending" then [1] - when "processed" then [2] - when "closed" then [3] - else - [0,1,2,3] + when "editing" then {status: 0} + when "processed" then {status: 2, public: 0} + when "pending" then {public: 1} + when "publiced" then {public: 2} + when "closed" then {status: 3} end - all_shixuns = all_shixuns.where(status: status) if status.present? + all_shixuns = all_shixuns.where(status) if status.present? + + if params[:fork_status].present? + all_shixuns = all_shixuns.where.not(fork_from: nil) + case params[:fork_status] + when 'Shixun', 'Course', 'Subject' + all_shixuns = all_shixuns.joins(:shixun_info).where(shixun_infos: {fork_reason: params[:fork_status]}) + when 'Other' + all_shixuns = all_shixuns.joins(:shixun_info).where("fork_reason is null or fork_reason not in ('Shixun', 'Course', 'Subject')") + end + end if params[:tag].present? all_shixuns = all_shixuns.joins(:mirror_repositories).where("mirror_repositories.id = ?",params[:tag].to_i) diff --git a/app/queries/admins/shixun_settings_query.rb b/app/queries/admins/shixun_settings_query.rb index 377e7bf60..1e45952bf 100644 --- a/app/queries/admins/shixun_settings_query.rb +++ b/app/queries/admins/shixun_settings_query.rb @@ -15,16 +15,15 @@ class Admins::ShixunSettingsQuery < ApplicationQuery all_shixuns = all_shixuns.where(id: params[:id]) if params[:id].present? status = - case params[:status] - when "editing" then [0] - when "pending" then [1] - when "processed" then [2] - when "closed" then [3] - else - [0,1,2,3] - end - - all_shixuns = all_shixuns.where(status: status) if status.present? + case params[:status] + when "editing" then {status: 0} + when "processed" then {status: 2, public: 0} + when "pending" then {public: 1} + when "publiced" then {public: 2} + when "closed" then {status: 3} + end + + all_shixuns = all_shixuns.where(status) if status.present? if params[:tag].present? all_shixuns = all_shixuns.joins(:mirror_repositories).where("mirror_repositories.id = ?",params[:tag].to_i) diff --git a/app/services/admins/identity_auths/agree_apply_service.rb b/app/services/admins/identity_auths/agree_apply_service.rb index d75a6d7db..4528debb4 100644 --- a/app/services/admins/identity_auths/agree_apply_service.rb +++ b/app/services/admins/identity_auths/agree_apply_service.rb @@ -10,7 +10,6 @@ class Admins::IdentityAuths::AgreeApplyService < ApplicationService ActiveRecord::Base.transaction do apply.update!(status: 1) user.update!(authentication: true) - RewardGradeService.call(user, container_id: user.id, container_type: 'Authentication', score: 500) deal_tiding! diff --git a/app/services/admins/professional_auths/agree_apply_service.rb b/app/services/admins/professional_auths/agree_apply_service.rb index 1ca2da2fc..3d723412b 100644 --- a/app/services/admins/professional_auths/agree_apply_service.rb +++ b/app/services/admins/professional_auths/agree_apply_service.rb @@ -10,7 +10,7 @@ class Admins::ProfessionalAuths::AgreeApplyService < ApplicationService ActiveRecord::Base.transaction do apply.update!(status: 1) user.update!(professional_certification: true) - + user.update!(is_shixun_marker: true) if user.is_teacher? RewardGradeService.call(user, container_id: user.id, container_type: 'Professional', score: 500) deal_tiding! diff --git a/app/services/admins/shixun_auths/agree_apply_service.rb b/app/services/admins/shixun_auths/agree_apply_service.rb index 4734e03bb..b8875cf09 100644 --- a/app/services/admins/shixun_auths/agree_apply_service.rb +++ b/app/services/admins/shixun_auths/agree_apply_service.rb @@ -10,7 +10,7 @@ class Admins::ShixunAuths::AgreeApplyService < ApplicationService def call ActiveRecord::Base.transaction do apply.update!(status: 1, dealer_id: user.id) - shixun.update!(status: 2, publish_time: Time.now) + shixun.update!(public: 2, publish_time: Time.now) # 奖励金币、经验 reward_grade_and_experience! diff --git a/app/services/admins/shixun_auths/refuse_apply_service.rb b/app/services/admins/shixun_auths/refuse_apply_service.rb index 49416a2b0..76d420e53 100644 --- a/app/services/admins/shixun_auths/refuse_apply_service.rb +++ b/app/services/admins/shixun_auths/refuse_apply_service.rb @@ -10,7 +10,7 @@ class Admins::ShixunAuths::RefuseApplyService < ApplicationService def call ActiveRecord::Base.transaction do - shixun.update!(status: 0) + shixun.update!(public: 0) apply.update!(status: 2, reason: reason, dealer_id: user.id) deal_tiding! diff --git a/app/services/admins/update_user_service.rb b/app/services/admins/update_user_service.rb index 41b5065d0..6b1c0c857 100644 --- a/app/services/admins/update_user_service.rb +++ b/app/services/admins/update_user_service.rb @@ -25,6 +25,7 @@ class Admins::UpdateUserService < ApplicationService ActiveRecord::Base.transaction do user.save! user.user_extension.save! + user.update!(is_shixun_marker: true) if user.is_certification_teacher update_gitlab_password if params[:password].present? end @@ -36,7 +37,7 @@ class Admins::UpdateUserService < ApplicationService def user_attributes params.slice(*%i[lastname nickname mail phone admin business is_test - professional_certification authentication]) + professional_certification authentication is_shixun_marker]) end def user_extension_attributes diff --git a/app/services/concerns/elasticsearch_able.rb b/app/services/concerns/elasticsearch_able.rb index 015aac29b..6caf37f8f 100644 --- a/app/services/concerns/elasticsearch_able.rb +++ b/app/services/concerns/elasticsearch_able.rb @@ -9,7 +9,7 @@ module ElasticsearchAble highlight: highlight_options, body_options: body_options, page: page, - per_page: per_page + per_page: 20 } end @@ -37,7 +37,7 @@ module ElasticsearchAble def per_page per_page = params[:per_page].to_s.strip.presence || params[:limit].to_s.strip.presence - per_page.to_i <= 0 ? 20 : per_page.to_i + per_page.to_i <= 0 || per_page.to_i > 20 ? 20 : per_page.to_i end def page diff --git a/app/services/git_service.rb b/app/services/git_service.rb index 076f62920..7867d063e 100644 --- a/app/services/git_service.rb +++ b/app/services/git_service.rb @@ -6,7 +6,7 @@ class GitService class << self - ['add_repository', 'fork_repository', 'delete_repository', 'file_tree', 'update_file', 'file_content', 'commits'].each do |method| + ['add_repository', 'fork_repository', 'delete_repository', 'file_tree', 'update_file', 'file_content', 'commits', 'add_tree', 'delete_file'].each do |method| define_method method do |params| post(method, params) end @@ -45,4 +45,4 @@ class GitService end end -end \ No newline at end of file +end diff --git a/app/services/homeworks_service.rb b/app/services/homeworks_service.rb index 0dc814c89..c70535e17 100644 --- a/app/services/homeworks_service.rb +++ b/app/services/homeworks_service.rb @@ -305,13 +305,20 @@ class HomeworksService myshixun_endtime = games.select{|game| game.status == 2}.size == games.size ? games.map(&:end_time).max : nil - if work.work_status == 0 - is_complete = myshixun_endtime && (myshixun_endtime < setting_time.end_time) - if is_complete || (myshixun.created_at < setting_time.end_time && (!homework.allow_late || setting_time.end_time >= Time.now)) - work.work_status = 1 - elsif homework.allow_late && myshixun.created_at < homework.late_time - work.work_status = 2 - end + is_complete = myshixun_endtime && (myshixun_endtime < setting_time.end_time) + + # if work.work_status == 0 + # if is_complete || (myshixun.created_at < setting_time.end_time && (!homework.allow_late || setting_time.end_time >= Time.now)) + # work.work_status = 1 + # elsif homework.allow_late && myshixun.created_at < homework.late_time + # work.work_status = 2 + # end + # end + + if !homework.allow_late || is_complete + work.work_status = 1 + elsif myshixun.created_at < homework.late_time + work.work_status = 2 end if work.work_status != 0 @@ -322,11 +329,16 @@ class HomeworksService work.efficiency = format("%.2f", efficiency) 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 + else + work.compelete_status = 1 # 未通关 end + else + work.compelete_status = 1 # 未通关 end work.late_penalty = work.work_status == 2 ? homework.late_penalty : 0 @@ -346,7 +358,7 @@ class HomeworksService work.work_score = format("%.2f",(score < 0 ? 0 : score).to_f) unless work.ultimate_score #logger.info("#############work_score: #{score}") work.calculation_time = Time.now - work.save! + work.save(validate: false) end end end \ No newline at end of file diff --git a/app/services/jupyter_service.rb b/app/services/jupyter_service.rb new file mode 100644 index 000000000..bbe0330bb --- /dev/null +++ b/app/services/jupyter_service.rb @@ -0,0 +1,246 @@ +#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? + gitUrl = "#{edu_setting('git_address_domain')}/#{shixun.repo_path}" + params = {tpiID: tpiID, identifier: shixun.identifier, needMount: mount, gitUrl: gitUrl, + :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? + + gitUrl = "#{edu_setting('git_address_domain')}/#{myshixun.repo_path}" + params = { tpiID: tpiID, + identifier: shixun.identifier, + myshixunIdentifier: myshixun.identifier, + gitUrl: gitUrl, + 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 + + def _jupyter_active(tpiID) + shixun_tomcat = edu_setting('cloud_bridge') + uri = "#{shixun_tomcat}/bridge/jupyter/active" + params = {:tpiID => tpiID} + res = uri_post uri, params + if res && res['code'].to_i != 0 + raise("实训云平台繁忙(繁忙等级:120)") + end + end + + # tpm 延时 + def jupyter_active_tpm(shixun) + tpiID = "tpm#{shixun.id}" + _jupyter_active(tpiID) + end + + # tpi 延时 + def jupyter_active_tpi(myshixun) + tpiID = myshixun.id + _jupyter_active(tpiID) + end + + def _jupyter_timeinfo(tpiID) + shixun_tomcat = edu_setting('cloud_bridge') + uri = "#{shixun_tomcat}/bridge/jupyter/getTimeInfo" + params = {:tpiID => tpiID} + res = uri_post uri, params + if res && res['code'].to_i != 0 + raise("实训云平台繁忙(繁忙等级:130)") + end + + res['data'] + end + + # 获取时间参数 + def jupyter_timeinfo_tpm(shixun) + tpiID = "tpm#{shixun.id}" + _jupyter_timeinfo(tpiID) + end + + # 获取时间参数 + def jupyter_timeinfo_tpi(myshixun) + tpiID = myshixun.id + _jupyter_timeinfo(tpiID) + end +end diff --git a/app/services/private_messages/create_service.rb b/app/services/private_messages/create_service.rb index 88f3a084f..89365c4a7 100644 --- a/app/services/private_messages/create_service.rb +++ b/app/services/private_messages/create_service.rb @@ -30,6 +30,6 @@ class PrivateMessages::CreateService < ApplicationService def validate! raise Error, '内容不能为空' if content.blank? - raise Error, '内容太长' if content.size > 255 + raise Error, '内容太长' if content.size > 500 end end \ No newline at end of file diff --git a/app/services/search_service.rb b/app/services/search_service.rb index 5eb11f398..a45875e07 100644 --- a/app/services/search_service.rb +++ b/app/services/search_service.rb @@ -30,7 +30,6 @@ class SearchService < ApplicationService model_options = { includes: modal_name.searchable_includes } - model_options.deep_merge!(where: { status: 2 }) if modal_name == Shixun model_options.deep_merge!(extra_options) model_options.deep_merge!(default_options) @@ -40,7 +39,7 @@ class SearchService < ApplicationService def extra_options case params[:type].to_s.strip when 'shixun' then - { where: { id: Laboratory.current.shixuns.pluck(:id) } } + { where: { id: Laboratory.current.shixuns.where(public: 2, status: 2, fork_from: nil).or(Laboratory.current.shixuns.where(status: 2, id: User.current.shixuns)).pluck(:id) } } when 'subject' then { where: { id: Laboratory.current.subjects.pluck(:id) } } when 'course' then diff --git a/app/services/shixun_search_service.rb b/app/services/shixun_search_service.rb index 580208dfe..32488a7c3 100644 --- a/app/services/shixun_search_service.rb +++ b/app/services/shixun_search_service.rb @@ -25,7 +25,7 @@ class ShixunSearchService < ApplicationService else none_shixun_ids = ShixunSchool.where("school_id != #{User.current.school_id}").pluck(:shixun_id) - @shixuns = @shixuns.where.not(id: none_shixun_ids).where(hidden: 0) + @shixuns = @shixuns.where.not(id: none_shixun_ids).where(hidden: 0, status: 2, public: 2).or(@shixuns.where(id: User.current.shixuns)) end end @@ -33,11 +33,16 @@ class ShixunSearchService < ApplicationService @shixuns = status == "published" ? @shixuns.where(status: 2) : @shixuns.where(status: [0, 1]) end + if params[:no_jupyter] + @shixuns = @shixuns.where(is_jupyter: 0) + end + ## 筛选 难度 if params[:diff].present? && params[:diff].to_i != 0 @shixuns = @shixuns.where(trainee: params[:diff]) end + Rails.logger.info("search_shixun_ids: #{@shixuns.pluck(:id)}") Shixun.search(keyword, search_options) end @@ -48,12 +53,16 @@ class ShixunSearchService < ApplicationService includes: [ :shixun_info, :challenges, :subjects, user: { user_extension: :school } ] } model_options.merge!(where: { id: @shixuns.pluck(:id) }) - model_options.merge!(order: {"myshixuns_count" => sort_str}) + model_options.merge!(order: {sort_str => order_str}) model_options.merge!(default_options) model_options end - def sort_str + def order_str params[:order] || "desc" end + + def sort_str + params[:sort] || "myshixuns_count" + end end \ No newline at end of file diff --git a/app/services/shixuns/create_shixun_service.rb b/app/services/shixuns/create_shixun_service.rb index aa9968f5b..c85455901 100644 --- a/app/services/shixuns/create_shixun_service.rb +++ b/app/services/shixuns/create_shixun_service.rb @@ -14,34 +14,45 @@ class CreateShixunService < ApplicationService shixun.user_id = user.id main_mirror = MirrorRepository.find params[:main_type] sub_mirrors = MirrorRepository.where(id: params[:sub_type]) - 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) + 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 - return shixun + rescue => e + Rails.logger.error("shixun_create_error: #{e.message}") + raise("创建实训失败!") end end diff --git a/app/services/subjects/copy_subject_service.rb b/app/services/subjects/copy_subject_service.rb index 94157dc7b..4715a8bad 100644 --- a/app/services/subjects/copy_subject_service.rb +++ b/app/services/subjects/copy_subject_service.rb @@ -60,7 +60,7 @@ class Subjects::CopySubjectService < ApplicationService shixun = stage_shixun.shixun to_shixun = Shixun.new 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.user_id = user.id if laboratory @@ -79,7 +79,7 @@ class Subjects::CopySubjectService < ApplicationService copy_shixun_service_configs_data!(shixun, to_shixun) copy_challenges_data!(shixun, to_shixun) copy_shixun_members_data!(to_shixun) - + copy_jupyter_data_sets(shixun, to_shixun) if shixun.is_jupyter? # 云上实验室 if laboratory laboratory.laboratory_shixuns.create(shixun: to_shixun) @@ -87,6 +87,25 @@ class Subjects::CopySubjectService < ApplicationService to_shixun end + # 复制jupyter的数据集 + def copy_jupyter_data_sets(shixun, to_shixun) + return unless shixun.is_jupyter? + folder = EduSetting.get('shixun_folder') + raise "存储目录未定义" unless folder.present? + path = "#{folder}/#{to_shixun.identifier}" + FileUtils.mkdir_p(path, :mode => 0777) unless File.directory?(path) + # 复制数据集 + save_path = File.join(folder, shixun.identifier) + shixun.data_sets.each do |set| + new_date_set = Attachment.new + new_date_set.attributes = set.attributes.dup.except("id", "container_id", "disk_directory") + new_date_set.container_id = to_shixun.id + new_date_set.disk_directory = to_shixun.identifier + new_date_set.save! + FileUtils.cp("#{save_path}/#{set.relative_path_filename}", path) + end + end + # 创建实训长字段内容 def copy_shixun_info_data!(shixun, to_shixun) to_shixun_info = ShixunInfo.new diff --git a/app/services/users/shixun_service.rb b/app/services/users/shixun_service.rb index ef399ce8c..b13b0ab1f 100644 --- a/app/services/users/shixun_service.rb +++ b/app/services/users/shixun_service.rb @@ -44,7 +44,7 @@ class Users::ShixunService def user_policy_filter(relations) # 只有自己或者管理员才有过滤筛选及查看全部状态下实训功能 if self_or_admin? - relations = relations.where.not(status: -1) + relations = relations.where.not(status: -1).where(hidden: false) status_filter(relations) else relations.where(status: [2, 3], hidden: false) @@ -65,13 +65,18 @@ class Users::ShixunService end def manage_shixun_status_filter(relations) - status = case params[:status] - when 'editing' then 0 - when 'applying' then 1 - when 'published' then 2 - when 'closed' then 3 - end - relations = relations.where(status: status) if status + if params[:status] == "publiced" + relations = relations.where(public: 2) + elsif params[:status] == "applying" + relations = relations.where(public: 1) + else + status = case params[:status] + when 'editing' then 0 + when 'published' then 2 + when 'closed' then 3 + end + relations = relations.where(status: status) if status + end relations end diff --git a/app/services/users/subject_service.rb b/app/services/users/subject_service.rb index 8a4fdce3b..53ff3f4b9 100644 --- a/app/services/users/subject_service.rb +++ b/app/services/users/subject_service.rb @@ -35,7 +35,7 @@ class Users::SubjectService def user_policy_filter(relations) # 只有自己或者管理员才有过滤筛选及查看全部状态下实训功能 if self_or_admin? - status_filter(relations) + status_filter(relations.unhidden) else relations.where(status: 2, hidden: false) end diff --git a/app/templates/shared/main.css b/app/templates/shared/main.css index 09d295421..704246b74 100644 --- a/app/templates/shared/main.css +++ b/app/templates/shared/main.css @@ -557,7 +557,6 @@ a.user_orangebg_btn{background-color:#FF6800;color: #fff;} a.user_greybg_btn{background-color:#747A7F;color: #fff;} /*.user_white_btn{border: 1px solid #ffffff;color: #ffffff!important;}*/ - .pointer{cursor: pointer} .cdefault{cursor: default} diff --git a/app/views/admins/myshixuns/shared/_list.html.erb b/app/views/admins/myshixuns/shared/_list.html.erb index a80a4ef23..af43c3c22 100644 --- a/app/views/admins/myshixuns/shared/_list.html.erb +++ b/app/views/admins/myshixuns/shared/_list.html.erb @@ -21,9 +21,17 @@ <%= myshixun.id %> <%= myshixun.identifier %> - <% current_task = myshixun.last_executable_task || myshixun.last_task %> - <%= link_to "/tasks/#{current_task.identifier}", target: '_blank' do %> - <%= overflow_hidden_span myshixun.shixun.name, width: 280 %> + <% if myshixun.shixun.is_jupyter? %> + <%= link_to "/tasks/#{myshixun.identifier}/jupyter", target: '_blank' do %> + <%= overflow_hidden_span myshixun.shixun.name, width: 280 %> + <% end %> + <% else %> + <% current_task = myshixun.last_executable_task || myshixun.last_task %> + <% if current_task %> + <%= link_to "/tasks/#{current_task.identifier}", target: '_blank' do %> + <%= overflow_hidden_span myshixun.shixun.name, width: 280 %> + <% end %> + <% end %> <% end %> <%= myshixun.shixun.user.real_name %> diff --git a/app/views/admins/schools/shared/_list.html.erb b/app/views/admins/schools/shared/_list.html.erb index ff0b17992..dd0a054e3 100644 --- a/app/views/admins/schools/shared/_list.html.erb +++ b/app/views/admins/schools/shared/_list.html.erb @@ -33,7 +33,7 @@ <%= school.province %> <%= school.city %> <%= school.address %> - <%= school.user_extensions.count %> + <%= school.users_count %> <%= @department_count.fetch(school.id, 0) %> <%= school.created_at&.strftime('%Y-%m-%d %H:%M') %> diff --git a/app/views/admins/shared/_sidebar.html.erb b/app/views/admins/shared/_sidebar.html.erb index 4b84068e7..09c115b06 100644 --- a/app/views/admins/shared/_sidebar.html.erb +++ b/app/views/admins/shared/_sidebar.html.erb @@ -2,7 +2,7 @@