Skip to content

Commit df0b905

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 df0b905

File tree

1 file changed

+226
-30
lines changed

1 file changed

+226
-30
lines changed

block_my_feedback.php

+226-30
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,105 @@ public static function fetch_marking(stdClass $user): ?array {
108108
// Marking.
109109
$marking = [];
110110

111+
foreach ($courses as $course) {
112+
// Skip hidden courses.
113+
if (!$course->visible) {
114+
continue;
115+
}
116+
// Skip none current course.
117+
if (!self::is_course_current($course)) {
118+
continue;
119+
}
120+
// Skip if no summative assessments.
121+
if (!$summatives = assess_type::get_assess_type_records_by_courseid($course->id, assess_type::ASSESS_TYPE_SUMMATIVE)) {
122+
continue;
123+
}
124+
125+
$modinfo = get_fast_modinfo($course->id);
126+
$mods = $modinfo->get_cms();
127+
// Mod ids array to check cmid exists.
128+
$cmids = [];
129+
foreach ($mods as $mod) {
130+
$cmids[] = $mod->id;
131+
}
132+
133+
// Loop through assessments for this course.
134+
foreach ($summatives as $summative) {
135+
136+
// Check this is a course mod.
137+
if ($summative->cmid != 0) {
138+
// Skip mods where cmid is not in the course.
139+
if (!in_array($summative->cmid, $cmids)) {
140+
continue;
141+
}
142+
143+
// Begin to build mod data for template.
144+
$cmid = $summative->cmid;
145+
$mod = $modinfo->get_cm($cmid);
146+
147+
148+
// Skip hidden mods.
149+
if (!$mod->visible) {
150+
continue;
151+
}
152+
153+
// Template.
154+
$assess = new stdClass;
155+
$assess->cmid = $cmid;
156+
$assess->modname = $mod->modname;
157+
// Turnitin assessments may have multiple parts. WIP
158+
if ($assess->modname === 'turnitintooltwo') {
159+
$turnitinparts = self::get_turnitin_parts($mod);
160+
foreach ($turnitinparts as $turnitinpart) {
161+
$turnitin = clone $assess;
162+
$turnitin->partid = $turnitinpart->id;
163+
$turnitin = self::get_mod_data($mod, $turnitin);
164+
165+
// Check mod has required marking (only set when there is a due date).
166+
if (isset($turnitin->requiremarking)) {
167+
// TODO - what is expensive here that we can do after sort and limit?
168+
$turnitin->name = $mod->name . ' ' . $turnitinpart->partname;;
169+
$turnitin->coursename = $course->fullname;
170+
$turnitin->url = new moodle_url('/mod/'. $mod->modname. '/view.php', ['id' => $cmid]);
171+
$turnitin->icon = course_summary_exporter::get_course_image($course);
172+
$marking[] = $turnitin;
173+
}
174+
}
175+
176+
} else {
177+
// Get due date and require marking.
178+
$assess = self::get_mod_data($mod, $assess);
179+
}
180+
181+
// Check mod has required marking (only set when there is a due date).
182+
if (isset($assess->requiremarking)) {
183+
// TODO - what is expensive here that we can do after sort and limit?
184+
$assess->name = $mod->name;
185+
$assess->coursename = $course->fullname;
186+
$assess->url = new moodle_url('/mod/'. $mod->modname. '/view.php', ['id' => $cmid]);
187+
$assess->icon = course_summary_exporter::get_course_image($course);
188+
$marking[] = $assess;
189+
}
190+
}
191+
}
192+
}
193+
194+
// Sort and return data.
195+
if ($marking) {
196+
usort($marking, function ($a, $b) {
197+
return $a->unixtimestamp <=> $b->unixtimestamp;
198+
});
199+
200+
return array_slice($marking, 0, 5);
201+
}
202+
return null;
203+
}
204+
public static function fetch_marking0(stdClass $user): ?array {
205+
// User courses.
206+
$courses = enrol_get_all_users_courses($user->id, false, ['enddate']);
207+
// Marking.
208+
$marking = [];
209+
111210
foreach ($courses as $course) {
112211
// Skip hidden courses.
113212
if (!$course->visible) {
@@ -183,49 +282,146 @@ public static function fetch_marking(stdClass $user): ?array {
183282
/**
184283
* Return mod data - due date & require marking.
185284
*
186-
* TODO - turnitin, quiz.
187-
*
188285
* @param cm_info $mod
189286
* @param stdClass $assess
190287
*/
191288
public static function get_mod_data($mod, $assess): ?stdClass {
192-
global $CFG;
193-
// Mods have different fields for due date, and require marking.
289+
global $CFG, $DB;
290+
// Mods have different fields for due date.
194291
switch ($mod->modname) {
195292
case 'assign':
196-
197293
// Check mod due date is relevant.
198294
$duedate = self::duedate_in_range($mod->customdata['duedate']);
199-
if (!$duedate) {
200-
return null;
201-
}
295+
break;
296+
case 'quiz':
297+
$record = $DB->get_record('quiz', ['id' => $mod->instance], 'timeclose');
298+
// Check if mod due date is present and relevant.
299+
$duedate = isset($record->timeclose) ? self::duedate_in_range($record->timeclose) : false;
300+
break;
301+
case 'turnitintooltwo':
302+
$record = $DB->get_record('turnitintooltwo_parts', ['id' => $assess->partid], 'dtdue');
303+
// Check if mod due date is present and relevant.
304+
$duedate = isset($record->dtdue) ? self::duedate_in_range($record->dtdue) : false;
305+
break;
306+
default:
307+
return null;
308+
}
309+
if (!$duedate) {
310+
return null;
311+
}
202312

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;
313+
// Add dates.
314+
$assess->unixtimestamp = $duedate;
315+
$assess->duedate = date('jS M', $duedate);
316+
317+
// Require marking.
318+
$assess->requiremarking = self::get_required_markings($mod);
319+
if (!$assess->requiremarking) {
320+
return null;
321+
}
322+
$assess->markingurl = new moodle_url('/mod/'. $mod->modname. '/view.php',
323+
['id' => $assess->cmid, 'action' => 'grader']
324+
);
325+
326+
// Return template data.
327+
return $assess;
328+
329+
}
330+
331+
/**
332+
* Get the required markings for an assessment module.
333+
*
334+
* @param cm_info $mod
335+
* @return int
336+
* @throws dml_exception
337+
*/
338+
protected static function get_required_markings(cm_info $mod) {
339+
global $CFG, $DB;
340+
341+
// Assignments provide a way to count submissions that needs grading.
342+
if ($mod->modname === 'assign') {
343+
require_once($CFG->dirroot.'/mod/assign/locallib.php');
344+
$context = context_module::instance($mod->id);
345+
$assignment = new assign($context, $mod, $mod->course);
346+
return $assignment->count_submissions_need_grading();
347+
}
348+
349+
// For modules other than assignments get the student IDs that have submissions.
350+
if ($submissions = self::get_module_submissions($mod)) {
351+
$sql = "SELECT DISTINCT gg.userid
352+
FROM {grade_grades} gg
353+
WHERE gg.itemid = :modid AND gg.finalgrade > :finalgrade";
354+
$params = ['modid' => $mod->id, 'finalgrade' => -1];
355+
356+
// Execute the query.
357+
$studentids = $DB->get_fieldset_sql($sql, $params);
358+
// Count and return all student IDs in submission that are not (yet) to be found in gradings.
359+
$missinggrades = 0;
360+
foreach ($submissions as $submitterid) {
361+
if (!in_array($submitterid, $studentids)) {
362+
$missinggrades++;
214363
}
215-
$assess->markingurl = new moodle_url('/mod/'. $mod->modname. '/view.php',
216-
['id' => $assess->cmid, 'action' => 'grader']
217-
);
364+
}
365+
return $missinggrades;
366+
}
367+
// No submissions - no missing grades.
368+
return 0;
369+
}
218370

219-
// Return template data.
220-
return $assess;
371+
/**
372+
* Get an array of distinct student IDs with submissions for a given module.
373+
*
374+
* @param cm_info $mod
375+
* @return array
376+
*/
377+
public static function get_module_submissions(cm_info $mod): array {
378+
global $DB;
221379

222-
// TODO - quiz - 'timeclose' ?.
223-
case 'quiz':
224-
return null;
225-
// TODO - turnitin.
226-
default:
227-
return null;
380+
if ($mod) {
381+
switch ($mod->modname) {
382+
case 'assign':
383+
// No need to support here, as assignments provide their own methods to count submissions and gradings.
384+
return [];
385+
case 'lesson':
386+
$sql = "SELECT DISTINCT userid FROM {lesson_attempts} WHERE lessonid = :lessonid";
387+
$params = ['lessonid' => $mod->instance, 'correct' => 1];
388+
break;
389+
case 'quiz':
390+
$sql = "SELECT DISTINCT userid FROM {quiz_attempts} WHERE quiz = :quiz AND state = :state";
391+
$params = ['quiz' => $mod->instance, 'state' => 'finished'];
392+
break;
393+
case 'turnitintooltwo':
394+
$sql = "SELECT DISTINCT userid FROM {turnitintooltwo_submissions} WHERE turnitintooltwoid = :turnitintooltwoid";
395+
$params = ['turnitintooltwoid' => $mod->instance];
396+
break;
397+
case 'scorm':
398+
return [];
399+
case 'workshop':
400+
$sql = "SELECT DISTINCT authorid FROM {workshop_submissions} WHERE workshopid = :workshopid";
401+
$params = ['workshopid' => $mod->instance];
402+
break;
403+
default:
404+
return [];
405+
}
406+
return $DB->get_fieldset_sql($sql, $params);
228407
}
408+
return [];
409+
}
410+
411+
/**
412+
* Get separate parts for a turnitin module.
413+
*
414+
* @param cm_info $mod
415+
* @return array
416+
* @throws dml_exception
417+
*/
418+
public static function get_turnitin_parts(cm_info $mod) {
419+
global $DB;
420+
421+
$sql = "SELECT * FROM {turnitintooltwo_parts} WHERE turnitintooltwoid = :iteminstance";
422+
$params = ['iteminstance' => $mod->instance];
423+
// Execute the query and return the result.
424+
return $DB->get_records_sql($sql, $params);
229425
}
230426

231427
/**

0 commit comments

Comments
 (0)