User.admins_order()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
c 0
b 0
f 0
dl 0
loc 4
rs 10
1
# frozen_string_literal: true
2
3
# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/.
4
#
5
# Copyright (c) 2018 BigBlueButton Inc. and by respective authors (see below).
6
#
7
# This program is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU Lesser General Public License as published by the Free Software
9
# Foundation; either version 3.0 of the License, or (at your option) any later
10
# version.
11
#
12
# BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
14
# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
15
#
16
# You should have received a copy of the GNU Lesser General Public License along
17
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
18
19
require 'bbb_api'
20
21
class User < ApplicationRecord
22
  include Deleteable
23
24
  attr_accessor :reset_token
25
  after_create :setup_user
26
27
  before_save { email.try(:downcase!) }
28
29
  before_destroy :destroy_rooms
30
31
  has_many :rooms
32
  belongs_to :main_room, class_name: 'Room', foreign_key: :room_id, required: false
33
34
  has_and_belongs_to_many :roles, -> { includes :role_permissions }, join_table: :users_roles
35
36
  validates :name, length: { maximum: 256 }, presence: true
37
  validates :provider, presence: true
38
  validate :check_if_email_can_be_blank
39
  validates :email, length: { maximum: 256 }, allow_blank: true,
40
                    uniqueness: { case_sensitive: false, scope: :provider },
41
                    format: { with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i }
42
43
  validates :password, length: { minimum: 6 }, confirmation: true, if: :greenlight_account?, on: :create
44
45
  # Bypass validation if omniauth
46
  validates :accepted_terms, acceptance: true,
47
                             unless: -> { !greenlight_account? || !Rails.configuration.terms }
48
49
  # We don't want to require password validations on all accounts.
50
  has_secure_password(validations: false)
51
52
  class << self
53
    include AuthValues
54
55
    # Generates a user from omniauth.
56
    def from_omniauth(auth)
57
      # Provider is the customer name if in loadbalanced config mode
58
      provider = auth['provider'] == "bn_launcher" ? auth['info']['customer'] : auth['provider']
59
      find_or_initialize_by(social_uid: auth['uid'], provider: provider).tap do |u|
60
        u.name = auth_name(auth) unless u.name
61
        u.username = auth_username(auth) unless u.username
62
        u.email = auth_email(auth)
63
        u.image = auth_image(auth) unless u.image
64
        auth_roles(u, auth)
65
        u.email_verified = true
66
        u.save!
67
      end
68
    end
69
  end
70
71
  def self.admins_search(string, role)
72
    active_database = Rails.configuration.database_configuration[Rails.env]["adapter"]
73
    # Postgres requires created_at to be cast to a string
74
    created_at_query = if active_database == "postgresql"
75
      "created_at::text"
76
    else
77
      "created_at"
78
    end
79
80
    search_query = ""
81
    role_search_param = ""
82
    if role.nil?
83
      search_query = "users.name LIKE :search OR email LIKE :search OR username LIKE :search" \
84
                    " OR users.#{created_at_query} LIKE :search OR users.provider LIKE :search" \
85
                    " OR roles.name LIKE :roles_search"
86
      role_search_param = "%#{string}%"
87
    else
88
      search_query = "(users.name LIKE :search OR email LIKE :search OR username LIKE :search" \
89
                    " OR users.#{created_at_query} LIKE :search OR users.provider LIKE :search)" \
90
                    " AND roles.name = :roles_search"
91
      role_search_param = role.name
92
    end
93
94
    search_param = "%#{string}%"
95
    joins("LEFT OUTER JOIN users_roles ON users_roles.user_id = users.id LEFT OUTER JOIN roles " \
96
      "ON roles.id = users_roles.role_id").distinct
97
      .where(search_query, search: search_param, roles_search: role_search_param)
98
  end
99
100
  def self.admins_order(column, direction)
101
    # Arel.sql to avoid sql injection
102
    order(Arel.sql("#{column} #{direction}"))
103
  end
104
105
  # Activates an account and initialize a users main room
106
  def activate
107
    update_attributes(email_verified: true, activated_at: Time.zone.now)
108
  end
109
110
  def activated?
111
    Rails.configuration.enable_email_verification ? email_verified : true
112
  end
113
114
  # Sets the password reset attributes.
115
  def create_reset_digest
116
    self.reset_token = User.new_token
117
    update_attributes(reset_digest: User.digest(reset_token), reset_sent_at: Time.zone.now)
118
  end
119
120
  # Returns true if the given token matches the digest.
121
  def authenticated?(attribute, token)
122
    digest = send("#{attribute}_digest")
123
    return false if digest.nil?
124
    BCrypt::Password.new(digest).is_password?(token)
125
  end
126
127
  # Return true if password reset link expires
128
  def password_reset_expired?
129
    reset_sent_at < 2.hours.ago
130
  end
