Merge branch 'MDL-64656-master' of git://github.com/jleyva/moodle

This commit is contained in:
Eloy Lafuente (stronk7) 2019-04-11 20:12:13 +02:00
commit ff3c8c0e6c
28 changed files with 1091 additions and 18 deletions

View file

@ -29,6 +29,7 @@ use external_util;
use external_files; use external_files;
use renderer_base; use renderer_base;
use context_system; use context_system;
use core_tag\external\tag_item_exporter;
/** /**
* Class for exporting a blog post (entry). * Class for exporting a blog post (entry).
@ -171,6 +172,12 @@ class post_exporter extends exporter {
'multiple' => true, 'multiple' => true,
'optional' => true 'optional' => true
), ),
'tags' => array(
'type' => tag_item_exporter::read_properties_definition(),
'description' => 'Tags.',
'multiple' => true,
'optional' => true,
),
); );
} }
@ -179,6 +186,12 @@ class post_exporter extends exporter {
$values['summaryfiles'] = external_util::get_area_files($context->id, 'blog', 'post', $this->data->id); $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); $values['attachmentfiles'] = external_util::get_area_files($context->id, 'blog', 'attachment', $this->data->id);
if ($this->data->module == 'blog_external') {
// For external blogs, the content field has the external blog id.
$values['tags'] = \core_tag\external\util::get_item_tags('core', 'blog_external', $this->data->content);
} else {
$values['tags'] = \core_tag\external\util::get_item_tags('core', 'post', $this->data->id);
}
return $values; return $values;
} }

View file

@ -108,6 +108,9 @@ class core_blog_external_testcase extends advanced_testcase {
$result = core_blog\external::get_entries(); $result = core_blog\external::get_entries();
$result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result);
$this->assertCount(1, $result['entries']); $this->assertCount(1, $result['entries']);
$this->assertCount(1, $result['entries'][0]['tags']);
$this->assertEquals('tag1', $result['entries'][0]['tags'][0]['rawname']);
$this->assertEquals($this->postid, $result['entries'][0]['id']); $this->assertEquals($this->postid, $result['entries'][0]['id']);
} }
@ -141,6 +144,9 @@ class core_blog_external_testcase extends advanced_testcase {
$result = core_blog\external::get_entries(); $result = core_blog\external::get_entries();
$result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result);
$this->assertCount(1, $result['entries']); $this->assertCount(1, $result['entries']);
$this->assertCount(1, $result['entries'][0]['tags']);
$this->assertEquals('tag1', $result['entries'][0]['tags'][0]['rawname']);
$this->assertEquals($this->postid, $result['entries'][0]['id']); $this->assertEquals($this->postid, $result['entries'][0]['id']);
} }
@ -331,6 +337,9 @@ class core_blog_external_testcase extends advanced_testcase {
$result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result);
$this->assertCount(2, $result['entries']); $this->assertCount(2, $result['entries']);
$this->assertEquals(2, $result['totalentries']); $this->assertEquals(2, $result['totalentries']);
$this->assertCount(0, $result['entries'][0]['tags']);
$this->assertCount(1, $result['entries'][1]['tags']);
$this->assertEquals('tag1', $result['entries'][1]['tags'][0]['rawname']);
$result = core_blog\external::get_entries(array(), 0, 1); $result = core_blog\external::get_entries(array(), 0, 1);
$result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result); $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result);
@ -365,6 +374,8 @@ class core_blog_external_testcase extends advanced_testcase {
$result = core_blog\external::get_entries(array(array('name' => 'courseid', 'value' => $this->courseid))); $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); $result = external_api::clean_returnvalue(core_blog\external::get_entries_returns(), $result);
$this->assertCount(1, $result['entries']); $this->assertCount(1, $result['entries']);
$this->assertCount(1, $result['entries'][0]['tags']);
$this->assertEquals('tag1', $result['entries'][0]['tags'][0]['rawname']);
// There is no entry associated with a wrong course. // There is no entry associated with a wrong course.
$result = core_blog\external::get_entries(array(array('name' => 'courseid', 'value' => $anothercourse->id))); $result = core_blog\external::get_entries(array(array('name' => 'courseid', 'value' => $anothercourse->id)));

View file

@ -1,3 +1,9 @@
This files describes API changes in /blog/* ,
information provided here is intended especially for developers.
=== 3.7 ===
* External function get_entries now returns an additional field "tags" returning the post tags.
=== 2.7 === === 2.7 ===
* blog_entry->add_associations() does not accept any params. * blog_entry->add_associations() does not accept any params.

View file

@ -494,6 +494,10 @@ class core_course_external extends external_api {
'userid' => new external_value(PARAM_INT, 'User who added this content to moodle'), 'userid' => new external_value(PARAM_INT, 'User who added this content to moodle'),
'author' => new external_value(PARAM_TEXT, 'Content owner'), 'author' => new external_value(PARAM_TEXT, 'Content owner'),
'license' => new external_value(PARAM_TEXT, 'Content license'), 'license' => new external_value(PARAM_TEXT, 'Content license'),
'tags' => new external_multiple_structure(
\core_tag\external\tag_item_exporter::get_read_structure(), 'Tags',
VALUE_OPTIONAL
),
) )
), VALUE_DEFAULT, array() ), VALUE_DEFAULT, array()
), ),

View file

@ -6,6 +6,8 @@ information provided here is intended especially for developers.
* External function core_course_external::get_course_contents new returns the following additional completiondata field: * External function core_course_external::get_course_contents new returns the following additional completiondata field:
- valueused (indicates whether the completion state affects the availability of other content) - valueused (indicates whether the completion state affects the availability of other content)
* External function core_course_external::get_course_contents now returns a new contentsinfo field with summary files information. * External function core_course_external::get_course_contents now returns a new contentsinfo field with summary files information.
* External function core_course_external::get_course_contents now returns an additional field "tags" returning the content tags.
=== 3.6 === === 3.6 ===

View file

@ -1525,6 +1525,7 @@ $functions = array(
'description' => 'Gets tag index page for one tag and one tag area', 'description' => 'Gets tag index page for one tag and one tag area',
'type' => 'read', 'type' => 'read',
'ajax' => true, 'ajax' => true,
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
), ),
'core_tag_get_tags' => array( 'core_tag_get_tags' => array(
'classname' => 'core_tag_external', 'classname' => 'core_tag_external',
@ -1540,6 +1541,34 @@ $functions = array(
'type' => 'write', 'type' => 'write',
'ajax' => true, 'ajax' => true,
), ),
'core_tag_get_tagindex_per_area' => array(
'classname' => 'core_tag_external',
'methodname' => 'get_tagindex_per_area',
'description' => 'Gets tag index page per different areas.',
'type' => 'read',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
),
'core_tag_get_tag_areas' => array(
'classname' => 'core_tag_external',
'methodname' => 'get_tag_areas',
'description' => 'Retrieves existing tag areas.',
'type' => 'read',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
),
'core_tag_get_tag_collections' => array(
'classname' => 'core_tag_external',
'methodname' => 'get_tag_collections',
'description' => 'Retrieves existing tag collections.',
'type' => 'read',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
),
'core_tag_get_tag_cloud' => array(
'classname' => 'core_tag_external',
'methodname' => 'get_tag_cloud',
'description' => 'Retrieves a tag cloud for the given collection and/or query search.',
'type' => 'read',
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
),
'core_update_inplace_editable' => array( 'core_update_inplace_editable' => array(
'classname' => 'core_external', 'classname' => 'core_external',
'methodname' => 'update_inplace_editable', 'methodname' => 'update_inplace_editable',

View file

@ -611,6 +611,7 @@ function book_export_contents($cm, $baseurl) {
$chapterindexfile['userid'] = null; $chapterindexfile['userid'] = null;
$chapterindexfile['author'] = null; $chapterindexfile['author'] = null;
$chapterindexfile['license'] = null; $chapterindexfile['license'] = null;
$chapterindexfile['tags'] = \core_tag\external\util::get_item_tags('mod_book', 'book_chapters', $chapter->id);
$contents[] = $chapterindexfile; $contents[] = $chapterindexfile;
// Chapter files (images usually). // Chapter files (images usually).

View file

@ -45,7 +45,8 @@ class mod_book_lib_testcase extends advanced_testcase {
} }
public function test_export_contents() { public function test_export_contents() {
global $DB; global $DB, $CFG;
require_once($CFG->dirroot . '/course/externallib.php');
$user = $this->getDataGenerator()->create_user(); $user = $this->getDataGenerator()->create_user();
$course = $this->getDataGenerator()->create_course(array('enablecomment' => 1)); $course = $this->getDataGenerator()->create_course(array('enablecomment' => 1));
@ -57,7 +58,10 @@ class mod_book_lib_testcase extends advanced_testcase {
$cm = get_coursemodule_from_id('book', $book->cmid); $cm = get_coursemodule_from_id('book', $book->cmid);
$bookgenerator = $this->getDataGenerator()->get_plugin_generator('mod_book'); $bookgenerator = $this->getDataGenerator()->get_plugin_generator('mod_book');
$chapter1 = $bookgenerator->create_chapter(array('bookid' => $book->id, "pagenum" => 1)); $chapter1 = $bookgenerator->create_chapter(array('bookid' => $book->id, "pagenum" => 1,
'tags' => array('Cats', 'Dogs')));
$tag = core_tag_tag::get_by_name(0, 'Cats');
$chapter2 = $bookgenerator->create_chapter(array('bookid' => $book->id, "pagenum" => 2)); $chapter2 = $bookgenerator->create_chapter(array('bookid' => $book->id, "pagenum" => 2));
$subchapter = $bookgenerator->create_chapter(array('bookid' => $book->id, "pagenum" => 3, "subchapter" => 1)); $subchapter = $bookgenerator->create_chapter(array('bookid' => $book->id, "pagenum" => 3, "subchapter" => 1));
$chapter3 = $bookgenerator->create_chapter(array('bookid' => $book->id, "pagenum" => 4, "hidden" => 1)); $chapter3 = $bookgenerator->create_chapter(array('bookid' => $book->id, "pagenum" => 4, "hidden" => 1));
@ -71,11 +75,24 @@ class mod_book_lib_testcase extends advanced_testcase {
$this->assertEquals('structure', $contents[0]['filename']); $this->assertEquals('structure', $contents[0]['filename']);
$this->assertEquals('index.html', $contents[1]['filename']); $this->assertEquals('index.html', $contents[1]['filename']);
$this->assertEquals('Chapter 1', $contents[1]['content']); $this->assertEquals('Chapter 1', $contents[1]['content']);
$this->assertCount(2, $contents[1]['tags']);
$this->assertEquals('Cats', $contents[1]['tags'][0]['rawname']);
$this->assertEquals($tag->id, $contents[1]['tags'][0]['id']);
$this->assertEquals('Dogs', $contents[1]['tags'][1]['rawname']);
$this->assertEquals('index.html', $contents[2]['filename']); $this->assertEquals('index.html', $contents[2]['filename']);
$this->assertEquals('Chapter 2', $contents[2]['content']); $this->assertEquals('Chapter 2', $contents[2]['content']);
$this->assertEquals('index.html', $contents[3]['filename']); $this->assertEquals('index.html', $contents[3]['filename']);
$this->assertEquals('Chapter 3', $contents[3]['content']); $this->assertEquals('Chapter 3', $contents[3]['content']);
// Now, test the function via the external API.
$contents = core_course_external::get_course_contents($course->id, array());
$contents = external_api::clean_returnvalue(core_course_external::get_course_contents_returns(), $contents);
$this->assertEquals('book', $contents[0]['modules'][0]['modname']);
$this->assertEquals($cm->id, $contents[0]['modules'][0]['id']);
$this->assertCount(2, $contents[0]['modules'][0]['contents'][1]['tags']);
$this->assertEquals('Cats', $contents[0]['modules'][0]['contents'][1]['tags'][0]['rawname']);
$this->assertEquals('Dogs', $contents[0]['modules'][0]['contents'][1]['tags'][1]['rawname']);
// Test empty book. // Test empty book.
$emptybook = $this->getDataGenerator()->create_module('book', array('course' => $course->id)); $emptybook = $this->getDataGenerator()->create_module('book', array('course' => $course->id));
$cm = get_coursemodule_from_id('book', $emptybook->cmid); $cm = get_coursemodule_from_id('book', $emptybook->cmid);

View file

@ -1,5 +1,9 @@
This files describes API changes in the book code. This files describes API changes in the book code.
=== 3.7 ===
* book_export_contents() callback now returns tags information for every chapter.
=== 3.1 === === 3.1 ===
* The following functions, previously used (exclusively) by upgrade steps are not available * The following functions, previously used (exclusively) by upgrade steps are not available

View file

@ -27,6 +27,7 @@ defined('MOODLE_INTERNAL') || die();
use core\external\exporter; use core\external\exporter;
use renderer_base; use renderer_base;
use core_user; use core_user;
use core_tag\external\tag_item_exporter;
/** /**
* Class for exporting record data. * Class for exporting record data.
@ -102,6 +103,12 @@ class record_exporter extends exporter {
'multiple' => true, 'multiple' => true,
'optional' => true, 'optional' => true,
), ),
'tags' => array(
'type' => tag_item_exporter::read_properties_definition(),
'description' => 'Tags.',
'multiple' => true,
'optional' => true,
),
); );
} }
@ -128,6 +135,9 @@ class record_exporter extends exporter {
} }
$values['contents'] = $contents; $values['contents'] = $contents;
} }
$values['tags'] = \core_tag\external\util::get_item_tags('mod_data', 'data_records', $this->data->id);
return $values; return $values;
} }
} }

View file

@ -412,9 +412,9 @@ class mod_data_external_testcase extends externallib_advanced_testcase {
} }
$this->setUser($this->student1); $this->setUser($this->student1);
$entry11 = $generator->create_entry($this->database, $fieldcontents, $this->group1->id); $entry11 = $generator->create_entry($this->database, $fieldcontents, $this->group1->id, ['Cats', 'Dogs']);
$this->setUser($this->student2); $this->setUser($this->student2);
$entry12 = $generator->create_entry($this->database, $fieldcontents, $this->group1->id); $entry12 = $generator->create_entry($this->database, $fieldcontents, $this->group1->id, ['Cats']);
$entry13 = $generator->create_entry($this->database, $fieldcontents, $this->group1->id); $entry13 = $generator->create_entry($this->database, $fieldcontents, $this->group1->id);
// Entry not in group. // Entry not in group.
$entry14 = $generator->create_entry($this->database, $fieldcontents, 0); $entry14 = $generator->create_entry($this->database, $fieldcontents, 0);
@ -447,10 +447,13 @@ class mod_data_external_testcase extends externallib_advanced_testcase {
$this->assertCount(3, $result['entries']); $this->assertCount(3, $result['entries']);
$this->assertEquals(3, $result['totalcount']); $this->assertEquals(3, $result['totalcount']);
$this->assertEquals($entry11, $result['entries'][0]['id']); $this->assertEquals($entry11, $result['entries'][0]['id']);
$this->assertCount(2, $result['entries'][0]['tags']);
$this->assertEquals($this->student1->id, $result['entries'][0]['userid']); $this->assertEquals($this->student1->id, $result['entries'][0]['userid']);
$this->assertEquals($this->group1->id, $result['entries'][0]['groupid']); $this->assertEquals($this->group1->id, $result['entries'][0]['groupid']);
$this->assertEquals($this->database->id, $result['entries'][0]['dataid']); $this->assertEquals($this->database->id, $result['entries'][0]['dataid']);
$this->assertEquals($entry12, $result['entries'][1]['id']); $this->assertEquals($entry12, $result['entries'][1]['id']);
$this->assertCount(1, $result['entries'][1]['tags']);
$this->assertEquals('Cats', $result['entries'][1]['tags'][0]['rawname']);
$this->assertEquals($this->student2->id, $result['entries'][1]['userid']); $this->assertEquals($this->student2->id, $result['entries'][1]['userid']);
$this->assertEquals($this->group1->id, $result['entries'][1]['groupid']); $this->assertEquals($this->group1->id, $result['entries'][1]['groupid']);
$this->assertEquals($this->database->id, $result['entries'][1]['dataid']); $this->assertEquals($this->database->id, $result['entries'][1]['dataid']);

View file

@ -1,6 +1,9 @@
This files describes API changes in /mod/data - plugins, This files describes API changes in /mod/data - plugins,
information provided here is intended especially for developers. information provided here is intended especially for developers.
=== 3.7 ===
* External functions get_entries, get_entry and search_entries now return an additional field "tags" containing the entry tags.
=== 3.4 === === 3.4 ===
* External function mod_data_external::search_entries() now returns the maxcount field: Total count of records that the user could * External function mod_data_external::search_entries() now returns the maxcount field: Total count of records that the user could
see in the database (if all the search criterias were removed). see in the database (if all the search criterias were removed).

View file

@ -421,6 +421,8 @@ class mod_forum_external extends external_api {
if (!empty($messageinlinefiles)) { if (!empty($messageinlinefiles)) {
$post->messageinlinefiles = $messageinlinefiles; $post->messageinlinefiles = $messageinlinefiles;
} }
// Post tags.
$post->tags = \core_tag\external\util::get_item_tags('mod_forum', 'forum_posts', $post->id);
$posts[] = $post; $posts[] = $post;
} }
@ -467,6 +469,9 @@ class mod_forum_external extends external_api {
'userpictureurl' => new external_value(PARAM_URL, 'Post author picture.', VALUE_OPTIONAL), 'userpictureurl' => new external_value(PARAM_URL, 'Post author picture.', VALUE_OPTIONAL),
'deleted' => new external_value(PARAM_BOOL, 'This post has been removed.'), 'deleted' => new external_value(PARAM_BOOL, 'This post has been removed.'),
'isprivatereply' => new external_value(PARAM_BOOL, 'The post is a private reply'), 'isprivatereply' => new external_value(PARAM_BOOL, 'The post is a private reply'),
'tags' => new external_multiple_structure(
\core_tag\external\tag_item_exporter::get_read_structure(), 'Tags', VALUE_OPTIONAL
),
), 'post' ), 'post'
) )
), ),

View file

@ -260,6 +260,7 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
$record->parent = $discussion1reply1->id; $record->parent = $discussion1reply1->id;
$record->userid = $user3->id; $record->userid = $user3->id;
$record->tags = array('Cats', 'Dogs');
$discussion1reply2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record); $discussion1reply2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
// Enrol the user in the course. // Enrol the user in the course.
@ -311,7 +312,12 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
'userpictureurl' => '', 'userpictureurl' => '',
'deleted' => false, 'deleted' => false,
'isprivatereply' => false, 'isprivatereply' => false,
'tags' => \core_tag\external\util::get_item_tags('mod_forum', 'forum_posts', $discussion1reply2->id),
); );
// Cast to expected.
$this->assertCount(2, $expectedposts['posts'][0]['tags']);
$expectedposts['posts'][0]['tags'][0]['isstandard'] = (bool) $expectedposts['posts'][0]['tags'][0]['isstandard'];
$expectedposts['posts'][0]['tags'][1]['isstandard'] = (bool) $expectedposts['posts'][0]['tags'][1]['isstandard'];
$expectedposts['posts'][] = array( $expectedposts['posts'][] = array(
'id' => $discussion1reply1->id, 'id' => $discussion1reply1->id,
@ -348,6 +354,7 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
'userpictureurl' => '', 'userpictureurl' => '',
'deleted' => false, 'deleted' => false,
'isprivatereply' => false, 'isprivatereply' => false,
'tags' => array(),
); );
// Test a discussion with two additional posts (total 3 posts). // Test a discussion with two additional posts (total 3 posts).

View file

@ -9,8 +9,8 @@ information provided here is intended especially for developers.
* The get_forum_discussion_posts web service has been deprecated in favour of get_discussion_posts. * The get_forum_discussion_posts web service has been deprecated in favour of get_discussion_posts.
* The forum_count_replies function has been deprecated in favour of get_reply_count_for_post_id_in_discussion_id in * The forum_count_replies function has been deprecated in favour of get_reply_count_for_post_id_in_discussion_id in
the Post vault. the Post vault.
* External function get_forums_by_courses now returns two additional fields "duedate" and "cutoffdate" containing the due date and the cutoff date * External function get_forums_by_courses now returns two additional fields "duedate" and "cutoffdate" containing the due date and the cutoff date for posting to the forums respectively.
for posting to the forums respectively. * External function get_forum_discussion_posts now returns an additional field "tags" returning the post tags.
=== 3.6 === === 3.6 ===

View file

@ -101,6 +101,9 @@ class mod_glossary_external extends external_api {
'casesensitive' => new external_value(PARAM_BOOL, 'When true, the matching is case sensitive'), 'casesensitive' => new external_value(PARAM_BOOL, 'When true, the matching is case sensitive'),
'fullmatch' => new external_value(PARAM_BOOL, 'When true, the matching is done on full words only'), 'fullmatch' => new external_value(PARAM_BOOL, 'When true, the matching is done on full words only'),
'approved' => new external_value(PARAM_BOOL, 'Whether the entry was approved'), 'approved' => new external_value(PARAM_BOOL, 'Whether the entry was approved'),
'tags' => new external_multiple_structure(
\core_tag\external\tag_item_exporter::get_read_structure(), 'Tags', VALUE_OPTIONAL
),
); );
if ($includecat) { if ($includecat) {
@ -149,6 +152,8 @@ class mod_glossary_external extends external_api {
if (!empty($definitioninlinefiles)) { if (!empty($definitioninlinefiles)) {
$entry->definitioninlinefiles = $definitioninlinefiles; $entry->definitioninlinefiles = $definitioninlinefiles;
} }
$entry->tags = \core_tag\external\util::get_item_tags('mod_glossary', 'glossary_entries', $entry->id);
} }
/** /**

View file

@ -203,7 +203,7 @@ class mod_glossary_external_testcase extends externallib_advanced_testcase {
$ctx = context_module::instance($g1->cmid); $ctx = context_module::instance($g1->cmid);
$this->getDataGenerator()->enrol_user($u1->id, $c1->id); $this->getDataGenerator()->enrol_user($u1->id, $c1->id);
$e1a = $gg->create_content($g1, array('approved' => 0, 'concept' => 'Bob', 'userid' => 2)); $e1a = $gg->create_content($g1, array('approved' => 0, 'concept' => 'Bob', 'userid' => 2, 'tags' => array('Cats', 'Dogs')));
$e1b = $gg->create_content($g1, array('approved' => 1, 'concept' => 'Jane', 'userid' => 2)); $e1b = $gg->create_content($g1, array('approved' => 1, 'concept' => 'Jane', 'userid' => 2));
$e1c = $gg->create_content($g1, array('approved' => 1, 'concept' => 'Alice', 'userid' => $u1->id)); $e1c = $gg->create_content($g1, array('approved' => 1, 'concept' => 'Alice', 'userid' => $u1->id));
$e1d = $gg->create_content($g1, array('approved' => 0, 'concept' => '0-day', 'userid' => $u1->id)); $e1d = $gg->create_content($g1, array('approved' => 0, 'concept' => '0-day', 'userid' => $u1->id));
@ -218,6 +218,8 @@ class mod_glossary_external_testcase extends externallib_advanced_testcase {
$this->assertEquals(3, $return['count']); $this->assertEquals(3, $return['count']);
$this->assertEquals($e1c->id, $return['entries'][0]['id']); $this->assertEquals($e1c->id, $return['entries'][0]['id']);
$this->assertEquals($e1a->id, $return['entries'][1]['id']); $this->assertEquals($e1a->id, $return['entries'][1]['id']);
$this->assertEquals('Cats', $return['entries'][1]['tags'][0]['rawname']);
$this->assertEquals('Dogs', $return['entries'][1]['tags'][1]['rawname']);
$this->assertEquals($e1b->id, $return['entries'][2]['id']); $this->assertEquals($e1b->id, $return['entries'][2]['id']);
// An admin user requesting all the entries. // An admin user requesting all the entries.
@ -311,7 +313,7 @@ class mod_glossary_external_testcase extends externallib_advanced_testcase {
$now = time(); $now = time();
$e1a = $gg->create_content($g1, array('approved' => 1, 'concept' => 'Bob', 'userid' => $u1->id, $e1a = $gg->create_content($g1, array('approved' => 1, 'concept' => 'Bob', 'userid' => $u1->id,
'timecreated' => 1, 'timemodified' => $now + 3600)); 'timecreated' => 1, 'timemodified' => $now + 3600, 'tags' => array('Cats', 'Dogs')));
$e1b = $gg->create_content($g1, array('approved' => 1, 'concept' => 'Jane', 'userid' => $u1->id, $e1b = $gg->create_content($g1, array('approved' => 1, 'concept' => 'Jane', 'userid' => $u1->id,
'timecreated' => $now + 3600, 'timemodified' => 1)); 'timecreated' => $now + 3600, 'timemodified' => 1));
$e1c = $gg->create_content($g1, array('approved' => 1, 'concept' => 'Alice', 'userid' => $u1->id, $e1c = $gg->create_content($g1, array('approved' => 1, 'concept' => 'Alice', 'userid' => $u1->id,
@ -328,6 +330,8 @@ class mod_glossary_external_testcase extends externallib_advanced_testcase {
$this->assertCount(3, $return['entries']); $this->assertCount(3, $return['entries']);
$this->assertEquals(3, $return['count']); $this->assertEquals(3, $return['count']);
$this->assertEquals($e1a->id, $return['entries'][0]['id']); $this->assertEquals($e1a->id, $return['entries'][0]['id']);
$this->assertEquals('Cats', $return['entries'][0]['tags'][0]['rawname']);
$this->assertEquals('Dogs', $return['entries'][0]['tags'][1]['rawname']);
$this->assertEquals($e1c->id, $return['entries'][1]['id']); $this->assertEquals($e1c->id, $return['entries'][1]['id']);
$this->assertEquals($e1b->id, $return['entries'][2]['id']); $this->assertEquals($e1b->id, $return['entries'][2]['id']);
@ -425,7 +429,7 @@ class mod_glossary_external_testcase extends externallib_advanced_testcase {
$u1 = $this->getDataGenerator()->create_user(); $u1 = $this->getDataGenerator()->create_user();
$ctx = context_module::instance($g1->cmid); $ctx = context_module::instance($g1->cmid);
$e1a1 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id)); $e1a1 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id, 'tags' => array('Cats', 'Dogs')));
$e1a2 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id)); $e1a2 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id));
$e1a3 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id)); $e1a3 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id));
$e1b1 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id)); $e1b1 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id));
@ -448,6 +452,8 @@ class mod_glossary_external_testcase extends externallib_advanced_testcase {
$this->assertCount(3, $return['entries']); $this->assertCount(3, $return['entries']);
$this->assertEquals(3, $return['count']); $this->assertEquals(3, $return['count']);
$this->assertEquals($e1a1->id, $return['entries'][0]['id']); $this->assertEquals($e1a1->id, $return['entries'][0]['id']);
$this->assertEquals('Cats', $return['entries'][0]['tags'][0]['rawname']);
$this->assertEquals('Dogs', $return['entries'][0]['tags'][1]['rawname']);
$this->assertEquals($e1a2->id, $return['entries'][1]['id']); $this->assertEquals($e1a2->id, $return['entries'][1]['id']);
$this->assertEquals($e1a3->id, $return['entries'][2]['id']); $this->assertEquals($e1a3->id, $return['entries'][2]['id']);
@ -562,7 +568,7 @@ class mod_glossary_external_testcase extends externallib_advanced_testcase {
$e1a2 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id)); $e1a2 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id));
$e1a3 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id)); $e1a3 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id));
$e1b1 = $gg->create_content($g1, array('approved' => 0, 'userid' => $u2->id)); $e1b1 = $gg->create_content($g1, array('approved' => 0, 'userid' => $u2->id));
$e1b2 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u2->id)); $e1b2 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u2->id, 'tags' => array('Cats', 'Dogs')));
$e1c1 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u3->id)); $e1c1 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u3->id));
$e1d1 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u4->id)); $e1d1 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u4->id));
$e2a = $gg->create_content($g2, array('approved' => 1, 'userid' => $u1->id)); $e2a = $gg->create_content($g2, array('approved' => 1, 'userid' => $u1->id));
@ -575,6 +581,8 @@ class mod_glossary_external_testcase extends externallib_advanced_testcase {
$this->assertCount(4, $return['entries']); $this->assertCount(4, $return['entries']);
$this->assertEquals(4, $return['count']); $this->assertEquals(4, $return['count']);
$this->assertEquals($e1b2->id, $return['entries'][0]['id']); $this->assertEquals($e1b2->id, $return['entries'][0]['id']);
$this->assertEquals('Cats', $return['entries'][0]['tags'][0]['rawname']);
$this->assertEquals('Dogs', $return['entries'][0]['tags'][1]['rawname']);
$this->assertEquals($e1a1->id, $return['entries'][1]['id']); $this->assertEquals($e1a1->id, $return['entries'][1]['id']);
$this->assertEquals($e1a2->id, $return['entries'][2]['id']); $this->assertEquals($e1a2->id, $return['entries'][2]['id']);
$this->assertEquals($e1a3->id, $return['entries'][3]['id']); $this->assertEquals($e1a3->id, $return['entries'][3]['id']);
@ -780,7 +788,7 @@ class mod_glossary_external_testcase extends externallib_advanced_testcase {
$e1 = $gg->create_content($g1, array('approved' => 1, 'concept' => 'House', 'timecreated' => time() + 3600)); $e1 = $gg->create_content($g1, array('approved' => 1, 'concept' => 'House', 'timecreated' => time() + 3600));
$e2 = $gg->create_content($g1, array('approved' => 1, 'concept' => 'Mouse', 'timemodified' => 1)); $e2 = $gg->create_content($g1, array('approved' => 1, 'concept' => 'Mouse', 'timemodified' => 1));
$e3 = $gg->create_content($g1, array('approved' => 1, 'concept' => 'Hero')); $e3 = $gg->create_content($g1, array('approved' => 1, 'concept' => 'Hero', 'tags' => array('Cats', 'Dogs')));
$e4 = $gg->create_content($g1, array('approved' => 0, 'concept' => 'Toulouse')); $e4 = $gg->create_content($g1, array('approved' => 0, 'concept' => 'Toulouse'));
$e5 = $gg->create_content($g1, array('approved' => 1, 'definition' => 'Heroes', 'concept' => 'Abcd')); $e5 = $gg->create_content($g1, array('approved' => 1, 'definition' => 'Heroes', 'concept' => 'Abcd'));
$e6 = $gg->create_content($g1, array('approved' => 0, 'definition' => 'When used for Heroes')); $e6 = $gg->create_content($g1, array('approved' => 0, 'definition' => 'When used for Heroes'));
@ -798,6 +806,8 @@ class mod_glossary_external_testcase extends externallib_advanced_testcase {
$this->assertCount(1, $return['entries']); $this->assertCount(1, $return['entries']);
$this->assertEquals(1, $return['count']); $this->assertEquals(1, $return['count']);
$this->assertEquals($e3->id, $return['entries'][0]['id']); $this->assertEquals($e3->id, $return['entries'][0]['id']);
$this->assertEquals('Cats', $return['entries'][0]['tags'][0]['rawname']);
$this->assertEquals('Dogs', $return['entries'][0]['tags'][1]['rawname']);
// Enabling full search. // Enabling full search.
$query = 'hero'; $query = 'hero';
@ -893,7 +903,8 @@ class mod_glossary_external_testcase extends externallib_advanced_testcase {
$this->setAdminUser(); $this->setAdminUser();
$e1 = $gg->create_content($g1, array('userid' => $u1->id, 'approved' => 1, 'concept' => 'cat')); $e1 = $gg->create_content($g1, array('userid' => $u1->id, 'approved' => 1, 'concept' => 'cat',
'tags' => array('Cats', 'Dogs')));
$e2 = $gg->create_content($g1, array('userid' => $u1->id, 'approved' => 1), array('cat', 'dog')); $e2 = $gg->create_content($g1, array('userid' => $u1->id, 'approved' => 1), array('cat', 'dog'));
$e3 = $gg->create_content($g1, array('userid' => $u1->id, 'approved' => 1), array('dog')); $e3 = $gg->create_content($g1, array('userid' => $u1->id, 'approved' => 1), array('dog'));
$e4 = $gg->create_content($g1, array('userid' => $u1->id, 'approved' => 0, 'concept' => 'dog')); $e4 = $gg->create_content($g1, array('userid' => $u1->id, 'approved' => 0, 'concept' => 'dog'));
@ -908,6 +919,8 @@ class mod_glossary_external_testcase extends externallib_advanced_testcase {
$expected = array($e1->id, $e2->id); $expected = array($e1->id, $e2->id);
$actual = array($return['entries'][0]['id'], $return['entries'][1]['id']); $actual = array($return['entries'][0]['id'], $return['entries'][1]['id']);
$this->assertEquals($expected, $actual, '', 0.0, 10, true); $this->assertEquals($expected, $actual, '', 0.0, 10, true);
$this->assertEquals('Cats', $return['entries'][0]['tags'][0]['rawname']);
$this->assertEquals('Dogs', $return['entries'][0]['tags'][1]['rawname']);
// Search alias. // Search alias.
$return = mod_glossary_external::get_entries_by_term($g1->id, 'dog', 0, 20, array('includenotapproved' => false)); $return = mod_glossary_external::get_entries_by_term($g1->id, 'dog', 0, 20, array('includenotapproved' => false));
@ -1063,7 +1076,7 @@ class mod_glossary_external_testcase extends externallib_advanced_testcase {
$ctx = context_module::instance($g1->cmid); $ctx = context_module::instance($g1->cmid);
$this->getDataGenerator()->enrol_user($u1->id, $c1->id); $this->getDataGenerator()->enrol_user($u1->id, $c1->id);
$e1 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id)); $e1 = $gg->create_content($g1, array('approved' => 1, 'userid' => $u1->id, 'tags' => array('Cats', 'Dogs')));
// Add a fake inline image to the entry. // Add a fake inline image to the entry.
$filename = 'shouldbeanimage.jpg'; $filename = 'shouldbeanimage.jpg';
$filerecordinline = array( $filerecordinline = array(
@ -1085,6 +1098,8 @@ class mod_glossary_external_testcase extends externallib_advanced_testcase {
$return = mod_glossary_external::get_entry_by_id($e1->id); $return = mod_glossary_external::get_entry_by_id($e1->id);
$return = external_api::clean_returnvalue(mod_glossary_external::get_entry_by_id_returns(), $return); $return = external_api::clean_returnvalue(mod_glossary_external::get_entry_by_id_returns(), $return);
$this->assertEquals($e1->id, $return['entry']['id']); $this->assertEquals($e1->id, $return['entry']['id']);
$this->assertEquals('Cats', $return['entry']['tags'][0]['rawname']);
$this->assertEquals('Dogs', $return['entry']['tags'][1]['rawname']);
$this->assertEquals($filename, $return['entry']['definitioninlinefiles'][0]['filename']); $this->assertEquals($filename, $return['entry']['definitioninlinefiles'][0]['filename']);
$return = mod_glossary_external::get_entry_by_id($e2->id); $return = mod_glossary_external::get_entry_by_id($e2->id);

View file

@ -1,6 +1,9 @@
This files describes API changes in /mod/glossary/*, This files describes API changes in /mod/glossary/*,
information provided here is intended especially for developers. information provided here is intended especially for developers.
=== 3.7 ===
* External functions get_entries_by_* and get_entry now return an additional field "tags" containing the entry tags.
=== 3.4 === === 3.4 ===
* External functions returning entries now return an additional field "ratinginfo" containing the entry rating information. * External functions returning entries now return an additional field "ratinginfo" containing the entry rating information.

View file

@ -492,7 +492,8 @@ class mod_wiki_external extends external_api {
'pageviews' => $page->pageviews, 'pageviews' => $page->pageviews,
'readonly' => $page->readonly, 'readonly' => $page->readonly,
'caneditpage' => $caneditpages, 'caneditpage' => $caneditpages,
'firstpage' => $page->id == $firstpage->id 'firstpage' => $page->id == $firstpage->id,
'tags' => \core_tag\external\util::get_item_tags('mod_wiki', 'wiki_pages', $page->id),
); );
// Refresh page cached content if needed. // Refresh page cached content if needed.
@ -555,6 +556,9 @@ class mod_wiki_external extends external_api {
'contentformat' => new external_format_value('cachedcontent', VALUE_OPTIONAL), 'contentformat' => new external_format_value('cachedcontent', VALUE_OPTIONAL),
'contentsize' => new external_value(PARAM_INT, 'Size of page contents in bytes (doesn\'t include'. 'contentsize' => new external_value(PARAM_INT, 'Size of page contents in bytes (doesn\'t include'.
' size of attached files).', VALUE_OPTIONAL), ' size of attached files).', VALUE_OPTIONAL),
'tags' => new external_multiple_structure(
\core_tag\external\tag_item_exporter::get_read_structure(), 'Tags', VALUE_OPTIONAL
),
), 'Pages' ), 'Pages'
) )
), ),
@ -623,6 +627,7 @@ class mod_wiki_external extends external_api {
$returnedpage['groupid'] = $subwiki->groupid; $returnedpage['groupid'] = $subwiki->groupid;
$returnedpage['userid'] = $subwiki->userid; $returnedpage['userid'] = $subwiki->userid;
$returnedpage['title'] = $page->title; $returnedpage['title'] = $page->title;
$returnedpage['tags'] = \core_tag\external\util::get_item_tags('mod_wiki', 'wiki_pages', $page->id);
// Refresh page cached content if needed. // Refresh page cached content if needed.
if ($page->timerendered + WIKI_REFRESH_CACHE_TIME < time()) { if ($page->timerendered + WIKI_REFRESH_CACHE_TIME < time()) {
@ -668,6 +673,9 @@ class mod_wiki_external extends external_api {
'contentformat' => new external_format_value('cachedcontent', VALUE_OPTIONAL), 'contentformat' => new external_format_value('cachedcontent', VALUE_OPTIONAL),
'caneditpage' => new external_value(PARAM_BOOL, 'True if user can edit the page.'), 'caneditpage' => new external_value(PARAM_BOOL, 'True if user can edit the page.'),
'version' => new external_value(PARAM_INT, 'Latest version of the page.', VALUE_OPTIONAL), 'version' => new external_value(PARAM_INT, 'Latest version of the page.', VALUE_OPTIONAL),
'tags' => new external_multiple_structure(
\core_tag\external\tag_item_exporter::get_read_structure(), 'Tags', VALUE_OPTIONAL
),
), 'Page' ), 'Page'
), ),
'warnings' => new external_warnings() 'warnings' => new external_warnings()

View file

@ -69,7 +69,8 @@ class mod_wiki_external_testcase extends externallib_advanced_testcase {
$this->getDataGenerator()->enrol_user($this->teacher->id, $this->course->id, $this->teacherrole->id, 'manual'); $this->getDataGenerator()->enrol_user($this->teacher->id, $this->course->id, $this->teacherrole->id, 'manual');
// Create first pages. // Create first pages.
$this->firstpage = $this->getDataGenerator()->get_plugin_generator('mod_wiki')->create_first_page($this->wiki); $this->firstpage = $this->getDataGenerator()->get_plugin_generator('mod_wiki')->create_first_page($this->wiki,
array('tags' => array('Cats', 'Dogs')));
} }
/** /**
@ -616,6 +617,10 @@ class mod_wiki_external_testcase extends externallib_advanced_testcase {
$expectedfirstpage['caneditpage'] = true; // No groups and students have 'mod/wiki:editpage' capability. $expectedfirstpage['caneditpage'] = true; // No groups and students have 'mod/wiki:editpage' capability.
$expectedfirstpage['firstpage'] = true; $expectedfirstpage['firstpage'] = true;
$expectedfirstpage['contentformat'] = 1; $expectedfirstpage['contentformat'] = 1;
$expectedfirstpage['tags'] = \core_tag\external\util::get_item_tags('mod_wiki', 'wiki_pages', $this->firstpage->id);
// Cast to expected.
$expectedfirstpage['tags'][0]['isstandard'] = (bool) $expectedfirstpage['tags'][0]['isstandard'];
$expectedfirstpage['tags'][1]['isstandard'] = (bool) $expectedfirstpage['tags'][1]['isstandard'];
$expectedpages[] = $expectedfirstpage; $expectedpages[] = $expectedfirstpage;
$result = mod_wiki_external::get_subwiki_pages($this->wiki->id); $result = mod_wiki_external::get_subwiki_pages($this->wiki->id);
@ -640,6 +645,7 @@ class mod_wiki_external_testcase extends externallib_advanced_testcase {
$expectednewpage['caneditpage'] = true; // No groups and students have 'mod/wiki:editpage' capability. $expectednewpage['caneditpage'] = true; // No groups and students have 'mod/wiki:editpage' capability.
$expectednewpage['firstpage'] = false; $expectednewpage['firstpage'] = false;
$expectednewpage['contentformat'] = 1; $expectednewpage['contentformat'] = 1;
$expectednewpage['tags'] = array();
array_unshift($expectedpages, $expectednewpage); // Add page to the beginning since it orders by title by default. array_unshift($expectedpages, $expectednewpage); // Add page to the beginning since it orders by title by default.
$result = mod_wiki_external::get_subwiki_pages($this->wiki->id); $result = mod_wiki_external::get_subwiki_pages($this->wiki->id);
@ -692,6 +698,7 @@ class mod_wiki_external_testcase extends externallib_advanced_testcase {
$expectedteacherpage['caneditpage'] = true; $expectedteacherpage['caneditpage'] = true;
$expectedteacherpage['firstpage'] = true; $expectedteacherpage['firstpage'] = true;
$expectedteacherpage['contentformat'] = 1; $expectedteacherpage['contentformat'] = 1;
$expectedteacherpage['tags'] = array();
$expectedpages = array($expectedteacherpage); $expectedpages = array($expectedteacherpage);
$result = mod_wiki_external::get_subwiki_pages($indwiki->id, 0, $this->teacher->id); $result = mod_wiki_external::get_subwiki_pages($indwiki->id, 0, $this->teacher->id);
@ -703,6 +710,7 @@ class mod_wiki_external_testcase extends externallib_advanced_testcase {
$expectedstudentpage['caneditpage'] = true; $expectedstudentpage['caneditpage'] = true;
$expectedstudentpage['firstpage'] = true; $expectedstudentpage['firstpage'] = true;
$expectedstudentpage['contentformat'] = 1; $expectedstudentpage['contentformat'] = 1;
$expectedstudentpage['tags'] = array();
$expectedpages = array($expectedstudentpage); $expectedpages = array($expectedstudentpage);
$result = mod_wiki_external::get_subwiki_pages($indwiki->id, 0, $this->student->id); $result = mod_wiki_external::get_subwiki_pages($indwiki->id, 0, $this->student->id);
@ -738,6 +746,7 @@ class mod_wiki_external_testcase extends externallib_advanced_testcase {
$expectedpage['caneditpage'] = true; // User belongs to group and has 'mod/wiki:editpage' capability. $expectedpage['caneditpage'] = true; // User belongs to group and has 'mod/wiki:editpage' capability.
$expectedpage['firstpage'] = true; $expectedpage['firstpage'] = true;
$expectedpage['contentformat'] = 1; $expectedpage['contentformat'] = 1;
$expectedpage['tags'] = array();
$expectedpages = array($expectedpage); $expectedpages = array($expectedpage);
$result = mod_wiki_external::get_subwiki_pages($this->wikisep->id, $this->group1->id); $result = mod_wiki_external::get_subwiki_pages($this->wikisep->id, $this->group1->id);
@ -760,6 +769,7 @@ class mod_wiki_external_testcase extends externallib_advanced_testcase {
$expectedpage['caneditpage'] = true; $expectedpage['caneditpage'] = true;
$expectedpage['firstpage'] = true; $expectedpage['firstpage'] = true;
$expectedpage['contentformat'] = 1; $expectedpage['contentformat'] = 1;
$expectedpage['tags'] = array();
$expectedpages = array($expectedpage); $expectedpages = array($expectedpage);
$result = mod_wiki_external::get_subwiki_pages($this->wikisep->id, 0); $result = mod_wiki_external::get_subwiki_pages($this->wikisep->id, 0);
@ -783,6 +793,7 @@ class mod_wiki_external_testcase extends externallib_advanced_testcase {
$expectedpage['caneditpage'] = true; // User belongs to group and has 'mod/wiki:editpage' capability. $expectedpage['caneditpage'] = true; // User belongs to group and has 'mod/wiki:editpage' capability.
$expectedpage['firstpage'] = true; $expectedpage['firstpage'] = true;
$expectedpage['contentformat'] = 1; $expectedpage['contentformat'] = 1;
$expectedpage['tags'] = array();
$expectedpages = array($expectedpage); $expectedpages = array($expectedpage);
$result = mod_wiki_external::get_subwiki_pages($this->wikivis->id, $this->group1->id); $result = mod_wiki_external::get_subwiki_pages($this->wikivis->id, $this->group1->id);
@ -794,6 +805,7 @@ class mod_wiki_external_testcase extends externallib_advanced_testcase {
$expectedpage['caneditpage'] = false; // User doesn't belong to group so he can't edit the page. $expectedpage['caneditpage'] = false; // User doesn't belong to group so he can't edit the page.
$expectedpage['firstpage'] = true; $expectedpage['firstpage'] = true;
$expectedpage['contentformat'] = 1; $expectedpage['contentformat'] = 1;
$expectedpage['tags'] = array();
$expectedpages = array($expectedpage); $expectedpages = array($expectedpage);
$result = mod_wiki_external::get_subwiki_pages($this->wikivis->id, $this->group2->id); $result = mod_wiki_external::get_subwiki_pages($this->wikivis->id, $this->group2->id);
@ -805,6 +817,7 @@ class mod_wiki_external_testcase extends externallib_advanced_testcase {
$expectedpage['caneditpage'] = false; $expectedpage['caneditpage'] = false;
$expectedpage['firstpage'] = true; $expectedpage['firstpage'] = true;
$expectedpage['contentformat'] = 1; $expectedpage['contentformat'] = 1;
$expectedpage['tags'] = array();
$expectedpages = array($expectedpage); $expectedpages = array($expectedpage);
$result = mod_wiki_external::get_subwiki_pages($this->wikivis->id, 0); $result = mod_wiki_external::get_subwiki_pages($this->wikivis->id, 0);
@ -827,6 +840,7 @@ class mod_wiki_external_testcase extends externallib_advanced_testcase {
$expectedpage['caneditpage'] = true; $expectedpage['caneditpage'] = true;
$expectedpage['firstpage'] = true; $expectedpage['firstpage'] = true;
$expectedpage['contentformat'] = 1; $expectedpage['contentformat'] = 1;
$expectedpage['tags'] = array();
$expectedpages = array($expectedpage); $expectedpages = array($expectedpage);
$result = mod_wiki_external::get_subwiki_pages($this->wikisepind->id, $this->group1->id, $this->student->id); $result = mod_wiki_external::get_subwiki_pages($this->wikisepind->id, $this->group1->id, $this->student->id);
@ -850,6 +864,7 @@ class mod_wiki_external_testcase extends externallib_advanced_testcase {
$expectedpage['caneditpage'] = false; $expectedpage['caneditpage'] = false;
$expectedpage['firstpage'] = true; $expectedpage['firstpage'] = true;
$expectedpage['contentformat'] = 1; $expectedpage['contentformat'] = 1;
$expectedpage['tags'] = array();
$expectedpages = array($expectedpage); $expectedpages = array($expectedpage);
$result = mod_wiki_external::get_subwiki_pages($this->wikisepind->id, $this->group1->id, $this->student2->id); $result = mod_wiki_external::get_subwiki_pages($this->wikisepind->id, $this->group1->id, $this->student2->id);
@ -872,6 +887,7 @@ class mod_wiki_external_testcase extends externallib_advanced_testcase {
$expectedpage['caneditpage'] = true; $expectedpage['caneditpage'] = true;
$expectedpage['firstpage'] = true; $expectedpage['firstpage'] = true;
$expectedpage['contentformat'] = 1; $expectedpage['contentformat'] = 1;
$expectedpage['tags'] = array();
$expectedpages = array($expectedpage); $expectedpages = array($expectedpage);
$result = mod_wiki_external::get_subwiki_pages($this->wikivisind->id, $this->group1->id, $this->student->id); $result = mod_wiki_external::get_subwiki_pages($this->wikivisind->id, $this->group1->id, $this->student->id);
@ -883,6 +899,7 @@ class mod_wiki_external_testcase extends externallib_advanced_testcase {
$expectedpage['caneditpage'] = false; $expectedpage['caneditpage'] = false;
$expectedpage['firstpage'] = true; $expectedpage['firstpage'] = true;
$expectedpage['contentformat'] = 1; $expectedpage['contentformat'] = 1;
$expectedpage['tags'] = array();
$expectedpages = array($expectedpage); $expectedpages = array($expectedpage);
$result = mod_wiki_external::get_subwiki_pages($this->wikivisind->id, $this->group2->id, $this->teacher->id); $result = mod_wiki_external::get_subwiki_pages($this->wikivisind->id, $this->group2->id, $this->teacher->id);
@ -894,6 +911,7 @@ class mod_wiki_external_testcase extends externallib_advanced_testcase {
$expectedpage['caneditpage'] = false; $expectedpage['caneditpage'] = false;
$expectedpage['firstpage'] = true; $expectedpage['firstpage'] = true;
$expectedpage['contentformat'] = 1; $expectedpage['contentformat'] = 1;
$expectedpage['tags'] = array();
$expectedpages = array($expectedpage); $expectedpages = array($expectedpage);
$result = mod_wiki_external::get_subwiki_pages($this->wikivisind->id, 0, $this->teacher->id); $result = mod_wiki_external::get_subwiki_pages($this->wikivisind->id, 0, $this->teacher->id);
@ -987,8 +1005,12 @@ class mod_wiki_external_testcase extends externallib_advanced_testcase {
'cachedcontent' => $this->firstpage->cachedcontent, 'cachedcontent' => $this->firstpage->cachedcontent,
'contentformat' => 1, 'contentformat' => 1,
'caneditpage' => true, 'caneditpage' => true,
'version' => 1 'version' => 1,
'tags' => \core_tag\external\util::get_item_tags('mod_wiki', 'wiki_pages', $this->firstpage->id),
); );
// Cast to expected.
$expectedpage['tags'][0]['isstandard'] = (bool) $expectedpage['tags'][0]['isstandard'];
$expectedpage['tags'][1]['isstandard'] = (bool) $expectedpage['tags'][1]['isstandard'];
$result = mod_wiki_external::get_page_contents($this->firstpage->id); $result = mod_wiki_external::get_page_contents($this->firstpage->id);
$result = external_api::clean_returnvalue(mod_wiki_external::get_page_contents_returns(), $result); $result = external_api::clean_returnvalue(mod_wiki_external::get_page_contents_returns(), $result);
@ -1000,6 +1022,7 @@ class mod_wiki_external_testcase extends externallib_advanced_testcase {
$expectedpage['id'] = $newpage->id; $expectedpage['id'] = $newpage->id;
$expectedpage['title'] = $newpage->title; $expectedpage['title'] = $newpage->title;
$expectedpage['cachedcontent'] = $newpage->cachedcontent; $expectedpage['cachedcontent'] = $newpage->cachedcontent;
$expectedpage['tags'] = array();
$result = mod_wiki_external::get_page_contents($newpage->id); $result = mod_wiki_external::get_page_contents($newpage->id);
$result = external_api::clean_returnvalue(mod_wiki_external::get_page_contents_returns(), $result); $result = external_api::clean_returnvalue(mod_wiki_external::get_page_contents_returns(), $result);
@ -1028,7 +1051,8 @@ class mod_wiki_external_testcase extends externallib_advanced_testcase {
'cachedcontent' => $this->fpsepg1indstu->cachedcontent, 'cachedcontent' => $this->fpsepg1indstu->cachedcontent,
'contentformat' => 1, 'contentformat' => 1,
'caneditpage' => true, 'caneditpage' => true,
'version' => 1 'version' => 1,
'tags' => array(),
); );
$result = mod_wiki_external::get_page_contents($this->fpsepg1indstu->id); $result = mod_wiki_external::get_page_contents($this->fpsepg1indstu->id);

View file

@ -1,6 +1,9 @@
This files describes API changes in /mod/wiki/*, This files describes API changes in /mod/wiki/*,
information provided here is intended especially for developers. information provided here is intended especially for developers.
=== 3.7 ===
* External functions get_subwiki_pages and get_page_contents now return an additional field "tags" returning the entry tags.
=== 3.2 === === 3.2 ===
* External functions that were returning file information now return the following file fields: * External functions that were returning file information now return the following file fields:
filename, filepath, mimetype, filesize, timemodified and fileurl. filename, filepath, mimetype, filesize, timemodified and fileurl.

View file

@ -335,4 +335,351 @@ class core_tag_external extends external_api {
), 'tag index' ), 'tag index'
); );
} }
/**
* Parameters for function get_tagindex_per_area()
*
* @return external_function_parameters
* @since Moodle 3.7
*/
public static function get_tagindex_per_area_parameters() {
return new external_function_parameters(
array(
'tagindex' => new external_single_structure(array(
'id' => new external_value(PARAM_INT, 'tag id', VALUE_OPTIONAL, 0),
'tag' => new external_value(PARAM_TAG, 'tag name', VALUE_OPTIONAL, ''),
'tc' => new external_value(PARAM_INT, 'tag collection id', VALUE_OPTIONAL, 0),
'ta' => new external_value(PARAM_INT, 'tag area id', VALUE_OPTIONAL, 0),
'excl' => new external_value(PARAM_BOOL, 'exlusive mode for this tag area', VALUE_OPTIONAL, 0),
'from' => new external_value(PARAM_INT, 'context id where the link was displayed', VALUE_OPTIONAL, 0),
'ctx' => new external_value(PARAM_INT, 'context id where to search for items', VALUE_OPTIONAL, 0),
'rec' => new external_value(PARAM_INT, 'search in the context recursive', VALUE_OPTIONAL, 1),
'page' => new external_value(PARAM_INT, 'page number (0-based)', VALUE_OPTIONAL, 0),
), 'parameters')
)
);
}
/**
* Returns the tag index per multiple areas if requested.
*
* @param array $params Tag index required information.
* @throws moodle_exception
* @since Moodle 3.7
*/
public static function get_tagindex_per_area($params) {
global $CFG, $PAGE;
// Validate and normalize parameters.
$tagindex = self::validate_parameters(
self::get_tagindex_per_area_parameters(), array('tagindex' => $params));
$params = $tagindex['tagindex'] + array( // Force defaults.
'id' => 0,
'tag' => '',
'tc' => 0,
'ta' => 0,
'excl' => 0,
'from' => 0,
'ctx' => 0,
'rec' => 1,
'page' => 0,
);
if (empty($CFG->usetags)) {
throw new moodle_exception('tagsaredisabled', 'tag');
}
if (!empty($params['tag'])) {
if (empty($params['tc'])) {
// Tag name specified but tag collection was not. Try to guess it.
$tags = core_tag_tag::guess_by_name($params['tag'], '*');
if (count($tags) > 1) {
// It is in more that one collection, do not display.
throw new moodle_exception('Tag is in more that one collection, please indicate one.');
} else if (count($tags) == 1) {
$tag = reset($tags);
}
} else {
if (!$tag = core_tag_tag::get_by_name($params['tc'], $params['tag'], '*')) {
// Not found in collection.
throw new moodle_exception('notagsfound', 'tag');
}
}
} else if (!empty($params['id'])) {
$tag = core_tag_tag::get($params['id'], '*');
}
if (empty($tag)) {
throw new moodle_exception('notagsfound', 'tag');
}
// Login to the course / module if applicable.
$context = !empty($params['ctx']) ? context::instance_by_id($params['ctx']) : context_system::instance();
self::validate_context($context);
$tag = core_tag_tag::get_by_name($params['tc'], $tag->name, '*', MUST_EXIST);
$tagareas = core_tag_collection::get_areas($params['tc']);
$tagareaid = $params['ta'];
$exclusivemode = 0;
// Find all areas in this collection and their items tagged with this tag.
if ($tagareaid) {
$tagareas = array($tagareas[$tagareaid]);
}
if (!$tagareaid && count($tagareas) == 1) {
// Automatically set "exclusive" mode for tag collection with one tag area only.
$params['excl'] = 1;
}
$renderer = $PAGE->get_renderer('core');
$result = array();
foreach ($tagareas as $ta) {
$tagindex = $tag->get_tag_index($ta, $params['excl'], $params['from'], $params['ctx'], $params['rec'], $params['page']);
if (!empty($tagindex->hascontent)) {
$result[] = $tagindex->export_for_template($renderer);
}
}
return $result;
}
/**
* Return structure for get_tagindex_per_area
*
* @return external_description
* @since Moodle 3.7
*/
public static function get_tagindex_per_area_returns() {
return new external_multiple_structure(
self::get_tagindex_returns()
);
}
/**
* Returns description of get_tag_areas() parameters.
*
* @return external_function_parameters
* @since Moodle 3.7
*/
public static function get_tag_areas_parameters() {
return new external_function_parameters(array());
}
/**
* Retrieves existing tag areas.
*
* @return array an array of warnings and objects containing the plugin information
* @throws moodle_exception
* @since Moodle 3.7
*/
public static function get_tag_areas() {
global $CFG, $PAGE;
if (empty($CFG->usetags)) {
throw new moodle_exception('tagsaredisabled', 'tag');
}
$context = context_system::instance();
self::validate_context($context);
$PAGE->set_context($context); // Needed by internal APIs.
$output = $PAGE->get_renderer('core');
$areas = core_tag_area::get_areas();
$exportedareas = array();
foreach ($areas as $itemtype => $component) {
foreach ($component as $area) {
// Move optional fields not part of the DB table to otherdata.
$locked = false;
if (isset($area->locked)) {
$locked = $area->locked;
unset($area->locked);
}
$exporter = new \core_tag\external\tag_area_exporter($area, array('locked' => $locked));
$exportedareas[] = $exporter->export($output);
}
}
return array(
'areas' => $exportedareas,
'warnings' => array(),
);
}
/**
* Returns description of get_tag_areas() result value.
*
* @return external_description
* @since Moodle 3.7
*/
public static function get_tag_areas_returns() {
return new external_single_structure(
array(
'areas' => new external_multiple_structure(
\core_tag\external\tag_area_exporter::get_read_structure()
),
'warnings' => new external_warnings(),
)
);
}
/**
* Returns description of get_tag_collections() parameters.
*
* @return external_function_parameters
* @since Moodle 3.7
*/
public static function get_tag_collections_parameters() {
return new external_function_parameters(array());
}
/**
* Retrieves existing tag collections.
*
* @return array an array of warnings and tag collections
* @throws moodle_exception
* @since Moodle 3.7
*/
public static function get_tag_collections() {
global $CFG, $PAGE;
if (empty($CFG->usetags)) {
throw new moodle_exception('tagsaredisabled', 'tag');
}
$context = context_system::instance();
self::validate_context($context);
$PAGE->set_context($context); // Needed by internal APIs.
$output = $PAGE->get_renderer('core');
$collections = core_tag_collection::get_collections();
$exportedcollections = array();
foreach ($collections as $collection) {
$exporter = new \core_tag\external\tag_collection_exporter($collection);
$exportedcollections[] = $exporter->export($output);
}
return array(
'collections' => $exportedcollections,
'warnings' => array(),
);
}
/**
* Returns description of get_tag_collections() result value.
*
* @return external_description
* @since Moodle 3.7
*/
public static function get_tag_collections_returns() {
return new external_single_structure(
array(
'collections' => new external_multiple_structure(
\core_tag\external\tag_collection_exporter::get_read_structure()
),
'warnings' => new external_warnings(),
)
);
}
/**
* Returns description of get_tag_cloud() parameters.
*
* @return external_function_parameters
* @since Moodle 3.7
*/
public static function get_tag_cloud_parameters() {
return new external_function_parameters(
array(
'tagcollid' => new external_value(PARAM_INT, 'Tag collection id.', VALUE_DEFAULT, 0),
'isstandard' => new external_value(PARAM_BOOL, 'Whether to return only standard tags.', VALUE_DEFAULT, false),
'limit' => new external_value(PARAM_INT, 'Maximum number of tags to retrieve.', VALUE_DEFAULT, 150),
'sort' => new external_value(PARAM_ALPHA, 'Sort order for display
(id, name, rawname, count, flag, isstandard, tagcollid).', VALUE_DEFAULT, 'name'),
'search' => new external_value(PARAM_RAW, 'Search string.', VALUE_DEFAULT, ''),
'fromctx' => new external_value(PARAM_INT, 'Context id where this tag cloud is displayed.', VALUE_DEFAULT, 0),
'ctx' => new external_value(PARAM_INT, 'Only retrieve tag instances in this context.', VALUE_DEFAULT, 0),
'rec' => new external_value(PARAM_INT, 'Retrieve tag instances in the $ctx context and it\'s children.',
VALUE_DEFAULT, 1),
)
);
}
/**
* Retrieves a tag cloud for display.
*
* @param int $tagcollid tag collection id
* @param bool $isstandard return only standard tags
* @param int $limit maximum number of tags to retrieve, tags are sorted by the instance count
* descending here regardless of $sort parameter
* @param string $sort sort order for display, default 'name' - tags will be sorted after they are retrieved
* @param string $search search string
* @param int $fromctx context id where this tag cloud is displayed
* @param int $ctx only retrieve tag instances in this context
* @param int $rec retrieve tag instances in the $ctx context and it's children (default 1)
* @return array an array of warnings and tag cloud information and items
* @throws moodle_exception
* @since Moodle 3.7
*/
public static function get_tag_cloud($tagcollid = 0, $isstandard = false, $limit = 150, $sort = 'name',
$search = '', $fromctx = 0, $ctx = 0, $rec = 1) {
global $CFG, $PAGE;
$params = self::validate_parameters(self::get_tag_cloud_parameters(),
array(
'tagcollid' => $tagcollid,
'isstandard' => $isstandard,
'limit' => $limit,
'sort' => $sort,
'search' => $search,
'fromctx' => $fromctx,
'ctx' => $ctx,
'rec' => $rec,
)
);
if (empty($CFG->usetags)) {
throw new moodle_exception('tagsaredisabled', 'tag');
}
$context = context_system::instance();
self::validate_context($context);
$PAGE->set_context($context); // Needed by internal APIs.
$output = $PAGE->get_renderer('core');
$tagcloud = core_tag_collection::get_tag_cloud($params['tagcollid'], $params['isstandard'], $params['limit'],
$params['sort'], $params['search'], $params['fromctx'], $params['ctx'], $params['rec']);
$result = $tagcloud->export_for_template($output);
$result->warnings = array();
return (array) $result;
}
/**
* Returns description of get_tag_cloud() result value.
*
* @return external_description
* @since Moodle 3.7
*/
public static function get_tag_cloud_returns() {
return new external_single_structure(
array(
'tags' => new external_multiple_structure(
new external_single_structure(
array(
'name' => new external_value(PARAM_TAG, 'Tag name.'),
'viewurl' => new external_value(PARAM_RAW, 'URL to view the tag index.'),
'flag' => new external_value(PARAM_BOOL, 'Whether the tag is flagged as inappropriate.',
VALUE_OPTIONAL),
'isstandard' => new external_value(PARAM_BOOL, 'Whether is a standard tag or not.', VALUE_OPTIONAL),
'count' => new external_value(PARAM_INT, 'Number of tag instances.', VALUE_OPTIONAL),
'size' => new external_value(PARAM_INT, 'Proportional size to display the tag.', VALUE_OPTIONAL),
), 'Tags.'
)
),
'tagscount' => new external_value(PARAM_INT, 'Number of tags returned.'),
'totalcount' => new external_value(PARAM_INT, 'Total count of tags.'),
'warnings' => new external_warnings(),
)
);
}
} }

