Actualización

This commit is contained in:
Xes
2025-04-10 12:36:07 +02:00
parent 1da7c3f3b9
commit 4aff98e77b
3147 changed files with 320647 additions and 0 deletions

116
plugin/bbb/lib/VM.php Normal file
View File

@@ -0,0 +1,116 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Class VM
*/
class VM
{
protected $config;
public $virtualMachine;
/**
* VM constructor.
* @param $config
*/
public function __construct($config)
{
$this->config = $config;
}
/**
* @return array
*/
public function getConfig()
{
return $this->config;
}
/**
* @param bool $checkEnabled Check if, additionnally to being installed, the plugin is enabled
* @return bool
*/
public function isEnabled(bool $checkEnabled = false): bool
{
$config = $this->getConfig();
if (!isset($config)) {
return false;
}
if (!is_array($config)) {
return false;
}
if (isset($config['enabled']) && $config['enabled']) {
return true;
}
return false;
}
/**
* @return VirtualMachineInterface
*/
public function getVirtualMachine()
{
return $this->virtualMachine;
}
/**
* @param VirtualMachineInterface $virtualMachine
*/
public function setVirtualMachine(VirtualMachineInterface $virtualMachine)
{
$this->virtualMachine = $virtualMachine;
}
/**
* @return VirtualMachineInterface
*/
public function getVirtualMachineFromConfig()
{
$vmList = $this->config['vms'];
foreach ($vmList as $vm) {
if (isset($vm['enabled']) && $vm['enabled'] == true) {
$className = $vm['name'].'VM';
return new $className($vm);
break;
}
}
return false;
}
/**
* Resize the VM to the max size
*/
public function resizeToMaxLimit()
{
$virtualMachine = $this->getVirtualMachineFromConfig();
$this->setVirtualMachine($virtualMachine);
$virtualMachine->resizeToMaxLimit();
}
/**
* Resize the VM to the min size
*/
public function resizeToMinLimit()
{
$virtualMachine = $this->getVirtualMachineFromConfig();
$this->setVirtualMachine($virtualMachine);
$virtualMachine->resizeToMinLimit();
}
public function runCron()
{
$virtualMachine = $this->getVirtualMachineFromConfig();
$this->setVirtualMachine($virtualMachine);
$virtualMachine->runCron();
}
}

2227
plugin/bbb/lib/bbb.lib.php Normal file

File diff suppressed because it is too large Load Diff

697
plugin/bbb/lib/bbb_api.php Normal file
View File

