fixed Zoom meeting start time and duration formating - refs BT#17288

using Zoom API class-inheriting proper business classes :
CourseMeeting, CourseMeetingListItem …
making main code easier to read and maintain
pull/3274/head
Sébastien Ducoulombier 6 years ago
parent 0b9197d56d
commit 94c17ca5d2
  1. 2
      plugin/zoom/admin.php
  2. 1
      plugin/zoom/lang/english.php
  3. 1
      plugin/zoom/lang/french.php
  4. 25
      plugin/zoom/lib/API/BaseMeetingTrait.php
  5. 4
      plugin/zoom/lib/API/CreatedRegistration.php
  6. 4
      plugin/zoom/lib/API/JWTClient.php
  7. 14
      plugin/zoom/lib/API/JsonDeserializableTrait.php
  8. 40
      plugin/zoom/lib/API/Meeting.php
  9. 2
      plugin/zoom/lib/API/MeetingInfo.php
  10. 2
      plugin/zoom/lib/API/MeetingInfoGet.php
  11. 2
      plugin/zoom/lib/API/MeetingInstance.php
  12. 12
      plugin/zoom/lib/API/MeetingInstances.php
  13. 10
      plugin/zoom/lib/API/MeetingList.php
  14. 32
      plugin/zoom/lib/API/MeetingListItem.php
  15. 2
      plugin/zoom/lib/API/MeetingRegistrant.php
  16. 2
      plugin/zoom/lib/API/MeetingRegistrantList.php
  17. 2
      plugin/zoom/lib/API/MeetingRegistrantListItem.php
  18. 2
      plugin/zoom/lib/API/MeetingSettings.php
  19. 4
      plugin/zoom/lib/API/Pagination.php
  20. 10
      plugin/zoom/lib/API/ParticipantList.php
  21. 2
      plugin/zoom/lib/API/ParticipantListItem.php
  22. 2
      plugin/zoom/lib/API/PastMeeting.php
  23. 4
      plugin/zoom/lib/API/RecordingFile.php
  24. 12
      plugin/zoom/lib/API/RecordingMeeting.php
  25. 43
      plugin/zoom/lib/CourseMeeting.php
  26. 44
      plugin/zoom/lib/CourseMeetingInfoGet.php
  27. 18
      plugin/zoom/lib/CourseMeetingList.php
  28. 42
      plugin/zoom/lib/CourseMeetingListItem.php
  29. 99
      plugin/zoom/lib/CourseMeetingTrait.php
  30. 65
      plugin/zoom/lib/DisplayableMeetingTrait.php
  31. 150
      plugin/zoom/lib/zoom_plugin.class.php
  32. 15
      plugin/zoom/meeting.php
  33. 11
      plugin/zoom/start.php
  34. 8
      plugin/zoom/view/admin.tpl
  35. 24
      plugin/zoom/view/meeting.tpl
  36. 27
      plugin/zoom/view/start.tpl

@ -2,7 +2,7 @@
/* For license terms, see /license.txt */
use Chamilo\PluginBundle\Zoom\JWTClient;
use Chamilo\PluginBundle\Zoom\API\JWTClient;
$course_plugin = 'zoom'; // needed in order to load the plugin lang variables
$cidReset = true;

@ -36,6 +36,7 @@ $strings['CreatedAt'] = "Created at";
$strings['DeleteMeeting'] = "Delete meeting";
$strings['Details'] = "Details";
$strings['Duration'] = "Duration";
$strings['DurationInMinutes'] = "Duration (in minutes)";
$strings['EndDate'] = "End Date";
$strings['Instant'] = "Instant";
$strings['Join'] = "Join";

@ -34,6 +34,7 @@ $strings['CreatedAt'] = "Créé à";
$strings['DeleteMeeting'] = "Effacer la conférence";
$strings['Details'] = "Détail";
$strings['Duration'] = "Durée";
$strings['DurationInMinutes'] = "Durée (en minutes)";
$strings['EndDate'] = "Date de fin";
$strings['Instant'] = "Instantané";
$strings['Join'] = "Rejoindre";

@ -0,0 +1,25 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
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;
}

