diff --git a/admin/tool/lp/classes/task/sync_plans_from_template_cohorts_task.php b/admin/tool/lp/classes/task/sync_plans_from_template_cohorts_task.php index 39ccee5c1f0..358a4253f8f 100644 --- a/admin/tool/lp/classes/task/sync_plans_from_template_cohorts_task.php +++ b/admin/tool/lp/classes/task/sync_plans_from_template_cohorts_task.php @@ -52,7 +52,7 @@ class sync_plans_from_template_cohorts_task extends \core\task\scheduled_task { */ public function execute() { - $missingplans = template_cohort::get_all_missing_plans(); + $missingplans = template_cohort::get_all_missing_plans(self::get_last_run_time()); foreach ($missingplans as $missingplan) { foreach ($missingplan['userids'] as $userid) { diff --git a/admin/tool/lp/classes/template_cohort.php b/admin/tool/lp/classes/template_cohort.php index dd4afe0ca45..1f529771307 100644 --- a/admin/tool/lp/classes/template_cohort.php +++ b/admin/tool/lp/classes/template_cohort.php @@ -180,28 +180,36 @@ class template_cohort extends persistent { * Note that only cohorts associated with visible templates are considered, * as well as only templates with a due date in the future, or no due date. * + * @param int $lastruntime The last time the Cohort ssync task ran. * @param bool $unlinkedaremissing When true, unlinked plans are considered as missing. * @return array( array( * 'template' => \tool_lp\template, * 'userids' => array * )) */ - public static function get_all_missing_plans($unlinkedaremissing = false) { + public static function get_all_missing_plans($lastruntime = 0, $unlinkedaremissing = false) { global $DB; - $skipsql = !$unlinkedaremissing ? '(t.id = p.templateid OR t.id = p.origtemplateid)' : 't.id = p.templateid'; + $planwhereclause = " WHERE (p.id is NULL AND (cm.timeadded >= :lastruntime1 OR tc.timecreated >= :lastruntime3 OR t.timemodified >= :lastruntime4))"; - $sql = "SELECT cm.userid, t.* + if ($unlinkedaremissing) { + $planwhereclause .= " OR (p.origtemplateid IS NOT NULL AND cm.timeadded < :lastruntime2)"; + } + + $sql = "SELECT " . $DB->sql_concat('cm.userid', 'tc.templateid') . " as uniqueid, cm.userid, t.* FROM {cohort_members} cm JOIN {" . self::TABLE . "} tc ON cm.cohortid = tc.cohortid JOIN {" . template::TABLE . "} t ON (tc.templateid = t.id AND t.visible = 1) - AND (t.duedate = 0 OR t.duedate > :time) - LEFT JOIN {" . plan::TABLE . "} p ON (cm.userid = p.userid AND $skipsql) - WHERE p.id IS NULL + AND (t.duedate = 0 OR t.duedate > :time1) + LEFT JOIN {" . plan::TABLE . "} p ON (cm.userid = p.userid AND (t.id = p.templateid OR t.id = p.origtemplateid)) + $planwhereclause ORDER BY t.id"; - $results = $DB->get_records_sql($sql, array('time' => time())); + $params = array('time1' => time(), 'time2' => time(), + 'lastruntime1' => $lastruntime, 'lastruntime2' => $lastruntime, + 'lastruntime3' => $lastruntime, 'lastruntime4' => $lastruntime); + $results = $DB->get_records_sql($sql, $params); $missingplans = array(); foreach ($results as $usertemplate) { @@ -212,6 +220,7 @@ class template_cohort extends persistent { $missingplans[$usertemplate->id]['userids'][] = $userid; } else { unset($usertemplate->userid); + unset($usertemplate->uniqueid); $template = new template(0, $usertemplate); $missingplans[$template->get_id()]['template'] = $template; $missingplans[$template->get_id()]['userids'][] = $userid; diff --git a/admin/tool/lp/tests/task_test.php b/admin/tool/lp/tests/task_test.php index 77083f52393..aee34644834 100644 --- a/admin/tool/lp/tests/task_test.php +++ b/admin/tool/lp/tests/task_test.php @@ -37,11 +37,20 @@ use tool_lp\plan; class tool_lp_task_testcase extends advanced_testcase { public function test_sync_plans_from_cohorts_task() { + global $DB; + $this->resetAfterTest(true); $this->setAdminUser(); $dg = $this->getDataGenerator(); $lpg = $dg->get_plugin_generator('tool_lp'); + // Sql to simulate the execution in time. + $cmsql = "UPDATE {cohort_members} SET timeadded = :currenttime WHERE cohortid = :cohortid AND userid = :userid"; + $tplsql = "UPDATE {tool_lp_template} SET timemodified = :currenttime WHERE id = :templateid"; + $plansql = "UPDATE {tool_lp_plan} SET timemodified = :currenttime WHERE id = :planid"; + + $currenttime = time(); + $user1 = $dg->create_user(); $user2 = $dg->create_user(); $user3 = $dg->create_user(); @@ -68,7 +77,9 @@ class tool_lp_task_testcase extends advanced_testcase { cohort_add_member($cohort->id, $user3->id); cohort_add_member($cohort->id, $user4->id); + $currenttime = $currenttime + 1; $task->execute(); + $task->set_last_run_time($currenttime); $this->assertEquals(4, plan::count_records(array('templateid' => $tpl->get_id()))); @@ -76,43 +87,73 @@ class tool_lp_task_testcase extends advanced_testcase { cohort_remove_member($cohort->id, $user3->id); cohort_remove_member($cohort->id, $user4->id); + $currenttime = $currenttime + 1; $task->execute(); + $task->set_last_run_time($currenttime); $this->assertEquals(4, plan::count_records(array('templateid' => $tpl->get_id()))); // The template is now hidden, and I've added a user with a missing plan. Nothing should happen. + $currenttime = $currenttime + 1; $tpl->set_visible(false); $tpl->update(); + $DB->execute($tplsql, array('currenttime' => $currenttime, 'templateid' => $tpl->get_id())); + $currenttime = $currenttime + 1; cohort_add_member($cohort->id, $user5->id); + $DB->execute($cmsql, array('currenttime' => $currenttime, 'cohortid' => $cohort->id, 'userid' => $user5->id)); $this->assertFalse(plan::record_exists_select('userid = ? AND templateid = ?', array($user5->id, $tpl->get_id()))); $this->assertEquals(4, plan::count_records(array('templateid' => $tpl->get_id()))); + $currenttime = $currenttime + 1; $task->execute(); + $task->set_last_run_time($currenttime); $this->assertFalse(plan::record_exists_select('userid = ? AND templateid = ?', array($user5->id, $tpl->get_id()))); $this->assertEquals(4, plan::count_records(array('templateid' => $tpl->get_id()))); // Now I set the template as visible again, the plan is created. + $currenttime = $currenttime + 1; $tpl->set_visible(true); $tpl->update(); + $DB->execute($tplsql, array('currenttime' => $currenttime, 'templateid' => $tpl->get_id())); + $currenttime = $currenttime + 1; $task->execute(); + $task->set_last_run_time($currenttime); $this->assertTrue(plan::record_exists_select('userid = ? AND templateid = ?', array($user5->id, $tpl->get_id()))); $this->assertEquals(5, plan::count_records(array('templateid' => $tpl->get_id()))); // Let's unlink the plan and run the task again, it should not be recreated. + $currenttime = $currenttime + 1; $plan = plan::get_record(array('userid' => $user5->id, 'templateid' => $tpl->get_id())); \tool_lp\api::unlink_plan_from_template($plan); + $DB->execute($plansql, array('currenttime' => $currenttime, 'planid' => $plan->get_id())); $this->assertTrue(plan::record_exists_select('userid = ?', array($user5->id))); $this->assertFalse(plan::record_exists_select('userid = ? AND templateid = ?', array($user5->id, $tpl->get_id()))); $this->assertEquals(4, plan::count_records(array('templateid' => $tpl->get_id()))); + $currenttime = $currenttime + 1; $task->execute(); + $task->set_last_run_time($currenttime); $this->assertTrue(plan::record_exists_select('userid = ?', array($user5->id))); $this->assertFalse(plan::record_exists_select('userid = ? AND templateid = ?', array($user5->id, $tpl->get_id()))); $this->assertEquals(4, plan::count_records(array('templateid' => $tpl->get_id()))); // Adding users to cohort that already exist in plans. + $currenttime = $currenttime + 1; cohort_add_member($cohort->id, $user3->id); cohort_add_member($cohort->id, $user4->id); + $DB->execute($cmsql, array('currenttime' => $currenttime, 'cohortid' => $cohort->id, 'userid' => $user3->id)); + $DB->execute($cmsql, array('currenttime' => $currenttime, 'cohortid' => $cohort->id, 'userid' => $user3->id)); + $currenttime = $currenttime + 1; $task->execute(); + $task->set_last_run_time($currenttime); $this->assertEquals(4, plan::count_records(array('templateid' => $tpl->get_id()))); + + // Test a user plan deleted will not be recreated + $currenttime = $currenttime + 1; + $plan = plan::get_record(array('userid' => $user4->id, 'templateid' => $tpl->get_id())); + \tool_lp\api::delete_plan($plan->get_id()); + $currenttime = $currenttime + 1; + $task->execute(); + $task->set_last_run_time($currenttime); + $this->assertEquals(3, plan::count_records(array('templateid' => $tpl->get_id()))); } public function test_sync_plans_from_cohorts_with_templateduedate_task() {