Skip to content

Commit

Permalink
CTP-4123, CTP-4128 : add support for quiz and turnitin modules
Browse files Browse the repository at this point in the history
- showing turinitin parts separately
  • Loading branch information
Matthias Opitz committed Jan 7, 2025
1 parent 6f632db commit df0b905
Showing 1 changed file with 226 additions and 30 deletions.
256 changes: 226 additions & 30 deletions block_my_feedback.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,105 @@ public static function fetch_marking(stdClass $user): ?array {
// Marking.
$marking = [];

foreach ($courses as $course) {
// Skip hidden courses.
if (!$course->visible) {
continue;
}
// Skip none current course.
if (!self::is_course_current($course)) {
continue;
}
// Skip if no summative assessments.
if (!$summatives = assess_type::get_assess_type_records_by_courseid($course->id, assess_type::ASSESS_TYPE_SUMMATIVE)) {
continue;
}

$modinfo = get_fast_modinfo($course->id);
$mods = $modinfo->get_cms();
// Mod ids array to check cmid exists.
$cmids = [];
foreach ($mods as $mod) {
$cmids[] = $mod->id;
}

// Loop through assessments for this course.
foreach ($summatives as $summative) {

// Check this is a course mod.
if ($summative->cmid != 0) {
// Skip mods where cmid is not in the course.
if (!in_array($summative->cmid, $cmids)) {
continue;
}

// Begin to build mod data for template.
$cmid = $summative->cmid;
$mod = $modinfo->get_cm($cmid);


// Skip hidden mods.
if (!$mod->visible) {
continue;
}

// Template.
$assess = new stdClass;
$assess->cmid = $cmid;
$assess->modname = $mod->modname;
// Turnitin assessments may have multiple parts. WIP
if ($assess->modname === 'turnitintooltwo') {
$turnitinparts = self::get_turnitin_parts($mod);
foreach ($turnitinparts as $turnitinpart) {
$turnitin = clone $assess;
$turnitin->partid = $turnitinpart->id;
$turnitin = self::get_mod_data($mod, $turnitin);

// Check mod has required marking (only set when there is a due date).
if (isset($turnitin->requiremarking)) {
// TODO - what is expensive here that we can do after sort and limit?
$turnitin->name = $mod->name . ' ' . $turnitinpart->partname;;
$turnitin->coursename = $course->fullname;
$turnitin->url = new moodle_url('/mod/'. $mod->modname. '/view.php', ['id' => $cmid]);
$turnitin->icon = course_summary_exporter::get_course_image($course);
$marking[] = $turnitin;
}
}

} else {
// Get due date and require marking.
$assess = self::get_mod_data($mod, $assess);
}

// Check mod has required marking (only set when there is a due date).
if (isset($assess->requiremarking)) {
// TODO - what is expensive here that we can do after sort and limit?
$assess->name = $mod->name;
$assess->coursename = $course->fullname;
$assess->url = new moodle_url('/mod/'. $mod->modname. '/view.php', ['id' => $cmid]);
$assess->icon = course_summary_exporter::get_course_image($course);
$marking[] = $assess;
}
}
}
}

// Sort and return data.
if ($marking) {
usort($marking, function ($a, $b) {
return $a->unixtimestamp <=> $b->unixtimestamp;
});

return array_slice($marking, 0, 5);
}
return null;
}
public static function fetch_marking0(stdClass $user): ?array {
// User courses.
$courses = enrol_get_all_users_courses($user->id, false, ['enddate']);
// Marking.
$marking = [];

foreach ($courses as $course) {
// Skip hidden courses.
if (!$course->visible) {
Expand Down Expand Up @@ -183,49 +282,146 @@ public static function fetch_marking(stdClass $user): ?array {
/**
* Return mod data - due date & require marking.
*
* TODO - turnitin, quiz.
*
* @param cm_info $mod
* @param stdClass $assess
*/
public static function get_mod_data($mod, $assess): ?stdClass {
global $CFG;
// Mods have different fields for due date, and require marking.
global $CFG, $DB;
// Mods have different fields for due date.
switch ($mod->modname) {
case 'assign':

// Check mod due date is relevant.
$duedate = self::duedate_in_range($mod->customdata['duedate']);
if (!$duedate) {
return null;
}
break;
case 'quiz':
$record = $DB->get_record('quiz', ['id' => $mod->instance], 'timeclose');
// Check if mod due date is present and relevant.
$duedate = isset($record->timeclose) ? self::duedate_in_range($record->timeclose) : false;
break;
case 'turnitintooltwo':
$record = $DB->get_record('turnitintooltwo_parts', ['id' => $assess->partid], 'dtdue');
// Check if mod due date is present and relevant.
$duedate = isset($record->dtdue) ? self::duedate_in_range($record->dtdue) : false;
break;
default:
return null;
}
if (!$duedate) {
return null;
}

// Add dates.
$assess->unixtimestamp = $duedate;
$assess->duedate = date('jS M', $duedate);

// Require marking.
require_once($CFG->dirroot.'/mod/assign/locallib.php');
$context = context_module::instance($mod->id);
$assignment = new assign($context, $mod, $mod->course);
$assess->requiremarking = $assignment->count_submissions_need_grading();
if (!$assess->requiremarking) {
return null;
// Add dates.
$assess->unixtimestamp = $duedate;
$assess->duedate = date('jS M', $duedate);

// Require marking.
$assess->requiremarking = self::get_required_markings($mod);
if (!$assess->requiremarking) {
return null;
}
$assess->markingurl = new moodle_url('/mod/'. $mod->modname. '/view.php',
['id' => $assess->cmid, 'action' => 'grader']
);

// Return template data.
return $assess;

}

/**
* Get the required markings for an assessment module.
*
* @param cm_info $mod
* @return int
* @throws dml_exception
*/
protected static function get_required_markings(cm_info $mod) {
global $CFG, $DB;

// Assignments provide a way to count submissions that needs grading.
if ($mod->modname === 'assign') {
require_once($CFG->dirroot.'/mod/assign/locallib.php');
$context = context_module::instance($mod->id);
$assignment = new assign($context, $mod, $mod->course);
return $assignment->count_submissions_need_grading();
}

// For modules other than assignments get the student IDs that have submissions.
if ($submissions = self::get_module_submissions($mod)) {
$sql = "SELECT DISTINCT gg.userid
FROM {grade_grades} gg
WHERE gg.itemid = :modid AND gg.finalgrade > :finalgrade";
$params = ['modid' => $mod->id, 'finalgrade' => -1];

// Execute the query.
$studentids = $DB->get_fieldset_sql($sql, $params);
// Count and return all student IDs in submission that are not (yet) to be found in gradings.
$missinggrades = 0;
foreach ($submissions as $submitterid) {
if (!in_array($submitterid, $studentids)) {
$missinggrades++;
}
$assess->markingurl = new moodle_url('/mod/'. $mod->modname. '/view.php',
['id' => $assess->cmid, 'action' => 'grader']
);
}
return $missinggrades;
}
// No submissions - no missing grades.
return 0;
}

// Return template data.
return $assess;
/**
* Get an array of distinct student IDs with submissions for a given module.
*
* @param cm_info $mod
* @return array
*/
public static function get_module_submissions(cm_info $mod): array {
global $DB;

// TODO - quiz - 'timeclose' ?.
case 'quiz':
return null;
// TODO - turnitin.
default:
return null;
if ($mod) {
switch ($mod->modname) {
case 'assign':
// No need to support here, as assignments provide their own methods to count submissions and gradings.
return [];
case 'lesson':
$sql = "SELECT DISTINCT userid FROM {lesson_attempts} WHERE lessonid = :lessonid";
$params = ['lessonid' => $mod->instance, 'correct' => 1];
break;
case 'quiz':
$sql = "SELECT DISTINCT userid FROM {quiz_attempts} WHERE quiz = :quiz AND state = :state";
$params = ['quiz' => $mod->instance, 'state' => 'finished'];
break;
case 'turnitintooltwo':
$sql = "SELECT DISTINCT userid FROM {turnitintooltwo_submissions} WHERE turnitintooltwoid = :turnitintooltwoid";
$params = ['turnitintooltwoid' => $mod->instance];
break;
case 'scorm':
return [];
case 'workshop':
$sql = "SELECT DISTINCT authorid FROM {workshop_submissions} WHERE workshopid = :workshopid";
$params = ['workshopid' => $mod->instance];
break;
default:
return [];
}
return $DB->get_fieldset_sql($sql, $params);
}
return [];
}

/**
* Get separate parts for a turnitin module.
*
* @param cm_info $mod
* @return array
* @throws dml_exception
*/
public static function get_turnitin_parts(cm_info $mod) {
global $DB;

$sql = "SELECT * FROM {turnitintooltwo_parts} WHERE turnitintooltwoid = :iteminstance";
$params = ['iteminstance' => $mod->instance];
// Execute the query and return the result.
return $DB->get_records_sql($sql, $params);
}

/**
Expand Down

0 comments on commit df0b905

Please sign in to comment.