Merge branch 'MDL-74638-master-test' of https://github.com/rezaies/moodle

This commit is contained in:
Jake Dallimore 2022-11-11 13:02:52 +08:00
commit 96e9f7c03e
41 changed files with 1481 additions and 89 deletions

View File

@ -0,0 +1,10 @@
define("mod_bigbluebuttonbn/guest_access_modal",["exports","core/str","core_form/modalform","core/toast","core/notification"],(function(_exports,_str,_modalform,_toast,_notification){var obj;
/**
* Javascript module for importing presets.
*
* @module mod_bigbluebuttonbn/guest_access_modal
* @copyright 2022 Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_modalform=(obj=_modalform)&&obj.__esModule?obj:{default:obj};const selectors_showGuestAccessButton='[data-action="show-guest-access"]';_exports.init=guestInfo=>{const showGuestAccessButton=document.querySelector(selectors_showGuestAccessButton),modalForm=new _modalform.default({modalConfig:{title:(0,_str.get_string)("guestaccess_title","mod_bigbluebuttonbn"),large:!0},args:guestInfo,saveButtonText:(0,_str.get_string)("ok","core_moodle"),formClass:"mod_bigbluebuttonbn\\form\\guest_add"});showGuestAccessButton.addEventListener("click",(event=>{modalForm.show().then((()=>((0,_toast.addToastRegion)(modalForm.modal.getRoot()[0]),!0))).catch(_notification.exception),modalForm.addEventListener(modalForm.events.FORM_SUBMITTED,(e=>{modalForm.modal.getRoot()[0].querySelectorAll(".toast-wrapper").forEach((reg=>reg.remove())),e.detail.result?e.detail.emailcount>0&&(0,_toast.add)((0,_str.get_string)("guestaccess_invite_success","mod_bigbluebuttonbn",e.detail),{type:"success"}):(0,_toast.add)((0,_str.get_string)("guestaccess_invite_failure","mod_bigbluebuttonbn",e.detail),{type:"warning"})}),{once:!0}),event.stopPropagation()}))}}));
//# sourceMappingURL=guest_access_modal.min.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"guest_access_modal.min.js","sources":["../src/guest_access_modal.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Javascript module for importing presets.\n *\n * @module mod_bigbluebuttonbn/guest_access_modal\n * @copyright 2022 Blindside Networks Inc\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport {get_string as getString} from 'core/str';\nimport ModalForm from 'core_form/modalform';\nimport {add as toastAdd, addToastRegion} from 'core/toast';\nimport {\n exception as displayException,\n} from 'core/notification';\nconst selectors = {\n showGuestAccessButton: '[data-action=\"show-guest-access\"]',\n};\n\n/**\n * Intialise the object and click event to show the popup form\n *\n * @param {object} guestInfo\n * @param {string} guestInfo.id\n * @param {string} guestInfo.groupid\n * @param {string} guestInfo.guestjoinurl\n * @param {string} guestInfo.guestpassword\n */\nexport const init = (guestInfo) => {\n const showGuestAccessButton = document.querySelector(selectors.showGuestAccessButton);\n\n const modalForm = new ModalForm({\n modalConfig: {\n title: getString('guestaccess_title', 'mod_bigbluebuttonbn'),\n large: true,\n },\n args: guestInfo,\n saveButtonText: getString('ok', 'core_moodle'),\n formClass: 'mod_bigbluebuttonbn\\\\form\\\\guest_add',\n });\n showGuestAccessButton.addEventListener('click', event => {\n modalForm.show().then(() => {\n addToastRegion(modalForm.modal.getRoot()[0]);\n return true;\n }).catch(displayException);\n modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, (e) => {\n // Remove toast region as if not it will be displayed on the closed modal.\n const modalElement = modalForm.modal.getRoot()[0];\n const regions = modalElement.querySelectorAll('.toast-wrapper');\n regions.forEach((reg) => reg.remove());\n if (e.detail.result) {\n if (e.detail.emailcount > 0) {\n toastAdd(getString('guestaccess_invite_success', 'mod_bigbluebuttonbn', e.detail),\n {\n type: 'success',\n }\n );\n }\n } else {\n toastAdd(getString('guestaccess_invite_failure', 'mod_bigbluebuttonbn', e.detail),\n {\n type: 'warning',\n }\n );\n }\n }, {once: true});\n event.stopPropagation();\n });\n};\n"],"names":["selectors","guestInfo","showGuestAccessButton","document","querySelector","modalForm","ModalForm","modalConfig","title","large","args","saveButtonText","formClass","addEventListener","event","show","then","modal","getRoot","catch","displayException","events","FORM_SUBMITTED","e","querySelectorAll","forEach","reg","remove","detail","result","emailcount","type","once","stopPropagation"],"mappings":";;;;;;;sJA4BMA,gCACqB,kDAYNC,kBACXC,sBAAwBC,SAASC,cAAcJ,iCAE/CK,UAAY,IAAIC,mBAAU,CAC5BC,YAAa,CACTC,OAAO,mBAAU,oBAAqB,uBACtCC,OAAO,GAEXC,KAAMT,UACNU,gBAAgB,mBAAU,KAAM,eAChCC,UAAW,yCAEfV,sBAAsBW,iBAAiB,SAASC,QAC5CT,UAAUU,OAAOC,MAAK,+BACHX,UAAUY,MAAMC,UAAU,KAClC,KACRC,MAAMC,yBACTf,UAAUQ,iBAAiBR,UAAUgB,OAAOC,gBAAiBC,IAEpClB,UAAUY,MAAMC,UAAU,GAClBM,iBAAiB,kBACtCC,SAASC,KAAQA,IAAIC,WACzBJ,EAAEK,OAAOC,OACLN,EAAEK,OAAOE,WAAa,mBACb,mBAAU,6BAA8B,sBAAuBP,EAAEK,QACtE,CACIG,KAAM,4BAKT,mBAAU,6BAA8B,sBAAuBR,EAAEK,QACtE,CACIG,KAAM,cAInB,CAACC,MAAM,IACVlB,MAAMmB"}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,6 @@ define("mod_bigbluebuttonbn/roomupdater",["exports","core/templates","core/notif
* @module mod_bigbluebuttonbn/roomupdater
* @copyright 2021 Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.updateRoom=_exports.stop=_exports.start=void 0,_templates=(obj=_templates)&&obj.__esModule?obj:{default:obj};let timerReference=null,timerRunning=!1,pollInterval=0,pollIntervalFactor=1;const resetValues=()=>{timerRunning=!1,timerReference=null,pollInterval=0,pollIntervalFactor=1};_exports.start=interval=>{resetValues(),timerRunning=!0,pollInterval=interval,poll()};_exports.stop=()=>{timerReference&&clearTimeout(timerReference),resetValues()};const poll=()=>{timerRunning&&pollInterval&&updateRoom().then((updateOk=>(updateOk||(pollIntervalFactor=pollIntervalFactor<10?pollIntervalFactor+1:10),timerReference=setTimeout((()=>poll()),pollInterval*pollIntervalFactor),!0))).catch()},updateRoom=function(){let updatecache=arguments.length>0&&void 0!==arguments[0]&&arguments[0];const bbbRoomViewElement=document.getElementById("bbb-room-view"),bbbId=bbbRoomViewElement.dataset.bbbId,groupId=bbbRoomViewElement.dataset.groupId;return(0,_repository.getMeetingInfo)(bbbId,groupId,updatecache).then((data=>(data.haspresentations=!(!data.presentations||!data.presentations.length),_templates.default.renderForPromise("mod_bigbluebuttonbn/room_view",data)))).then((_ref=>{let{html:html,js:js}=_ref;return _templates.default.replaceNodeContents(bbbRoomViewElement,html,js)})).then((()=>!0)).catch((ex=>((0,_notification.exception)(ex),!1)))};_exports.updateRoom=updateRoom}));
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.updateRoom=_exports.stop=_exports.start=void 0,_templates=(obj=_templates)&&obj.__esModule?obj:{default:obj};let timerReference=null,timerRunning=!1,pollInterval=0,pollIntervalFactor=1;const resetValues=()=>{timerRunning=!1,timerReference=null,pollInterval=0,pollIntervalFactor=1};_exports.start=interval=>{resetValues(),timerRunning=!0,pollInterval=interval,poll()};_exports.stop=()=>{timerReference&&clearTimeout(timerReference),resetValues()};const poll=()=>{timerRunning&&pollInterval&&updateRoom().then((updateOk=>(updateOk||(pollIntervalFactor=pollIntervalFactor<10?pollIntervalFactor+1:10),timerReference=setTimeout((()=>poll()),pollInterval*pollIntervalFactor),!0))).catch()},updateRoom=function(){let updatecache=arguments.length>0&&void 0!==arguments[0]&&arguments[0];const bbbRoomViewElement=document.getElementById("bigbluebuttonbn-room-view"),bbbId=bbbRoomViewElement.dataset.bbbId,groupId=bbbRoomViewElement.dataset.groupId;return(0,_repository.getMeetingInfo)(bbbId,groupId,updatecache).then((data=>(data.haspresentations=!(!data.presentations||!data.presentations.length),_templates.default.renderForPromise("mod_bigbluebuttonbn/room_view",data)))).then((_ref=>{let{html:html,js:js}=_ref;return _templates.default.replaceNode(bbbRoomViewElement,html,js)})).then((()=>!0)).catch((ex=>((0,_notification.exception)(ex),!1)))};_exports.updateRoom=updateRoom}));
//# sourceMappingURL=roomupdater.min.js.map

View File

@ -1 +1 @@
{"version":3,"file":"roomupdater.min.js","sources":["../src/roomupdater.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * JS room updater.\n *\n * @module mod_bigbluebuttonbn/roomupdater\n * @copyright 2021 Blindside Networks Inc\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Templates from \"core/templates\";\nimport {exception as displayException} from 'core/notification';\nimport {getMeetingInfo} from './repository';\n\nlet timerReference = null;\nlet timerRunning = false;\nlet pollInterval = 0;\nlet pollIntervalFactor = 1;\nconst MAX_POLL_INTERVAL_FACTOR = 10;\n\nconst resetValues = () => {\n timerRunning = false;\n timerReference = null;\n pollInterval = 0;\n pollIntervalFactor = 1;\n};\n\n/**\n * Start the information poller.\n * @param {Number} interval interval in miliseconds between each poll action.\n */\nexport const start = (interval) => {\n resetValues();\n timerRunning = true;\n pollInterval = interval;\n poll();\n};\n\n/**\n * Stop the room updater.\n */\nexport const stop = () => {\n if (timerReference) {\n clearTimeout(timerReference);\n }\n resetValues();\n};\n\n/**\n * Start the information poller.\n */\nconst poll = () => {\n if (!timerRunning || !pollInterval) {\n // The poller has been stopped.\n return;\n }\n updateRoom()\n .then((updateOk) => {\n if (!updateOk) {\n pollIntervalFactor = (pollIntervalFactor < MAX_POLL_INTERVAL_FACTOR) ?\n pollIntervalFactor + 1 : MAX_POLL_INTERVAL_FACTOR;\n // We make sure if there is an error that we do not try too often.\n }\n timerReference = setTimeout(() => poll(), pollInterval * pollIntervalFactor);\n return true;\n })\n .catch();\n};\n\n/**\n * Update the room information.\n *\n * @param {boolean} [updatecache=false] should we update cache\n * @returns {Promise}\n */\nexport const updateRoom = (updatecache = false) => {\n const bbbRoomViewElement = document.getElementById('bbb-room-view');\n const bbbId = bbbRoomViewElement.dataset.bbbId;\n const groupId = bbbRoomViewElement.dataset.groupId;\n return getMeetingInfo(bbbId, groupId, updatecache)\n .then(data => {\n // Just make sure we have the right information for the template.\n data.haspresentations = !!(data.presentations && data.presentations.length);\n return Templates.renderForPromise('mod_bigbluebuttonbn/room_view', data);\n })\n .then(({html, js}) => Templates.replaceNodeContents(bbbRoomViewElement, html, js))\n .then(() => true)\n .catch((ex) => {\n displayException(ex);\n return false;\n });\n};\n"],"names":["timerReference","timerRunning","pollInterval","pollIntervalFactor","resetValues","interval","poll","clearTimeout","updateRoom","then","updateOk","setTimeout","catch","updatecache","bbbRoomViewElement","document","getElementById","bbbId","dataset","groupId","data","haspresentations","presentations","length","Templates","renderForPromise","_ref","html","js","replaceNodeContents","ex"],"mappings":";;;;;;;uLA2BIA,eAAiB,KACjBC,cAAe,EACfC,aAAe,EACfC,mBAAqB,QAGnBC,YAAc,KAChBH,cAAe,EACfD,eAAiB,KACjBE,aAAe,EACfC,mBAAqB,kBAOHE,WAClBD,cACAH,cAAe,EACfC,aAAeG,SACfC,sBAMgB,KACZN,gBACAO,aAAaP,gBAEjBI,qBAMEE,KAAO,KACJL,cAAiBC,cAItBM,aACKC,MAAMC,WACEA,WACDP,mBAAsBA,mBAzCL,GA0CbA,mBAAqB,EA1CR,IA6CrBH,eAAiBW,YAAW,IAAML,QAAQJ,aAAeC,qBAClD,KAEVS,SASIJ,WAAa,eAACK,0EACjBC,mBAAqBC,SAASC,eAAe,iBAC7CC,MAAQH,mBAAmBI,QAAQD,MACnCE,QAAUL,mBAAmBI,QAAQC,eACpC,8BAAeF,MAAOE,QAASN,aACjCJ,MAAKW,OAEFA,KAAKC,oBAAsBD,KAAKE,gBAAiBF,KAAKE,cAAcC,QAC7DC,mBAAUC,iBAAiB,gCAAiCL,SAEtEX,MAAKiB,WAACC,KAACA,KAADC,GAAOA,gBAAQJ,mBAAUK,oBAAoBf,mBAAoBa,KAAMC,OAC7EnB,MAAK,KAAM,IACXG,OAAOkB,iCACaA,KACV"}
{"version":3,"file":"roomupdater.min.js","sources":["../src/roomupdater.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * JS room updater.\n *\n * @module mod_bigbluebuttonbn/roomupdater\n * @copyright 2021 Blindside Networks Inc\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Templates from \"core/templates\";\nimport {exception as displayException} from 'core/notification';\nimport {getMeetingInfo} from './repository';\n\nlet timerReference = null;\nlet timerRunning = false;\nlet pollInterval = 0;\nlet pollIntervalFactor = 1;\nconst MAX_POLL_INTERVAL_FACTOR = 10;\n\nconst resetValues = () => {\n timerRunning = false;\n timerReference = null;\n pollInterval = 0;\n pollIntervalFactor = 1;\n};\n\n/**\n * Start the information poller.\n * @param {Number} interval interval in miliseconds between each poll action.\n */\nexport const start = (interval) => {\n resetValues();\n timerRunning = true;\n pollInterval = interval;\n poll();\n};\n\n/**\n * Stop the room updater.\n */\nexport const stop = () => {\n if (timerReference) {\n clearTimeout(timerReference);\n }\n resetValues();\n};\n\n/**\n * Start the information poller.\n */\nconst poll = () => {\n if (!timerRunning || !pollInterval) {\n // The poller has been stopped.\n return;\n }\n updateRoom()\n .then((updateOk) => {\n if (!updateOk) {\n pollIntervalFactor = (pollIntervalFactor < MAX_POLL_INTERVAL_FACTOR) ?\n pollIntervalFactor + 1 : MAX_POLL_INTERVAL_FACTOR;\n // We make sure if there is an error that we do not try too often.\n }\n timerReference = setTimeout(() => poll(), pollInterval * pollIntervalFactor);\n return true;\n })\n .catch();\n};\n\n/**\n * Update the room information.\n *\n * @param {boolean} [updatecache=false] should we update cache\n * @returns {Promise}\n */\nexport const updateRoom = (updatecache = false) => {\n const bbbRoomViewElement = document.getElementById('bigbluebuttonbn-room-view');\n const bbbId = bbbRoomViewElement.dataset.bbbId;\n const groupId = bbbRoomViewElement.dataset.groupId;\n return getMeetingInfo(bbbId, groupId, updatecache)\n .then(data => {\n // Just make sure we have the right information for the template.\n data.haspresentations = !!(data.presentations && data.presentations.length);\n return Templates.renderForPromise('mod_bigbluebuttonbn/room_view', data);\n })\n .then(({html, js}) => Templates.replaceNode(bbbRoomViewElement, html, js))\n .then(() => true)\n .catch((ex) => {\n displayException(ex);\n return false;\n });\n};\n"],"names":["timerReference","timerRunning","pollInterval","pollIntervalFactor","resetValues","interval","poll","clearTimeout","updateRoom","then","updateOk","setTimeout","catch","updatecache","bbbRoomViewElement","document","getElementById","bbbId","dataset","groupId","data","haspresentations","presentations","length","Templates","renderForPromise","_ref","html","js","replaceNode","ex"],"mappings":";;;;;;;uLA2BIA,eAAiB,KACjBC,cAAe,EACfC,aAAe,EACfC,mBAAqB,QAGnBC,YAAc,KAChBH,cAAe,EACfD,eAAiB,KACjBE,aAAe,EACfC,mBAAqB,kBAOHE,WAClBD,cACAH,cAAe,EACfC,aAAeG,SACfC,sBAMgB,KACZN,gBACAO,aAAaP,gBAEjBI,qBAMEE,KAAO,KACJL,cAAiBC,cAItBM,aACKC,MAAMC,WACEA,WACDP,mBAAsBA,mBAzCL,GA0CbA,mBAAqB,EA1CR,IA6CrBH,eAAiBW,YAAW,IAAML,QAAQJ,aAAeC,qBAClD,KAEVS,SASIJ,WAAa,eAACK,0EACjBC,mBAAqBC,SAASC,eAAe,6BAC7CC,MAAQH,mBAAmBI,QAAQD,MACnCE,QAAUL,mBAAmBI,QAAQC,eACpC,8BAAeF,MAAOE,QAASN,aACjCJ,MAAKW,OAEFA,KAAKC,oBAAsBD,KAAKE,gBAAiBF,KAAKE,cAAcC,QAC7DC,mBAAUC,iBAAiB,gCAAiCL,SAEtEX,MAAKiB,WAACC,KAACA,KAADC,GAAOA,gBAAQJ,mBAAUK,YAAYf,mBAAoBa,KAAMC,OACrEnB,MAAK,KAAM,IACXG,OAAOkB,iCACaA,KACV"}

View File

@ -0,0 +1,82 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Javascript module for importing presets.
*
* @module mod_bigbluebuttonbn/guest_access_modal
* @copyright 2022 Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import {get_string as getString} from 'core/str';
import ModalForm from 'core_form/modalform';
import {add as toastAdd, addToastRegion} from 'core/toast';
import {
exception as displayException,
} from 'core/notification';
const selectors = {
showGuestAccessButton: '[data-action="show-guest-access"]',
};
/**
* Intialise the object and click event to show the popup form
*
* @param {object} guestInfo
* @param {string} guestInfo.id
* @param {string} guestInfo.groupid
* @param {string} guestInfo.guestjoinurl
* @param {string} guestInfo.guestpassword
*/
export const init = (guestInfo) => {
const showGuestAccessButton = document.querySelector(selectors.showGuestAccessButton);
const modalForm = new ModalForm({
modalConfig: {
title: getString('guestaccess_title', 'mod_bigbluebuttonbn'),
large: true,
},
args: guestInfo,
saveButtonText: getString('ok', 'core_moodle'),
formClass: 'mod_bigbluebuttonbn\\form\\guest_add',
});
showGuestAccessButton.addEventListener('click', event => {
modalForm.show().then(() => {
addToastRegion(modalForm.modal.getRoot()[0]);
return true;
}).catch(displayException);
modalForm.addEventListener(modalForm.events.FORM_SUBMITTED, (e) => {
// Remove toast region as if not it will be displayed on the closed modal.
const modalElement = modalForm.modal.getRoot()[0];
const regions = modalElement.querySelectorAll('.toast-wrapper');
regions.forEach((reg) => reg.remove());
if (e.detail.result) {
if (e.detail.emailcount > 0) {
toastAdd(getString('guestaccess_invite_success', 'mod_bigbluebuttonbn', e.detail),
{
type: 'success',
}
);
}
} else {
toastAdd(getString('guestaccess_invite_failure', 'mod_bigbluebuttonbn', e.detail),
{
type: 'warning',
}
);
}
}, {once: true});
event.stopPropagation();
});
};

View File

@ -140,6 +140,9 @@ const applyInstanceTypeProfile = (profileType, isFeatureEnabled) => {
// Show lock settings validation.
showFieldset('id_lock', showAll ||
isFeatureEnabled(profileType, 'lock'));
// Show guest settings validation.
showFieldset('id_guestaccess', showAll ||
isFeatureEnabled(profileType, 'showroom'));
// Preuploadpresentation feature validation.
showFieldset('id_preuploadpresentation', showAll ||
isFeatureEnabled(profileType, 'preuploadpresentation'));

View File

@ -87,7 +87,7 @@ const poll = () => {
* @returns {Promise}
*/
export const updateRoom = (updatecache = false) => {
const bbbRoomViewElement = document.getElementById('bbb-room-view');
const bbbRoomViewElement = document.getElementById('bigbluebuttonbn-room-view');
const bbbId = bbbRoomViewElement.dataset.bbbId;
const groupId = bbbRoomViewElement.dataset.groupId;
return getMeetingInfo(bbbId, groupId, updatecache)
@ -96,7 +96,7 @@ export const updateRoom = (updatecache = false) => {
data.haspresentations = !!(data.presentations && data.presentations.length);
return Templates.renderForPromise('mod_bigbluebuttonbn/room_view', data);
})
.then(({html, js}) => Templates.replaceNodeContents(bbbRoomViewElement, html, js))
.then(({html, js}) => Templates.replaceNode(bbbRoomViewElement, html, js))
.then(() => true)
.catch((ex) => {
displayException(ex);

View File

@ -51,7 +51,8 @@ class backup_bigbluebuttonbn_activity_structure_step extends backup_activity_str
'recordings_html', 'recordings_deleted', 'recordings_imported', 'recordings_preview',
'clienttype', 'muteonstart', 'completionattendance',
'completionengagementchats', 'completionengagementtalks', 'completionengagementraisehand',
'completionengagementpollvotes', 'completionengagementemojis']);
'completionengagementpollvotes', 'completionengagementemojis',
'guestallowed', 'mustapproveuser']);
$logs = new backup_nested_element('logs');

View File

@ -117,6 +117,7 @@ class meeting_info extends external_api {
'cmid' => new external_value(PARAM_INT, 'CM id'),
'userlimit' => new external_value(PARAM_INT, 'User limit'),
'bigbluebuttonbnid' => new external_value(PARAM_RAW, 'bigbluebuttonbn instance id'),
'groupid' => new external_value(PARAM_INT, 'bigbluebuttonbn group id', VALUE_DEFAULT, 0),
'meetingid' => new external_value(PARAM_RAW, 'Meeting id'),
'openingtime' => new external_value(PARAM_INT, 'Opening time', VALUE_OPTIONAL),
'closingtime' => new external_value(PARAM_INT, 'Closing time', VALUE_OPTIONAL),
@ -140,6 +141,9 @@ class meeting_info extends external_api {
])
),
'joinurl' => new external_value(PARAM_URL, 'Join URL'),
'guestaccessenabled' => new external_value(PARAM_BOOL, 'Guest access enabled', VALUE_OPTIONAL),
'guestjoinurl' => new external_value(PARAM_URL, 'Guest URL', VALUE_OPTIONAL),
'guestpassword' => new external_value(PARAM_RAW, 'Guest join password', VALUE_OPTIONAL),
'features' => new \external_multiple_structure(
new external_single_structure([
'name' => new external_value(PARAM_ALPHA, 'Feature name.'),

View File

@ -0,0 +1,220 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_bigbluebuttonbn\form;
use context;
use core_form\dynamic_form;
use mod_bigbluebuttonbn\instance;
use mod_bigbluebuttonbn\local\exceptions\bigbluebutton_exception;
use mod_bigbluebuttonbn\task\send_guest_emails;
use moodle_exception;
use moodle_url;
use MoodleQuickForm;
/**
* Popup form to add new guests to a meeting and show/copy credential to access the guest login page.
*
* @package mod_bigbluebuttonbn
* @copyright 2022 onwards, Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @author Laurent David (laurent [at] call-learning [dt] fr)
*/
class guest_add extends dynamic_form {
/**
* Max length for credential and url fields.
*/
const MAX_INPUT_LENGTH = 35;
/**
* Process the form submission, used if form was submitted via AJAX.
*
* @return array
*/
public function process_dynamic_submission(): array {
global $USER;
$data = $this->get_data();
$allmails = [];
if (!empty($data->emails)) {
$emails = explode(',', $data->emails);
foreach ($emails as $email) {
$email = trim($email);
if (validate_email($email)) {
$allmails[] = $email;
}
}
$adhoctask = new send_guest_emails();
$adhoctask->set_custom_data(
[
'emails' => $allmails,
'useridfrom' => $USER->id
]
);
$adhoctask->set_instance_id($data->id);
\core\task\manager::queue_adhoc_task($adhoctask);
}
return [
'result' => true,
'emails' => join(', ', $allmails),
'emailcount' => count($allmails),
'errors' => ''
];
}
/**
* Perform some validation.
*
* @param array $formdata
* @param array $files
* @return array
*/
public function validation($formdata, $files): array {
$errors = [];
$emailserrors = [];
if (!empty($formdata['emails'])) {
$emails = explode(',', $formdata['emails']);
foreach ($emails as $email) {
$email = trim($email);
if (!validate_email($email)) {
$emailserrors[] .= get_string('guestaccess_emails_invalidemail', 'mod_bigbluebuttonbn', $email);
}
}
}
if (!empty($emailserrors)) {
$errors['emails'] = \html_writer::alist($emailserrors);
}
return $errors;
}
/**
* Load in existing data as form defaults (not applicable).
*
* @return void
*/
public function set_data_for_dynamic_submission(): void {
$instance = $this->get_instance_from_params();
$data = [
'id' => $instance->get_instance_id(),
'groupid' => $instance->get_group_id(),
'guestjoinurl' => $instance->get_guest_access_url(),
'guestpassword' => $instance->get_guest_access_password(),
];
$this->set_data($data);
}
/**
* Get BigblueButton instance from context params
*
* @return instance
* @throws moodle_exception
*/
protected function get_instance_from_params(): instance {
$bbid = $this->optional_param('id', null, PARAM_INT);
$groupid = $this->optional_param('groupid', null, PARAM_INT);
if (empty($bbid)) {
throw new moodle_exception('guestaccess_add_no_id', 'mod_bigbluebuttonbn');
}
$instance = instance::get_from_instanceid($bbid);
if ($groupid) {
$instance->set_group_id($groupid);
}
return $instance;
}
/**
* Form definition
*/
protected function definition() {
self::add_meeting_links_elements($this->_form);
$mform = $this->_form;
$mform->addElement('text', 'emails',
get_string('guestaccess_emails', 'mod_bigbluebuttonbn'),
);
$mform->addHelpButton('emails', 'guestaccess_emails', 'mod_bigbluebuttonbn');
$mform->setDefault('emails', '');
$mform->setType('emails', PARAM_RAW);
$mform->addElement('hidden', 'id');
$mform->setType('id', PARAM_INT);
$mform->addElement('hidden', 'groupid');
$mform->setType('groupid', PARAM_INT);
}
/**
* Add meeting links element. Helper for this form and the mod_form (module form)
*
* @param MoodleQuickForm $mform
* @return void
*/
public static function add_meeting_links_elements(MoodleQuickForm &$mform): void {
global $CFG;
MoodleQuickForm::registerElementType('text_with_copy',
"$CFG->dirroot/mod/bigbluebuttonbn/classes/form/text_with_copy_element.php",
text_with_copy_element::class);
$mform->addElement('text_with_copy', 'guestjoinurl',
get_string('guestaccess_meeting_link', 'mod_bigbluebuttonbn'),
[
'copylabel' => get_string('guestaccess_copy_link', 'mod_bigbluebuttonbn'),
'size' => self::MAX_INPUT_LENGTH,
'readonly' => 'readonly'
]
);
$mform->setType('guestjoinurl', PARAM_URL);
$mform->addElement('text_with_copy', 'guestpassword',
get_string('guestaccess_meeting_password', 'mod_bigbluebuttonbn'),
[
'copylabel' => get_string('guestaccess_copy_password', 'mod_bigbluebuttonbn'),
'readonly' => 'readonly',
'size' => self::MAX_INPUT_LENGTH,
]
);
$mform->setType('guestpassword', PARAM_RAW);
}
/**
* Check if current user has access to this form, otherwise throw exception.
*
* @return void
* @throws moodle_exception
*/
protected function check_access_for_dynamic_submission(): void {
$context = $this->get_context_for_dynamic_submission();
$instance = instance::get_from_cmid($context->instanceid);
if (!$instance->is_moderator()) {
throw new \restricted_context_exception();
}
}
/**
* Return form context
*
* @return context
*/
protected function get_context_for_dynamic_submission(): context {
$instance = $this->get_instance_from_params();
return $instance->get_context();
}
/**
* Returns url to set in $PAGE->set_url() when form is being rendered or submitted via AJAX.
*
* @return moodle_url
*/
protected function get_page_url_for_dynamic_submission(): moodle_url {
$context = $this->get_context_for_dynamic_submission();
return new moodle_url('/mod/bigbluebuttonbn/view.php', ['id' => $context->instanceid]);
}
}

View File

@ -0,0 +1,78 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_bigbluebuttonbn\form;
defined('MOODLE_INTERNAL') || die;
global $CFG;
require_once($CFG->libdir . '/formslib.php');
/**
* Guest login form.
*
* @package mod_bigbluebuttonbn
* @copyright 2022 onwards, Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @author Laurent David (laurent [at] call-learning [dt] fr)
*/
class guest_login extends \moodleform {
/**
* Form definition
*/
protected function definition() {
global $USER;
$mform = $this->_form;
$mform->addElement('text', 'username',
get_string('guestaccess_username', 'mod_bigbluebuttonbn'));
$mform->setType('username', PARAM_NOTAGS);
$mform->addRule('username',
get_string('required'), 'required', null, 'client');
if (isloggedin() && !isguestuser()) {
$mform->setConstant('username', fullname($USER));
$mform->freeze('username');
}
$mform->addElement('password', 'password',
get_string('guestaccess_password', 'mod_bigbluebuttonbn'));
$mform->setType('password', PARAM_RAW);
$mform->addRule('password',
get_string('required'), 'required', null, 'client');
$mform->addElement('hidden', 'uid', $this->_customdata['uid']);
$mform->setType('uid', PARAM_ALPHANUMEXT);
$this->add_action_buttons(false, get_string('guestaccess_join_meeting', 'mod_bigbluebuttonbn'));
}
/**
* Validate form
*
* @param array $data
* @param array $files
* @return array
* @throws \coding_exception
*/
public function validation($data, $files): array {
$errors = parent::validation($data, $files);
$instance = $this->_customdata['instance'];
if ($data['password'] != $instance->get_guest_access_password()) {
$errors['password'] = get_string('guestaccess_meeting_invalid_password', 'mod_bigbluebuttonbn');
}
return $errors;
}
}

View File

@ -0,0 +1,94 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_bigbluebuttonbn\form;
use MoodleQuickForm_text;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once("$CFG->libdir/form/text.php");
/**
* Text type form element with a copy widget
*
* Contains HTML class for a text type element and a link that will copy its content in the copy/paste buffer
*
* @package mod_bigbluebuttonbn
* @copyright 2022 onwards, Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @author Laurent David (laurent [at] call-learning [dt] fr)
*/
class text_with_copy_element extends MoodleQuickForm_text {
/**
* Accepts a renderer
*
* @param object $renderer An HTML_QuickForm_Renderer object
* @param bool $required Whether an element is required
* @param string $error An error message associated with an element
* @return void
*/
public function accept(&$renderer, $required = false, $error = null) {
global $OUTPUT;
$elementname = $this->getName();
// Make sure the element has an id.
$this->_generateId();
$advanced = isset($renderer->_advancedElements[$elementname]);
$elementcontext = $this->export_for_template($OUTPUT);
$helpbutton = '';
if (method_exists($this, 'getHelpButton')) {
$helpbutton = $this->getHelpButton();
}
$label = $this->getLabel();
$text = '';
if (method_exists($this, 'getText')) {
// There currently exists code that adds a form element with an empty label.
// If this is the case then set the label to the description.
if (empty($label)) {
$label = $this->getText();
} else {
$text = $this->getText();
}
}
$context = array(
'element' => $elementcontext,
'label' => $label,
'text' => $text,
'required' => $required,
'advanced' => $advanced,
'helpbutton' => $helpbutton,
'error' => $error,
'copylabel' => $this->_attributes['copylabel'] ?? get_string('copy', 'core_editor')
);
$html = $OUTPUT->render_from_template('mod_bigbluebuttonbn/element_text_with_copy', $context);
if ($renderer->_inGroup) {
$this->_groupElementTemplate = $html;
}
if (($renderer->_inGroup) && !empty($renderer->_groupElementTemplate)) {
$renderer->_groupElementTemplate = $html;
} else if (!isset($renderer->_templates[$elementname])) {
$renderer->_templates[$elementname] = $html;
}
if (in_array($elementname, $renderer->_stopFieldsetElements) && $renderer->_fieldsetsOpen > 0) {
$renderer->_html .= $renderer->_closeFieldsetTemplate;
$renderer->_fieldsetsOpen--;
}
$renderer->_html .= $html;
}
}

View File

@ -536,7 +536,6 @@ EOF;
*/
public function get_user(): stdClass {
global $USER;
return $USER;
}
@ -547,8 +546,7 @@ EOF;
*/
public function get_user_id(): int {
$user = $this->get_user();
return $user->id;
return $user->id ?? 0;
}
/**
@ -558,7 +556,6 @@ EOF;
*/
public function get_user_fullname(): string {
$user = $this->get_user();
return fullname($user);
}
@ -763,6 +760,16 @@ EOF;
return (bool) $this->get_instance_var('record');
}
/**
* Moderator approval required ?
*
* By default we leave it as false as "ALWAYS_ACCEPT" is the default value for
* the guestPolicy create parameter (https://docs.bigbluebutton.org/dev/api.html)
* @return bool
*/
public function is_moderator_approval_required(): bool {
return $this->get_instance_var('mustapproveuser') ?? false;
}
/**
* Whether this instance can import recordings from another instance.
*
@ -1170,4 +1177,54 @@ EOF;
}
return true;
}
/**
* Get current guest link url
*
* @return moodle_url
*/
public function get_guest_access_url(): moodle_url {
$guestlinkuid = $this->get_instance_var('guestlinkuid');
if (empty($guestlinkuid)) {
$this->generate_guest_credentials();
$guestlinkuid = $this->get_instance_var('guestlinkuid');
}
return new moodle_url('/mod/bigbluebuttonbn/guest.php', ['uid' => $guestlinkuid]);
}
/**
* Is guest access allowed in this instance.
*
* @return bool
*/
public function is_guest_allowed(): bool {
return !$this->is_type_recordings_only() &&
config::get('guestaccess_enabled') && $this->get_instance_var('guestallowed');
}
/**
* Get current meeting password
*
* @return string
*/
public function get_guest_access_password() : string {
$guestpassword = $this->get_instance_var('guestpassword');
if (empty($guestpassword)) {
$this->generate_guest_credentials();
$guestpassword = $this->get_instance_var('guestpassword');
}
return $guestpassword;
}
/**
* Generate credentials for this instance and persist the value in the database
*
* @return void
*/
private function generate_guest_credentials():void {
global $DB;
[$this->instancedata->guestlinkuid, $this->instancedata->guestpassword] =
\mod_bigbluebuttonbn\plugin::generate_guest_meeting_credentials();
$DB->update_record('bigbluebuttonbn', $this->instancedata);
}
}

View File

@ -218,6 +218,7 @@ class config {
'welcome_default' => self::get('welcome_default'),
'welcome_editable' => self::get('welcome_editable'),
'poll_interval' => self::get('poll_interval'),
'guestaccess_enabled' => self::get('guestaccess_enabled'),
];
}

