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