/**
  * Get the content of the block.
  *
  * @return stdObject
  */
 public function get_content()
 {
     global $USER, $DB;
     if (!isloggedin()) {
         return null;
     }
     if ($this->content !== null) {
         return $this->content;
     }
     $this->content = new \stdClass();
     $this->content->text = '';
     $this->content->footer = '';
     try {
         $o365connected = \local_o365\utils::is_o365_connected($USER->id);
         if ($o365connected === true) {
             $this->content->text .= $this->get_content_connected();
         } else {
             $connection = $DB->get_record('local_o365_connections', ['muserid' => $USER->id]);
             if (!empty($connection)) {
                 $uselogin = !empty($connection->uselogin) ? true : false;
                 $this->content->text .= $this->get_content_matched($connection->aadupn, $uselogin);
             } else {
                 $this->content->text .= $this->get_content_notconnected();
             }
         }
     } catch (\Exception $e) {
         $this->content->text = $e->getMessage();
     }
     return $this->content;
 }
Beispiel #2
0
 /**
  * Run before the main page mode - determines connection status.
  *
  * @return bool Success/Failure.
  */
 public function header()
 {
     global $USER, $DB;
     $this->o365loginconnected = $USER->auth === 'oidc' ? true : false;
     $this->o365connected = \local_o365\utils::is_o365_connected($USER->id);
     return true;
 }
Beispiel #3
0
 /**
  * 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;
 }
Beispiel #4
0
 /**
  * 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);
 }
Beispiel #5
0
 /**
  * Create a OneNote page inside the given section using the postdata containing the content of the page.
  * @param string $sectionid Id of OneNote section which the page will be created in.
  * @param string $postdata String containing the postdata containing the contents of the page.
  * @param string $boundary Boundary string to be used during the POST request.
  * @return mixed|null|string The HTTP response object from the POST request.
  */
 protected function create_page_from_postdata($sectionid, $postdata, $boundary)
 {
     try {
         $url = static::API . '/sections/' . $sectionid . '/pages';
         $token = $this->get_token();
         if (empty($token)) {
             \local_o365\utils::debug('Could not get user token', 'create_page_from_postdata');
             return null;
         }
         $ch = curl_init($url);
         curl_setopt($ch, CURLOPT_HEADER, 1);
         curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
         $headers = ['Content-Type: multipart/form-data; boundary=' . $boundary, 'Authorization: Bearer ' . rawurlencode($token)];
         curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
         curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
         curl_setopt($ch, CURLOPT_POST, true);
         curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
         $rawresponse = curl_exec($ch);
         // Check if curl call fails.
         if ($rawresponse === false) {
             $errorno = curl_errno($ch);
             curl_close($ch);
             // If curl call fails and reason is net connectivity return it or return null.
             return in_array($errorno, ['6', '7', '28']) ? 'connection_error' : null;
         }
         $info = curl_getinfo($ch);
         curl_close($ch);
         if ($info['http_code'] == 201) {
             $responsewithoutheader = substr($rawresponse, $info['header_size']);
             $response = json_decode($responsewithoutheader);
             return $response;
         }
     } catch (\Exception $e) {
         \local_o365\utils::debug($e->getMessage());
     }
     return null;
 }
 /**
  * Do the job.
  */
 public function execute()
 {
     global $DB;
     // API Setup.
     try {
         $spresource = \local_o365\rest\sharepoint::get_resource();
         if (empty($spresource)) {
             throw new \moodle_exception('erroracplocalo365notconfig', 'local_o365');
         }
         $httpclient = new \local_o365\httpclient();
         $clientdata = \local_o365\oauth2\clientdata::instance_from_oidc();
         $sptoken = \local_o365\oauth2\systemtoken::instance(null, $spresource, $clientdata, $httpclient);
         if (empty($sptoken)) {
             throw new \moodle_exception('erroracpnosptoken', 'local_o365');
         }
         $sharepoint = new \local_o365\rest\sharepoint($sptoken, $httpclient);
     } catch (\Exception $e) {
         $errmsg = 'ERROR: Problem initializing SharePoint API. Reason: ' . $e->getMessage();
         mtrace($errmsg);
         \local_o365\utils::debug($errmsg, 'local_o365\\task\\sharepointinit::execute');
         set_config('sharepoint_initialized', 'error', 'local_o365');
         return false;
     }
     // Create parent site(s).
     try {
         mtrace('Creating parent site for Moodle...');
         $moodlesiteuri = $sharepoint->get_moodle_parent_site_uri();
         $sitelevels = explode('/', $moodlesiteuri);
         $currentparentsite = '';
         foreach ($sitelevels as $partialurl) {
             $sharepoint->set_site($currentparentsite);
             if ($sharepoint->site_exists($currentparentsite . '/' . $partialurl) === false) {
                 $moodlesitename = get_string('acp_parentsite_name', 'local_o365');
                 $moodlesitedesc = get_string('acp_parentsite_desc', 'local_o365');
                 $frontpagerec = $DB->get_record('course', ['id' => SITEID], 'id,shortname');
                 if (!empty($frontpagerec) && !empty($frontpagerec->shortname)) {
                     $moodlesitename = $frontpagerec->shortname;
                 }
                 mtrace('Setting parent site to "' . $currentparentsite . '", creating subsite "' . $partialurl . '"');
                 $result = $sharepoint->create_site($moodlesitename, $partialurl, $moodlesitedesc);
                 $currentparentsite .= '/' . $partialurl;
                 mtrace('Created parent site "' . $currentparentsite . '"');
             } else {
                 $currentparentsite .= '/' . $partialurl;
                 mtrace('Parent site "' . $currentparentsite . '" already exists.');
             }
         }
         mtrace('Finished creating Moodle parent site.');
     } catch (\Exception $e) {
         $errmsg = 'ERROR: Problem creating parent site. Reason: ' . $e->getMessage();
         mtrace($errmsg);
         \local_o365\utils::debug($errmsg, 'local_o365\\task\\sharepointinit::execute');
         set_config('sharepoint_initialized', 'error', 'local_o365');
         return false;
     }
     // Create course sites.
     mtrace('Creating course subsites in "' . $moodlesiteuri . '"');
     $sharepoint->set_site($moodlesiteuri);
     $courses = $DB->get_recordset('course');
     $successes = [];
     $failures = [];
     foreach ($courses as $course) {
         if ($course->id == SITEID) {
             continue;
         }
         try {
             $sharepoint->create_course_site($course);
             $successes[] = $course->id;
             mtrace('Created course subsite for course ' . $course->id);
         } catch (\Exception $e) {
             mtrace('Encountered error creating course subsite for course ' . $course->id);
             $failures[$course->id] = $e->getMessage();
         }
     }
     if (!empty($failures)) {
         $errmsg = 'ERROR: Encountered problems creating course sites.';
         mtrace($errmsg . ' See logs.');
         \local_o365\utils::debug($errmsg, 'local_o365\\task\\sharepointinit::execute', $failures);
         set_config('sharepoint_initialized', 'error', 'local_o365');
     } else {
         set_config('sharepoint_initialized', '1', 'local_o365');
         mtrace('SharePoint successfully initialized.');
         return true;
     }
 }
