Skip to content

Commit 0cc28ba

Browse files
author
Matthias Opitz
committed
CTP-4123, CTP-4128 : add support for quiz and turnitin modules
- showing turinitin parts separately
1 parent 6f632db commit 0cc28ba

File tree

1 file changed

+150
-33
lines changed

1 file changed

+150
-33
lines changed

block_my_feedback.php

+150-33
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,30 @@ public static function fetch_marking(stdClass $user): ?array {
153153
$assess = new stdClass;
154154
$assess->cmid = $cmid;
155155
$assess->modname = $mod->modname;
156-
// Get due date and require marking.
157-
$assess = self::get_mod_data($mod, $assess);
156+
// Turnitin assessments may have multiple parts, so treat them separately.
157+
if ($assess->modname === 'turnitintooltwo') {
158+
$turnitinparts = self::get_turnitin_parts($mod);
159+
foreach ($turnitinparts as $turnitinpart) {
160+
$turnitin = clone $assess;
161+
$turnitin->partid = $turnitinpart->id;
162+
$turnitin = self::get_mod_data($mod, $turnitin);
163+
164+
// Check mod has required marking (only set when there is a due date).
165+
if (isset($turnitin->requiremarking)) {
166+
// TODO - what is expensive here that we can do after sort and limit?
167+
$turnitin->name = $mod->name . ' ' . $turnitinpart->partname;;
168+
$turnitin->coursename = $course->fullname;
169+
$turnitin->url = new moodle_url('/mod/'. $mod->modname. '/view.php', ['id' => $cmid]);
170+
$turnitin->icon = course_summary_exporter::get_course_image($course);
171+
$marking[] = $turnitin;
172+
}
173+
}
174+
} else {
175+
// Get due date and require marking.
176+
$assess = self::get_mod_data($mod, $assess);
177+
}
158178

159-
// Check mod has require marking (only set when there is a due date).
179+
// Check mod has required marking (only set when there is a due date).
160180
if (isset($assess->requiremarking)) {
161181
// TODO - what is expensive here that we can do after sort and limit?
162182
$assess->name = $mod->name;
@@ -183,49 +203,146 @@ public static function fetch_marking(stdClass $user): ?array {
183203
/**
184204
* Return mod data - due date & require marking.
185205
*
186-
* TODO - turnitin, quiz.
187-
*
188206
* @param cm_info $mod
189207
* @param stdClass $assess
190208
*/
191209
public static function get_mod_data($mod, $assess): ?stdClass {
192-
global $CFG;
193-
// Mods have different fields for due date, and require marking.
210+
global $CFG, $DB;
211+
// Mods have different fields for due date.
194212
switch ($mod->modname) {
195213
case 'assign':
196-
197214
// Check mod due date is relevant.
198215
$duedate = self::duedate_in_range($mod->customdata['duedate']);
199-
if (!$duedate) {
200-
return null;
201-
}
216+
break;
217+
case 'quiz':
218+
$record = $DB->get_record('quiz', ['id' => $mod->instance], 'timeclose');
219+
// Check if mod due date is present and relevant.
220+
$duedate = isset($record->timeclose) ? self::duedate_in_range($record->timeclose) : false;
221+
break;
222+
case 'turnitintooltwo':
223+
$record = $DB->get_record('turnitintooltwo_parts', ['id' => $assess->partid], 'dtdue');
224+
// Check if mod due date is present and relevant.
225+
$duedate = isset($record->dtdue) ? self::duedate_in_range($record->dtdue) : false;
226+
break;
227+
default:
228+
return null;
229+
}
230+
if (!$duedate) {
231+
return null;
232+
}
233+
234+
// Add dates.
235+
$assess->unixtimestamp = $duedate;
236+
$assess->duedate = date('jS M', $duedate);
237+
238+
// Require marking.
239+
$assess->requiremarking = self::get_required_markings($mod);
240+
if (!$assess->requiremarking) {
241+
return null;
242+
}
243+
$assess->markingurl = new moodle_url('/mod/'. $mod->modname. '/view.php',
244+
['id' => $assess->cmid, 'action' => 'grader']
245+
);
246+
247+
// Return template data.
248+
return $assess;
249+
250+
}
251+
252+
/**
253+
* Get the required markings for an assessment module.
254+
*
255+
* @param cm_info $mod
256+
* @return int
257+
* @throws dml_exception
258+
*/
259+
protected static function get_required_markings(cm_info $mod) {
260+
global $CFG, $DB;
261+
262+
// Assignments provide a way to count submissions that needs grading.
263+
if ($mod->modname === 'assign') {
264+
require_once($CFG->dirroot.'/mod/assign/locallib.php');
265+
$context = context_module::instance($mod->id);
266+
$assignment = new assign($context, $mod, $mod->course);
267+
return $assignment->count_submissions_need_grading();
268+
}
202269

203-
// Add dates.
204-
$assess->unixtimestamp = $duedate;
205-
$assess->duedate = date('jS M', $duedate);
206-
207-
// Require marking.
208-
require_once($CFG->dirroot.'/mod/assign/locallib.php');
209-
$context = context_module::instance($mod->id);
210-
$assignment = new assign($context, $mod, $mod->course);
211-
$assess->requiremarking = $assignment->count_submissions_need_grading();
212-
if (!$assess->requiremarking) {
213-
return null;
270+
// For modules other than assignments get the student IDs that have submissions.
271+
if ($submissions = self::get_module_submissions($mod)) {
272+
$sql = "SELECT DISTINCT gg.userid
273+
FROM {grade_grades} gg
274+
WHERE gg.itemid = :modid AND gg.finalgrade > :finalgrade";
275+
$params = ['modid' => $mod->id, 'finalgrade' => -1];
276+
277+
// Execute the query.
278+
$studentids = $DB->get_fieldset_sql($sql, $params);
279+
// Count and return all student IDs in submission that are not (yet) to be found in gradings.
280+
$missinggrades = 0;
281+
foreach ($submissions as $submitterid) {
282+
if (!in_array($submitterid, $studentids)) {
283+
$missinggrades++;
214284
}
215-
$assess->markingurl = new moodle_url('/mod/'. $mod->modname. '/view.php',
216-
['id' => $assess->cmid, 'action' => 'grader']
217-
);
285+
}
286+
return $missinggrades;
287+
}
288+
// No submissions - no missing grades.
289+
return 0;
290+
}
218291

219-
// Return template data.
220-
return $assess;
292+
/**
293+
* Get an array of distinct student IDs with submissions for a given module.
294+
*
295+
* @param cm_info $mod
296+
* @return array
297+
*/
298+
public static function get_module_submissions(cm_info $mod): array {
299+
global $DB;
221300

222-
// TODO - quiz - 'timeclose' ?.
223-
case 'quiz':
224-
return null;
225-
// TODO - turnitin.
226-
default:
227-
return null;
301+
if ($mod) {
302+
switch ($mod->modname) {
303+
case 'assign':
304+
// No need to support here, as assignments provide their own methods to count submissions and gradings.
305+
return [];
306+
case 'lesson':
307+
$sql = "SELECT DISTINCT userid FROM {lesson_attempts} WHERE lessonid = :lessonid";
308+
$params = ['lessonid' => $mod->instance, 'correct' => 1];
309+
break;
310+
case 'quiz':
311+
$sql = "SELECT DISTINCT userid FROM {quiz_attempts} WHERE quiz = :quiz AND state = :state";
312+
$params = ['quiz' => $mod->instance, 'state' => 'finished'];
313+
break;
314+
case 'turnitintooltwo':
315+
$sql = "SELECT DISTINCT userid FROM {turnitintooltwo_submissions} WHERE turnitintooltwoid = :turnitintooltwoid";
316+
$params = ['turnitintooltwoid' => $mod->instance];
317+
break;
318+
case 'scorm':
319+
return [];
320+
case 'workshop':
321+
$sql = "SELECT DISTINCT authorid FROM {workshop_submissions} WHERE workshopid = :workshopid";
322+
$params = ['workshopid' => $mod->instance];
323+
break;
324+
default:
325+
return [];
326+
}
327+
return $DB->get_fieldset_sql($sql, $params);
228328
}
329+
return [];
330+
}
331+
332+
/**
333+
* Get separate parts for a turnitin module.
334+
*
335+
* @param cm_info $mod
336+
* @return array
337+
* @throws dml_exception
338+
*/
339+
public static function get_turnitin_parts(cm_info $mod) {
340+
global $DB;
341+
342+
$sql = "SELECT * FROM {turnitintooltwo_parts} WHERE turnitintooltwoid = :iteminstance";
343+
$params = ['iteminstance' => $mod->instance];
344+
// Execute the query and return the result.
345+
return $DB->get_records_sql($sql, $params);
229346
}
230347

231348
/**

0 commit comments

Comments
 (0)