From 5e4aab248f08714bb719b81044d810f803408672 Mon Sep 17 00:00:00 2001 From: Amaia Anabitarte Date: Tue, 16 Feb 2021 13:17:51 +0100 Subject: [PATCH] MDL-65553 core_analytics: Don't allow to flag predictions several times Even if a prediction is hidden from the report once is flagged, it can be flagged several times if the user visits detailed view via URL. We remove the checkbox to select a prediction and flag it once it has already been flagged. --- analytics/classes/prediction.php | 27 +++++++ analytics/tests/prediction_actions_test.php | 80 +++++++++++++++++++++ analytics/upgrade.txt | 5 ++ report/insights/classes/output/insight.php | 47 +++++++----- 4 files changed, 141 insertions(+), 18 deletions(-) diff --git a/analytics/classes/prediction.php b/analytics/classes/prediction.php index 6b0929e2707..3b0aced6c9d 100644 --- a/analytics/classes/prediction.php +++ b/analytics/classes/prediction.php @@ -178,6 +178,33 @@ class prediction { \core\event\prediction_action_started::create($eventdata)->trigger(); } + /** + * Get the executed actions. + * + * Actions could be filtered by actionname. + * + * @param array $actionnamefilter Limit the results obtained to this list of action names. + * @param int $userid the user id. Current user by default. + * @return array of actions. + */ + public function get_executed_actions(array $actionnamefilter = null, int $userid = 0): array { + global $USER, $DB; + + $conditions[] = "predictionid = :predictionid"; + $params['predictionid'] = $this->get_prediction_data()->id; + if (!$userid) { + $userid = $USER->id; + } + $conditions[] = "userid = :userid"; + $params['userid'] = $userid; + if ($actionnamefilter) { + list($actionsql, $actionparams) = $DB->get_in_or_equal($actionnamefilter, SQL_PARAMS_NAMED); + $conditions[] = "actionname $actionsql"; + $params = $params + $actionparams; + } + return $DB->get_records_select('analytics_prediction_actions', implode(' AND ', $conditions), $params); + } + /** * format_calculations * diff --git a/analytics/tests/prediction_actions_test.php b/analytics/tests/prediction_actions_test.php index f3768788e0f..e378f8ea938 100644 --- a/analytics/tests/prediction_actions_test.php +++ b/analytics/tests/prediction_actions_test.php @@ -112,6 +112,86 @@ class analytics_prediction_actions_testcase extends advanced_testcase { $this->assertEquals(2, $DB->count_records('analytics_prediction_actions')); } + /** + * Data provider for test_get_executed_actions. + * + * @return array + */ + public function execute_actions_provider(): array { + return [ + 'Empty actions with no filter' => [ + [], + [], + 0 + ], + 'Empty actions with filter' => [ + [], + [\core_analytics\prediction::ACTION_FIXED], + 0 + ], + 'Multiple actions with no filter' => [ + [ + \core_analytics\prediction::ACTION_FIXED, + \core_analytics\prediction::ACTION_FIXED, + \core_analytics\prediction::ACTION_INCORRECTLY_FLAGGED + ], + [], + 3 + ], + 'Multiple actions applying filter' => [ + [ + \core_analytics\prediction::ACTION_FIXED, + \core_analytics\prediction::ACTION_FIXED, + \core_analytics\prediction::ACTION_INCORRECTLY_FLAGGED + ], + [\core_analytics\prediction::ACTION_FIXED], + 2 + ], + 'Multiple actions not applying filter' => [ + [ + \core_analytics\prediction::ACTION_FIXED, + \core_analytics\prediction::ACTION_FIXED, + \core_analytics\prediction::ACTION_INCORRECTLY_FLAGGED + ], + [\core_analytics\prediction::ACTION_NOT_APPLICABLE], + 0 + ], + 'Multiple actions with multiple filter' => [ + [ + \core_analytics\prediction::ACTION_FIXED, + \core_analytics\prediction::ACTION_FIXED, + \core_analytics\prediction::ACTION_INCORRECTLY_FLAGGED + ], + [\core_analytics\prediction::ACTION_FIXED, \core_analytics\prediction::ACTION_INCORRECTLY_FLAGGED], + 3 + ], + ]; + } + + /** + * Tests for get_executed_actions() function. + * + * @dataProvider execute_actions_provider + * @param array $actionstoexecute An array of actions to execute + * @param array $actionnamefilter Actions to filter + * @param int $returned Number of actions returned + * + * @covers \core_analytics\prediction::get_executed_actions + */ + public function test_get_executed_actions(array $actionstoexecute, array $actionnamefilter, int $returned) { + + $this->setUser($this->teacher2); + list($ignored, $predictions) = $this->model->get_predictions($this->context, true); + $prediction = reset($predictions); + $target = $this->model->get_target(); + foreach($actionstoexecute as $action) { + $prediction->action_executed($action, $target); + } + + $filteredactions = $prediction->get_executed_actions($actionnamefilter); + $this->assertCount($returned, $filteredactions); + } + /** * test_get_predictions */ diff --git a/analytics/upgrade.txt b/analytics/upgrade.txt index 4773d4a793d..44f03c499b0 100644 --- a/analytics/upgrade.txt +++ b/analytics/upgrade.txt @@ -1,6 +1,11 @@ This files describes API changes in analytics sub system, information provided here is intended especially for developers. +=== 3.9.7 === + +* A new function get_executed_actions() has been added to \core_analytics\prediction class + to get all (or filtered by action name) executed actions of a prediction + === 3.8 === * "Time-splitting method" have been replaced by "Analysis interval" for the language strings that are diff --git a/report/insights/classes/output/insight.php b/report/insights/classes/output/insight.php index 4d5d045cf8e..183cac33f2b 100644 --- a/report/insights/classes/output/insight.php +++ b/report/insights/classes/output/insight.php @@ -24,6 +24,8 @@ namespace report_insights\output; +use core_analytics\prediction; + defined('MOODLE_INTERNAL') || die(); /** @@ -173,25 +175,34 @@ class insight implements \renderable, \templatable { ); } - // This is only rendered in report_insights/insight_details template. We need it to automatically enable - // the bulk action buttons in report/insights/prediction.php. - $toggleall = new \core\output\checkbox_toggleall('insight-bulk-action-' . $predictedvalue, true, [ - 'id' => 'id-toggle-all-' . $predictedvalue, - 'name' => 'toggle-all-' . $predictedvalue, - 'classes' => 'hidden', - 'label' => get_string('selectall'), - 'labelclasses' => 'sr-only', - 'checked' => false - ]); - $data->hiddencheckboxtoggleall = $output->render($toggleall); + // This is only rendered in report_insights/insight_details template for predictions with no action. + // We need it to automatically enable the bulk action buttons in report/insights/prediction.php. + $filtered = [ + \core_analytics\prediction::ACTION_FIXED, + \core_analytics\prediction::ACTION_NOT_USEFUL, + \core_analytics\prediction::ACTION_USEFUL, + \core_analytics\prediction::ACTION_NOT_APPLICABLE, + \core_analytics\prediction::ACTION_INCORRECTLY_FLAGGED, + ]; + if (!$this->prediction->get_executed_actions($filtered)) { + $toggleall = new \core\output\checkbox_toggleall('insight-bulk-action-' . $predictedvalue, true, [ + 'id' => 'id-toggle-all-' . $predictedvalue, + 'name' => 'toggle-all-' . $predictedvalue, + 'classes' => 'hidden', + 'label' => get_string('selectall'), + 'labelclasses' => 'sr-only', + 'checked' => false, + ]); + $data->hiddencheckboxtoggleall = $output->render($toggleall); - $toggle = new \core\output\checkbox_toggleall('insight-bulk-action-' . $predictedvalue, false, [ - 'id' => 'id-select-' . $data->predictionid, - 'name' => 'select-' . $data->predictionid, - 'label' => get_string('selectprediction', 'report_insights', $data->sampledescription), - 'labelclasses' => 'accesshide', - ]); - $data->toggleslave = $output->render($toggle); + $toggle = new \core\output\checkbox_toggleall('insight-bulk-action-' . $predictedvalue, false, [ + 'id' => 'id-select-' . $data->predictionid, + 'name' => 'select-' . $data->predictionid, + 'label' => get_string('selectprediction', 'report_insights', $data->sampledescription), + 'labelclasses' => 'accesshide', + ]); + $data->toggleslave = $output->render($toggle); + } return $data; }