diff --git a/analytics/classes/manager.php b/analytics/classes/manager.php index 0fdbb3a95b0..4b0bcac480d 100644 --- a/analytics/classes/manager.php +++ b/analytics/classes/manager.php @@ -474,7 +474,7 @@ class manager { '\core_course\analytics\indicator\potential_social_breadth', '\core\analytics\indicator\any_access_after_end', '\core\analytics\indicator\any_access_before_start', - '\core\analytics\indicator\any_write_action', + '\core\analytics\indicator\any_write_action_in_course', '\core\analytics\indicator\read_actions', ); $indicators = array(); diff --git a/lang/en/moodle.php b/lang/en/moodle.php index 5af498bcaf4..71e29cd774b 100644 --- a/lang/en/moodle.php +++ b/lang/en/moodle.php @@ -1041,6 +1041,8 @@ $string['indicator:accessesbeforestart'] = 'Course accessed before start date'; $string['indicator:accessesbeforestart_help'] = 'This indicator reflects if the student accessed the course before the course start date.'; $string['indicator:anywrite'] = 'Any write action'; $string['indicator:anywrite_help'] = 'This indicator represents any write (submit) action taken by the student.'; +$string['indicator:anywriteincourse'] = 'Any write action in the course'; +$string['indicator:anywriteincourse_help'] = 'This indicator represents any write (submit) action taken by the student in any course activity.'; $string['indicator:completeduserprofile'] = 'User profile is completed'; $string['indicator:completeduserprofile_help'] = 'This indicator represents that the student has completed their user profile.'; $string['indicator:completionenabled'] = 'Completion tracking enabled'; diff --git a/lib/classes/analytics/indicator/any_write_action_in_course.php b/lib/classes/analytics/indicator/any_write_action_in_course.php new file mode 100644 index 00000000000..e9eab4ed49f --- /dev/null +++ b/lib/classes/analytics/indicator/any_write_action_in_course.php @@ -0,0 +1,101 @@ +. + +/** + * Write actions in a course indicator. + * + * @package core + * @copyright 2016 David Monllao {@link http://www.davidmonllao.com} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace core\analytics\indicator; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Write actions in a course indicator. + * + * @package core + * @copyright 2016 David Monllao {@link http://www.davidmonllao.com} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class any_write_action_in_course extends \core_analytics\local\indicator\binary { + + /** + * Returns the name. + * + * If there is a corresponding '_help' string this will be shown as well. + * + * @return \lang_string + */ + public static function get_name() : \lang_string { + return new \lang_string('indicator:anywriteincourse'); + } + + /** + * required_sample_data + * + * @return string[] + */ + public static function required_sample_data() { + // User is not required, calculate_sample can handle its absence. + return array('course'); + } + + /** + * calculate_sample + * + * @param int $sampleid + * @param string $sampleorigin + * @param int $starttime + * @param int $endtime + * @return float + */ + protected function calculate_sample($sampleid, $sampleorigin, $starttime = false, $endtime = false) { + global $DB; + + if (!$logstore = \core_analytics\manager::get_analytics_logstore()) { + throw new \coding_exception('No available log stores'); + } + + // Filter by context to use the logstore_standard_log db table index. + $course = $this->retrieve('course', $sampleid); + $select = "courseid = :courseid AND anonymous = :anonymous AND (crud = 'c' OR crud = 'u')"; + $params = array('courseid' => $course->id, 'anonymous' => '0'); + + if ($user = $this->retrieve('user', $sampleid)) { + $select .= " AND userid = :userid"; + $params['userid'] = $user->id; + } + + if ($starttime) { + $select .= " AND timecreated > :starttime"; + $params['starttime'] = $starttime; + } + if ($endtime) { + $select .= " AND timecreated <= :endtime"; + $params['endtime'] = $endtime; + } + + $nlogs = $logstore->get_events_select_count($select, $params); + if ($nlogs) { + return self::get_max_value(); + } else { + return self::get_min_value(); + } + } +} diff --git a/lib/tests/indicators_test.php b/lib/tests/indicators_test.php index 79b9478341d..45117665358 100644 --- a/lib/tests/indicators_test.php +++ b/lib/tests/indicators_test.php @@ -175,6 +175,61 @@ class core_analytics_indicators_testcase extends advanced_testcase { $this->assertEquals($indicator::get_max_value(), $values[$course1->id][0]); $this->assertEquals($indicator::get_min_value(), $values[$course2->id][0]); + // Test any write action in the course. + $course1 = $this->getDataGenerator()->create_course(); + $coursecontext1 = \context_course::instance($course1->id); + $activity1 = $this->getDataGenerator()->create_module('forum', array('course' => $course1->id)); + $activity1context = \context_module::instance($activity1->cmid); + $course2 = $this->getDataGenerator()->create_course(); + $coursecontext2 = \context_course::instance($course2->id); + $this->getDataGenerator()->enrol_user($user1->id, $course2->id); + + $indicator = new \core\analytics\indicator\any_write_action_in_course(); + + $sampleids = array($user1->id => $user1->id, $user2->id => $user2->id); + $data = array($user1->id => array( + 'context' => $coursecontext1, + 'course' => $course1, + 'user' => $user1 + )); + $data[$user2->id] = $data[$user1->id]; + $data[$user2->id]['user'] = $user2; + $indicator->add_sample_data($data); + + list($values, $unused) = $indicator->calculate($sampleids, 'user'); + $this->assertEquals($indicator::get_min_value(), $values[$user1->id][0]); + $this->assertEquals($indicator::get_min_value(), $values[$user2->id][0]); + + $beforecourseeventcreate = time(); + sleep(1); + + \logstore_standard\event\unittest_executed::create( + array('context' => $activity1context, 'userid' => $user1->id))->trigger(); + list($values, $unused) = $indicator->calculate($sampleids, 'user'); + $this->assertEquals($indicator::get_max_value(), $values[$user1->id][0]); + $this->assertEquals($indicator::get_min_value(), $values[$user2->id][0]); + + // Now try with course-level samples where user is not available. + $sampleids = array($course1->id => $course1->id, $course2->id => $course2->id); + $data = array( + $course1->id => array( + 'context' => $coursecontext1, + 'course' => $course1, + ), + $course2->id => array( + 'context' => $coursecontext2, + 'course' => $course2, + ) + ); + $indicator->clear_sample_data(); + $indicator->add_sample_data($data); + + // Limited by time to avoid previous logs interfering as other logs + // have been generated by the system. + list($values, $unused) = $indicator->calculate($sampleids, 'course', $beforecourseeventcreate); + $this->assertEquals($indicator::get_max_value(), $values[$course1->id][0]); + $this->assertEquals($indicator::get_min_value(), $values[$course2->id][0]); + // Test read actions. $course = $this->getDataGenerator()->create_course(); $coursecontext = \context_course::instance($course->id);