MDL-52051 repository_dropbox: Move v1 API aside
This commit is contained in:
@@ -0,0 +1,654 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* This plugin is used to access user's dropbox files
|
||||
*
|
||||
* @since Moodle 2.0
|
||||
* @package repository_dropbox
|
||||
* @copyright 2012 Marina Glancy
|
||||
* @copyright 2010 Dongsheng Cai {@link http://dongsheng.org}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/repository/lib.php');
|
||||
|
||||
/**
|
||||
* Repository to access Dropbox files
|
||||
*
|
||||
* @package repository_dropbox
|
||||
* @copyright 2010 Dongsheng Cai
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class repository_dropbox_legacy extends repository {
|
||||
/** @var dropbox the instance of dropbox client */
|
||||
private $dropbox;
|
||||
/** @var array files */
|
||||
public $files;
|
||||
/** @var bool flag of login status */
|
||||
public $logged = false;
|
||||
/** @var int maximum size of file to cache in moodle filepool */
|
||||
public $cachelimit = null;
|
||||
|
||||
/** @var int cached file ttl */
|
||||
private $cachedfilettl = null;
|
||||
|
||||
/**
|
||||
* Constructor of dropbox plugin
|
||||
*
|
||||
* @param int $repositoryid
|
||||
* @param stdClass $context
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {
|
||||
global $CFG;
|
||||
$options['page'] = optional_param('p', 1, PARAM_INT);
|
||||
parent::__construct($repositoryid, $context, $options);
|
||||
|
||||
$this->setting = 'dropbox_';
|
||||
|
||||
$this->dropbox_key = $this->get_option('dropbox_key');
|
||||
$this->dropbox_secret = $this->get_option('dropbox_secret');
|
||||
|
||||
// One day.
|
||||
$this->cachedfilettl = 60 * 60 * 24;
|
||||
|
||||
if (isset($options['access_key'])) {
|
||||
$this->access_key = $options['access_key'];
|
||||
} else {
|
||||
$this->access_key = get_user_preferences($this->setting.'_access_key', '');
|
||||
}
|
||||
if (isset($options['access_secret'])) {
|
||||
$this->access_secret = $options['access_secret'];
|
||||
} else {
|
||||
$this->access_secret = get_user_preferences($this->setting.'_access_secret', '');
|
||||
}
|
||||
|
||||
if (!empty($this->access_key) && !empty($this->access_secret)) {
|
||||
$this->logged = true;
|
||||
}
|
||||
|
||||
$callbackurl = new moodle_url($CFG->wwwroot.'/repository/repository_callback.php', array(
|
||||
'callback' => 'yes',
|
||||
'repo_id' => $repositoryid
|
||||
));
|
||||
|
||||
$args = array(
|
||||
'oauth_consumer_key' => $this->dropbox_key,
|
||||
'oauth_consumer_secret' => $this->dropbox_secret,
|
||||
'oauth_callback' => $callbackurl->out(false),
|
||||
'api_root' => 'https://api.dropbox.com/1/oauth',
|
||||
);
|
||||
|
||||
$this->dropbox = new repository_dropbox_legacy_dropbox($args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type name (no whitespace)
|
||||
* For a human readable name, use get_readablename()
|
||||
*
|
||||
* @return string the type name
|
||||
*/
|
||||
public function get_typename() {
|
||||
return 'dropbox';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set access key
|
||||
*
|
||||
* @param string $access_key
|
||||
*/
|
||||
public function set_access_key($access_key) {
|
||||
$this->access_key = $access_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set access secret
|
||||
*
|
||||
* @param string $access_secret
|
||||
*/
|
||||
public function set_access_secret($access_secret) {
|
||||
$this->access_secret = $access_secret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if moodle has got access token and secret
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function check_login() {
|
||||
return !empty($this->logged);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate dropbox login url
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function print_login() {
|
||||
$result = $this->dropbox->request_token();
|
||||
set_user_preference($this->setting.'_request_secret', $result['oauth_token_secret']);
|
||||
$url = $result['authorize_url'];
|
||||
if ($this->options['ajax']) {
|
||||
$ret = array();
|
||||
$popup_btn = new stdClass();
|
||||
$popup_btn->type = 'popup';
|
||||
$popup_btn->url = $url;
|
||||
$ret['login'] = array($popup_btn);
|
||||
return $ret;
|
||||
} else {
|
||||
echo '<a target="_blank" href="'.$url.'">'.get_string('login', 'repository').'</a>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Request access token
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function callback() {
|
||||
$token = optional_param('oauth_token', '', PARAM_TEXT);
|
||||
$secret = get_user_preferences($this->setting.'_request_secret', '');
|
||||
$access_token = $this->dropbox->get_access_token($token, $secret);
|
||||
set_user_preference($this->setting.'_access_key', $access_token['oauth_token']);
|
||||
set_user_preference($this->setting.'_access_secret', $access_token['oauth_token_secret']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get dropbox files
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $page
|
||||
* @return array
|
||||
*/
|
||||
public function get_listing($path = '', $page = '1') {
|
||||
global $OUTPUT;
|
||||
if (empty($path) || $path == '/') {
|
||||
$path = '/';
|
||||
} else {
|
||||
$path = file_correct_filepath($path);
|
||||
}
|
||||
$encoded_path = str_replace("%2F", "/", rawurlencode($path));
|
||||
|
||||
$list = array();
|
||||
$list['list'] = array();
|
||||
$list['manage'] = 'https://www.dropbox.com/home';
|
||||
$list['dynload'] = true;
|
||||
$list['nosearch'] = true;
|
||||
$list['logouturl'] = 'https://www.dropbox.com/logout';
|
||||
$list['message'] = get_string('logoutdesc', 'repository_dropbox');
|
||||
// Process breadcrumb trail.
|
||||
$list['path'] = array(
|
||||
array('name' => get_string('dropbox', 'repository_dropbox'), 'path' => '/')
|
||||
);
|
||||
|
||||
$result = $this->dropbox->get_listing($encoded_path, $this->access_key, $this->access_secret);
|
||||
|
||||
if (!is_object($result) || empty($result)) {
|
||||
return $list;
|
||||
}
|
||||
if (empty($result->path)) {
|
||||
$current_path = '/';
|
||||
} else {
|
||||
$current_path = file_correct_filepath($result->path);
|
||||
}
|
||||
|
||||
$trail = '';
|
||||
if (!empty($path)) {
|
||||
$parts = explode('/', $path);
|
||||
if (count($parts) > 1) {
|
||||
foreach ($parts as $part) {
|
||||
if (!empty($part)) {
|
||||
$trail .= ('/'.$part);
|
||||
$list['path'][] = array('name' => $part, 'path' => $trail);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$list['path'][] = array('name' => $path, 'path' => $path);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($result->error)) {
|
||||
// Reset access key.
|
||||
set_user_preference($this->setting.'_access_key', '');
|
||||
set_user_preference($this->setting.'_access_secret', '');
|
||||
throw new repository_exception('repositoryerror', 'repository', '', $result->error);
|
||||
}
|
||||
if (empty($result->contents) or !is_array($result->contents)) {
|
||||
return $list;
|
||||
}
|
||||
$files = $result->contents;
|
||||
$dirslist = array();
|
||||
$fileslist = array();
|
||||
foreach ($files as $file) {
|
||||
if ($file->is_dir) {
|
||||
$dirslist[] = array(
|
||||
'title' => substr($file->path, strpos($file->path, $current_path) + strlen($current_path)),
|
||||
'path' => file_correct_filepath($file->path),
|
||||
'date' => strtotime($file->modified),
|
||||
'thumbnail' => $OUTPUT->pix_url(file_folder_icon(64))->out(false),
|
||||
'thumbnail_height' => 64,
|
||||
'thumbnail_width' => 64,
|
||||
'children' => array(),
|
||||
);
|
||||
} else {
|
||||
$thumbnail = null;
|
||||
if ($file->thumb_exists) {
|
||||
$thumburl = new moodle_url('/repository/dropbox/thumbnail.php',
|
||||
array('repo_id' => $this->id,
|
||||
'ctx_id' => $this->context->id,
|
||||
'source' => $file->path,
|
||||
'rev' => $file->rev // include revision to avoid cache problems
|
||||
));
|
||||
$thumbnail = $thumburl->out(false);
|
||||
}
|
||||
$fileslist[] = array(
|
||||
'title' => substr($file->path, strpos($file->path, $current_path) + strlen($current_path)),
|
||||
'source' => $file->path,
|
||||
'size' => $file->bytes,
|
||||
'date' => strtotime($file->modified),
|
||||
'thumbnail' => $OUTPUT->pix_url(file_extension_icon($file->path, 64))->out(false),
|
||||
'realthumbnail' => $thumbnail,
|
||||
'thumbnail_height' => 64,
|
||||
'thumbnail_width' => 64,
|
||||
);
|
||||
}
|
||||
}
|
||||
$fileslist = array_filter($fileslist, array($this, 'filter'));
|
||||
$list['list'] = array_merge($dirslist, array_values($fileslist));
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a thumbnail for current user's dropbox file
|
||||
*
|
||||
* @param string $string
|
||||
*/
|
||||
public function send_thumbnail($source) {
|
||||
global $CFG;
|
||||
$saveas = $this->prepare_file('');
|
||||
try {
|
||||
$access_key = get_user_preferences($this->setting.'_access_key', '');
|
||||
$access_secret = get_user_preferences($this->setting.'_access_secret', '');
|
||||
$this->dropbox->set_access_token($access_key, $access_secret);
|
||||
$this->dropbox->get_thumbnail($source, $saveas, $CFG->repositorysyncimagetimeout);
|
||||
$content = file_get_contents($saveas);
|
||||
unlink($saveas);
|
||||
// Set 30 days lifetime for the image. If the image is changed in dropbox it will have
|
||||
// different revision number and URL will be different. It is completely safe
|
||||
// to cache thumbnail in the browser for a long time.
|
||||
send_file($content, basename($source), 30*24*60*60, 0, true);
|
||||
} catch (Exception $e) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout from dropbox
|
||||
* @return array
|
||||
*/
|
||||
public function logout() {
|
||||
set_user_preference($this->setting.'_access_key', '');
|
||||
set_user_preference($this->setting.'_access_secret', '');
|
||||
$this->access_key = '';
|
||||
$this->access_secret = '';
|
||||
return $this->print_login();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes references in DB that contains user credentials
|
||||
*
|
||||
* @param string $reference contents of DB field files_reference.reference
|
||||
*/
|
||||
public function fix_old_style_reference($reference) {
|
||||
global $CFG;
|
||||
$ref = unserialize($reference);
|
||||
if (!isset($ref->url)) {
|
||||
$this->dropbox->set_access_token($ref->access_key, $ref->access_secret);
|
||||
$ref->url = $this->dropbox->get_file_share_link($ref->path, $CFG->repositorygetfiletimeout);
|
||||
if (!$ref->url) {
|
||||
// Some error occurred, do not fix reference for now.
|
||||
return $reference;
|
||||
}
|
||||
}
|
||||
unset($ref->access_key);
|
||||
unset($ref->access_secret);
|
||||
$newreference = serialize($ref);
|
||||
if ($newreference !== $reference) {
|
||||
// We need to update references in the database.
|
||||
global $DB;
|
||||
$params = array(
|
||||
'newreference' => $newreference,
|
||||
'newhash' => sha1($newreference),
|
||||
'reference' => $reference,
|
||||
'hash' => sha1($reference),
|
||||
'repoid' => $this->id
|
||||
);
|
||||
$refid = $DB->get_field_sql('SELECT id FROM {files_reference}
|
||||
WHERE reference = :reference AND referencehash = :hash
|
||||
AND repositoryid = :repoid', $params);
|
||||
if (!$refid) {
|
||||
return $newreference;
|
||||
}
|
||||
$existingrefid = $DB->get_field_sql('SELECT id FROM {files_reference}
|
||||
WHERE reference = :newreference AND referencehash = :newhash
|
||||
AND repositoryid = :repoid', $params);
|
||||
if ($existingrefid) {
|
||||
// The same reference already exists, we unlink all files from it,
|
||||
// link them to the current reference and remove the old one.
|
||||
$DB->execute('UPDATE {files} SET referencefileid = :refid
|
||||
WHERE referencefileid = :existingrefid',
|
||||
array('refid' => $refid, 'existingrefid' => $existingrefid));
|
||||
$DB->delete_records('files_reference', array('id' => $existingrefid));
|
||||
}
|
||||
// Update the reference.
|
||||
$params['refid'] = $refid;
|
||||
$DB->execute('UPDATE {files_reference}
|
||||
SET reference = :newreference, referencehash = :newhash
|
||||
WHERE id = :refid', $params);
|
||||
}
|
||||
return $newreference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a URL received from dropbox API function 'shares' into URL that
|
||||
* can be used to download/access file directly
|
||||
*
|
||||
* @param string $sharedurl
|
||||
* @return string
|
||||
*/
|
||||
private function get_file_download_link($sharedurl) {
|
||||
$url = new \moodle_url($sharedurl);
|
||||
$url->param('dl', 1);
|
||||
|
||||
return $url->out(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads a file from external repository and saves it in temp dir
|
||||
*
|
||||
* @throws moodle_exception when file could not be downloaded
|
||||
*
|
||||
* @param string $reference the content of files.reference field or result of
|
||||
* function {@link repository_dropbox::get_file_reference()}
|
||||
* @param string $saveas filename (without path) to save the downloaded file in the
|
||||
* temporary directory, if omitted or file already exists the new filename will be generated
|
||||
* @return array with elements:
|
||||
* path: internal location of the file
|
||||
* url: URL to the source (from parameters)
|
||||
*/
|
||||
public function get_file($reference, $saveas = '') {
|
||||
global $CFG;
|
||||
$ref = unserialize($reference);
|
||||
$saveas = $this->prepare_file($saveas);
|
||||
if (isset($ref->access_key) && isset($ref->access_secret) && isset($ref->path)) {
|
||||
$this->dropbox->set_access_token($ref->access_key, $ref->access_secret);
|
||||
return $this->dropbox->get_file($ref->path, $saveas, $CFG->repositorygetfiletimeout);
|
||||
} else if (isset($ref->url)) {
|
||||
$c = new curl;
|
||||
$url = $this->get_file_download_link($ref->url);
|
||||
$result = $c->download_one($url, null, array('filepath' => $saveas, 'timeout' => $CFG->repositorygetfiletimeout, 'followlocation' => true));
|
||||
$info = $c->get_info();
|
||||
if ($result !== true || !isset($info['http_code']) || $info['http_code'] != 200) {
|
||||
throw new moodle_exception('errorwhiledownload', 'repository', '', $result);
|
||||
}
|
||||
return array('path' => $saveas, 'url' => $url);
|
||||
}
|
||||
throw new moodle_exception('cannotdownload', 'repository');
|
||||
}
|
||||
|
||||
/**
|
||||
* Dropbox plugin supports all kinds of files
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function supported_filetypes() {
|
||||
return '*';
|
||||
}
|
||||
|
||||
/**
|
||||
* User cannot use the external link to dropbox
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function supported_returntypes() {
|
||||
return FILE_INTERNAL | FILE_REFERENCE | FILE_EXTERNAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return file URL for external link
|
||||
*
|
||||
* @param string $reference the result of get_file_reference()
|
||||
* @return string
|
||||
*/
|
||||
public function get_link($reference) {
|
||||
global $CFG;
|
||||
$ref = unserialize($reference);
|
||||
if (!isset($ref->url)) {
|
||||
$this->dropbox->set_access_token($ref->access_key, $ref->access_secret);
|
||||
$ref->url = $this->dropbox->get_file_share_link($ref->path, $CFG->repositorygetfiletimeout);
|
||||
}
|
||||
return $this->get_file_download_link($ref->url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare file reference information
|
||||
*
|
||||
* @param string $source
|
||||
* @return string file referece
|
||||
*/
|
||||
public function get_file_reference($source) {
|
||||
global $USER, $CFG;
|
||||
$reference = new stdClass;
|
||||
$reference->path = $source;
|
||||
$reference->userid = $USER->id;
|
||||
$reference->username = fullname($USER);
|
||||
$reference->access_key = get_user_preferences($this->setting.'_access_key', '');
|
||||
$reference->access_secret = get_user_preferences($this->setting.'_access_secret', '');
|
||||
|
||||
// By API we don't know if we need this reference to just download a file from dropbox
|
||||
// into moodle filepool or create a reference. Since we need to create a shared link
|
||||
// only in case of reference we analyze the script parameter.
|
||||
$usefilereference = optional_param('usefilereference', false, PARAM_BOOL);
|
||||
if ($usefilereference) {
|
||||
$this->dropbox->set_access_token($reference->access_key, $reference->access_secret);
|
||||
$url = $this->dropbox->get_file_share_link($source, $CFG->repositorygetfiletimeout);
|
||||
if ($url) {
|
||||
unset($reference->access_key);
|
||||
unset($reference->access_secret);
|
||||
$reference->url = $url;
|
||||
}
|
||||
}
|
||||
return serialize($reference);
|
||||
}
|
||||
|
||||
public function sync_reference(stored_file $file) {
|
||||
global $CFG;
|
||||
|
||||
if ($file->get_referencelastsync() + DAYSECS > time()) {
|
||||
// Synchronise not more often than once a day.
|
||||
return false;
|
||||
}
|
||||
$ref = unserialize($file->get_reference());
|
||||
if (!isset($ref->url)) {
|
||||
// This is an old-style reference in DB. We need to fix it.
|
||||
$ref = unserialize($this->fix_old_style_reference($file->get_reference()));
|
||||
}
|
||||
if (!isset($ref->url)) {
|
||||
return false;
|
||||
}
|
||||
$c = new curl;
|
||||
$url = $this->get_file_download_link($ref->url);
|
||||
if (file_extension_in_typegroup($ref->path, 'web_image')) {
|
||||
$saveas = $this->prepare_file('');
|
||||
try {
|
||||
$result = $c->download_one($url, array(), array('filepath' => $saveas, 'timeout' => $CFG->repositorysyncimagetimeout, 'followlocation' => true));
|
||||
$info = $c->get_info();
|
||||
if ($result === true && isset($info['http_code']) && $info['http_code'] == 200) {
|
||||
$fs = get_file_storage();
|
||||
list($contenthash, $filesize, $newfile) = $fs->add_file_to_pool($saveas);
|
||||
$file->set_synchronized($contenthash, $filesize);
|
||||
return true;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
}
|
||||
$c->get($url, null, array('timeout' => $CFG->repositorysyncimagetimeout, 'followlocation' => true, 'nobody' => true));
|
||||
$info = $c->get_info();
|
||||
if (isset($info['http_code']) && $info['http_code'] == 200 &&
|
||||
array_key_exists('download_content_length', $info) &&
|
||||
$info['download_content_length'] >= 0) {
|
||||
$filesize = (int)$info['download_content_length'];
|
||||
$file->set_synchronized(null, $filesize);
|
||||
return true;
|
||||
}
|
||||
$file->set_missingsource();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache file from external repository by reference.
|
||||
*
|
||||
* Dropbox repository regularly caches all external files that are smaller than
|
||||
* {@link repository_dropbox::max_cache_bytes()}
|
||||
*
|
||||
* @param string $reference this reference is generated by
|
||||
* repository::get_file_reference()
|
||||
* @param stored_file $storedfile created file reference
|
||||
*/
|
||||
public function cache_file_by_reference($reference, $storedfile) {
|
||||
try {
|
||||
$this->import_external_file_contents($storedfile, $this->max_cache_bytes());
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return human readable reference information.
|
||||
* {@link stored_file::get_reference()}
|
||||
*
|
||||
* @param string $reference
|
||||
* @param int $filestatus status of the file, 0 - ok, 666 - source missing
|
||||
* @return string
|
||||
*/
|
||||
public function get_reference_details($reference, $filestatus = 0) {
|
||||
global $USER;
|
||||
$ref = unserialize($reference);
|
||||
$detailsprefix = $this->get_name();
|
||||
if (isset($ref->userid) && $ref->userid != $USER->id && isset($ref->username)) {
|
||||
$detailsprefix .= ' ('.$ref->username.')';
|
||||
}
|
||||
$details = $detailsprefix;
|
||||
if (isset($ref->path)) {
|
||||
$details .= ': '. $ref->path;
|
||||
}
|
||||
if (isset($ref->path) && !$filestatus) {
|
||||
// Indicate this is from dropbox with path.
|
||||
return $details;
|
||||
} else {
|
||||
if (isset($ref->url)) {
|
||||
$details = $detailsprefix. ': '. $ref->url;
|
||||
}
|
||||
return get_string('lostsource', 'repository', $details);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the source information
|
||||
*
|
||||
* @param string $source
|
||||
* @return string
|
||||
*/
|
||||
public function get_file_source_info($source) {
|
||||
global $USER;
|
||||
return 'Dropbox ('.fullname($USER).'): ' . $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Repository method to serve the referenced file
|
||||
*
|
||||
* This method is ivoked from {@link send_stored_file()}.
|
||||
* Dropbox repository first caches the file by reading it into temporary folder and then
|
||||
* serves from there.
|
||||
*
|
||||
* @param stored_file $storedfile the file that contains the reference
|
||||
* @param int $lifetime Number of seconds before the file should expire from caches (null means $CFG->filelifetime)
|
||||
* @param int $filter 0 (default)=no filtering, 1=all files, 2=html files only
|
||||
* @param bool $forcedownload If true (default false), forces download of file rather than view in browser/plugin
|
||||
* @param array $options additional options affecting the file serving
|
||||
*/
|
||||
public function send_file($storedfile, $lifetime=null , $filter=0, $forcedownload=false, array $options = null) {
|
||||
$ref = unserialize($storedfile->get_reference());
|
||||
if ($storedfile->get_filesize() > $this->max_cache_bytes()) {
|
||||
header('Location: '.$this->get_file_download_link($ref->url));
|
||||
die;
|
||||
}
|
||||
try {
|
||||
$this->import_external_file_contents($storedfile, $this->max_cache_bytes());
|
||||
if (!is_array($options)) {
|
||||
$options = array();
|
||||
}
|
||||
$options['sendcachedexternalfile'] = true;
|
||||
send_stored_file($storedfile, $lifetime, $filter, $forcedownload, $options);
|
||||
} catch (moodle_exception $e) {
|
||||
// Redirect to Dropbox, it will show the error.
|
||||
// We redirect to Dropbox shared link, not to download link here!
|
||||
header('Location: '.$ref->url);
|
||||
die;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum size of the Dropbox files to cache in moodle.
|
||||
*
|
||||
* Note that {@link repository_dropbox::sync_reference()} will try to cache images even
|
||||
* when they are bigger in order to generate thumbnails. However there is
|
||||
* a small timeout for downloading images for synchronisation and it will
|
||||
* probably fail if the image is too big.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function max_cache_bytes() {
|
||||
if ($this->cachelimit === null) {
|
||||
$this->cachelimit = (int) get_config('dropbox', 'dropbox_cachelimit');
|
||||
}
|
||||
return $this->cachelimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches all references to Dropbox files in moodle filepool
|
||||
*
|
||||
* Invoked by {@link repository_dropbox_cron()}. Only files smaller than
|
||||
* {@link repository_dropbox::max_cache_bytes()} and only files which
|
||||
* synchronisation timeout have not expired are cached.
|
||||
*/
|
||||
public function cron() {
|
||||
$fs = get_file_storage();
|
||||
$files = $fs->get_external_files($this->id);
|
||||
$fetchedreferences = [];
|
||||
foreach ($files as $file) {
|
||||
if (isset($fetchedreferences[$file->get_referencefileid()])) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
// This call will cache all files that are smaller than max_cache_bytes()
|
||||
// and synchronise file size of all others
|
||||
$this->import_external_file_contents($file, $this->max_cache_bytes());
|
||||
$fetchedreferences[$file->get_referencefileid()] = true;
|
||||
} catch (moodle_exception $e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,7 @@ require_once($CFG->libdir.'/oauthlib.php');
|
||||
* @copyright 2010 Dongsheng Cai
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class dropbox extends oauth_helper {
|
||||
class repository_dropbox_legacy_dropbox extends oauth_helper {
|
||||
/** @var string dropbox access type, can be dropbox or sandbox */
|
||||
private $mode = 'dropbox';
|
||||
/** @var string dropbox api url*/
|
||||
+245
-588
@@ -24,7 +24,6 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
require_once($CFG->dirroot . '/repository/lib.php');
|
||||
require_once(dirname(__FILE__).'/locallib.php');
|
||||
|
||||
/**
|
||||
* Repository to access Dropbox files
|
||||
@@ -34,419 +33,214 @@ require_once(dirname(__FILE__).'/locallib.php');
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class repository_dropbox extends repository {
|
||||
/** @var dropbox the instance of dropbox client */
|
||||
private $dropbox;
|
||||
/** @var array files */
|
||||
public $files;
|
||||
/** @var bool flag of login status */
|
||||
public $logged=false;
|
||||
/** @var int maximum size of file to cache in moodle filepool */
|
||||
public $cachelimit=null;
|
||||
|
||||
/** @var int cached file ttl */
|
||||
private $cachedfilettl = null;
|
||||
/**
|
||||
* @var int The maximum file size to cache in the moodle filepool.
|
||||
*/
|
||||
public $cachelimit = null;
|
||||
|
||||
/**
|
||||
* Constructor of dropbox plugin
|
||||
*
|
||||
* @param int $repositoryid
|
||||
* @param stdClass $context
|
||||
* @param array $options
|
||||
* @var repository The actual repository.
|
||||
*/
|
||||
public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {
|
||||
global $CFG;
|
||||
$options['page'] = optional_param('p', 1, PARAM_INT);
|
||||
protected $legacy;
|
||||
|
||||
/**
|
||||
* Constructor of dropbox plugin.
|
||||
*
|
||||
* @inheritDocs
|
||||
*/
|
||||
public function __construct($repositoryid, $context = SYSCONTEXTID, $options = []) {
|
||||
$this->legacy = new repository_dropbox_legacy($repositoryid, $context, $options);
|
||||
|
||||
parent::__construct($repositoryid, $context, $options);
|
||||
|
||||
$this->setting = 'dropbox_';
|
||||
|
||||
$this->dropbox_key = $this->get_option('dropbox_key');
|
||||
$this->dropbox_secret = $this->get_option('dropbox_secret');
|
||||
|
||||
// one day
|
||||
$this->cachedfilettl = 60 * 60 * 24;
|
||||
|
||||
if (isset($options['access_key'])) {
|
||||
$this->access_key = $options['access_key'];
|
||||
} else {
|
||||
$this->access_key = get_user_preferences($this->setting.'_access_key', '');
|
||||
}
|
||||
if (isset($options['access_secret'])) {
|
||||
$this->access_secret = $options['access_secret'];
|
||||
} else {
|
||||
$this->access_secret = get_user_preferences($this->setting.'_access_secret', '');
|
||||
}
|
||||
|
||||
if (!empty($this->access_key) && !empty($this->access_secret)) {
|
||||
$this->logged = true;
|
||||
}
|
||||
|
||||
$callbackurl = new moodle_url($CFG->wwwroot.'/repository/repository_callback.php', array(
|
||||
'callback'=>'yes',
|
||||
'repo_id'=>$repositoryid
|
||||
));
|
||||
|
||||
$args = array(
|
||||
'oauth_consumer_key'=>$this->dropbox_key,
|
||||
'oauth_consumer_secret'=>$this->dropbox_secret,
|
||||
'oauth_callback' => $callbackurl->out(false),
|
||||
'api_root' => 'https://api.dropbox.com/1/oauth',
|
||||
);
|
||||
|
||||
$this->dropbox = new dropbox($args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set access key
|
||||
* Repository method to serve the referenced file.
|
||||
*
|
||||
* @param string $access_key
|
||||
* @inheritDocs
|
||||
*/
|
||||
public function set_access_key($access_key) {
|
||||
$this->access_key = $access_key;
|
||||
public function send_file($storedfile, $lifetime=null , $filter=0, $forcedownload=false, array $options = null) {
|
||||
return $this->legacy->send_file($storedfile, $lifetime, $filter, $forcedownload, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set access secret
|
||||
* Return human readable reference information.
|
||||
* {@link stored_file::get_reference()}
|
||||
*
|
||||
* @param string $access_secret
|
||||
* @inheritDocs
|
||||
*/
|
||||
public function set_access_secret($access_secret) {
|
||||
$this->access_secret = $access_secret;
|
||||
public function get_reference_details($reference, $filestatus = 0) {
|
||||
return $this->legacy->get_reference_details($reference, $filestatus);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if moodle has got access token and secret
|
||||
* Cache file from external repository by reference.
|
||||
* {@link repository::get_file_reference()}
|
||||
* {@link repository::get_file()}
|
||||
* Invoked at MOODLE/repository/repository_ajax.php.
|
||||
*
|
||||
* @return bool
|
||||
* @inheritDocs
|
||||
*/
|
||||
public function check_login() {
|
||||
return !empty($this->logged);
|
||||
public function cache_file_by_reference($reference, $storedfile) {
|
||||
return $this->legacy->cache_file_by_reference($reference, $storedfile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate dropbox login url
|
||||
* Return the source information.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function print_login() {
|
||||
$result = $this->dropbox->request_token();
|
||||
set_user_preference($this->setting.'_request_secret', $result['oauth_token_secret']);
|
||||
$url = $result['authorize_url'];
|
||||
if ($this->options['ajax']) {
|
||||
$ret = array();
|
||||
$popup_btn = new stdClass();
|
||||
$popup_btn->type = 'popup';
|
||||
$popup_btn->url = $url;
|
||||
$ret['login'] = array($popup_btn);
|
||||
return $ret;
|
||||
} else {
|
||||
echo '<a target="_blank" href="'.$url.'">'.get_string('login', 'repository').'</a>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Request access token
|
||||
* The result of the function is stored in files.source field. It may be analysed
|
||||
* when the source file is lost or repository may use it to display human-readable
|
||||
* location of reference original.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function callback() {
|
||||
$token = optional_param('oauth_token', '', PARAM_TEXT);
|
||||
$secret = get_user_preferences($this->setting.'_request_secret', '');
|
||||
$access_token = $this->dropbox->get_access_token($token, $secret);
|
||||
set_user_preference($this->setting.'_access_key', $access_token['oauth_token']);
|
||||
set_user_preference($this->setting.'_access_secret', $access_token['oauth_token_secret']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get dropbox files
|
||||
* This method is called when file is picked for the first time only. When file
|
||||
* (either copy or a reference) is already in moodle and it is being picked
|
||||
* again to another file area (also as a copy or as a reference), the value of
|
||||
* files.source is copied.
|
||||
*
|
||||
* @param string $path
|
||||
* @param int $page
|
||||
* @return array
|
||||
* @inheritDocs
|
||||
*/
|
||||
public function get_listing($path = '', $page = '1') {
|
||||
global $OUTPUT;
|
||||
if (empty($path) || $path=='/') {
|
||||
$path = '/';
|
||||
} else {
|
||||
$path = file_correct_filepath($path);
|
||||
}
|
||||
$encoded_path = str_replace("%2F", "/", rawurlencode($path));
|
||||
|
||||
$list = array();
|
||||
$list['list'] = array();
|
||||
$list['manage'] = 'https://www.dropbox.com/home';
|
||||
$list['dynload'] = true;
|
||||
$list['nosearch'] = true;
|
||||
$list['logouturl'] = 'https://www.dropbox.com/logout';
|
||||
$list['message'] = get_string('logoutdesc', 'repository_dropbox');
|
||||
// process breadcrumb trail
|
||||
$list['path'] = array(
|
||||
array('name'=>get_string('dropbox', 'repository_dropbox'), 'path'=>'/')
|
||||
);
|
||||
|
||||
$result = $this->dropbox->get_listing($encoded_path, $this->access_key, $this->access_secret);
|
||||
|
||||
if (!is_object($result) || empty($result)) {
|
||||
return $list;
|
||||
}
|
||||
if (empty($result->path)) {
|
||||
$current_path = '/';
|
||||
} else {
|
||||
$current_path = file_correct_filepath($result->path);
|
||||
}
|
||||
|
||||
$trail = '';
|
||||
if (!empty($path)) {
|
||||
$parts = explode('/', $path);
|
||||
if (count($parts) > 1) {
|
||||
foreach ($parts as $part) {
|
||||
if (!empty($part)) {
|
||||
$trail .= ('/'.$part);
|
||||
$list['path'][] = array('name'=>$part, 'path'=>$trail);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$list['path'][] = array('name'=>$path, 'path'=>$path);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($result->error)) {
|
||||
// reset access key
|
||||
set_user_preference($this->setting.'_access_key', '');
|
||||
set_user_preference($this->setting.'_access_secret', '');
|
||||
throw new repository_exception('repositoryerror', 'repository', '', $result->error);
|
||||
}
|
||||
if (empty($result->contents) or !is_array($result->contents)) {
|
||||
return $list;
|
||||
}
|
||||
$files = $result->contents;
|
||||
$dirslist = array();
|
||||
$fileslist = array();
|
||||
foreach ($files as $file) {
|
||||
if ($file->is_dir) {
|
||||
$dirslist[] = array(
|
||||
'title' => substr($file->path, strpos($file->path, $current_path)+strlen($current_path)),
|
||||
'path' => file_correct_filepath($file->path),
|
||||
'date' => strtotime($file->modified),
|
||||
'thumbnail' => $OUTPUT->pix_url(file_folder_icon(64))->out(false),
|
||||
'thumbnail_height' => 64,
|
||||
'thumbnail_width' => 64,
|
||||
'children' => array(),
|
||||
);
|
||||
} else {
|
||||
$thumbnail = null;
|
||||
if ($file->thumb_exists) {
|
||||
$thumburl = new moodle_url('/repository/dropbox/thumbnail.php',
|
||||
array('repo_id' => $this->id,
|
||||
'ctx_id' => $this->context->id,
|
||||
'source' => $file->path,
|
||||
'rev' => $file->rev // include revision to avoid cache problems
|
||||
));
|
||||
$thumbnail = $thumburl->out(false);
|
||||
}
|
||||
$fileslist[] = array(
|
||||
'title' => substr($file->path, strpos($file->path, $current_path)+strlen($current_path)),
|
||||
'source' => $file->path,
|
||||
'size' => $file->bytes,
|
||||
'date' => strtotime($file->modified),
|
||||
'thumbnail' => $OUTPUT->pix_url(file_extension_icon($file->path, 64))->out(false),
|
||||
'realthumbnail' => $thumbnail,
|
||||
'thumbnail_height' => 64,
|
||||
'thumbnail_width' => 64,
|
||||
);
|
||||
}
|
||||
}
|
||||
$fileslist = array_filter($fileslist, array($this, 'filter'));
|
||||
$list['list'] = array_merge($dirslist, array_values($fileslist));
|
||||
return $list;
|
||||
public function get_file_source_info($source) {
|
||||
return $this->legacy->get_file_source_info($source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a thumbnail for current user's dropbox file
|
||||
* Prepare file reference information.
|
||||
*
|
||||
* @param string $string
|
||||
* @inheritDocs
|
||||
*/
|
||||
public function send_thumbnail($source) {
|
||||
global $CFG;
|
||||
$saveas = $this->prepare_file('');
|
||||
try {
|
||||
$access_key = get_user_preferences($this->setting.'_access_key', '');
|
||||
$access_secret = get_user_preferences($this->setting.'_access_secret', '');
|
||||
$this->dropbox->set_access_token($access_key, $access_secret);
|
||||
$this->dropbox->get_thumbnail($source, $saveas, $CFG->repositorysyncimagetimeout);
|
||||
$content = file_get_contents($saveas);
|
||||
unlink($saveas);
|
||||
// set 30 days lifetime for the image. If the image is changed in dropbox it will have
|
||||
// different revision number and URL will be different. It is completely safe
|
||||
// to cache thumbnail in the browser for a long time
|
||||
send_file($content, basename($source), 30*24*60*60, 0, true);
|
||||
} catch (Exception $e) {}
|
||||
public function get_file_reference($source) {
|
||||
return $this->legacy->get_file_reference($source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout from dropbox
|
||||
* @return array
|
||||
*/
|
||||
public function logout() {
|
||||
set_user_preference($this->setting.'_access_key', '');
|
||||
set_user_preference($this->setting.'_access_secret', '');
|
||||
$this->access_key = '';
|
||||
$this->access_secret = '';
|
||||
return $this->print_login();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set dropbox option
|
||||
* @param array $options
|
||||
* @return mixed
|
||||
*/
|
||||
public function set_option($options = array()) {
|
||||
if (!empty($options['dropbox_key'])) {
|
||||
set_config('dropbox_key', trim($options['dropbox_key']), 'dropbox');
|
||||
}
|
||||
if (!empty($options['dropbox_secret'])) {
|
||||
set_config('dropbox_secret', trim($options['dropbox_secret']), 'dropbox');
|
||||
}
|
||||
if (!empty($options['dropbox_cachelimit'])) {
|
||||
$this->cachelimit = (int)trim($options['dropbox_cachelimit']);
|
||||
set_config('dropbox_cachelimit', $this->cachelimit, 'dropbox');
|
||||
}
|
||||
unset($options['dropbox_key']);
|
||||
unset($options['dropbox_secret']);
|
||||
unset($options['dropbox_cachelimit']);
|
||||
$ret = parent::set_option($options);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get dropbox options
|
||||
* @param string $config
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_option($config = '') {
|
||||
if ($config==='dropbox_key') {
|
||||
return trim(get_config('dropbox', 'dropbox_key'));
|
||||
} elseif ($config==='dropbox_secret') {
|
||||
return trim(get_config('dropbox', 'dropbox_secret'));
|
||||
} elseif ($config==='dropbox_cachelimit') {
|
||||
return $this->max_cache_bytes();
|
||||
} else {
|
||||
$options = parent::get_option();
|
||||
$options['dropbox_key'] = trim(get_config('dropbox', 'dropbox_key'));
|
||||
$options['dropbox_secret'] = trim(get_config('dropbox', 'dropbox_secret'));
|
||||
$options['dropbox_cachelimit'] = $this->max_cache_bytes();
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes references in DB that contains user credentials
|
||||
* Return file URL for external link.
|
||||
*
|
||||
* @param string $reference contents of DB field files_reference.reference
|
||||
* @inheritDocs
|
||||
*/
|
||||
public function fix_old_style_reference($reference) {
|
||||
global $CFG;
|
||||
$ref = unserialize($reference);
|
||||
if (!isset($ref->url)) {
|
||||
$this->dropbox->set_access_token($ref->access_key, $ref->access_secret);
|
||||
$ref->url = $this->dropbox->get_file_share_link($ref->path, $CFG->repositorygetfiletimeout);
|
||||
if (!$ref->url) {
|
||||
// some error occurred, do not fix reference for now
|
||||
return $reference;
|
||||
}
|
||||
}
|
||||
unset($ref->access_key);
|
||||
unset($ref->access_secret);
|
||||
$newreference = serialize($ref);
|
||||
if ($newreference !== $reference) {
|
||||
// we need to update references in the database
|
||||
global $DB;
|
||||
$params = array(
|
||||
'newreference' => $newreference,
|
||||
'newhash' => sha1($newreference),
|
||||
'reference' => $reference,
|
||||
'hash' => sha1($reference),
|
||||
'repoid' => $this->id
|
||||
);
|
||||
$refid = $DB->get_field_sql('SELECT id FROM {files_reference}
|
||||
WHERE reference = :reference AND referencehash = :hash
|
||||
AND repositoryid = :repoid', $params);
|
||||
if (!$refid) {
|
||||
return $newreference;
|
||||
}
|
||||
$existingrefid = $DB->get_field_sql('SELECT id FROM {files_reference}
|
||||
WHERE reference = :newreference AND referencehash = :newhash
|
||||
AND repositoryid = :repoid', $params);
|
||||
if ($existingrefid) {
|
||||
// the same reference already exists, we unlink all files from it,
|
||||
// link them to the current reference and remove the old one
|
||||
$DB->execute('UPDATE {files} SET referencefileid = :refid
|
||||
WHERE referencefileid = :existingrefid',
|
||||
array('refid' => $refid, 'existingrefid' => $existingrefid));
|
||||
$DB->delete_records('files_reference', array('id' => $existingrefid));
|
||||
}
|
||||
// update the reference
|
||||
$params['refid'] = $refid;
|
||||
$DB->execute('UPDATE {files_reference}
|
||||
SET reference = :newreference, referencehash = :newhash
|
||||
WHERE id = :refid', $params);
|
||||
}
|
||||
return $newreference;
|
||||
public function get_link($reference) {
|
||||
return $this->legacy->get_link($reference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a URL received from dropbox API function 'shares' into URL that
|
||||
* can be used to download/access file directly
|
||||
* Downloads a file from external repository and saves it in temp dir.
|
||||
*
|
||||
* @param string $sharedurl
|
||||
* @return string
|
||||
*/
|
||||
private function get_file_download_link($sharedurl) {
|
||||
return preg_replace('|^(\w*://)www(.dropbox.com)|','\1dl\2',$sharedurl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads a file from external repository and saves it in temp dir
|
||||
*
|
||||
* @throws moodle_exception when file could not be downloaded
|
||||
*
|
||||
* @param string $reference the content of files.reference field or result of
|
||||
* function {@link repository_dropbox::get_file_reference()}
|
||||
* @param string $saveas filename (without path) to save the downloaded file in the
|
||||
* temporary directory, if omitted or file already exists the new filename will be generated
|
||||
* @return array with elements:
|
||||
* path: internal location of the file
|
||||
* url: URL to the source (from parameters)
|
||||
* @inheritDocs
|
||||
*/
|
||||
public function get_file($reference, $saveas = '') {
|
||||
global $CFG;
|
||||
$ref = unserialize($reference);
|
||||
$saveas = $this->prepare_file($saveas);
|
||||
if (isset($ref->access_key) && isset($ref->access_secret) && isset($ref->path)) {
|
||||
$this->dropbox->set_access_token($ref->access_key, $ref->access_secret);
|
||||
return $this->dropbox->get_file($ref->path, $saveas, $CFG->repositorygetfiletimeout);
|
||||
} else if (isset($ref->url)) {
|
||||
$c = new curl;
|
||||
$url = $this->get_file_download_link($ref->url);
|
||||
$result = $c->download_one($url, null, array('filepath' => $saveas, 'timeout' => $CFG->repositorygetfiletimeout, 'followlocation' => true));
|
||||
$info = $c->get_info();
|
||||
if ($result !== true || !isset($info['http_code']) || $info['http_code'] != 200) {
|
||||
throw new moodle_exception('errorwhiledownload', 'repository', '', $result);
|
||||
}
|
||||
return array('path'=>$saveas, 'url'=>$url);
|
||||
}
|
||||
throw new moodle_exception('cannotdownload', 'repository');
|
||||
return $this->legacy->get_file($reference, $saveas);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dropbox plugin supports all kinds of files.
|
||||
*
|
||||
* @inheritDocs
|
||||
*/
|
||||
public function supported_filetypes() {
|
||||
return $this->legacy->supported_filetypes();
|
||||
}
|
||||
|
||||
/**
|
||||
* User cannot use the external link to dropbox.
|
||||
*
|
||||
* @inheritDocs
|
||||
*/
|
||||
public function supported_returntypes() {
|
||||
return $this->legacy->supported_returntypes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get dropbox files.
|
||||
*
|
||||
* @inheritDocs
|
||||
*/
|
||||
public function get_listing($path = '', $page = '1') {
|
||||
return $this->legacy->get_listing($path, $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get dropbox files in the specified path.
|
||||
*
|
||||
* @param string $query The search query
|
||||
* @param int $page The page number
|
||||
* @return array
|
||||
*/
|
||||
public function search($query, $page = 0) {
|
||||
return parent::search($query, $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a thumbnail for current user's dropbox file.
|
||||
*
|
||||
* @inheritDocs
|
||||
*/
|
||||
public function send_thumbnail($source) {
|
||||
return $this->legacy->send_thumbnail($source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes references in DB that contains user credentials.
|
||||
*
|
||||
* @param string $packed Content of DB field files_reference.reference
|
||||
* @return string New serialized reference
|
||||
*/
|
||||
protected function fix_old_style_reference($packed) {
|
||||
return $this->legacy->fix_old_style_reference($packed);
|
||||
}
|
||||
/**
|
||||
* Add Plugin settings input to Moodle form
|
||||
* Logout from dropbox.
|
||||
*
|
||||
* @param moodleform $mform Moodle form (passed by reference)
|
||||
* @param string $classname repository class name
|
||||
* @inheritDocs
|
||||
*/
|
||||
public function logout() {
|
||||
return $this->legacy->logout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if moodle has got access token and secret.
|
||||
*
|
||||
* @inheritDocs
|
||||
*/
|
||||
public function check_login() {
|
||||
return $this->legacy->check_login();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate dropbox login url.
|
||||
*
|
||||
* @inheritDocs
|
||||
*/
|
||||
public function print_login() {
|
||||
return $this->legacy->print_login();
|
||||
}
|
||||
|
||||
/**
|
||||
* Request access token.
|
||||
*
|
||||
* @inheritDocs
|
||||
*/
|
||||
public function callback() {
|
||||
return $this->legacy->callback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches all references to Dropbox files in moodle filepool.
|
||||
*
|
||||
* Invoked by {@link repository_dropbox_cron()}. Only files smaller than
|
||||
* {@link repository_dropbox::max_cache_bytes()} and only files which
|
||||
* synchronisation timeout have not expired are cached.
|
||||
*
|
||||
* @inheritDocs
|
||||
*/
|
||||
public function cron() {
|
||||
return $this->legacy->cron();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Plugin settings input to Moodle form.
|
||||
*
|
||||
* @inheritDocs
|
||||
*/
|
||||
public static function type_config_form($mform, $classname = 'repository') {
|
||||
global $CFG;
|
||||
parent::type_config_form($mform);
|
||||
$key = get_config('dropbox', 'dropbox_key');
|
||||
$secret = get_config('dropbox', 'dropbox_secret');
|
||||
@@ -458,200 +252,116 @@ class repository_dropbox extends repository {
|
||||
$secret = '';
|
||||
}
|
||||
|
||||
$strrequired = get_string('required');
|
||||
|
||||
$mform->addElement('text', 'dropbox_key', get_string('apikey', 'repository_dropbox'), array('value'=>$key,'size' => '40'));
|
||||
$mform->setType('dropbox_key', PARAM_RAW_TRIMMED);
|
||||
$mform->addElement('text', 'dropbox_secret', get_string('secret', 'repository_dropbox'), array('value'=>$secret,'size' => '40'));
|
||||
|
||||
$mform->addRule('dropbox_key', $strrequired, 'required', null, 'client');
|
||||
$mform->addRule('dropbox_secret', $strrequired, 'required', null, 'client');
|
||||
$mform->addRule('dropbox_key', get_string('required'), 'required', null, 'client');
|
||||
$mform->addRule('dropbox_secret', get_string('required'), 'required', null, 'client');
|
||||
$mform->setType('dropbox_secret', PARAM_RAW_TRIMMED);
|
||||
$str_getkey = get_string('instruction', 'repository_dropbox');
|
||||
$mform->addElement('static', null, '', $str_getkey);
|
||||
$mform->addElement('static', null, '', get_string('instruction', 'repository_dropbox'));
|
||||
|
||||
$mform->addElement('text', 'dropbox_cachelimit', get_string('cachelimit', 'repository_dropbox'), array('size' => '40'));
|
||||
$mform->addRule('dropbox_cachelimit', null, 'numeric', null, 'client');
|
||||
$mform->setType('dropbox_cachelimit', PARAM_INT);
|
||||
$mform->addElement('static', 'dropbox_cachelimit_info', '', get_string('cachelimit_info', 'repository_dropbox'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Option names of dropbox plugin
|
||||
* Set options.
|
||||
*
|
||||
* @return array
|
||||
* @param array $options
|
||||
* @return mixed
|
||||
*/
|
||||
public function set_option($options = []) {
|
||||
if (!empty($options['dropbox_key'])) {
|
||||
set_config('dropbox_key', trim($options['dropbox_key']), 'dropbox');
|
||||
unset($options['dropbox_key']);
|
||||
}
|
||||
if (!empty($options['dropbox_secret'])) {
|
||||
set_config('dropbox_secret', trim($options['dropbox_secret']), 'dropbox');
|
||||
unset($options['dropbox_secret']);
|
||||
}
|
||||
if (!empty($options['dropbox_cachelimit'])) {
|
||||
$this->cachelimit = (int) trim($options['dropbox_cachelimit']);
|
||||
set_config('dropbox_cachelimit', $this->cachelimit, 'dropbox');
|
||||
unset($options['dropbox_cachelimit']);
|
||||
}
|
||||
|
||||
return parent::set_option($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get dropbox options
|
||||
* @param string $config
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_option($config = '') {
|
||||
if ($config === 'dropbox_key') {
|
||||
return trim(get_config('dropbox', 'dropbox_key'));
|
||||
} else if ($config === 'dropbox_secret') {
|
||||
return trim(get_config('dropbox', 'dropbox_secret'));
|
||||
} else if ($config === 'dropbox_cachelimit') {
|
||||
return $this->max_cache_bytes();
|
||||
} else {
|
||||
$options = parent::get_option();
|
||||
$options['dropbox_key'] = trim(get_config('dropbox', 'dropbox_key'));
|
||||
$options['dropbox_secret'] = trim(get_config('dropbox', 'dropbox_secret'));
|
||||
$options['dropbox_cachelimit'] = $this->max_cache_bytes();
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Option names of dropbox plugin.
|
||||
*
|
||||
* @inheritDocs
|
||||
*/
|
||||
public static function get_type_option_names() {
|
||||
return array('dropbox_key', 'dropbox_secret', 'pluginname', 'dropbox_cachelimit');
|
||||
return [
|
||||
'dropbox_key',
|
||||
'dropbox_secret',
|
||||
'pluginname',
|
||||
'dropbox_cachelimit',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Dropbox plugin supports all kinds of files
|
||||
* Performs synchronisation of an external file if the previous one has expired.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function supported_filetypes() {
|
||||
return '*';
|
||||
}
|
||||
|
||||
/**
|
||||
* User cannot use the external link to dropbox
|
||||
* This function must be implemented for external repositories supporting
|
||||
* FILE_REFERENCE, it is called for existing aliases when their filesize,
|
||||
* contenthash or timemodified are requested. It is not called for internal
|
||||
* repositories (see {@link repository::has_moodle_files()}), references to
|
||||
* internal files are updated immediately when source is modified.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function supported_returntypes() {
|
||||
return FILE_INTERNAL | FILE_REFERENCE | FILE_EXTERNAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return file URL for external link
|
||||
* Referenced files may optionally keep their content in Moodle filepool (for
|
||||
* thumbnail generation or to be able to serve cached copy). In this
|
||||
* case both contenthash and filesize need to be synchronized. Otherwise repositories
|
||||
* should use contenthash of empty file and correct filesize in bytes.
|
||||
*
|
||||
* @param string $reference the result of get_file_reference()
|
||||
* @return string
|
||||
*/
|
||||
public function get_link($reference) {
|
||||
global $CFG;
|
||||
$ref = unserialize($reference);
|
||||
if (!isset($ref->url)) {
|
||||
$this->dropbox->set_access_token($ref->access_key, $ref->access_secret);
|
||||
$ref->url = $this->dropbox->get_file_share_link($ref->path, $CFG->repositorygetfiletimeout);
|
||||
}
|
||||
return $this->get_file_download_link($ref->url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare file reference information
|
||||
* Note that this function may be run for EACH file that needs to be synchronised at the
|
||||
* moment. If anything is being downloaded or requested from external sources there
|
||||
* should be a small timeout. The synchronisation is performed to update the size of
|
||||
* the file and/or to update image and re-generated image preview. There is nothing
|
||||
* fatal if syncronisation fails but it is fatal if syncronisation takes too long
|
||||
* and hangs the script generating a page.
|
||||
*
|
||||
* @param string $source
|
||||
* @return string file referece
|
||||
* Note: If you wish to call $file->get_filesize(), $file->get_contenthash() or
|
||||
* $file->get_timemodified() make sure that recursion does not happen.
|
||||
*
|
||||
* Called from {@link stored_file::sync_external_file()}
|
||||
*
|
||||
* @inheritDocs
|
||||
*/
|
||||
public function get_file_reference($source) {
|
||||
global $USER, $CFG;
|
||||
$reference = new stdClass;
|
||||
$reference->path = $source;
|
||||
$reference->userid = $USER->id;
|
||||
$reference->username = fullname($USER);
|
||||
$reference->access_key = get_user_preferences($this->setting.'_access_key', '');
|
||||
$reference->access_secret = get_user_preferences($this->setting.'_access_secret', '');
|
||||
|
||||
// by API we don't know if we need this reference to just download a file from dropbox
|
||||
// into moodle filepool or create a reference. Since we need to create a shared link
|
||||
// only in case of reference we analyze the script parameter
|
||||
$usefilereference = optional_param('usefilereference', false, PARAM_BOOL);
|
||||
if ($usefilereference) {
|
||||
$this->dropbox->set_access_token($reference->access_key, $reference->access_secret);
|
||||
$url = $this->dropbox->get_file_share_link($source, $CFG->repositorygetfiletimeout);
|
||||
if ($url) {
|
||||
unset($reference->access_key);
|
||||
unset($reference->access_secret);
|
||||
$reference->url = $url;
|
||||
}
|
||||
}
|
||||
return serialize($reference);
|
||||
}
|
||||
|
||||
public function sync_reference(stored_file $file) {
|
||||
global $CFG;
|
||||
|
||||
if ($file->get_referencelastsync() + DAYSECS > time()) {
|
||||
// Synchronise not more often than once a day.
|
||||
return false;
|
||||
}
|
||||
$ref = unserialize($file->get_reference());
|
||||
if (!isset($ref->url)) {
|
||||
// this is an old-style reference in DB. We need to fix it
|
||||
$ref = unserialize($this->fix_old_style_reference($file->get_reference()));
|
||||
}
|
||||
if (!isset($ref->url)) {
|
||||
return false;
|
||||
}
|
||||
$c = new curl;
|
||||
$url = $this->get_file_download_link($ref->url);
|
||||
if (file_extension_in_typegroup($ref->path, 'web_image')) {
|
||||
$saveas = $this->prepare_file('');
|
||||
try {
|
||||
$result = $c->download_one($url, array(), array('filepath' => $saveas, 'timeout' => $CFG->repositorysyncimagetimeout, 'followlocation' => true));
|
||||
$info = $c->get_info();
|
||||
if ($result === true && isset($info['http_code']) && $info['http_code'] == 200) {
|
||||
$fs = get_file_storage();
|
||||
list($contenthash, $filesize, $newfile) = $fs->add_file_to_pool($saveas);
|
||||
$file->set_synchronized($contenthash, $filesize);
|
||||
return true;
|
||||
}
|
||||
} catch (Exception $e) {}
|
||||
}
|
||||
$c->get($url, null, array('timeout' => $CFG->repositorysyncimagetimeout, 'followlocation' => true, 'nobody' => true));
|
||||
$info = $c->get_info();
|
||||
if (isset($info['http_code']) && $info['http_code'] == 200 &&
|
||||
array_key_exists('download_content_length', $info) &&
|
||||
$info['download_content_length'] >= 0) {
|
||||
$filesize = (int)$info['download_content_length'];
|
||||
$file->set_synchronized(null, $filesize);
|
||||
return true;
|
||||
}
|
||||
$file->set_missingsource();
|
||||
return true;
|
||||
return $this->legacy->sync_reference($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache file from external repository by reference
|
||||
*
|
||||
* Dropbox repository regularly caches all external files that are smaller than
|
||||
* {@link repository_dropbox::max_cache_bytes()}
|
||||
*
|
||||
* @param string $reference this reference is generated by
|
||||
* repository::get_file_reference()
|
||||
* @param stored_file $storedfile created file reference
|
||||
*/
|
||||
public function cache_file_by_reference($reference, $storedfile) {
|
||||
try {
|
||||
$this->import_external_file_contents($storedfile, $this->max_cache_bytes());
|
||||
} catch (Exception $e) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return human readable reference information
|
||||
* {@link stored_file::get_reference()}
|
||||
*
|
||||
* @param string $reference
|
||||
* @param int $filestatus status of the file, 0 - ok, 666 - source missing
|
||||
* @return string
|
||||
*/
|
||||
public function get_reference_details($reference, $filestatus = 0) {
|
||||
global $USER;
|
||||
$ref = unserialize($reference);
|
||||
$detailsprefix = $this->get_name();
|
||||
if (isset($ref->userid) && $ref->userid != $USER->id && isset($ref->username)) {
|
||||
$detailsprefix .= ' ('.$ref->username.')';
|
||||
}
|
||||
$details = $detailsprefix;
|
||||
if (isset($ref->path)) {
|
||||
$details .= ': '. $ref->path;
|
||||
}
|
||||
if (isset($ref->path) && !$filestatus) {
|
||||
// Indicate this is from dropbox with path
|
||||
return $details;
|
||||
} else {
|
||||
if (isset($ref->url)) {
|
||||
$details = $detailsprefix. ': '. $ref->url;
|
||||
}
|
||||
return get_string('lostsource', 'repository', $details);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the source information
|
||||
*
|
||||
* @param string $source
|
||||
* @return string
|
||||
*/
|
||||
public function get_file_source_info($source) {
|
||||
global $USER;
|
||||
return 'Dropbox ('.fullname($USER).'): ' . $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum size of the Dropbox files to cache in moodle
|
||||
* Returns the maximum size of the Dropbox files to cache in moodle.
|
||||
*
|
||||
* Note that {@link repository_dropbox::sync_reference()} will try to cache images even
|
||||
* when they are bigger in order to generate thumbnails. However there is
|
||||
@@ -662,67 +372,14 @@ class repository_dropbox extends repository {
|
||||
*/
|
||||
public function max_cache_bytes() {
|
||||
if ($this->cachelimit === null) {
|
||||
$this->cachelimit = (int)get_config('dropbox', 'dropbox_cachelimit');
|
||||
$this->cachelimit = (int) get_config('dropbox', 'dropbox_cachelimit');
|
||||
}
|
||||
return $this->cachelimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Repository method to serve the referenced file
|
||||
*
|
||||
* This method is ivoked from {@link send_stored_file()}.
|
||||
* Dropbox repository first caches the file by reading it into temporary folder and then
|
||||
* serves from there.
|
||||
*
|
||||
* @param stored_file $storedfile the file that contains the reference
|
||||
* @param int $lifetime Number of seconds before the file should expire from caches (null means $CFG->filelifetime)
|
||||
* @param int $filter 0 (default)=no filtering, 1=all files, 2=html files only
|
||||
* @param bool $forcedownload If true (default false), forces download of file rather than view in browser/plugin
|
||||
* @param array $options additional options affecting the file serving
|
||||
*/
|
||||
public function send_file($storedfile, $lifetime=null , $filter=0, $forcedownload=false, array $options = null) {
|
||||
$ref = unserialize($storedfile->get_reference());
|
||||
if ($storedfile->get_filesize() > $this->max_cache_bytes()) {
|
||||
header('Location: '.$this->get_file_download_link($ref->url));
|
||||
die;
|
||||
}
|
||||
try {
|
||||
$this->import_external_file_contents($storedfile, $this->max_cache_bytes());
|
||||
if (!is_array($options)) {
|
||||
$options = array();
|
||||
}
|
||||
$options['sendcachedexternalfile'] = true;
|
||||
send_stored_file($storedfile, $lifetime, $filter, $forcedownload, $options);
|
||||
} catch (moodle_exception $e) {
|
||||
// redirect to Dropbox, it will show the error.
|
||||
// We redirect to Dropbox shared link, not to download link here!
|
||||
header('Location: '.$ref->url);
|
||||
die;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches all references to Dropbox files in moodle filepool
|
||||
*
|
||||
* Invoked by {@link repository_dropbox_cron()}. Only files smaller than
|
||||
* {@link repository_dropbox::max_cache_bytes()} and only files which
|
||||
* synchronisation timeout have not expired are cached.
|
||||
*/
|
||||
public function cron() {
|
||||
$fs = get_file_storage();
|
||||
$files = $fs->get_external_files($this->id);
|
||||
foreach ($files as $file) {
|
||||
try {
|
||||
// This call will cache all files that are smaller than max_cache_bytes()
|
||||
// and synchronise file size of all others
|
||||
$this->import_external_file_contents($file, $this->max_cache_bytes());
|
||||
} catch (moodle_exception $e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dropbox plugin cron task
|
||||
* Dropbox plugin cron task.
|
||||
*/
|
||||
function repository_dropbox_cron() {
|
||||
$instances = repository::get_instances(array('type'=>'dropbox'));
|
||||
|
||||
Reference in New Issue
Block a user