/**
 * Looks for links pointing to Office 365 Video content and processes them.
 *
 * @param $link HTML tag containing a link
 * @return string HTML content after processing.
 */
function filter_oembed_o365videocallback($link)
{
    if (empty($link[3])) {
        return $link[0];
    }
    $link[3] = preg_replace("/&amp;/", "&", $link[3]);
    $values = array();
    parse_str($link[3], $values);
    if (empty($values['chid']) || empty($values['vid'])) {
        return $link[0];
    }
    if (!\local_o365\rest\sharepoint::is_configured()) {
        \local_o365\utils::debug('filter_oembed share point is not configured', 'filter_oembed_o365videocallback');
        return $link[0];
    }
    try {
        $spresource = \local_o365\rest\sharepoint::get_resource();
        if (!empty($spresource)) {
            $httpclient = new \local_o365\httpclient();
            $clientdata = \local_o365\oauth2\clientdata::instance_from_oidc();
            $sptoken = \local_o365\oauth2\systemtoken::instance(null, $spresource, $clientdata, $httpclient);
            if (!empty($sptoken)) {
                $sharepoint = new \local_o365\rest\sharepoint($sptoken, $httpclient);
                // Retrieve api url for video service.
                $url = $sharepoint->videoservice_discover();
                if (!empty($url)) {
                    $sharepoint->override_resource($url);
                    $width = 640;
                    if (!empty($values['width'])) {
                        $width = $values['width'];
                    }
                    $height = 360;
                    if (!empty($values['height'])) {
                        $height = $values['height'];
                    }
                    // Retrieve embed code.
                    return $sharepoint->get_video_embed_code($values['chid'], $values['vid'], $width, $height);
                }
            }
        }
    } catch (\Exception $e) {
        \local_o365\utils::debug('filter_oembed share point execption: ' . $e->getMessage(), 'filter_oembed_o365videocallback');
    }
    return $link[0];
}
 /**
  * Do the job.
  */
 public function execute()
 {
     global $DB;
     $sql = 'SELECT mq.*,
                    u.id as muserid,
                    muserconn.id as muserexistingconnectionid,
                    officeconn.id as officeuserexistingconnectionid,
                    oidctok.id as officeuserexistingoidctoken
               FROM {local_o365_matchqueue} mq
          LEFT JOIN {user} u ON mq.musername = u.username
          LEFT JOIN {local_o365_connections} muserconn ON muserconn.muserid = u.id
          LEFT JOIN {local_o365_connections} officeconn ON officeconn.aadupn = mq.o365username
          LEFT JOIN {auth_oidc_token} oidctok ON oidctok.oidcusername = mq.o365username
              WHERE mq.completed = ? AND mq.errormessage = ""
           ORDER BY mq.id ASC
              LIMIT 0, 100';
     $params = ['0'];
     $matchqueue = $DB->get_recordset_sql($sql, $params);
     $apiclient = $this->get_api();
     foreach ($matchqueue as $matchrec) {
         mtrace('Processing ' . $matchrec->musername . '/' . $matchrec->o365username);
         try {
             // Check for matching Moodle user.
             if (empty($matchrec->muserid)) {
                 $updatedrec = new \stdClass();
                 $updatedrec->id = $matchrec->id;
                 $updatedrec->errormessage = get_string('task_processmatchqueue_err_nomuser', 'local_o365');
                 $updatedrec->completed = 1;
                 $DB->update_record('local_o365_matchqueue', $updatedrec);
                 mtrace($updatedrec->errormessage);
                 continue;
             }
             // Check whether Moodle user is already o365 connected.
             if (\local_o365\utils::is_o365_connected($matchrec->muserid)) {
                 $updatedrec = new \stdClass();
                 $updatedrec->id = $matchrec->id;
                 $updatedrec->errormessage = get_string('task_processmatchqueue_err_museralreadyo365', 'local_o365');
                 $updatedrec->completed = 1;
                 $DB->update_record('local_o365_matchqueue', $updatedrec);
                 mtrace($updatedrec->errormessage);
                 continue;
             }
             // Check existing matches for Moodle user.
             if (!empty($matchrec->muserexistingconnectionid)) {
                 $updatedrec = new \stdClass();
                 $updatedrec->id = $matchrec->id;
                 $updatedrec->errormessage = get_string('task_processmatchqueue_err_museralreadymatched', 'local_o365');
                 $updatedrec->completed = 1;
                 $DB->update_record('local_o365_matchqueue', $updatedrec);
                 mtrace($updatedrec->errormessage);
                 continue;
             }
             // Check existing matches for Office user.
             if (!empty($matchrec->officeuserexistingconnectionid)) {
                 $updatedrec = new \stdClass();
                 $updatedrec->id = $matchrec->id;
                 $updatedrec->errormessage = get_string('task_processmatchqueue_err_o365useralreadymatched', 'local_o365');
                 $updatedrec->completed = 1;
                 $DB->update_record('local_o365_matchqueue', $updatedrec);
                 mtrace($updatedrec->errormessage);
                 continue;
             }
             // Check existing tokens for Office 365 user (indicates o365 user is already connected to someone).
             if (!empty($matchrec->officeuserexistingoidctoken)) {
                 $updatedrec = new \stdClass();
                 $updatedrec->id = $matchrec->id;
                 $updatedrec->errormessage = get_string('task_processmatchqueue_err_o365useralreadyconnected', 'local_o365');
                 $updatedrec->completed = 1;
                 $DB->update_record('local_o365_matchqueue', $updatedrec);
                 mtrace($updatedrec->errormessage);
                 continue;
             }
             // Check o365 username.
             $userfound = false;
             try {
                 $o365user = $apiclient->get_user_by_upn($matchrec->o365username);
                 $userfound = true;
             } catch (\Exception $e) {
                 $userfound = false;
             }
             if ($userfound !== true) {
                 $updatedrec = new \stdClass();
                 $updatedrec->id = $matchrec->id;
                 $updatedrec->errormessage = get_string('task_processmatchqueue_err_noo365user', 'local_o365');
                 $updatedrec->completed = 1;
                 $DB->update_record('local_o365_matchqueue', $updatedrec);
                 mtrace($updatedrec->errormessage);
                 continue;
             }
             // Match validated.
             $connectionrec = new \stdClass();
             $connectionrec->muserid = $matchrec->muserid;
             $connectionrec->aadupn = \core_text::strtolower($o365user['userPrincipalName']);
             $connectionrec->uselogin = 0;
             $DB->insert_record('local_o365_connections', $connectionrec);
             $updatedrec = new \stdClass();
             $updatedrec->id = $matchrec->id;
             $updatedrec->completed = 1;
             $DB->update_record('local_o365_matchqueue', $updatedrec);
             mtrace('Match record created for userid #' . $matchrec->muserid . ' and o365 user ' . $connectionrec->aadupn);
         } catch (\Exception $e) {
             $exceptionstring = $e->getMessage() . ': ' . $e->debuginfo;
             $updatedrec = new \stdClass();
             $updatedrec->id = $matchrec->id;
             $updatedrec->errormessage = $exceptionstring;
             $updatedrec->completed = 1;
             $DB->update_record('local_o365_matchqueue', $updatedrec);
             mtrace($exceptionstring);
         }
     }
     $matchqueue->close();
     return true;
 }