131
132
  # Retrives a list of all a users rooms that are not the main room, sorted by last session date.
133
  def secondary_rooms
134
    room_list = rooms.where.not(uid: main_room.uid)
135
    room_list.where.not(last_session: nil).order("last_session desc") + room_list.where(last_session: nil)
136
  end
137
138
  def name_chunk
139
    charset = ("a".."z").to_a - %w(b i l o s) + ("2".."9").to_a - %w(5 8)
140
    chunk = name.parameterize[0...3]
141
    if chunk.empty?
142
      chunk + (0...3).map { charset.to_a[rand(charset.size)] }.join
143
    elsif chunk.length == 1
144
      chunk + (0...2).map { charset.to_a[rand(charset.size)] }.join
145
    elsif chunk.length == 2
146
      chunk + (0...1).map { charset.to_a[rand(charset.size)] }.join
147
    else
148
      chunk
149
    end
150
  end
151
152
  def greenlight_account?
153
    social_uid.nil?
154
  end
155
156
  def activation_token
157
    # Create the token.
158
    create_reset_activation_digest(User.new_token)
159
  end
160
161
  def admin_of?(user)
162
    if Rails.configuration.loadbalanced_configuration
163
      if has_role? :super_admin
164
        id != user.id
165
      else
166
        highest_priority_role.get_permission("can_manage_users") && (id != user.id) && (provider == user.provider) &&
167
          (!user.has_role? :super_admin)
168
      end
169
    else
170
      (highest_priority_role.get_permission("can_manage_users") || (has_role? :super_admin)) && (id != user.id)
171
    end
172
  end
173
174
  def self.digest(string)
175
    cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost
176
    BCrypt::Password.create(string, cost: cost)
177
  end
178
179
  # Returns a random token.
180
  def self.new_token
181
    SecureRandom.urlsafe_base64
182
  end
183
184
  # role functions
185
  def highest_priority_role
186
    roles.by_priority.first
187
  end
188
189
  def add_role(role)
190
    unless has_role?(role)
191
      role_provider = Rails.configuration.loadbalanced_configuration ? provider : "greenlight"
192
193
      new_role = Role.find_by(name: role, provider: role_provider)
194
195
      if new_role.nil?
196
        return if Role.duplicate_name(role, role_provider) || role.strip.empty?
197
198
        new_role = Role.create_new_role(role, role_provider)
199
      end
200
201
      roles << new_role
202
203
      save!
204
    end
205
  end
206
207
  def remove_role(role)
208
    if has_role?(role)
209
      role_provider = Rails.configuration.loadbalanced_configuration ? provider : "greenlight"
210
211
      roles.delete(Role.find_by(name: role, provider: role_provider))
212
      save!
213
    end
214
  end
215
216
  # This rule is disabled as the function name must be has_role?
217
  # rubocop:disable Naming/PredicateName
218
  def has_role?(role)
219
    # rubocop:enable Naming/PredicateName
220
    roles.exists?(name: role)
221
  end
222
223
  def self.with_role(role)
224
    User.all_users_with_roles.where(roles: { name: role })
225
  end
226
227
  def self.without_role(role)
228
    User.where.not(id: with_role(role).pluck(:id))
229
  end
230
231
  def self.all_users_with_roles
232
    User.joins("INNER JOIN users_roles ON users_roles.user_id = users.id INNER JOIN roles " \
233
      "ON roles.id = users_roles.role_id INNER JOIN role_permissions ON roles.id = role_permissions.role_id").distinct
234
  end
235
236
  private
237
238
  def create_reset_activation_digest(token)
239
    # Create the digest and persist it.
240
    update_attribute(:activation_digest, User.digest(token))
241
    token
242
  end
243
244
  # Destory a users rooms when they are removed.
245
  def destroy_rooms
246
    rooms.destroy_all
247
  end
248
249
  def setup_user
250
    # Initializes a room for the user and assign a BigBlueButton user id.
251
    id = "gl-#{(0...12).map { rand(65..90).chr }.join.downcase}"
252
    room = Room.create!(owner: self, name: I18n.t("home_room"))
253
254
    update_attributes(uid: id, main_room: room)
255
256
    # Initialize the user to use the default user role
257
    role_provider = Rails.configuration.loadbalanced_configuration ? provider : "greenlight"
258
259
    Role.create_default_roles(role_provider) if Role.where(provider: role_provider).count.zero?
260
    add_role(:user) if roles.blank?
261
  end
262
263
  def check_if_email_can_be_blank
264
    if email.blank?
265
      if Rails.configuration.loadbalanced_configuration && greenlight_account?
266
        errors.add(:email, I18n.t("errors.messages.blank"))
267
      elsif provider == "greenlight"
268
        errors.add(:email, I18n.t("errors.messages.blank"))
269
      end
270
    end
271
  end
272
end
273