Merge branch 'MDL-55928-master' of git://github.com/jleyva/moodle
authorAndrew Nicols <andrew@nicols.co.uk>
Tue, 4 Oct 2016 06:59:11 +0000 (14:59 +0800)
committerAndrew Nicols <andrew@nicols.co.uk>
Tue, 4 Oct 2016 06:59:11 +0000 (14:59 +0800)
grade/report/upgrade.txt
grade/report/user/db/services.php
grade/report/user/externallib.php
grade/report/user/lib.php
grade/report/user/tests/externallib_test.php
grade/report/user/version.php
lib/classes/grades_external.php

index 9236fc8..e74ef64 100644 (file)
@@ -1,5 +1,10 @@
 This files describes API changes in /grade/report/*,
 information provided here is intended especially for developers.
+
+=== 3.2 ===
+* External function gradereport_user_external::get_grades_table now has an optional groupid parameter.
+Is recommended to use this parameter in courses with separate groups or when the user requesting the report is in more than one group.
+
 === 2.9 ===
 * Deprecating grade_report_grader:get_collapsing_icon.
 * A new web service function gradereport_user_get_grades_table has been added which will allow external system to retrieve grade information ready to be formatted as a table similar to the gradebook user report one.
index 252e4b8..e134414 100644 (file)
@@ -41,5 +41,14 @@ $functions = array(
         'type' => 'write',
         'capabilities' => 'gradereport/user:view',
         'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
+    ),
+    'gradereport_user_get_grade_items' => array(
+        'classname' => 'gradereport_user_external',
+        'methodname' => 'get_grade_items',
+        'classpath' => 'grade/report/user/externallib.php',
+        'description' => 'Returns the complete list of grade items for users in a course',
+        'type' => 'read',
+        'capabilities' => 'gradereport/user:view',
+        'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
     )
 );
index 057666c..9ed53bd 100644 (file)
@@ -37,45 +37,32 @@ require_once("$CFG->libdir/externallib.php");
  */
 class gradereport_user_external extends external_api {
 
-    /**
-     * Describes the parameters for get_grades_table.
-     *
-     * @return external_external_function_parameters
-     * @since Moodle 2.9
-     */
-    public static function get_grades_table_parameters() {
-        return new external_function_parameters (
-            array(
-                'courseid' => new external_value(PARAM_INT, 'Course Id', VALUE_REQUIRED),
-                'userid'   => new external_value(PARAM_INT, 'Return grades only for this user (optional)', VALUE_DEFAULT, 0)
-            )
-        );
-    }
 
     /**
-     * Returns a list of grades tables for users in a course.
-     *
-     * @param int $courseid Course Id
-     * @param int $userid   Only this user (optional)
+     * Validate access permissions to the report
      *
-     * @return array the grades tables
-     * @since Moodle 2.9
+     * @param  int  $courseid the courseid
+     * @param  int  $userid   the user id to retrieve data from
+     * @param  int $groupid   the group id
+     * @return array with the parameters cleaned and other required information
+     * @since  Moodle 3.2
      */
-    public static function get_grades_table($courseid, $userid = 0) {
-        global $CFG, $USER;
-
-        $warnings = array();
+    protected static function check_report_access($courseid, $userid, $groupid = 0) {
+        global $USER;
 
         // Validate the parameter.
         $params = self::validate_parameters(self::get_grades_table_parameters(),
             array(
                 'courseid' => $courseid,
-                'userid' => $userid)
-            );
+                'userid' => $userid,
+                'groupid' => $groupid,
+            )
+        );
 
         // Compact/extract functions are not recommended.
         $courseid = $params['courseid'];
         $userid   = $params['userid'];
+        $groupid  = $params['groupid'];
 
         // Function get_course internally throws an exception if the course doesn't exist.
         $course = get_course($courseid);
@@ -93,6 +80,11 @@ class gradereport_user_external extends external_api {
         } else {
             $user = core_user::get_user($userid, '*', MUST_EXIST);
             core_user::require_active_user($user);
+            // Check if we can view the user group (if any).
+            // When userid == 0, we are retrieving all the users, we'll check then if a groupid is required.
+            if (!groups_user_groups_visible($course, $user->id)) {
+                throw new moodle_exception('notingroup');
+            }
         }
 
         $access = false;
@@ -109,6 +101,42 @@ class gradereport_user_external extends external_api {
             throw new moodle_exception('nopermissiontoviewgrades', 'error');
         }
 
+        if (!empty($groupid)) {
+            // Determine is the group is visible to user.
+            if (!groups_group_visible($groupid, $course)) {
+                throw new moodle_exception('notingroup');
+            }
+        } else {
+            // Check to see if groups are being used here.
+            if ($groupmode = groups_get_course_groupmode($course)) {
+                $groupid = groups_get_course_group($course);
+                // Determine is the group is visible to user (this is particullary for the group 0).
+                if (!groups_group_visible($groupid, $course)) {
+                    throw new moodle_exception('notingroup');
+                }
+            } else {
+                $groupid = 0;
+            }
+        }
+
+        return array($params, $course, $context, $user, $groupid);
+    }
+
+    /**
+     * Get the report data
+     * @param  stdClass $course  course object
+     * @param  stdClass $context context object
+     * @param  stdClass $user    user object (it can be null for all the users)
+     * @param  int $userid       the user to retrieve data from, 0 for all
+     * @param  int $groupid      the group id to filter
+     * @param  bool $tabledata   whether to get the table data (true) or the gradeitemdata
+     * @return array data and possible warnings
+     * @since  Moodle 3.2
+     */
+    protected static function get_report_data($course, $context, $user, $userid, $groupid, $tabledata = true) {
+        global $CFG;
+
+        $warnings = array();
         // Require files here to save some memory in case validation fails.
         require_once($CFG->dirroot . '/group/lib.php');
         require_once($CFG->libdir  . '/gradelib.php');
@@ -122,49 +150,95 @@ class gradereport_user_external extends external_api {
             array(
                 'type' => 'report',
                 'plugin' => 'user',
-                'courseid' => $courseid,
+                'courseid' => $course->id,
                 'userid' => $userid)
             );
 
-        $tables = array();
+        $reportdata = array();
 
         // Just one user.
         if ($user) {
-            $report = new grade_report_user($courseid, $gpr, $context, $userid);
+            $report = new grade_report_user($course->id, $gpr, $context, $userid);
             $report->fill_table();
 
-            $tables[] = array(
-                'courseid'      => $courseid,
+            $gradeuserdata = array(
+                'courseid'      => $course->id,
                 'userid'        => $user->id,
                 'userfullname'  => fullname($user),
                 'maxdepth'      => $report->maxdepth,
-                'tabledata'     => $report->tabledata
             );
-
+            if ($tabledata) {
+                $gradeuserdata['tabledata'] = $report->tabledata;
+            } else {
+                $gradeuserdata['gradeitems'] = $report->gradeitemsdata;
+            }
+            $reportdata[] = $gradeuserdata;
         } else {
             $defaultgradeshowactiveenrol = !empty($CFG->grade_report_showonlyactiveenrol);
             $showonlyactiveenrol = get_user_preferences('grade_report_showonlyactiveenrol', $defaultgradeshowactiveenrol);
             $showonlyactiveenrol = $showonlyactiveenrol || !has_capability('moodle/course:viewsuspendedusers', $context);
 
-            $gui = new graded_users_iterator($course);
+            $gui = new graded_users_iterator($course, null, $groupid);
             $gui->require_active_enrolment($showonlyactiveenrol);
             $gui->init();
 
             while ($userdata = $gui->next_user()) {
                 $currentuser = $userdata->user;
-                $report = new grade_report_user($courseid, $gpr, $context, $currentuser->id);
+                $report = new grade_report_user($course->id, $gpr, $context, $currentuser->id);
                 $report->fill_table();
 
-                $tables[] = array(
-                    'courseid'      => $courseid,
+                $gradeuserdata = array(
+                    'courseid'      => $course->id,
                     'userid'        => $currentuser->id,
                     'userfullname'  => fullname($currentuser),
                     'maxdepth'      => $report->maxdepth,
-                    'tabledata'     => $report->tabledata
                 );
+                if ($tabledata) {
+                    $gradeuserdata['tabledata'] = $report->tabledata;
+                } else {
+                    $gradeuserdata['gradeitems'] = $report->gradeitemsdata;
+                }
+                $reportdata[] = $gradeuserdata;
             }
             $gui->close();
         }
+        return array($reportdata, $warnings);
+    }
+
+    /**
+     * Describes the parameters for get_grades_table.
+     *
+     * @return external_external_function_parameters
+     * @since Moodle 2.9
+     */
+    public static function get_grades_table_parameters() {
+        return new external_function_parameters (
+            array(
+                'courseid' => new external_value(PARAM_INT, 'Course Id', VALUE_REQUIRED),
+                'userid'   => new external_value(PARAM_INT, 'Return grades only for this user (optional)', VALUE_DEFAULT, 0),
+                'groupid'  => new external_value(PARAM_INT, 'Get users from this group only', VALUE_DEFAULT, 0)
+            )
+        );
+    }
+
+    /**
+     * Returns a list of grades tables for users in a course.
+     *
+     * @param int $courseid Course Id
+     * @param int $userid   Only this user (optional)
+     * @param int $groupid  Get users from this group only
+     *
+     * @return array the grades tables
+     * @since Moodle 2.9
+     */
+    public static function get_grades_table($courseid, $userid = 0, $groupid = 0) {
+        global $CFG, $USER;
+
+        list($params, $course, $context, $user, $groupid) = self::check_report_access($courseid, $userid, $groupid);
+        $userid   = $params['userid'];
+
+        // We pass userid because it can be still 0.
+        list($tables, $warnings) = self::get_report_data($course, $context, $user, $userid, $groupid);
 
         $result = array();
         $result['tables'] = $tables;
@@ -268,7 +342,7 @@ class gradereport_user_external extends external_api {
         return new external_function_parameters(
             array(
                 'courseid' => new external_value(PARAM_INT, 'id of the course'),
-                'userid' => new external_value(PARAM_INT, 'id of the user, 0 means current user', VALUE_DEFAULT, 0)
+                'userid' => new external_value(PARAM_INT, 'id of the user, 0 means current user', VALUE_DEFAULT, 0),
             )
         );
     }
@@ -346,4 +420,105 @@ class gradereport_user_external extends external_api {
             )
         );
     }
+
+    /**
+     * Describes the parameters for get_grade_items.
+     *
+     * @return external_external_function_parameters
+     * @since Moodle 3.2
+     */
+    public static function get_grade_items_parameters() {
+        return self::get_grades_table_parameters();
+    }
+
+    /**
+     * Returns the complete list of grade items for users in a course.
+     *
+     * @param int $courseid Course Id
+     * @param int $userid   Only this user (optional)
+     * @param int $groupid  Get users from this group only
+     *
+     * @return array the grades tables
+     * @since Moodle 3.2
+     */
+    public static function get_grade_items($courseid, $userid = 0, $groupid = 0) {
+        global $CFG, $USER;
+
+        list($params, $course, $context, $user, $groupid) = self::check_report_access($courseid, $userid, $groupid);
+        $userid   = $params['userid'];
+
+        // We pass userid because it can be still 0.
+        list($gradeitems, $warnings) = self::get_report_data($course, $context, $user, $userid, $groupid, false);
+
+        foreach ($gradeitems as $gradeitem) {
+            if (isset($gradeitem['feedback']) and isset($gradeitem['feedbackformat'])) {
+                list($gradeitem['feedback'], $gradeitem['feedbackformat']) =
+                    external_format_text($gradeitem['feedback'], $gradeitem['feedbackformat'], $context->id);
+            }
+        }
+
+        $result = array();
+        $result['usergrades'] = $gradeitems;
+        $result['warnings'] = $warnings;
+        return $result;
+    }
+
+    /**
+     * Describes tget_grade_items return value.
+     *
+     * @return external_single_structure
+     * @since Moodle 3.2
+     */
+    public static function get_grade_items_returns() {
+        return new external_single_structure(
+            array(
+                'usergrades' => new external_multiple_structure(
+                    new external_single_structure(
+                        array(
+                            'courseid' => new external_value(PARAM_INT, 'course id'),
+                            'userid'   => new external_value(PARAM_INT, 'user id'),
+                            'userfullname' => new external_value(PARAM_TEXT, 'user fullname'),
+                            'maxdepth'   => new external_value(PARAM_INT, 'table max depth (needed for printing it)'),
+                            'gradeitems' => new external_multiple_structure(
+                                new external_single_structure(
+                                    array(
+                                        'id' => new external_value(PARAM_INT, 'Grade item id'),
+                                        'itemtype' => new external_value(PARAM_ALPHA, 'Grade item type'),
+                                        'itemmodule' => new external_value(PARAM_PLUGIN, 'Grade item module'),
+                                        'iteminstance' => new external_value(PARAM_INT, 'Grade item instance'),
+                                        'itemnumber' => new external_value(PARAM_INT, 'Grade item item number'),
+                                        'categoryid' => new external_value(PARAM_INT, 'Grade item category id'),
+                                        'outcomeid' => new external_value(PARAM_INT, 'Outcome id'),
+                                        'scaleid' => new external_value(PARAM_INT, 'Scale id'),
+                                        'cmid' => new external_value(PARAM_INT, 'Course module id (if type mod)', VALUE_OPTIONAL),
+                                        'weightraw' => new external_value(PARAM_FLOAT, 'Weight raw', VALUE_OPTIONAL),
+                                        'weightformatted' => new external_value(PARAM_NOTAGS, 'Weight', VALUE_OPTIONAL),
+                                        'status' => new external_value(PARAM_ALPHA, 'Status', VALUE_OPTIONAL),
+                                        'graderaw' => new external_value(PARAM_FLOAT, 'Grade raw', VALUE_OPTIONAL),
+                                        'gradedatesubmitted' => new external_value(PARAM_INT, 'Grade submit date', VALUE_OPTIONAL),
+                                        'gradedategraded' => new external_value(PARAM_INT, 'Grade graded date', VALUE_OPTIONAL),
+                                        'gradehiddenbydate' => new external_value(PARAM_BOOL, 'Grade hidden by date?', VALUE_OPTIONAL),
+                                        'gradeneedsupdate' => new external_value(PARAM_BOOL, 'Grade needs update?', VALUE_OPTIONAL),
+                                        'gradeishidden' => new external_value(PARAM_BOOL, 'Grade is hidden?', VALUE_OPTIONAL),
+                                        'gradeformatted' => new external_value(PARAM_NOTAGS, 'The grade formatted', VALUE_OPTIONAL),
+                                        'grademin' => new external_value(PARAM_FLOAT, 'Grade min', VALUE_OPTIONAL),
+                                        'grademax' => new external_value(PARAM_FLOAT, 'Grade max', VALUE_OPTIONAL),
+                                        'rangeformatted' => new external_value(PARAM_NOTAGS, 'Range formatted', VALUE_OPTIONAL),
+                                        'percentageformatted' => new external_value(PARAM_NOTAGS, 'Percentage', VALUE_OPTIONAL),
+                                        'lettergradeformatted' => new external_value(PARAM_NOTAGS, 'Letter grade', VALUE_OPTIONAL),
+                                        'rank' => new external_value(PARAM_INT, 'Rank in the course', VALUE_OPTIONAL),
+                                        'numusers' => new external_value(PARAM_INT, 'Num users in course', VALUE_OPTIONAL),
+                                        'averageformatted' => new external_value(PARAM_NOTAGS, 'Grade average', VALUE_OPTIONAL),
+                                        'feedback' => new external_value(PARAM_RAW, 'Grade feedback', VALUE_OPTIONAL),
+                                        'feedbackformat' => new external_format_value('feedback'),
+                                    ), 'Grade items'
+                                )
+                            )
+                        )
+                    )
+                ),
+                'warnings' => new external_warnings()
+            )
+        );
+    }
 }
