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

View File

@@ -0,0 +1,67 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
trait Api2RequestTrait
{
/**
* @throws Exception
*/
public function send($httpMethod, $relativePath, $parameters = [], $requestBody = null): string
{
$options = [
CURLOPT_CUSTOMREQUEST => $httpMethod,
CURLOPT_ENCODING => '',
CURLOPT_HTTPHEADER => [
'authorization: Bearer '.$this->token,
'content-type: application/json',
],
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_MAXREDIRS => 10,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
];
if (!is_null($requestBody)) {
$jsonRequestBody = json_encode($requestBody);
if (false === $jsonRequestBody) {
throw new Exception('Could not generate JSON request body');
}
$options[CURLOPT_POSTFIELDS] = $jsonRequestBody;
}
$url = "https://api.zoom.us/v2/$relativePath";
if (!empty($parameters)) {
$url .= '?'.http_build_query($parameters);
}
$curl = curl_init($url);
if (false === $curl) {
throw new Exception("curl_init returned false");
}
curl_setopt_array($curl, $options);
$responseBody = curl_exec($curl);
$responseCode = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
$curlError = curl_error($curl);
curl_close($curl);
if ($curlError) {
throw new Exception("cURL Error: $curlError");
}
if (false === $responseBody || !is_string($responseBody)) {
throw new Exception('cURL Error');
}
if (empty($responseCode)
|| $responseCode < 200
|| $responseCode >= 300
) {
throw new Exception($responseBody, $responseCode);
}
return $responseBody;
}
}

View File

@@ -0,0 +1,41 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
/**
* Trait BaseMeetingTrait.
* Common meeting properties definitions.
*/
trait BaseMeetingTrait
{
/** @var string */
public $topic;
/** @var int */
public $type;
/** @var string "yyyy-MM-dd'T'HH:mm:ss'Z'" for GMT, same without 'Z' for local time (as set on zoom account) */
public $start_time;
/** @var int in minutes, for scheduled meetings only */
public $duration;
/** @var string the timezone for start_time */
public $timezone;
/** @var string description */
public $agenda;
/** @var string description */
public $host_email;
/**
* @throws Exception
*/
public function update(): void
{
}
}

View File

@@ -0,0 +1,56 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
/**
* Interface Client.
* Two implementations are currently possible : OAuth and JWT.
*
* @see https://marketplace.zoom.us/docs/api-reference/zoom-api
*/
abstract class Client
{
/** @var Client */
private static $instance;
/**
* Returns an initialized Client.
*
* @return Client
*/
public static function getInstance()
{
return self::$instance;
}
/**
* Sends a Zoom API-compliant HTTP request and retrieves the response.
*
* On success, returns the body of the response
* On error, throws an exception with an detailed error message
*
* @param string $httpMethod GET, POST, PUT, DELETE ...
* @param string $relativePath to append to https://api.zoom.us/v2/
* @param array $parameters request query parameters
* @param object $requestBody json-encoded body of the request
*
* @throws Exception describing the error (message and code)
*
* @return string response body (not json-decoded)
*/
abstract public function send($httpMethod, $relativePath, $parameters = [], $requestBody = null);
/**
* Registers an initialized Client.
*
* @param Client $instance
*/
protected static function register($instance)
{
self::$instance = $instance;
}
}

View File

@@ -0,0 +1,42 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
/**
* Class CreatedRegistration.
* An instance of this class is returned by the Zoom server upon recording a registrant to a meeting.
*/
class CreatedRegistration
{
use JsonDeserializableTrait;
/** @var int meeting ID */
public $id;
/** @var string Unique URL for this registrant to join the meeting.
* This URL should only be shared with the registrant for whom the API request was made.
* If the meeting was created with manual approval type (1), the join URL will not be returned in the response.
*/
public $join_url;
/** @var string Unique identifier of the registrant */
public $registrant_id;
/** @var string The start time for the meeting. */
public $start_time;
/** @var string Topic of the meeting. */
public $topic;
/**
* {@inheritdoc}
*/
protected function itemClass($propertyName)
{
throw new Exception("no such array property $propertyName");
}
}

View File

@@ -0,0 +1,18 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
/**
* Class CustomQuestion.
* A list of instances of this class is included in a MeetingRegistrant instance.
*/
class CustomQuestion
{
/** @var string */
public $title;
/** @var string */
public $value;
}

View File

@@ -0,0 +1,26 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
class FollowUpUsers
{
use JsonDeserializableTrait;
/**
* @var bool
*/
public $enable;
/**
* @var
*/
public $type;
public function itemClass($propertyName)
{
throw new Exception("No such array property $propertyName");
}
}

View File

@@ -0,0 +1,39 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
/**
* Class GlobalDialInNumber.
* A list of these is included in a meeting settings.
*/
class GlobalDialInNumber
{
use JsonDeserializableTrait;
/** @var string Country code. For example, BR. */
public $country;
/** @var string Full name of country. For example, Brazil. */
public $country_name;
/** @var string City of the number, if any. For example, Chicago. */
public $city;
/** @var string Phone number. For example, +1 2332357613. */
public $number;
/** @var string Type of number. Either "toll" or "tollfree". */
public $type;
/**
* {@inheritdoc}
*/
public function itemClass($propertyName)
{
throw new Exception("No such array property $propertyName");
}
}

View File

@@ -0,0 +1,38 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Firebase\JWT\JWT;
/**
* Class JWTClient.
*
* @see https://marketplace.zoom.us/docs/guides/auth/jwt
*/
class JWTClient extends Client
{
use Api2RequestTrait;
public $token;
/**
* JWTClient constructor.
* Requires JWT app credentials.
*
* @param string $apiKey JWT API Key
* @param string $apiSecret JWT API Secret
*/
public function __construct($apiKey, $apiSecret)
{
$this->token = JWT::encode(
[
'iss' => $apiKey,
'exp' => (time() + 60) * 1000, // will expire in one minute
],
$apiSecret
);
self::register($this);
}
}

View File