View file

@ -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/>.
/**
* Contains related class for displaying information of a tag area.
*
* @package core_tag
* @copyright 2019 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_tag\external;
defined('MOODLE_INTERNAL') || die();
use core\external\exporter;
use renderer_base;
/**
* Contains related class for displaying information of a tag area.
*
* @package core_tag
* @copyright 2019 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class tag_area_exporter extends exporter {
/**
* Return the list of properties.
*
* @return array
*/
protected static function define_properties() {
return [
'id' => [
'type' => PARAM_INT,
'description' => 'Area id.',
],
'component' => [
'type' => PARAM_COMPONENT,
'description' => 'Component the area is related to.',
],
'itemtype' => [
'type' => PARAM_ALPHANUMEXT,
'description' => 'Type of item in the component.',
],
'enabled' => [
'type' => PARAM_BOOL,
'description' => 'Whether this area is enabled.',
'default' => true,
],
'tagcollid' => [
'type' => PARAM_INT,
'description' => 'The tag collection this are belongs to.',
],
'callback' => [
'type' => PARAM_ALPHANUMEXT,
'description' => 'Component callback for processing tags.',
'null' => NULL_ALLOWED,
],
'callbackfile' => [
'type' => PARAM_RAW,
'description' => 'Component callback file.',
'null' => NULL_ALLOWED,
],
'showstandard' => [
'type' => PARAM_INT,
'description' => 'Return whether to display only standard, only non-standard or both tags.',
'default' => 0,
],
'multiplecontexts' => [
'type' => PARAM_BOOL,
'description' => 'Whether the tag area allows tag instances to be created in multiple contexts. ',
'default' => false,
],
];
}
protected static function define_related() {
return array(
'locked' => 'bool?'
);
}
protected static function define_other_properties() {
return array(
'locked' => [
'type' => PARAM_BOOL,
'description' => 'Whether the area is locked.',
'null' => NULL_ALLOWED,
'default' => false,
'optional' => true,
]
);
}
protected function get_other_values(renderer_base $output) {
$values['locked'] = $this->related['locked'] ? true : false;
return $values;
}
}