Beispiel #9
0
 /**
  * Get a token instance for a new resource.
  *
  * @param string $resource The new resource.
  * @param \local_o365\oauth2\clientdata $clientdata Client information.
  * @param \local_o365\httpclientinterface $httpclient An HTTP client.
  * @return \local_o365\oauth2\token|bool A constructed token for the new resource, or false if failure.
  */
 public static function get_for_new_resource($userid, $resource, \local_o365\oauth2\clientdata $clientdata, $httpclient)
 {
     $aadgraphtoken = static::instance($userid, 'https://graph.windows.net', $clientdata, $httpclient);
     if (!empty($aadgraphtoken)) {
         $params = ['client_id' => $clientdata->get_clientid(), 'client_secret' => $clientdata->get_clientsecret(), 'grant_type' => 'refresh_token', 'refresh_token' => $aadgraphtoken->get_refreshtoken(), 'resource' => $resource];
         $params = http_build_query($params, '', '&');
         $tokenendpoint = $clientdata->get_tokenendpoint();
         $header = ['Content-Type: application/x-www-form-urlencoded', 'Content-Length: ' . strlen($params)];
         $httpclient->resetHeader();
         $httpclient->setHeader($header);
         $tokenresult = $httpclient->post($tokenendpoint, $params);
         $tokenresult = @json_decode($tokenresult, true);
         if (!empty($tokenresult) && isset($tokenresult['token_type']) && $tokenresult['token_type'] === 'Bearer') {
             static::store_new_token($userid, $tokenresult['access_token'], $tokenresult['expires_on'], $tokenresult['refresh_token'], $tokenresult['scope'], $tokenresult['resource']);
             $token = static::instance($userid, $resource, $clientdata, $httpclient);
             return $token;
         } else {
             $errmsg = 'Problem encountered getting a new token.';
             if (isset($tokenresult['access_token'])) {
                 $tokenresult['access_token'] = '---';
             }
             if (isset($tokenresult['refresh_token'])) {
                 $tokenresult['refresh_token'] = '---';
             }
             $debuginfo = ['tokenresult' => $tokenresult, 'resource' => $resource];
             \local_o365\utils::debug($errmsg, 'local_o365\\oauth2\\token::get_for_new_resource', $debuginfo);
         }
     }
     return false;
 }