index 65f66a6..a6f15d1 100644 (file)
@@ -67,6 +67,12 @@ class grade_report_user extends grade_report {
      */
     public $tabledata = array();
 
+    /**
+     * An array containing the grade items data for external usage (web services, ajax, etc...)
+     * @var array
+     */
+    public $gradeitemsdata = array();
+
     /**
      * The grade tree structure
      * @var grade_tree
@@ -387,6 +393,7 @@ class grade_report_user extends grade_report {
         $element['userid'] = $this->user->id;
         $fullname = $this->gtree->get_element_header($element, true, true, true, true, true);
         $data = array();
+        $gradeitemdata = array();
         $hidden = '';
         $excluded = '';
         $itemlevel = ($type == 'categoryitem' || $type == 'category' || $type == 'courseitem') ? $depth : ($depth + 1);
@@ -436,6 +443,7 @@ class grade_report_user extends grade_report {
                 $instances = $this->modinfo->get_instances_of($grade_object->itemmodule);
                 if (!empty($instances[$grade_object->iteminstance])) {
                     $cm = $instances[$grade_object->iteminstance];
+                    $gradeitemdata['cmid'] = $cm->id;
                     if (!$cm->uservisible) {
                         // If there is 'availableinfo' text then it is only greyed
                         // out and not entirely hidden.
@@ -499,6 +507,16 @@ class grade_report_user extends grade_report {
                 $data['itemname']['celltype'] = 'th';
                 $data['itemname']['id'] = $header_row;
 
+                // Basic grade item information.
+                $gradeitemdata['id'] = $grade_object->id;
+                $gradeitemdata['itemtype'] = $grade_object->itemtype;
+                $gradeitemdata['itemmodule'] = $grade_object->itemmodule;
+                $gradeitemdata['iteminstance'] = $grade_object->iteminstance;
+                $gradeitemdata['itemnumber'] = $grade_object->itemnumber;
+                $gradeitemdata['categoryid'] = $grade_object->categoryid;
+                $gradeitemdata['outcomeid'] = $grade_object->outcomeid;
+                $gradeitemdata['scaleid'] = $grade_object->outcomeid;
+
                 if ($this->showfeedback) {
                     // Copy $class before appending itemcenter as feedback should not be centered
                     $classfeedback = $class;
@@ -513,13 +531,23 @@ class grade_report_user extends grade_report {
                     // This obliterates the weight because it provides a more informative description.
                     if (is_numeric($hint['weight'])) {
                         $data['weight']['content'] = format_float($hint['weight'] * 100.0, 2) . ' %';
+                        $gradeitemdata['weightraw'] = $hint['weight'];
+                        $gradeitemdata['weightformatted'] = $data['weight']['content'];
                     }
                     if ($hint['status'] != 'used' && $hint['status'] != 'unknown') {
                         $data['weight']['content'] .= '<br>' . get_string('aggregationhint' . $hint['status'], 'grades');
+                        $gradeitemdata['status'] = $hint['status'];
                     }
                 }
 
                 if ($this->showgrade) {
+                    $gradeitemdata['graderaw'] = '';
+                    $gradeitemdata['gradehiddenbydate'] = false;
+                    $gradeitemdata['gradeneedsupdate'] = $grade_grade->grade_item->needsupdate;
+                    $gradeitemdata['gradeishidden'] = $grade_grade->is_hidden();
+                    $gradeitemdata['gradedatesubmitted'] = $grade_grade->get_datesubmitted();
+                    $gradeitemdata['gradedategraded'] = $grade_grade->get_dategraded();
+
                     if ($grade_grade->grade_item->needsupdate) {
                         $data['grade']['class'] = $class.' gradingerror';
                         $data['grade']['content'] = get_string('error');
@@ -529,11 +557,13 @@ class grade_report_user extends grade_report {
                         $class .= ' datesubmitted';
                         $data['grade']['class'] = $class;
                         $data['grade']['content'] = get_string('submittedon', 'grades', userdate($grade_grade->get_datesubmitted(), get_string('strftimedatetimeshort')));
-
+                        $gradeitemdata['gradehiddenbydate'] = true;
                     } else if ($grade_grade->is_hidden()) {
                         $data['grade']['class'] = $class.' dimmed_text';
                         $data['grade']['content'] = '-';
+
                         if ($this->canviewhidden) {
+                            $gradeitemdata['graderaw'] = $gradeval;
                             $data['grade']['content'] = grade_format_gradevalue($gradeval,
                                                                                 $grade_grade->grade_item,
                                                                                 true);
@@ -543,8 +573,10 @@ class grade_report_user extends grade_report {
                         $data['grade']['content'] = grade_format_gradevalue($gradeval,
                                                                             $grade_grade->grade_item,
                                                                             true);
+                        $gradeitemdata['graderaw'] = $gradeval;
                     }
                     $data['grade']['headers'] = "$header_cat $header_row grade";
+                    $gradeitemdata['gradeformatted'] = $data['grade']['content'];
                 }
 
                 // Range
@@ -552,6 +584,10 @@ class grade_report_user extends grade_report {
                     $data['range']['class'] = $class;
                     $data['range']['content'] = $grade_grade->grade_item->get_formatted_range(GRADE_DISPLAY_TYPE_REAL, $this->rangedecimals);
                     $data['range']['headers'] = "$header_cat $header_row range";
+
+                    $gradeitemdata['rangeformatted'] = $data['range']['content'];
+                    $gradeitemdata['grademin'] = $grade_grade->grade_item->grademin;
+                    $gradeitemdata['grademax'] = $grade_grade->grade_item->grademax;
                 }
 
                 // Percentage
@@ -570,6 +606,7 @@ class grade_report_user extends grade_report {
                         $data['percentage']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true, GRADE_DISPLAY_TYPE_PERCENTAGE);
                     }
                     $data['percentage']['headers'] = "$header_cat $header_row percentage";
+                    $gradeitemdata['percentageformatted'] = $data['percentage']['content'];
                 }
 
                 // Lettergrade
@@ -589,10 +626,12 @@ class grade_report_user extends grade_report {
                         $data['lettergrade']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true, GRADE_DISPLAY_TYPE_LETTER);
                     }
                     $data['lettergrade']['headers'] = "$header_cat $header_row lettergrade";
+                    $gradeitemdata['lettergradeformatted'] = $data['lettergrade']['content'];
                 }
 
                 // Rank
                 if ($this->showrank) {
+                    $gradeitemdata['rank'] = 0;
                     if ($grade_grade->grade_item->needsupdate) {
                         $data['rank']['class'] = $class.' gradingerror';
                         $data['rank']['content'] = get_string('error');
@@ -614,16 +653,23 @@ class grade_report_user extends grade_report {
                         $rank = $DB->count_records_sql($sql, array($grade_grade->finalgrade, $grade_grade->grade_item->id)) + 1;
 
                         $data['rank']['class'] = $class;
-                        $data['rank']['content'] = "$rank/".$this->get_numusers(false); // total course users
+                        $numusers = $this->get_numusers(false);
+                        $data['rank']['content'] = "$rank/$numusers"; // Total course users.
+
+                        $gradeitemdata['rank'] = $rank;
+                        $gradeitemdata['numusers'] = $numusers;
                     }
                     $data['rank']['headers'] = "$header_cat $header_row rank";
                 }
 
                 // Average
                 if ($this->showaverage) {
+                    $gradeitemdata['averageformatted'] = '';
+
                     $data['average']['class'] = $class;
                     if (!empty($this->gtree->items[$eid]->avg)) {
                         $data['average']['content'] = $this->gtree->items[$eid]->avg;
+                        $gradeitemdata['averageformatted'] = $this->gtree->items[$eid]->avg;
                     } else {
                         $data['average']['content'] = '-';
                     }
@@ -632,15 +678,20 @@ class grade_report_user extends grade_report {
 
                 // Feedback
                 if ($this->showfeedback) {
+                    $gradeitemdata['feedback'] = '';
+                    $gradeitemdata['feedbackformat'] = $grade_grade->feedbackformat;
+
                     if ($grade_grade->overridden > 0 AND ($type == 'categoryitem' OR $type == 'courseitem')) {
                     $data['feedback']['class'] = $classfeedback.' feedbacktext';
                         $data['feedback']['content'] = get_string('overridden', 'grades').': ' . format_text($grade_grade->feedback, $grade_grade->feedbackformat);
+                        $gradeitemdata['feedback'] = $grade_grade->feedback;
                     } else if (empty($grade_grade->feedback) or (!$this->canviewhidden and $grade_grade->is_hidden())) {
                         $data['feedback']['class'] = $classfeedback.' feedbacktext';
                         $data['feedback']['content'] = '&nbsp;';
                     } else {
                         $data['feedback']['class'] = $classfeedback.' feedbacktext';
                         $data['feedback']['content'] = format_text($grade_grade->feedback, $grade_grade->feedbackformat);
+                        $gradeitemdata['feedback'] = $grade_grade->feedback;
                     }
                     $data['feedback']['headers'] = "$header_cat $header_row feedback";
                 }
@@ -651,6 +702,7 @@ class grade_report_user extends grade_report {
                     $data['contributiontocoursetotal']['headers'] = "$header_cat $header_row contributiontocoursetotal";
 
                 }
+                $this->gradeitemsdata[] = $gradeitemdata;
             }
             // We collect the aggregation hints whether they are hidden or not.
             if ($this->showcontributiontocoursetotal) {
index 2c04c20..02c79e4 100644 (file)
@@ -49,7 +49,7 @@ class gradereport_user_externallib_testcase extends externallib_advanced_testcas
     private function load_data($s1grade, $s2grade) {
         global $DB;
 
-        $course = $this->getDataGenerator()->create_course();
+        $course = $this->getDataGenerator()->create_course(array('groupmode' => SEPARATEGROUPS, 'groupmodeforce' => 1));
 
         $studentrole = $DB->get_record('role', array('shortname' => 'student'));
         $student1 = $this->getDataGenerator()->create_user();
@@ -58,10 +58,20 @@ class gradereport_user_externallib_testcase extends externallib_advanced_testcas
         $student2 = $this->getDataGenerator()->create_user();
         $this->getDataGenerator()->enrol_user($student2->id, $course->id, $studentrole->id);
 
-        $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
+        $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
         $teacher = $this->getDataGenerator()->create_user();
         $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id);
 
+        $context = context_course::instance($course->id);
+        assign_capability('moodle/site:accessallgroups', CAP_PROHIBIT, $teacherrole->id, $context);
+        accesslib_clear_all_caches_for_unit_testing();
+
+        $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
+        $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
+        groups_add_member($group1->id, $student1->id);
+        groups_add_member($group1->id, $teacher->id);
+        groups_add_member($group2->id, $student2->id);
+
         $assignment = $this->getDataGenerator()->create_module('assign', array('name' => "Test assign", 'course' => $course->id));
         $modcontext = get_coursemodule_from_instance('assign', $assignment->id, $course->id);
         $assignment->cmidnumber = $modcontext->id;
@@ -71,7 +81,7 @@ class gradereport_user_externallib_testcase extends externallib_advanced_testcas
         $studentgrades = array($student1->id => $student1grade, $student2->id => $student2grade);
         assign_grade_item_update($assignment, $studentgrades);
 
-        return array($course, $teacher, $student1, $student2);
+        return array($course, $teacher, $student1, $student2, $assignment);
     }
 
     /**
@@ -84,30 +94,26 @@ class gradereport_user_externallib_testcase extends externallib_advanced_testcas
         $s1grade = 80;
         $s2grade = 60;
 
-        list($course, $teacher, $student1, $student2) = $this->load_data($s1grade, $s2grade);
+        list($course, $teacher, $student1, $student2, $assignment) = $this->load_data($s1grade, $s2grade);
 
-        // A teacher must see all student grades.
+        // A teacher must see all student grades (in their group only).
         $this->setUser($teacher);
 
         $studentgrades = gradereport_user_external::get_grades_table($course->id);
         $studentgrades = external_api::clean_returnvalue(gradereport_user_external::get_grades_table_returns(), $studentgrades);
 
         // No warnings returned.
-        $this->assertTrue(count($studentgrades['warnings']) == 0);
+        $this->assertCount(0, $studentgrades['warnings']);
 
-        // Check that two grades are returned (each for student).
-        $this->assertTrue(count($studentgrades['tables']) == 2);
+        // Check that only grades for the student in the teacher group are returned.
+        $this->assertCount(1, $studentgrades['tables']);
 
         // Read returned grades.
         $studentreturnedgrades = array();
         $studentreturnedgrades[$studentgrades['tables'][0]['userid']] =
             (int) $studentgrades['tables'][0]['tabledata'][1]['grade']['content'];
 
-        $studentreturnedgrades[$studentgrades['tables'][1]['userid']] =
-            (int) $studentgrades['tables'][1]['tabledata'][1]['grade']['content'];
-
         $this->assertEquals($s1grade, $studentreturnedgrades[$student1->id]);
-        $this->assertEquals($s2grade, $studentreturnedgrades[$student2->id]);
     }
 
     /**
@@ -121,7 +127,7 @@ class gradereport_user_externallib_testcase extends externallib_advanced_testcas
         $s1grade = 80;
         $s2grade = 60;
 
-        list($course, $teacher, $student1, $student2) = $this->load_data($s1grade, $s2grade);
+        list($course, $teacher, $student1, $student2, $assignment) = $this->load_data($s1grade, $s2grade);
 
         // A user can see his own grades.
         $this->setUser($student1);
@@ -148,7 +154,7 @@ class gradereport_user_externallib_testcase extends externallib_advanced_testcas
         $s1grade = 80;
         $s2grade = 60;
 
-        list($course, $teacher, $student1, $student2) = $this->load_data($s1grade, $s2grade);
+        list($course, $teacher, $student1, $student2, $assignment) = $this->load_data($s1grade, $s2grade);
 
         $this->setUser($student2);
 
@@ -156,9 +162,8 @@ class gradereport_user_externallib_testcase extends externallib_advanced_testcas
             $studentgrade = gradereport_user_external::get_grades_table($course->id, $student1->id);
             $this->fail('Exception expected due to not perissions to view other user grades.');
         } catch (moodle_exception $e) {
-            $this->assertEquals('nopermissiontoviewgrades', $e->errorcode);
+            $this->assertEquals('notingroup', $e->errorcode);
         }
-
     }
 
     /**
@@ -171,7 +176,7 @@ class gradereport_user_externallib_testcase extends externallib_advanced_testcas
 
         $s1grade = 80;
         $s2grade = 60;
-        list($course, $teacher, $student1, $student2) = $this->load_data($s1grade, $s2grade);
+        list($course, $teacher, $student1, $student2, $assignment) = $this->load_data($s1grade, $s2grade);
 
         // Redirect events to the sink, so we can recover them later.
         $sink = $this->redirectEvents();
@@ -207,7 +212,152 @@ class gradereport_user_externallib_testcase extends externallib_advanced_testcas
         } catch (moodle_exception $e) {
             $this->assertEquals('nopermissiontoviewgrades', $e->errorcode);
         }
+    }
+
+    /**
+     * Test get_grades_items function case teacher
+     */
+    public function test_get_grade_items_teacher() {
+
+        $this->resetAfterTest(true);
+
+        $s1grade = 80;
+        $s2grade = 60;
+
+        list($course, $teacher, $student1, $student2, $assignment) = $this->load_data($s1grade, $s2grade);
+
+        // A teacher must see all student grades (in their group only).
+        $this->setUser($teacher);
 
+        grade_set_setting($course->id, 'report_user_showrank', 1);
+        grade_set_setting($course->id, 'report_user_showpercentage', 1);
+        grade_set_setting($course->id, 'report_user_showhiddenitems', 1);
+        grade_set_setting($course->id, 'report_user_showgrade', 1);
+        grade_set_setting($course->id, 'report_user_showfeedback', 1);
+        grade_set_setting($course->id, 'report_user_showweight', 1);
+        grade_set_setting($course->id, 'report_user_showcontributiontocoursetotal', 1);
+        grade_set_setting($course->id, 'report_user_showlettergrade', 1);
+        grade_set_setting($course->id, 'report_user_showaverage', 1);
+
+        $studentgrades = gradereport_user_external::get_grade_items($course->id);
+        $studentgrades = external_api::clean_returnvalue(gradereport_user_external::get_grade_items_returns(), $studentgrades);
+        // No warnings returned.
+        $this->assertCount(0, $studentgrades['warnings']);
+
+        // Check that only grades for the student in the teacher group are returned.
+        $this->assertCount(1, $studentgrades['usergrades']);
+        $this->assertCount(2, $studentgrades['usergrades'][0]['gradeitems']);
+
+        $this->assertEquals($course->id, $studentgrades['usergrades'][0]['courseid']);
+        $this->assertEquals($student1->id, $studentgrades['usergrades'][0]['userid']);
+        // Module grades.
+        $this->assertEquals('mod', $studentgrades['usergrades'][0]['gradeitems'][0]['itemtype']);
+        $this->assertEquals('assign', $studentgrades['usergrades'][0]['gradeitems'][0]['itemmodule']);
+        $this->assertEquals($assignment->id, $studentgrades['usergrades'][0]['gradeitems'][0]['iteminstance']);
+        $this->assertEquals($assignment->cmidnumber, $studentgrades['usergrades'][0]['gradeitems'][0]['cmid']);
+        $this->assertEquals(0, $studentgrades['usergrades'][0]['gradeitems'][0]['itemnumber']);
+        $this->assertEmpty($studentgrades['usergrades'][0]['gradeitems'][0]['outcomeid']);
+        $this->assertEmpty($studentgrades['usergrades'][0]['gradeitems'][0]['scaleid']);
+        $this->assertEquals(80, $studentgrades['usergrades'][0]['gradeitems'][0]['graderaw']);
+        $this->assertEquals('80.00', $studentgrades['usergrades'][0]['gradeitems'][0]['gradeformatted']);
+        $this->assertEquals(0, $studentgrades['usergrades'][0]['gradeitems'][0]['grademin']);
+        $this->assertEquals(100, $studentgrades['usergrades'][0]['gradeitems'][0]['grademax']);
+        $this->assertEquals('0&ndash;100', $studentgrades['usergrades'][0]['gradeitems'][0]['rangeformatted']);
+        $this->assertEquals('80.00 %', $studentgrades['usergrades'][0]['gradeitems'][0]['percentageformatted']);
+        $this->assertEmpty($studentgrades['usergrades'][0]['gradeitems'][0]['feedback']);
+        $this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][0]['gradehiddenbydate']);
+        $this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][0]['gradeneedsupdate']);
+        $this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][0]['gradeishidden']);
+        $this->assertEquals('B-', $studentgrades['usergrades'][0]['gradeitems'][0]['lettergradeformatted']);
+        $this->assertEquals(1, $studentgrades['usergrades'][0]['gradeitems'][0]['rank']);
+        $this->assertEquals(2, $studentgrades['usergrades'][0]['gradeitems'][0]['numusers']);
+        $this->assertEquals(70, $studentgrades['usergrades'][0]['gradeitems'][0]['averageformatted']);
+
+        // Course grades.
+        $this->assertEquals('course', $studentgrades['usergrades'][0]['gradeitems'][1]['itemtype']);
+        $this->assertEquals(80, $studentgrades['usergrades'][0]['gradeitems'][1]['graderaw']);
+        $this->assertEquals('80.00', $studentgrades['usergrades'][0]['gradeitems'][1]['gradeformatted']);
+        $this->assertEquals(0, $studentgrades['usergrades'][0]['gradeitems'][1]['grademin']);
+        $this->assertEquals(100, $studentgrades['usergrades'][0]['gradeitems'][1]['grademax']);
+        $this->assertEquals('0&ndash;100', $studentgrades['usergrades'][0]['gradeitems'][1]['rangeformatted']);
+        $this->assertEquals('80.00 %', $studentgrades['usergrades'][0]['gradeitems'][1]['percentageformatted']);
+        $this->assertEmpty($studentgrades['usergrades'][0]['gradeitems'][1]['feedback']);
+        $this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][1]['gradehiddenbydate']);
+        $this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][1]['gradeneedsupdate']);
+        $this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][1]['gradeishidden']);
+        $this->assertEquals('B-', $studentgrades['usergrades'][0]['gradeitems'][1]['lettergradeformatted']);
+        $this->assertEquals(1, $studentgrades['usergrades'][0]['gradeitems'][1]['rank']);
+        $this->assertEquals(2, $studentgrades['usergrades'][0]['gradeitems'][1]['numusers']);
+        $this->assertEquals(70, $studentgrades['usergrades'][0]['gradeitems'][1]['averageformatted']);
+    }
+
+    /**
+     * Test get_grades_items function case student
+     */
+    public function test_get_grade_items_student() {
+
+        $this->resetAfterTest(true);
+
+        $s1grade = 80;
+        $s2grade = 60;
+
+        list($course, $teacher, $student1, $student2, $assignment) = $this->load_data($s1grade, $s2grade);
+
+        grade_set_setting($course->id, 'report_user_showrank', 1);
+        grade_set_setting($course->id, 'report_user_showpercentage', 1);
+        grade_set_setting($course->id, 'report_user_showgrade', 1);
+        grade_set_setting($course->id, 'report_user_showfeedback', 1);
+        grade_set_setting($course->id, 'report_user_showweight', 1);
+        grade_set_setting($course->id, 'report_user_showcontributiontocoursetotal', 1);
+        grade_set_setting($course->id, 'report_user_showlettergrade', 1);
+        grade_set_setting($course->id, 'report_user_showaverage', 1);
+
+        $this->setUser($student1);
+
+        $studentgrades = gradereport_user_external::get_grade_items($course->id, $student1->id);
+        $studentgrades = external_api::clean_returnvalue(gradereport_user_external::get_grade_items_returns(), $studentgrades);
+        // No warnings returned.
+        $this->assertCount(0, $studentgrades['warnings']);
+
+        // Check that only grades for the student in the teacher group are returned.
+        $this->assertCount(1, $studentgrades['usergrades']);
+        $this->assertCount(2, $studentgrades['usergrades'][0]['gradeitems']);
+
+        $this->assertEquals($course->id, $studentgrades['usergrades'][0]['courseid']);
+        $this->assertEquals($student1->id, $studentgrades['usergrades'][0]['userid']);
+        $this->assertEquals('mod', $studentgrades['usergrades'][0]['gradeitems'][0]['itemtype']);
+        $this->assertEquals('assign', $studentgrades['usergrades'][0]['gradeitems'][0]['itemmodule']);
+        $this->assertEquals($assignment->id, $studentgrades['usergrades'][0]['gradeitems'][0]['iteminstance']);
+        $this->assertEquals($assignment->cmidnumber, $studentgrades['usergrades'][0]['gradeitems'][0]['cmid']);
+        $this->assertEquals(0, $studentgrades['usergrades'][0]['gradeitems'][0]['itemnumber']);
+        $this->assertEmpty($studentgrades['usergrades'][0]['gradeitems'][0]['outcomeid']);
+        $this->assertEmpty($studentgrades['usergrades'][0]['gradeitems'][0]['scaleid']);
+        $this->assertEquals(80, $studentgrades['usergrades'][0]['gradeitems'][0]['graderaw']);
+        $this->assertEquals('80.00', $studentgrades['usergrades'][0]['gradeitems'][0]['gradeformatted']);
+        $this->assertEquals(0, $studentgrades['usergrades'][0]['gradeitems'][0]['grademin']);
+        $this->assertEquals(100, $studentgrades['usergrades'][0]['gradeitems'][0]['grademax']);
+        $this->assertEquals('0&ndash;100', $studentgrades['usergrades'][0]['gradeitems'][0]['rangeformatted']);
+        $this->assertEquals('80.00 %', $studentgrades['usergrades'][0]['gradeitems'][0]['percentageformatted']);
+        $this->assertEmpty($studentgrades['usergrades'][0]['gradeitems'][0]['feedback']);
+        $this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][0]['gradehiddenbydate']);
+        $this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][0]['gradeneedsupdate']);
+        $this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][0]['gradeishidden']);
+        $this->assertEquals('B-', $studentgrades['usergrades'][0]['gradeitems'][0]['lettergradeformatted']);
+        $this->assertEquals(1, $studentgrades['usergrades'][0]['gradeitems'][0]['rank']);
+        $this->assertEquals(2, $studentgrades['usergrades'][0]['gradeitems'][0]['numusers']);
+        $this->assertEquals(70, $studentgrades['usergrades'][0]['gradeitems'][0]['averageformatted']);
+
+        // Hide one grade for the user.
+        $gradegrade = new grade_grade(array('userid' => $student1->id,
+                                        'itemid' => $studentgrades['usergrades'][0]['gradeitems'][0]['id']), true);
+        $gradegrade->set_hidden(1);
+        $studentgrades = gradereport_user_external::get_grade_items($course->id, $student1->id);
+        $studentgrades = external_api::clean_returnvalue(gradereport_user_external::get_grade_items_returns(), $studentgrades);
+
+        // Check we get only the course final grade.
+        $this->assertCount(1, $studentgrades['usergrades']);
+        $this->assertCount(1, $studentgrades['usergrades'][0]['gradeitems']);
+        $this->assertEquals('course', $studentgrades['usergrades'][0]['gradeitems'][0]['itemtype']);
     }
 
 }
