function execute($data, $row, $user, $courseid, $starttime = 0, $endtime = 0)
 {
     global $DB, $USER, $CFG;
     $courseid = $row->id;
     require_once $CFG->libdir . '/gradelib.php';
     require_once $CFG->dirroot . '/grade/querylib.php';
     if ($grade = grade_get_course_grade($user->id, $courseid)) {
         return $grade->grade;
     }
     return '';
 }
Example #2
0
/**
 * Returns the aggregated or calculated course grade for the given user(s).
 * @public
 * @param int $userid
 * @param int $courseid optional id of course or array of ids, empty means all uses courses (returns array if not present)
 * @return mixed grade info or grades array including item info, false if error
 */
function grade_get_course_grade($userid, $courseid_or_ids = null)
{
    if (!is_array($courseid_or_ids)) {
        if (empty($courseid_or_ids)) {
            if (!($courses = enrol_get_users_courses($userid))) {
                return false;
            }
            $courseids = array_keys($courses);
            return grade_get_course_grade($userid, $courseids);
        }
        if (!is_numeric($courseid_or_ids)) {
            return false;
        }
        if (!($grades = grade_get_course_grade($userid, array($courseid_or_ids)))) {
            return false;
        } else {
            // only one grade - not array
            $grade = reset($grades);
            return $grade;
        }
    }
    foreach ($courseid_or_ids as $courseid) {
        $grade_item = grade_item::fetch_course_item($courseid);
        $course_items[$grade_item->courseid] = $grade_item;
    }
    $grades = array();
    foreach ($course_items as $grade_item) {
        if ($grade_item->needsupdate) {
            grade_regrade_final_grades($courseid);
        }
        $item = new stdClass();
        $item->scaleid = $grade_item->scaleid;
        $item->name = $grade_item->get_name();
        $item->grademin = $grade_item->grademin;
        $item->grademax = $grade_item->grademax;
        $item->gradepass = $grade_item->gradepass;
        $item->locked = $grade_item->is_locked();
        $item->hidden = $grade_item->is_hidden();
        switch ($grade_item->gradetype) {
            case GRADE_TYPE_NONE:
                continue;
            case GRADE_TYPE_VALUE:
                $item->scaleid = 0;
                break;
            case GRADE_TYPE_TEXT:
                $item->scaleid = 0;
                $item->grademin = 0;
                $item->grademax = 0;
                $item->gradepass = 0;
                break;
        }
        $grade_grade = new grade_grade(array('userid' => $userid, 'itemid' => $grade_item->id));
        $grade_grade->grade_item =& $grade_item;
        $grade = new stdClass();
        $grade->grade = $grade_grade->finalgrade;
        $grade->locked = $grade_grade->is_locked();
        $grade->hidden = $grade_grade->is_hidden();
        $grade->overridden = $grade_grade->overridden;
        $grade->feedback = $grade_grade->feedback;
        $grade->feedbackformat = $grade_grade->feedbackformat;
        $grade->usermodified = $grade_grade->usermodified;
        $grade->dategraded = $grade_grade->get_dategraded();
        $grade->item = $item;
        // create text representation of grade
        if ($grade_item->needsupdate) {
            $grade->grade = false;
            $grade->str_grade = get_string('error');
            $grade->str_long_grade = $grade->str_grade;
        } else {
            if (is_null($grade->grade)) {
                $grade->str_grade = '-';
                $grade->str_long_grade = $grade->str_grade;
            } else {
                $grade->str_grade = grade_format_gradevalue($grade->grade, $grade_item);
                if ($grade_item->gradetype == GRADE_TYPE_SCALE or $grade_item->get_displaytype() != GRADE_DISPLAY_TYPE_REAL) {
                    $grade->str_long_grade = $grade->str_grade;
                } else {
                    $a = new stdClass();
                    $a->grade = $grade->str_grade;
                    $a->max = grade_format_gradevalue($grade_item->grademax, $grade_item);
                    $grade->str_long_grade = get_string('gradelong', 'grades', $a);
                }
            }
        }
        // create html representation of feedback
        if (is_null($grade->feedback)) {
            $grade->str_feedback = '';
        } else {
            $grade->str_feedback = format_text($grade->feedback, $grade->feedbackformat);
        }
        $grades[$grade_item->courseid] = $grade;
    }
    return $grades;
}
Example #3
0
 /**
  * Performs the synchronisation of grades.
  *
  * @return bool|void
  */
 public function execute()
 {
     global $DB, $CFG;
     require_once $CFG->dirroot . '/enrol/lti/ims-blti/OAuth.php';
     require_once $CFG->dirroot . '/enrol/lti/ims-blti/OAuthBody.php';
     require_once $CFG->dirroot . '/lib/completionlib.php';
     require_once $CFG->libdir . '/gradelib.php';
     require_once $CFG->dirroot . '/grade/querylib.php';
     // Check if the authentication plugin is disabled.
     if (!is_enabled_auth('lti')) {
         mtrace('Skipping task - ' . get_string('pluginnotenabled', 'auth', get_string('pluginname', 'auth_lti')));
         return true;
     }
     // Check if the enrolment plugin is disabled - isn't really necessary as the task should not run if
     // the plugin is disabled, but there is no harm in making sure core hasn't done something wrong.
     if (!enrol_is_enabled('lti')) {
         mtrace('Skipping task - ' . get_string('enrolisdisabled', 'enrol_lti'));
         return true;
     }
     // Get all the enabled tools.
     if ($tools = \enrol_lti\helper::get_lti_tools(array('status' => ENROL_INSTANCE_ENABLED, 'gradesync' => 1))) {
         foreach ($tools as $tool) {
             mtrace("Starting - Grade sync for shared tool '{$tool->id}' for the course '{$tool->courseid}'.");
             // Variables to keep track of information to display later.
             $usercount = 0;
             $sendcount = 0;
             // We check for all the users - users can access the same tool from different consumers.
             if ($ltiusers = $DB->get_records('enrol_lti_users', array('toolid' => $tool->id), 'lastaccess DESC')) {
                 $completion = new \completion_info(get_course($tool->courseid));
                 foreach ($ltiusers as $ltiuser) {
                     $mtracecontent = "for the user '{$ltiuser->userid}' in the tool '{$tool->id}' for the course " . "'{$tool->courseid}'";
                     $usercount = $usercount + 1;
                     // Check if we do not have a serviceurl - this can happen if the sync process has an unexpected error.
                     if (empty($ltiuser->serviceurl)) {
                         mtrace("Skipping - Empty serviceurl {$mtracecontent}.");
                         continue;
                     }
                     // Check if we do not have a sourceid - this can happen if the sync process has an unexpected error.
                     if (empty($ltiuser->sourceid)) {
                         mtrace("Skipping - Empty sourceid {$mtracecontent}.");
                         continue;
                     }
                     // Need a valid context to continue.
                     if (!($context = \context::instance_by_id($tool->contextid))) {
                         mtrace("Failed - Invalid contextid '{$tool->contextid}' for the tool '{$tool->id}'.");
                         continue;
                     }
                     // Ok, let's get the grade.
                     $grade = false;
                     if ($context->contextlevel == CONTEXT_COURSE) {
                         // Check if the user did not completed the course when it was required.
                         if ($tool->gradesynccompletion && !$completion->is_course_complete($ltiuser->userid)) {
                             mtrace("Skipping - Course not completed {$mtracecontent}.");
                             continue;
                         }
                         // Get the grade.
                         if ($grade = grade_get_course_grade($ltiuser->userid, $tool->courseid)) {
                             $grademax = floatval($grade->item->grademax);
                             $grade = $grade->grade;
                         }
                     } else {
                         if ($context->contextlevel == CONTEXT_MODULE) {
                             $cm = get_coursemodule_from_id(false, $context->instanceid, 0, false, MUST_EXIST);
                             if ($tool->gradesynccompletion) {
                                 $data = $completion->get_data($cm, false, $ltiuser->userid);
                                 if ($data->completionstate != COMPLETION_COMPLETE_PASS && $data->completionstate != COMPLETION_COMPLETE) {
                                     mtrace("Skipping - Activity not completed {$mtracecontent}.");
                                     continue;
                                 }
                             }
                             $grades = grade_get_grades($cm->course, 'mod', $cm->modname, $cm->instance, $ltiuser->userid);
                             if (!empty($grades->items[0]->grades)) {
                                 $grade = reset($grades->items[0]->grades);
                                 if (!empty($grade->item)) {
                                     $grademax = floatval($grade->item->grademax);
                                 } else {
                                     $grademax = floatval($grades->items[0]->grademax);
                                 }
                                 $grade = $grade->grade;
                             }
                         }
                     }
                     if ($grade === false || $grade === null || strlen($grade) < 1) {
                         mtrace("Skipping - Invalid grade {$mtracecontent}.");
                         continue;
                     }
                     // No need to be dividing by zero.
                     if (empty($grademax)) {
                         mtrace("Skipping - Invalid grade {$mtracecontent}.");
                         continue;
                     }
                     // This can happen if the sync process has an unexpected error.
                     if ($grade == $ltiuser->lastgrade) {
                         mtrace("Not sent - The grade {$mtracecontent} was not sent as the grades are the same.");
                         continue;
                     }
                     // Sync with the external system.
                     $floatgrade = $grade / $grademax;
                     $body = \enrol_lti\helper::create_service_body($ltiuser->sourceid, $floatgrade);
                     try {
                         $response = sendOAuthBodyPOST('POST', $ltiuser->serviceurl, $ltiuser->consumerkey, $ltiuser->consumersecret, 'application/xml', $body);
                     } catch (\Exception $e) {
                         mtrace("Failed - The grade '{$floatgrade}' {$mtracecontent} failed to send.");
                         mtrace($e->getMessage());
                         continue;
                     }
                     if (strpos(strtolower($response), 'success') !== false) {
                         $DB->set_field('enrol_lti_users', 'lastgrade', intval($grade), array('id' => $ltiuser->id));
                         mtrace("Success - The grade '{$floatgrade}' {$mtracecontent} was sent.");
                         $sendcount = $sendcount + 1;
                     } else {
                         mtrace("Failed - The grade '{$floatgrade}' {$mtracecontent} failed to send.");
                     }
                 }
             }
             mtrace("Completed - Synced grades for tool '{$tool->id}' in the course '{$tool->courseid}'. " . "Processed {$usercount} users; sent {$sendcount} grades.");
             mtrace("");
         }
     }
 }
