bbb_node.module in BigBlueButton 8
Big Blue Button - Enables universities and colleges to deliver a high-quality learning experience.
@author Stefan Auditor <stefan.auditor@erdfisch.de>
TODO:
- Add 'start meeting' button
- Rework waiting page
- do a seperate page with a big throbber, that tells the status of the meeeting, so that it's clear you have to wait here.
File
modules/bbb_node/bbb_node.moduleView source
<?php
/**
* @file
* Big Blue Button - Enables universities and colleges to deliver a high-quality
* learning experience.
*
* @author
* Stefan Auditor <stefan.auditor@erdfisch.de>
*
* TODO:
* - Add 'start meeting' button
* - Rework waiting page
* - do a seperate page with a big throbber, that tells the status of the
* meeeting, so that it's clear you have to wait here.
*/
// API version
use BigBlueButton\Parameters\CreateMeetingParameters;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormState;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\node\NodeInterface;
/**
* Implement HOOK_menu().
*/
function bbb_menu() {
$items = [];
// @ToDo: Move rest of hook_menu into the relevant configuration.
$show_local_tasks = \Drupal::config('bbb_node.settings')
->get('local_tasks');
$items['node/%node/meeting/attend'] = [
'title' => 'Attend Meeting',
'route_name' => 'bbb_node.meeting.attend',
'type' => $show_local_tasks ? 'MENU_LOCAL_TASK' : 'MENU_CALLBACK',
'weight' => 2,
];
$items['node/%node/meeting/moderate'] = [
'title' => 'Moderate Meeting',
'route_name' => 'bbb_node.meeting.moderate',
'type' => $show_local_tasks ? 'MENU_LOCAL_TASK' : 'MENU_CALLBACK',
'weight' => 2,
];
$items['node/%node/meeting/end-confirm'] = [
'title' => 'Terminate Meeting',
'type' => 'MENU_CALLBACK',
];
$items['node/%node/redirect/attend'] = [
'type' => 'MENU_CALLBACK',
];
$items['node/%node/redirect/moderate'] = [
'type' => 'MENU_CALLBACK',
];
$items['node/%node/meeting/status'] = [
'type' => 'MENU_CALLBACK',
];
return $items;
}
/**
* Implements hook_node_access().
*/
function bbb_node_node_access(NodeInterface $node, $op, AccountInterface $account) {
/** @var \Drupal\bbb_node\Service\NodeMeeting $node_meeting */
$node_meeting = \Drupal::service('bbb_node.meeting');
if (in_array($op, [
'create',
'update',
]) && $node_meeting
->isTypeOf($node)) {
// No bother to check for node access since this will be on edit/create pages.
if ($account
->hasPermission('bbb_node record meetings') || $account
->hasPermission('administer big blue button')) {
return AccessResult::allowed();
}
return AccessResult::forbidden();
}
return AccessResult::neutral();
}
/**
* Implements hook_form_alter().
*/
function bbb_node_form_alter(&$form, FormStateInterface $form_state, $form_id) {
// Node type settings form
switch ($form_id) {
case 'node_type_edit_form':
case 'node_type_add_form':
$manager = \Drupal::entityTypeManager();
$storage = $manager
->getStorage('bbb_node_type');
/** @var \Drupal\node\NodeTypeInterface $node_type */
$node_type = $form_state
->getFormObject()
->getEntity();
/** @var \Drupal\bbb_node\Service\NodeMeeting $node_meeting */
$node_meeting = \Drupal::service('bbb_node.meeting');
if (!$node_meeting
->isTypeOf($node_type)) {
return;
}
if ($form_id == 'node_type_edit_form') {
$id = $node_type
->id();
$label = $node_type
->label();
$entity = $storage
->load($id);
if (!$entity) {
$entity = $storage
->create([
'id' => $id,
'label' => $label,
]);
}
}
else {
$entity = $storage
->create();
}
$bbb_form = $manager
->getFormObject($entity
->getEntityTypeId(), 'edit');
$bbb_form
->setEntity($entity);
$form['bbb'] = $bbb_form
->buildForm([], new FormState());
if (!empty($form['bbb']['#submit'])) {
$form['#submit'][] = array_pop($form['bbb']['#submit']);
}
if (!empty($form['actions']['submit']['#validate']) && !empty($form['bbb']['actions']['submit']['#validate'])) {
$form['actions']['submit']['#validate'] = array_merge($form['actions']['submit']['#validate'], $form['bbb']['actions']['submit']['#validate']);
}
if (!empty($form['actions']['submit']['#submit']) && !empty($form['bbb']['actions']['submit']['#submit'])) {
$form['actions']['submit']['#submit'] = array_merge($form['actions']['submit']['#submit'], $form['bbb']['actions']['submit']['#submit']);
$form['actions']['submit']['#submit'][] = [
$bbb_form,
'saveEntity',
];
}
$form['bbb']['actions']['#access'] = FALSE;
break;
default:
break;
}
}
/**
* Implements hook_form_BASE_FORM_ID_alter().
*/
function bbb_node_form_node_form_alter(&$form, FormStateInterface $form_state, $form_id) {
/** @var \Drupal\bbb_node\Service\NodeMeeting $node_meeting */
$node_meeting = \Drupal::service('bbb_node.meeting');
/** @var \Drupal\node\NodeInterface $node */
$node = $form_state
->getFormObject()
->getEntity();
if ($node_meeting
->isTypeOf($node)) {
$meeting = $node_meeting
->get($node);
/** @var \BigBlueButton\Parameters\CreateMeetingParameters $meeting_info */
$meeting_info = !empty($meeting['info']) ? $meeting['info'] : $node_meeting
->init($node);
$form['bbb'] = [];
$record = [
'#title' => t('Record meeting'),
'#type' => 'select',
'#default_value' => $meeting_info
->isRecorded(),
'#options' => [
0 => t('Do not record'),
1 => t('Record'),
],
'#weight' => -1,
];
if (\Drupal::currentUser()
->hasPermission('administer big blue button')) {
$form['bbb']['welcome'] = [
'#title' => t('Welcome message'),
'#type' => 'textfield',
'#default_value' => $meeting_info
->getWelcomeMessage(),
'#maxlength' => 255,
'#description' => t('A welcome message that gets displayed on the chat window when the participant joins. You can include keywords (%%CONFNAME%%, %%DIALNUM%%, %%CONFNUM%%) which will be substituted automatically.'),
];
$form['bbb']['dialNumber'] = [
'#title' => t('Dial number'),
'#type' => 'textfield',
'#default_value' => $meeting_info
->getDialNumber(),
'#maxlength' => 32,
'#description' => t('The dial access number that participants can call in using regular phone.'),
];
$form['bbb']['moderatorPW'] = [
'#title' => t('Moderator password'),
'#type' => 'textfield',
'#default_value' => $meeting_info
->getModeratorPassword(),
'#maxlength' => 32,
'#description' => t('The password that will be required for moderators to join the meeting or for certain administrative actions (i.e. ending a meeting).'),
];
$form['bbb']['attendeePW'] = [
'#title' => t('Attendee password'),
'#type' => 'textfield',
'#default_value' => $meeting_info
->getAttendeePassword(),
'#maxlength' => 32,
'#description' => t('The password that will be required for attendees to join the meeting.'),
];
$form['bbb']['logoutURL'] = [
'#title' => t('Logout URL'),
'#type' => 'textfield',
'#default_value' => $meeting_info
->getLogoutUrl(),
'#maxlength' => 255,
'#description' => t('The URL that the Big Blue Button client will go to after users click the OK button on the <em>You have been logged out message</em>.'),
];
$form['bbb']['record'] = $record;
}
if (\Drupal::currentUser()
->hasPermission('bbb_node record meetings') && empty($form['bbb']['record'])) {
// this clause is for users who have the record meetings permission but no permissions to "administer BBB"
$form['bbb']['record'] = $record;
}
// Add details block and show if any of form elements added.
$form['bbb'] += [
'#access' => !empty($form['bbb']),
'#title' => t('Meeting settings'),
'#type' => 'details',
'#description' => t("The following settings may be changed until the meeting first starts."),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#tree' => TRUE,
'#group' => 'advanced',
'#weight' => 100,
];
}
}
/**
* Implements hook_ENTITY_TYPE_insert().
* @see hook_ENTITY_TYPE_insert()
*/
function bbb_node_node_insert(EntityInterface $node) {
/** @var \Drupal\bbb_node\Service\NodeMeeting $node_meeting */
$node_meeting = \Drupal::service('bbb_node.meeting');
/** @var \Drupal\node\NodeInterface $node */
if ($node_meeting
->isTypeOf($node)) {
$params = new CreateMeetingParameters($node
->uuid(), $node
->getTitle());
\Drupal::moduleHandler()
->alter('bbb_node_create', $params, $node);
$meeting = $node_meeting
->create($node, $params);
$node_meeting
->store($node, $params);
}
}
/**
* Implements hook_ENTITY_TYPE_update().
*/
function bbb_node_node_update(EntityInterface $node) {
/** @var \Drupal\bbb_node\Service\NodeMeeting $meeting */
$meeting = \Drupal::service('bbb_node.meeting');
/** @var \Drupal\node\NodeInterface $node */
if ($meeting
->isTypeOf($node)) {
$meeting
->update($node, $node->bbb['info'] ?: new CreateMeetingParameters($node
->uuid(), $node
->getTitle()));
}
}
/**
* Implements hook_ENTITY_TYPE_view().
*/
function bbb_node_node_view(array &$build, EntityInterface $node, EntityViewDisplayInterface $display, $view_mode) {
/** @var \Drupal\bbb_node\Service\NodeMeeting $node_meeting */
$node_meeting = \Drupal::service('bbb_node.meeting');
/** @var \Drupal\node\NodeInterface $node */
$node_type = $node
->getType();
if (!$node_meeting
->isTypeOf($node)) {
return;
}
$meeting = $node_meeting
->get($node);
$BBBNodeTypeConfig = \Drupal::entityTypeManager()
->getStorage('bbb_node_type')
->load($node
->getType());
// Show meeting status.
if ($BBBNodeTypeConfig
->get('showStatus')) {
$build['content']['bbb_meeting_status'] = [
'#theme' => 'bbb_meeting_status',
'#meeting' => $meeting,
'#weight' => 10,
];
$build['content']['bbb_meeting_record'] = [
'#theme' => 'bbb_meeting_record',
'#meeting' => $meeting,
'#weight' => 11,
];
}
// Add links to content.
$links = [];
$show = $BBBNodeTypeConfig
->get('showLinks');
if ($view_mode !== 'teaser' && $show) {
$meeting = $node_meeting
->get($node);
$current_user = \Drupal::currentUser();
if ($current_user
->hasPermission('bbb_node attend meetings') || $current_user
->hasPermission('administer big blue button')) {
$links['meeting_attend'] = [
'title' => t('Attend meeting'),
'href' => Url::fromRoute('bbb_node.meeting.attend', [
'node' => $node
->id(),
])
->toString(),
];
}
if (\Drupal::currentUser()
->hasPermission('bbb_node moderate meetings') || $current_user
->hasPermission('administer big blue button') || $current_user
->id() == $node
->getAuthor()
->id() && $current_user
->hasPermission('bbb_node moderate own meetings')) {
$links['meeting_moderate'] = [
'title' => t('Moderate meeting'),
'href' => Url::fromRoute('bbb_node.meeting.moderate', [
'node' => $node
->id(),
])
->toString(),
];
}
if ($current_user
->hasPermission('bbb_node moderate meetings') || $current_user
->hasPermission('administer big blue button') || $current_user
->id() == $node
->getAuthor()
->id() && $current_user
->hasPermission('bbb_node moderate own meetings') && $meeting['info']
->isRunning()) {
$links['meeting_end'] = [
'title' => t('Terminate meeting'),
'href' => Url::fromRoute('bbb_node.meeting.end_meeting_confirm_form', [
'node' => $node
->id(),
])
->toString(),
];
}
if (!empty($links)) {
$build['content']['links']['bbb'] = [
'#links' => $links,
];
}
}
}
/**
* Implements hook_ENTITY_TYPE_load().
*/
function bbb_node_node_load($entities) {
/** @var \Drupal\bbb_node\Service\NodeMeeting $meeting */
$meeting = \Drupal::service('bbb_node.meeting');
/** @var NodeInterface[] $entities */
foreach ($entities as $node) {
if ($meeting
->isTypeOf($node)) {
$node->bbb = $meeting
->get($node);
}
}
}
/**
* Implements hook_ENTITY_TYPE_delete().
*/
function bbb_node_node_delete(EntityInterface $entity) {
/** @var \Drupal\bbb_node\Service\NodeMeeting $meeting */
$meeting = \Drupal::service('bbb_node.meeting');
/** @var \Drupal\node\NodeInterface $entity */
if ($meeting
->isTypeOf($entity)) {
$meeting
->delete($entity);
}
}
/**
* Implements hook_theme().
*/
function bbb_node_theme($existing, $type, $theme, $path) {
return [
'bbb_meeting' => [
'variables' => [
'meeting' => NULL,
'mode' => NULL,
'params' => [],
],
],
'bbb_meeting_status' => [
'variables' => [
'meeting' => NULL,
],
],
'bbb_meeting_record' => [
'variables' => [
'meeting' => NULL,
],
],
'bbb_meeting_join_moderator' => [
'variables' => [
'meeting' => NULL,
],
],
'bbb_meeting_join_attendee' => [
'variables' => [
'meeting' => NULL,
],
],
'bbb_block_meeting' => [
'variables' => [
'meeting' => NULL,
],
],
];
}
/* Themeables */
/**
* Theme inline meeting
*/
function theme_bbb_meeting($meeting) {
/** @var \Drupal\bbb\Service\Theme $theme */
$theme = \Drupal::service('bbb.theme');
return $theme
->meeting($meeting);
}
/**
* Theme meeting status
*/
function theme_bbb_meeting_status($meeting) {
/** @var \Drupal\bbb\Service\Theme $theme */
$theme = \Drupal::service('bbb.theme');
return $theme
->meetingStatus($meeting);
}
/**
* Theme meeting recording
*/
function theme_bbb_meeting_record($meeting) {
/** @var \Drupal\bbb\Service\Theme $theme */
$theme = \Drupal::service('bbb.theme');
return $theme
->meetingRecord($meeting);
}
/**
* Theme meeting details block
*/
function theme_bbb_block_meeting($meeting) {
/** @var \Drupal\bbb\Service\Theme $theme */
$theme = \Drupal::service('bbb.theme');
return $theme
->blockMeeting($meeting);
}
Functions
Name | Description |
---|---|
bbb_menu | Implement HOOK_menu(). |
bbb_node_form_alter | Implements hook_form_alter(). |
bbb_node_form_node_form_alter | Implements hook_form_BASE_FORM_ID_alter(). |
bbb_node_node_access | Implements hook_node_access(). |
bbb_node_node_delete | Implements hook_ENTITY_TYPE_delete(). |
bbb_node_node_insert | Implements hook_ENTITY_TYPE_insert(). |
bbb_node_node_load | Implements hook_ENTITY_TYPE_load(). |
bbb_node_node_update | Implements hook_ENTITY_TYPE_update(). |
bbb_node_node_view | Implements hook_ENTITY_TYPE_view(). |
bbb_node_theme | Implements hook_theme(). |
theme_bbb_block_meeting | Theme meeting details block |
theme_bbb_meeting | Theme inline meeting |
theme_bbb_meeting_record | Theme meeting recording |
theme_bbb_meeting_status | Theme meeting status |