@@ -0,0 +1,122 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
/**
* Trait JsonDeserializableTrait.
* Utility functions to help convert server-generated JSON to API class instances.
*/
trait JsonDeserializableTrait
{
/**
* Builds a class instance from the Json description of the object.
*
* @param string $json
*
* @throws Exception on JSON-decode error or unexpected object property
*
* @return static
*/
public static function fromJson($json)
{
if (empty($json)) {
throw new Exception('Cannot JSON-decode empty string');
}
$object = json_decode($json);
if (null === $object) {
throw new Exception('Could not decode JSON: '.$json);
}
return static::fromObject($object);
}
/**
* Builds a class instance from an already json-decoded object.
*
* @param object $object
*
* @throws Exception on unexpected object property
*
* @return static
*/
public static function fromObject($object)
{
$instance = new static();
static::recursivelyCopyObjectProperties($object, $instance);
return $instance;
}
/**
* Returns the class name of the items to be found in the named array property.
*
* To override in classes that have a property of type array
*
* @param string $propertyName array property name
*
* @throws Exception if not implemented for this propertyName
*
* @return string class name of the items to be found in the named array property
*/
abstract public function itemClass($propertyName);
/**
* Initializes properties that can be calculated from json-decoded properties.
*
* Called at the end of method recursivelyCopyObjectProperties()
* and indirectly at the end of static method fromJson().
*
* By default it does nothing.
*/
public function initializeExtraProperties()
{
// default does nothing
}
/**
* Copies values from another object properties to an instance, recursively.
*
* @param object $source source object
* @param object $destination specific class instance, with already initialized properties
*
* @throws Exception when the source object has an unexpected property
*/
protected static function recursivelyCopyObjectProperties($source, &$destination)
{
foreach (get_object_vars($source) as $name => $value) {
if (property_exists($destination, $name)) {
if (is_object($value)) {
if (is_object($destination->$name)) {
static::recursivelyCopyObjectProperties($value, $destination->$name);
} else {
throw new Exception("Source property $name is an object, which is not expected");
}
} elseif (is_array($value)) {
if (is_array($destination->$name)) {
$itemClass = $destination->itemClass($name);
foreach ($value as $sourceItem) {
if ('string' === $itemClass) {
$destination->$name[] = $sourceItem;
} else {
$item = new $itemClass();
static::recursivelyCopyObjectProperties($sourceItem, $item);
$destination->$name[] = $item;
}
}
} else {
throw new Exception("Source property $name is an array, which is not expected");
}
} else {
$destination->$name = $value;
}
} else {
error_log("Source object has property $name, which was not expected: ".json_encode($source));
}
}
$destination->initializeExtraProperties();
}
}

View File

@@ -0,0 +1,88 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
/**
* Class Meeting, minimal meeting definition required to create one from scratch or update an existing one
* Also referred to as MeetingUpdate in the API documentation
* Does not represent an actual created meeting.
*/
class Meeting
{
use BaseMeetingTrait;
use JsonDeserializableTrait;
public const TYPE_INSTANT = 1;
public const TYPE_SCHEDULED = 2;
public const TYPE_RECURRING_WITH_NO_FIXED_TIME = 3;
public const TYPE_RECURRING_WITH_FIXED_TIME = 8;
/** @var string password to join. [a-z A-Z 0-9 @ - _ *]. Max of 10 characters. */
public $password;
/** @var TrackingField[] Tracking fields */
public $tracking_fields;
/** @var object, only for a recurring meeting with fixed time (type 8) */
public $recurrence;
/** @var MeetingSettings */
public $settings;
/**
* Meeting constructor.
*/
protected function __construct()
{
$this->tracking_fields = [];
$this->settings = new MeetingSettings();
}
/**
* {@inheritdoc}
*/
public function itemClass($propertyName)
{
if ('tracking_fields' === $propertyName) {
return TrackingField::class;
}
throw new Exception("no such array property $propertyName");
}
/**
* Creates a meeting on the server and returns the resulting MeetingInfoGet.
*
* @throws Exception describing the error (message and code)
*
* @return MeetingInfoGet meeting
*/
public function create($userId = null)
{
$userId = empty($userId) ? 'me' : $userId;
return MeetingInfoGet::fromJson(
Client::getInstance()->send('POST', "users/$userId/meetings", [], $this)
);
}
/**
* Creates a Meeting instance from a topic.
*
* @param string $topic
* @param int $type
*
* @return static
*/
public static function fromTopicAndType($topic, $type = self::TYPE_SCHEDULED)
{
$instance = new static();
$instance->topic = $topic;
$instance->type = $type;
return $instance;
}
}

View File

@@ -0,0 +1,34 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
/**
* Class MeetingInfo
* Used to define MeetingInfoGet
* Does not seem to be used directly.
*/
class MeetingInfo extends Meeting
{
/** @var string */
public $created_at;
/** @var string, allows host to start the meeting as the host (without password) - not to be shared */
public $start_url;
/** @var string, for participants to join the meeting - to share with users to invite */
public $join_url;
/** @var string undocumented */
public $registration_url;
/** @var string H.323/SIP room system password */
public $h323_password;
/** @var int Personal Meeting Id. Only used for scheduled meetings and recurring meetings with no fixed time */
public $pmi;
/** @var object[] */
public $occurrences;
}

View File

@@ -0,0 +1,148 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
/**
* Class MeetingInfoGet
* Full Meeting as returned by the server, with unique identifiers and current status.
*/
class MeetingInfoGet extends MeetingInfo
{
/** @var string unique meeting instance ID */
public $uuid;
/** @var string meeting number */
public $id;
/** @var string host Zoom user id */
public $host_id;
/** @var string meeting status, either "waiting", "started" or "finished" */
public $status;
/** @var string undocumented */
public $pstn_password;
/** @var string Encrypted password for third party endpoints (H323/SIP). */
public $encrypted_password;
/**
* Retrieves a meeting from its numeric identifier.
*
* @param int $id
*
* @throws Exception
*
* @return static the meeting
*/
public static function fromId($id)
{
return static::fromJson(Client::getInstance()->send('GET', "meetings/$id"));
}
/**
* Updates the meeting on server.
*
* @throws Exception
*/
public function update(): void
{
Client::getInstance()->send('PATCH', 'meetings/'.$this->id, [], $this);
}
/**
* Ends the meeting on server.
*
* @throws Exception
*/
public function endNow()
{
Client::getInstance()->send('PUT', "meetings/$this->id/status", [], (object) ['action' => 'end']);
}
/**
* Deletes the meeting on server.
*
* @throws Exception
*/
public function delete()
{
Client::getInstance()->send('DELETE', "meetings/$this->id");
}
/**
* Adds a registrant to the meeting.
*
* @param RegistrantSchema $registrant with at least 'email' and 'first_name'.
* 'last_name' will also be recorded by Zoom.
* Other properties remain ignored, or not returned by Zoom
* (at least while using profile "Pro")
* @param string $occurrenceIds separated by comma
*
* @throws Exception
*
* @return CreatedRegistration with unique join_url and registrant_id properties
*/
public function addRegistrant(RegistrantSchema $registrant, string $occurrenceIds = ''): CreatedRegistration
{
return CreatedRegistration::fromJson(
Client::getInstance()->send(
'POST',
"meetings/$this->id/registrants",
empty($occurrenceIds) ? [] : ['occurrence_ids' => $occurrenceIds],
$registrant
)
);
}
/**
* Removes registrants from the meeting.
*
* @param MeetingRegistrant[] $registrants registrants to remove (id and email)
* @param string $occurrenceIds separated by comma
*
* @throws Exception
*/
public function removeRegistrants($registrants, $occurrenceIds = '')
{
if (!empty($registrants)) {
Client::getInstance()->send(
'PUT',
"meetings/$this->id/registrants/status",
empty($occurrenceIds) ? [] : ['occurrence_ids' => $occurrenceIds],
(object) [
'action' => 'cancel',
'registrants' => $registrants,
]
);
}
}
/**
* Retrieves meeting registrants.
*
* @throws Exception
*
* @return MeetingRegistrantListItem[] the meeting registrants
*/
public function getRegistrants()
{
return MeetingRegistrantList::loadMeetingRegistrants($this->id);
}
/**
* Retrieves the meeting's instances.
*
* @throws Exception
*
* @return MeetingInstance[]
*/
public function getInstances()
{
return MeetingInstances::fromMeetingId($this->id)->meetings;
}
}

