MDL-30106 forum: New web service mod_forum_get_forum_discussion_posts
authorJuan Leyva <juanleyvadelgado@gmail.com>
Tue, 4 Mar 2014 14:45:27 +0000 (15:45 +0100)
committerJuan Leyva <juanleyvadelgado@gmail.com>
Mon, 5 May 2014 09:55:43 +0000 (11:55 +0200)
lib/db/services.php
mod/forum/db/services.php
mod/forum/externallib.php
mod/forum/tests/externallib_test.php
mod/forum/tests/generator/lib.php

index 820e527..cc81df4 100644 (file)
@@ -947,7 +947,10 @@ $services = array(
             'message_airnotifier_is_system_configured',
             'message_airnotifier_are_notification_preferences_configured',
             'core_grades_get_grades',
-            'core_grades_update_grades'),
+            'core_grades_update_grades',
+            'mod_forum_get_forums_by_courses',
+            'mod_forum_get_forum_discussions',
+            'mod_forum_get_forum_discussion_posts'),
         'enabled' => 0,
         'restrictedusers' => 0,
         'shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE,
index 29d666b..9c735f8 100644 (file)
@@ -43,5 +43,14 @@ $functions = array(
         'description' => 'Returns a list of forum discussions contained within a given set of forums.',
         'type' => 'read',
         'capabilities' => 'mod/forum:viewdiscussion, mod/forum:viewqandawithoutposting'
+    ),
+
+    'mod_forum_get_forum_discussion_posts' => array(
+        'classname' => 'mod_forum_external',
+        'methodname' => 'get_forum_discussion_posts',
+        'classpath' => 'mod/forum/externallib.php',
+        'description' => 'Returns a list of forum posts for a discussion.',
+        'type' => 'read',
+        'capabilities' => 'mod/forum:viewdiscussion, mod/forum:viewqandawithoutposting'
     )
 );
index 862d299..139358e 100644 (file)
@@ -354,4 +354,169 @@ class mod_forum_external extends external_api {
             )
         );
     }
