MDL-56307 course: New course_check_module_updates_since method
authorJuan Leyva <juanleyvadelgado@gmail.com>
Tue, 11 Oct 2016 12:48:24 +0000 (13:48 +0100)
committerJuan Leyva <juanleyvadelgado@gmail.com>
Tue, 25 Oct 2016 09:10:52 +0000 (10:10 +0100)
19 files changed:
course/lib.php
course/tests/courselib_test.php
mod/assign/lib.php
mod/book/lib.php
mod/choice/lib.php
mod/folder/lib.php
mod/forum/lib.php
mod/glossary/lib.php
mod/imscp/lib.php
mod/label/lib.php
mod/lti/lib.php
mod/page/lib.php
mod/quiz/lib.php
mod/resource/lib.php
mod/scorm/lib.php
mod/survey/lib.php
mod/upgrade.txt
mod/url/lib.php
mod/wiki/lib.php

index e731709..0cb1ad7 100644 (file)
@@ -3601,3 +3601,172 @@ function course_validate_dates($coursedata) {
 
     return false;
 }
+
+/**
+ * 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 = get_plugin_list_with_function('mod', 'check_updates_since');
+
+    // Check instances.
+    foreach ($tocheck as $instance) {
+        if ($instance['contextlevel'] == 'module') {
+            // Check module visibility.
+            $modinfoexception = false;
+            try {
+                $cm = $modinfo->get_cm($instance['id']);
+            } catch (Exception $e) {
+                $modinfoexception = true;
+            }
+
+            if ($modinfoexception or !$cm->uservisible) {
+                $warnings[] = array(
+                    'item' => 'module',
+                    'itemid' => $instance['id'],
+                    'warningcode' => 'nonuservisible',
+                    'message' => 'You don\'t have access to this module.'
+                );
+                continue;
+            }
+            if (empty($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;
+            }
+            // Retrieve the module instance.
+            $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);
+}
+
+/**
+ * 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 = $mod->timemodified > $from;
+    }
+
+    // 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();
+        $extrasql = 'AND (f.timecreated > :since1 OR f.timemodified > :since2)';
+        $extraconditions = array('since1' => $from, 'since2' => $from);
+        foreach ($fileareas as $fileareaname) {
+            $files = $fs->get_area_files($context->id, $component, $fileareaname, false, "itemid", true, $extrasql, $extraconditions);
+            $updates->{$fileareaname . 'files'} = !empty($files);
+        }
+    }
+
+    // Check completion.
+    $updates->completion = false;
+    $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))) {
+        $completion = new completion_info($course);
+        // Use wholecourse to cache all the modules the first time.
+        $completiondata = $completion->get_data($cm, true);
+        $updates->completion = !empty($completiondata->timemodified) && $completiondata->timemodified > $from;
+    }
+
+    // Check grades.
+    $updates->gradeitems = false;
+    $updates->outcomes = false;
+    $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)) {
+            foreach ($grades->items as $gradeitem) {
+                foreach ($gradeitem->grades as $grade) {
+                    if ($grade->datesubmitted > $from or $grade->dategraded > $from) {
+                        $updates->gradeitems = true;
+                        break 2;
+                    }
+                }
+            }
+        }
+        
+        if (empty($filter) or in_array('outcomes', $filter)) {
+            foreach ($grades->outcomes as $outcome) {
+                foreach ($outcome->grades as $grade) {
+                    if ($grade->datesubmitted > $from or $grade->dategraded > $from) {
+                        $updates->outcomes = true;
+                        break 2;
+                    }
+                }
+            }
+        }
+    }
+
+    // Check comments.
+    $updates->comments = false;
+    if (plugin_supports('mod', $cm->modname, FEATURE_COMMENT) and (empty($filter) or in_array('comments', $filter))) {
+        require_once($CFG->dirroot . '/comment/locallib.php');
+        $manager = new comment_manager();
+        $updates->comments = count($manager->get_component_comments_since($course, $cm, $context, $component, $from)) > 0;
+    }
+
+    // Check ratings.
+    $updates->ratings = false;
+    if (plugin_supports('mod', $cm->modname, FEATURE_RATE) and (empty($filter) or in_array('ratings', $filter))) {
+        require_once($CFG->dirroot . '/rating/lib.php');
+        $manager = new rating_manager();
+        $updates->ratings = count($manager->get_component_ratings_since($course, $cm, $context, $component, $from)) > 0;
+    }
+
+    return $updates;
+}
index e470289..5c97ea6 100644 (file)
@@ -3297,4 +3297,92 @@ class core_course_courselib_testcase extends advanced_testcase {
             ]
         ];
     }
+
+    public function test_course_check_module_updates_since() {
+        global $CFG, $DB, $USER;
+        require_once($CFG->dirroot . '/mod/glossary/lib.php');
+        require_once($CFG->dirroot . '/rating/lib.php');
+        require_once($CFG->dirroot . '/comment/lib.php');
+
+        $this->resetAfterTest(true);
+
+        $CFG->enablecompletion = true;
+        $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
+        $glossary = $this->getDataGenerator()->create_module('glossary', array(
+            'course' => $course->id,
+            'completion' => COMPLETION_TRACKING_AUTOMATIC,
+            'completionview' => 1,
+            'allowcomments' => 1,
+            'assessed' => RATING_AGGREGATE_AVERAGE,
+            'scale' => 100
+        ));
+        $glossarygenerator = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
+        $context = context_module::instance($glossary->cmid);
+        $modinfo = get_fast_modinfo($course);
+        $cm = $modinfo->get_cm($glossary->cmid);
+        $user = $this->getDataGenerator()->create_user();
+        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
+        $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
+        $from = time();
+
+        $teacher = $this->getDataGenerator()->create_user();
+        $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
+        $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id);
+
+        assign_capability('mod/glossary:viewanyrating', CAP_ALLOW, $studentrole->id, $context->id, true);
+
+        // Check nothing changed right now.
+        $updates = course_check_module_updates_since($cm, $from);
+        $this->assertFalse($updates->configuration);
+        $this->assertFalse($updates->completion);
+        $this->assertFalse($updates->gradeitems);
+        $this->assertFalse($updates->comments);
+        $this->assertFalse($updates->ratings);
+        $this->assertFalse($updates->introfiles);
+        $this->assertFalse($updates->outcomes);
+
+        $this->waitForSecond();
+
+        // Do some changes.
+        $this->setUser($user);
+        $entry = $glossarygenerator->create_content($glossary);
+
+        $this->setUser($teacher);
+        // Name.
+        set_coursemodule_name($glossary->cmid, 'New name');
+
+        // Add some ratings.
+        $rm = new rating_manager();
+        $result = $rm->add_rating($cm, $context, 'mod_glossary', 'entry', $entry->id, 100, 50, $user->id, RATING_AGGREGATE_AVERAGE);
+
+        // Change grades.
+        $glossary->cmidnumber = $glossary->cmid;
+        glossary_update_grades($glossary, $user->id);
+
+        $this->setUser($user);
+        // Completion status.
+        glossary_view($glossary, $course, $cm, $context, 'letter');
+
+        // Add one comment.
+        $args = new stdClass;
+        $args->context   = $context;
+        $args->course    = $course;
+        $args->cm        = $cm;
+        $args->area      = 'glossary_entry';
+        $args->itemid    = $entry->id;
+        $args->client_id = 1;
+        $args->component = 'mod_glossary';
+        $manager = new comment($args);
+        $manager->add('blah blah blah');
+
+        // Check upgrade status.
+        $updates = course_check_module_updates_since($cm, $from);
+        $this->assertTrue($updates->configuration);
+        $this->assertTrue($updates->completion);
+        $this->assertTrue($updates->gradeitems);
+        $this->assertTrue($updates->comments);
+        $this->assertTrue($updates->ratings);
+        $this->assertFalse($updates->introfiles);
+        $this->assertFalse($updates->outcomes);
+    }
 }
index fec9a7e..ecf1a45 100644 (file)
@@ -1517,3 +1517,28 @@ function mod_assign_output_fragment_gradingpanel($args) {
 
     return $assign->view('gradingpanel', $viewargs);
 }
+
+/**
+ * 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 = $DB->count_records_select('assign_submission', $select, $params) > 0;
+    $updates->grades = $DB->count_records_select('assign_grades', $select, $params) > 0;
+
+    return $updates;
+}
index d07a279..06be5e8 100644 (file)
@@ -636,3 +636,32 @@ function book_view($book, $chapter, $islastchapter, $course, $cm, $context) {
         }
     }
 }
+
+/**
+ * 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 = $DB->count_records_select('book_chapters', $select, $params) > 0;
+
+    return $updates;
+}
index 770077d..f4c16c3 100644 (file)
@@ -1131,3 +1131,34 @@ function choice_refresh_events($courseid = 0) {
     return true;
 }
 
+/**
+ * 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.
+    $select = 'choiceid = :id AND timemodified > :since';
+    $params = array('id' => $choice->id, 'since' => $from);
+    $updates->answers = $DB->count_records_select('choice_answers', $select, $params) > 0;
+
+    return $updates;
+}
index 64390e4..17f1ce6 100644 (file)
@@ -746,3 +746,17 @@ function folder_print_recent_activity($course, $viewfullnames, $timestart) {
     echo $list;
     return true;
 }
+
+ /**
+ * 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 folder_check_updates_since(cm_info $cm, $from, $filter = array()) {
+    $updates = course_check_module_updates_since($cm, $from, array('content'), $filter);
+    return $updates;
+}
index 621553e..43391ec 100644 (file)
@@ -2521,10 +2521,13 @@ function forum_count_discussions($forum, $cm, $course) {
  * @param int $perpage
  * @param int $groupid if groups enabled, get discussions for this group overriding the current group.
  *                     Use FORUM_POSTS_ALL_USER_GROUPS for all the user groups
+ * @param string $extrasql additional SQL code for the query
+ * @param array $extraparams additional params for the $extrasql
  * @return array
  */
 function forum_get_discussions($cm, $forumsort="", $fullpost=true, $unused=-1, $limit=-1,
-                                $userlastmodified=false, $page=-1, $perpage=0, $groupid = -1) {
+                                $userlastmodified=false, $page=-1, $perpage=0, $groupid = -1,
+                                $extrasql = '', $extraparams = array()) {
     global $CFG, $DB, $USER;
 
     $timelimit = '';
@@ -2643,8 +2646,11 @@ function forum_get_discussions($cm, $forumsort="", $fullpost=true, $unused=-1, $
                    JOIN {user} u ON p.userid = u.id
                    $umtable
              WHERE d.forum = ? AND p.parent = 0
-                   $timelimit $groupselect
+                   $timelimit $groupselect $extrasql
           ORDER BY $forumsort, d.id DESC";
+    if (!empty($extrasql)) {
+        $params = array_merge($params, $extraparams);
+    }
     return $DB->get_records_sql($sql, $params, $limitfrom, $limitnum);
 }
 
@@ -8038,3 +8044,31 @@ function forum_discussion_is_locked($forum, $discussion) {
 
     return false;
 }
+
+/**
+ * Check if the module has any update that affects the current user since a given time.
+ *
+ * @param  cm_info $cm course module data
+ * @param  stdClass $context context object
+ * @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 forum_check_updates_since(cm_info $cm, $from, $filter = array()) {
+
+    $context = $cm->context;
+    $updates = new stdClass();
+    if (!has_capability('mod/forum:viewdiscussion', $context)) {
+        return $updates;
+    }
+
+    $updates = course_check_module_updates_since($cm, $from, array(), $filter);
+
+    // Check if there are new discussions in the forum.
+    $sql = 'AND (d.timemodified > ? OR p.created > ? OR p.modified > ?)';
+    $params = array($from, $from, $from);
+    $discussions = forum_get_discussions($cm, '', false, -1, -1, true, -1, 0, FORUM_POSTS_ALL_USER_GROUPS, $sql, $params);
+    $updates->discussions = count($discussions) > 0;
+
+    return $updates;
+}
index cbd1901..ca31d65 100644 (file)
@@ -4101,3 +4101,27 @@ function glossary_edit_entry($entry, $course, $cm, $glossary, $context) {
     }
     return $entry;
 }
+
+/**
+ * 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);
+
+    $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';
+    }
+    $updates->entries = $DB->count_records_select('glossary_entries', $select, $params) > 0;
+
+    return $updates;
+}
index 973ef14..a7bdb71 100644 (file)
@@ -444,3 +444,17 @@ function imscp_view($imscp, $course, $cm, $context) {
     $completion = new completion_info($course);
     $completion->set_module_viewed($cm);
 }
+
+/**
+ * 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 imscp_check_updates_since(cm_info $cm, $from, $filter = array()) {
+    $updates = course_check_module_updates_since($cm, $from, array('content'), $filter);
+    return $updates;
+}
index 49837b9..ad7289c 100644 (file)
@@ -324,3 +324,17 @@ function label_generate_resized_image(stored_file $file, $maxwidth, $maxheight)
         return $img;
     }
 }
+
+/**
+ * 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 label_check_updates_since(cm_info $cm, $from, $filter = array()) {
+    $updates = course_check_module_updates_since($cm, $from, array(), $filter);
+    return $updates;
+}
index 2df8030..732a0bd 100644 (file)
@@ -560,3 +560,25 @@ function lti_view($lti, $course, $cm, $context) {
     $completion = new completion_info($course);
     $completion->set_module_viewed($cm);
 }
+
+/**
+ * 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.
+    $select = 'ltiid = :id AND userid = :userid AND (datesubmitted > :since1 OR dateupdated > :since2)';
+    $params = array('id' => $cm->instance, 'userid' => $USER->id, 'since1' => $from, 'since2' => $from);
+    $updates->submissions = $DB->count_records_select('lti_submission', $select, $params) > 0;
+
+    return $updates;
+}
index 66ac9f5..f389010 100644 (file)
@@ -508,3 +508,17 @@ function page_view($page, $course, $cm, $context) {
     $completion = new completion_info($course);
     $completion->set_module_viewed($cm);
 }
+
+/**
+ * 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 page_check_updates_since(cm_info $cm, $from, $filter = array()) {
+    $updates = course_check_module_updates_since($cm, $from, array('content'), $filter);
+    return $updates;
+}
index ef2a706..bae7159 100644 (file)
@@ -1908,3 +1908,42 @@ function quiz_get_completion_state($course, $cm, $userid, $type) {
     }
     return false;
 }
+
+/**
+ * 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.
+    $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;
+        $updates->questions = $DB->count_records_select('question', $select, $params) > 0;
+    } else {
+        $updates->questions = false;
+    }
+
+    // Check for new attempts or grades.
+    $select = 'quiz = ? AND userid = ? AND timemodified > ?';
+    $params = array($cm->instance, $USER->id, $from);
+    $updates->attempts = $DB->count_records_select('quiz_attempts', $select, $params) > 0;
+    $updates->grades = $DB->count_records_select('quiz_grades', $select, $params) > 0;
+
+    return $updates;
+}
index 6296f2e..6100a5c 100644 (file)
@@ -519,3 +519,17 @@ function resource_view($resource, $course, $cm, $context) {
     $completion = new completion_info($course);
     $completion->set_module_viewed($cm);
 }
+
+/**
+ * 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 resource_check_updates_since(cm_info $cm, $from, $filter = array()) {
+    $updates = course_check_module_updates_since($cm, $from, array('content'), $filter);
+    return $updates;
+}
index f2c1d9f..5269c55 100644 (file)
@@ -1494,3 +1494,30 @@ function scorm_view($scorm, $course, $cm, $context) {
     $event->add_record_snapshot('scorm', $scorm);
     $event->trigger();
 }
+
+/**
+ * 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);
+
+    $select = 'scormid = ? AND userid = ? AND timemodified > ?';
+    $params = array($scorm->id, $USER->id, $from);
+    $updates->tracks = $DB->count_records_select('scorm_scoes_track', $select, $params) > 0;
+    return $updates;
+}
index a3e7756..ee84e05 100644 (file)
@@ -1050,3 +1050,27 @@ function survey_get_completion_state($course, $cm, $userid, $type) {
         return $type;
     }
 }
+
+/**
+ * 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);
+
+    $select = 'survey = ? AND userid = ? AND time > ?';
+    $params = array($cm->instance, $USER->id, $from);
+    $updates->tracks = $DB->count_records_select('survey_answers', $select, $params) > 0;
+    return $updates;
+}
index 09f1298..24549c5 100644 (file)
@@ -7,6 +7,8 @@ information provided here is intended especially for developers.
 * update_module_button() and core_renderer::update_module_button() have been deprecated and should not be used anymore.
   Activity modules should not add the edit module button, the link is already available in the Administration block.
   Themes can choose to display the link in the buttons row consistently for all module types.
+* New callback check_updates_since available. Check if the module has any update that affects the current user since the given time.
+  Please refer to mod/assign/lib.php, mod/forum/lib.php or mod/quiz/lib.php for sample code.
 
 === 3.1 ===
 
index 527b394..76b24d9 100644 (file)
@@ -351,3 +351,17 @@ function url_view($url, $course, $cm, $context) {
     $completion = new completion_info($course);
     $completion->set_module_viewed($cm);
 }
+
+/**
+ * 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 url_check_updates_since(cm_info $cm, $from, $filter = array()) {
+    $updates = course_check_module_updates_since($cm, $from, array('content'), $filter);
+    return $updates;
+}
index 6d236eb..55e376f 100644 (file)
@@ -739,3 +739,40 @@ function wiki_page_view($wiki, $page, $course, $cm, $context, $uid = null, $othe
     $completion = new completion_info($course);
     $completion->set_module_viewed($cm);
 }
+
+/**
+ * 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.
+    $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;
+        $updates->pages = $DB->count_records_select('wiki_pages', $select, $params) > 0;
+    } else {
+        $updates->pages = false;
+    }
+    return $updates;
+}