'boolean',
'apiKey' => 'text',
'apiSecret' => 'text',
'verificationToken' => 'text',
self::SETTING_ACCOUNT_ID => 'text',
self::SETTING_CLIENT_ID => 'text',
self::SETTING_CLIENT_SECRET => 'text',
self::SETTING_SECRET_TOKEN => 'text',
'enableParticipantRegistration' => 'boolean',
'enablePresenter' => 'boolean',
'enableCloudRecording' => [
'type' => 'select',
'options' => [
self::RECORDING_TYPE_CLOUD => 'Cloud',
self::RECORDING_TYPE_LOCAL => 'Local',
self::RECORDING_TYPE_NONE => get_lang('None'),
],
],
'enableGlobalConference' => 'boolean',
'globalConferenceAllowRoles' => [
'type' => 'select',
'options' => [
PLATFORM_ADMIN => get_lang('Administrator'),
COURSEMANAGER => get_lang('Teacher'),
STUDENT => get_lang('Student'),
STUDENT_BOSS => get_lang('StudentBoss'),
SESSIONADMIN => get_lang('SessionsAdmin'),
],
'attributes' => ['multiple' => 'multiple'],
],
'accountSelector' => 'text',
]
);
$this->isAdminPlugin = true;
$accountId = $this->get(self::SETTING_ACCOUNT_ID);
$clientId = $this->get(self::SETTING_CLIENT_ID);
$clientSecret = $this->get(self::SETTING_CLIENT_SECRET);
if (!empty($accountId) && !empty($clientId) && !empty($clientSecret)) {
$this->jwtClient = new ServerToServerOAuthClient($accountId, $clientId, $clientSecret);
} else {
$this->jwtClient = new JWTClient($this->get('apiKey'), $this->get('apiSecret'));
}
}
/**
* Caches and returns an instance of this class.
*
* @return ZoomPlugin the instance to use
*/
public static function create(): ZoomPlugin
{
static $instance = null;
return $instance ? $instance : $instance = new self();
}
/**
* @return bool
*/
public static function currentUserCanJoinGlobalMeeting()
{
$user = api_get_user_entity(api_get_user_id());
if (null === $user) {
return false;
}
//return 'true' === api_get_plugin_setting('zoom', 'enableGlobalConference') && api_user_is_login();
return
'true' === api_get_plugin_setting('zoom', 'enableGlobalConference')
&& in_array(
(api_is_platform_admin() ? PLATFORM_ADMIN : $user->getStatus()),
(array) api_get_plugin_setting('zoom', 'globalConferenceAllowRoles')
);
}
/**
* @return array
*/
public function getProfileBlockItems()
{
$elements = $this->meetingsToWhichCurrentUserIsRegisteredComingSoon();
$addMeetingLink = false;
if (self::currentUserCanJoinGlobalMeeting()) {
$addMeetingLink = true;
}
if ($addMeetingLink) {
$elements[$this->get_lang('Meetings')] = api_get_path(WEB_PLUGIN_PATH).'zoom/meetings.php';
}
$items = [];
foreach ($elements as $title => $link) {
$items[] = [
'class' => 'video-conference',
'icon' => Display::return_icon(
'bbb.png',
get_lang('VideoConference')
),
'link' => $link,
'title' => $title,
];
}
return $items;
}
/**
* @return array [ $title => $link ]
*/
public function meetingsToWhichCurrentUserIsRegisteredComingSoon()
{
$linkTemplate = api_get_path(WEB_PLUGIN_PATH).'zoom/join_meeting.php?meetingId=%s';
$user = api_get_user_entity(api_get_user_id());
$meetings = self::getRegistrantRepository()->meetingsComingSoonRegistrationsForUser($user);
$items = [];
foreach ($meetings as $registrant) {
$meeting = $registrant->getMeeting();
$items[sprintf(
$this->get_lang('DateMeetingTitle'),
$meeting->formattedStartTime,
$meeting->getTopic()
)] = sprintf($linkTemplate, $meeting->getMeetingId());
}
return $items;
}
/**
* @return RegistrantRepository|EntityRepository
*/
public static function getRegistrantRepository()
{
return Database::getManager()->getRepository(Registrant::class);
}
/**
* Creates this plugin's related tables in the internal database.
* Installs course fields in all courses.
*
* @throws ToolsException
*/
public function install()
{
$schemaManager = Database::getManager()->getConnection()->getSchemaManager();
$tablesExists = $schemaManager->tablesExist(
[
'plugin_zoom_meeting',
'plugin_zoom_meeting_activity',
'plugin_zoom_recording',
'plugin_zoom_registrant',
'plugin_zoom_signature',
]
);
if ($tablesExists) {
return;
}
$em = Database::getManager();
(new SchemaTool($em))->createSchema(
[
$em->getClassMetadata(Meeting::class),
$em->getClassMetadata(Webinar::class),
$em->getClassMetadata(MeetingActivity::class),
$em->getClassMetadata(Recording::class),
$em->getClassMetadata(Registrant::class),
$em->getClassMetadata(Signature::class),
]
);
// Copy icons into the main/img/icons folder
$iconName = 'zoom_meet';
$iconsList = [
'64/'.$iconName.'.png',
'64/'.$iconName.'_na.png',
'32/'.$iconName.'.png',
'32/'.$iconName.'_na.png',
'22/'.$iconName.'.png',
'22/'.$iconName.'_na.png',
];
$sourceDir = api_get_path(SYS_PLUGIN_PATH).'zoom/resources/img/';
$destinationDir = api_get_path(SYS_CODE_PATH).'img/icons/';
foreach ($iconsList as $icon) {
$src = $sourceDir.$icon;
$dest = $destinationDir.$icon;
copy($src, $dest);
}
$this->install_course_fields_in_all_courses(true, 'zoom_meet.png');
}
/**
* Drops this plugins' related tables from the internal database.
* Uninstalls course fields in all courses().
*/
public function uninstall()
{
$em = Database::getManager();
(new SchemaTool($em))->dropSchema(
[
$em->getClassMetadata(Meeting::class),
$em->getClassMetadata(Webinar::class),
$em->getClassMetadata(MeetingActivity::class),
$em->getClassMetadata(Recording::class),
$em->getClassMetadata(Registrant::class),
$em->getClassMetadata(Signature::class),
]
);
$this->uninstall_course_fields_in_all_courses();
// Remove icons from the main/img/icons folder
$iconName = 'zoom_meet';
$iconsList = [
'64/'.$iconName.'.png',
'64/'.$iconName.'_na.png',
'32/'.$iconName.'.png',
'32/'.$iconName.'_na.png',
'22/'.$iconName.'.png',
'22/'.$iconName.'_na.png',
];
$destinationDir = api_get_path(SYS_CODE_PATH).'img/icons/';
foreach ($iconsList as $icon) {
$dest = $destinationDir.$icon;
if (is_file($dest)) {
@unlink($dest);
}
}
}
/**
* Generates the search form to include in the meeting list administration page.
* The form has DatePickers 'start' and 'end' and Checkbox 'reloadRecordingLists'.
*
* @return FormValidator the form
*/
public function getAdminSearchForm()
{
$form = new FormValidator('search');
$form->addHeader($this->get_lang('SearchMeeting'));
$form->addDatePicker('start', get_lang('StartDate'));
$form->addDatePicker('end', get_lang('EndDate'));
$form->addButtonSearch(get_lang('Search'));
$oneMonth = new DateInterval('P1M');
if ($form->validate()) {
try {
$start = new DateTime($form->getSubmitValue('start'));
} catch (Exception $exception) {
$start = new DateTime();
$start->sub($oneMonth);
}
try {
$end = new DateTime($form->getSubmitValue('end'));
} catch (Exception $exception) {
$end = new DateTime();
$end->add($oneMonth);
}
} else {
$start = new DateTime();
$start->sub($oneMonth);
$end = new DateTime();
$end->add($oneMonth);
}
try {
$form->setDefaults(
[
'start' => $start->format('Y-m-d'),
'end' => $end->format('Y-m-d'),
]
);
} catch (Exception $exception) {
error_log(join(':', [__FILE__, __LINE__, $exception]));
}
return $form;
}
/**
* @throws Exception
*/
public function getEditConferenceForm(Meeting $conference): FormValidator
{
$isWebinar = $conference instanceof Webinar;
$requiresDateAndDuration = $conference->requiresDateAndDuration();
/** @var BaseMeetingTrait $schema */
$schema = $isWebinar ? $conference->getWebinarSchema() : $conference->getMeetingInfoGet();
$form = new FormValidator('edit', 'post', $_SERVER['REQUEST_URI']);
$form->addHeader(
$isWebinar ? $this->get_lang('UpdateWebinar') : $this->get_lang('UpdateMeeting')
);
$form->addLabel(get_lang('Type'), $conference->typeName);
if ($conference->getAccountEmail()) {
$form->addLabel(
$this->get_lang('AccountEmail'),
$conference->getAccountEmail()
);
}
$form->addText('topic', $this->get_lang('Topic'));
if ($requiresDateAndDuration) {
$startTimeDatePicker = $form->addDateTimePicker('startTime', get_lang('StartTime'));
$durationNumeric = $form->addNumeric('duration', $this->get_lang('DurationInMinutes'));
$form->setRequired($startTimeDatePicker);
$form->setRequired($durationNumeric);
}
$form->addTextarea('agenda', get_lang('Agenda'), ['maxlength' => 2000]);
$form->addCheckBox('sign_attendance', $this->get_lang('SignAttendance'), get_lang('Yes'));
$form->addTextarea('reason_to_sign', $this->get_lang('ReasonToSign'), ['rows' => 5]);
$form->addButtonUpdate(get_lang('Update'));
if ($form->validate()) {
$formValues = $form->exportValues();
$em = Database::getManager();
if ($requiresDateAndDuration) {
$schema->start_time = (new DateTime($formValues['startTime']))->format(DATE_ATOM);
$schema->timezone = date_default_timezone_get();
$schema->duration = (int) $formValues['duration'];
}
$schema->topic = $formValues['topic'];
$schema->agenda = $formValues['agenda'];
$conference
->setSignAttendance(isset($formValues['sign_attendance']))
->setReasonToSignAttendance($formValues['reason_to_sign']);
try {
$schema->update();
if ($isWebinar) {
$conference->setWebinarSchema($schema);
} else {
$conference->setMeetingInfoGet($schema);
}
$em->persist($conference);
$em->flush();
Display::addFlash(
Display::return_message(
$isWebinar ? $this->get_lang('WebinarUpdated') : $this->get_lang('MeetingUpdated'),
'confirm'
)
);
} catch (Exception $exception) {
Display::addFlash(
Display::return_message($exception->getMessage(), 'error')
);
}
}
$defaults = [
'topic' => $schema->topic,
'agenda' => $schema->agenda,
];
if ($requiresDateAndDuration) {
$defaults['startTime'] = $conference->startDateTime->format('Y-m-d H:i');
$defaults['duration'] = $schema->duration;
}
$defaults['sign_attendance'] = $conference->isSignAttendance();
$defaults['reason_to_sign'] = $conference->getReasonToSignAttendance();
$form->setDefaults($defaults);
return $form;
}
/**
* Generates a meeting delete form and deletes the meeting on validation.
*
* @param Meeting $meeting
* @param string $returnURL where to redirect to on successful deletion
*
* @throws Exception
*
* @return FormValidator
*/
public function getDeleteMeetingForm($meeting, $returnURL)
{
$id = $meeting->getMeetingId();
$form = new FormValidator('delete', 'post', api_get_self().'?meetingId='.$id);
$form->addButtonDelete($this->get_lang('DeleteMeeting'));
if ($form->validate()) {
$this->deleteMeeting($meeting, $returnURL);
}
return $form;
}
public function getDeleteWebinarForm(Webinar $webinar, string $returnURL): FormValidator
{
$id = $webinar->getMeetingId();
$form = new FormValidator('delete', 'post', api_get_self()."?meetingId=$id");
$form->addButtonDelete($this->get_lang('DeleteWebinar'));
if ($form->validate()) {
$this->deleteWebinar($webinar, $returnURL);
}
return $form;
}
/**
* @param Meeting $meeting
* @param string $returnURL
*/
public function deleteMeeting($meeting, $returnURL): bool
{
if (null === $meeting) {
return false;
}
// No need to delete a instant meeting.
if (\Chamilo\PluginBundle\Zoom\API\Meeting::TYPE_INSTANT == $meeting->getMeetingInfoGet()->type) {
return false;
}
try {
$meeting->getMeetingInfoGet()->delete();
} catch (Exception $exception) {
$this->handleException($exception);
}
$em = Database::getManager();
$em->remove($meeting);
$em->flush();
Display::addFlash(
Display::return_message($this->get_lang('MeetingDeleted'), 'confirm')
);
api_location($returnURL);
return true;
}
public function deleteWebinar(Webinar $webinar, string $returnURL)
{
try {
$webinar->getWebinarSchema()->delete();
} catch (Exception $exception) {
$this->handleException($exception);
}
$em = Database::getManager();
$em->remove($webinar);
$em->flush();
Display::addFlash(
Display::return_message($this->get_lang('WebinarDeleted'), 'success')
);
api_location($returnURL);
}
/**
* @param Exception $exception
*/
public function handleException($exception)
{
if ($exception instanceof Exception) {
$error = json_decode($exception->getMessage());
$message = $exception->getMessage();
if ($error->message) {
$message = $error->message;
}
Display::addFlash(
Display::return_message($message, 'error')
);
}
}
/**
* Generates a registrant list update form listing course and session users.
* Updates the list on validation.
*
* @param Meeting $meeting
*
* @throws Exception
*
* @return FormValidator
*/
public function getRegisterParticipantForm($meeting)
{
$form = new FormValidator('register', 'post', $_SERVER['REQUEST_URI']);
$userIdSelect = $form->addSelect('userIds', $this->get_lang('RegisteredUsers'));
$userIdSelect->setMultiple(true);
$form->addButtonSend($this->get_lang('UpdateRegisteredUserList'));
$selfRegistrationUrl = api_get_path(WEB_PLUGIN_PATH)
.'zoom/subscription.php?meetingId='.$meeting->getMeetingId();
$form->addHtml(
'
'
);
$users = $meeting->getRegistrableUsers();
foreach ($users as $user) {
$userIdSelect->addOption(
api_get_person_name($user->getFirstname(), $user->getLastname()),
$user->getId()
);
}
if ($form->validate()) {
$selectedUserIds = $form->getSubmitValue('userIds');
$selectedUsers = [];
if (!empty($selectedUserIds)) {
foreach ($users as $user) {
if (in_array($user->getId(), $selectedUserIds)) {
$selectedUsers[] = $user;
}
}
}
try {
$this->updateRegistrantList($meeting, $selectedUsers);
Display::addFlash(
Display::return_message($this->get_lang('RegisteredUserListWasUpdated'), 'confirm')
);
} catch (Exception $exception) {
Display::addFlash(
Display::return_message($exception->getMessage(), 'error')
);
}
}
$registeredUserIds = [];
foreach ($meeting->getRegistrants() as $registrant) {
$registeredUserIds[] = $registrant->getUser()->getId();
}
$userIdSelect->setSelected($registeredUserIds);
return $form;
}
public function getRegisterPresenterForm(Meeting $meeting): FormValidator
{
$form = new FormValidator('register_presenter', 'post', $_SERVER['REQUEST_URI']);
$presenterIdSelect = $form->addSelect('presenterIds', $this->get_lang('RegisteredPresenters'));
$presenterIdSelect->setMultiple(true);
$form->addButtonSend($this->get_lang('UpdateRegisteredUserList'));
$users = $meeting->getRegistrableUsers();
foreach ($users as $user) {
$presenterIdSelect->addOption(
api_get_person_name($user->getFirstname(), $user->getLastname()),
$user->getId()
);
}
if ($form->validate()) {
$selectedPresenterIds = $form->getSubmitValue('presenterIds') ?: [];
$selectedPresenters = [];
foreach ($users as $user) {
if (in_array($user->getId(), $selectedPresenterIds)) {
$selectedPresenters[] = $user;
}
}
try {
$this->updatePresenterList($meeting, $selectedPresenters);
Display::addFlash(
Display::return_message($this->get_lang('RegisteredUserListWasUpdated'), 'confirm')
);
} catch (Exception $exception) {
Display::addFlash(
Display::return_message($exception->getMessage(), 'error')
);
}
}
$registeredPresenterIds = [];
foreach ($meeting->getPresenters() as $registrant) {
if ($registrant instanceof Presenter) {
$registeredPresenterIds[] = $registrant->getUser()->getId();
}
}
$presenterIdSelect->setSelected($registeredPresenterIds);
return $form;
}
/**
* Generates a meeting recording files management form.
* Takes action on validation.
*
* @param Meeting $meeting
*
* @throws Exception
*
* @return FormValidator
*/
public function getFileForm($meeting, $returnURL)
{
$form = new FormValidator('fileForm', 'post', $_SERVER['REQUEST_URI']);
if (!$meeting->getRecordings()->isEmpty()) {
$fileIdSelect = $form->addSelect('fileIds', get_lang('Files'));
$fileIdSelect->setMultiple(true);
$recordingList = $meeting->getRecordings();
foreach ($recordingList as &$recording) {
// $recording->instanceDetails = $plugin->getPastMeetingInstanceDetails($instance->uuid);
$options = [];
$recordings = $recording->getRecordingMeeting()->recording_files;
foreach ($recordings as $file) {
$options[] = [
'text' => sprintf(
'%s.%s (%s)',
$file->recording_type,
$file->file_type,
$file->file_size
),
'value' => $file->id,
];
}
$fileIdSelect->addOptGroup(
$options,
sprintf("%s (%s)", $recording->formattedStartTime, $recording->formattedDuration)
);
}
$actions = [];
if ($meeting->isCourseMeeting()) {
$actions['CreateLinkInCourse'] = $this->get_lang('CreateLinkInCourse');
$actions['CopyToCourse'] = $this->get_lang('CopyToCourse');
}
$actions['DeleteFile'] = $this->get_lang('DeleteFile');
$form->addRadio(
'action',
get_lang('Action'),
$actions
);
$form->addButtonUpdate($this->get_lang('DoIt'));
if ($form->validate()) {
$action = $form->getSubmitValue('action');
$idList = $form->getSubmitValue('fileIds');
foreach ($recordingList as $recording) {
$recordings = $recording->getRecordingMeeting()->recording_files;
foreach ($recordings as $file) {
if (in_array($file->id, $idList)) {
$name = sprintf(
$this->get_lang('XRecordingOfMeetingXFromXDurationXDotX'),
$file->recording_type,
$meeting->getId(),
$recording->formattedStartTime,
$recording->formattedDuration,
$file->file_type
);
if ('CreateLinkInCourse' === $action && $meeting->isCourseMeeting()) {
try {
$this->createLinkToFileInCourse($meeting, $file, $name);
Display::addFlash(
Display::return_message(
$this->get_lang('LinkToFileWasCreatedInCourse'),
'success'
)
);
} catch (Exception $exception) {
Display::addFlash(
Display::return_message($exception->getMessage(), 'error')
);
}
} elseif ('CopyToCourse' === $action && $meeting->isCourseMeeting()) {
try {
$this->copyFileToCourse($meeting, $file, $name);
Display::addFlash(
Display::return_message($this->get_lang('FileWasCopiedToCourse'), 'confirm')
);
} catch (Exception $exception) {
Display::addFlash(
Display::return_message($exception->getMessage(), 'error')
);
}
} elseif ('DeleteFile' === $action) {
try {
$name = $file->recording_type;
$file->delete();
Display::addFlash(
Display::return_message($this->get_lang('FileWasDeleted').': '.$name, 'confirm')
);
} catch (Exception $exception) {
Display::addFlash(
Display::return_message($exception->getMessage(), 'error')
);
}
}
}
}
}
api_location($returnURL);
}
}
return $form;
}
/**
* Adds to the meeting course documents a link to a meeting instance recording file.
*
* @param Meeting $meeting
* @param RecordingFile $file
* @param string $name
*
* @throws Exception
*/
public function createLinkToFileInCourse($meeting, $file, $name)
{
$course = $meeting->getCourse();
if (null === $course) {
throw new Exception('This meeting is not linked to a course');
}
$courseInfo = api_get_course_info_by_id($course->getId());
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(get_lang(DocumentManager::cloudLinkExists($courseInfo, $path, $file->play_url) ? 'UrlAlreadyExists' : 'ErrorAddCloudLink'));
}
}
/**
* Copies a recording file to a meeting's course.
*
* @param Meeting $meeting
* @param RecordingFile $file
* @param string $name
*
* @throws Exception
*/
public function copyFileToCourse($meeting, $file, $name)
{
$course = $meeting->getCourse();
if (null === $course) {
throw new Exception('This meeting is not linked to a course');
}
$courseInfo = api_get_course_info_by_id($course->getId());
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($file->getFullDownloadURL($this->jwtClient->token));
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));
}
$sessionId = 0;
$session = $meeting->getSession();
if (null !== $session) {
$sessionId = $session->getId();
}
$groupId = 0;
$group = $meeting->getGroup();
if (null !== $group) {
$groupId = $group->getIid();
}
$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,
'move_file' => true,
'type' => $file->file_type,
],
api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document',
'/',
api_get_user_id(),
$groupId,
null,
0,
'overwrite',
true,
false,
null,
$sessionId,
true
);
fclose($tmpFile);
if (false === $newPath) {
throw new Exception('Could not handle uploaded document');
}
}
/**
* Generates a form to fast and easily create and start an instant meeting.
* On validation, create it then redirect to it and exit.
*
* @return FormValidator
*/
public function getCreateInstantMeetingForm(
User $user,
Course $course,
CGroupInfo $group = null,
Session $session = null
) {
$extraUrl = '';
if (!empty($course)) {
$extraUrl = api_get_cidreq();
}
$form = new FormValidator('createInstantMeetingForm', 'post', api_get_self().'?'.$extraUrl, '_blank');
$form->addButton('startButton', $this->get_lang('StartInstantMeeting'), 'video-camera', 'primary');
if ($form->validate()) {
try {
$this->startInstantMeeting($this->get_lang('InstantMeeting'), $user, $course, $group, $session);
} catch (Exception $exception) {
Display::addFlash(
Display::return_message($exception->getMessage(), 'error')
);
}
}
return $form;
}
/**
* Generates a form to schedule a meeting.
* On validation, creates it and redirects to its page.
*
* @throws Exception
*
* @return FormValidator
*/
public function getScheduleMeetingForm(User $user, Course $course = null, CGroupInfo $group = null, Session $session = null)
{
$extraUrl = '';
if (!empty($course)) {
$extraUrl = api_get_cidreq();
}
$form = new FormValidator('scheduleMeetingForm', 'post', api_get_self().'?'.$extraUrl);
$form->addHeader($this->get_lang('ScheduleAMeeting'));
$form->addSelect(
'conference_type',
$this->get_lang('ConferenceType'),
[
'meeting' => $this->get_lang('Meeting'),
'webinar' => $this->get_lang('Webinar'),
]
);
$form->addRule('conference_type', get_lang('ThisFieldIsRequired'), 'required');
$startTimeDatePicker = $form->addDateTimePicker('startTime', get_lang('StartTime'));
$form->setRequired($startTimeDatePicker);
$form->addText('topic', $this->get_lang('Topic'), true);
$form->addTextarea('agenda', get_lang('Agenda'), ['maxlength' => 2000]);
$durationNumeric = $form->addNumeric('duration', $this->get_lang('DurationInMinutes'));
$form->setRequired($durationNumeric);
if (null === $course && 'true' === $this->get('enableGlobalConference')) {
$options = [];
$options['everyone'] = $this->get_lang('ForEveryone');
$options['registered_users'] = $this->get_lang('SomeUsers');
if (!empty($options)) {
if (1 === count($options)) {
$form->addHidden('type', key($options));
} else {
$form->addSelect('type', $this->get_lang('AudienceType'), $options);
}
}
} else {
// To course
$form->addHidden('type', 'course');
}
/*
// $passwordText = $form->addText('password', get_lang('Password'), false, ['maxlength' => '10']);
if (null !== $course) {
$registrationOptions = [
'RegisterAllCourseUsers' => $this->get_lang('RegisterAllCourseUsers'),
];
$groups = GroupManager::get_groups();
if (!empty($groups)) {
$registrationOptions['RegisterTheseGroupMembers'] = get_lang('RegisterTheseGroupMembers');
}
$registrationOptions['RegisterNoUser'] = $this->get_lang('RegisterNoUser');
$userRegistrationRadio = $form->addRadio(
'userRegistration',
$this->get_lang('UserRegistration'),
$registrationOptions
);
$groupOptions = [];
foreach ($groups as $group) {
$groupOptions[$group['id']] = $group['name'];
}
$groupIdsSelect = $form->addSelect(
'groupIds',
$this->get_lang('RegisterTheseGroupMembers'),
$groupOptions
);
$groupIdsSelect->setMultiple(true);
if (!empty($groups)) {
$jsCode = sprintf(
"getElementById('%s').parentNode.parentNode.parentNode.style.display = getElementById('%s').checked ? 'block' : 'none'",
$groupIdsSelect->getAttribute('id'),
$userRegistrationRadio->getelements()[1]->getAttribute('id')
);
$form->setAttribute('onchange', $jsCode);
}
}*/
$form->addCheckBox('sign_attendance', $this->get_lang('SignAttendance'), get_lang('Yes'));
$form->addTextarea('reason_to_sign', $this->get_lang('ReasonToSign'), ['rows' => 5]);
$accountEmails = $this->getAccountEmails();
if (!empty($accountEmails)) {
$form->addSelect('account_email', $this->get_lang('AccountEmail'), $accountEmails);
}
$form->addButtonCreate(get_lang('Save'));
if ($form->validate()) {
$formValues = $form->exportValues();
$conferenceType = $formValues['conference_type'];
$password = substr(uniqid('z', true), 0, 10);
switch ($formValues['type']) {
case 'everyone':
$user = null;
$group = null;
$course = null;
$session = null;
break;
case 'registered_users':
//$user = null;
$course = null;
$session = null;
break;
case 'course':
$user = null;
//$course = null;
//$session = null;
break;
}
$accountEmail = $formValues['account_email'] ?? null;
$accountEmail = $accountEmail && in_array($accountEmail, $accountEmails) ? $accountEmail : null;
try {
$startTime = new DateTime($formValues['startTime']);
if ('meeting' === $conferenceType) {
$newMeeting = $this->createScheduleMeeting(
$user,
$course,
$group,
$session,
$startTime,
$formValues['duration'],
$formValues['topic'],
$formValues['agenda'],
$password,
isset($formValues['sign_attendance']),
$formValues['reason_to_sign'],
$accountEmail
);
Display::addFlash(
Display::return_message($this->get_lang('NewMeetingCreated'))
);
} elseif ('webinar' === $conferenceType) {
$newMeeting = $this->createScheduleWebinar(
$user,
$course,
$group,
$session,
$startTime,
$formValues['duration'],
$formValues['topic'],
$formValues['agenda'],
$password,
isset($formValues['sign_attendance']),
$formValues['reason_to_sign'],
$accountEmail
);
Display::addFlash(
Display::return_message($this->get_lang('NewWebinarCreated'))
);
} else {
throw new Exception('Invalid conference type');
}
if ($newMeeting->isCourseMeeting()) {
if ('RegisterAllCourseUsers' === $form->getSubmitValue('userRegistration')) {
$this->registerAllCourseUsers($newMeeting);
Display::addFlash(
Display::return_message($this->get_lang('AllCourseUsersWereRegistered'))
);
} elseif ('RegisterTheseGroupMembers' === $form->getSubmitValue('userRegistration')) {
$userIds = [];
foreach ($form->getSubmitValue('groupIds') as $groupId) {
$userIds = array_unique(array_merge($userIds, GroupManager::get_users($groupId)));
}
$users = Database::getManager()->getRepository('ChamiloUserBundle:User')->findBy(
['id' => $userIds]
);
$this->registerUsers($newMeeting, $users);
Display::addFlash(
Display::return_message($this->get_lang('GroupUsersWereRegistered'))
);
}
}
api_location('meeting.php?meetingId='.$newMeeting->getMeetingId().'&'.$extraUrl);
} catch (Exception $exception) {
Display::addFlash(
Display::return_message($exception->getMessage(), 'error')
);
}
} else {
$form->setDefaults(
[
'duration' => 60,
'userRegistration' => 'RegisterAllCourseUsers',
]
);
}
return $form;
}
/**
* Return the current global meeting (create it if needed).
*
* @throws Exception
*
* @return string
*/
public function getGlobalMeeting()
{
foreach ($this->getMeetingRepository()->unfinishedGlobalMeetings() as $meeting) {
return $meeting;
}
return $this->createGlobalMeeting();
}
/**
* @return MeetingRepository|EntityRepository
*/
public static function getMeetingRepository()
{
return Database::getManager()->getRepository(Meeting::class);
}
/**
* Returns the URL to enter (start or join) a meeting or null if not possible to enter the meeting,
* The returned URL depends on the meeting current status (waiting, started or finished) and the current user.
*
* @throws OptimisticLockException
* @throws Exception
*
* @return string|null
*/
public function getStartOrJoinMeetingURL(Meeting $meeting)
{
if ($meeting instanceof Webinar) {
$status = 'started';
} else {
$status = $meeting->getMeetingInfoGet()->status;
}
$userId = api_get_user_id();
$currentUser = api_get_user_entity($userId);
$isGlobal = 'true' === $this->get('enableGlobalConference') && $meeting->isGlobalMeeting();
switch ($status) {
case 'ended':
if ($this->userIsConferenceManager($meeting)) {
return $meeting->getMeetingInfoGet()->start_url;
}
break;
case 'waiting':
// Zoom does not allow for a new meeting to be started on first participant join.
// It requires the host to start the meeting first.
// Therefore for global meetings we must make the first participant the host
// that is use start_url rather than join_url.
// the participant will not be registered and will appear as the Zoom user account owner.
// For course and user meetings, only the host can start the meeting.
if ($this->userIsConferenceManager($meeting)) {
return $meeting->getMeetingInfoGet()->start_url;
}
break;
case 'started':
// User per conference.
if ($currentUser === $meeting->getUser()) {
return $meeting instanceof Webinar
? $meeting->getWebinarSchema()->start_url
: $meeting->getMeetingInfoGet()->join_url;
}
// The participant is not registered, he can join only the global meeting (automatic registration).
if ($isGlobal) {
return $this->registerUser($meeting, $currentUser)->getCreatedRegistration()->join_url;
}
if ($meeting->isCourseMeeting()) {
if ($this->userIsCourseConferenceManager()) {
return $meeting instanceof Webinar
? $meeting->getWebinarSchema()->start_url
: $meeting->getMeetingInfoGet()->start_url;
}
$sessionId = api_get_session_id();
$courseCode = api_get_course_id();
if (empty($sessionId)) {
$isSubscribed = CourseManager::is_user_subscribed_in_course(
$userId,
$courseCode,
false
);
} else {
$isSubscribed = CourseManager::is_user_subscribed_in_course(
$userId,
$courseCode,
true,
$sessionId
);
}
if ($isSubscribed) {
if ($meeting->isCourseGroupMeeting()) {
$groupInfo = GroupManager::get_group_properties($meeting->getGroup()->getIid(), true);
$isInGroup = GroupManager::is_user_in_group($userId, $groupInfo);
if (false === $isInGroup) {
throw new Exception($this->get_lang('YouAreNotRegisteredToThisMeeting'));
}
}
if (!$meeting instanceof Webinar
&& \Chamilo\PluginBundle\Zoom\API\Meeting::TYPE_INSTANT == $meeting->getMeetingInfoGet()->type
) {
return $meeting->getMeetingInfoGet()->join_url;
}
return $this->registerUser($meeting, $currentUser)->getCreatedRegistration()->join_url;
}
throw new Exception($this->get_lang('YouAreNotRegisteredToThisMeeting'));
}
//if ('true' === $this->get('enableParticipantRegistration')) {
//if ('true' === $this->get('enableParticipantRegistration') && $meeting->requiresRegistration()) {
// the participant must be registered
$registrant = $meeting->getRegistrantByUser($currentUser);
if (null == $registrant) {
throw new Exception($this->get_lang('YouAreNotRegisteredToThisMeeting'));
}
// the participant is registered
return $registrant->getCreatedRegistration()->join_url;
//}
break;
}
return null;
}
/**
* @param Meeting $meeting
*
* @return bool whether the logged-in user can manage conferences in this context, that is either
* the current course or session coach, the platform admin or the current course admin
*/
public function userIsConferenceManager($meeting)
{
if (null === $meeting) {
return false;
}
if (api_is_coach() || api_is_platform_admin()) {
return true;
}
if ($meeting->isCourseMeeting() && api_get_course_id() && api_is_course_admin()) {
return true;
}
$currentUser = api_get_user_entity(api_get_user_id());
if ('true' === $this->get('enableParticipantRegistration')
&& 'true' === $this->get('enablePresenter')
&& $currentUser
&& $meeting->hasUserAsPresenter($currentUser)
) {
return true;
}
return $meeting->isUserMeeting() && $meeting->getUser()->getId() == api_get_user_id();
}
/**
* @return bool whether the logged-in user can manage conferences in this context, that is either
* the current course or session coach, the platform admin or the current course admin
*/
public function userIsCourseConferenceManager()
{
if (api_is_coach() || api_is_platform_admin()) {
return true;
}
if (api_get_course_id() && api_is_course_admin()) {
return true;
}
return false;
}
/**
* Update local recording list from remote Zoom server's version.
* Kept to implement a future administration button ("import existing data from zoom server").
*
* @param DateTime $startDate
* @param DateTime $endDate
*
* @throws OptimisticLockException
* @throws Exception
*/
public function reloadPeriodRecordings($startDate, $endDate)
{
$em = Database::getManager();
$recordingRepo = $this->getRecordingRepository();
$meetingRepo = $this->getMeetingRepository();
$recordings = RecordingList::loadPeriodRecordings($startDate, $endDate);
foreach ($recordings as $recordingMeeting) {
$recordingEntity = $recordingRepo->findOneBy(['uuid' => $recordingMeeting->uuid]);
if (null === $recordingEntity) {
$recordingEntity = new Recording();
$meeting = $meetingRepo->findOneBy(['meetingId' => $recordingMeeting->id]);
if (null === $meeting) {
try {
$meetingInfoGet = MeetingInfoGet::fromId($recordingMeeting->id);
} catch (Exception $exception) {
$meetingInfoGet = null; // deleted meeting with recordings
}
if (null !== $meetingInfoGet) {
$meeting = $this->createMeetingFromMeeting(
(new Meeting())->setMeetingInfoGet($meetingInfoGet)
);
$em->persist($meeting);
}
}
if (null !== $meeting) {
$recordingEntity->setMeeting($meeting);
}
}
$recordingEntity->setRecordingMeeting($recordingMeeting);
$em->persist($recordingEntity);
}
$em->flush();
}
/**
* @return RecordingRepository|EntityRepository
*/
public static function getRecordingRepository()
{
return Database::getManager()->getRepository(Recording::class);
}
public function getToolbar(string $returnUrl = ''): string
{
$isPlatformOrSessionAdmin = api_is_platform_admin(true);
$isSessionAdmin = api_is_session_admin();
if (!$isPlatformOrSessionAdmin) {
return '';
}
$actionsLeft = '';
$back = '';
$courseId = api_get_course_id();
if (empty($courseId)) {
$actionsLeft .=
Display::url(
Display::return_icon('bbb.png', $this->get_lang('Meetings'), null, ICON_SIZE_MEDIUM),
api_get_path(WEB_PLUGIN_PATH).'zoom/meetings.php'
);
} else {
$actionsLeft .=
Display::url(
Display::return_icon('bbb.png', $this->get_lang('Meetings'), null, ICON_SIZE_MEDIUM),
api_get_path(WEB_PLUGIN_PATH).'zoom/start.php?'.api_get_cidreq()
);
}
if (!empty($returnUrl)) {
$back = Display::url(
Display::return_icon('back.png', get_lang('Back'), null, ICON_SIZE_MEDIUM),
$returnUrl
);
}
if (!$isSessionAdmin) {
$actionsLeft .= Display::url(
Display::return_icon('agenda.png', get_lang('Calendar'), [], ICON_SIZE_MEDIUM),
'calendar.php'
);
$actionsLeft .= Display::url(
Display::return_icon('settings.png', get_lang('Settings'), null, ICON_SIZE_MEDIUM),
api_get_path(WEB_CODE_PATH).'admin/configure_plugin.php?name=zoom'
);
}
return Display::toolbarAction('toolbar', [$back.PHP_EOL.$actionsLeft]);
}
public function getRecordingSetting()
{
$recording = (string) $this->get('enableCloudRecording');
if (in_array($recording, [self::RECORDING_TYPE_LOCAL, self::RECORDING_TYPE_CLOUD], true)) {
return $recording;
}
return self::RECORDING_TYPE_NONE;
}
public function hasRecordingAvailable()
{
$recording = $this->getRecordingSetting();
return self::RECORDING_TYPE_NONE !== $recording;
}
/**
* @throws OptimisticLockException
* @throws \Doctrine\ORM\ORMException
*/
public function saveSignature(Registrant $registrant, string $file): bool
{
if (empty($file)) {
return false;
}
$signature = $registrant->getSignature();
if (null !== $signature) {
return false;
}
$signature = new Signature();
$signature
->setFile($file)
->setRegisteredAt(api_get_utc_datetime(null, false, true))
;
$registrant->setSignature($signature);
$em = Database::getManager();
$em->persist($signature);
$em->flush();
return true;
}
public function getSignature(int $userId, Meeting $meeting): ?Signature
{
$signatureRepo = Database::getManager()
->getRepository(Signature::class)
;
return $signatureRepo->findOneBy(['user' => $userId, 'meeting' => $meeting]);
}
public function exportSignatures(Meeting $meeting, $formatToExport)
{
$signatures = array_map(
function (Registrant $registrant) use ($formatToExport) {
$signature = $registrant->getSignature();
$item = [
$registrant->getUser()->getLastname(),
$registrant->getUser()->getFirstname(),
$signature
? api_convert_and_format_date($signature->getRegisteredAt(), DATE_TIME_FORMAT_LONG)
: '-',
];
if ('pdf' === $formatToExport) {
$item[] = $signature
? Display::img($signature->getFile(), '', ['style' => 'width: 150px;'], false)
: '-';
}
return $item;
},
$meeting->getRegistrants()->toArray()
);
$data = array_merge(
[
[
get_lang('LastName'),
get_lang('FirstName'),
get_lang('DateTime'),
'pdf' === $formatToExport ? get_lang('File') : null,
],
],
$signatures
);
if ('pdf' === $formatToExport) {
$params = [
'filename' => get_lang('Attendance'),
'pdf_title' => get_lang('Attendance'),
'pdf_description' => $meeting->getIntroduction(),
'show_teacher_as_myself' => false,
];
Export::export_table_pdf($data, $params);
}
if ('xls' === $formatToExport) {
$introduction = array_map(
function ($line) {
return [
strip_tags(trim($line)),
];
},
explode(PHP_EOL, $meeting->getIntroduction())
);
Export::arrayToXls(
array_merge($introduction, $data),
get_lang('Attendance')
);
}
}
/**
* @throws Exception
*/
public function createWebinarFromSchema(Webinar $webinar, WebinarSchema $schema): Webinar
{
$currentUser = api_get_user_entity(api_get_user_id());
$schema->settings->contact_email = $currentUser->getEmail();
$schema->settings->contact_name = $currentUser->getFullname();
$schema->settings->auto_recording = $this->getRecordingSetting();
$schema->settings->registrants_email_notification = false;
$schema->settings->attendees_and_panelists_reminder_email_notification->enable = false;
$schema->settings->follow_up_attendees_email_notification->enable = false;
$schema->settings->follow_up_absentees_email_notification->enable = false;
$schema = $schema->create($webinar->getAccountEmail());
$webinar->setWebinarSchema($schema);
$em = Database::getManager();
$em->persist($webinar);
$em->flush();
return $webinar;
}
public function getAccountEmails(): array
{
$currentValue = $this->get('accountSelector');
if (empty($currentValue)) {
return [];
}
$emails = explode(';', $currentValue);
$trimmed = array_map('trim', $emails);
$filtered = array_filter($trimmed);
return array_combine($filtered, $filtered);
}
/**
* Register users to a meeting.
*
* @param User[] $users
*
* @throws OptimisticLockException
*
* @return User[] failed registrations [ user id => errorMessage ]
*/
public function registerUsers(Meeting $meeting, array $users)
{
$failedUsers = [];
foreach ($users as $user) {
try {
$this->registerUser($meeting, $user, false);
} catch (Exception $exception) {
$failedUsers[$user->getId()] = $exception->getMessage();
}
}
Database::getManager()->flush();
return $failedUsers;
}
/**
* @param array $users
*
* @throws OptimisticLockException
* @throws \Doctrine\ORM\ORMException
*/
public function registerPresenters(Meeting $meeting, array $users): array
{
$failedUsers = [];
foreach ($users as $user) {
try {
$this->registerUser($meeting, $user, false, true);
} catch (Exception $exception) {
$failedUsers[$user->getId()] = $exception->getMessage();
}
}
Database::getManager()->flush();
return $failedUsers;
}
/**
* Removes registrants from a meeting.
*
* @param Registrant[] $registrants
*
* @throws Exception
*/
public function unregister(Meeting $meeting, array $registrants)
{
$meetingRegistrants = [];
foreach ($registrants as $registrant) {
$meetingRegistrants[] = $registrant->getMeetingRegistrant();
}
if ($meeting instanceof Webinar) {
$meeting->getWebinarSchema()->removeRegistrants($meetingRegistrants);
} else {
$meeting->getMeetingInfoGet()->removeRegistrants($meetingRegistrants);
}
$em = Database::getManager();
foreach ($registrants as $registrant) {
$em->remove($registrant);
}
$em->flush();
}
/**
* Updates meeting registrants list. Adds the missing registrants and removes the extra.
*
* @param Meeting $meeting
* @param User[] $users list of users to be registered
*
* @throws Exception
*/
private function updateRegistrantList($meeting, $users)
{
$usersToAdd = [];
foreach ($users as $user) {
$found = false;
foreach ($meeting->getRegistrants() as $registrant) {
if ($registrant->getUser() === $user) {
$found = true;
break;
}
}
if (!$found) {
$usersToAdd[] = $user;
}
}
$registrantsToRemove = [];
foreach ($meeting->getRegistrants() as $registrant) {
$found = false;
foreach ($users as $user) {
if ($registrant->getUser() === $user) {
$found = true;
break;
}
}
if (!$found) {
$registrantsToRemove[] = $registrant;
}
}
$this->registerUsers($meeting, $usersToAdd);
$this->unregister($meeting, $registrantsToRemove);
}
private function updatePresenterList($meeting, $users)
{
/** @var array $presenters */
$presenters = $meeting->getPresenters();
$presenterToAdd = [];
foreach ($users as $user) {
$foundPresenter = false;
foreach ($presenters as $presenter) {
if ($presenter->getUser() === $user) {
$foundPresenter = true;
break;
}
}
if (!$foundPresenter) {
$presenterToAdd[] = $user;
}
}
$registrantsToRemove = [];
foreach ($presenters as $registrant) {
$found = false;
foreach ($users as $user) {
if ($registrant->getUser() === $user) {
$found = true;
break;
}
}
if (!$found) {
$registrantsToRemove[] = $registrant;
}
}
$this->registerPresenters($meeting, $presenterToAdd);
$this->unregister($meeting, $registrantsToRemove);
}
/**
* @throws Exception
* @throws OptimisticLockException
*
* @return Registrant
*/
private function registerUser(Meeting $meeting, User $user, $andFlush = true, bool $isPresenter = false)
{
if (empty($user->getEmail())) {
throw new Exception($this->get_lang('CannotRegisterWithoutEmailAddress'));
}
if ($meeting instanceof Webinar) {
$meetingRegistrant = WebinarRegistrantSchema::fromEmailAndFirstName(
$user->getEmail(),
$user->getFirstname(),
$user->getLastname()
);
} else {
$meetingRegistrant = MeetingRegistrant::fromEmailAndFirstName(
$user->getEmail(),
$user->getFirstname(),
$user->getLastname()
);
}
$registrantEntity = new Registrant();
if ($isPresenter) {
$registrantEntity = new Presenter();
}
$registrantEntity
->setMeeting($meeting)
->setUser($user)
->setMeetingRegistrant($meetingRegistrant)
;
if ($meeting instanceof Webinar) {
$registrantEntity->setCreatedRegistration($meeting->getWebinarSchema()->addRegistrant($meetingRegistrant));
} else {
$registrantEntity->setCreatedRegistration($meeting->getMeetingInfoGet()->addRegistrant($meetingRegistrant));
}
Database::getManager()->persist($registrantEntity);
if ($andFlush) {
Database::getManager()->flush($registrantEntity);
}
return $registrantEntity;
}
/**
* Starts a new instant meeting and redirects to its start url.
*
* @param string $topic
* @param User|null $user
* @param Course|null $course
* @param CGroupInfo|null $group
* @param Session|null $session
*
* @throws Exception
*/
private function startInstantMeeting($topic, $user = null, $course = null, $group = null, $session = null)
{
$meetingInfoGet = MeetingInfoGet::fromTopicAndType($topic, MeetingInfoGet::TYPE_INSTANT);
//$meetingInfoGet->settings->approval_type = MeetingSettings::APPROVAL_TYPE_AUTOMATICALLY_APPROVE;
$meeting = $this->createMeetingFromMeeting(
(new Meeting())
->setMeetingInfoGet($meetingInfoGet)
->setUser($user)
->setGroup($group)
->setCourse($course)
->setSession($session)
);
api_location($meeting->getMeetingInfoGet()->start_url);
}
/**
* Creates a meeting on Zoom servers and stores it in the local database.
*
* @param Meeting $meeting a new, unsaved meeting with at least a type and a topic
*
* @throws Exception
*
* @return Meeting
*/
private function createMeetingFromMeeting($meeting)
{
$currentUser = api_get_user_entity(api_get_user_id());
$meeting->getMeetingInfoGet()->settings->contact_email = $currentUser->getEmail();
$meeting->getMeetingInfoGet()->settings->contact_name = $currentUser->getFullname();
$meeting->getMeetingInfoGet()->settings->auto_recording = $this->getRecordingSetting();
$meeting->getMeetingInfoGet()->settings->registrants_email_notification = false;
//$meeting->getMeetingInfoGet()->host_email = $currentUser->getEmail();
//$meeting->getMeetingInfoGet()->settings->alternative_hosts = $currentUser->getEmail();
// Send create to Zoom.
$meeting->setMeetingInfoGet(
$meeting->getMeetingInfoGet()->create(
$meeting->getAccountEmail()
)
);
Database::getManager()->persist($meeting);
Database::getManager()->flush();
return $meeting;
}
/**
* @throws Exception
*
* @return Meeting
*/
private function createGlobalMeeting()
{
$meetingInfoGet = MeetingInfoGet::fromTopicAndType(
$this->get_lang('GlobalMeeting'),
MeetingInfoGet::TYPE_SCHEDULED
);
$meetingInfoGet->start_time = (new DateTime())->format(DATE_ATOM);
$meetingInfoGet->duration = 60;
$meetingInfoGet->settings->approval_type =
('true' === $this->get('enableParticipantRegistration'))
? MeetingSettings::APPROVAL_TYPE_AUTOMATICALLY_APPROVE
: MeetingSettings::APPROVAL_TYPE_NO_REGISTRATION_REQUIRED;
// $meetingInfoGet->settings->host_video = true;
$meetingInfoGet->settings->participant_video = true;
$meetingInfoGet->settings->join_before_host = true;
$meetingInfoGet->settings->registrants_email_notification = false;
return $this->createMeetingFromMeeting((new Meeting())->setMeetingInfoGet($meetingInfoGet));
}
/**
* Schedules a meeting and returns it.
* set $course, $session and $user to null in order to create a global meeting.
*
* @param DateTime $startTime meeting local start date-time (configure local timezone on your Zoom account)
* @param int $duration in minutes
* @param string $topic short title of the meeting, required
* @param string $agenda ordre du jour
* @param string $password meeting password
*
* @throws Exception
*
* @return Meeting meeting
*/
private function createScheduleMeeting(
User $user = null,
Course $course = null,
CGroupInfo $group = null,
Session $session = null,
$startTime,
$duration,
$topic,
$agenda,
$password,
bool $signAttendance = false,
string $reasonToSignAttendance = '',
string $accountEmail = null
) {
$meetingInfoGet = MeetingInfoGet::fromTopicAndType($topic, MeetingInfoGet::TYPE_SCHEDULED);
$meetingInfoGet->duration = $duration;
$meetingInfoGet->start_time = $startTime->format(DATE_ATOM);
$meetingInfoGet->agenda = $agenda;
$meetingInfoGet->password = $password;
$meetingInfoGet->settings->approval_type = MeetingSettings::APPROVAL_TYPE_NO_REGISTRATION_REQUIRED;
if ('true' === $this->get('enableParticipantRegistration')) {
$meetingInfoGet->settings->approval_type = MeetingSettings::APPROVAL_TYPE_AUTOMATICALLY_APPROVE;
}
return $this->createMeetingFromMeeting(
(new Meeting())
->setMeetingInfoGet($meetingInfoGet)
->setUser($user)
->setCourse($course)
->setGroup($group)
->setSession($session)
->setSignAttendance($signAttendance)
->setReasonToSignAttendance($reasonToSignAttendance)
->setAccountEmail($accountEmail)
);
}
/**
* @throws Exception
*/
private function createScheduleWebinar(
?User $user,
?Course $course,
?CGroupInfo $group,
?Session $session,
DateTime $startTime,
$duration,
$topic,
$agenda,
$password,
bool $signAttendance = false,
string $reasonToSignAttendance = '',
string $accountEmail = null
): Webinar {
$webinarSchema = WebinarSchema::fromTopicAndType($topic);
$webinarSchema->duration = $duration;
$webinarSchema->start_time = $startTime->format(DATE_ATOM);
$webinarSchema->agenda = $agenda;
$webinarSchema->password = $password;
if ('true' === $this->get('enableParticipantRegistration')) {
$webinarSchema->settings->approval_type = WebinarSettings::APPROVAL_TYPE_AUTOMATICALLY_APPROVE;
}
$webinar = (new Webinar())
->setUser($user)
->setCourse($course)
->setGroup($group)
->setSession($session)
->setSignAttendance($signAttendance)
->setReasonToSignAttendance($reasonToSignAttendance)
->setAccountEmail($accountEmail)
;
return $this->createWebinarFromSchema($webinar, $webinarSchema);
}
/**
* Registers all the course users to a course meeting.
*
* @param Meeting $meeting
*
* @throws OptimisticLockException
*/
private function registerAllCourseUsers($meeting)
{
$this->registerUsers($meeting, $meeting->getRegistrableUsers());
}
}