+
+    /**
+     * Describes the parameters for get_forum_discussion_posts.
+     *
+     * @return external_external_function_parameters
+     * @since Moodle 2.7
+     */
+    public static function get_forum_discussion_posts_parameters() {
+        return new external_function_parameters (
+            array(
+                'discussionid' => new external_value(PARAM_INT, 'discussion ID', VALUE_REQUIRED),
+                'sortby' => new external_value(PARAM_ALPHA,
+                    'sort by this element: id, created or modified', VALUE_DEFAULT, 'created'),
+                'sortdirection' => new external_value(PARAM_ALPHA, 'sort direction: ASC or DESC', VALUE_DEFAULT, 'DESC')
+            )
+        );
+    }
+
+    /**
+     * Returns a list of forum posts for a discussion
+     *
+     * @param int $discussionid the post ids
+     * @param string $sortby sort by this element (id, created or modified)
+     * @param string $sortdirection sort direction: ASC or DESC
+     *
+     * @return array the forum post details
+     * @since Moodle 2.7
+     */
+    public static function get_forum_discussion_posts($discussionid, $sortby = "id", $sortdirection = "ASC") {
+        global $CFG, $DB, $USER;
+
+        $warnings = array();
+
+        // Validate the parameter.
+        $params = self::validate_parameters(self::get_forum_discussion_posts_parameters(),
+            array(
+                'discussionid' => $discussionid,
+                'sortby' => $sortby,
+                'sortdirection' => $sortdirection));
+
+        // Compact/extract functions are not recommended.
+        $discussionid   = $params['discussionid'];
+        $sortby         = $params['sortby'];
+        $sortdirection  = $params['sortdirection'];
+
+        $sortallowedvalues = array('id', 'created', 'modified');
+        if (!in_array($sortby, $sortallowedvalues)) {
+            throw new invalid_parameter_exception('Invalid value for sortby parameter (value: ' . $sortby . '),' .
+                'allowed values are: ' . implode(',', $sortallowedvalues));
+        }
+
+        $sortdirection = strtoupper($sortdirection);
+        $directionallowedvalues = array('ASC', 'DESC');
+        if (!in_array($sortdirection, $directionallowedvalues)) {
+            throw new invalid_parameter_exception('Invalid value for sortdirection parameter (value: ' . $sortdirection . '),' .
+                'allowed values are: ' . implode(',', $directionallowedvalues));
+        }
+
+        $discussion = $DB->get_record('forum_discussions', array('id' => $discussionid), '*', MUST_EXIST);
+        $forum = $DB->get_record('forum', array('id' => $discussion->forum), '*', MUST_EXIST);
+        $course = $DB->get_record('course', array('id' => $forum->course), '*', MUST_EXIST);
+        $cm = get_coursemodule_from_instance('forum', $forum->id, $course->id, false, MUST_EXIST);
+
+        // Validate the module context. It checks everything that affects the module visibility (including groupings, etc..).
+        $modcontext = context_module::instance($cm->id);
+        self::validate_context($modcontext);
+
+        // This require must be here, see mod/forum/discuss.php.
+        require_once($CFG->dirroot . "/mod/forum/lib.php");
+
+        // Check they have the view forum capability.
+        require_capability('mod/forum:viewdiscussion', $modcontext, null, true, 'noviewdiscussionspermission', 'forum');
+
+        if (! $post = forum_get_post_full($discussion->firstpost)) {
+            throw new moodle_exception('notexists', 'forum');
+        }
+
+        // This function check groups, qanda, timed discussions, etc.
+        if (!forum_user_can_see_post($forum, $discussion, $post, null, $cm)) {
+            throw new moodle_exception('noviewdiscussionspermission', 'forum');
+        }
+
+        $canviewfullname = has_capability('moodle/site:viewfullnames', $modcontext);
+
+        // We will add this field in the response.
+        $canreply = forum_user_can_post($forum, $discussion, $USER, $cm, $course, $modcontext);
+
+        $forumtracked = forum_tp_is_tracked($forum);
+
+        $sort = 'p.' . $sortby . ' ' . $sortdirection;
+        $posts = forum_get_all_discussion_posts($discussion->id, $sort, $forumtracked);
+
+        foreach ($posts as $pid => $post) {
+
+            if (!forum_user_can_see_post($forum, $discussion, $post, null, $cm)) {
+                $warning = array();
+                $warning['item'] = 'post';
+                $warning['itemid'] = $post->id;
+                $warning['warningcode'] = '1';
+                $warning['message'] = 'You can\'t see this post';
+                $warnings[] = $warning;
+                continue;
+            }
+
+            // Function forum_get_all_discussion_posts adds postread field.
+            if (!isset($post->postread)) {
+                $posts[$pid]->postread = false;
+            }
+            $posts[$pid]->canreply = $canreply;
+            $posts[$pid]->children = array();
+            if (!empty($posts[$pid]->children)) {
+                $posts[$pid]->children = array_keys($posts[$pid]->children);
+            }
+
+            $user = new stdclass();
+            $user = username_load_fields_from_object($user, $post);
+            $posts[$pid]->userfullname = fullname($user, $canviewfullname);
+
+            $posts[$pid] = (array) $post;
+        }
+
+        $result = array();
+        $result['posts'] = $posts;
+        $result['warnings'] = $warnings;
+        return $result;
+    }
+
+    /**
+     * Describes the get_forum_discussion_posts return value.
+     *
+     * @return external_single_structure
+     * @since Moodle 2.7
+     */
+    public static function get_forum_discussion_posts_returns() {
+        return new external_single_structure(
+            array(
+                'posts' => new external_multiple_structure(
+                        new external_single_structure(
+                            array(
+                                'id' => new external_value(PARAM_INT, 'Post id'),
+                                'discussion' => new external_value(PARAM_INT, 'Discussion id'),
+                                'parent' => new external_value(PARAM_INT, 'Parent id'),
+                                'userid' => new external_value(PARAM_INT, 'User id'),
+                                'created' => new external_value(PARAM_INT, 'Creation time'),
+                                'modified' => new external_value(PARAM_INT, 'Time modified'),
+                                'mailed' => new external_value(PARAM_INT, 'Mailed?'),
+                                'subject' => new external_value(PARAM_TEXT, 'The post subject'),
+                                'message' => new external_value(PARAM_RAW, 'The post message'),
+                                'messageformat' => new external_value(PARAM_INT, 'The post message format'),
+                                'messagetrust' => new external_value(PARAM_INT, 'Can we trust?'),
+                                'attachment' => new external_value(PARAM_RAW, 'Attachments'),
+                                'totalscore' => new external_value(PARAM_INT, 'The post message total score'),
+                                'mailnow' => new external_value(PARAM_INT, 'Mail now?'),
+                                'children' => new external_multiple_structure(new external_value(PARAM_INT, 'children post id')),
+                                'canreply' => new external_value(PARAM_BOOL, 'The user can reply to posts?'),
+                                'postread' => new external_value(PARAM_BOOL, 'The post was read'),
+                                'userfullname' => new external_value(PARAM_TEXT, 'Post author full name')
+                            ), 'post'
+                        )
+                    ),
+                'warnings' => new external_warnings()
+            )
+        );
+    }
+
 }
