Zoom meeting recording file management - refs BT#17288

pull/3274/head
Sébastien Ducoulombier 6 years ago
parent a1ed80a9ca
commit 024b9ea4e9
  1. 5
      plugin/zoom/admin.php
  2. 28
      plugin/zoom/lang/english.php
  3. 28
      plugin/zoom/lang/french.php
  4. 56
      plugin/zoom/lib/API/JWTClient.php
  5. 36
      plugin/zoom/lib/API/RecordingList.php
  6. 2
      plugin/zoom/lib/API/RecordingMeeting.php
  7. 31
      plugin/zoom/lib/File.php
  8. 71
      plugin/zoom/lib/Recording.php
  9. 164
      plugin/zoom/lib/zoom_plugin.class.php
  10. 147
      plugin/zoom/meeting.php
  11. 2
      plugin/zoom/start.php
  12. 30
      plugin/zoom/view/admin.tpl
  13. 142
      plugin/zoom/view/meeting.tpl

@ -11,7 +11,7 @@ require_once __DIR__.'/config.php';
api_protect_admin_script();
$tool_name = get_lang('ZoomVideoconference');
$tool_name = get_lang('ZoomVideoconferences');
$plugin = ZoomPlugin::create();
@ -49,6 +49,9 @@ $form->setDefaults([
$tpl = new Template($tool_name);
$tpl->assign('meetings', $plugin->getPeriodMeetings($type, $startDate, $endDate));
if ($plugin->get('enableCloudRecording')) {
$tpl->assign('recordings', $plugin->getRecordings($startDate, $endDate));
}
$tpl->assign('search_form', $form->returnForm());
$tpl->assign('content', $tpl->fetch('zoom/view/admin.tpl'));
$tpl->display_one_col_template();

@ -42,39 +42,38 @@ Will not work for a <em>basic</em> profile.";
// please keep these lines alphabetically sorted
$strings['AllCourseUsersWereRegistered'] = "All course students were registered";
$strings['AllRecordingsWereCopiedToCourse'] = "All recordings were copied to the course";
$strings['Agenda'] = "Agenda";
$strings['CopyAllRecordingsToCourse'] = "Copy all recordings to course";
$strings['CopyingJoinURL'] = "Copying join URL";
$strings['CopyJoinURL'] = "Copy join URL";
$strings['CopyRecordingToCourse'] = "Copy recording to course";
$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['DeleteMeeting'] = "Delete meeting";
$strings['DeleteRecordings'] = "Delete recordings";
$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['Files'] = "Files";
$strings['Finished'] = "finished";
$strings['FileWasCopiedToCourse'] = "The file was copied to the course";
$strings['FileWasDeleted'] = "The file was deleted";
$strings['InstantMeeting'] = "Instant meeting";
$strings['InstanceParticipants'] = "Participants";
$strings['InstancesAndRecordings'] = "Instances et enregistrements";
$strings['Join'] = "Join";
$strings['JoinMeeting'] = "Join meeting";
$strings['JoinURL'] = "Join URL";
$strings['JoinMeetingAsMyself'] = "Join meeting as myself";
$strings['JoinURLCopied'] = "Join URL copied";
$strings['JoinURLToSendToParticipants'] = "Join URL to send to participants";
$strings['JoinURLToShare'] = "Join URL to share";
$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['RecordingsWereDeleted'] = "Recordings were deleted";
$strings['RecordingWasCopiedToCourse'] = "The recording was copied to the course";
$strings['RecurringWithFixedTime'] = "Recurring with fixed time";
$strings['RecurringWithNoFixedTime'] = "Recurring with no fixed time";
$strings['RegisterAllCourseUsers'] = "Register all course users";
@ -93,12 +92,11 @@ $strings['StartMeeting'] = "Start meeting";
$strings['StartTime'] = "Start time";
$strings['Topic'] = "Topic";
$strings['TopicAndAgenda'] = "Topic and agenda";
$strings['TotalSize'] = "Total size";
$strings['Type'] = "Type";
$strings['UpcomingMeetings'] = "Upcoming meetings";
$strings['UpdateMeeting'] = "Update meeting";
$strings['UpdateRegisteredUserList'] = "Update registered user list";
$strings['Y-m-d H:i'] = "Y-m-d H:i";
$strings['Waiting'] = "waiting";
$strings['ZoomVideoconference'] = "Zoom Videoconference";
$strings['ZoomVideoconferences'] = "Zoom Videoconferences";
$strings['XRecordingOfMeetingXFromXDurationXDotX'] = "%s recording of meeting %s from %s (%s).%s";
$strings['ZoomVideoConferences'] = "Zoom Video Conferences";

@ -41,39 +41,38 @@ 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['AllRecordingsWereCopiedToCourse'] = "Tous les enregistrements ont été copiés dans le cours";
$strings['Agenda'] = "Ordre du jour";
$strings['CopyAllRecordingsToCourse'] = "Copier tous les enregistrements dans le cours";
$strings['CopyingJoinURL'] = "Copie de l'URL pour rejoindre en cours";
$strings['CopyJoinURL'] = "Copier l'URL pour rejoindre";
$strings['CopyRecordingToCourse'] = "Copier l'enregistrement dans le 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['DeleteMeeting'] = "Effacer la conférence";
$strings['DeleteRecordings'] = "Supprimer l'enregistrement";
$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['Files'] = "Fichiers";
$strings['Finished'] = "terminée";
$strings['FileWasCopiedToCourse'] = "Le fichier a été copié dans le cours";
$strings['FileWasDeleted'] = "Le fichier a été effacé";
$strings['InstantMeeting'] = "Conférence instantanée";
$strings['InstanceParticipants'] = "Participants";
$strings['InstancesAndRecordings'] = "Instances et enregistrements";
$strings['Join'] = "Rejoindre";
$strings['JoinMeeting'] = "Rejoindre la conférence";
$strings['JoinURL'] = "URL pour rejoindre";
$strings['JoinMeetingAsMyself'] = "Rejoindre la conférence en tant que moi-même";
$strings['JoinURLCopied'] = "URL pour rejoindre copiée";
$strings['JoinURLToSendToParticipants'] = "URL pour assister à la conférence (à envoyer aux participants)";
$strings['JoinURLToShare'] = "URL pour rejoindre, à partager";
$strings['LiveMeetings'] = "Conférences en cours";
$strings['LinkToFileWasCreatedInCourse'] = "A link to the file was added to the course";
$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['RecordingsWereDeleted'] = "Les enregistrements ont été supprimés";
$strings['RecordingWasCopiedToCourse'] = "L'enregistrement a été copié dans le cours";
$strings['RecurringWithFixedTime'] = "Recurrent, à heure fixe";
$strings['RecurringWithNoFixedTime'] = "Recurrent, sans heure fixe";
$strings['RegisterAllCourseUsers'] = "Inscrire tous les utilisateurs du cours";
@ -88,16 +87,15 @@ $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['StartMeeting'] = "Démarrer la conférence";
$strings['StartTime'] = "Heure de début";
$strings['Topic'] = "Objet";
$strings['TopicAndAgenda'] = "Objet et ordre du jour";
$strings['TotalSize'] = "Taille totale";
$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['Y-m-d H:i'] = "d/m/Y à H\hi";
$strings['Waiting'] = "en attente";
$strings['ZoomVideoconference'] = "Conférence vidéo Zoom";
$strings['XRecordingOfMeetingXFromXDurationXDotX'] = "Enregistrement (%s) de la conférence %s de %s (%s).%s";
$strings['ZoomVideoconferences'] = "Conférences vidéo Zoom";

@ -3,6 +3,7 @@
namespace Chamilo\PluginBundle\Zoom\API;
use DateTime;
use Exception;
use Firebase\JWT\JWT;
@ -294,7 +295,7 @@ class JWTClient
*
* @return RecordingMeeting the recordings for this meeting
*/
public function getRecordings($instanceUUID)
public function getInstanceRecordings($instanceUUID)
{
return RecordingMeeting::fromJson(
$this->send(
@ -304,6 +305,29 @@ class JWTClient
);
}
/**
* Lists All Recordings.
*
* @param DateTime $startDate
* @param DateTime $endDate
*
* @throws Exception
*
* @return RecordingMeeting[] list of all recordings
*/
public function getRecordings($startDate, $endDate)
{
return $this->getFullList(
'/users/me/recordings',
RecordingList::class,
'meetings',
[
'from' => $startDate->format('Y-m-d'),
'to' => $endDate->format('Y-m-d'),
]
);
}
/**
* Deletes a meetings recordings.
*
@ -316,6 +340,23 @@ class JWTClient
$this->send('DELETE', 'meetings/'.$this->doubleEncode($instanceUUID).'/recordings', ['action' => 'delete']);
}
/**
* Deletes a meeting instance recording file.
*
* @param int $meetingId
* @param string $fileId
*
* @throws Exception
*/
public function deleteRecordingFile($meetingId, $fileId)
{
$this->send(
'DELETE',
"/meetings/$meetingId/recordings/$fileId",
['action' => 'delete']
);
}
/**
* Retrieves information on participants from a past meeting.
*
@ -334,6 +375,19 @@ class JWTClient
);
}
/**
* Builds the recording file download URL with the access_token query parameter
* @see RecordingFile::$download_url
*
* @param $recordingFile RecordingFile
*
* @return string full URL
*/
public function getRecordingFileDownloadURL($recordingFile)
{
return $recordingFile->download_url.'?access_token='.$this->token;
}
/**
* Retrieves a full list of items using one or more API calls to the Zoom server.
*

@ -0,0 +1,36 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom\API;
use Exception;
class RecordingList
{
use Pagination;
/** @var string Start Date */
public $from;
/** @var string End Date */
public $to;
/** @var RecordingMeeting[] List of recordings */
public $meetings;
public function __construct()
{
$this->meetings = [];
}
/**
* @inheritDoc
*/
public function itemClass($propertyName)
{
if ('meetings' === $propertyName) {
return RecordingMeeting::class;
}
throw new Exception("No such array property $propertyName");
}
}

@ -51,7 +51,7 @@ class RecordingMeeting
/**
* RecordingMeeting constructor.
*/
protected function __construct()
public function __construct()
{
$this->recording_files = [];
}

@ -0,0 +1,31 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
use Exception;
class File extends API\RecordingFile
{
/** @var string */
public $formattedFileSize;
/**
* Makes a File out of a RecordingFile.
*
* @param API\RecordingFile $source
*
* @throws Exception
*
* @return static
*/
public static function fromRecordingFile($source)
{
$instance = new static();
self::recursivelyCopyObjectProperties($source, $instance);
$instance->formattedFileSize = format_file_size($instance->file_size);
return $instance;
}
}

@ -0,0 +1,71 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\Zoom;
use DateInterval;
use DateTime;
use DateTimeZone;
use Exception;
class Recording extends API\RecordingMeeting
{
/** @var File[] List of recording file. */
public $recording_files;
/** @var DateTime */
public $startDateTime;
/** @var string */
public $formattedStartTime;
/** @var DateInterval */
public $durationInterval;
/** @var string */
public $formattedDuration;
/**
* Builds a Recording from a RecordingMeeting.
*
* @param API\RecordingMeeting $recordingMeeting
*
* @throws Exception
*
* @return static
*/
public static function fromRecodingMeeting($recordingMeeting)
{
$instance = new static();
self::recursivelyCopyObjectProperties($recordingMeeting, $instance);
$newRecordingFiles = [];
foreach ($instance->recording_files as $file) {
$newRecordingFiles[] = File::fromRecordingFile($file);
}
$instance->recording_files = $newRecordingFiles;
$instance->startDateTime = new DateTime($instance->start_time);
$instance->startDateTime->setTimezone(new DateTimeZone(date_default_timezone_get()));
$instance->formattedStartTime = $instance->startDateTime->format(get_lang('Y-m-d H:i'));
$now = new DateTime();
$later = new DateTime();
$later->add(new DateInterval('PT'.$instance->duration.'M'));
$instance->durationInterval = $later->diff($now);
$instance->formattedDuration = $instance->durationInterval->format(get_lang('DurationFormat'));
return $instance;
}
/**
* {@inheritdoc}
*/
public function itemClass($propertyName)
{
if ('recording_files' === $propertyName) {
return File::class;
}
return parent::itemClass($propertyName);
}
}

@ -8,10 +8,11 @@ use Chamilo\PluginBundle\Zoom\API\MeetingInstance;
use Chamilo\PluginBundle\Zoom\API\MeetingSettings;
use Chamilo\PluginBundle\Zoom\API\ParticipantListItem;
use Chamilo\PluginBundle\Zoom\API\PastMeeting;
use Chamilo\PluginBundle\Zoom\API\RecordingMeeting;
use Chamilo\PluginBundle\Zoom\CourseMeeting;
use Chamilo\PluginBundle\Zoom\CourseMeetingInfoGet;
use Chamilo\PluginBundle\Zoom\CourseMeetingListItem;
use Chamilo\PluginBundle\Zoom\File;
use Chamilo\PluginBundle\Zoom\Recording;
use Chamilo\PluginBundle\Zoom\UserMeetingRegistrant;
use Chamilo\PluginBundle\Zoom\UserMeetingRegistrantListItem;
@ -277,17 +278,62 @@ class ZoomPlugin extends Plugin
}
/**
* @see JWTClient::getRecordings()
* Retrieves an instance's recording.
*
* @param string $instanceUUID
* @param string $instanceUUID instance UUID
*
* @throws Exception on API error
*
* @return RecordingMeeting the recordings of the meeting
* @return Recording the recording of the meeting
*/
public function getInstanceRecording($instanceUUID)
{
return Recording::fromRecodingMeeting($this->jwtClient()->getInstanceRecordings($instanceUUID));
}
/**
* Retrieves all recordings.
*
* @param DateTime $startDate start date
* @param DateTime $endDate end date
*
* @throws Exception
*
* @return Recording[] all recordings
*/
public function getRecordings($startDate, $endDate)
{
$recordings = [];
foreach ($this->jwtClient()->getRecordings($startDate, $endDate) as $recording) {
$recordings[] = Recording::fromRecodingMeeting($recording);
}
return $recordings;
}
/**
* Retrieves a meetings instances' recordings.
*
* @param CourseMeetingInfoGet $meeting
*
* @throws Exception
*
* @return Recording[] meeting instances' recordings
*/
public function getRecordings($instanceUUID)
public function getMeetingRecordings($meeting)
{
return $this->jwtClient()->getRecordings($instanceUUID);
$interval = new DateInterval('P1M');
$startDate = clone $meeting->startDateTime;
$startDate->sub($interval);
$endDate = clone $meeting->startDateTime;
$endDate->add($interval);
$recordings = [];
foreach ($this->getRecordings($startDate, $endDate) as $recording) {
if ($recording->id == $meeting->id) {
$recordings[] = $recording;
}
}
return $recordings;
}
/**
@ -393,6 +439,97 @@ class ZoomPlugin extends Plugin
$this->removeRegistrants($meetingId, $registrantsToRemove);
}
/**
* Adds to the meeting course documents a link to a meeting instance recording file.
*
* @param CourseMeetingInfoGet $meeting
* @param File $file
* @param string $name
*
* @throws Exception
*/
public function createLinkToFileInCourse($meeting, $file, $name)
{
$courseInfo = api_get_course_info_by_id($meeting->courseId);
if (empty($courseInfo)) {
throw new Exception('This meeting is not linked to a valid course');
}
$path = '/zoom_meeting_recording_file_'.$file->id.'.'.$file->file_type;
$docId = DocumentManager::addCloudLink($courseInfo, $path, $file->play_url, $name);
if (!$docId) {
throw new Exception(
DocumentManager::cloudLinkExists($courseInfo, $path, $file->play_url)
? get_lang('UrlAlreadyExists')
: get_lang('ErrorAddCloudLink')
);
}
}
/**
* Copies a recording file to a meeting's course.
*
* @param CourseMeetingInfoGet $meeting
* @param File $file
* @param string $name
*
* @throws Exception
*/
public function copyFileToCourse($meeting, $file, $name)
{
$courseInfo = api_get_course_info_by_id($meeting->courseId);
if (empty($courseInfo)) {
throw new Exception('This meeting is not linked to a valid course');
}
$tmpFile = tmpfile();
if (false === $tmpFile) {
throw new Exception('tmpfile() returned false');
}
$curl = curl_init($this->jwtClient()->getRecordingFileDownloadURL($file));
if (false === $curl) {
throw new Exception('Could not init curl: '.curl_error($curl));
}
if (!curl_setopt_array(
$curl,
[
CURLOPT_FILE => $tmpFile,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 120,
]
)) {
throw new Exception("Could not set curl options: ".curl_error($curl));
}
if (false === curl_exec($curl)) {
throw new Exception("curl_exec failed: ".curl_error($curl));
}
$newPath = handle_uploaded_document(
$courseInfo,
[
'name' => $name,
'tmp_name' => stream_get_meta_data($tmpFile)['uri'],
'size' => filesize(stream_get_meta_data($tmpFile)['uri']),
'from_file' => true,
'type' => $file->file_type,
],
'/',
api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document',
api_get_user_id(),
0,
null,
0,
'',
true,
false,
null,
$meeting->sessionId,
true
);
fclose($tmpFile);
if (false === $newPath) {
throw new Exception('could not handle uploaded document');
}
}
/**
* Deletes a meeting instance's recordings.
*
@ -400,11 +537,24 @@ class ZoomPlugin extends Plugin
*
* @throws Exception
*/
public function deleteRecordings($instanceUUID)
public function deleteInstanceRecordings($instanceUUID)
{
$this->jwtClient()->deleteRecordings($instanceUUID);
}
/**
* Deletes a meeting instance recording file.
*
* @param int $meetingId
* @param string $fileId
*
* @throws Exception
*/
public function deleteFile($meetingId, $fileId)
{
$this->jwtClient()->deleteRecordingFile($meetingId, $fileId);
}
/**
* Caches and returns the JWT client instance, initialized with plugin settings.
*

@ -101,8 +101,6 @@ if ($plugin->userIsConferenceManager()) {
if ($plugin->get('enableParticipantRegistration')
&& MeetingSettings::APPROVAL_TYPE_NO_REGISTRATION_REQUIRED != $meeting->settings->approval_type) {
$tpl->assign('enableParticipantRegistration', true);
$registerParticipantForm = new FormValidator('registerParticipantForm', 'post', $_SERVER['REQUEST_URI']);
$userIdSelect = $registerParticipantForm->addSelect('userIds', get_lang('RegisteredUsers'));
$userIdSelect->setMultiple(true);
@ -155,83 +153,86 @@ if ($plugin->userIsConferenceManager()) {
&& 'cloud' === $meeting->settings->auto_recording
// && 'finished' === $meeting->status
) {
$instances = [];
foreach ($plugin->getEndedMeetingInstances($meeting->id) as $instance) {
// $instance->instanceDetails = $plugin->getPastMeetingInstanceDetails($instance->uuid);
try {
$instance->recordings = $plugin->getRecordings($instance->uuid);
} catch (Exception $exception) {
Display::addFlash(
Display::return_message($exception->getMessage(), 'error')
);
$recordings = $plugin->getMeetingRecordings($meeting);
$fileForm = new FormValidator('fileForm', 'post', $_SERVER['REQUEST_URI']);
$fileIdSelect = $fileForm->addSelect('fileIds', get_lang('Files'));
$fileIdSelect->setMultiple(true);
foreach ($recordings as &$recording) {
// $recording->instanceDetails = $plugin->getPastMeetingInstanceDetails($instance->uuid);
$options = [];
foreach ($recording->recording_files as $file) {
$options[] = [
'text' => sprintf("%s.%s (%s)", $file->recording_type, $file->file_type, $file->formattedFileSize),
'value' => $file->id
];
}
foreach ($instance->recordings->recording_files as &$file) {
$copyToCourseForm = new FormValidator(
'copyToCourseForm'.$file->id,
'post',
$_SERVER['REQUEST_URI']
);
$copyToCourseForm->addButtonCopy(get_lang('CopyRecordingToCourse'));
if ($copyToCourseForm->validate()) {
try {
$plugin->copyRecordingToCourse($meeting, $file);
Display::addFlash(
Display::return_message(get_lang('RecordingWasCopiedToCourse'), 'confirm')
);
} catch (Exception $exception) {
Display::addFlash(
Display::return_message($exception->getMessage(), 'error')
$fileIdSelect->addOptGroup(
$options,
sprintf("%s (%s)", $recording->formattedStartTime, $recording->formattedDuration)
);
}
$actionRadio = $fileForm->addRadio(
'action',
get_lang('Action'),
[
'CreateLinkInCourse' => get_lang('CreateLinkInCourse'),
'CopyToCourse' => get_lang('CopyToCourse'),
'DeleteFile' => get_lang('DeleteFile'),
]
);
$fileForm->addButtonUpdate(get_lang('DoIt'));
if ($fileForm->validate()) {
foreach ($recordings as $recording) {
foreach ($recording->recording_files as $file) {
if (in_array($file->id, $fileIdSelect->getValue())) {
$name = sprintf(
get_lang('XRecordingOfMeetingXFromXDurationXDotX'),
$file->recording_type,
$meeting->id,
$recording->formattedStartTime,
$recording->formattedDuration,
$file->file_type
);
if ('CreateLinkInCourse' === $actionRadio->getValue()) {
try {
$plugin->createLinkToFileInCourse($meeting, $file, $name);
Display::addFlash(
Display::return_message(get_lang('LinkToFileWasCreatedInCourse'), 'success')
);
} catch (Exception $exception) {
Display::addFlash(
Display::return_message($exception->getMessage(), 'error')
);
}
} elseif ('CopyToCourse' === $actionRadio->getValue()) {
try {
$plugin->copyFileToCourse($meeting, $file, $name);
Display::addFlash(
Display::return_message(get_lang('FileWasCopiedToCourse'), 'confirm')
);
} catch (Exception $exception) {
Display::addFlash(
Display::return_message($exception->getMessage(), 'error')
);
}
} elseif ('DeleteFile' === $actionRadio->getValue()) {
try {
$plugin->deleteFile($meeting->id, $file->id);
Display::addFlash(
Display::return_message(get_lang('FileWasDeleted'), 'confirm')
);
} catch (Exception $exception) {
Display::addFlash(
Display::return_message($exception->getMessage(), 'error')
);
}
}
}
}
$file->copyToCourseForm = $copyToCourseForm->returnForm();
}
$copyAllRecordingsToCourseForm = new FormValidator(
'copyAllRecordingsToCourseForm'.$instance->uuid,
'post',
$_SERVER['REQUEST_URI']
);
$copyAllRecordingsToCourseForm->addButtonCopy(get_lang('CopyAllRecordingsToCourse'));
if ($copyAllRecordingsToCourseForm->validate()) {
try {
$plugin->copyAllRecordingsToCourse($instance->uuid);
Display::addFlash(
Display::return_message(get_lang('AllRecordingsWereCopiedToCourse'), 'confirm')
);
} catch (Exception $exception) {
Display::addFlash(
Display::return_message($exception->getMessage(), 'error')
);
}
}
$instance->copyAllRecordingsToCourseForm = $copyAllRecordingsToCourseForm->returnForm();
$deleteRecordingsForm = new FormValidator(
'deleteRecordingsForm'.$instance->uuid,
'post',
$_SERVER['REQUEST_URI']
);
$deleteRecordingsForm->addButtonSend(get_lang('DeleteRecordings'));
if ($deleteRecordingsForm->validate()) {
try {
$plugin->deleteRecordings($instance->uuid);
Display::addFlash(
Display::return_message(get_lang('RecordingsWereDeleted'), 'confirm')
);
} catch (Exception $exception) {
Display::addFlash(
Display::return_message($exception->getMessage(), 'error')
);
}
}
$instance->deleteRecordingsForm = $deleteRecordingsForm->returnForm();
// $instance->participants = $plugin->getParticipants($instance->uuid);
$instances[] = $instance;
}
$tpl->assign('instances', $instances);
$tpl->assign('recordings', $recordings);
$tpl->assign('fileForm', $fileForm->returnForm());
}
} elseif (MeetingSettings::APPROVAL_TYPE_NO_REGISTRATION_REQUIRED != $meeting->settings->approval_type) {
$userId = api_get_user_id();

@ -16,7 +16,7 @@ $logInfo = [
Event::registerLog($logInfo);
$tool_name = get_lang('ZoomVideoconference');
$tool_name = get_lang('ZoomVideoconferences');
$tpl = new Template($tool_name);
$plugin = ZoomPlugin::create();

@ -1,11 +1,15 @@
{{ search_form }}
<table class="table table-hover table-striped">
<caption>{{ 'MeetingsFound'|get_lang }}</caption>
<thead>
<tr>
<th>{{ 'StartTime'|get_lang }}</th>
<th>{{ 'Course'|get_lang }}</th>
<th>{{ 'Session'|get_lang }}</th>
<th>{{ 'Topic'|get_lang }}</th>
{% if recordings %}
<th>{{ 'Recordings'|get_lang }}</th>
{% endif %}
<th></th>
</tr>
</thead>
@ -16,6 +20,30 @@
<td>{{ meeting.course ? meeting.course.title : '-' }}</td>
<td>{{ meeting.session ? meeting.session.name : '-' }}</td>
<td>{{ meeting.topic }}</td>
{% if recordings %}
<td>
{% for recording in recordings %}
{% if recording.id == meeting.id %}
<dl>
<dt>
{{ recording.formattedStartTime }}
({{ recording.formattedDuration }})
</dt>
<dd>
<ul>
{% for file in recording.recording_files %}
<li>
{{ file.recording_type }}.{{ file.file_type }}
({{ file.formattedFileSize }})
</li>
{% endfor %}
</ul>
</dd>
</dl>
{% endif %}
{% endfor %}
</td>
{% endif %}
<td>
<a class="btn" href="meeting_from_admin.php?meetingId={{ meeting.id }}">
{{ 'Details'|get_lang }}
@ -24,4 +52,4 @@
</tr>
{% endfor %}
</tbody>
</table>
</table>

@ -1,23 +1,8 @@
<p>{{ meeting.typeName }} {{ meeting.id }} ({{ meeting.statusName }})</p>
<h2>{{ meeting.topic }}</h2>
{% if meeting.agenda %}
<blockquote>{{ meeting.agenda| nl2br }}</blockquote>
{% endif %}
{% if meeting.type == 2 or meeting.type == 8 %}
<dl class="meeting_properties">
<dt>{{ 'StartTime'|get_lang }}</dt>
<dd>{{ meeting.formattedStartTime }}</dd>
<dt>{{ 'Duration'|get_lang }}</dt>
<dd>{{ meeting.formattedDuration }}</dd>
</dl>
{% endif %}
{% if isConferenceManager and meeting.status == 'waiting' %}
<p>
<a class="btn" href="{{ meeting.start_url }}">
<a href="{{ meeting.start_url }}" target="_blank">
{{ 'StartMeeting'|get_lang }}
</a>
</p>
@ -25,8 +10,8 @@
{% if currentUserJoinURL %}
<p>
<a href="{{ currentUserJoinURL }}">
{{ 'JoinMeeting'|get_lang }}
<a href="{{ currentUserJoinURL }}" target="_blank">
{{ 'JoinMeetingAsMyself'|get_lang }}
</a>
</p>
{% endif %}
@ -34,101 +19,60 @@
{% if meeting.settings.approval_type == 2 %}
<p>
<label>
{{ 'JoinURLToShare'|get_lang }}
<input readonly value="{{ meeting.join_url }}"/>
{{ 'JoinURLToSendToParticipants'|get_lang }}
<input readonly value="{{ meeting.join_url }}">
</label>
</p>
{% endif %}
{% if instances %}
<h3>{{ 'InstancesAndRecordings'|get_lang }}</h3>
{% for instance in instances %}
<div>
<h4>{{ instance.start_time }} ({{ instance.recordings.duration }} minutes)</h4>
<a href="{{ instance.recordings.share_url }}">
{{ instance.recordings.recording_count }} recordings
{{ instance.deleteRecordingsForm }}
</a>
<table class="table">
{% for file in instance.recordings.recording_files %}
<tr>
<th>{{ file.file_type }}<th>
<td>
<a href="{{file.play_url}}" target="_blank">
Play {{file.recording_type}}
</a>
</td>
<td class="right">
<a href="{{file.download_url}}">Download {{ file.file_size }} bytes</a>
</td>
<td>
{{ file.copyToCourseForm }}
</td>
</tr>
{% endfor %}
<tr>
<th colspan="4" class="right">
{{ 'TotalSize'|get_lang }} {{ instance.recordings.total_size }} bytes
</th>
<td>
{{ instance.copyAllRecordingsToCourseForm }}
</td>
</tr>
</table>
{% if instance.participants %}
<h4>{{ 'InstanceParticipants'|get_lang }}</h4>
<ul>
{% for participant in instance.participants %}
<li>
{{ participant.name }}
</li>
{% endfor %}
</ul>
{% endif %}
</div>
{% endfor %}
{% endif %}
{% if registrants and isConferenceManager %}
{% if isConferenceManager %}
{{ editMeetingForm }}
{{ deleteMeetingForm }}
{{ registerParticipantForm }}
{{ fileForm }}
{% if registrants and meeting.settings.approval_type != 2 %}
<script>
function copyJoinURL(event, url) {
event.target.textContent = '{{ 'CopyingJoinURL'|get_lang|escape }}';
navigator.clipboard.writeText(url).then(function() {
event.target.textContent = '{{ 'JoinURLCopied'|get_lang|escape }}';
}, function() {
event.target.textContent = '{{ 'CouldNotCopyJoinURL'|get_lang|escape }}' + ' ' + url;
});
navigator.clipboard.writeText(url).then(
function() {
event.target.textContent = '{{ 'JoinURLCopied'|get_lang|escape }}';
}, function() {
event.target.textContent = '{{ 'CouldNotCopyJoinURL'|get_lang|escape }}' + ' ' + url;
}
);
}
</script>
<table class="table">
<tr>
<th>{{ 'RegisteredUsers'|get_lang }}</th>
<th>{{ 'JoinURL'|get_lang }}</th>
</tr>
<ul>
{% for registrant in registrants %}
<tr>
<td>
{{ registrant.fullName }}
</td>
<td>
<a onclick="copyJoinURL(event, '{{ registrant.join_url }}')">
{{ 'CopyJoinURL'|get_lang }}
</a>
</td>
</tr>
<li>
<a onclick="copyJoinURL(event, '{{ registrant.join_url }}')">
{{ 'CopyJoinAsURL'|get_lang }}
</a>
{{ registrant.fullName }}
</li>
{% endfor %}
</table>
</ul>
{% endif %}
{% else %}
<p>
{{ 'JoinURLToSendToParticipants'|get_lang }}
{{meeting.join_url}}
</p>
<h2>{{ meeting.topic }}</h2>
{% if meeting.agenda %}
<blockquote>{{ meeting.agenda| nl2br }}</blockquote>
{% endif %}
{% if isConferenceManager %}
{{ editMeetingForm }}
{{ deleteMeetingForm }}
{% if enableParticipantRegistration %}
{{ registerParticipantForm }}
{% if meeting.type == 2 or meeting.type == 8 %}
<dl class="meeting_properties">
<dt>{{ 'StartTime'|get_lang }}</dt>
<dd>{{ meeting.formattedStartTime }}</dd>
<dt>{{ 'Duration'|get_lang }}</dt>
<dd>{{ meeting.formattedDuration }}</dd>
</dl>
{% endif %}
{% endif %}

Loading…
Cancel
Save