View file

@ -0,0 +1,82 @@
<?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/>.
/**
* Contains related class for displaying information of a tag collection.
*
* @package core_tag
* @copyright 2019 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_tag\external;
defined('MOODLE_INTERNAL') || die();
use core\external\exporter;
/**
* Contains related class for displaying information of a tag collection.
*
* @package core_tag
* @copyright 2019 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class tag_collection_exporter extends exporter {
/**
* Return the list of properties.
*
* @return array
*/
protected static function define_properties() {
return [
'id' => [
'type' => PARAM_INT,
'description' => 'Collection id.',
],
'name' => [
'type' => PARAM_NOTAGS,
'description' => 'Collection name.',
'null' => NULL_ALLOWED,
],
'isdefault' => [
'type' => PARAM_BOOL,
'description' => 'Whether is the default collection.',
'default' => false,
],
'component' => [
'type' => PARAM_COMPONENT,
'description' => 'Component the collection is related to.',
'null' => NULL_ALLOWED,
],
'sortorder' => [
'type' => PARAM_INT,
'description' => 'Collection ordering in the list.',
],
'searchable' => [
'type' => PARAM_BOOL,
'description' => 'Whether the tag collection is searchable.',
'default' => true,
],
'customurl' => [
'type' => PARAM_NOTAGS,
'description' => 'Custom URL for the tag page instead of /tag/index.php.',
'null' => NULL_ALLOWED,
],
];
}
}