View File

@@ -0,0 +1,50 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
/**
* Class MeetingInstance
* A meeting (numerical id) can have one or more instances (string UUID).
* Each instance has its own start time, participants and recording files.
*
* @see MeetingInstances
* @see PastMeeting for the full record
*/
class MeetingInstance
{
/** @var string */
public $uuid;
/** @var string */
public $start_time;
/**
* Retrieves the recording of the instance.
*
* @throws Exception with code 404 when there is no recording for this meeting
*
* @return RecordingMeeting the recording
*/
public function getRecordings()
{
return RecordingMeeting::fromJson(
Client::getInstance()->send('GET', 'meetings/'.htmlentities($this->uuid).'/recordings')
);
}
/**
* Retrieves the instance's participants.
*
* @throws Exception
*
* @return ParticipantListItem[]
*/
public function getParticipants()
{
return ParticipantList::loadInstanceParticipants($this->uuid);
}
}

View File

@@ -0,0 +1,53 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
/**
* Class MeetingInstances. The list of one meeting's ended instances.
*
* @see MeetingInstance
*/
class MeetingInstances
{
use JsonDeserializableTrait;
/** @var MeetingInstance[] List of ended meeting instances. */
public $meetings;
/**
* MeetingInstances constructor.
*/
public function __construct()
{
$this->meetings = [];
}
/**
* Retrieves a meeting's instances.
*
* @param int $meetingId
*
* @throws Exception
*
* @return MeetingInstances the meeting's instances
*/
public static function fromMeetingId($meetingId)
{
return static::fromJson(Client::getInstance()->send('GET', "past_meetings/$meetingId/instances"));
}
/**
* {@inheritdoc}
*/
public function itemClass($propertyName)
{
if ('meetings' === $propertyName) {
return MeetingInstance::class;
}
throw new Exception("No such array property $propertyName");
}
}

View File

@@ -0,0 +1,58 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
/**
* Class MeetingList. Lists Meetings.
*
* @see MeetingListItem
*/
class MeetingList
{
use Pagination;
public const TYPE_SCHEDULED = 'scheduled'; // all valid past meetings (unexpired),
// live meetings and upcoming scheduled meetings.
public const TYPE_LIVE = 'live'; // all the ongoing meetings.
public const TYPE_UPCOMING = 'upcoming'; // all upcoming meetings, including live meetings.
/** @var MeetingListItem[] */
public $meetings;
/**
* MeetingList constructor.
*/
public function __construct()
{
$this->meetings = [];
}
/**
* Retrieves all meetings of a type.
*
* @param int $type TYPE_SCHEDULED, TYPE_LIVE or TYPE_UPCOMING
*
* @throws Exception
*
* @return MeetingListItem[] all meetings
*/
public static function loadMeetings($type)
{
return static::loadItems('meetings', 'users/me/meetings', ['type' => $type]);
}
/**
* {@inheritdoc}
*/
public function itemClass($propertyName)
{
if ('meetings' === $propertyName) {
return MeetingListItem::class;
}
throw new Exception("No such array property $propertyName");
}
}

View File

@@ -0,0 +1,44 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
/**
* Class MeetingListItem. Item of a list of meetings.
*
* @see MeetingList
*/
class MeetingListItem
{
use BaseMeetingTrait;
use JsonDeserializableTrait;
/** @var string unique meeting instance ID */
public $uuid;
/** @var string meeting number */
public $id;
/** @var string host Zoom user id */
public $host_id;
/** @var string */
public $created_at;
/** @var string */
public $join_url;
/** @var string truncated to 250 characters */
// public $agenda;
/**
* {@inheritdoc}
*/
public function itemClass($propertyName)
{
throw new Exception("no such array property $propertyName");
}
}

View File

@@ -0,0 +1,22 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
/**
* Class Registrant.
*
* Structure of the information to send the server in order to register someone to a meeting.
*/
class MeetingRegistrant extends RegistrantSchema
{
public $auto_approve;
public function __construct()
{
parent::__construct();
$this->auto_approve = true;
}
}

View File

@@ -0,0 +1,53 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
/**
* Class MeetingRegistrantList. List of meeting registrants.
*
* @see MeetingRegistrantListItem
*/
class MeetingRegistrantList
{
use Pagination;
/** @var MeetingRegistrantListItem[] */
public $registrants;
/**
* MeetingRegistrantList constructor.
*/
public function __construct()
{
$this->registrants = [];
}
/**
* Retrieves all registrant for a meeting.
*
* @param int $meetingId
*
* @throws Exception
*
* @return MeetingRegistrantListItem[] all registrants of the meeting
*/
public static function loadMeetingRegistrants($meetingId)
{
return static::loadItems('registrants', "meetings/$meetingId/registrants");
}
/**
* {@inheritdoc}
*/
public function itemClass($propertyName)
{
if ('registrants' === $propertyName) {
return MeetingRegistrantListItem::class;
}
throw new Exception("no such array property $propertyName");
}
}

View File

@@ -0,0 +1,29 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
/**
* Class MeetingRegistrantListItem. Item in a list of meeting registrants.
*
* @see MeetingRegistrantList
*/
class MeetingRegistrantListItem extends MeetingRegistrant
{
/** @var string Registrant ID. */
public $id;
/** @var string The status of the registrant's registration.
* `approved`: User has been successfully approved for the webinar.
* `pending`: The registration is still pending.
* `denied`: User has been denied from joining the webinar.
*/
public $status;
/** @var string The time at which the registrant registered. */
public $create_time;
/** @var string The URL using which an approved registrant can join the webinar. */
public $join_url;
}

View File

