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