index a22d175..2c1fa28 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2016052300;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2016052301;        // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2016051900;        // Requires this Moodle version
 $plugin->component = 'gradereport_user'; // Full name of the plugin (used for diagnostics)
index f2a0e6d..70af39c 100644 (file)
@@ -39,7 +39,7 @@ class core_grades_external extends external_api {
      * @return external_function_parameters
      * @since Moodle 2.7
      * @deprecated Moodle 3.2 MDL-51373 - Please do not call this function any more.
-     * @see gradereport_user_external::get_grades_table for a similar function
+     * @see gradereport_user_external::get_grade_items for a similar function
      */
     public static function get_grades_parameters() {
         return new external_function_parameters(
@@ -68,7 +68,7 @@ class core_grades_external extends external_api {
      * @return array                Array of grades
      * @since Moodle 2.7
      * @deprecated Moodle 3.2 MDL-51373 - Please do not call this function any more.
-     * @see gradereport_user_external::get_grades_table for a similar function
+     * @see gradereport_user_external::get_grade_items for a similar function
      */
     public static function get_grades($courseid, $component = null, $activityid = null, $userids = array()) {
         global $CFG, $USER, $DB;
@@ -298,7 +298,7 @@ class core_grades_external extends external_api {
      * @param  int $itemnumber      Item number
      * @return grade_item           A grade_item instance
      * @deprecated Moodle 3.2 MDL-51373 - Please do not call this function any more.
-     * @see gradereport_user_external::get_grades_table for a similar function
+     * @see gradereport_user_external::get_grade_items for a similar function
      */
     private static function get_grade_item($courseid, $itemtype, $itemmodule = null, $iteminstance = null, $itemnumber = null) {
         $gradeiteminstance = null;
@@ -318,7 +318,7 @@ class core_grades_external extends external_api {
      * @return external_description
      * @since Moodle 2.7
      * @deprecated Moodle 3.2 MDL-51373 - Please do not call this function any more.
-     * @see gradereport_user_external::get_grades_table for a similar function
+     * @see gradereport_user_external::get_grade_items for a similar function
      */
     public static function get_grades_returns() {
         return new external_single_structure(