@@ -0,0 +1,143 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
/**
* Class MeetingSettings. An instance of this class is included in each Meeting instance.
*/
class MeetingSettings
{
use JsonDeserializableTrait;
public const APPROVAL_TYPE_AUTOMATICALLY_APPROVE = 0;
public const APPROVAL_TYPE_MANUALLY_APPROVE = 1;
public const APPROVAL_TYPE_NO_REGISTRATION_REQUIRED = 2;
public const REGISTRATION_TYPE_REGISTER_ONCE_ATTEND_ANY = 1;
public const REGISTRATION_TYPE_REGISTER_EACH = 2;
public const REGISTRATION_TYPE_REGISTER_ONCE_CHOOSE = 3;
/** @var bool Start video when the host joins the meeting */
public $host_video;
/** @var bool Start video when participants join the meeting */
public $participant_video;
/** @var bool Host meeting in China */
public $cn_meeting;
/** @var bool Host meeting in India */
public $in_meeting;
/** @var bool Allow participants to join the meeting before the host starts the meeting.
* Only used for scheduled or recurring meetings.
*/
public $join_before_host;
/** @var bool Mute participants upon entry */
public $mute_upon_entry;
/** @var bool Add watermark when viewing a shared screen */
public $watermark;
/** @var bool Use a personal meeting ID.
* Only used for scheduled meetings and recurring meetings with no fixed time.
*/
public $use_pmi;
/** @var int Enable registration and set approval for the registration.
* Note that this feature requires the host to be of **Licensed** user type.
* **Registration cannot be enabled for a basic user.**
*/
public $approval_type;
/** @var int Used for recurring meeting with fixed time only. */
public $registration_type;
/** @var string either both, telephony or voip */
public $audio;
/** @var string either local, cloud or none */
public $auto_recording;
/** @var bool @deprecated only signed in users can join this meeting */
public $enforce_login;
/** @var string @deprecated only signed in users with specified domains can join meetings */
public $enforce_login_domains;
/** @var string Alternative host's emails or IDs: multiple values separated by a comma. */
public $alternative_hosts;
/** @var bool Close registration after event date */
public $close_registration;
/** @var bool Enable waiting room */
public $waiting_room;
/** @var bool undocumented */
public $request_permission_to_unmute_participants;
/** @var string[] List of global dial-in countries */
public $global_dial_in_countries;
/** @var GlobalDialInNumber[] Global Dial-in Countries/Regions */
public $global_dial_in_numbers;
/** @var string Contact name for registration */
public $contact_name;
/** @var string Contact email for registration */
public $contact_email;
/** @var bool Send confirmation email to registrants upon successful registration */
public $registrants_confirmation_email;
/** @var bool Send email notifications to registrants about approval, cancellation, denial of the registration.
* The value of this field must be set to true in order to use the `registrants_confirmation_email` field.
*/
public $registrants_email_notification;
/** @var bool Only authenticated users can join meetings. */
public $meeting_authentication;
/** @var string Meeting authentication option id. */
public $authentication_option;
/** @var string
* @see https://support.zoom.us/hc/en-us/articles/360037117472-Authentication-Profiles-for-Meetings-and-Webinars#h_5c0df2e1-cfd2-469f-bb4a-c77d7c0cca6f
*/
public $authentication_domains;
/** @var string
* @see https://support.zoom.us/hc/en-us/articles/360037117472-Authentication-Profiles-for-Meetings-and-Webinars#h_5c0df2e1-cfd2-469f-bb4a-c77d7c0cca6f
*/
public $authentication_name;
/**
* MeetingSettings constructor.
*/
public function __construct()
{
$this->global_dial_in_countries = [];
$this->global_dial_in_numbers = [];
}
/**
* {@inheritdoc}
*/
public function itemClass($propertyName)
{
if ('global_dial_in_countries' === $propertyName) {
return 'string';
}
if ('global_dial_in_numbers' === $propertyName) {
return GlobalDialInNumber::class;
}
throw new Exception("No such array property $propertyName");
}
}

View File

@@ -0,0 +1,22 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
class Ocurrence
{
use JsonDeserializableTrait;
public $occurrence_id;
public $start_time;
public $duration;
public $status;
public function itemClass($propertyName)
{
throw new Exception("No such array property $propertyName");
}
}

View File

@@ -0,0 +1,68 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
/**
* Trait Pagination
* properties for Pagination objects, which are paginated lists of items,
* retrieved in chunks from the server over one or several API calls, one per page.
*/
trait Pagination
{
use JsonDeserializableTrait;
/** @var int The number of pages returned for the request made. */
public $page_count;
/** @var int The page number of the current results, counting from 1 */
public $page_number;
/** @var int The number of records returned with a single API call. Default 30, max 300. */
public $page_size;
/** @var int The total number of all the records available across pages. */
public $total_records;
/**
* Retrieves all items from the server, possibly generating several API calls.
*
* @param string $arrayPropertyName item array property name
* @param string $relativePath relative path to pass to Client::send
* @param array $parameters parameter array to pass to Client::send
*
* @throws Exception
*
* @return array united list of items
*/
protected static function loadItems($arrayPropertyName, $relativePath, $parameters = [])
{
$items = [];
$pageCount = 1;
$pageSize = 300;
$totalRecords = 0;
for ($pageNumber = 1; $pageNumber <= $pageCount; $pageNumber++) {
$response = static::fromJson(
Client::getInstance()->send(
'GET',
$relativePath,
array_merge(['page_size' => $pageSize, 'page_number' => $pageNumber], $parameters)
)
);
$items = array_merge($items, $response->$arrayPropertyName);
if (0 === $totalRecords) {
$pageCount = $response->page_count;
$pageSize = $response->page_size;
$totalRecords = $response->total_records;
}
}
if (count($items) !== $totalRecords) {
error_log('Zoom announced '.$totalRecords.' records but returned '.count($items));
}
return $items;
}
}

View File

@@ -0,0 +1,71 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
/**
* Trait PaginationToken
* properties for PaginationToken objects, which are paginated lists of items,
* retrieved in chunks from the server over one or several API calls, one per page.
*/
trait PaginationToken
{
use JsonDeserializableTrait;
/** @var int The number of pages returned for the request made. */
public $page_count;
/** @var int The number of records returned within a single API call. Default 30, max 300. */
public $page_size;
/** @var int The number of all records available across pages. */
public $total_records;
/** @var string The next page token is used to paginate through large result sets.
* A next page token will be returned whenever the set of available results exceeds the current page size.
* The expiration period for this token is 15 minutes.
*/
public $next_page_token;
/**
* Retrieves all items from the server, possibly generating several API calls.
*
* @param string $arrayPropertyName item array property name
* @param string $relativePath relative path to pass to Client::send
* @param array $parameters parameter array to pass to Client::send
*
* @throws Exception
*
* @return array united list of items
*/
protected static function loadItems($arrayPropertyName, $relativePath, $parameters = [])
{
$items = [];
$pageSize = 300;
$totalRecords = 0;
$nextPageToken = '';
do {
$response = static::fromJson(
Client::getInstance()->send(
'GET',
$relativePath,
array_merge(['page_size' => $pageSize, 'next_page_token' => $nextPageToken], $parameters)
)
);
$items = array_merge($items, $response->$arrayPropertyName);
$nextPageToken = $response->next_page_token;
if (0 === $totalRecords) {
$pageSize = $response->page_size;
$totalRecords = $response->total_records;
}
} while (!empty($nextPagetoken));
if (count($items) !== $totalRecords) {
error_log('Zoom announced '.$totalRecords.' records but returned '.count($items));
}
return $items;
}
}

