user_role.rb 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. # frozen_string_literal: true
  2. # == Schema Information
  3. #
  4. # Table name: user_roles
  5. #
  6. # id :bigint(8) not null, primary key
  7. # name :string default(""), not null
  8. # color :string default(""), not null
  9. # position :integer default(0), not null
  10. # permissions :bigint(8) default(0), not null
  11. # highlighted :boolean default(FALSE), not null
  12. # created_at :datetime not null
  13. # updated_at :datetime not null
  14. #
  15. class UserRole < ApplicationRecord
  16. FLAGS = {
  17. administrator: (1 << 0),
  18. view_devops: (1 << 1),
  19. view_audit_log: (1 << 2),
  20. view_dashboard: (1 << 3),
  21. manage_reports: (1 << 4),
  22. manage_federation: (1 << 5),
  23. manage_settings: (1 << 6),
  24. manage_blocks: (1 << 7),
  25. manage_taxonomies: (1 << 8),
  26. manage_appeals: (1 << 9),
  27. manage_users: (1 << 10),
  28. manage_invites: (1 << 11),
  29. manage_rules: (1 << 12),
  30. manage_announcements: (1 << 13),
  31. manage_custom_emojis: (1 << 14),
  32. manage_webhooks: (1 << 15),
  33. invite_users: (1 << 16),
  34. manage_roles: (1 << 17),
  35. manage_user_access: (1 << 18),
  36. delete_user_data: (1 << 19),
  37. }.freeze
  38. EVERYONE_ROLE_ID = -99
  39. NOBODY_POSITION = -1
  40. module Flags
  41. NONE = 0
  42. ALL = FLAGS.values.reduce(&:|)
  43. DEFAULT = FLAGS[:invite_users]
  44. CATEGORIES = {
  45. invites: %i(
  46. invite_users
  47. ).freeze,
  48. moderation: %i(
  49. view_dashboard
  50. view_audit_log
  51. manage_users
  52. manage_user_access
  53. delete_user_data
  54. manage_reports
  55. manage_appeals
  56. manage_federation
  57. manage_blocks
  58. manage_taxonomies
  59. manage_invites
  60. ).freeze,
  61. administration: %i(
  62. manage_settings
  63. manage_rules
  64. manage_roles
  65. manage_webhooks
  66. manage_custom_emojis
  67. manage_announcements
  68. ).freeze,
  69. devops: %i(
  70. view_devops
  71. ).freeze,
  72. special: %i(
  73. administrator
  74. ).freeze,
  75. }.freeze
  76. end
  77. attr_writer :current_account
  78. validates :name, presence: true, unless: :everyone?
  79. validates :color, format: { with: /\A#?(?:[A-F0-9]{3}){1,2}\z/i }, unless: -> { color.blank? }
  80. validate :validate_permissions_elevation
  81. validate :validate_position_elevation
  82. validate :validate_dangerous_permissions
  83. validate :validate_own_role_edition
  84. before_validation :set_position
  85. scope :assignable, -> { where.not(id: EVERYONE_ROLE_ID).order(position: :asc) }
  86. scope :highlighted, -> { where(highlighted: true) }
  87. scope :with_color, -> { where.not(color: [nil, '']) }
  88. scope :providing_styles, -> { highlighted.with_color }
  89. has_many :users, inverse_of: :role, foreign_key: 'role_id', dependent: :nullify
  90. def self.nobody
  91. @nobody ||= UserRole.new(permissions: Flags::NONE, position: NOBODY_POSITION)
  92. end
  93. def self.everyone
  94. UserRole.find(EVERYONE_ROLE_ID)
  95. rescue ActiveRecord::RecordNotFound
  96. UserRole.create!(id: EVERYONE_ROLE_ID, permissions: Flags::DEFAULT)
  97. end
  98. def self.that_can(*any_of_privileges)
  99. all.select { |role| role.can?(*any_of_privileges) }
  100. end
  101. def everyone?
  102. id == EVERYONE_ROLE_ID
  103. end
  104. def nobody?
  105. id.nil?
  106. end
  107. def permissions_as_keys
  108. FLAGS.keys.select { |privilege| permissions & FLAGS[privilege] == FLAGS[privilege] }.map(&:to_s)
  109. end
  110. def permissions_as_keys=(value)
  111. self.permissions = value.filter_map(&:presence).reduce(Flags::NONE) { |bitmask, privilege| FLAGS.key?(privilege.to_sym) ? (bitmask | FLAGS[privilege.to_sym]) : bitmask }
  112. end
  113. def can?(*any_of_privileges)
  114. any_of_privileges.any? { |privilege| in_permissions?(privilege) }
  115. end
  116. def overrides?(other_role)
  117. other_role.nil? || position > other_role.position
  118. end
  119. def computed_permissions
  120. # If called on the everyone role, no further computation needed
  121. return permissions if everyone?
  122. # If called on the nobody role, no permissions are there to be given
  123. return Flags::NONE if nobody?
  124. # Otherwise, compute permissions based on special conditions
  125. @computed_permissions ||= begin
  126. permissions = self.class.everyone.permissions | self.permissions
  127. if permissions & FLAGS[:administrator] == FLAGS[:administrator]
  128. Flags::ALL
  129. else
  130. permissions
  131. end
  132. end
  133. end
  134. def to_log_human_identifier
  135. name
  136. end
  137. private
  138. def in_permissions?(privilege)
  139. raise ArgumentError, "Unknown privilege: #{privilege}" unless FLAGS.key?(privilege)
  140. computed_permissions & FLAGS[privilege] == FLAGS[privilege]
  141. end
  142. def set_position
  143. self.position = NOBODY_POSITION if everyone?
  144. end
  145. def validate_own_role_edition
  146. return unless defined?(@current_account) && @current_account.user_role.id == id
  147. errors.add(:permissions_as_keys, :own_role) if permissions_changed?
  148. errors.add(:position, :own_role) if position_changed?
  149. end
  150. def validate_permissions_elevation
  151. errors.add(:permissions_as_keys, :elevated) if defined?(@current_account) && @current_account.user_role.computed_permissions & permissions != permissions
  152. end
  153. def validate_position_elevation
  154. errors.add(:position, :elevated) if defined?(@current_account) && @current_account.user_role.position < position
  155. end
  156. def validate_dangerous_permissions
  157. errors.add(:permissions_as_keys, :dangerous) if everyone? && Flags::DEFAULT & permissions != permissions
  158. end
  159. end