Example #4
0
/**
 * This will provide summary info about the user's grade in the subcourse below the link on
 * the course/view.php page
 *
 * @param cm_info $cm
 * @return void
 */
function mod_subcourse_cm_info_view(cm_info $cm)
{
    global $USER, $CFG;
    $html = '';
    require_once $CFG->dirroot . '/grade/querylib.php';
    $currentgrade = grade_get_course_grade($USER->id, $cm->course);
    $html .= html_writer::empty_tag('br');
    $html .= html_writer::start_tag('span');
    $html .= get_string('currentgrade', 'subcourse') . ' ' . $currentgrade->str_grade;
    $html .= html_writer::end_tag('span');
    $cm->set_after_link($html);
}
 /**
  * Review this criteria and decide if it has been completed
  *
  * @return bool Whether criteria is complete
  */
 public function review($userid)
 {
     global $DB;
     foreach ($this->params as $param) {
         $course = $DB->get_record('course', array('id' => $param['course']));
         $info = new completion_info($course);
         $check_grade = true;
         $check_date = true;
         if (isset($param['grade'])) {
             $grade = grade_get_course_grade($userid, $course->id);
             $check_grade = $grade->grade >= $param['grade'];
         }
         if (isset($param['bydate'])) {
             $cparams = array('userid' => $userid, 'course' => $course->id);
             $completion = new completion_completion($cparams);
             $date = $completion->timecompleted;
             $check_date = $date <= $param['bydate'];
         }
         $overall = false;
         if ($this->method == BADGE_CRITERIA_AGGREGATION_ALL) {
             if ($info->is_course_complete($userid) && $check_grade && $check_date) {
                 $overall = true;
                 continue;
             } else {
                 return false;
             }
         } else {
             if ($this->method == BADGE_CRITERIA_AGGREGATION_ANY) {
                 if ($info->is_course_complete($userid) && $check_grade && $check_date) {
                     return true;
                 } else {
                     $overall = false;
                     continue;
                 }
             }
         }
     }
     return $overall;
 }
 if (strlen($user->serviceurl) < 1) {
     mtrace("   Empty serviceurl");
     continue;
 }
 if (strlen($user->sourceid) < 1) {
     mtrace("   Empty sourceid");
     continue;
 }
 $grade = false;
 if ($context = $DB->get_record('context', array('id' => $tool->contextid))) {
     if ($context->contextlevel == CONTEXT_COURSE) {
         if ($tool->requirecompletion and !$completion->is_course_complete($user->userid)) {
             mtrace("   Skipping user {$user->userid} since he didn't complete the course");
             continue;
         }
         if ($grade = grade_get_course_grade($user->userid, $tool->courseid)) {
             $grademax = floatval($grade->item->grademax);
             $grade = $grade->grade;
         }
     } else {
         if ($context->contextlevel == CONTEXT_MODULE) {
             $cm = get_coursemodule_from_id(false, $context->instanceid, 0, false, MUST_EXIST);
             if ($tool->requirecompletion) {
                 $data = $completion->get_data($cm, false, $user->userid);
                 if ($data->completionstate != COMPLETION_COMPLETE_PASS and $data->completionstate != COMPLETION_COMPLETE) {
                     mtrace("   Skipping user {$user->userid} since he didn't complete the activity");
                     continue;
                 }
             }
             $grades = grade_get_grades($cm->course, 'mod', $cm->modname, $cm->instance, $user->userid);
             if (empty($grades->items[0]->grades)) {
/**
 * Retrieves an array with grade information including grade obtained by a user for a course in Moodle, maximum grade for that course and min grade.  Returns null if the module is not gradable
 * or if the user has not been graded.
 * @author elever
 * @param int $id_course : native id of the course
 * @param int $userid : moodle identifier of the user
 * @return array $grade_info | null
 */
function block_intuitel_get_grade_info_course($id_course, $userid)
{
    global $CFG;
    require_once $CFG->dirroot . '/lib/gradelib.php';
    require_once $CFG->dirroot . '/grade/querylib.php';
    $grade_info = \grade_get_course_grade($userid, $id_course);
    $grade = array();
    $grade['grade'] = $grade_info->grade;
    $grade['grademax'] = $grade_info->item->grademax;
    $grade['grademin'] = $grade_info->item->grademin;
    //TODO check result if user has not been graded in the course
    return $grade;
}
 /**
  * Review this criteria and decide if it has been completed
  *
  * @param int $userid User whose criteria completion needs to be reviewed.
  * @param bool $filtered An additional parameter indicating that user list
  *        has been reduced and some expensive checks can be skipped.
  *
  * @return bool Whether criteria is complete
  */
 public function review($userid, $filtered = false)
 {
     $course = new stdClass();
     $course->id = $this->courseid;
     if ($this->coursestartdate > time()) {
         return false;
     }
     $info = new completion_info($course);
     foreach ($this->params as $param) {
         $check_grade = true;
         $check_date = true;
         if (isset($param['grade'])) {
             $grade = grade_get_course_grade($userid, $course->id);
             $check_grade = $grade->grade >= $param['grade'];
         }
         if (!$filtered && isset($param['bydate'])) {
             $cparams = array('userid' => $userid, 'course' => $course->id);
             $completion = new completion_completion($cparams);
             $date = $completion->timecompleted;
             $check_date = $date <= $param['bydate'];
         }
         if ($info->is_course_complete($userid) && $check_grade && $check_date) {
             return true;
         }
     }
     return false;
 }
 /**
  * Get user's course grade in this course
  *
  * @param completion_completion $completion an instance of completion_completion class
  * @return float
  */
 private function get_grade($completion)
 {
     $grade = grade_get_course_grade($completion->userid, $this->course);
     return $grade->grade;
 }
/**
 * Return the users custom profile field
 *
 * @param int $userid
 * @param int $courseid
 * @param str $format the format of the date
 * @return object
 */
function jemena_get_course_completion_stats($userid, $courseid, $format = '')
{
    global $CFG, $DB;
    require_once $CFG->dirroot . '/lib/gradelib.php';
    require_once $CFG->dirroot . '/grade/querylib.php';
    $completionstats = new stdClass();
    // Get the score for the course
    $objgrade = grade_get_course_grade($userid, $courseid);
    $completionstats->score = round($objgrade->grade, 2);
    $sql = "SELECT * " . "FROM {course_completions} cc " . "WHERE userid = '{$userid}' " . "AND course = '{$courseid}' " . "AND timecompleted IS NOT NULL";
    if ($stats = $DB->get_record_sql($sql)) {
        $completionstats->completed = get_string('completed', 'report_jemena');
        $completionstats->datecompleted = userdate($stats->timecompleted, $format);
    } else {
        $completionstats->completed = get_string('notcompleted', 'report_jemena');
        $completionstats->datecompleted = "";
    }
    return $completionstats;
}
 /**
  * Review this criteria and decide if it has been completed
  *
  * @param int $userid User whose criteria completion needs to be reviewed.
  * @return bool Whether criteria is complete
  */
 public function review($userid)
 {
     global $DB;
     foreach ($this->params as $param) {
         $course = $DB->get_record('course', array('id' => $param['course']));
         if ($course->startdate > time()) {
             return false;
         }
         $info = new completion_info($course);
         $check_grade = true;
         $check_date = true;
         if (isset($param['grade'])) {
             $grade = grade_get_course_grade($userid, $course->id);
             $check_grade = $grade->grade >= $param['grade'];
         }
         if (isset($param['bydate'])) {
             $cparams = array('userid' => $userid, 'course' => $course->id);
             $completion = new completion_completion($cparams);
             $date = $completion->timecompleted;
             $check_date = $date <= $param['bydate'];
         }
         if ($info->is_course_complete($userid) && $check_grade && $check_date) {
             return true;
         }
     }
     return false;
 }
Example #12
0
/**
 * Cron function for sync grades
 * @return void
 */
function local_ltiprovider_cron()
{
    global $DB, $CFG;
    require_once $CFG->dirroot . "/local/ltiprovider/locallib.php";
    require_once $CFG->dirroot . "/local/ltiprovider/ims-blti/OAuth.php";
    require_once $CFG->dirroot . "/local/ltiprovider/ims-blti/OAuthBody.php";
    require_once $CFG->libdir . '/gradelib.php';
    require_once $CFG->dirroot . '/grade/querylib.php';
    // TODO - Add a global setting for this
    $synctime = 60 * 60;
    // Every 1 hour grades are sync
    $timenow = time();
    mtrace('Running cron for ltiprovider');
    mtrace('Deleting LTI tools assigned to deleted courses');
    if ($tools = $DB->get_records('local_ltiprovider')) {
        foreach ($tools as $tool) {
            local_ltiprovider_check_missing_course($tool);
        }
    }
    // Grades service.
    if ($tools = $DB->get_records_select('local_ltiprovider', 'disabled = ? AND sendgrades = ?', array(0, 1))) {
        foreach ($tools as $tool) {
            if ($tool->lastsync + $synctime < $timenow) {
                mtrace(" Starting sync tool for grades id {$tool->id} course id {$tool->courseid}");
                if ($tool->requirecompletion) {
                    mtrace("  Grades require activity or course completion");
                }
                $user_count = 0;
                $send_count = 0;
                $error_count = 0;
                $completion = new completion_info(get_course($tool->courseid));
                if ($users = $DB->get_records('local_ltiprovider_user', array('toolid' => $tool->id))) {
                    foreach ($users as $user) {
                        $user_count = $user_count + 1;
                        // This can happen is the sync process has an unexpected error
                        if (strlen($user->serviceurl) < 1) {
                            mtrace("   Empty serviceurl");
                            continue;
                        }
                        if (strlen($user->sourceid) < 1) {
                            mtrace("   Empty sourceid");
                            continue;
                        }
                        if ($user->lastsync > $tool->lastsync) {
                            mtrace("   Skipping user {$user->id} due to recent sync");
                            continue;
                        }
                        $grade = false;
                        if ($context = $DB->get_record('context', array('id' => $tool->contextid))) {
                            if ($context->contextlevel == CONTEXT_COURSE) {
                                if ($tool->requirecompletion and !$completion->is_course_complete($user->userid)) {
                                    mtrace("   Skipping user {$user->userid} since he didn't complete the course");
                                    continue;
                                }
                                if ($grade = grade_get_course_grade($user->userid, $tool->courseid)) {
                                    $grademax = floatval($grade->item->grademax);
                                    $grade = $grade->grade;
                                }
                            } else {
                                if ($context->contextlevel == CONTEXT_MODULE) {
                                    $cm = get_coursemodule_from_id(false, $context->instanceid, 0, false, MUST_EXIST);
                                    if ($tool->requirecompletion) {
                                        $data = $completion->get_data($cm, false, $user->userid);
                                        if ($data->completionstate != COMPLETION_COMPLETE_PASS and $data->completionstate != COMPLETION_COMPLETE) {
                                            mtrace("   Skipping user {$user->userid} since he didn't complete the activity");
                                            continue;
                                        }
                                    }
                                    $grades = grade_get_grades($cm->course, 'mod', $cm->modname, $cm->instance, $user->userid);
                                    if (empty($grades->items[0]->grades)) {
                                        $grade = false;
                                    } else {
                                        $grade = reset($grades->items[0]->grades);
                                        if (!empty($grade->item)) {
                                            $grademax = floatval($grade->item->grademax);
                                        } else {
                                            $grademax = floatval($grades->items[0]->grademax);
                                        }
                                        $grade = $grade->grade;
                                    }
                                }
                            }
                            if ($grade === false || $grade === NULL || strlen($grade) < 1) {
                                mtrace("   Invalid grade {$grade}");
                                continue;
                            }
                            // No need to be dividing by zero
                            if ($grademax == 0.0) {
                                $grademax = 100.0;
                            }
                            // TODO: Make lastgrade should be float or string - but it is integer so we truncate
                            // TODO: Then remove those intval() calls
                            // Don't double send
                            if (intval($grade) == $user->lastgrade) {
                                mtrace("   Skipping, last grade send is equal to current grade");
                                continue;
                            }
                            // We sync with the external system only when the new grade differs with the previous one
                            // TODO - Global setting for check this
                            if ($grade >= 0 and $grade <= $grademax) {
                                $float_grade = $grade / $grademax;
                                $body = local_ltiprovider_create_service_body($user->sourceid, $float_grade);
                                try {
                                    $response = ltiprovider\sendOAuthBodyPOST('POST', $user->serviceurl, $user->consumerkey, $user->consumersecret, 'application/xml', $body);
                                } catch (Exception $e) {
                                    mtrace(" " . $e->getMessage());
                                    $error_count = $error_count + 1;
                                    continue;
                                }
                                // TODO - Check for errors in $retval in a correct way (parsing xml)
                                if (strpos(strtolower($response), 'success') !== false) {
                                    $DB->set_field('local_ltiprovider_user', 'lastsync', $timenow, array('id' => $user->id));
                                    $DB->set_field('local_ltiprovider_user', 'lastgrade', intval($grade), array('id' => $user->id));
                                    mtrace(" User grade sent to remote system. userid: {$user->userid} grade: {$float_grade}");
                                    $send_count = $send_count + 1;
                                } else {
                                    mtrace(" User grade send failed. userid: {$user->userid} grade: {$float_grade}: " . $response);
                                    $error_count = $error_count + 1;
                                }
                            } else {
                                mtrace(" User grade for user {$user->userid} out of range: grade = " . $grade);
                                $error_count = $error_count + 1;
                            }
                        } else {
                            mtrace(" Invalid context: contextid = " . $tool->contextid);
                        }
                    }
                }
                mtrace(" Completed sync tool id {$tool->id} course id {$tool->courseid} users={$user_count} sent={$send_count} errors={$error_count}");
                $DB->set_field('local_ltiprovider', 'lastsync', $timenow, array('id' => $tool->id));
            }
        }
    }
    $timenow = time();
    // Automatic course restaurations.
    if ($croncourses = get_config('local_ltiprovider', 'croncourses')) {
        $croncourses = unserialize($croncourses);
        if (is_array($croncourses)) {
            mtrace('Starting restauration of pending courses');
            foreach ($croncourses as $key => $course) {
                mtrace('Starting restoration of ' . $key);
                // We limit the backups to 1 hour, then retry.
                if ($course->restorestart and $timenow < $course->restorestart + 3600) {
                    mtrace('Skipping restoration in process for: ' . $key);
                    continue;
                }
                $course->restorestart = time();
                $croncourses[$key] = $course;
                $croncoursessafe = serialize($croncourses);
                set_config('croncourses', $croncoursessafe, 'local_ltiprovider');
                if ($destinationcourse = $DB->get_record('course', array('id' => $course->destinationid))) {
                    // Duplicate course + users.
                    local_ltiprovider_duplicate_course($course->id, $destinationcourse, 1, $options = array(array('name' => 'users', 'value' => 1)), $course->userrestoringid, $course->context);
                    mtrace('Restoration for ' . $key . ' finished');
                } else {
                    mtrace('Restoration for ' . $key . ' finished (destination course not exists)');
                }
                unset($croncourses[$key]);
                $croncoursessafe = serialize($croncourses);
                set_config('croncourses', $croncoursessafe, 'local_ltiprovider');
            }
        }
    }
    // Membership service.
    $timenow = time();
    $userphotos = array();
    if ($tools = $DB->get_records('local_ltiprovider', array('disabled' => 0, 'syncmembers' => 1))) {
        mtrace('Starting sync of member using the memberships service');
        $consumers = array();
        foreach ($tools as $tool) {
            $lastsync = get_config('local_ltiprovider', 'membershipslastsync-' . $tool->id);
            if (!$lastsync) {
                $lastsync = 0;
            }
            if ($lastsync + $tool->syncperiod < $timenow) {
                mtrace('Starting sync of tool: ' . $tool->id);
                // We check for all the users, notice that users can access the same tool from different consumers.
                if ($users = $DB->get_records('local_ltiprovider_user', array('toolid' => $tool->id), 'lastaccess DESC')) {
                    $response = "";
                    foreach ($users as $user) {
                        if (!$user->membershipsurl or !$user->membershipsid) {
                            continue;
                        }
                        $consumer = md5($user->membershipsurl . ':' . $user->membershipsid . ':' . $user->consumerkey . ':' . $user->consumersecret);
                        if (in_array($consumer, $consumers)) {
                            // We had syncrhonized with this consumer yet.
                            continue;
                        }
                        $consumers[] = $consumer;
                        $params = array('lti_message_type' => 'basic-lis-readmembershipsforcontext', 'id' => $user->membershipsid, 'lti_version' => 'LTI-1p0');
                        mtrace('Calling memberships url: ' . $user->membershipsurl . ' with body: ' . json_encode($params));
                        try {
                            $response = ltiprovider\sendOAuthParamsPOST('POST', $user->membershipsurl, $user->consumerkey, $user->consumersecret, 'application/x-www-form-urlencoded', $params);
                        } catch (Exception $e) {
                            mtrace("Exception: " . $e->getMessage());
                            $response = false;
                        }
                        if ($response) {
                            $data = new SimpleXMLElement($response);
                            if (!empty($data->statusinfo)) {
                                if (strpos(strtolower($data->statusinfo->codemajor), 'success') !== false) {
                                    $members = $data->memberships->member;
                                    mtrace(count($members) . ' members received');
                                    $currentusers = array();
                                    foreach ($members as $member) {
                                        $username = local_ltiprovider_create_username($user->consumerkey, $member->user_id);
                                        $userobj = $DB->get_record('user', array('username' => $username));
                                        if (!$userobj) {
                                            // Old format.
                                            $oldusername = '******' . md5($user->consumerkey . ':' . $member->user_id);
                                            $userobj = $DB->get_record('user', array('username' => $oldusername));
                                            if ($userobj) {
                                                $DB->set_field('user', 'username', $username, array('id' => $userobj->id));
                                            }
                                            $userobj = $DB->get_record('user', array('username' => $username));
                                        }
                                        if ($userobj) {
                                            $currentusers[] = $userobj->id;
                                            $userobj->firstname = clean_param($member->person_name_given, PARAM_TEXT);
                                            $userobj->lastname = clean_param($member->person_name_family, PARAM_TEXT);
                                            $userobj->email = clean_param($member->person_contact_email_primary, PARAM_EMAIL);
                                            $userobj->timemodified = time();
                                            $DB->update_record('user', $userobj);
                                            $userphotos[$userobj->id] = $member->user_image;
                                            // Trigger event.
                                            $event = \core\event\user_updated::create(array('objectid' => $userobj->id, 'relateduserid' => $userobj->id, 'context' => context_user::instance($userobj->id)));
                                            $event->trigger();
                                        } else {
                                            // New members.
                                            if ($tool->syncmode == 1 or $tool->syncmode == 2) {
                                                // We have to enrol new members so we have to create it.
                                                $userobj = new stdClass();
                                                // clean_param , email username text
                                                $auth = get_config('local_ltiprovider', 'defaultauthmethod');
                                                if ($auth) {
                                                    $userobj->auth = $auth;
                                                } else {
                                                    $userobj->auth = 'nologin';
                                                }
                                                $username = local_ltiprovider_create_username($user->consumerkey, $member->user_id);
                                                $userobj->username = $username;
                                                $userobj->password = md5(uniqid(rand(), 1));
                                                $userobj->firstname = clean_param($member->person_name_given, PARAM_TEXT);
                                                $userobj->lastname = clean_param($member->person_name_family, PARAM_TEXT);
                                                $userobj->email = clean_param($member->person_contact_email_primary, PARAM_EMAIL);
                                                $userobj->city = $tool->city;
                                                $userobj->country = $tool->country;
                                                $userobj->institution = $tool->institution;
                                                $userobj->timezone = $tool->timezone;
                                                $userobj->maildisplay = $tool->maildisplay;
                                                $userobj->mnethostid = $CFG->mnet_localhost_id;
                                                $userobj->confirmed = 1;
                                                $userobj->lang = $tool->lang;
                                                $userobj->timecreated = time();
                                                if (!$userobj->lang) {
                                                    // TODO: This should be changed for detect the course lang
                                                    $userobj->lang = current_language();
                                                }
                                                $userobj->id = $DB->insert_record('user', $userobj);
                                                // Reload full user
                                                $userobj = $DB->get_record('user', array('id' => $userobj->id));
                                                $userphotos[$userobj->id] = $member->user_image;
                                                // Trigger event.
                                                $event = \core\event\user_created::create(array('objectid' => $userobj->id, 'relateduserid' => $userobj->id, 'context' => context_user::instance($userobj->id)));
                                                $event->trigger();
                                                $currentusers[] = $userobj->id;
                                            }
                                        }
                                        // 1 -> Enrol and unenrol, 2 -> enrol
                                        if ($tool->syncmode == 1 or $tool->syncmode == 2) {
                                            // Enroll the user in the course. We don't know if it was previously unenrolled.
                                            $roles = explode(',', strtolower($member->roles));
                                            local_ltiprovider_enrol_user($tool, $userobj, $roles, true);
                                        }
                                    }
                                    // Now we check if we have to unenrol users for keep both systems sync.
                                    if ($tool->syncmode == 1 or $tool->syncmode == 3) {
                                        // Unenrol users also.
                                        $context = context_course::instance($tool->courseid);
                                        $eusers = get_enrolled_users($context);
                                        foreach ($eusers as $euser) {
                                            if (!in_array($euser->id, $currentusers)) {
                                                local_ltiprovider_unenrol_user($tool, $euser);
                                            }
                                        }
                                    }
                                } else {
                                    mtrace('Error recived from the remote system: ' . $data->statusinfo->codemajor . ' ' . $data->statusinfo->severity . ' ' . $data->statusinfo->codeminor);
                                }
                            } else {
                                mtrace('Error parsing the XML received' . substr($response, 0, 125) . '... (Displaying only 125 chars)');
                            }
                        } else {
                            mtrace('No response received from ' . $user->membershipsurl);
                        }
                    }
                }
                set_config('membershipslastsync-' . $tool->id, $timenow, 'local_ltiprovider');
            } else {
                $last = format_time(time() - $lastsync);
                mtrace("Tool {$tool->id} synchronized {$last} ago");
            }
            mtrace('Finished sync of member using the memberships service');
        }
    }
    // Sync of user photos.
    mtrace("Sync user profile images");
    $counter = 0;
    if ($userphotos) {
        foreach ($userphotos as $userid => $url) {
            if ($url) {
                $result = local_ltiprovider_update_user_profile_image($userid, $url);
                if ($result === true) {
                    $counter++;
                    mtrace("Profile image succesfully downloaded and created from {$url}");
                } else {
                    mtrace($result);
                }
            }
        }
    }
    mtrace("{$counter} profile images updated");
}
 /**
  * Load the course completion info
  *
  * @param object $user User object from database
  * @param object $cinfo Course object from database
  */
 public static final function load_course_completioninfo($user, $cinfo)
 {
     global $DB, $CFG;
     static $cstatus, $completioninfo = array();
     require_once $CFG->dirroot . '/lib/gradelib.php';
     require_once $CFG->dirroot . '/grade/querylib.php';
     require_once $CFG->dirroot . '/lib/completionlib.php';
     // Completion status 'cache' values (speed up, lass!).
     if ($cstatus === null) {
         $cstatus = array();
         $cstatus['started'] = get_string('report:status_started', 'block_coupon');
         $cstatus['notstarted'] = get_string('report:status_not_started', 'block_coupon');
         $cstatus['complete'] = get_string('report:status_completed', 'block_coupon');
     }
     // Completion info 'cache' (speed up, lass!).
     if (!isset($completioninfo[$cinfo->id])) {
         $completioninfo[$cinfo->id] = new \completion_info($cinfo);
     }
     $ci = new \stdClass();
     $ci->complete = false;
     $ci->str_status = $cstatus['notstarted'];
     $ci->date_started = '-';
     $ci->date_complete = '-';
     $ci->str_grade = '-';
     $ci->gradeinfo = null;
     // Ok, fill out real data according to completion status/info.
     $com = $completioninfo[$cinfo->id];
     if ($com->is_tracked_user($user->id)) {
         // Do we have an enrolment for the course for this user.
         $sql = 'SELECT ue.* FROM {user_enrolments} ue
                 JOIN {enrol} e ON ue.enrolid=e.id
                 WHERE ue.userid = ? AND e.courseid = ?
                 ORDER BY timestart ASC, timecreated ASC';
         $records = $DB->get_records_sql($sql, array($user->id, $cinfo->id));
         if (count($records) === 1) {
             $record = array_shift($records);
             $ci->time_started = $record->timestart > 0 ? $record->timestart : $record->timecreated;
             $ci->date_started = date('d-m-Y H:i:s', $ci->time_started);
         } else {
             $started = 0;
             $created = 0;
             foreach ($records as $record) {
                 if ($record->timestart > 0) {
                     $started = $started == 0 ? $record->timestart : min($record->timestart, $started);
                 }
                 $created = $created == 0 ? $record->timecreated : min($record->timecreated, $created);
             }
             $ci->time_started = $started > 0 ? $started : $created;
             $ci->date_started = date('d-m-Y H:i:s', $started > 0 ? $started : $created);
         }
         if ($com->is_course_complete($user->id)) {
             // Fetch details for course completion.
             $ci->complete = true;
             $comcom = new \completion_completion(array('userid' => $user->id, 'course' => $cinfo->id));
             $ci->date_complete = date('d-m-Y H:i:s', $comcom->timecompleted);
             $ci->gradeinfo = grade_get_course_grade($user->id, $cinfo->id);
             if ($ci->gradeinfo !== false) {
                 $ci->str_grade = $ci->gradeinfo->str_grade;
             }
             $ci->str_status = $cstatus['complete'];
         } else {
             $ci->str_status = $cstatus['started'];
         }
     }
     return $ci;
 }
Example #14
0
/**
 * Cron function for sync grades
 * @return void
 */
function local_ltiprovider_cron() {
    global $DB, $CFG;
    require_once($CFG->dirroot . "/local/ltiprovider/ims-blti/OAuth.php");
    require_once($CFG->dirroot . "/local/ltiprovider/ims-blti/OAuthBody.php");
    require_once($CFG->libdir . '/gradelib.php');
    require_once($CFG->dirroot . '/grade/querylib.php');

    // TODO - Add a global setting for this
    $synctime = 60 * 60;  // Every 1 hour grades are sync
    $timenow = time();

    mtrace('Running cron for ltiprovider');
    if ($tools = $DB->get_records_select('local_ltiprovider', 'disabled = ? AND sendgrades = ?', array(0, 1))) {
        foreach ($tools as $tool) {
            if ($tool->lastsync + $synctime < $timenow) {
                mtrace(" Starting sync tool id $tool->id course id $tool->courseid");
                $user_count = 0;
                $send_count = 0;
                $error_count = 0;
                if ($users = $DB->get_records('local_ltiprovider_user', array('toolid' => $tool->id))) {
                    foreach ($users as $user) {
                        $user_count = $user_count + 1;
                        // This can happen is the sync process has an unexpected error
                        if (strlen($user->serviceurl) < 1)
                            continue;
                        if (strlen($user->sourceid) < 1)
                            continue;
                        if ($user->lastsync > $tool->lastsync) {
                            mtrace("Skipping user {$user->id}");
                            continue;
                        }

                        $grade = false;
                        if ($context = $DB->get_record('context', array('id' => $tool->contextid))) {
                            if ($context->contextlevel == CONTEXT_COURSE) {

                                if ($grade = grade_get_course_grade($user->userid, $tool->courseid)) {
                                    $grademax = floatval($grade->item->grademax);
                                    $grade = $grade->grade;
                                }
                            } else if ($context->contextlevel == CONTEXT_MODULE) {

                                $cm = get_coursemodule_from_id(false, $context->instanceid, 0, false, MUST_EXIST);
                                $grades = grade_get_grades($cm->course, 'mod', $cm->modname, $cm->instance, $user->userid);
                                if (empty($grades->items[0]->grades)) {
                                    $grade = false;
                                } else {
                                    $grade = reset($grades->items[0]->grades);
                                    $grademax = floatval($grade->item->grademax);
                                    $grade = $grade->grade;
                                }
                            }

                            if ($grade === false || $grade === NULL || strlen($grade) < 1)
                                continue;

                            // No need to be dividing by zero
                            if ($grademax == 0.0)
                                $grademax = 100.0;

                            // TODO: Make lastgrade should be float or string - but it is integer so we truncate
                            // TODO: Then remove those intval() calls
                            // Don't double send
                            if (intval($grade) == $user->lastgrade)
                                continue;

                            // We sync with the external system only when the new grade differs with the previous one
                            // TODO - Global setting for check this
                            if ($grade > 0 and $grade <= $grademax) {
                                $float_grade = $grade / $grademax;
                                $body = ltiprovider_create_service_body($user->sourceid, $float_grade);

                                try {
                                    $response = ltiprovider\sendOAuthBodyPOST('POST', $user->serviceurl, $user->consumerkey, $user->consumersecret, 'application/xml', $body);
                                } catch (Exception $e) {
                                    mtrace(" " . $e->getMessage());
                                    $error_count = $error_count + 1;
                                    continue;
                                }

                                // TODO - Check for errors in $retval in a correct way (parsing xml)
                                if (strpos(strtolower($response), 'success') !== false) {

                                    $DB->set_field('local_ltiprovider_user', 'lastsync', $timenow, array('id' => $user->id));
                                    $DB->set_field('local_ltiprovider_user', 'lastgrade', intval($grade), array('id' => $user->id));
                                    mtrace(" User grade sent to remote system. userid: $user->userid grade: $float_grade");
                                    $send_count = $send_count + 1;
                                } else {
                                    mtrace(" User grade send failed: " . $response);
                                    $error_count = $error_count + 1;
                                }
                            } else {
                                mtrace(" User grade out of range: grade = " . $grade);
                                $error_count = $error_count + 1;
                            }
                        } else {
                            mtrace(" Invalid context: contextid = " . $tool->contextid);
                        }
                    }
                }
                mtrace(" Completed sync tool id $tool->id course id $tool->courseid users=$user_count sent=$send_count errors=$error_count");
                $DB->set_field('local_ltiprovider', 'lastsync', $timenow, array('id' => $tool->id));
            }
        }
    }
}
Example #15
0
 /**
  * Retorna a nota do aluno em um curso informado.
  *
  * Significado dos valores negativos:
  * -1 Nota não informada
  * -9999 a grade não existe
  * -8888 a grade retornou null
  *
  * @param int $userid
  * @param int $courseid
  * @return int Nota do aluno no curso.
  */
 public static function get_final_grade_by_user_id_and_course_id($userid, $courseid)
 {
     // no MOODLE não temos factories
     // obtemos os acessores diretamente via variaveis globais
     global $CFG;
     require_once $CFG->dirroot . '/grade/lib.php';
     require_once $CFG->dirroot . '/grade/querylib.php';
     require_once $CFG->dirroot . "/user/lib.php";
     // para trabalhar com as grades de notas precisa-se ter
     // as seguintes habilidades:
     // * moodle/grade:export
     // * gradeexprt/txt:view
     // primeiro pego o contexto do sistema com base no usuário corrente
     $context = get_context_instance(CONTEXT_SYSTEM);
     // então verifico as abilidades uma a uma
     require_capability('moodle/grade:export', $context);
     require_capability('gradeexport/txt:view', $context);
     // neste ponto se verifica os parametros informados estão corretos
     // e dentro do exigido pela função
     // observe que solicitei os parametros como sendo do tipo inteiro
     // diretamente sem que sejam algum tipo de estrutura. Isto facilita
     // o acesso aos parametros,
     $funcParams = self::validate_parameters(self::get_final_grade_by_user_id_and_course_id_parameters(), array('userId' => $userid, 'courseId' => $courseid));
     // OK, agora que está tudo ok, consulto no banco de dados a nota
     // do usuário conforme o curso
     $grade = grade_get_course_grade($funcParams['userId'], $funcParams['courseId']);
     /*
      * $grade é um objeto com detalhes da nota dada ao usuário
      * como neste caso informei apenas um curso retorna uma grade, se
      * informar mais de um curso ou nenhum curso retorna um array com
      * todas as notas disponiveis para o curso informado ou para os
      * cursos matriculados respectivamente.
      *
      * $grade->grade			// Nota, obrigatorio
      * $grade->locked			//
      * $grade->hidden			//
      * $grade->overridden		//
      * $grade->feedback			//
      * $grade->feedbackformat	//
      * $grade->usermodified		//
      * $grade->dategraded		//
      * $grade->item				//
      *
      * formato de $grade->item
      * $item->name			// Nome do Item (Por exemplo: Total do Curso)
      * $item->grademin		// Valor Minimo da Nota
      * $item->grademax		// Valor Máximo
      * $item->gradepass		//
      * $item->locked
      * $item->hidden
      *
      */
     // TODO, estudar melhorias neste retorno.
     $result = array();
     if ($grade === false) {
         $result['grade'] = grade_floatval(-9999);
     } else {
         if ($grade === null) {
             $result['grade'] = grade_floatval(-8888);
         } else {
             $result['grade'] = grade_floatval($grade->grade);
         }
     }
     return $result;
 }
Example #16
0
function local_ltiprovider_send_grade($tool, $user, $timenow)
{
    // I've set this up this way to potentially use the Event API to trigger a grade send automatically.
    // TODO:  Probably don't need all of these...
    global $DB, $CFG, $PAGE;
    require_once $CFG->dirroot . "/local/ltiprovider/locallib.php";
    require_once $CFG->dirroot . "/local/ltiprovider/ims-blti/OAuth.php";
    require_once $CFG->dirroot . "/local/ltiprovider/ims-blti/OAuthBody.php";
    require_once $CFG->libdir . '/gradelib.php';
    require_once $CFG->dirroot . '/grade/querylib.php';
    $PAGE->set_context(context_system::instance());
    $grade = false;
    if ($context = $DB->get_record('context', array('id' => $tool->contextid))) {
        if ($context->contextlevel == CONTEXT_COURSE) {
            if ($grade = grade_get_course_grade($user->userid, $tool->courseid)) {
                $grademax = floatval($grade->item->grademax);
                $grade = $grade->grade;
            }
        } else {
            if ($context->contextlevel == CONTEXT_MODULE) {
                $cm = get_coursemodule_from_id(false, $context->instanceid, 0, false, MUST_EXIST);
                $grades = grade_get_grades($cm->course, 'mod', $cm->modname, $cm->instance, $user->userid);
                if (empty($grades->items[0]->grades)) {
                    $grade = false;
                } else {
                    $grade = reset($grades->items[0]->grades);
                    if (!empty($grade->item)) {
                        $grademax = floatval($grade->item->grademax);
                    } else {
                        $grademax = floatval($grades->items[0]->grademax);
                    }
                    $grade = $grade->grade;
                }
            }
        }
        if ($grade === false || $grade === NULL || strlen($grade) < 1) {
            continue;
        }
        // No need to be dividing by zero
        if ($grademax == 0.0) {
            $grademax = 100.0;
        }
        // TODO: Make lastgrade should be float or string - but it is integer so we truncate
        // TODO: Then remove those intval() calls
        // Don't double send
        // TODO:  toggle this.  There are places where replacing the grade
        // every time is desirable.  This should probably be on the tool
        // level.
        //if ( intval($grade) == $user->lastgrade ) continue;
        // We sync with the external system only when the new grade differs with the previous one
        // TODO - Global setting for check this
        if ($grade > 0 and $grade <= $grademax) {
            $float_grade = $grade / $grademax;
            $body = local_ltiprovider_create_service_body($user->sourceid, $float_grade);
            try {
                $response = ltiprovider\sendOAuthBodyPOST('POST', $user->serviceurl, $user->consumerkey, $user->consumersecret, 'application/xml', $body);
            } catch (Exception $e) {
                mtrace(" " . $e->getMessage());
                $error_count = $error_count + 1;
                continue;
            }
            // Checking the return value and properly coping with it.
            $xml = simplexml_load_string(str_replace('xmlns', 'ns', $response));
            $imsx_codeMajor = $xml->xpath('/imsx_POXEnvelopeResponse/imsx_POXHeader' . '/imsx_POXResponseHeaderInfo/imsx_statusInfo/imsx_codeMajor');
            $imsx_description = $xml->xpath('/imsx_POXEnvelopeResponse/imsx_POXHeader' . '/imsx_POXResponseHeaderInfo/imsx_statusInfo/imsx_description');
            mtrace(" Remote system description was " . $imsx_description[0]);
            if (strtolower($imsx_codeMajor[0]) === 'success') {
                $DB->set_field('local_ltiprovider_user', 'lastsync', $timenow, array('id' => $user->id));
                $DB->set_field('local_ltiprovider_user', 'lastgrade', intval($grade), array('id' => $user->id));
                mtrace(" User grade sent to remote system. userid: {$user->userid} grade: {$float_grade}");
                return array(true, "Successfully set grade");
            } else {
                mtrace(" User grade send failed: " . $response);
                $error_count = $error_count + 1;
            }
        } else {
            mtrace(" User grade out of range: grade = " . $grade);
            $error_count = $error_count + 1;
        }
    } else {
        mtrace(" Invalid context: contextid = " . $tool->contextid);
    }
}