From e85c2f372bd38f9df4b4d50fe4958199c355d015 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Monlla=C3=B3?= Date: Thu, 14 Mar 2019 16:52:43 +0100 Subject: [PATCH] MDL-64783 analytics: Improvements to the insights system --- analytics/classes/local/target/base.php | 57 ++++++++++++++----- analytics/classes/local/target/binary.php | 2 +- analytics/classes/local/target/discrete.php | 2 +- analytics/classes/model.php | 2 +- analytics/classes/prediction_action.php | 14 ++--- .../tests/fixtures/test_target_shortname.php | 2 +- .../tests/fixtures/test_target_site_users.php | 2 +- .../fixtures/test_timesplitting_seconds.php | 1 + analytics/upgrade.txt | 1 + lang/en/analytics.php | 13 +++-- lang/en/moodle.php | 5 +- .../analytics/target/course_dropout.php | 11 ---- lib/classes/analytics/target/no_teaching.php | 21 +++---- report/insights/classes/output/insight.php | 20 +++++-- .../insights/classes/output/insights_list.php | 20 +++++-- report/insights/done.php | 30 ++++++++++ report/insights/insights.php | 16 ++++++ report/insights/lang/en/report_insights.php | 1 + .../templates/insight_details.mustache | 4 +- .../insights/templates/insights_list.mustache | 20 ++++--- .../target/upcoming_activities_due.php | 29 +++++++--- 21 files changed, 197 insertions(+), 76 deletions(-) create mode 100644 report/insights/done.php diff --git a/analytics/classes/local/target/base.php b/analytics/classes/local/target/base.php index d6369dc5a9f..65e68b4c6dd 100644 --- a/analytics/classes/local/target/base.php +++ b/analytics/classes/local/target/base.php @@ -122,12 +122,12 @@ abstract class base extends \core_analytics\calculable { if ($includedetailsaction) { - $predictionurl = new \moodle_url('/report/insights/prediction.php', - array('id' => $predictionid)); + $predictionurl = new \moodle_url('/report/insights/prediction.php', array('id' => $predictionid)); + $detailstext = $this->get_view_details_text(); $actions[] = new \core_analytics\prediction_action(\core_analytics\prediction::ACTION_PREDICTION_DETAILS, $prediction, - $predictionurl, new \pix_icon('t/preview', get_string('viewprediction', 'analytics')), - get_string('viewprediction', 'analytics')); + $predictionurl, new \pix_icon('t/preview', $detailstext), + $detailstext); } // Flag as fixed / solved. @@ -151,6 +151,25 @@ abstract class base extends \core_analytics\calculable { return $actions; } + /** + * Returns the view details link text. + * @return string + */ + private function get_view_details_text() { + if ($this->based_on_assumptions()) { + $analyserclass = $this->get_analyser_class(); + if ($analyserclass::one_sample_per_analysable()) { + $detailstext = get_string('viewinsightdetails', 'analytics'); + } else { + $detailstext = get_string('viewdetails', 'analytics'); + } + } else { + $detailstext = get_string('viewprediction', 'analytics'); + } + + return $detailstext; + } + /** * Callback to execute once a prediction has been returned from the predictions processor. * @@ -190,23 +209,34 @@ abstract class base extends \core_analytics\calculable { $coursecontext = \context_course::instance(SITEID); } - $predictionactions = $this->prediction_actions($prediction, false); + $predictionactions = $this->prediction_actions($prediction, true); - // TODO Proper language strings. - $fullmessage = ''; - $fullmessagehtml = ''; + $messageactions = ''; + $messageactionshtml = ''; $insighturl = null; foreach ($predictionactions as $action) { + $actionurl = $action->get_url(); + if (!$actionurl->get_param('forwardurl')) { + + $actiondoneurl = new \moodle_url('/report/insights/done.php'); + // Set the forward url to the 'done' script. + $actionurl->param('forwardurl', $actiondoneurl->out(false)); + } if (empty($insighturl)) { // We use the primary action url as insight url so we logged that the user followed the provided link. - $insighturl = $action->get_action_url(); + $insighturl = $action->get_url(); } - $fullmessage .= PHP_EOL . $action->get_action_name() . ': ' . $action->get_action_url()->out(false); - $fullmessagehtml .= '
' . $action->get_action_name() . ': ' . $action->get_action_url()->out(); + $messageactions .= $action->get_text() . ': ' . $action->get_url()->out(false) . PHP_EOL; + $messageactionshtml .= '' . + $action->get_text() . ''; } + $fullmessage = get_string('insightinfomessageprediction', 'analytics', $messageactions); + $fullmessagehtml = get_string('insightinfomessagepredictionhtml', 'analytics', $messageactionshtml); + foreach ($users as $user) { - $this->generate_insight_notification($user, $subject, $insighturl, $coursecontext, $fullmessage, $fullmessagehtml); + $this->generate_insight_notification($user, $subject, $insighturl, $coursecontext, + $fullmessage, $fullmessagehtml); } } @@ -225,7 +255,8 @@ abstract class base extends \core_analytics\calculable { $insighturl = $this->get_insight_context_url($modelid, $context); $fullmessage = get_string('insightinfomessage', 'analytics', $insighturl->out(false)); $fullmessagehtml = get_string('insightinfomessagehtml', 'analytics', $insighturl->out()); - $this->generate_insight_notification($user, $subject, $insighturl, $coursecontext, $fullmessage, $fullmessagehtml); + $this->generate_insight_notification($user, $subject, $insighturl, $coursecontext, + $fullmessage, $fullmessagehtml); } } } diff --git a/analytics/classes/local/target/binary.php b/analytics/classes/local/target/binary.php index f8c3b04dc1d..97e9a3f9bb5 100644 --- a/analytics/classes/local/target/binary.php +++ b/analytics/classes/local/target/binary.php @@ -60,7 +60,7 @@ abstract class binary extends discrete { * * @return array */ - protected function ignored_predicted_classes() { + public function ignored_predicted_classes() { // Zero-value class is usually ignored in binary classifiers. return array(0); } diff --git a/analytics/classes/local/target/discrete.php b/analytics/classes/local/target/discrete.php index 26044c7ac5d..8332ee324c5 100644 --- a/analytics/classes/local/target/discrete.php +++ b/analytics/classes/local/target/discrete.php @@ -145,7 +145,7 @@ abstract class discrete extends base { * * @return array List of values that will be ignored (array keys are ignored). */ - protected function ignored_predicted_classes() { + public function ignored_predicted_classes() { // Coding exception as this will only be called if this target have non-linear values. throw new \coding_exception('Overwrite ignored_predicted_classes() and return an array with the classes that should not ' . 'trigger the callback'); diff --git a/analytics/classes/model.php b/analytics/classes/model.php index 492bdd9e930..efa5e090353 100644 --- a/analytics/classes/model.php +++ b/analytics/classes/model.php @@ -916,7 +916,7 @@ class model { return $prediction; }, $predictionrecords); } else { - $predictions = false; + $predictions = []; } $this->get_target()->generate_insight_notifications($this->model->id, $samplecontexts, $predictions); diff --git a/analytics/classes/prediction_action.php b/analytics/classes/prediction_action.php index c06b8835647..6f3ee338e13 100644 --- a/analytics/classes/prediction_action.php +++ b/analytics/classes/prediction_action.php @@ -43,7 +43,7 @@ class prediction_action { /** * @var \moodle_url */ - protected $actionurl = null; + protected $url = null; /** * @var \action_menu_link @@ -55,7 +55,7 @@ class prediction_action { * * @param string $actionname They should match a-zA-Z_0-9-, as we apply a PARAM_ALPHANUMEXT filter * @param \core_analytics\prediction $prediction - * @param \moodle_url $actionurl + * @param \moodle_url $actionurl The final URL where the user should be forwarded. * @param \pix_icon $icon Link icon * @param string $text Link text * @param bool $primary Primary button or secondary. @@ -71,12 +71,12 @@ class prediction_action { // We want to track how effective are our suggested actions, we pass users through a script that will log these actions. $params = array('action' => $this->actionname, 'predictionid' => $prediction->get_prediction_data()->id, 'forwardurl' => $actionurl->out(false)); - $this->actionurl = new \moodle_url('/report/insights/action.php', $params); + $this->url = new \moodle_url('/report/insights/action.php', $params); if ($primary === false) { - $this->actionlink = new \action_menu_link_secondary($this->actionurl, $icon, $this->text, $attributes); + $this->actionlink = new \action_menu_link_secondary($this->url, $icon, $this->text, $attributes); } else { - $this->actionlink = new \action_menu_link_primary($this->actionurl, $icon, $this->text, $attributes); + $this->actionlink = new \action_menu_link_primary($this->url, $icon, $this->text, $attributes); } } @@ -94,8 +94,8 @@ class prediction_action { * * @return \moodle_url */ - public function get_action_url() { - return $this->actionurl; + public function get_url() { + return $this->url; } /** diff --git a/analytics/tests/fixtures/test_target_shortname.php b/analytics/tests/fixtures/test_target_shortname.php index bd3be06f034..6e9a71560ef 100644 --- a/analytics/tests/fixtures/test_target_shortname.php +++ b/analytics/tests/fixtures/test_target_shortname.php @@ -87,7 +87,7 @@ class test_target_shortname extends \core_analytics\local\target\binary { * We don't want to discard results. * @return array */ - protected function ignored_predicted_classes() { + public function ignored_predicted_classes() { return array(); } diff --git a/analytics/tests/fixtures/test_target_site_users.php b/analytics/tests/fixtures/test_target_site_users.php index 6f8b30b03b7..e78cbf584c0 100644 --- a/analytics/tests/fixtures/test_target_site_users.php +++ b/analytics/tests/fixtures/test_target_site_users.php @@ -89,7 +89,7 @@ class test_target_site_users extends \core_analytics\local\target\binary { * We don't want to discard results. * @return array */ - protected function ignored_predicted_classes() { + public function ignored_predicted_classes() { return array(); } diff --git a/analytics/tests/fixtures/test_timesplitting_seconds.php b/analytics/tests/fixtures/test_timesplitting_seconds.php index 46f789f77c5..e4b4f70423c 100644 --- a/analytics/tests/fixtures/test_timesplitting_seconds.php +++ b/analytics/tests/fixtures/test_timesplitting_seconds.php @@ -34,6 +34,7 @@ defined('MOODLE_INTERNAL') || die(); class test_timesplitting_seconds extends \core_analytics\local\time_splitting\periodic { /** + * Every second. * @return \DateInterval */ public function periodicity() { diff --git a/analytics/upgrade.txt b/analytics/upgrade.txt index a761e0f70ab..af47e4a2167 100644 --- a/analytics/upgrade.txt +++ b/analytics/upgrade.txt @@ -27,6 +27,7 @@ information provided here is intended especially for developers. * Analysers can overwrite a new one_sample_per_analysable method if the analysables they use only have one sample. The insights generated by models will then include the suggested actions in the notification. +* The visibility of target's ignored_predicted_classes method must now be public. === 3.5 === diff --git a/lang/en/analytics.php b/lang/en/analytics.php index ae39824dca5..2b6c17599ef 100644 --- a/lang/en/analytics.php +++ b/lang/en/analytics.php @@ -68,10 +68,12 @@ $string['eventpredictionactionstarted'] = 'Prediction process started'; $string['eventinsightsviewed'] = 'Insights viewed'; $string['fixedack'] = 'Acknowledged'; $string['insightmessagesubject'] = 'New insight for "{$a->contextname}": {$a->insightname}'; -$string['insightinfomessage'] = 'The system generated some insights for you: {$a}'; -$string['insightinfomessagehtml'] = 'The system generated some insights for you: {$a}.'; -$string['insightinfomessageprediction'] = 'The system generated some insights for you: {$a}'; -$string['insightinfomessagepredictionhtml'] = 'The system generated some insights for you: {$a}.'; +$string['insightinfomessage'] = 'The system generated an insight for you: {$a}'; +$string['insightinfomessagehtml'] = 'The system generated an insight for you.

View insight'; +$string['insightinfomessageprediction'] = 'Some suggested actions you could perform: + +{$a}'; +$string['insightinfomessagepredictionhtml'] = 'Some suggested actions you could perform:

{$a}'; $string['invalidtimesplitting'] = 'Model with ID {$a} needs a time-splitting method before it can be used to train.'; $string['invalidanalysablefortimesplitting'] = 'It cannot be analysed using {$a} time-splitting method.'; $string['nocourses'] = 'No courses to analyse'; @@ -126,4 +128,7 @@ $string['successfullyanalysed'] = 'Successfully analysed'; $string['timesplittingmethod'] = 'Time-splitting method'; $string['timesplittingmethod_help'] = 'The time-splitting method is what defines when the system will calculate predictions and the portion of activity logs that will be considered for those predictions. E.g. they can divide the course duration in parts and generate a prediction at the end of these parts.'; $string['timesplittingmethod_link'] = 'Time_splitting_methods'; +$string['viewdetails'] = 'View details'; +$string['viewinsight'] = 'View insight'; +$string['viewinsightdetails'] = 'View insight details'; $string['viewprediction'] = 'View prediction details'; diff --git a/lang/en/moodle.php b/lang/en/moodle.php index be0d3655edf..1950c26a5ed 100644 --- a/lang/en/moodle.php +++ b/lang/en/moodle.php @@ -886,6 +886,7 @@ $string['general'] = 'General'; $string['geolocation'] = 'latitude - longitude'; $string['gettheselogs'] = 'Get these logs'; $string['go'] = 'Go'; +$string['gotodashboard'] = 'Go to Dashboard'; $string['gpl'] = 'Copyright (C) 1999 onwards Martin Dougiamas (http://moodle.com) This program is free software; you can redistribute it and/or modify @@ -1430,6 +1431,7 @@ $string['nosuchemail'] = 'No such email address'; $string['notavailable'] = 'Not available'; $string['notavailablecourse'] = '{$a} is not available'; $string['noteachersyet'] = 'No teachers in this course yet'; +$string['noteachingupcomingcourses'] = 'Upcoming courses have no teachers or students'; $string['notenrolled'] = '{$a} is not enrolled in this course.'; $string['notenrolledprofile'] = 'This profile is not available because this user is not enrolled in this course.'; $string['noteusercannotrolldatesoncontext'] = 'Note: The ability to roll dates when restoring this backup has been disabled because you lack the required permissions.'; @@ -1949,6 +1951,7 @@ $string['stringsnotset'] = 'The following strings are not defined in {$a}'; $string['studentnotallowed'] = 'Sorry, but you can not enter this course as \'{$a}\''; $string['students'] = 'Students'; $string['studentsandteachers'] = 'Students and teachers'; +$string['studentsatriskincourse'] = 'Students at risk of dropping out in {$a} course'; $string['subcategories'] = 'Subcategories'; $string['subcategory'] = 'Subcategory'; $string['subcategoryof'] = 'Subcategory of {$a}'; @@ -2147,7 +2150,6 @@ $string['view'] = 'View'; $string['viewing'] = 'Viewing:'; $string['viewallcourses'] = 'View all courses'; $string['viewallcoursescategories'] = 'View all courses and categories'; -$string['viewdashboard'] = 'View dashboard'; $string['viewmore'] = 'View more'; $string['viewallsubcategories'] = 'View all subcategories'; $string['viewfileinpopup'] = 'View file in a popup window'; @@ -2214,6 +2216,7 @@ $string['years'] = 'years'; $string['yes'] = 'Yes'; $string['youareabouttocreatezip'] = 'You are about to create a zip file containing'; $string['youaregoingtorestorefrom'] = 'You are about to start the restore process for'; +$string['youhaveupcomingactivitiesdue'] = 'You have upcoming activities due'; $string['youneedtoenrol'] = 'To perform that action you need to enrol in this course.'; $string['yourlastlogin'] = 'Your last login was'; $string['yourself'] = 'yourself'; diff --git a/lib/classes/analytics/target/course_dropout.php b/lib/classes/analytics/target/course_dropout.php index 9a7cfd867eb..170602d4ca5 100644 --- a/lib/classes/analytics/target/course_dropout.php +++ b/lib/classes/analytics/target/course_dropout.php @@ -63,17 +63,6 @@ class course_dropout extends \core\analytics\target\course_enrolments { ); } - /** - * Returns the predicted classes that will be ignored. - * - * Overwriten because we are also interested in knowing when the student is far from the risk of dropping out. - * - * @return array - */ - protected function ignored_predicted_classes() { - return array(); - } - /** * Discards courses that are not yet ready to be used for training or prediction. * diff --git a/lib/classes/analytics/target/no_teaching.php b/lib/classes/analytics/target/no_teaching.php index f4b1352712c..a9e50103643 100644 --- a/lib/classes/analytics/target/no_teaching.php +++ b/lib/classes/analytics/target/no_teaching.php @@ -55,6 +55,17 @@ class no_teaching extends \core_analytics\local\target\binary { return new \lang_string('target:noteachingactivity'); } + /** + * Overwritten to show a simpler language string. + * + * @param int $modelid + * @param \context $context + * @return string + */ + public function get_insight_subject(int $modelid, \context $context) { + return get_string('noteachingupcomingcourses'); + } + /** * prediction_actions * @@ -103,16 +114,6 @@ class no_teaching extends \core_analytics\local\target\binary { ); } - /** - * Returns the predicted classes that will be ignored. - * - * @return array - */ - protected function ignored_predicted_classes() { - // No need to list the course if there is teaching activity. - return array(0); - } - /** * get_analyser_class * diff --git a/report/insights/classes/output/insight.php b/report/insights/classes/output/insight.php index d0ffa6e2114..c424e940faa 100644 --- a/report/insights/classes/output/insight.php +++ b/report/insights/classes/output/insight.php @@ -74,8 +74,20 @@ class insight implements \renderable, \templatable { // Get the prediction data. $predictiondata = $this->prediction->get_prediction_data(); + $target = $this->model->get_target(); + $data = new \stdClass(); - $data->insightname = format_string($this->model->get_target()->get_name()); + $data->insightname = format_string($target->get_name()); + + $data->showpredictionheading = true; + if (!$target->is_linear()) { + $nclasses = count($target::get_classes()); + $nignoredclasses = count($target->ignored_predicted_classes()); + if ($nclasses - $nignoredclasses <= 1) { + // Hide the prediction heading if there is only 1 class displayed. Otherwise it is redundant with the insight name. + $data->showpredictionheading = false; + } + } // Get the details. $data->timecreated = userdate($predictiondata->timecreated); @@ -99,11 +111,11 @@ class insight implements \renderable, \templatable { // Prediction info. $predictedvalue = $predictiondata->prediction; $predictionid = $predictiondata->id; - $data->predictiondisplayvalue = $this->model->get_target()->get_display_value($predictedvalue); - list($data->style, $data->outcomeicon) = self::get_calculation_display($this->model->get_target(), + $data->predictiondisplayvalue = $target->get_display_value($predictedvalue); + list($data->style, $data->outcomeicon) = self::get_calculation_display($target, floatval($predictedvalue), $output); - $actions = $this->model->get_target()->prediction_actions($this->prediction, $this->includedetailsaction); + $actions = $target->prediction_actions($this->prediction, $this->includedetailsaction); if ($actions) { $actionsmenu = new \action_menu(); $actionsmenu->set_menu_trigger(get_string('actions')); diff --git a/report/insights/classes/output/insights_list.php b/report/insights/classes/output/insights_list.php index 1ef320e9963..821c867d85c 100644 --- a/report/insights/classes/output/insights_list.php +++ b/report/insights/classes/output/insights_list.php @@ -87,8 +87,20 @@ class insights_list implements \renderable, \templatable { public function export_for_template(\renderer_base $output) { global $PAGE; + $target = $this->model->get_target(); + $data = new \stdClass(); - $data->insightname = format_string($this->model->get_target()->get_name()); + $data->insightname = format_string($target->get_name()); + + $data->showpredictionheading = true; + if (!$target->is_linear()) { + $nclasses = count($target::get_classes()); + $nignoredclasses = count($target->ignored_predicted_classes()); + if ($nclasses - $nignoredclasses <= 1) { + // Hide the prediction heading if there is only 1 class displayed. Otherwise it is redundant with the insight name. + $data->showpredictionheading = false; + } + } $total = 0; @@ -112,9 +124,9 @@ class insights_list implements \renderable, \templatable { // Only need to fill this data once. if (!isset($predictionvalues[$predictedvalue])) { $preddata = array(); - $preddata['predictiondisplayvalue'] = $this->model->get_target()->get_display_value($predictedvalue); + $preddata['predictiondisplayvalue'] = $target->get_display_value($predictedvalue); list($preddata['style'], $preddata['outcomeicon']) = - insight::get_calculation_display($this->model->get_target(), floatval($predictedvalue), $output); + insight::get_calculation_display($target, floatval($predictedvalue), $output); $predictionvalues[$predictedvalue] = $preddata; } @@ -123,7 +135,7 @@ class insights_list implements \renderable, \templatable { } // Order predicted values. - if ($this->model->get_target()->is_linear()) { + if ($target->is_linear()) { // During regression what we will be interested on most of the time is in low values so let's show them first. ksort($predictionvalues); } else { diff --git a/report/insights/done.php b/report/insights/done.php new file mode 100644 index 00000000000..f21dfe3e9d2 --- /dev/null +++ b/report/insights/done.php @@ -0,0 +1,30 @@ +. + +/** + * Forwards the user to the action they selected. + * + * @package report_insights + * @copyright 2017 David Monllao {@link http://www.davidmonllao.com} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require_once(__DIR__ . '/../../config.php'); + +require_login(); + +$url = new \moodle_url('/'); +redirect($url, get_string('actionsaved', 'report_insights'), null, \core\output\notification::NOTIFY_SUCCESS); diff --git a/report/insights/insights.php b/report/insights/insights.php index 452f9d9e6bd..499041233b0 100644 --- a/report/insights/insights.php +++ b/report/insights/insights.php @@ -106,6 +106,22 @@ if (!$model->uses_insights()) { $PAGE->set_title($insightinfo->insightname); $PAGE->set_heading($insightinfo->contextname); +// Some models generate one single prediction per context. We can directly show the prediction details in this case. +if ($model->get_analyser()::one_sample_per_analysable()) { + + // Param $perpage to 2 so we can detect if this model's analyser is using one_sample_per_analysable incorrectly. + $predictionsdata = $model->get_predictions($context, true, false, 2); + if ($predictionsdata) { + list($total, $predictions) = $predictionsdata; + if ($total > 1) { + throw new \coding_exception('This model\'s analyser processed more than one sample for a single analysable element.' . + 'Therefore, the analyser\'s one_sample_per_analysable() method should return false.'); + } + $prediction = reset($predictions); + $redirecturl = new \moodle_url('/report/insights/prediction.php', ['id' => $prediction->get_prediction_data()->id]); + redirect($redirecturl); + } +} echo $OUTPUT->header(); $renderable = new \report_insights\output\insights_list($model, $context, $othermodels, $page, $perpage); diff --git a/report/insights/lang/en/report_insights.php b/report/insights/lang/en/report_insights.php index 2051e30ee65..e21e8dbf31a 100644 --- a/report/insights/lang/en/report_insights.php +++ b/report/insights/lang/en/report_insights.php @@ -22,6 +22,7 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +$string['actionsaved'] = 'Your action has been saved.'; $string['calculatedvalue'] = 'Calculated value'; $string['disabledmodel'] = 'Sorry, this model has been disabled by the administrator'; $string['indicator'] = 'Indicator'; diff --git a/report/insights/templates/insight_details.mustache b/report/insights/templates/insight_details.mustache index 3b59962adea..ad61ef1b94a 100644 --- a/report/insights/templates/insight_details.mustache +++ b/report/insights/templates/insight_details.mustache @@ -75,7 +75,8 @@

{{#str}}insightprediction, report_insights, {{insightname}} {{/str}}

- + {{/showpredicionheading}} diff --git a/report/insights/templates/insights_list.mustache b/report/insights/templates/insights_list.mustache index c2db15eed44..5f8da0c1588 100644 --- a/report/insights/templates/insights_list.mustache +++ b/report/insights/templates/insights_list.mustache @@ -87,15 +87,17 @@ {{{ pagingbar }}} {{#predictions}}
+ {{#showpredicionheading}} + {{#str}}prediction, report_insights{{/str}}: {{#outcomeicon}} @@ -84,6 +85,7 @@ {{predictiondisplayvalue}}
{{#str}}name{{/str}}
- + {{#showpredicionheading}} + + {{/showpredicionheading}} diff --git a/user/classes/analytics/target/upcoming_activities_due.php b/user/classes/analytics/target/upcoming_activities_due.php index 7670d18083f..39383356e5a 100644 --- a/user/classes/analytics/target/upcoming_activities_due.php +++ b/user/classes/analytics/target/upcoming_activities_due.php @@ -57,6 +57,17 @@ class upcoming_activities_due extends \core_analytics\local\target\binary { return new \lang_string('target:upcomingactivitiesdue'); } + /** + * Overwritten to show a simpler language string. + * + * @param int $modelid + * @param \context $context + * @return string + */ + protected function get_insight_subject(int $modelid, \context $context) { + return get_string('youhaveupcomingactivitiesdue'); + } + /** * classes_description * @@ -74,7 +85,7 @@ class upcoming_activities_due extends \core_analytics\local\target\binary { * * @return array */ - protected function ignored_predicted_classes() { + public function ignored_predicted_classes() { // No need to process users without upcoming activities due. return array(0); } @@ -142,15 +153,19 @@ class upcoming_activities_due extends \core_analytics\local\target\binary { * @return \core_analytics\prediction_action[] */ public function prediction_actions(\core_analytics\prediction $prediction, $includedetailsaction = false) { - global $CFG; - - $url = new \moodle_url('/my/index.php'); - $pix = new \pix_icon('i/dashboard', get_string('viewdashboard')); - $action = new \core_analytics\prediction_action('viewupcoming', $prediction, - $url, $pix, get_string('viewdashboard')); + global $CFG, $USER; $parentactions = parent::prediction_actions($prediction, $includedetailsaction); + if ($USER->id != $prediction->get_prediction_data()->sampleid) { + return $parentactions; + } + + $url = new \moodle_url('/my/index.php'); + $pix = new \pix_icon('i/dashboard', get_string('gotodashboard')); + $action = new \core_analytics\prediction_action('viewupcoming', $prediction, + $url, $pix, get_string('gotodashboard')); + return array_merge([$action], $parentactions); } }
- {{#str}}prediction, report_insights{{/str}}: - - {{#outcomeicon}} - {{> core/pix_icon}} - {{/outcomeicon}} - {{predictiondisplayvalue}} - - + {{#str}}prediction, report_insights{{/str}}: + + {{#outcomeicon}} + {{> core/pix_icon}} + {{/outcomeicon}} + {{predictiondisplayvalue}} + +
{{#str}}name{{/str}}