mirror of
https://github.com/moodle/moodle.git
synced 2025-04-13 20:42:22 +02:00
MDL-52051 repository_dropbox: Migrate to v2 API
This commit is contained in:
parent
3a4c497c15
commit
066963cd18
38
repository/dropbox/classes/authentication_exception.php
Normal file
38
repository/dropbox/classes/authentication_exception.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Dropbox Authentication exception.
|
||||
*
|
||||
* @since Moodle 3.2
|
||||
* @package repository_dropbox
|
||||
* @copyright Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace repository_dropbox;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Dropbox Authentication exception.
|
||||
*
|
||||
* @package repository_dropbox
|
||||
* @copyright Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class authentication_exception extends dropbox_exception {
|
||||
}
|
368
repository/dropbox/classes/dropbox.php
Normal file
368
repository/dropbox/classes/dropbox.php
Normal file
@ -0,0 +1,368 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Dropbox V2 API.
|
||||
*
|
||||
* @since Moodle 3.2
|
||||
* @package repository_dropbox
|
||||
* @copyright Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace repository_dropbox;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/oauthlib.php');
|
||||
|
||||
/**
|
||||
* Dropbox V2 API.
|
||||
*
|
||||
* @package repository_dropbox
|
||||
* @copyright Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class dropbox extends \oauth2_client {
|
||||
|
||||
/**
|
||||
* Create the DropBox API Client.
|
||||
*
|
||||
* @param string $key The API key
|
||||
* @param string $secret The API secret
|
||||
* @param string $callback The callback URL
|
||||
*/
|
||||
public function __construct($key, $secret, $callback) {
|
||||
parent::__construct($key, $secret, $callback, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the auth url for OAuth 2.0 request.
|
||||
*
|
||||
* @return string the auth url
|
||||
*/
|
||||
protected function auth_url() {
|
||||
return 'https://www.dropbox.com/oauth2/authorize';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the token url for OAuth 2.0 request.
|
||||
*
|
||||
* @return string the auth url
|
||||
*/
|
||||
protected function token_url() {
|
||||
return 'https://api.dropboxapi.com/oauth2/token';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the constructed API endpoint URL.
|
||||
*
|
||||
* @param string $endpoint The endpoint to be contacted
|
||||
* @return moodle_url The constructed API URL
|
||||
*/
|
||||
protected function get_api_endpoint($endpoint) {
|
||||
return new \moodle_url('https://api.dropboxapi.com/2/' . $endpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the constructed content endpoint URL.
|
||||
*
|
||||
* @param string $endpoint The endpoint to be contacted
|
||||
* @return moodle_url The constructed content URL
|
||||
*/
|
||||
protected function get_content_endpoint($endpoint) {
|
||||
return new \moodle_url('https://api-content.dropbox.com/2/' . $endpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an API call against the specified endpoint with supplied data.
|
||||
*
|
||||
* @param string $endpoint The endpoint to be contacted
|
||||
* @param array $data Any data to pass to the endpoint
|
||||
* @return object Content decoded from the endpoint
|
||||
*/
|
||||
protected function fetch_dropbox_data($endpoint, $data = []) {
|
||||
$url = $this->get_api_endpoint($endpoint);
|
||||
$this->cleanopt();
|
||||
$this->resetHeader();
|
||||
|
||||
if ($data === null) {
|
||||
// Some API endpoints explicitly expect a data submission of 'null'.
|
||||
$options['CURLOPT_POSTFIELDS'] = 'null';
|
||||
} else {
|
||||
$options['CURLOPT_POSTFIELDS'] = json_encode($data);
|
||||
}
|
||||
$options['CURLOPT_POST'] = 1;
|
||||
$this->setHeader('Content-Type: application/json');
|
||||
|
||||
$response = $this->request($url, $options);
|
||||
$result = json_decode($response);
|
||||
|
||||
$this->check_and_handle_api_errors($result);
|
||||
|
||||
if ($this->has_additional_results($result)) {
|
||||
// Any API endpoint returning 'has_more' will provide a cursor, and also have a matching endpoint suffixed
|
||||
// with /continue which takes that cursor.
|
||||
if (preg_match('_/continue$_', $endpoint) === 0) {
|
||||
// Only add /continue if it is not already present.
|
||||
$endpoint .= '/continue';
|
||||
}
|
||||
|
||||
// Fetch the next page of results.
|
||||
$additionaldata = $this->fetch_dropbox_data($endpoint, [
|
||||
'cursor' => $result->cursor,
|
||||
]);
|
||||
|
||||
// Merge the list of entries.
|
||||
$result->entries = array_merge($result->entries, $additionaldata->entries);
|
||||
}
|
||||
|
||||
if (isset($result->has_more)) {
|
||||
// Unset the cursor and has_more flags.
|
||||
unset($result->cursor);
|
||||
unset($result->has_more);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the supplied result is paginated and not the final page.
|
||||
*
|
||||
* @param object $result The result of an operation
|
||||
* @return boolean
|
||||
*/
|
||||
public function has_additional_results($result) {
|
||||
return !empty($result->has_more) && !empty($result->cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch content from the specified endpoint with the supplied data.
|
||||
*
|
||||
* @param string $endpoint The endpoint to be contacted
|
||||
* @param array $data Any data to pass to the endpoint
|
||||
* @return string The returned data
|
||||
*/
|
||||
protected function fetch_dropbox_content($endpoint, $data = []) {
|
||||
$url = $this->get_content_endpoint($endpoint);
|
||||
$this->cleanopt();
|
||||
$this->resetHeader();
|
||||
|
||||
$options['CURLOPT_POST'] = 1;
|
||||
$this->setHeader('Content-Type: ');
|
||||
$this->setHeader('Dropbox-API-Arg: ' . json_encode($data));
|
||||
|
||||
$response = $this->request($url, $options);
|
||||
|
||||
$this->check_and_handle_api_errors($response);
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for an attempt to handle API errors.
|
||||
*
|
||||
* This function attempts to deal with errors as per
|
||||
* https://www.dropbox.com/developers/documentation/http/documentation#error-handling.
|
||||
*
|
||||
* @param string $data The returned content.
|
||||
* @throws moodle_exception
|
||||
*/
|
||||
protected function check_and_handle_api_errors($data) {
|
||||
if ($this->info['http_code'] == 200) {
|
||||
// Dropbox only returns errors on non-200 response codes.
|
||||
return;
|
||||
}
|
||||
|
||||
switch($this->info['http_code']) {
|
||||
case 400:
|
||||
// Bad input parameter. Error message should indicate which one and why.
|
||||
throw new \coding_exception('Invalid input parameter passed to DropBox API.');
|
||||
break;
|
||||
case 401:
|
||||
// Bad or expired token. This can happen if the access token is expired or if the access token has been
|
||||
// revoked by Dropbox or the user. To fix this, you should re-authenticate the user.
|
||||
throw new authentication_exception('Authentication token expired');
|
||||
break;
|
||||
case 409:
|
||||
// Endpoint-specific error. Look to the response body for the specifics of the error.
|
||||
throw new \coding_exception('Endpoint specific error: ' . $data);
|
||||
break;
|
||||
case 429:
|
||||
// Your app is making too many requests for the given user or team and is being rate limited. Your app
|
||||
// should wait for the number of seconds specified in the "Retry-After" response header before trying
|
||||
// again.
|
||||
throw new rate_limit_exception();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ($this->info['http_code'] >= 500 && $this->info['http_code'] < 600) {
|
||||
throw new \invalid_response_exception($this->info['http_code'] . ": " . $data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file listing from dropbox.
|
||||
*
|
||||
* @param string $path The path to query
|
||||
* @return object The returned directory listing, or null on failure
|
||||
*/
|
||||
public function get_listing($path = '') {
|
||||
if ($path === '/') {
|
||||
$path = '';
|
||||
}
|
||||
|
||||
$data = $this->fetch_dropbox_data('files/list_folder', [
|
||||
'path' => $path,
|
||||
]);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file search results from dropbox.
|
||||
*
|
||||
* @param string $query The search query
|
||||
* @return object The returned directory listing, or null on failure
|
||||
*/
|
||||
public function search($query = '') {
|
||||
$data = $this->fetch_dropbox_data('files/search', [
|
||||
'path' => '',
|
||||
'query' => $query,
|
||||
]);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the entry is expected to have a thumbnail.
|
||||
* See docs at https://www.dropbox.com/developers/documentation/http/documentation#files-get_thumbnail.
|
||||
*
|
||||
* @param object $entry The file entry received from the DropBox API
|
||||
* @return boolean Whether dropbox has a thumbnail available
|
||||
*/
|
||||
public function supports_thumbnail($entry) {
|
||||
if ($entry->{".tag"} !== "file") {
|
||||
// Not a file. No thumbnail available.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Thumbnails are available for files under 20MB with file extensions jpg, jpeg, png, tiff, tif, gif, and bmp.
|
||||
if ($entry->size > 20 * 1024 * 1024) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$supportedtypes = [
|
||||
'jpg' => true,
|
||||
'jpeg' => true,
|
||||
'png' => true,
|
||||
'tiff' => true,
|
||||
'tif' => true,
|
||||
'gif' => true,
|
||||
'bmp' => true,
|
||||
];
|
||||
|
||||
$extension = substr($entry->path_lower, strrpos($entry->path_lower, '.') + 1);
|
||||
return isset($supportedtypes[$extension]) && $supportedtypes[$extension];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the thumbnail for the content, as supplied by dropbox.
|
||||
*
|
||||
* @param string $path The path to fetch a thumbnail for
|
||||
* @return string Thumbnail image content
|
||||
*/
|
||||
public function get_thumbnail($path) {
|
||||
$content = $this->fetch_dropbox_content('files/get_thumbnail', [
|
||||
'path' => $path,
|
||||
]);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a valid public share link for the specified file.
|
||||
*
|
||||
* @param string $id The file path or file id of the file to fetch information for.
|
||||
* @return object An object containing the id, path, size, and URL of the entry
|
||||
*/
|
||||
public function get_file_share_info($id) {
|
||||
// Attempt to fetch any existing shared link first.
|
||||
$data = $this->fetch_dropbox_data('sharing/list_shared_links', [
|
||||
'path' => $id,
|
||||
]);
|
||||
|
||||
if (isset($data->links)) {
|
||||
$link = reset($data->links);
|
||||
if (isset($link->{".tag"}) && $link->{".tag"} === "file") {
|
||||
return $this->normalize_file_share_info($link);
|
||||
}
|
||||
}
|
||||
|
||||
// No existing link available.
|
||||
// Create a new one.
|
||||
$link = $this->fetch_dropbox_data('sharing/create_shared_link_with_settings', [
|
||||
'path' => $id,
|
||||
'settings' => [
|
||||
'requested_visibility' => 'public',
|
||||
],
|
||||
]);
|
||||
|
||||
if (isset($link->{".tag"}) && $link->{".tag"} === "file") {
|
||||
return $this->normalize_file_share_info($link);
|
||||
}
|
||||
|
||||
// Some kind of error we don't know how to handle at this stage.
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize the file share info.
|
||||
*
|
||||
* @param object $entry Information retrieved from share endpoints
|
||||
* @return object Normalized entry information to store as repository information
|
||||
*/
|
||||
protected function normalize_file_share_info($entry) {
|
||||
return (object) [
|
||||
'id' => $entry->id,
|
||||
'path' => $entry->path_lower,
|
||||
'url' => $entry->url,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the callback.
|
||||
*/
|
||||
public function callback() {
|
||||
$this->log_out();
|
||||
$this->is_logged_in();
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke the current access token.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function logout() {
|
||||
try {
|
||||
$this->fetch_dropbox_data('auth/token/revoke', null);
|
||||
} catch(authentication_exception $e) {
|
||||
// An authentication_exception may be expected if the token has
|
||||
// already expired.
|
||||
}
|
||||
}
|
||||
}
|
38
repository/dropbox/classes/dropbox_exception.php
Normal file
38
repository/dropbox/classes/dropbox_exception.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* General Dropbox Exception.
|
||||
*
|
||||
* @since Moodle 3.2
|
||||
* @package repository_dropbox
|
||||
* @copyright Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace repository_dropbox;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* General Dropbox Exception.
|
||||
*
|
||||
* @package repository_dropbox
|
||||
* @copyright Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class dropbox_exception extends \moodle_exception {
|
||||
}
|
38
repository/dropbox/classes/provider_exception.php
Normal file
38
repository/dropbox/classes/provider_exception.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Upstream issue exception.
|
||||
*
|
||||
* @since Moodle 3.2
|
||||
* @package repository_dropbox
|
||||
* @copyright Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace repository_dropbox;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Upstream issue exception.
|
||||
*
|
||||
* @package repository_dropbox
|
||||
* @copyright Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class provider_exception extends dropbox_exception {
|
||||
}
|
44
repository/dropbox/classes/rate_limit_exception.php
Normal file
44
repository/dropbox/classes/rate_limit_exception.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Dropbox Rate Limit Encountered.
|
||||
*
|
||||
* @since Moodle 3.2
|
||||
* @package repository_dropbox
|
||||
* @copyright Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace repository_dropbox;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Dropbox Rate Limit Encountered.
|
||||
*
|
||||
* @package repository_dropbox
|
||||
* @copyright Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class rate_limit_exception extends dropbox_exception {
|
||||
/**
|
||||
* Constructor for rate_limit_exception.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct('Rate limit hit');
|
||||
}
|
||||
}
|
@ -21,8 +21,6 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* @return bool result
|
||||
*/
|
||||
function xmldb_repository_dropbox_upgrade($oldversion) {
|
||||
global $CFG;
|
||||
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
@ -35,5 +33,9 @@ function xmldb_repository_dropbox_upgrade($oldversion) {
|
||||
// Moodle v3.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
if ($oldversion < 2016091300) {
|
||||
unset_config('legacyapi', 'dropbox');
|
||||
upgrade_plugin_savepoint(true, 2016091300, 'repository', 'dropbox');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -34,3 +34,4 @@ $string['cachelimit'] = 'Cache limit';
|
||||
$string['cachelimit_info'] = 'Enter the maximum size of files (in bytes) to be cached on server for Dropbox aliases/shortcuts. Cached files will be served when the source is no longer available. Empty value or zero mean caching of all files regardless of size.';
|
||||
$string['dropbox:view'] = 'View a Dropbox folder';
|
||||
$string['logoutdesc'] = '(Logout when you finish using Dropbox)';
|
||||
$string['oauth2redirecturi'] = 'OAuth 2 Redirect URI';
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,168 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A helper class to access dropbox resources
|
||||
*
|
||||
* @since Moodle 2.0
|
||||
* @package repository_dropbox
|
||||
* @copyright 2012 Marina Glancy
|
||||
* @copyright 2010 Dongsheng Cai
|
||||
* @author Dongsheng Cai <dongsheng@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
require_once($CFG->libdir.'/oauthlib.php');
|
||||
|
||||
/**
|
||||
* Authentication class to access Dropbox API
|
||||
*
|
||||
* @package repository_dropbox
|
||||
* @copyright 2010 Dongsheng Cai
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class dropbox extends oauth_helper {
|
||||
/** @var string dropbox access type, can be dropbox or sandbox */
|
||||
private $mode = 'dropbox';
|
||||
/** @var string dropbox api url*/
|
||||
private $dropbox_api = 'https://api.dropbox.com/1';
|
||||
/** @var string dropbox content api url*/
|
||||
private $dropbox_content_api = 'https://api-content.dropbox.com/1';
|
||||
|
||||
/**
|
||||
* Constructor for dropbox class
|
||||
*
|
||||
* @param array $args
|
||||
*/
|
||||
function __construct($args) {
|
||||
parent::__construct($args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file listing from dropbox
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $token
|
||||
* @param string $secret
|
||||
* @return array
|
||||
*/
|
||||
public function get_listing($path='/', $token='', $secret='') {
|
||||
$url = $this->dropbox_api.'/metadata/'.$this->mode.$path;
|
||||
$content = $this->get($url, array(), $token, $secret);
|
||||
$data = json_decode($content);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the filename to pass to Dropbox API as part of URL
|
||||
*
|
||||
* @param string $filepath
|
||||
* @return string
|
||||
*/
|
||||
protected function prepare_filepath($filepath) {
|
||||
$info = pathinfo($filepath);
|
||||
$dirname = $info['dirname'];
|
||||
$basename = $info['basename'];
|
||||
$filepath = $dirname . rawurlencode($basename);
|
||||
if ($dirname != '/') {
|
||||
$filepath = $dirname . '/' . $basename;
|
||||
$filepath = str_replace("%2F", "/", rawurlencode($filepath));
|
||||
}
|
||||
return $filepath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the default (64x64) thumbnail for dropbox file
|
||||
*
|
||||
* @throws moodle_exception when file could not be downloaded
|
||||
*
|
||||
* @param string $filepath local path in Dropbox
|
||||
* @param string $saveas path to file to save the result
|
||||
* @param int $timeout request timeout in seconds, 0 means no timeout
|
||||
* @return array with attributes 'path' and 'url'
|
||||
*/
|
||||
public function get_thumbnail($filepath, $saveas, $timeout = 0) {
|
||||
$url = $this->dropbox_content_api.'/thumbnails/'.$this->mode.$this->prepare_filepath($filepath);
|
||||
if (!($fp = fopen($saveas, 'w'))) {
|
||||
throw new moodle_exception('cannotwritefile', 'error', '', $saveas);
|
||||
}
|
||||
$this->setup_oauth_http_options(array('timeout' => $timeout, 'file' => $fp, 'BINARYTRANSFER' => true));
|
||||
$result = $this->get($url);
|
||||
fclose($fp);
|
||||
if ($result === true) {
|
||||
return array('path'=>$saveas, 'url'=>$url);
|
||||
} else {
|
||||
unlink($saveas);
|
||||
throw new moodle_exception('errorwhiledownload', 'repository', '', $result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads a file from Dropbox and saves it locally
|
||||
*
|
||||
* @throws moodle_exception when file could not be downloaded
|
||||
*
|
||||
* @param string $filepath local path in Dropbox
|
||||
* @param string $saveas path to file to save the result
|
||||
* @param int $timeout request timeout in seconds, 0 means no timeout
|
||||
* @return array with attributes 'path' and 'url'
|
||||
*/
|
||||
public function get_file($filepath, $saveas, $timeout = 0) {
|
||||
$url = $this->dropbox_content_api.'/files/'.$this->mode.$this->prepare_filepath($filepath);
|
||||
if (!($fp = fopen($saveas, 'w'))) {
|
||||
throw new moodle_exception('cannotwritefile', 'error', '', $saveas);
|
||||
}
|
||||
$this->setup_oauth_http_options(array('timeout' => $timeout, 'file' => $fp, 'BINARYTRANSFER' => true));
|
||||
$result = $this->get($url);
|
||||
fclose($fp);
|
||||
if ($result === true) {
|
||||
return array('path'=>$saveas, 'url'=>$url);
|
||||
} else {
|
||||
unlink($saveas);
|
||||
throw new moodle_exception('errorwhiledownload', 'repository', '', $result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns direct link to Dropbox file
|
||||
*
|
||||
* @param string $filepath local path in Dropbox
|
||||
* @param int $timeout request timeout in seconds, 0 means no timeout
|
||||
* @return string|null information object or null if request failed with an error
|
||||
*/
|
||||
public function get_file_share_link($filepath, $timeout = 0) {
|
||||
$url = $this->dropbox_api.'/shares/'.$this->mode.$this->prepare_filepath($filepath);
|
||||
$this->setup_oauth_http_options(array('timeout' => $timeout));
|
||||
$result = $this->post($url, array('short_url'=>0));
|
||||
if (!$this->http->get_errno()) {
|
||||
$data = json_decode($result);
|
||||
if (isset($data->url)) {
|
||||
return $data->url;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets Dropbox API mode (dropbox or sandbox, default dropbox)
|
||||
*
|
||||
* @param string $mode
|
||||
*/
|
||||
public function set_mode($mode) {
|
||||
$this->mode = $mode;
|
||||
}
|
||||
}
|
621
repository/dropbox/tests/api_test.php
Normal file
621
repository/dropbox/tests/api_test.php
Normal file
@ -0,0 +1,621 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Tests for the Dropbox API (v2).
|
||||
*
|
||||
* @package repository_dropbox
|
||||
* @copyright Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tests for the Dropbox API (v2).
|
||||
*
|
||||
* @package repository_dropbox
|
||||
* @copyright Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class repository_dropbox_api_testcase extends advanced_testcase {
|
||||
/**
|
||||
* Data provider for has_additional_results.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function has_additional_results_provider() {
|
||||
return [
|
||||
'No more results' => [
|
||||
(object) [
|
||||
'has_more' => false,
|
||||
'cursor' => '',
|
||||
],
|
||||
false
|
||||
],
|
||||
'Has more, No cursor' => [
|
||||
(object) [
|
||||
'has_more' => true,
|
||||
'cursor' => '',
|
||||
],
|
||||
false
|
||||
],
|
||||
'Has more, Has cursor' => [
|
||||
(object) [
|
||||
'has_more' => true,
|
||||
'cursor' => 'example_cursor',
|
||||
],
|
||||
true
|
||||
],
|
||||
'Missing has_more' => [
|
||||
(object) [
|
||||
'cursor' => 'example_cursor',
|
||||
],
|
||||
false
|
||||
],
|
||||
'Missing cursor' => [
|
||||
(object) [
|
||||
'has_more' => 'example_cursor',
|
||||
],
|
||||
false
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for the has_additional_results API function.
|
||||
*
|
||||
* @dataProvider has_additional_results_provider
|
||||
* @param object $result The data to test
|
||||
* @param bool $expected The expected result
|
||||
*/
|
||||
public function test_has_additional_results($result, $expected) {
|
||||
$mock = $this->getMockBuilder(\repository_dropbox\dropbox::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(null)
|
||||
->getMock();
|
||||
|
||||
$this->assertEquals($expected, $mock->has_additional_results($result));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for check_and_handle_api_errors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function check_and_handle_api_errors_provider() {
|
||||
return [
|
||||
'200 http_code' => [
|
||||
['http_code' => 200],
|
||||
'',
|
||||
null,
|
||||
null,
|
||||
],
|
||||
'400 http_code' => [
|
||||
['http_code' => 400],
|
||||
'Unused',
|
||||
'coding_exception',
|
||||
'Invalid input parameter passed to DropBox API.',
|
||||
],
|
||||
'401 http_code' => [
|
||||
['http_code' => 401],
|
||||
'Unused',
|
||||
\repository_dropbox\authentication_exception::class,
|
||||
'Authentication token expired',
|
||||
],
|
||||
'409 http_code' => [
|
||||
['http_code' => 409],
|
||||
'Some data here',
|
||||
'coding_exception',
|
||||
'Endpoint specific error: Some data here',
|
||||
],
|
||||
'429 http_code' => [
|
||||
['http_code' => 429],
|
||||
'Unused',
|
||||
\repository_dropbox\rate_limit_exception::class,
|
||||
'Rate limit hit',
|
||||
],
|
||||
'500 http_code' => [
|
||||
['http_code' => 500],
|
||||
'Response body',
|
||||
'invalid_response_exception',
|
||||
'500: Response body',
|
||||
],
|
||||
'599 http_code' => [
|
||||
['http_code' => 599],
|
||||
'Response body',
|
||||
'invalid_response_exception',
|
||||
'599: Response body',
|
||||
],
|
||||
'600 http_code (invalid, but not officially an error)' => [
|
||||
['http_code' => 600],
|
||||
'',
|
||||
null,
|
||||
null,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for check_and_handle_api_errors.
|
||||
*
|
||||
* @dataProvider check_and_handle_api_errors_provider
|
||||
* @param object $info The response to test
|
||||
* @param string $data The contented returned by the curl call
|
||||
* @param string $exception The name of the expected exception
|
||||
* @param string $exceptionmessage The expected message in the exception
|
||||
*/
|
||||
public function test_check_and_handle_api_errors($info, $data, $exception, $exceptionmessage) {
|
||||
$mock = $this->getMockBuilder(\repository_dropbox\dropbox::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(null)
|
||||
->getMock();
|
||||
|
||||
$mock->info = $info;
|
||||
|
||||
$rc = new \ReflectionClass(\repository_dropbox\dropbox::class);
|
||||
$rcm = $rc->getMethod('check_and_handle_api_errors');
|
||||
$rcm->setAccessible(true);
|
||||
|
||||
if ($exception) {
|
||||
$this->expectException($exception);
|
||||
}
|
||||
|
||||
if ($exceptionmessage) {
|
||||
$this->expectExceptionMessage($exceptionmessage);
|
||||
}
|
||||
|
||||
$result = $rcm->invoke($mock, $data);
|
||||
|
||||
$this->assertNull($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for the supports_thumbnail function.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function supports_thumbnail_provider() {
|
||||
$tests = [
|
||||
'Only files support thumbnails' => [
|
||||
(object) ['.tag' => 'folder'],
|
||||
false,
|
||||
],
|
||||
'Dropbox currently only supports thumbnail generation for files under 20MB' => [
|
||||
(object) [
|
||||
'.tag' => 'file',
|
||||
'size' => 21 * 1024 * 1024,
|
||||
],
|
||||
false,
|
||||
],
|
||||
'Unusual file extension containing a working format but ending in a non-working one' => [
|
||||
(object) [
|
||||
'.tag' => 'file',
|
||||
'size' => 100 * 1024,
|
||||
'path_lower' => 'Example.jpg.pdf',
|
||||
],
|
||||
false,
|
||||
],
|
||||
'Unusual file extension ending in a working extension' => [
|
||||
(object) [
|
||||
'.tag' => 'file',
|
||||
'size' => 100 * 1024,
|
||||
'path_lower' => 'Example.pdf.jpg',
|
||||
],
|
||||
true,
|
||||
],
|
||||
];
|
||||
|
||||
// See docs at https://www.dropbox.com/developers/documentation/http/documentation#files-get_thumbnail.
|
||||
$types = [
|
||||
'pdf' => false,
|
||||
'doc' => false,
|
||||
'docx' => false,
|
||||
'jpg' => true,
|
||||
'jpeg' => true,
|
||||
'png' => true,
|
||||
'tiff' => true,
|
||||
'tif' => true,
|
||||
'gif' => true,
|
||||
'bmp' => true,
|
||||
];
|
||||
foreach ($types as $type => $result) {
|
||||
$tests["Test support for {$type}"] = [
|
||||
(object) [
|
||||
'.tag' => 'file',
|
||||
'size' => 100 * 1024,
|
||||
'path_lower' => "example_filename.{$type}",
|
||||
],
|
||||
$result,
|
||||
];
|
||||
}
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the supports_thumbnail function.
|
||||
*
|
||||
* @dataProvider supports_thumbnail_provider
|
||||
* @param object $entry The entry to test
|
||||
* @param bool $expected Whether this entry supports thumbnail generation
|
||||
*/
|
||||
public function test_supports_thumbnail($entry, $expected) {
|
||||
$mock = $this->getMockBuilder(\repository_dropbox\dropbox::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(null)
|
||||
->getMock();
|
||||
|
||||
$this->assertEquals($expected, $mock->supports_thumbnail($entry));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the logout makes a call to the correct revocation endpoint.
|
||||
*/
|
||||
public function test_logout_revocation() {
|
||||
$mock = $this->getMockBuilder(\repository_dropbox\dropbox::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(['fetch_dropbox_data'])
|
||||
->getMock();
|
||||
|
||||
$mock->expects($this->once())
|
||||
->method('fetch_dropbox_data')
|
||||
->with($this->equalTo('auth/token/revoke'), $this->equalTo(null));
|
||||
|
||||
$this->assertNull($mock->logout());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the logout function catches authentication_exception exceptions and discards them.
|
||||
*/
|
||||
public function test_logout_revocation_catch_auth_exception() {
|
||||
$mock = $this->getMockBuilder(\repository_dropbox\dropbox::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(['fetch_dropbox_data'])
|
||||
->getMock();
|
||||
|
||||
$mock->expects($this->once())
|
||||
->method('fetch_dropbox_data')
|
||||
->will($this->throwException(new \repository_dropbox\authentication_exception('Exception should be caught')));
|
||||
|
||||
$this->assertNull($mock->logout());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the logout function does not catch any other exception.
|
||||
*/
|
||||
public function test_logout_revocation_does_not_catch_other_exceptions() {
|
||||
$mock = $this->getMockBuilder(\repository_dropbox\dropbox::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(['fetch_dropbox_data'])
|
||||
->getMock();
|
||||
|
||||
$mock->expects($this->once())
|
||||
->method('fetch_dropbox_data')
|
||||
->will($this->throwException(new \repository_dropbox\rate_limit_exception));
|
||||
|
||||
$this->expectException(\repository_dropbox\rate_limit_exception::class);
|
||||
$mock->logout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test basic fetch_dropbox_data function.
|
||||
*/
|
||||
public function test_fetch_dropbox_data_endpoint() {
|
||||
$mock = $this->getMockBuilder(\repository_dropbox\dropbox::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods([
|
||||
'request',
|
||||
'get_api_endpoint',
|
||||
'get_content_endpoint',
|
||||
])
|
||||
->getMock();
|
||||
|
||||
$endpoint = 'testEndpoint';
|
||||
|
||||
// The fetch_dropbox_data call should be called against the standard endpoint only.
|
||||
$mock->expects($this->once())
|
||||
->method('get_api_endpoint')
|
||||
->with($endpoint)
|
||||
->will($this->returnValue("https://example.com/api/2/{$endpoint}"));
|
||||
|
||||
$mock->expects($this->never())
|
||||
->method('get_content_endpoint');
|
||||
|
||||
$mock->expects($this->once())
|
||||
->method('request')
|
||||
->will($this->returnValue(json_encode([])));
|
||||
|
||||
// Make the call.
|
||||
$rc = new \ReflectionClass(\repository_dropbox\dropbox::class);
|
||||
$rcm = $rc->getMethod('fetch_dropbox_data');
|
||||
$rcm->setAccessible(true);
|
||||
$rcm->invoke($mock, $endpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Some Dropbox endpoints require that the POSTFIELDS be set to null exactly.
|
||||
*/
|
||||
public function test_fetch_dropbox_data_postfields_null() {
|
||||
$mock = $this->getMockBuilder(\repository_dropbox\dropbox::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods([
|
||||
'request',
|
||||
])
|
||||
->getMock();
|
||||
|
||||
$endpoint = 'testEndpoint';
|
||||
|
||||
$mock->expects($this->once())
|
||||
->method('request')
|
||||
->with($this->anything(), $this->callback(function($d) {
|
||||
return $d['CURLOPT_POSTFIELDS'] === 'null';
|
||||
}))
|
||||
->will($this->returnValue(json_encode([])));
|
||||
|
||||
// Make the call.
|
||||
$rc = new \ReflectionClass(\repository_dropbox\dropbox::class);
|
||||
$rcm = $rc->getMethod('fetch_dropbox_data');
|
||||
$rcm->setAccessible(true);
|
||||
$rcm->invoke($mock, $endpoint, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* When data is specified, it should be json_encoded in POSTFIELDS.
|
||||
*/
|
||||
public function test_fetch_dropbox_data_postfields_data() {
|
||||
$mock = $this->getMockBuilder(\repository_dropbox\dropbox::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods([
|
||||
'request',
|
||||
])
|
||||
->getMock();
|
||||
|
||||
$endpoint = 'testEndpoint';
|
||||
$data = ['something' => 'somevalue'];
|
||||
|
||||
$mock->expects($this->once())
|
||||
->method('request')
|
||||
->with($this->anything(), $this->callback(function($d) use ($data) {
|
||||
return $d['CURLOPT_POSTFIELDS'] === json_encode($data);
|
||||
}))
|
||||
->will($this->returnValue(json_encode([])));
|
||||
|
||||
// Make the call.
|
||||
$rc = new \ReflectionClass(\repository_dropbox\dropbox::class);
|
||||
$rcm = $rc->getMethod('fetch_dropbox_data');
|
||||
$rcm->setAccessible(true);
|
||||
$rcm->invoke($mock, $endpoint, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* When more results are available, these should be fetched until there are no more.
|
||||
*/
|
||||
public function test_fetch_dropbox_data_recurse_on_additional_records() {
|
||||
$mock = $this->getMockBuilder(\repository_dropbox\dropbox::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods([
|
||||
'request',
|
||||
'get_api_endpoint',
|
||||
])
|
||||
->getMock();
|
||||
|
||||
$endpoint = 'testEndpoint';
|
||||
|
||||
// We can't detect if fetch_dropbox_data was called twice because
|
||||
// we can'
|
||||
$mock->expects($this->exactly(3))
|
||||
->method('request')
|
||||
->will($this->onConsecutiveCalls(
|
||||
json_encode(['has_more' => true, 'cursor' => 'Example', 'entries' => ['foo', 'bar']]),
|
||||
json_encode(['has_more' => true, 'cursor' => 'Example', 'entries' => ['baz']]),
|
||||
json_encode(['has_more' => false, 'cursor' => '', 'entries' => ['bum']])
|
||||
));
|
||||
|
||||
// We automatically adjust for the /continue endpoint.
|
||||
$mock->expects($this->exactly(3))
|
||||
->method('get_api_endpoint')
|
||||
->withConsecutive(['testEndpoint'], ['testEndpoint/continue'], ['testEndpoint/continue'])
|
||||
->willReturn($this->onConsecutiveCalls(
|
||||
'https://example.com/api/2/testEndpoint',
|
||||
'https://example.com/api/2/testEndpoint/continue',
|
||||
'https://example.com/api/2/testEndpoint/continue'
|
||||
));
|
||||
|
||||
// Make the call.
|
||||
$rc = new \ReflectionClass(\repository_dropbox\dropbox::class);
|
||||
$rcm = $rc->getMethod('fetch_dropbox_data');
|
||||
$rcm->setAccessible(true);
|
||||
$result = $rcm->invoke($mock, $endpoint, null);
|
||||
|
||||
$this->assertEquals([
|
||||
'foo',
|
||||
'bar',
|
||||
'baz',
|
||||
'bum',
|
||||
], $result->entries);
|
||||
|
||||
$this->assertFalse(isset($result->cursor));
|
||||
$this->assertFalse(isset($result->has_more));
|
||||
}
|
||||
|
||||
/**
|
||||
* Base tests for the fetch_dropbox_content function.
|
||||
*/
|
||||
public function test_fetch_dropbox_content() {
|
||||
$mock = $this->getMockBuilder(\repository_dropbox\dropbox::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods([
|
||||
'request',
|
||||
'setHeader',
|
||||
'get_content_endpoint',
|
||||
'get_api_endpoint',
|
||||
'check_and_handle_api_errors',
|
||||
])
|
||||
->getMock();
|
||||
|
||||
$data = ['exampledata' => 'examplevalue'];
|
||||
$endpoint = 'getContent';
|
||||
$url = "https://example.com/api/2/{$endpoint}";
|
||||
$response = 'Example content';
|
||||
|
||||
// Only the content endpoint should be called.
|
||||
$mock->expects($this->once())
|
||||
->method('get_content_endpoint')
|
||||
->with($endpoint)
|
||||
->will($this->returnValue($url));
|
||||
|
||||
$mock->expects($this->never())
|
||||
->method('get_api_endpoint');
|
||||
|
||||
$mock->expects($this->exactly(2))
|
||||
->method('setHeader')
|
||||
->withConsecutive(
|
||||
[$this->equalTo('Content-Type: ')],
|
||||
[$this->equalTo('Dropbox-API-Arg: ' . json_encode($data))]
|
||||
);
|
||||
|
||||
// Only one request should be made, and it should forcibly be a POST.
|
||||
$mock->expects($this->once())
|
||||
->method('request')
|
||||
->with($this->equalTo($url), $this->callback(function($options) {
|
||||
return $options['CURLOPT_POST'] === 1;
|
||||
}))
|
||||
->willReturn($response);
|
||||
|
||||
$mock->expects($this->once())
|
||||
->method('check_and_handle_api_errors')
|
||||
->with($this->equalTo($response))
|
||||
;
|
||||
|
||||
// Make the call.
|
||||
$rc = new \ReflectionClass(\repository_dropbox\dropbox::class);
|
||||
$rcm = $rc->getMethod('fetch_dropbox_content');
|
||||
$rcm->setAccessible(true);
|
||||
$result = $rcm->invoke($mock, $endpoint, $data);
|
||||
|
||||
$this->assertEquals($response, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the get_file_share_info function returns an existing link if one is available.
|
||||
*/
|
||||
public function test_get_file_share_info_existing() {
|
||||
$mock = $this->getMockBuilder(\repository_dropbox\dropbox::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods([
|
||||
'fetch_dropbox_data',
|
||||
'normalize_file_share_info',
|
||||
])
|
||||
->getMock();
|
||||
|
||||
$id = 'LifeTheUniverseAndEverything';
|
||||
$file = (object) ['.tag' => 'file', 'id' => $id, 'path_lower' => 'SomeValue'];
|
||||
$sharelink = 'https://example.com/share/link';
|
||||
|
||||
// Mock fetch_dropbox_data to return an existing file.
|
||||
$mock->expects($this->once())
|
||||
->method('fetch_dropbox_data')
|
||||
->with(
|
||||
$this->equalTo('sharing/list_shared_links'),
|
||||
$this->equalTo(['path' => $id])
|
||||
)
|
||||
->willReturn((object) ['links' => [$file]]);
|
||||
|
||||
$mock->expects($this->once())
|
||||
->method('normalize_file_share_info')
|
||||
->with($this->equalTo($file))
|
||||
->will($this->returnValue($sharelink));
|
||||
|
||||
$this->assertEquals($sharelink, $mock->get_file_share_info($id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the get_file_share_info function creates a new link if one is not available.
|
||||
*/
|
||||
public function test_get_file_share_info_new() {
|
||||
$mock = $this->getMockBuilder(\repository_dropbox\dropbox::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods([
|
||||
'fetch_dropbox_data',
|
||||
'normalize_file_share_info',
|
||||
])
|
||||
->getMock();
|
||||
|
||||
$id = 'LifeTheUniverseAndEverything';
|
||||
$file = (object) ['.tag' => 'file', 'id' => $id, 'path_lower' => 'SomeValue'];
|
||||
$sharelink = 'https://example.com/share/link';
|
||||
|
||||
// Mock fetch_dropbox_data to return an existing file.
|
||||
$mock->expects($this->exactly(2))
|
||||
->method('fetch_dropbox_data')
|
||||
->withConsecutive(
|
||||
[$this->equalTo('sharing/list_shared_links'), $this->equalTo(['path' => $id])],
|
||||
[$this->equalTo('sharing/create_shared_link_with_settings'), $this->equalTo([
|
||||
'path' => $id,
|
||||
'settings' => [
|
||||
'requested_visibility' => 'public',
|
||||
]
|
||||
])]
|
||||
)
|
||||
->will($this->onConsecutiveCalls(
|
||||
(object) ['links' => []],
|
||||
$file
|
||||
));
|
||||
|
||||
$mock->expects($this->once())
|
||||
->method('normalize_file_share_info')
|
||||
->with($this->equalTo($file))
|
||||
->will($this->returnValue($sharelink));
|
||||
|
||||
$this->assertEquals($sharelink, $mock->get_file_share_info($id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test failure behaviour with get_file_share_info fails to create a new link.
|
||||
*/
|
||||
public function test_get_file_share_info_new_failure() {
|
||||
$mock = $this->getMockBuilder(\repository_dropbox\dropbox::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods([
|
||||
'fetch_dropbox_data',
|
||||
'normalize_file_share_info',
|
||||
])
|
||||
->getMock();
|
||||
|
||||
$id = 'LifeTheUniverseAndEverything';
|
||||
|
||||
// Mock fetch_dropbox_data to return an existing file.
|
||||
$mock->expects($this->exactly(2))
|
||||
->method('fetch_dropbox_data')
|
||||
->withConsecutive(
|
||||
[$this->equalTo('sharing/list_shared_links'), $this->equalTo(['path' => $id])],
|
||||
[$this->equalTo('sharing/create_shared_link_with_settings'), $this->equalTo([
|
||||
'path' => $id,
|
||||
'settings' => [
|
||||
'requested_visibility' => 'public',
|
||||
]
|
||||
])]
|
||||
)
|
||||
->will($this->onConsecutiveCalls(
|
||||
(object) ['links' => []],
|
||||
null
|
||||
));
|
||||
|
||||
$mock->expects($this->never())
|
||||
->method('normalize_file_share_info');
|
||||
|
||||
$this->assertNull($mock->get_file_share_info($id));
|
||||
}
|
||||
}
|
@ -28,17 +28,21 @@
|
||||
require(__DIR__.'/../../config.php');
|
||||
require_once(__DIR__.'/lib.php');
|
||||
|
||||
$repo_id = optional_param('repo_id', 0, PARAM_INT); // Repository ID
|
||||
$repoid = optional_param('repo_id', 0, PARAM_INT); // Repository ID
|
||||
$contextid = optional_param('ctx_id', SYSCONTEXTID, PARAM_INT); // Context ID
|
||||
$source = optional_param('source', '', PARAM_TEXT); // File path in current user's dropbox
|
||||
|
||||
if (isloggedin() && $repo_id && $source
|
||||
&& ($repo = repository::get_repository_by_id($repo_id, $contextid))
|
||||
&& method_exists($repo, 'send_thumbnail')) {
|
||||
// try requesting thumbnail and outputting it. This function exits if thumbnail was retrieved
|
||||
$thumbnailavailable = isloggedin();
|
||||
$thumbnailavailable = $thumbnailavailable && $repoid;
|
||||
$thumbnailavailable = $thumbnailavailable && $source;
|
||||
$thumbnailavailable = $thumbnailavailable && ($repo = repository::get_repository_by_id($repoid, $contextid));
|
||||
$thumbnailavailable = $thumbnailavailable && method_exists($repo, 'send_thumbnail');
|
||||
if ($thumbnailavailable) {
|
||||
// Try requesting thumbnail and outputting it.
|
||||
// This function exits if thumbnail was retrieved.
|
||||
$repo->send_thumbnail($source);
|
||||
}
|
||||
|
||||
// send default icon for the file type
|
||||
// Send default icon for the file type.
|
||||
$fileicon = file_extension_icon($source, 64);
|
||||
send_file($CFG->dirroot.'/pix/'.$fileicon.'.png', basename($fileicon).'.png');
|
||||
send_file($CFG->dirroot . '/pix/' . $fileicon . '.png', basename($fileicon) . '.png');
|
||||
|
@ -25,6 +25,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2016052300; // The current plugin version (Date: YYYYMMDDXX)
|
||||
$plugin->version = 2016091300; // The current plugin version (Date: YYYYMMDDXX)
|
||||
$plugin->requires = 2016051900; // Requires this Moodle version
|
||||
$plugin->component = 'repository_dropbox'; // Full name of the plugin (used for diagnostics)
|
||||
|
Loading…
x
Reference in New Issue
Block a user