diff --git a/blog/classes/external.php b/blog/classes/external.php new file mode 100644 index 0000000000000..9333d2b31935b --- /dev/null +++ b/blog/classes/external.php @@ -0,0 +1,180 @@ +. + +/** + * This is the external API for blogs. + * + * @package core_blog + * @copyright 2018 Juan Leyva + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core_blog; +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->libdir .'/externallib.php'); +require_once($CFG->dirroot .'/blog/lib.php'); +require_once($CFG->dirroot .'/blog/locallib.php'); + +use external_api; +use external_function_parameters; +use external_value; +use external_single_structure; +use external_multiple_structure; +use external_warnings; +use context_system; +use context_course; +use moodle_exception; +use core_blog\external\post_exporter; + +/** + * This is the external API for blogs. + * + * @copyright 2018 Juan Leyva + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class external extends external_api { + + /** + * Returns description of get_entries() parameters. + * + * @return external_function_parameters + * @since Moodle 3.6 + */ + public static function get_entries_parameters() { + return new external_function_parameters( + array( + 'filters' => new external_multiple_structure ( + new external_single_structure( + array( + 'name' => new external_value(PARAM_ALPHA, + 'The expected keys (value format) are: + tag PARAM_NOTAGS blog tag + tagid PARAM_INT blog tag id + userid PARAM_INT blog author (userid) + cmid PARAM_INT course module id + entryid PARAM_INT entry id + groupid PARAM_INT group id + courseid PARAM_INT course id + search PARAM_RAW search term + ' + ), + 'value' => new external_value(PARAM_RAW, 'The value of the filter.') + ) + ), 'Parameters to filter blog listings.', VALUE_DEFAULT, array() + ), + 'page' => new external_value(PARAM_INT, 'The blog page to return.', VALUE_DEFAULT, 0), + 'perpage' => new external_value(PARAM_INT, 'The number of posts to return per page.', VALUE_DEFAULT, 10), + ) + ); + } + + /** + * Return blog entries. + * + * @param array $filters the parameters to filter the blog listing + * @param int $page the blog page to return + * @param int $perpage the number of posts to return per page + * @return array with the blog entries and warnings + * @since Moodle 3.6 + */ + public static function get_entries($filters = array(), $page = 0, $perpage = 10) { + global $CFG, $DB, $PAGE; + + $warnings = array(); + $params = self::validate_parameters(self::get_entries_parameters(), + array('filters' => $filters, 'page' => $page, 'perpage' => $perpage)); + + if (empty($CFG->enableblogs)) { + throw new moodle_exception('blogdisable', 'blog'); + } + + // Init filters. + $filterstype = array('courseid' => PARAM_INT, 'groupid' => PARAM_INT, 'userid' => PARAM_INT, 'tagid' => PARAM_INT, + 'tag' => PARAM_NOTAGS, 'cmid' => PARAM_INT, 'entryid' => PARAM_INT, 'search' => PARAM_RAW); + $filters = array('courseid' => null, 'groupid' => null, 'userid' => null, 'tagid' => null, + 'tag' => null, 'cmid' => null, 'entryid' => null, 'search' => null); + + foreach ($params['filters'] as $filter) { + $name = trim($filter['name']); + if (!isset($filterstype[$name])) { + throw new moodle_exception('errorinvalidparam', 'webservice', '', $name); + } + $filters[$name] = clean_param($filter['value'], $filterstype[$name]); + } + + // Do not overwrite here the filters, blog_get_headers and blog_listing will take care of that. + list($courseid, $userid) = blog_validate_access($filters['courseid'], $filters['cmid'], $filters['groupid'], + $filters['entryid'], $filters['userid']); + + if ($courseid && $courseid != SITEID) { + $context = context_course::instance($courseid); + self::validate_context($context); + } else { + $context = context_system::instance(); + if ($CFG->bloglevel == BLOG_GLOBAL_LEVEL) { + // Everybody can see anything - no login required unless site is locked down using forcelogin. + if ($CFG->forcelogin) { + self::validate_context($context); + } + } else { + self::validate_context($context); + } + } + $PAGE->set_context($context); // Needed by internal APIs. + + // Get filters. + $blogheaders = blog_get_headers($filters['courseid'], $filters['groupid'], $filters['userid'], $filters['tagid'], + $filters['tag'], $filters['cmid'], $filters['entryid'], $filters['search']); + $bloglisting = new \blog_listing($blogheaders['filters']); + + $page = $params['page']; + $limit = empty($params['perpage']) ? get_user_preferences('blogpagesize', 10) : $params['perpage']; + $start = $page * $limit; + $entries = $bloglisting->get_entries($start, $limit); + $totalentries = $bloglisting->count_entries(); + + $exportedentries = array(); + $output = $PAGE->get_renderer('core'); + foreach ($entries as $entry) { + $exporter = new post_exporter($entry, array('context' => $context)); + $exportedentries[] = $exporter->export($output); + } + return array( + 'warnings' => $warnings, + 'entries' => $exportedentries, + 'totalentries' => $totalentries, + ); + } + + /** + * Returns description of get_entries() result value. + * + * @return external_description + * @since Moodle 3.6 + */ + public static function get_entries_returns() { + return new external_single_structure( + array( + 'entries' => new external_multiple_structure( + post_exporter::get_read_structure() + ), + 'totalentries' => new external_value(PARAM_INT, 'The total number of entries found.'), + 'warnings' => new external_warnings(), + ) + ); + } +} diff --git a/blog/classes/external/post_exporter.php b/blog/classes/external/post_exporter.php new file mode 100644 index 0000000000000..3d69299ef6045 --- /dev/null +++ b/blog/classes/external/post_exporter.php @@ -0,0 +1,185 @@ +. + +/** + * Class for exporting a blog post (entry). + * + * @package core_blog + * @copyright 2018 Juan Leyva + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace core_blog\external; +defined('MOODLE_INTERNAL') || die(); + +use core\external\exporter; +use external_util; +use external_files; +use renderer_base; +use context_system; + +/** + * Class for exporting a blog post (entry). + * + * @copyright 2018 Juan Leyva + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class post_exporter extends exporter { + + /** + * Return the list of properties. + * + * @return array list of properties + */ + protected static function define_properties() { + return array( + 'id' => array( + 'type' => PARAM_INT, + 'null' => NULL_ALLOWED, + 'description' => 'Post/entry id.', + ), + 'module' => array( + 'type' => PARAM_ALPHANUMEXT, + 'null' => NULL_NOT_ALLOWED, + 'description' => 'Where it was published the post (blog, blog_external...).', + ), + 'userid' => array( + 'type' => PARAM_INT, + 'null' => NULL_NOT_ALLOWED, + 'default' => 0, + 'description' => 'Post author.', + ), + 'courseid' => array( + 'type' => PARAM_INT, + 'null' => NULL_NOT_ALLOWED, + 'default' => 0, + 'description' => 'Course where the post was created.', + ), + 'groupid' => array( + 'type' => PARAM_INT, + 'null' => NULL_NOT_ALLOWED, + 'default' => 0, + 'description' => 'Group post was created for.', + ), + 'moduleid' => array( + 'type' => PARAM_INT, + 'null' => NULL_NOT_ALLOWED, + 'default' => 0, + 'description' => 'Module id where the post was created (not used anymore).', + ), + 'coursemoduleid' => array( + 'type' => PARAM_INT, + 'null' => NULL_NOT_ALLOWED, + 'default' => 0, + 'description' => 'Course module id where the post was created.', + ), + 'subject' => array( + 'type' => PARAM_TEXT, + 'null' => NULL_NOT_ALLOWED, + 'description' => 'Post subject.', + ), + 'summary' => array( + 'type' => PARAM_RAW, + 'null' => NULL_ALLOWED, + 'description' => 'Post summary.', + ), + 'content' => array( + 'type' => PARAM_RAW, + 'null' => NULL_ALLOWED, + 'description' => 'Post content.', + ), + 'uniquehash' => array( + 'type' => PARAM_RAW, + 'null' => NULL_NOT_ALLOWED, + 'description' => 'Post unique hash.', + ), + 'rating' => array( + 'type' => PARAM_INT, + 'null' => NULL_NOT_ALLOWED, + 'default' => 0, + 'description' => 'Post rating.', + ), + 'format' => array( + 'type' => PARAM_INT, + 'null' => NULL_NOT_ALLOWED, + 'default' => 0, + 'description' => 'Post content format.', + ), + 'summaryformat' => array( + 'choices' => array(FORMAT_HTML, FORMAT_MOODLE, FORMAT_PLAIN, FORMAT_MARKDOWN), + 'type' => PARAM_INT, + 'default' => FORMAT_MOODLE, + 'description' => 'Format for the summary field.', + ), + 'attachment' => array( + 'type' => PARAM_RAW, + 'null' => NULL_ALLOWED, + 'description' => 'Post atachment.', + ), + 'publishstate' => array( + 'type' => PARAM_ALPHA, + 'null' => NULL_NOT_ALLOWED, + 'default' => 'draft', + 'description' => 'Post publish state.', + ), + 'lastmodified' => array( + 'type' => PARAM_INT, + 'null' => NULL_NOT_ALLOWED, + 'default' => 0, + 'description' => 'When it was last modified.', + ), + 'created' => array( + 'type' => PARAM_INT, + 'null' => NULL_NOT_ALLOWED, + 'default' => 0, + 'description' => 'When it was created.', + ), + 'usermodified' => array( + 'type' => PARAM_INT, + 'null' => NULL_ALLOWED, + 'description' => 'User that updated the post.', + ), + ); + } + + protected static function define_related() { + return array( + 'context' => 'context' + ); + } + + protected static function define_other_properties() { + return array( + 'summaryfiles' => array( + 'type' => external_files::get_properties_for_exporter(), + 'multiple' => true + ), + 'attachmentfiles' => array( + 'type' => external_files::get_properties_for_exporter(), + 'multiple' => true, + 'optional' => true + ), + ); + } + + protected function get_other_values(renderer_base $output) { + $context = context_system::instance(); // Files always on site context. + + $values['summaryfiles'] = external_util::get_area_files($context->id, 'blog', 'post', $this->data->id); + $values['attachmentfiles'] = external_util::get_area_files($context->id, 'blog', 'attachment', $this->data->id); + + return $values; + } +} diff --git a/blog/tests/external_test.php b/blog/tests/external_test.php new file mode 100644 index 0000000000000..016865c92c25b --- /dev/null +++ b/blog/tests/external_test.php @@ -0,0 +1,565 @@ +. + +/** + * Unit tests for blog external API. + * + * @package core_blog + * @copyright 2018 Juan Leyva + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; +require_once($CFG->dirroot . '/blog/locallib.php'); +require_once($CFG->dirroot . '/blog/lib.php'); + +/** + * Unit tests for blog external API. + * + * @package core_blog + * @copyright 2018 Juan Leyva + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class core_blog_external_testcase extends advanced_testcase { + + private $courseid; + private $cmid; + private $userid; + private $groupid; + private $tagid; + private $postid; + + protected function setUp() { + global $DB, $CFG; + parent::setUp(); + + $this->resetAfterTest(); + + // Create default course. + $course = $this->getDataGenerator()->create_course(array('category' => 1, 'shortname' => 'ANON')); + $this->assertNotEmpty($course); + $page = $this->getDataGenerator()->create_module('page', array('course' => $course->id)); + $this->assertNotEmpty($page); + + // Create default user. + $user = $this->getDataGenerator()->create_user(array( + 'username' => 'testuser', + 'firstname' => 'Jimmy', + 'lastname' => 'Kinnon' + )); + // Enrol user. + $this->getDataGenerator()->enrol_user($user->id, $course->id); + + $group = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); + $this->getDataGenerator()->create_group_member(array('groupid' => $group->id, 'userid' => $user->id)); + + // Create default post. + $post = new stdClass(); + $post->userid = $user->id; + $post->courseid = $course->id; + $post->groupid = $group->id; + $post->content = 'test post content text'; + $post->module = 'blog'; + $post->id = $DB->insert_record('post', $post); + + core_tag_tag::set_item_tags('core', 'post', $post->id, context_user::instance($user->id), array('tag1')); + $tagid = $DB->get_field('tag', 'id', array('name' => 'tag1')); + + // Grab important ids. + $this->courseid = $course->id; + $this->cmid = $page->cmid; + $this->userid = $user->id; + $this->groupid = $group->id; + $this->tagid = $tagid; + $this->postid = $post->id; + $this->publishstate = 'site'; // To be override in tests. + + // Set default blog level. + $CFG->bloglevel = BLOG_SITE_LEVEL; + } + + /** + * Get global public entries even for not authenticated users. + * We get the entry since is public. + */ + public function test_get_public_entries_global_level_by_non_logged_users() { + global $CFG, $DB; + + $CFG->bloglevel = BLOG_GLOBAL_LEVEL; + $CFG->forcelogin = 0; + // Set current entry global. + $DB->set_field('post', 'publishstate', 'public', array('id' => $this->postid)); + + $result = core_blog\external::get_entries(); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(1, $result['entries']); + $this->assertEquals($this->postid, $result['entries'][0]['id']); + } + + /** + * Get global public entries even for not authenticated users in closed site. + */ + public function test_get_public_entries_global_level_by_non_logged_users_closed_site() { + global $CFG, $DB; + + $CFG->bloglevel = BLOG_GLOBAL_LEVEL; + $CFG->forcelogin = 1; + // Set current entry global. + $DB->set_field('post', 'publishstate', 'public', array('id' => $this->postid)); + + $this->expectException('moodle_exception'); + core_blog\external::get_entries(); + } + + /** + * Get global public entries for guest users. + * We get the entry since is public. + */ + public function test_get_public_entries_global_level_by_guest_users() { + global $CFG, $DB; + + $CFG->bloglevel = BLOG_GLOBAL_LEVEL; + // Set current entry global. + $DB->set_field('post', 'publishstate', 'public', array('id' => $this->postid)); + + $this->setGuestUser(); + $result = core_blog\external::get_entries(); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(1, $result['entries']); + $this->assertEquals($this->postid, $result['entries'][0]['id']); + } + + /** + * Get global not public entries even for not authenticated users withouth being authenticated. + * We don't get any because they are not public (restricted to site users). + */ + public function test_get_not_public_entries_global_level_by_non_logged_users() { + global $CFG; + + $CFG->bloglevel = BLOG_GLOBAL_LEVEL; + + $result = core_blog\external::get_entries(); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(0, $result['entries']); + } + + /** + * Get global not public entries users being guest. + * We don't get any because they are not public (restricted to real site users). + */ + public function test_get_not_public_entries_global_level_by_guest_user() { + global $CFG; + + $CFG->bloglevel = BLOG_GLOBAL_LEVEL; + + $this->setGuestUser(); + $result = core_blog\external::get_entries(); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(0, $result['entries']); + } + + /** + * Get site not public entries for not authenticated users. + * We don't get any because they are not public (restricted to real site users). + */ + public function test_get_not_public_entries_site_level_by_non_logged_users() { + $this->expectException('require_login_exception'); // In this case we get a security exception. + $result = core_blog\external::get_entries(); + } + + /** + * Get site not public entries for guest users. + * We don't get any because they are not public (restricted to real site users). + */ + public function test_get_not_public_entries_site_level_by_guest_users() { + + $this->setGuestUser(); + $result = core_blog\external::get_entries(); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(0, $result['entries']); + } + + /** + * Get site entries at site level by system users. + */ + public function test_get_site_entries_site_level_by_normal_users() { + + $this->setUser($this->userid); + $result = core_blog\external::get_entries(); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(1, $result['entries']); + $this->assertEquals($this->postid, $result['entries'][0]['id']); + } + + /** + * Get draft site entries by authors. + */ + public function test_get_draft_entries_site_level_by_author_users() { + global $DB; + + // Set current entry global. + $DB->set_field('post', 'publishstate', 'draft', array('id' => $this->postid)); + + $this->setUser($this->userid); + $result = core_blog\external::get_entries(); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(1, $result['entries']); + $this->assertEquals($this->postid, $result['entries'][0]['id']); + } + + /** + * Get draft site entries by not authors. + */ + public function test_get_draft_entries_site_level_by_not_author_users() { + global $DB; + + // Set current entry global. + $DB->set_field('post', 'publishstate', 'draft', array('id' => $this->postid)); + $user = $this->getDataGenerator()->create_user(); + + $this->setUser($user); + $result = core_blog\external::get_entries(); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(0, $result['entries']); + } + + /** + * Get draft site entries by admin. + */ + public function test_get_draft_entries_site_level_by_admin_users() { + global $DB; + + // Set current entry global. + $DB->set_field('post', 'publishstate', 'draft', array('id' => $this->postid)); + $user = $this->getDataGenerator()->create_user(); + + $this->setAdminUser(); + $result = core_blog\external::get_entries(); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(1, $result['entries']); + $this->assertEquals($this->postid, $result['entries'][0]['id']); + } + + /** + * Get draft user entries by authors. + */ + public function test_get_draft_entries_user_level_by_author_users() { + global $CFG, $DB; + + $CFG->bloglevel = BLOG_USER_LEVEL; + // Set current entry global. + $DB->set_field('post', 'publishstate', 'draft', array('id' => $this->postid)); + + $this->setUser($this->userid); + $result = core_blog\external::get_entries(); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(1, $result['entries']); + $this->assertEquals($this->postid, $result['entries'][0]['id']); + } + + /** + * Get draft user entries by not authors. + */ + public function test_get_draft_entries_user_level_by_not_author_users() { + global $CFG, $DB; + + $CFG->bloglevel = BLOG_USER_LEVEL; + // Set current entry global. + $DB->set_field('post', 'publishstate', 'draft', array('id' => $this->postid)); + $user = $this->getDataGenerator()->create_user(); + + $this->setUser($user); + $result = core_blog\external::get_entries(); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(0, $result['entries']); + } + + /** + * Get draft user entries by admin. + */ + public function test_get_draft_entries_user_level_by_admin_users() { + global $CFG, $DB; + + $CFG->bloglevel = BLOG_USER_LEVEL; + // Set current entry global. + $DB->set_field('post', 'publishstate', 'draft', array('id' => $this->postid)); + $user = $this->getDataGenerator()->create_user(); + + $this->setAdminUser(); + $result = core_blog\external::get_entries(); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(1, $result['entries']); + $this->assertEquals($this->postid, $result['entries'][0]['id']); + } + + /** + * Test get all entries including testing pagination. + */ + public function test_get_all_entries_including_pagination() { + global $DB, $USER; + + $DB->set_field('post', 'publishstate', 'site', array('id' => $this->postid)); + + // Create another entry. + $this->setAdminUser(); + $newpost = new stdClass(); + $newpost->userid = $USER->id; + $newpost->content = 'test post content text'; + $newpost->module = 'blog'; + $newpost->publishstate = 'site'; + $newpost->created = time() + HOURSECS; + $newpost->lastmodified = time() + HOURSECS; + $newpost->id = $DB->insert_record('post', $newpost); + + $this->setUser($this->userid); + $result = core_blog\external::get_entries(); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(2, $result['entries']); + $this->assertEquals(2, $result['totalentries']); + + $result = core_blog\external::get_entries(array(), 0, 1); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(1, $result['entries']); + $this->assertEquals(2, $result['totalentries']); + $this->assertEquals($newpost->id, $result['entries'][0]['id']); + + $result = core_blog\external::get_entries(array(), 1, 1); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(1, $result['entries']); + $this->assertEquals(2, $result['totalentries']); + $this->assertEquals($this->postid, $result['entries'][0]['id']); + } + + /** + * Test get entries filtering by course. + */ + public function test_get_entries_filtering_by_course() { + global $CFG, $DB; + + $DB->set_field('post', 'publishstate', 'site', array('id' => $this->postid)); + + $this->setAdminUser(); + $coursecontext = context_course::instance($this->courseid); + $anothercourse = $this->getDataGenerator()->create_course(); + + // Add blog associations with a course. + $blog = new blog_entry($this->postid); + $blog->add_association($coursecontext->id); + + // There is one entry associated with a course. + $result = core_blog\external::get_entries(array(array('name' => 'courseid', 'value' => $this->courseid))); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(1, $result['entries']); + + // There is no entry associated with a wrong course. + $result = core_blog\external::get_entries(array(array('name' => 'courseid', 'value' => $anothercourse->id))); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(0, $result['entries']); + + // There is no entry associated with a module. + $result = core_blog\external::get_entries(array(array('name' => 'cmid', 'value' => $this->cmid))); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(0, $result['entries']); + } + + /** + * Test get entries filtering by module. + */ + public function test_get_entries_filtering_by_module() { + global $CFG, $DB; + + $DB->set_field('post', 'publishstate', 'site', array('id' => $this->postid)); + + $this->setAdminUser(); + $coursecontext = context_course::instance($this->courseid); + $contextmodule = context_module::instance($this->cmid); + $anothermodule = $this->getDataGenerator()->create_module('page', array('course' => $this->courseid)); + + // Add blog associations with a module. + $blog = new blog_entry($this->postid); + $blog->add_association($contextmodule->id); + + // There is no entry associated with a course. + $result = core_blog\external::get_entries(array(array('name' => 'courseid', 'value' => $this->courseid))); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(0, $result['entries']); + + // There is one entry associated with a module. + $result = core_blog\external::get_entries(array(array('name' => 'cmid', 'value' => $this->cmid))); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(1, $result['entries']); + + // There is no entry associated with a wrong module. + $result = core_blog\external::get_entries(array(array('name' => 'cmid', 'value' => $anothermodule->cmid))); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(0, $result['entries']); + } + + /** + * Test get entries filtering by author. + */ + public function test_get_entries_filtering_by_author() { + $this->setAdminUser(); + // Filter by author. + $result = core_blog\external::get_entries(array(array('name' => 'userid', 'value' => $this->userid))); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(1, $result['entries']); + // No author. + $anotheruser = $this->getDataGenerator()->create_user(); + $result = core_blog\external::get_entries(array(array('name' => 'userid', 'value' => $anotheruser->id))); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(0, $result['entries']); + } + + /** + * Test get entries filtering by entry. + */ + public function test_get_entries_filtering_by_entry() { + $this->setAdminUser(); + // Filter by correct entry. + $result = core_blog\external::get_entries(array(array('name' => 'entryid', 'value' => $this->postid))); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(1, $result['entries']); + // Non-existent entry. + $this->expectException('moodle_exception'); + $result = core_blog\external::get_entries(array(array('name' => 'entryid', 'value' => -1))); + } + + /** + * Test get entries filtering by search. + */ + public function test_get_entries_filtering_by_search() { + $this->setAdminUser(); + // Filter by correct search. + $result = core_blog\external::get_entries(array(array('name' => 'search', 'value' => 'test'))); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(1, $result['entries']); + // Non-existent search. + $result = core_blog\external::get_entries(array(array('name' => 'search', 'value' => 'abc'))); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(0, $result['entries']); + } + + /** + * Test get entries filtering by tag. + */ + public function test_get_entries_filtering_by_tag() { + $this->setAdminUser(); + // Filter by correct tag. + $result = core_blog\external::get_entries(array(array('name' => 'tag', 'value' => 'tag1'))); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(1, $result['entries']); + // Create tag. + $tag = $this->getDataGenerator()->create_tag(array('userid' => $this->userid, 'name' => 'tag2', + 'isstandard' => 1)); + + $result = core_blog\external::get_entries(array(array('name' => 'tag', 'value' => 'tag2'))); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(0, $result['entries']); + } + + /** + * Test get entries filtering by tag id. + */ + public function test_get_entries_filtering_by_tagid() { + $this->setAdminUser(); + // Filter by correct tag. + $result = core_blog\external::get_entries(array(array('name' => 'tagid', 'value' => $this->tagid))); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(1, $result['entries']); + // Non-existent tag. + + // Create tag. + $tag = $this->getDataGenerator()->create_tag(array('userid' => $this->userid, 'name' => 'tag2', + 'isstandard' => 1)); + + $result = core_blog\external::get_entries(array(array('name' => 'tagid', 'value' => $tag->id))); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(0, $result['entries']); + } + + /** + * Test get entries filtering by group. + */ + public function test_get_entries_filtering_by_group() { + $this->setAdminUser(); + // Add blog associations with a course. + $coursecontext = context_course::instance($this->courseid); + $blog = new blog_entry($this->postid); + $blog->add_association($coursecontext->id); + + // Filter by correct group. + $result = core_blog\external::get_entries(array(array('name' => 'groupid', 'value' => $this->groupid))); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(1, $result['entries']); + // Non-existent group. + $anotheruser = $this->getDataGenerator()->create_user(); + $this->expectException('moodle_exception'); + core_blog\external::get_entries(array(array('name' => 'groupid', 'value' => -1))); + } + + /** + * Test get entries multiple filter. + */ + public function test_get_entries_multiple_filter() { + $this->setAdminUser(); + // Add blog associations with a course. + $coursecontext = context_course::instance($this->courseid); + $blog = new blog_entry($this->postid); + $blog->add_association($coursecontext->id); + + $result = core_blog\external::get_entries(array( + array('name' => 'tagid', 'value' => $this->tagid), + array('name' => 'userid', 'value' => $this->userid), + )); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(1, $result['entries']); + + // Non-existent multiple filter. + $result = core_blog\external::get_entries(array( + array('name' => 'search', 'value' => 'www'), + array('name' => 'userid', 'value' => $this->userid), + )); + $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); + $this->assertCount(0, $result['entries']); + } + + /** + * Test get entries filtering by invalid_filter. + */ + public function test_get_entries_filtering_by_invalid_filter() { + $this->setAdminUser(); + // Filter by incorrect filter. + $this->expectException('moodle_exception'); + $result = core_blog\external::get_entries(array(array('name' => 'zzZZzz', 'value' => 'wwWWww'))); + } + + /** + * Test get entries when blog is disabled. + */ + public function test_get_entries_blog_disabled() { + global $CFG; + + $this->setAdminUser(); + $CFG->enableblogs = 0; + // Filter by incorrect filter. + $this->expectException('moodle_exception'); + $result = core_blog\external::get_entries(array(array('name' => 'zzZZzz', 'value' => 'wwWWww'))); + } +} + diff --git a/lib/db/services.php b/lib/db/services.php index 08195cc6bd1c0..973ca1f1aa785 100644 --- a/lib/db/services.php +++ b/lib/db/services.php @@ -74,6 +74,15 @@ 'capabilities' => 'moodle/badges:viewotherbadges', 'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE), ), + 'core_blog_get_entries' => array( + 'classname' => 'core_blog\external', + 'methodname' => 'get_entries', + 'description' => 'Returns blog entries.', + 'type' => 'read', + 'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE), + 'ajax' => true, + 'loginrequired' => false, + ), 'core_calendar_get_calendar_monthly_view' => array( 'classname' => 'core_calendar_external', 'methodname' => 'get_calendar_monthly_view', diff --git a/version.php b/version.php index 3ee8253c3c0eb..bd986811c0ab7 100644 --- a/version.php +++ b/version.php @@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2018092700.01; // YYYYMMDD = weekly release date of this DEV branch. +$version = 2018092700.02; // YYYYMMDD = weekly release date of this DEV branch. // RR = release increments - 00 in DEV branches. // .XX = incremental changes.