diff --git a/mod/data/classes/external.php b/mod/data/classes/external.php index 0cd94578410..b188cbeec71 100644 --- a/mod/data/classes/external.php +++ b/mod/data/classes/external.php @@ -542,6 +542,7 @@ class mod_data_external extends external_api { $result = array( 'entry' => $entry, + 'ratinginfo' => \core_rating\external\util::get_rating_info($database, $context, 'mod_data', 'entry', array($record)), 'warnings' => $warnings ); // Check if we should return the entry rendered. @@ -564,6 +565,7 @@ class mod_data_external extends external_api { array( 'entry' => record_exporter::get_read_structure(), 'entryviewcontents' => new external_value(PARAM_RAW, 'The entry as is rendered in the site.', VALUE_OPTIONAL), + 'ratinginfo' => \core_rating\external\util::external_ratings_structure(), 'warnings' => new external_warnings() ) ); diff --git a/mod/data/tests/externallib_test.php b/mod/data/tests/externallib_test.php index 82208174b92..dece2fe9eea 100644 --- a/mod/data/tests/externallib_test.php +++ b/mod/data/tests/externallib_test.php @@ -1251,4 +1251,68 @@ class mod_data_external_testcase extends externallib_advanced_testcase { $this->expectException('moodle_exception'); mod_data_external::update_entry($entry11, []); } + + /** + * Test get_entry_rating_information. + */ + public function test_get_entry_rating_information() { + global $DB, $CFG; + require_once($CFG->dirroot . '/rating/lib.php'); + + $DB->set_field('data', 'assessed', RATING_AGGREGATE_SUM, array('id' => $this->database->id)); + $DB->set_field('data', 'scale', 100, array('id' => $this->database->id)); + list($entry11, $entry12, $entry13, $entry21) = self::populate_database_with_entries(); + + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + $this->getDataGenerator()->enrol_user($user1->id, $this->course->id, $this->studentrole->id, 'manual'); + $this->getDataGenerator()->enrol_user($user2->id, $this->course->id, $this->studentrole->id, 'manual'); + + // Rate the entry as user1. + $rating1 = new stdClass(); + $rating1->contextid = $this->context->id; + $rating1->component = 'mod_data'; + $rating1->ratingarea = 'entry'; + $rating1->itemid = $entry11; + $rating1->rating = 50; + $rating1->scaleid = 100; + $rating1->userid = $user1->id; + $rating1->timecreated = time(); + $rating1->timemodified = time(); + $rating1->id = $DB->insert_record('rating', $rating1); + + // Rate the entry as user2. + $rating2 = new stdClass(); + $rating2->contextid = $this->context->id; + $rating2->component = 'mod_data'; + $rating2->ratingarea = 'entry'; + $rating2->itemid = $entry11; + $rating2->rating = 100; + $rating2->scaleid = 100; + $rating2->userid = $user2->id; + $rating2->timecreated = time() + 1; + $rating2->timemodified = time() + 1; + $rating2->id = $DB->insert_record('rating', $rating2); + + // As student, retrieve ratings information. + $this->setUser($this->student2); + $result = mod_data_external::get_entry($entry11); + $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result); + $this->assertCount(1, $result['ratinginfo']['ratings']); + $this->assertFalse($result['ratinginfo']['ratings'][0]['canviewaggregate']); + $this->assertFalse($result['ratinginfo']['canviewall']); + $this->assertFalse($result['ratinginfo']['ratings'][0]['canrate']); + $this->assertTrue(!isset($result['ratinginfo']['ratings'][0]['count'])); + + // Now, as teacher, I should see the info correctly. + $this->setUser($this->teacher); + $result = mod_data_external::get_entry($entry11); + $result = external_api::clean_returnvalue(mod_data_external::get_entry_returns(), $result); + $this->assertCount(1, $result['ratinginfo']['ratings']); + $this->assertTrue($result['ratinginfo']['ratings'][0]['canviewaggregate']); + $this->assertTrue($result['ratinginfo']['canviewall']); + $this->assertTrue($result['ratinginfo']['ratings'][0]['canrate']); + $this->assertEquals(2, $result['ratinginfo']['ratings'][0]['count']); + $this->assertEquals(100, $result['ratinginfo']['ratings'][0]['aggregate']); // Expect maximium scale value. + } } diff --git a/mod/data/upgrade.txt b/mod/data/upgrade.txt index 92ede9dcf5f..28f7a44f24b 100644 --- a/mod/data/upgrade.txt +++ b/mod/data/upgrade.txt @@ -4,6 +4,7 @@ information provided here is intended especially for developers. === 3.4 === * 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). +* External function get_entry now returns an additional field "ratinginfo" containing the entry rating information. === 3.3.2 === * data_refresh_events() Now takes two additional parameters to refine the update to a specific instance. This function diff --git a/mod/forum/externallib.php b/mod/forum/externallib.php index 12c0e1278b1..9bdb2d4a59e 100644 --- a/mod/forum/externallib.php +++ b/mod/forum/externallib.php @@ -309,6 +309,7 @@ class mod_forum_external extends external_api { $result = array(); $result['posts'] = $posts; + $result['ratinginfo'] = \core_rating\external\util::get_rating_info($forum, $modcontext, 'mod_forum', 'post', $posts); $result['warnings'] = $warnings; return $result; } @@ -349,6 +350,7 @@ class mod_forum_external extends external_api { ), 'post' ) ), + 'ratinginfo' => \core_rating\external\util::external_ratings_structure(), 'warnings' => new external_warnings() ) ); diff --git a/mod/forum/tests/externallib_test.php b/mod/forum/tests/externallib_test.php index e3ee2b66a23..cfe301f47cb 100644 --- a/mod/forum/tests/externallib_test.php +++ b/mod/forum/tests/externallib_test.php @@ -275,6 +275,15 @@ class mod_forum_external_testcase extends externallib_advanced_testcase { // Create what we expect to be returned when querying the discussion. $expectedposts = array( 'posts' => array(), + 'ratinginfo' => array( + 'contextid' => $forum1context->id, + 'component' => 'mod_forum', + 'ratingarea' => 'post', + 'canviewall' => null, + 'canviewany' => null, + 'scales' => array(), + 'ratings' => array(), + ), 'warnings' => array(), ); @@ -1066,4 +1075,95 @@ class mod_forum_external_testcase extends externallib_advanced_testcase { } + /** + * Test get forum posts discussions including rating information. + */ + public function test_mod_forum_get_forum_discussion_rating_information() { + global $DB, $CFG; + require_once($CFG->dirroot . '/rating/lib.php'); + + $this->resetAfterTest(true); + + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + $user3 = self::getDataGenerator()->create_user(); + $teacher = self::getDataGenerator()->create_user(); + + // Create course to add the module. + $course = self::getDataGenerator()->create_course(); + + $studentrole = $DB->get_record('role', array('shortname' => 'student')); + $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher')); + $this->getDataGenerator()->enrol_user($user1->id, $course->id, $studentrole->id, 'manual'); + $this->getDataGenerator()->enrol_user($user2->id, $course->id, $studentrole->id, 'manual'); + $this->getDataGenerator()->enrol_user($user3->id, $course->id, $studentrole->id, 'manual'); + $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id, 'manual'); + + // Create the forum. + $record = new stdClass(); + $record->course = $course->id; + // Set Aggregate type = Average of ratings. + $record->assessed = RATING_AGGREGATE_AVERAGE; + $record->scale = 100; + $forum = self::getDataGenerator()->create_module('forum', $record); + $context = context_module::instance($forum->cmid); + + // Add discussion to the forum. + $record = new stdClass(); + $record->course = $course->id; + $record->userid = $user1->id; + $record->forum = $forum->id; + $discussion = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); + + // Retrieve the first post. + $post = $DB->get_record('forum_posts', array('discussion' => $discussion->id)); + + // Rate the discussion as user2. + $rating1 = new stdClass(); + $rating1->contextid = $context->id; + $rating1->component = 'mod_forum'; + $rating1->ratingarea = 'post'; + $rating1->itemid = $post->id; + $rating1->rating = 50; + $rating1->scaleid = 100; + $rating1->userid = $user2->id; + $rating1->timecreated = time(); + $rating1->timemodified = time(); + $rating1->id = $DB->insert_record('rating', $rating1); + + // Rate the discussion as user3. + $rating2 = new stdClass(); + $rating2->contextid = $context->id; + $rating2->component = 'mod_forum'; + $rating2->ratingarea = 'post'; + $rating2->itemid = $post->id; + $rating2->rating = 100; + $rating2->scaleid = 100; + $rating2->userid = $user3->id; + $rating2->timecreated = time() + 1; + $rating2->timemodified = time() + 1; + $rating2->id = $DB->insert_record('rating', $rating2); + + // Retrieve the rating for the post as student. + $this->setUser($user1); + $posts = mod_forum_external::get_forum_discussion_posts($discussion->id); + $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts); + $this->assertCount(1, $posts['ratinginfo']['ratings']); + $this->assertTrue($posts['ratinginfo']['ratings'][0]['canviewaggregate']); + $this->assertFalse($posts['ratinginfo']['canviewall']); + $this->assertFalse($posts['ratinginfo']['ratings'][0]['canrate']); + $this->assertEquals(2, $posts['ratinginfo']['ratings'][0]['count']); + $this->assertEquals(($rating1->rating + $rating2->rating) / 2, $posts['ratinginfo']['ratings'][0]['aggregate']); + + // Retrieve the rating for the post as teacher. + $this->setUser($teacher); + $posts = mod_forum_external::get_forum_discussion_posts($discussion->id); + $posts = external_api::clean_returnvalue(mod_forum_external::get_forum_discussion_posts_returns(), $posts); + $this->assertCount(1, $posts['ratinginfo']['ratings']); + $this->assertTrue($posts['ratinginfo']['ratings'][0]['canviewaggregate']); + $this->assertTrue($posts['ratinginfo']['canviewall']); + $this->assertTrue($posts['ratinginfo']['ratings'][0]['canrate']); + $this->assertEquals(2, $posts['ratinginfo']['ratings'][0]['count']); + $this->assertEquals(($rating1->rating + $rating2->rating) / 2, $posts['ratinginfo']['ratings'][0]['aggregate']); + } } diff --git a/mod/forum/upgrade.txt b/mod/forum/upgrade.txt index 1645cf74217..b34d16eafb8 100644 --- a/mod/forum/upgrade.txt +++ b/mod/forum/upgrade.txt @@ -1,6 +1,9 @@ This files describes API changes in /mod/forum/*, information provided here is intended especially for developers. +=== 3.4 === + * External function get_forum_discussion_posts now returns an additional field "ratinginfo" containing rating information. + === 3.3 === * External function get_forums_by_courses now returns and additional field "istracked" that indicates if the user is tracking the related forum. diff --git a/mod/glossary/classes/external.php b/mod/glossary/classes/external.php index c8ea35781ca..e900e04f1af 100644 --- a/mod/glossary/classes/external.php +++ b/mod/glossary/classes/external.php @@ -486,6 +486,7 @@ class mod_glossary_external extends external_api { return array( 'count' => $count, 'entries' => $entries, + 'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry', $entries), 'warnings' => $warnings ); } @@ -502,6 +503,7 @@ class mod_glossary_external extends external_api { 'entries' => new external_multiple_structure( self::get_entry_return_structure() ), + 'ratinginfo' => \core_rating\external\util::external_ratings_structure(), 'warnings' => new external_warnings() )); } @@ -583,6 +585,7 @@ class mod_glossary_external extends external_api { return array( 'count' => $count, 'entries' => $entries, + 'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry', $entries), 'warnings' => $warnings ); } @@ -599,6 +602,7 @@ class mod_glossary_external extends external_api { 'entries' => new external_multiple_structure( self::get_entry_return_structure() ), + 'ratinginfo' => \core_rating\external\util::external_ratings_structure(), 'warnings' => new external_warnings() )); } @@ -760,6 +764,7 @@ class mod_glossary_external extends external_api { return array( 'count' => $count, 'entries' => $entries, + 'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry', $entries), 'warnings' => $warnings ); } @@ -776,6 +781,7 @@ class mod_glossary_external extends external_api { 'entries' => new external_multiple_structure( self::get_entry_return_structure(true) ), + 'ratinginfo' => \core_rating\external\util::external_ratings_structure(), 'warnings' => new external_warnings() )); } @@ -954,6 +960,7 @@ class mod_glossary_external extends external_api { return array( 'count' => $count, 'entries' => $entries, + 'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry', $entries), 'warnings' => $warnings ); } @@ -970,6 +977,7 @@ class mod_glossary_external extends external_api { 'entries' => new external_multiple_structure( self::get_entry_return_structure() ), + 'ratinginfo' => \core_rating\external\util::external_ratings_structure(), 'warnings' => new external_warnings() )); } @@ -1057,6 +1065,7 @@ class mod_glossary_external extends external_api { return array( 'count' => $count, 'entries' => $entries, + 'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry', $entries), 'warnings' => $warnings ); } @@ -1073,6 +1082,7 @@ class mod_glossary_external extends external_api { 'entries' => new external_multiple_structure( self::get_entry_return_structure() ), + 'ratinginfo' => \core_rating\external\util::external_ratings_structure(), 'warnings' => new external_warnings() )); } @@ -1158,6 +1168,7 @@ class mod_glossary_external extends external_api { return array( 'count' => $count, 'entries' => $entries, + 'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry', $entries), 'warnings' => $warnings ); } @@ -1174,6 +1185,7 @@ class mod_glossary_external extends external_api { 'entries' => new external_multiple_structure( self::get_entry_return_structure() ), + 'ratinginfo' => \core_rating\external\util::external_ratings_structure(), 'warnings' => new external_warnings() )); } @@ -1238,6 +1250,7 @@ class mod_glossary_external extends external_api { return array( 'count' => $count, 'entries' => $entries, + 'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry', $entries), 'warnings' => $warnings ); } @@ -1254,6 +1267,7 @@ class mod_glossary_external extends external_api { 'entries' => new external_multiple_structure( self::get_entry_return_structure() ), + 'ratinginfo' => \core_rating\external\util::external_ratings_structure(), 'warnings' => new external_warnings() )); } @@ -1324,6 +1338,7 @@ class mod_glossary_external extends external_api { return array( 'count' => $count, 'entries' => $entries, + 'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry', $entries), 'warnings' => $warnings ); } @@ -1340,6 +1355,7 @@ class mod_glossary_external extends external_api { 'entries' => new external_multiple_structure( self::get_entry_return_structure() ), + 'ratinginfo' => \core_rating\external\util::external_ratings_structure(), 'warnings' => new external_warnings() )); } @@ -1385,6 +1401,8 @@ class mod_glossary_external extends external_api { return array( 'entry' => $entry, + 'ratinginfo' => \core_rating\external\util::get_rating_info($glossary, $context, 'mod_glossary', 'entry', + array($entry)), 'warnings' => $warnings ); } @@ -1398,6 +1416,7 @@ class mod_glossary_external extends external_api { public static function get_entry_by_id_returns() { return new external_single_structure(array( 'entry' => self::get_entry_return_structure(), + 'ratinginfo' => \core_rating\external\util::external_ratings_structure(), 'warnings' => new external_warnings() )); } diff --git a/mod/glossary/tests/external_test.php b/mod/glossary/tests/external_test.php index 60cf1e52273..7320657a5e8 100644 --- a/mod/glossary/tests/external_test.php +++ b/mod/glossary/tests/external_test.php @@ -1250,4 +1250,90 @@ class mod_glossary_external_testcase extends externallib_advanced_testcase { $this->assertEquals('shouldbeanimage.txt', $editorfiles[0]['filename']); $this->assertEquals('attachment.txt', $attachmentfiles[0]['filename']); } + + /** + * Test get entry including rating information. + */ + public function test_get_entry_rating_information() { + $this->resetAfterTest(true); + + global $DB, $CFG; + require_once($CFG->dirroot . '/rating/lib.php'); + + $this->resetAfterTest(true); + + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + $user3 = self::getDataGenerator()->create_user(); + $teacher = self::getDataGenerator()->create_user(); + + // Create course to add the module. + $course = self::getDataGenerator()->create_course(); + + $studentrole = $DB->get_record('role', array('shortname' => 'student')); + $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher')); + $this->getDataGenerator()->enrol_user($user1->id, $course->id, $studentrole->id, 'manual'); + $this->getDataGenerator()->enrol_user($user2->id, $course->id, $studentrole->id, 'manual'); + $this->getDataGenerator()->enrol_user($user3->id, $course->id, $studentrole->id, 'manual'); + $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id, 'manual'); + + // Create the glossary and contents. + $record = new stdClass(); + $record->course = $course->id; + $record->assessed = RATING_AGGREGATE_AVERAGE; + $scale = $this->getDataGenerator()->create_scale(array('scale' => 'A,B,C,D')); + $record->scale = "-$scale->id"; + $glossary = $this->getDataGenerator()->create_module('glossary', $record); + $context = context_module::instance($glossary->cmid); + + $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary'); + $entry = $gg->create_content($glossary, array('approved' => 1, 'userid' => $user1->id)); + + // Rate the entry as user2. + $rating1 = new stdClass(); + $rating1->contextid = $context->id; + $rating1->component = 'mod_glossary'; + $rating1->ratingarea = 'entry'; + $rating1->itemid = $entry->id; + $rating1->rating = 1; // 1 is A. + $rating1->scaleid = "-$scale->id"; + $rating1->userid = $user2->id; + $rating1->timecreated = time(); + $rating1->timemodified = time(); + $rating1->id = $DB->insert_record('rating', $rating1); + + // Rate the entry as user3. + $rating2 = new stdClass(); + $rating2->contextid = $context->id; + $rating2->component = 'mod_glossary'; + $rating2->ratingarea = 'entry'; + $rating2->itemid = $entry->id; + $rating2->rating = 3; // 3 is C. + $rating2->scaleid = "-$scale->id"; + $rating2->userid = $user3->id; + $rating2->timecreated = time() + 1; + $rating2->timemodified = time() + 1; + $rating2->id = $DB->insert_record('rating', $rating2); + + // As student, retrieve ratings information. + $this->setUser($user1); + $result = mod_glossary_external::get_entry_by_id($entry->id); + $result = external_api::clean_returnvalue(mod_glossary_external::get_entry_by_id_returns(), $result); + $this->assertCount(1, $result['ratinginfo']['ratings']); + $this->assertFalse($result['ratinginfo']['ratings'][0]['canviewaggregate']); + $this->assertFalse($result['ratinginfo']['canviewall']); + $this->assertFalse($result['ratinginfo']['ratings'][0]['canrate']); + $this->assertTrue(!isset($result['ratinginfo']['ratings'][0]['count'])); + + // Now, as teacher, I should see the info correctly. + $this->setUser($teacher); + $result = mod_glossary_external::get_entry_by_id($entry->id); + $result = external_api::clean_returnvalue(mod_glossary_external::get_entry_by_id_returns(), $result); + $this->assertCount(1, $result['ratinginfo']['ratings']); + $this->assertTrue($result['ratinginfo']['ratings'][0]['canviewaggregate']); + $this->assertTrue($result['ratinginfo']['canviewall']); + $this->assertTrue($result['ratinginfo']['ratings'][0]['canrate']); + $this->assertEquals(2, $result['ratinginfo']['ratings'][0]['count']); + $this->assertEquals(2, $result['ratinginfo']['ratings'][0]['aggregate']); // 2 is B, that is the average of A + C. + } } diff --git a/mod/glossary/upgrade.txt b/mod/glossary/upgrade.txt index a537f650884..6b298d2bbca 100644 --- a/mod/glossary/upgrade.txt +++ b/mod/glossary/upgrade.txt @@ -1,6 +1,9 @@ This files describes API changes in /mod/glossary/*, information provided here is intended especially for developers. +=== 3.4 === + * External functions returning entries now return an additional field "ratinginfo" containing the entry rating information. + === 3.2 === * External functions that were returning file information now return the following file fields: filename, filepath, mimetype, filesize, timemodified and fileurl. diff --git a/rating/classes/external/util.php b/rating/classes/external/util.php new file mode 100644 index 00000000000..39b165243c8 --- /dev/null +++ b/rating/classes/external/util.php @@ -0,0 +1,189 @@ +. + +/** + * Rating external functions utility class. + * + * @package core_rating + * @copyright 2017 Juan Leyva + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core_rating\external; + +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->dirroot . '/rating/lib.php'); +require_once($CFG->libdir . '/externallib.php'); + +use external_multiple_structure; +use external_single_structure; +use external_value; +use rating_manager; +use stdClass; + +/** + * Rating external functions utility class. + * + * @package core_rating + * @copyright 2017 Juan Leyva + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 3.4 + */ +class util { + + /** + * Returns the ratings definition for external functions. + */ + public static function external_ratings_structure() { + + return new external_single_structure ( + [ + 'contextid' => new external_value(PARAM_INT, 'Context id.'), + 'component' => new external_value(PARAM_COMPONENT, 'Context name.'), + 'ratingarea' => new external_value(PARAM_AREA, 'Rating area name.'), + 'canviewall' => new external_value(PARAM_BOOL, 'Whether the user can view all the individual ratings.', + VALUE_OPTIONAL), + 'canviewany' => new external_value(PARAM_BOOL, 'Whether the user can view aggregate of ratings of others.', + VALUE_OPTIONAL), + 'scales' => new external_multiple_structure( + new external_single_structure ( + [ + 'id' => new external_value(PARAM_INT, 'Scale id.'), + 'courseid' => new external_value(PARAM_INT, 'Course id.', VALUE_OPTIONAL), + 'name' => new external_value(PARAM_TEXT, 'Scale name (when a real scale is used).', VALUE_OPTIONAL), + 'max' => new external_value(PARAM_INT, 'Max value for the scale.'), + 'isnumeric' => new external_value(PARAM_BOOL, 'Whether is a numeric scale.'), + 'items' => new external_multiple_structure( + new external_single_structure ( + [ + 'value' => new external_value(PARAM_INT, 'Scale value/option id.'), + 'name' => new external_value(PARAM_NOTAGS, 'Scale name.'), + ] + ), 'Scale items. Only returned for not numerical scales.', VALUE_OPTIONAL + ) + ], 'Scale information' + ), 'Different scales used information', VALUE_OPTIONAL + ), + 'ratings' => new external_multiple_structure( + new external_single_structure ( + [ + 'itemid' => new external_value(PARAM_INT, 'Item id.'), + 'scaleid' => new external_value(PARAM_INT, 'Scale id.', VALUE_OPTIONAL), + 'userid' => new external_value(PARAM_INT, 'User who rated id.', VALUE_OPTIONAL), + 'aggregate' => new external_value(PARAM_FLOAT, 'Aggregated ratings grade.', VALUE_OPTIONAL), + 'aggregatestr' => new external_value(PARAM_NOTAGS, 'Aggregated ratings as string.', VALUE_OPTIONAL), + 'aggregatelabel' => new external_value(PARAM_NOTAGS, 'The aggregation label.', VALUE_OPTIONAL), + 'count' => new external_value(PARAM_INT, 'Ratings count (used when aggregating).', VALUE_OPTIONAL), + 'rating' => new external_value(PARAM_INT, 'The rating the user gave.', VALUE_OPTIONAL), + 'canrate' => new external_value(PARAM_BOOL, 'Whether the user can rate the item.', VALUE_OPTIONAL), + 'canviewaggregate' => new external_value(PARAM_BOOL, 'Whether the user can view the aggregated grade.', + VALUE_OPTIONAL), + ] + ), 'The ratings', VALUE_OPTIONAL + ), + ], 'Rating information', VALUE_OPTIONAL + ); + } + + /** + * Returns rating information inside a data structure like the one defined by external_ratings_structure. + * + * @param stdClass $mod course module object + * @param stdClass $context context object + * @param str $component component name + * @param str $ratingarea rating area + * @param array $items items to add ratings + * @return array ratings ready to be returned by external functions. + */ + public static function get_rating_info($mod, $context, $component, $ratingarea, $items) { + global $USER; + + $ratinginfo = [ + 'contextid' => $context->id, + 'component' => $component, + 'ratingarea' => $ratingarea, + 'canviewall' => null, + 'canviewany' => null, + 'scales' => [], + 'ratings' => [], + ]; + if ($mod->assessed != RATING_AGGREGATE_NONE) { + $ratingoptions = new stdClass; + $ratingoptions->context = $context; + $ratingoptions->component = $component; + $ratingoptions->ratingarea = $ratingarea; + $ratingoptions->items = $items; + $ratingoptions->aggregate = $mod->assessed; + $ratingoptions->scaleid = $mod->scale; + $ratingoptions->userid = $USER->id; + $ratingoptions->assesstimestart = $mod->assesstimestart; + $ratingoptions->assesstimefinish = $mod->assesstimefinish; + + $rm = new rating_manager(); + $allitems = $rm->get_ratings($ratingoptions); + + foreach ($allitems as $item) { + if (empty($item->rating)) { + continue; + } + $rating = [ + 'itemid' => $item->rating->itemid, + 'scaleid' => $item->rating->scaleid, + 'userid' => $item->rating->userid, + 'rating' => $item->rating->rating, + 'canrate' => $item->rating->user_can_rate(), + 'canviewaggregate' => $item->rating->user_can_view_aggregate(), + ]; + // Fill the capabilities fields the first time (the rest are the same values because they are not item dependent). + if ($ratinginfo['canviewall'] === null) { + $ratinginfo['canviewall'] = $item->rating->settings->permissions->viewall && + $item->rating->settings->pluginpermissions->viewall; + $ratinginfo['canviewany'] = $item->rating->settings->permissions->viewany && + $item->rating->settings->pluginpermissions->viewany; + } + + // Return only the information the user can see. + if ($rating['canviewaggregate']) { + $rating['aggregate'] = $item->rating->aggregate; + $rating['aggregatestr'] = $item->rating->get_aggregate_string(); + $rating['aggregatelabel'] = $rm->get_aggregate_label($item->rating->settings->aggregationmethod); + $rating['count'] = $item->rating->count; + } + // If the user can rate, return the scale information only one time. + if ($rating['canrate'] && + !empty($item->rating->settings->scale->id) && + !isset($ratinginfo['scales'][$item->rating->settings->scale->id])) { + $scale = $item->rating->settings->scale; + // Return only non numeric scales (to avoid return lots of data just including items from 0 to $scale->max). + if (!$scale->isnumeric) { + $scaleitems = []; + foreach ($scale->scaleitems as $value => $name) { + $scaleitems[] = [ + 'name' => $name, + 'value' => $value, + ]; + } + $scale->items = $scaleitems; + } + $ratinginfo['scales'][$item->rating->settings->scale->id] = (array) $scale; + } + $ratinginfo['ratings'][] = $rating; + } + } + return $ratinginfo; + } +}