MDL-60388 analytics: Any write action looking at all contexts below course
authorDavid Monllao <davidm@moodle.com>
Tue, 10 Oct 2017 09:00:41 +0000 (11:00 +0200)
committerDavid Monllao <davidm@moodle.com>
Fri, 20 Oct 2017 11:20:46 +0000 (13:20 +0200)
analytics/classes/manager.php
lang/en/moodle.php
lib/classes/analytics/indicator/any_write_action_in_course.php [new file with mode: 0644]
lib/tests/indicators_test.php

index 0fdbb3a..4b0bcac 100644 (file)
@@ -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();
index ffcbbe4..1c5ee25 100644 (file)
@@ -1038,6 +1038,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 (file)
index 0000000..e9eab4e
--- /dev/null
@@ -0,0 +1,101 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * 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();
+        }
+    }
+}
index 79b9478..4511766 100644 (file)
@@ -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);