diff --git a/communication/classes/api.php b/communication/classes/api.php index d49c00543275b..40d73715b9519 100644 --- a/communication/classes/api.php +++ b/communication/classes/api.php @@ -56,6 +56,7 @@ class api { * @param string $component The component of the item for the instance * @param string $instancetype The type of the item for the instance * @param int $instanceid The id of the instance + * @param string|null $provider The provider type - if null will load for this context's active provider. * */ private function __construct( @@ -63,12 +64,14 @@ private function __construct( private string $component, private string $instancetype, private int $instanceid, + private ?string $provider = null, ) { $this->communication = processor::load_by_instance( context: $context, component: $component, instancetype: $instancetype, instanceid: $instanceid, + provider: $provider, ); } @@ -79,6 +82,7 @@ private function __construct( * @param string $component The component of the item for the instance * @param string $instancetype The type of the item for the instance * @param int $instanceid The id of the instance + * @param string|null $provider The provider type - if null will load for this context's active provider. * @return api */ public static function load_by_instance( @@ -86,12 +90,14 @@ public static function load_by_instance( string $component, string $instancetype, int $instanceid, + ?string $provider = null, ): self { return new self( context: $context, component: $component, instancetype: $instancetype, instanceid: $instanceid, + provider: $provider, ); } @@ -104,6 +110,7 @@ public function reload(): void { component: $this->component, instancetype: $this->instancetype, instanceid: $this->instanceid, + provider: $this->provider, ); } @@ -246,31 +253,33 @@ public function form_definition( * @param string $provider The provider name */ public function form_definition_for_provider(\MoodleQuickForm $mform, string $provider = processor::PROVIDER_NONE): void { - if ($provider !== processor::PROVIDER_NONE) { - // Room name for the communication provider. - $mform->insertElementBefore( - $mform->createElement( - 'text', - 'communicationroomname', - get_string('communicationroomname', 'communication'), - 'maxlength="100" size="20"' - ), - 'addcommunicationoptionshere' - ); - $mform->setType('communicationroomname', PARAM_TEXT); - - $mform->insertElementBefore( - $mform->createElement( - 'static', - 'communicationroomnameinfo', - '', - get_string('communicationroomnameinfo', 'communication'), - ), - 'addcommunicationoptionshere', - ); - - processor::set_provider_specific_form_definition($provider, $mform); + if ($provider === processor::PROVIDER_NONE) { + return; } + + // Room name for the communication provider. + $mform->insertElementBefore( + $mform->createElement( + 'text', + 'communicationroomname', + get_string('communicationroomname', 'communication'), + 'maxlength="100" size="20"' + ), + 'addcommunicationoptionshere' + ); + $mform->setType('communicationroomname', PARAM_TEXT); + + $mform->insertElementBefore( + $mform->createElement( + 'static', + 'communicationroomnameinfo', + '', + get_string('communicationroomnameinfo', 'communication'), + ), + 'addcommunicationoptionshere', + ); + + processor::set_provider_specific_form_definition($provider, $mform); } /** @@ -407,109 +416,99 @@ public function create_and_configure_room( ?\stored_file $avatar = null, ?\stdClass $instance = null, ): void { - if ($selectedcommunication !== processor::PROVIDER_NONE && $selectedcommunication !== '') { - // Create communication record. - $this->communication = processor::create_instance( - context: $this->context, - provider: $selectedcommunication, - instanceid: $this->instanceid, - component: $this->component, - instancetype: $this->instancetype, - roomname: $communicationroomname, - ); + if ($selectedcommunication === processor::PROVIDER_NONE || $selectedcommunication === '') { + return; + } - // Update provider record from form data. - if ($instance !== null) { - $this->communication->get_form_provider()->save_form_data($instance); - } + // Create communication record. + $this->communication = processor::create_instance( + context: $this->context, + provider: $selectedcommunication, + instanceid: $this->instanceid, + component: $this->component, + instancetype: $this->instancetype, + roomname: $communicationroomname, + ); - // Set the avatar. - if (!empty($avatar)) { - $this->set_avatar($avatar); - } + // Update provider record from form data. + if ($instance !== null) { + $this->communication->get_form_provider()->save_form_data($instance); + } - // Add ad-hoc task to create the provider room. - create_and_configure_room_task::queue( - $this->communication, - ); + // Set the avatar. + if (!empty($avatar)) { + $this->set_avatar($avatar); } + + // Add ad-hoc task to create the provider room. + create_and_configure_room_task::queue( + $this->communication, + ); } /** * Create a communication ad-hoc task for update operation. * This method will add a task to the queue to update the room. * - * @param string $selectedprovider The selected communication provider - * @param string $communicationroomname The communication room name + * @param null|int $active The selected active state of the provider + * @param null|string $communicationroomname The communication room name * @param null|\stored_file $avatar The stored file for the avatar * @param \stdClass|null $instance The actual instance object */ public function update_room( - ?string $selectedprovider = null, + ?int $active = null, ?string $communicationroomname = null, ?\stored_file $avatar = null, ?\stdClass $instance = null, ): void { - // Existing object found, let's update the communication record and associated actions. - if ($this->communication !== null) { - // Get the previous data to compare for update. - $previousprovider = $this->communication->get_provider(); - if ($previousprovider === $selectedprovider) { - // If the provider is the same, unset it. - $selectedprovider = null; - } - - $previousroomname = $this->communication->get_room_name(); - if ($previousroomname === $communicationroomname) { - // If the room name is the same, we don't need to update the room. - $communicationroomname = null; - } + // Reload so the currently selected provider is used. + $this->reload(); - if ($selectedprovider !== null || $communicationroomname !== null) { - // Something to update. Update communication record. - $this->communication->update_instance( - provider: $selectedprovider, - roomname: $communicationroomname, - ); - } + // If the provider is none, we don't need to do anything from room point of view. + if ($this->communication->get_provider() === processor::PROVIDER_NONE) { + return; + } - // Reload so the currently selected provider is used. - $this->reload(); + $roomnamechange = null; + $activestatuschange = null; - // Update provider record from form data. - if ($instance !== null) { - $this->communication->get_form_provider()->save_form_data($instance); - } + // Check if the room name is being changed. + if ( + $communicationroomname !== null && + $communicationroomname !== $this->communication->get_room_name() + ) { + $roomnamechange = $communicationroomname; + } - // Update the avatar. - // If the value is `null`, then unset the avatar. - $this->set_avatar($avatar); + // Check if the active status of the provider is being changed. + if ( + $active !== null && + $active !== $this->communication->is_instance_active() + ) { + $activestatuschange = $active; + } - // If the provider is none, we don't need to do anything from room point of view. - if ($this->communication->get_provider() === processor::PROVIDER_NONE) { - return; - } + if ($roomnamechange !== null || $activestatuschange !== null) { + $this->communication->update_instance( + active: $active, + roomname: $communicationroomname, + ); + } - // Add ad-hoc task to update the provider room if the room name changed. - // TODO add efficiency considering dynamic fields. - if ( - $previousprovider === $selectedprovider - ) { - update_room_task::queue( - $this->communication, - ); - } else if ( - $previousprovider !== $selectedprovider - ) { - // Add ad-hoc task to create the provider room. - create_and_configure_room_task::queue( - $this->communication, - ); - } - } else { - // The instance didn't have any communication record, so create one. - $this->create_and_configure_room($selectedprovider, $communicationroomname, $avatar, $instance); + // Update provider record from form data. + if ($instance !== null) { + $this->communication->get_form_provider()->save_form_data($instance); } + + // Update the avatar. + // If the value is `null`, then unset the avatar. + $this->set_avatar($avatar); + + // Always queue a room update, even if none of the above standard fields have changed. + // It is possible for providers to have custom fields that have been updated. + update_room_task::queue( + $this->communication, + ); } /** diff --git a/communication/classes/processor.php b/communication/classes/processor.php index e1bd735c10ed9..8f90ada1d1928 100644 --- a/communication/classes/processor.php +++ b/communication/classes/processor.php @@ -109,22 +109,17 @@ public static function create_instance( /** * Update the communication instance with any changes. * - * @param null|string $provider The communication provider + * @param null|int $active Active state of the instance (PROVIDER_ACTIVE or PROVIDER_INACTIVE) * @param null|string $roomname The room name */ public function update_instance( - ?string $provider = null, + ?string $active = null, ?string $roomname = null, ): void { global $DB; - if ($provider !== null) { - if ($provider === self::PROVIDER_NONE) { - $this->instancedata->active = self::PROVIDER_INACTIVE; - } else { - $this->instancedata->provider = $provider; - $this->instancedata->active = self::PROVIDER_ACTIVE; - } + if ($active !== null && in_array($active, [self::PROVIDER_ACTIVE, self::PROVIDER_INACTIVE])) { + $this->instancedata->active = $active; } if ($roomname !== null) { @@ -365,24 +360,38 @@ public static function load_by_id(int $id): ?self { * @param string $component The component name * @param string $instancetype The instance type * @param int $instanceid The instance id + * @param string|null $provider The provider type - if null will load for this context's active provider. * @return processor|null */ public static function load_by_instance( context $context, string $component, string $instancetype, - int $instanceid + int $instanceid, + ?string $provider = null, ): ?self { global $DB; - $record = $DB->get_record('communication', [ - 'contextid' => $context->id, - 'instanceid' => $instanceid, - 'component' => $component, - 'instancetype' => $instancetype, - ]); - + if ($provider === null) { + // Fetch the active provider in this context. + $record = $DB->get_record('communication', [ + 'contextid' => $context->id, + 'instanceid' => $instanceid, + 'component' => $component, + 'instancetype' => $instancetype, + 'active' => 1, + ]); + } else { + // Fetch a specific provider in this context (which may be inactive). + $record = $DB->get_record('communication', [ + 'contextid' => $context->id, + 'instanceid' => $instanceid, + 'component' => $component, + 'instancetype' => $instancetype, + 'provider' => $provider, + ]); + } if ($record && self::is_provider_available($record->provider)) { return new self($record); } @@ -464,15 +473,12 @@ public function get_component(): string { } /** - * Get communication provider. + * Get communication provider type. * * @return string|null */ public function get_provider(): ?string { - if ((int)$this->instancedata->active === self::PROVIDER_ACTIVE) { - return $this->instancedata->provider; - } - return self::PROVIDER_NONE; + return $this->instancedata->provider; } /** diff --git a/communication/configure.php b/communication/configure.php index 9a9f226685006..b3e16881e5bf8 100644 --- a/communication/configure.php +++ b/communication/configure.php @@ -52,6 +52,7 @@ component: $component, instancetype: $instancetype, instanceid: $instanceid, + provider: $selectedcommunication, ); // No communication, no way this form can be used. diff --git a/course/lib.php b/course/lib.php index 3cfb4f6a6d20d..0efb035360458 100644 --- a/course/lib.php +++ b/course/lib.php @@ -2292,6 +2292,7 @@ function create_course($data, $editoroptions = NULL) { component: 'core_course', instancetype: 'coursecommunication', instanceid: $course->id, + provider: $provider, ); $communication->create_and_configure_room( $provider, @@ -2461,38 +2462,99 @@ function update_course($data, $editoroptions = NULL) { $enrolledusers[] = $user->id; } + // Existing communication provider. $communication = \core_communication\api::load_by_instance( context: $context, component: 'core_course', instancetype: 'coursecommunication', instanceid: $data->id, ); + $existingprovider = $communication->get_provider(); + $addusersrequired = false; + $enablenewprovider = false; - $addafterupdate = false; - if ($provider !== $communication->get_provider()) { - // If provider set to none, remove all the members. - if ($provider === 'none') { + // Action required changes if provider has changed. + if ($provider !== $existingprovider) { + // Provider changed, flag new one to be enabled. + $enablenewprovider = true; + + // If provider set to none, remove all the members from previous provider. + if ($provider === 'none' && $existingprovider !== '') { $communication->remove_members_from_room($enrolledusers); } else if ( - // If previous provider was not none and current provider is not none, but a different provider, remove members. - $communication->get_provider() !== '' && - $communication->get_provider() !== 'none' && - $provider !== $communication->get_provider() + // If previous provider was not none and current provider is not none, + // remove members from previous provider. + $existingprovider !== '' && + $existingprovider !== 'none' ) { $communication->remove_members_from_room($enrolledusers); - $addafterupdate = true; + $addusersrequired = true; } else if ( - // If previous provider was none and current provider is not none, but a different provider, remove members. - ($communication->get_provider() === '' || $communication->get_provider() === 'none') && - $provider !== $communication->get_provider() + // If previous provider was none and current provider is not none, + // remove members from previous provider. + ($existingprovider === '' || $existingprovider === 'none') ) { - $addafterupdate = true; + $addusersrequired = true; + } + + // Disable previous provider, if one was enabled. + if ($existingprovider !== '' && $existingprovider !== 'none') { + $communication->update_room( + active: \core_communication\processor::PROVIDER_INACTIVE, + ); + } + + // Switch to the newly selected provider so it can be updated. + if ($provider !== 'none') { + $communication = \core_communication\api::load_by_instance( + context: $context, + component: 'core_course', + instancetype: 'coursecommunication', + instanceid: $data->id, + provider: $provider, + ); + + // Create it if it does not exist. + if ($communication->get_provider() === '') { + $communication->create_and_configure_room( + selectedcommunication: $provider, + communicationroomname: $communicationroomname, + avatar: $courseimage, + instance: $data + ); + + $communication = \core_communication\api::load_by_instance( + context: $context, + component: 'core_course', + instancetype: 'coursecommunication', + instanceid: $data->id, + provider: $provider, + ); + + $addusersrequired = true; + $queuememberstask = false; + } else if ($addusersrequired) { + // Existing room that requires users can queue the members task now. + $queuememberstask = true; + } + + // Complete room membership tasks if required. + // Newly created providers complete the user mapping but do not queue the task + // (it will be handled by the room creation task). + if ($addusersrequired) { + $communication->add_members_to_room($enrolledusers, $queuememberstask); + } } } - $communication->update_room($provider, $communicationroomname, $courseimage, $data); - if ($addafterupdate) { - $communication->add_members_to_room($enrolledusers, false); + if ($provider !== 'none') { + // Update the currently enabled provider's room data. + $communication->update_room( + active: $enablenewprovider ? \core_communication\processor::PROVIDER_ACTIVE : null, + communicationroomname: $communicationroomname, + avatar: $courseimage, + instance: $data, + ); } }