View file

@ -0,0 +1,92 @@
<?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/>.
/**
* Contains related class for displaying information of a tag item.
*
* @package core_tag
* @copyright 2019 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_tag\external;
defined('MOODLE_INTERNAL') || die();
use core\external\exporter;
/**
* Contains related class for displaying information of a tag item.
*
* @package core_tag
* @copyright 2019 Juan Leyva <juan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class tag_item_exporter extends exporter {
/**
* Return the list of properties.
*
* @return array
*/
protected static function define_properties() {
return [
'id' => [
'type' => PARAM_INT,
'description' => 'Tag id.',
],
'name' => [
'type' => PARAM_TAG,
'description' => 'Tag name.',
],
'rawname' => [
'type' => PARAM_RAW,
'description' => 'The raw, unnormalised name for the tag as entered by users.',
],
'isstandard' => [
'type' => PARAM_BOOL,
'description' => 'Whether this tag is standard.',
'default' => false,
],
'tagcollid' => [
'type' => PARAM_INT,
'description' => 'Tag collection id.',
],
'taginstanceid' => [
'type' => PARAM_INT,
'description' => 'Tag instance id.',
],
'taginstancecontextid' => [
'type' => PARAM_INT,
'description' => 'Context the tag instance belongs to.',
],
'itemid' => [
'type' => PARAM_INT,
'description' => 'Id of the record tagged.',
],
'ordering' => [
'type' => PARAM_INT,
'description' => 'Tag ordering.',
],
'flag' => [
'type' => PARAM_INT,
'description' => 'Whether the tag is flagged as inappropriate.',
'default' => 0,
'null' => NULL_ALLOWED,
],
];
}
}