Beispiel #10
0
 /**
  * Get the Azure AD UPN of a connected Moodle user.
  *
  * @param \stdClass $user The Moodle user.
  * @return string|bool The user's Azure AD UPN, or false if failure.
  */
 public static function get_muser_upn($user)
 {
     global $DB;
     $now = time();
     if (is_numeric($user)) {
         $user = $DB->get_record('user', ['id' => $user]);
         if (empty($user)) {
             \local_o365\utils::debug('User not found', 'rest\\azuread\\get_muser_upn', $user);
             return false;
         }
     }
     // Get user UPN.
     $userobjectdata = $DB->get_record('local_o365_objects', ['type' => 'user', 'moodleid' => $user->id]);
     if (!empty($userobjectdata)) {
         return $userobjectdata->o365name;
     } else {
         // Get user data.
         $authoidcuserdata = $DB->get_record('auth_oidc_token', ['username' => $user->username]);
         if (empty($authoidcuserdata)) {
             // No data for the user in the OIDC token table. Can't proceed.
             \local_o365\utils::debug('No oidc token found for user.', 'rest\\azuread\\get_muser_upn', $user->username);
             return false;
         }
         $httpclient = new \local_o365\httpclient();
         try {
             $clientdata = \local_o365\oauth2\clientdata::instance_from_oidc();
         } catch (\Exception $e) {
             \local_o365\utils::debug($e->getMessage());
             return false;
         }
         $resource = static::get_resource();
         $token = \local_o365\oauth2\systemtoken::instance(null, $resource, $clientdata, $httpclient);
         $aadapiclient = new \local_o365\rest\azuread($token, $httpclient);
         $aaduserdata = $aadapiclient->get_user($authoidcuserdata->oidcuniqid);
         $userobjectdata = (object) ['type' => 'user', 'subtype' => '', 'objectid' => $aaduserdata['objectId'], 'o365name' => $aaduserdata['userPrincipalName'], 'moodleid' => $user->id, 'timecreated' => $now, 'timemodified' => $now];
         $userobjectdata->id = $DB->insert_record('local_o365_objects', $userobjectdata);
         return $userobjectdata->o365name;
     }
 }
