MDL-64820 forum: add subscription toggling to discussion list
authorRyan Wyllie <ryan@moodle.com>
Mon, 11 Mar 2019 01:43:13 +0000 (09:43 +0800)
committerRyan Wyllie <ryan@moodle.com>
Fri, 22 Mar 2019 01:31:20 +0000 (09:31 +0800)
13 files changed:
mod/forum/amd/build/discussion_list.min.js [new file with mode: 0644]
mod/forum/amd/build/repository.min.js [new file with mode: 0644]
mod/forum/amd/build/selectors.min.js [new file with mode: 0644]
mod/forum/amd/build/subscription_toggle.min.js [new file with mode: 0644]
mod/forum/amd/src/discussion_list.js [new file with mode: 0644]
mod/forum/amd/src/repository.js [new file with mode: 0644]
mod/forum/amd/src/selectors.js [new file with mode: 0644]
mod/forum/amd/src/subscription_toggle.js [new file with mode: 0644]
mod/forum/db/services.php
mod/forum/externallib.php
mod/forum/templates/discussion_list.mustache
mod/forum/templates/discussion_subscription_toggle.mustache [new file with mode: 0644]
mod/forum/version.php

diff --git a/mod/forum/amd/build/discussion_list.min.js b/mod/forum/amd/build/discussion_list.min.js
new file mode 100644 (file)
index 0000000..0f7bc8b
Binary files /dev/null and b/mod/forum/amd/build/discussion_list.min.js differ
diff --git a/mod/forum/amd/build/repository.min.js b/mod/forum/amd/build/repository.min.js
new file mode 100644 (file)
index 0000000..2b3fcee
Binary files /dev/null and b/mod/forum/amd/build/repository.min.js differ
diff --git a/mod/forum/amd/build/selectors.min.js b/mod/forum/amd/build/selectors.min.js
new file mode 100644 (file)
index 0000000..8a80492
Binary files /dev/null and b/mod/forum/amd/build/selectors.min.js differ
diff --git a/mod/forum/amd/build/subscription_toggle.min.js b/mod/forum/amd/build/subscription_toggle.min.js
new file mode 100644 (file)
index 0000000..4ff0470
Binary files /dev/null and b/mod/forum/amd/build/subscription_toggle.min.js differ
diff --git a/mod/forum/amd/src/discussion_list.js b/mod/forum/amd/src/discussion_list.js
new file mode 100644 (file)
index 0000000..f2bfab9
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+
+/**
+ * Module for the list of discussions on when viewing a forum.
+ *
+ * @module     mod_forum/discussion_list
+ * @package    mod_forum
+ * @copyright  2019 Andrew Nicols <andrew@nicols.co.uk>
+ * @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 (file)
index 0000000..c09a6d8
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+
+/**
+ * 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 <andrew@nicols.co.uk>
+ * @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 (file)
index 0000000..e547569
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+
+/**
+ * Common CSS selectors for the forum UI.
+ *
+ * @module     mod_forum/selectors
+ * @package    mod_forum
+ * @copyright  2019 Andrew Nicols <andrew@nicols.co.uk>
+ * @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 (file)
index 0000000..f4f39b3
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+
+/**
+ * Handle discussion subscription toggling on a discussion list in
+ * the forum view.
+ *
+ * @module     mod_forum/subscription_toggle
+ * @package    mod_forum
+ * @copyright  2019 Andrew Nicols <andrew@nicols.co.uk>
+ * @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);
+        }
+    };
+});
index ce30779..90cd941 100644 (file)
@@ -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),
+    ),
 );
index db31cef..0cf11d1 100644 (file)
@@ -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();
+    }
 }
index 74ebcaa..ecf57e0 100644 (file)
@@ -32,7 +32,7 @@
     {
     }
 }}
-<span id="{{uniqid}}">
+<div id="discussion-list-{{uniqid}}">
     {{{groupchangemenu}}}
 
     {{#notifications}}
@@ -70,6 +70,9 @@
                         {{/forum.userstate.tracked}}
                     {{/forum.capabilities.viewdiscussions}}
                     <th scope="col" class="lastpost">{{#str}}lastpost, mod_forum{{/str}}</th>
+                    {{#forum.capabilities.subscribe}}
+                        <th scope="col" class="discussionsubscription"></th>
+                    {{/forum.capabilities.subscribe}}
                 </tr>
             </thead>
             {{/discussion_list_header}}
                                 </div>
                             {{/latestpostid}}
                         </td>
+                        <td scope="col" class="p-0 align-middle">
+                            {{#discussion}}
+                                {{> mod_forum/discussion_subscription_toggle}}
+                            {{/discussion}}
+                        </td>
                     </tr>
                 {{/summaries}}
             </tbody>
         </div>
     {{/state.hasdiscussions}}
 
-</span>
-
+</div>
+{{#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 (file)
index 0000000..0e5cb43
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+}}
+{{!
+    @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}}
+    <button
+        class="p-3 btn btn-link"
+        data-type="subscription-toggle"
+        data-action="toggle"
+        data-discussionid="{{id}}"
+        data-forumid="{{forumid}}"
+        {{#userstate.subscribed}}
+            data-targetstate="0"
+        {{/userstate.subscribed}}
+        {{^userstate.subscribed}}
+            data-targetstate="1"
+        {{/userstate.subscribed}}
+    >
+        {{#userstate.subscribed}}
+            {{#pix}}t/subscribed, mod_forum, {{#str}}clicktounsubscribe, mod_forum{{/str}}{{/pix}}
+        {{/userstate.subscribed}}
+        {{^userstate.subscribed}}
+            {{#pix}}t/unsubscribed, mod_forum, {{#str}}clicktosubscribe, mod_forum{{/str}}{{/pix}}
+        {{/userstate.subscribed}}
+    </button>
+{{/capabilities.subscribe}}
index 73b44fb..2eb0507 100644 (file)
@@ -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)