lib.php 7.85 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php

/**
 * @package     local_asystgrade
 * @author      Artem Baranovskyi
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

//
// 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/>.

23
use local_asystgrade\api\client;
24
use local_asystgrade\api\http_client;
25
use local_asystgrade\db\quizquery;
26
27
28

defined('MOODLE_INTERNAL') || die();

Artem Baranovskyi's avatar
Artem Baranovskyi committed
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//global $PAGE;
//require_once(__DIR__ . '/../../config.php');
//require_login();
//$PAGE->set_url('/local/asystgrade/index.php');
//$PAGE->set_context(context_system::instance());
//$PAGE->set_title('Your Page Title');
//$PAGE->set_heading('Your Page Heading');

//$slot = optional_param('slot', false, PARAM_INT);
//$PAGE->requires->js_call_amd('local_asystgrade/marks', 'init');

//function local_asystgrade_page_init() {
//    global $PAGE;
//    $slot = optional_param('slot', false, PARAM_INT);
//    echo "Calling js_call_amd..."; // Добавьте перед вызовом js_call_amd
//    $PAGE->requires->js_call_amd('local_asystgrade/marks', 'init');
//
//
//    if ($PAGE->url->compare(new moodle_url('/mod/quiz/report.php'), URL_MATCH_BASE) && $slot) {
//        echo "Calling js_call_amd..."; // Добавьте перед вызовом js_call_amd
//        $PAGE->requires->js_call_amd('local_asystgrade/marks', 'init');
//    }
//}

53
54
55
56
57
58
59
60
61
/**
 * A hook function that will process the data and insert the rating value.
 * The function must be called on the desired page like https://www.moodle.loc/mod/quiz/report.php?id=2&mode=grading&slot=1&qid=1&grade=needsgrading&includeauto=1
 *
 * @return void
 */

function local_asystgrade_before_footer()
{
62
    global $PAGE;
63
    // Obtaining parameters from URL
Artem Baranovskyi's avatar
Artem Baranovskyi committed
64
    $qid  = optional_param('qid', null, PARAM_INT);
65
66
    $slot = optional_param('slot', false, PARAM_INT);

Artem Baranovskyi's avatar
Artem Baranovskyi committed
67
68
69
    $PAGE->requires->js_call_amd('local_asystgrade/marks', 'init');

    /*if ($PAGE->url->compare(new moodle_url('/mod/quiz/report.php'), URL_MATCH_BASE) && $slot) {
70
        $quizQuery = new quizquery();
71

72
73
74
75
76
        if ($quizQuery->gradesExist($qid, $slot)) {
            error_log('Grades already exist in the database.');
            return;
        }

77
78
        $question_attempts = $quizQuery->get_question_attempts($qid, $slot);
        $referenceAnswer = $quizQuery->get_reference_answer($qid);
Artem Baranovskyi's avatar
Artem Baranovskyi committed
79
        $maxmark = (float)$question_attempts->current()->maxmark;
80
        $data = prepare_api_data($quizQuery, $question_attempts, $referenceAnswer);
81
82
83

        foreach (array_keys($data['studentData']) as $studentId) {
            if ($quizQuery->gradesExist($qid, $studentId)) {
84
85
86
                return;
            }
        }
87
88
89

        $studentData = $data['studentData'];
        $inputNames = array_column($studentData, 'inputName');
90
91
92
93
94

        error_log('Data prepared: ' . print_r($data, true));

        $apiendpoint = get_config('local_asystgrade', 'apiendpoint');
        if (!$apiendpoint) {
95
            $apiendpoint = 'http://flask:5000/api/autograde'; // Default setting, flask is the name of flask container
96
97
98
99
100
        }

        error_log('APIendpoint: ' . $apiendpoint);

        try {
101
102
            $httpClient = new http_client();
            $apiClient = client::getInstance($apiendpoint, $httpClient);
103
104
105
            error_log('ApiClient initiated.');

            error_log('Sending data to API and getting grade');
106
107
108
109
            $response = $apiClient->send_data([
                'referenceAnswer' => $data['referenceAnswer'],
                'studentAnswers' => array_column($studentData, 'studentAnswer')
            ]);
110
            $grades = json_decode($response, true);
111
112
113
114
115
116
117
118
119

            error_log('Grade obtained: ' . print_r($grades, true));
        } catch (Exception $e) {
            error_log('Error sending data to API: ' . $e->getMessage());
            return;
        }

        error_log('After API call');

Artem Baranovskyi's avatar
Artem Baranovskyi committed
120
        pasteGradedMarks($grades, $inputNames, $maxmark);
121
122

        error_log('URL matches /mod/quiz/report.php in page_init');
Artem Baranovskyi's avatar
Artem Baranovskyi committed
123
    }*/
124
125
126
127
}