View File

@ -59,7 +59,7 @@ class bigbluebutton_proxy extends proxy_base {
* @param string $logouturl
* @param string $role
* @param string|null $configtoken
* @param string|null $userid
* @param int $userid
* @param string|null $createtime
*
* @return string
@ -71,9 +71,9 @@ class bigbluebutton_proxy extends proxy_base {
string $logouturl,
string $role,
string $configtoken = null,
string $userid = null,
int $userid = 0,
string $createtime = null
): ?string {
): string {
$data = [
'meetingID' => $meetingid,
'fullName' => $username,
@ -86,8 +86,11 @@ class bigbluebutton_proxy extends proxy_base {
$data['configToken'] = $configtoken;
}
if (!is_null($userid)) {
if (!empty($userid)) {
$data['userID'] = $userid;
$data['guest'] = "false";
} else {
$data['guest'] = "true";
}
if (!is_null($createtime)) {

View File

@ -192,7 +192,7 @@ class meeting {
*
* @return string
*/
public function get_join_url() {
public function get_join_url(): string {
return bigbluebutton_proxy::get_join_url(
$this->instance->get_meeting_id(),
$this->instance->get_user_fullname(),
@ -205,6 +205,26 @@ class meeting {
);
}
/**
* Get meeting join URL for guest
*
* @param string $fullname
* @return string
*/
public function get_guest_join_url(string $fullname): string {
return bigbluebutton_proxy::get_join_url(
$this->instance->get_meeting_id(),
$fullname,
$this->instance->get_current_user_password(),
$this->instance->get_guest_access_url()->out(false),
$this->instance->get_current_user_role(),
null,
0,
$this->get_meeting_info()->createtime
);
}
/**
* Return meeting information for this meeting.
*
@ -281,9 +301,13 @@ class meeting {
$meetinginfo->attendees[] = (array) $attendee;
}
}
$meetinginfo->guestaccessenabled = $instance->is_guest_allowed();
if ($meetinginfo->guestaccessenabled && $instance->is_moderator()) {
$meetinginfo->guestjoinurl = $instance->get_guest_access_url()->out();
$meetinginfo->guestpassword = $instance->get_guest_access_password();
}
$meetinginfo->features = $instance->get_enabled_features();
return $meetinginfo;
}
@ -390,6 +414,11 @@ class meeting {
if ($this->instance->get_mute_on_start()) {
$data['muteOnStart'] = 'true';
}
// Here a bit of a change compared to the API default behaviour: we should not allow guest to join
// a meeting managed by Moodle by default.
if ($this->instance->is_guest_allowed()) {
$data['guestPolicy'] = $this->instance->is_moderator_approval_required() ? 'ASK_MODERATOR' : 'ALWAYS_ACCEPT';
}
// Locks settings.
foreach (self::LOCK_SETTINGS_MEETING_DATA as $instancevarname => $lockname) {
$instancevar = $this->instance->get_instance_var($instancevarname);
@ -513,18 +542,17 @@ class meeting {
}
/**
* Join a meeting.
* Prepare join meeting action
*
* @param int $origin The spec
* @return string The URL to redirect to
* @throws meeting_join_exception
* @param int $origin
* @return void
*/
public function join(int $origin): string {
protected function prepare_meeting_join_action(int $origin) {
$this->do_get_meeting_info(true);
if ($this->is_running()) {
if (
$this->instance->has_user_limit_been_reached($this->get_participant_count())
&& $this->instance->does_current_user_count_towards_user_limit()
$this->instance->has_user_limit_been_reached($this->get_participant_count())
&& $this->instance->does_current_user_count_towards_user_limit()
) {
throw new meeting_join_exception('userlimitreached');
}
@ -538,6 +566,29 @@ class meeting {
// Before executing the redirect, increment the number of participants.
roles::participant_joined($this->instance->get_meeting_id(), $this->instance->is_moderator());
}
/**
* Join a meeting.
*
* @param int $origin The spec
* @return string The URL to redirect to
* @throws meeting_join_exception
*/
public function join(int $origin): string {
$this->prepare_meeting_join_action($origin);
return $this->get_join_url();
}
/**
* Join a meeting as a guest.
*
* @param int $origin The spec
* @param string $userfullname Fullname for the guest user
* @return string The URL to redirect to
* @throws meeting_join_exception
*/
public function guest_join(int $origin, string $userfullname): string {
$this->prepare_meeting_join_action($origin);
return $this->get_join_url();
}
}

View File

@ -65,4 +65,15 @@ abstract class plugin {
} while ($unique == $password);
return $password;
}
/**
* Generate random credentials for guest access
*
* @return array
*/
public static function generate_guest_meeting_credentials(): array {
$password = self::random_password();
$guestlinkuid = sha1(self::random_password(1024));
return [$guestlinkuid, $password];
}
}

View File

@ -907,6 +907,18 @@ class settings {
$item,
$experimentalfeaturessetting
);
// UI for 'register meeting events' feature.
$item = new admin_setting_configcheckbox(
'bigbluebuttonbn_guestaccess_enabled',
get_string('config_guestaccess_enabled', 'bigbluebuttonbn'),
get_string('config_guestaccess_enabled_description', 'bigbluebuttonbn'),
0
);
$this->add_conditional_element(
'guestaccess_enabled',
$item,
$experimentalfeaturessetting
);
}
$this->admin->add($this->parent, $experimentalfeaturessetting);
}

View File

@ -0,0 +1,109 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_bigbluebuttonbn\task;
use core_user;
use html_writer;
/**
* This adhoc task will send emails to guest users with the meeting's details
*
* @package mod_bigbluebuttonbn
* @copyright 2022 onwards, Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @author Laurent David (laurent [at] call-learning [dt] fr)
*/
class send_guest_emails extends send_notification {
/**
* Get the notification type.
*
* @return string
*/
protected function get_notification_type(): string {
return 'guest_invited';
}
/**
* Send all the emails
*/
protected function send_all_notifications(): void {
$customdata = $this->get_custom_data();
if (!empty($customdata->emails)) {
foreach ($customdata->emails as $email) {
$user = core_user::get_noreply_user();
$user->email = $email;
$user->mailformat = 1; // HTML format.
email_to_user(
$user,
core_user::get_noreply_user(),
$this->get_subject(),
$this->get_small_message(),
$this->get_html_message()
);
}
}
}
/**
* Get the subject of the notification.
*
* @return string
*/
protected function get_subject(): string {
return get_string('guest_invitation_subject', 'mod_bigbluebuttonbn', $this->get_string_vars());
}
/**
* Get variables to make available to strings.
*
* @return array
*/
protected function get_string_vars(): array {
$customdata = $this->get_custom_data();
$sender = core_user::get_user($customdata->useridfrom);
return [
'course_fullname' => $this->get_instance()->get_course()->fullname,
'course_shortname' => $this->get_instance()->get_course()->shortname,
'name' => $this->get_instance()->get_cm()->name,
'guestjoinurl' => $this->get_instance()->get_guest_access_url()->out(false),
'guestpassword' => $this->get_instance()->get_guest_access_password(),
'sender' => fullname($sender)
];
}
/**
* Get the short summary message.
*
* @return string
*/
protected function get_small_message(): string {
return get_string('guest_invitation_small_message', 'mod_bigbluebuttonbn', $this->get_string_vars());
}
/**
* Get the HTML message content.
*
* @return string
*/
protected function get_html_message(): string {
return html_writer::tag(
'p',
get_string('guest_invitation_full_message', 'mod_bigbluebuttonbn', $this->get_string_vars())
);
}
}

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="mod/bigbluebuttonbn/db" VERSION="20220804" COMMENT="XMLDB file for Moodle mod/bigbluebuttonbn"
<XMLDB PATH="mod/bigbluebuttonbn/db" VERSION="20210909" COMMENT="XMLDB file for Moodle mod/bigbluebuttonbn"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
>
@ -47,6 +47,10 @@
<FIELD NAME="completionengagementraisehand" TYPE="int" LENGTH="9" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Nonzero if raising hand during the meeting is required to mark an activity completed for a user."/>
<FIELD NAME="completionengagementpollvotes" TYPE="int" LENGTH="9" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Nonzero if poll voting during the meeting is required to mark an activity completed for a user."/>
<FIELD NAME="completionengagementemojis" TYPE="int" LENGTH="9" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Nonzero if the use of emojis during the meeting is required to mark an activity completed for a user."/>
<FIELD NAME="guestallowed" TYPE="int" LENGTH="2" NOTNULL="false" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="mustapproveuser" TYPE="int" LENGTH="2" NOTNULL="false" DEFAULT="1" SEQUENCE="false"/>
<FIELD NAME="guestlinkuid" TYPE="char" LENGTH="1024" NOTNULL="false" SEQUENCE="false"/>
<FIELD NAME="guestpassword" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>

View File

@ -452,6 +452,34 @@ function xmldb_bigbluebuttonbn_upgrade($oldversion = 0) {
// Bigbluebuttonbn savepoint reached.
upgrade_mod_savepoint(true, 2022080400, 'bigbluebuttonbn');
}
if ($oldversion < 2022101900) {
$table = new xmldb_table('bigbluebuttonbn');
$field = new xmldb_field('guestallowed', XMLDB_TYPE_INTEGER, '2', null, null, null, '0', 'completionengagementemojis');
// Conditionally launch add field guestallowed.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
$field = new xmldb_field('mustapproveuser', XMLDB_TYPE_INTEGER, '2', null, null, null, '1', 'guestallowed');
// Conditionally launch add field mustapproveuser.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
$field = new xmldb_field('guestlinkuid', XMLDB_TYPE_CHAR, '1024', null, null, null, null, 'mustapproveuser');
// Conditionally launch add field guestlinkuid.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
$field = new xmldb_field('guestpassword', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'guestlinkuid');
// Conditionally launch add field guestpassword.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
upgrade_mod_savepoint(true, 2022101900, 'bigbluebuttonbn');
}
return true;
}

View File

@ -0,0 +1,80 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Guest access implementation
*
* @package mod_bigbluebuttonbn
* @copyright 2022 onwards, Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @author Laurent David (laurent [at] call-learning [dt] fr)
*/
use mod_bigbluebuttonbn\form\guest_login;
use mod_bigbluebuttonbn\local\exceptions\server_not_available_exception;
use mod_bigbluebuttonbn\local\proxy\bigbluebutton_proxy;
use mod_bigbluebuttonbn\meeting;
use mod_bigbluebuttonbn\plugin;
require(__DIR__.'/../../config.php');
global $PAGE, $OUTPUT, $DB, $SITE;
// Still run through basic setup of the page.
require_course_login($SITE);
$uid = required_param('uid', PARAM_ALPHANUMEXT);
$bbid = $DB->get_field('bigbluebuttonbn', 'id', ['guestlinkuid' => trim($uid)]);
if (empty($bbid)) {
throw new moodle_exception('guestaccess_activitynotfound', 'mod_bigbluebuttonbn');
}
$instance = \mod_bigbluebuttonbn\instance::get_from_instanceid($bbid);
// Prevent access to this page if the guest access has been disabled on this instance.
if (!$instance->is_guest_allowed()) {
throw new moodle_exception('guestaccess_feature_disabled', 'mod_bigbluebuttonbn');
}
// Get the guest matching guest access link.
$PAGE->set_url('/mod/bigbluebuttonbn/guest.php', ['uid' => $uid]);
$title = $instance->get_course()->shortname . ': ' . format_string($instance->get_meeting_name());
$PAGE->set_title($title);
$PAGE->set_heading($title);
$PAGE->set_pagelayout('standard');
$form = new guest_login(null, ['uid' => $uid, 'instance' => $instance]);
// Specific for the tests: we allow to set the password in the form here.
if (defined('BEHAT_SITE_RUNNING')) {
$form->set_data(['password' => optional_param('password', '', PARAM_RAW)]);
}
if ($data = $form->get_data()) {
$username = $data->username;
try {
$meeting = new meeting($instance);
// As the meeting doesn't exist, we raise an exception.
if (!empty($meeting->get_meeting_info()->createtime)) {
$url = $meeting->get_guest_join_url($username);
redirect($url);
} else {
\core\notification::add(
get_string('guestaccess_meeting_not_started', 'mod_bigbluebuttonbn'),
\core\output\notification::NOTIFY_ERROR
);
}
} catch (server_not_available_exception $e) {
bigbluebutton_proxy::handle_server_not_available($instance);
}
}
echo $OUTPUT->header();
echo $form->render();
echo $OUTPUT->footer();

View File

@ -48,7 +48,8 @@ $string['bigbluebuttondisablednotification_subject'] = 'BigBlueButton activity m
$string['bigbluebuttondisablednotification'] = 'The BigBlueButton activity module has been disabled and any existing BigBlueButton course activities are currently not accessible. Prior to re-enabling this plugin, please ensure that you have read and accepted the <a href="{$a}" target="_blank">data processing agreement</a> with Blindside Networks Inc.';
$string['cannotperformaction'] = 'Cannot perform action {$a} on this recording';
$string['enablingbigbluebutton'] = 'Enabling BigBlueButton activity';
$string['enablingbigbluebuttondpainfo'] = 'In order to meet your data protection obligations, before enabling this plugin, you must confirm that you have read and accepted the <a href="{$a}" target="_blank">Blindside Networks data processing agreement</a>. Please consult with your own privacy professionals for advice.';
$string['enablingbigbluebuttondpainfo'] = 'In order to meet your data protection obligations, prior to enabling this plugin, you may need to ensure that you have read and accepted the <a href="{$a}" target="_blank">data processing agreement</a> with Blindside Networks Inc.<br/>
Please consult with your own privacy professionals for advice.';
$string['indicator:cognitivedepth'] = 'BigBlueButton cognitive';
$string['indicator:cognitivedepth_help'] = 'This indicator is based on the cognitive depth reached by the student in a BigBlueButton activity.';
$string['indicator:socialbreadth'] = 'BigBlueButton social';
@ -130,6 +131,10 @@ $string['minute'] = 'minute';
$string['minutes'] = 'minutes';
$string['config_dpa_note'] = 'Note: In order to meet your data protection obligations, before using a service provider for this plugin, you must ensure that you have read and accepted the service provider\'s data processing agreement. For the default free BigBlueButton service, this is the <a href="{$a}" target="_blank">Blindside Networks data processing agreement</a>. Please consult with your own privacy professionals for advice.';
$string['config_guestaccess_enabled'] = 'Create guest access link for external guests.';
$string['config_guestaccess_enabled_description'] = 'You can use the guest access link to invite external guests who do not have a Moodle account to this conference room.';
$string['config_general'] = 'General settings';
$string['config_general_description'] = 'These settings are always used.';
$string['config_server_url'] = 'BigBlueButton server URL';
@ -300,6 +305,42 @@ $string['general_error_not_allowed_to_create_instances'] = 'User is not allowed
$string['general_error_not_found'] = 'Cannot find the BigBlueButton activity ({$a}).';
$string['general_error_cannot_create_meeting'] = 'Cannot create session.';
$string['general_error_cannot_get_recordings'] = 'Cannot get recordings.';
$string['guestaccess_add'] = 'Add guests';
$string['guestaccess_add_no_id'] = 'No bigbluebutton instance ID provided.';
$string['guestaccess_emails'] = 'Add guests emails';
$string['guestaccess_emails_help'] = 'Emails of users you want to invite, separated by commas';
$string['guestaccess_emails_invalidemail'] = 'The email {$a} is invalid, please correct it.';
$string['guestaccess_username'] = 'Guest username';
$string['guestaccess_meeting_link'] = 'Meeting link';
$string['guestaccess_meeting_password'] = 'Meeting password';
$string['guestaccess_password'] = 'Password';
$string['guestaccess_meeting_not_started'] = 'Sorry, the meeting has not started yet. Please try again later.';
$string['guestaccess_meeting_invalid_password'] = 'Incorrect password.';
$string['guestaccess_activitynotfound'] = 'The BigblueButton activity is not found for this access as guest. Contact your
support.';
$string['guestaccess_feature_disabled'] = 'Guest access: feature is disabled.';
$string['guestaccess_title'] = 'Add guests to this meeting';
$string['guestaccess_copy_link'] = 'Copy link';
$string['guestaccess_copy_password'] = 'Copy password';
$string['guestaccess_invite_success'] = 'An invitation will be sent to guest(s) {$a->emails} via email.';
$string['guestaccess_invite_failure'] = 'Error {$a->errors} when inviting guests {$a->emails}, please contact your support.';
$string['guestaccess_join_meeting'] = 'Join meeting';
$string['guest_invitation_subject'] = 'You have been invited to the session {$a->name} on {$a->course_fullname} !';
$string['guest_invitation_small_message'] = 'Hi,
You have been invited as a guest to a BigblueButton session "{$a->name}" on "{$a->course_fullname}" course.
You can join the session by following the link here : {$a->guestjoinurl}.
You will then be prompted for your name and the following password: "{$a->guestpassword}".
If you need help, please contact {$a->sender}.
';
$string['guest_invitation_full_message'] = 'Hi,
<p>You have been invited as a guest to a BigblueButton session "{$a->name}" on "{$a->course_fullname}" course.</p>
<p>You can join the session by <a href="{$a->guestjoinurl}"> following the link here</a>.
You will then be prompted for your name and the following password: "{$a->guestpassword}".</p>
<p>If you need help, please contact {$a->sender}.</p>';
$string['index_confirm_end'] = 'Do you want to end the session?';
$string['index_disabled'] = 'disabled';
$string['index_enabled'] = 'enabled';
@ -317,6 +358,7 @@ $string['index_heading_viewer'] = 'Viewers';
$string['index_heading'] = 'BigBlueButton rooms';
$string['instanceprofilewithoutrecordings'] = 'This instance profile cannot display recordings';
$string['mod_form_block_general'] = 'General';
$string['mod_form_block_guestaccess'] = 'Guest access';
$string['mod_form_block_room'] = 'Room settings';
$string['mod_form_block_recordings'] = 'Recording view';
$string['mod_form_block_presentation'] = 'Presentation content';
@ -330,6 +372,8 @@ $string['mod_form_field_intro'] = 'Description';
$string['mod_form_field_intro_help'] = 'A short description of the room.';
$string['mod_form_field_duration_help'] = 'Setting the duration for a meeting will establish the maximum time for a meeting to keep alive before the recording finish';
$string['mod_form_field_duration'] = 'Duration';
$string['mod_form_field_guestallowed'] = 'Allow guest access in the meeting';
$string['mod_form_field_mustapproveuser'] = 'User must be approved by moderators';
$string['mod_form_field_userlimit'] = 'User limit';
$string['mod_form_field_userlimit_help'] = 'The maximum number of users allowed in a session. Set to 0 to allow an unlimited number of users.';
$string['mod_form_field_name'] = 'Room name';
@ -443,18 +487,18 @@ $string['view_message_notavailableyet'] = 'This session is not yet available.';
$string['view_recording_select_course'] = 'Select a course first in the drop down menu';
$string['view_message_session_started_at'] = 'This session started at';
$string['view_message_session_started_at'] = 'Session started at';
$string['view_message_session_running_for'] = 'This session has been running for';
$string['view_message_hour'] = 'hour';
$string['view_message_hours'] = 'hours';
$string['view_message_minute'] = 'minute';
$string['view_message_minutes'] = 'minutes';
$string['view_message_moderator'] = 'moderator';
$string['view_message_moderators'] = 'moderators';
$string['view_message_viewer'] = 'viewer';
$string['view_message_viewers'] = 'viewers';
$string['view_message_user'] = 'user';
$string['view_message_users'] = 'users';
$string['view_message_moderator'] = 'Moderator';
$string['view_message_moderators'] = 'Moderators';
$string['view_message_viewer'] = 'Viewer';
$string['view_message_viewers'] = 'Viewers';
$string['view_message_user'] = 'User';
$string['view_message_users'] = 'Users';
$string['view_message_has_joined'] = 'has joined';
$string['view_message_have_joined'] = 'have joined';
$string['view_message_session_no_users'] = 'There are no users in this session';

View File

@ -99,6 +99,8 @@ function bigbluebuttonbn_add_instance($bigbluebuttonbn) {
$bigbluebuttonbn->presentation = files::save_media_file($bigbluebuttonbn);
// Encode meetingid.
$bigbluebuttonbn->meetingid = meeting::get_unique_meetingid_seed();
[$bigbluebuttonbn->guestlinkuid, $bigbluebuttonbn->guestpassword] =
\mod_bigbluebuttonbn\plugin::generate_guest_meeting_credentials();
// Insert a record.
$bigbluebuttonbn->id = $DB->insert_record('bigbluebuttonbn', $bigbluebuttonbn);
// Log insert action.
@ -125,6 +127,10 @@ function bigbluebuttonbn_update_instance($bigbluebuttonbn) {
$bigbluebuttonbn->id = $bigbluebuttonbn->instance;
$bigbluebuttonbn->presentation = files::save_media_file($bigbluebuttonbn);
if (empty($bigbluebuttonbn->guestjoinurl) || empty($bigbluebuttonbn->guestpassword)) {
[$bigbluebuttonbn->guestlinkuid, $bigbluebuttonbn->guestpassword] =
\mod_bigbluebuttonbn\plugin::generate_guest_meeting_credentials();
}
// Update a record.
$DB->update_record('bigbluebuttonbn', $bigbluebuttonbn);

View File

@ -24,6 +24,7 @@
* @author Fred Dixon (ffdixon [at] blindsidenetworks [dt] com)
*/
use mod_bigbluebuttonbn\instance;
use mod_bigbluebuttonbn\local\helpers\roles;
use mod_bigbluebuttonbn\local\proxy\bigbluebutton_proxy;
@ -80,6 +81,8 @@ class mod_bigbluebuttonbn_mod_form extends moodleform_mod {
$this->bigbluebuttonbn_mform_add_block_preuploads($mform, $cfg);
// Add block 'Participant List'.
$this->bigbluebuttonbn_mform_add_block_user_role_mapping($mform, $participantlist);
// Add block 'Guest Access'.
$this->bigbluebuttonbn_mform_add_block_guest_access($mform, $cfg, $this->current);
// Add block 'Schedule'.
$this->bigbluebuttonbn_mform_add_block_schedule($mform, $this->current);
// Add standard elements, common to all modules.
@ -597,6 +600,42 @@ class mod_bigbluebuttonbn_mod_form extends moodleform_mod {
get_string('mod_form_field_participant_list', 'bigbluebuttonbn'), $html);
}
/**
* Function to add guest acces settings to the instance
*
* @param MoodleQuickForm $mform
* @param array $cfg
* @param stdClass $current
* @return void
* @throws coding_exception
*/
private function bigbluebuttonbn_mform_add_block_guest_access(MoodleQuickForm $mform, array $cfg, stdClass $current) {
if (!empty($cfg['guestaccess_enabled'])) {
$mform->addElement('header', 'guestaccess', get_string('mod_form_block_guestaccess', 'bigbluebuttonbn'));
$mform->setExpanded('guestaccess');
$mform->addElement('advcheckbox', 'guestallowed',
get_string('mod_form_field_guestallowed', 'bigbluebuttonbn'));
$mform->addElement('advcheckbox', 'mustapproveuser',
get_string('mod_form_field_mustapproveuser', 'bigbluebuttonbn'));
$mform->hideIf('mustapproveuser', 'guestallowed');
if (!empty($this->_cm)) {
$instance = instance::get_from_cmid($this->_cm->id);
\mod_bigbluebuttonbn\form\guest_add::add_meeting_links_elements($mform);
$mform->setDefault('guestjoinurl', $instance->get_guest_access_url());
$mform->setDefault('guestpassword', $instance->get_guest_access_password());
$mform->hideIf('guestjoinurl', 'guestallowed');
$mform->hideIf('guestpassword', 'guestallowed');
}
} else {
$mform->addElement('hidden', 'guestallowed', 0);
$mform->addElement('hidden', 'mustapproveuser', 0);
}
$mform->setType('guestallowed', PARAM_BOOL);
$mform->setType('mustapproveuser', PARAM_BOOL);
$mform->setDefault('guestallowed', 0);
$mform->setDefault('mustapproveuser', 1);
}
/**
* Function for showing the block for integration with the calendar.
*

View File

@ -34,3 +34,12 @@
.bbb_index_form {
display: inline-block;
}
.bigbluebuttonbn_icon_btn i.icon {
margin-right: auto;
}
/* Disable gray background for text input */
input.form-control[readonly][name="guestpassword"],
input.form-control[readonly][name="guestjoinurl"] {
background: initial;
}

View File

@ -0,0 +1,71 @@
{{!
This file is part of Moodle - http://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template mod_bigbluebuttonbn/text_with-copy
This template renders a text input form element with a copy link next to it.
Context variables required for this template:
* label
* required
* advanced
* helpbutton
* error
* element
* id
* name
Example context (json):
{
"label": "Course full name",
"required": true,
"advanced": false,
"error": null,
"element": {
"wrapperid": "fitem_id_fullname",
"id": "id_fullname",
"name": "fullname",
"iderror": "id_error"
}
}
}}
{{< core_form/element-template }}
{{$element}}
<input type="text"
class="form-control {{#error}}is-invalid{{/error}}"
name="{{element.name}}"
{{#element.frozen}}
readonly {{#element.hardfrozen}}disabled{{/element.hardfrozen}}
{{/element.frozen}}
id="{{element.id}}"
value="{{element.value}}"
{{#element.size}}size="{{element.size}}"{{/element.size}}
{{#error}}
autofocus aria-describedby="{{element.iderror}}"
{{/error}}
{{{element.attributes}}} >
<button id="{{element.id}}-button"
data-action="copytoclipboard" data-clipboard-target="#{{element.id}}"
data-clipboard-success-message="{{#str}}success{{/str}}"
class="btn btn-link bigbluebuttonbn_icon_btn bigbluebuttonbn_cp_info_btn">
{{#pix}}t/copy, core{{/pix}} {{copylabel}}
</button>
{{/element}}
{{/ core_form/element-template }}
{{#js}}
require(['core/copy_to_clipboard']);
{{/js}}

View File

@ -34,7 +34,7 @@
}} data-action="end"{{!
}} data-bbb-id="{{bigbluebuttonbnid}}"{{!
}} data-group-id="{{groupid}}"{{!
}} class="btn btn-secondary bbb-btn-action"{{!
}} class="btn btn-outline-dark bbb-btn-action m-1"{{!
}}>
{{#str}}view_conference_action_end, mod_bigbluebuttonbn{{/str}}
</a>

View File

@ -0,0 +1,41 @@
{{!
This file is part of Moodle - http://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template mod_bigbluebuttonbn/guest_links
This template renders the mobile page.
Example context (json):
{
"guestaccessenabled": 1,
"guestjoinurl": "http://moodle.org/",
"guestpassword": "password"
}
}}
{{#guestaccessenabled}}
<button class="btn btn-link m-1" type="button" data-action="show-guest-access">
{{#pix}}t/add, core{{/pix}}{{#str}}guestaccess_add, mod_bigbluebuttonbn{{/str}}
</button>
{{/guestaccessenabled}}
{{#js}}
require(['mod_bigbluebuttonbn/guest_access_modal'], function(GuestLinkAccess) {
GuestLinkAccess.init({
id: "{{ bigbluebuttonbnid }}",
groupid: "{{ groupid }}"
});
});
{{/js}}

View File

@ -21,6 +21,8 @@
Example context (json):
{
"bigbluebuttonbnid": 1,
"groupid": 0,
"statusclosed": true,
"statusclosed": false,
"openingtime": 123456789,
@ -28,71 +30,86 @@
}
}}
<div id="bbb-room-view" class="box py-3 generalbox boxaligncenter" data-bbb-id="{{bigbluebuttonbnid}}"
<div id="bigbluebuttonbn-room-view" class="box py-3 generalbox boxaligncenter d-flex flex-column flex-md-row" data-bbb-id="{{bigbluebuttonbnid}}"
data-group-id="{{groupid}}">
<span id="status_bar">
<span class="status-message">{{statusmessage}}</span>
<span class="conf-opening-time">
{{#openingtime}}
<span class="conf-opening">
{{#str}}mod_form_field_openingtime, bigbluebuttonbn{{/str}}:
{{#userdate}} {{.}}, {{#str}} strftimedaydatetime, langconfig {{/str}} {{/userdate}}
</span>
{{/openingtime}}
{{#closingtime}}
<span class="conf-closing">
{{#str}}mod_form_field_closingtime, bigbluebuttonbn{{/str}}:
{{#userdate}} {{.}}, {{#str}} strftimedaydatetime, langconfig {{/str}} {{/userdate}}
</span>
{{/closingtime}}
</span>
{{#statusrunning}}
<div>
<span>{{#str}}view_message_session_started_at, mod_bigbluebuttonbn{{/str}}</span>
<strong>{{#userdate}} {{startedat}}, {{#str}} strftimetime, core_langconfig{{/str}} {{/userdate}}</strong>
<span>
{{#moderatorplural}}{{#str}}view_message_moderators, mod_bigbluebuttonbn{{/str}}{{/moderatorplural}}
{{^moderatorplural}}{{#str}}view_message_moderator, mod_bigbluebuttonbn{{/str}}{{/moderatorplural}}
<strong>{{moderatorcount}}</strong>
</span>
<span>
{{#viewerplural}}{{#str}}view_message_viewers, mod_bigbluebuttonbn{{/str}}{{/viewerplural}}
{{^viewerplural}}{{#str}}view_message_viewer, mod_bigbluebuttonbn{{/str}}{{/viewerplural}}
<strong>{{participantcount}}</strong>.
</span>
</div>
{{/statusrunning}}
</span>
<div id="room_view_control_panel" data-bbb-id="{{bigbluebuttonbnid}}">
{{#haspresentations}}
<h4>{{#str}}view_section_title_presentation, mod_bigbluebuttonbn{{/str}}</h4>
<div class="list-group list-group-flush">
{{#presentations}}
<a href="{{url}}" target="_blank" class="list-group-item list-group-item-action">
{{#pix}}{{iconname}},core, {{icondesc}}{{/pix}}
{{name}}
</a>
{{/presentations}}
<div id="bigbluebuttonbn-information">
<div id="bigbluebuttonbn-status-bar" class="text-wrap">
{{#statusrunning}}
<div>
<span class="font-weight-bold">{{#str}}view_message_session_started_at, mod_bigbluebuttonbn{{/str}}:</span>
<span>{{#userdate}} {{startedat}}, {{#str}} strftimetime, core_langconfig{{/str}} {{/userdate}}.</span>
<span class="status-message">{{statusmessage}}</span>
</div>
{{/statusrunning}}
{{^statusrunning}}
<div class="status-message">{{statusmessage}}</div>
{{/statusrunning}}
<div class="conf-opening-time">
{{#openingtime}}
<span class="conf-opening">
<span class="font-weight-bold">{{#str}}mod_form_field_openingtime, bigbluebuttonbn{{/str}}:</span>
{{#userdate}} {{.}}, {{#str}} strftimedaydatetime, langconfig {{/str}} {{/userdate}}
</span>
{{/openingtime}}
{{#closingtime}}
<div class="conf-closing">
<span class="font-weight-bold">{{#str}}mod_form_field_closingtime, bigbluebuttonbn{{/str}}:</span>
{{#userdate}} {{.}}, {{#str}} strftimedaydatetime, langconfig {{/str}} {{/userdate}}
</div>
{{/closingtime}}
</div>
{{/haspresentations}}
{{#statusrunning}}
<div>
<span class="font-weight-bold">
{{#moderatorplural}}{{#str}}view_message_moderators, mod_bigbluebuttonbn{{/str}}{{/moderatorplural}}
{{^moderatorplural}}{{#str}}view_message_moderator, mod_bigbluebuttonbn{{/str}}{{/moderatorplural}}:
</span>
<span>{{moderatorcount}}</span>
</div>
<div>
<span class="font-weight-bold">
{{#viewerplural}}{{#str}}view_message_viewers, mod_bigbluebuttonbn{{/str}}{{/viewerplural}}
{{^viewerplural}}{{#str}}view_message_viewer, mod_bigbluebuttonbn{{/str}}{{/viewerplural}}:
</span>
<span>{{participantcount}}</span>
</div>
{{/statusrunning}}
</div>
<div id="bigbluebuttonbn-room-view-control-panel" data-bbb-id="{{bigbluebuttonbnid}}" class="mt-2">
{{#haspresentations}}
<h5>{{#str}}view_section_title_presentation, mod_bigbluebuttonbn{{/str}}</h5>
<div class="list-group list-group-flush">
{{#presentations}}
<a href="{{url}}" target="_blank" class="list-group-item list-group-item-action">
{{#pix}}{{iconname}},core, {{icondesc}}{{/pix}}
{{name}}
</a>
{{/presentations}}
</div>
{{/haspresentations}}
</div>
</div>
<div id="bigbluebuttonbn_view_action_button_box" class="box py-3 generalbox boxaligncenter">
<div id="room_view_action_buttons">
<div id="bigbluebuttonbn-view-action-button-box" class="mt-0 ml-auto mr-auto mr-md-0">
<div id="bigbluebuttonbn-room-view-action-buttons"
class="d-flex flex-column-reverse flex-md-row">
{{#ismoderator}}
{{> mod_bigbluebuttonbn/guest_links}}
{{/ismoderator}}
{{#ismoderator}}
{{> mod_bigbluebuttonbn/end_session_button}}
{{/ismoderator}}
{{#canjoin}}
<a {{!
}} href="{{{joinurl}}}"{{!
}} class="btn btn-primary bbb-btn-action"{{!
}} class="btn btn-primary bbb-btn-action m-1"{{!
}} data-action="join"{{!
}} target="_blank"{{!
}}>
{{#str}}view_conference_action_join, mod_bigbluebuttonbn{{/str}}
</a>
{{/canjoin}}
{{#ismoderator}}
{{> mod_bigbluebuttonbn/end_session_button}}
{{/ismoderator}}
</div>
</div>
</div>

View File

@ -51,12 +51,15 @@
{{/sitenotification}}
<h3>{{meetingname}}</h3>
<h5>{{{meetingdescription}}}</h5>
{{#room}}
{{>mod_bigbluebuttonbn/room_view}}
{{/room}}
{{#recordings}}
{{>mod_bigbluebuttonbn/recordings_session}}
{{/recordings}}

View File

@ -27,6 +27,7 @@ require_once(__DIR__ . '/../../../../lib/behat/behat_base.php');
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
use Behat\Gherkin\Node\TableNode;
use mod_bigbluebuttonbn\instance;
use Moodle\BehatExtension\Exception\SkippedException;
/**
@ -138,7 +139,13 @@ XPATH
return new moodle_url('/mod/bigbluebuttonbn/index.php', [
'id' => $this->get_course_id($identifier),
]);
case 'BigblueButtonBN Guest':
$cm = $this->get_cm_by_activity_name('bigbluebuttonbn', $identifier);
$instance = instance::get_from_cmid($cm->id);
$url = $instance->get_guest_access_url();
// We have to make sure we set the password. It makes it then easy to submit the form with the right password.
$url->param('password', $instance->get_guest_access_password());
return $url;
default:
throw new Exception("Unrecognised page type '{$type}'.");
}

View File

@ -0,0 +1,63 @@
@mod @mod_bigbluebuttonbn
Feature: Guest access allows external users to connect to a meeting
Background:
Given a BigBlueButton mock server is configured
And I enable "bigbluebuttonbn" "mod" plugin
And the following "courses" exist:
| fullname | shortname | category |
| Test Course 1 | C1 | 0 |
And the following "activities" exist:
| activity | name | intro | course | idnumber | type | recordings_imported | guestallowed |
| bigbluebuttonbn | RoomRecordings | Test Room Recording description | C1 | bigbluebuttonbn1 | 0 | 0 | 0 |
| bigbluebuttonbn | RoomRecordingsWithguest | Test Room with guest | C1 | bigbluebuttonbn1 | 0 | 0 | 1 |
@javascript
Scenario: I need to enable guest access to see the instance parameters
Given the following config values are set as admin:
| bigbluebuttonbn_guestaccess_enabled | 1 |
When I am on the "RoomRecordings" "bigbluebuttonbn activity editing" page logged in as "admin"
Then I should see "Guest access"
Then I log out
Given the following config values are set as admin:
| bigbluebuttonbn_guestaccess_enabled | 0 |
When I am on the "RoomRecordings" "bigbluebuttonbn activity editing" page logged in as "admin"
Then I should not see "Guest access"
Then I log out
@javascript
Scenario: I should see Guest settings on the module form
Given the following config values are set as admin:
| bigbluebuttonbn_guestaccess_enabled | 1 |
When I am on the "RoomRecordings" "bigbluebuttonbn activity editing" page logged in as "admin"
Then I should see "Guest access"
Then I click on "Expand all" "link"
Then I should see "Allow guest access in the meeting"
And I should not see "Meeting link"
And I should not see "Meeting password"
When I set the field "Allow guest access in the meeting" to "1"
Then I should see "User must be approved by moderators"
And I should see "Meeting link"
And I should see "Meeting password"
And I should see "Copy link"
And I should see "Copy password"
Then I log out
@javascript
Scenario: I should be able to invite guest to the meeting
Given the following config values are set as admin:
| bigbluebuttonbn_guestaccess_enabled | 1 |
When I am on the "RoomRecordingsWithguest" "bigbluebuttonbn activity" page logged in as "admin"
Then I should see "Add guests"
And I click on "Add guests" "button"
And I should see "Meeting link"
And I should see "Meeting password"
And I should see "Copy link"
And I should see "Copy password"
When I set the field "Add guests emails" to "123"
When I click on "OK" "button" in the "Add guests to this meeting" "dialogue"
Then I should see "The email 123 is invalid, please correct it."
When I set the field "Add guests emails" to "testuser@email.com"
When I click on "OK" "button" in the "Add guests to this meeting" "dialogue"
Then I should see "An invitation will be sent to guest(s) testuser@email.com via email."
Then I log out

View File

@ -0,0 +1,53 @@
@mod @mod_bigbluebuttonbn @javascript
Feature: Test the ability to run the full meeting lifecycle (start to end) for guest users
Background:
Given a BigBlueButton mock server is configured
And I enable "bigbluebuttonbn" "mod" plugin
And the following config values are set as admin:
| bigbluebuttonbn_guestaccess_enabled | 1 |
And the following course exists:
| name | Test course |
| shortname | C1 |
And the following "users" exist:
| username | firstname | lastname | email |
| traverst | Terry | Travers | t.travers@example.com |
| teacher | Teacher | Teacher | t.eacher@example.com |
And the following "course enrolments" exist:
| user | course | role |
| traverst | C1 | student |
| teacher | C1 | editingteacher |
And the following "activity" exists:
| course | C1 |
| activity | bigbluebuttonbn |
| name | Room recordings |
| idnumber | Room recordings |
| moderators | role:editingteacher |
| wait | 0 |
| guestallowed | 1 |
Scenario: Student users should be able to see the guest user information
When I am on the "Room recordings" Activity page logged in as traverst
Then I should not see "Add guests"
Scenario: Teacher users should be able to see the guest user information
When I am on the "Room recordings" Activity page logged in as teacher
Then I should see "Add guests"
When I click on "Add guests" "button"
Then I should see "Add guests to this meeting" in the ".modal-dialog" "css_element"
Scenario: Guest users should be able to join a meeting as guest when the meeting is running.
When I am on the "Room recordings" Activity page logged in as traverst
Then "Join session" "link" should exist
When I click on "Join session" "link"
And I switch to the main window
Then I log out
And I close all opened windows
Then I am on the "Room recordings" "mod_bigbluebuttonbn > BigblueButtonBN Guest" page
Then I should see "Guest username"
And I should see "Password"
And I set the field "username" to "Test Guest User"
And I click on "Join meeting" "button"
Then I should see "Test Guest User"
And I click on "Leave Meeting" "link"
Then I should see "C1: Room recordings"

View File

@ -542,4 +542,64 @@ class instance_test extends advanced_testcase {
];
}
/**
* Test get user id (guest or current user)
* @covers \mod_bigbluebuttonbn\instance::get_user_id
*/
public function test_get_user_id(): void {
$this->resetAfterTest();
$this->setUser(null);
['record' => $record ] = $this->get_test_instance();
$instance = instance::get_from_instanceid($record->id);
$this->assertEquals(0, $instance->get_user_id());
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
$this->assertEquals($user->id, $instance->get_user_id());
}
/**
* Test guest access URL
*
* @covers ::get_guest_access_url
*/
public function test_get_guest_access_url() {
global $CFG;
$this->resetAfterTest();
['record' => $record ] = $this->get_test_instance(['guestallowed' => true]);
$CFG->bigbluebuttonbn['guestaccess_enabled'] = 1;
$instance = instance::get_from_instanceid($record->id);
$this->assertNotEmpty($instance->get_guest_access_url());
}
/**
* Test guest allowed flag
*
* @covers ::is_guest_allowed
*/
public function test_is_guest_allowed() {
global $CFG;
$this->resetAfterTest();
['record' => $record ] = $this->get_test_instance(['guestallowed' => true]);
$CFG->bigbluebuttonbn['guestaccess_enabled'] = 1;
$instance = instance::get_from_instanceid($record->id);
$this->assertTrue($instance->is_guest_allowed());
$CFG->bigbluebuttonbn['guestaccess_enabled'] = 0;
$this->assertFalse($instance->is_guest_allowed());
}
/**
* Test guest access password
*
* @covers ::get_guest_access_password
*/
public function get_guest_access_password() {
global $CFG;
$this->resetAfterTest();
['record' => $record ] = $this->get_test_instance(['guestallowed' => true]);
$CFG->bigbluebuttonbn['guestaccess_enabled'] = 1;
$instance = instance::get_from_instanceid($record->id);
$this->assertNotEmpty($instance->get_guest_access_password());
}
}

View File

@ -0,0 +1,62 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_bigbluebuttonbn;
use advanced_testcase;
use moodle_exception;
/**
* Tests for the Big Blue Button Plugin class.
*
* @package mod_bigbluebuttonbn
* @copyright 2021 Andrew Lyons <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \mod_bigbluebuttonbn\plugin
*/
class plugin_test extends advanced_testcase {
/**
* Test html2text
*
* @covers ::html2text
*/
public function test_html2text(): void {
$this->assertEquals('My text is in HTML', plugin::html2text('<p>My text is&nbsp;in HTML</p>', 100));
$this->assertEquals('My...', plugin::html2text('<p>My text is&nbsp;in HTML</p>', 2));
}
/**
* Test random_password
*
* @covers ::random_password
*/
public function test_random_password(): void {
$password = plugin::random_password(10);
$this->assertEquals(10, strlen($password));
$this->assertMatchesRegularExpression(
'/[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]+/', $password);
}
/**
* Test generate_guest_meeting_credentials
*
* @covers ::generate_guest_meeting_credentials
*/
public function test_generate_guest_meeting_credentials(): void {
[$guestlinkuid, $password] = plugin::generate_guest_meeting_credentials();
$this->assertEquals(40, strlen($guestlinkuid));
}
}

View File

@ -0,0 +1,66 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace mod_bigbluebuttonbn\task;
use advanced_testcase;
/**
* Send guest email tests
*
* @package mod_bigbluebuttonbn
* @copyright 2019 onwards, Blindside Networks Inc
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \mod_bigbluebuttonbn\task\send_guest_emails
* @coversDefaultClass \mod_bigbluebuttonbn\task\send_guest_emails
*/
class send_guest_emails_test extends advanced_testcase {
/**
* Check if set instance ID works correctly
*
*/
public function test_send_emails(): void {
$this->resetAfterTest();
$emailsink = $this->redirectEmails();
$generator = $this->getDataGenerator();
$course = $generator->create_course();
$instancedata = $generator->create_module('bigbluebuttonbn', [
'course' => $course->id,
]);
$moderatoruser = $generator->create_user();
$guestemail = new send_guest_emails();
$guestemail->set_custom_data(
[
'emails' => ['test1@email.com', 'test2@email.com'],
'useridfrom' => $moderatoruser->id
]
);
$guestemail->set_instance_id($instancedata->id);
\core\task\manager::queue_adhoc_task($guestemail);
$this->runAdhocTasks();
// Check the events.
$messages = $emailsink->get_messages();
$this->assertCount(2, $messages);
$this->assertEquals('You have been invited to the session BigBlueButton 1 on Test course 1 !', $messages[0]->subject);
$this->assertEquals('noreply@www.example.com', $messages[0]->from);
$this->assertEquals('test1@email.com', $messages[0]->to);
$this->assertEquals('test2@email.com', $messages[1]->to);
}
}

View File

@ -3,3 +3,5 @@ This files describes API changes in the bigbluebuttonbn code.
=== 4.1 ===
* External function mod_bigbluebuttonbn\external\meeting_info now return the list of the instance features and whether they are
enabled or not.
* External function mod_bigbluebuttonbn\external\meeting_info may now return guestaccessenabled, guestjoinurl, and guestpassword
if the callee can have access to them.

View File

@ -27,6 +27,6 @@
defined('MOODLE_INTERNAL') || die;
$plugin->version = 2022080400;
$plugin->version = 2022101900;
$plugin->requires = 2022041200;
$plugin->component = 'mod_bigbluebuttonbn';