Chris@0: # redMine - project management software Chris@0: # Copyright (C) 2006 Jean-Philippe Lang Chris@0: # Chris@0: # This program is free software; you can redistribute it and/or Chris@0: # modify it under the terms of the GNU General Public License Chris@0: # as published by the Free Software Foundation; either version 2 Chris@0: # of the License, or (at your option) any later version. Chris@0: # Chris@0: # This program is distributed in the hope that it will be useful, Chris@0: # but WITHOUT ANY WARRANTY; without even the implied warranty of Chris@0: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Chris@0: # GNU General Public License for more details. Chris@0: # Chris@0: # You should have received a copy of the GNU General Public License Chris@0: # along with this program; if not, write to the Free Software Chris@0: # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Chris@0: Chris@0: class Role < ActiveRecord::Base Chris@0: # Built-in roles Chris@0: BUILTIN_NON_MEMBER = 1 Chris@0: BUILTIN_ANONYMOUS = 2 Chris@0: Chris@0: named_scope :givable, { :conditions => "builtin = 0", :order => 'position' } Chris@0: named_scope :builtin, lambda { |*args| Chris@0: compare = 'not' if args.first == true Chris@0: { :conditions => "#{compare} builtin = 0" } Chris@0: } Chris@0: Chris@0: before_destroy :check_deletable Chris@0: has_many :workflows, :dependent => :delete_all do Chris@0: def copy(source_role) Chris@0: Workflow.copy(nil, source_role, nil, proxy_owner) Chris@0: end Chris@0: end Chris@0: Chris@0: has_many :member_roles, :dependent => :destroy Chris@0: has_many :members, :through => :member_roles Chris@0: acts_as_list Chris@0: Chris@0: serialize :permissions, Array Chris@0: attr_protected :builtin Chris@0: Chris@0: validates_presence_of :name Chris@0: validates_uniqueness_of :name Chris@0: validates_length_of :name, :maximum => 30 Chris@0: validates_format_of :name, :with => /^[\w\s\'\-]*$/i Chris@0: Chris@0: def permissions Chris@0: read_attribute(:permissions) || [] Chris@0: end Chris@0: Chris@0: def permissions=(perms) Chris@0: perms = perms.collect {|p| p.to_sym unless p.blank? }.compact.uniq if perms Chris@0: write_attribute(:permissions, perms) Chris@0: end Chris@0: Chris@0: def add_permission!(*perms) Chris@0: self.permissions = [] unless permissions.is_a?(Array) Chris@0: Chris@0: permissions_will_change! Chris@0: perms.each do |p| Chris@0: p = p.to_sym Chris@0: permissions << p unless permissions.include?(p) Chris@0: end Chris@0: save! Chris@0: end Chris@0: Chris@0: def remove_permission!(*perms) Chris@0: return unless permissions.is_a?(Array) Chris@0: permissions_will_change! Chris@0: perms.each { |p| permissions.delete(p.to_sym) } Chris@0: save! Chris@0: end Chris@0: Chris@0: # Returns true if the role has the given permission Chris@0: def has_permission?(perm) Chris@0: !permissions.nil? && permissions.include?(perm.to_sym) Chris@0: end Chris@0: Chris@0: def <=>(role) Chris@0: role ? position <=> role.position : -1 Chris@0: end Chris@0: Chris@0: def to_s Chris@0: name Chris@0: end Chris@0: Chris@0: # Return true if the role is a builtin role Chris@0: def builtin? Chris@0: self.builtin != 0 Chris@0: end Chris@0: Chris@0: # Return true if the role is a project member role Chris@0: def member? Chris@0: !self.builtin? Chris@0: end Chris@0: Chris@0: # Return true if role is allowed to do the specified action Chris@0: # action can be: Chris@0: # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit') Chris@0: # * a permission Symbol (eg. :edit_project) Chris@0: def allowed_to?(action) Chris@0: if action.is_a? Hash Chris@0: allowed_actions.include? "#{action[:controller]}/#{action[:action]}" Chris@0: else Chris@0: allowed_permissions.include? action Chris@0: end Chris@0: end Chris@0: Chris@0: # Return all the permissions that can be given to the role Chris@0: def setable_permissions Chris@0: setable_permissions = Redmine::AccessControl.permissions - Redmine::AccessControl.public_permissions Chris@0: setable_permissions -= Redmine::AccessControl.members_only_permissions if self.builtin == BUILTIN_NON_MEMBER Chris@0: setable_permissions -= Redmine::AccessControl.loggedin_only_permissions if self.builtin == BUILTIN_ANONYMOUS Chris@0: setable_permissions Chris@0: end Chris@0: Chris@0: # Find all the roles that can be given to a project member Chris@0: def self.find_all_givable Chris@0: find(:all, :conditions => {:builtin => 0}, :order => 'position') Chris@0: end Chris@0: Chris@0: # Return the builtin 'non member' role. If the role doesn't exist, Chris@0: # it will be created on the fly. Chris@0: def self.non_member Chris@0: non_member_role = find(:first, :conditions => {:builtin => BUILTIN_NON_MEMBER}) Chris@0: if non_member_role.nil? Chris@0: non_member_role = create(:name => 'Non member', :position => 0) do |role| Chris@0: role.builtin = BUILTIN_NON_MEMBER Chris@0: end Chris@0: raise 'Unable to create the non-member role.' if non_member_role.new_record? Chris@0: end Chris@0: non_member_role Chris@0: end Chris@0: Chris@0: # Return the builtin 'anonymous' role. If the role doesn't exist, Chris@0: # it will be created on the fly. Chris@0: def self.anonymous Chris@0: anonymous_role = find(:first, :conditions => {:builtin => BUILTIN_ANONYMOUS}) Chris@0: if anonymous_role.nil? Chris@0: anonymous_role = create(:name => 'Anonymous', :position => 0) do |role| Chris@0: role.builtin = BUILTIN_ANONYMOUS Chris@0: end Chris@0: raise 'Unable to create the anonymous role.' if anonymous_role.new_record? Chris@0: end Chris@0: anonymous_role Chris@0: end Chris@0: Chris@0: Chris@0: private Chris@0: def allowed_permissions Chris@0: @allowed_permissions ||= permissions + Redmine::AccessControl.public_permissions.collect {|p| p.name} Chris@0: end Chris@0: Chris@0: def allowed_actions Chris@0: @actions_allowed ||= allowed_permissions.inject([]) { |actions, permission| actions += Redmine::AccessControl.allowed_actions(permission) }.flatten Chris@0: end Chris@0: Chris@0: def check_deletable Chris@0: raise "Can't delete role" if members.any? Chris@0: raise "Can't delete builtin role" if builtin? Chris@0: end Chris@0: end