Beispiel #11
0
 /**
  * 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;
 }
Beispiel #12
0
 /**
  * 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;
 }
Beispiel #13
0
 /**
  * Processes API responses.
  *
  * @param string $response The raw response from an API call.
  * @param array $expectedstructure A structure to validate.
  * @return array|null Array if successful, null if not.
  */
 public function process_apicall_response($response, array $expectedstructure = array())
 {
     $backtrace = debug_backtrace(0);
     $callingclass = isset($backtrace[1]['class']) ? $backtrace[1]['class'] : '?';
     $callingfunc = isset($backtrace[1]['function']) ? $backtrace[1]['function'] : '?';
     $callingline = isset($backtrace[0]['line']) ? $backtrace[0]['line'] : '?';
     $caller = $callingclass . '::' . $callingfunc . ':' . $callingline;
     $result = @json_decode($response, true);
     if (empty($result) || !is_array($result)) {
         \local_o365\utils::debug('Bad response received', $caller, $response);
         throw new \moodle_exception('erroro365apibadcall', 'local_o365');
     }
     if (isset($result['odata.error'])) {
         $errmsg = 'Error response received.';
         \local_o365\utils::debug($errmsg, $caller, $result['odata.error']);
         if (isset($result['odata.error']['message']) && isset($result['odata.error']['message']['value'])) {
             $apierrormessage = $result['odata.error']['message']['value'];
             throw new \moodle_exception('erroro365apibadcall_message', 'local_o365', '', htmlentities($apierrormessage));
         } else {
             throw new \moodle_exception('erroro365apibadcall', 'local_o365');
         }
     }
     if (isset($result['error'])) {
         $errmsg = 'Error response received.';
         \local_o365\utils::debug($errmsg, $caller, $result['error']);
         if (isset($result['error']['message'])) {
             $apierrormessage = 'Unknown error, check logs for more information.';
             if (is_string($result['error']['message'])) {
                 $apierrormessage = $result['error']['message'];
             } else {
                 if (is_array($result['error']['message']) && isset($result['error']['message']['value'])) {
                     $apierrormessage = $result['error']['message']['value'];
                 }
             }
             throw new \moodle_exception('erroro365apibadcall_message', 'local_o365', '', htmlentities($apierrormessage));
         } else {
             throw new \moodle_exception('erroro365apibadcall', 'local_o365');
         }
     }
     foreach ($expectedstructure as $key => $val) {
         if (!isset($result[$key])) {
             $errmsg = 'Invalid structure received. No "' . $key . '"';
             \local_o365\utils::debug($errmsg, $caller, $result);
             throw new \moodle_exception('erroro365apibadcall_message', 'local_o365', '', $errmsg);
         }
         if ($val !== null && $result[$key] !== $val) {
             $strreceivedval = \local_o365\utils::tostring($result[$key]);
             $strval = \local_o365\utils::tostring($val);
             $errmsg = 'Invalid structure received. Invalid "' . $key . '". Received "' . $strreceivedval . '", expected "' . $strval . '"';
             \local_o365\utils::debug($errmsg, $caller, $result);
             throw new \moodle_exception('erroro365apibadcall_message', 'local_o365', '', $errmsg);
         }
     }
     return $result;
 }