/**
 * Adds JavasScript scrypt to update marks
Artem Baranovskyi's avatar
Artem Baranovskyi committed
128
129
130
 * @param  array $grades
 * @param  array $inputNames
 * @param  float $maxmark
131
132
 * @return void
 */
Artem Baranovskyi's avatar
Artem Baranovskyi committed
133
134

function pasteGradedMarks(array $grades, array $inputNames, float $maxmark): void
135
{
Artem Baranovskyi's avatar
Artem Baranovskyi committed
136
    echo generate_script($grades, $inputNames, $maxmark);
137
138
139
}

/**
Artem Baranovskyi's avatar
Artem Baranovskyi committed
140
141
 * Processes question attempts and answers to prepare for API a data to estimate answers
 *
142
 * @param quizquery $database
143
144
145
146
 * @param $question_attempts
 * @param $referenceAnswer
 * @return array
 */
147
function prepare_api_data(quizquery $database, $question_attempts, $referenceAnswer): array
148
{
149
    $studentData = [];
150
151
152
153
154
155
156

    foreach ($question_attempts as $question_attempt) {
        $quizattempt_steps = $database->get_attempt_steps($question_attempt->id);

        foreach ($quizattempt_steps as $quizattempt_step) {
            if ($quizattempt_step->state === 'complete') {
                $studentAnswer = $database->get_student_answer($quizattempt_step->id);
157
158
159
160
161
162
163
164
165
166
                $studentId = $quizattempt_step->userid;
                $inputName = "q" . $question_attempt->questionusageid . ":" . $question_attempt->slot . "_-mark";

                // Adding data to an associative array
                $studentData[$studentId] = [
                    'studentAnswer' => $studentAnswer,
                    'inputName' => $inputName // identifying name for mark input field updating
                ];

                error_log("Student ID: $studentId, Student Answer: $studentAnswer, Input Name: $inputName");
167
168
            }
        }
169

170
        $quizattempt_steps->close();
171
    }
172
173
174
175
176

    $question_attempts->close();

    return [
        'referenceAnswer' => $referenceAnswer,
177
        'studentData' => $studentData
178
    ];
179
180
}

181
182
183
/**
 * Builds JavasScript scrypt to update marks using DOM manipulations
 *
Artem Baranovskyi's avatar
Artem Baranovskyi committed
184
185
186
 * @param  array $grades
 * @param  array $inputNames
 * @param  float $maxmark
187
188
 * @return string
 */
Artem Baranovskyi's avatar
Artem Baranovskyi committed
189
function generate_script(array $grades, array $inputNames, float $maxmark) {
190
191
192
193
194
    $script = "<script type='text/javascript'>
        document.addEventListener('DOMContentLoaded', function() {";

    foreach ($grades as $index => $grade) {
        if (isset($grade['predicted_grade'])) {
Artem Baranovskyi's avatar
Artem Baranovskyi committed
195
            $predicted_grade = $grade['predicted_grade'] == 'correct' ? $maxmark : 0;
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
            $input_name = $inputNames[$index];
            $script .= "
                console.log('Trying to update input: {$input_name} with grade: {$predicted_grade}');
                var gradeInput = document.querySelector('input[name=\"{$input_name}\"]');
                if (gradeInput) {
                    console.log('Found input: {$input_name}');
                    gradeInput.value = '{$predicted_grade}';
                } else {
                    console.log('Input not found: {$input_name}');
                }";
        }
    }

    $script .= "});
    </script>";

    return $script;
}

/**
 * Autoloader registration
 */
218
219
220
221
222
223
224
225
226
227
228
229
230
//spl_autoload_register(function ($classname) {
//    // Check if the class name starts with our plugin's namespace
//    if (strpos($classname, 'local_asystgrade\\') === 0) {
//        // Transforming the Namespace into the Path
//        $classname = str_replace('local_asystgrade\\', '', $classname);
//        $classname = str_replace('\\', DIRECTORY_SEPARATOR, $classname);
//        $filepath  = __DIR__ . DIRECTORY_SEPARATOR . 'classes' . DIRECTORY_SEPARATOR . $classname . '.php';
//
//        if (file_exists($filepath)) {
//            require_once($filepath);
//        }
//    }
//});