Actualización
706
plugin/zoom/Entity/Meeting.php
Normal file
@@ -0,0 +1,706 @@
|
||||
<?php
|
||||
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
namespace Chamilo\PluginBundle\Zoom;
|
||||
|
||||
use Chamilo\CoreBundle\Entity\Course;
|
||||
use Chamilo\CoreBundle\Entity\CourseRelUser;
|
||||
use Chamilo\CoreBundle\Entity\Session;
|
||||
use Chamilo\CoreBundle\Entity\SessionRelCourseRelUser;
|
||||
use Chamilo\CoreBundle\Entity\SysAnnouncement;
|
||||
use Chamilo\CourseBundle\Entity\CGroupInfo;
|
||||
use Chamilo\PluginBundle\Zoom\API\BaseMeetingTrait;
|
||||
use Chamilo\PluginBundle\Zoom\API\MeetingInfoGet;
|
||||
use Chamilo\PluginBundle\Zoom\API\MeetingListItem;
|
||||
use Chamilo\PluginBundle\Zoom\API\MeetingSettings;
|
||||
use Chamilo\UserBundle\Entity\User;
|
||||
use Database;
|
||||
use DateInterval;
|
||||
use DateTime;
|
||||
use DateTimeZone;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Class Meeting.
|
||||
*
|
||||
* @ORM\Entity(repositoryClass="Chamilo\PluginBundle\Zoom\MeetingRepository")
|
||||
* @ORM\Table(
|
||||
* name="plugin_zoom_meeting",
|
||||
* indexes={
|
||||
* @ORM\Index(name="user_id_index", columns={"user_id"}),
|
||||
* @ORM\Index(name="course_id_index", columns={"course_id"}),
|
||||
* @ORM\Index(name="session_id_index", columns={"session_id"})
|
||||
* }
|
||||
* )
|
||||
* @ORM\HasLifecycleCallbacks
|
||||
* @ORM\InheritanceType("SINGLE_TABLE")
|
||||
* @ORM\DiscriminatorColumn(name="type", type="string")
|
||||
* @ORM\DiscriminatorMap({"meeting" = "Chamilo\PluginBundle\Zoom\Meeting", "webinar" = "Chamilo\PluginBundle\Zoom\Webinar"})
|
||||
*/
|
||||
class Meeting
|
||||
{
|
||||
/** @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 */
|
||||
public $statusName;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @ORM\Column(type="integer", name="id")
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue()
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @var int the remote zoom meeting identifier
|
||||
* @ORM\Column(name="meeting_id", type="string")
|
||||
*/
|
||||
protected $meetingId;
|
||||
|
||||
/**
|
||||
* @var User
|
||||
* @ORM\ManyToOne(targetEntity="Chamilo\UserBundle\Entity\User")
|
||||
* @ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=true)
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* @var Course
|
||||
* @ORM\ManyToOne(targetEntity="Chamilo\CoreBundle\Entity\Course")
|
||||
* @ORM\JoinColumn(name="course_id", referencedColumnName="id", nullable=true)
|
||||
*/
|
||||
protected $course;
|
||||
|
||||
/**
|
||||
* @var CGroupInfo
|
||||
* @ORM\ManyToOne(targetEntity="Chamilo\CourseBundle\Entity\CGroupInfo")
|
||||
* @ORM\JoinColumn(name="group_id", referencedColumnName="iid", nullable=true)
|
||||
*/
|
||||
protected $group;
|
||||
|
||||
/**
|
||||
* @var Session
|
||||
* @ORM\ManyToOne(targetEntity="Chamilo\CoreBundle\Entity\Session")
|
||||
* @ORM\JoinColumn(name="session_id", referencedColumnName="id", nullable=true)
|
||||
*/
|
||||
protected $session;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @ORM\Column(type="text", name="meeting_list_item_json", nullable=true)
|
||||
*/
|
||||
protected $meetingListItemJson;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @ORM\Column(type="text", name="meeting_info_get_json", nullable=true)
|
||||
*/
|
||||
protected $meetingInfoGetJson;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*
|
||||
* @ORM\Column(type="boolean", name="sign_attendance")
|
||||
*/
|
||||
protected $signAttendance;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*
|
||||
* @ORM\Column(type="text", name="reason_to_sign_attendance", nullable=true)
|
||||
*/
|
||||
protected $reasonToSignAttendance;
|
||||
|
||||
/** @var MeetingListItem */
|
||||
protected $meetingListItem;
|
||||
|
||||
/** @var MeetingInfoGet */
|
||||
protected $meetingInfoGet;
|
||||
|
||||
/**
|
||||
* @var MeetingActivity[]|ArrayCollection
|
||||
* @ORM\OrderBy({"createdAt" = "DESC"})
|
||||
* @ORM\OneToMany(targetEntity="MeetingActivity", mappedBy="meeting", cascade={"persist", "remove"})
|
||||
*/
|
||||
protected $activities;
|
||||
|
||||
/**
|
||||
* @var Registrant[]|ArrayCollection
|
||||
*
|
||||
* @ORM\OneToMany(targetEntity="Registrant", mappedBy="meeting", cascade={"persist", "remove"})
|
||||
*/
|
||||
protected $registrants;
|
||||
|
||||
/**
|
||||
* @var Recording[]|ArrayCollection
|
||||
*
|
||||
* @ORM\OneToMany(targetEntity="Recording", mappedBy="meeting", cascade={"persist"}, orphanRemoval=true)
|
||||
*/
|
||||
protected $recordings;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*
|
||||
* @ORM\Column(type="string", name="account_email", nullable=true)
|
||||
*/
|
||||
protected $accountEmail;
|
||||
|
||||
/**
|
||||
* @var SysAnnouncement|null
|
||||
*
|
||||
* @ORM\OneToOne(targetEntity="Chamilo\CoreBundle\Entity\SysAnnouncement")
|
||||
* @ORM\JoinColumn(name="sys_announcement_id", referencedColumnName="id", onDelete="SET NULL")
|
||||
*/
|
||||
protected $sysAnnouncement;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->registrants = new ArrayCollection();
|
||||
$this->recordings = new ArrayCollection();
|
||||
$this->activities = new ArrayCollection();
|
||||
$this->signAttendance = false;
|
||||
$this->sysAnnouncement = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return sprintf('Meeting %d', $this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getMeetingId()
|
||||
{
|
||||
return $this->meetingId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $meetingId
|
||||
*
|
||||
* @return Meeting
|
||||
*/
|
||||
public function setMeetingId($meetingId)
|
||||
{
|
||||
$this->meetingId = $meetingId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return User
|
||||
*/
|
||||
public function getUser()
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Course
|
||||
*/
|
||||
public function getCourse()
|
||||
{
|
||||
return $this->course;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Session
|
||||
*/
|
||||
public function getSession()
|
||||
{
|
||||
return $this->session;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Registrant[]|ArrayCollection
|
||||
*/
|
||||
public function getRegistrants()
|
||||
{
|
||||
return $this->registrants->filter(function (Registrant $registrant) {
|
||||
return !$registrant instanceof Presenter;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArrayCollection<int, Presenter>
|
||||
*/
|
||||
public function getPresenters(): ArrayCollection
|
||||
{
|
||||
return $this->registrants->filter(function (Registrant $registrant) {
|
||||
return $registrant instanceof Presenter;
|
||||
});
|
||||
}
|
||||
|
||||
public function hasUserAsPresenter(User $user): bool
|
||||
{
|
||||
$presenters = $this->getPresenters();
|
||||
|
||||
$criteria = Criteria::create();
|
||||
$criteria->where(
|
||||
Criteria::expr()->eq('user', $user)
|
||||
);
|
||||
|
||||
return $presenters->matching($criteria)->count() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Recording[]|ArrayCollection
|
||||
*/
|
||||
public function getRecordings()
|
||||
{
|
||||
return $this->recordings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MeetingActivity[]|ArrayCollection
|
||||
*/
|
||||
public function getActivities()
|
||||
{
|
||||
return $this->activities;
|
||||
}
|
||||
|
||||
public function addActivity(MeetingActivity $activity)
|
||||
{
|
||||
$activity->setMeeting($this);
|
||||
$this->activities[] = $activity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MeetingActivity[]|ArrayCollection $activities
|
||||
*
|
||||
* @return Meeting
|
||||
*/
|
||||
public function setActivities($activities)
|
||||
{
|
||||
$this->activities = $activities;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ORM\PostLoad
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function postLoad()
|
||||
{
|
||||
if (null !== $this->meetingListItemJson) {
|
||||
$this->meetingListItem = MeetingListItem::fromJson($this->meetingListItemJson);
|
||||
}
|
||||
if (null !== $this->meetingInfoGetJson) {
|
||||
$this->meetingInfoGet = MeetingInfoGet::fromJson($this->meetingInfoGetJson);
|
||||
}
|
||||
$this->initializeDisplayableProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* @ORM\PostUpdate
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function postUpdate()
|
||||
{
|
||||
$this->initializeDisplayableProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* @ORM\PreFlush
|
||||
*/
|
||||
public function preFlush()
|
||||
{
|
||||
if (null !== $this->meetingListItem) {
|
||||
$this->meetingListItemJson = json_encode($this->meetingListItem);
|
||||
}
|
||||
if (null !== $this->meetingInfoGet) {
|
||||
$this->meetingInfoGetJson = json_encode($this->meetingInfoGet);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MeetingListItem
|
||||
*/
|
||||
public function getMeetingListItem()
|
||||
{
|
||||
return $this->meetingListItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MeetingInfoGet
|
||||
*/
|
||||
public function getMeetingInfoGet()
|
||||
{
|
||||
return $this->meetingInfoGet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setUser($user)
|
||||
{
|
||||
$this->user = $user;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Course $course
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setCourse($course)
|
||||
{
|
||||
$this->course = $course;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Session $session
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSession($session)
|
||||
{
|
||||
$this->session = $session;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CGroupInfo
|
||||
*/
|
||||
public function getGroup()
|
||||
{
|
||||
return $this->group;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CGroupInfo $group
|
||||
*
|
||||
* @return Meeting
|
||||
*/
|
||||
public function setGroup($group)
|
||||
{
|
||||
$this->group = $group;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MeetingListItem $meetingListItem
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
* @return Meeting
|
||||
*/
|
||||
public function setMeetingListItem($meetingListItem)
|
||||
{
|
||||
if (null === $this->meetingId) {
|
||||
$this->meetingId = $meetingListItem->id;
|
||||
} elseif ($this->meetingId != $meetingListItem->id) {
|
||||
throw new Exception('the Meeting identifier differs from the MeetingListItem identifier');
|
||||
}
|
||||
$this->meetingListItem = $meetingListItem;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MeetingInfoGet|BaseMeetingTrait $meetingInfoGet
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
* @return Meeting
|
||||
*/
|
||||
public function setMeetingInfoGet($meetingInfoGet)
|
||||
{
|
||||
if (null === $this->meetingId) {
|
||||
$this->meetingId = $meetingInfoGet->id;
|
||||
} elseif ($this->meetingId != $meetingInfoGet->id) {
|
||||
throw new Exception('the Meeting identifier differs from the MeetingInfoGet identifier');
|
||||
}
|
||||
$this->meetingInfoGet = $meetingInfoGet;
|
||||
$this->initializeDisplayableProperties();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isCourseMeeting()
|
||||
{
|
||||
return null !== $this->course;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isCourseGroupMeeting()
|
||||
{
|
||||
return null !== $this->course && null !== $this->group;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isUserMeeting()
|
||||
{
|
||||
return null !== $this->user && null === $this->course;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isGlobalMeeting()
|
||||
{
|
||||
return null === $this->user && null === $this->course;
|
||||
}
|
||||
|
||||
public function setStatus($status)
|
||||
{
|
||||
$this->meetingInfoGet->status = $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the list of users that can register into this meeting.
|
||||
* Zoom requires an email address, therefore users without an email address are excluded from the list.
|
||||
*
|
||||
* @return User[] the list of users
|
||||
*/
|
||||
public function getRegistrableUsers()
|
||||
{
|
||||
$users = [];
|
||||
if (!$this->isCourseMeeting()) {
|
||||
$criteria = ['active' => true];
|
||||
$users = Database::getManager()->getRepository('ChamiloUserBundle:User')->findBy($criteria);
|
||||
} elseif (null === $this->session) {
|
||||
if (null !== $this->course) {
|
||||
/** @var CourseRelUser $courseRelUser */
|
||||
foreach ($this->course->getUsers() as $courseRelUser) {
|
||||
$users[] = $courseRelUser->getUser();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (null !== $this->course) {
|
||||
$subscriptions = $this->session->getUserCourseSubscriptionsByStatus($this->course, Session::STUDENT);
|
||||
if ($subscriptions) {
|
||||
/** @var SessionRelCourseRelUser $sessionCourseUser */
|
||||
foreach ($subscriptions as $sessionCourseUser) {
|
||||
$users[] = $sessionCourseUser->getUser();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$activeUsersWithEmail = [];
|
||||
foreach ($users as $user) {
|
||||
if ($user->isActive() && !empty($user->getEmail())) {
|
||||
$activeUsersWithEmail[] = $user;
|
||||
}
|
||||
}
|
||||
|
||||
return $activeUsersWithEmail;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function requiresDateAndDuration()
|
||||
{
|
||||
return MeetingInfoGet::TYPE_SCHEDULED === $this->meetingInfoGet->type
|
||||
|| MeetingInfoGet::TYPE_RECURRING_WITH_FIXED_TIME === $this->meetingInfoGet->type;
|
||||
}
|
||||
|
||||
public function requiresRegistration(): bool
|
||||
{
|
||||
return true; //MeetingSettings::APPROVAL_TYPE_AUTOMATICALLY_APPROVE === $this->meetingInfoGet->settings->approval_type;
|
||||
/*return
|
||||
MeetingSettings::APPROVAL_TYPE_NO_REGISTRATION_REQUIRED != $this->meetingInfoGet->settings->approval_type;*/
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function hasCloudAutoRecordingEnabled()
|
||||
{
|
||||
return \ZoomPlugin::RECORDING_TYPE_NONE !== $this->meetingInfoGet->settings->auto_recording;
|
||||
}
|
||||
|
||||
public function getRegistrantByUser(User $user): ?Registrant
|
||||
{
|
||||
$criteria = Criteria::create()
|
||||
->where(
|
||||
Criteria::expr()->eq('user', $user)
|
||||
)
|
||||
;
|
||||
|
||||
return $this->registrants->matching($criteria)->first() ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a short presentation of the meeting for the future participant.
|
||||
* To be displayed above the "Enter meeting" link.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIntroduction()
|
||||
{
|
||||
$introduction = sprintf('<h1>%s</h1>', $this->getTopic()).PHP_EOL;
|
||||
if (!$this->isGlobalMeeting()) {
|
||||
if (!empty($this->formattedStartTime)) {
|
||||
$introduction .= $this->formattedStartTime;
|
||||
if (!empty($this->formattedDuration)) {
|
||||
$introduction .= ' ('.$this->formattedDuration.')';
|
||||
}
|
||||
$introduction .= PHP_EOL;
|
||||
}
|
||||
}
|
||||
if ($this->user) {
|
||||
$introduction .= sprintf('<p>%s</p>', $this->user->getFullname()).PHP_EOL;
|
||||
} elseif ($this->isCourseMeeting()) {
|
||||
if (null === $this->session) {
|
||||
$introduction .= sprintf('<p class="main">%s</p>', $this->course).PHP_EOL;
|
||||
} else {
|
||||
$introduction .= sprintf('<p class="main">%s (%s)</p>', $this->course, $this->session).PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->getAgenda())) {
|
||||
$introduction .= sprintf('<p>%s</p>', $this->getAgenda()).PHP_EOL;
|
||||
}
|
||||
|
||||
return $introduction;
|
||||
}
|
||||
|
||||
public function isSignAttendance(): bool
|
||||
{
|
||||
return $this->signAttendance;
|
||||
}
|
||||
|
||||
public function setSignAttendance(bool $signAttendance): Meeting
|
||||
{
|
||||
$this->signAttendance = $signAttendance;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAccountEmail(): ?string
|
||||
{
|
||||
return $this->accountEmail;
|
||||
}
|
||||
|
||||
public function setAccountEmail(?string $accountEmail): self
|
||||
{
|
||||
$this->accountEmail = $accountEmail;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getReasonToSignAttendance(): ?string
|
||||
{
|
||||
return $this->reasonToSignAttendance;
|
||||
}
|
||||
|
||||
public function setReasonToSignAttendance(string $reasonToSignAttendance): Meeting
|
||||
{
|
||||
$this->reasonToSignAttendance = $reasonToSignAttendance;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTopic(): string
|
||||
{
|
||||
return $this->meetingInfoGet->topic;
|
||||
}
|
||||
|
||||
public function getAgenda(): ?string
|
||||
{
|
||||
return $this->meetingInfoGet->agenda;
|
||||
}
|
||||
|
||||
public function getSysAnnouncement(): ?SysAnnouncement
|
||||
{
|
||||
return $this->sysAnnouncement;
|
||||
}
|
||||
|
||||
public function setSysAnnouncement(?SysAnnouncement $sysAnnouncement): Meeting
|
||||
{
|
||||
$this->sysAnnouncement = $sysAnnouncement;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception on unexpected start_time or duration
|
||||
*/
|
||||
protected function initializeDisplayableProperties()
|
||||
{
|
||||
$zoomPlugin = new \ZoomPlugin();
|
||||
|
||||
$typeList = [
|
||||
API\Meeting::TYPE_INSTANT => $zoomPlugin->get_lang('InstantMeeting'),
|
||||
API\Meeting::TYPE_SCHEDULED => $zoomPlugin->get_lang('ScheduledMeeting'),
|
||||
API\Meeting::TYPE_RECURRING_WITH_NO_FIXED_TIME => $zoomPlugin->get_lang('RecurringWithNoFixedTime'),
|
||||
API\Meeting::TYPE_RECURRING_WITH_FIXED_TIME => $zoomPlugin->get_lang('RecurringWithFixedTime'),
|
||||
];
|
||||
$this->typeName = $typeList[$this->meetingInfoGet->type];
|
||||
|
||||
if (property_exists($this, 'status')) {
|
||||
$statusList = [
|
||||
'waiting' => $zoomPlugin->get_lang('Waiting'),
|
||||
'started' => $zoomPlugin->get_lang('Started'),
|
||||
'finished' => $zoomPlugin->get_lang('Finished'),
|
||||
];
|
||||
$this->statusName = $statusList[$this->meetingInfoGet->status];
|
||||
}
|
||||
$this->startDateTime = null;
|
||||
$this->formattedStartTime = '';
|
||||
$this->durationInterval = null;
|
||||
$this->formattedDuration = '';
|
||||
if (!empty($this->meetingInfoGet->start_time)) {
|
||||
$this->startDateTime = new DateTime($this->meetingInfoGet->start_time);
|
||||
$this->startDateTime->setTimezone(new DateTimeZone(api_get_timezone()));
|
||||
$this->formattedStartTime = $this->startDateTime->format('Y-m-d H:i');
|
||||
}
|
||||
|
||||
if (!empty($this->meetingInfoGet->duration)) {
|
||||
$now = new DateTime();
|
||||
$later = new DateTime();
|
||||
$later->add(new DateInterval('PT'.$this->meetingInfoGet->duration.'M'));
|
||||
$this->durationInterval = $now->diff($later);
|
||||
$this->formattedDuration = $this->durationInterval->format($zoomPlugin->get_lang('DurationFormat'));
|
||||
}
|
||||
}
|
||||
}
|
||||
208
plugin/zoom/Entity/MeetingActivity.php
Normal file
@@ -0,0 +1,208 @@
|
||||
<?php
|
||||
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
namespace Chamilo\PluginBundle\Zoom;
|
||||
|
||||
use DateTime;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* Class Meeting.
|
||||
*
|
||||
* @ORM\Entity()
|
||||
* @ORM\Table(name="plugin_zoom_meeting_activity")
|
||||
* @ORM\HasLifecycleCallbacks
|
||||
*/
|
||||
class MeetingActivity
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue()
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @var Meeting
|
||||
*
|
||||
* @ORM\ManyToOne(targetEntity="Meeting", inversedBy="activities")
|
||||
* @ORM\JoinColumn(name="meeting_id")
|
||||
*/
|
||||
protected $meeting;
|
||||
|
||||
/**
|
||||
* @var Meeting
|
||||
*
|
||||
* @ORM\ManyToOne(targetEntity="Chamilo\UserBundle\Entity\User")
|
||||
* @ORM\JoinColumn(name="user_id", referencedColumnName="id")
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @ORM\Column(type="string", name="name", length=255, nullable=false)
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @ORM\Column(type="string", name="type", length=255, nullable=false)
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @ORM\Column(type="text", name="event", nullable=true)
|
||||
*/
|
||||
protected $event;
|
||||
|
||||
/**
|
||||
* @var \DateTime
|
||||
*
|
||||
* @ORM\Column(name="created_at", type="datetime", nullable=false)
|
||||
*/
|
||||
protected $createdAt;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->createdAt = new \DateTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return sprintf('Activity %d', $this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Meeting
|
||||
*/
|
||||
public function getMeeting()
|
||||
{
|
||||
return $this->meeting;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Meeting $meeting
|
||||
*
|
||||
* @return MeetingActivity
|
||||
*/
|
||||
public function setMeeting($meeting)
|
||||
{
|
||||
$this->meeting = $meeting;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return MeetingActivity
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
*
|
||||
* @return MeetingActivity
|
||||
*/
|
||||
public function setType($type)
|
||||
{
|
||||
$this->type = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DateTime
|
||||
*/
|
||||
public function getCreatedAt()
|
||||
{
|
||||
return $this->createdAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEvent()
|
||||
{
|
||||
return $this->event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Meeting
|
||||
*/
|
||||
public function getUser()
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Meeting $user
|
||||
*
|
||||
* @return MeetingActivity
|
||||
*/
|
||||
public function setUser($user)
|
||||
{
|
||||
$this->user = $user;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getEventDecoded()
|
||||
{
|
||||
if (!empty($this->event)) {
|
||||
return json_decode($this->event);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $event
|
||||
*
|
||||
* @return MeetingActivity
|
||||
*/
|
||||
public function setEvent($event)
|
||||
{
|
||||
$this->event = $event;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
38
plugin/zoom/Entity/Presenter.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
namespace Chamilo\PluginBundle\Zoom;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* @ORM\Entity()
|
||||
* @ORM\HasLifecycleCallbacks()
|
||||
*/
|
||||
class Presenter extends Registrant
|
||||
{
|
||||
public function __toString()
|
||||
{
|
||||
return sprintf('Presenter %d', $this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ORM\PostLoad()
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function postLoad()
|
||||
{
|
||||
parent::postLoad();
|
||||
}
|
||||
|
||||
/**
|
||||
* @ORM\PreFlush()
|
||||
*/
|
||||
public function preFlush()
|
||||
{
|
||||
parent::preFlush();
|
||||
}
|
||||
}
|
||||
193
plugin/zoom/Entity/Recording.php
Normal file
@@ -0,0 +1,193 @@
|
||||
<?php
|
||||
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
namespace Chamilo\PluginBundle\Zoom;
|
||||
|
||||
use Chamilo\PluginBundle\Zoom\API\RecordingMeeting;
|
||||
use Database;
|
||||
use DateInterval;
|
||||
use DateTime;
|
||||
use DateTimeZone;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Class RecordingEntity.
|
||||
*
|
||||
* @ORM\Entity(repositoryClass="Chamilo\PluginBundle\Zoom\RecordingRepository")
|
||||
* @ORM\Table(
|
||||
* name="plugin_zoom_recording",
|
||||
* indexes={
|
||||
* @ORM\Index(name="meeting_id_index", columns={"meeting_id"}),
|
||||
* }
|
||||
* )
|
||||
* @ORM\HasLifecycleCallbacks
|
||||
*/
|
||||
class Recording
|
||||
{
|
||||
/** @var DateTime */
|
||||
public $startDateTime;
|
||||
|
||||
/** @var string */
|
||||
public $formattedStartTime;
|
||||
|
||||
/** @var DateInterval */
|
||||
public $durationInterval;
|
||||
|
||||
/** @var string */
|
||||
public $formattedDuration;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue()
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @ORM\Column(type="string")
|
||||
*/
|
||||
protected $uuid;
|
||||
|
||||
/**
|
||||
* @var Meeting
|
||||
*
|
||||
* @ORM\ManyToOne(targetEntity="Meeting", inversedBy="recordings")
|
||||
* @ORM\JoinColumn(name="meeting_id")
|
||||
*/
|
||||
protected $meeting;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @ORM\Column(type="text", name="recording_meeting_json", nullable=true)
|
||||
*/
|
||||
protected $recordingMeetingJson;
|
||||
|
||||
/** @var RecordingMeeting */
|
||||
protected $recordingMeeting;
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
$object = $this->getRecordingMeeting();
|
||||
if (property_exists($object, $name)) {
|
||||
return $object->$name;
|
||||
}
|
||||
throw new Exception(sprintf('%s does not know property %s', $this, $name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return sprintf('Recording %d', $this->uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Meeting
|
||||
*/
|
||||
public function getMeeting()
|
||||
{
|
||||
return $this->meeting;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*
|
||||
* @return RecordingMeeting
|
||||
*/
|
||||
public function getRecordingMeeting()
|
||||
{
|
||||
return $this->recordingMeeting;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Meeting $meeting
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setMeeting($meeting)
|
||||
{
|
||||
$this->meeting = $meeting;
|
||||
$this->meeting->getRecordings()->add($this);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RecordingMeeting $recordingMeeting
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
* @return Recording
|
||||
*/
|
||||
public function setRecordingMeeting($recordingMeeting)
|
||||
{
|
||||
if (null === $this->uuid) {
|
||||
$this->uuid = $recordingMeeting->uuid;
|
||||
} elseif ($this->uuid !== $recordingMeeting->uuid) {
|
||||
throw new Exception('the RecordingEntity identifier differs from the RecordingMeeting identifier');
|
||||
}
|
||||
if (null === $this->meeting) {
|
||||
$this->meeting = Database::getManager()->getRepository(Meeting::class)->find($recordingMeeting->id);
|
||||
} elseif ($this->meeting->getMeetingId() != $recordingMeeting->id) {
|
||||
// $this->meeting remains null when the remote RecordingMeeting refers to a deleted meeting.
|
||||
throw new Exception('The RecordingEntity meeting id differs from the RecordingMeeting meeting id');
|
||||
}
|
||||
$this->recordingMeeting = $recordingMeeting;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ORM\PostLoad
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function postLoad()
|
||||
{
|
||||
if (null !== $this->recordingMeetingJson) {
|
||||
$this->recordingMeeting = RecordingMeeting::fromJson($this->recordingMeetingJson);
|
||||
}
|
||||
$this->initializeExtraProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* @ORM\PreFlush
|
||||
*/
|
||||
public function preFlush()
|
||||
{
|
||||
if (null !== $this->recordingMeeting) {
|
||||
$this->recordingMeetingJson = json_encode($this->recordingMeeting);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function initializeExtraProperties()
|
||||
{
|
||||
$this->startDateTime = new DateTime($this->recordingMeeting->start_time);
|
||||
$this->startDateTime->setTimezone(new DateTimeZone(api_get_timezone()));
|
||||
$this->formattedStartTime = $this->startDateTime->format('Y-m-d H:i');
|
||||
|
||||
$now = new DateTime();
|
||||
$later = new DateTime();
|
||||
$later->add(new DateInterval('PT'.$this->recordingMeeting->duration.'M'));
|
||||
$this->durationInterval = $later->diff($now);
|
||||
$this->formattedDuration = $this->durationInterval->format(get_lang('DurationFormat'));
|
||||
}
|
||||
}
|
||||
283
plugin/zoom/Entity/Registrant.php
Normal file
@@ -0,0 +1,283 @@
|
||||
<?php
|
||||
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
namespace Chamilo\PluginBundle\Zoom;
|
||||
|
||||
use Chamilo\PluginBundle\Zoom\API\CreatedRegistration;
|
||||
use Chamilo\PluginBundle\Zoom\API\MeetingRegistrant;
|
||||
use Chamilo\PluginBundle\Zoom\API\MeetingRegistrantListItem;
|
||||
use Chamilo\UserBundle\Entity\User;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Class RegistrantEntity.
|
||||
*
|
||||
* @ORM\Entity(repositoryClass="RegistrantRepository")
|
||||
* @ORM\Table(
|
||||
* name="plugin_zoom_registrant",
|
||||
* indexes={
|
||||
* @ORM\Index(name="user_id_index", columns={"user_id"}),
|
||||
* @ORM\Index(name="meeting_id_index", columns={"meeting_id"}),
|
||||
* }
|
||||
* )
|
||||
* @ORM\HasLifecycleCallbacks
|
||||
* @ORM\InheritanceType("SINGLE_TABLE")
|
||||
* @ORM\DiscriminatorColumn(name="type", type="string")
|
||||
* @ORM\DiscriminatorMap({"registrant" = "Chamilo\PluginBundle\Zoom\Registrant", "presenter" = "Chamilo\PluginBundle\Zoom\Presenter"})
|
||||
*/
|
||||
class Registrant
|
||||
{
|
||||
/** @var string */
|
||||
public $fullName;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @ORM\Column(type="integer", name="id")
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @var User
|
||||
* @ORM\ManyToOne(targetEntity="Chamilo\UserBundle\Entity\User")
|
||||
* @ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=false)
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* @var Meeting
|
||||
* @ORM\ManyToOne(targetEntity="Meeting", inversedBy="registrants")
|
||||
* @ORM\JoinColumn(name="meeting_id", referencedColumnName="id")
|
||||
*/
|
||||
protected $meeting;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @ORM\Column(type="text", name="created_registration_json", nullable=true)
|
||||
*/
|
||||
protected $createdRegistrationJson;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @ORM\Column(type="text", name="meeting_registrant_list_item_json", nullable=true)
|
||||
*/
|
||||
protected $meetingRegistrantListItemJson;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @ORM\Column(type="text", name="meeting_registrant_json", nullable=true)
|
||||
*/
|
||||
protected $meetingRegistrantJson;
|
||||
|
||||
/**
|
||||
* @var Signature|null
|
||||
*
|
||||
* @ORM\OneToOne(targetEntity="Chamilo\PluginBundle\Zoom\Signature", mappedBy="registrant", orphanRemoval=true)
|
||||
*/
|
||||
protected $signature;
|
||||
|
||||
/** @var CreatedRegistration */
|
||||
protected $createdRegistration;
|
||||
|
||||
/** @var MeetingRegistrant */
|
||||
protected $meetingRegistrant;
|
||||
|
||||
/** @var MeetingRegistrantListItem */
|
||||
protected $meetingRegistrantListItem;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return sprintf('Registrant %d', $this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Meeting
|
||||
*/
|
||||
public function getMeeting()
|
||||
{
|
||||
return $this->meeting;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Meeting $meeting
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setMeeting($meeting)
|
||||
{
|
||||
$this->meeting = $meeting;
|
||||
$this->meeting->getRegistrants()->add($this);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return User
|
||||
*/
|
||||
public function getUser()
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setUser($user)
|
||||
{
|
||||
$this->user = $user;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*
|
||||
* @return MeetingRegistrantListItem
|
||||
*/
|
||||
public function getMeetingRegistrantListItem()
|
||||
{
|
||||
return $this->meetingRegistrantListItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MeetingRegistrantListItem $meetingRegistrantListItem
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setMeetingRegistrantListItem($meetingRegistrantListItem)
|
||||
{
|
||||
if (!is_null($this->meeting) && $this->meeting->getId() != $meetingRegistrantListItem->id) {
|
||||
throw new Exception('RegistrantEntity meeting id differs from MeetingRegistrantListItem id');
|
||||
}
|
||||
$this->meetingRegistrantListItem = $meetingRegistrantListItem;
|
||||
$this->computeFullName();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function computeFullName()
|
||||
{
|
||||
$this->fullName = api_get_person_name(
|
||||
$this->meetingRegistrant->first_name,
|
||||
$this->meetingRegistrant->last_name
|
||||
);
|
||||
}
|
||||
|
||||
public function getJoinUrl()
|
||||
{
|
||||
if (!$this->createdRegistration) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $this->createdRegistration->join_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*
|
||||
* @return CreatedRegistration
|
||||
*/
|
||||
public function getCreatedRegistration()
|
||||
{
|
||||
return $this->createdRegistration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CreatedRegistration $createdRegistration
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setCreatedRegistration($createdRegistration)
|
||||
{
|
||||
if (null === $this->id) {
|
||||
$this->id = $createdRegistration->registrant_id;
|
||||
} elseif ($this->id != $createdRegistration->registrant_id) {
|
||||
throw new Exception('RegistrantEntity id differs from CreatedRegistration identifier');
|
||||
}
|
||||
$this->createdRegistration = $createdRegistration;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*
|
||||
* @return MeetingRegistrant
|
||||
*/
|
||||
public function getMeetingRegistrant()
|
||||
{
|
||||
return $this->meetingRegistrant;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function setMeetingRegistrant(API\RegistrantSchema $meetingRegistrant): Registrant
|
||||
{
|
||||
$this->meetingRegistrant = $meetingRegistrant;
|
||||
$this->computeFullName();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ORM\PostLoad
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function postLoad()
|
||||
{
|
||||
if (null !== $this->meetingRegistrantJson) {
|
||||
$this->meetingRegistrant = MeetingRegistrant::fromJson($this->meetingRegistrantJson);
|
||||
}
|
||||
if (null !== $this->createdRegistrationJson) {
|
||||
$this->createdRegistration = CreatedRegistration::fromJson($this->createdRegistrationJson);
|
||||
}
|
||||
if (null !== $this->meetingRegistrantListItemJson) {
|
||||
$this->meetingRegistrantListItem = MeetingRegistrantListItem::fromJson(
|
||||
$this->meetingRegistrantListItemJson
|
||||
);
|
||||
}
|
||||
$this->computeFullName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @ORM\PreFlush
|
||||
*/
|
||||
public function preFlush()
|
||||
{
|
||||
if (null !== $this->meetingRegistrant) {
|
||||
$this->meetingRegistrantJson = json_encode($this->meetingRegistrant);
|
||||
}
|
||||
if (null !== $this->createdRegistration) {
|
||||
$this->createdRegistrationJson = json_encode($this->createdRegistration);
|
||||
}
|
||||
if (null !== $this->meetingRegistrantListItem) {
|
||||
$this->meetingRegistrantListItemJson = json_encode($this->meetingRegistrantListItem);
|
||||
}
|
||||
}
|
||||
|
||||
public function setSignature(Signature $signature): void
|
||||
{
|
||||
$this->signature = $signature;
|
||||
|
||||
$signature->setRegistrant($this);
|
||||
}
|
||||
|
||||
public function getSignature(): ?Signature
|
||||
{
|
||||
return $this->signature;
|
||||
}
|
||||
}
|
||||
84
plugin/zoom/Entity/Signature.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
namespace Chamilo\PluginBundle\Zoom;
|
||||
|
||||
use DateTime;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity()
|
||||
* @ORM\Table(name="plugin_zoom_signature")
|
||||
*/
|
||||
class Signature
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
private $id;
|
||||
/**
|
||||
* @var Registrant
|
||||
*
|
||||
* @ORM\OneToOne(targetEntity="Chamilo\PluginBundle\Zoom\Registrant", inversedBy="signature")
|
||||
* @ORM\JoinColumn(name="registrant_id", referencedColumnName="id")
|
||||
*/
|
||||
private $registrant;
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @ORM\Column(name="signature", type="text")
|
||||
*/
|
||||
private $file;
|
||||
/**
|
||||
* @var DateTime
|
||||
*
|
||||
* @ORM\Column(name="registered_at", type="datetime")
|
||||
*/
|
||||
private $registeredAt;
|
||||
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getRegistrant(): Registrant
|
||||
{
|
||||
return $this->registrant;
|
||||
}
|
||||
|
||||
public function setRegistrant(Registrant $registrant): Signature
|
||||
{
|
||||
$this->registrant = $registrant;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFile(): string
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
public function setFile(string $file): Signature
|
||||
{
|
||||
$this->file = $file;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRegisteredAt(): DateTime
|
||||
{
|
||||
return $this->registeredAt;
|
||||
}
|
||||
|
||||
public function setRegisteredAt(DateTime $registeredAt): Signature
|
||||
{
|
||||
$this->registeredAt = $registeredAt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
138
plugin/zoom/Entity/Webinar.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
namespace Chamilo\PluginBundle\Zoom;
|
||||
|
||||
use Chamilo\PluginBundle\Zoom\API\BaseMeetingTrait;
|
||||
use Chamilo\PluginBundle\Zoom\API\WebinarSchema;
|
||||
use Chamilo\PluginBundle\Zoom\API\WebinarSettings;
|
||||
use DateInterval;
|
||||
use DateTime;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Exception;
|
||||
use ZoomPlugin;
|
||||
|
||||
/**
|
||||
* @ORM\Entity()
|
||||
* @ORM\HasLifecycleCallbacks
|
||||
*/
|
||||
class Webinar extends Meeting
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @ORM\Column(name="webinar_schema_json", type="text", nullable=true)
|
||||
*/
|
||||
protected $webinarSchemaJson;
|
||||
|
||||
/**
|
||||
* @var WebinarSchema
|
||||
*/
|
||||
protected $webinarSchema;
|
||||
|
||||
public function preFlush()
|
||||
{
|
||||
if (null !== $this->webinarSchema) {
|
||||
$this->webinarSchemaJson = json_encode($this->webinarSchema);
|
||||
}
|
||||
}
|
||||
|
||||
public function postLoad()
|
||||
{
|
||||
if (null !== $this->webinarSchemaJson) {
|
||||
$this->webinarSchema = WebinarSchema::fromJson($this->webinarSchemaJson);
|
||||
}
|
||||
|
||||
$this->initializeDisplayableProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebinarSchema|BaseMeetingTrait $webinarSchema
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function setWebinarSchema(WebinarSchema $webinarSchema): Webinar
|
||||
{
|
||||
if (null === $this->meetingId) {
|
||||
$this->meetingId = $webinarSchema->id;
|
||||
} elseif ($this->meetingId != $webinarSchema->id) {
|
||||
throw new Exception('the Meeting identifier differs from the MeetingInfoGet identifier');
|
||||
}
|
||||
|
||||
$this->webinarSchema = $webinarSchema;
|
||||
|
||||
$this->initializeDisplayableProperties();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getWebinarSchema(): WebinarSchema
|
||||
{
|
||||
return $this->webinarSchema;
|
||||
}
|
||||
|
||||
public function hasCloudAutoRecordingEnabled(): bool
|
||||
{
|
||||
return $this->webinarSchema->settings->auto_recording !== ZoomPlugin::RECORDING_TYPE_NONE;
|
||||
}
|
||||
|
||||
public function requiresDateAndDuration(): bool
|
||||
{
|
||||
return WebinarSchema::TYPE_WEBINAR == $this->webinarSchema->type;
|
||||
}
|
||||
|
||||
public function requiresRegistration(): bool
|
||||
{
|
||||
return in_array(
|
||||
$this->webinarSchema->settings->approval_type,
|
||||
[
|
||||
WebinarSettings::APPROVAL_TYPE_AUTOMATICALLY_APPROVE,
|
||||
WebinarSettings::APPROVAL_TYPE_MANUALLY_APPROVE,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function getTopic(): string
|
||||
{
|
||||
return $this->webinarSchema->topic;
|
||||
}
|
||||
|
||||
public function getAgenda(): ?string
|
||||
{
|
||||
return $this->webinarSchema->agenda;
|
||||
}
|
||||
|
||||
protected function initializeDisplayableProperties()
|
||||
{
|
||||
$zoomPlugin = ZoomPlugin::create();
|
||||
|
||||
$namedTypes = [
|
||||
WebinarSchema::TYPE_WEBINAR => $zoomPlugin->get_lang('Webinar'),
|
||||
WebinarSchema::TYPE_RECURRING_NO_FIXED_TIME => $zoomPlugin->get_lang('RecurringWithNoFixedTime'),
|
||||
WebinarSchema::TYPE_RECURRING_FIXED_TIME => $zoomPlugin->get_lang('RecurringWithFixedTime'),
|
||||
];
|
||||
|
||||
$this->typeName = $namedTypes[$this->webinarSchema->type];
|
||||
|
||||
if ($this->webinarSchema->start_time) {
|
||||
$this->startDateTime = new DateTime(
|
||||
$this->webinarSchema->start_time,
|
||||
new \DateTimeZone(api_get_timezone())
|
||||
);
|
||||
$this->formattedStartTime = $this->startDateTime->format('Y-m-d H:i');
|
||||
}
|
||||
|
||||
if ($this->webinarSchema->duration) {
|
||||
$now = new DateTime();
|
||||
$later = new DateTime();
|
||||
$later->add(
|
||||
new DateInterval('PT'.$this->webinarSchema->duration.'M')
|
||||
);
|
||||
$this->durationInterval = $now->diff($later);
|
||||
$this->formattedDuration = $this->durationInterval->format(
|
||||
$zoomPlugin->get_lang('DurationFormat')
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
70
plugin/zoom/README.code.md
Normal file
@@ -0,0 +1,70 @@
|
||||
The Chamilo Zoom plugin class itself is defined in _plugin/zoom/lib/ZoomPlugin.php_
|
||||
|
||||
It manipulates both **remote Zoom server objects** and **local database entities**:
|
||||
|
||||
# Local database entities
|
||||
|
||||
The local entities map the remote objects to Chamilo courses/sessions and users.
|
||||
|
||||
They also maintain a cache of the matching remote objects.
|
||||
|
||||
_Entity/*Entity.php_ are the local database entity classes.
|
||||
|
||||
Doctrine entity manager repository classes are in _lib/*EntityRepository.php_.
|
||||
|
||||
# Remote Zoom server objets
|
||||
|
||||
_lib/API/*.php_ contains the Zoom API data structure definition classes,
|
||||
based on Zoom's own API specification:
|
||||
|
||||
* https://marketplace.zoom.us/docs/api-reference/zoom-api
|
||||
* https://marketplace.zoom.us/docs/api-reference/zoom-api/Zoom%20API.oas2.json
|
||||
|
||||
These classes provide methods to list, create, update and delete the remote objects.
|
||||
|
||||
# JWT Client
|
||||
|
||||
API class methods use a JWT client implemented in _lib/API/JWTClient.php_.
|
||||
|
||||
The plugin constructor initializes the JWT Client, giving it required API key and secret.
|
||||
|
||||
# Event notification handler
|
||||
|
||||
_endpoint.php_ is the Zoom API event notification web hook end point.
|
||||
|
||||
It handles notifications sent by Zoom servers on useful events :
|
||||
|
||||
* meeting start and end,
|
||||
* registrant join and leave,
|
||||
* recordings created and deleted
|
||||
|
||||
# Administrative interface
|
||||
|
||||
_admin.php_ is the administrative interface.
|
||||
It lists all meetings and recordings.
|
||||
|
||||
# Course tool
|
||||
|
||||
_start.php_ is the **course** tool target:
|
||||
|
||||
* to the course teacher, it shows a course meeting management interface;
|
||||
* to the course learners, it shows the list of scheduled course meetings.
|
||||
|
||||
# Home page's profile block (also on "My Courses" page)
|
||||
|
||||
This plugin can add 3 kinds of links to "profile block" :
|
||||
|
||||
1. _join_meeting.php?meetingId=…_ links to upcoming meetings accessible to the current user.
|
||||
_join_meeting.php_ presents the meeting and shows a link to enter the meeting.
|
||||
2. _user.php_ is the **user**'s own meeting management interface.
|
||||
3. _global.php_ directs the user to _join_meeting.php_ with the **global** meeting.
|
||||
|
||||
# Meeting management page
|
||||
|
||||
_admin.php_, _start.php_ and _user.php_ link to _meeting.php_.
|
||||
|
||||
_meeting.php_ is the meeting management page, where one can manage
|
||||
|
||||
* the meeting properties,
|
||||
* the list of its registrants and
|
||||
* its recordings.
|
||||
148
plugin/zoom/README.md
Normal file
@@ -0,0 +1,148 @@
|
||||
This plugin adds Zoom meetings, user registration to meetings and meeting recordings.
|
||||
|
||||
> This plugin requires a Zoom account to manage meetings.
|
||||
|
||||
Once enabled, it will show as an additional course tool in all courses' homepage: teachers will be able to launch a
|
||||
conference and student to join it.
|
||||
|
||||
## Configuration
|
||||
|
||||
The Zoom API uses JSON Web Tokens (JWT) to authenticate account-level access. JWT apps provide an API Key and Secret
|
||||
required to authenticate with JWT. To get them, create a JWT App or a Server-to-Sever OAuth app:
|
||||
|
||||
> From June 1, 2023, Zoom recommend that you create a Server-to-Server OAuth application to replace the funcionality of
|
||||
> a JWT app in your account.
|
||||
|
||||
1. Log into your [Zoom profile page](https://zoom.us/profile)
|
||||
2. Click on Advanced / Application Marketplace
|
||||
3. Click on [Develop / Build App](https://marketplace.zoom.us/develop/create)
|
||||
4. Choose JWT or Server-to-Serve OAuth and then Create
|
||||
5. Information: Fill in fields about your "App" (application and company names, contact name and email address)
|
||||
6. Click on Continue
|
||||
7. App Credentials
|
||||
1. For a JWT application: Copy your API Key and Secret to the plugin configuration
|
||||
2. For a Server-to-Server OAuth application: Copy your *Account ID*, *Client ID* anf *Client secret* to the plugin
|
||||
configuration
|
||||
8. Click on Continue
|
||||
9. Feature: enable Event Subscriptions to add a new one with endpoint
|
||||
URL `https://your.chamilo.url/plugin/zoom/endpoint.php` (validate the endpoint to allow to activate the app) and add
|
||||
these event types:
|
||||
|
||||
- Start Meeting
|
||||
- End Meeting
|
||||
- Participant/Host joined meeting
|
||||
- Participant/Host left meeting
|
||||
- Start Webinar
|
||||
- End Webinar
|
||||
- Participant/Host joined webinar
|
||||
- Participant/Host left webinar
|
||||
- All Recordings have completed
|
||||
- Recording transcript files have completed
|
||||
|
||||
Then click on Done then on Save and copy your *Verification Token* if you have a JWT application or the *Secret
|
||||
Token* if you have an Server-to-Server OAuth application to the plugin configuration
|
||||
10. click on Continue
|
||||
11. Scopes (only for Server-to-Server OAuth application): Click on Add Scopes and select *meeting:write:admin*,
|
||||
*webinar:write:admin*, *recording:write:admin*. Then click on Done.
|
||||
|
||||
## Changelog
|
||||
|
||||
**v0.5**
|
||||
|
||||
* Added the ability to create a system announcement.
|
||||
|
||||
**v0.4**
|
||||
|
||||
* The creation of webinars is now allowed.
|
||||
* Added signed attendance to allow you to configure an attendance sheet where participants register their signature. The
|
||||
signed attendance functionality is similar to that found in the Exercise Signature plugin but does not reuse it.
|
||||
* Allows you to use multiple accounts and subaccounts to create meetings/webinars
|
||||
|
||||
## Meetings - Webinars
|
||||
|
||||
A **meeting** or **webinar** can be linked to a local **user** and/or a local **course**/**session**:
|
||||
|
||||
* a meeting/webinar with a course is a _course meeting/webinar_;
|
||||
* a meeting/webinar with a user and no course is a _user meeting/webinar_;
|
||||
* a meeting/webinar with no course nor user is a _global meeting/webinar_.
|
||||
|
||||
A webinar only can be creadted when your Zoom account has a plan with the webinars feature.
|
||||
|
||||
## Registrants
|
||||
|
||||
A **registrant** is the registration of a local user to a meeting/webinar.
|
||||
|
||||
Users do not register themselves to meetings.
|
||||
|
||||
* They are registered to a course meeting/webinar by the course manager.
|
||||
* They are registered to a user meeting/webinar by that user.
|
||||
* They are registered automatically to the global meeting/webinar, when they enter it.
|
||||
|
||||
## Recordings
|
||||
|
||||
A **recording** is the list of files created during a past meeting/webinar instance.
|
||||
|
||||
Course meeting/webinar files can be copied to the course by the course manager.
|
||||
|
||||
# Required Zoom user account
|
||||
|
||||
Recordings and user registration are only available to paying Zoom customers.
|
||||
|
||||
For a non-paying Zoom user, this plugin still works but participants will join anonymously.
|
||||
|
||||
The user that starts the meeting/webinar will be identified as the Zoom account that is defined in the plugin. Socreate
|
||||
a generic account that works for all the users that start meetings.
|
||||
|
||||
# Databace changelog
|
||||
|
||||
Please, execute this queries in your database:
|
||||
|
||||
**Updatnig to v0.6 from v.0.5**
|
||||
```sql
|
||||
UPDATE plugin_zoom_registrant SET type = 'registrant';
|
||||
|
||||
ALTER TABLE plugin_zoom_registrant
|
||||
ADD type VARCHAR(255) NOT NULL;
|
||||
```
|
||||
|
||||
**Updating to v0.5 from v.0.4**
|
||||
|
||||
```sql
|
||||
ALTER TABLE plugin_zoom_meeting
|
||||
ADD sys_announcement_id INT DEFAULT NULL;
|
||||
ALTER TABLE plugin_zoom_meeting
|
||||
ADD CONSTRAINT FK_3448092778FB10C FOREIGN KEY (sys_announcement_id) REFERENCES sys_announcement (id) ON DELETE SET NULL;
|
||||
CREATE INDEX IDX_3448092778FB10C ON plugin_zoom_meeting (sys_announcement_id);
|
||||
```
|
||||
|
||||
**Updating to v0.4 from v0.3**
|
||||
|
||||
```sql
|
||||
ALTER TABLE plugin_zoom_meeting
|
||||
ADD account_email VARCHAR(255) DEFAULT NULL,
|
||||
ADD type VARCHAR(255) NOT NULL,
|
||||
ADD webinar_schema_json LONGTEXT DEFAULT NULL;
|
||||
|
||||
CREATE TABLE plugin_zoom_signature (
|
||||
id INT AUTO_INCREMENT NOT NULL,
|
||||
registrant_id INT DEFAULT NULL,
|
||||
signature LONGTEXT NOT NULL,
|
||||
registered_at DATETIME NOT NULL,
|
||||
UNIQUE INDEX UNIQ_D41895893304A716 (registrant_id),
|
||||
PRIMARY KEY (id)
|
||||
)
|
||||
DEFAULT CHARACTER SET utf8
|
||||
COLLATE `utf8_unicode_ci`
|
||||
ENGINE = InnoDB;
|
||||
|
||||
ALTER TABLE plugin_zoom_signature
|
||||
ADD CONSTRAINT FK_D41895893304A716 FOREIGN KEY (registrant_id) REFERENCES plugin_zoom_registrant (id);
|
||||
|
||||
ALTER TABLE plugin_zoom_meeting
|
||||
ADD sign_attendance TINYINT(1) NOT NULL,
|
||||
ADD reason_to_sign_attendance LONGTEXT DEFAULT NULL;
|
||||
```
|
||||
|
||||
# Contributing
|
||||
|
||||
Read README.code.md for an introduction to the plugin's code.
|
||||
55
plugin/zoom/activity.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?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';
|
||||
|
||||
$plugin = ZoomPlugin::create();
|
||||
$tool_name = $plugin->get_lang('ZoomVideoConferences');
|
||||
$meetingId = isset($_REQUEST['meetingId']) ? (int) $_REQUEST['meetingId'] : 0;
|
||||
if (empty($meetingId)) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
$content = '';
|
||||
/** @var Meeting $meeting */
|
||||
$meeting = $plugin->getMeetingRepository()->findOneBy(['meetingId' => $meetingId]);
|
||||
if (null === $meeting) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
if (!$plugin->userIsConferenceManager($meeting)) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
$returnURL = 'meetings.php';
|
||||
$urlExtra = '';
|
||||
if ($meeting->isCourseMeeting()) {
|
||||
api_protect_course_script(true);
|
||||
$urlExtra = api_get_cidreq();
|
||||
$returnURL = 'start.php?'.$urlExtra;
|
||||
if (api_is_in_group()) {
|
||||
$interbreadcrumb[] = [
|
||||
'url' => api_get_path(WEB_CODE_PATH).'group/group.php?'.api_get_cidreq(),
|
||||
'name' => get_lang('Groups'),
|
||||
];
|
||||
$interbreadcrumb[] = [
|
||||
'url' => api_get_path(WEB_CODE_PATH).'group/group_space.php?'.api_get_cidreq(),
|
||||
'name' => get_lang('GroupSpace').' '.$meeting->getGroup()->getName(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$interbreadcrumb[] = [
|
||||
'url' => $returnURL,
|
||||
'name' => $plugin->get_lang('ZoomVideoConferences'),
|
||||
];
|
||||
$tpl = new Template($meeting->getMeetingId());
|
||||
$tpl->assign('actions', $plugin->getToolbar());
|
||||
$tpl->assign('meeting', $meeting);
|
||||
$tpl->assign('url_extra', $urlExtra);
|
||||
$tpl->assign('content', $tpl->fetch('zoom/view/activity.tpl'));
|
||||
$tpl->display_one_col_template();
|
||||
181
plugin/zoom/attendance.php
Normal file
@@ -0,0 +1,181 @@
|
||||
<?php
|
||||
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
use Chamilo\PluginBundle\Zoom\Meeting;
|
||||
use Chamilo\PluginBundle\Zoom\Registrant;
|
||||
use Symfony\Component\HttpFoundation\Request as HttpRequest;
|
||||
|
||||
require_once __DIR__.'/config.php';
|
||||
|
||||
api_block_anonymous_users();
|
||||
|
||||
$httpRequest = HttpRequest::createFromGlobals();
|
||||
|
||||
$meetingId = $httpRequest->get('meetingId', 0);
|
||||
|
||||
if (empty($meetingId)) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
$plugin = ZoomPlugin::create();
|
||||
$em = Database::getManager();
|
||||
/** @var Meeting $meeting */
|
||||
$meeting = $plugin->getMeetingRepository()->findOneBy(['meetingId' => $meetingId]);
|
||||
$registrantsRepo = $em->getRepository(Registrant::class);
|
||||
|
||||
if (null === $meeting) {
|
||||
api_not_allowed(
|
||||
true,
|
||||
Display::return_message($plugin->get_lang('MeetingNotFound'), 'error')
|
||||
);
|
||||
}
|
||||
|
||||
if (!$plugin->userIsConferenceManager($meeting)
|
||||
|| !$meeting->isSignAttendance()
|
||||
) {
|
||||
api_not_allowed(
|
||||
true,
|
||||
Display::return_message(get_lang('NotAvailable'), 'warning')
|
||||
);
|
||||
}
|
||||
|
||||
$getNumberOfSignatures = function () use ($meeting) {
|
||||
return $meeting->getRegistrants()->count();
|
||||
};
|
||||
|
||||
$getSignaturesData = function (
|
||||
$from,
|
||||
$limit,
|
||||
$column,
|
||||
$direction
|
||||
) use ($registrantsRepo, $meeting) {
|
||||
if (0 === $column) {
|
||||
$columnField = 'u.lastname';
|
||||
} elseif (1 === $column) {
|
||||
$columnField = 'u.firstname';
|
||||
} else {
|
||||
$columnField = 's.registeredAt';
|
||||
}
|
||||
|
||||
$result = $registrantsRepo->findByMeetingPaginated($meeting, $from, $limit, $columnField, $direction);
|
||||
|
||||
return array_map(
|
||||
function (Registrant $registrant) {
|
||||
$signature = $registrant->getSignature();
|
||||
|
||||
return [
|
||||
$registrant->getUser()->getLastname(),
|
||||
$registrant->getUser()->getFirstname(),
|
||||
$signature ? $signature->getRegisteredAt() : null,
|
||||
$signature ? $signature->getFile() : null,
|
||||
];
|
||||
},
|
||||
$result
|
||||
);
|
||||
};
|
||||
|
||||
if ($httpRequest->query->has('export')) {
|
||||
$plugin->exportSignatures(
|
||||
$meeting,
|
||||
$httpRequest->query->getAlnum('export')
|
||||
);
|
||||
}
|
||||
|
||||
$table = new SortableTable('zoom_signatures', $getNumberOfSignatures, $getSignaturesData, 2);
|
||||
$table->set_header(0, get_lang('LastName'));
|
||||
$table->set_header(1, get_lang('FirstName'));
|
||||
$table->set_header(2, get_lang('DateTime'), true, ['class' => 'text-center'], ['class' => 'text-center']);
|
||||
$table->set_header(3, $plugin->get_lang('Signature'), false, ['style' => 'width: 200px', 'class' => 'text-center']);
|
||||
$table->set_additional_parameters(
|
||||
array_filter(
|
||||
$httpRequest->query->all(),
|
||||
function ($key): bool {
|
||||
return strpos($key, 'zoom_signatures_') === false;
|
||||
},
|
||||
ARRAY_FILTER_USE_KEY
|
||||
)
|
||||
);
|
||||
$table->set_column_filter(
|
||||
2,
|
||||
function ($dateTime) {
|
||||
return $dateTime ? api_convert_and_format_date($dateTime, DATE_TIME_FORMAT_LONG) : null;
|
||||
}
|
||||
);
|
||||
$table->set_column_filter(
|
||||
3,
|
||||
function ($imgData) use ($plugin) {
|
||||
if (empty($imgData)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Display::img(
|
||||
$imgData,
|
||||
$plugin->get_lang('SignatureDone'),
|
||||
['class' => 'img-thumbnail'],
|
||||
false
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
$cidReq = api_get_cidreq();
|
||||
$queryParams = 'meetingId='.$meeting->getMeetingId().'&'.$cidReq;
|
||||
$returnURL = 'meetings.php';
|
||||
|
||||
if ($meeting->isCourseMeeting()) {
|
||||
api_protect_course_script(true);
|
||||
|
||||
$this_section = SECTION_COURSES;
|
||||
|
||||
$returnURL = 'start.php?'.$cidReq;
|
||||
|
||||
if (api_is_in_group()) {
|
||||
$interbreadcrumb[] = [
|
||||
'url' => api_get_path(WEB_CODE_PATH).'group/group.php?'.$cidReq,
|
||||
'name' => get_lang('Groups'),
|
||||
];
|
||||
$interbreadcrumb[] = [
|
||||
'url' => api_get_path(WEB_CODE_PATH).'group/group_space.php?'.$cidReq,
|
||||
'name' => get_lang('GroupSpace').' '.$meeting->getGroup()->getName(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$interbreadcrumb[] = [
|
||||
'url' => $returnURL,
|
||||
'name' => $plugin->get_lang('ZoomVideoConferences'),
|
||||
];
|
||||
$interbreadcrumb[] = [
|
||||
'url' => 'meeting.php?'.$queryParams,
|
||||
'name' => $meeting->getMeetingInfoGet()->topic,
|
||||
];
|
||||
|
||||
$exportPdfLink = Display::url(
|
||||
Display::return_icon('pdf.png', get_lang('ExportToPDF'), [], ICON_SIZE_MEDIUM),
|
||||
api_get_self().'?'.$queryParams.'&export=pdf'
|
||||
);
|
||||
$exportXlsLink = Display::url(
|
||||
Display::return_icon('excel.png', get_lang('ExportAsXLS'), [], ICON_SIZE_MEDIUM),
|
||||
api_get_self().'?'.$queryParams.'&export=xls'
|
||||
);
|
||||
|
||||
$pageTitle = $plugin->get_lang('Attendance');
|
||||
|
||||
$content = '
|
||||
<dl>
|
||||
<dt>'.$plugin->get_lang('ReasonToSign').'</dt>
|
||||
<dd>'.$meeting->getReasonToSignAttendance().'</dd>
|
||||
</dl>
|
||||
'.$table->return_table();
|
||||
|
||||
$tpl = new Template($pageTitle);
|
||||
$tpl->assign(
|
||||
'actions',
|
||||
Display::toolbarAction(
|
||||
'attendance-actions',
|
||||
[$exportPdfLink.PHP_EOL.$exportXlsLink]
|
||||
)
|
||||
);
|
||||
$tpl->assign('header', $pageTitle);
|
||||
$tpl->assign('content', $content);
|
||||
$tpl->display_one_col_template();
|
||||
66
plugin/zoom/calendar.ajax.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
/* For license terms, see /license.txt */
|
||||
|
||||
use Chamilo\PluginBundle\Zoom\API\BaseMeetingTrait;
|
||||
use Chamilo\PluginBundle\Zoom\Meeting;
|
||||
use Chamilo\PluginBundle\Zoom\Webinar;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request as HttpRequest;
|
||||
|
||||
$course_plugin = 'zoom'; // needed in order to load the plugin lang variables
|
||||
|
||||
$cidReset = true;
|
||||
|
||||
require_once __DIR__.'/config.php';
|
||||
|
||||
api_protect_admin_script();
|
||||
|
||||
$request = HttpRequest::createFromGlobals();
|
||||
|
||||
$plugin = ZoomPlugin::create();
|
||||
$user = api_get_user_entity(api_get_user_id());
|
||||
|
||||
$action = $request->get('a');
|
||||
|
||||
if ($action == 'get_events') {
|
||||
$startDate = $request->query->get('start');
|
||||
$endDate = $request->query->get('end');
|
||||
|
||||
$startDate = api_get_utc_datetime($startDate, true, true);
|
||||
$endDate = api_get_utc_datetime($endDate, true, true);
|
||||
|
||||
$meetings = $plugin
|
||||
->getMeetingRepository()
|
||||
->periodMeetings($startDate, $endDate);
|
||||
|
||||
$meetingsAsEvents = array_map(
|
||||
function (Meeting $conference) {
|
||||
$isWebinar = $conference instanceof Webinar;
|
||||
/** @var BaseMeetingTrait $schema */
|
||||
$schema = $isWebinar ? $conference->getWebinarSchema() : $conference->getMeetingInfoGet();
|
||||
|
||||
$endDate = new DateTime($conference->formattedStartTime);
|
||||
$endDate->add($conference->durationInterval);
|
||||
|
||||
return [
|
||||
'id' => 'meeting_'.$conference->getId(),
|
||||
'title' => $schema->topic,
|
||||
'typeName' => $conference->typeName,
|
||||
'editable' => false,
|
||||
'start' => $conference->formattedStartTime,
|
||||
'start_date_localtime' => $conference->formattedStartTime,
|
||||
'end' => $endDate->format('Y-m-d H:i'),
|
||||
'end_date_localtime' => $endDate->format('Y-m-d H:i'),
|
||||
'duration' => $conference->formattedDuration,
|
||||
'description' => $schema->agenda,
|
||||
'allDay' => false,
|
||||
'accountEmail' => $conference->getAccountEmail(),
|
||||
];
|
||||
},
|
||||
$meetings
|
||||
);
|
||||
|
||||
$response = JsonResponse::create($meetingsAsEvents);
|
||||
$response->send();
|
||||
}
|
||||
47
plugin/zoom/calendar.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
/* For license terms, see /license.txt */
|
||||
|
||||
$course_plugin = 'zoom'; // needed in order to load the plugin lang variables
|
||||
|
||||
$cidReset = true;
|
||||
|
||||
require_once __DIR__.'/config.php';
|
||||
|
||||
api_protect_admin_script();
|
||||
|
||||
$plugin = ZoomPlugin::create();
|
||||
$toolName = $plugin->get_lang('ZoomVideoConferences');
|
||||
|
||||
$defaultView = api_get_setting('default_calendar_view');
|
||||
|
||||
if (empty($defaultView)) {
|
||||
$defaultView = 'month';
|
||||
}
|
||||
|
||||
$regionValue = api_get_language_isocode();
|
||||
|
||||
$htmlHeadXtra[] = api_get_asset('qtip2/jquery.qtip.min.js');
|
||||
$htmlHeadXtra[] = api_get_asset('fullcalendar/dist/fullcalendar.js');
|
||||
$htmlHeadXtra[] = api_get_asset('fullcalendar/dist/locale-all.js');
|
||||
$htmlHeadXtra[] = api_get_css_asset('fullcalendar/dist/fullcalendar.min.css');
|
||||
$htmlHeadXtra[] = api_get_css_asset('qtip2/jquery.qtip.min.css');
|
||||
|
||||
$tpl = new Template($toolName);
|
||||
|
||||
$tpl->assign('web_agenda_ajax_url', 'calendar.ajax.php?sec_token='.Security::get_token());
|
||||
$tpl->assign('default_view', $defaultView);
|
||||
$tpl->assign('region_value', 'en' === $regionValue ? 'en-GB' : $regionValue);
|
||||
|
||||
$onHoverInfo = Agenda::returnOnHoverInfo();
|
||||
$tpl->assign('on_hover_info', $onHoverInfo);
|
||||
|
||||
$extraSettings = Agenda::returnFullCalendarExtraSettings();
|
||||
|
||||
$tpl->assign('fullcalendar_settings', $extraSettings);
|
||||
|
||||
$content = $tpl->fetch('zoom/view/calendar.tpl');
|
||||
|
||||
$tpl->assign('actions', $plugin->getToolbar());
|
||||
$tpl->assign('content', $content);
|
||||
$tpl->display_one_col_template();
|
||||
5
plugin/zoom/config.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
require_once __DIR__.'/../../main/inc/global.inc.php';
|
||||
176
plugin/zoom/endpoint.php
Normal file
@@ -0,0 +1,176 @@
|
||||
<?php
|
||||
|
||||
/* For license terms, see /license.txt */
|
||||
|
||||
use Chamilo\PluginBundle\Zoom\API\RecordingMeeting;
|
||||
use Chamilo\PluginBundle\Zoom\Meeting;
|
||||
use Chamilo\PluginBundle\Zoom\MeetingActivity;
|
||||
use Chamilo\PluginBundle\Zoom\Recording;
|
||||
use Symfony\Component\HttpFoundation\Request as HttpRequest;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
require_once __DIR__.'/config.php';
|
||||
|
||||
$request = HttpRequest::createFromGlobals();
|
||||
|
||||
if (!$request->isMethod('POST')) {
|
||||
http_response_code(Response::HTTP_NOT_FOUND);
|
||||
exit;
|
||||
}
|
||||
|
||||
$configAccountId = api_get_plugin_setting('zoom', ZoomPlugin::SETTING_ACCOUNT_ID);
|
||||
$configClientId = api_get_plugin_setting('zoom', ZoomPlugin::SETTING_CLIENT_ID);
|
||||
$configClientSecret = api_get_plugin_setting('zoom', ZoomPlugin::SETTING_CLIENT_SECRET);
|
||||
$configSecretToken = api_get_plugin_setting('zoom', ZoomPlugin::SETTING_SECRET_TOKEN);
|
||||
|
||||
$isS2SApp = !empty($configAccountId) && !empty($configClientId) && !empty($configClientSecret);
|
||||
$isJwtApp = !$isS2SApp;
|
||||
|
||||
$authorizationHeaderValue = $request->headers->get('Authorization');
|
||||
|
||||
if ($isJwtApp && api_get_plugin_setting('zoom', 'verificationToken') !== $authorizationHeaderValue) {
|
||||
error_log('verificationToken not valid, please check your zoom configuration');
|
||||
http_response_code(Response::HTTP_UNAUTHORIZED);
|
||||
exit;
|
||||
}
|
||||
|
||||
$body = file_get_contents('php://input');
|
||||
$decoded = json_decode($body);
|
||||
|
||||
if ('endpoint.url_validation' === $decoded->event) {
|
||||
$json = json_encode([
|
||||
'plainToken' => $decoded->payload->plainToken,
|
||||
'encryptedToken' => hash_hmac('sha256', $decoded->payload->plainToken, $configSecretToken),
|
||||
]);
|
||||
|
||||
echo $json;
|
||||
exit();
|
||||
}
|
||||
|
||||
if (is_null($decoded) || !is_object($decoded) || !isset($decoded->event) || !isset($decoded->payload->object)) {
|
||||
error_log(sprintf('Did not recognize event notification: %s', $body));
|
||||
http_response_code(Response::HTTP_UNPROCESSABLE_ENTITY);
|
||||
exit;
|
||||
}
|
||||
|
||||
$object = $decoded->payload->object;
|
||||
list($objectType, $action) = explode('.', $decoded->event);
|
||||
|
||||
$em = Database::getManager();
|
||||
|
||||
$meetingRepository = $em->getRepository(Meeting::class);
|
||||
$meeting = null;
|
||||
if ($object->id) {
|
||||
/** @var Meeting $meeting */
|
||||
$meeting = $meetingRepository->findOneBy(['meetingId' => $object->id]);
|
||||
}
|
||||
|
||||
if (null === $meeting) {
|
||||
error_log("Meeting not found");
|
||||
error_log(sprintf('Event "%s" on %s was unhandled: %s', $action, $objectType, $body));
|
||||
http_response_code(Response::HTTP_NOT_FOUND);
|
||||
exit;
|
||||
}
|
||||
|
||||
$activity = new MeetingActivity();
|
||||
$activity->setName($action);
|
||||
$activity->setType($objectType);
|
||||
$activity->setEvent(json_encode($object));
|
||||
|
||||
switch ($objectType) {
|
||||
case 'meeting':
|
||||
error_log('Meeting '.$action.' - '.$meeting->getId());
|
||||
error_log(print_r($object, 1));
|
||||
|
||||
switch ($action) {
|
||||
case 'deleted':
|
||||
$em->remove($meeting);
|
||||
break;
|
||||
case 'ended':
|
||||
case 'started':
|
||||
$meeting->setStatus($action);
|
||||
$meeting->addActivity($activity);
|
||||
$em->persist($meeting);
|
||||
break;
|
||||
default:
|
||||
$meeting->addActivity($activity);
|
||||
$em->persist($meeting);
|
||||
break;
|
||||
}
|
||||
$em->flush();
|
||||
break;
|
||||
case 'webinar':
|
||||
$meeting->addActivity($activity);
|
||||
$em->persist($meeting);
|
||||
$em->flush();
|
||||
break;
|
||||
case 'recording':
|
||||
$recordingRepository = $em->getRepository(Recording::class);
|
||||
|
||||
$recordingEntity = null;
|
||||
if ($object->uuid) {
|
||||
/** @var Recording $recordingEntity */
|
||||
$recordingEntity = $recordingRepository->findOneBy(['uuid' => $object->uuid, 'meeting' => $meeting]);
|
||||
}
|
||||
|
||||
error_log("Recording: $action");
|
||||
error_log(print_r($object, 1));
|
||||
|
||||
switch ($action) {
|
||||
case 'completed':
|
||||
$recording = new Recording();
|
||||
$recording->setRecordingMeeting(RecordingMeeting::fromObject($object));
|
||||
$recording->setMeeting($meeting);
|
||||
$meeting->addActivity($activity);
|
||||
$em->persist($meeting);
|
||||
$em->persist($recording);
|
||||
$em->flush();
|
||||
break;
|
||||
case 'recovered':
|
||||
/*if (null === $recordingEntity) {
|
||||
$em->persist(
|
||||
(new Recording())->setRecordingMeeting(RecordingMeeting::fromObject($object))
|
||||
);
|
||||
$em->flush();
|
||||
}*/
|
||||
break;
|
||||
case 'trashed':
|
||||
case 'deleted':
|
||||
$meeting->addActivity($activity);
|
||||
if (null !== $recordingEntity) {
|
||||
$recordMeeting = $recordingEntity->getRecordingMeeting();
|
||||
$recordingToDelete = RecordingMeeting::fromObject($object);
|
||||
$files = [];
|
||||
if ($recordingToDelete->recording_files) {
|
||||
foreach ($recordingToDelete->recording_files as $fileToDelete) {
|
||||
foreach ($recordMeeting->recording_files as $file) {
|
||||
if ($fileToDelete->id != $file->id) {
|
||||
$files[] = $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($files)) {
|
||||
$em->remove($recordingEntity);
|
||||
} else {
|
||||
$recordMeeting->recording_files = $files;
|
||||
$recordingEntity->setRecordingMeeting($recordMeeting);
|
||||
$em->persist($recordingEntity);
|
||||
}
|
||||
}
|
||||
$em->persist($meeting);
|
||||
$em->flush();
|
||||
break;
|
||||
default:
|
||||
$meeting->addActivity($activity);
|
||||
$em->persist($meeting);
|
||||
$em->flush();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error_log(sprintf('Event "%s" on %s was unhandled: %s', $action, $objectType, $body));
|
||||
http_response_code(501); // Not Implemented
|
||||
break;
|
||||
}
|
||||
13
plugin/zoom/global.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
/* For license terms, see /license.txt */
|
||||
|
||||
$course_plugin = 'zoom'; // needed in order to load the plugin lang variables
|
||||
|
||||
require_once __DIR__.'/config.php';
|
||||
|
||||
if (!ZoomPlugin::currentUserCanJoinGlobalMeeting()) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
api_location('join_meeting.php?meetingId='.ZoomPlugin::create()->getGlobalMeeting()->getMeetingId());
|
||||
1
plugin/zoom/index.php
Normal file
@@ -0,0 +1 @@
|
||||
<?php
|
||||
8
plugin/zoom/install.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
/* For license terms, see /license.txt */
|
||||
|
||||
if (!api_is_platform_admin()) {
|
||||
exit('You must have admin permissions to install plugins');
|
||||
}
|
||||
|
||||
ZoomPlugin::create()->install();
|
||||
114
plugin/zoom/join_meeting.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
/* For license terms, see /license.txt */
|
||||
|
||||
use Chamilo\PluginBundle\Zoom\Meeting;
|
||||
|
||||
require_once __DIR__.'/config.php';
|
||||
|
||||
api_block_anonymous_users();
|
||||
|
||||
$course_plugin = 'zoom'; // needed in order to load the plugin lang variables
|
||||
$meetingId = isset($_REQUEST['meetingId']) ? (int) $_REQUEST['meetingId'] : 0;
|
||||
if (empty($meetingId)) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
$plugin = ZoomPlugin::create();
|
||||
/** @var Meeting $meeting */
|
||||
$meeting = $plugin->getMeetingRepository()->findOneBy(['meetingId' => $meetingId]);
|
||||
if (null === $meeting) {
|
||||
api_not_allowed(true, $plugin->get_lang('MeetingNotFound'));
|
||||
}
|
||||
|
||||
if ($meeting->isCourseMeeting()) {
|
||||
api_protect_course_script(true);
|
||||
if (api_is_in_group()) {
|
||||
$interbreadcrumb[] = [
|
||||
'url' => api_get_path(WEB_CODE_PATH).'group/group.php?'.api_get_cidreq(),
|
||||
'name' => get_lang('Groups'),
|
||||
];
|
||||
$interbreadcrumb[] = [
|
||||
'url' => api_get_path(WEB_CODE_PATH).'group/group_space.php?'.api_get_cidreq(),
|
||||
'name' => get_lang('GroupSpace').' '.$meeting->getGroup()->getName(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$startJoinURL = '';
|
||||
$detailsURL = '';
|
||||
$signature = '';
|
||||
$btnAnnouncement = '';
|
||||
|
||||
$currentUser = api_get_user_entity(api_get_user_id());
|
||||
$isConferenceManager = $plugin->userIsConferenceManager($meeting);
|
||||
|
||||
try {
|
||||
$startJoinURL = $plugin->getStartOrJoinMeetingURL($meeting);
|
||||
|
||||
if (empty($startJoinURL)) {
|
||||
Display::addFlash(
|
||||
Display::return_message($plugin->get_lang('ConferenceNotAvailable'), 'warning')
|
||||
);
|
||||
}
|
||||
|
||||
if ($meeting->isSignAttendance() && !$isConferenceManager) {
|
||||
$registrant = $meeting->getRegistrantByUser($currentUser);
|
||||
$signature = $registrant ? $registrant->getSignature() : null;
|
||||
|
||||
Security::get_token('zoom_signature');
|
||||
}
|
||||
|
||||
if ($isConferenceManager) {
|
||||
$detailsURL = api_get_path(WEB_PLUGIN_PATH).'zoom/meeting.php?meetingId='.$meeting->getMeetingId();
|
||||
}
|
||||
|
||||
$allowAnnouncementsToSessionAdmin = api_get_configuration_value('session_admin_access_system_announcement');
|
||||
|
||||
if (api_is_platform_admin($allowAnnouncementsToSessionAdmin)) {
|
||||
$announcementUrl = '';
|
||||
|
||||
if ($announcement = $meeting->getSysAnnouncement()) {
|
||||
$announcementUrl = api_get_path(WEB_CODE_PATH).'admin/system_announcements.php?'
|
||||
.http_build_query(
|
||||
[
|
||||
'action' => 'edit',
|
||||
'id' => $announcement->getId(),
|
||||
]
|
||||
);
|
||||
} else {
|
||||
$announcementUrl = api_get_path(WEB_CODE_PATH).'admin/system_announcements.php?'
|
||||
.http_build_query(
|
||||
[
|
||||
'action' => 'add',
|
||||
'type' => 'zoom_conference',
|
||||
'meeting' => $meeting->getMeetingId(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
$btnAnnouncement = Display::toolbarButton(
|
||||
$announcement ? get_lang('EditSystemAnnouncement') : get_lang('AddSystemAnnouncement'),
|
||||
$announcementUrl,
|
||||
'bullhorn'
|
||||
);
|
||||
}
|
||||
} catch (Exception $exception) {
|
||||
Display::addFlash(
|
||||
Display::return_message($exception->getMessage(), 'warning')
|
||||
);
|
||||
}
|
||||
|
||||
$htmlHeadXtra[] = api_get_asset('signature_pad/signature_pad.umd.js');
|
||||
|
||||
$tpl = new Template($meeting->getMeetingId());
|
||||
$tpl->assign('meeting', $meeting);
|
||||
$tpl->assign('start_url', $startJoinURL);
|
||||
$tpl->assign('details_url', $detailsURL);
|
||||
$tpl->assign('btn_announcement', $btnAnnouncement);
|
||||
$tpl->assign('is_conference_manager', $isConferenceManager);
|
||||
$tpl->assign('signature', $signature);
|
||||
$content = $tpl->fetch('zoom/view/join.tpl');
|
||||
$tpl->assign('actions', $plugin->getToolbar());
|
||||
$tpl->assign('content', $content);
|
||||
$tpl->display_one_col_template();
|
||||
191
plugin/zoom/lang/english.php
Normal file
@@ -0,0 +1,191 @@
|
||||
<?php
|
||||
/* License: see /license.txt */
|
||||
|
||||
// Needed in order to show the plugin title
|
||||
$strings['plugin_title'] = "Zoom Videoconference";
|
||||
$strings['plugin_comment'] = "Zoom Videoconference integration in courses and sessions";
|
||||
|
||||
$strings['tool_enable'] = 'Zoom videoconference tool enabled';
|
||||
$strings['apiKey'] = 'API Key';
|
||||
$strings['apiKey_help'] = 'For a JWT application type (<small>this app type will be deprecated on 6/1/2023</small>)';
|
||||
$strings['apiSecret'] = 'API Secret';
|
||||
$strings['apiSecret_help'] = 'For a JWT application type (<small>this app type will be deprecated on 6/1/2023</small>)';
|
||||
$strings['verificationToken'] = 'Verification Token';
|
||||
$strings['verificationToken_help'] = 'For a JWT application type (<small>this app type will be deprecated on 6/1/2023</small>)';
|
||||
$strings[ZoomPlugin::SETTING_ACCOUNT_ID] = 'Account ID';
|
||||
$strings[ZoomPlugin::SETTING_ACCOUNT_ID.'_help'] = 'For a Server-to-Server OAuth application type';
|
||||
$strings[ZoomPlugin::SETTING_CLIENT_ID] = 'Client ID';
|
||||
$strings[ZoomPlugin::SETTING_CLIENT_ID.'_help'] = 'For a Server-to-Server OAuth application type';
|
||||
$strings[ZoomPlugin::SETTING_CLIENT_SECRET] = 'Client secret';
|
||||
$strings[ZoomPlugin::SETTING_CLIENT_SECRET.'_help'] = 'For a Server-to-Server OAuth application type';
|
||||
$strings[ZoomPlugin::SETTING_SECRET_TOKEN] = 'Secret token';
|
||||
$strings[ZoomPlugin::SETTING_SECRET_TOKEN.'_help'] = 'For a Server-to-Server OAuth application type';
|
||||
$strings['enableParticipantRegistration'] = 'Enable participant registration';
|
||||
$strings['enablePresenter'] = 'Enable presenter';
|
||||
$strings['enablePresenter_help'] = 'It requires that <i>Enable participant registration</i> settings is enabled.';
|
||||
$strings['enableCloudRecording'] = 'Automatic recording type';
|
||||
$strings['enableGlobalConference'] = 'Enable global conference';
|
||||
$strings['enableGlobalConferencePerUser'] = 'Enable global conference per user';
|
||||
$strings['globalConferenceAllowRoles'] = "Global conference link only visible for these user roles";
|
||||
$strings['globalConferencePerUserAllowRoles'] = "Global conference per user link only visible for these user roles";
|
||||
$strings['accountSelector'] = 'Account selector';
|
||||
$strings['accountSelector_help'] = 'It allows you to declare the emails of the different accounts with whom you want to open the Zoom videos. Separated by semicolons (account_one@example.come;account_two@exaple.com).';
|
||||
|
||||
$strings['tool_enable_help'] = "Choose whether you want to enable the Zoom videoconference tool.
|
||||
Once enabled, it will show as an additional course tool in all courses' homepage :
|
||||
teachers will be able to <strong>launch</strong> a conference and student to <strong>join</strong> it.
|
||||
<br/>
|
||||
This plugin requires a Zoom account to manage meetings.
|
||||
<p>The Zoom API uses JSON Web Tokens (JWT) to authenticate account-level access. To get them, create a JWT App or a Server-to-Sever OAuth app:</p>
|
||||
<blockquote>
|
||||
<p>From June 1, 2023, Zoom recommend that you create a Server-to-Server OAuth application to replace the funcionality of
|
||||
a JWT app in your account.</p>
|
||||
</blockquote>
|
||||
<ol>
|
||||
<li>Log into your <a href=\"https://zoom.us/profile\">Zoom profile page</a></li>
|
||||
<li>Click on Advanced / Application Marketplace</li>
|
||||
<li>Click on <a href=\"https://marketplace.zoom.us/develop/create\">Develop / Build App</a></li>
|
||||
<li>Choose JWT or Server-to-Serve OAuth and then Create</li>
|
||||
<li>Information: Fill in fields about your \"App\" (application and company names, contact name and email address)</li>
|
||||
<li>Click on Continue</li>
|
||||
<li>App Credentials
|
||||
<ol>
|
||||
<li>For a JWT application: Copy your API Key and Secret to the plugin configuration</li>
|
||||
<li>For a Server-to-Server OAuth application: Copy your <em>Account ID</em>, <em>Client ID</em> and <em>Client secret</em> to the plugin
|
||||
configuration</li>
|
||||
</ol></li>
|
||||
<li>Click on Continue</li>
|
||||
<li><p>Feature: enable <em>Event Subscriptions</em> to add a new one with endpoint URL
|
||||
<code>https://your.chamilo.url/plugin/zoom/endpoint.php</code> (validate the endpoint to allow to activate the app) and add
|
||||
these event types:</p>
|
||||
<ul>
|
||||
<li>Start Meeting</li>
|
||||
<li>End Meeting</li>
|
||||
<li>Participant/Host joined meeting</li>
|
||||
<li>Participant/Host left meeting</li>
|
||||
<li>Start Webinar</li>
|
||||
<li>End Webinar</li>
|
||||
<li>Participant/Host joined webinar</li>
|
||||
<li>Participant/Host left webinar</li>
|
||||
<li>All Recordings have completed</li>
|
||||
<li>Recording transcript files have completed</li>
|
||||
</ul>
|
||||
<p>Then click on Done then on Save and copy your <em>Verification Token</em> if you have a JWT application or the <em>Secret
|
||||
Token</em> if you have an Server-to-Server OAuth application to the plugin configuration</p></li>
|
||||
<li>click on Continue</li>
|
||||
<li>Scopes (only for Server-to-Server OAuth application): Click on <em>Add Scopes</em> and select <em>meeting:write:admin</em>,
|
||||
<em>webinar:write:admin</em>, <em>recording:write:admin</em>. Then click on Done.</li>
|
||||
</ol>
|
||||
<br/>
|
||||
<strong>Attention</strong>:
|
||||
<br/>Zoom is <em>NOT</em> free software and specific rules apply to personal data protection.
|
||||
Please check with Zoom and make sure they satisfy you and learning users.";
|
||||
|
||||
$strings['enableParticipantRegistration_help'] = "Requires a paying Zoom profile.
|
||||
Will not work for a <em>basic</em> profile.";
|
||||
|
||||
$strings['enableCloudRecording_help'] = "Requires a paying Zoom profile.
|
||||
Will not work for a <em>basic</em> profile.";
|
||||
|
||||
// please keep these lines alphabetically sorted
|
||||
$strings['AllCourseUsersWereRegistered'] = "All course students were registered";
|
||||
$strings['Agenda'] = "Agenda";
|
||||
$strings['CannotRegisterWithoutEmailAddress'] = "Cannot register without email address";
|
||||
$strings['CopyingJoinURL'] = "Copying join URL";
|
||||
$strings['CopyJoinAsURL'] = "Copy 'join as' URL";
|
||||
$strings['CopyToCourse'] = "Copy to course";
|
||||
$strings['CouldNotCopyJoinURL'] = "Could not copy join URL";
|
||||
$strings['Course'] = "Cours";
|
||||
$strings['CreatedAt'] = "Created at";
|
||||
$strings['CreateLinkInCourse'] = "Create link(s) in course";
|
||||
$strings['CreateUserVideoConference'] = "Create user conference";
|
||||
$strings['DateMeetingTitle'] = "%s: %s";
|
||||
$strings['DeleteMeeting'] = "Delete meeting";
|
||||
$strings['DeleteFile'] = "Delete file(s)";
|
||||
$strings['Details'] = "Details";
|
||||
$strings['DoIt'] = "Do it";
|
||||
$strings['Duration'] = "Duration";
|
||||
$strings['DurationFormat'] = "%hh%I";
|
||||
$strings['DurationInMinutes'] = "Duration (in minutes)";
|
||||
$strings['EndDate'] = "End Date";
|
||||
$strings['EnterMeeting'] = "Enter meeting";
|
||||
$strings['ViewMeeting'] = "View meeting";
|
||||
$strings['Files'] = "Files";
|
||||
$strings['Finished'] = "finished";
|
||||
$strings['FileWasCopiedToCourse'] = "The file was copied to the course";
|
||||
$strings['FileWasDeleted'] = "The file was deleted";
|
||||
$strings['GlobalMeeting'] = "Global conference";
|
||||
$strings['GlobalMeetingPerUser'] = "Global conference per user";
|
||||
$strings['GroupUsersWereRegistered'] = "Group members were registered";
|
||||
$strings['InstantMeeting'] = "Instant meeting";
|
||||
$strings['Join'] = "Join";
|
||||
$strings['JoinGlobalVideoConference'] = "Join global conference";
|
||||
$strings['JoinURLCopied'] = "Join URL copied";
|
||||
$strings['JoinURLToSendToParticipants'] = "Join URL to send to participants";
|
||||
$strings['LiveMeetings'] = "Live meetings";
|
||||
$strings['LinkToFileWasCreatedInCourse'] = "A link to the file was added to the course";
|
||||
$strings['MeetingDeleted'] = "Meeting deleted";
|
||||
$strings['MeetingsFound'] = "Meetings found";
|
||||
$strings['MeetingUpdated'] = "Meeting updated";
|
||||
$strings['NewMeetingCreated'] = "New meeting created";
|
||||
$strings['Password'] = "Password";
|
||||
$strings['RecurringWithFixedTime'] = "Recurring with fixed time";
|
||||
$strings['RecurringWithNoFixedTime'] = "Recurring with no fixed time";
|
||||
$strings['RegisterAllCourseUsers'] = "Register all course users";
|
||||
$strings['RegisteredUserListWasUpdated'] = "Registered user list updated";
|
||||
$strings['RegisteredUsers'] = "Registered users";
|
||||
$strings['RegisteredPresenters'] = "Registered presenters";
|
||||
$strings['RegisterNoUser'] = "Register no user";
|
||||
$strings['RegisterTheseGroupMembers'] = "Register these group members";
|
||||
$strings['ScheduleAMeeting'] = "Schedule a meeting";
|
||||
$strings['ScheduledMeeting'] = "Scheduled meeting";
|
||||
$strings['ScheduledMeetings'] = "Scheduled Meetings";
|
||||
$strings['ScheduleAMeeting'] = "Schedule a meeting";
|
||||
$strings['SearchMeeting'] = "Search meeting";
|
||||
$strings['Session'] = "Session";
|
||||
$strings['StartDate'] = "Start Date";
|
||||
$strings['Started'] = "started";
|
||||
$strings['StartInstantMeeting'] = "Start instant meeting";
|
||||
$strings['StartMeeting'] = "Start meeting";
|
||||
$strings['StartTime'] = "Start time";
|
||||
$strings['Topic'] = "Topic";
|
||||
$strings['TopicAndAgenda'] = "Topic and agenda";
|
||||
$strings['Type'] = "Type";
|
||||
$strings['UpcomingMeetings'] = "Upcoming meetings";
|
||||
$strings['UpdateMeeting'] = "Update meeting";
|
||||
$strings['UpdateRegisteredUserList'] = "Update registered user list";
|
||||
$strings['UserRegistration'] = "User registration";
|
||||
$strings['Y-m-d H:i'] = "Y-m-d H:i";
|
||||
$strings['Waiting'] = "waiting";
|
||||
$strings['XRecordingOfMeetingXFromXDurationXDotX'] = "%s recording of meeting %s from %s (%s).%s";
|
||||
$strings['YouAreNotRegisteredToThisMeeting'] = "You are not registered to this meeting";
|
||||
$strings['ZoomVideoConferences'] = "Zoom Video Conferences";
|
||||
$strings['Recordings'] = "Recordings";
|
||||
$strings['CreateGlobalVideoConference'] = "Create global video conference";
|
||||
$strings['ConferenceNotStarted'] = "Conference not started";
|
||||
$strings['MeetingNotFound'] = "Meeting not found";
|
||||
$strings['JoinURLNotAvailable'] = "URL not available";
|
||||
$strings['Meetings'] = "Meetings";
|
||||
$strings['ConferenceType'] = "Conference type";
|
||||
$strings['ForEveryone'] = "Everyone";
|
||||
$strings['SomeUsers'] = "Some users (Select later)";
|
||||
$strings['Activity'] = "Activity";
|
||||
$strings['ConferenceNotAvailable'] = "Conference not available";
|
||||
$strings['SignAttendance'] = "Sign attendance";
|
||||
$strings['ReasonToSign'] = 'Reason to sign attendance';
|
||||
$strings['ConferenceWithAttendance'] = "Conference with attendance sign";
|
||||
$strings['Sign'] = "Sign";
|
||||
$strings['Signature'] = "Signature";
|
||||
$strings['Meeting'] = "Meeting";
|
||||
$strings['Webinar'] = "Webinar";
|
||||
$strings['AudienceType'] = 'Audience type';
|
||||
$strings['AccountEmail'] = 'Account email';
|
||||
$strings['NewWebinarCreated'] = "New webinar created";
|
||||
$strings['UpdateWebinar'] = 'Update webinar';
|
||||
$strings['WebinarUpdated'] = "Webinar updated";
|
||||
$strings['DeleteWebinar'] = "Delete webinar";
|
||||
$strings['WebinarDeleted'] = "Webinar deleted";
|
||||
$strings['UrlForSelfRegistration'] = "URL for self registration";
|
||||
$strings['RegisterMeToConference'] = "Register me to conference";
|
||||
$strings['UnregisterMeToConference'] = "Unregister me to conference";
|
||||
$strings['Presenters'] = "Presenters";
|
||||
173
plugin/zoom/lang/french.php
Normal file
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
/* License: see /license.txt */
|
||||
|
||||
// Needed in order to show the plugin title
|
||||
$strings['plugin_title'] = "Conférence vidéo Zoom";
|
||||
$strings['plugin_comment'] = "Intégration de conférences vidéo Zoom dans les cours et les sessions";
|
||||
|
||||
$strings['tool_enable'] = 'Outil de conférence vidéos Zoom activé';
|
||||
$strings['apiKey'] = "Clé d'API (<em>API Key</em>)";
|
||||
$strings['apiSecret'] = "Code secret d'API (<em>API Secret</em>)";
|
||||
$strings['enableParticipantRegistration'] = "Activer l'inscription des participants";
|
||||
$strings['enableCloudRecording'] = "Type d'enregistrement automatique";
|
||||
$strings['enableGlobalConference'] = "Activer les conférences globales";
|
||||
$strings['enableGlobalConferencePerUser'] = "Activer les conférences globales par utilisateur";
|
||||
$strings['globalConferenceAllowRoles'] = "Visibilité du lien de vidéo conférence global pour les profils suivant";
|
||||
$strings['globalConferencePerUserAllowRoles'] = "Visibilité du lien de vidéo conférence global par utilisateur pour les profils suivant";
|
||||
$strings['tool_enable_help'] = "Choisissez si vous voulez activer l'outil de conférence vidéo Zoom.
|
||||
Une fois activé, il apparaitra dans les pages d'accueil de tous les cours :
|
||||
les enseignants pourront <strong>démarrer</strong> une conférence et les étudiants la <strong>rejoindre</strong>.
|
||||
<br/>
|
||||
Ce plugin requiert un compte Zoom pour gérer les conférences.
|
||||
<p>L'API de Zoom utilise les <em>JSON Web Tokens (JWT)</em> pour autoriser l'accès à un compte.
|
||||
Pour les obtenir, créez une application JWT ou une application OAuth serveur à serveur :</p>
|
||||
<blockquote>
|
||||
<p>À partir du 1er juin 2023, Zoom recommande de créer une application OAuth serveur à serveur
|
||||
pour remplacer la fonctionnalité d'une application JWT dans votre compte.</p>
|
||||
</blockquote>
|
||||
<ol>
|
||||
<li>Connectez-vous à votre <a href=\"https://zoom.us/profile\">page de profil Zoom</a></li>
|
||||
<li>Cliquez sur Avancé / Marketplace d'application</li>
|
||||
<li>Cliquez sur <a href=\"https://marketplace.zoom.us/develop/create\">Développer / Créer une application</a></li>
|
||||
<li>Choisissez JWT ou OAuth serveur à serveur, puis Créer</li>
|
||||
<li>Informations : Remplissez les champs sur votre \"App\" (noms de l'application et de la société, nom et adresse e-mail de contact)</li>
|
||||
<li>Cliquez sur Continuer</li>
|
||||
<li>Identifiants de l'application
|
||||
<ol>
|
||||
<li>Pour une application JWT : Copiez votre clé API (API Key) et votre code secret (API Secret) dans la configuration du plugin</li>
|
||||
<li>Pour une application OAuth serveur à serveur : Copiez votre <em>ID de compte</em>, votre <em>ID de client</em> et votre <em>secret de client</em> dans la configuration du plugin</li>
|
||||
</ol></li>
|
||||
<li>Cliquez sur Continuer</li>
|
||||
<li><p>Fonctionnalité : activez les <em>Abonnements aux événements / Event Subscriptions</em> pour en ajouter un nouveau avec comme endpoint URL
|
||||
<code>https://your.chamilo.url/plugin/zoom/endpoint.php</code> (validez le point de terminaison pour permettre l'activation de l'application) et ajoutez
|
||||
ces types d'événements :</p>
|
||||
<ul>
|
||||
<li>Démarrer une réunion / Start Meeting</li>
|
||||
<li>Terminer une réunion / End Meeting</li>
|
||||
<li>Participant/hôte a rejoint la réunion / Participant/Host joined meeting</li>
|
||||
<li>Participant/hôte a quitté la réunion / Participant/Host left meeting</li>
|
||||
<li>Démarrer un webinar / Start Webinar</li>
|
||||
<li>Terminer un webinar / End Webinar</li>
|
||||
<li>Participant/hôte a rejoint le webinar / Participant/Host joined webinar</li>
|
||||
<li>Participant/hôte a quitté le webinar / Participant/Host left webinar</li>
|
||||
<li>Toutes les enregistrements sont terminées / All Recordings have completed</li>
|
||||
<li>Les fichiers de transcription d'enregistrement sont terminés / Recording transcript files have completed</li>
|
||||
</ul>
|
||||
<p>Ensuite, cliquez sur Terminé, puis sur Enregistrer et copiez votre <em>Jeton de vérification / Verification Token</em> si vous avez une application JWT ou le <em>Jeton Secret / Secret
|
||||
Token</em> si vous avez une application OAuth serveur à serveur dans la configuration du plugin</p></li>
|
||||
<li>cliquez sur Continuer</li>
|
||||
<li>Scopes (uniquement pour l'application OAuth serveur à serveur) : cliquez sur <em>Ajouter des scopes / Add Scopes</em> et sélectionnez <em>meeting:write:admin</em>, <em>webinar:write:admin</em>, <em>recording:write:admin</em>. Puis cliquez sur Terminé.</li>
|
||||
</ol>
|
||||
<br/>
|
||||
<strong>Attention</strong> :
|
||||
<br/>Zoom n'est <em>PAS</em> un logiciel libre
|
||||
et des règles spécifiques de protection des données personnelles s'y appliquent.
|
||||
Merci de vérifier auprès de Zoom qu'elles sont satisfaisantes pour vous et les apprenants qui l'utiliseront.";
|
||||
|
||||
$strings['enableParticipantRegistration_help'] = "Nécessite un profil Zoom payant.
|
||||
Ne fonctionnera pas pour un profil <em>de base</em>.";
|
||||
|
||||
$strings['enableCloudRecording_help'] = "Nécessite un profil Zoom payant.
|
||||
Ne fonctionnera pas pour un profil <em>de base</em>.";
|
||||
|
||||
// please keep these lines alphabetically sorted
|
||||
$strings['AllCourseUsersWereRegistered'] = "Tous les étudiants du cours sont inscrits";
|
||||
$strings['Agenda'] = "Ordre du jour";
|
||||
$strings['CannotRegisterWithoutEmailAddress'] = "Impossible d'inscrire un utilisateur sans adresse de courriel";
|
||||
$strings['CopyingJoinURL'] = "Copie de l'URL pour rejoindre en cours";
|
||||
$strings['CopyJoinAsURL'] = "Copier l'URL pour 'rejoindre en tant que'";
|
||||
$strings['CopyToCourse'] = "Copier dans le cours";
|
||||
$strings['CouldNotCopyJoinURL'] = "Échec de la copie de l'URL pour rejoindre";
|
||||
$strings['Course'] = "Cours";
|
||||
$strings['CreatedAt'] = "Créé à";
|
||||
$strings['CreateLinkInCourse'] = "Créer dans le cours un ou des lien(s) vers le(s) fichier(s)";
|
||||
$strings['CreateUserVideoConference'] = "Créer des conferences par utilisateur";
|
||||
$strings['DateMeetingTitle'] = "%s : %s";
|
||||
$strings['DeleteMeeting'] = "Effacer la conférence";
|
||||
$strings['DeleteFile'] = "Supprimer ce(s) fichier(s)";
|
||||
$strings['Details'] = "Détail";
|
||||
$strings['DoIt'] = "Fais-le";
|
||||
$strings['Duration'] = "Durée";
|
||||
$strings['DurationFormat'] = "%hh%I";
|
||||
$strings['DurationInMinutes'] = "Durée (en minutes)";
|
||||
$strings['EndDate'] = "Date de fin";
|
||||
$strings['EnterMeeting'] = "Entrer dans la conférence";
|
||||
$strings['ViewMeeting'] = "Voir la conférence";
|
||||
$strings['Files'] = "Fichiers";
|
||||
$strings['Finished'] = "terminée";
|
||||
$strings['FileWasCopiedToCourse'] = "Le fichier a été copié dans le cours";
|
||||
$strings['FileWasDeleted'] = "Le fichier a été effacé";
|
||||
$strings['GlobalMeeting'] = "Conférence globale";
|
||||
$strings['GroupUsersWereRegistered'] = "Les membres des groupes ont été inscrits";
|
||||
$strings['InstantMeeting'] = "Conférence instantanée";
|
||||
$strings['Join'] = "Rejoindre";
|
||||
$strings['JoinGlobalVideoConference'] = "Rejoindre la conférence globale";
|
||||
$strings['JoinURLCopied'] = "URL pour rejoindre copiée";
|
||||
$strings['JoinURLToSendToParticipants'] = "URL pour assister à la conférence (à envoyer aux participants)";
|
||||
$strings['LiveMeetings'] = "Conférences en cours";
|
||||
$strings['LinkToFileWasCreatedInCourse'] = "Un lien vers le fichier a été ajouter au cours";
|
||||
$strings['MeetingDeleted'] = "Conférence effacée";
|
||||
$strings['MeetingsFound'] = "Conférences trouvées";
|
||||
$strings['MeetingUpdated'] = "Conférence mise à jour";
|
||||
$strings['NewMeetingCreated'] = "Nouvelle conférence créée";
|
||||
$strings['Password'] = "Mot de passe";
|
||||
$strings['RecurringWithFixedTime'] = "Recurrent, à heure fixe";
|
||||
$strings['RecurringWithNoFixedTime'] = "Recurrent, sans heure fixe";
|
||||
$strings['RegisterAllCourseUsers'] = "Inscrire tous les utilisateurs du cours";
|
||||
$strings['RegisteredUserListWasUpdated'] = "Liste des utilisateurs inscrits mise à jour";
|
||||
$strings['RegisteredUsers'] = "Utilisateurs inscrits";
|
||||
$strings['RegisterNoUser'] = "N'inscrire aucun utilisateur";
|
||||
$strings['RegisterTheseGroupMembers'] = "Inscrire les membres de ces groupes";
|
||||
$strings['ScheduleAMeeting'] = "Programmer une conférence";
|
||||
$strings['ScheduledMeeting'] = "Conférence programmée";
|
||||
$strings['ScheduledMeetings'] = "Conférences programmées";
|
||||
$strings['ScheduleAMeeting'] = "Programmer une conférence";
|
||||
$strings['SearchMeeting'] = "Rechercher une conférence";
|
||||
$strings['Session'] = "Session";
|
||||
$strings['StartDate'] = "Date de début";
|
||||
$strings['Started'] = "démarrée";
|
||||
$strings['StartInstantMeeting'] = "Démarrer une conférence instantanée";
|
||||
$strings['StartMeeting'] = "Démarrer la conférence";
|
||||
$strings['StartTime'] = "Heure de début";
|
||||
$strings['Topic'] = "Objet";
|
||||
$strings['TopicAndAgenda'] = "Objet et ordre du jour";
|
||||
$strings['Type'] = "Type";
|
||||
$strings['UpcomingMeeting'] = "Conférences à venir";
|
||||
$strings['UpdateMeeting'] = "Mettre à jour la conférence";
|
||||
$strings['UpdateRegisteredUserList'] = "Mettre à jour la liste des utilisateurs inscrits";
|
||||
$strings['UserRegistration'] = "Inscription des utilisateurs";
|
||||
$strings['Y-m-d H:i'] = "d/m/Y à H\hi";
|
||||
$strings['verificationToken'] = 'Verification Token';
|
||||
$strings['Waiting'] = "en attente";
|
||||
$strings['XRecordingOfMeetingXFromXDurationXDotX'] = "Enregistrement (%s) de la conférence %s de %s (%s).%s";
|
||||
$strings['YouAreNotRegisteredToThisMeeting'] = "Vous n'êtes pas inscrit à cette conférence";
|
||||
$strings['ZoomVideoConferences'] = "Conférences vidéo Zoom";
|
||||
$strings['Recordings'] = "Enregistrements";
|
||||
$strings['CreateGlobalVideoConference'] = "Créer une conférence global";
|
||||
$strings['JoinURLNotAvailable'] = "URL pas disponible";
|
||||
$strings['Meetings'] = "Conférences";
|
||||
$strings['Activity'] = "Activité";
|
||||
$strings['ConferenceNotAvailable'] = "Conférence non disponible";
|
||||
$strings['SignAttendance'] = "Signer la feuille d'émargement";
|
||||
$strings['ReasonToSign'] = "Explication pour signer la feuille d'émargement";
|
||||
$strings['ConferenceWithAttendance'] = "Conférence avec signature d'émargement";
|
||||
$strings['Sign'] = "Signer";
|
||||
$strings['Signature'] = "Signature";
|
||||
$strings['Meeting'] = "Meeting";
|
||||
$strings['Webinar'] = "Webinar";
|
||||
$strings['AudienceType'] = "Type d'audience";
|
||||
$strings['AccountEmail'] = "Compte email";
|
||||
$strings['NewWebinarCreated'] = "Nouveau webinar créé";
|
||||
$strings['UpdateWebinar'] = "Mettre à jour le webinar";
|
||||
$strings['WebinarUpdated'] = "Webinar mis à jour";
|
||||
$strings['DeleteWebinar'] = "Supprimer le webinar";
|
||||
$strings['WebinarDeleted'] = "Webinar supprimé";
|
||||
$strings['UrlForSelfRegistration'] = "URL pour l'auto-inscription des participants";
|
||||
$strings['RegisterMeToConference'] = "M'inscrire à la visio";
|
||||
$strings['UnregisterMeToConference'] = "Me désinscrire de la visio";
|
||||
$strings['ForEveryone'] = "Tout le monde";
|
||||
$strings['SomeUsers'] = "Utilisateurs inscrits (à inscrire après)";
|
||||
$strings['Presenters'] = "Animateurs";
|
||||
$strings['RegisteredPresenters'] = "Animateurs enregistrés";
|
||||
$strings['enablePresenter_help'] = "Il est nécessaire que l'option <i>Activer l'inscription des participants</i> soit sur Oui.";
|
||||
$strings['enablePresenter'] = 'Activer les animateurs';
|
||||
174
plugin/zoom/lang/spanish.php
Normal file
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
/* License: see /license.txt */
|
||||
|
||||
// Needed in order to show the plugin title
|
||||
$strings['plugin_title'] = "Videoconferencia Zoom";
|
||||
$strings['plugin_comment'] = "Integración de videoconferencias Zoom en los cursos y las sesiones";
|
||||
|
||||
$strings['tool_enable'] = 'Herramienta activada';
|
||||
$strings['apiKey'] = "Clave API (<em>API Key</em>)";
|
||||
$strings['apiSecret'] = "Código secreto de API (<em>API Secret</em>)";
|
||||
$strings['enableParticipantRegistration'] = "Activar la inscripción de participantes";
|
||||
$strings['enablePresenter'] = 'Activar presentadores';
|
||||
$strings['enablePresenter_help'] = 'Requiere que el parametro <i>Activar la inscripción de participantes</i> este activado.';
|
||||
$strings['enableCloudRecording'] = "Tipo de grabación automática";
|
||||
$strings['enableGlobalConference'] = "Activar las conferencias globales";
|
||||
$strings['enableGlobalConferencePerUser'] = "Activar las conferencias globales por usuario";
|
||||
$strings['globalConferenceAllowRoles'] = "Visibilidad del enlace global de videoconferencia para los perfiles siguientes";
|
||||
$strings['globalConferencePerUserAllowRoles'] = "Visibilidad del enlace global de videoconferencia por usuario para los perfiles siguientes";
|
||||
$strings['accountSelector'] = 'Selector de cuentas';
|
||||
$strings['accountSelector_help'] = 'Te permite declarar los correos de las diferentes cuentas con las que quieres abrir los videos de Zoom. Separados por punto y coma (account_one@example.come;account_two@exaple.com).';
|
||||
|
||||
$strings['tool_enable_help'] = "Escoja si desea activar la herramienta Zoom.
|
||||
Una vez activada, aparecerá en las páginas principales de todos los cursos. Los profesores podrán
|
||||
<strong>iniciar</strong> una conferencia y los alumnos <strong>juntarse</strong> a ella.
|
||||
<br/>
|
||||
Este plugin requiere una cuenta Zoom para gestionar las conferencias.
|
||||
<p>El API de Zoom utiliza los <em>JSON Web Tokens (JWT)</em> para autorizar el acceso a una cuenta.
|
||||
Para obtenerlos, crea una <em>app JWT</em> o una aplicación Server-to-Server OAuth:</p>
|
||||
<blockquote>
|
||||
<p>Desde el 1 de junio de 2023, Zoom recomienda que usted cree una aplicación Server-to-Server OAuth para reemplazar
|
||||
la funcionalidad de una aplicación JWT en tu cuenta.</p>
|
||||
</blockquote>
|
||||
<ol>
|
||||
<li>logéase en <a href=\"https://zoom.us/profile\">Su perfil Zoom</a></li>
|
||||
<li>de clic en <em>Avanzado / Marketplace de aplicaciones</em></li>
|
||||
<li>de clic en <em><a href=\"https://marketplace.zoom.us/develop/create\">Develop / build App</a></em></li>
|
||||
<li>escoja <em>JWT o Sever-to-Server OAuth y luego Create</em></li>
|
||||
<li>Information: ingrese algunas informaciones sobre vuestra \"App\"
|
||||
(nombres de la aplicación, de la empresa, nombre y dirección de correo de contacto)
|
||||
<li>de clic en <em>Continue</em></li>
|
||||
<li>App Credentials:
|
||||
<ol>
|
||||
<li>Para una aplicación JWT: copia la clave (API Key) y el código secreto (API Secret) por ingresar aquí.</li>
|
||||
<li>Para una aplicación Server-to-Server OAuth: Copia los valores de <em>Account ID</em>, <em>Client ID</em> y <em>Client secret</em> para ingresar aquí</li>
|
||||
</ol>
|
||||
<li>de clic en <em>Continue</em></li>
|
||||
<li><p>Feature : activez <em>Event Subscriptions</em> para agregar uno con su endpoint URL
|
||||
<code>https://your.chamilo.url/plugin/zoom/endpoint.php</code> (valida el endpoint para permitir activar la aplicación)
|
||||
y agrega este tipo de eventos:</p>
|
||||
<ul>
|
||||
<li>Start Meeting</li>
|
||||
<li>End Meeting</li>
|
||||
<li>Participant/Host joined meeting</li>
|
||||
<li>Participant/Host left meeting</li>
|
||||
<li>Start Webinar</li>
|
||||
<li>End Webinar</li>
|
||||
<li>Participant/Host joined webinar</li>
|
||||
<li>Participant/Host left webinar</li>
|
||||
<li>All Recordings have completed</li>
|
||||
<li>Recording transcript files have completed</li>
|
||||
</ul>
|
||||
<p>Luego de clic en <em>Done</em> y luego en <em>Save</em> y copie su <em>Verification Token</em> si tiene una aplicación JWT o el <em>Secret token</em> si tiene una aplicación Server-to-Server OAuth para ingresar aquí</li>
|
||||
<li>de clic en <em>Continue</em></li>
|
||||
<li>Scopes (solo para una aplicación Server-to-Server OAuth): click en <em>Add Scopes</em> y seleccione <em>meeting:write:admin</em>,
|
||||
<em>webinar:write:admin</em>, <em>recording:write:admin</em>. Luego, haga click en Done.</li>
|
||||
</ol>
|
||||
<br/>
|
||||
<strong>Atención</strong> :
|
||||
<br/>Zoom <em>NO ES</em> un software libre, y reglas específicas de protección de datos se aplican a este.
|
||||
Por favor verifique con Zoom que éstas le den satisfacción a Usted y los alumnos que la usarán.";
|
||||
|
||||
$strings['enableParticipantRegistration_help'] = "Requiere un perfil Zoom de pago.
|
||||
No funcionará para un perfil <em>base/gratuito</em>.";
|
||||
|
||||
$strings['enableCloudRecording_help'] = "Requiere un perfil Zoom de pago.
|
||||
No funcionará para un perfil <em>base/gratuito</em>.";
|
||||
|
||||
// please keep these lines alphabetically sorted
|
||||
$strings['AllCourseUsersWereRegistered'] = "Todos los alumnos del curso están inscritos";
|
||||
$strings['Agenda'] = "Orden del día";
|
||||
$strings['CannotRegisterWithoutEmailAddress'] = "No se puede registrar usuario sin dirección de correo electrónico";
|
||||
$strings['CopyingJoinURL'] = "Copia de la URL para ingresar";
|
||||
$strings['CopyJoinAsURL'] = "Copiar la URL para 'ingresar como'";
|
||||
$strings['CopyToCourse'] = "Copiar en el curso";
|
||||
$strings['CouldNotCopyJoinURL'] = "Falló la copia de la URL de ingreso";
|
||||
$strings['Course'] = "Curso";
|
||||
$strings['CreatedAt'] = "Creado el";
|
||||
$strings['CreateLinkInCourse'] = "Crear en el curso uno o más vínculos hacia el/los archivo(s)";
|
||||
$strings['CreateUserVideoConference'] = "Crear conferencias de usario";
|
||||
$strings['DateMeetingTitle'] = "%s: %s";
|
||||
$strings['DeleteMeeting'] = "Borrar la conferencia";
|
||||
$strings['DeleteFile'] = "Borrar este/estos archivo(s)";
|
||||
$strings['Details'] = "Detalle";
|
||||
$strings['DoIt'] = "Hágalo";
|
||||
$strings['Duration'] = "Duración";
|
||||
$strings['DurationFormat'] = "%hh%I";
|
||||
$strings['DurationInMinutes'] = "Duración (en minutos)";
|
||||
$strings['EndDate'] = "Fecha de fin";
|
||||
$strings['EnterMeeting'] = "Ingresar la conferencia";
|
||||
$strings['ViewMeeting'] = "Ver la conferencia";
|
||||
$strings['Files'] = "Archivos";
|
||||
$strings['Finished'] = "terminada";
|
||||
$strings['FileWasCopiedToCourse'] = "El archivo ha sido copiado en el curso";
|
||||
$strings['FileWasDeleted'] = "El archivo ha sido borrado";
|
||||
$strings['GlobalMeeting'] = "Conferencia global";
|
||||
$strings['GroupUsersWereRegistered'] = "Miembros de los grupos han sido registrados";
|
||||
$strings['InstantMeeting'] = "Conferencia instantánea";
|
||||
$strings['Join'] = "Ingresar";
|
||||
$strings['JoinGlobalVideoConference'] = "Ingresar la conrencia global";
|
||||
$strings['JoinURLCopied'] = "URL para juntarse copiada";
|
||||
$strings['JoinURLToSendToParticipants'] = "URL para asistir a la conferencia (para enviar a los participantes)";
|
||||
$strings['LiveMeetings'] = "Conferencias activas";
|
||||
$strings['LinkToFileWasCreatedInCourse'] = "Un enlace al archivo ha sido añadido al curso";
|
||||
$strings['MeetingDeleted'] = "Conferencia borrada";
|
||||
$strings['MeetingsFound'] = "Conferencias encontradas";
|
||||
$strings['MeetingUpdated'] = "Conferencias actualizadas";
|
||||
$strings['NewMeetingCreated'] = "Nueva conferencia creada";
|
||||
$strings['Password'] = "Contraseña";
|
||||
$strings['RecurringWithFixedTime'] = "Recurrente, a una hora fija";
|
||||
$strings['RecurringWithNoFixedTime'] = "Recurrente, sin hora fija";
|
||||
$strings['RegisterAllCourseUsers'] = "Inscribir todos los usuarios del curso";
|
||||
$strings['RegisteredUserListWasUpdated'] = "Lista de usuarios inscritos actualizada";
|
||||
$strings['RegisteredUsers'] = "Usuarios inscritos";
|
||||
$strings['RegisteredPresenters'] = "Presentadores registrados";
|
||||
$strings['RegisterNoUser'] = "No inscribir ningún usuario";
|
||||
$strings['RegisterTheseGroupMembers'] = "Inscribir los miembros de estos grupos";
|
||||
$strings['ScheduleAMeeting'] = "Programar una conferencia";
|
||||
$strings['ScheduledMeeting'] = "Conferencia programada";
|
||||
$strings['ScheduledMeetings'] = "Conferencias programadas";
|
||||
$strings['ScheduleAMeeting'] = "Programar una conferencia";
|
||||
$strings['SearchMeeting'] = "Buscar una conferencia";
|
||||
$strings['Session'] = "Sesión";
|
||||
$strings['StartDate'] = "Fecha de inicio";
|
||||
$strings['Started'] = "iniciada";
|
||||
$strings['StartInstantMeeting'] = "Iniciar una conferencia instantánea";
|
||||
$strings['StartMeeting'] = "Iniciar la conferencia";
|
||||
$strings['StartTime'] = "Hora de inicio";
|
||||
$strings['Topic'] = "Objeto";
|
||||
$strings['TopicAndAgenda'] = "Objeto y orden del día";
|
||||
$strings['Type'] = "Tipo";
|
||||
$strings['UpcomingMeeting'] = "Próximas conferencias";
|
||||
$strings['UpdateMeeting'] = "Actualizar la conferencia";
|
||||
$strings['UpdateRegisteredUserList'] = "Actualizar la lista de usuarios inscritos";
|
||||
$strings['UserRegistration'] = "Inscripción de los usuarios";
|
||||
$strings['Y-m-d H:i'] = "d/m/Y a las H\hi";
|
||||
$strings['verificationToken'] = 'Verification Token';
|
||||
$strings['Waiting'] = "en espera";
|
||||
$strings['XRecordingOfMeetingXFromXDurationXDotX'] = "Grabación (%s) de la conferencia %s de %s (%s).%s";
|
||||
$strings['YouAreNotRegisteredToThisMeeting'] = "No estás registrado en esta reunión";
|
||||
$strings['ZoomVideoConferences'] = "Videoconferencias Zoom";
|
||||
$strings['Recordings'] = "Grabaciones";
|
||||
$strings['CreateGlobalVideoConference'] = "Crear una videoconferencia global";
|
||||
$strings['JoinURLNotAvailable'] = "URL no disponible";
|
||||
$strings['Meetings'] = "Conferencias";
|
||||
$strings['Activity'] = "Actividad";
|
||||
$strings['ConferenceNotAvailable'] = "Conferencia no disponible";
|
||||
$strings['SignAttendance'] = "Firmar asistencia";
|
||||
$strings['ReasonToSign'] = 'Razón para firmar asistencia';
|
||||
$strings['ConferenceWithAttendance'] = "Conferencia con registro de asistencia";
|
||||
$strings['Sign'] = "Firmar";
|
||||
$strings['Signature'] = "Firma";
|
||||
$strings['Meeting'] = "Conferencia";
|
||||
$strings['Webinar'] = "Seminario web";
|
||||
$strings['AudienceType'] = 'Tipo de público';
|
||||
$strings['AccountEmail'] = 'Correo electrónico de la cuenta';
|
||||
$strings['NewWebinarCreated'] = "Nuevo seminario web creado";
|
||||
$strings['UpdateWebinar'] = 'Actualizar seminario web';
|
||||
$strings['WebinarUpdated'] = "Seminario web actualizado";
|
||||
$strings['DeleteWebinar'] = "Borrar seminario web";
|
||||
$strings['WebinarDeleted'] = "Seminario web borrado";
|
||||
$strings['UrlForSelfRegistration'] = "URL para auto registro";
|
||||
$strings['RegisterMeToConference'] = "Registrarme a la conferencia";
|
||||
$strings['UnregisterMeToConference'] = "Cancelar registro a la conferencia";
|
||||
$strings['Presenters'] = "Presentadores";
|
||||
67
plugin/zoom/lib/API/Api2RequestTrait.php
Normal 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;
|
||||
}
|
||||
}
|
||||
41
plugin/zoom/lib/API/BaseMeetingTrait.php
Normal 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
|
||||
{
|
||||
}
|
||||
}
|
||||
56
plugin/zoom/lib/API/Client.php
Normal 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;
|
||||
}
|
||||
}
|
||||
42
plugin/zoom/lib/API/CreatedRegistration.php
Normal 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");
|
||||
}
|
||||
}
|
||||
18
plugin/zoom/lib/API/CustomQuestion.php
Normal 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;
|
||||
}
|
||||
26
plugin/zoom/lib/API/FollowUpUsers.php
Normal 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");
|
||||
}
|
||||
}
|
||||
39
plugin/zoom/lib/API/GlobalDialInNumber.php
Normal 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");
|
||||
}
|
||||
}
|
||||
38
plugin/zoom/lib/API/JWTClient.php
Normal 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);
|
||||
}
|
||||
}
|
||||
122
plugin/zoom/lib/API/JsonDeserializableTrait.php
Normal 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();
|
||||
}
|
||||
}
|
||||
88
plugin/zoom/lib/API/Meeting.php
Normal 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;
|
||||
}
|
||||
}
|
||||
34
plugin/zoom/lib/API/MeetingInfo.php
Normal 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;
|
||||
}
|
||||
148
plugin/zoom/lib/API/MeetingInfoGet.php
Normal 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;
|
||||
}
|
||||
}
|
||||
50
plugin/zoom/lib/API/MeetingInstance.php
Normal 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);
|
||||
}
|
||||
}
|
||||
53
plugin/zoom/lib/API/MeetingInstances.php
Normal 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");
|
||||
}
|
||||
}
|
||||
58
plugin/zoom/lib/API/MeetingList.php
Normal 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");
|
||||
}
|
||||
}
|
||||
44
plugin/zoom/lib/API/MeetingListItem.php
Normal 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");
|
||||
}
|
||||
}
|
||||
22
plugin/zoom/lib/API/MeetingRegistrant.php
Normal 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;
|
||||
}
|
||||
}
|
||||
53
plugin/zoom/lib/API/MeetingRegistrantList.php
Normal 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");
|
||||
}
|
||||
}
|
||||
29
plugin/zoom/lib/API/MeetingRegistrantListItem.php
Normal 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;
|
||||
}
|
||||
143
plugin/zoom/lib/API/MeetingSettings.php
Normal 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");
|
||||
}
|
||||
}
|
||||
22
plugin/zoom/lib/API/Ocurrence.php
Normal 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");
|
||||
}
|
||||
}
|
||||
68
plugin/zoom/lib/API/Pagination.php
Normal 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;
|
||||
}
|
||||
}
|
||||
71
plugin/zoom/lib/API/PaginationToken.php
Normal 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;
|
||||
}
|
||||
}
|
||||
57
plugin/zoom/lib/API/ParticipantList.php
Normal 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");
|
||||
}
|
||||
}
|
||||
22
plugin/zoom/lib/API/ParticipantListItem.php
Normal 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;
|
||||
}
|
||||
74
plugin/zoom/lib/API/PastMeeting.php
Normal 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);
|
||||
}
|
||||
}
|
||||
23
plugin/zoom/lib/API/QuestionAndAnswer.php
Normal 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");
|
||||
}
|
||||
}
|
||||
115
plugin/zoom/lib/API/RecordingFile.php
Normal 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");
|
||||
}
|
||||
}
|
||||
65
plugin/zoom/lib/API/RecordingList.php
Normal 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");
|
||||
}
|
||||
}
|
||||
95
plugin/zoom/lib/API/RecordingMeeting.php
Normal 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");
|
||||
}
|
||||
}
|
||||
103
plugin/zoom/lib/API/RegistrantSchema.php
Normal 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");
|
||||
}
|
||||
}
|
||||
84
plugin/zoom/lib/API/ServerToServerOAuthClient.php
Normal 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'];
|
||||
}
|
||||
}
|
||||
29
plugin/zoom/lib/API/TrackingField.php
Normal 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");
|
||||
}
|
||||
}
|
||||
9
plugin/zoom/lib/API/WebinarRegistrantSchema.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
namespace Chamilo\PluginBundle\Zoom\API;
|
||||
|
||||
class WebinarRegistrantSchema extends RegistrantSchema
|
||||
{
|
||||
}
|
||||
137
plugin/zoom/lib/API/WebinarSchema.php
Normal 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
|
||||
);
|
||||
}
|
||||
}
|
||||
201
plugin/zoom/lib/API/WebinarSettings.php
Normal 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");
|
||||
}
|
||||
}
|
||||
215
plugin/zoom/lib/MeetingRepository.php
Normal 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)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
65
plugin/zoom/lib/RecordingRepository.php
Normal 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;
|
||||
}
|
||||
);
|
||||
}*/
|
||||
}
|
||||
49
plugin/zoom/lib/RegistrantRepository.php
Normal 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();
|
||||
}
|
||||
}
|
||||
2000
plugin/zoom/lib/ZoomPlugin.php
Normal file
50
plugin/zoom/meeting.ajax.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
use Chamilo\PluginBundle\Zoom\Meeting;
|
||||
use Symfony\Component\HttpFoundation\Request as HttpRequest;
|
||||
|
||||
require_once __DIR__.'/config.php';
|
||||
|
||||
api_block_anonymous_users(false);
|
||||
|
||||
$httpRequest = HttpRequest::createFromGlobals();
|
||||
|
||||
$meetingId = $httpRequest->get('meetingId', 0);
|
||||
|
||||
if (empty($meetingId)) {
|
||||
api_not_allowed();
|
||||
}
|
||||
|
||||
$plugin = ZoomPlugin::create();
|
||||
/** @var Meeting $meeting */
|
||||
$meeting = $plugin->getMeetingRepository()->findOneBy(['meetingId' => $meetingId]);
|
||||
$currentUserId = api_get_user_id();
|
||||
$currentUser = api_get_user_entity($currentUserId);
|
||||
|
||||
if (null === $meeting) {
|
||||
api_not_allowed(false, $plugin->get_lang('MeetingNotFound'));
|
||||
}
|
||||
|
||||
switch ($httpRequest->get('a')) {
|
||||
case 'sign_attempt':
|
||||
$registrant = $meeting->getRegistrantByUser($currentUser);
|
||||
|
||||
if (!$meeting->isSignAttendance() ||
|
||||
null === $registrant
|
||||
) {
|
||||
api_not_allowed();
|
||||
}
|
||||
|
||||
$file = $httpRequest->request->get('file', '');
|
||||
|
||||
$secToken = Security::get_token('zoom_signature');
|
||||
|
||||
if (!Security::check_token($secToken, null, 'zoom_signature')) {
|
||||
api_not_allowed();
|
||||
}
|
||||
|
||||
echo (int) $plugin->saveSignature($registrant, $file);
|
||||
exit;
|
||||
}
|
||||
110
plugin/zoom/meeting.php
Normal file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
/* For license terms, see /license.txt */
|
||||
|
||||
use Chamilo\PluginBundle\Zoom\Meeting;
|
||||
use Chamilo\PluginBundle\Zoom\Webinar;
|
||||
|
||||
require_once __DIR__.'/config.php';
|
||||
|
||||
$meetingId = isset($_REQUEST['meetingId']) ? (int) $_REQUEST['meetingId'] : 0;
|
||||
if (empty($meetingId)) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
$plugin = ZoomPlugin::create();
|
||||
/** @var Meeting $meeting */
|
||||
$meeting = $plugin->getMeetingRepository()->findOneBy(['meetingId' => $meetingId]);
|
||||
|
||||
if (null === $meeting) {
|
||||
api_not_allowed(true, $plugin->get_lang('MeetingNotFound'));
|
||||
}
|
||||
|
||||
$course_plugin = 'zoom'; // needed in order to load the plugin lang variables
|
||||
$returnURL = 'meetings.php';
|
||||
$urlExtra = '';
|
||||
if ($meeting->isCourseMeeting()) {
|
||||
api_protect_course_script(true);
|
||||
$this_section = SECTION_COURSES;
|
||||
$urlExtra = api_get_cidreq();
|
||||
$returnURL = 'start.php?'.$urlExtra;
|
||||
|
||||
if (api_is_in_group()) {
|
||||
$interbreadcrumb[] = [
|
||||
'url' => api_get_path(WEB_CODE_PATH).'group/group.php?'.$urlExtra,
|
||||
'name' => get_lang('Groups'),
|
||||
];
|
||||
$interbreadcrumb[] = [
|
||||
'url' => api_get_path(WEB_CODE_PATH).'group/group_space.php?'.$urlExtra,
|
||||
'name' => get_lang('GroupSpace').' '.$meeting->getGroup()->getName(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$logInfo = [
|
||||
'tool' => 'Videoconference Zoom',
|
||||
];
|
||||
Event::registerLog($logInfo);
|
||||
|
||||
$interbreadcrumb[] = [
|
||||
'url' => $returnURL,
|
||||
'name' => $plugin->get_lang('ZoomVideoConferences'),
|
||||
];
|
||||
|
||||
$tpl = new Template($meeting->getMeetingId());
|
||||
|
||||
if ($plugin->userIsConferenceManager($meeting)) {
|
||||
// user can edit, start and delete meeting
|
||||
$tpl->assign('isConferenceManager', true);
|
||||
|
||||
$tpl->assign('editMeetingForm', $plugin->getEditConferenceForm($meeting)->returnForm());
|
||||
|
||||
if ($meeting instanceof Webinar) {
|
||||
$tpl->assign('deleteMeetingForm', $plugin->getDeleteWebinarForm($meeting, $returnURL)->returnForm());
|
||||
} elseif ($meeting instanceof Meeting) {
|
||||
$tpl->assign('deleteMeetingForm', $plugin->getDeleteMeetingForm($meeting, $returnURL)->returnForm());
|
||||
}
|
||||
|
||||
$pluginEnableParticipantRegistration = 'true' === $plugin->get('enableParticipantRegistration');
|
||||
|
||||
if ($pluginEnableParticipantRegistration && $meeting->requiresRegistration()) {
|
||||
if (false === $meeting->isGlobalMeeting()
|
||||
&& false == $meeting->isCourseMeeting()
|
||||
) {
|
||||
$tpl->assign('registerParticipantForm', $plugin->getRegisterParticipantForm($meeting)->returnForm());
|
||||
$tpl->assign('registrants', $meeting->getRegistrants());
|
||||
}
|
||||
|
||||
if ('true' === $plugin->get('enablePresenter') && !$meeting->isCourseMeeting()) {
|
||||
$tpl->assign('registerPresenterForm', $plugin->getRegisterPresenterForm($meeting)->returnForm());
|
||||
$tpl->assign('presenters', $meeting->getPresenters());
|
||||
}
|
||||
}
|
||||
|
||||
if (ZoomPlugin::RECORDING_TYPE_NONE !== $plugin->getRecordingSetting() &&
|
||||
$meeting->hasCloudAutoRecordingEnabled()
|
||||
) {
|
||||
$tpl->assign('fileForm', $plugin->getFileForm($meeting, $returnURL)->returnForm());
|
||||
$tpl->assign('recordings', $meeting->getRecordings());
|
||||
}
|
||||
} elseif ($meeting->requiresRegistration()) {
|
||||
$userId = api_get_user_id();
|
||||
try {
|
||||
foreach ($meeting->getRegistrants() as $registrant) {
|
||||
if ($registrant->getUser()->getId() == $userId) {
|
||||
$tpl->assign('currentUserJoinURL', $registrant->getJoinUrl());
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception $exception) {
|
||||
Display::addFlash(
|
||||
Display::return_message($exception->getMessage(), 'error')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$tpl->assign('actions', $plugin->getToolbar());
|
||||
$tpl->assign('meeting', $meeting);
|
||||
$tpl->assign('url_extra', $urlExtra);
|
||||
$tpl->assign('content', $tpl->fetch('zoom/view/meeting.tpl'));
|
||||
$tpl->display_one_col_template();
|
||||
28
plugin/zoom/meetings.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/* For license terms, see /license.txt */
|
||||
|
||||
$course_plugin = 'zoom'; // needed in order to load the plugin lang variables
|
||||
|
||||
$cidReset = true;
|
||||
require_once __DIR__.'/config.php';
|
||||
|
||||
if (!ZoomPlugin::currentUserCanJoinGlobalMeeting()) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
$plugin = ZoomPlugin::create();
|
||||
$user = api_get_user_entity(api_get_user_id());
|
||||
|
||||
$form = $plugin->getAdminSearchForm();
|
||||
$startDate = new DateTime($form->getElement('start')->getValue());
|
||||
$endDate = new DateTime($form->getElement('end')->getValue());
|
||||
$scheduleForm = $plugin->getScheduleMeetingForm($user);
|
||||
$tpl = new Template();
|
||||
$tpl->assign('meetings', $plugin->getMeetingRepository()->periodUserMeetings($startDate, $endDate, $user));
|
||||
$tpl->assign('allow_recording', $plugin->hasRecordingAvailable());
|
||||
$tpl->assign('actions', $plugin->getToolbar());
|
||||
$tpl->assign('search_form', $form->returnForm());
|
||||
$tpl->assign('schedule_form', $scheduleForm->returnForm());
|
||||
$tpl->assign('content', $tpl->fetch('zoom/view/meetings.tpl'));
|
||||
$tpl->display_one_col_template();
|
||||
4
plugin/zoom/plugin.php
Normal file
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
/* For license terms, see /license.txt */
|
||||
|
||||
$plugin_info = ZoomPlugin::create()->get_info();
|
||||
BIN
plugin/zoom/resources/img/22/zoom_meet.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
plugin/zoom/resources/img/22/zoom_meet_na.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
plugin/zoom/resources/img/32/zoom_meet.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
plugin/zoom/resources/img/32/zoom_meet_na.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
plugin/zoom/resources/img/64/zoom_meet.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
plugin/zoom/resources/img/64/zoom_meet_na.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
291
plugin/zoom/resources/img/svg/zoommeet.svg
Normal file
@@ -0,0 +1,291 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="124"
|
||||
height="124"
|
||||
viewBox="0 0 124 124"
|
||||
version="1.1"
|
||||
preserveAspectRatio="xMidYMid"
|
||||
id="svg68"
|
||||
sodipodi:docname="googlemeet.svg"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
|
||||
<metadata
|
||||
id="metadata72">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1860"
|
||||
inkscape:window-height="1016"
|
||||
id="namedview70"
|
||||
showgrid="false"
|
||||
inkscape:zoom="3.5336739"
|
||||
inkscape:cx="20.920415"
|
||||
inkscape:cy="96.925373"
|
||||
inkscape:window-x="60"
|
||||
inkscape:window-y="1107"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="g965" />
|
||||
<defs
|
||||
id="defs37">
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient950">
|
||||
<stop
|
||||
style="stop-color:#007266;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop946" />
|
||||
<stop
|
||||
style="stop-color:#007266;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop948" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
x1="71.77459"
|
||||
y1="187.32983"
|
||||
x2="206.34541"
|
||||
y2="53.078278"
|
||||
id="linearGradient-1"
|
||||
gradientTransform="matrix(0.35264551,0,0,0.40800991,10.373845,5.6478575)"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#058B7E"
|
||||
offset="0%"
|
||||
id="stop2" />
|
||||
<stop
|
||||
stop-color="#058D80"
|
||||
offset="0%"
|
||||
id="stop4" />
|
||||
<stop
|
||||
stop-color="#058D7F"
|
||||
offset="100%"
|
||||
id="stop6" />
|
||||
</linearGradient>
|
||||
<path
|
||||
d="M 127.68269,0 C 57.165748,0 0,55.790933 0,124.61227 0,193.43392 57.165748,249.22453 127.68269,249.22453 l 0.27148,46.91374 c 65.60585,-37.27075 128,-87.01882 128,-171.526 C 255.95417,55.790933 198.19994,0 127.68269,0 Z"
|
||||
id="path-2"
|
||||
inkscape:connector-curvature="0" />
|
||||
<filter
|
||||
x="-0.0040000002"
|
||||
y="-0.003"
|
||||
width="1.008"
|
||||
height="1.007"
|
||||
filterUnits="objectBoundingBox"
|
||||
id="filter-3">
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="2"
|
||||
in="SourceAlpha"
|
||||
result="shadowOffsetInner1"
|
||||
id="feOffset10" />
|
||||
<feComposite
|
||||
in="shadowOffsetInner1"
|
||||
in2="SourceAlpha"
|
||||
operator="arithmetic"
|
||||
k2="-1"
|
||||
k3="1"
|
||||
result="shadowInnerInner1"
|
||||
id="feComposite12"
|
||||
k1="0"
|
||||
k4="0" />
|
||||
<feColorMatrix
|
||||
values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.2 0"
|
||||
type="matrix"
|
||||
in="shadowInnerInner1"
|
||||
id="feColorMatrix14" />
|
||||
</filter>
|
||||
<path
|
||||
d="M 127.68269,0 C 57.165748,0 0,55.790933 0,124.61227 0,193.43392 57.165748,249.22453 127.68269,249.22453 l 0.27148,46.91374 c 65.60585,-37.27075 128,-87.01882 128,-171.526 C 255.95417,55.790933 198.19994,0 127.68269,0 Z"
|
||||
id="path-4"
|
||||
inkscape:connector-curvature="0" />
|
||||
<filter
|
||||
x="-0.0040000002"
|
||||
y="-0.003"
|
||||
width="1.008"
|
||||
height="1.007"
|
||||
filterUnits="objectBoundingBox"
|
||||
id="filter-5">
|
||||
<feOffset
|
||||
dx="0"
|
||||
dy="-2"
|
||||
in="SourceAlpha"
|
||||
result="shadowOffsetInner1"
|
||||
id="feOffset18" />
|
||||
<feComposite
|
||||
in="shadowOffsetInner1"
|
||||
in2="SourceAlpha"
|
||||
operator="arithmetic"
|
||||
k2="-1"
|
||||
k3="1"
|
||||
result="shadowInnerInner1"
|
||||
id="feComposite20"
|
||||
k1="0"
|
||||
k4="0" />
|
||||
<feColorMatrix
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"
|
||||
type="matrix"
|
||||
in="shadowInnerInner1"
|
||||
id="feColorMatrix22" />
|
||||
</filter>
|
||||
<path
|
||||
d="M 127.68269,0 C 57.165748,0 0,55.790933 0,124.61227 0,193.43392 57.165748,249.22453 127.68269,249.22453 l 0.27148,46.91374 c 65.60585,-37.27075 128,-87.01882 128,-171.526 C 255.95417,55.790933 198.19994,0 127.68269,0 Z"
|
||||
id="path-6"
|
||||
inkscape:connector-curvature="0" />
|
||||
<linearGradient
|
||||
x1="119.3371"
|
||||
y1="153.50986"
|
||||
x2="236.07732"
|
||||
y2="282.50131"
|
||||
id="linearGradient-8"
|
||||
gradientTransform="scale(1.1271732,0.88717512)"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#000000"
|
||||
offset="0%"
|
||||
id="stop26" />
|
||||
<stop
|
||||
stop-color="#D8D8D8"
|
||||
stop-opacity="0"
|
||||
offset="100%"
|
||||
id="stop28" />
|
||||
</linearGradient>
|
||||
<path
|
||||
d="m 55.580192,128.1054 v 34.23858 c 0,9.03901 7.395555,16.43457 16.434567,16.43457 h 85.016021 c 9.03901,0 16.43457,-7.39556 16.43457,-16.43457 v -21.62283 l 33.65926,33.65925 v -46.275 z"
|
||||
id="path-9"
|
||||
inkscape:connector-curvature="0" />
|
||||
<filter
|
||||
x="-0.0099999998"
|
||||
y="-0.029999999"
|
||||
width="1.026"
|
||||
height="1.118"
|
||||
filterUnits="objectBoundingBox"
|
||||
id="filter-10">
|
||||
<feOffset
|
||||
dx="1"
|
||||
dy="3"
|
||||
in="SourceAlpha"
|
||||
result="shadowOffsetOuter1"
|
||||
id="feOffset32" />
|
||||
<feColorMatrix
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"
|
||||
type="matrix"
|
||||
in="shadowOffsetOuter1"
|
||||
id="feColorMatrix34" />
|
||||
</filter>
|
||||
<mask
|
||||
id="mask-7"
|
||||
fill="white">
|
||||
<use
|
||||
xlink:href="#path-6"
|
||||
id="use49"
|
||||
x="0"
|
||||
y="0"
|
||||
width="100%"
|
||||
height="100%" />
|
||||
</mask>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient950"
|
||||
id="linearGradient952"
|
||||
x1="80.086624"
|
||||
y1="68.221016"
|
||||
x2="96.365685"
|
||||
y2="82.936577"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<g
|
||||
id="g1001"
|
||||
inkscape:export-filename="/var/www/chamilo11/plugin/google_meet/resources/img/64/meet.png"
|
||||
inkscape:export-xdpi="49.548386"
|
||||
inkscape:export-ydpi="49.548386">
|
||||
<rect
|
||||
y="0"
|
||||
x="0"
|
||||
height="124"
|
||||
width="124"
|
||||
id="rect967"
|
||||
style="opacity:0;fill:#008072;fill-opacity:1;stroke:none;stroke-width:1.63019824;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.63019823, 3.26039649000000020;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers" />
|
||||
<g
|
||||
id="g965">
|
||||
<g
|
||||
style="fill:#000000;fill-opacity:1"
|
||||
id="g43"
|
||||
transform="matrix(0.37931894,0,0,0.37931894,10.373845,5.6478575)">
|
||||
<use
|
||||
height="100%"
|
||||
width="100%"
|
||||
y="0"
|
||||
x="0"
|
||||
style="filter:url(#filter-3)"
|
||||
id="use41"
|
||||
xlink:href="#path-2" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:#5599ff;stroke-width:0.37931895"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path39"
|
||||
d="m 58.806308,5.6478575 c -26.748411,0 -48.432463,21.1625575 -48.432463,47.2677945 0,26.105355 21.684052,47.267788 48.432463,47.267788 v 0 c 26.086173,-0.13013 48.655802,-15.212614 48.655802,-47.267788 0,-26.105237 -21.907273,-47.2677945 -48.655802,-47.2677945 z"
|
||||
sodipodi:nodetypes="ssccss" />
|
||||
<g
|
||||
id="g916"
|
||||
transform="matrix(0.96698632,0,0,0.96698632,2.218741,3.1352548)">
|
||||
<g
|
||||
transform="matrix(0.39226919,0,0,0.39226919,8.433526,2.598385)"
|
||||
id="g62">
|
||||
<use
|
||||
xlink:href="#path-9"
|
||||
id="use58"
|
||||
style="fill:#000000;fill-opacity:1;filter:url(#filter-10)"
|
||||
x="0"
|
||||
y="0"
|
||||
width="100%"
|
||||
height="100%" />
|
||||
</g>
|
||||
<path
|
||||
d="M 89.682141,52.850186 V 34.646356 L 76.47865,47.821703 v -8.402255 c 0,-3.54585 -2.90105,-6.446774 -6.446775,-6.446774 H 36.68271 c -1.772863,0 -5.479585,-0.03472 -6.43699,-0.0086 0.04687,1.181868 -0.0098,4.682401 -0.0098,6.455326 v 13.430738 z"
|
||||
id="path64"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#e2e2e2;stroke-width:0.39226919"
|
||||
sodipodi:nodetypes="cccssscscc" />
|
||||
<use
|
||||
transform="matrix(0.39226919,0,0,0.39226919,8.4335257,2.5983849)"
|
||||
xlink:href="#path-9"
|
||||
id="use60"
|
||||
style="fill:#f6f6f6;fill-rule:evenodd"
|
||||
x="0"
|
||||
y="0"
|
||||
width="100%"
|
||||
height="100%" />
|
||||
<rect
|
||||
style="opacity:1;fill:#5599ff;fill-opacity:1;stroke:none;stroke-width:1.36803973;stroke-opacity:1"
|
||||
id="rect1681"
|
||||
width="1.0864193"
|
||||
height="28.55731"
|
||||
x="76.49678"
|
||||
y="38.07761" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.1 KiB |
118
plugin/zoom/start.php
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
/* For license terms, see /license.txt */
|
||||
|
||||
$course_plugin = 'zoom'; // needed in order to load the plugin lang variables
|
||||
|
||||
require_once __DIR__.'/config.php';
|
||||
|
||||
api_protect_course_script(true);
|
||||
|
||||
$this_section = SECTION_COURSES;
|
||||
$logInfo = [
|
||||
'tool' => 'Videoconference Zoom',
|
||||
];
|
||||
Event::registerLog($logInfo);
|
||||
|
||||
$course = api_get_course_entity();
|
||||
if (null === $course) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
$group = api_get_group_entity();
|
||||
$session = api_get_session_entity();
|
||||
$plugin = ZoomPlugin::create();
|
||||
|
||||
if (null !== $group) {
|
||||
$interbreadcrumb[] = [
|
||||
'url' => api_get_path(WEB_CODE_PATH).'group/group.php?'.api_get_cidreq(),
|
||||
'name' => get_lang('Groups'),
|
||||
];
|
||||
$interbreadcrumb[] = [
|
||||
'url' => api_get_path(WEB_CODE_PATH).'group/group_space.php?'.api_get_cidreq(),
|
||||
'name' => get_lang('GroupSpace').' '.$group->getName(),
|
||||
];
|
||||
}
|
||||
|
||||
$url = api_get_self().'?'.api_get_cidreq(true, false).'&gidReq=';
|
||||
$htmlHeadXtra[] = '<script>
|
||||
$(function() {
|
||||
$("#group_select").on("change", function() {
|
||||
var groupId = $(this).find("option:selected").val();
|
||||
var url = "'.$url.'";
|
||||
window.location.replace(url+groupId);
|
||||
});
|
||||
});
|
||||
</script>';
|
||||
|
||||
$tool_name = $plugin->get_lang('ZoomVideoConferences');
|
||||
$tpl = new Template($tool_name);
|
||||
|
||||
$action = isset($_REQUEST['action']) ? $_REQUEST['action'] : '';
|
||||
|
||||
$isManager = $plugin->userIsCourseConferenceManager();
|
||||
if ($isManager) {
|
||||
$groupId = api_get_group_id();
|
||||
$groups = GroupManager::get_groups();
|
||||
if (!empty($groups)) {
|
||||
$form = new FormValidator('group_filter');
|
||||
$groupList[0] = get_lang('Select');
|
||||
foreach ($groups as $groupData) {
|
||||
$itemGroupId = $groupData['iid'];
|
||||
/*if (isset($meetingsGroup[$itemGroupId]) && $meetingsGroup[$itemGroupId] == 1) {
|
||||
$groupData['name'] .= ' ('.get_lang('Active').')';
|
||||
}*/
|
||||
$groupList[$itemGroupId] = $groupData['name'];
|
||||
}
|
||||
$form->addSelect('group_id', get_lang('Groups'), $groupList, ['id' => 'group_select']);
|
||||
$form->setDefaults(['group_id' => $groupId]);
|
||||
$formToString = $form->returnForm();
|
||||
|
||||
$tpl->assign('group_form', $formToString);
|
||||
}
|
||||
|
||||
switch ($action) {
|
||||
case 'delete':
|
||||
$meeting = $plugin->getMeetingRepository()->findOneBy(['meetingId' => $_REQUEST['meetingId']]);
|
||||
if ($meeting && $meeting->isCourseMeeting()) {
|
||||
$plugin->deleteMeeting($meeting, api_get_self().'?'.api_get_cidreq());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$user = api_get_user_entity(api_get_user_id());
|
||||
|
||||
$tpl->assign(
|
||||
'instant_meeting_form',
|
||||
$plugin->getCreateInstantMeetingForm(
|
||||
$user,
|
||||
$course,
|
||||
$group,
|
||||
$session
|
||||
)->returnForm()
|
||||
);
|
||||
$tpl->assign(
|
||||
'schedule_meeting_form',
|
||||
$plugin->getScheduleMeetingForm(
|
||||
$user,
|
||||
$course,
|
||||
$group,
|
||||
$session
|
||||
)->returnForm()
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
$tpl->assign(
|
||||
'meetings',
|
||||
$plugin->getMeetingRepository()->courseMeetings($course, $group, $session)
|
||||
);
|
||||
} catch (Exception $exception) {
|
||||
Display::addFlash(
|
||||
Display::return_message('Could not retrieve scheduled meeting list: '.$exception->getMessage(), 'error')
|
||||
);
|
||||
}
|
||||
|
||||
$tpl->assign('is_manager', $isManager);
|
||||
$tpl->assign('content', $tpl->fetch('zoom/view/start.tpl'));
|
||||
$tpl->display_one_col_template();
|
||||
117
plugin/zoom/subscription.php
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
/* For license terms, see /license.txt */
|
||||
|
||||
use Chamilo\PluginBundle\Zoom\Meeting;
|
||||
use Chamilo\UserBundle\Entity\User;
|
||||
|
||||
require_once __DIR__.'/config.php';
|
||||
|
||||
api_block_anonymous_users();
|
||||
|
||||
$course_plugin = 'zoom'; // needed in order to load the plugin lang variables
|
||||
|
||||
if (empty($_REQUEST['meetingId'])) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
$plugin = ZoomPlugin::create();
|
||||
|
||||
/** @var Meeting $meeting */
|
||||
$meeting = $plugin->getMeetingRepository()->findOneBy(['meetingId' => $_REQUEST['meetingId']]);
|
||||
|
||||
if (null === $meeting) {
|
||||
api_not_allowed(true, $plugin->get_lang('MeetingNotFound'));
|
||||
}
|
||||
|
||||
if (false !== $meeting->isGlobalMeeting()
|
||||
|| false != $meeting->isCourseMeeting()
|
||||
|| 'true' !== $plugin->get('enableParticipantRegistration')
|
||||
|| !$meeting->requiresRegistration()
|
||||
) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
$currentUser = api_get_user_entity(api_get_user_id());
|
||||
$userRegistrant = $meeting->getRegistrantByUser($currentUser);
|
||||
|
||||
if ($meeting->isCourseMeeting()) {
|
||||
api_protect_course_script(true);
|
||||
|
||||
if (api_is_in_group()) {
|
||||
$interbreadcrumb[] = [
|
||||
'url' => api_get_path(WEB_CODE_PATH).'group/group.php?'.api_get_cidreq(),
|
||||
'name' => get_lang('Groups'),
|
||||
];
|
||||
$interbreadcrumb[] = [
|
||||
'url' => api_get_path(WEB_CODE_PATH).'group/group_space.php?'.api_get_cidreq(),
|
||||
'name' => get_lang('GroupSpace').' '.$meeting->getGroup()->getName(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$form = new FormValidator('subscription');
|
||||
$form->addHidden('meetingId', $meeting->getMeetingId());
|
||||
|
||||
if (!empty($userRegistrant)) {
|
||||
$form->addButton(
|
||||
'unregister',
|
||||
$plugin->get_lang('UnregisterMeToConference'),
|
||||
'user-times',
|
||||
'warning'
|
||||
);
|
||||
|
||||
$form->addHtml(
|
||||
'<div class="form-group"><div class="col-sm-8 col-sm-offset-2">'
|
||||
.Display::url(
|
||||
$plugin->get_lang('ViewMeeting'),
|
||||
api_get_path(WEB_PLUGIN_PATH).'zoom/join_meeting.php?meetingId='.$meeting->getMeetingId(),
|
||||
['class' => 'btn btn-primary']
|
||||
)
|
||||
.'</div></div>'
|
||||
);
|
||||
} else {
|
||||
$filtered = array_filter(
|
||||
$meeting->getRegistrableUsers(),
|
||||
function (User $registableUser) use ($currentUser) {
|
||||
return $registableUser->getId() === $currentUser->getId();
|
||||
}
|
||||
);
|
||||
|
||||
if (empty($filtered)) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
$form->addButton(
|
||||
'register',
|
||||
$plugin->get_lang('RegisterMeToConference'),
|
||||
'user-plus',
|
||||
'success'
|
||||
);
|
||||
}
|
||||
|
||||
if ($form->validate()) {
|
||||
$values = $form->exportValues();
|
||||
|
||||
if (isset($values['unregister'])) {
|
||||
$plugin->unregister($meeting, [$userRegistrant]);
|
||||
} else {
|
||||
$plugin->registerUsers($meeting, [$currentUser]);
|
||||
}
|
||||
|
||||
Display::addFlash(
|
||||
Display::return_message($plugin->get_lang('RegisteredUserListWasUpdated'), 'success')
|
||||
);
|
||||
|
||||
api_location('?meetingId='.$meeting->getMeetingId());
|
||||
} else {
|
||||
$form->protect();
|
||||
}
|
||||
|
||||
$view = new Template('');
|
||||
$view->assign('meeting', $meeting);
|
||||
$view->assign('frm_register_unregister', $form->returnForm());
|
||||
$content = $view->fetch('zoom/view/subscription.tpl');
|
||||
|
||||
$view->assign('content', $content);
|
||||
$view->display_one_col_template();
|
||||
8
plugin/zoom/uninstall.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
/* For license terms, see /license.txt */
|
||||
|
||||
if (!api_is_platform_admin()) {
|
||||
exit('You must have admin permissions to uninstall plugins');
|
||||
}
|
||||
|
||||
ZoomPlugin::create()->uninstall();
|
||||
57
plugin/zoom/view/activity.tpl
Normal file
@@ -0,0 +1,57 @@
|
||||
<h4>
|
||||
{{ meeting.typeName }} {{ meeting.meetingId }}
|
||||
</h4>
|
||||
|
||||
<a class="btn btn-primary" href="meeting.php?meetingId={{ meeting.meetingId }}&{{ url_extra }}">
|
||||
{{ 'Edit'|get_lang }}
|
||||
</a>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ 'Type'|get_lang }}</th>
|
||||
<th>{{ 'Action'|get_plugin_lang('ZoomPlugin') }}</th>
|
||||
{# <th>{{ 'User'|get_lang }}</th>#}
|
||||
<th>{{ 'Date'|get_lang }}</th>
|
||||
<th>{{ 'Details'|get_lang }} </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for activity in meeting.activities %}
|
||||
<tr>
|
||||
<td>
|
||||
{{ activity.type }}
|
||||
</td>
|
||||
<td>
|
||||
{{ activity.name }}
|
||||
</td>
|
||||
<td>
|
||||
{{ activity.createdAt | api_convert_and_format_date(3)}}
|
||||
</td>
|
||||
{# <td>#}
|
||||
{# {% if _u.is_admin %}#}
|
||||
{# <a href="{{ _p.web_main }}admin/user_information.php?user_id={{ activity.user.id }}" >#}
|
||||
{# {{ activity.user.firstname }} {{ activity.user.lastname }} ({{ activity.user.username }})#}
|
||||
{# </a>#}
|
||||
{# {% else %}#}
|
||||
{# {{ activity.user.firstname }} {{ activity.user.lastname }} ({{ activity.user.username }})#}
|
||||
{# {% endif %}#}
|
||||
{# </td>#}
|
||||
<td>
|
||||
{% if activity.eventDecoded.registrant %}
|
||||
{{ 'User' | get_lang }} :
|
||||
{{ activity.eventDecoded.registrant.first_name }} -
|
||||
{{ activity.eventDecoded.registrant.last_name }} -
|
||||
{{ activity.eventDecoded.registrant.email }} -
|
||||
{{ activity.eventDecoded.registrant.status }}
|
||||
{% endif %}
|
||||
|
||||
{% if activity.eventDecoded.participant %}
|
||||
{{ 'User' | get_lang }} :
|
||||
{{ activity.eventDecoded.participant.user_name }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
324
plugin/zoom/view/calendar.tpl
Normal file
@@ -0,0 +1,324 @@
|
||||
<div id="loading" style="margin-left:150px;position:absolute;display:none">
|
||||
{{ "Loading"|get_lang }} …
|
||||
</div>
|
||||
|
||||
<div id="calendar"></div>
|
||||
|
||||
<div class="modal fade" tabindex="-1" role="dialog" id="simple-dialog-form">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="{{ 'Close'|get_lang }}">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h4 class="modal-title">{{ 'Details'|get_lang }}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">{{ 'Type' }}</label>
|
||||
<div class="col-sm-8">
|
||||
<p id="simple_type"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">{{ "Date"|get_lang }}</label>
|
||||
<div class="col-sm-8">
|
||||
<p>
|
||||
<span id="simple_start_date"></span>
|
||||
<span id="simple_end_date"></span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">{{ "Title"|get_lang }}</label>
|
||||
<div class="col-sm-8">
|
||||
<p id="simple_title"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">{{ "Description"|get_lang }}</label>
|
||||
<div class="col-sm-8">
|
||||
<p id="simple_content"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">{{ "AccountEmail"|get_plugin_lang('ZoomPlugin') }}</label>
|
||||
<div class="col-sm-8">
|
||||
<p id="simple_account"></p>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{ 'Close'|get_lang }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function () {
|
||||
var cookieData = Cookies.getJSON('agenda_cookies');
|
||||
var defaultView = (cookieData && cookieData.view) || '{{ default_view }}';
|
||||
var defaultStartDate = (cookieData && cookieData.start) || moment.now();
|
||||
|
||||
var CustomListViewGrid = ListViewGrid.extend({
|
||||
fgSegHtml: function (seg) {
|
||||
var view = this.view;
|
||||
var classes = ['fc-list-item'].concat(this.getSegCustomClasses(seg));
|
||||
var bgColor = this.getSegBackgroundColor(seg);
|
||||
var event = seg.event;
|
||||
var url = event.url;
|
||||
var timeHtml;
|
||||
|
||||
if (view.isMultiDayEvent(event)) { // if the event appears to span more than one day
|
||||
if (seg.isStart || seg.isEnd) { // outer segment that probably lasts part of the day
|
||||
timeHtml = htmlEscape(this.getEventTimeText(seg));
|
||||
} else { // inner segment that lasts the whole day
|
||||
timeHtml = view.getAllDayHtml();
|
||||
}
|
||||
} else {
|
||||
// Display the normal time text for the *event's* times
|
||||
timeHtml = htmlEscape(this.getEventTimeText(event));
|
||||
}
|
||||
|
||||
if (url) {
|
||||
classes.push('fc-has-url');
|
||||
}
|
||||
|
||||
return '<tr class="' + classes.join(' ') + '">' +
|
||||
(this.displayEventTime
|
||||
? '<td class="fc-list-item-time ' + view.widgetContentClass + '">' + (timeHtml || '') + '</td>'
|
||||
: ''
|
||||
) +
|
||||
'<td class="fc-list-item-marker ' + view.widgetContentClass + '">' +
|
||||
'<span class="fc-event-dot"' +
|
||||
(bgColor ? ' style="background-color:' + bgColor + '"' : '') +
|
||||
'></span>' +
|
||||
'</td>' +
|
||||
'<td class="fc-list-item-title ' + view.widgetContentClass + '">' +
|
||||
'<a' + (url ? ' href="' + htmlEscape(url) + '"' : '') + '>' +
|
||||
htmlEscape(seg.event.title || '') + (seg.event.description || '') +
|
||||
'</a>' +
|
||||
'</td>' +
|
||||
'</tr>';
|
||||
},
|
||||
|
||||
// render the event segments in the view
|
||||
renderSegList: function (allSegs) {
|
||||
var segsByDay = this.groupSegsByDay(allSegs); // sparse array
|
||||
var dayIndex;
|
||||
var daySegs;
|
||||
var i;
|
||||
var tableEl = $('<table class="fc-list-table"><tbody/></table>');
|
||||
var tbodyEl = tableEl.find('tbody');
|
||||
var eventList = [];
|
||||
for (dayIndex = 0; dayIndex < segsByDay.length; dayIndex++) {
|
||||
daySegs = segsByDay[dayIndex];
|
||||
if (daySegs) { // sparse array, so might be undefined
|
||||
this.sortEventSegs(daySegs);
|
||||
for (i = 0; i < daySegs.length; i++) {
|
||||
var event = daySegs[i].event;
|
||||
if (jQuery.inArray(event.id, eventList) !== -1) {
|
||||
continue;
|
||||
}
|
||||
eventList.push(event.id);
|
||||
// append a day header
|
||||
tbodyEl.append(this.dayHeaderHtml(
|
||||
this.view.start.clone().add(dayIndex, 'days'),
|
||||
event
|
||||
));
|
||||
|
||||
tbodyEl.append(daySegs[i].el); // append event row
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.el.empty().append(tableEl);
|
||||
},
|
||||
// generates the HTML for the day headers that live amongst the event rows
|
||||
dayHeaderHtml: function (dayDate, event) {
|
||||
var view = this.view;
|
||||
var mainFormat = 'LL';
|
||||
var altFormat = 'dddd';
|
||||
var checkIfSame = true;
|
||||
if (event.end) {
|
||||
checkIfSame = event.end.format(mainFormat) === dayDate.format(mainFormat);
|
||||
}
|
||||
|
||||
return '<tr class="fc-list-heading" data-date="' + dayDate.format('YYYY-MM-DD') + '">' +
|
||||
'<td class="' + view.widgetHeaderClass + '" colspan="3">' +
|
||||
(
|
||||
mainFormat
|
||||
? view.buildGotoAnchorHtml(
|
||||
dayDate,
|
||||
{ 'class': 'fc-list-heading-main' },
|
||||
htmlEscape(dayDate.format(mainFormat)) // inner HTML
|
||||
)
|
||||
: ''
|
||||
) +
|
||||
(
|
||||
(checkIfSame === false && mainFormat)
|
||||
? view.buildGotoAnchorHtml(
|
||||
dayDate,
|
||||
{ 'class': 'fc-list-heading-main' },
|
||||
' - ' + htmlEscape(event.end.format(mainFormat)) // inner HTML
|
||||
)
|
||||
: ''
|
||||
) +
|
||||
(
|
||||
altFormat
|
||||
? view.buildGotoAnchorHtml(
|
||||
dayDate,
|
||||
{ 'class': 'fc-list-heading-alt' },
|
||||
htmlEscape(dayDate.format(altFormat)) // inner HTML
|
||||
)
|
||||
: ''
|
||||
) +
|
||||
'</td>' +
|
||||
'</tr>'
|
||||
}
|
||||
})
|
||||
|
||||
var FC = $.fullCalendar; // a reference to FullCalendar's root namespace
|
||||
var View = ListView; // the class that all views must inherit from
|
||||
var CustomView; // our subclass
|
||||
|
||||
CustomView = View.extend({ // make a subclass of View
|
||||
initialize: function () {
|
||||
this.grid = new CustomListViewGrid(this);
|
||||
this.scroller = new Scroller({
|
||||
overflowX: 'hidden',
|
||||
overflowY: 'auto'
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
FC.views.CustomView = CustomView; // register our class with the view system
|
||||
var height = '';
|
||||
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
|
||||
height = 'auto';
|
||||
}
|
||||
|
||||
$('#calendar').fullCalendar({
|
||||
height: height,
|
||||
header: {
|
||||
left: 'today,prev,next',
|
||||
center: 'title',
|
||||
right: 'month,agendaWeek,agendaDay,CustomView'
|
||||
},
|
||||
views: {
|
||||
CustomView: { // name of view
|
||||
type: 'list',
|
||||
buttonText: '{{ 'AgendaList'|get_lang | escape('js') }}',
|
||||
duration: { month: 1 },
|
||||
defaults: {
|
||||
'listDayAltFormat': 'dddd' // day-of-week is nice-to-have
|
||||
}
|
||||
},
|
||||
month: {
|
||||
'displayEventEnd': true
|
||||
}
|
||||
},
|
||||
locale: '{{ region_value }}',
|
||||
defaultView: defaultView,
|
||||
defaultDate: defaultStartDate,
|
||||
firstHour: 8,
|
||||
firstDay: 1,
|
||||
{% if fullcalendar_settings %}
|
||||
{{ fullcalendar_settings }}
|
||||
{% endif %}
|
||||
selectable: false,
|
||||
selectHelper: true,
|
||||
viewRender: function (view, element) {
|
||||
var data = {
|
||||
'view': view.name,
|
||||
'start': view.intervalStart.format('YYYY-MM-DD')
|
||||
};
|
||||
Cookies.set('agenda_cookies', data, 1); // Expires 1 day
|
||||
},
|
||||
eventRender: function (event, element) {
|
||||
{% if on_hover_info.description %}
|
||||
if (event.description) {
|
||||
element.qtip({
|
||||
content: event.description,
|
||||
position: {
|
||||
at: 'top center',
|
||||
my: 'bottom center',
|
||||
viewport: $(window)
|
||||
}
|
||||
});
|
||||
}
|
||||
{% endif %}
|
||||
},
|
||||
eventClick: function (calEvent, jsEvent, view) {
|
||||
var start = calEvent.start;
|
||||
var end = calEvent.end;
|
||||
var diffDays = moment(end).diff(start, 'days');
|
||||
var endDateMinusOne = '';
|
||||
|
||||
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
|
||||
// If event is not editable then just return the qtip
|
||||
{% if on_hover_info.description %}
|
||||
if (calEvent.description) {
|
||||
$(this).qtip({
|
||||
overwrite: false,
|
||||
show: { ready: true },
|
||||
content: calEvent.description,
|
||||
position: {
|
||||
at: 'top center',
|
||||
my: 'bottom center',
|
||||
viewport: $(window)
|
||||
}
|
||||
});
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var clone = end.clone();
|
||||
endDateMinusOne = clone.subtract(1, 'days').format('{{ js_format_date }}');
|
||||
var startDateToString = start.format("{{ js_format_date }}");
|
||||
|
||||
// Simple form
|
||||
$('#simple_start_date').text(startDateToString);
|
||||
if (diffDays > 1) {
|
||||
$('#simple_end_date').text(' - ' + endDateMinusOne);
|
||||
} else if (diffDays == 0) {
|
||||
var start_date_value = start.format('ll');
|
||||
var startTime = start.format('LT');
|
||||
var endTime = end.format('LT');
|
||||
$('#simple_start_date').html('');
|
||||
$('#simple_end_date').html(start_date_value + ' (' + startTime + ' - ' + endTime + ') ');
|
||||
} else {
|
||||
$('#simple_end_date').text('');
|
||||
}
|
||||
|
||||
$('#simple_type').text(calEvent.typeName);
|
||||
$('#simple_title').text(calEvent.title);
|
||||
$('#simple_content').empty().text(calEvent.description);
|
||||
|
||||
if (calEvent.accountEmail) {
|
||||
$('#simple_account').text(calEvent.accountEmail).parents('.form-group').show();
|
||||
} else {
|
||||
$('#simple_account').empty().parents('.form-group').hide();
|
||||
}
|
||||
|
||||
$('#simple-dialog-form').modal('show');
|
||||
},
|
||||
editable: false,
|
||||
events: "{{ web_agenda_ajax_url }}&a=get_events",
|
||||
axisFormat: 'H(:mm)', // pm-am format -> h(:mm)a
|
||||
timeFormat: 'H:mm', // pm-am format -> h:mm
|
||||
loading: function (bool) {
|
||||
if (bool) {
|
||||
$('#loading').show();
|
||||
} else {
|
||||
$('#loading').hide();
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
196
plugin/zoom/view/join.tpl
Normal file
@@ -0,0 +1,196 @@
|
||||
{% include 'zoom/view/meeting_details.tpl' %}
|
||||
|
||||
{% if is_conference_manager and meeting.isSignAttendance %}
|
||||
<p class="text-info">
|
||||
<span class="fa fa-list-alt"></span>
|
||||
{{ 'ConferenceWithAttendance'|get_plugin_lang('ZoomPlugin') }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<hr>
|
||||
|
||||
{% set btn_start = '' %}
|
||||
|
||||
{% if start_url %}
|
||||
{% set btn_start %}
|
||||
<a href="{{ start_url }}" class="btn btn-primary">
|
||||
{{ 'EnterMeeting'|get_plugin_lang('ZoomPlugin') }}
|
||||
</a>
|
||||
{% endset %}
|
||||
{% endif %}
|
||||
|
||||
{% if not is_conference_manager %}
|
||||
{% if meeting.isSignAttendance %}
|
||||
<div class="row">
|
||||
<div class="col-md-offset-3 col-md-6">
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
<span class="fa fa-pencil-square-o fa-fw" aria-hidden="true"></span>
|
||||
{{ 'Attendance'|get_lang }}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>{{ meeting.reasonToSignAttendance }}</p>
|
||||
|
||||
{% if signature %}
|
||||
<div class="thumbnail">
|
||||
<img src="{{ signature.file }}"
|
||||
alt="{{ 'SignatureDone'|get_plugin_lang('ZoomPlugin') }}">
|
||||
<div class="caption text-center">
|
||||
{{ signature.registeredAt|api_convert_and_format_date(constant('DATE_TIME_FORMAT_LONG')) }}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
{% set btn_start = '' %}
|
||||
|
||||
{% if 'started' == meeting.meetingInfoGet.status %}
|
||||
<button class="btn btn-info" id="btn-sign" data-toggle="modal"
|
||||
data-target="#signature-modal">
|
||||
<i class="fa fa-pencil fa-fw" aria-hidden="true"></i>
|
||||
{{ 'Sign'|get_plugin_lang('ZoomPlugin') }}
|
||||
</button>
|
||||
|
||||
<div class="modal fade" tabindex="-1" role="dialog" id="signature-modal"
|
||||
data-backdrop="static">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal"
|
||||
aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h4 class="modal-title">{{ 'SignAttendance'|get_plugin_lang('ZoomPlugin') }}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div id="signature-modal--signature-area" class="well">
|
||||
<canvas></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<span id="signature-modal--loader" aria-hidden="true"
|
||||
class="fa fa-refresh fa-spin"
|
||||
aria-label="{{ 'Loading'|get_lang }}" style="display: none;">
|
||||
</span>
|
||||
<span id="signature-modal--save-controls">
|
||||
<button id="signature-modal--btn-save" class="btn btn-primary">
|
||||
<em class="fa fa-save" aria-hidden="true"></em>
|
||||
{{ 'Save'|get_lang }}
|
||||
</button>
|
||||
<button id="signature-modal--btn-clean" class="btn btn-default">
|
||||
<em class="fa fa-eraser" aria-hidden="true"></em>
|
||||
{{ 'Clean'|get_lang }}
|
||||
</button>
|
||||
</span>
|
||||
<div id="signature-modal--close-controls" style="display: none;">
|
||||
<span id="signature-modal--results"></span>
|
||||
<button class="btn btn-default"
|
||||
data-dismiss="modal">{{ 'Close'|get_lang }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function () {
|
||||
var $signatureArea = $('#signature-modal--signature-area')
|
||||
var $loader = $('#signature-modal--loader')
|
||||
var $saveControls = $('#signature-modal--save-controls')
|
||||
var $btnSave = $('#signature-modal--btn-save')
|
||||
var $btnClean = $('#signature-modal--btn-clean')
|
||||
var $closeControls = $('#signature-modal--close-controls')
|
||||
var $txtResults = $('#signature-modal--results')
|
||||
|
||||
var imageFormat = 'image/png'
|
||||
var canvas = document.querySelector('#signature-modal--signature-area canvas')
|
||||
var signaturePad = new SignaturePad(canvas)
|
||||
|
||||
$('#signature-modal')
|
||||
.on('shown.bs.modal', function (e) {
|
||||
var parentWidth = $signatureArea.width()
|
||||
var parentHeight = $signatureArea.height()
|
||||
|
||||
canvas.setAttribute('width', parentWidth + 'px')
|
||||
canvas.setAttribute('height', parentHeight + 'px')
|
||||
|
||||
signaturePad = new SignaturePad(canvas)
|
||||
})
|
||||
.on('hide.bs.modal', function (e) {
|
||||
$loader.hide()
|
||||
$saveControls.show()
|
||||
$closeControls.hide()
|
||||
$signatureArea.show()
|
||||
$btnSave.prop('disabled', false)
|
||||
$btnClean.prop('disabled', false)
|
||||
})
|
||||
|
||||
$btnClean.on('click', function () {
|
||||
signaturePad.clear()
|
||||
})
|
||||
|
||||
$btnSave.on('click', function () {
|
||||
if (signaturePad.isEmpty()) {
|
||||
alert('{{ 'ProvideASignatureFirst'|get_plugin_lang('ZoomPlugin')|e('js') }}')
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
var dataURL = signaturePad.toDataURL(imageFormat)
|
||||
|
||||
$.ajax({
|
||||
beforeSend: function () {
|
||||
$loader.show()
|
||||
$btnSave.prop('disabled', true)
|
||||
$btnClean.prop('disabled', true)
|
||||
},
|
||||
type: 'POST',
|
||||
url: 'meeting.ajax.php?{{ _p.web_cid_query }}',
|
||||
data: {
|
||||
a: 'sign_attempt',
|
||||
meetingId: {{ meeting.meetingId }},
|
||||
file: dataURL
|
||||
},
|
||||
success: function (data) {
|
||||
$btnSave.prop('disabled', false)
|
||||
$btnClean.prop('disabled', false)
|
||||
$loader.hide()
|
||||
$saveControls.hide()
|
||||
$signatureArea.hide()
|
||||
|
||||
signaturePad.clear()
|
||||
|
||||
if ('1' === data) {
|
||||
$txtResults.html('{{ 'Saved'|get_lang }}')
|
||||
|
||||
window.location.reload()
|
||||
} else {
|
||||
$txtResults.html('{{ 'Error'|get_lang }}')
|
||||
}
|
||||
|
||||
$closeControls.show()
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{{ btn_start }}
|
||||
|
||||
{% if details_url %}
|
||||
<a href="{{ details_url }}" class="btn btn-default">
|
||||
{{ 'Details'|get_lang }}
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
{% if btn_announcement %}
|
||||
{{ btn_announcement }}
|
||||
{% endif %}
|
||||
136
plugin/zoom/view/meeting.tpl
Normal file
@@ -0,0 +1,136 @@
|
||||
<h4>
|
||||
{{ meeting.typeName }} {{ meeting.meetingId }}
|
||||
{% if meeting.meetingInfoGet.status %}
|
||||
({{ meeting.meetingInfoGet.status }})
|
||||
{% endif %}
|
||||
</h4>
|
||||
|
||||
<div class="btn-group" role="group">
|
||||
|
||||
{% if meeting.meetingInfoGet.status != 'finished' %}
|
||||
<a class="btn btn-primary" href="join_meeting.php?meetingId={{ meeting.meetingId }}&{{ url_extra }}">
|
||||
{{ 'ViewMeeting'|get_plugin_lang('ZoomPlugin') }}
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
{% if isConferenceManager %}
|
||||
{% if meeting.status == 'waiting' %}
|
||||
<a class="btn btn-primary" href="{{ meeting.meetingInfoGet.start_url }}" target="_blank">
|
||||
{{ 'StartMeeting'|get_plugin_lang('ZoomPlugin') }}
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
<a class="btn btn-default" href="activity.php?meetingId={{ meeting.meetingId }}&{{ url_extra }}">
|
||||
{{ 'Activity'|get_plugin_lang('ZoomPlugin') }}
|
||||
</a>
|
||||
|
||||
<a href="attendance.php?meetingId={{ meeting.meetingId ~ '&' ~ url_extra }}" class="btn btn-info">
|
||||
{{ 'Attendance'|get_lang }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if isConferenceManager %}
|
||||
<br />
|
||||
<br />
|
||||
<div class="panel panel-default conference">
|
||||
<div class="panel-body">
|
||||
<div class="share">
|
||||
{{ 'JoinURLToSendToParticipants'| get_plugin_lang('ZoomPlugin') }}
|
||||
</div>
|
||||
<div class="form-inline">
|
||||
<div class="form-group">
|
||||
<input id="share_button_flash" type="text"
|
||||
style="width:460px"
|
||||
class="form-control" readonly
|
||||
value="{{ _p.web }}plugin/zoom/join_meeting.php?meetingId={{ meeting.meetingId }}&{{ url_extra }}"
|
||||
>
|
||||
<button onclick="copyTextToClipBoard('share_button_flash');" class="btn btn-default">
|
||||
<span class="fa fa-copy"></span> {{ 'CopyTextToClipboard' | get_lang }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if currentUserJoinURL %}
|
||||
{#<p>#}
|
||||
{# <a href="{{ currentUserJoinURL }}" target="_blank">#}
|
||||
{# {{ 'JoinMeeting'|get_plugin_lang('ZoomPlugin') }}#}
|
||||
{# </a>#}
|
||||
{#</p>#}
|
||||
{% endif %}
|
||||
|
||||
{% if isConferenceManager %}
|
||||
{{ editMeetingForm }}
|
||||
{{ deleteMeetingForm }}
|
||||
{% if registerParticipantForm %}
|
||||
<hr>
|
||||
{{ registerParticipantForm }}
|
||||
{% endif %}
|
||||
|
||||
{% if registerPresenterForm %}
|
||||
{{ registerPresenterForm }}
|
||||
{% endif %}
|
||||
|
||||
{{ fileForm }}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-m6">
|
||||
{% if presenters %}
|
||||
<h3>{{ 'Presenters'|get_plugin_lang('ZoomPlugin') }}</h3>
|
||||
<table class="table">
|
||||
{% for presenter in presenters %}
|
||||
<tr>
|
||||
<td>
|
||||
{{ presenter.fullName }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-m6">
|
||||
{# {% if registrants and meeting.meetingInfoGet.settings.approval_type != 2 %}#}
|
||||
{% if registrants.count > 0 %}
|
||||
<script>
|
||||
function copyJoinURL(event, url) {
|
||||
event.target.textContent = '{{ 'CopyingJoinURL'|get_plugin_lang('ZoomPlugin')|escape }}';
|
||||
navigator.clipboard.writeText(url).then(
|
||||
function() {
|
||||
event.target.textContent = '{{ 'JoinURLCopied'|get_plugin_lang('ZoomPlugin')|escape }}';
|
||||
}, function() {
|
||||
event.target.textContent = '{{ 'CouldNotCopyJoinURL'|get_plugin_lang('ZoomPlugin')|escape }}' + ' ' + url;
|
||||
}
|
||||
);
|
||||
}
|
||||
</script>
|
||||
<h3>{{ 'Users' | get_lang }}</h3>
|
||||
<br />
|
||||
<table class="table">
|
||||
{% for registrant in registrants %}
|
||||
<tr>
|
||||
<td>
|
||||
{{ registrant.fullName }}
|
||||
</td>
|
||||
<td>
|
||||
{# {% if registrant.joinUrl %}#}
|
||||
{# <a class="btn btn-primary" onclick="copyJoinURL(event, '{{ registrant.joinUrl }}')">#}
|
||||
{# {{ 'CopyJoinAsURL'|get_plugin_lang('ZoomPlugin') }}#}
|
||||
{# </a>#}
|
||||
{# {% else %}#}
|
||||
{# <a class="btn btn-primary disabled" >#}
|
||||
{# {{ 'JoinURLNotAvailable'|get_plugin_lang('ZoomPlugin') }}#}
|
||||
{# </a>#}
|
||||
{# {% endif %}#}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
{% include 'zoom/view/meeting_details.tpl' %}
|
||||
{% endif %}
|
||||
23
plugin/zoom/view/meeting_details.tpl
Normal file
@@ -0,0 +1,23 @@
|
||||
<h2 class="page-header">
|
||||
{{ meeting.topic}}
|
||||
<small>{{ meeting.typeName }}</small>
|
||||
</h2>
|
||||
|
||||
<dl class="meeting_properties dl-horizontal">
|
||||
{% if meeting.requiresDateAndDuration %}
|
||||
<dt>{{ 'StartTime'|get_lang }}</dt>
|
||||
<dd>{{ meeting.formattedStartTime }}</dd>
|
||||
|
||||
<dt>{{ 'Duration'|get_lang }}</dt>
|
||||
<dd>{{ meeting.formattedDuration }}</dd>
|
||||
{% endif %}
|
||||
|
||||
{% if meeting.accountEmail %}
|
||||
<dt>{{ 'AccountEmail'|get_lang }}</dt>
|
||||
<dd>{{ meeting.accountEmail }}</dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
|
||||
{% if meeting.agenda %}
|
||||
<p class="lead">{{ meeting.agenda|nl2br }}</p>
|
||||
{% endif %}
|
||||
64
plugin/zoom/view/meetings.tpl
Normal file
@@ -0,0 +1,64 @@
|
||||
{% import "default/document/recycle.tpl" as macro %}
|
||||
|
||||
{{ schedule_form }}
|
||||
{{ search_form }}
|
||||
|
||||
{% if meetings %}
|
||||
<h4>{{ 'MeetingsFound'|get_plugin_lang('ZoomPlugin') }}: </h4>
|
||||
<table class="table table-hover table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ 'Type'|get_lang }}</th>
|
||||
<th>{{ 'Topic'|get_plugin_lang('ZoomPlugin') }}</th>
|
||||
<th>{{ 'StartTime'|get_lang }}</th>
|
||||
<th>{{ 'ForEveryone'|get_plugin_lang('ZoomPlugin') }}</th>
|
||||
{# <th>{{ 'Course'|get_lang }}</th>#}
|
||||
{# <th>{{ 'Session'|get_lang }}</th>#}
|
||||
{% if allow_recording %}
|
||||
<th>{{ 'Recordings'|get_plugin_lang('ZoomPlugin') }}</th>
|
||||
{% endif %}
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for meeting in meetings %}
|
||||
<tr>
|
||||
<td>{{ meeting.typeName }}</td>
|
||||
<td>{{ meeting.topic }}</td>
|
||||
<td>{{ meeting.formattedStartTime }}</td>
|
||||
<td>{{ meeting.user ? 'No'|get_lang : 'Yes'|get_lang }}</td>
|
||||
{# <td>{{ meeting.course ? meeting.course : '-' }}</td>#}
|
||||
{# <td>{{ meeting.session ? meeting.session : '-' }}</td>#}
|
||||
<td>
|
||||
{% if allow_recording and meeting.recordings.count > 0 %}
|
||||
{% for recording in meeting.recordings %}
|
||||
<dl>
|
||||
<dt>
|
||||
{{ recording.formattedStartTime }} ({{ recording.formattedDuration }}) {{ 'Password' | get_lang }}: {{ recording.recordingMeeting.password }}
|
||||
</dt>
|
||||
<dd>
|
||||
<ul>
|
||||
{% for file in recording.recordingMeeting.recording_files %}
|
||||
<li>
|
||||
<a href="{{ file.play_url }}" target="_blank">
|
||||
{{ file.recording_type }}.{{ file.file_type }}
|
||||
({{ macro.bytesToSize(file.file_size) }})
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<a class="btn btn-primary" href="meeting.php?meetingId={{ meeting.meetingId }}">
|
||||
{{ 'Details'|get_lang }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
60
plugin/zoom/view/start.tpl
Normal file
@@ -0,0 +1,60 @@
|
||||
{% if instant_meeting_form %}
|
||||
{{ instant_meeting_form }}
|
||||
{% endif %}
|
||||
|
||||
{% if group_form %}
|
||||
{{ group_form }}
|
||||
{% endif %}
|
||||
|
||||
{% if meetings.count %}
|
||||
<div class="page-header">
|
||||
<h2>{{ 'ScheduledMeetings'|get_lang }}</h2>
|
||||
</div>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>{{ 'Type'|get_lang }}</th>
|
||||
<th>{{ 'Topic'|get_plugin_lang('ZoomPlugin') }}</th>
|
||||
<th>{{ 'Agenda'|get_plugin_lang('ZoomPlugin') }}</th>
|
||||
<th>{{ 'StartTime'|get_lang }}</th>
|
||||
<th>{{ 'Duration'|get_lang }}</th>
|
||||
<th>{{ 'Actions'|get_lang }}</th>
|
||||
</tr>
|
||||
{% for meeting in meetings %}
|
||||
<tr>
|
||||
<td>{{ meeting.typeName }}</td>
|
||||
<td>
|
||||
{{ meeting.meetingInfoGet.topic }}
|
||||
{{ meeting.webinarSchema.topic }}
|
||||
</td>
|
||||
<td>
|
||||
{{ meeting.meetingInfoGet.agenda|nl2br }}
|
||||
{{ meeting.webinarSchema.agenda|nl2br }}
|
||||
</td>
|
||||
<td>{{ meeting.formattedStartTime }}</td>
|
||||
<td>{{ meeting.formattedDuration }}</td>
|
||||
<td>
|
||||
<a class="btn btn-primary" href="join_meeting.php?meetingId={{ meeting.meetingId }}&{{ _p.web_cid_query }}">
|
||||
{{ 'Join'|get_plugin_lang('ZoomPlugin') }}
|
||||
</a>
|
||||
|
||||
{% if is_manager %}
|
||||
<a class="btn btn-default" href="meeting.php?meetingId={{ meeting.meetingId }}&{{ _p.web_cid_query }}">
|
||||
{{ 'Details'|get_plugin_lang('ZoomPlugin') }}
|
||||
</a>
|
||||
|
||||
<a class="btn btn-danger"
|
||||
href="start.php?action=delete&meetingId={{ meeting.meetingId }}&{{ _p.web_cid_query }}"
|
||||
onclick="javascript:if(!confirm('{{ 'AreYouSureToDelete' | get_lang }}')) return false;"
|
||||
>
|
||||
{{ 'Delete'|get_lang }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
{% if schedule_meeting_form %}
|
||||
{{ schedule_meeting_form }}
|
||||
{% endif %}
|
||||
3
plugin/zoom/view/subscription.tpl
Normal file
@@ -0,0 +1,3 @@
|
||||
{% include 'zoom/view/meeting_details.tpl' %}
|
||||
|
||||
{{ frm_register_unregister }}
|
||||