MDL-58219 googledocs: Update to new model for controlledlinks

Part of MDL-58220
This commit is contained in:
Damyon Wiese 2017-03-14 12:50:09 +08:00
parent 141ee541ca
commit 72643dc688
3 changed files with 39 additions and 203 deletions

View File

@ -123,15 +123,6 @@ class rest extends \core\oauth2\rest {
],
'response' => 'json'
],
'list_permissions' => [
'endpoint' => 'https://www.googleapis.com/drive/v3/files/{fileid}/permissions',
'method' => 'get',
'args' => [
'fileid' => PARAM_RAW,
'fields' => PARAM_RAW
],
'response' => 'json'
],
];
}
}

View File

@ -42,9 +42,9 @@ $string['supportedreturntypes'] = 'Supported files';
$string['defaultreturntype'] = 'Default return type';
$string['fileoptions'] = 'The types and defaults for returned files is configurable here. Note that all files linked externally will be updated so that the owner is the Moodle system account.';
$string['owner'] = 'Owned by: {$a}';
$string['cachedef_folder'] = 'Google File IDs for folders in the system account';
// Deprecated since Moodle 3.3.
$string['oauthinfo'] = '<p>To use this plugin, you must register your site with Google, as described in the documentation <a href="{$a->docsurl}">Google OAuth 2.0 setup</a>.</p><p>As part of the registration process, you will need to enter the following URL as \'Authorized Redirect URIs\':</p><p>{$a->callbackurl}</p><p>Once registered, you will be provided with a client ID and secret which can be used to configure all Google Drive and Picasa plugins.</p><p>Please also note that you will have to enable the service \'Drive API\'.</p>';
$string['secret'] = 'Secret';
$string['clientid'] = 'Client ID';
$string['cachedef_folder'] = 'Google File IDs for folders in the system account';

View File

