MDL-50173 ratings: Use proper checks to ensure ratings are viewable.
[moodle.git] / rating / classes / external.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Rating external API
19  *
20  * @package    core_rating
21  * @category   external
22  * @copyright  2015 Costantino Cito <ccito@cvaconsulting.com>
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  * @since      Moodle 2.9
25  */
27 defined('MOODLE_INTERNAL') || die;
29 require_once("$CFG->libdir/externallib.php");
30 require_once("$CFG->dirroot/rating/lib.php");
32 /**
33  * Rating external functions
34  *
35  * @package    core_rating
36  * @category   external
37  * @copyright  2015 Costantino Cito <ccito@cvaconsulting.com>
38  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
39  * @since      Moodle 2.9
40  */
41 class core_rating_external extends external_api {
43     /**
44      * Returns description of get_item_ratings parameters.
45      *
46      * @return external_function_parameters
47      * @since Moodle 2.9
48      */
49     public static function get_item_ratings_parameters() {
50         return new external_function_parameters (
51             array(
52                 'contextlevel'  => new external_value(PARAM_ALPHA, 'context level: course, module, user, etc...'),
53                 'instanceid'    => new external_value(PARAM_INT, 'the instance id of item associated with the context level'),
54                 'component'     => new external_value(PARAM_COMPONENT, 'component'),
55                 'ratingarea'    => new external_value(PARAM_AREA, 'rating area'),
56                 'itemid'        => new external_value(PARAM_INT, 'associated id'),
57                 'scaleid'       => new external_value(PARAM_INT, 'scale id'),
58                 'sort'          => new external_value(PARAM_ALPHA, 'sort order (firstname, rating or timemodified)')
59             )
60         );
61     }
63     /**
64      * Retrieve a list of ratings for a given item (forum post etc)
65      *
66      * @param string $contextlevel course, module, user...
67      * @param int $instanceid the instance if for the context element
68      * @param string $component the name of the component
69      * @param string $ratingarea rating area
70      * @param int $itemid the item id
71      * @param int $scaleid the scale id
72      * @param string $sort sql order (firstname, rating or timemodified)
73      * @return array Result and possible warnings
74      * @throws moodle_exception
75      * @since Moodle 2.9
76      */
77     public static function get_item_ratings($contextlevel, $instanceid, $component, $ratingarea, $itemid, $scaleid, $sort) {
78         global $USER;
80         $warnings = array();
82         $arrayparams = array(
83             'contextlevel' => $contextlevel,
84             'instanceid'   => $instanceid,
85             'component'    => $component,
86             'ratingarea'   => $ratingarea,
87             'itemid'       => $itemid,
88             'scaleid'      => $scaleid,
89             'sort'         => $sort
90         );
92         // Validate and normalize parameters.
93         $params = self::validate_parameters(self::get_item_ratings_parameters(), $arrayparams);
95         $context = self::get_context_from_params($params);
96         self::validate_context($context);
98         // Minimal capability required.
99         $callbackparams = array('contextid' => $context->id,
100                         'component' => $component,
101                         'ratingarea' => $ratingarea,
102                         'itemid' => $itemid,
103                         'scaleid' => $scaleid);
104         if (!has_capability('moodle/rating:view', $context) ||
105                 !component_callback($component, 'rating_can_see_item_ratings', array($callbackparams), true)) {
106             throw new moodle_exception('noviewrate', 'rating');
107         }
109         list($context, $course, $cm) = get_context_info_array($context->id);
111         // Can we see all ratings?
112         $canviewallratings = has_capability('moodle/rating:viewall', $context);
114         // Create the Sql sort order string.
115         switch ($params['sort']) {
116             case 'firstname':
117                 $sqlsort = "u.firstname ASC";
118                 break;
119             case 'rating':
120                 $sqlsort = "r.rating ASC";
121                 break;
122             default:
123                 $sqlsort = "r.timemodified ASC";
124         }
126         $ratingoptions = new stdClass;
127         $ratingoptions->context = $context;
128         $ratingoptions->component = $params['component'];
129         $ratingoptions->ratingarea = $params['ratingarea'];
130         $ratingoptions->itemid = $params['itemid'];
131         $ratingoptions->sort = $sqlsort;
133         $rm = new rating_manager();
134         $ratings = $rm->get_all_ratings_for_item($ratingoptions);
135         $scalemenu = make_grades_menu($params['scaleid']);
137         // If the scale was changed after ratings were submitted some ratings may have a value above the current maximum.
138         // We can't just do count($scalemenu) - 1 as custom scales start at index 1, not 0.
139         $maxrating = max(array_keys($scalemenu));
141         $results = array();
143         foreach ($ratings as $rating) {
144             if ($canviewallratings || $USER->id == $rating->userid) {
145                 if ($rating->rating > $maxrating) {
146                     $rating->rating = $maxrating;
147                 }
149                 $profileimageurl = '';
150                 // We can have ratings from deleted users. In this case, those users don't have a valid context.
151                 $usercontext = context_user::instance($rating->userid, IGNORE_MISSING);
152                 if ($usercontext) {
153                     $profileimageurl = moodle_url::make_webservice_pluginfile_url($usercontext->id, 'user', 'icon', null,
154                                                                                     '/', 'f1')->out(false);
155                 }
157                 $result = array();
158                 $result['id'] = $rating->id;
159                 $result['userid'] = $rating->userid;
160                 $result['userpictureurl'] = $profileimageurl;
161                 $result['userfullname'] = fullname($rating);
162                 $result['rating'] = $scalemenu[$rating->rating];
163                 $result['timemodified'] = $rating->timemodified;
164                 $results[] = $result;
165             }
166         }
168         return array(
169             'ratings' => $results,
170             'warnings' => $warnings
171         );
172     }
174     /**
175      * Returns description of get_item_ratings result values.
176      *
177      * @return external_single_structure
178      * @since Moodle 2.9
179      */
180     public static function get_item_ratings_returns() {
182         return new external_single_structure(
183             array(
184                 'ratings'    => new external_multiple_structure(
185                     new external_single_structure(
186                         array(
187                             'id'              => new external_value(PARAM_INT,  'rating id'),
188                             'userid'          => new external_value(PARAM_INT,  'user id'),
189                             'userpictureurl'  => new external_value(PARAM_URL,  'URL user picture'),
190                             'userfullname'    => new external_value(PARAM_NOTAGS, 'user fullname'),
191                             'rating'          => new external_value(PARAM_NOTAGS, 'rating on scale'),
192                             'timemodified'    => new external_value(PARAM_INT,  'time modified (timestamp)')
193                         ), 'Rating'
194                     ), 'list of ratings'
195                 ),
196                 'warnings'  => new external_warnings(),
197             )
198         );
199     }