index e78f863..9f85647 100644 (file)
@@ -384,4 +384,132 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
             $this->assertEquals('requireloginerror', $e->errorcode);
         }
     }
+
+    /**
+     * Test get forum posts
+     */
+    public function test_mod_forum_get_forum_discussion_posts() {
+        global $CFG;
+
+        $this->resetAfterTest(true);
+
+        // Set the CFG variable to allow track forums.
+        $CFG->forum_trackreadposts = true;
+
+        // Create a user who can track forums.
+        $record = new stdClass();
+        $record->trackforums = true;
+        $user1 = self::getDataGenerator()->create_user($record);
+        // Create a bunch of other users to post.
+        $user2 = self::getDataGenerator()->create_user();
+        $user3 = self::getDataGenerator()->create_user();
+
+        // Set the first created user to the test user.
+        self::setUser($user1);
+
+        // Create course to add the module.
+        $course1 = self::getDataGenerator()->create_course();
+
+        // Forum with tracking off.
+        $record = new stdClass();
+        $record->course = $course1->id;
+        $record->trackingtype = FORUM_TRACKING_OFF;
+        $forum1 = self::getDataGenerator()->create_module('forum', $record);
+        $forum1context = context_module::instance($forum1->cmid);
+
+        // Add discussions to the forums.
+        $record = new stdClass();
+        $record->course = $course1->id;
+        $record->userid = $user1->id;
+        $record->forum = $forum1->id;
+        $discussion1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
+
+        $record = new stdClass();
+        $record->course = $course1->id;
+        $record->userid = $user2->id;
+        $record->forum = $forum1->id;
+        $discussion2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
+
+        // Add 2 replies to the discussion 1 from different users.
+        $record = new stdClass();
+        $record->discussion = $discussion1->id;
+        $record->parent = $discussion1->firstpost;
+        $record->userid = $user2->id;
+        $discussion1reply1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
+
+        $record->parent = $discussion1reply1->id;
+        $record->userid = $user3->id;
+        $discussion1reply2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
+
+        // Enrol the user in the  course.
+        $enrol = enrol_get_plugin('manual');
+        // Following line enrol and assign default role id to the user.
+        // So the user automatically gets mod/forum:viewdiscussion on all forums of the course.
+        $this->getDataGenerator()->enrol_user($user1->id, $course1->id);
+        $this->getDataGenerator()->enrol_user($user2->id, $course1->id);
+        $this->getDataGenerator()->enrol_user($user3->id, $course1->id);
+
+        // Create what we expect to be returned when querying the discussion.
+        $expectedposts = array(
+            'posts' => array(),
+            'warnings' => array(),
+        );
+        $expectedposts['posts'][] = array(
+            'id' => $discussion1reply2->id,
+            'discussion' => $discussion1reply2->discussion,
+            'parent' => $discussion1reply2->parent,
+            'userid' => $discussion1reply2->userid,
+            'created' => $discussion1reply2->created,
+            'modified' => $discussion1reply2->modified,
+            'mailed' => $discussion1reply2->mailed,
+            'subject' => $discussion1reply2->subject,
+            'message' => file_rewrite_pluginfile_urls($discussion1reply2->message, 'pluginfile.php',
+                    $forum1context->id, 'mod_forum', 'post', $discussion1reply2->id),
+            'messageformat' => $discussion1reply2->messageformat,
+            'messagetrust' => $discussion1reply2->messagetrust,
+            'attachment' => $discussion1reply2->attachment,
+            'totalscore' => $discussion1reply2->totalscore,
+            'mailnow' => $discussion1reply2->mailnow,
+            'children' => array(),
+            'canreply' => true,
+            'postread' => false,
+            'userfullname' => fullname($user3)
+        );
+        $expectedposts['posts'][] = array(
+            'id' => $discussion1reply1->id,
+            'discussion' => $discussion1reply1->discussion,
+            'parent' => $discussion1reply1->parent,
+            'userid' => $discussion1reply1->userid,
+            'created' => $discussion1reply1->created,
+            'modified' => $discussion1reply1->modified,
+            'mailed' => $discussion1reply1->mailed,
+            'subject' => $discussion1reply1->subject,
+            'message' => file_rewrite_pluginfile_urls($discussion1reply1->message, 'pluginfile.php',
+                    $forum1context->id, 'mod_forum', 'post', $discussion1reply1->id),
+            'messageformat' => $discussion1reply1->messageformat,
+            'messagetrust' => $discussion1reply1->messagetrust,
+            'attachment' => $discussion1reply1->attachment,
+            'totalscore' => $discussion1reply1->totalscore,
+            'mailnow' => $discussion1reply1->mailnow,
+            'children' => array(),
+            'canreply' => true,
+            'postread' => false,
+            'userfullname' => fullname($user2)
+        );
+
+        // Test a discussion with two additional posts (total 3 posts).
+        $posts = mod_forum_external::get_forum_discussion_posts($discussion1->id, 'modified', 'DESC');
+        $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
+        $this->assertEquals(3, count($posts['posts']));
+
+        // Unset the initial discussion post.
+        array_pop($posts['posts']);
+        $this->assertEquals($expectedposts, $posts);
+
+        // Test discussion without additional posts. There should be only one post (the one created by the discussion).
+        $posts = mod_forum_external::get_forum_discussion_posts($discussion2->id, 'modified', 'DESC');
+        $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts);
+        $this->assertEquals(1, count($posts['posts']));
+
+    }
 }
index 449ec18..a371c15 100644 (file)
@@ -198,6 +198,30 @@ class mod_forum_generator extends testing_module_generator {
             $record['modified'] = $time;
         }
 
+        if (!isset($record['mailed'])) {
+            $record['mailed'] = 1;
+        }
+
+        if (!isset($record['messageformat'])) {
+            $record['messageformat'] = 1;
+        }
+
+        if (!isset($record['messagetrust'])) {
+            $record['messagetrust'] = 1;
+        }
+
+        if (!isset($record['attachment'])) {
+            $record['attachment'] = "";
+        }
+
+        if (!isset($record['totalscore'])) {
+            $record['totalscore'] = 0;
+        }
+
+        if (!isset($record['mailnow'])) {
+            $record['mailnow'] = 0;
+        }
+
         $record = (object) $record;
 
         // Add the post.