role.rb 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. # Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
  2. class Role < ApplicationModel
  3. include HasDefaultModelUserRelations
  4. include CanBeImported
  5. include HasActivityStreamLog
  6. include ChecksClientNotification
  7. include ChecksHtmlSanitized
  8. include HasGroups
  9. include HasCollectionUpdate
  10. include Role::Assets
  11. has_and_belongs_to_many :users, after_add: :cache_update, after_remove: :cache_update
  12. has_and_belongs_to_many :permissions,
  13. before_add: %i[validate_agent_limit_by_permission validate_permissions],
  14. after_add: %i[cache_update cache_add_kb_permission],
  15. before_remove: :last_admin_check_by_permission,
  16. after_remove: %i[cache_update cache_remove_kb_permission]
  17. validates :name, presence: true
  18. store :preferences
  19. has_many :knowledge_base_permissions, class_name: 'KnowledgeBase::Permission', dependent: :destroy
  20. before_create :check_default_at_signup_permissions
  21. before_update :last_admin_check_by_attribute, :validate_agent_limit_by_attributes, :check_default_at_signup_permissions
  22. # ignore Users because this will lead to huge
  23. # results for e.g. the Customer role
  24. association_attributes_ignored :users
  25. activity_stream_permission 'admin.role'
  26. validates :note, length: { maximum: 250 }
  27. sanitized_html :note
  28. =begin
  29. grant permission to role
  30. role.permission_grant('permission.key')
  31. =end
  32. def permission_grant(key)
  33. permission = Permission.lookup(name: key)
  34. raise "Invalid permission #{key}" if !permission
  35. return true if permission_ids.include?(permission.id)
  36. self.permission_ids = permission_ids.push permission.id # rubocop:disable Style/RedundantSelfAssignment
  37. true
  38. end
  39. =begin
  40. revoke permission of role
  41. role.permission_revoke('permission.key')
  42. =end
  43. def permission_revoke(key)
  44. permission = Permission.lookup(name: key)
  45. raise "Invalid permission #{key}" if !permission
  46. return true if permission_ids.exclude?(permission.id)
  47. self.permission_ids = self.permission_ids -= [permission.id]
  48. true
  49. end
  50. =begin
  51. get signup roles
  52. Role.signup_roles
  53. returns
  54. [role1, role2, ...]
  55. =end
  56. def self.signup_roles
  57. Role.where(active: true, default_at_signup: true)
  58. end
  59. =begin
  60. get signup role ids
  61. Role.signup_role_ids
  62. returns
  63. [role1, role2, ...]
  64. =end
  65. def self.signup_role_ids
  66. signup_roles.map(&:id)
  67. end
  68. =begin
  69. get all roles with permission
  70. roles = Role.with_permissions('admin.session')
  71. get all roles with permission "admin.session" or "ticket.agent"
  72. roles = Role.with_permissions(['admin.session', 'ticket.agent'])
  73. returns
  74. [role1, role2, ...]
  75. =end
  76. def self.with_permissions(keys)
  77. permission_ids = Role.permission_ids_by_name(keys)
  78. Role.joins(:permissions_roles).joins(:permissions).where(
  79. 'permissions_roles.permission_id IN (?) AND roles.active = ? AND permissions.active = ?', permission_ids, true, true
  80. ).distinct
  81. end
  82. =begin
  83. check if roles is with permission
  84. role = Role.find(123)
  85. role.with_permission?('admin.session')
  86. get if role has permission of "admin.session" or "ticket.agent"
  87. role.with_permission?(['admin.session', 'ticket.agent'])
  88. returns
  89. true | false
  90. =end
  91. def with_permission?(keys)
  92. permission_ids = Role.permission_ids_by_name(keys)
  93. return true if Role.joins(:permissions_roles).joins(:permissions).where(
  94. 'roles.id = ? AND permissions_roles.permission_id IN (?) AND permissions.active = ?', id, permission_ids, true
  95. ).distinct.count.nonzero?
  96. false
  97. end
  98. def self.permission_ids_by_name(keys)
  99. Array(keys).each_with_object([]) do |key, result|
  100. ::Permission.with_parents(key).each do |local_key|
  101. permission = ::Permission.lookup(name: local_key)
  102. next if !permission
  103. result.push permission.id
  104. end
  105. end
  106. end
  107. private
  108. def validate_permissions(permission)
  109. Rails.logger.debug { "self permission: #{permission.id}" }
  110. raise "Permission #{permission.name} is disabled" if permission.preferences[:disabled]
  111. permission.preferences[:not]
  112. &.find { |name| name.in?(permissions.map(&:name)) }
  113. &.tap { |conflict| raise "Permission #{permission} conflicts with #{conflict}" }
  114. permissions.find { |p| p.preferences[:not]&.include?(permission.name) }
  115. &.tap { |conflict| raise "Permission #{permission} conflicts with #{conflict}" }
  116. end
  117. def last_admin_check_by_attribute
  118. return true if !will_save_change_to_attribute?('active')
  119. return true if active != false
  120. return true if !with_permission?(['admin', 'admin.user'])
  121. raise Exceptions::UnprocessableEntity, __('At least one user needs to have admin permissions.') if last_admin_check_admin_count < 1
  122. true
  123. end
  124. def last_admin_check_by_permission(permission)
  125. return true if Setting.get('import_mode')
  126. return true if permission.name != 'admin' && permission.name != 'admin.user'
  127. raise Exceptions::UnprocessableEntity, __('At least one user needs to have admin permissions.') if last_admin_check_admin_count < 1
  128. true
  129. end
  130. def last_admin_check_admin_count
  131. admin_role_ids = Role.joins(:permissions).where(permissions: { name: ['admin', 'admin.user'], active: true }, roles: { active: true }).where.not(id: id).pluck(:id)
  132. User.joins(:roles).where(roles: { id: admin_role_ids }, users: { active: true }).distinct.count
  133. end
  134. def validate_agent_limit_by_attributes
  135. return true if Setting.get('system_agent_limit').blank?
  136. return true if !will_save_change_to_attribute?('active')
  137. return true if active != true
  138. return true if !with_permission?('ticket.agent')
  139. ticket_agent_role_ids = Role.joins(:permissions).where(permissions: { name: 'ticket.agent', active: true }, roles: { active: true }).pluck(:id)
  140. currents = User.joins(:roles).where(roles: { id: ticket_agent_role_ids }, users: { active: true }).distinct.pluck(:id)
  141. news = User.joins(:roles).where(roles: { id: id }, users: { active: true }).distinct.pluck(:id)
  142. count = currents.concat(news).uniq.count
  143. raise Exceptions::UnprocessableEntity, __('Agent limit exceeded, please check your account settings.') if count > Setting.get('system_agent_limit').to_i
  144. true
  145. end
  146. def validate_agent_limit_by_permission(permission)
  147. return true if Setting.get('system_agent_limit').blank?
  148. return true if active != true
  149. return true if permission.active != true
  150. return true if permission.name != 'ticket.agent'
  151. ticket_agent_role_ids = Role.joins(:permissions).where(permissions: { name: 'ticket.agent' }, roles: { active: true }).pluck(:id)
  152. ticket_agent_role_ids.push(id)
  153. count = User.joins(:roles).where(roles: { id: ticket_agent_role_ids }, users: { active: true }).distinct.count
  154. raise Exceptions::UnprocessableEntity, __('Agent limit exceeded, please check your account settings.') if count > Setting.get('system_agent_limit').to_i
  155. true
  156. end
  157. def check_default_at_signup_permissions
  158. return true if !default_at_signup
  159. forbidden_permissions = permissions.reject(&:allow_signup)
  160. return true if forbidden_permissions.blank?
  161. raise Exceptions::UnprocessableEntity, "Cannot set default at signup when role has #{forbidden_permissions.join(', ')} permissions."
  162. end
  163. def cache_add_kb_permission(permission)
  164. return if !permission.name.starts_with? 'knowledge_base.'
  165. return if !KnowledgeBase.granular_permissions?
  166. KnowledgeBase::Category.all.each(&:touch)
  167. end
  168. def cache_remove_kb_permission(permission)
  169. return if !permission.name.starts_with? 'knowledge_base.'
  170. return if !KnowledgeBase.granular_permissions?
  171. has_editor = permissions.where(name: 'knowledge_base.editor').any?
  172. has_reader = permissions.where(name: 'knowledge_base.reader').any?
  173. KnowledgeBase::Permission
  174. .where(role: self)
  175. .each do |elem|
  176. if !has_editor && !has_reader
  177. elem.destroy!
  178. elsif !has_editor && has_reader
  179. elem.update!(access: 'reader') if permission.access == 'editor'
  180. end
  181. end
  182. KnowledgeBase::Category.all.each(&:touch)
  183. end
  184. end