/** * Do the job. */ public function execute() { if (\local_o365\utils::is_configured() !== true) { return false; } $aadsyncenabled = get_config('local_o365', 'aadsync'); if (empty($aadsyncenabled) || $aadsyncenabled === 'photosynconlogin') { mtrace('Azure AD cron sync disabled. Nothing to do.'); return true; } $httpclient = new \local_o365\httpclient(); $clientdata = \local_o365\oauth2\clientdata::instance_from_oidc(); $usersync = new \local_o365\feature\usersync\main($clientdata, $httpclient); $skiptoken = get_config('local_o365', 'task_usersync_lastskiptoken'); if (empty($skiptoken)) { $skiptoken = ''; } for ($i = 0; $i < 5; $i++) { $users = $usersync->get_users('default', $skiptoken); if (!empty($users) && is_array($users) && !empty($users['value']) && is_array($users['value'])) { $usersync->sync_users($users['value']); } else { // No users returned, we're likely past the last page of results. Erase deltalink state and exit loop. mtrace('No more users to sync.'); set_config('task_usersync_lastskiptoken', '', 'local_o365'); break; } $nextlink = ''; if (isset($users['odata.nextLink'])) { $nextlink = $users['odata.nextLink']; } else { if (isset($users['@odata.nextLink'])) { $nextlink = $users['@odata.nextLink']; } } // If we have an odata.nextLink, extract deltalink value and store in $deltalink for the next loop. Otherwise break. if (!empty($nextlink)) { $skiptoken = $this->extract_skiptoken($nextlink); if (empty($skiptoken)) { $skiptoken = ''; mtrace('Bad odata.nextLink received.'); break; } } else { $skiptoken = ''; mtrace('No odata.nextLink received.'); break; } } if (!empty($skiptoken)) { mtrace('Partial user sync completed. Saving place for next run.'); } else { mtrace('Full user sync completed. Resetting saved state for new run.'); } set_config('task_usersync_lastskiptoken', $skiptoken, 'local_o365'); return true; }
/** * Handle role_deleted event * * Does the following: * - Unfortunately the role has already been deleted when we hear about it here, and have no way to determine the affected * users. Therefore, we have to do a global sync. * * @param \core\event\role_deleted $event The triggered event. * @return bool Success/Failure. */ public static function handle_role_deleted(\core\event\role_deleted $event) { if (\local_o365\utils::is_configured() !== true) { return false; } $roleid = $event->objectid; // Role deletions can be heavy - run in cron. $spaccesssync = new \local_o365\task\sharepointaccesssync(); $spaccesssync->set_custom_data(['roleid' => '*', 'userid' => '*', 'contextid' => null]); \core\task\manager::queue_adhoc_task($spaccesssync); return true; }
/** * Setup repistory form. * * @param moodleform $mform Moodle form (passed by reference) * @param string $classname repository class name */ public static function type_config_form($mform, $classname = 'repository') { global $CFG; $a = new stdClass(); if (\local_o365\utils::is_configured() !== true) { $mform->addElement('static', null, '', get_string('notconfigured', 'repository_onenote', $CFG->wwwroot)); } parent::type_config_form($mform); }
/** * Handle group_member_removed event to remove a user from an o365 group. * * @param \core\event\group_member_removed $event The triggered event. * @return bool Success/Failure. */ public static function handle_group_member_removed(\core\event\group_member_removed $event) { global $DB; if (\local_o365\utils::is_configured() !== true) { return false; } $unifiedapiclient = static::get_unified_api('handle_group_member_removed'); if (empty($unifiedapiclient)) { return false; } $azureadapiclient = static::get_azuread_api('handle_group_member_removed'); if (empty($azureadapiclient)) { return false; } $newmemberid = $event->relateduserid; $usergroupid = $event->objectid; // Look up group. $groupobjectrec = static::get_stored_groupdata($usergroupid, 'handle_group_member_removed'); if (empty($groupobjectrec)) { return false; } // Look up user. $userobjectdata = $DB->get_record('local_o365_objects', ['type' => 'user', 'moodleid' => $newmemberid]); if (empty($userobjectdata)) { $msg = 'Not removing user "' . $newmemberid . '" from group "' . $usergroupid . '". No Azure AD data for user found.'; $caller = '\\local_o365\\feature\\usergroups\\observers::handle_group_member_removed'; \local_o365\utils::debug($msg, $caller); return false; } $result = $azureadapiclient->remove_member_from_group($groupobjectrec->objectid, $userobjectdata->objectid); if ($result !== true) { $msg = 'Couldn\'t remove user from group.'; $caller = '\\local_o365\\feature\\usergroups\\observers::handle_group_member_removed'; \local_o365\utils::debug($msg, $caller, $result); return false; } return true; }
/** * Do the job. */ public function execute() { global $DB, $CFG; require_once $CFG->dirroot . '/calendar/lib.php'; if (\local_o365\utils::is_configured() !== true) { return false; } // Get calendars set to sync in. $starttime = time(); \local_o365\feature\calsync\observers::set_event_import(true); // Using a direct query here so we don't run into static cache issues. $laststarttime = $DB->get_record('config_plugins', ['plugin' => 'local_o365', 'name' => 'calsyncinlastrun']); $laststarttime = !empty($laststarttime) && !empty($laststarttime->value) ? $laststarttime->value : 0; $httpclient = new \local_o365\httpclient(); $clientdata = \local_o365\oauth2\clientdata::instance_from_oidc(); $calsubs = $DB->get_recordset_select('local_o365_calsub', 'syncbehav = ? OR syncbehav = ?', ['in', 'both']); $calsync = new \local_o365\feature\calsync\main($clientdata, $httpclient); foreach ($calsubs as $i => $calsub) { try { mtrace('Syncing events for user #' . $calsub->user_id); $events = $calsync->get_events($calsub->user_id, $calsub->o365calid, $laststarttime); if (!empty($events) && is_array($events) && isset($events['value']) && is_array($events['value'])) { if (!empty($events['value'])) { foreach ($events['value'] as $i => $event) { if (!isset($event['Id'])) { $errmsg = 'Skipped an event because of malformed data.'; \local_o365\utils::debug($errmsg, 'importfromoutlook', $event); mtrace($errmsg); continue; } $idmapexists = $DB->record_exists('local_o365_calidmap', ['outlookeventid' => $event['Id']]); if ($idmapexists === false) { // Create Moodle event. $eventparams = ['name' => $event['Subject'], 'description' => $event['Body']['Content'], 'eventtype' => $calsub->caltype, 'repeatid' => 0, 'modulename' => 0, 'instance' => 0, 'timestart' => strtotime($event['Start']), 'visible' => 1, 'uuid' => '', 'sequence' => 1]; $end = strtotime($event['End']); $eventparams['timeduration'] = $end - $eventparams['timestart']; if ($calsub->caltype === 'user') { $eventparams['userid'] = $calsub->caltypeid; } if ($calsub->caltype === 'course') { $eventparams['courseid'] = $calsub->caltypeid; } $moodleevent = \calendar_event::create($eventparams, false); if (!empty($moodleevent) && !empty($moodleevent->id)) { $idmaprec = ['eventid' => $moodleevent->id, 'outlookeventid' => $event['Id'], 'origin' => 'o365', 'userid' => $calsub->user_id]; $DB->insert_record('local_o365_calidmap', (object) $idmaprec); mtrace('Successfully imported event #' . $moodleevent->id); } } } } else { mtrace('No new events to sync in.'); } } else { $errmsg = 'Bad response received when fetching events.'; \local_o365\utils::debug($errmsg, 'importfromoutlook', $events); mtrace($errmsg); } } catch (\Exception $e) { \local_o365\utils::debug('Error syncing events', 'importfromoutlook', $e->getMessage()); mtrace('Error: ' . $e->getMessage()); } } $calsubs->close(); \local_o365\feature\calsync\observers::set_event_import(false); set_config('calsyncinlastrun', $starttime, 'local_o365'); return true; }
/** * Handle calendar_unsubscribed event - queue calendar sync jobs for cron. * * @param \local_o365\event\calendar_unsubscribed $event The triggered event. * @return bool Success/Failure. */ public static function handle_calendar_unsubscribed(\local_o365\event\calendar_unsubscribed $event) { if (\local_o365\utils::is_configured() !== true) { return false; } $eventdata = $event->get_data(); $calunsubscribe = new \local_o365\feature\calsync\task\syncoldevents(); $calunsubscribe->set_custom_data(['caltype' => $eventdata['other']['caltype'], 'caltypeid' => isset($eventdata['other']['caltypeid']) ? $eventdata['other']['caltypeid'] : 0, 'userid' => $eventdata['userid'], 'timecreated' => time()]); \core\task\manager::queue_adhoc_task($calunsubscribe); return true; }
/** * Do the job. */ public function execute() { $opdata = $this->get_custom_data(); $timecreated = isset($opdata->timecreated) ? $opdata->timecreated : time(); if (\local_o365\utils::is_configured() !== true) { \local_o365\utils::debug(get_string('erroracpauthoidcnotconfig', 'local_o365'), get_called_class()); return false; } // Sync site events. if ($opdata->caltype === 'site') { $this->sync_siteevents($timecreated); } else { if ($opdata->caltype === 'course') { $this->sync_courseevents($opdata->caltypeid, $timecreated); } else { if ($opdata->caltype === 'user') { $this->sync_userevents($opdata->userid, $timecreated); } } } }
/** * Do the job. */ public function execute() { global $DB; if (\local_o365\utils::is_configured() !== true) { return false; } $configsetting = get_config('local_o365', 'creategroups'); if (empty($configsetting)) { mtrace('Groups not enabled, skipping...'); return true; } $now = time(); $httpclient = new \local_o365\httpclient(); $clientdata = \local_o365\oauth2\clientdata::instance_from_oidc(); $unifiedresource = \local_o365\rest\unified::get_resource(); $unifiedtoken = \local_o365\oauth2\systemtoken::instance(null, $unifiedresource, $clientdata, $httpclient); if (empty($unifiedtoken)) { mtrace('Could not get unified API token.'); return true; } $unifiedclient = new \local_o365\rest\unified($unifiedtoken, $httpclient); $aadresource = \local_o365\rest\azuread::get_resource(); $aadtoken = \local_o365\oauth2\systemtoken::instance(null, $aadresource, $clientdata, $httpclient); if (empty($aadtoken)) { mtrace('Could not get Azure AD token.'); return true; } $aadclient = new \local_o365\rest\azuread($aadtoken, $httpclient); $siterec = $DB->get_record('course', ['id' => SITEID]); $siteshortname = strtolower(preg_replace('/[^a-z0-9]+/iu', '', $siterec->shortname)); $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 != ? LIMIT 0, 5'; $params = ['group', 'course', SITEID]; $courses = $DB->get_recordset_sql($sql, $params); foreach ($courses as $course) { // Create group. $groupname = $siterec->shortname . ': ' . $course->fullname; $groupshortname = $siteshortname . '_' . $course->shortname; $response = $unifiedclient->create_group($groupname, $groupshortname); if (empty($response) || !is_array($response) || empty($response['id'])) { mtrace('Could not create group for course #' . $course->id); var_dump($response); continue; } mtrace('Created group ' . $response['id'] . ' for course #' . $course->id); $objectrec = ['type' => 'group', 'subtype' => 'course', 'objectid' => $response['id'], 'moodleid' => $course->id, 'o365name' => $groupname, 'timecreated' => $now, 'timemodified' => $now]; $objectrec['id'] = $DB->insert_record('local_o365_objects', (object) $objectrec); mtrace('Recorded group object (' . $objectrec['objectid'] . ') into object table with record id ' . $objectrec['id']); // It takes a little while for the group object to register. mtrace('Waiting 10 seconds for group to register...'); sleep(10); // Add enrolled users to group. mtrace('Adding users to group (' . $objectrec['objectid'] . ')'); $coursecontext = \context_course::instance($course->id); list($esql, $params) = get_enrolled_sql($coursecontext); $sql = "SELECT u.*,\n tok.oidcuniqid as userobjectid\n FROM {user} u\n JOIN ({$esql}) je ON je.id = u.id\n JOIN {auth_oidc_token} tok ON tok.username = u.username AND tok.resource = :tokresource\n WHERE u.deleted = 0"; $params['tokresource'] = 'https://graph.windows.net'; $enrolled = $DB->get_recordset_sql($sql, $params); foreach ($enrolled as $user) { $response = $aadclient->add_member_to_group($objectrec['objectid'], $user->userobjectid); if ($response === true) { mtrace('Added user #' . $user->id . ' (' . $user->userobjectid . ')'); } else { mtrace('Could not add user #' . $user->id . ' (' . $user->userobjectid . ')'); mtrace('Received: ' . $response); } } $enrolled->close(); } $courses->close(); }