in classes/feature/usergroups/coursegroups.php [92:270]
public function create_groups_for_new_courses() {
global $DB;
$createteams = get_config('local_o365', 'createteams');
if ($createteams === 'onall' || $createteams === 'oncustom') {
$coursesenabled = \local_o365\feature\usergroups\utils::get_enabled_courses();
if (empty($coursesenabled)) {
$this->mtrace('Custom group creation is enabled, but no courses are enabled.');
return false;
}
} else {
$this->mtrace('Group creation is disabled.');
return false;
}
if (is_array($coursesenabled)) {
[$coursesinsql, $coursesparams] = $DB->get_in_or_equal($coursesenabled);
} else {
$coursesinsql = '';
$coursesparams = [];
}
// First process courses with groups that have been "soft-deleted".
$sql = 'SELECT crs.id as courseid,
obj.*
FROM {course} crs
JOIN {local_o365_objects} obj ON obj.type = ? AND obj.subtype = ? AND obj.moodleid = crs.id';
$params = ['group', 'course'];
if (!empty($coursesinsql)) {
$sql .= ' WHERE crs.id '.$coursesinsql;
$params = array_merge($params, $coursesparams);
}
$objectrecs = $DB->get_recordset_sql($sql, $params);
foreach ($objectrecs as $objectrec) {
$metadata = (!empty($objectrec->metadata)) ? @json_decode($objectrec->metadata, true) : [];
if (is_array($metadata) && !empty($metadata['softdelete'])) {
$this->mtrace('Attempting to restore group for course #'.$objectrec->courseid);
$result = $this->restore_group($objectrec->id, $objectrec->objectid, $metadata);
if ($result === true) {
$this->mtrace('....success!');
} else {
$this->mtrace('....failed. Group may have been deleted for too long.');
}
}
}
// Process courses without an associated group.
$sql = 'SELECT crs.*
FROM {course} crs
LEFT JOIN {local_o365_objects} obj ON obj.type = ? AND obj.subtype = ? AND obj.moodleid = crs.id
WHERE obj.id IS NULL AND crs.id != ? AND crs.visible != 0';
// The "crs.visible != 0" is used to filter out courses in the process of copy or restore, which may contain incorrect or
// incomplete contents.
$params = ['group', 'course', SITEID];
if (!empty($coursesinsql)) {
$sql .= ' AND crs.id '.$coursesinsql;
$params = array_merge($params, $coursesparams);
}
$courselimit = get_config('local_o365', 'courses_per_task');
if (!$courselimit) {
$courselimit = 5;
}
$courses = $DB->get_recordset_sql($sql, $params, 0, $courselimit);
$coursesprocessed = 0;
foreach ($courses as $course) {
$coursesprocessed++;
$createclassteam = false;
$creategrouponly = true;
$ownerid = null;
$teacherid = null;
if (\local_o365\feature\usergroups\utils::course_is_group_feature_enabled($course->id, 'team')) {
$creategrouponly = false;
$teacherids = static::get_team_owner_ids_by_course_id($course->id);
foreach ($teacherids as $teacherid) {
if ($ownerid = $DB->get_field('local_o365_objects', 'objectid', ['type' => 'user', 'moodleid' => $teacherid])) {
$createclassteam = true;
break;
}
}
}
if ($createclassteam) {
// Create class team directly.
try {
$objectrec = $this->create_class_team($course, $ownerid);
} catch (\Exception $e) {
$this->mtrace('Could not create class team for course #' . $course->id . '. Reason: ' . $e->getMessage());
continue;
}
} else if ($creategrouponly || get_config('local_o365', 'group_creation_fallback') == true) {
// Create group.
try {
$objectrec = $this->create_group($course);
} catch (\Exception $e) {
$this->mtrace('Could not create group for course #' . $course->id . '. Reason: ' . $e->getMessage());
continue;
}
} else {
// Option to fall back to group is disabled, and Team owner is not found.
$this->mtrace('Skip creating class team for course #' . $course->id . '. Reason: missing Team owner');
continue;
}
$retrycounter = 0;
while ($retrycounter <= API_CALL_RETRY_LIMIT) {
if ($retrycounter) {
$this->mtrace('..... Retry #' . $retrycounter);
sleep(10);
}
try {
$this->resync_group_membership($course->id, $objectrec['objectid']);
break;
} catch (\Exception $e) {
$this->mtrace('Could not sync users to group for course #'.$course->id.'. Reason: '.$e->getMessage());
$retrycounter++;
}
}
}
if (empty($coursesprocessed)) {
$this->mtrace('All courses have a group recorded.');
} else {
$this->mtrace('Processed courses: '.$coursesprocessed);
}
$courses->close();
// Process team sync changes.
$sql = 'SELECT crs.*
FROM {course} crs
LEFT JOIN {local_o365_objects} obj_g ON obj_g.type = ? AND obj_g.subtype = ? AND obj_g.moodleid = crs.id
LEFT JOIN {local_o365_objects} obj_t ON obj_t.type = ? AND obj_t.subtype = ? AND obj_t.moodleid = crs.id
WHERE obj_g.id IS NOT NULL
AND obj_t.id IS NULL
AND crs.id != ?';
$params = ['group', 'course', 'group', 'courseteam', SITEID];
if (!empty($coursesinsql)) {
$sql .= ' AND crs.id ' . $coursesinsql;
$params = array_merge($params, $coursesparams);
}
$courses = $DB->get_recordset_sql($sql, $params);
$coursesprocessed = 0;
// Get app ID.
if (!empty($courses)) {
$appid = get_config('local_o365', 'moodle_app_id');
}
foreach ($courses as $course) {
if (\local_o365\feature\usergroups\utils::course_is_group_feature_enabled($course->id, 'team')) {
$this->mtrace('Attempting to create team for course #' . $course->id . '...');
$coursesprocessed++;
$groupobjectrec = $DB->get_record('local_o365_objects',
['type' => 'group', 'subtype' => 'course', 'moodleid' => $course->id]);
if (empty($groupobjectrec)) {
$errmsg = 'Could not find group object ID in local_o365_objects for course ' . $course->id;
$errmsg .= 'Please ensure group exists first.';
$this->mtrace($errmsg);
continue;
}
$teacherids = static::get_team_owner_ids_by_course_id($course->id);
$hasowner = false;
foreach ($teacherids as $teacherid) {
if ($ownerid = $DB->get_field('local_o365_objects', 'objectid', ['type' => 'user', 'moodleid' => $teacherid])) {
$hasowner = true;
break;
}
}
if ($hasowner) {
try {
$this->create_team($course->id, $groupobjectrec->objectid, $appid);
} catch (\Exception $e) {
$this->mtrace('Could not create team for course #' . $course->id . '. Reason: ' . $e->getMessage());
}
} else {
$this->mtrace('Skip creating team for course #' . $course->id . '. Reason: No owner');
}
}
}
}