Beispiel #14
0
 /**
  * Gets the instance of the correct api class. Use this method to get an instance of the api class.
  *
  * @return \local_onenote\api\base An implementation of the OneNote API.
  */
 public static function getinstance()
 {
     global $USER, $SESSION, $CFG;
     $msaccountclass = '\\local_onenote\\api\\msaccount';
     $o365class = '\\local_onenote\\api\\o365';
     $iso365user = \local_o365\utils::is_o365_connected($USER->id) === true && class_exists('\\local_o365\\rest\\onenote') ? true : false;
     if ($iso365user === true) {
         require_once $CFG->dirroot . '/local/msaccount/msaccount_client.php';
         $sesskey = 'msaccount_client-' . md5(\msaccount_client::SCOPE);
         $disableo365onenote = get_user_preferences('local_o365_disableo365onenote', 0);
         $iso365user = !empty($SESSION->{$sesskey}) || !empty($disableo365onenote) ? false : $iso365user;
         if ($iso365user === true) {
             try {
                 $httpclient = new \local_o365\httpclient();
                 $clientdata = \local_o365\oauth2\clientdata::instance_from_oidc();
                 $onenoteresource = \local_o365\rest\onenote::get_resource();
                 $token = \local_o365\oauth2\token::instance($USER->id, $onenoteresource, $clientdata, $httpclient);
                 if (empty($token)) {
                     $iso365user = false;
                 }
             } catch (\Exception $e) {
                 $iso365user = false;
             }
         }
         $class = $iso365user === true ? $o365class : $msaccountclass;
     } else {
         $class = $msaccountclass;
     }
     if (empty(self::$instance)) {
         self::$instance = new $class();
     }
     return self::$instance;
 }
 /**
  * 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()
 {
     $reqcap = \local_o365\rest\sharepoint::get_course_site_required_capability();
     $oidcconfig = get_config('auth_oidc');
     if (!empty($oidcconfig)) {
         $spresource = \local_o365\rest\sharepoint::get_resource();
         if (!empty($spresource)) {
             $httpclient = new \local_o365\httpclient();
             $clientdata = new \local_o365\oauth2\clientdata($oidcconfig->clientid, $oidcconfig->clientsecret, $oidcconfig->authendpoint, $oidcconfig->tokenendpoint);
             $sptoken = \local_o365\oauth2\systemtoken::instance(null, $spresource, $clientdata, $httpclient);
             if (!empty($sptoken)) {
                 $sharepoint = new \local_o365\rest\sharepoint($sptoken, $httpclient);
             } else {
                 $errmsg = 'Could not get system API user token for SharePoint';
                 \local_o365\utils::debug($errmsg, 'local_o365\\task\\sharepointaccesssync::execute');
             }
         }
     }
     if (empty($sharepoint)) {
         throw new \moodle_exception('errorcreatingsharepointclient', 'local_o365');
     }
     $opdata = $this->get_custom_data();
     if ($opdata->userid !== '*' && $opdata->roleid !== '*' && !empty($opdata->contextid)) {
         // Single user role assign/unassign.
         $this->do_role_assignmentchange($opdata->roleid, $opdata->userid, $opdata->contextid, $reqcap, $sharepoint);
     } else {
         if ($opdata->userid === '*' && $opdata->roleid !== '*') {
             // Capability update.
             $this->do_role_capabilitychange($opdata->roleid, $reqcap, $sharepoint);
         } else {
             if ($opdata->roleid === '*' && $opdata->userid === '*') {
                 // Role deleted.
                 $this->do_role_delete($reqcap, $sharepoint);
             }
         }
     }
 }
 /**
  * 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();
 }
 /**
  * Render OneNote section of the block.
  *
  * @return string HTML for the rendered OneNote section of the block.
  */
 protected function render_onenote()
 {
     global $USER, $PAGE;
     $action = optional_param('action', '', PARAM_TEXT);
     try {
         $onenoteapi = \local_onenote\api\base::getinstance();
         $output = '';
         if ($onenoteapi->is_logged_in()) {
             // Add the "save to onenote" button if we are on an assignment page.
             $onassignpage = $PAGE->cm && $PAGE->cm->modname == 'assign' && $action == 'editsubmission' ? true : false;
             if ($onassignpage === true && $onenoteapi->is_student($PAGE->cm->id, $USER->id)) {
                 $workstr = get_string('workonthis', 'block_microsoft');
                 $output .= $onenoteapi->render_action_button($workstr, $PAGE->cm->id) . '<br /><br />';
             }
             // Find moodle notebook, create if not found.
             $moodlenotebook = null;
             $cache = \cache::make('block_microsoft', 'onenotenotebook');
             $moodlenotebook = $cache->get($USER->id);
             if (empty($moodlenotebook)) {
                 $moodlenotebook = $this->get_onenote_notebook($onenoteapi);
                 $result = $cache->set($USER->id, $moodlenotebook);
             }
             if (!empty($moodlenotebook)) {
                 $url = new \moodle_url($moodlenotebook['url']);
                 $stropennotebook = get_string('linkonenote', 'block_microsoft');
                 $linkattrs = ['onclick' => 'window.open(this.href,\'_blank\'); return false;', 'class' => 'servicelink block_microsoft_onenote'];
                 $output .= \html_writer::link($url->out(false), $stropennotebook, $linkattrs);
             } else {
                 $output .= get_string('error_nomoodlenotebook', 'block_microsoft');
             }
         } else {
             $output .= $this->render_signin_widget($onenoteapi->get_login_url());
         }
         return $output;
     } catch (\Exception $e) {
         if (class_exists('\\local_o365\\utils')) {
             $debuginfo = !empty($e->debuginfo) ? $e->debuginfo : null;
             \local_o365\utils::debug($e->getMessage(), 'block_microsoft', $debuginfo);
         }
         return '<span class="block_microsoft_onenote servicelink">' . get_string('linkonenote_unavailable', 'block_microsoft') . '<br /><small>' . get_string('contactadmin', 'block_microsoft') . '</small></span>';
     }
 }
