MDL-83893 mod_forum: Add WS calls to support toggle
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
define("mod_forum/forum_overview_toggle",["exports","core/notification","core/str","mod_forum/repository"],(function(_exports,_notification,_str,_repository){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
|
||||
/**
|
||||
* Handle forum subscription/tracking toggling.
|
||||
*
|
||||
* @module mod_forum/forum_overview_toggle
|
||||
* @copyright 2025 Sara Arjona <sara@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/function registerEventListeners(toggleElement){toggleElement.addEventListener("change",(()=>{"forum-subscription-toggle"===toggleElement.dataset.type&&async function(toggleElement){const forumId=toggleElement.dataset.forumid,newState=toggleElement.dataset.targetstate;if(!forumId||!newState)return;try{const newTargetState=!!(await _repository.default.setForumSubscriptionState(forumId,newState)).userstate.subscribed;updateSwitchState(toggleElement,newTargetState,newTargetState?"subscribe":"unsubscribe")}catch(error){_notification.default.exception(error)}}(toggleElement),"forum-track-toggle"===toggleElement.dataset.type&&async function(toggleElement){const forumId=toggleElement.dataset.forumid,newState=toggleElement.dataset.targetstate;if(!forumId||!newState)return;try{const newTargetState=!!(await _repository.default.setForumTrackingState(forumId,newState)).userstate.tracked;updateSwitchState(toggleElement,newTargetState,newTargetState?"trackingon":"trackingoff")}catch(error){_notification.default.exception(error)}}(toggleElement)}))}async function updateSwitchState(toggleElement,newTargetState,stringKey){toggleElement.dataset.targetstate=newTargetState?0:1;const string=await(0,_str.getString)(stringKey,"mod_forum");toggleElement.closest("td").querySelector('label[for="'.concat(toggleElement.id,'"] span')).textContent=string}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_notification=_interopRequireDefault(_notification),_repository=_interopRequireDefault(_repository);_exports.init=toggleSelector=>{const toggleElement=document.querySelector(toggleSelector);toggleElement&®isterEventListeners(toggleElement)}}));
|
||||
|
||||
//# sourceMappingURL=forum_overview_toggle.min.js.map
|
||||
File diff suppressed because one or more lines are too long
+1
-1
@@ -6,6 +6,6 @@
|
||||
* @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
define("mod_forum/repository",["core/ajax"],(function(Ajax){return{setDiscussionSubscriptionState:function(forumId,discussionId,targetState){var request={methodname:"mod_forum_set_subscription_state",args:{forumid:forumId,discussionid:discussionId,targetstate:targetState}};return Ajax.call([request])[0]},addDiscussionPost:function(postid,subject,message,messageformat,isprivatereply,topreferredformat){var request={methodname:"mod_forum_add_discussion_post",args:{postid:postid,message:message,messageformat:messageformat,subject:subject,options:[{name:"private",value:isprivatereply},{name:"topreferredformat",value:topreferredformat}]}};return Ajax.call([request])[0]},setDiscussionLockState:function(forumId,discussionId,targetState){var request={methodname:"mod_forum_set_lock_state",args:{forumid:forumId,discussionid:discussionId,targetstate:targetState}};return Ajax.call([request])[0]},setFavouriteDiscussionState:function(forumId,discussionId,targetState){var request={methodname:"mod_forum_toggle_favourite_state",args:{discussionid:discussionId,targetstate:targetState}};return Ajax.call([request])[0]},setPinDiscussionState:function(forumid,discussionid,targetstate){var request={methodname:"mod_forum_set_pin_state",args:{discussionid:discussionid,targetstate:targetstate}};return Ajax.call([request])[0]},getDiscussionByUserID:function(userid,cmid){let sortby=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"modified",sortdirection=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"DESC";var request={methodname:"mod_forum_get_discussion_posts_by_userid",args:{userid:userid,cmid:cmid,sortby:sortby,sortdirection:sortdirection}};return Ajax.call([request])[0]},getDiscussionPosts:function(discussionId){let sortby=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"created",sortdirection=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"ASC";var request={methodname:"mod_forum_get_discussion_posts",args:{discussionid:discussionId,sortby:sortby,sortdirection:sortdirection}};return Ajax.call([request])[0]}}}));
|
||||
define("mod_forum/repository",["core/ajax"],(function(Ajax){return{setForumSubscriptionState:function(forumId,targetState){const request={methodname:"mod_forum_set_forum_subscription",args:{forumid:forumId,targetstate:targetState}};return Ajax.call([request])[0]},setForumTrackingState:function(forumId,targetState){const request={methodname:"mod_forum_set_forum_tracking",args:{forumid:forumId,targetstate:targetState}};return Ajax.call([request])[0]},setDiscussionSubscriptionState:function(forumId,discussionId,targetState){var request={methodname:"mod_forum_set_subscription_state",args:{forumid:forumId,discussionid:discussionId,targetstate:targetState}};return Ajax.call([request])[0]},addDiscussionPost:function(postid,subject,message,messageformat,isprivatereply,topreferredformat){var request={methodname:"mod_forum_add_discussion_post",args:{postid:postid,message:message,messageformat:messageformat,subject:subject,options:[{name:"private",value:isprivatereply},{name:"topreferredformat",value:topreferredformat}]}};return Ajax.call([request])[0]},setDiscussionLockState:function(forumId,discussionId,targetState){var request={methodname:"mod_forum_set_lock_state",args:{forumid:forumId,discussionid:discussionId,targetstate:targetState}};return Ajax.call([request])[0]},setFavouriteDiscussionState:function(forumId,discussionId,targetState){var request={methodname:"mod_forum_toggle_favourite_state",args:{discussionid:discussionId,targetstate:targetState}};return Ajax.call([request])[0]},setPinDiscussionState:function(forumid,discussionid,targetstate){var request={methodname:"mod_forum_set_pin_state",args:{discussionid:discussionid,targetstate:targetstate}};return Ajax.call([request])[0]},getDiscussionByUserID:function(userid,cmid){let sortby=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"modified",sortdirection=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"DESC";var request={methodname:"mod_forum_get_discussion_posts_by_userid",args:{userid:userid,cmid:cmid,sortby:sortby,sortdirection:sortdirection}};return Ajax.call([request])[0]},getDiscussionPosts:function(discussionId){let sortby=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"created",sortdirection=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"ASC";var request={methodname:"mod_forum_get_discussion_posts",args:{discussionid:discussionId,sortby:sortby,sortdirection:sortdirection}};return Ajax.call([request])[0]}}}));
|
||||
|
||||
//# sourceMappingURL=repository.min.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,123 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Handle forum subscription/tracking toggling.
|
||||
*
|
||||
* @module mod_forum/forum_overview_toggle
|
||||
* @copyright 2025 Sara Arjona <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import Notification from 'core/notification';
|
||||
import {getString} from 'core/str';
|
||||
import Repository from 'mod_forum/repository';
|
||||
|
||||
/**
|
||||
* Register event listeners for the subscription/tracking toggles in the overview.
|
||||
* @param {HTMLElement} toggleElement The toggle root element
|
||||
*/
|
||||
function registerEventListeners(toggleElement) {
|
||||
toggleElement.addEventListener('change', () => {
|
||||
if (toggleElement.dataset.type === 'forum-subscription-toggle') {
|
||||
subscriptionToggleClickHandler(toggleElement);
|
||||
}
|
||||
if (toggleElement.dataset.type === 'forum-track-toggle') {
|
||||
trackToggleClickHanldler(toggleElement);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle subscription element click handler.
|
||||
*
|
||||
* @param {HTMLElement} toggleElement The toggle element that was clicked
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async function subscriptionToggleClickHandler(toggleElement) {
|
||||
const forumId = toggleElement.dataset.forumid;
|
||||
const newState = toggleElement.dataset.targetstate;
|
||||
if (!forumId || !newState) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const context = await Repository.setForumSubscriptionState(forumId, newState);
|
||||
const newTargetState = !!context.userstate.subscribed;
|
||||
|
||||
updateSwitchState(
|
||||
toggleElement,
|
||||
newTargetState,
|
||||
newTargetState ? 'subscribe' : 'unsubscribe',
|
||||
);
|
||||
} catch (error) {
|
||||
Notification.exception(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle track element click handler.
|
||||
*
|
||||
* @param {HTMLElement} toggleElement The toggle element that was clicked
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async function trackToggleClickHanldler(toggleElement) {
|
||||
const forumId = toggleElement.dataset.forumid;
|
||||
const newState = toggleElement.dataset.targetstate;
|
||||
if (!forumId || !newState) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const context = await Repository.setForumTrackingState(forumId, newState);
|
||||
const newTargetState = !!context.userstate.tracked;
|
||||
|
||||
updateSwitchState(
|
||||
toggleElement,
|
||||
newTargetState,
|
||||
newTargetState ? 'trackingon' : 'trackingoff',
|
||||
);
|
||||
} catch (error) {
|
||||
Notification.exception(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the switch state of the toggle element.
|
||||
*
|
||||
* @param {HTMLElement} toggleElement The toggle element to update
|
||||
* @param {Boolean} newTargetState The new target state to set (true for subscribed, false for unsubscribed)
|
||||
* @param {string} stringKey The string key to retrieve the label text
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async function updateSwitchState(toggleElement, newTargetState, stringKey) {
|
||||
toggleElement.dataset.targetstate = newTargetState ? 0 : 1;
|
||||
const string = await getString(stringKey, 'mod_forum');
|
||||
const label = toggleElement.closest('td').querySelector(`label[for="${toggleElement.id}"] span`);
|
||||
label.textContent = string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the forum overview toggle functionality.
|
||||
*
|
||||
* @param {string} toggleSelector The CSS selector for the toggle element to initialize
|
||||
* @throws {Error} If no elements are found with the provided selector
|
||||
*/
|
||||
export const init = (toggleSelector) => {
|
||||
const toggleElement = document.querySelector(toggleSelector);
|
||||
if (!toggleElement) {
|
||||
// If the user cannot track/subscribe to any course forum, the toggle will not be present.
|
||||
return;
|
||||
}
|
||||
registerEventListeners(toggleElement);
|
||||
};
|
||||
@@ -22,6 +22,42 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
define(['core/ajax'], function(Ajax) {
|
||||
/**
|
||||
* Set the subscription state for forum.
|
||||
*
|
||||
* @param {number} forumId ID of the forum to set the subscription state for
|
||||
* @param {boolean} targetState Set the subscribed state. True == subscribed; false == unsubscribed.
|
||||
* @return {object} jQuery promise
|
||||
*/
|
||||
const setForumSubscriptionState = function(forumId, targetState) {
|
||||
const request = {
|
||||
methodname: 'mod_forum_set_forum_subscription',
|
||||
args: {
|
||||
forumid: forumId,
|
||||
targetstate: targetState
|
||||
}
|
||||
};
|
||||
return Ajax.call([request])[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the tracking state for forum.
|
||||
*
|
||||
* @param {number} forumId ID of the forum to set the tracking state for
|
||||
* @param {boolean} targetState Set the tracking state for unread messages. True == track; false == untrack.
|
||||
* @return {object} jQuery promise
|
||||
*/
|
||||
const setForumTrackingState = function(forumId, targetState) {
|
||||
const request = {
|
||||
methodname: 'mod_forum_set_forum_tracking',
|
||||
args: {
|
||||
forumid: forumId,
|
||||
targetstate: targetState
|
||||
}
|
||||
};
|
||||
return Ajax.call([request])[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the subscription state for a discussion in a forum.
|
||||
*
|
||||
@@ -154,6 +190,8 @@ define(['core/ajax'], function(Ajax) {
|
||||
};
|
||||
|
||||
return {
|
||||
setForumSubscriptionState: setForumSubscriptionState,
|
||||
setForumTrackingState: setForumTrackingState,
|
||||
setDiscussionSubscriptionState: setDiscussionSubscriptionState,
|
||||
addDiscussionPost: addDiscussionPost,
|
||||
setDiscussionLockState: setDiscussionLockState,
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
<?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_forum\external;
|
||||
|
||||
use core_external\external_api;
|
||||
use core_external\external_function_parameters;
|
||||
use core_external\external_single_structure;
|
||||
use core_external\external_value;
|
||||
use mod_forum\local\exporters\forum as forum_exporter;
|
||||
|
||||
/**
|
||||
* Web Service to control the state of a forum subscription
|
||||
*
|
||||
* @package mod_forum
|
||||
* @category external
|
||||
* @copyright 2025 Sara Arjona <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class set_forum_subscription extends external_api {
|
||||
/**
|
||||
* Returns description of method parameters
|
||||
*
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function execute_parameters(): external_function_parameters {
|
||||
return new external_function_parameters(
|
||||
[
|
||||
'forumid' => new external_value(PARAM_INT, 'Forum that the user wants to subscribe or unsubscribe from'),
|
||||
'targetstate' => new external_value(PARAM_BOOL, 'The target state'),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the forum subscription state.
|
||||
*
|
||||
* @param int $forumid The forum identifier.
|
||||
* @param bool $targetstate Whether to subscribe or unsubscribe the user to the forum.
|
||||
* @return \stdClass
|
||||
*/
|
||||
public static function execute(
|
||||
int $forumid,
|
||||
bool $targetstate,
|
||||
): \stdClass {
|
||||
global $PAGE, $USER;
|
||||
|
||||
$params = self::validate_parameters(self::execute_parameters(), [
|
||||
'forumid' => $forumid,
|
||||
'targetstate' => $targetstate,
|
||||
]);
|
||||
|
||||
$vaultfactory = \mod_forum\local\container::get_vault_factory();
|
||||
$forumvault = $vaultfactory->get_forum_vault();
|
||||
$forum = $forumvault->get_from_id($params['forumid']);
|
||||
if (!$forum) {
|
||||
throw new \moodle_exception('invalidforumid', 'mod_forum', '', $params['forumid']);
|
||||
}
|
||||
$coursemodule = $forum->get_course_module_record();
|
||||
$context = $forum->get_context();
|
||||
|
||||
self::validate_context($context);
|
||||
|
||||
$legacydatamapperfactory = \mod_forum\local\container::get_legacy_data_mapper_factory();
|
||||
$forumrecord = $legacydatamapperfactory->get_forum_data_mapper()->to_legacy_object($forum);
|
||||
if (
|
||||
!\mod_forum\subscriptions::is_subscribable($forumrecord)
|
||||
&& !has_capability('mod/forum:managesubscriptions', $context)
|
||||
) {
|
||||
// Nothing to do. We won't actually output any content here though.
|
||||
throw new \moodle_exception('cannotsubscribe', 'mod_forum');
|
||||
}
|
||||
|
||||
$issubscribed = \mod_forum\subscriptions::is_subscribed(
|
||||
$USER->id,
|
||||
$forumrecord,
|
||||
null,
|
||||
$coursemodule
|
||||
);
|
||||
|
||||
// If the current state doesn't equal the desired state then update the current
|
||||
// state to the desired state.
|
||||
if ($issubscribed != (bool) $params['targetstate']) {
|
||||
if ($params['targetstate']) {
|
||||
\mod_forum\subscriptions::subscribe_user($USER->id, $forumrecord, $context, true);
|
||||
} else {
|
||||
\mod_forum\subscriptions::unsubscribe_user($USER->id, $forumrecord, $context, true);
|
||||
}
|
||||
}
|
||||
|
||||
/** @var \mod_forum\local\factories\exporter $exporterfactory */
|
||||
$exporterfactory = \mod_forum\local\container::get_exporter_factory();
|
||||
$exporter = $exporterfactory->get_forum_exporter(
|
||||
user: $USER,
|
||||
forum: $forum,
|
||||
currentgroup: null,
|
||||
);
|
||||
return $exporter->export($PAGE->get_renderer('mod_forum'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe the return structure of the external service.
|
||||
*
|
||||
* @return external_single_structure
|
||||
*/
|
||||
public static function execute_returns(): external_single_structure {
|
||||
return forum_exporter::get_read_structure();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
<?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_forum\external;
|
||||
|
||||
use core_external\external_api;
|
||||
use core_external\external_function_parameters;
|
||||
use core_external\external_single_structure;
|
||||
use core_external\external_value;
|
||||
use mod_forum\local\exporters\forum as forum_exporter;
|
||||
|
||||
/**
|
||||
* Web Service to control the state of a forum tracking.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @category external
|
||||
* @copyright 2025 Sara Arjona <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class set_forum_tracking extends external_api {
|
||||
/**
|
||||
* Returns description of method parameters
|
||||
*
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function execute_parameters(): external_function_parameters {
|
||||
return new external_function_parameters(
|
||||
[
|
||||
'forumid' => new external_value(PARAM_INT, 'Forum that the user wants tracking for'),
|
||||
'targetstate' => new external_value(PARAM_BOOL, 'The target state'),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the forum tracking state.
|
||||
*
|
||||
* @param int $forumid The forum identifier.
|
||||
* @param bool $targetstate Whether to track or not the unread posts in the forum.
|
||||
* @return \stdClass
|
||||
*/
|
||||
public static function execute(
|
||||
int $forumid,
|
||||
bool $targetstate,
|
||||
): \stdClass {
|
||||
global $PAGE, $USER;
|
||||
|
||||
$params = self::validate_parameters(self::execute_parameters(), [
|
||||
'forumid' => $forumid,
|
||||
'targetstate' => $targetstate,
|
||||
]);
|
||||
|
||||
$vaultfactory = \mod_forum\local\container::get_vault_factory();
|
||||
$forumvault = $vaultfactory->get_forum_vault();
|
||||
$forum = $forumvault->get_from_id($params['forumid']);
|
||||
if (!$forum) {
|
||||
throw new \moodle_exception('invalidforumid', 'mod_forum', '', $params['forumid']);
|
||||
}
|
||||
$context = $forum->get_context();
|
||||
|
||||
self::validate_context($context);
|
||||
|
||||
$legacydatamapperfactory = \mod_forum\local\container::get_legacy_data_mapper_factory();
|
||||
$forumrecord = $legacydatamapperfactory->get_forum_data_mapper()->to_legacy_object($forum);
|
||||
|
||||
$usetracking = forum_tp_can_track_forums($forum);
|
||||
if (!$usetracking) {
|
||||
// Nothing to do. We won't actually output any content here though.
|
||||
throw new \moodle_exception('cannottrack', 'mod_forum');
|
||||
}
|
||||
|
||||
$istracked = forum_tp_is_tracked($forumrecord);
|
||||
// If the current state doesn't equal the desired state then update the current
|
||||
// state to the desired state.
|
||||
if ($istracked != (bool) $params['targetstate']) {
|
||||
if ($params['targetstate']) {
|
||||
forum_tp_start_tracking($forumrecord->id);
|
||||
} else {
|
||||
forum_tp_stop_tracking($forumrecord->id);
|
||||
}
|
||||
$cache = \cache::make('mod_forum', 'forum_is_tracked');
|
||||
$cache->purge();
|
||||
}
|
||||
|
||||
/** @var \mod_forum\local\factories\exporter $exporterfactory */
|
||||
$exporterfactory = \mod_forum\local\container::get_exporter_factory();
|
||||
$exporter = $exporterfactory->get_forum_exporter(
|
||||
user: $USER,
|
||||
forum: $forum,
|
||||
currentgroup: null,
|
||||
);
|
||||
return $exporter->export($PAGE->get_renderer('mod_forum'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe the return structure of the external service.
|
||||
*
|
||||
* @return external_single_structure
|
||||
*/
|
||||
public static function execute_returns(): external_single_structure {
|
||||
return forum_exporter::get_read_structure();
|
||||
}
|
||||
}
|
||||
@@ -71,6 +71,7 @@ class forum extends exporter {
|
||||
'userstate' => [
|
||||
'type' => [
|
||||
'tracked' => ['type' => PARAM_INT],
|
||||
'subscribed' => ['type' => PARAM_INT],
|
||||
],
|
||||
],
|
||||
'capabilities' => [
|
||||
@@ -125,7 +126,11 @@ class forum extends exporter {
|
||||
'gradingenabled' => $this->forum->is_grading_enabled()
|
||||
],
|
||||
'userstate' => [
|
||||
'tracked' => forum_tp_is_tracked($this->get_forum_record(), $this->related['user']),
|
||||
'tracked' => (int) forum_tp_is_tracked($this->get_forum_record(), $this->related['user']),
|
||||
'subscribed' => (int) \mod_forum\subscriptions::is_subscribed(
|
||||
$this->related['user']->id,
|
||||
$this->get_forum_record(),
|
||||
),
|
||||
],
|
||||
'capabilities' => [
|
||||
'viewdiscussions' => $capabilitymanager->can_view_discussions($user),
|
||||
|
||||
@@ -198,4 +198,21 @@ $functions = array(
|
||||
'type' => 'write',
|
||||
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
|
||||
),
|
||||
'mod_forum_set_forum_subscription' => [
|
||||
'classname' => 'mod_forum\external\set_forum_subscription',
|
||||
'methodname' => 'execute',
|
||||
'description' => 'Subscribe or unsubscribe the user to a forum.',
|
||||
'type' => 'write',
|
||||
'ajax' => true,
|
||||
'services' => [MOODLE_OFFICIAL_MOBILE_SERVICE],
|
||||
],
|
||||
|
||||
'mod_forum_set_forum_tracking' => [
|
||||
'classname' => 'mod_forum\external\set_forum_tracking',
|
||||
'methodname' => 'execute',
|
||||
'description' => 'Track or not unread messages in a forum for the user.',
|
||||
'type' => 'write',
|
||||
'ajax' => true,
|
||||
'services' => [MOODLE_OFFICIAL_MOBILE_SERVICE],
|
||||
],
|
||||
);
|
||||
|
||||
@@ -4660,8 +4660,14 @@ function forum_tp_can_track_forums($forum=false, $user=false) {
|
||||
$forum = $DB->get_record('forum', array('id' => $forum), '', 'id,trackingtype');
|
||||
}
|
||||
|
||||
$forumallows = ($forum->trackingtype == FORUM_TRACKING_OPTIONAL);
|
||||
$forumforced = ($forum->trackingtype == FORUM_TRACKING_FORCED);
|
||||
if (method_exists($forum, 'get_tracking_type')) {
|
||||
$trackingtype = $forum->get_tracking_type();
|
||||
} else {
|
||||
$trackingtype = $forum->trackingtype;
|
||||
}
|
||||
|
||||
$forumallows = ($trackingtype == FORUM_TRACKING_OPTIONAL);
|
||||
$forumforced = ($trackingtype == FORUM_TRACKING_FORCED);
|
||||
|
||||
if ($CFG->forum_allowforcedreadtracking) {
|
||||
// If we allow forcing, then forced forums takes procidence over user setting.
|
||||
|
||||
@@ -16,7 +16,11 @@
|
||||
|
||||
namespace mod_forum;
|
||||
|
||||
use mod_forum\local\entities\forum as forum_entity;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/mod/forum/lib.php');
|
||||
|
||||
use mod_forum\local\exporters\forum as forum_exporter;
|
||||
|
||||
/**
|
||||
@@ -27,6 +31,23 @@ use mod_forum\local\exporters\forum as forum_exporter;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
final class exporters_forum_test extends \advanced_testcase {
|
||||
|
||||
#[\Override]
|
||||
public function setUp(): void {
|
||||
parent::setUp();
|
||||
// We must clear the subscription caches.
|
||||
// This has to be done both before each test, and after in case of other tests using these functions.
|
||||
subscriptions::reset_forum_cache();
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function tearDown(): void {
|
||||
// We must clear the subscription caches.
|
||||
// // This has to be done both before each test, and after in case of other tests using these functions.
|
||||
subscriptions::reset_forum_cache();
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the export function returns expected values.
|
||||
*/
|
||||
@@ -40,7 +61,8 @@ final class exporters_forum_test extends \advanced_testcase {
|
||||
$course = $datagenerator->create_course();
|
||||
$forum = $datagenerator->create_module('forum', [
|
||||
'course' => $course->id,
|
||||
'groupmode' => VISIBLEGROUPS
|
||||
'groupmode' => VISIBLEGROUPS,
|
||||
'forcesubscribe' => FORUM_FORCESUBSCRIBE,
|
||||
]);
|
||||
$coursemodule = get_coursemodule_from_instance('forum', $forum->id);
|
||||
$context = \context_module::instance($coursemodule->id);
|
||||
@@ -61,10 +83,17 @@ final class exporters_forum_test extends \advanced_testcase {
|
||||
$this->assertEquals($forum->get_id(), $exportedforum->id);
|
||||
$this->assertEquals(VISIBLEGROUPS, $exportedforum->state['groupmode']);
|
||||
$this->assertEquals(false, $exportedforum->userstate['tracked']);
|
||||
$this->assertEquals(false, $exportedforum->userstate['subscribed']);
|
||||
$this->assertEquals(false, $exportedforum->capabilities['viewdiscussions']);
|
||||
$this->assertEquals(false, $exportedforum->capabilities['create']);
|
||||
$this->assertEquals(false, $exportedforum->capabilities['subscribe']);
|
||||
$this->assertNotEquals(null, $exportedforum->urls['create']);
|
||||
$this->assertNotEquals(null, $exportedforum->urls['markasread']);
|
||||
|
||||
// Enrol the user in the course and check the capabilities and user state.
|
||||
$datagenerator->enrol_user($user->id, $course->id);
|
||||
$exportedforum = $exporter->export($renderer);
|
||||
$this->assertEquals(true, $exportedforum->userstate['subscribed']);
|
||||
$this->assertEquals(true, $exportedforum->capabilities['viewdiscussions']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
<?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_forum\external;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
|
||||
require_once($CFG->dirroot . '/mod/forum/lib.php');
|
||||
|
||||
use core_external\external_api;
|
||||
use mod_forum\external\set_forum_subscription;
|
||||
use mod_forum\subscriptions;
|
||||
|
||||
/**
|
||||
* Tests for the set_forum_subscription external function.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @category test
|
||||
* @copyright 2025 Sara Arjona <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @covers \mod_forum\external\set_forum_subscription
|
||||
*/
|
||||
final class set_forum_subscription_test extends \externallib_advanced_testcase {
|
||||
|
||||
#[\Override]
|
||||
public function setUp(): void {
|
||||
parent::setUp();
|
||||
// We must clear the subscription caches.
|
||||
// This has to be done both before each test, and after in case of other tests using these functions.
|
||||
subscriptions::reset_forum_cache();
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function tearDown(): void {
|
||||
// We must clear the subscription caches.
|
||||
// This has to be done both before each test, and after in case of other tests using these functions.
|
||||
subscriptions::reset_forum_cache();
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test execute method.
|
||||
*
|
||||
* @dataProvider execute_provider
|
||||
* @covers ::execute
|
||||
*
|
||||
* @param bool|null $initialstate Initialise subscription state, null means no initial state.
|
||||
* @param bool $targetstate Expected target state of the subscription.
|
||||
* @param int $subscriptionmode Subscription mode for the forum.
|
||||
* @param bool $expectedexception Whether an exception is expected.
|
||||
*/
|
||||
public function test_execute(
|
||||
?bool $initialstate,
|
||||
bool $targetstate,
|
||||
int $subscriptionmode = FORUM_CHOOSESUBSCRIBE,
|
||||
bool $expectedexception = false,
|
||||
): void {
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
$user = self::getDataGenerator()->create_user();
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$this->getDataGenerator()->enrol_user($user->id, $course->id);
|
||||
$this->setUser($user);
|
||||
|
||||
$forum = self::getDataGenerator()->create_module(
|
||||
'forum',
|
||||
[
|
||||
'course' => $course->id,
|
||||
'forcesubscribe' => $subscriptionmode,
|
||||
]
|
||||
);
|
||||
|
||||
if ($expectedexception) {
|
||||
$this->expectException(\moodle_exception::class);
|
||||
} else if ($initialstate !== null) {
|
||||
// Set the initial state of the subscription.
|
||||
if ($initialstate) {
|
||||
subscriptions::subscribe_user($user->id, $forum);
|
||||
} else {
|
||||
subscriptions::unsubscribe_user($user->id, $forum);
|
||||
}
|
||||
$this->assertEquals($initialstate, subscriptions::is_subscribed($user->id, $forum));
|
||||
}
|
||||
|
||||
$return = external_api::clean_returnvalue(
|
||||
set_forum_subscription::execute_returns(),
|
||||
set_forum_subscription::execute($forum->id, $targetstate),
|
||||
);
|
||||
$this->assertEquals($targetstate, $return['userstate']['subscribed']);
|
||||
$this->assertEquals($targetstate, subscriptions::is_subscribed($user->id, $forum));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for test_execute.
|
||||
*
|
||||
* @return array The data provider array.
|
||||
*/
|
||||
public static function execute_provider(): array {
|
||||
return [
|
||||
'Subscription initially false, set to true' => [
|
||||
'initialstate' => false,
|
||||
'targetstate' => true,
|
||||
],
|
||||
'Subscription initially true, set to false' => [
|
||||
'initialstate' => true,
|
||||
'targetstate' => false,
|
||||
],
|
||||
'Subscription initially false, set to false' => [
|
||||
'initialstate' => false,
|
||||
'targetstate' => false,
|
||||
],
|
||||
'Subscription initially true, set to true' => [
|
||||
'initialstate' => true,
|
||||
'targetstate' => true,
|
||||
],
|
||||
'Subscription forced on' => [
|
||||
'initialstate' => null,
|
||||
'targetstate' => true,
|
||||
'subscriptionmode' => FORUM_FORCESUBSCRIBE,
|
||||
'expectedexception' => true,
|
||||
],
|
||||
'Subscription forced off' => [
|
||||
'initialstate' => null,
|
||||
'targetstate' => false,
|
||||
'subscriptionmode' => FORUM_DISALLOWSUBSCRIBE,
|
||||
'expectedexception' => true,
|
||||
],
|
||||
'Subscription initial on' => [
|
||||
'initialstate' => true,
|
||||
'targetstate' => false,
|
||||
'subscriptionmode' => FORUM_INITIALSUBSCRIBE,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test execute method when forum is not subscribable.
|
||||
*
|
||||
* @covers ::execute
|
||||
*/
|
||||
public function test_execute_not_subscribable(): void {
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
$admin = get_admin();
|
||||
$teacher = self::getDataGenerator()->create_user();
|
||||
$student = self::getDataGenerator()->create_user();
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$this->getDataGenerator()->enrol_user($teacher->id, $course->id, 'editingteacher');
|
||||
$this->getDataGenerator()->enrol_user($student->id, $course->id);
|
||||
|
||||
$forum = self::getDataGenerator()->create_module('forum', [
|
||||
'course' => $course->id,
|
||||
'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE,
|
||||
]);
|
||||
|
||||
// Admin user can subscribe to a forum that does not allow subscriptions.
|
||||
$this->setAdminUser();
|
||||
$return = external_api::clean_returnvalue(
|
||||
set_forum_subscription::execute_returns(),
|
||||
set_forum_subscription::execute($forum->id, true),
|
||||
);
|
||||
$this->assertEquals(true, $return['userstate']['subscribed']);
|
||||
$this->assertEquals(true, subscriptions::is_subscribed($admin->id, $forum));
|
||||
|
||||
// Teacher user can subscribe to a forum that does not allow subscriptions because they have the capability.
|
||||
$this->setUser($teacher);
|
||||
$return = external_api::clean_returnvalue(
|
||||
set_forum_subscription::execute_returns(),
|
||||
set_forum_subscription::execute($forum->id, true),
|
||||
);
|
||||
$this->assertEquals(true, $return['userstate']['subscribed']);
|
||||
$this->assertEquals(true, subscriptions::is_subscribed($teacher->id, $forum));
|
||||
|
||||
// Attempt to subscribe to a forum that does not allow subscriptions without the required capability.
|
||||
$this->setUser($student);
|
||||
$this->expectException(\moodle_exception::class);
|
||||
external_api::clean_returnvalue(
|
||||
set_forum_subscription::execute_returns(),
|
||||
set_forum_subscription::execute($forum->id, true),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test execute method when forum does not exist.
|
||||
*
|
||||
* @covers ::execute
|
||||
*/
|
||||
public function test_execute_unexisting_forum(): void {
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
$this->setAdminUser();
|
||||
$this->expectException(\moodle_exception::class);
|
||||
external_api::clean_returnvalue(
|
||||
set_forum_subscription::execute_returns(),
|
||||
set_forum_subscription::execute(9999, true),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test execute method when user is not enrolled in the course of the forum.
|
||||
*
|
||||
* @covers ::execute
|
||||
*/
|
||||
public function test_execute_unenrolled_user(): void {
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
$user = self::getDataGenerator()->create_user();
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$this->setUser($user);
|
||||
$forum = self::getDataGenerator()->create_module('forum', ['course' => $course->id]);
|
||||
|
||||
$this->expectException(\moodle_exception::class);
|
||||
external_api::clean_returnvalue(
|
||||
set_forum_subscription::execute_returns(),
|
||||
set_forum_subscription::execute($forum->id, true),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
<?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_forum\external;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
|
||||
require_once($CFG->dirroot . '/mod/forum/lib.php');
|
||||
|
||||
use core_external\external_api;
|
||||
use mod_forum\external\set_forum_tracking;
|
||||
use mod_forum\subscriptions;
|
||||
|
||||
/**
|
||||
* Tests for the set_forum_tracking external function.
|
||||
*
|
||||
* @package mod_forum
|
||||
* @category test
|
||||
* @copyright 2025 Sara Arjona <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @covers \mod_forum\external\set_forum_tracking
|
||||
*/
|
||||
final class set_forum_tracking_test extends \externallib_advanced_testcase {
|
||||
|
||||
#[\Override]
|
||||
public function setUp(): void {
|
||||
parent::setUp();
|
||||
// We must clear the subscription caches.
|
||||
// This has to be done both before each test, and after in case of other tests using these functions.
|
||||
subscriptions::reset_forum_cache();
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function tearDown(): void {
|
||||
// We must clear the subscription caches.
|
||||
// This has to be done both before each test, and after in case of other tests using these functions.
|
||||
subscriptions::reset_forum_cache();
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test execute method.
|
||||
*
|
||||
* @dataProvider execute_provider
|
||||
* @covers ::execute
|
||||
*
|
||||
* @param bool|null $initialstate Initialise tracking state, null means no initial state.
|
||||
* @param bool $targetstate Expected target state of the tracking.
|
||||
* @param int $forumtype Tracking mode for the forum.
|
||||
* @param bool $expectedexception Whether an exception is expected.
|
||||
*/
|
||||
public function test_execute(
|
||||
?bool $initialstate,
|
||||
bool $targetstate,
|
||||
int $forumtype = FORUM_TRACKING_OPTIONAL,
|
||||
bool $expectedexception = false,
|
||||
): void {
|
||||
|
||||
global $CFG;
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Allow force.
|
||||
$CFG->forum_allowforcedreadtracking = 1;
|
||||
|
||||
$user = self::getDataGenerator()->create_user(['trackforums' => 1]);
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$this->getDataGenerator()->enrol_user($user->id, $course->id);
|
||||
$forum = self::getDataGenerator()->create_module(
|
||||
'forum',
|
||||
[
|
||||
'course' => $course->id,
|
||||
'trackingtype' => $forumtype,
|
||||
],
|
||||
);
|
||||
|
||||
$this->setUser($user);
|
||||
|
||||
if ($expectedexception) {
|
||||
$this->expectException(\moodle_exception::class);
|
||||
} else if ($initialstate !== null) {
|
||||
// Set the initial state of the subscription.
|
||||
if ($initialstate) {
|
||||
forum_tp_start_tracking($forum->id);
|
||||
} else {
|
||||
forum_tp_stop_tracking($forum->id);
|
||||
}
|
||||
$this->assertEquals($initialstate, forum_tp_is_tracked($forum));
|
||||
}
|
||||
$return = external_api::clean_returnvalue(
|
||||
set_forum_tracking::execute_returns(),
|
||||
set_forum_tracking::execute($forum->id, $targetstate),
|
||||
);
|
||||
$this->assertEquals($targetstate, $return['userstate']['tracked']);
|
||||
$this->assertEquals($targetstate, forum_tp_is_tracked($forum));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for test_execute.
|
||||
*
|
||||
* @return array The data provider array.
|
||||
*/
|
||||
public static function execute_provider(): array {
|
||||
return [
|
||||
'Initially false, set to true' => [
|
||||
'initialstate' => false,
|
||||
'targetstate' => true,
|
||||
],
|
||||
'Initially false, set to false' => [
|
||||
'initialstate' => false,
|
||||
'targetstate' => false,
|
||||
],
|
||||
'Initially true, set to false' => [
|
||||
'initialstate' => true,
|
||||
'targetstate' => false,
|
||||
],
|
||||
'Initially true, set to true' => [
|
||||
'initialstate' => true,
|
||||
'targetstate' => true,
|
||||
],
|
||||
'Forced off' => [
|
||||
'initialstate' => null,
|
||||
'targetstate' => false,
|
||||
'forumtype' => FORUM_TRACKING_OFF,
|
||||
'expectedexception' => true,
|
||||
],
|
||||
'Forced on' => [
|
||||
'initialstate' => null,
|
||||
'targetstate' => true,
|
||||
'forumtype' => FORUM_TRACKING_FORCED,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test execute method when tracking is not enabled for the user.
|
||||
*
|
||||
* @covers ::execute
|
||||
*/
|
||||
public function test_execute_no_tracking(): void {
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
$user = self::getDataGenerator()->create_user(['trackforums' => 0]);
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$this->getDataGenerator()->enrol_user($user->id, $course->id);
|
||||
$forum = self::getDataGenerator()->create_module('forum', [ 'course' => $course->id]);
|
||||
|
||||
$this->setUser($user);
|
||||
|
||||
$this->expectException(\moodle_exception::class);
|
||||
external_api::clean_returnvalue(
|
||||
set_forum_tracking::execute_returns(),
|
||||
set_forum_tracking::execute($forum->id, true),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test execute method when forum does not exist.
|
||||
*
|
||||
* @covers ::execute
|
||||
*/
|
||||
public function test_execute_unexisting_forum(): void {
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
$this->setAdminUser();
|
||||
$this->expectException(\moodle_exception::class);
|
||||
external_api::clean_returnvalue(
|
||||
set_forum_tracking::execute_returns(),
|
||||
set_forum_tracking::execute(9999, true),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test execute method when user is not enrolled in the course of the forum.
|
||||
*
|
||||
* @covers ::execute
|
||||
*/
|
||||
public function test_execute_unenrolled_user(): void {
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
$user = self::getDataGenerator()->create_user();
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$this->setUser($user);
|
||||
$forum = self::getDataGenerator()->create_module('forum', ['course' => $course->id]);
|
||||
|
||||
$this->expectException(\moodle_exception::class);
|
||||
external_api::clean_returnvalue(
|
||||
set_forum_tracking::execute_returns(),
|
||||
set_forum_tracking::execute($forum->id, true),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -195,6 +195,12 @@ final class externallib_test extends externallib_advanced_testcase {
|
||||
$expectedforums[$forum1->id] = (array) $forum1;
|
||||
$expectedforums[$forum2->id] = (array) $forum2;
|
||||
|
||||
// Reset static cache.
|
||||
$forum1cm = get_coursemodule_from_id('forum', $forum1->cmid);
|
||||
forum_tp_count_forum_unread_posts($forum1cm, $course1, true);
|
||||
$forum2cm = get_coursemodule_from_id('forum', $forum2->cmid);
|
||||
forum_tp_count_forum_unread_posts($forum2cm, $course2, true);
|
||||
|
||||
// Call the external function passing course ids.
|
||||
$forums = mod_forum_external::get_forums_by_courses(array($course1->id, $course2->id));
|
||||
$forums = external_api::clean_returnvalue(mod_forum_external::get_forums_by_courses_returns(), $forums);
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2025041401; // The current module version (Date: YYYYMMDDXX).
|
||||
$plugin->version = 2025041402; // The current module version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2025040800; // Requires this Moodle version.
|
||||
$plugin->component = 'mod_forum'; // Full name of the plugin (used for diagnostics)
|
||||
|
||||
Reference in New Issue
Block a user