@@ -0,0 +1,697 @@
<?php
/*
Copyright 2010 Blindside Networks
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Versions:
1.0 -- Initial version written by DJP
(email: djp [a t ] architectes DOT .org)
1.1 -- Updated by Omar Shammas and Sebastian Schneider
(email : omar DOT shammas [a t ] g m ail DOT com)
(email : seb DOT sschneider [ a t ] g m ail DOT com)
1.2 -- Updated by Omar Shammas
(email : omar DOT shammas [a t ] g m ail DOT com)
1.3 -- Refactored by Peter Mentzer
(email : peter@petermentzerdesign.com)
- This update will BREAK your external existing code if
you've used the previous versions <= 1.2 already so:
-- update your external code to use new method names if needed
-- update your external code to pass new parameters to methods
- Working example of joinIfRunning.php now included
- Added support for BBB 0.8b recordings
- Now using Zend coding, naming and style conventions
- Refactored methods to accept standardized parameters & match BBB API structure
-- See included samples for usage examples
*/
class BigBlueButtonBN
{
private $_securitySalt;
private $_bbbServerBaseUrl;
private $_bbbServerProtocol;
public function __construct()
{
/*
Establish just our basic elements in the constructor:
*/
// BASE CONFIGS - set these for your BBB server in config.php and they will
// simply flow in here via the constants:
$this->_securitySalt = CONFIG_SECURITY_SALT;
$this->_bbbServerBaseUrl = CONFIG_SERVER_BASE_URL;
$this->_bbbServerProtocol = CONFIG_SERVER_PROTOCOL;
}
private function _processXmlResponse($url)
{
/*
A private utility method used by other public methods to process XML responses.
*/
if (extension_loaded('curl')) {
$ch = curl_init() or die ( curl_error($ch) );
$timeout = 10;
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt( $ch, CURLOPT_URL, $this->_bbbServerProtocol.$url );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, $timeout);
// Following redirect required to use Scalelite, BBB's Load Balancer
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true);
$data = curl_exec( $ch );
curl_close( $ch );
if ($data) {
return (new SimpleXMLElement($data));
} else {
return false;
}
}
return (simplexml_load_file($url));
}
private function _requiredParam($param) {
/* Process required params and throw errors if we don't get values */
if ((isset($param)) && ($param != '')) {
return $param;
}
elseif (!isset($param)) {
throw new Exception('Missing parameter.');
}
else {
throw new Exception(''.$param.' is required.');
}
}
private function _optionalParam($param) {
/* Pass most optional params through as set value, or set to '' */
/* Don't know if we'll use this one, but let's build it in case. */
if ((isset($param)) && ($param != '')) {
return $param;
}
else {
$param = '';
return $param;
}
}
/* __________________ BBB ADMINISTRATION METHODS _________________ */
/* The methods in the following section support the following categories of the BBB API:
-- create
-- join
-- end
*/
public function getCreateMeetingUrl($creationParams) {
/*
USAGE:
(see $creationParams array in createMeetingArray method.)
*/
$this->_meetingId = $this->_requiredParam($creationParams['meetingId']);
$this->_meetingName = $this->_requiredParam($creationParams['meetingName']);
// Set up the basic creation URL:
$creationUrl = $this->_bbbServerBaseUrl."api/create?";
// Add params:
$params =
'name='.urlencode($this->_meetingName).
'&meetingID='.urlencode($this->_meetingId).
'&attendeePW='.urlencode($creationParams['attendeePw']).
'&moderatorPW='.urlencode($creationParams['moderatorPw']).
'&dialNumber='.urlencode($creationParams['dialNumber']).
'&voiceBridge='.urlencode($creationParams['voiceBridge']).
'&webVoice='.urlencode($creationParams['webVoice']).
'&logoutURL='.urlencode($creationParams['logoutUrl']).
'&maxParticipants='.urlencode($creationParams['maxParticipants']).
'&record='.urlencode($creationParams['record']).
'&duration='.urlencode($creationParams['duration']).
'&meta_OriginURL'.urlencode($creationParams['meta_OriginURL'])
;
//'&meta_category='.urlencode($creationParams['meta_category']);
$welcomeMessage = $creationParams['welcomeMsg'];
if (trim($welcomeMessage)) {
$params .= '&welcome='.urlencode($welcomeMessage);
}
// Return the complete URL:
return ($creationUrl.$params.'&checksum='.sha1("create".$params.$this->_securitySalt));
}
public function createMeetingWithXmlResponseArray($creationParams)
{
/*
USAGE:
$creationParams = array(
'name' => 'Meeting Name', -- A name for the meeting (or username)
'meetingId' => '1234', -- A unique id for the meeting
'attendeePw' => 'ap', -- Set to 'ap' and use 'ap' to join = no user pass required.
'moderatorPw' => 'mp', -- Set to 'mp' and use 'mp' to join = no user pass required.
'welcomeMsg' => '', -- ''= use default. Change to customize.
'dialNumber' => '', -- The main number to call into. Optional.
'voiceBridge' => '', -- 5 digits PIN to join voice. Required.
'webVoice' => '', -- Alphanumeric to join voice. Optional.
'logoutUrl' => '', -- Default in bigbluebutton.properties. Optional.
'maxParticipants' => '-1', -- Optional. -1 = unlimitted. Not supported in BBB. [number]
'record' => 'false', -- New. 'true' will tell BBB to record the meeting.
'duration' => '0', -- Default = 0 which means no set duration in minutes. [number]
'meta_category' => '', -- Use to pass additional info to BBB server. See API docs to enable.
);
*/
$xml = $this->_processXmlResponse($this->getCreateMeetingURL($creationParams));
if ($xml) {
if ($xml->meetingID) {
return [
'returncode' => $xml->returncode->__toString(),
'message' => $xml->message->__toString(),
'messageKey' => $xml->messageKey->__toString(),
'meetingId' => $xml->meetingID->__toString(),
'attendeePw' => $xml->attendeePW->__toString(),
'moderatorPw' => $xml->moderatorPW->__toString(),
'hasBeenForciblyEnded' => $xml->hasBeenForciblyEnded->__toString(),
'createTime' => $xml->createTime->__toString(),
'internalMeetingID' => $xml->internalMeetingID->__toString(),
];
} else {
return [
'returncode' => $xml->returncode->__toString(),
'message' => $xml->message->__toString(),
'messageKey' => $xml->messageKey->__toString(),
];
}
} else {
return null;
}
}
public function getJoinMeetingURL($joinParams)
{
/*
NOTE: At this point, we don't use a corresponding joinMeetingWithXmlResponse here because the API
doesn't respond on success, but you can still code that method if you need it. Or, you can take the URL
that's returned from this method and simply send your users off to that URL in your code.
USAGE:
$joinParams = array(
'meetingId' => '1234', -- REQUIRED - A unique id for the meeting
'username' => 'Jane Doe', -- REQUIRED - The name that will display for the user in the meeting
'password' => 'ap', -- REQUIRED - The attendee or moderator password, depending on what's passed here
'createTime' => '', -- OPTIONAL - string. Leave blank ('') unless you set this correctly.
'userID' => '', -- OPTIONAL - string
'webVoiceConf' => '' -- OPTIONAL - string
);
*/
$this->_meetingId = $this->_requiredParam($joinParams['meetingId']);
$this->_username = $this->_requiredParam($joinParams['username']);
$this->_password = $this->_requiredParam($joinParams['password']);
// Establish the basic join URL:
$joinUrl = $this->_bbbServerBaseUrl."api/join?";
// Add parameters to the URL:
$params =
'meetingID='.urlencode($this->_meetingId).
'&fullName='.urlencode($this->_username).
'&password='.urlencode($this->_password).
'&userID='.urlencode($joinParams['userID']).
'&webVoiceConf='.urlencode($joinParams['webVoiceConf'])
;
// Only use createTime if we really want to use it. If it's '', then don't pass it:
if ((isset($joinParams['createTime']) && $joinParams['createTime'] != '')) {
$params .= '&createTime='.urlencode($joinParams['createTime']);
}
/*if (isset($joinParams['interface']) && (int) $joinParams['interface'] === BBBPlugin::INTERFACE_HTML5) {
$bbbHost = api_remove_trailing_slash(CONFIG_SERVER_URL_WITH_PROTOCOL);
if (preg_match('#/bigbluebutton$#', $bbbHost)) {
$bbbHost = preg_replace('#/bigbluebutton$#', '', $bbbHost);
}
$params .= '&redirectClient=true&clientURL='.$bbbHost.'/html5client/join';
}*/
// Return the URL:
return $joinUrl.$params.'&checksum='.sha1('join'.$params.$this->_securitySalt);
}
public function getEndMeetingURL($endParams)
{
/* USAGE:
$endParams = array (
'meetingId' => '1234', -- REQUIRED - The unique id for the meeting
'password' => 'mp' -- REQUIRED - The moderator password for the meeting
);
*/
$this->_meetingId = $this->_requiredParam($endParams['meetingId']);
$this->_password = $this->_requiredParam($endParams['password']);
$endUrl = $this->_bbbServerBaseUrl."api/end?";
$params =
'meetingID='.urlencode($this->_meetingId).
'&password='.urlencode($this->_password)
;
return ($endUrl.$params.'&checksum='.sha1("end".$params.$this->_securitySalt));
}
public function endMeetingWithXmlResponseArray($endParams) {
/* USAGE:
$endParams = array (
'meetingId' => '1234', -- REQUIRED - The unique id for the meeting
'password' => 'mp' -- REQUIRED - The moderator password for the meeting
);
*/
$xml = $this->_processXmlResponse($this->getEndMeetingURL($endParams));
if ($xml) {
return array(
'returncode' => $xml->returncode->__toString(),
'message' => $xml->message->__toString(),
'messageKey' => $xml->messageKey->__toString()
);
}
else {
return null;
}
}
/* __________________ BBB MONITORING METHODS _________________ */
/* The methods in the following section support the following categories of the BBB API:
-- isMeetingRunning
-- getMeetings
-- getMeetingInfo
*/
public function getIsMeetingRunningUrl($meetingId) {
/* USAGE:
$meetingId = '1234' -- REQUIRED - The unique id for the meeting
*/
$this->_meetingId = $this->_requiredParam($meetingId);
$runningUrl = $this->_bbbServerBaseUrl."api/isMeetingRunning?";
$params =
'meetingID='.urlencode($this->_meetingId);
return ($runningUrl.$params.'&checksum='.sha1("isMeetingRunning".$params.$this->_securitySalt));
}
public function isMeetingRunningWithXmlResponseArray($meetingId) {
/* USAGE:
$meetingId = '1234' -- REQUIRED - The unique id for the meeting
*/
$xml = $this->_processXmlResponse($this->getIsMeetingRunningUrl($meetingId));
if($xml) {
return array(
'returncode' => $xml->returncode->__toString(),
'running' => $xml->running->__toString() // -- Returns true/false.
);
}
else {
return null;
}
}
public function getGetMeetingsUrl() {
/* Simply formulate the getMeetings URL
We do this in a separate function so we have the option to just get this
URL and print it if we want for some reason.
*/
$getMeetingsUrl = $this->_bbbServerBaseUrl."api/getMeetings?checksum=".sha1("getMeetings".$this->_securitySalt);
return $getMeetingsUrl;
}
public function getMeetingsWithXmlResponseArray()
{
/* USAGE:
We don't need to pass any parameters with this one, so we just send the query URL off to BBB
and then handle the results that we get in the XML response.
*/
$xml = $this->_processXmlResponse($this->getGetMeetingsUrl());
if($xml) {
// If we don't get a success code, stop processing and return just the returncode:
if ($xml->returncode != 'SUCCESS') {
$result = array(
'returncode' => $xml->returncode->__toString()
);
return $result;
}
elseif ($xml->messageKey == 'noMeetings') {
/* No meetings on server, so return just this info: */
$result = array(
'returncode' => $xml->returncode->__toString(),
'messageKey' => $xml->messageKey->__toString(),
'message' => $xml->message->__toString()
);
return $result;
}
else {
// In this case, we have success and meetings. First return general response:
$result = array(
'returncode' => $xml->returncode->__toString(),
'messageKey' => $xml->messageKey->__toString(),
'message' => $xml->message->__toString()
);
// Then interate through meeting results and return them as part of the array:
foreach ($xml->meetings->meeting as $m) {
$result[] = array(
'meetingId' => $m->meetingID->__toString(),
'meetingName' => $m->meetingName->__toString(),
'createTime' => $m->createTime->__toString(),
'attendeePw' => $m->attendeePW->__toString(),
'moderatorPw' => $m->moderatorPW->__toString(),
'hasBeenForciblyEnded' => $m->hasBeenForciblyEnded->__toString(),
'running' => $m->running->__toString()
);
}
return $result;
}
}
else {
return null;
}
}
public function getMeetingInfoUrl($infoParams) {
/* USAGE:
$infoParams = array(
'meetingId' => '1234', -- REQUIRED - The unique id for the meeting
'password' => 'mp' -- REQUIRED - The moderator password for the meeting
);
*/
$this->_meetingId = $this->_requiredParam($infoParams['meetingId']);
$this->_password = $this->_requiredParam($infoParams['password']);
$infoUrl = $this->_bbbServerBaseUrl."api/getMeetingInfo?";
$params =
'meetingID='.urlencode($this->_meetingId).
'&password='.urlencode($this->_password);
return ($infoUrl.$params.'&checksum='.sha1("getMeetingInfo".$params.$this->_securitySalt));
}
public function getMeetingInfoWithXmlResponseArray($infoParams) {
/* USAGE:
$infoParams = array(
'meetingId' => '1234', -- REQUIRED - The unique id for the meeting
'password' => 'mp' -- REQUIRED - The moderator password for the meeting
);
*/
$xml = $this->_processXmlResponse($this->getMeetingInfoUrl($infoParams));
if($xml) {
// If we don't get a success code or messageKey, find out why:
if (($xml->returncode != 'SUCCESS') || ($xml->messageKey == null)) {
$result = array(
'returncode' => $xml->returncode->__toString(),
'messageKey' => $xml->messageKey->__toString(),
'message' => $xml->message->__toString()
);
return $result;
} else {
// In this case, we have success and meeting info:
$result = array(
'returncode' => $xml->returncode->__toString(),
'meetingName' => $xml->meetingName->__toString(),
'meetingId' => $xml->meetingID->__toString(),
'createTime' => $xml->createTime->__toString(),
'voiceBridge' => $xml->voiceBridge->__toString(),
'attendeePw' => $xml->attendeePW->__toString(),
'moderatorPw' => $xml->moderatorPW->__toString(),
'running' => $xml->running->__toString(),
'recording' => $xml->recording->__toString(),
'hasBeenForciblyEnded' => $xml->hasBeenForciblyEnded->__toString(),
'startTime' => $xml->startTime->__toString(),
'endTime' => $xml->endTime->__toString(),
'participantCount' => $xml->participantCount->__toString(),
'maxUsers' => $xml->maxUsers->__toString(),
'moderatorCount' => $xml->moderatorCount->__toString(),
'internalMeetingID' => $xml->internalMeetingID->__toString()
);
// Then interate through attendee results and return them as part of the array:
foreach ($xml->attendees->attendee as $a) {
$result[] = array(
'userId' => $a->userID->__toString(),
'fullName' => $a->fullName->__toString(),
'role' => $a->role->__toString()
);
}
return $result;
}
}
else {
return null;
}
}
/* __________________ BBB RECORDING METHODS _________________ */
/* The methods in the following section support the following categories of the BBB API:
-- getRecordings
-- publishRecordings
-- deleteRecordings
*/
public function getRecordingsUrl($recordingParams) {
/* USAGE:
$recordingParams = array(
'meetingId' => '1234', -- OPTIONAL - comma separate if multiple ids
);
*/
$recordingsUrl = $this->_bbbServerBaseUrl."api/getRecordings?";
$params = 'meetingID='.urlencode($recordingParams['meetingId']);
return ($recordingsUrl.$params.'&checksum='.sha1("getRecordings".$params.$this->_securitySalt));
}
public function getRecordingsWithXmlResponseArray($recordingParams) {
/* USAGE:
$recordingParams = array(
'meetingId' => '1234', -- OPTIONAL - comma separate if multiple ids
);
NOTE: 'duration' DOES work when creating a meeting, so if you set duration
when creating a meeting, it will kick users out after the duration. Should
probably be required in user code when 'recording' is set to true.
*/
$xml = $this->_processXmlResponse($this->getRecordingsUrl($recordingParams));
if($xml) {
// If we don't get a success code or messageKey, find out why:
if (($xml->returncode != 'SUCCESS') || ($xml->messageKey == null)) {
$result = array(
'returncode' => $xml->returncode->__toString(),
'messageKey' => $xml->messageKey->__toString(),
'message' => $xml->message->__toString()
);
return $result;
}
else {
// In this case, we have success and recording info:
$result = array(
'returncode' => $xml->returncode->__toString(),
'messageKey' => $xml->messageKey->__toString(),
'message' => $xml->message->__toString()
);
$formats = [];
foreach ($xml->recordings->recording as $r) {
foreach ($r->playback->format as $format) {
$formats[] = $format;
}
$result[] = array(
'recordId' => $r->recordID->__toString(),
'meetingId' => $r->meetingID->__toString(),
'name' => $r->name->__toString(),
'published' => $r->published->__toString(),
'startTime' => $r->startTime->__toString(),
'endTime' => $r->endTime->__toString(),
'playbackFormat' => $formats,
'playbackFormatType' => $r->playback->format->type->__toString(),
'playbackFormatUrl' => $r->playback->format->url->__toString(),
'playbackFormatLength' => $r->playback->format->length->__toString(),
'metadataTitle' => $r->metadata->title->__toString(),
'metadataSubject' => $r->metadata->subject->__toString(),
'metadataDescription' => $r->metadata->description->__toString(),
'metadataCreator' => $r->metadata->creator->__toString(),
'metadataContributor' => $r->metadata->contributor->__toString(),
'metadataLanguage' => $r->metadata->language->__toString(),
// Add more here as needed for your app depending on your
// use of metadata when creating recordings.
);
}
return $result;
}
}
else {
return null;
}
}
/**
* @param $array recordingParams
*
* @return array|null
*/
public function getRecordings($recordingParams)
{
/* USAGE:
$recordingParams = array(
'meetingId' => '1234', -- OPTIONAL - comma separate if multiple ids
);
NOTE: 'duration' DOES work when creating a meeting, so if you set duration
when creating a meeting, it will kick users out after the duration. Should
probably be required in user code when 'recording' is set to true.
*/
$xml = $this->_processXmlResponse($this->getRecordingsUrl($recordingParams));
if($xml) {
// If we don't get a success code or messageKey, find out why:
if (($xml->returncode != 'SUCCESS') || ($xml->messageKey == null)) {
$result = array(
'returncode' => $xml->returncode->__toString(),
'messageKey' => $xml->messageKey->__toString(),
'message' => $xml->message->__toString()
);
return $result;
}
else {
// In this case, we have success and recording info:
$result = array(
'returncode' => $xml->returncode->__toString(),
'messageKey' => $xml->messageKey->__toString(),
'message' => $xml->message->__toString()
);
$result['records'] = [];
if (!empty($xml->recordings->recording)) {
$formats = [];
foreach ($xml->recordings->recording as $r) {
foreach ($r->playback->format as $format) {
$formats[] = $format;
}
$result['records'][] = array(
'recordId' => $r->recordID->__toString(),
'meetingId' => $r->meetingID->__toString(),
'name' => $r->name->__toString(),
'published' => $r->published->__toString(),
'startTime' => $r->startTime->__toString(),
'endTime' => $r->endTime->__toString(),
'playbackFormat' => $formats,
'playbackFormatType' => $r->playback->format->type->__toString(),
'playbackFormatUrl' => $r->playback->format->url->__toString(),
'playbackFormatLength' => $r->playback->format->length->__toString(),
'metadataTitle' => $r->metadata->title->__toString(),
'metadataSubject' => $r->metadata->subject->__toString(),
'metadataDescription' => $r->metadata->description->__toString(),
'metadataCreator' => $r->metadata->creator->__toString(),
'metadataContributor' => $r->metadata->contributor->__toString(),
'metadataLanguage' => $r->metadata->language->__toString(),
);
}
}
return $result;
}
}
return null;
}
public function getPublishRecordingsUrl($recordingParams) {
/* USAGE:
$recordingParams = array(
'recordId' => '1234', -- REQUIRED - comma separate if multiple ids
'publish' => 'true', -- REQUIRED - boolean: true/false
);
*/
$recordingsUrl = $this->_bbbServerBaseUrl."api/publishRecordings?";
$params =
'recordID='.urlencode($recordingParams['recordId']).
'&publish='.urlencode($recordingParams['publish']);
return ($recordingsUrl.$params.'&checksum='.sha1("publishRecordings".$params.$this->_securitySalt));
}
public function publishRecordingsWithXmlResponseArray($recordingParams) {
/* USAGE:
$recordingParams = array(
'recordId' => '1234', -- REQUIRED - comma separate if multiple ids
'publish' => 'true', -- REQUIRED - boolean: true/false
);
*/
$xml = $this->_processXmlResponse($this->getPublishRecordingsUrl($recordingParams));
if($xml) {
return array(
'returncode' => $xml->returncode->__toString(),
'published' => $xml->published->__toString() // -- Returns true/false.
);
}
else {
return null;
}
}
public function getDeleteRecordingsUrl($recordingParams) {
/* USAGE:
$recordingParams = array(
'recordId' => '1234', -- REQUIRED - comma separate if multiple ids
);
*/
$recordingsUrl = $this->_bbbServerBaseUrl."api/deleteRecordings?";
$params =
'recordID='.urlencode($recordingParams['recordId']);
return ($recordingsUrl.$params.'&checksum='.sha1("deleteRecordings".$params.$this->_securitySalt));
}
public function deleteRecordingsWithXmlResponseArray($recordingParams) {
/* USAGE:
$recordingParams = array(
'recordId' => '1234', -- REQUIRED - comma separate if multiple ids
);
*/
$xml = $this->_processXmlResponse($this->getDeleteRecordingsUrl($recordingParams));
if($xml) {
return array(
'returncode' => $xml->returncode->__toString(),
'deleted' => $xml->deleted->__toString() // -- Returns true/false.
);
}
else {
return null;
}
}
/** USAGE:
* $recordingParams = array(
* 'recordId' => '1234', -- REQUIRED - comma separate if multiple ids
* );
*/
public function generateRecording($recordingParams)
{
if (empty($recordingParams)) {
return false;
}
$recordingsUrl = $this->_bbbServerBaseUrl.'../demo/regenerateRecord.jsp?';
$params = 'recordID='.urlencode($recordingParams['recordId']);
$url = $recordingsUrl.$params.'&checksum='.sha1('regenerateRecord'.$params.$this->_securitySalt);
$ch = curl_init() or die ( curl_error($ch) );
$timeout = 10;
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt( $ch, CURLOPT_URL, $url );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, $timeout);
$data = curl_exec( $ch );
curl_close( $ch );
return true;
}
}