Beispiel #19
0
 /**
  * Delete a course site and it's associated groups.
  * @param int $courseid The ID of the course to delete the site for.
  * @return bool Success/Failure.
  */
 public function delete_course_site($courseid)
 {
     global $DB;
     $spsite = $DB->get_record('local_o365_coursespsite', ['courseid' => $courseid]);
     if (empty($spsite)) {
         // No site created (that we know about).
         $errmsg = 'Did not delete course SharePoint site because no record of a SharePoint site for that course was found.';
         \local_o365\utils::debug($errmsg, 'rest\\sharepoint\\delete_course_site', $courseid);
         return false;
     }
     $this->set_site($spsite->siteurl);
     $spgroupsql = 'SELECT spgroup.*
                      FROM {local_o365_spgroupdata} spgroup
                      JOIN {local_o365_coursespsite} spsite
                           ON spgroup.coursespsiteid = spsite.id
                     WHERE spsite.courseid = ?';
     $spgroups = $DB->get_records_sql($sqlgroupsql, [$courseid]);
     foreach ($spgroups as $spgroup) {
         try {
             $this->delete_group_by_id($spgroup->groupid);
             $DB->delete_records('local_o365_spgroupdata', ['id' => $spgroup->id]);
         } catch (\Exception $e) {
             // If the API call failed we can still continue.
             // Error is logged in API call function if failed.
         }
     }
     $this->delete_site();
     $DB->delete_records('local_o365_coursespsite', ['courseid' => $courseid]);
     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;
 }
Beispiel #21
0
 /**
  * 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;
     $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;
 }
Beispiel #22
0
 /**
  * Initiate an OIDC authorization request.
  *
  * @param bool $uselogin Whether to switch the user's Moodle login method to OpenID Connect upon successful authorization.
  */
 protected function doauthrequest($uselogin)
 {
     global $CFG, $SESSION, $DB, $USER;
     require_once $CFG->dirroot . '/auth/oidc/auth.php';
     $stateparams = ['redirect' => '/local/o365/ucp.php'];
     $extraparams = [];
     $promptlogin = false;
     $o365connected = \local_o365\utils::is_o365_connected($USER->id);
     if ($o365connected === true) {
         // User is already connected.
         redirect('/local/o365/ucp.php');
     }
     $connection = $DB->get_record('local_o365_connections', ['muserid' => $USER->id]);
     if (!empty($connection)) {
         // Matched user.
         $extraparams['login_hint'] = $connection->aadupn;
         $promptlogin = true;
     }
     $auth = new \auth_oidc\loginflow\authcode();
     $auth->set_httpclient(new \auth_oidc\httpclient());
     if ($uselogin !== true) {
         $SESSION->auth_oidc_connectiononly = true;
         $stateparams['connectiononly'] = true;
     }
     $auth->initiateauthrequest($promptlogin, $stateparams, $extraparams);
 }