70
tag/classes/external/util.php vendored Normal file
View file

@ -0,0 +1,70 @@
<?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/>.
/**
* Tag external functions utility class.
*
* @package core_tag
* @copyright 2019 Juan Leyva
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_tag\external;
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir . '/externallib.php');
use core_tag\external\tag_item_exporter;
use core_tag_tag;
/**
* Tag external functions utility class.
*
* @package core_tag
* @copyright 2019 Juan Leyva
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 3.7
*/
class util {
/**
* Get the array of core_tag_tag objects for external functions associated with an item (instances).
*
* @param string $component component responsible for tagging. For BC it can be empty but in this case the
* query will be slow because DB index will not be used.
* @param string $itemtype type of the tagged item
* @param int $itemid
* @param int $standardonly wether to return only standard tags or any
* @param int $tiuserid tag instance user id, only needed for tag areas with user tagging
* @return array tags for external functions
*/
public static function get_item_tags($component, $itemtype, $itemid, $standardonly = core_tag_tag::BOTH_STANDARD_AND_NOT,
$tiuserid = 0) {
global $PAGE;
$output = $PAGE->get_renderer('core');
$tagitems = core_tag_tag::get_item_tags($component, $itemtype, $itemid, $standardonly, $tiuserid);
$exportedtags = [];
foreach ($tagitems as $tagitem) {
$exporter = new tag_item_exporter($tagitem->to_object());
$exportedtags[] = (array) $exporter->export($output);
}
return $exportedtags;
}
}

