# frozen_string_literal: true # BigBlueButton open source conferencing system - http://www.bigbluebutton.org/. # # Copyright (c) 2018 BigBlueButton Inc. and by respective authors (see below). # # This program is free software; you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free Software # Foundation; either version 3.0 of the License, or (at your option) any later # version. # # BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License along # with BigBlueButton; if not, see . require 'bbb_api' class User < ApplicationRecord include ::APIConcern include ::BbbApi attr_accessor :reset_token after_create :initialize_main_room before_save { email.try(:downcase!) } before_destroy :destroy_rooms has_many :rooms belongs_to :main_room, class_name: 'Room', foreign_key: :room_id, required: false validates :name, length: { maximum: 256 }, presence: true validates :provider, presence: true validates :email, length: { maximum: 256 }, allow_blank: true, uniqueness: { case_sensitive: false, scope: :provider }, format: { with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i } validates :password, length: { minimum: 6 }, confirmation: true, if: :greenlight_account?, on: :create # Bypass validation if omniauth validates :accepted_terms, acceptance: true, unless: -> { !greenlight_account? || !Rails.configuration.terms } # We don't want to require password validations on all accounts. has_secure_password(validations: false) class << self # Generates a user from omniauth. def from_omniauth(auth) # Provider is the customer name if in loadbalanced config mode provider = auth['provider'] == "bn_launcher" ? auth['info']['customer'] : auth['provider'] find_or_initialize_by(social_uid: auth['uid'], provider: provider).tap do |u| u.name = auth_name(auth) unless u.name u.username = auth_username(auth) unless u.username u.email = auth_email(auth) u.image = auth_image(auth) u.email_verified = true u.save! end end private # Provider attributes. def auth_name(auth) case auth['provider'] when :microsoft_office365 auth['info']['display_name'] else auth['info']['name'] end end def auth_username(auth) case auth['provider'] when :google auth['info']['email'].split('@').first when :bn_launcher auth['info']['username'] else auth['info']['nickname'] end end def auth_email(auth) auth['info']['email'] end def auth_image(auth) case auth['provider'] when :twitter auth['info']['image'].gsub("http", "https").gsub("_normal", "") else auth['info']['image'] unless auth['provider'] == :microsoft_office365 end end end def all_recordings pag_num = Rails.configuration.pagination_number pag_loops = rooms.length / pag_num - 1 res = { recordings: [] } (0..pag_loops).each do |i| pag_rooms = rooms[pag_num * i, pag_num] # bbb.get_recordings returns an object # take only the array portion of the object that is returned full_res = bbb.get_recordings(meetingID: pag_rooms.pluck(:bbb_id)) res[:recordings].push(*full_res[:recordings]) end last_pag_room = rooms[pag_num * (pag_loops + 1), rooms.length % pag_num] full_res = bbb.get_recordings(meetingID: last_pag_room.pluck(:bbb_id)) res[:recordings].push(*full_res[:recordings]) format_recordings(res) end # Activates an account and initialize a users main room def activate update_attribute(:email_verified, true) update_attribute(:activated_at, Time.zone.now) save end def activated? return true unless Rails.configuration.enable_email_verification email_verified end def send_activation_email(url) UserMailer.verify_email(self, url).deliver end # Sets the password reset attributes. def create_reset_digest self.reset_token = User.new_token update_attribute(:reset_digest, User.digest(reset_token)) update_attribute(:reset_sent_at, Time.zone.now) end # Sends password reset email. def send_password_reset_email(url) UserMailer.password_reset(self, url).deliver_now end # Returns true if the given token matches the digest. def authenticated?(attribute, token) digest = send("#{attribute}_digest") return false if digest.nil? BCrypt::Password.new(digest).is_password?(token) end # Return true if password reset link expires def password_reset_expired? reset_sent_at < 2.hours.ago end # Retrives a list of all a users rooms that are not the main room, sorted by last session date. def secondary_rooms secondary = (rooms - [main_room]) no_session, session = secondary.partition { |r| r.last_session.nil? } sorted = session.sort_by(&:last_session) sorted + no_session end def name_chunk charset = ("a".."z").to_a - %w(b i l o s) + ("2".."9").to_a - %w(5 8) chunk = name.parameterize[0...3] if chunk.empty? chunk + (0...3).map { charset.to_a[rand(charset.size)] }.join elsif chunk.length == 1 chunk + (0...2).map { charset.to_a[rand(charset.size)] }.join elsif chunk.length == 2 chunk + (0...1).map { charset.to_a[rand(charset.size)] }.join else chunk end end def greenlight_account? return true unless provider # For testing cases when provider is set to null return provider == "greenlight" unless Rails.configuration.loadbalanced_configuration # No need to retrive the provider info if the provider is whitelisted return true if launcher_allow_user_signup_whitelisted?(provider) # Proceed with fetching the provider info provider_info = retrieve_provider_info(provider, 'api2', 'getUserGreenlightCredentials') provider_info['provider'] == 'greenlight' end def activation_token # Create the token. create_reset_activation_digest(User.new_token) end def self.digest(string) cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost BCrypt::Password.create(string, cost: cost) end # Returns a random token. def self.new_token SecureRandom.urlsafe_base64 end private def create_reset_activation_digest(token) # Create the digest and persist it. self.activation_digest = User.digest(token) save token end # Destory a users rooms when they are removed. def destroy_rooms rooms.destroy_all end # Initializes a room for the user and assign a BigBlueButton user id. def initialize_main_room self.uid = "gl-#{(0...12).map { (65 + rand(26)).chr }.join.downcase}" self.main_room = Room.create!(owner: self, name: I18n.t("home_room")) save end end