Beispiel #23
0
 /**
  * Determines whether the given Azure AD UPN is already matched to a Moodle user (and has not been completed).
  *
  * @return false|stdClass Either the matched Moodle user record, or false if not matched.
  */
 protected function check_for_matched($aadupn)
 {
     global $DB;
     $dbman = $DB->get_manager();
     if ($dbman->table_exists('local_o365_connections')) {
         $match = $DB->get_record('local_o365_connections', ['aadupn' => $aadupn]);
         if (!empty($match) && \local_o365\utils::is_o365_connected($match->muserid) !== true) {
             return $DB->get_record('user', ['id' => $match->muserid]);
         }
     }
     return false;
 }
Beispiel #24
0
 /**
  * Check setup in Azure.
  */
 public function mode_checksetup()
 {
     $data = new \stdClass();
     $success = false;
     $enableunifiedapi = optional_param('enableunifiedapi', 0, PARAM_INT);
     set_config('enableunifiedapi', $enableunifiedapi, 'local_o365');
     $chineseapi = optional_param('chineseapi', 0, PARAM_INT);
     set_config('chineseapi', $chineseapi, 'local_o365');
     $aadtenant = required_param('aadtenant', PARAM_TEXT);
     set_config('aadtenant', $aadtenant, 'local_o365');
     $odburl = required_param('odburl', PARAM_TEXT);
     set_config('odburl', $odburl, 'local_o365');
     $resource = \local_o365\rest\azuread::get_resource();
     $clientdata = \local_o365\oauth2\clientdata::instance_from_oidc();
     $httpclient = new \local_o365\httpclient();
     $token = \local_o365\oauth2\systemtoken::instance(null, $resource, $clientdata, $httpclient);
     if (empty($token)) {
         throw new \moodle_exception('errorchecksystemapiuser', 'local_o365');
     }
     // Legacy API.
     $legacyapi = new \stdClass();
     try {
         $aadapiclient = new \local_o365\rest\azuread($token, $httpclient);
         list($missingperms, $haswrite) = $aadapiclient->check_permissions();
         $legacyapi->missingperms = $missingperms;
         $legacyapi->haswrite = $haswrite;
     } catch (\Exception $e) {
         \local_o365\utils::debug($e->getMessage(), 'mode_checksetup:legacy');
         $legacyapi->error = $e->getMessage();
     }
     $data->legacyapi = $legacyapi;
     // Unified API.
     $unifiedapi = new \stdClass();
     $unifiedapi->active = false;
     if (\local_o365\rest\unified::is_enabled() === true) {
         try {
             $httpclient = new \local_o365\httpclient();
             $unifiedresource = \local_o365\rest\unified::get_resource();
             $token = \local_o365\oauth2\systemtoken::instance(null, $unifiedresource, $clientdata, $httpclient);
             if (empty($token)) {
                 throw new \moodle_exception('errorchecksystemapiuser', 'local_o365');
             }
             $unifiedapiclient = new \local_o365\rest\unified($token, $httpclient);
             $unifiedpermsresult = $unifiedapiclient->check_permissions();
             if ($unifiedpermsresult === null) {
                 $unifiedapi->active = false;
             } else {
                 $unifiedapi->active = true;
                 $unifiedapi->missingperms = $unifiedpermsresult;
             }
         } catch (\Exception $e) {
             $unifiedapi->active = false;
             \local_o365\utils::debug($e->getMessage(), 'mode_checksetup:unified');
             $unifiedapi->error = $e->getMessage();
         }
     }
     $data->unifiedapi = $unifiedapi;
     set_config('unifiedapiactive', (int) $unifiedapi->active, 'local_o365');
     set_config('azuresetupresult', serialize($data), 'local_o365');
     $success = true;
     echo $this->ajax_response($data, $success);
 }