require 'bigbluebutton_api' class BigbluebuttonServer < ActiveRecord::Base include ActiveModel::ForbiddenAttributesProtection has_many :recordings, class_name: 'BigbluebuttonRecording', foreign_key: 'server_id', dependent: :destroy has_one :config, class_name: 'BigbluebuttonServerConfig', foreign_key: 'server_id', dependent: :destroy delegate :update_config, to: :config delegate :available_layouts, to: :config delegate :available_layouts_names, to: :config delegate :available_layouts_for_select, to: :config validates :name, :presence => true, :length => { :minimum => 1, :maximum => 500 } validates :url, :presence => true, :length => { :maximum => 500 }, :format => { :with => /http[s]?:\/\/.*\/bigbluebutton\/api/, :message => I18n.t('bigbluebutton_rails.servers.errors.url_format') } validates :slug, :presence => true, :uniqueness => true, :length => { :minimum => 3 }, :format => { :with => /\A[a-zA-Z\d_]+[a-zA-Z\d_-]*[a-zA-Z\d_]+\z/, :message => I18n.t('bigbluebutton_rails.servers.errors.slug_format') } validates :secret, :presence => true, :length => { :minimum => 1, :maximum => 500 } validates :version, :inclusion => { :in => ['0.8', '0.81', '0.9', '1.0'] }, :allow_blank => true # Array of BigbluebuttonMeeting attr_reader :meetings after_initialize :init before_validation :set_slug after_create :create_config after_create :update_config before_save :check_for_version_update after_update :check_for_config_update # Schedules a recording update right after a recording server is added. after_create do Resque.enqueue(::BigbluebuttonUpdateRecordingsWorker, self.id) end # In case there's no config created yet, build one. def config_with_initialize config_without_initialize || build_config(server: self) end alias_method_chain :config, :initialize # Helper to get the default server def self.default self.first end # Returns the API object (BigBlueButton::BigBlueButtonAPI defined in # bigbluebutton-api-ruby) associated with this server. def api return @api if @api.present? version = self.version version = set_api_version_from_server if version.blank? @api = BigBlueButton::BigBlueButtonApi.new(self.url, self.secret, version.to_s, BigbluebuttonRails.configuration.debug) end # Fetches the meetings currently created in the server (running or not). # # Using the response, updates meetings with a list of BigbluebuttonMeeting # objects. # # Triggers API call: getMeetings. def fetch_meetings response = self.api.get_meetings # updates the information in the rooms that are currently in BBB @meetings = [] response[:meetings].each do |attr| room = BigbluebuttonRoom.find_by(meetingid: attr[:meetingID]) # TODO: there might be more attributes returned by the API, review them all if room.nil? attrs = { meetingid: attr[:meetingID], name: attr[:meetingID], attendee_api_password: attr[:attendeePW], moderator_api_password: attr[:moderatorPW], external: true, private: true } room = BigbluebuttonRoom.new(attrs) else room.update_attributes(attendee_api_password: attr[:attendeePW], moderator_api_password: attr[:moderatorPW]) end room.running = attr[:running] room.update_current_meeting_record @meetings << room end end # Sends a call to the BBB server to publish or unpublish a recording or a set # of recordings. # ids:: IDs of the recordings that will be affected. Accepts the same format # accepted by BigBlueButtonApi::publish_recordings # publish:: Publish or unpublish the recordings? # # Triggers API call: publishRecordings. def send_publish_recordings(ids, publish) self.api.publish_recordings(ids, publish) # Update #published in all recordings ids = ids.split(",") if ids.instance_of?(String) # "id1,id2" to ["id1", "id2"] ids.each do |id| recording = BigbluebuttonRecording.find_by_recordid(id.strip) recording.update_attributes(:published => publish) unless recording.nil? end end # Sends a call to the BBB server to delete a recording or a set or recordings. # ids:: IDs of the recordings that will be affected. Accepts the same format # accepted by BigBlueButtonApi::delete_recordings # # Triggers API call: deleteRecordings. def send_delete_recordings(ids) self.api.delete_recordings(ids) end # Sends a call to the BBB server to get the list of recordings and updates # the database with these recordings. # filter:: filters to be used, uses the same format accepted by # BigBlueButtonApi::get_recordings. Can filter by meetingID and/or # metadata values. # # Triggers API call: getRecordings. def fetch_recordings(filter=nil, full_sync=false) filter ||= {} logger.info "Fetching recordings for the server #{self.inspect} with filter: #{filter.inspect}" recordings = self.api.get_recordings(filter) if recordings and recordings[:recordings] BigbluebuttonRecording.sync(self, recordings[:recordings], full_sync) end end def to_param self.slug end def set_api_version_from_server begin # creating the object with version=nil makes the gem fetch the version from the server api = BigBlueButton::BigBlueButtonApi.new(self.url, self.secret, nil, false) self.version = api.version rescue BigBlueButton::BigBlueButtonException # we just ignore errors in case the server is not responding # in these cases, the version will be fetched later on Rails.logger.error "Could not fetch the API version from the server #{self.id}. The URL probably incorrect." self.version = nil end self.version end # Returns the URL to the /check request in the server. def check_url self.api.check_url end protected def init # fetched attributes @meetings = [] end # if :slug wasn't set, sets it as :name downcase and parameterized def set_slug if self.slug.blank? self.slug = self.name.parameterize.downcase unless self.name.nil? end end def create_config BigbluebuttonServerConfig.create(server: self) end # Checks if we have to update the server version or not and do it if needed. # If the user only changes the version, we assume he's trying to force an API version. # If the user changes url/secret and the version, we also assume that he wants # to force the API version def check_for_version_update if [:url, :secret, :version].any? { |k| self.changes.key?(k) } self.set_api_version_from_server end end def check_for_config_update if [:url, :secret, :version].any?{ |k| self.changes.key?(k) } self.update_config end end end