diff --git a/mod/forum/amd/build/discussion_list.min.js b/mod/forum/amd/build/discussion_list.min.js new file mode 100644 index 00000000000..0f7bc8b3328 --- /dev/null +++ b/mod/forum/amd/build/discussion_list.min.js @@ -0,0 +1 @@ +define(["mod_forum/subscription_toggle"],function(a){return{init:function(b){a.init(b)}}}); \ No newline at end of file diff --git a/mod/forum/amd/build/repository.min.js b/mod/forum/amd/build/repository.min.js new file mode 100644 index 00000000000..2b3fcee891d --- /dev/null +++ b/mod/forum/amd/build/repository.min.js @@ -0,0 +1 @@ +define(["core/ajax"],function(a){var b=function(b,c,d){var e={methodname:"mod_forum_set_subscription_state",args:{forumid:b,discussionid:c,targetstate:d}};return a.call([e])[0]};return{setDiscussionSubscriptionState:b}}); \ No newline at end of file diff --git a/mod/forum/amd/build/selectors.min.js b/mod/forum/amd/build/selectors.min.js new file mode 100644 index 00000000000..8a80492504d --- /dev/null +++ b/mod/forum/amd/build/selectors.min.js @@ -0,0 +1 @@ +define([],function(){return{subscription:{toggle:"[data-type='subscription-toggle'][data-action='toggle']"}}}); \ No newline at end of file diff --git a/mod/forum/amd/build/subscription_toggle.min.js b/mod/forum/amd/build/subscription_toggle.min.js new file mode 100644 index 00000000000..4ff04706fe2 --- /dev/null +++ b/mod/forum/amd/build/subscription_toggle.min.js @@ -0,0 +1 @@ +define(["jquery","core/templates","core/notification","mod_forum/repository","mod_forum/selectors"],function(a,b,c,d,e){var f=function(f){f.on("click",e.subscription.toggle,function(e){var f=a(this),g=f.data("forumid"),h=f.data("discussionid"),i=f.data("targetstate");d.setDiscussionSubscriptionState(g,h,i).then(function(a){return b.render("mod_forum/discussion_subscription_toggle",a)}).then(function(a,c){return b.replaceNode(f,a,c)})["catch"](c.exception),e.preventDefault()})};return{init:function(a){f(a)}}}); \ No newline at end of file diff --git a/mod/forum/amd/src/discussion_list.js b/mod/forum/amd/src/discussion_list.js new file mode 100644 index 00000000000..f2bfab9480d --- /dev/null +++ b/mod/forum/amd/src/discussion_list.js @@ -0,0 +1,30 @@ +// 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 . + +/** + * Module for the list of discussions on when viewing a forum. + * + * @module mod_forum/discussion_list + * @package mod_forum + * @copyright 2019 Andrew Nicols + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +define(['mod_forum/subscription_toggle'], function(SubscriptionToggle) { + return { + init: function(root) { + SubscriptionToggle.init(root); + } + }; +}); diff --git a/mod/forum/amd/src/repository.js b/mod/forum/amd/src/repository.js new file mode 100644 index 00000000000..c09a6d868cc --- /dev/null +++ b/mod/forum/amd/src/repository.js @@ -0,0 +1,49 @@ +// 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 . + +/** + * Forum repository class to encapsulate all of the AJAX requests that + * can be sent for forum. + * + * @module mod_forum/repository + * @package mod_forum + * @copyright 2019 Andrew Nicols + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +define(['core/ajax'], function(Ajax) { + /** + * Set the subscription state for a discussion in a forum. + * + * @param {number} forumId ID of the forum the discussion belongs to + * @param {number} discussionId ID of the discussion with the subscription state + * @param {boolean} targetState Set the subscribed state. True == subscribed; false == unsubscribed. + * @return {object} jQuery promise + */ + var 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]; + }; + + return { + setDiscussionSubscriptionState: setDiscussionSubscriptionState, + }; +}); diff --git a/mod/forum/amd/src/selectors.js b/mod/forum/amd/src/selectors.js new file mode 100644 index 00000000000..e54756929b5 --- /dev/null +++ b/mod/forum/amd/src/selectors.js @@ -0,0 +1,30 @@ +// 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 . + +/** + * Common CSS selectors for the forum UI. + * + * @module mod_forum/selectors + * @package mod_forum + * @copyright 2019 Andrew Nicols + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +define([], function() { + return { + subscription: { + toggle: "[data-type='subscription-toggle'][data-action='toggle']", + } + }; +}); diff --git a/mod/forum/amd/src/subscription_toggle.js b/mod/forum/amd/src/subscription_toggle.js new file mode 100644 index 00000000000..f4f39b390cd --- /dev/null +++ b/mod/forum/amd/src/subscription_toggle.js @@ -0,0 +1,69 @@ +// 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 . + +/** + * Handle discussion subscription toggling on a discussion list in + * the forum view. + * + * @module mod_forum/subscription_toggle + * @package mod_forum + * @copyright 2019 Andrew Nicols + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +define([ + 'jquery', + 'core/templates', + 'core/notification', + 'mod_forum/repository', + 'mod_forum/selectors', + ], function( + $, + Templates, + Notification, + Repository, + Selectors + ) { + + /** + * Register event listeners for the subscription toggle. + * + * @param {object} root The discussion list root element + */ + var registerEventListeners = function(root) { + root.on('click', Selectors.subscription.toggle, function(e) { + var toggleElement = $(this); + var forumId = toggleElement.data('forumid'); + var discussionId = toggleElement.data('discussionid'); + var subscriptionState = toggleElement.data('targetstate'); + + Repository.setDiscussionSubscriptionState(forumId, discussionId, subscriptionState) + .then(function(context) { + return Templates.render('mod_forum/discussion_subscription_toggle', context); + }) + .then(function(html, js) { + return Templates.replaceNode(toggleElement, html, js); + }) + .catch(Notification.exception); + + e.preventDefault(); + }); + }; + + return { + init: function(root) { + registerEventListeners(root); + } + }; +}); diff --git a/mod/forum/db/services.php b/mod/forum/db/services.php index ce30779ad01..90cd94185f9 100644 --- a/mod/forum/db/services.php +++ b/mod/forum/db/services.php @@ -113,4 +113,14 @@ $functions = array( 'type' => 'read', 'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE), ), + + 'mod_forum_set_subscription_state' => array( + 'classname' => 'mod_forum_external', + 'methodname' => 'set_subscription_state', + 'classpath' => 'mod/forum/externallib.php', + 'description' => 'Set the subscription state', + 'type' => 'write', + 'ajax' => true, + 'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE), + ), ); diff --git a/mod/forum/externallib.php b/mod/forum/externallib.php index db31cef0a6c..0cf11d1c77f 100644 --- a/mod/forum/externallib.php +++ b/mod/forum/externallib.php @@ -1258,4 +1258,89 @@ class mod_forum_external extends external_api { return new external_single_structure($structure); } + + /** + * Set the subscription state. + * + * @param int $forumid + * @param int $discussionid + * @param bool $targetstate + * @return \stdClass + */ + public static function set_subscription_state($forumid, $discussionid, $targetstate) { + global $DB, $PAGE, $USER; + + $params = self::validate_parameters(self::set_subscription_state_parameters(), [ + 'forumid' => $forumid, + 'discussionid' => $discussionid, + 'targetstate' => $targetstate + ]); + + $vaultfactory = mod_forum\local\container::get_vault_factory(); + $forumvault = $vaultfactory->get_forum_vault(); + $forum = $forumvault->get_from_id($params['forumid']); + $course = $forum->get_course_record(); + $coursemodule = $forum->get_course_module_record(); + + self::validate_context($forum->get_context()); + + $managerfactory = mod_forum\local\container::get_manager_factory(); + $capabilitymanager = $managerfactory->get_capability_manager($forum); + $discussionvault = $vaultfactory->get_discussion_vault(); + $discussion = $discussionvault->get_from_id($params['discussionid']); + $legacydatamapperfactory = mod_forum\local\container::get_legacy_data_mapper_factory(); + + $forumrecord = $legacydatamapperfactory->get_forum_data_mapper()->to_legacy_object($forum); + $discussionrecord = $legacydatamapperfactory->get_discussion_data_mapper()->to_legacy_object($discussion); + + if (!\mod_forum\subscriptions::is_subscribable($forumrecord)) { + // 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, + $discussion->get_id(), + $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_to_discussion($USER->id, $discussionrecord, $context); + } else { + \mod_forum\subscriptions::unsubscribe_user_from_discussion($USER->id, $discussionrecord, $context); + } + } + + $exporterfactory = mod_forum\local\container::get_exporter_factory(); + $exporter = $exporterfactory->get_discussion_exporter($USER, $forum, $discussion); + return $exporter->export($PAGE->get_renderer('mod_forum')); + } + + /** + * Returns description of method parameters. + * + * @return external_function_parameters + */ + public static function set_subscription_state_parameters() { + return new external_function_parameters( + [ + 'forumid' => new external_value(PARAM_INT, 'Forum that the discussion is in'), + 'discussionid' => new external_value(PARAM_INT, 'The discussion to subscribe or unsubscribe'), + 'targetstate' => new external_value(PARAM_BOOL, 'The target state') + ] + ); + } + + /** + * Returns description of method result value. + * + * @return external_description + */ + public static function set_subscription_state_returns() { + return \mod_forum\local\exporters\discussion::get_read_structure(); + } } diff --git a/mod/forum/templates/discussion_list.mustache b/mod/forum/templates/discussion_list.mustache index 74ebcaa355f..ecf57e0f06b 100644 --- a/mod/forum/templates/discussion_list.mustache +++ b/mod/forum/templates/discussion_list.mustache @@ -32,7 +32,7 @@ { } }} - +
{{{groupchangemenu}}} {{#notifications}} @@ -70,6 +70,9 @@ {{/forum.userstate.tracked}} {{/forum.capabilities.viewdiscussions}} {{#str}}lastpost, mod_forum{{/str}} + {{#forum.capabilities.subscribe}} + + {{/forum.capabilities.subscribe}} {{/discussion_list_header}} @@ -176,6 +179,11 @@
{{/latestpostid}} + + {{#discussion}} + {{> mod_forum/discussion_subscription_toggle}} + {{/discussion}} + {{/summaries}} @@ -201,5 +209,10 @@ {{/state.hasdiscussions}} -
- + +{{#js}} + require(['jquery', 'mod_forum/discussion_list'], function($, View) { + var root = $('#discussion-list-{{uniqid}}'); + View.init(root); + }); +{{/js}} diff --git a/mod/forum/templates/discussion_subscription_toggle.mustache b/mod/forum/templates/discussion_subscription_toggle.mustache new file mode 100644 index 00000000000..0e5cb43e175 --- /dev/null +++ b/mod/forum/templates/discussion_subscription_toggle.mustache @@ -0,0 +1,56 @@ +{{! + 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 . +}} +{{! + @template mod_forum/discussion_subscription_toggle + + Template to display the discussion subscription toggle. + + Classes required for JS: + * none + + Data attributes required for JS: + * none + + Context variables required for this template: + * TODO + + Example context (json): + { + } +}} +{{#capabilities.subscribe}} + +{{/capabilities.subscribe}} diff --git a/mod/forum/version.php b/mod/forum/version.php index 73b44fba398..2eb0507e4ea 100644 --- a/mod/forum/version.php +++ b/mod/forum/version.php @@ -24,6 +24,6 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2018120301; // The current module version (Date: YYYYMMDDXX) +$plugin->version = 2018120302; // The current module version (Date: YYYYMMDDXX) $plugin->requires = 2018112800; // Requires this Moodle version $plugin->component = 'mod_forum'; // Full name of the plugin (used for diagnostics)