##// END OF EJS Templates
Skip validation if attribute did not change....
Jean-Philippe Lang -
r13469:0eda7765fa55
parent child
Show More
@@ -1,221 +1,221
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2014 Jean-Philippe Lang
2 # Copyright (C) 2006-2014 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class Role < ActiveRecord::Base
18 class Role < ActiveRecord::Base
19 # Custom coder for the permissions attribute that should be an
19 # Custom coder for the permissions attribute that should be an
20 # array of symbols. Rails 3 uses Psych which can be *unbelievably*
20 # array of symbols. Rails 3 uses Psych which can be *unbelievably*
21 # slow on some platforms (eg. mingw32).
21 # slow on some platforms (eg. mingw32).
22 class PermissionsAttributeCoder
22 class PermissionsAttributeCoder
23 def self.load(str)
23 def self.load(str)
24 str.to_s.scan(/:([a-z0-9_]+)/).flatten.map(&:to_sym)
24 str.to_s.scan(/:([a-z0-9_]+)/).flatten.map(&:to_sym)
25 end
25 end
26
26
27 def self.dump(value)
27 def self.dump(value)
28 YAML.dump(value)
28 YAML.dump(value)
29 end
29 end
30 end
30 end
31
31
32 # Built-in roles
32 # Built-in roles
33 BUILTIN_NON_MEMBER = 1
33 BUILTIN_NON_MEMBER = 1
34 BUILTIN_ANONYMOUS = 2
34 BUILTIN_ANONYMOUS = 2
35
35
36 ISSUES_VISIBILITY_OPTIONS = [
36 ISSUES_VISIBILITY_OPTIONS = [
37 ['all', :label_issues_visibility_all],
37 ['all', :label_issues_visibility_all],
38 ['default', :label_issues_visibility_public],
38 ['default', :label_issues_visibility_public],
39 ['own', :label_issues_visibility_own]
39 ['own', :label_issues_visibility_own]
40 ]
40 ]
41
41
42 USERS_VISIBILITY_OPTIONS = [
42 USERS_VISIBILITY_OPTIONS = [
43 ['all', :label_users_visibility_all],
43 ['all', :label_users_visibility_all],
44 ['members_of_visible_projects', :label_users_visibility_members_of_visible_projects]
44 ['members_of_visible_projects', :label_users_visibility_members_of_visible_projects]
45 ]
45 ]
46
46
47 scope :sorted, lambda { order(:builtin, :position) }
47 scope :sorted, lambda { order(:builtin, :position) }
48 scope :givable, lambda { order(:position).where(:builtin => 0) }
48 scope :givable, lambda { order(:position).where(:builtin => 0) }
49 scope :builtin, lambda { |*args|
49 scope :builtin, lambda { |*args|
50 compare = (args.first == true ? 'not' : '')
50 compare = (args.first == true ? 'not' : '')
51 where("#{compare} builtin = 0")
51 where("#{compare} builtin = 0")
52 }
52 }
53
53
54 before_destroy :check_deletable
54 before_destroy :check_deletable
55 has_many :workflow_rules, :dependent => :delete_all do
55 has_many :workflow_rules, :dependent => :delete_all do
56 def copy(source_role)
56 def copy(source_role)
57 WorkflowRule.copy(nil, source_role, nil, proxy_association.owner)
57 WorkflowRule.copy(nil, source_role, nil, proxy_association.owner)
58 end
58 end
59 end
59 end
60 has_and_belongs_to_many :custom_fields, :join_table => "#{table_name_prefix}custom_fields_roles#{table_name_suffix}", :foreign_key => "role_id"
60 has_and_belongs_to_many :custom_fields, :join_table => "#{table_name_prefix}custom_fields_roles#{table_name_suffix}", :foreign_key => "role_id"
61
61
62 has_many :member_roles, :dependent => :destroy
62 has_many :member_roles, :dependent => :destroy
63 has_many :members, :through => :member_roles
63 has_many :members, :through => :member_roles
64 acts_as_list
64 acts_as_list
65
65
66 serialize :permissions, ::Role::PermissionsAttributeCoder
66 serialize :permissions, ::Role::PermissionsAttributeCoder
67 attr_protected :builtin
67 attr_protected :builtin
68
68
69 validates_presence_of :name
69 validates_presence_of :name
70 validates_uniqueness_of :name
70 validates_uniqueness_of :name
71 validates_length_of :name, :maximum => 30
71 validates_length_of :name, :maximum => 30
72 validates_inclusion_of :issues_visibility,
72 validates_inclusion_of :issues_visibility,
73 :in => ISSUES_VISIBILITY_OPTIONS.collect(&:first),
73 :in => ISSUES_VISIBILITY_OPTIONS.collect(&:first),
74 :if => lambda {|role| role.respond_to?(:issues_visibility)}
74 :if => lambda {|role| role.respond_to?(:issues_visibility) && role.issues_visibility_changed?}
75 validates_inclusion_of :users_visibility,
75 validates_inclusion_of :users_visibility,
76 :in => USERS_VISIBILITY_OPTIONS.collect(&:first),
76 :in => USERS_VISIBILITY_OPTIONS.collect(&:first),
77 :if => lambda {|role| role.respond_to?(:users_visibility)}
77 :if => lambda {|role| role.respond_to?(:users_visibility) && role.users_visibility_changed?}
78
78
79 # Copies attributes from another role, arg can be an id or a Role
79 # Copies attributes from another role, arg can be an id or a Role
80 def copy_from(arg, options={})
80 def copy_from(arg, options={})
81 return unless arg.present?
81 return unless arg.present?
82 role = arg.is_a?(Role) ? arg : Role.find_by_id(arg.to_s)
82 role = arg.is_a?(Role) ? arg : Role.find_by_id(arg.to_s)
83 self.attributes = role.attributes.dup.except("id", "name", "position", "builtin", "permissions")
83 self.attributes = role.attributes.dup.except("id", "name", "position", "builtin", "permissions")
84 self.permissions = role.permissions.dup
84 self.permissions = role.permissions.dup
85 self
85 self
86 end
86 end
87
87
88 def permissions=(perms)
88 def permissions=(perms)
89 perms = perms.collect {|p| p.to_sym unless p.blank? }.compact.uniq if perms
89 perms = perms.collect {|p| p.to_sym unless p.blank? }.compact.uniq if perms
90 write_attribute(:permissions, perms)
90 write_attribute(:permissions, perms)
91 end
91 end
92
92
93 def add_permission!(*perms)
93 def add_permission!(*perms)
94 self.permissions = [] unless permissions.is_a?(Array)
94 self.permissions = [] unless permissions.is_a?(Array)
95
95
96 permissions_will_change!
96 permissions_will_change!
97 perms.each do |p|
97 perms.each do |p|
98 p = p.to_sym
98 p = p.to_sym
99 permissions << p unless permissions.include?(p)
99 permissions << p unless permissions.include?(p)
100 end
100 end
101 save!
101 save!
102 end
102 end
103
103
104 def remove_permission!(*perms)
104 def remove_permission!(*perms)
105 return unless permissions.is_a?(Array)
105 return unless permissions.is_a?(Array)
106 permissions_will_change!
106 permissions_will_change!
107 perms.each { |p| permissions.delete(p.to_sym) }
107 perms.each { |p| permissions.delete(p.to_sym) }
108 save!
108 save!
109 end
109 end
110
110
111 # Returns true if the role has the given permission
111 # Returns true if the role has the given permission
112 def has_permission?(perm)
112 def has_permission?(perm)
113 !permissions.nil? && permissions.include?(perm.to_sym)
113 !permissions.nil? && permissions.include?(perm.to_sym)
114 end
114 end
115
115
116 def consider_workflow?
116 def consider_workflow?
117 has_permission?(:add_issues) || has_permission?(:edit_issues)
117 has_permission?(:add_issues) || has_permission?(:edit_issues)
118 end
118 end
119
119
120 def <=>(role)
120 def <=>(role)
121 if role
121 if role
122 if builtin == role.builtin
122 if builtin == role.builtin
123 position <=> role.position
123 position <=> role.position
124 else
124 else
125 builtin <=> role.builtin
125 builtin <=> role.builtin
126 end
126 end
127 else
127 else
128 -1
128 -1
129 end
129 end
130 end
130 end
131
131
132 def to_s
132 def to_s
133 name
133 name
134 end
134 end
135
135
136 def name
136 def name
137 case builtin
137 case builtin
138 when 1; l(:label_role_non_member, :default => read_attribute(:name))
138 when 1; l(:label_role_non_member, :default => read_attribute(:name))
139 when 2; l(:label_role_anonymous, :default => read_attribute(:name))
139 when 2; l(:label_role_anonymous, :default => read_attribute(:name))
140 else; read_attribute(:name)
140 else; read_attribute(:name)
141 end
141 end
142 end
142 end
143
143
144 # Return true if the role is a builtin role
144 # Return true if the role is a builtin role
145 def builtin?
145 def builtin?
146 self.builtin != 0
146 self.builtin != 0
147 end
147 end
148
148
149 # Return true if the role is the anonymous role
149 # Return true if the role is the anonymous role
150 def anonymous?
150 def anonymous?
151 builtin == 2
151 builtin == 2
152 end
152 end
153
153
154 # Return true if the role is a project member role
154 # Return true if the role is a project member role
155 def member?
155 def member?
156 !self.builtin?
156 !self.builtin?
157 end
157 end
158
158
159 # Return true if role is allowed to do the specified action
159 # Return true if role is allowed to do the specified action
160 # action can be:
160 # action can be:
161 # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
161 # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
162 # * a permission Symbol (eg. :edit_project)
162 # * a permission Symbol (eg. :edit_project)
163 def allowed_to?(action)
163 def allowed_to?(action)
164 if action.is_a? Hash
164 if action.is_a? Hash
165 allowed_actions.include? "#{action[:controller]}/#{action[:action]}"
165 allowed_actions.include? "#{action[:controller]}/#{action[:action]}"
166 else
166 else
167 allowed_permissions.include? action
167 allowed_permissions.include? action
168 end
168 end
169 end
169 end
170
170
171 # Return all the permissions that can be given to the role
171 # Return all the permissions that can be given to the role
172 def setable_permissions
172 def setable_permissions
173 setable_permissions = Redmine::AccessControl.permissions - Redmine::AccessControl.public_permissions
173 setable_permissions = Redmine::AccessControl.permissions - Redmine::AccessControl.public_permissions
174 setable_permissions -= Redmine::AccessControl.members_only_permissions if self.builtin == BUILTIN_NON_MEMBER
174 setable_permissions -= Redmine::AccessControl.members_only_permissions if self.builtin == BUILTIN_NON_MEMBER
175 setable_permissions -= Redmine::AccessControl.loggedin_only_permissions if self.builtin == BUILTIN_ANONYMOUS
175 setable_permissions -= Redmine::AccessControl.loggedin_only_permissions if self.builtin == BUILTIN_ANONYMOUS
176 setable_permissions
176 setable_permissions
177 end
177 end
178
178
179 # Find all the roles that can be given to a project member
179 # Find all the roles that can be given to a project member
180 def self.find_all_givable
180 def self.find_all_givable
181 Role.givable.to_a
181 Role.givable.to_a
182 end
182 end
183
183
184 # Return the builtin 'non member' role. If the role doesn't exist,
184 # Return the builtin 'non member' role. If the role doesn't exist,
185 # it will be created on the fly.
185 # it will be created on the fly.
186 def self.non_member
186 def self.non_member
187 find_or_create_system_role(BUILTIN_NON_MEMBER, 'Non member')
187 find_or_create_system_role(BUILTIN_NON_MEMBER, 'Non member')
188 end
188 end
189
189
190 # Return the builtin 'anonymous' role. If the role doesn't exist,
190 # Return the builtin 'anonymous' role. If the role doesn't exist,
191 # it will be created on the fly.
191 # it will be created on the fly.
192 def self.anonymous
192 def self.anonymous
193 find_or_create_system_role(BUILTIN_ANONYMOUS, 'Anonymous')
193 find_or_create_system_role(BUILTIN_ANONYMOUS, 'Anonymous')
194 end
194 end
195
195
196 private
196 private
197
197
198 def allowed_permissions
198 def allowed_permissions
199 @allowed_permissions ||= permissions + Redmine::AccessControl.public_permissions.collect {|p| p.name}
199 @allowed_permissions ||= permissions + Redmine::AccessControl.public_permissions.collect {|p| p.name}
200 end
200 end
201
201
202 def allowed_actions
202 def allowed_actions
203 @actions_allowed ||= allowed_permissions.inject([]) { |actions, permission| actions += Redmine::AccessControl.allowed_actions(permission) }.flatten
203 @actions_allowed ||= allowed_permissions.inject([]) { |actions, permission| actions += Redmine::AccessControl.allowed_actions(permission) }.flatten
204 end
204 end
205
205
206 def check_deletable
206 def check_deletable
207 raise "Cannot delete role" if members.any?
207 raise "Cannot delete role" if members.any?
208 raise "Cannot delete builtin role" if builtin?
208 raise "Cannot delete builtin role" if builtin?
209 end
209 end
210
210
211 def self.find_or_create_system_role(builtin, name)
211 def self.find_or_create_system_role(builtin, name)
212 role = where(:builtin => builtin).first
212 role = where(:builtin => builtin).first
213 if role.nil?
213 if role.nil?
214 role = create(:name => name, :position => 0) do |r|
214 role = create(:name => name, :position => 0) do |r|
215 r.builtin = builtin
215 r.builtin = builtin
216 end
216 end
217 raise "Unable to create the #{name} role." if role.new_record?
217 raise "Unable to create the #{name} role." if role.new_record?
218 end
218 end
219 role
219 role
220 end
220 end
221 end
221 end
General Comments 0
You need to be logged in to leave comments. Login now