Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
/**
18
 * Update Overdue Attempts Task
19
 *
20
 * @package    mod_quiz
21
 * @copyright  2017 Michael Hughes
22
 * @author Michael Hughes
23
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24
 */
25
namespace mod_quiz\task;
26
 
27
use mod_quiz\quiz_attempt;
28
use moodle_exception;
29
use moodle_recordset;
30
 
31
defined('MOODLE_INTERNAL') || die();
32
 
33
global $CFG;
34
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
35
 
36
/**
37
 * Update Overdue Attempts Task
38
 *
39
 * @package    mod_quiz
40
 * @copyright  2017 Michael Hughes
41
 * @author Michael Hughes
42
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
43
 *
44
 */
45
class update_overdue_attempts extends \core\task\scheduled_task {
46
 
47
    public function get_name(): string {
48
        return get_string('updateoverdueattemptstask', 'mod_quiz');
49
    }
50
 
51
    /**
52
     * Close off any overdue attempts.
53
     */
54
    public function execute() {
55
        $timenow = time();
56
        $processto = $timenow - get_config('quiz', 'graceperiodmin');
57
 
58
        mtrace('  Looking for quiz overdue quiz attempts...');
59
 
60
        list($count, $quizcount) = $this->update_all_overdue_attempts($timenow, $processto);
61
 
62
        mtrace('  Considered ' . $count . ' attempts in ' . $quizcount . ' quizzes.');
63
    }
64
 
65
    /**
66
     * Do the processing required.
67
     *
68
     * @param int $timenow the time to consider as 'now' during the processing.
69
     * @param int $processto only process attempt with timecheckstate longer ago than this.
70
     * @return array with two elements, the number of attempt considered, and how many different quizzes that was.
71
     */
72
    public function update_all_overdue_attempts(int $timenow, int $processto): array {
73
        global $DB;
74
 
75
        $attemptstoprocess = $this->get_list_of_overdue_attempts($processto);
76
 
77
        $course = null;
78
        $quiz = null;
79
        $cm = null;
80
 
81
        $count = 0;
82
        $quizcount = 0;
83
        foreach ($attemptstoprocess as $attempt) {
84
            try {
85
 
86
                // If we have moved on to a different quiz, fetch the new data.
87
                if (!$quiz || $attempt->quiz != $quiz->id) {
88
                    $quiz = $DB->get_record('quiz', ['id' => $attempt->quiz], '*', MUST_EXIST);
89
                    $cm = get_coursemodule_from_instance('quiz', $attempt->quiz);
90
                    $quizcount += 1;
91
                }
92
 
93
                // If we have moved on to a different course, fetch the new data.
94
                if (!$course || $course->id != $quiz->course) {
95
                    $course = get_course($quiz->course);
96
                }
97
 
98
                // Make a specialised version of the quiz settings, with the relevant overrides.
99
                $quizforuser = clone($quiz);
100
                $quizforuser->timeclose = $attempt->usertimeclose;
101
                $quizforuser->timelimit = $attempt->usertimelimit;
102
 
103
                // Trigger any transitions that are required.
104
                $attemptobj = new quiz_attempt($attempt, $quizforuser, $cm, $course);
105
                $attemptobj->handle_if_time_expired($timenow, false);
106
                $count += 1;
107
 
108
            } catch (moodle_exception $e) {
109
                // If an error occurs while processing one attempt, don't let that kill cron.
110
                mtrace("Error while processing attempt $attempt->id at $attempt->quiz quiz:");
111
                mtrace($e->getMessage());
112
                mtrace($e->getTraceAsString());
113
                // Close down any currently open transactions, otherwise one error
114
                // will stop following DB changes from being committed.
115
                $DB->force_transaction_rollback();
116
            }
117
        }
118
 
119
        $attemptstoprocess->close();
120
        return [$count, $quizcount];
121
    }
122
 
123
    /**
124
     * Get a recordset of all the attempts that need to be processed now.
125
     *
126
     * (Only public to allow unit testing. Do not use!)
127
     *
128
     * @param int $processto timestamp to process up to.
129
     * @return moodle_recordset of quiz_attempts that need to be processed because time has
130
     *     passed, sorted by courseid then quizid.
131
     */
132
    public function get_list_of_overdue_attempts(int $processto): moodle_recordset {
133
        global $DB;
134
 
135
        // SQL to compute timeclose and timelimit for each attempt.
136
        $quizausersql = quiz_get_attempt_usertime_sql(
137
                "iquiza.state IN ('inprogress', 'overdue') AND iquiza.timecheckstate <= :iprocessto");
138
 
139
        // This query should have all the quiz_attempts columns.
140
        return $DB->get_recordset_sql("
141
         SELECT quiza.*,
142
                quizauser.usertimeclose,
143
                quizauser.usertimelimit
144
 
145
           FROM {quiz_attempts} quiza
146
           JOIN {quiz} quiz ON quiz.id = quiza.quiz
147
           JOIN ( $quizausersql ) quizauser ON quizauser.id = quiza.id
148
 
149
          WHERE quiza.state IN ('inprogress', 'overdue')
150
            AND quiza.timecheckstate <= :processto
151
       ORDER BY quiz.course, quiza.quiz",
152
 
153
                ['processto' => $processto, 'iprocessto' => $processto]);
154
    }
155
}