socialforge/app/models/course.rb

312 lines
10 KiB
Ruby
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

class Course < ActiveRecord::Base
include Redmine::SafeAttributes
STATUS_ACTIVE = 1
STATUS_CLOSED = 5
STATUS_ARCHIVED = 9
attr_accessible :code, :extra, :name, :state, :tea_id, :time , :location, :state, :term, :password,:is_public,:description,:class_period
belongs_to :project, :class_name => 'Course', :foreign_key => :extra, primary_key: :identifier
belongs_to :teacher, :class_name => 'User', :foreign_key => :tea_id # 定义一个方法teacher该方法通过tea_id来调用User表
belongs_to :school, :class_name => 'School', :foreign_key => :school_id #定义一个方法school该方法通过school_id来调用School表
has_many :bid
has_many :members, :include => [:principal, :roles], :conditions => "#{Principal.table_name}.type='User' AND #{Principal.table_name}.status=#{Principal::STATUS_ACTIVE}"
has_many :memberships, :class_name => 'Member'
has_many :member_principals, :class_name => 'Member',
:include => :principal,
:conditions => "#{Principal.table_name}.type='Group' OR (#{Principal.table_name}.type='User' AND #{Principal.table_name}.status=#{Principal::STATUS_ACTIVE})"
has_many :principals, :through => :member_principals, :source => :principal
has_many :users, :through => :members
has_many :homeworks, :through => :homework_for_courses, :source => :bid, :dependent => :destroy
has_many :journals_for_messages, :as => :jour, :dependent => :destroy
has_many :homework_for_courses, :dependent => :destroy
has_many :student, :class_name => 'StudentsForCourse', :source => :user
has_many :course_infos, :class_name => 'CourseInfos',:dependent => :destroy
has_many :enabled_modules, :dependent => :delete_all
has_many :boards, :dependent => :destroy, :order => "position ASC"
#has_many :course_journals_for_messages, :class_name => 'CourseJournalsForMessage', :as => :jour, :dependent => :destroy
has_many :news, :dependent => :destroy, :include => :author
has_one :course_status, :class_name => "CourseStatus", :dependent => :destroy
acts_as_taggable
acts_as_nested_set :order => 'name', :dependent => :destroy
acts_as_attachable :view_permission => :view_files,
:delete_permission => :manage_files
validates_presence_of :password, :term,:name ,:class_period
validates_format_of :class_period, :with =>/^\d*$/
#validates_format_of :name,:with =>/^[a-zA-Z0-9_\u4e00-\u9fa5]+$/
before_save :self_validate
after_create :create_board_sync
before_destroy :delete_all_members
safe_attributes 'extra',
'time',
'name',
'extra',
'code',
'location',
'tea_id',
'password',
'term',
'is_public',
'description',
'class_period'
acts_as_customizable
scope :all_course
scope :active, lambda { where(:status => STATUS_ACTIVE) }
scope :status, lambda {|arg| where(arg.blank? ? nil : {:status => arg.to_i}) }
scope :all_public, lambda { where(:is_public => true) }
scope :visible, lambda {|*args| where(Course.visible_condition(args.shift || User.current, *args)) }
scope :allowed_to, lambda {|*args|
user = User.current
permission = nil
if args.first.is_a?(Symbol)
permission = args.shift
else
user = args.shift
permission = args.shift
end
where(Course.allowed_to_condition(user, permission, *args))
}
scope :like, lambda {|arg|
if arg.blank?
where(nil)
else
pattern = "%#{arg.to_s.strip.downcase}%"
where(" LOWER(name) LIKE :p ", :p => pattern)
end
}
def visible?(user=User.current)
user.allowed_to?(:view_course, self)
end
def parent_id_changed?
false
end
# Returns the mail adresses of users that should be always notified on project events
def recipients
notified_users.collect {|user| user.mail}
end
# Returns the users that should be notified on project events
def notified_users
# TODO: User part should be extracted to User#notify_about?
members.select {|m| m.principal.present? && (m.mail_notification? || m.principal.mail_notification == 'all')}.collect {|m| m.principal}
end
# 课程的短描述信息
def short_description(length = 255)
description.gsub(/<\/?.*?>/,"").html_safe if description
#description.gsub(/^(.{#{length}}[^\n\r]*).*$/m, '\1...').strip if description
end
# 课程的短名称信息
def short_name(length = 8)
name.gsub(/<\/?.*?>/,"").html_safe if name
end
def strip_html(html)
return html if html.empty? || !html.include?('<')
output = ""
tokenizer = HTML::Tokenizer.new(html)
while token = tokenizer.next
node = HTML::Node.parse(nil, 0, 0, token, false)
output += token unless (node.kind_of? HTML::Tag) or (token =~ /^<!/)
end
return output
end
def extra_frozen?
errors[:extra].blank? && !(new_record? || extra.blank?)
end
def archived?
self.status == STATUS_ARCHIVED
end
def self.visible_condition(user, options={})
allowed_to_condition(user, :view_course, options)
end
# 获取课程的资源类型列表
def attachmenttypes
@attachmenttypes = Attachmentstype.find(:all, :conditions => ["#{Attachmentstype.table_name}.typeId= ?",self.attachmenttype ])
end
# 获取资源后缀名列表
def contenttypes
attachmenttypes
if @attachmenttypes.length >0
@attachmenttypes.last().suffixArr
end
end
def active?
self.status == STATUS_ACTIVE
end
#课程权限判断
def allows_to?(action)
if archived?
# No action allowed on archived projects
return false
end
unless active? || Redmine::AccessControl.read_action?(action)
# No write action allowed on closed projects
return false
end
# No action allowed on disabled modules
if action.is_a? Hash
allowed_actions.include? "#{action[:controller]}/#{action[:action]}"
else
allowed_permissions.include? action
end
end
# 课程允许的权限集合
def allowed_permissions
@allowed_permissions ||= begin
module_names = enabled_modules.all(:select => :name).collect {|m| m.name}
Redmine::AccessControl.modules_permissions(module_names).collect {|p| p.name}
end
end
# 课程允许的动作集合
def allowed_actions
@actions_allowed ||= allowed_permissions.inject([]) { |actions, permission| actions += Redmine::AccessControl.allowed_actions(permission) }.flatten
end
# 返回用户组可以访问的课程
def users_by_role
members.includes(:user, :roles).all.inject({}) do |h, m|
m.roles.each do |r|
h[r] ||= []
h[r] << m.user
end
h
end
end
#自定义验证
def self_validate
end
# 创建课程讨论区
def create_board_sync
@board = self.boards.build
self.name=" #{l(:label_borad_course) }"
@board.name = self.name
@board.description = self.name.to_s
@board.project_id = -1
if @board.save
logger.debug "[Course Model] ===> #{@board.to_json}"
else
logger.error "[Course Model] ===> Auto create board when course saved, because #{@board.full_messages}"
end
end
# 新增课程留言
# add by nwb
def self.add_new_jour(user, notes, id, options={})
course = Course.find(id)
if options.count == 0
pjfm = course.journals_for_messages.build(:user_id => user.id, :notes => notes, :reply_id => 0)
else
pjfm = course.journals_for_messages.build(options)
end
pjfm.save
pjfm
end
# 删除课程所有成员
def delete_all_members
if self.members && self.members.count > 0
me, mr = Member.table_name, MemberRole.table_name
connection.delete("DELETE FROM #{mr} WHERE #{mr}.member_id IN (SELECT #{me}.id FROM #{me} WHERE #{me}.course_id = #{id})")
Member.delete_all(['course_id = ?', id])
end
end
def get_endup_time
begin
end_time = Time.parse(self.endup_time)
rescue Exception => e
end_time = Time.parse("3000-01-01")
Rails.logger.error "[Error] course endup_time error. ===> #{e}"
ensure
return end_time
end
end
def get_time
begin
time = Date.new(self.time).to_time
rescue Exception => e
time = Time.parse("3000-01-01")
Rails.logger.error "[Error] course time error. ===> #{e}"
ensure
return time
end
end
def self.allowed_to_condition(user, permission, options={})
perm = Redmine::AccessControl.permission(permission)
base_statement = (perm && perm.read? ? "#{Course.table_name}.status <> #{Course::STATUS_ARCHIVED}" : "#{Course.table_name}.status = #{Course::STATUS_ACTIVE}")
if perm && perm.course_module
base_statement << " AND #{Course.table_name}.id IN (SELECT em.course_id FROM #{EnabledModule.table_name} em WHERE em.name='#{perm.course_module}')"
end
if options[:course]
course_statement = "#{Course.table_name}.id = #{options[:course].id}"
course_statement << " OR (#{Course.table_name}.lft > #{options[:course].lft} AND #{Course.table_name}.rgt < #{options[:course].rgt})" if options[:with_subcourses]
base_statement = "(#{course_statement}) AND (#{base_statement})"
end
if user.admin?
base_statement
else
statement_by_role = {}
unless options[:member]
role = user.logged? ? Role.non_member : Role.anonymous
if role.allowed_to?(permission)
statement_by_role[role] = "#{Course.table_name}.is_public = #{connection.quoted_true}"
end
end
if user.logged?
user.courses_by_role.each do |role, courses|
if role.allowed_to?(permission) && courses.any?
statement_by_role[role] = "#{Course.table_name}.id IN (#{courses.collect(&:id).join(',')})"
end
end
end
if statement_by_role.empty?
"1=0"
else
if block_given?
statement_by_role.each do |role, statement|
if s = yield(role, user)
statement_by_role[role] = "(#{statement} AND (#{s}))"
end
end
end
"((#{base_statement}) AND (#{statement_by_role.values.join(' OR ')}))"
end
end
end
#项目与课程分离后,很多课程的名称等信息为空,这些数据信息存储在项目表中!!就是数据兼容的问题
#def name
# read_attribute('name') || Project.find_by_identifier(self.extra).try(:name)
#end
end