@ -317,8 +317,7 @@ class repository_googledocs extends repository {
'id' => $gfile->id,
'name' => $gfile->name,
'exportformat' => 'download',
'link' => $link,
'claimed' => false
'link' => $link
]);
$title = $gfile->name;
} else {
@ -366,8 +365,7 @@ class repository_googledocs extends repository {
'id' => $gfile->id,
'exportformat' => $exporttype,
'link' => $link,
'name' => $gfile->name,
'claimed' => false
'name' => $gfile->name
]);
}
// Adds the file to the file list. Using the itemId along with the name as key
@ -553,7 +551,7 @@ class repository_googledocs extends repository {
$storedfile->get_filepath(),
$storedfile->get_filename());
if (!empty($source->claimed) && $info->is_writable()) {
if ($info->is_writable()) {
// Add the current user as an OAuth writer.
$systemauth = \core\oauth2\api::get_system_oauth_client($this->issuer);
@ -594,90 +592,6 @@ class repository_googledocs extends repository {
}
}
/**
* Update an external file so only Moodle has write access to it.
* This function must be implemented by all repositories supporting FILE_CONTROLLED_LINK return types.
*
* Throw exceptions on error and the transaction will be rolled back
* (because it is called on an entire filearea at a time).
*
* @param stored_file $file
*/
public function prevent_changes_to_external_file(stored_file $file) {
global $DB;
// Copy the file (will make it owned by moodle system account).
// Update the sharing settings on the file.
// Prevent editors from sharing the file.
$source = json_decode($file->get_reference());
$systemauth = \core\oauth2\api::get_system_oauth_client($this->issuer);
if ($systemauth === false) {
$details = 'Cannot connect as system user';
throw new repository_exception('errorwhilecommunicatingwith', 'repository', '', $details);
}
$systemservice = new repository_googledocs\rest($systemauth);
// Copy the file so we get a snapshot file owned by Moodle.
$newsource = $this->copy_file($systemservice, $source->id, $source->name);
// Set the sharing options.
$this->set_file_sharing_anyone_with_link_can_read($systemservice, $newsource->id);
$this->prevent_writers_from_sharing_file($systemservice, $newsource->id);
// Delete the original file from the Moodle account. This only deletes it for us (not the original owner).
$summary = $this->get_file_summary($systemservice, $source->id);
if (!empty($summary->parents[0])) {
$myparent = $summary->parents[0];
$this->remove_file_parent($systemservice, $source->id, $myparent);
}
// We need to change the source on the existing file now to point to the new id.
$source->id = $newsource->id;
$source->link = isset($newsource->webViewLink) ? $newsource->webViewLink : '';
if (empty($source->link)) {
$source->link = isset($newsource->webContentLink) ? $newsource->webContentLink : '';
}
$source->claimed = true;
$reference = json_encode($source);
$file->set_source($reference);
// We need to update the reference in the file_reference table.
$refid = $file->get_referencefileid();
$newref = (object) [
'id' => $refid,
'reference' => $reference,
'referencehash' => sha1($reference)
];
$DB->update_record('files_reference', $newref);
return true;
}
/**
* Grant write access and redirect to an edit link for the file.
*
* @param stored_file $storedfile the file that contains the reference
*/
public function edit_external_file($storedfile) {
// Grant writer access to this file.
// Redirect to the file.
$this->send_file($storedfile);
}
/**
* List the permissions on a file.
*
* @param \repository_googledocs\rest $client Authenticated client.
* @param string $fileid The id of the file.
* @return array
*/
protected function list_file_permissions(\repository_googledocs\rest $client, $fileid) {
$fields = "permissions(id,type,emailAddress,role,allowFileDiscovery,displayName)";
return $client->call('list_permissions', ['fileid' => $fileid]);
}
/**
* See if a folder exists within a folder
*
@ -721,23 +635,6 @@ class repository_googledocs extends repository {
return $created->id;
}
/**
* Get capabilities for a file.
*
* @param \repository_googledocs\rest $client Authenticated client.
* @param string $fileid The file we are checking.
*
* @return stdClass The file info with capabilities.
*/
protected function get_file_capabilities(\repository_googledocs\rest $client, $fileid) {
$fields = "id,capabilities,writersCanShare";
$params = [
'fileid' => $fileid,
'fields' => $fields
];
return $client->call('get', $params);
}
/**
* Get simple file info for humans.
*
@ -755,30 +652,6 @@ class repository_googledocs extends repository {
return $client->call('get', $params);
}
/**
* Update file owner.
*
* @param \repository_googledocs\rest $client Authenticated client.
* @param string $fileid The file we are updating.
* @param string $owneremail
*
* @return boolean Did it work?
*/
protected function update_file_owner(\repository_googledocs\rest $client, $fileid, $owneremail) {
$updateowner = [
'emailAddress' => $owneremail,
'role' => 'owner',
'type' => 'user'
];
$params = ['fileid' => $fileid, 'transferOwnership' => 'true'];
try {
$response = $client->call('create_permission', $params, json_encode($updateowner));
} catch (\core\oauth2\rest_exception $re) {
return false;
}
return !empty($response->id);
}
/**
* Copy a file and return the new file details. A side effect of the copy
* is that the owner will be the account authenticated with this oauth client.
@ -808,23 +681,6 @@ class repository_googledocs extends repository {
return $fileinfo;
}
/**
* Delete a file (for the current user).
*
* @param \repository_googledocs\rest $client Authenticated client.
* @param string $fileid The file we are deleting.
* @return boolean
*/
protected function delete_file(\repository_googledocs\rest $client, $fileid) {
$params = ['fileid' => $fileid];
$response = $client->call('delete', $params, ' ');
if (empty($response->id)) {
$details = 'Cannot delete file: ' . $fileid;
throw new repository_exception('errorwhilecommunicatingwith', 'repository', '', $details);
}
return true;
}
/**
* Add a writer to the permissions on the file (temporary).
*
@ -898,27 +754,6 @@ class repository_googledocs extends repository {
return true;
}
/**
* Remove parent
*
* @param \repository_googledocs\rest $client Authenticated client.
* @param string $fileid The file we are updating.
* @param string $folderid The id of the folder we are removing
* @return boolean
*/
protected function remove_file_parent(\repository_googledocs\rest $client, $fileid, $folderid) {
// Set the parent.
$params = [
'fileid' => $fileid, 'removeParents' => $folderid
];
$response = $client->call('update', $params, ' ');
if (empty($response->id)) {
$details = 'Cannot remove the file parent: ' . $fileid . ', ' . $folderid;
throw new repository_exception('errorwhilecommunicatingwith', 'repository', '', $details);
}
return true;
}
/**
* Prevent writers from sharing.
*
@ -971,9 +806,12 @@ class repository_googledocs extends repository {
* @param string $reference this reference is generated by
* repository::get_file_reference()
* @param context $context the target context for this new file.
* @return string $modifiedreference (final one before saving to DB)
* @param string $component the target component for this new file.
* @param string $filearea the target filearea for this new file.
* @param string $itemid the target itemid for this new file.
* @return string updated reference (final one before it's saved to db).
*/
public function reference_file_selected($reference, $context) {
public function reference_file_selected($reference, $context, $component, $filearea, $itemid) {
// What we need to do here is transfer ownership to the system user (or copy)
// then set the permissions so anyone with the share link can view,
// finally update the reference to contain the share link if it was not
@ -1000,21 +838,6 @@ class repository_googledocs extends repository {
$userservice = new repository_googledocs\rest($userauth);
$systemservice = new repository_googledocs\rest($systemauth);
// Get the list of existing permissions so we can see if the owner is already the system account,
// and whether we need to update the link sharing options.
$permissions = $this->list_file_permissions($userservice, $source->id);
$readshareupdaterequired = true;
$ownerupdaterequired = true;
foreach ($permissions->permissions as $permission) {
if ($permission->id == 'anyoneWithLink' &&
$permission->type == 'anyone' &&
$permission->role == 'reader' &&
$permission->allowFileDiscovery == false) {
$readshareupdaterequired = false;
}
}
// Add Moodle as writer.
$this->add_writer_to_file($userservice, $source->id, $systemuseremail);
@ -1024,12 +847,22 @@ class repository_googledocs extends repository {
$cache = cache::make('repository_googledocs', 'folder');
$parentid = 'root';
$fullpath = 'root';
$allfolders = [];
foreach ($contextlist as $context) {
// Make sure a folder exists here.
$foldername = $context->get_context_name();
$foldername = clean_param($context->get_context_name(), PARAM_PATH);
$allfolders[] = $foldername;
}
$allfolders[] = clean_param($component, PARAM_PATH);
$allfolders[] = clean_param($filearea, PARAM_PATH);
$allfolders[] = clean_param($itemid, PARAM_PATH);
foreach ($allfolders as $foldername) {
// Make sure a folder exists here.
$fullpath .= '/' . $foldername;
$folderid = $cache->get('fullpath');
$folderid = $cache->get($fullpath);
if (empty($folderid)) {
$folderid = $this->folder_exists_in_folder($systemservice, $foldername, $parentid);
}
@ -1043,13 +876,22 @@ class repository_googledocs extends repository {
}
}
$this->move_file_from_root_to_folder($systemservice, $source->id, $parentid);
// Copy the file so we get a snapshot file owned by Moodle.
$newsource = $this->copy_file($systemservice, $source->id, $source->name);
// Move the copied file to the correct folder.
$this->move_file_from_root_to_folder($systemservice, $newsource->id, $parentid);
if ($readshareupdaterequired) {
$this->set_file_sharing_anyone_with_link_can_read($systemservice, $source->id);
// Set the sharing options.
$this->set_file_sharing_anyone_with_link_can_read($systemservice, $newsource->id);
$this->prevent_writers_from_sharing_file($systemservice, $newsource->id);
$source->id = $newsource->id;
$source->link = isset($newsource->webViewLink) ? $newsource->webViewLink : '';
if (empty($source->link)) {
$source->link = isset($newsource->webContentLink) ? $newsource->webContentLink : '';
}
$reference = json_encode($source);
// We did not update the reference at all.
return $reference;
}
@ -1183,6 +1025,9 @@ class repository_googledocs extends repository {
*
* @return string
*/
function repository_googledocs_oauth2_system_scopes() {
return 'https://www.googleapis.com/auth/drive';
function repository_googledocs_oauth2_system_scopes(\core\oauth2\issuer $issuer) {
if ($issuer->get('id') == get_config('googledocs', 'issuerid')) {
return 'https://www.googleapis.com/auth/drive';
}
return '';
}