View File

@@ -0,0 +1,407 @@
<?php
/* For licensing terms, see /license.txt */
/* To show the plugin course icons you need to add these icons:
* main/img/icons/22/plugin_name.png
* main/img/icons/64/plugin_name.png
* main/img/icons/64/plugin_name_na.png
*/
/**
* Videoconference plugin with BBB
*/
class BBBPlugin extends Plugin
{
const ROOM_OPEN = 0;
const ROOM_CLOSE = 1;
const ROOM_CHECK = 2;
public $isCoursePlugin = true;
// When creating a new course this settings are added to the course
public $course_settings = [
[
'name' => 'big_blue_button_record_and_store',
'type' => 'checkbox',
],
[
'name' => 'bbb_enable_conference_in_groups',
'type' => 'checkbox',
],
[
'name' => 'bbb_force_record_generation',
'type' => 'checkbox',
],
[
'name' => 'big_blue_button_students_start_conference_in_groups',
'type' => 'checkbox',
],
];
/**
* BBBPlugin constructor.
*/
protected function __construct()
{
$settings = [
'tool_enable' => 'boolean',
'host' => 'text',
'salt' => 'text',
'enable_global_conference' => 'boolean',
'enable_global_conference_per_user' => 'boolean',
'enable_conference_in_course_groups' => 'boolean',
'enable_global_conference_link' => 'boolean',
'disable_download_conference_link' => 'boolean',
'max_users_limit' => 'text',
'global_conference_allow_roles' => [
'type' => 'select',
'options' => [
PLATFORM_ADMIN => get_lang('Administrator'),
COURSEMANAGER => get_lang('Teacher'),
STUDENT => get_lang('Student'),
STUDENT_BOSS => get_lang('StudentBoss'),
],
'attributes' => ['multiple' => 'multiple'],
],
'allow_regenerate_recording' => 'boolean',
// Default course settings, must be the same as $course_settings
'big_blue_button_record_and_store' => 'checkbox',
'bbb_enable_conference_in_groups' => 'checkbox',
'bbb_force_record_generation' => 'checkbox',
'disable_course_settings' => 'boolean',
'meeting_duration' => 'text',
];
if (1 === (int) api_get_current_access_url_id()) {
$settings['plugin_bbb_multiple_urls_cron_apply_to_all'] = 'checkbox';
}
parent::__construct(
'2.11',
'Julio Montoya, Yannick Warnier, Angel Fernando Quiroz Campos, Jose Angel Ruiz, Ghazi Triki, Adnen Manssouri',
$settings
);
$this->isAdminPlugin = true;
}
/**
* @return BBBPlugin|null
*/
public static function create()
{
static $result = null;
return $result ? $result : $result = new self();
}
/**
* @param string $variable
*
* @return bool
*/
public function validateCourseSetting($variable)
{
if ($this->get('disable_course_settings') === 'true') {
return false;
}
$result = true;
switch ($variable) {
case 'bbb_enable_conference_in_groups':
$result = $this->get('enable_conference_in_course_groups') === 'true';
break;
case 'bbb_force_record_generation':
$result = $this->get('allow_regenerate_recording') === 'true';
break;
case 'big_blue_button_record_and_store':
}
return $result;
}
/**
*
* @return array
*/
public function getCourseSettings()
{
$settings = [];
if ($this->get('disable_course_settings') !== 'true') {
$settings = parent::getCourseSettings();
}
return $settings;
}
/**
*
* @return \Plugin
*/
public function performActionsAfterConfigure()
{
$result = $this->get('disable_course_settings') === 'true';
if ($result) {
$valueConference = $this->get('bbb_enable_conference_in_groups') === 'true' ? 1 : 0;
self::update_course_field_in_all_courses('bbb_enable_conference_in_groups', $valueConference);
$valueForceRecordGeneration = $this->get('bbb_force_record_generation') === 'true' ? 1 : 0;
self::update_course_field_in_all_courses('bbb_force_record_generation', $valueForceRecordGeneration);
$valueForceRecordStore = $this->get('big_blue_button_record_and_store') === 'true' ? 1 : 0;
self::update_course_field_in_all_courses('big_blue_button_record_and_store', $valueForceRecordStore);
}
return $this;
}
/**
* Install
*/
public function install()
{
$sql = "CREATE TABLE IF NOT EXISTS plugin_bbb_meeting (
id INT unsigned NOT NULL auto_increment PRIMARY KEY,
c_id INT unsigned NOT NULL DEFAULT 0,
group_id INT unsigned NOT NULL DEFAULT 0,
user_id INT unsigned NOT NULL DEFAULT 0,
meeting_name VARCHAR(255) NOT NULL DEFAULT '',
attendee_pw VARCHAR(255) NOT NULL DEFAULT '',
moderator_pw VARCHAR(255) NOT NULL DEFAULT '',
record INT NOT NULL DEFAULT 0,
status INT NOT NULL DEFAULT 0,
created_at VARCHAR(255) NOT NULL,
closed_at VARCHAR(255) NOT NULL,
calendar_id INT DEFAULT 0,
welcome_msg VARCHAR(255) NOT NULL DEFAULT '',
session_id INT unsigned DEFAULT 0,
remote_id CHAR(30),
internal_meeting_id VARCHAR(255) DEFAULT NULL,
visibility TINYINT NOT NULL DEFAULT 1,
voice_bridge INT NOT NULL DEFAULT 1,
access_url INT NOT NULL DEFAULT 1,
video_url TEXT NULL,
has_video_m4v TINYINT NOT NULL DEFAULT 0
)";
Database::query($sql);
Database::query(
"CREATE TABLE IF NOT EXISTS plugin_bbb_room (
id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
meeting_id int NOT NULL,
participant_id int(11) NOT NULL,
in_at datetime,
out_at datetime,
close INT NOT NULL DEFAULT 0
);"
);
$fieldLabel = 'plugin_bbb_course_users_limit';
$fieldType = ExtraField::FIELD_TYPE_INTEGER;
$fieldTitle = $this->get_lang('MaxUsersInConferenceRoom');
$fieldDefault = '0';
$extraField = new ExtraField('course');
$fieldId = CourseManager::create_course_extra_field(
$fieldLabel,
$fieldType,
$fieldTitle,
$fieldDefault
);
$extraField->find($fieldId);
$extraField->update(
[
'id' => $fieldId,
'variable' => 'plugin_bbb_course_users_limit',
'changeable' => 1,
'visible_to_self' => 1,
'visible_to_others' => 0,
]
);
$fieldLabel = 'plugin_bbb_session_users_limit';
$extraField = new ExtraField('session');
$fieldId = SessionManager::create_session_extra_field(
$fieldLabel,
$fieldType,
$fieldTitle,
$fieldDefault
);
$extraField->find($fieldId);
$extraField->update(
[
'id' => $fieldId,
'variable' => 'plugin_bbb_session_users_limit',
'changeable' => 1,
'visible_to_self' => 1,
'visible_to_others' => 0,
]
);
Database::query(
"CREATE TABLE IF NOT EXISTS plugin_bbb_meeting_format (
id int unsigned not null PRIMARY KEY AUTO_INCREMENT,
meeting_id int unsigned not null,
format_type varchar(255) not null,
resource_url text not null
);"
);
// Copy icons into the main/img/icons folder
$iconName = 'bigbluebutton';
$iconsList = [
'64/'.$iconName.'.png',
'64/'.$iconName.'_na.png',
'32/'.$iconName.'.png',
'32/'.$iconName.'_na.png',
'22/'.$iconName.'.png',
'22/'.$iconName.'_na.png',
];
$sourceDir = api_get_path(SYS_PLUGIN_PATH).'bbb/resources/img/';
$destinationDir = api_get_path(SYS_CODE_PATH).'img/icons/';
foreach ($iconsList as $icon) {
$src = $sourceDir.$icon;
$dest = $destinationDir.$icon;
copy($src, $dest);
}
// Installing course settings
$this->install_course_fields_in_all_courses(true);
}
/**
* Uninstall
*/
public function uninstall()
{
$t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
$t_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
$t_tool = Database::get_course_table(TABLE_TOOL_LIST);
$variables = [
'bbb_salt',
'bbb_host',
'bbb_tool_enable',
'enable_global_conference',
'enable_global_conference_per_user',
'enable_global_conference_link',
'disable_download_conference_link',
'enable_conference_in_course_groups',
'bbb_plugin',
'bbb_plugin_host',
'bbb_plugin_salt',
'max_users_limit',
'global_conference_allow_roles'
];
$urlId = api_get_current_access_url_id();
foreach ($variables as $variable) {
$sql = "DELETE FROM $t_settings WHERE variable = '$variable' AND access_url = $urlId";
Database::query($sql);
}
$em = Database::getManager();
$sm = $em->getConnection()->getSchemaManager();
if ($sm->tablesExist('plugin_bbb_meeting')) {
Database::query("DELETE FROM plugin_bbb_meeting WHERE access_url = $urlId");
}
// Only delete tables if it's uninstalled from main url.
if (1 == $urlId) {
$extraField = new ExtraField('course');
$extraFieldInfo = $extraField->get_handler_field_info_by_field_variable(
'plugin_bbb_course_users_limit'
);
if (!empty($extraFieldInfo)) {
$extraField->delete($extraFieldInfo['id']);
}
$extraField = new ExtraField('session');
$extraFieldInfo = $extraField->get_handler_field_info_by_field_variable(
'plugin_bbb_session_users_limit'
);
if (!empty($extraFieldInfo)) {
$extraField->delete($extraFieldInfo['id']);
}
$sql = "DELETE FROM $t_options WHERE variable = 'bbb_plugin'";
Database::query($sql);
// hack to get rid of Database::query warning (please add c_id...)
$sql = "DELETE FROM $t_tool WHERE name = 'bbb' AND c_id != 0";
Database::query($sql);
if ($sm->tablesExist('plugin_bbb_meeting_format')) {
Database::query('DROP TABLE IF EXISTS plugin_bbb_meeting_format');
}
if ($sm->tablesExist('plugin_bbb_room')) {
Database::query('DROP TABLE IF EXISTS plugin_bbb_room');
}
if ($sm->tablesExist('plugin_bbb_meeting')) {
Database::query('DROP TABLE IF EXISTS plugin_bbb_meeting');
}
// Deleting course settings
$this->uninstall_course_fields_in_all_courses($this->course_settings);
// Remove icons from the main/img/icons folder
$iconName = 'bigbluebutton';
$iconsList = [
'64/'.$iconName.'.png',
'64/'.$iconName.'_na.png',
'32/'.$iconName.'.png',
'32/'.$iconName.'_na.png',
'22/'.$iconName.'.png',
'22/'.$iconName.'_na.png',
];
$destinationDir = api_get_path(SYS_CODE_PATH).'img/icons/';
foreach ($iconsList as $icon) {
$dest = $destinationDir.$icon;
if (is_file($dest)) {
@unlink($dest);
}
}
}
}
/**
* Update
*/
public function update()
{
$sql = "SHOW COLUMNS FROM plugin_bbb_room WHERE Field = 'close'";
$res = Database::query($sql);
if (Database::num_rows($res) === 0) {
$sql = "ALTER TABLE plugin_bbb_room ADD close int unsigned NULL";
$res = Database::query($sql);
if (!$res) {
echo Display::return_message($this->get_lang('ErrorUpdateFieldDB'), 'warning');
}
Database::update(
'plugin_bbb_room',
['close' => BBBPlugin::ROOM_CLOSE]
);
}
}
/**
* Set the course setting in all courses
*
* @param bool $variable Course setting to update
* @param bool $value New values of the course setting
*/
public function update_course_field_in_all_courses($variable, $value)
{
// Update existing courses to add the new course setting value
$table = Database::get_main_table(TABLE_MAIN_COURSE);
$sql = "SELECT id FROM $table ORDER BY id";
$res = Database::query($sql);
$courseSettingTable = Database::get_course_table(TABLE_COURSE_SETTING);
while ($row = Database::fetch_assoc($res)) {
Database::update(
$courseSettingTable,
['value' => $value],
['variable = ? AND c_id = ?' => [$variable, $row['id']]]
);
}
}
}

