Skip to content
This repository has been archived by the owner on Dec 13, 2024. It is now read-only.

Commit

Permalink
Merge branch 'MDL-59153_master' of git://github.com/dmonllao/moodle
Browse files Browse the repository at this point in the history
  • Loading branch information
danpoltawski authored and David Monllao committed Sep 7, 2017
2 parents 30375ee + 1d5b1d0 commit 3c4675a
Show file tree
Hide file tree
Showing 19 changed files with 604 additions and 85 deletions.
4 changes: 3 additions & 1 deletion admin/tool/analytics/classes/output/models_list.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ public function export_for_template(\renderer_base $output) {
}

// Model predictions list.
if ($model->uses_insights()) {
if (!$model->is_enabled()) {
$modeldata->noinsights = get_string('disabledmodel', 'analytics');
} else if ($model->uses_insights()) {
$predictioncontexts = $model->get_predictions_contexts();
if ($predictioncontexts) {

Expand Down
19 changes: 19 additions & 0 deletions analytics/classes/model.php
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,12 @@ public function update($enabled, $indicators = false, $timesplittingid = '') {

// Reset trained flag.
$this->model->trained = 0;

} else if ($this->model->enabled != $enabled) {
// We purge the cached contexts with insights as some will not be visible anymore.
$this->purge_insights_cache();
}

$this->model->enabled = intval($enabled);
$this->model->indicators = $indicatorsstr;
$this->model->timesplitting = $timesplittingid;
Expand Down Expand Up @@ -971,6 +976,13 @@ public function enable($timesplittingid = false) {
$this->model->timesplitting = $timesplittingid;
$this->model->version = $now;
}

// Purge pages with insights as this may change things.
if ($timesplittingid && $timesplittingid !== $this->model->timesplitting ||
$this->model->enabled != 1) {
$this->purge_insights_cache();
}

$this->model->enabled = 1;
$this->model->timemodified = $now;

Expand Down Expand Up @@ -1375,6 +1387,13 @@ private function clear_model() {

// We don't expect people to clear models regularly and the cost of filling the cache is
// 1 db read per context.
$this->purge_insights_cache();
}

/**
* Purges the insights cache.
*/
private function purge_insights_cache() {
$cache = \cache::make('core', 'contextwithinsights');
$cache->purge();
}
Expand Down
2 changes: 1 addition & 1 deletion lang/en/analytics.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
$string['analyticssettings'] = 'Analytics settings';
$string['coursetoolong'] = 'The course is too long';
$string['enabledtimesplittings'] = 'Time splitting methods';
$string['disabledmodel'] = 'Disabled model';
$string['erroralreadypredict'] = '{$a} file has already been used to predict';
$string['errorcannotreaddataset'] = 'Dataset file {$a} can not be read';
$string['errorcannotwritedataset'] = 'Dataset file {$a} can not be written';
Expand All @@ -53,7 +54,6 @@
$string['errorunknownaction'] = 'Unknown action';
$string['eventpredictionactionstarted'] = 'Prediction action started';
$string['insightmessagesubject'] = 'New insight for "{$a->contextname}": {$a->insightname}';
$string['insightinfo'] = '{$a->insightname} - {$a->contextname}';
$string['insightinfomessage'] = 'The system generated some insights for you: {$a}';
$string['insightinfomessagehtml'] = 'The system generated some insights for you: <a href="{$a}">{$a}</a>.';
$string['invalidtimesplitting'] = 'Model with id {$a} needs a time splitting method before it can be used to train';
Expand Down
4 changes: 2 additions & 2 deletions report/insights/action.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@
}

$modelready = $model->is_enabled() && $model->is_trained() && $model->predictions_exist($context);
if (!$modelready && !has_capability('moodle/analytics:managemodels', $context)) {
if (!$modelready) {

$PAGE->set_pagelayout('report');

// We don't want to disclose the name of the model if it has not been enabled.
$PAGE->set_title($context->get_context_name());
$PAGE->set_heading($context->get_context_name());
echo $OUTPUT->header();
echo $OUTPUT->notification(get_string('disabledmodel', 'analytics'), \core\output\notification::NOTIFY_INFO);
echo $OUTPUT->notification(get_string('disabledmodel', 'report_insights'), \core\output\notification::NOTIFY_INFO);
echo $OUTPUT->footer();
exit(0);
}
Expand Down
44 changes: 33 additions & 11 deletions report/insights/classes/output/insight.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,20 +73,22 @@ public function __construct(\core_analytics\prediction $prediction, \core_analyt
public function export_for_template(\renderer_base $output) {

$data = new \stdClass();
$data->insightname = format_string($this->model->get_target()->get_name());

// Sample info (determined by the analyser).
list($data->sampledescription, $samplerenderable) = $this->model->prediction_sample_description($this->prediction);

// Sampleimage is a renderable we should pass it to HTML.
if ($samplerenderable) {
$data->samplelink = $output->render($samplerenderable);
$data->sampleimage = $output->render($samplerenderable);
}

// Prediction info.
$predictedvalue = $this->prediction->get_prediction_data()->prediction;
$predictionid = $this->prediction->get_prediction_data()->id;
$data->predictiondisplayvalue = $this->model->get_target()->get_display_value($predictedvalue);
$data->predictionstyle = $this->get_calculation_style($this->model->get_target(), $predictedvalue);
list($data->style, $data->outcomeicon) = $this->get_calculation_display($this->model->get_target(), $predictedvalue,
$output);

$actions = $this->model->get_target()->prediction_actions($this->prediction, $this->includedetailsaction);
if ($actions) {
Expand Down Expand Up @@ -122,46 +124,66 @@ public function export_for_template(\renderer_base $output) {
$obj = new \stdClass();
$obj->name = call_user_func(array($calculation->indicator, 'get_name'));
$obj->displayvalue = $calculation->indicator->get_display_value($calculation->value, $calculation->subtype);
$obj->style = $this->get_calculation_style($calculation->indicator, $calculation->value, $calculation->subtype);
list($obj->style, $obj->outcomeicon) = $this->get_calculation_display($calculation->indicator, $calculation->value,
$output, $calculation->subtype);

$data->calculations[] = $obj;
}

if (empty($data->calculations)) {
$data->nocalculations = (object)array(
'message' => get_string('nodetailsavailable', 'report_insights'),
'closebutton' => false
);
}

return $data;
}

/**
* Returns a CSS class from the calculated value outcome.
* Returns display info for the calculated value outcome.
*
* @param \core_analytics\calculable $calculable
* @param float $value
* @param \renderer_base $output
* @param string|false $subtype
* @return string
* @return array The style as 'success', 'info', 'warning' or 'danger' and pix_icon
*/
protected function get_calculation_style(\core_analytics\calculable $calculable, $value, $subtype = false) {
protected function get_calculation_display(\core_analytics\calculable $calculable, $value, $output, $subtype = false) {
$outcome = $calculable->get_calculation_outcome($value, $subtype);
switch ($outcome) {
case \core_analytics\calculable::OUTCOME_NEUTRAL:
$style = '';
$text = get_string('outcomeneutral', 'report_insights');
$icon = 't/check';
break;
case \core_analytics\calculable::OUTCOME_VERY_POSITIVE:
$style = 'alert alert-success';
$style = 'success';
$text = get_string('outcomeverypositive', 'report_insights');
$icon = 't/approve';
break;
case \core_analytics\calculable::OUTCOME_OK:
$style = 'alert alert-info';
$style = 'info';
$text = get_string('outcomeok', 'report_insights');
$icon = 't/check';
break;
case \core_analytics\calculable::OUTCOME_NEGATIVE:
$style = 'alert alert-warning';
$style = 'warning';
$text = get_string('outcomenegative', 'report_insights');
$icon = 'i/warning';
break;
case \core_analytics\calculable::OUTCOME_VERY_NEGATIVE:
$style = 'alert alert-danger';
$style = 'danger';
$text = get_string('outcomeverynegative', 'report_insights');
$icon = 'i/warning';
break;
default:
throw new \coding_exception('The outcome returned by ' . get_class($calculable) . '::get_calculation_outcome is ' .
'not one of the accepted values. Please use \core_analytics\calculable::OUTCOME_VERY_POSITIVE, ' .
'\core_analytics\calculable::OUTCOME_OK, \core_analytics\calculable::OUTCOME_NEGATIVE, ' .
'\core_analytics\calculable::OUTCOME_VERY_NEGATIVE or \core_analytics\calculable::OUTCOME_NEUTRAL');
}
return $style;
$icon = new \pix_icon($icon, $text);
return array($style, $icon->export_for_template($output));
}
}
2 changes: 2 additions & 0 deletions report/insights/classes/output/insights_list.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ public function export_for_template(\renderer_base $output) {
global $PAGE;

$data = new \stdClass();
$data->insightname = format_string($this->model->get_target()->get_name());

$total = 0;

if ($this->model->uses_insights()) {
Expand Down
2 changes: 1 addition & 1 deletion report/insights/classes/output/renderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public function render_model_disabled($insightinfo) {
$PAGE->set_heading($insightinfo->contextname);

$output = $OUTPUT->header();
$output .= $OUTPUT->notification(get_string('disabledmodel', 'analytics'), \core\output\notification::NOTIFY_INFO);
$output .= $OUTPUT->notification(get_string('disabledmodel', 'report_insights'), \core\output\notification::NOTIFY_INFO);
$output .= $OUTPUT->footer();

return $output;
Expand Down
27 changes: 22 additions & 5 deletions report/insights/insights.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/

require_once(__DIR__ . '/../../config.php');
require_once($CFG->libdir . '/adminlib.php');

$contextid = required_param('contextid', PARAM_INT);
$modelid = optional_param('modelid', false, PARAM_INT);
Expand Down Expand Up @@ -52,15 +53,32 @@
unset($othermodels[$modelid]);
}

// The URL in navigation only contains the contextid.
$params = array('contextid' => $contextid);
$url = new \moodle_url('/report/insights/insights.php', $params);
$navurl = new \moodle_url('/report/insights/insights.php', $params);

// This is the real page url, we need it to include the modelid so pagination and
// other stuff works as expected.
$url = clone $navurl;
if ($modelid) {
$url->param('modelid', $modelid);
}

$PAGE->set_url($url);
$PAGE->set_pagelayout('report');

if ($context->contextlevel === CONTEXT_SYSTEM) {
admin_externalpage_setup('reportinsights', '', null, '', array('pagelayout' => 'report'));
} else if ($context->contextlevel === CONTEXT_USER) {
$user = \core_user::get_user($context->instanceid, '*', MUST_EXIST);
$PAGE->navigation->extend_for_user($user);
$PAGE->add_report_nodes($user->id, array(
'name' => get_string('insights', 'report_insights'),
'url' => $url
));
}
$PAGE->navigation->override_active_url($navurl);

$renderer = $PAGE->get_renderer('report_insights');

// No models with insights available at this context level.
Expand All @@ -74,9 +92,8 @@
$insightinfo = new stdClass();
$insightinfo->contextname = $context->get_context_name();
$insightinfo->insightname = $model->get_target()->get_name();
$title = get_string('insightinfo', 'analytics', $insightinfo);

if (!$model->is_enabled() && !has_capability('moodle/analytics:managemodels', $context)) {
if (!$model->is_enabled()) {
echo $renderer->render_model_disabled($insightinfo);
exit(0);
}
Expand All @@ -86,8 +103,8 @@
exit(0);
}

$PAGE->set_title($title);
$PAGE->set_heading($title);
$PAGE->set_title($insightinfo->insightname);
$PAGE->set_heading($insightinfo->contextname);

echo $OUTPUT->header();

Expand Down
14 changes: 13 additions & 1 deletion report/insights/lang/en/report_insights.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,22 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/


$string['calculatedvalue'] = 'Calculated value';
$string['disabledmodel'] = 'Sorry, this model has been disabled by the administrator';
$string['indicator'] = 'Indicator';
$string['insightprediction'] = '{$a} prediction';
$string['insight'] = 'Insight';
$string['insights'] = 'Insights';
$string['outcome'] = 'Outcome';
$string['outcomenegative'] = 'Negative outcome';
$string['outcomeneutral'] = 'Neutral outcome';
$string['outcomeok'] = 'Ok outcome';
$string['outcomepositive'] = 'Positive outcome';
$string['outcomeverypositive'] = 'Very positive outcome';
$string['outcomeverynegative'] = 'Very negative outcome';
$string['pluginname'] = 'Insights';
$string['prediction'] = 'Prediction';
$string['predictioncalculations'] = 'Indicator calculations';
$string['predictiondetails'] = 'Prediction details';
$string['nodetailsavailable'] = 'No prediction details are relevant.';
$string['selectotherinsights'] = 'Select other insights...';
85 changes: 75 additions & 10 deletions report/insights/lib.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,85 @@ function report_insights_extend_navigation_course($navigation, $course, $context

if (has_capability('moodle/analytics:listinsights', $context)) {

$cache = \cache::make('core', 'contextwithinsights');
$modelids = $cache->get($context->id);
if ($modelids === false) {
// They will be full unless a model has been cleared.
$models = \core_analytics\manager::get_models_with_insights($context);
$modelids = array_keys($models);
$cache->set($context->id, $modelids);
$modelids = report_insights_context_insights($context);
if (!empty($modelids)) {
$url = new moodle_url('/report/insights/insights.php', array('contextid' => $context->id));
$node = navigation_node::create(get_string('insights', 'report_insights'), $url, navigation_node::TYPE_SETTING,
null, null, new pix_icon('i/report', get_string('insights', 'report_insights')));
$navigation->add_node($node);
}
}
}

/**
* Add nodes to myprofile page.
*
* @param \core_user\output\myprofile\tree $tree Tree object
* @param stdClass $user user object
* @param bool $iscurrentuser
* @param stdClass $course Course object
*
* @return bool
*/
function report_insights_myprofile_navigation(core_user\output\myprofile\tree $tree, $user, $iscurrentuser, $course) {

$context = \context_user::instance($user->id);
if (has_capability('moodle/analytics:listinsights', $context)) {

$modelids = report_insights_context_insights($context);
if (!empty($modelids)) {
$url = new moodle_url('/report/insights/insights.php', array('contextid' => $context->id));
$settingsnode = navigation_node::create(get_string('insights', 'report_insights'), $url, navigation_node::TYPE_SETTING,
null, null, new pix_icon('i/settings', ''));
$navigation->add_node($settingsnode);
$node = new core_user\output\myprofile\node('reports', 'insights', get_string('insights', 'report_insights'),
null, $url);
$tree->add_node($node);
}
}
}

/**
* Adds nodes to category navigation
*
* @param navigation_node $navigation The navigation node to extend
* @param context $context The context of the course
* @return void|null return null if we don't want to display the node.
*/
function report_insights_extend_navigation_category_settings($navigation, $context) {

if (has_capability('moodle/analytics:listinsights', $context)) {

$modelids = report_insights_context_insights($context);
if (!empty($modelids)) {
$url = new moodle_url('/report/insights/insights.php', array('contextid' => $context->id));

$node = navigation_node::create(
get_string('insights', 'report_insights'),
$url,
navigation_node::NODETYPE_LEAF,
null,
'insights',
new pix_icon('i/report', get_string('insights', 'report_insights'))
);

$navigation->add_node($node);
}
}
}

/**
* Returns the models that generated insights in the provided context.
*
* @param \context $context
* @return int[]
*/
function report_insights_context_insights(\context $context) {

$cache = \cache::make('core', 'contextwithinsights');
$modelids = $cache->get($context->id);
if ($modelids === false) {
// They will be full unless a model has been cleared.
$models = \core_analytics\manager::get_models_with_insights($context);
$modelids = array_keys($models);
$cache->set($context->id, $modelids);
}
return $modelids;
}
Loading

0 comments on commit 3c4675a

Please sign in to comment.