Merge branch 'MDL-65050-master' of git://github.com/lameze/moodle
This commit is contained in:
+2
-1
@@ -1243,7 +1243,8 @@ $string['taskpasswordresetcleanup'] = 'Cleanup password reset attempts';
|
||||
$string['taskplagiarismcron'] = 'Background processing for legacy cron in plagiarism plugins';
|
||||
$string['taskportfoliocron'] = 'Background processing for portfolio plugins';
|
||||
$string['taskprocessing'] = 'Task processing';
|
||||
$string['taskquestioncron'] = 'Background processing for question engine';
|
||||
$string['taskquestioncron'] = 'Background processing for cleaning up the old question previews';
|
||||
$string['taskquestionstatscleanupcron'] = 'Background processing for cleaning up the old question statistics cache';
|
||||
$string['taskrefreshsystemtokens'] = 'Refresh OAuth tokens for service accounts';
|
||||
$string['taskregistrationcron'] = 'Site registration';
|
||||
$string['tasksendfailedloginnotifications'] = 'Send failed login notifications';
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* A scheduled task.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2013 onwards Martin Dougiamas http://dougiamas.com
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace core\task;
|
||||
|
||||
/**
|
||||
* Simple task to run the question cron.
|
||||
*/
|
||||
class question_cron_task extends scheduled_task {
|
||||
|
||||
/**
|
||||
* Get a descriptive name for this task (shown to admins).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return get_string('taskquestioncron', 'admin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the job.
|
||||
* Throw exceptions on errors (the job will be retried).
|
||||
*/
|
||||
public function execute() {
|
||||
global $CFG;
|
||||
|
||||
// Run question bank clean-up.
|
||||
require_once($CFG->libdir . '/questionlib.php');
|
||||
\question_bank::cron();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Task to cleanup old question previews.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2013 onwards Martin Dougiamas http://dougiamas.com
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace core\task;
|
||||
|
||||
/**
|
||||
* A task to cleanup old question previews.
|
||||
*
|
||||
* @copyright 2013 onwards Martin Dougiamas http://dougiamas.com
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class question_preview_cleanup_task extends scheduled_task {
|
||||
|
||||
/**
|
||||
* Get a descriptive name for this task (shown to admins).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return get_string('taskquestioncron', 'admin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the job.
|
||||
* Throw exceptions on errors (the job will be retried).
|
||||
*/
|
||||
public function execute() {
|
||||
|
||||
// We delete previews that have not been touched for 24 hours.
|
||||
$lastmodifiedcutoff = time() - DAYSECS;
|
||||
|
||||
mtrace("\n Cleaning up old question previews...", '');
|
||||
$oldpreviews = new \qubaid_join('{question_usages} quba', 'quba.id',
|
||||
'quba.component = :qubacomponent
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM {question_attempts} subq_qa
|
||||
JOIN {question_attempt_steps} subq_qas ON subq_qas.questionattemptid = subq_qa.id
|
||||
JOIN {question_usages} subq_qu ON subq_qu.id = subq_qa.questionusageid
|
||||
WHERE subq_qa.questionusageid = quba.id
|
||||
AND subq_qu.component = :qubacomponent2
|
||||
AND (subq_qa.timemodified > :qamodifiedcutoff
|
||||
OR subq_qas.timecreated > :stepcreatedcutoff)
|
||||
)
|
||||
',
|
||||
['qubacomponent' => 'core_question_preview', 'qubacomponent2' => 'core_question_preview',
|
||||
'qamodifiedcutoff' => $lastmodifiedcutoff, 'stepcreatedcutoff' => $lastmodifiedcutoff]);
|
||||
|
||||
\question_engine::delete_questions_usage_by_activities($oldpreviews);
|
||||
mtrace('done.');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Task to cleanup old question statistics cache.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2019 Simey Lameze <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace core\task;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* A task to cleanup old question statistics cache.
|
||||
*
|
||||
* @copyright 2019 Simey Lameze <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class question_stats_cleanup_task extends scheduled_task {
|
||||
|
||||
/**
|
||||
* Get a descriptive name for this task (shown to admins).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return get_string('taskquestionstatscleanupcron', 'admin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the cleanup task.
|
||||
*/
|
||||
public function execute() {
|
||||
global $DB;
|
||||
|
||||
mtrace("\n Cleaning up old question statistics cache records...", '');
|
||||
|
||||
$expiretime = time() - 5 * HOURSECS;
|
||||
$DB->delete_records_select('question_statistics', 'timemodified < ?', [$expiretime]);
|
||||
$responseanlysisids = $DB->get_records_select_menu('question_response_analysis',
|
||||
'timemodified < ?',
|
||||
[$expiretime],
|
||||
'id',
|
||||
'id, id AS id2');
|
||||
$DB->delete_records_list('question_response_analysis', 'id', $responseanlysisids);
|
||||
$DB->delete_records_list('question_response_count', 'analysisid', $responseanlysisids);
|
||||
|
||||
mtrace('done.');
|
||||
}
|
||||
}
|
||||
+10
-1
@@ -213,7 +213,16 @@ $tasks = array(
|
||||
'month' => '*'
|
||||
),
|
||||
array(
|
||||
'classname' => 'core\task\question_cron_task',
|
||||
'classname' => 'core\task\question_preview_cleanup_task',
|
||||
'blocking' => 0,
|
||||
'minute' => '*',
|
||||
'hour' => '*',
|
||||
'day' => '*',
|
||||
'dayofweek' => '*',
|
||||
'month' => '*'
|
||||
),
|
||||
array(
|
||||
'classname' => 'core\task\question_stats_cleanup_task',
|
||||
'blocking' => 0,
|
||||
'minute' => '*',
|
||||
'hour' => '*',
|
||||
|
||||
@@ -2947,5 +2947,20 @@ function xmldb_main_upgrade($oldversion) {
|
||||
upgrade_main_savepoint(true, 2019032900.00);
|
||||
}
|
||||
|
||||
if ($oldversion < 2019032900.01) {
|
||||
$sql = "UPDATE {task_scheduled}
|
||||
SET classname = ?
|
||||
WHERE component = ?
|
||||
AND classname = ?";
|
||||
$DB->execute($sql, [
|
||||
'\core\task\question_preview_cleanup_task',
|
||||
'moodle',
|
||||
'\core\task\question_cron_task'
|
||||
]);
|
||||
|
||||
// Main savepoint reached.
|
||||
upgrade_main_savepoint(true, 2019032900.01);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -408,21 +408,6 @@ abstract class question_bank {
|
||||
return self::$fractionoptionsfull;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform scheduled maintenance tasks relating to the question bank.
|
||||
*/
|
||||
public static function cron() {
|
||||
global $CFG;
|
||||
|
||||
// Delete any old question preview that got left in the database.
|
||||
require_once($CFG->dirroot . '/question/previewlib.php');
|
||||
question_preview_cron();
|
||||
|
||||
// Clear older calculated stats from cache.
|
||||
require_once($CFG->dirroot . '/question/engine/statisticslib.php');
|
||||
question_usage_statistics_cron();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of the different question types present in the given categories.
|
||||
*
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Functions common to the question usage statistics code.
|
||||
*
|
||||
* @package moodlecore
|
||||
* @subpackage questionbank
|
||||
* @copyright 2013 The Open University
|
||||
* @author Jamie Pratt <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Question statistics cron code. Deletes cached stats more than a certain age.
|
||||
*/
|
||||
function question_usage_statistics_cron() {
|
||||
global $DB;
|
||||
|
||||
$expiretime = time() - 5 * HOURSECS;
|
||||
|
||||
mtrace("\n Cleaning up old question statistics cache records...", '');
|
||||
|
||||
$DB->delete_records_select('question_statistics', 'timemodified < ?', array($expiretime));
|
||||
$responseanlysisids = $DB->get_records_select_menu('question_response_analysis',
|
||||
'timemodified < ?',
|
||||
array($expiretime),
|
||||
'id',
|
||||
'id, id AS id2');
|
||||
|
||||
$DB->delete_records_list('question_response_analysis', 'id', $responseanlysisids);
|
||||
$DB->delete_records_list('question_response_count', 'analysisid', $responseanlysisids);
|
||||
|
||||
mtrace('done.');
|
||||
return true;
|
||||
}
|
||||
@@ -327,32 +327,3 @@ function restart_preview($previewid, $questionid, $displayoptions, $context) {
|
||||
redirect(question_preview_url($questionid, $displayoptions->behaviour,
|
||||
$displayoptions->maxmark, $displayoptions, $displayoptions->variant, $context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Scheduled tasks relating to question preview. Specifically, delete any old
|
||||
* previews that are left over in the database.
|
||||
*/
|
||||
function question_preview_cron() {
|
||||
$maxage = 24*60*60; // We delete previews that have not been touched for 24 hours.
|
||||
$lastmodifiedcutoff = time() - $maxage;
|
||||
|
||||
mtrace("\n Cleaning up old question previews...", '');
|
||||
$oldpreviews = new qubaid_join('{question_usages} quba', 'quba.id',
|
||||
'quba.component = :qubacomponent
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM {question_attempts} subq_qa
|
||||
JOIN {question_attempt_steps} subq_qas ON subq_qas.questionattemptid = subq_qa.id
|
||||
JOIN {question_usages} subq_qu ON subq_qu.id = subq_qa.questionusageid
|
||||
WHERE subq_qa.questionusageid = quba.id
|
||||
AND subq_qu.component = :qubacomponent2
|
||||
AND (subq_qa.timemodified > :qamodifiedcutoff
|
||||
OR subq_qas.timecreated > :stepcreatedcutoff)
|
||||
)
|
||||
',
|
||||
array('qubacomponent' => 'core_question_preview', 'qubacomponent2' => 'core_question_preview',
|
||||
'qamodifiedcutoff' => $lastmodifiedcutoff, 'stepcreatedcutoff' => $lastmodifiedcutoff));
|
||||
|
||||
question_engine::delete_questions_usage_by_activities($oldpreviews);
|
||||
mtrace('done.');
|
||||
}
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Quiz events tests.
|
||||
*
|
||||
* @package mod_quiz
|
||||
* @category phpunit
|
||||
* @copyright 2013 Adrian Greeve
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/question/previewlib.php');
|
||||
|
||||
/**
|
||||
* Unit tests for question preview.
|
||||
*
|
||||
* @package question
|
||||
* @category phpunit
|
||||
* @copyright 2016 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class question_previewlib_testcase extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* Setup some convenience test data with a single attempt.
|
||||
*
|
||||
* @return question_usage_by_activity
|
||||
*/
|
||||
protected function prepare_question_data() {
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
|
||||
|
||||
// Create a questions and start the preview.
|
||||
$cat = $questiongenerator->create_question_category();
|
||||
|
||||
$quba = question_engine::make_questions_usage_by_activity('core_question_preview', context_system::instance());
|
||||
$quba->set_preferred_behaviour('deferredfeedback');
|
||||
$questiondata = $questiongenerator->create_question('numerical', null, array('category' => $cat->id));
|
||||
$question = question_bank::load_question($questiondata->id);
|
||||
$quba->add_question($question);
|
||||
$quba->start_all_questions();
|
||||
question_engine::save_questions_usage_by_activity($quba);
|
||||
|
||||
return $quba;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the attempt deleted event.
|
||||
*/
|
||||
public function test_question_preview_cron() {
|
||||
global $DB;
|
||||
|
||||
// Create some quiz data.
|
||||
// This will create two questions.
|
||||
$quba1 = $this->prepare_question_data();
|
||||
|
||||
// Run the cron.
|
||||
ob_start();
|
||||
question_preview_cron();
|
||||
$output = ob_get_clean();
|
||||
$this->assertEquals("\n Cleaning up old question previews...done.\n", $output);
|
||||
|
||||
// The attempt should not have been removed.
|
||||
// There should be one question usage with two question attempts.
|
||||
$this->assertEquals(1, $DB->count_records('question_usages', array('id' => $quba1->get_id())));
|
||||
$this->assertEquals(1, $DB->count_records('question_attempts', array('questionusageid' => $quba1->get_id())));
|
||||
$this->assertEquals(1, $DB->count_records('question_attempt_steps'));
|
||||
$this->assertEquals(1, $DB->count_records('question_attempt_step_data'));
|
||||
|
||||
// Update the timemodified and timecreated to be in the past.
|
||||
$DB->set_field('question_attempts', 'timemodified', time() - WEEKSECS);
|
||||
$DB->set_field('question_attempt_steps', 'timecreated', time() - WEEKSECS);
|
||||
|
||||
// Create some quiz data.
|
||||
// This will create two questions.
|
||||
$quba2 = $this->prepare_question_data();
|
||||
|
||||
// There will now be 2 usages, etc.
|
||||
$this->assertEquals(2, $DB->count_records('question_usages'));
|
||||
$this->assertEquals(2, $DB->count_records('question_attempts'));
|
||||
$this->assertEquals(2, $DB->count_records('question_attempt_steps'));
|
||||
$this->assertEquals(2, $DB->count_records('question_attempt_step_data'));
|
||||
|
||||
// Run the cron again.
|
||||
// $quba1 will be removed, but $quba2 should still be present.
|
||||
ob_start();
|
||||
question_preview_cron();
|
||||
$output = ob_get_clean();
|
||||
$this->assertEquals("\n Cleaning up old question previews...done.\n", $output);
|
||||
|
||||
$this->assertEquals(0, $DB->count_records('question_usages', array('id' => $quba1->get_id())));
|
||||
$this->assertEquals(0, $DB->count_records('question_attempts', array('questionusageid' => $quba1->get_id())));
|
||||
$this->assertEquals(1, $DB->count_records('question_usages', array('id' => $quba2->get_id())));
|
||||
$this->assertEquals(1, $DB->count_records('question_attempts', array('questionusageid' => $quba2->get_id())));
|
||||
$this->assertEquals(1, $DB->count_records('question_attempt_steps'));
|
||||
$this->assertEquals(1, $DB->count_records('question_attempt_step_data'));
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,10 @@ The exportprocess function of the qformat_default class doesn't output a blank l
|
||||
if the result of the writequestion function is null. This permit to qformat plugins
|
||||
to ignore some questions without the need to overwrite this function.
|
||||
|
||||
* The question_preview_cron() has been deleted. Please use \core\task\question_cron_task::execute().
|
||||
* The question_usage_statistics_cron() has been deleted. Please use \core\task\question_cron_task::execute().
|
||||
* The method question_bank::cron() has been deleted, please use question related scheduled tasks.
|
||||
|
||||
=== 3.5 ===
|
||||
|
||||
1) The question format exportprocess function now adds a
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2019032900.00; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
$version = 2019032900.01; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user