View File

@@ -0,0 +1,50 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Class AbstractVM
*/
abstract class AbstractVM
{
public $name;
public $host;
public $user;
public $vmId;
public $vmMinSize;
public $vmMaxSize;
public $apiKey;
public $vmClientId;
public $messages = array();
protected $connector;
/**
* @param array $settings
*/
public function __construct($settings)
{
$this->name = $settings['name'];
$this->host = $settings['host'];
$this->user = $settings['user'];
$this->apiKey = $settings['api_key'];
$this->vmId = $settings['vm_id'];
$this->vmMinSize = $settings['vm_min_size_id'];
$this->vmMaxSize = $settings['vm_max_size_id'];
$this->vmClientId = $settings['vm_client_id'];
}
/**
* @param string $message
*/
public function addMessage($message)
{
$this->messages[] = $message;
}
/**
* @return string
*/
public function getMessageToString()
{
return implode(PHP_EOL, $this->messages);
}
}

View File

@@ -0,0 +1,44 @@
<?php
/* For licensing terms, see /license.txt */
use DigitalOcean\DigitalOcean;
use DigitalOcean\Credentials;
/**
* Class AmazonVM
*/
class AmazonVM extends AbstractVM implements VirtualMachineInterface
{
/**
* @inheritdoc
*/
public function connect()
{
}
/**
* @inheritdoc
*/
public function runCron()
{
}
/**
* @inheritdoc
*/
public function resizeToMaxLimit()
{
}
/**
* @inheritdoc
*/
public function resizeToMinLimit()
{
}
}