View File

@@ -0,0 +1,57 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
/**
* Class ParticipantList
* List of past meeting instance participants.
*
* @see ParticipantListItem;
*/
class ParticipantList
{
use PaginationToken;
/** @var ParticipantListItem[] */
public $participants;
/**
* ParticipantList constructor.
*/
public function __construct()
{
$this->participants = [];
}
/**
* Retrieves a meeting instance's participants.
*
* @param string $instanceUUID
*
* @throws Exception
*
* @return ParticipantListItem[] participants
*/
public static function loadInstanceParticipants($instanceUUID)
{
return static::loadItems(
'participants',
'past_meetings/'.htmlentities($instanceUUID).'/participants'
);
}
/**
* {@inheritdoc}
*/
public function itemClass($propertyName)
{
if ('participants' === $propertyName) {
return ParticipantListItem::class;
}
throw new Exception("No such array property $propertyName");
}
}

View File

@@ -0,0 +1,22 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
/**
* Class ParticipantListItem. Item in a list of past meeting instance participants.
*
* @see ParticipantList
*/
class ParticipantListItem
{
/** @var string participant UUID */
public $id;
/** @var string display name */
public $name;
/** @var string Email address of the user; will be returned if the user logged into Zoom to join the meeting. */
public $user_email;
}

View File

@@ -0,0 +1,74 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
/**
* Class PastMeeting.
* A past meeting, really a past meeting instance, as returned from the server.
*
* Each past meeting instance is identified by its own UUID.
* Many past meeting instances can be part of the same meeting, identified by property 'id'.
* Each instance has its own start time, participants and recording files.
*/
class PastMeeting extends Meeting
{
/** @var string unique meeting instance ID */
public $uuid;
/** @var string meeting number */
public $id;
/** @var string host Zoom user id */
public $host_id;
/** @var string user display name */
public $user_name;
/** @var string */
public $user_email;
/** @var string "yyyy-MM-dd'T'HH:mm:ss'Z'" (GMT) */
public $start_time;
/** @var string "yyyy-MM-dd'T'HH:mm:ss'Z'" (GMT) */
public $end_time;
/** @var int sum of meeting minutes from all participants in the meeting. */
public $total_minutes;
/** @var int number of meeting participants */
public $participants_count;
/** @var string undocumented */
public $dept;
/**
* Retrieves a past meeting instance from its identifier.
*
* @param string $uuid
*
* @throws Exception
*
* @return PastMeeting the past meeting
*/
public static function fromUUID($uuid)
{
return static::fromJson(Client::getInstance()->send('GET', 'past_meetings/'.htmlentities($uuid)));
}
/**
* Retrieves information on participants from a past meeting instance.
*
* @throws Exception
*
* @return ParticipantListItem[] participants
*/
public function getParticipants()
{
return ParticipantList::loadInstanceParticipants($this->uuid);
}
}

View File

@@ -0,0 +1,23 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
class QuestionAndAnswer
{
use JsonDeserializableTrait;
public $enable;
public $allow_anonymous_questions;
public $answer_questions;
public $attendees_can_upvote;
public $attendees_can_comment;
public function itemClass($propertyName)
{
throw new Exception("No such array property $propertyName");
}
}

View File

@@ -0,0 +1,115 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
/**
* Class RecordingFile. A video, audio or text file, part of a past meeting instance recording.
*
* @see RecordingMeeting
*/
class RecordingFile
{
use JsonDeserializableTrait;
/** @var string The recording file ID. Included in the response of general query. */
public $id;
/** @var string The meeting ID. */
public $meeting_id;
/** @var string The recording start time. */
public $recording_start;
/** @var string The recording end time. Response in general query. */
public $recording_end;
/** @var string The recording file type. The value of this field could be one of the following:<br>
* `MP4`: Video file of the recording.<br>
* `M4A` Audio-only file of the recording.<br>
* `TIMELINE`: Timestamp file of the recording.
* To get a timeline file, the "Add a timestamp to the recording" setting must be enabled in the recording settings
* (https://support.zoom.us/hc/en-us/articles/203741855-Cloud-recording#h_3f14c3a4-d16b-4a3c-bbe5-ef7d24500048).
* The time will display in the host's timezone, set on their Zoom profile.
* `TRANSCRIPT`: Transcription file of the recording.
* `CHAT`: A TXT file containing in-meeting chat messages that were sent during the meeting.
* `CC`: File containing closed captions of the recording.
* A recording file object with file type of either `CC` or `TIMELINE` **does not have** the following properties:
* `id`, `status`, `file_size`, `recording_type`, and `play_url`.
*/
public $file_type;
/** @var int The recording file size. */
public $file_size;
/** @var string The URL using which a recording file can be played. */
public $play_url;
/** @var string The URL using which the recording file can be downloaded.
* To access a private or password protected cloud recording, you must use a [Zoom JWT App Type]
* (https://marketplace.zoom.us/docs/guides/getting-started/app-types/create-jwt-app).
* Use the generated JWT token as the value of the `access_token` query parameter
* and include this query parameter at the end of the URL as shown in the example.
* Example: `https://api.zoom.us/recording/download/{{ Download Path }}?access_token={{ JWT Token }}`
*/
public $download_url;
/** @var string The recording status. "completed". */
public $status;
/** @var string The time at which recording was deleted. Returned in the response only for trash query. */
public $deleted_time;
/** @var string The recording type. The value of this field can be one of the following:
* `shared_screen_with_speaker_view(CC)`
* `shared_screen_with_speaker_view`
* `shared_screen_with_gallery_view`
* `speaker_view`
* `gallery_view`
* `shared_screen`
* `audio_only`
* `audio_transcript`
* `chat_file`
* `TIMELINE`
*/
public $recording_type;
/**
* Builds the recording file download URL with the access_token query parameter.
*
* @see RecordingFile::$download_url
*
* @param string $token
*
* @return string full URL
*/
public function getFullDownloadURL($token)
{
return $this->download_url.'?access_token='.$token;
}
/**
* Deletes the file.
*
* @throws Exception
*/
public function delete()
{
Client::getInstance()->send(
'DELETE',
"/meetings/$this->meeting_id/recordings/$this->id",
['action' => 'delete']
);
}
/**
* {@inheritdoc}
*/
public function itemClass($propertyName)
{
throw new Exception("No such array property $propertyName");
}
}

