Skip to content

Instantly share code, notes, and snippets.

@jleyva
Created December 8, 2016 10:39
Show Gist options
  • Save jleyva/a5ca0d3ea8be619ef868322744381927 to your computer and use it in GitHub Desktop.
Save jleyva/a5ca0d3ea8be619ef868322744381927 to your computer and use it in GitHub Desktop.
check_updates backport local_mobile
require_once($CFG->dirroot . '/course/lib.php');
if (!function_exists('course_check_updates')) {
/**
* Check for course updates in the given context level instances (only modules supported right Now)
*
* @param stdClass $course course object
* @param array $tocheck instances to check for updates
* @param array $filter check only for updates in these areas
* @return array list of warnings and instances with updates information
* @since Moodle 3.2
*/
function course_check_updates($course, $tocheck, $filter = array()) {
global $CFG, $DB;
$instances = array();
$warnings = array();
$modulescallbacksupport = array();
$modinfo = get_fast_modinfo($course);
$supportedplugins = array(
'mod_assign' => true,
'mod_book' => true,
'mod_choice' => true,
'mod_folder' => array('content'),
'mod_glossary' => true,
'mod_imscp' => array('content'),
'mod_label' => array(),
'mod_lti' => true,
'mod_page' => array('content'),
'mod_quiz' => true,
'mod_resource' => array('content'),
'mod_scorm' => true,
'mod_survey' => true,
'mod_url' => array('content'),
'mod_wiki' => true,
);
// Check instances.
foreach ($tocheck as $instance) {
if ($instance['contextlevel'] == 'module') {
// Check module visibility.
try {
$cm = $modinfo->get_cm($instance['id']);
} catch (Exception $e) {
$warnings[] = array(
'item' => 'module',
'itemid' => $instance['id'],
'warningcode' => 'cmidnotincourse',
'message' => 'This module id does not belong to this course.'
);
continue;
}
if (!$cm->uservisible) {
$warnings[] = array(
'item' => 'module',
'itemid' => $instance['id'],
'warningcode' => 'nonuservisible',
'message' => 'You don\'t have access to this module.'
);
continue;
}
if (!isset($supportedplugins['mod_' . $cm->modname])) {
$warnings[] = array(
'item' => 'module',
'itemid' => $instance['id'],
'warningcode' => 'missingcallback',
'message' => 'This module does not implement the check_updates_since callback: ' . $instance['contextlevel'],
);
continue;
}
$content = $supportedplugins['mod_' . $cm->modname];
if (is_array($content)) {
$instances[] = array(
'contextlevel' => $instance['contextlevel'],
'id' => $instance['id'],
'updates' => course_check_module_updates_since($cm, $instance['since'], $content, $filter)
);
} else {
$instances[] = array(
'contextlevel' => $instance['contextlevel'],
'id' => $instance['id'],
'updates' => call_user_func($cm->modname . '_check_updates_since', $cm, $instance['since'], $filter)
);
}
} else {
$warnings[] = array(
'item' => 'contextlevel',
'itemid' => $instance['id'],
'warningcode' => 'contextlevelnotsupported',
'message' => 'Context level not yet supported ' . $instance['contextlevel'],
);
}
}
return array($instances, $warnings);
}
}
if (!function_exists('course_check_module_updates_since')) {
/**
* Check module updates since a given time.
* This function checks for updates in the module config, file areas, completion, grades, comments and ratings.
*
* @param cm_info $cm course module data
* @param int $from the time to check
* @param array $fileareas additional file ares to check
* @param array $filter if we need to filter and return only selected updates
* @return stdClass object with the different updates
* @since Moodle 3.2
*/
function course_check_module_updates_since($cm, $from, $fileareas = array(), $filter = array()) {
global $DB, $CFG, $USER;
$context = $cm->context;
$mod = $DB->get_record($cm->modname, array('id' => $cm->instance), '*', MUST_EXIST);
$updates = new stdClass();
$course = get_course($cm->course);
$component = 'mod_' . $cm->modname;
// Check changes in the module configuration.
if (isset($mod->timemodified) and (empty($filter) or in_array('configuration', $filter))) {
$updates->configuration = (object) array('updated' => false);
if ($updates->configuration->updated = $mod->timemodified > $from) {
$updates->configuration->timeupdated = $mod->timemodified;
}
}
// Check for updates in files.
if (plugin_supports('mod', $cm->modname, FEATURE_MOD_INTRO)) {
$fileareas[] = 'intro';
}
if (!empty($fileareas) and (empty($filter) or in_array('fileareas', $filter))) {
$fs = get_file_storage();
$files = local_mobile_fs_get_area_files($context->id, $component, $fileareas, false, "filearea, timemodified DESC", true, $from);
foreach ($fileareas as $filearea) {
$updates->{$filearea . 'files'} = (object) array('updated' => false);
}
foreach ($files as $file) {
$updates->{$file->get_filearea() . 'files'}->updated = true;
$updates->{$file->get_filearea() . 'files'}->itemids[] = $file->get_id();
}
}
// Check completion.
$supportcompletion = plugin_supports('mod', $cm->modname, FEATURE_COMPLETION_HAS_RULES);
$supportcompletion = $supportcompletion or plugin_supports('mod', $cm->modname, FEATURE_COMPLETION_TRACKS_VIEWS);
if ($supportcompletion and (empty($filter) or in_array('completion', $filter))) {
$updates->completion = (object) array('updated' => false);
$completion = new completion_info($course);
// Use wholecourse to cache all the modules the first time.
$completiondata = $completion->get_data($cm, true);
if ($updates->completion->updated = !empty($completiondata->timemodified) && $completiondata->timemodified > $from) {
$updates->completion->timemodified = $completiondata->timemodified;
}
}
// Check grades.
$supportgrades = plugin_supports('mod', $cm->modname, FEATURE_GRADE_HAS_GRADE);
$supportgrades = $supportgrades or plugin_supports('mod', $cm->modname, FEATURE_GRADE_OUTCOMES);
if ($supportgrades and (empty($filter) or (in_array('gradeitems', $filter) or in_array('outcomes', $filter)))) {
require_once($CFG->libdir . '/gradelib.php');
$grades = grade_get_grades($course->id, 'mod', $cm->modname, $mod->id, $USER->id);
if (empty($filter) or in_array('gradeitems', $filter)) {
$updates->gradeitems = (object) array('updated' => false);
foreach ($grades->items as $gradeitem) {
foreach ($gradeitem->grades as $grade) {
if ($grade->datesubmitted > $from or $grade->dategraded > $from) {
$updates->gradeitems->updated = true;
$updates->gradeitems->itemids[] = $gradeitem->id;
}
}
}
}
}
return $updates;
}
}
/**
* Returns all area files (optionally limited by itemid)
*
* @param int $contextid context ID
* @param string $component component
* @param mixed $filearea file area/s, you cannot specify multiple fileareas as well as an itemid
* @param int $itemid item ID or all files if not specified
* @param string $sort A fragment of SQL to use for sorting
* @param bool $includedirs whether or not include directories
* @param int $updatedsince return files updated since this time
* @return stored_file[] array of stored_files indexed by pathanmehash
*/
function local_mobile_fs_get_area_files($contextid, $component, $filearea, $itemid = false, $sort = "itemid, filepath, filename",
$includedirs = true, $updatedsince = 0) {
global $DB, $CFG;
require_once($CFG->libdir . '/filestorage/file_storage.php');
$fs = get_file_storage();
list($areasql, $conditions) = $DB->get_in_or_equal($filearea, SQL_PARAMS_NAMED);
$conditions['contextid'] = $contextid;
$conditions['component'] = $component;
if ($itemid !== false && is_array($filearea)) {
throw new coding_exception('You cannot specify multiple fileareas as well as an itemid.');
} else if ($itemid !== false) {
$itemidsql = ' AND f.itemid = :itemid ';
$conditions['itemid'] = $itemid;
} else {
$itemidsql = '';
}
$updatedsincesql = '';
if (!empty($updatedsince)) {
$conditions['time'] = $updatedsince;
$updatedsincesql = 'AND f.timemodified > :time';
}
$sql = "SELECT ".file_storage::instance_sql_fields('f', 'r')."
FROM {files} f
LEFT JOIN {files_reference} r
ON f.referencefileid = r.id
WHERE f.contextid = :contextid
AND f.component = :component
AND f.filearea $areasql
$updatedsincesql
$itemidsql";
if (!empty($sort)) {
$sql .= " ORDER BY {$sort}";
}
$result = array();
$filerecords = $DB->get_records_sql($sql, $conditions);
foreach ($filerecords as $filerecord) {
if (!$includedirs and $filerecord->filename === '.') {
continue;
}
$result[$filerecord->pathnamehash] = $fs->get_file_instance($filerecord);
}
return $result;
}
require_once("$CFG->dirroot/mod/assign/lib.php");
if (function_exists('assign_check_updates_since')) {
/**
* Check if the module has any update that affects the current user since a given time.
*
* @param cm_info $cm course module data
* @param int $from the time to check updates from
* @param array $filter if we need to check only specific updates
* @return stdClass an object with the different type of areas indicating if they were updated or not
* @since Moodle 3.2
*/
function assign_check_updates_since(cm_info $cm, $from, $filter = array()) {
global $DB, $USER, $CFG;
require_once($CFG->dirroot . '/mod/assign/locallib.php');
$updates = new stdClass();
$updates = course_check_module_updates_since($cm, $from, array(ASSIGN_INTROATTACHMENT_FILEAREA), $filter);
// Check if there is a new submission by the user or new grades.
$select = 'assignment = :id AND userid = :userid AND (timecreated > :since1 OR timemodified > :since2)';
$params = array('id' => $cm->instance, 'userid' => $USER->id, 'since1' => $from, 'since2' => $from);
$updates->submissions = (object) array('updated' => false);
$submissions = $DB->get_records_select('assign_submission', $select, $params, '', 'id');
if (!empty($submissions)) {
$updates->submissions->updated = true;
$updates->submissions->itemids = array_keys($submissions);
}
$updates->grades = (object) array('updated' => false);
$grades = $DB->get_records_select('assign_grades', $select, $params, '', 'id');
if (!empty($grades)) {
$updates->grades->updated = true;
$updates->grades->itemids = array_keys($grades);
}
return $updates;
}
}
require_once("$CFG->dirroot/mod/book/lib.php");
if (function_exists('book_check_updates_since')) {
/**
* Check if the module has any update that affects the current user since a given time.
*
* @param cm_info $cm course module data
* @param int $from the time to check updates from
* @param array $filter if we need to check only specific updates
* @return stdClass an object with the different type of areas indicating if they were updated or not
* @since Moodle 3.2
*/
function book_check_updates_since(cm_info $cm, $from, $filter = array()) {
global $DB;
$context = $cm->context;
$updates = new stdClass();
if (!has_capability('mod/book:read', $context)) {
return $updates;
}
$updates = course_check_module_updates_since($cm, $from, array('content'), $filter);
$select = 'bookid = :id AND (timecreated > :since1 OR timemodified > :since2)';
$params = array('id' => $cm->instance, 'since1' => $from, 'since2' => $from);
if (!has_capability('mod/book:viewhiddenchapters', $context)) {
$select .= ' AND hidden = 0';
}
$updates->entries = (object) array('updated' => false);
$entries = $DB->get_records_select('book_chapters', $select, $params, '', 'id');
if (!empty($entries)) {
$updates->entries->updated = true;
$updates->entries->itemids = array_keys($entries);
}
return $updates;
}
}
require_once("$CFG->dirroot/mod/choice/lib.php");
if (function_exists('choice_check_updates_since')) {
/**
* Check if the module has any update that affects the current user since a given time.
*
* @param cm_info $cm course module data
* @param int $from the time to check updates from
* @param array $filter if we need to check only specific updates
* @return stdClass an object with the different type of areas indicating if they were updated or not
* @since Moodle 3.2
*/
function choice_check_updates_since(cm_info $cm, $from, $filter = array()) {
global $DB;
$updates = new stdClass();
$choice = $DB->get_record($cm->modname, array('id' => $cm->instance), '*', MUST_EXIST);
list($available, $warnings) = choice_get_availability_status($choice);
if (!$available) {
return $updates;
}
$updates = course_check_module_updates_since($cm, $from, array(), $filter);
if (!choice_can_view_results($choice)) {
return $updates;
}
// Check if there are new responses in the choice.
$updates->answers = (object) array('updated' => false);
$select = 'choiceid = :id AND timemodified > :since';
$params = array('id' => $choice->id, 'since' => $from);
$answers = $DB->get_records_select('choice_answers', $select, $params, '', 'id');
if (!empty($answers)) {
$updates->answers->updated = true;
$updates->answers->itemids = array_keys($answers);
}
return $updates;
}
}
require_once("$CFG->dirroot/mod/glossary/lib.php");
if (function_exists('glossary_check_updates_since')) {
/**
* Check if the module has any update that affects the current user since a given time.
*
* @param cm_info $cm course module data
* @param int $from the time to check updates from
* @param array $filter if we need to check only specific updates
* @return stdClass an object with the different type of areas indicating if they were updated or not
* @since Moodle 3.2
*/
function glossary_check_updates_since(cm_info $cm, $from, $filter = array()) {
global $DB;
$updates = course_check_module_updates_since($cm, $from, array('attachment', 'entry'), $filter);
$updates->entries = (object) array('updated' => false);
$select = 'glossaryid = :id AND (timecreated > :since1 OR timemodified > :since2)';
$params = array('id' => $cm->instance, 'since1' => $from, 'since2' => $from);
if (!has_capability('mod/glossary:approve', $cm->context)) {
$select .= ' AND approved = 1';
}
$entries = $DB->get_records_select('glossary_entries', $select, $params, '', 'id');
if (!empty($entries)) {
$updates->entries->updated = true;
$updates->entries->itemids = array_keys($entries);
}
return $updates;
}
}
require_once("$CFG->dirroot/mod/lti/lib.php");
if (function_exists('lti_check_updates_since')) {
/**
* Check if the module has any update that affects the current user since a given time.
*
* @param cm_info $cm course module data
* @param int $from the time to check updates from
* @param array $filter if we need to check only specific updates
* @return stdClass an object with the different type of areas indicating if they were updated or not
* @since Moodle 3.2
*/
function lti_check_updates_since(cm_info $cm, $from, $filter = array()) {
global $DB, $USER;
$updates = course_check_module_updates_since($cm, $from, array(), $filter);
// Check if there is a new submission.
$updates->submissions = (object) array('updated' => false);
$select = 'ltiid = :id AND userid = :userid AND (datesubmitted > :since1 OR dateupdated > :since2)';
$params = array('id' => $cm->instance, 'userid' => $USER->id, 'since1' => $from, 'since2' => $from);
$submissions = $DB->get_records_select('lti_submission', $select, $params, '', 'id');
if (!empty($submissions)) {
$updates->submissions->updated = true;
$updates->submissions->itemids = array_keys($submissions);
}
return $updates;
}
}
require_once("$CFG->dirroot/mod/quiz/lib.php");
if (function_exists('quiz_check_updates_since')) {
/**
* Check if the module has any update that affects the current user since a given time.
*
* @param cm_info $cm course module data
* @param int $from the time to check updates from
* @param array $filter if we need to check only specific updates
* @return stdClass an object with the different type of areas indicating if they were updated or not
* @since Moodle 3.2
*/
function quiz_check_updates_since(cm_info $cm, $from, $filter = array()) {
global $DB, $USER, $CFG;
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
$updates = course_check_module_updates_since($cm, $from, array(), $filter);
// Check if questions were updated.
$updates->questions = (object) array('updated' => false);
$quizobj = quiz::create($cm->instance, $USER->id);
$quizobj->preload_questions();
$quizobj->load_questions();
$questionids = array_keys($quizobj->get_questions());
if (!empty($questionids)) {
list($questionsql, $params) = $DB->get_in_or_equal($questionids, SQL_PARAMS_NAMED);
$select = 'id ' . $questionsql . ' AND (timemodified > :time1 OR timecreated > :time2)';
$params['time1'] = $from;
$params['time2'] = $from;
$questions = $DB->get_records_select('question', $select, $params, '', 'id');
if (!empty($questions)) {
$updates->questions->updated = true;
$updates->questions->itemids = array_keys($questions);
}
}
// Check for new attempts or grades.
$updates->attempts = (object) array('updated' => false);
$updates->grades = (object) array('updated' => false);
$select = 'quiz = ? AND userid = ? AND timemodified > ?';
$params = array($cm->instance, $USER->id, $from);
$attempts = $DB->get_records_select('quiz_attempts', $select, $params, '', 'id');
if (!empty($attempts)) {
$updates->attempts->updated = true;
$updates->attempts->itemids = array_keys($attempts);
}
$grades = $DB->get_records_select('quiz_grades', $select, $params, '', 'id');
if (!empty($grades)) {
$updates->grades->updated = true;
$updates->grades->itemids = array_keys($grades);
}
return $updates;
}
}
require_once("$CFG->dirroot/mod/scorm/lib.php");
if (function_exists('scorm_check_updates_since')) {
/**
* Check if the module has any update that affects the current user since a given time.
*
* @param cm_info $cm course module data
* @param int $from the time to check updates from
* @param array $filter if we need to check only specific updates
* @return stdClass an object with the different type of areas indicating if they were updated or not
* @since Moodle 3.2
*/
function scorm_check_updates_since(cm_info $cm, $from, $filter = array()) {
global $DB, $USER, $CFG;
require_once($CFG->dirroot . '/mod/scorm/locallib.php');
$scorm = $DB->get_record($cm->modname, array('id' => $cm->instance), '*', MUST_EXIST);
$updates = new stdClass();
list($available, $warnings) = scorm_get_availability_status($scorm, true, $cm->context);
if (!$available) {
return $updates;
}
$updates = course_check_module_updates_since($cm, $from, array('package'), $filter);
$updates->tracks = (object) array('updated' => false);
$select = 'scormid = ? AND userid = ? AND timemodified > ?';
$params = array($scorm->id, $USER->id, $from);
$tracks = $DB->get_records_select('scorm_scoes_track', $select, $params, '', 'id');
if (!empty($tracks)) {
$updates->tracks->updated = true;
$updates->tracks->itemids = array_keys($tracks);
}
return $updates;
}
}
require_once("$CFG->dirroot/mod/survey/lib.php");
if (function_exists('survey_check_updates_since')) {
/**
* Check if the module has any update that affects the current user since a given time.
*
* @param cm_info $cm course module data
* @param int $from the time to check updates from
* @param array $filter if we need to check only specific updates
* @return stdClass an object with the different type of areas indicating if they were updated or not
* @since Moodle 3.2
*/
function survey_check_updates_since(cm_info $cm, $from, $filter = array()) {
global $DB, $USER;
$updates = new stdClass();
if (!has_capability('mod/survey:participate', $cm->context)) {
return $updates;
}
$updates = course_check_module_updates_since($cm, $from, array(), $filter);
$updates->answers = (object) array('updated' => false);
$select = 'survey = ? AND userid = ? AND time > ?';
$params = array($cm->instance, $USER->id, $from);
$answers = $DB->get_records_select('survey_answers', $select, $params, '', 'id');
if (!empty($answers)) {
$updates->answers->updated = true;
$updates->answers->itemids = array_keys($answers);
}
return $updates;
}
}
require_once("$CFG->dirroot/mod/wiki/lib.php");
if (function_exists('wiki_check_updates_since')) {
/**
* Check if the module has any update that affects the current user since a given time.
*
* @param cm_info $cm course module data
* @param int $from the time to check updates from
* @param array $filter if we need to check only specific updates
* @return stdClass an object with the different type of areas indicating if they were updated or not
* @since Moodle 3.2
*/
function wiki_check_updates_since(cm_info $cm, $from, $filter = array()) {
global $DB, $CFG;
require_once($CFG->dirroot . '/mod/wiki/locallib.php');
$updates = new stdClass();
if (!has_capability('mod/wiki:viewpage', $cm->context)) {
return $updates;
}
$updates = course_check_module_updates_since($cm, $from, array('attachments'), $filter);
// Check only pages updated in subwikis the user can access.
$updates->pages = (object) array('updated' => false);
$wiki = $DB->get_record($cm->modname, array('id' => $cm->instance), '*', MUST_EXIST);
if ($subwikis = wiki_get_visible_subwikis($wiki, $cm, $cm->context)) {
$subwikisids = array();
foreach ($subwikis as $subwiki) {
$subwikisids[] = $subwiki->id;
}
list($subwikissql, $params) = $DB->get_in_or_equal($subwikisids, SQL_PARAMS_NAMED);
$select = 'subwikiid ' . $subwikissql . ' AND (timemodified > :since1 OR timecreated > :since2)';
$params['since1'] = $from;
$params['since2'] = $from;
$pages = $DB->get_records_select('wiki_pages', $select, $params, '', 'id');
if (!empty($pages)) {
$updates->pages->updated = true;
$updates->pages->itemids = array_keys($pages);
}
}
return $updates;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment