mirror of
https://github.com/moodle/moodle.git
synced 2025-01-18 05:58:34 +01:00
Merge branch 'MDL-78129-master' of https://github.com/andrewnicols/moodle
This commit is contained in:
commit
bd323aede7
@ -32,11 +32,14 @@ use moodle_url;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class manage_communication_providers_page extends admin_setting {
|
||||
|
||||
public function __construct() {
|
||||
$this->nosave = true;
|
||||
parent::__construct('managecommunications',
|
||||
new \lang_string('managecommunicationproviders', 'core_communication'), '', '');
|
||||
parent::__construct(
|
||||
'managecommunications',
|
||||
new \lang_string('managecommunicationproviders', 'core_communication'),
|
||||
'',
|
||||
''
|
||||
);
|
||||
}
|
||||
|
||||
public function get_setting(): bool {
|
||||
@ -71,20 +74,26 @@ class manage_communication_providers_page extends admin_setting {
|
||||
foreach ($plugins as $plugin) {
|
||||
$class = '';
|
||||
$actionurl = new moodle_url('/admin/communication.php', ['sesskey' => sesskey(), 'name' => $plugin->name]);
|
||||
if ($pluginmanager->get_plugin_info('communication_' . $plugin->name)->get_status() ===
|
||||
core_plugin_manager::PLUGIN_STATUS_MISSING) {
|
||||
if (
|
||||
$pluginmanager->get_plugin_info('communication_' . $plugin->name)->get_status() ===
|
||||
core_plugin_manager::PLUGIN_STATUS_MISSING
|
||||
) {
|
||||
$strtypename = $plugin->displayname . ' (' . get_string('missingfromdisk') . ')';
|
||||
} else {
|
||||
$strtypename = $plugin->displayname;
|
||||
}
|
||||
|
||||
if ($plugin->is_enabled()) {
|
||||
$hideshow = html_writer::link($actionurl->out(false, ['action' => 'disable']),
|
||||
$OUTPUT->pix_icon('t/hide', get_string('disable'), 'moodle', ['class' => 'iconsmall']));
|
||||
$hideshow = html_writer::link(
|
||||
$actionurl->out(false, ['action' => 'disable']),
|
||||
$OUTPUT->pix_icon('t/hide', get_string('disable'), 'moodle', ['class' => 'iconsmall'])
|
||||
);
|
||||
} else {
|
||||
$class = 'dimmed_text';
|
||||
$hideshow = html_writer::link($actionurl->out(false, ['action' => 'enable']),
|
||||
$OUTPUT->pix_icon('t/show', get_string('enable'), 'moodle', ['class' => 'iconsmall']));
|
||||
$hideshow = html_writer::link(
|
||||
$actionurl->out(false, ['action' => 'enable']),
|
||||
$OUTPUT->pix_icon('t/show', get_string('enable'), 'moodle', ['class' => 'iconsmall'])
|
||||
);
|
||||
}
|
||||
|
||||
$settings = '';
|
||||
@ -93,8 +102,12 @@ class manage_communication_providers_page extends admin_setting {
|
||||
}
|
||||
|
||||
$uninstall = '';
|
||||
if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url(
|
||||
'communication_' . $plugin->name, 'manage')) {
|
||||
if (
|
||||
$uninstallurl = core_plugin_manager::instance()->get_uninstall_url(
|
||||
'communication_' . $plugin->name,
|
||||
'manage'
|
||||
)
|
||||
) {
|
||||
$uninstall = html_writer::link($uninstallurl, get_string('uninstallplugin', 'core_admin'));
|
||||
}
|
||||
|
||||
@ -114,8 +127,10 @@ class manage_communication_providers_page extends admin_setting {
|
||||
}
|
||||
$types = core_plugin_manager::instance()->get_plugins_of_type('communication');
|
||||
foreach ($types as $type) {
|
||||
if (strpos($type->component, $query) !== false ||
|
||||
strpos(core_text::strtolower($type->displayname), $query) !== false) {
|
||||
if (
|
||||
strpos($type->component, $query) !== false ||
|
||||
strpos(core_text::strtolower($type->displayname), $query) !== false
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ use core_communication\task\create_and_configure_room_task;
|
||||
use core_communication\task\delete_room_task;
|
||||
use core_communication\task\remove_members_from_room;
|
||||
use core_communication\task\update_room_task;
|
||||
use core_communication\task\update_room_membership_task;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
@ -39,7 +40,6 @@ use stdClass;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class api {
|
||||
|
||||
/**
|
||||
* @var null|processor $communication The communication settings object
|
||||
*/
|
||||
@ -166,7 +166,7 @@ class api {
|
||||
$selection[processor::PROVIDER_NONE] = get_string('nocommunicationselected', 'communication');
|
||||
$communicationplugins = \core\plugininfo\communication::get_enabled_plugins();
|
||||
foreach ($communicationplugins as $pluginname => $notusing) {
|
||||
$selection['communication_' . $pluginname] = get_string('pluginname', 'communication_'. $pluginname);
|
||||
$selection['communication_' . $pluginname] = get_string('pluginname', 'communication_' . $pluginname);
|
||||
}
|
||||
return $selection;
|
||||
}
|
||||
@ -199,8 +199,7 @@ class api {
|
||||
): void {
|
||||
global $PAGE;
|
||||
|
||||
list($communicationproviders, $defaulprovider) = self::
|
||||
get_enabled_providers_and_default($selectdefaultcommunication);
|
||||
[$communicationproviders, $defaulprovider] = self::get_enabled_providers_and_default($selectdefaultcommunication);
|
||||
|
||||
$PAGE->requires->js_call_amd('core_communication/providerchooser', 'init');
|
||||
|
||||
@ -216,10 +215,12 @@ class api {
|
||||
$mform->setDefault('selectedcommunication', $defaulprovider);
|
||||
|
||||
$mform->registerNoSubmitButton('updatecommunicationprovider');
|
||||
$mform->addElement('submit',
|
||||
$mform->addElement(
|
||||
'submit',
|
||||
'updatecommunicationprovider',
|
||||
'update communication',
|
||||
['data-communicationchooser-field' => 'updateButton', 'class' => 'd-none',]);
|
||||
['data-communicationchooser-field' => 'updateButton', 'class' => 'd-none']
|
||||
);
|
||||
|
||||
// Just a placeholder for the communication options.
|
||||
$mform->addElement('hidden', 'addcommunicationoptionshere');
|
||||
@ -239,7 +240,9 @@ class api {
|
||||
$mform->createElement(
|
||||
'text',
|
||||
'communicationroomname',
|
||||
get_string('communicationroomname', 'communication'), 'maxlength="100" size="20"'),
|
||||
get_string('communicationroomname', 'communication'),
|
||||
'maxlength="100" size="20"'
|
||||
),
|
||||
'addcommunicationoptionshere'
|
||||
);
|
||||
$mform->addHelpButton('communicationroomname', 'communicationroomname', 'communication');
|
||||
@ -247,7 +250,6 @@ class api {
|
||||
|
||||
processor::set_provider_specific_form_definition($provider, $mform);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -529,6 +531,34 @@ class api {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a communication ad-hoc task for updating members operation and update the user mapping.
|
||||
*
|
||||
* This method will add a task to the queue to update the room users.
|
||||
*
|
||||
* @param array $userids The user ids to add to the room
|
||||
* @param bool $queue Whether to queue the task or not
|
||||
*/
|
||||
public function update_room_membership(array $userids, bool $queue = true): void {
|
||||
// No communication object? something not done right.
|
||||
if (!$this->communication) {
|
||||
return;
|
||||
}
|
||||
|
||||
// No userids? don't bother doing anything.
|
||||
if (empty($userids)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->communication->reset_users_sync_flag($userids);
|
||||
|
||||
if ($queue) {
|
||||
update_room_membership_task::queue(
|
||||
$this->communication
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a communication ad-hoc task for remove members operation or action immediately.
|
||||
*
|
||||
@ -582,7 +612,6 @@ class api {
|
||||
|
||||
switch ($roomstatus) {
|
||||
case 'pending':
|
||||
|
||||
\core\notification::add($message, \core\notification::INFO);
|
||||
break;
|
||||
|
||||
|
@ -28,7 +28,6 @@ namespace core_communication;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
interface communication_provider {
|
||||
|
||||
/**
|
||||
* A base communication provider.
|
||||
*
|
||||
|
@ -26,13 +26,12 @@ namespace core_communication\form;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir.'/formslib.php');
|
||||
require_once($CFG->libdir . '/formslib.php');
|
||||
|
||||
/**
|
||||
* Defines the configure communication form.
|
||||
*/
|
||||
class configure_form extends \moodleform {
|
||||
|
||||
/**
|
||||
* @var \core_communication\api $communication The communication api object.
|
||||
*/
|
||||
|
@ -26,7 +26,6 @@ namespace core_communication;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
interface form_provider {
|
||||
|
||||
/**
|
||||
* Set the form data to the instance if any data is available.
|
||||
*
|
||||
|
@ -29,10 +29,10 @@ use core_privacy\local\request\userlist;
|
||||
* @copyright 2023 Huong Nguyen <huongnv13@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class provider implements \core_privacy\local\metadata\provider,
|
||||
\core_privacy\local\request\subsystem\provider,
|
||||
\core_privacy\local\request\core_userlist_provider {
|
||||
|
||||
class provider implements
|
||||
\core_privacy\local\request\core_userlist_provider,
|
||||
\core_privacy\local\metadata\provider,
|
||||
\core_privacy\local\request\subsystem\provider {
|
||||
public static function get_metadata(collection $collection): collection {
|
||||
|
||||
$collection->add_database_table('communication_user', [
|
||||
|
@ -29,7 +29,6 @@ use stored_file;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class processor {
|
||||
|
||||
/** @var string The magic 'none' provider */
|
||||
public const PROVIDER_NONE = 'none';
|
||||
|
||||
@ -171,6 +170,21 @@ class processor {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the user ids flagged as deleted.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_all_delete_flagged_userids(): array {
|
||||
global $DB;
|
||||
return $DB->get_fieldset_select(
|
||||
'communication_user',
|
||||
'userid',
|
||||
'commid = ? AND deleted = ?',
|
||||
[$this->instancedata->id, 1]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create communication user record for mapping and sync.
|
||||
*
|
||||
@ -309,7 +323,7 @@ class processor {
|
||||
|
||||
$DB->delete_records_select(
|
||||
'communication_user',
|
||||
'commid = ? AND userid IN (' . implode(',', $userids) . ') AND synced = ?' ,
|
||||
'commid = ? AND userid IN (' . implode(',', $userids) . ') AND synced = ?',
|
||||
[$this->instancedata->id, 0]
|
||||
);
|
||||
}
|
||||
@ -400,6 +414,15 @@ class processor {
|
||||
/**
|
||||
* Get communication instance id.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_instance_id(): int {
|
||||
return $this->instancedata->instanceid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get communication instance component.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_component(): string {
|
||||
|
@ -26,7 +26,6 @@ namespace core_communication;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
interface room_chat_provider {
|
||||
|
||||
/**
|
||||
* Create a provider room when a instance is created.
|
||||
*/
|
||||
|
@ -31,6 +31,13 @@ interface room_user_provider {
|
||||
*/
|
||||
public function add_members_to_room(array $userids): void;
|
||||
|
||||
/**
|
||||
* Update room membership for the communication room.
|
||||
*
|
||||
* @param array $userids The user ids to be updated
|
||||
*/
|
||||
public function update_room_membership(array $userids): void;
|
||||
|
||||
/**
|
||||
* Remove members from room.
|
||||
*
|
||||
|
@ -27,7 +27,6 @@ use core_communication\processor;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class add_members_to_room_task extends adhoc_task {
|
||||
|
||||
public function execute() {
|
||||
// Initialize the custom data operation to be used for the action.
|
||||
$data = $this->get_custom_data();
|
||||
@ -55,7 +54,7 @@ class add_members_to_room_task extends adhoc_task {
|
||||
// Add ad-hoc task to update the provider room.
|
||||
$task = new self();
|
||||
$task->set_custom_data([
|
||||
'id' => $communication->get_id()
|
||||
'id' => $communication->get_id(),
|
||||
]);
|
||||
|
||||
// Queue the task for the next run.
|
||||
|
@ -29,7 +29,6 @@ use core_communication\processor;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class create_and_configure_room_task extends adhoc_task {
|
||||
|
||||
public function execute() {
|
||||
$data = $this->get_custom_data();
|
||||
|
||||
@ -66,7 +65,7 @@ class create_and_configure_room_task extends adhoc_task {
|
||||
// Add ad-hoc task to update the provider room.
|
||||
$task = new self();
|
||||
$task->set_custom_data([
|
||||
'id' => $communication->get_id()
|
||||
'id' => $communication->get_id(),
|
||||
]);
|
||||
|
||||
// Queue the task for the next run.
|
||||
|
@ -29,7 +29,6 @@ use core_communication\processor;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class delete_room_task extends adhoc_task {
|
||||
|
||||
public function execute() {
|
||||
$data = $this->get_custom_data();
|
||||
|
||||
@ -63,7 +62,7 @@ class delete_room_task extends adhoc_task {
|
||||
// Add ad-hoc task to update the provider room.
|
||||
$task = new self();
|
||||
$task->set_custom_data([
|
||||
'id' => $communication->get_id()
|
||||
'id' => $communication->get_id(),
|
||||
]);
|
||||
|
||||
// Queue the task for the next run.
|
||||
|
@ -27,7 +27,6 @@ use core_communication\processor;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class remove_members_from_room extends adhoc_task {
|
||||
|
||||
public function execute() {
|
||||
// Initialize the custom data operation to be used for the action.
|
||||
$data = $this->get_custom_data();
|
||||
@ -40,7 +39,7 @@ class remove_members_from_room extends adhoc_task {
|
||||
return;
|
||||
}
|
||||
|
||||
$communication->get_room_user_provider()->remove_members_from_room($communication->get_instance_userids(true, true));
|
||||
$communication->get_room_user_provider()->remove_members_from_room($communication->get_all_delete_flagged_userids());
|
||||
|
||||
// Now remove any mapping for users who are not in the room.
|
||||
$communication->delete_instance_non_synced_user_mapping($communication->get_instance_userids(false, true));
|
||||
@ -58,7 +57,7 @@ class remove_members_from_room extends adhoc_task {
|
||||
// Add ad-hoc task to update the provider room.
|
||||
$task = new self();
|
||||
$task->set_custom_data([
|
||||
'id' => $communication->get_id()
|
||||
'id' => $communication->get_id(),
|
||||
]);
|
||||
|
||||
// Queue the task for the next run.
|
||||
|
63
communication/classes/task/update_room_membership_task.php
Normal file
63
communication/classes/task/update_room_membership_task.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?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 core_communication\task;
|
||||
|
||||
use core\task\adhoc_task;
|
||||
use core_communication\processor;
|
||||
|
||||
/**
|
||||
* Class update_room_membership_task to add the task to update members for the room and execute the task to action the addition.
|
||||
*
|
||||
* @package core_communication
|
||||
* @copyright 2023 Safat Shahin <safat.shahin@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class update_room_membership_task extends adhoc_task {
|
||||
public function execute() {
|
||||
// Initialize the custom data operation to be used for the action.
|
||||
$data = $this->get_custom_data();
|
||||
|
||||
// Call the communication api to action the operation.
|
||||
$communication = processor::load_by_id($data->id);
|
||||
|
||||
if ($communication === null) {
|
||||
mtrace("Skipping room creation because the instance does not exist");
|
||||
return;
|
||||
}
|
||||
|
||||
$communication->get_room_user_provider()->update_room_membership($communication->get_instance_userids());
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue the task for the next run.
|
||||
*
|
||||
* @param processor $communication The communication processor to perform the action on
|
||||
*/
|
||||
public static function queue(
|
||||
processor $communication
|
||||
): void {
|
||||
|
||||
// Add ad-hoc task to update the provider room.
|
||||
$task = new self();
|
||||
$task->set_custom_data([
|
||||
'id' => $communication->get_id(),
|
||||
]);
|
||||
|
||||
// Queue the task for the next run.
|
||||
\core\task\manager::queue_adhoc_task($task);
|
||||
}
|
||||
}
|
@ -29,7 +29,6 @@ use core_communication\processor;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class update_room_task extends adhoc_task {
|
||||
|
||||
public function execute() {
|
||||
$data = $this->get_custom_data();
|
||||
|
||||
@ -56,7 +55,7 @@ class update_room_task extends adhoc_task {
|
||||
// Add ad-hoc task to update the provider room.
|
||||
$task = new self();
|
||||
$task->set_custom_data([
|
||||
'id' => $communication->get_id()
|
||||
'id' => $communication->get_id(),
|
||||
]);
|
||||
|
||||
// Queue the task for the next run.
|
||||
|
@ -24,7 +24,6 @@ namespace core_communication;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
interface user_provider {
|
||||
|
||||
/**
|
||||
* Create members.
|
||||
*
|
||||
|
@ -52,7 +52,7 @@ if (!$communication) {
|
||||
}
|
||||
|
||||
// Set variables according to the component callback and use them on the page.
|
||||
list($instance, $context, $heading, $returnurl) = component_callback(
|
||||
[$instance, $context, $heading, $returnurl] = component_callback(
|
||||
$component,
|
||||
'get_communication_instance_data',
|
||||
[$instanceid]
|
||||
@ -79,11 +79,8 @@ $form = new \core_communication\form\configure_form(
|
||||
|
||||
|
||||
if ($form->is_cancelled()) {
|
||||
|
||||
redirect($returnurl);
|
||||
|
||||
} else if ($data = $form->get_data()) {
|
||||
|
||||
component_callback($component, 'update_communication_instance_data', [$data]);
|
||||
redirect($returnurl);
|
||||
}
|
||||
|
@ -27,9 +27,8 @@ use core_communication\processor;
|
||||
*/
|
||||
class communication_feature implements
|
||||
\core_communication\communication_provider,
|
||||
\core_communication\room_chat_provider,
|
||||
\core_communication\form_provider {
|
||||
|
||||
\core_communication\form_provider,
|
||||
\core_communication\room_chat_provider {
|
||||
/** @var string The database table storing custom link specific data */
|
||||
protected const CUSTOMLINK_TABLE = 'communication_customlink';
|
||||
|
||||
@ -132,7 +131,6 @@ class communication_feature implements
|
||||
// Create the record if it does not exist.
|
||||
$newrecord->commid = $commid;
|
||||
$DB->insert_record(self::CUSTOMLINK_TABLE, $newrecord);
|
||||
|
||||
} else if ($newrecord->url !== $existingrecord->url) {
|
||||
// Update record if the URL has changed.
|
||||
$newrecord->id = $existingrecord->id;
|
||||
@ -154,15 +152,22 @@ class communication_feature implements
|
||||
|
||||
public static function set_form_definition(\MoodleQuickForm $mform): void {
|
||||
// Custom link description for the communication provider.
|
||||
$mform->insertElementBefore($mform->createElement('text', 'customlinkurl',
|
||||
$mform->insertElementBefore($mform->createElement(
|
||||
'text',
|
||||
'customlinkurl',
|
||||
get_string('customlinkurl', 'communication_customlink'),
|
||||
'maxlength="255" size="40"'), 'addcommunicationoptionshere');
|
||||
'maxlength="255" size="40"'
|
||||
), 'addcommunicationoptionshere');
|
||||
$mform->addHelpButton('customlinkurl', 'customlinkurl', 'communication_customlink');
|
||||
$mform->setType('customlinkurl', PARAM_URL);
|
||||
$mform->addRule('customlinkurl', get_string('required'), 'required', null, 'client');
|
||||
$mform->addRule('customlinkurl', get_string('maximumchars', '', 255), 'maxlength', 255);
|
||||
$mform->insertElementBefore($mform->createElement('static', 'customlinkurlinfo', '',
|
||||
$mform->insertElementBefore($mform->createElement(
|
||||
'static',
|
||||
'customlinkurlinfo',
|
||||
'',
|
||||
get_string('customlinkurlinfo', 'communication_customlink'),
|
||||
'addcommunicationoptionshere'), 'addcommunicationoptionshere');
|
||||
'addcommunicationoptionshere'
|
||||
), 'addcommunicationoptionshere');
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ use core_privacy\local\metadata\null_provider;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class provider implements null_provider {
|
||||
|
||||
/**
|
||||
* Get the language string identifier with the component's language
|
||||
* file to explain why this plugin stores no data.
|
||||
|
@ -33,7 +33,6 @@ require_once(__DIR__ . '/../../../tests/communication_test_helper_trait.php');
|
||||
* @coversDefaultClass \communication_customlink\communication_feature
|
||||
*/
|
||||
class communication_feature_test extends \advanced_testcase {
|
||||
|
||||
use communication_test_helper_trait;
|
||||
|
||||
public function setUp(): void {
|
||||
|
@ -45,12 +45,11 @@ use GuzzleHttp\Psr7\Response;
|
||||
*/
|
||||
class communication_feature implements
|
||||
\core_communication\communication_provider,
|
||||
\core_communication\user_provider,
|
||||
\core_communication\form_provider,
|
||||
\core_communication\room_chat_provider,
|
||||
\core_communication\room_user_provider,
|
||||
\core_communication\form_provider {
|
||||
|
||||
/** @var matrix_room $room The matrix room object to update room information */
|
||||
\core_communication\user_provider {
|
||||
/** @var ?matrix_room $room The matrix room object to update room information */
|
||||
private ?matrix_room $room = null;
|
||||
|
||||
/** @var string|null The URI of the home server */
|
||||
@ -127,10 +126,7 @@ class communication_feature implements
|
||||
* @return null|matrix_room
|
||||
*/
|
||||
public function get_room_configuration(): ?matrix_room {
|
||||
if ($this->room === null) {
|
||||
$this->room = matrix_room::load_by_processor_id($this->processor->get_id());
|
||||
}
|
||||
|
||||
$this->room = matrix_room::load_by_processor_id($this->processor->get_id());
|
||||
return $this->room;
|
||||
}
|
||||
|
||||
@ -166,10 +162,10 @@ class communication_feature implements
|
||||
$response = $this->matrixapi->create_user(
|
||||
userid: $qualifiedmuid,
|
||||
displayname: $userfullname,
|
||||
threepids: [(object)[
|
||||
threepids: [(object) [
|
||||
'medium' => 'email',
|
||||
'address' => $user->email
|
||||
]],
|
||||
'address' => $user->email,
|
||||
], ],
|
||||
externalids: [],
|
||||
);
|
||||
$body = json_decode($response->getBody());
|
||||
@ -184,10 +180,19 @@ class communication_feature implements
|
||||
}
|
||||
}
|
||||
|
||||
// Set the power level of the users.
|
||||
if (!empty($addedmembers) && $this->is_power_levels_update_required($addedmembers)) {
|
||||
$this->set_matrix_power_levels();
|
||||
}
|
||||
|
||||
// Mark then users as synced for the added members.
|
||||
$this->processor->mark_users_as_synced($addedmembers);
|
||||
}
|
||||
|
||||
public function update_room_membership(array $userids): void {
|
||||
$this->set_matrix_power_levels();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add members to a room.
|
||||
*
|
||||
@ -209,6 +214,11 @@ class communication_feature implements
|
||||
}
|
||||
}
|
||||
|
||||
// Set the power level of the users.
|
||||
if (!empty($addedmembers) && $this->is_power_levels_update_required($addedmembers)) {
|
||||
$this->set_matrix_power_levels();
|
||||
}
|
||||
|
||||
// Mark then users as synced for the added members.
|
||||
$this->processor->mark_users_as_synced($addedmembers);
|
||||
|
||||
@ -229,8 +239,8 @@ class communication_feature implements
|
||||
|
||||
if (!$this->check_room_membership($matrixuserid)) {
|
||||
$response = $this->matrixapi->invite_member_to_room(
|
||||
$this->get_room_id(),
|
||||
$matrixuserid,
|
||||
roomid: $this->get_room_id(),
|
||||
userid: $matrixuserid,
|
||||
);
|
||||
|
||||
$body = self::get_body($response);
|
||||
@ -256,25 +266,41 @@ class communication_feature implements
|
||||
// This API requiures the remove_members_from_room feature.
|
||||
$this->matrixapi->require_feature(remove_member_from_room_feature::class);
|
||||
|
||||
if ($this->get_room_id() === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the power level for the user first.
|
||||
$this->set_matrix_power_levels($userids);
|
||||
|
||||
$membersremoved = [];
|
||||
|
||||
$currentpowerlevels = $this->get_current_powerlevel_data();
|
||||
$currentuserpowerlevels = (array) $currentpowerlevels->users ?? [];
|
||||
|
||||
foreach ($userids as $userid) {
|
||||
// Check user is member of room first.
|
||||
$matrixuserid = matrix_user_manager::get_matrixid_from_moodle($userid);
|
||||
|
||||
// Check if user is the room admin and halt removal of this user.
|
||||
$response = $this->matrixapi->get_room_info($this->get_room_id());
|
||||
$matrixroomdata = self::get_body($response);
|
||||
$roomadmin = $matrixroomdata->creator;
|
||||
$isadmin = $matrixuserid === $roomadmin;
|
||||
if (!$matrixuserid) {
|
||||
// Unable to find a matrix userid for this user.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (array_key_exists($matrixuserid, $currentuserpowerlevels)) {
|
||||
if ($currentuserpowerlevels[$matrixuserid] >= matrix_constants::POWER_LEVEL_MAXIMUM) {
|
||||
// Skip removing the user if they are an admin.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
!$isadmin && $matrixuserid && $this->check_user_exists($matrixuserid) &&
|
||||
$this->check_user_exists($matrixuserid) &&
|
||||
$this->check_room_membership($matrixuserid)
|
||||
) {
|
||||
$this->matrixapi->remove_member_from_room(
|
||||
$this->get_room_id(),
|
||||
$matrixuserid,
|
||||
roomid: $this->get_room_id(),
|
||||
userid: $matrixuserid,
|
||||
);
|
||||
|
||||
$membersremoved[] = $userid;
|
||||
@ -295,7 +321,9 @@ class communication_feature implements
|
||||
// This API requires the get_user_info feature.
|
||||
$this->matrixapi->require_feature(get_user_info_feature::class);
|
||||
|
||||
$response = $this->matrixapi->get_user_info($matrixuserid);
|
||||
$response = $this->matrixapi->get_user_info(
|
||||
userid: $matrixuserid,
|
||||
);
|
||||
$body = self::get_body($response);
|
||||
|
||||
return isset($body->name);
|
||||
@ -312,7 +340,9 @@ class communication_feature implements
|
||||
// This API requires the get_room_members feature.
|
||||
$this->matrixapi->require_feature(get_room_members_feature::class);
|
||||
|
||||
$response = $this->matrixapi->get_room_members($this->get_room_id());
|
||||
$response = $this->matrixapi->get_room_members(
|
||||
roomid: $this->get_room_id(),
|
||||
);
|
||||
$body = self::get_body($response);
|
||||
|
||||
// Check user id is in the returned room member ids.
|
||||
@ -376,12 +406,17 @@ class communication_feature implements
|
||||
]);
|
||||
|
||||
// Get room data.
|
||||
$response = $this->matrixapi->get_room_info($this->get_room_id());
|
||||
$response = $this->matrixapi->get_room_info(
|
||||
roomid: $this->get_room_id(),
|
||||
);
|
||||
$remoteroomdata = self::get_body($response);
|
||||
|
||||
// Update the room name when it's updated from the form.
|
||||
if ($remoteroomdata->name !== $this->processor->get_room_name()) {
|
||||
$this->matrixapi->update_room_name($this->get_room_id(), $this->processor->get_room_name());
|
||||
$this->matrixapi->update_room_name(
|
||||
roomid: $this->get_room_id(),
|
||||
name: $this->processor->get_room_name(),
|
||||
);
|
||||
}
|
||||
|
||||
// Update the room topic if set.
|
||||
@ -431,12 +466,18 @@ class communication_feature implements
|
||||
$contenturi = self::get_body($response)->content_uri;
|
||||
|
||||
// Now update the room avatar.
|
||||
$response = $this->matrixapi->update_room_avatar($this->get_room_id(), $contenturi);
|
||||
$response = $this->matrixapi->update_room_avatar(
|
||||
roomid: $this->get_room_id(),
|
||||
avatarurl: $contenturi,
|
||||
);
|
||||
|
||||
// And finally upload the content.
|
||||
$this->matrixapi->upload_content($instanceimage);
|
||||
} else {
|
||||
$response = $this->matrixapi->update_room_avatar($this->get_room_id(), null);
|
||||
$response = $this->matrixapi->update_room_avatar(
|
||||
roomid: $this->get_room_id(),
|
||||
avatarurl: null,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Prior to v1.7 the only way to upload content was to upload the content, which returns a mxc URI to use.
|
||||
@ -449,7 +490,10 @@ class communication_feature implements
|
||||
}
|
||||
|
||||
// Now update the room avatar.
|
||||
$response = $this->matrixapi->update_room_avatar($this->get_room_id(), $contenturi);
|
||||
$response = $this->matrixapi->update_room_avatar(
|
||||
roomid: $this->get_room_id(),
|
||||
avatarurl: $contenturi,
|
||||
);
|
||||
}
|
||||
|
||||
// Indicate the avatar has been synced if it was successfully set with Matrix.
|
||||
@ -497,9 +541,12 @@ class communication_feature implements
|
||||
|
||||
public static function set_form_definition(\MoodleQuickForm $mform): void {
|
||||
// Room description for the communication provider.
|
||||
$mform->insertElementBefore($mform->createElement('text', 'matrixroomtopic',
|
||||
$mform->insertElementBefore($mform->createElement(
|
||||
'text',
|
||||
'matrixroomtopic',
|
||||
get_string('matrixroomtopic', 'communication_matrix'),
|
||||
'maxlength="255" size="20"'), 'addcommunicationoptionshere');
|
||||
'maxlength="255" size="20"'
|
||||
), 'addcommunicationoptionshere');
|
||||
$mform->addHelpButton('matrixroomtopic', 'matrixroomtopic', 'communication_matrix');
|
||||
$mform->setType('matrixroomtopic', PARAM_TEXT);
|
||||
}
|
||||
@ -515,4 +562,193 @@ class communication_feature implements
|
||||
|
||||
return json_decode($body, false, 512, JSON_THROW_ON_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the matrix power level with the room.
|
||||
*
|
||||
* Users with a non-moodle power level are not typically removed unless specified in the $forceremoval param.
|
||||
* Matrix Admin users are never removed.
|
||||
*
|
||||
* @param array $forceremoval The users to force removal from the room, even if they have a custom power level
|
||||
*/
|
||||
private function set_matrix_power_levels(
|
||||
array $forceremoval = [],
|
||||
): void {
|
||||
// Get the current power levels.
|
||||
$currentpowerlevels = $this->get_current_powerlevel_data();
|
||||
$currentuserpowerlevels = (array) $currentpowerlevels->users ?? [];
|
||||
|
||||
// Get all the current users who need to be in the room.
|
||||
$userlist = $this->processor->get_all_userids_for_instance();
|
||||
|
||||
// Translate the user ids to matrix user ids.
|
||||
$userlist = array_combine(
|
||||
array_map(
|
||||
fn ($userid) => matrix_user_manager::get_matrixid_from_moodle($userid),
|
||||
$userlist,
|
||||
),
|
||||
$userlist,
|
||||
);
|
||||
|
||||
// Determine the power levels, and filter out anyone with the default level.
|
||||
$newuserpowerlevels = array_filter(
|
||||
array_map(
|
||||
fn($userid) => $this->get_user_allowed_power_level($userid),
|
||||
$userlist,
|
||||
),
|
||||
fn($level) => $level !== matrix_constants::POWER_LEVEL_DEFAULT,
|
||||
);
|
||||
|
||||
// Keep current room admins, and users which don't use our MODERATOR power level without changing them.
|
||||
$staticusers = $this->get_users_with_custom_power_level($currentuserpowerlevels);
|
||||
foreach ($staticusers as $userid => $level) {
|
||||
$newuserpowerlevels[$userid] = $level;
|
||||
}
|
||||
|
||||
if (!empty($forceremoval)) {
|
||||
// Remove the users from the power levels if they are not admins.
|
||||
foreach ($forceremoval as $userid) {
|
||||
if ($newuserpowerlevels < matrix_constants::POWER_LEVEL_MAXIMUM) {
|
||||
unset($newuserpowerlevels[$userid]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->power_levels_changed($currentuserpowerlevels, $newuserpowerlevels)) {
|
||||
// No changes to make.
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Update the power levels for the room.
|
||||
$this->matrixapi->update_room_power_levels(
|
||||
roomid: $this->get_room_id(),
|
||||
users: $newuserpowerlevels,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the list of users provided to remove those with a moodle-related power level.
|
||||
*
|
||||
* @param array $users
|
||||
* @return array
|
||||
*/
|
||||
private function get_users_with_custom_power_level(array $users): array {
|
||||
return array_filter(
|
||||
$users,
|
||||
function ($level): bool {
|
||||
switch ($level) {
|
||||
case matrix_constants::POWER_LEVEL_DEFAULT:
|
||||
case matrix_constants::POWER_LEVEL_MOODLE_SITE_ADMIN:
|
||||
case matrix_constants::POWER_LEVEL_MOODLE_MODERATOR:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether power levels have changed compared with the proposed power levels.
|
||||
*
|
||||
* @param array $currentuserpowerlevels The current power levels
|
||||
* @param array $newuserpowerlevels The new power levels proposed
|
||||
* @return bool Whether there is any change to be made
|
||||
*/
|
||||
private function power_levels_changed(
|
||||
array $currentuserpowerlevels,
|
||||
array $newuserpowerlevels,
|
||||
): bool {
|
||||
if (count($newuserpowerlevels) !== count($currentuserpowerlevels)) {
|
||||
// Different number of keys - there must be a difference then.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Sort the power levels.
|
||||
ksort($newuserpowerlevels, SORT_NUMERIC);
|
||||
|
||||
// Get the current power levels.
|
||||
ksort($currentuserpowerlevels);
|
||||
|
||||
$diff = array_merge(
|
||||
array_diff_assoc(
|
||||
$newuserpowerlevels,
|
||||
$currentuserpowerlevels,
|
||||
),
|
||||
array_diff_assoc(
|
||||
$currentuserpowerlevels,
|
||||
$newuserpowerlevels,
|
||||
),
|
||||
);
|
||||
|
||||
return count($diff) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current power level for the room.
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
private function get_current_powerlevel_data(): \stdClass {
|
||||
$roomid = $this->get_room_id();
|
||||
$response = $this->matrixapi->get_room_power_levels(
|
||||
roomid: $roomid,
|
||||
);
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
throw new \moodle_exception(
|
||||
'Unable to get power levels for room',
|
||||
);
|
||||
}
|
||||
|
||||
$powerdata = $this->get_body($response);
|
||||
$powerdata = array_filter(
|
||||
$powerdata->rooms->join->{$roomid}->state->events,
|
||||
fn($value) => $value->type === 'm.room.power_levels'
|
||||
);
|
||||
$powerdata = reset($powerdata);
|
||||
|
||||
return $powerdata->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a power level update is required.
|
||||
* Matrix will always set a user to the default power level of 0 when a power level update is made.
|
||||
* That is, unless we specify another level. As long as one person's level is greater than the default,
|
||||
* we will need to set the power levels of all users greater than the default.
|
||||
*
|
||||
* @param array $userids The users to evaluate
|
||||
* @return boolean Returns true if an update is required
|
||||
*/
|
||||
private function is_power_levels_update_required(array $userids): bool {
|
||||
// Is the user's power level greater than the default?
|
||||
foreach ($userids as $userid) {
|
||||
if ($this->get_user_allowed_power_level($userid) > matrix_constants::POWER_LEVEL_DEFAULT) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the allowed power level for the user id according to perms/site admin or default.
|
||||
*
|
||||
* @param int $userid
|
||||
* @return int
|
||||
*/
|
||||
public function get_user_allowed_power_level(int $userid): int {
|
||||
$context = \core\context\course::instance($this->processor->get_instance_id());
|
||||
$powerlevel = matrix_constants::POWER_LEVEL_DEFAULT;
|
||||
|
||||
if (has_capability('communication/matrix:moderator', $context, $userid)) {
|
||||
$powerlevel = matrix_constants::POWER_LEVEL_MOODLE_MODERATOR;
|
||||
}
|
||||
|
||||
// If site admin, override all caps.
|
||||
if (is_siteadmin($userid)) {
|
||||
$powerlevel = matrix_constants::POWER_LEVEL_MOODLE_SITE_ADMIN;
|
||||
}
|
||||
|
||||
return $powerlevel;
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,6 @@ use GuzzleHttp\Psr7\Response;
|
||||
* This code does not warrant being tested. Testing offers no discernible benefit given its usage is tested.
|
||||
*/
|
||||
trait create_room_v3 {
|
||||
|
||||
/**
|
||||
* Create a new room.
|
||||
*
|
||||
|
@ -31,7 +31,6 @@ use GuzzleHttp\Psr7\Response;
|
||||
* This code does not warrant being tested. Testing offers no discernible benefit given its usage is tested.
|
||||
*/
|
||||
trait get_room_members_v3 {
|
||||
|
||||
/**
|
||||
* Get a list of room members.
|
||||
*
|
||||
|
@ -0,0 +1,91 @@
|
||||
<?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 communication_matrix\local\spec\features\matrix;
|
||||
|
||||
use communication_matrix\local\command;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
|
||||
/**
|
||||
* Matrix API feature to fetch room power levels using the sync API.
|
||||
*
|
||||
* https://spec.matrix.org/v1.1/client-server-api/#get_matrixclientv3sync
|
||||
*
|
||||
* @package communication_matrix
|
||||
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @codeCoverageIgnore
|
||||
* This code does not warrant being tested. Testing offers no discernible benefit given its usage is tested.
|
||||
*/
|
||||
trait get_room_powerlevels_from_sync_v3 {
|
||||
/**
|
||||
* Get a list of room members.
|
||||
*
|
||||
* @param string $roomid The room ID
|
||||
* @return Response
|
||||
*/
|
||||
public function get_room_power_levels(string $roomid): Response {
|
||||
// Filter the event data according to the API:
|
||||
// https://spec.matrix.org/v1.1/client-server-api/#filtering
|
||||
// We have to filter out all of the object data that we do not want,
|
||||
// and set a filter to only fetch the one room that we do want.
|
||||
$filter = (object) [
|
||||
"account_data" => (object) [
|
||||
// We don't want any account info for this call.
|
||||
"not_types" => ['*'],
|
||||
],
|
||||
"event_fields" => [
|
||||
// We only care about type, and content. Not sender.
|
||||
"type",
|
||||
"content",
|
||||
],
|
||||
"event_format" => "client",
|
||||
"presence" => (object) [
|
||||
// We don't need any presence data.
|
||||
"not_types" => ['*'],
|
||||
],
|
||||
"room" => (object) [
|
||||
// We only want state information for power levels, not timeline and ephemeral data.
|
||||
"rooms" => [
|
||||
$roomid,
|
||||
],
|
||||
"state" => (object) [
|
||||
"types" => [
|
||||
"m.room.power_levels",
|
||||
],
|
||||
],
|
||||
"ephemeral" => (object) [
|
||||
"not_types" => ['*'],
|
||||
],
|
||||
"timeline" => (object) [
|
||||
"not_types" => ['*'],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$query = [
|
||||
'filter' => json_encode($filter),
|
||||
];
|
||||
|
||||
return $this->execute(new command(
|
||||
$this,
|
||||
method: 'GET',
|
||||
endpoint: '_matrix/client/v3/sync',
|
||||
query: $query,
|
||||
sendasjson: false,
|
||||
));
|
||||
}
|
||||
}
|
@ -31,7 +31,6 @@ use GuzzleHttp\Psr7\Response;
|
||||
* This code does not warrant being tested. Testing offers no discernible benefit given its usage is tested.
|
||||
*/
|
||||
trait media_create_v1 {
|
||||
|
||||
/**
|
||||
* Create a media URI.
|
||||
*
|
||||
|
@ -31,7 +31,6 @@ use GuzzleHttp\Psr7\Response;
|
||||
* This code does not warrant being tested. Testing offers no discernible benefit given its usage is tested.
|
||||
*/
|
||||
trait remove_member_from_room_v3 {
|
||||
|
||||
/**
|
||||
* Remove a member from a room.
|
||||
*
|
||||
|
@ -31,7 +31,6 @@ use GuzzleHttp\Psr7\Response;
|
||||
* This code does not warrant being tested. Testing offers no discernible benefit given its usage is tested.
|
||||
*/
|
||||
trait update_room_avatar_v3 {
|
||||
|
||||
/**
|
||||
* Set the avatar for a room to the specified URL.
|
||||
*
|
||||
@ -56,5 +55,4 @@ trait update_room_avatar_v3 {
|
||||
params: $params,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -31,7 +31,6 @@ use GuzzleHttp\Psr7\Response;
|
||||
* This code does not warrant being tested. Testing offers no discernible benefit given its usage is tested.
|
||||
*/
|
||||
trait update_room_name_v3 {
|
||||
|
||||
/**
|
||||
* Set the name for a room.
|
||||
*
|
||||
|
@ -0,0 +1,77 @@
|
||||
<?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 communication_matrix\local\spec\features\matrix;
|
||||
|
||||
use communication_matrix\local\command;
|
||||
use communication_matrix\matrix_constants;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
|
||||
/**
|
||||
* Matrix API feature to update a room power levels.
|
||||
*
|
||||
* Matrix rooms have a concept of power levels, which are used to determine what actions a user can perform in a room.
|
||||
*
|
||||
* https://spec.matrix.org/v1.1/client-server-api/#mroompower_levels
|
||||
*
|
||||
* @package communication_matrix
|
||||
* @copyright 2023 Safat Shahin <safat.shahin@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @codeCoverageIgnore
|
||||
* This code does not warrant being tested. Testing offers no discernible benefit given its usage is tested.
|
||||
*/
|
||||
trait update_room_power_levels_v3 {
|
||||
/**
|
||||
* Set the avatar for a room to the specified URL.
|
||||
*
|
||||
* @param string $roomid The roomid to set for
|
||||
* @param array $users The users to set power levels for
|
||||
* @param int $ban The level required to ban a user
|
||||
* @param int $invite The level required to invite a user
|
||||
* @param int $kick The level required to kick a user
|
||||
* @param array $notifications The level required to send notifications
|
||||
* @param int $redact The level required to redact events
|
||||
* @return Response
|
||||
*/
|
||||
public function update_room_power_levels(
|
||||
string $roomid,
|
||||
array $users,
|
||||
int $ban = matrix_constants::POWER_LEVEL_MAXIMUM,
|
||||
int $invite = matrix_constants::POWER_LEVEL_MODERATOR,
|
||||
int $kick = matrix_constants::POWER_LEVEL_MODERATOR,
|
||||
array $notifications = [
|
||||
'room' => matrix_constants::POWER_LEVEL_MODERATOR,
|
||||
],
|
||||
int $redact = matrix_constants::POWER_LEVEL_MODERATOR,
|
||||
): Response {
|
||||
$params = [
|
||||
':roomid' => $roomid,
|
||||
'ban' => $ban,
|
||||
'invite' => $invite,
|
||||
'kick' => $kick,
|
||||
'notifications' => $notifications,
|
||||
'redact' => $redact,
|
||||
'users' => $users,
|
||||
];
|
||||
|
||||
return $this->execute(new command(
|
||||
$this,
|
||||
method: 'PUT',
|
||||
endpoint: '_matrix/client/v3/rooms/:roomid/state/m.room.power_levels',
|
||||
params: $params,
|
||||
));
|
||||
}
|
||||
}
|
@ -31,7 +31,6 @@ use GuzzleHttp\Psr7\Response;
|
||||
* This code does not warrant being tested. Testing offers no discernible benefit given its usage is tested.
|
||||
*/
|
||||
trait update_room_topic_v3 {
|
||||
|
||||
/**
|
||||
* Set the topic for a room.
|
||||
*
|
||||
@ -51,6 +50,5 @@ trait update_room_topic_v3 {
|
||||
endpoint: '_matrix/client/v3/rooms/:roomid/state/m.room.topic',
|
||||
params: $params,
|
||||
));
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,6 @@ use GuzzleHttp\Psr7\Utils;
|
||||
* This code does not warrant being tested. Testing offers no discernible benefit given its usage is tested.
|
||||
*/
|
||||
trait upload_content_v3 {
|
||||
|
||||
/**
|
||||
* Upload the content in the matrix/synapse server.
|
||||
*
|
||||
@ -60,7 +59,7 @@ trait upload_content_v3 {
|
||||
sendasjson: false,
|
||||
query: $query,
|
||||
params: [
|
||||
'mediaid' => $mediaid,
|
||||
':mediaid' => $mediaid,
|
||||
],
|
||||
);
|
||||
} else {
|
||||
|
@ -31,7 +31,6 @@ use GuzzleHttp\Psr7\Response;
|
||||
* This code does not warrant being tested. Testing offers no discernible benefit given its usage is tested.
|
||||
*/
|
||||
trait create_user_v2 {
|
||||
|
||||
/**
|
||||
* Create a new user.
|
||||
*
|
||||
@ -63,5 +62,4 @@ trait create_user_v2 {
|
||||
params: $params,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -31,7 +31,6 @@ use GuzzleHttp\Psr7\Response;
|
||||
* This code does not warrant being tested. Testing offers no discernible benefit given its usage is tested.
|
||||
*/
|
||||
trait get_room_info_v1 {
|
||||
|
||||
/**
|
||||
* Get room info.
|
||||
*
|
||||
|
@ -31,7 +31,6 @@ use GuzzleHttp\Psr7\Response;
|
||||
* This code does not warrant being tested. Testing offers no discernible benefit given its usage is tested.
|
||||
*/
|
||||
trait get_user_info_v2 {
|
||||
|
||||
/**
|
||||
* Get user info.
|
||||
*
|
||||
@ -49,5 +48,4 @@ trait get_user_info_v2 {
|
||||
],
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -31,7 +31,6 @@ use GuzzleHttp\Psr7\Response;
|
||||
* This code does not warrant being tested. Testing offers no discernible benefit given its usage is tested.
|
||||
*/
|
||||
trait invite_member_to_room_v1 {
|
||||
|
||||
/**
|
||||
* Join a user to a room.
|
||||
*
|
||||
|
@ -34,6 +34,8 @@ class v1p1 extends \communication_matrix\matrix_client {
|
||||
use features\matrix\update_room_name_v3;
|
||||
use features\matrix\update_room_topic_v3;
|
||||
use features\matrix\upload_content_v3;
|
||||
use features\matrix\update_room_power_levels_v3;
|
||||
use features\matrix\get_room_powerlevels_from_sync_v3;
|
||||
|
||||
// We use the Synapse API here because it can invite users to a room without requiring them to accept the invite.
|
||||
use features\synapse\invite_member_to_room_v1;
|
||||
|
@ -30,6 +30,5 @@ class v1p7 extends v1p6 {
|
||||
// Note: A new Content Upload API was introduced.
|
||||
// See details in the spec:
|
||||
// https://github.com/matrix-org/matrix-spec-proposals/pull/2246.
|
||||
|
||||
use features\matrix\media_create_v1;
|
||||
}
|
||||
|
@ -36,7 +36,6 @@ use GuzzleHttp\Psr7\Response;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
abstract class matrix_client {
|
||||
|
||||
/** @var string $serverurl The URL of the home server */
|
||||
/** @var string $accesstoken The access token of the matrix server */
|
||||
|
||||
|
51
communication/provider/matrix/classes/matrix_constants.php
Normal file
51
communication/provider/matrix/classes/matrix_constants.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?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 communication_matrix;
|
||||
|
||||
/**
|
||||
* class matrix_constants to have one location to store all constants related to matrix.
|
||||
*
|
||||
* @package communication_matrix
|
||||
* @copyright 2023 Safat Shahin <safat.shahin@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class matrix_constants {
|
||||
/**
|
||||
* User default power level for matrix.
|
||||
*/
|
||||
public const POWER_LEVEL_DEFAULT = 0;
|
||||
|
||||
/**
|
||||
* User moderator power level for matrix.
|
||||
*/
|
||||
public const POWER_LEVEL_MODERATOR = 50;
|
||||
|
||||
/**
|
||||
* User moderator power level for matrix.
|
||||
*/
|
||||
public const POWER_LEVEL_MOODLE_MODERATOR = 51;
|
||||
|
||||
/**
|
||||
* User power level for matrix associated to moodle site admins. It is a custom power level for site admins.
|
||||
*/
|
||||
public const POWER_LEVEL_MOODLE_SITE_ADMIN = 90;
|
||||
|
||||
/**
|
||||
* User maximum power level for matrix. This is only associated to the token user to allow god mode actions.
|
||||
*/
|
||||
public const POWER_LEVEL_MAXIMUM = 100;
|
||||
}
|
@ -26,7 +26,6 @@ use stdClass;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class matrix_room {
|
||||
|
||||
private const TABLE = 'matrix_room';
|
||||
|
||||
/** @var \stdClass|null $record The matrix room record from db */
|
||||
|
@ -24,7 +24,6 @@ namespace communication_matrix;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class matrix_user_manager {
|
||||
|
||||
/**
|
||||
* Gets matrix user id from moodle.
|
||||
*
|
||||
@ -33,7 +32,7 @@ class matrix_user_manager {
|
||||
*/
|
||||
public static function get_matrixid_from_moodle(
|
||||
int $userid,
|
||||
) : ?string {
|
||||
): ?string {
|
||||
self::load_requirements();
|
||||
$field = profile_user_record($userid);
|
||||
$matrixprofilefield = get_config('communication_matrix', 'matrixuserid_field');
|
||||
@ -141,7 +140,7 @@ class matrix_user_manager {
|
||||
// Check if matrixuserid exists in user_info_field table.
|
||||
$matrixuserid = $DB->count_records('user_info_field', [
|
||||
'shortname' => 'matrixuserid',
|
||||
'categoryid' => $categoryid
|
||||
'categoryid' => $categoryid,
|
||||
]);
|
||||
|
||||
if ($matrixuserid < 1) {
|
||||
@ -158,7 +157,7 @@ class matrix_user_manager {
|
||||
'visible' => 0,
|
||||
'locked' => 1,
|
||||
'param1' => 30,
|
||||
'param2' => 2048
|
||||
'param2' => 2048,
|
||||
];
|
||||
|
||||
$profileclass->define_save($data);
|
||||
|
@ -27,7 +27,6 @@ use core_privacy\local\metadata\null_provider;
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class provider implements null_provider {
|
||||
|
||||
/**
|
||||
* Get the language string identifier with the component's language
|
||||
* file to explain why this plugin stores no data.
|
||||
|
39
communication/provider/matrix/db/access.php
Normal file
39
communication/provider/matrix/db/access.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Capability definitions for matrix communication.
|
||||
*
|
||||
* @package communication_matrix
|
||||
* @copyright 2023 Safat Shahin <safat.shahin@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$capabilities = [
|
||||
|
||||
// Matrix moderator capability which aligns with the matrix moderator role or power level 50.
|
||||
'communication/matrix:moderator' => [
|
||||
'captype' => 'read',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'archetypes' => [
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'manager' => CAP_ALLOW,
|
||||
'teacher' => CAP_ALLOW,
|
||||
],
|
||||
],
|
||||
];
|
@ -52,5 +52,4 @@ function xmldb_communication_matrix_upgrade($oldversion) {
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
@ -35,5 +35,6 @@ $string['matrixelementurl'] = 'Element web URL';
|
||||
$string['matrixelementurl_desc'] = 'The URL to Element Web instance.';
|
||||
$string['matrixroomtopic'] = 'Room topic';
|
||||
$string['matrixroomtopic_help'] = 'A short description of what this room is for.';
|
||||
$string['matrix:moderator'] = 'Matrix moderator';
|
||||
$string['pluginname'] = 'Matrix';
|
||||
$string['privacy:metadata'] = 'Matrix communication plugin does not store any personal data.';
|
||||
|
@ -14,6 +14,8 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// phpcs:disable PSR1.Classes.ClassDeclaration.MissingNamespace
|
||||
|
||||
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
|
||||
use communication_matrix\matrix_test_helper_trait;
|
||||
use Moodle\BehatExtension\Exception\SkippedException;
|
||||
@ -31,7 +33,6 @@ require_once(__DIR__ . '/../../../../tests/communication_test_helper_trait.php')
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class behat_communication_matrix extends \behat_base {
|
||||
|
||||
use \core_communication\communication_test_helper_trait;
|
||||
use matrix_test_helper_trait;
|
||||
|
||||
|
@ -18,6 +18,7 @@ namespace communication_matrix;
|
||||
|
||||
use core_communication\api;
|
||||
use core_communication\communication_test_helper_trait;
|
||||
use core_communication\processor;
|
||||
use stored_file;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
@ -32,6 +33,7 @@ require_once(__DIR__ . '/../../../tests/communication_test_helper_trait.php');
|
||||
* @category test
|
||||
* @copyright 2023 Safat Shahin <safat.shahin@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @covers \communication_matrix\communication_feature
|
||||
* @coversDefaultClass \communication_matrix\communication_feature
|
||||
*/
|
||||
class communication_feature_test extends \advanced_testcase {
|
||||
@ -66,6 +68,7 @@ class communication_feature_test extends \advanced_testcase {
|
||||
],
|
||||
);
|
||||
|
||||
// phpcs:ignore moodle.Commenting.InlineComment.DocBlock
|
||||
/** @var communication_feature */
|
||||
$provider = $communication->get_room_provider();
|
||||
$this->assertInstanceOf(
|
||||
@ -124,6 +127,7 @@ class communication_feature_test extends \advanced_testcase {
|
||||
roomtopic: 'Our room topic',
|
||||
);
|
||||
|
||||
// phpcs:ignore moodle.Commenting.InlineComment.DocBlock
|
||||
/** @var communication_feature */
|
||||
$provider = $communication->get_room_provider();
|
||||
$this->assertInstanceOf(
|
||||
@ -191,7 +195,6 @@ class communication_feature_test extends \advanced_testcase {
|
||||
'Our updated room name',
|
||||
$communication->get_room_name(),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -360,8 +363,11 @@ class communication_feature_test extends \advanced_testcase {
|
||||
* @covers ::add_members_to_room
|
||||
* @covers ::add_registered_matrix_user_to_room
|
||||
* @covers ::check_room_membership
|
||||
* @covers ::set_matrix_power_levels
|
||||
*/
|
||||
public function test_add_and_remove_members_from_room(): void {
|
||||
$this->markTestSkipped('Skipping while we update the Mock Server with the new route');
|
||||
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
|
||||
@ -396,6 +402,98 @@ class communication_feature_test extends \advanced_testcase {
|
||||
$this->assertContains("@{$user2->username}", $userids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test update of room membership.
|
||||
*
|
||||
* @covers ::update_room_membership
|
||||
* @covers ::set_matrix_power_levels
|
||||
* @covers ::is_power_levels_update_required
|
||||
* @covers ::get_user_allowed_power_level
|
||||
*/
|
||||
public function test_update_room_membership(): void {
|
||||
$this->markTestSkipped('Skipping while we update the Mock Server with the new route');
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
global $DB;
|
||||
|
||||
// Create a new room.
|
||||
$course = $this->get_course('Sampleroom', 'none');
|
||||
$user = $this->get_user();
|
||||
|
||||
$communication = $this->create_room(
|
||||
component: 'core_course',
|
||||
itemtype: 'coursecommunication',
|
||||
itemid: $course->id
|
||||
);
|
||||
$provider = $communication->get_room_user_provider();
|
||||
|
||||
// Add the members to the room.
|
||||
$provider->add_members_to_room([$user->id]);
|
||||
|
||||
// Assign teacher role to the user.
|
||||
$coursecontext = \context_course::instance($course->id);
|
||||
$teacherrole = $DB->get_record('role', ['shortname' => 'teacher']);
|
||||
$this->getDataGenerator()->enrol_user($user->id, $course->id);
|
||||
role_assign($teacherrole->id, $user->id, $coursecontext->id);
|
||||
|
||||
// Test the tasks added as the role is a teacher.
|
||||
$provider->update_room_membership([$user->id]);
|
||||
|
||||
$processor = \core_communication\processor::load_by_instance(
|
||||
component: 'core_course',
|
||||
instancetype: 'coursecommunication',
|
||||
instanceid: $course->id,
|
||||
);
|
||||
$synceduser = $processor->get_instance_userids(
|
||||
synced: true,
|
||||
);
|
||||
$synceduser = reset($synceduser);
|
||||
|
||||
// Test if the communication user record is synced.
|
||||
$this->assertEquals($user->id, $synceduser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the user power level allocation according to context.
|
||||
*
|
||||
* @covers ::get_user_allowed_power_level
|
||||
*/
|
||||
public function test_get_user_allowed_power_level(): void {
|
||||
$this->resetAfterTest();
|
||||
global $DB;
|
||||
|
||||
// Create users.
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
|
||||
$course = $this->get_course();
|
||||
$coursecontext = \context_course::instance($course->id);
|
||||
$teacherrole = $DB->get_record('role', ['shortname' => 'editingteacher']);
|
||||
$studentrole = $DB->get_record('role', ['shortname' => 'student']);
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id);
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id);
|
||||
// Assign roles.
|
||||
role_assign($teacherrole->id, $user1->id, $coursecontext->id);
|
||||
role_assign($studentrole->id, $user2->id, $coursecontext->id);
|
||||
|
||||
$communicationprocessor = processor::load_by_instance(
|
||||
component: 'core_course',
|
||||
instancetype: 'coursecommunication',
|
||||
instanceid: $course->id
|
||||
);
|
||||
|
||||
// Test if the power level is set according to the context.
|
||||
$this->assertEquals(
|
||||
matrix_constants::POWER_LEVEL_MOODLE_MODERATOR,
|
||||
$communicationprocessor->get_room_provider()->get_user_allowed_power_level($user1->id)
|
||||
);
|
||||
$this->assertEquals(
|
||||
matrix_constants::POWER_LEVEL_DEFAULT,
|
||||
$communicationprocessor->get_room_provider()->get_user_allowed_power_level($user2->id)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to create a room.
|
||||
*
|
||||
|
@ -266,7 +266,7 @@ class command_test extends \advanced_testcase {
|
||||
mock: $mock,
|
||||
);
|
||||
|
||||
$mock->append(function(Request $request) use ($expected): Response {
|
||||
$mock->append(function (Request $request) use ($expected): Response {
|
||||
$this->assertSame(
|
||||
$expected,
|
||||
$request->getUri()->getQuery(),
|
||||
|
@ -301,7 +301,7 @@ class matrix_client_test extends \advanced_testcase {
|
||||
*/
|
||||
public function require_features_provider(): array {
|
||||
// We'll just add to the standard testcases.
|
||||
$testcases = array_map(static function(array $testcase): array {
|
||||
$testcases = array_map(static function (array $testcase): array {
|
||||
$testcase[1] = [$testcase[1]];
|
||||
return $testcase;
|
||||
}, $this->implements_feature_provider());
|
||||
|
@ -47,7 +47,7 @@ trait matrix_client_test_trait {
|
||||
mocked_matrix_client::reset_client();
|
||||
}
|
||||
|
||||
public function tearDown():void {
|
||||
public function tearDown(): void {
|
||||
parent::tearDown();
|
||||
|
||||
// Reset the test client.
|
||||
|
@ -26,7 +26,6 @@ namespace communication_matrix;
|
||||
* @coversDefaultClass \communication_matrix\matrix_room
|
||||
*/
|
||||
class matrix_room_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test for load_by_processor_id with no record.
|
||||
*
|
||||
@ -84,7 +83,6 @@ class matrix_room_test extends \advanced_testcase {
|
||||
$this->assertEquals(54321, $reloadedroom->get_processor_id());
|
||||
$this->assertEquals('The topic of this room is thusly', $reloadedroom->get_topic());
|
||||
$this->assertEquals('This is a roomid', $reloadedroom->get_room_id());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -26,7 +26,6 @@ use GuzzleHttp\Psr7\Response;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
trait matrix_test_helper_trait {
|
||||
|
||||
/**
|
||||
* @var string $accesstoken The token for matrix connection
|
||||
*/
|
||||
@ -46,7 +45,7 @@ trait matrix_test_helper_trait {
|
||||
$this->matrixhomeserverurl = TEST_COMMUNICATION_MATRIX_MOCK_SERVER;
|
||||
set_config('matrixhomeserverurl', $this->matrixhomeserverurl, 'communication_matrix');
|
||||
$request = $this->request();
|
||||
$response = $request->post($this->matrixhomeserverurl. '/backoffice/create-admin');
|
||||
$response = $request->post($this->matrixhomeserverurl . '/backoffice/create-admin');
|
||||
$admindata = json_decode($response->getBody());
|
||||
$json = [
|
||||
'identifier' => [
|
||||
@ -57,7 +56,7 @@ trait matrix_test_helper_trait {
|
||||
'password' => $admindata->password,
|
||||
];
|
||||
$request = $this->request($json);
|
||||
$response = $request->post($this->matrixhomeserverurl. '/_matrix/client/r0/login');
|
||||
$response = $request->post($this->matrixhomeserverurl . '/_matrix/client/r0/login');
|
||||
$response = json_decode($response->getBody());
|
||||
if (empty($response->access_token)) {
|
||||
$this->markTestSkipped(
|
||||
@ -161,10 +160,15 @@ trait matrix_test_helper_trait {
|
||||
array $rooms = [],
|
||||
): Response {
|
||||
$client = new \core\http_client();
|
||||
return $client->put($this->get_backoffice_uri('create'), ['json' => [
|
||||
'users' => $users,
|
||||
'rooms' => $rooms,
|
||||
]]);
|
||||
return $client->put(
|
||||
$this->get_backoffice_uri('create'),
|
||||
[
|
||||
'json' => [
|
||||
'users' => $users,
|
||||
'rooms' => $rooms,
|
||||
],
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -225,7 +229,7 @@ trait matrix_test_helper_trait {
|
||||
public function reset_mock(): void {
|
||||
if (defined('TEST_COMMUNICATION_MATRIX_MOCK_SERVER')) {
|
||||
$request = $this->request();
|
||||
$response = $request->post(TEST_COMMUNICATION_MATRIX_MOCK_SERVER. '/backoffice/reset');
|
||||
$response = $request->post(TEST_COMMUNICATION_MATRIX_MOCK_SERVER . '/backoffice/reset');
|
||||
$response = json_decode($response->getBody());
|
||||
if (empty($response->reset)) {
|
||||
$this->markTestSkipped(
|
||||
|
@ -25,6 +25,6 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->component = 'communication_matrix';
|
||||
$plugin->version = 2023071900;
|
||||
$plugin->version = 2023090600;
|
||||
$plugin->requires = 2023011300;
|
||||
$plugin->maturity = MATURITY_ALPHA;
|
||||
|
@ -27,10 +27,9 @@ require_once(__DIR__ . '/communication_test_helper_trait.php');
|
||||
* @category test
|
||||
* @copyright 2023 Safat Shahin <safat.shahin@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @covers \core_communication\api
|
||||
* @covers \core_communication\api
|
||||
*/
|
||||
class api_test extends \advanced_testcase {
|
||||
|
||||
use communication_test_helper_trait;
|
||||
|
||||
public function setUp(): void {
|
||||
@ -251,9 +250,12 @@ class api_test extends \advanced_testcase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the update_room_membership for adding adn removing members.
|
||||
* Test the adding and removing of members from room.
|
||||
*
|
||||
* @covers ::add_members_to_room
|
||||
* @covers ::remove_members_from_room
|
||||
*/
|
||||
public function test_update_room_membership(): void {
|
||||
public function test_adding_and_removing_of_room_membership(): void {
|
||||
$course = $this->get_course();
|
||||
$userid = $this->get_user()->id;
|
||||
|
||||
@ -281,11 +283,40 @@ class api_test extends \advanced_testcase {
|
||||
* Test the enabled communication plugin list and default.
|
||||
*/
|
||||
public function test_get_enabled_providers_and_default(): void {
|
||||
list($communicationproviders, $defaulprovider) = \core_communication\api::get_enabled_providers_and_default();
|
||||
[$communicationproviders, $defaulprovider] = \core_communication\api::get_enabled_providers_and_default();
|
||||
// Get the communication plugins.
|
||||
$plugins = \core_component::get_plugin_list('communication');
|
||||
// Check the number of plugins matches plus 1 as we have none in the selection.
|
||||
$this->assertCount(count($plugins) + 1, $communicationproviders);
|
||||
$this->assertEquals(processor::PROVIDER_NONE, $defaulprovider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the update of room membership with the change user role.
|
||||
*
|
||||
* @covers ::update_room_membership
|
||||
*/
|
||||
public function test_update_room_membership_on_user_role_change(): void {
|
||||
global $DB;
|
||||
|
||||
// Generate the data.
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$course = $this->get_course();
|
||||
$coursecontext = \context_course::instance($course->id);
|
||||
$teacherrole = $DB->get_record('role', ['shortname' => 'teacher']);
|
||||
$this->getDataGenerator()->enrol_user($user->id, $course->id);
|
||||
|
||||
$adhoctask = \core\task\manager::get_adhoc_tasks('\\core_communication\\task\\add_members_to_room_task');
|
||||
$this->assertCount(1, $adhoctask);
|
||||
|
||||
$adhoctask = reset($adhoctask);
|
||||
$this->assertInstanceOf('\\core_communication\\task\\add_members_to_room_task', $adhoctask);
|
||||
|
||||
// Test the tasks added as the role is a teacher.
|
||||
$adhoctask = \core\task\manager::get_adhoc_tasks('\\core_communication\\task\\update_room_membership_task');
|
||||
$this->assertCount(1, $adhoctask);
|
||||
|
||||
$adhoctask = reset($adhoctask);
|
||||
$this->assertInstanceOf('\\core_communication\\task\\update_room_membership_task', $adhoctask);
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,8 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// phpcs:disable PSR1.Classes.ClassDeclaration.MissingNamespace
|
||||
|
||||
require_once(__DIR__ . '/../../../lib/behat/behat_base.php');
|
||||
require_once(__DIR__ . '/../../tests/communication_test_helper_trait.php');
|
||||
|
||||
@ -26,7 +28,6 @@ require_once(__DIR__ . '/../../tests/communication_test_helper_trait.php');
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class behat_communication extends \behat_base {
|
||||
|
||||
use \core_communication\communication_test_helper_trait;
|
||||
|
||||
/**
|
||||
|
@ -25,7 +25,6 @@ namespace core_communication;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
trait communication_test_helper_trait {
|
||||
|
||||
/**
|
||||
* Setup necessary configs for communication subsystem.
|
||||
*
|
||||
@ -83,7 +82,7 @@ trait communication_test_helper_trait {
|
||||
$records = [
|
||||
'firstname' => $firstname,
|
||||
'lastname' => $lastname,
|
||||
'username' => $username
|
||||
'username' => $username,
|
||||
];
|
||||
|
||||
return $this->getDataGenerator()->create_user($records);
|
||||
|
@ -30,7 +30,6 @@ require_once(__DIR__ . '/communication_test_helper_trait.php');
|
||||
* @coversDefaultClass \core_communication\processor
|
||||
*/
|
||||
class processor_test extends \advanced_testcase {
|
||||
|
||||
use communication_test_helper_trait;
|
||||
|
||||
/**
|
||||
@ -61,8 +60,10 @@ class processor_test extends \advanced_testcase {
|
||||
);
|
||||
|
||||
// Now test the record against the database.
|
||||
$communicationrecord = $DB->get_record('communication',
|
||||
['instanceid' => $instanceid, 'component' => $component, 'instancetype' => $instancetype]);
|
||||
$communicationrecord = $DB->get_record(
|
||||
'communication',
|
||||
['instanceid' => $instanceid, 'component' => $component, 'instancetype' => $instancetype]
|
||||
);
|
||||
|
||||
// Test against the set data.
|
||||
$this->assertNotEmpty($communicationrecord);
|
||||
@ -114,7 +115,7 @@ class processor_test extends \advanced_testcase {
|
||||
$communicationrecord = $DB->get_record('communication', [
|
||||
'instanceid' => $instanceid,
|
||||
'component' => $component,
|
||||
'instancetype' => $instancetype
|
||||
'instancetype' => $instancetype,
|
||||
]);
|
||||
|
||||
// Test against the set data.
|
||||
@ -163,7 +164,7 @@ class processor_test extends \advanced_testcase {
|
||||
$communicationrecord = $DB->get_record('communication', [
|
||||
'instanceid' => $instanceid,
|
||||
'component' => $component,
|
||||
'instancetype' => $instancetype
|
||||
'instancetype' => $instancetype,
|
||||
]);
|
||||
|
||||
// Test against the set data.
|
||||
@ -173,7 +174,8 @@ class processor_test extends \advanced_testcase {
|
||||
$communicationprocessor = processor::load_by_instance(
|
||||
$component,
|
||||
$instancetype,
|
||||
$instanceid);
|
||||
$instanceid
|
||||
);
|
||||
$this->assertNull($communicationprocessor);
|
||||
}
|
||||
|
||||
@ -428,4 +430,44 @@ class processor_test extends \advanced_testcase {
|
||||
set_config('disabled', 1, $communicationprovider);
|
||||
$this->assertFalse(processor::is_provider_enabled($communicationprovider));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test delete flagged user id's return correct users.
|
||||
*
|
||||
* @covers ::get_all_delete_flagged_userids
|
||||
*/
|
||||
public function test_get_all_delete_flagged_userids(): void {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$course = $this->get_course('Sampleroom', 'none');
|
||||
$user1 = $this->getDataGenerator()->create_user()->id;
|
||||
$user2 = $this->getDataGenerator()->create_user()->id;
|
||||
|
||||
// Sample data.
|
||||
$communicationroomname = 'Sampleroom';
|
||||
$selectedcommunication = 'communication_matrix';
|
||||
$component = 'core_course';
|
||||
$instancetype = 'coursecommunication';
|
||||
|
||||
// Load the communication api.
|
||||
$communication = \core_communication\api::load_by_instance(
|
||||
'core_course',
|
||||
'coursecommunication',
|
||||
$course->id
|
||||
);
|
||||
$communication->create_and_configure_room($selectedcommunication, $communicationroomname);
|
||||
$communication->add_members_to_room([$user1, $user2]);
|
||||
|
||||
// Now remove user1 from the room.
|
||||
$communication->remove_members_from_room([$user1]);
|
||||
|
||||
// Test against the object.
|
||||
$communicationprocessor = processor::load_by_instance(
|
||||
$component,
|
||||
$instancetype,
|
||||
$course->id
|
||||
);
|
||||
|
||||
$this->assertEquals([$user1], $communicationprocessor->get_all_delete_flagged_userids());
|
||||
}
|
||||
}
|
||||
|
@ -1645,6 +1645,17 @@ function role_assign($roleid, $userid, $contextid, $component = '', $itemid = 0,
|
||||
|
||||
core_course_category::role_assignment_changed($roleid, $context);
|
||||
|
||||
// Update the room membership and power levels when the user role changes.
|
||||
if (\core_communication\api::is_available() && $coursecontext = $context->get_course_context(false)) {
|
||||
$communication = \core_communication\api::load_by_instance(
|
||||
'core_course',
|
||||
'coursecommunication',
|
||||
$coursecontext->instanceid,
|
||||
);
|
||||
|
||||
$communication->update_room_membership([$userid]);
|
||||
}
|
||||
|
||||
$event = \core\event\role_assigned::create(array(
|
||||
'context' => $context,
|
||||
'objectid' => $ra->roleid,
|
||||
@ -1750,6 +1761,19 @@ function role_unassign_all(array $params, $subcontexts = false, $includemanual =
|
||||
$event->add_record_snapshot('role_assignments', $ra);
|
||||
$event->trigger();
|
||||
core_course_category::role_assignment_changed($ra->roleid, $context);
|
||||
|
||||
// Update the room membership and power levels when the user role changes.
|
||||
if (\core_communication\api::is_available() && $coursecontext = $context->get_course_context(false)) {
|
||||
$communication = \core_communication\api::load_by_instance(
|
||||
'core_course',
|
||||
'coursecommunication',
|
||||
$coursecontext->instanceid,
|
||||
);
|
||||
|
||||
$communication->update_room_membership([$ra->userid]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
unset($ras);
|
||||
|
Loading…
x
Reference in New Issue
Block a user