@ -1,11 +1,11 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
namespace Chamilo\PluginBundle\Zoom\API;
class CreatedRegistration
{
use JsonDeserializable;
use JsonDeserializableTrait;
/** @var int meeting ID */
public $id;

@ -1,7 +1,7 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
use Firebase\JWT\JWT;
@ -158,7 +158,7 @@ class JWTClient
*
* @throws Exception describing the error (message and code)
*
* @return Meeting meeting
* @return MeetingInfoGet meeting
*/
public function getMeeting($meetingId)
{

@ -1,11 +1,11 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
trait JsonDeserializable
trait JsonDeserializableTrait
{
/**
* Builds a class instance from the Json description of the object.
@ -40,12 +40,10 @@ trait JsonDeserializable
* @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
*/
protected function itemClass($propertyName)
{
throw new Exception(__FUNCTION__.' not implemented for property '.$propertyName.' in class '.static::class);
}
abstract protected function itemClass($propertyName);
/**
* Copies values from another object properties to an instance, recursively.
@ -55,7 +53,7 @@ trait JsonDeserializable
*
* @throws Exception when the source object has an unexpected property
*/
private static function recursivelyCopyObjectProperties($source, &$destination)
protected static function recursivelyCopyObjectProperties($source, &$destination)
{
foreach (get_object_vars($source) as $name => $value) {
if (property_exists($destination, $name)) {

@ -1,38 +1,23 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
class Meeting
{
use JsonDeserializable;
use BaseMeetingTrait;
use JsonDeserializableTrait;
const TYPE_INSTANT = 1;
const TYPE_SCHEDULED = 2;
const TYPE_RECURRING_WITH_NO_FIXED_TIME = 3;
const TYPE_RECURRING_WITH_FIXED_TIME = 8;
/** @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 password to join. [a-z A-Z 0-9 @ - _ *]. Max of 10 characters. */
public $password;
/** @var string description */
public $agenda;
/** @var array field => value */
public $tracking_fields;
@ -52,11 +37,16 @@ class Meeting
}
/**
* Creates a Meeting instance from a topic.
*
* @param string $topic
* @param int $type
*
* @throws Exception
*
* @return static
*/
public static function fromTopicAndType($topic, $type = self::TYPE_SCHEDULED)
protected static function fromTopicAndType($topic, $type = self::TYPE_SCHEDULED)
{
$instance = new static();
$instance->topic = $topic;
@ -64,4 +54,12 @@ class Meeting
return $instance;
}
/**
* @inheritDoc
*/
protected function itemClass($propertyName)
{
throw new Exception("no such array property $propertyName");
}
}

@ -1,7 +1,7 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
namespace Chamilo\PluginBundle\Zoom\API;
class MeetingInfo extends Meeting
{

@ -1,7 +1,7 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
namespace Chamilo\PluginBundle\Zoom\API;
class MeetingInfoGet extends MeetingInfo
{

@ -1,7 +1,7 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
namespace Chamilo\PluginBundle\Zoom\API;
class MeetingInstance
{

@ -1,13 +1,13 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
class MeetingInstances
{
use JsonDeserializable;
use JsonDeserializableTrait;
/** @var MeetingInstance[] List of ended meeting instances. */
public $meetings;
@ -21,13 +21,7 @@ class MeetingInstances
}
/**
* @see JsonDeserializable::itemClass()
*
* @param string $propertyName array property name
*
* @throws Exception on wrong propertyName
*
* @return string
* @inheritDoc
*/
protected function itemClass($propertyName)
{

@ -1,7 +1,7 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
@ -21,13 +21,7 @@ class MeetingList
}
/**
* @see JsonDeserializable::itemClass()
*
* @param string $propertyName array property name
*
* @throws Exception on wrong propertyName
*
* @return string
* @inheritDoc
*/
protected function itemClass($propertyName)
{

@ -1,11 +1,14 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
class MeetingListItem
{
use JsonDeserializable;
use BaseMeetingTrait;
use JsonDeserializableTrait;
/** @var string unique meeting instance ID */
public $uuid;
@ -16,21 +19,6 @@ class MeetingListItem
/** @var string host Zoom user id */
public $host_id;
/** @var string */
public $topic;
/** @var int @see Meeting */
public $type;
/** @var string */
public $start_time;
/** @var int in minutes */
public $duration;
/** @var string */
public $timezone;
/** @var string */
public $created_at;
@ -38,5 +26,13 @@ class MeetingListItem
public $join_url;
/** @var string truncated to 250 characters */
public $agenda;
// public $agenda;
/**
* @inheritDoc
*/
protected function itemClass($propertyName)
{
throw new Exception("no such array property $propertyName");
}
}

@ -1,7 +1,7 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
namespace Chamilo\PluginBundle\Zoom\API;
class MeetingRegistrant
{

@ -1,7 +1,7 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
namespace Chamilo\PluginBundle\Zoom\API;
class MeetingRegistrantList
{

@ -1,7 +1,7 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
namespace Chamilo\PluginBundle\Zoom\API;
class MeetingRegistrantListItem extends MeetingRegistrant
{

@ -1,7 +1,7 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
namespace Chamilo\PluginBundle\Zoom\API;
class MeetingSettings
{

@ -1,11 +1,11 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
namespace Chamilo\PluginBundle\Zoom\API;
trait Pagination
{
use JsonDeserializable;
use JsonDeserializableTrait;
/** @var int */
public $page_count;

@ -1,7 +1,7 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
@ -21,13 +21,7 @@ class ParticipantList
}
/**
* @see JsonDeserializable::itemClass()
*
* @param string $propertyName array property name
*
* @throws Exception on wrong propertyName
*
* @return string
* @inheritDoc
*/
protected function itemClass($propertyName)
{

@ -1,7 +1,7 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
namespace Chamilo\PluginBundle\Zoom\API;
class ParticipantListItem
{

@ -1,7 +1,7 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
namespace Chamilo\PluginBundle\Zoom\API;
class PastMeeting extends Meeting
{

@ -1,11 +1,11 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
namespace Chamilo\PluginBundle\Zoom\API;
class RecordingFile
{
use JsonDeserializable;
use JsonDeserializableTrait;
/** @var string The recording file ID. Included in the response of general query. */
public $id;

@ -1,13 +1,13 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
class RecordingMeeting
{
use JsonDeserializable;
use JsonDeserializableTrait;
/** @var string Unique Meeting Identifier. Each instance of the meeting will have its own UUID. */
public $uuid;
@ -48,13 +48,7 @@ class RecordingMeeting
}
/**
* @see JsonDeserializable::itemClass()
*
* @param string $propertyName array property name
*
* @throws Exception on wrong propertyName
*
* @return string
* @inheritDoc
*/
protected function itemClass($propertyName)
{

@ -0,0 +1,43 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
use Exception;
class CourseMeeting extends API\Meeting
{
use CourseMeetingTrait;
use DisplayableMeetingTrait;
/**
* @inheritDoc
*/
public static function fromJson($json)
{
$instance = parent::fromJson($json);
$instance->decodeAndRemoveTag();
$instance->initializeDisplayableProperties();
return $instance;
}
/**
* Creates a CourseMeeting instance from a topic.
*
* @param int $courseId
* @param int $sessionId
* @param string $topic
* @param int $type
*
* @throws Exception
*
* @return static
*/
public static function fromCourseSessionTopicAndType($courseId, $sessionId, $topic, $type)
{
$instance = parent::fromTopicAndType($topic, $type);
$instance->setCourseAndSessionId($courseId, $sessionId);
$instance->initializeDisplayableProperties();
return $instance;
}
}

@ -0,0 +1,44 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
use Exception;
class CourseMeetingInfoGet extends API\MeetingInfoGet
{
use CourseMeetingTrait;
use DisplayableMeetingTrait;
/**
* @inheritDoc
*/
public static function fromJson($json)
{
$instance = parent::fromJson($json);
$instance->decodeAndRemoveTag();
$instance->initializeDisplayableProperties();
return $instance;
}
/**
* CourseMeetingListItem constructor.
*
* @param API\MeetingInfoGet $meeting
*
* @throws Exception
*
* @return static
*/
public static function fromMeetingInfoGet($meeting)
{
$instance = new static();
self::recursivelyCopyObjectProperties($meeting, $instance);
$instance->decodeAndRemoveTag();
$instance->loadCourse();
$instance->loadSession();
$instance->initializeDisplayableProperties();
return $instance;
}
}

@ -0,0 +1,18 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
class CourseMeetingList extends API\MeetingList
{
/**
* @inheritDoc
*/
protected function itemClass($propertyName)
{
if ('meetings' === $propertyName) {
return CourseMeetingListItem::class;
}
return parent::itemClass($propertyName);
}
}

@ -0,0 +1,42 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
use Exception;
class CourseMeetingListItem extends API\MeetingListItem
{
use CourseMeetingTrait;
use DisplayableMeetingTrait;
/**
* @inheritDoc
*/
public static function fromJson($json)
{
$instance = parent::fromJson($json);
$instance->decodeAndRemoveTag();
$instance->initializeDisplayableProperties();
return $instance;
}
/**
* CourseMeetingListItem constructor.
*
* @param API\MeetingListItem $meetingListItem
*
* @throws Exception
*
* @return static
*/
public static function fromMeetingListItem($meetingListItem)
{
$instance = new static();
self::recursivelyCopyObjectProperties($meetingListItem, $instance);
$instance->decodeAndRemoveTag();
$instance->initializeDisplayableProperties();
return $instance;
}
}

@ -0,0 +1,99 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
/**
* Trait CourseMeetingTrait.
* A Zoom meeting linked to a (course, session) pair
*
* @package Chamilo\PluginBundle\Zoom
*/
trait CourseMeetingTrait
{
use API\BaseMeetingTrait;
/** @var bool whether the agenda contains the course and session identifiers */
public $isTaggedWithCourseId;
/** @var int meeting course id as found in the agenda field */
public $courseId;
/** @var array meeting course info */
public $course;
/** @var int meeting session id as found in the agenda field */
public $sessionId;
/** @var array meeting session info */
public $session;
public function loadCourse()
{
$this->course = api_get_course_info_by_id($this->courseId); // TODO cache
}
public function loadSession()
{
$this->session = api_get_session_info($this->sessionId); // TODO cache
}
public function setCourseAndSessionId($courseId, $sessionId)
{
$this->courseId = $courseId;
$this->sessionId = $sessionId;
}
public function tagAgenda()
{
$this->agenda = $this->getUntaggedAgenda().$this->getTag();
}
public function untagAgenda()
{
$this->agenda = $this->getUntaggedAgenda();
}
/**
* @param int $courseId
* @param int $sessionId
*
* @return bool whether both values match this CourseMeeting
*/
public function matches($courseId, $sessionId)
{
return $courseId == $this->courseId && $sessionId == $this->sessionId;
}
protected function decodeAndRemoveTag()
{
$this->isTaggedWithCourseId = preg_match(self::getTagPattern(), $this->agenda, $matches);
if ($this->isTaggedWithCourseId) {
$this->setCourseAndSessionId($matches['courseId'], $matches['sessionId']);
$this->untagAgenda();
} else {
$this->setCourseAndSessionId(0, 0);
}
$this->course = [];
$this->session = [];
}
protected function getUntaggedAgenda()
{
return str_replace($this->getTag(), '', $this->agenda);
}
/**
* @return string a tag to append to a meeting agenda so to link it to a (course, session) tuple
*/
private function getTag()
{
return "\n(course $this->courseId, session $this->sessionId)";
}
private static function getTagPattern()
{
return '/course (?P<courseId>\d+), session (?P<sessionId>\d+)/m';
}
}

@ -0,0 +1,65 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
use DateInterval;
use DateTime;
use DateTimeZone;
use Exception;
trait DisplayableMeetingTrait
{
use API\BaseMeetingTrait;
/** @var string meeting type name */
public $typeName;
/** @var DateTime meeting start time as a DateTime instance */
public $startDateTime;
/** @var string meeting formatted start time */
public $formattedStartTime;
/** @var DateInterval meeting duration as a DateInterval instance */
public $durationInterval;
/** @var string meeting formatted duration */
public $formattedDuration;
/** @var string meeting details URL */
public $detailURL;
/**
* @throws Exception on unexpected start_time or duration
*/
public function initializeDisplayableProperties()
{
$this->typeName = [
API\Meeting::TYPE_INSTANT => get_lang('Instant'),
API\Meeting::TYPE_SCHEDULED => get_lang('Scheduled'),
API\Meeting::TYPE_RECURRING_WITH_NO_FIXED_TIME => get_lang('RecurringWithNoFixedTime'),
API\Meeting::TYPE_RECURRING_WITH_FIXED_TIME => get_lang('RecurringWithFixedTime'),
][$this->type];
$this->startDateTime = null;
$this->formattedStartTime = '';
$this->durationInterval = null;
$this->formattedDuration = '';
if (!empty($this->start_time)) {
$this->startDateTime = new DateTime($this->start_time);
$this->startDateTime->setTimezone(new DateTimeZone(date_default_timezone_get()));
$this->formattedStartTime = $this->startDateTime->format(get_lang('Y-m-d H:i'));
}
if (!empty($this->duration)) {
$now = new DateTime();
$later = new DateTime();
$later->add(new DateInterval('PT' . $this->duration . 'M'));
$this->durationInterval = $later->diff($now);
$this->formattedDuration = $this->durationInterval->format(get_lang('%Hh%I'));
}
if (property_exists($this, 'id')) {
$this->detailURL = 'meeting.php?meetingId=' . $this->id;
}
}
}

@ -2,17 +2,15 @@
/* For licensing terms, see /license.txt */
use Chamilo\PluginBundle\Zoom\JWTClient;
use Chamilo\PluginBundle\Zoom\Meeting;
use Chamilo\PluginBundle\Zoom\MeetingInfoGet;
use Chamilo\PluginBundle\Zoom\MeetingListItem;
use Chamilo\PluginBundle\Zoom\ParticipantListItem;
use Chamilo\PluginBundle\Zoom\RecordingMeeting;
use Chamilo\PluginBundle\Zoom\API\JWTClient;
use Chamilo\PluginBundle\Zoom\API\ParticipantListItem;
use Chamilo\PluginBundle\Zoom\API\RecordingMeeting;
use Chamilo\PluginBundle\Zoom\CourseMeeting;
use Chamilo\PluginBundle\Zoom\CourseMeetingInfoGet;
use Chamilo\PluginBundle\Zoom\CourseMeetingListItem;
class ZoomPlugin extends Plugin
{
const TABLE_NAME = 'plugin_zoom_meeting';
public $isCoursePlugin = true;
protected function __construct()
@ -67,7 +65,7 @@ class ZoomPlugin extends Plugin
*
* @throws Exception on API error
*
* @return MeetingListItem[] matching meetings with extra_data
* @return CourseMeetingListItem[] matching meetings
*/
public function getPeriodMeetings($type, $startDate, $endDate)
{
@ -76,14 +74,21 @@ class ZoomPlugin extends Plugin
if (property_exists($meeting, 'start_time')) {
$startTime = new DateTime($meeting->start_time);
if ($startDate <= $startTime && $startTime <= $endDate) {
$matchingMeetings[] = $meeting;
$matchingMeeting = CourseMeetingListItem::fromMeetingListItem($meeting);
$matchingMeeting->loadCourse();
$matchingMeeting->loadSession();
$matchingMeetings[] = $matchingMeeting;
}
}
}
return $this->computeMeetingExtraData($matchingMeetings);
return $matchingMeetings;
}
/**
* @return bool whether the logged-in user can manage conferences in this context, that is either
* the current course or session coach, the platform admin or the current course admin
*/
public function userIsConferenceManager()
{
return api_is_coach()
@ -92,17 +97,17 @@ class ZoomPlugin extends Plugin
}
/**
* Retrieves a meeting properties and extra_data.
* Retrieves a meeting properties.
*
* @param int $meetingId
*
* @throws Exception
*
* @return Meeting
* @return CourseMeetingInfoGet
*/
public function getMeeting($meetingId)
{
return $this->computeMeetingExtraData([$this->jwtClient()->getMeeting($meetingId)])[0];
return CourseMeetingInfoGet::fromMeetingInfoGet($this->jwtClient()->getMeeting($meetingId));
}
/**
@ -110,11 +115,11 @@ class ZoomPlugin extends Plugin
*
* @throws Exception on API error
*
* @return Meeting[] matching meetings
* @return CourseMeetingListItem[] matching meetings
*/
public function getLiveMeetings()
{
return $this->computeMeetingExtraData($this->getMeetings(JWTClient::MEETING_LIST_TYPE_LIVE));
return $this->getMeetings(JWTClient::MEETING_LIST_TYPE_LIVE);
}
/**
@ -122,11 +127,11 @@ class ZoomPlugin extends Plugin
*
* @throws Exception on API error
*
* @return Meeting[] matching meetings
* @return CourseMeetingListItem[] matching meetings
*/
public function getScheduledMeetings()
{
return $this->computeMeetingExtraData($this->getMeetings(JWTClient::MEETING_LIST_TYPE_SCHEDULED));
return $this->getMeetings(JWTClient::MEETING_LIST_TYPE_SCHEDULED);
}
/**
@ -134,11 +139,11 @@ class ZoomPlugin extends Plugin
*
* @throws Exception on API error
*
* @return Meeting[] matching meetings
* @return CourseMeetingListItem[] matching meetings
*/
public function getUpcomingMeetings()
{
return $this->computeMeetingExtraData($this->getMeetings(JWTClient::MEETING_LIST_TYPE_UPCOMING));
return $this->getMeetings(JWTClient::MEETING_LIST_TYPE_UPCOMING);
}
/**
@ -146,7 +151,7 @@ class ZoomPlugin extends Plugin
*
* @throws Exception describing the error (message and code)
*
* @return MeetingInfoGet meeting
* @return CourseMeetingInfoGet meeting
*/
public function createInstantMeeting()
{
@ -158,7 +163,12 @@ class ZoomPlugin extends Plugin
}
$courseInfo = api_get_course_info();
$topic .= $courseInfo['title'].', '.date('yy-m-d H:i');
$meeting = Meeting::fromTopicAndType($topic, Meeting::TYPE_INSTANT);
$meeting = CourseMeeting::fromCourseSessionTopicAndType(
api_get_course_int_id(),
api_get_session_id(),
$topic,
CourseMeeting::TYPE_INSTANT
);
return $this->createMeeting($meeting);
}
@ -174,11 +184,16 @@ class ZoomPlugin extends Plugin
*
* @throws Exception describing the error (message and code)
*
* @return MeetingInfoGet meeting
* @return CourseMeetingInfoGet meeting
*/
public function createScheduledMeeting($startTime, $duration, $topic, $agenda = '', $password = '')
{
$meeting = Meeting::fromTopicAndType($topic, Meeting::TYPE_SCHEDULED);
$meeting = CourseMeeting::fromCourseSessionTopicAndType(
api_get_course_int_id(),
api_get_session_id(),
$topic,
CourseMeeting::TYPE_SCHEDULED
);
$meeting->duration = $duration;
$meeting->start_time = $startTime->format(DateTimeInterface::ISO8601);
$meeting->agenda = $agenda;
@ -190,14 +205,14 @@ class ZoomPlugin extends Plugin
/**
* Updates a meeting.
*
* @param int $meetingId
* @param Meeting $meeting with updated properties
* @param int $meetingId
* @param CourseMeetingInfoGet $meeting with updated properties
*
* @throws Exception on API error
*/
public function updateMeeting($meetingId, $meeting)
{
$meeting->agenda .= $this->agendaTag();
$meeting->tagAgenda();
$this->jwtClient()->updateMeeting($meetingId, $meeting);
}
@ -291,27 +306,6 @@ class ZoomPlugin extends Plugin
return $jwtClient;
}
/**
* @return string a tag to append to a meeting agenda so to link it to a (course, session) tuple
*/
private function agendaTag()
{
$courseId = api_get_course_int_id();
$sessionId = api_get_session_id();
return "\n(course $courseId, session $sessionId)";
}
private function courseIdAndSessionIdFromAgenda($agenda)
{
return preg_match('/course (?P<courseId>\d+), session (?P<sessionId>\d+)/m', $agenda, $matches)
? $matches
: [
'courseId' => 0,
'sessionId' => 0,
];
}
/**
* Retrieves all meetings of a specific type and linked to current course and session.
*
@ -319,76 +313,36 @@ class ZoomPlugin extends Plugin
*
* @throws Exception on API error
*
* @return MeetingListItem[] matching meetings
* @return CourseMeetingListItem[] matching meetings
*/
private function getMeetings($type)
{
$matchingMeetings = [];
$tag = $this->agendaTag();
$courseId = api_get_course_int_id();
$sessionId = api_get_session_id();
foreach ($this->jwtClient()->getMeetings($type) as $meeting) {
if (property_exists($meeting, 'agenda') && substr($meeting->agenda, -strlen($tag)) === $tag) {
$matchingMeetings[] = $meeting;
$candidateMeeting = CourseMeetingListItem::fromMeetingListItem($meeting);
if ($candidateMeeting->matches($courseId, $sessionId)) {
$matchingMeetings[] = $candidateMeeting;
}
}
return $matchingMeetings;
}
/**
* Computes and append extra data for each listed meeting.
*
* @param MeetingListItem[] $meetings list of retrieved meetings
*
* @throws Exception on API error
*
* @return Meeting[]|MeetingListItem[] same meetings with extra_data added
*/
private function computeMeetingExtraData($meetings)
{
$completeMeetings = [];
$tag = $this->agendaTag();
$typeNames = [
Meeting::TYPE_INSTANT => get_lang('Instant'),
Meeting::TYPE_SCHEDULED => get_lang('Scheduled'),
Meeting::TYPE_RECURRING_WITH_NO_FIXED_TIME => get_lang('RecurringWithNoFixedTime'),
Meeting::TYPE_RECURRING_WITH_FIXED_TIME => get_lang('RecurringWithFixedTime'),
];
foreach ($meetings as $meeting) {
$completeMeeting = $meeting;
$startTime = new DateTime($meeting->start_time);
$duration = new DateInterval('PT'.$meeting->duration.'M');
$completeMeeting->extra_data = [
'type_name' => $typeNames[$meeting->type],
'formatted_start_time' => $startTime->format(get_lang('Y-m-d H:i')),
'formatted_duration' => $duration->format(get_lang('%Hh%I')),
'meeting_details_url' => 'meeting.php?meetingId='.$meeting->id,
];
if (property_exists($meeting, 'agenda')) {
$completeMeeting->extra_data['stripped_agenda'] = substr($meeting->agenda, 0, -strlen($tag));
$courseIdAndSessionId = $this->courseIdAndSessionIdFromAgenda($meeting->agenda);
$completeMeeting->extra_data['course'] = api_get_course_info_by_id($courseIdAndSessionId['courseId']);
$completeMeeting->extra_data['session'] = api_get_session_info($courseIdAndSessionId['sessionId']);
}
$completeMeetings[] = $completeMeeting;
}
return $completeMeetings;
}
/**
* Creates a meeting and returns it.
*
* @param Meeting $meeting a meeting with at least a type and a topic
* @param CourseMeeting $meeting a meeting with at least a type and a topic
*
* @throws Exception describing the error (message and code)
*
* @return MeetingInfoGet meeting
* @return CourseMeetingInfoGet meeting
*/
private function createMeeting($meeting)
{
$meeting->settings->auto_recording = 'cloud';
$meeting->agenda .= $this->agendaTag();
return $this->jwtClient()->createMeeting($meeting);
$meeting->tagAgenda();
return CourseMeetingInfoGet::fromMeetingInfoGet($this->jwtClient()->createMeeting($meeting));
}
}

@ -1,8 +1,6 @@
<?php
/* For license terms, see /license.txt */
use Chamilo\PluginBundle\Zoom\Meeting;
$course_plugin = 'zoom'; // needed in order to load the plugin lang variables
require_once __DIR__.'/config.php';
@ -30,12 +28,14 @@ if ($plugin->userIsConferenceManager()) {
$editMeetingForm = new FormValidator('editMeetingForm');
$editMeetingForm->addHidden('meetingId', $meeting->id);
if (Meeting::TYPE_SCHEDULED === $meeting->type
if ($meeting::TYPE_SCHEDULED === $meeting->type
||
Meeting::TYPE_RECURRING_WITH_FIXED_TIME === $meeting->type
$meeting::TYPE_RECURRING_WITH_FIXED_TIME === $meeting->type
) {
$startTimeDatePicker = $editMeetingForm->addDateTimePicker('start_time', get_lang('StartTime'));
$durationNumeric = $editMeetingForm->addNumeric('duration', get_lang('Duration'));
$editMeetingForm->setRequired($startTimeDatePicker);
$durationNumeric = $editMeetingForm->addNumeric('duration', get_lang('DurationInMinutes'));
$editMeetingForm->setRequired($durationNumeric);
}
$topicText = $editMeetingForm->addText('topic', get_lang('Topic'));
$agendaTextArea = $editMeetingForm->addTextarea('agenda', get_lang('Agenda'), ['maxlength' => 2000]);
@ -43,6 +43,7 @@ if ($plugin->userIsConferenceManager()) {
$editMeetingForm->addButtonUpdate(get_lang('UpdateMeeting'));
if ($editMeetingForm->validate()) {
$meeting->start_time = $editMeetingForm->getSubmitValue('start_time');
$meeting->timezone = date_default_timezone_get();
$meeting->duration = $editMeetingForm->getSubmitValue('duration');
$meeting->topic = $editMeetingForm->getSubmitValue('topic');
$meeting->agenda = $editMeetingForm->getSubmitValue('agenda');
@ -58,10 +59,10 @@ if ($plugin->userIsConferenceManager()) {
try {
$editMeetingForm->setDefaults(
[
'start_time' => $meeting->start_time,
'start_time' => $meeting->startDateTime->format('c'),
'duration' => $meeting->duration,
'topic' => $meeting->topic,
'agenda' => $meeting->extra_data['stripped_agenda'],
'agenda' => $meeting->agenda,
]
);
} catch (Exception $exception) {

@ -43,7 +43,8 @@ if ($plugin->userIsConferenceManager()) {
$scheduleMeetingForm = new FormValidator('scheduleMeetingForm');
$startTimeDatePicker = $scheduleMeetingForm->addDateTimePicker('start_time', get_lang('StartTime'));
$scheduleMeetingForm->setRequired($startTimeDatePicker);
$durationNumeric = $scheduleMeetingForm->addNumeric('duration', get_lang('Duration'));
$durationNumeric = $scheduleMeetingForm->addNumeric('duration', get_lang('DurationInMinutes'));
$scheduleMeetingForm->setRequired($durationNumeric);
$topicText = $scheduleMeetingForm->addText('topic', get_lang('Topic'), true);
$agendaTextArea = $scheduleMeetingForm->addTextarea('agenda', get_lang('Agenda'), ['maxlength' => 2000]);
// $passwordText = $scheduleMeetingForm->addText('password', get_lang('Password'), false, ['maxlength' => '10']);
@ -79,14 +80,6 @@ if ($plugin->userIsConferenceManager()) {
$tpl->assign('scheduleMeetingForm', $scheduleMeetingForm->returnForm());
}
try {
$tpl->assign('liveMeetings', $plugin->getLiveMeetings());
} catch (Exception $exception) {
Display::addFlash(
Display::return_message('Could not retrieve live meeting list: '.$exception->getMessage(), 'error')
);
}
try {
$tpl->assign('scheduledMeetings', $plugin->getScheduledMeetings());
} catch (Exception $exception) {

@ -12,12 +12,12 @@
<tbody>
{% for meeting in meetings %}
<tr>
<td>{{ meeting.extra_data.formatted_start_time }}</td>
<td>{{ meeting.extra_data.course ? meeting.extra_data.course.title : '-' }}</td>
<td>{{ meeting.extra_data.session ? meeting.extra_data.session.name : '-' }}</td>
<td>{{ meeting.formattedStartTime }}</td>
<td>{{ meeting.course ? meeting.course.title : '-' }}</td>
<td>{{ meeting.session ? meeting.session.name : '-' }}</td>
<td>{{ meeting.topic }}</td>
<td>
<a class="btn" href="{{ meeting.extra_data.meeting_details_url }} ">
<a class="btn" href="{{ meeting.detailURL }} ">
{{ 'Details'|get_lang }}
</a>
</td>

@ -1,19 +1,25 @@
<div class="page-header">
<h2>{{ 'Meeting'|get_lang }}</h2>
</div>
<dl>
<style>
dl.meeting_properties dt {
margin-top: 1em;
font-size: smaller;
}
</style>
<dl class="meeting_properties">
<dt>{{ 'Course'|get_lang }}</dt>
<dd>
{% if meeting.extra_data.course %}
<a href="{{ meeting.extra_data.course.course_public_url }}">
{{ meeting.extra_data.course.title }}
{% if meeting.course %}
<a href="{{ meeting.course.course_public_url }}">
{{ meeting.course.title }}
</a>
{% else %}
-
{% endif %}
</dd>
<dt>{{ 'Session'|get_lang }}</dt>
<dd>{{ meeting.extra_data.session ? meeting.extra_data.session.name : '-' }}</dd>
<dd>{{ meeting.session ? meeting.session.name : '-' }}</dd>
<dt>{{ 'Status'|get_lang }}</dt>
<dd>{{ meeting.status }}</dd>
@ -22,16 +28,16 @@
<dd>{{ meeting.topic }}</dd>
<dt>{{ 'Agenda'|get_lang }}</dt>
<dd>{{ meeting.extra_data.stripped_agenda| nl2br }}</dd>
<dd>{{ meeting.agenda| nl2br }}</dd>
<dt>{{ 'Type'|get_lang }}</dt>
<dd>{{meeting.extra_data.type_name}}</dd>
<dd>{{meeting.typeName}}</dd>
<dt>{{ 'StartTime'|get_lang }}</dt>
<dd>{{ meeting.extra_data.formatted_start_time }}</dd>
<dd>{{ meeting.formattedStartTime }}</dd>
<dt>{{ 'Duration'|get_lang }}</dt>
<dd>({{ meeting.extra_data.formatted_duration }})</dd>
<dd>{{ meeting.formattedDuration }}</dd>
{% if isConferenceManager %}

@ -1,23 +1,6 @@
{% if liveMeetings %}
<div class="page-header">
<h2>{{ 'LiveMeetings'|get_lang }}</h2>
</div>
{% for meeting in liveMeetings %}
<h3>{{ meeting.topic }}</h3>
<p>{{ meeting.agenda }}</p>
<p>
<a class="btn btn-default" href="{{ meeting.join_url }} ">
{{ 'Join'|get_lang }}
</a>
</p>
{% endfor %}
{% else %}
<!-- p>No live meeting currently</p -->
{% endif %}
{% if createInstantMeetingForm %}
{{ createInstantMeetingForm }}
{% endif %}
</div>
<div class ="col-md-12">
{% if scheduledMeetings %}
<div class="page-header">
@ -35,15 +18,15 @@
{% for meeting in scheduledMeetings %}
<tr>
<!-- td>{{ meeting.created_at }}</td -->
<td>{{ meeting.extra_data.formatted_start_time }}</td>
<td>{{ meeting.extra_data.formatted_duration }}</td>
<!-- td>{{ meeting.extra_data.type_name }}</td -->
<td>{{ meeting.formattedStartTime }}</td>
<td>{{ meeting.formattedDuration }}</td>
<!-- td>{{ meeting.typeName }}</td -->
<td>
<strong>{{ meeting.topic }}</strong>
<p class="small">{{ meeting.extra_data.stripped_agenda| nl2br }}</p>
<p class="small">{{ meeting.agenda| nl2br }}</p>
</td>
<td>
<a class="btn" href="{{ meeting.extra_data.meeting_details_url }} ">
<a class="btn" href="{{ meeting.detailURL }} ">
{{ 'Details'|get_lang }}
</a>
<a class="btn" href="{{ meeting.join_url }} ">

Loading…
Cancel
Save