Skip to content

Commit

Permalink
Merge pull request #525 from jrchamp/fix/check-oauth-scopes
Browse files Browse the repository at this point in the history
webservice: check OAuth scopes
  • Loading branch information
jrchamp authored Sep 28, 2023
2 parents 67a04c4 + 92a38cc commit ea77159
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 15 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Optional functionality can be enabled by granting additional scopes:
- Reports for meetings / webinars
- dashboard_meetings:read:admin (Business accounts and higher)
- dashboard_webinars:read:admin (Business accounts and higher)
- report:read:admin (Pro user and up)
- report:read:admin (Pro accounts and higher)
- Allow recordings to be viewed (zoom | viewrecordings)
- recording:read:admin
- Tracking fields (zoom | defaulttrackingfields)
Expand Down
34 changes: 22 additions & 12 deletions classes/task/get_meeting_reports.php
Original file line number Diff line number Diff line change
Expand Up @@ -130,19 +130,16 @@ public function execute($paramstart = null, $paramend = null, $hostuuids = null)
mtrace(sprintf('Finding meetings between %s to %s', $start, $end));

$recordedallmeetings = true;
try {
if (!empty($hostuuids)) {
// Can only query on $hostuuids using Report API. So throw
// exception to skip Dashboard API.
throw new \Exception('Querying $hostuuids; need to use Report API');
}

// Can only query on $hostuuids using Report API.
if (empty($hostuuids) && $this->service->has_scope('dashboard_meetings:read:admin')) {
$allmeetings = $this->get_meetings_via_dashboard($start, $end);
} catch (\Exception $e) {
mtrace($e->getMessage());
// If ran into exception, then Dashboard API must have failed. Try
// using Report API.
} else if ($this->service->has_scope('report:read:admin')) {
$allmeetings = $this->get_meetings_via_reports($start, $end, $hostuuids);
} else {
$requiredscope = !empty($hostuuids) ? 'report:read:admin' : 'dashboard_meetings:read:admin or report:read:admin';
mtrace('Skipping task - missing required OAuth scope: ' . $requiredscope);
return;
}

// Sort all meetings based on end_time so that we know where to pick
Expand Down Expand Up @@ -205,6 +202,11 @@ public function format_participant($participant, $detailsid, $names, $emails) {
$moodleuserid = null;
$name = null;

// Consolidate fields.
$participant->name = $participant->name ?? $participant->user_name ?? '';
$participant->id = $participant->id ?? $participant->participant_user_id ?? '';
$participant->user_email = $participant->user_email ?? $participant->email ?? '';

// Cleanup the name. For some reason # gets into the name instead of a comma.
$participant->name = str_replace('#', ',', $participant->name);

Expand Down Expand Up @@ -373,8 +375,16 @@ public function get_meetings_via_reports($start, $end, $hostuuids) {
public function get_meetings_via_dashboard($start, $end) {
mtrace('Using Dashboard API');

$meetings = $this->service->get_meetings($start, $end);
$webinars = $this->service->get_webinars($start, $end);
$meetings = [];
if ($this->service->has_scope('dashboard_meetings:read:admin')) {
$meetings = $this->service->get_meetings($start, $end);
}

$webinars = [];
if ($this->service->has_scope('dashboard_webinars:read:admin')) {
$webinars = $this->service->get_webinars($start, $end);
}

$allmeetings = array_merge($meetings, $webinars);

return $allmeetings;
Expand Down
41 changes: 39 additions & 2 deletions classes/webservice.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,12 @@ class mod_zoom_webservice {
*/
protected $makecallretries = 0;

/**
* Granted OAuth scopes
* @var array
*/
protected $scopes;

/**
* The constructor for the webservice class.
* @throws moodle_exception Moodle exception is thrown for missing config settings.
Expand Down Expand Up @@ -844,8 +850,20 @@ public function list_meetings($userid, $webinar) {
*/
public function get_meeting_participants($meetinguuid, $webinar) {
$meetinguuid = $this->encode_uuid($meetinguuid);
return $this->make_paginated_call('report/' . ($webinar ? 'webinars' : 'meetings') . '/'
. $meetinguuid . '/participants', null, 'participants');

$meetingtype = ($webinar ? 'webinars' : 'meetings');

if ($this->has_scope('report:read:admin')) {
$apitype = 'report';
} else if ($this->has_scope('dashboard_' . $meetingtype . ':read:admin')) {
$apitype = 'metrics';
} else {
mtrace('Missing required OAuth scope: report:read:admin or dashboard_' . $meetingtype . ':read:admin');
return [];
}

$url = $apitype . '/' . $meetingtype . '/' . $meetinguuid . '/participants';
return $this->make_paginated_call($url, [], 'participants');
}

/**
Expand Down Expand Up @@ -1012,6 +1030,22 @@ protected function get_access_token() {
return $token;
}

/**
* Has the request OAuth scope been granted?
*
* @param string $scope OAuth scope.
* @throws moodle_exception
* @return bool
*/
public function has_scope($scope) {
if (!isset($this->scopes)) {
$this->get_access_token();
}

mtrace('checking has_scope(' . $scope . ')');
return \in_array($scope, $this->scopes, true);
}

/**
* Stores token and expiration in cache, returns token from OAuth call.
*
Expand Down Expand Up @@ -1054,6 +1088,9 @@ private function oauth($cache) {
$scopes = explode(' ', $response->scope);
$missingscopes = array_diff($requiredscopes, $scopes);

// Keep the scope information in memory.
$this->scopes = $scopes;

if (!empty($missingscopes)) {
$missingscopes = implode(', ', $missingscopes);
throw new moodle_exception('errorwebservice', 'mod_zoom', '', get_string('zoomerr_scopes', 'mod_zoom', $missingscopes));
Expand Down

0 comments on commit ea77159

Please sign in to comment.