View File

@@ -0,0 +1,180 @@
<?php
/* For licensing terms, see /license.txt */
use DigitalOcean\DigitalOcean;
use DigitalOcean\Credentials;
/**
* Class DigitalOceanVM
*/
class DigitalOceanVM extends AbstractVM implements VirtualMachineInterface
{
/**
*
*/
public function __construct($settings)
{
parent::__construct($settings);
$this->connect();
}
/**
* @inheritdoc
*/
public function connect()
{
// Set up your credentials.
$credentials = new Credentials($this->vmClientId, $this->apiKey);
// Use the default adapter, CurlHttpAdapter.
$this->connector = new DigitalOcean($credentials);
// Or use BuzzHttpAdapter.
//$this->connector = new DigitalOcean($credentials, new BuzzHttpAdapter());
}
/**
* @return DigitalOcean
*/
public function getConnector()
{
return $this->connector;
}
/**
* @param string $type min or max
*/
public function resizeTo($type = 'min')
{
try {
$droplets = $this->getConnector()->droplets();
$sizes = $this->getConnector()->sizes();
$availableSizes = $sizes->getAll();
if (isset($availableSizes->status) && $availableSizes->status == 'OK') {
$minSizeIdExists = false;
$maxSizeIdExists = false;
foreach ($availableSizes->sizes as $size) {
if ($size->id == $this->vmMaxSize) {
$maxSizeIdExists = true;
}
if ($size->id == $this->vmMinSizeSize) {
$minSizeIdExists = true;
}
}
if ($maxSizeIdExists && $minSizeIdExists) {
throw new \Exception('Sizes are not well configured');
}
} else {
throw new \Exception('Sizes not available');
}
// Returns all active droplets that are currently running in your account.
//$allActive = $droplets->showAllActive();
$dropletInfo = $droplets->show($this->vmId);
if ($dropletInfo->status == 'OK') {
switch ($type) {
case 'min':
if ($dropletInfo->droplet->size_id == $this->vmMinSize) {
// No resize
$this->addMessage(
'Nothing to execute. The size was already reduced.'
);
} else {
$this->resize($this->vmMinSize);
}
break;
case 'max':
if ($dropletInfo->droplet->size_id == $this->vmMaxSize) {
// No resize
$this->addMessage(
'Nothing to execute. The size was already boost.'
);
} else {
$this->resize($this->vmMaxSize);
}
break;
}
} else {
throw new \Exception(" Id ".$this->vmId." doesn't exists.");
}
} catch (Exception $e) {
die($e->getMessage());
}
}
/**
* Turns off / resize / turns on
* @param int $sizeId
*/
public function resize($sizeId)
{
$droplets = $this->getConnector()->droplets();
$dropletInfo = $droplets->show($this->vmId);
$powerOff = $droplets->powerOff($this->vmId);
$this->addMessage('Power off droplet #'.$this->vmId);
$this->waitForEvent($powerOff->event_id);
$this->addMessage('Current status: '.$dropletInfo->droplet->status);
$resizeDroplet = $droplets->resize(
$this->vmId,
array('size_id' => intval($sizeId))
);
$this->addMessage('Resize droplet to size id: '.$sizeId);
$this->waitForEvent($resizeDroplet->event_id);
$powerOn = $droplets->powerOn($this->vmId);
$this->waitForEvent($powerOn->event_id);
$this->addMessage('Power on droplet #'.$this->vmId);
}
/**
* Loops until an event answer 100 percentage
* @param int $eventId
*/
public function waitForEvent($eventId)
{
$events = $this->getConnector()->events();
$status = false;
while ($status == false) {
$infoStatus = $events->show($eventId);
if ($infoStatus->status == 'OK' && $infoStatus->event->percentage == 100) {
$status = true;
}
}
}
/**
* @inheritdoc
*/
public function runCron()
{
$this->resizeToMinLimit();
echo $this->getMessageToString();
}
/**
* @inheritdoc
*/
public function resizeToMaxLimit()
{
$this->resizeTo('max');
}
/**
* @inheritdoc
*/
public function resizeToMinLimit()
{
$this->resizeTo('min');
}
}

View File

@@ -0,0 +1,29 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Interface VirtualMachineInterface
*/
interface VirtualMachineInterface
{
/**
* @return mixed
*/
function connect();
/**
* @return mixed
*/
function runCron();
/**
* @return mixed
*/
function resizeToMaxLimit();
/**
* @return mixed
*/
function resizeToMinLimit();
}