You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
educoder/app/models/shixun.rb

334 lines
10 KiB

6 years ago
class Shixun < ApplicationRecord
include Searchable::Shixun
attr_accessor :page_no #管理员页面 实训配置更新状态时需要接受page_no参数
6 years ago
# status: 0编辑 1申请发布 2正式发布 3关闭 -1软删除
# public: 0未公开 1申请公开 2公开
# hide_code 隐藏代码窗口
# code_hidden: 隐藏代码目录
# task_pass: 跳关
5 years ago
# webssh 0不开启webssh1开启练习模式; 2开启评测模式
# trainee 实训的难度
# vnc: VCN实训是否用于评测
5 years ago
validates_presence_of :name, message: "实训名称不能为空"
6 years ago
has_many :challenges, -> {order("challenges.position asc")}, dependent: :destroy
has_many :challenge_tags, through: :challenges
6 years ago
has_many :myshixuns, :dependent => :destroy
has_many :shixun_members, dependent: :destroy
has_many :users, through: :shixun_members
has_many :discusses, as: :dis, dependent: :destroy
has_many :evaluate_records, dependent: :destroy
has_many :shixun_mirror_repositories
has_many :mirror_repositories, through: :shixun_mirror_repositories
has_many :shixun_schools, :dependent => :destroy
has_many :schools, :through => :shixun_schools
has_many :shixun_tag_repertoires, dependent: :destroy
has_many :tag_repertoires, through: :shixun_tag_repertoires
has_one :first_shixun_tag_repertoire, class_name: 'ShixunTagRepertoire'
has_one :first_tag_repertoire, through: :first_shixun_tag_repertoire, source: :tag_repertoire
5 years ago
has_many :homework_commons_shixuns, class_name: 'HomeworkCommonsShixun'
5 years ago
has_many :homework_commons, through: :homework_commons_shixuns
5 years ago
has_many :fork_shixuns, foreign_key: "fork_from", class_name: 'Shixun'
6 years ago
#实训的关卡
has_many :exercise_shixun_challenges, :dependent => :destroy
has_many :exercise_bank_shixun_challenges, :dependent => :destroy
# 注意:这个地方是一张关联表,关联三张表(多对多关系)
has_many :stage_shixuns, dependent: :destroy
has_many :stages, through: :stage_shixuns
has_many :subjects, through: :stage_shixuns
has_one :shixun_info, dependent: :destroy
5 years ago
# 第二版本库
has_one :shixun_secret_repository, dependent: :destroy
6 years ago
belongs_to :user
# 实训服务配置
has_many :shixun_service_configs, :dependent => :destroy
6 years ago
has_many :tidings, as: :container, dependent: :destroy
# 实训审核记录
5 years ago
has_many :shixun_reviews, -> {order("shixun_reviews.created_at desc")}, :dependent => :destroy
6 years ago
has_many :laboratory_shixuns, dependent: :destroy
belongs_to :laboratory, optional: true
5 years ago
# Jupyter数据集,附件
5 years ago
has_many :data_sets, ->{where(attachtype: 2)}, class_name: 'Attachment', as: :container, dependent: :destroy
5 years ago
# 试卷的实训题
has_many :exercise_questions
6 years ago
scope :search_by_name, ->(keyword) { where("name like ? or description like ? ",
"%#{keyword}%", "%#{keyword}%") }
#scope :include_user, ->(user_id) { where(id: Myshixun.where(user_id: user_id).pluck(:shixun_id))}
scope :filter_tag, ->(tag_level, tag_id) {
case tag_level
when 1 #大类
where(id: Repertoire.find(tag_id).tag_repertoires.joins(:shixun_tag_repertoires).pluck("shixun_tag_repertoires.shixun_id"))
when 2 #子类
where(id: SubRepertoire.find(tag_id).tag_repertoires.joins(:shixun_tag_repertoires).pluck("shixun_tag_repertoires.shixun_id"))
when 3 #tag
where(id: TagRepertoire.find(tag_id).shixun_tag_repertoires.pluck(:shixun_id))
end
}
scope :visible, -> { where.not(status: -1) }
6 years ago
scope :published, lambda{ where(status: 2) }
scope :published_closed, lambda{ where(status: [2, 3]) }
scope :none_closed, lambda{ where(status: [0, 1, 2]) }
6 years ago
scope :unhidden, lambda{ where(hidden: 0, status: 2) }
scope :publiced, lambda{ where(public: 2) }
6 years ago
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) }
6 years ago
after_create :send_tiding
#同步到trustie
after_create do
SyncTrustieJob.perform_later("practical_training_project", 1) if allow_sync_to_trustie?
end
6 years ago
# REDO: 
def propaedeutics
shixun_info.try(:propaedeutics)
end
def description
shixun_info.try(:description)
end
def evaluate_script
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
5 years ago
def fork_identifier
5 years ago
self.fork_from.nil? ? "--" : fork_shixuns.first&.identifier
5 years ago
end
def shixun_status
status = ""
case self.status
when 0
status = "编辑中"
when 1
status = "审核中"
when 2
status = "已发布"
when 3
status = "已关闭"
end
status
end
5 years ago
def is_tag_used?(id)
tag_repertoires.map(&:id).include?(id)
end
6 years ago
# 实训用户tag
def user_tags_name(user = User.current)
6 years ago
Shixun.joins(challenges: [:challenge_tags, :games]).where(games: {status: 2, user_id: user.id}, shixuns: {id:id})
.pluck("challenge_tags.name").uniq
6 years ago
end
# 实训关卡tag
def challenge_tags_name
ChallengeTag.where(challenge_id: challenges.pluck(:id)).pluck(:name).uniq
end
def repo_path
"#{repo_name}.git"
end
# 实训对应的镜像主类别名(已选)
def main_mirror_name
mirror_repositories.published_main_mirror.first.try(:type_name) || ""
end
def main_mirror_id
mirror_repositories.published_main_mirror.first.try(:id) || -1
end
# 实训对应的镜像小类别名(已选)
def small_mirror_name
names = mirror_repositories.small_mirror.map(&:type_name)
names.blank? ? [] : names
6 years ago
end
def small_mirror_id
mirror_repositories.published_small_mirror.map(&:id)
end
# 实训镜像名
def mirror_name
names = mirror_repositories.map(&:type_name)
names.blank? ? '' : names
end
def script_tag
return unless mirror_script_id
MirrorScript.find_by_id(mirror_script_id)
end
def standrad_script
mirrors_id = mirror_repositories.map(&:id)
mirror_scripts = MirrorScript.where(mirror_repository_id: mirrors_id)
mirror_scripts.map { |ms| { scptname: ms.script_type, id: ms.id } }
end
def owner
5 years ago
User.find_by_id(self.user_id)
6 years ago
end
5 years ago
def shixun_main_name
self.mirror_repositories.published_main_mirror.first.try(:type_name)
end
6 years ago
def is_published?
status > 1
end
# 当前用户开启的实训
5 years ago
def current_myshixun(user)
return nil unless user.logged?
myshixuns.find_by(user_id: user.id)
6 years ago
end
# 实训技术平台
def show_shixun_mirror
mirror_repositories.map(&:type_name).join(';')
end
# 实训评分 cnt-评分次数 sum-总评分
def shixun_preference
game_star_info = Game.find_by_sql("select g.star from
(games g left join (myshixuns m join shixuns s on s.id = m.shixun_id) on m.id = g.myshixun_id)
where g.star != 0 and s.id = #{self.id}")
if game_star_info.present?
cnt = game_star_info.count
sum = game_star_info.sum(&:star).to_f
(sum / cnt.to_f).round(1)
else
5.0
end
end
# 实训评分信息
# return [实训评分, 5星评分比例 4星评分比例 3星评分比例 2星评分比例 1星评分比例]
def shixun_preference_info
game_star_info = Game.joins(challenge: :shixun).where(shixuns: {id: id}).where.not(games: {star: 0}).pluck(:star)
6 years ago
star_info = []
if game_star_info.present?
5.downto(1) do |i|
star_info << ((game_star_info.select{|s| s == i}.count / game_star_info.count.to_f) * 100).round
6 years ago
end
sum = star_info.sum
max = star_info.max
# 四舍五入引起5星比例超过100% 将最大的比例的评分做出调整
if sum > 100
star_info = star_info.map{|s| s == max ? s - 1 : s}
elsif sum < 100
star_info = star_info.map{|s| s == max ? s + 1 : s}
end
cnt = game_star_info.count
sum = game_star_info.sum
6 years ago
star_info.unshift((sum / cnt.to_f).round(1))
else
star_info = [5.0, 100, 0, 0, 0, 0]
end
star_info
end
# 实训关卡的总分(由于大部分是实践题,因此没关联查choose表)
# 提前加载问题由于选择题比较少所以几乎不会触发选择题的查询所以没必要提前载入choose_score
def all_score
5 years ago
self.challenges.sum(:score)
6 years ago
end
### fork 数量
def fork_count
self.class.where(fork_from: id).count
end
# 学员等级
def shixun_trainee
case trainee
when 1 then '初级学员'
when 2 then '中级学员'
when 3 then '中高级学员'
when 4 then '高级学员'
6 years ago
else ''
end
end
def shixun_level
case trainee
when 1 then '初级'
when 2 then '中级'
when 3 then '中高级'
when 4 then '高级'
6 years ago
else ''
end
end
# 纯选择提类型
def is_choice_type?
challenges_count == challenges.where(st: 1).count
end
# 实训受用学校个数
def school_count
UserExtension.find_by_sql("select count(distinct ue.school_id) school_count from user_extensions ue right join myshixuns
on ue.user_id = myshixuns.user_id where myshixuns.shixun_id = #{self.id}").first.try(:school_count).to_i
end
def has_manager?(user)
return true if user.admin? || user.business?
6 years ago
shixun_members.where(role: [1, 2]).exists?(user_id: user.id)
end
def finished_challenges_count(user)
Game.joins(:myshixun).where(user_id: user.id, status: 2, myshixuns: { shixun_id: id }).count
end
def has_web_route?
6 years ago
self.mirror_name.include?('JavaWeb') || self.mirror_name.include?('PHP') && self.mirror_name.include?('Mysql') || self.mirror_name.include?('Web')
end
# 所属实践课程
def relation_path
5 years ago
subjects.visible.unhidden.uniq
end
private
def send_tiding
6 years ago
self.tidings << Tiding.new(:user_id => user_id, :trigger_user_id => 1, :belong_container_id => id, :belong_container_type =>'Shixun', :tiding_type => "System", :viewed => 0)
end
6 years ago
end