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

327 lines
10 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

class Shixun < ApplicationRecord
include Searchable::Shixun
attr_accessor :page_no #管理员页面 实训配置更新状态时需要接受page_no参数
# status: 0编辑 1申请发布 2正式发布 3关闭 -1软删除
# public: 0未公开 1申请公开 2公开
# hide_code 隐藏代码窗口
# code_hidden: 隐藏代码目录
# task_pass: 跳关
# webssh 0不开启webssh1开启练习模式; 2开启评测模式
# trainee 实训的难度
# vnc: VCN实训是否用于评测
validates_presence_of :name, message: "实训名称不能为空"
has_many :challenges, -> {order("challenges.position asc")}, dependent: :destroy
has_many :challenge_tags, through: :challenges
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
has_many :homework_commons_shixuns, class_name: 'HomeworkCommonsShixun'
has_many :fork_shixuns, foreign_key: "fork_from", class_name: 'Shixun'
#实训的关卡
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
# 第二版本库
has_one :shixun_secret_repository, dependent: :destroy
belongs_to :user
# 实训服务配置
has_many :shixun_service_configs, :dependent => :destroy
has_many :tidings, as: :container, dependent: :destroy
# 实训审核记录
has_many :shixun_reviews, -> {order("shixun_reviews.created_at desc")}, :dependent => :destroy
has_many :laboratory_shixuns, dependent: :destroy
belongs_to :laboratory, optional: true
# Jupyter数据集,附件
has_many :data_sets, ->{where(attachtype: 2)}, class_name: 'Attachment', as: :container, dependent: :destroy
scope :search_by_name, ->(keyword) { where("name like ? or description like ? ",
"%#{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) }
scope :published, lambda{ where(status: 2) }
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
after_create do
SyncTrustieJob.perform_later("practical_training_project", 1) if allow_sync_to_trustie?
end
# 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
def fork_identifier
self.fork_from.nil? ? "--" : fork_shixuns.first&.identifier
end
def shixun_status
status = ""
case self.status
when 0
status = "编辑中"
when 1
status = "审核中"
when 2
status = "已发布"
when 3
status = "已关闭"
end
status
end
def is_tag_used?(id)
tag_repertoires.map(&:id).include?(id)
end
# 实训用户tag
def user_tags_name(user = User.current)
Shixun.joins(challenges: [:challenge_tags, :games]).where(games: {status: 2, user_id: user.id}, shixuns: {id:id})
.pluck("challenge_tags.name").uniq
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
mirror_repositories.published_small_mirror.map(&:type_name)
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
User.find_by_id(self.user_id)
end
def shixun_main_name
self.mirror_repositories.published_main_mirror.first.try(:type_name)
end
def is_published?
status > 1
end
# 当前用户开启的实训
def current_myshixun(user_id)
myshixuns.find_by(user_id: user_id)
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)
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
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
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
self.challenges.pluck(:score).sum
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 '顶级学员'
else ''
end
end
def shixun_level
case trainee
when 1 then '初级'
when 2 then '中级'
when 3 then '高级'
when 4 then '顶级'
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?
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?
self.mirror_name.include?('JavaWeb') || self.mirror_name.include?('PHP') && self.mirror_name.include?('Mysql') || self.mirror_name.include?('Web')
end
# 所属实践课程
def relation_path
subjects.visible.unhidden.uniq
end
private
def send_tiding
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
end