View File

@@ -0,0 +1,65 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use DateTime;
use Exception;
/**
* Class RecordingList. A list of past meeting instance recordings generated between two dates.
*
* @see RecordingMeeting
*/
class RecordingList
{
use PaginationToken;
/** @var string Start Date */
public $from;
/** @var string End Date */
public $to;
/** @var RecordingMeeting[] List of recordings */
public $meetings;
public function __construct()
{
$this->meetings = [];
}
/**
* Retrieves all recordings from a period of time.
*
* @param DateTime $startDate first day of the period
* @param DateTime $endDate last day of the period
*
* @throws Exception
*
* @return RecordingMeeting[] all recordings from that period
*/
public static function loadPeriodRecordings($startDate, $endDate)
{
return static::loadItems(
'meetings',
'users/me/recordings',
[
'from' => $startDate->format('Y-m-d'),
'to' => $endDate->format('Y-m-d'),
]
);
}
/**
* {@inheritdoc}
*/
public function itemClass($propertyName)
{
if ('meetings' === $propertyName) {
return RecordingMeeting::class;
}
throw new Exception("No such array property $propertyName");
}
}

View File

@@ -0,0 +1,95 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
/**
* Class RecordingMeeting.
* A meeting instance can be recorded, hence creating an instance of this class.
* Contains a list of recording files.
*
* @see PastMeeting
* @see RecordingFile
*/
class RecordingMeeting
{
use JsonDeserializableTrait;
/** @var string Unique Meeting Identifier. Each instance of the meeting will have its own UUID. */
public $uuid;
/** @var string Meeting ID - also known as the meeting number. */
public $id;
/** @var string Unique Identifier of the user account. */
public $account_id;
/** @var string ID of the user set as host of meeting. */
public $host_id;
/** @var string Meeting topic. */
public $topic;
/** @var int undocumented */
public $type;
/** @var string The time at which the meeting started. */
public $start_time;
/** @var string undocumented */
public $timezone;
/** @var int Meeting duration. */
public $duration;
/** @var string Total size of the recording. */
public $total_size;
/** @var string Number of recording files returned in the response of this API call. */
public $recording_count;
/** @var string undocumented */
public $share_url;
/** @var string */
public $password;
/** @var RecordingFile[] List of recording file. */
public $recording_files;
/**
* RecordingMeeting constructor.
*/
public function __construct()
{
$this->recording_files = [];
}
/**
* Deletes the recording on the server.
*
* @throws Exception
*/
public function delete()
{
Client::getInstance()->send(
'DELETE',
'meetings/'.htmlentities($this->uuid).'/recordings',
['action' => 'delete']
);
}
/**
* {@inheritdoc}
*/
public function itemClass($propertyName)
{
if ('recording_files' === $propertyName) {
return RecordingFile::class;
}
throw new Exception("No such array property $propertyName");
}
}

View File

@@ -0,0 +1,103 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
abstract class RegistrantSchema
{
use JsonDeserializableTrait;
/** @var string */
public $email;
/**
* @var string
*/
public $status;
/** @var string */
public $first_name;
/** @var string */
public $last_name;
/** @var string */
public $address;
/** @var string */
public $city;
/** @var string */
public $country;
/** @var string */
public $zip;
/** @var string */
public $state;
/** @var string */
public $phone;
/** @var string */
public $industry;
/** @var string */
public $org;
/** @var string */
public $job_title;
/** @var string */
public $purchasing_time_frame;
/** @var string */
public $role_in_purchase_process;
/** @var string */
public $no_of_employees;
/** @var string */
public $comments;
/** @var object[] title => value */
public $custom_questions;
/**
* @var string
*/
public $language;
/**
* MeetingRegistrant constructor.
*/
public function __construct()
{
$this->status = 'approved';
$this->custom_questions = [];
}
public static function fromEmailAndFirstName(string $email, string $firstName, string $lastName = null): RegistrantSchema
{
$instance = new static();
$instance->first_name = $firstName;
$instance->email = $email;
if (null !== $lastName) {
$instance->last_name = $lastName;
}
return $instance;
}
/**
* {@inheritdoc}
*/
public function itemClass($propertyName): string
{
if ('custom_questions' === $propertyName) {
return CustomQuestion::class;
}
throw new Exception("no such array property $propertyName");
}
}

View File

@@ -0,0 +1,84 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
class ServerToServerOAuthClient extends Client
{
use Api2RequestTrait;
/**
* @var string
*/
public $token;
public function __construct(string $accountId, string $clientId, string $clientSecret)
{
try {
$this->token = $this->requireAccessToken($accountId, $clientId, $clientSecret);
} catch (Exception $e) {
error_log('Zoom: Can\'t require access token: '.$e->getMessage());
}
self::register($this);
}
private function requireAccessToken(string $accountId, string $clientId, string $clientSecret)
{
$options = [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_ENCODING => '',
CURLOPT_HTTPHEADER => [
'Authorization: Basic '.base64_encode("$clientId:$clientSecret"),
'Content-Type: application/x-www-form-urlencoded',
'Host: zoom.us',
],
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_MAXREDIRS => 10,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query([
'grant_type' => 'account_credentials',
'account_id' => $accountId,
]),
];
$url = 'https://zoom.us/oauth/token';
$curl = curl_init($url);
if (false === $curl) {
throw new Exception("curl_init returned false");
}
curl_setopt_array($curl, $options);
$responseBody = curl_exec($curl);
$responseCode = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
$curlError = curl_error($curl);
curl_close($curl);
if ($curlError) {
throw new Exception("cURL Error: $curlError");
}
if (false === $responseBody || !is_string($responseBody)) {
throw new Exception('cURL Error');
}
if (empty($responseCode) || $responseCode < 200 || $responseCode >= 300) {
throw new Exception($responseBody, $responseCode);
}
$jsonResponseBody = json_decode($responseBody, true);
if (false === $jsonResponseBody) {
throw new Exception('Could not generate JSON responso body');
}
return $jsonResponseBody['access_token'];
}
}

View File

@@ -0,0 +1,29 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
/**
* Class TrackingField. Instances of this class can be listed in a meeting object.
*/
class TrackingField
{
use JsonDeserializableTrait;
/** @var string Tracking fields type */
public $field;
/** @var string Tracking fields value */
public $value;
/**
* {@inheritdoc}
*/
public function itemClass($propertyName)
{
throw new Exception("no such array property $propertyName");
}
}

View File

@@ -0,0 +1,9 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
class WebinarRegistrantSchema extends RegistrantSchema
{
}

View File