View file

@ -181,4 +181,197 @@ class core_tag_external_testcase extends externallib_advanced_testcase {
$this->assertEquals('Rename me again', $res['value']); $this->assertEquals('Rename me again', $res['value']);
$this->assertEquals('Rename me again', $DB->get_field('tag', 'rawname', array('id' => $tag->id))); $this->assertEquals('Rename me again', $DB->get_field('tag', 'rawname', array('id' => $tag->id)));
} }
/**
* Test get_tagindex_per_area.
*/
public function test_get_tagindex_per_area() {
global $USER;
$this->resetAfterTest(true);
// Create tags for two user profiles and one course.
$this->setAdminUser();
$context = context_user::instance($USER->id);
core_tag_tag::set_item_tags('core', 'user', $USER->id, $context, array('test'));
$this->setUser($this->getDataGenerator()->create_user());
$context = context_user::instance($USER->id);
core_tag_tag::set_item_tags('core', 'user', $USER->id, $context, array('test'));
$course = $this->getDataGenerator()->create_course();
$context = context_course::instance($course->id);
core_tag_tag::set_item_tags('core', 'course', $course->id, $context, array('test'));
$tag = core_tag_tag::get_by_name(0, 'test');
// First, search by id.
$result = core_tag_external::get_tagindex_per_area(array('id' => $tag->id));
$result = external_api::clean_returnvalue(core_tag_external::get_tagindex_per_area_returns(), $result);
$this->assertCount(2, $result); // Two different areas: course and user.
$this->assertEquals($tag->id, $result[0]['tagid']);
$this->assertEquals('course', $result[0]['itemtype']);
$this->assertEquals($tag->id, $result[1]['tagid']);
$this->assertEquals('user', $result[1]['itemtype']);
// Now, search by name.
$result = core_tag_external::get_tagindex_per_area(array('tag' => 'test'));
$result = external_api::clean_returnvalue(core_tag_external::get_tagindex_per_area_returns(), $result);
$this->assertCount(2, $result); // Two different areas: course and user.
$this->assertEquals($tag->id, $result[0]['tagid']);
$this->assertEquals('course', $result[0]['itemtype']);
$this->assertEquals($tag->id, $result[1]['tagid']);
$this->assertEquals('user', $result[1]['itemtype']);
// Filter by tag area.
$result = core_tag_external::get_tagindex_per_area(array('tag' => 'test', 'ta' => $result[0]['ta']));
$result = external_api::clean_returnvalue(core_tag_external::get_tagindex_per_area_returns(), $result);
$this->assertCount(1, $result); // Just the given area.
$this->assertEquals($tag->id, $result[0]['tagid']);
$this->assertEquals('course', $result[0]['itemtype']);
// Now, search by tag collection (use default).
$result = core_tag_external::get_tagindex_per_area(array('id' => $tag->id, 'tc' => 1));
$result = external_api::clean_returnvalue(core_tag_external::get_tagindex_per_area_returns(), $result);
$this->assertCount(2, $result); // Two different areas: course and user.
}
/**
* Test get_tag_areas.
*/
public function test_get_tag_areas() {
global $DB;
$this->resetAfterTest(true);
$this->setAdminUser();
$result = core_tag_external::get_tag_areas();
$result = external_api::clean_returnvalue(core_tag_external::get_tag_areas_returns(), $result);
$areas = $DB->get_records('tag_area');
$this->assertCount(count($areas), $result['areas']);
foreach ($result['areas'] as $area) {
$this->assertEquals($areas[$area['id']]->component, $area['component']);
$this->assertEquals($areas[$area['id']]->itemtype, $area['itemtype']);
}
}
/**
* Test get_tag_collections.
*/
public function test_get_tag_collections() {
global $DB;
$this->resetAfterTest(true);
// Create new tag collection.
$data = (object) array('name' => 'new tag coll');
core_tag_collection::create($data);
$this->setAdminUser();
$result = core_tag_external::get_tag_collections();
$result = external_api::clean_returnvalue(core_tag_external::get_tag_collections_returns(), $result);
$collections = $DB->get_records('tag_coll');
$this->assertCount(count($collections), $result['collections']);
foreach ($result['collections'] as $collection) {
$this->assertEquals($collections[$collection['id']]->component, $collection['component']);
$this->assertEquals($collections[$collection['id']]->name, $collection['name']);
}
}
/**
* Test get_tag_cloud.
*/
public function test_get_tag_cloud() {
global $USER, $DB;
$this->resetAfterTest(true);
// Create tags for two user profiles, a post and one course.
$this->setAdminUser();
$context = context_user::instance($USER->id);
core_tag_tag::set_item_tags('core', 'user', $USER->id, $context, array('Cats', 'Dogs'));
$this->setUser($this->getDataGenerator()->create_user());
$context = context_user::instance($USER->id);
core_tag_tag::set_item_tags('core', 'user', $USER->id, $context, array('Mice'));
$course = $this->getDataGenerator()->create_course();
$coursecontext = context_course::instance($course->id);
core_tag_tag::set_item_tags('core', 'course', $course->id, $coursecontext, array('Cats'));
$post = new stdClass();
$post->userid = $USER->id;
$post->content = 'test post content text';
$post->id = $DB->insert_record('post', $post);
$context = context_system::instance();
core_tag_tag::set_item_tags('core', 'post', $post->id, $context, array('Horses', 'Cats'));
// First, retrieve complete cloud.
$result = core_tag_external::get_tag_cloud();
$result = external_api::clean_returnvalue(core_tag_external::get_tag_cloud_returns(), $result);
$this->assertCount(4, $result['tags']); // Four different tags: Cats, Dogs, Mice, Horses.
$this->assertEquals(4, $result['tagscount']);
$this->assertEquals(4, $result['totalcount']);
foreach ($result['tags'] as $tag) {
if ($tag['name'] == 'Cats') {
$this->assertEquals(3, $tag['count']);
} else {
$this->assertEquals(1, $tag['count']);
}
}
// Test filter by collection, pagination and sorting.
$defaultcoll = core_tag_collection::get_default();
$result = core_tag_external::get_tag_cloud($defaultcoll, false, 2, 'count');
$result = external_api::clean_returnvalue(core_tag_external::get_tag_cloud_returns(), $result);
$this->assertCount(2, $result['tags']); // Only two tags.
$this->assertEquals(2, $result['tagscount']);
$this->assertEquals(4, $result['totalcount']);
$this->assertEquals('Dogs', $result['tags'][0]['name']); // Lower count first.
// Test search.
$result = core_tag_external::get_tag_cloud(0, false, 150, 'name', 'Mice');
$result = external_api::clean_returnvalue(core_tag_external::get_tag_cloud_returns(), $result);
$this->assertCount(1, $result['tags']); // Only the searched tags.
$this->assertEquals(1, $result['tagscount']);
$this->assertEquals(1, $result['totalcount']); // When searching, the total is always for the search.
$this->assertEquals('Mice', $result['tags'][0]['name']);
$result = core_tag_external::get_tag_cloud(0, false, 150, 'name', 'Conejo');
$result = external_api::clean_returnvalue(core_tag_external::get_tag_cloud_returns(), $result);
$this->assertCount(0, $result['tags']); // Nothing found.
$this->assertEquals(0, $result['tagscount']);
$this->assertEquals(0, $result['totalcount']); // When searching, the total is always for the search.
// Test standard filtering.
$micetag = core_tag_tag::get_by_name($defaultcoll, 'Mice', '*');
$micetag->update(array('isstandard' => 1));
$result = core_tag_external::get_tag_cloud(0, true);
$result = external_api::clean_returnvalue(core_tag_external::get_tag_cloud_returns(), $result);
$this->assertCount(1, $result['tags']);
$this->assertEquals(1, $result['tagscount']);
$this->assertEquals(1, $result['totalcount']); // When searching, the total is always for the search.
$this->assertEquals('Mice', $result['tags'][0]['name']);
// Test course context filtering.
$result = core_tag_external::get_tag_cloud(0, false, 150, 'name', '', 0, $coursecontext->id);
$result = external_api::clean_returnvalue(core_tag_external::get_tag_cloud_returns(), $result);
$this->assertCount(1, $result['tags']);
$this->assertEquals(1, $result['tagscount']);
$this->assertEquals(1, $result['totalcount']); // When searching, the total is always for the search.
$this->assertEquals('Cats', $result['tags'][0]['name']);
// Complete system context.
$result = core_tag_external::get_tag_cloud(0, false, 150, 'name', '', 0, context_system::instance()->id);
$result = external_api::clean_returnvalue(core_tag_external::get_tag_cloud_returns(), $result);
$this->assertCount(4, $result['tags']);
$this->assertEquals(4, $result['tagscount']);
// Just system context - avoid children.
$result = core_tag_external::get_tag_cloud(0, false, 150, 'name', '', 0, context_system::instance()->id, 0);
$result = external_api::clean_returnvalue(core_tag_external::get_tag_cloud_returns(), $result);
$this->assertCount(2, $result['tags']);
$this->assertEquals(2, $result['tagscount']); // Horses and Cats.
$this->assertEquals('Cats', $result['tags'][0]['name']);
$this->assertEquals('Horses', $result['tags'][1]['name']);
}
} }

View file

@ -29,7 +29,7 @@
defined('MOODLE_INTERNAL') || die(); defined('MOODLE_INTERNAL') || die();
$version = 2019041000.03; // YYYYMMDD = weekly release date of this DEV branch. $version = 2019041000.04; // YYYYMMDD = weekly release date of this DEV branch.
// RR = release increments - 00 in DEV branches. // RR = release increments - 00 in DEV branches.
// .XX = incremental changes. // .XX = incremental changes.