Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

role.rb 9.5KB

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