@@ -0,0 +1,137 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
use stdClass;
class WebinarSchema
{
use BaseMeetingTrait;
use JsonDeserializableTrait;
public const TYPE_WEBINAR = 5;
public const TYPE_RECURRING_NO_FIXED_TIME = 6;
public const TYPE_RECURRING_FIXED_TIME = 9;
public $uuid;
public $id;
public $host_id;
public $created_at;
public $start_url;
public $join_url;
public $registration_url;
public $password;
/**
* @var WebinarSettings
*/
public $settings;
public $registrants_confirmation_email;
/**
* @var array<int, TrackingField>
*/
public $tracking_fields;
public $recurrence;
public $template_id;
/**
* @var array<int, Ocurrence>
*/
public $ocurrences;
protected function __construct()
{
$this->tracking_fields = [];
$this->settings = new WebinarSettings();
$this->ocurrences = [];
}
public function itemClass($propertyName): string
{
if ('tracking_fields' === $propertyName) {
return TrackingField::class;
}
if ('ocurrences' === $propertyName) {
return Ocurrence::class;
}
throw new Exception("no such array property $propertyName");
}
public static function fromTopicAndType($topic, $type = self::TYPE_WEBINAR): WebinarSchema
{
$instance = new static();
$instance->topic = $topic;
$instance->type = $type;
return $instance;
}
/**
* @throws Exception
*/
public function create($userId = null): WebinarSchema
{
$client = Client::getInstance();
$userId = empty($userId) ? 'me' : $userId;
return self::fromJson(
$client->send('POST', "users/$userId/webinars", [], $this)
);
}
/**
* @throws Exception
*/
public function update(): void
{
Client::getInstance()->send('PATCH', 'webinars/'.$this->id, [], $this);
}
/**
* @throws Exception
*/
public function delete()
{
Client::getInstance()->send('DELETE', "webinars/$this->id");
}
/**
* @throws Exception
*/
public function addRegistrant(RegistrantSchema $registrant, string $occurrenceIds = ''): CreatedRegistration
{
return CreatedRegistration::fromJson(
Client::getInstance()->send(
'POST',
"webinars/$this->id/registrants",
empty($occurrenceIds) ? [] : ['occurrence_ids' => $occurrenceIds],
$registrant
)
);
}
/**
* @throws Exception
*/
public function removeRegistrants(array $registrants, string $occurrenceIds = '')
{
if (empty($registrants)) {
return;
}
$requestBody = new stdClass();
$requestBody->action = 'cancel';
$requestBody->registrants = $registrants;
Client::getInstance()->send(
'PUT',
"webinars/$this->id/registrants/status",
empty($occurrenceIds) ? [] : ['occurrence_ids' => $occurrenceIds],
$requestBody
);
}
}

View File

@@ -0,0 +1,201 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
class WebinarSettings
{
use JsonDeserializableTrait;
public const APPROVAL_TYPE_AUTOMATICALLY_APPROVE = 0;
public const APPROVAL_TYPE_MANUALLY_APPROVE = 1;
public const APPROVAL_TYPE_NO_REGISTRATION_REQUIRED = 2;
public const REGISTRATION_TYPE_REGISTER_ONCE_ATTEND_ANY = 1;
public const REGISTRATION_TYPE_REGISTER_EACH = 2;
public const REGISTRATION_TYPE_REGISTER_ONCE_CHOOSE = 3;
/**
* @var bool
*/
public $host_video;
/**
* @var bool
*/
public $panelists_video;
/**
* @var int
*/
public $approval_type;
/**
* @var string
*/
public $audio;
/**
* @var string
*/
public $auto_recording;
/**
* @var bool
*/
public $enforce_login;
/**
* @var string
*/
public $enforce_login_domains;
/**
* @var string
*/
public $alternative_hosts;
/**
* @var bool
*/
public $close_registration;
/**
* @var bool
*/
public $show_share_button;
/**
* @var bool
*/
public $allow_multiple_devices;
/**
* @var bool
*/
public $practice_session;
/**
* @var bool
*/
public $hd_video;
/**
* @var object
*/
public $question_answer;
/**
* @var bool
*/
public $registrants_confirmation_email;
/**
* @var bool
*/
public $on_demand;
/**
* @var bool
*/
public $request_permission_to_unmute_participants;
/**
* @var array<int,string>
*/
public $global_dial_in_countries;
/**
* @var array<int,GlobalDialInNumber>
*/
public $global_dial_in_numbers;
/**
* @var string
*/
public $contact_name;
/**
* @var string
*/
public $contact_email;
/**
* @var int
*/
public $registrants_restrict_number;
/**
* @var bool
*/
public $registrants_email_notification;
/**
* @var bool
*/
public $post_webinar_survey;
/**
* @var bool
*/
public $meeting_authentication;
/**
* @var QuestionAndAnswer
*/
public $question_and_answer;
/**
* @var bool
*/
public $hd_video_for_attendees;
/**
* @var bool
*/
public $send_1080p_video_to_attendees;
/**
* @var string
*/
public $email_language;
/**
* @var bool
*/
public $panelists_invitation_email_notification;
/**
* @var FollowUpUsers
*/
public $attendees_and_panelists_reminder_email_notification;
/**
* @var FollowUpUsers
*/
public $follow_up_attendees_email_notification;
/**
* @var FollowUpUsers
*/
public $follow_up_absentees_email_notification;
/**
* @var int
*/
public $registration_type;
/**
* @var string
*/
public $auto;
/**
* @var string
*/
public $survey_url;
/**
* @var string
*/
public $authentication_option;
/**
* @var string
*/
public $authentication_domains;
/**
* @var string
*/
public $authentication_name;
public function __construct()
{
$this->global_dial_in_countries = [];
$this->global_dial_in_numbers = [];
$this->question_and_answer = new QuestionAndAnswer();
$this->attendees_and_panelists_reminder_email_notification = new FollowUpUsers();
$this->follow_up_absentees_email_notification = new FollowUpUsers();
$this->follow_up_attendees_email_notification = new FollowUpUsers();
}
public function itemClass($propertyName): string
{
if ('global_dial_in_countries' === $propertyName) {
return 'string';
}
if ('global_dial_in_numbers' === $propertyName) {
return GlobalDialInNumber::class;
}
throw new Exception("No such array property $propertyName");
}
}

View File

@@ -0,0 +1,215 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
use Chamilo\CoreBundle\Entity\Course;
use Chamilo\CoreBundle\Entity\Session;
use Chamilo\CourseBundle\Entity\CGroupInfo;
use Chamilo\PageBundle\Entity\User;
use DateTime;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\QueryBuilder;
/**
* Class MeetingRepository.
*/
class MeetingRepository extends EntityRepository
{
/**
* Retrieves information about meetings having a start_time between two dates.
*
* @param DateTime $startDate
* @param DateTime $endDate
*
* @return Meeting[]
*/
public function periodMeetings($startDate, $endDate)
{
$matching = [];
$all = $this->findAll();
/** @var Meeting $candidate */
foreach ($all as $candidate) {
if (API\Meeting::TYPE_INSTANT === $candidate->getMeetingInfoGet()->type) {
continue;
}
$cantidateEndDate = clone $candidate->startDateTime;
$cantidateEndDate->add($candidate->durationInterval);
if (($candidate->startDateTime >= $startDate && $candidate->startDateTime <= $endDate)
|| ($candidate->startDateTime <= $startDate && $cantidateEndDate >= $startDate)
) {
$matching[] = $candidate;
}
}
return $matching;
}
/**
* @return ArrayCollection|Collection|Meeting[]
*/
public function globalMeetings()
{
return $this->matching(
Criteria::create()->where(
Criteria::expr()->andX(
Criteria::expr()->eq('course', null),
Criteria::expr()->eq('user', null)
)
)
);
}
/**
* @return ArrayCollection|Collection|Meeting[]
*/
public function unfinishedGlobalMeetings()
{
return $this->globalMeetings()->filter(
function ($meeting) {
return 'finished' !== $meeting->getMeetingInfoGet()->status;
}
);
}
/**
* Returns either a user's meetings or all user meetings.
*
* @param User|null $user
*
* @return QueryBuilder
*/
public function userMeetings($user = null)
{
$qb = $this->createQueryBuilder('m');
$qb
->select('m')
->leftJoin('m.registrants', 'r');
//$qb->select('m');
/*$criteria = Criteria::create()->where(
Criteria::expr()->andX(
Criteria::expr()->isNull('course'),
Criteria::expr()->orX(
Criteria::expr()->isNull('user'),
Criteria::expr()->eq('user', $user)
)
));*/
/*$qb->where(Criteria::expr()->andX(
Criteria::expr()->isNull('course'),
Criteria::expr()->orX(
Criteria::expr()->isNull('user'),
Criteria::expr()->eq('user', $user)
)
));*/
$qb
->andWhere('m.course IS NULL')
->andWhere('m.user IS NULL OR m.user = :user OR r.user = :user');
$qb->setParameters(['user' => $user]);
return $qb;
/*return $this->matching(
,
Criteria::expr()->andX(
Criteria::expr()->eq('registrants', null),
Criteria::expr()->orX(
Criteria::expr()->eq('user', null),
Criteria::expr()->eq('user', $user)
)
)
)
);*/
/*return $this->matching(
Criteria::create()->where(
Criteria::expr()->andX(
Criteria::expr()->eq('course', null),
Criteria::expr()->orX(
Criteria::expr()->eq('user', null),
Criteria::expr()->eq('user', $user)
)
)
)
);*/
}
/**
* @param User|null $user
*
* @return Meeting[]
*/
public function unfinishedUserMeetings($user = null)
{
/*return $this->userMeetings($user)->filter(
function ($meeting) {
return 'finished' !== $meeting->getMeetingInfoGet()->status;
}
);*/
$results = @$this->userMeetings($user)->getQuery()->getResult();
$list = [];
foreach ($results as $meeting) {
if ('finished' === $meeting->getMeetingInfoGet()->status) {
$list[] = $meeting;
}
}
return $list;
}
/**
* @param DateTime $start
* @param DateTime $end
* @param User $user
*
* @return ArrayCollection|Collection|Meeting[]
*/
public function periodUserMeetings($start, $end, $user = null)
{
/*return $this->userMeetings($user)->filter(
function ($meeting) use ($start, $end) {
return $meeting->startDateTime >= $start && $meeting->startDateTime <= $end;
}
);*/
$results = @$this->userMeetings($user)->getQuery()->getResult();
$list = [];
if ($results) {
foreach ($results as $meeting) {
if ($meeting->startDateTime >= $start && $meeting->startDateTime <= $end) {
$list[] = $meeting;
}
}
}
return $list;
}
/**
* Returns either a course's meetings or all course meetings.
*
* @return ArrayCollection|Collection|Meeting[]
*/
public function courseMeetings(Course $course, CGroupInfo $group = null, Session $session = null)
{
return $this->matching(
Criteria::create()->where(
Criteria::expr()->andX(
Criteria::expr()->eq('group', $group),
Criteria::expr()->eq('course', $course),
Criteria::expr()->eq('session', $session)
)
)
);
}
}

View File

@@ -0,0 +1,65 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
use Chamilo\ClassificationBundle\Entity\Collection;
use Chamilo\UserBundle\Entity\User;
use DateTime;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\EntityRepository;
/**
* Class RecordingRepository.
*/
class RecordingRepository extends EntityRepository
{
public function getPeriodRecordings($startDate, $endDate)
{
$matching = [];
$all = $this->findAll();
foreach ($all as $candidate) {
if ($candidate->startDateTime >= $startDate && $candidate->startDateTime <= $endDate) {
$matching[] = $candidate;
}
}
return $matching;
}
/**
* Returns a user's meeting recordings.
*
* @param User $user
*
* @return ArrayCollection|Collection|Recording[]
*/
/*public function userRecordings($user)
{
return $this->matching(
Criteria::create()->where(
Criteria::expr()->in(
'meeting',
$this->getEntityManager()->getRepository(Meeting::class)->userMeetings($user)->toArray()
)
)
);
}*/
/**
* @param DateTime $start
* @param DateTime $end
* @param User $user
*
* @return ArrayCollection|Recording[]
*/
/*public function getPeriodUserRecordings($start, $end, $user = null)
{
return $this->userRecordings($user)->filter(
function ($meeting) use ($start, $end) {
return $meeting->startDateTime >= $start && $meeting->startDateTime <= $end;
}
);
}*/
}

View File

@@ -0,0 +1,49 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
use Chamilo\UserBundle\Entity\User;
use DateInterval;
use DateTime;
use Doctrine\ORM\EntityRepository;
/**
* Class RegistrantEntityRepository.
*/
class RegistrantRepository extends EntityRepository
{
/**
* Returns the upcoming meeting registrations for the given user.
*
* @param User $user
*
* @return array|Registrant[]
*/
public function meetingsComingSoonRegistrationsForUser($user)
{
$start = new DateTime();
$end = new DateTime();
$end->add(new DateInterval('P7D'));
$meetings = $this->getEntityManager()->getRepository(Meeting::class)->periodMeetings($start, $end);
return $this->findBy(['meeting' => $meetings, 'user' => $user]);
}
public function findByMeetingPaginated(Meeting $meeting, int $from, int $limit, string $column, string $direction)
{
$queryBuilder = $this->createQueryBuilder('r')
->join('r.user', 'u')
->leftJoin('r.signature', 's')
->where('r.meeting = :meeting')
->setFirstResult($from)
->setMaxResults($limit)
->orderBy($column, $direction)
;
$queryBuilder->setParameter('meeting', $meeting);
return $queryBuilder->getQuery()->getResult();
}
}

File diff suppressed because it is too large Load Diff