Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 and 403] [Versions 402 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * This plugin is used to access user's dropbox files 19 * 20 * @since Moodle 2.0 21 * @package repository_dropbox 22 * @copyright 2012 Marina Glancy 23 * @copyright 2010 Dongsheng Cai {@link http://dongsheng.org} 24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 25 */ 26 require_once($CFG->dirroot . '/repository/lib.php'); 27 28 /** 29 * Repository to access Dropbox files 30 * 31 * @package repository_dropbox 32 * @copyright 2010 Dongsheng Cai 33 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 34 */ 35 class repository_dropbox extends repository { 36 /** 37 * @var dropbox The instance of dropbox client. 38 */ 39 private $dropbox; 40 41 /** 42 * @var int The maximum file size to cache in the moodle filepool. 43 */ 44 public $cachelimit = null; 45 46 /** 47 * Constructor of dropbox plugin. 48 * 49 * @inheritDocs 50 */ 51 public function __construct($repositoryid, $context = SYSCONTEXTID, $options = []) { 52 $options['page'] = optional_param('p', 1, PARAM_INT); 53 parent::__construct($repositoryid, $context, $options); 54 55 $returnurl = new moodle_url('/repository/repository_callback.php', [ 56 'callback' => 'yes', 57 'repo_id' => $repositoryid, 58 'sesskey' => sesskey(), 59 ]); 60 61 // Create the dropbox API instance. 62 $issuer = \core\oauth2\api::get_issuer(get_config('dropbox', 'dropbox_issuerid')); 63 $this->dropbox = new repository_dropbox\dropbox($issuer, $returnurl); 64 } 65 66 /** 67 * Repository method to serve the referenced file. 68 * 69 * @inheritDocs 70 */ 71 public function send_file($storedfile, $lifetime=null , $filter=0, $forcedownload=false, array $options = null) { 72 $reference = $this->unpack_reference($storedfile->get_reference()); 73 74 $maxcachesize = $this->max_cache_bytes(); 75 if (empty($maxcachesize)) { 76 // Always cache the file, regardless of size. 77 $cachefile = true; 78 } else { 79 // Size available. Only cache if it is under maxcachesize. 80 $cachefile = $storedfile->get_filesize() < $maxcachesize; 81 } 82 83 if (!$cachefile) { 84 \core\session\manager::write_close(); 85 header('Location: ' . $this->get_file_download_link($reference->url)); 86 die; 87 } 88 89 try { 90 $this->import_external_file_contents($storedfile, $this->max_cache_bytes()); 91 if (!is_array($options)) { 92 $options = array(); 93 } 94 $options['sendcachedexternalfile'] = true; 95 \core\session\manager::write_close(); 96 send_stored_file($storedfile, $lifetime, $filter, $forcedownload, $options); 97 } catch (moodle_exception $e) { 98 // Redirect to Dropbox, it will show the error. 99 // Note: We redirect to Dropbox shared link, not to the download link here! 100 \core\session\manager::write_close(); 101 header('Location: ' . $reference->url); 102 die; 103 } 104 } 105 106 /** 107 * Return human readable reference information. 108 * {@link stored_file::get_reference()} 109 * 110 * @inheritDocs 111 */ 112 public function get_reference_details($reference, $filestatus = 0) { 113 global $USER; 114 $ref = unserialize($reference); 115 $detailsprefix = $this->get_name(); 116 if (isset($ref->userid) && $ref->userid != $USER->id && isset($ref->username)) { 117 $detailsprefix .= ' ('.$ref->username.')'; 118 } 119 $details = $detailsprefix; 120 if (isset($ref->path)) { 121 $details .= ': '. $ref->path; 122 } 123 if (isset($ref->path) && !$filestatus) { 124 // Indicate this is from dropbox with path. 125 return $details; 126 } else { 127 if (isset($ref->url)) { 128 $details = $detailsprefix. ': '. $ref->url; 129 } 130 return get_string('lostsource', 'repository', $details); 131 } 132 } 133 134 /** 135 * Cache file from external repository by reference. 136 * {@link repository::get_file_reference()} 137 * {@link repository::get_file()} 138 * Invoked at MOODLE/repository/repository_ajax.php. 139 * 140 * @inheritDocs 141 */ 142 public function cache_file_by_reference($reference, $storedfile) { 143 try { 144 $this->import_external_file_contents($storedfile, $this->max_cache_bytes()); 145 } catch (Exception $e) { 146 // Cache failure should not cause a fatal error. This is only a nice-to-have feature. 147 } 148 } 149 150 /** 151 * Return the source information. 152 * 153 * The result of the function is stored in files.source field. It may be analysed 154 * when the source file is lost or repository may use it to display human-readable 155 * location of reference original. 156 * 157 * This method is called when file is picked for the first time only. When file 158 * (either copy or a reference) is already in moodle and it is being picked 159 * again to another file area (also as a copy or as a reference), the value of 160 * files.source is copied. 161 * 162 * @inheritDocs 163 */ 164 public function get_file_source_info($source) { 165 global $USER; 166 return 'Dropbox ('.fullname($USER).'): ' . $source; 167 } 168 169 /** 170 * Prepare file reference information. 171 * 172 * @inheritDocs 173 */ 174 public function get_file_reference($source) { 175 global $USER; 176 $reference = new stdClass; 177 $reference->userid = $USER->id; 178 $reference->username = fullname($USER); 179 $reference->path = $source; 180 181 // Determine whether we are downloading the file, or should use a file reference. 182 $usefilereference = optional_param('usefilereference', false, PARAM_BOOL); 183 if ($usefilereference) { 184 if ($data = $this->dropbox->get_file_share_info($source)) { 185 $reference = (object) array_merge((array) $data, (array) $reference); 186 } 187 } 188 189 return serialize($reference); 190 } 191 192 /** 193 * Return file URL for external link. 194 * 195 * @inheritDocs 196 */ 197 public function get_link($reference) { 198 $unpacked = $this->unpack_reference($reference); 199 200 return $this->get_file_download_link($unpacked->url); 201 } 202 203 /** 204 * Downloads a file from external repository and saves it in temp dir. 205 * 206 * @inheritDocs 207 */ 208 public function get_file($reference, $saveas = '') { 209 $unpacked = $this->unpack_reference($reference); 210 211 // This is a shared link, and hopefully it is still active. 212 $downloadlink = $this->get_file_download_link($unpacked->url); 213 214 $saveas = $this->prepare_file($saveas); 215 file_put_contents($saveas, fopen($downloadlink, 'r')); 216 217 return ['path' => $saveas]; 218 } 219 220 /** 221 * Dropbox plugin supports all kinds of files. 222 * 223 * @inheritDocs 224 */ 225 public function supported_filetypes() { 226 return '*'; 227 } 228 229 /** 230 * User cannot use the external link to dropbox. 231 * 232 * @inheritDocs 233 */ 234 public function supported_returntypes() { 235 return FILE_INTERNAL | FILE_REFERENCE | FILE_EXTERNAL; 236 } 237 238 /** 239 * Get dropbox files. 240 * 241 * @inheritDocs 242 */ 243 public function get_listing($path = '', $page = '1') { 244 if (empty($path) || $path == '/') { 245 $path = ''; 246 } else { 247 $path = file_correct_filepath($path); 248 } 249 250 $list = [ 251 'list' => [], 252 'manage' => 'https://www.dropbox.com/home', 253 'logouturl' => 'https://www.dropbox.com/logout', 254 'message' => get_string('logoutdesc', 'repository_dropbox'), 255 'dynload' => true, 256 'path' => $this->process_breadcrumbs($path), 257 ]; 258 259 // Note - we deliberately do not catch the coding exceptions here. 260 try { 261 $result = $this->dropbox->get_listing($path); 262 } catch (\repository_dropbox\authentication_exception $e) { 263 // The token has expired. 264 return $this->print_login(); 265 } catch (\repository_dropbox\dropbox_exception $e) { 266 // There was some other form of non-coding failure. 267 // This could be a rate limit, or it could be a server-side error. 268 // Just return early instead. 269 return $list; 270 } 271 272 if (!is_object($result) || empty($result)) { 273 return $list; 274 } 275 276 if (empty($result->entries) or !is_array($result->entries)) { 277 return $list; 278 } 279 280 $list['list'] = $this->process_entries($result->entries); 281 return $list; 282 } 283 284 /** 285 * Get dropbox files in the specified path. 286 * 287 * @param string $query The search query 288 * @param int $page The page number 289 * @return array 290 */ 291 public function search($query, $page = 0) { 292 $list = [ 293 'list' => [], 294 'manage' => 'https://www.dropbox.com/home', 295 'logouturl' => 'https://www.dropbox.com/logout', 296 'message' => get_string('logoutdesc', 'repository_dropbox'), 297 'dynload' => true, 298 ]; 299 300 // Note - we deliberately do not catch the coding exceptions here. 301 try { 302 $result = $this->dropbox->search($query); 303 } catch (\repository_dropbox\authentication_exception $e) { 304 // The token has expired. 305 return $this->print_login(); 306 } catch (\repository_dropbox\dropbox_exception $e) { 307 // There was some other form of non-coding failure. 308 // This could be a rate limit, or it could be a server-side error. 309 // Just return early instead. 310 return $list; 311 } 312 313 if (!is_object($result) || empty($result)) { 314 return $list; 315 } 316 317 if (empty($result->matches) or !is_array($result->matches)) { 318 return $list; 319 } 320 321 $list['list'] = $this->process_entries($result->matches); 322 return $list; 323 } 324 325 /** 326 * Displays a thumbnail for current user's dropbox file. 327 * 328 * @inheritDocs 329 */ 330 public function send_thumbnail($source) { 331 $content = $this->dropbox->get_thumbnail($source); 332 333 // Set 30 days lifetime for the image. 334 // If the image is changed in dropbox it will have different revision number and URL will be different. 335 // It is completely safe to cache the thumbnail in the browser for a long time. 336 send_file($content, basename($source), 30 * DAYSECS, 0, true); 337 } 338 339 /** 340 * Fixes references in DB that contains user credentials. 341 * 342 * @param string $packed Content of DB field files_reference.reference 343 * @return string New serialized reference 344 */ 345 protected function fix_old_style_reference($packed) { 346 $ref = unserialize($packed); 347 $ref = $this->dropbox->get_file_share_info($ref->path); 348 if (!$ref || empty($ref->url)) { 349 // Some error occurred, do not fix reference for now. 350 return $packed; 351 } 352 353 $newreference = serialize($ref); 354 if ($newreference !== $packed) { 355 // We need to update references in the database. 356 global $DB; 357 $params = array( 358 'newreference' => $newreference, 359 'newhash' => sha1($newreference), 360 'reference' => $packed, 361 'hash' => sha1($packed), 362 'repoid' => $this->id, 363 ); 364 $refid = $DB->get_field_sql('SELECT id FROM {files_reference} 365 WHERE reference = :reference AND referencehash = :hash 366 AND repositoryid = :repoid', $params); 367 if (!$refid) { 368 return $newreference; 369 } 370 371 $existingrefid = $DB->get_field_sql('SELECT id FROM {files_reference} 372 WHERE reference = :newreference AND referencehash = :newhash 373 AND repositoryid = :repoid', $params); 374 if ($existingrefid) { 375 // The same reference already exists, we unlink all files from it, 376 // link them to the current reference and remove the old one. 377 $DB->execute('UPDATE {files} SET referencefileid = :refid 378 WHERE referencefileid = :existingrefid', 379 array('refid' => $refid, 'existingrefid' => $existingrefid)); 380 $DB->delete_records('files_reference', array('id' => $existingrefid)); 381 } 382 383 // Update the reference. 384 $params['refid'] = $refid; 385 $DB->execute('UPDATE {files_reference} 386 SET reference = :newreference, referencehash = :newhash 387 WHERE id = :refid', $params); 388 } 389 return $newreference; 390 } 391 392 /** 393 * Unpack the supplied serialized reference, fixing it if required. 394 * 395 * @param string $packed The packed reference 396 * @return object The unpacked reference 397 */ 398 protected function unpack_reference($packed) { 399 $reference = unserialize($packed); 400 if (empty($reference->url)) { 401 // The reference is missing some information. Attempt to update it. 402 return unserialize($this->fix_old_style_reference($packed)); 403 } 404 405 return $reference; 406 } 407 408 /** 409 * Converts a URL received from dropbox API function 'shares' into URL that 410 * can be used to download/access file directly 411 * 412 * @param string $sharedurl 413 * @return string 414 */ 415 protected function get_file_download_link($sharedurl) { 416 $url = new \moodle_url($sharedurl); 417 $url->param('dl', 1); 418 419 return $url->out(false); 420 } 421 422 /** 423 * Logout from dropbox. 424 * 425 * @inheritDocs 426 */ 427 public function logout() { 428 $this->dropbox->logout(); 429 430 return $this->print_login(); 431 } 432 433 /** 434 * Check if the dropbox is logged in via the oauth process. 435 * 436 * @inheritDocs 437 */ 438 public function check_login() { 439 return $this->dropbox->is_logged_in(); 440 } 441 442 /** 443 * Generate dropbox login url. 444 * 445 * @inheritDocs 446 */ 447 public function print_login() { 448 $url = $this->dropbox->get_login_url(); 449 if ($this->options['ajax']) { 450 $ret = array(); 451 $btn = new \stdClass(); 452 $btn->type = 'popup'; 453 $btn->url = $url->out(false); 454 $ret['login'] = array($btn); 455 return $ret; 456 } else { 457 echo html_writer::link($url, get_string('login', 'repository'), array('target' => '_blank')); 458 } 459 } 460 461 /** 462 * Request access token. 463 * 464 * @inheritDocs 465 */ 466 public function callback() { 467 $this->dropbox->callback(); 468 } 469 470 /** 471 * Caches all references to Dropbox files in moodle filepool. 472 * 473 * Invoked by {@link repository_dropbox_cron()}. Only files smaller than 474 * {@link repository_dropbox::max_cache_bytes()} and only files which 475 * synchronisation timeout have not expired are cached. 476 * 477 * @inheritDocs 478 */ 479 public function cron() { 480 $fs = get_file_storage(); 481 $files = $fs->get_external_files($this->id); 482 $fetchedreferences = []; 483 foreach ($files as $file) { 484 if (isset($fetchedreferences[$file->get_referencefileid()])) { 485 continue; 486 } 487 try { 488 // This call will cache all files that are smaller than max_cache_bytes() 489 // and synchronise file size of all others. 490 $this->import_external_file_contents($file, $this->max_cache_bytes()); 491 $fetchedreferences[$file->get_referencefileid()] = true; 492 } catch (moodle_exception $e) { 493 // If an exception is thrown, just continue. This is only a pre-fetch to help speed up general use. 494 } 495 } 496 } 497 498 /** 499 * Add Plugin settings input to Moodle form. 500 * 501 * @inheritDocs 502 */ 503 public static function type_config_form($mform, $classname = 'repository') { 504 parent::type_config_form($mform); 505 $options = []; 506 $issuers = \core\oauth2\api::get_all_issuers(); 507 foreach ($issuers as $issuer) { 508 $options[$issuer->get('id')] = s($issuer->get('name')); 509 } 510 $strrequired = get_string('required'); 511 $mform->addElement('select', 'dropbox_issuerid', get_string('issuer', 'repository_dropbox'), $options); 512 $mform->addHelpButton('dropbox_issuerid', 'issuer', 'repository_dropbox'); 513 $mform->addRule('dropbox_issuerid', $strrequired, 'required', null, 'client'); 514 $mform->addElement('text', 'dropbox_cachelimit', get_string('cachelimit', 'repository_dropbox'), array('size' => '40')); 515 $mform->addRule('dropbox_cachelimit', null, 'numeric', null, 'client'); 516 $mform->setType('dropbox_cachelimit', PARAM_INT); 517 $mform->addElement('static', 'dropbox_cachelimit_info', '', get_string('cachelimit_info', 'repository_dropbox')); 518 519 } 520 521 /** 522 * Set options. 523 * 524 * @param array $options 525 * @return mixed 526 */ 527 public function set_option($options = []) { 528 if (!empty($options['dropbox_issuerid'])) { 529 set_config('dropbox_issuerid', trim($options['dropbox_issuerid']), 'dropbox'); 530 unset($options['dropbox_issuerid']); 531 } 532 if (!empty($options['dropbox_cachelimit'])) { 533 $this->cachelimit = (int) trim($options['dropbox_cachelimit']); 534 set_config('dropbox_cachelimit', $this->cachelimit, 'dropbox'); 535 unset($options['dropbox_cachelimit']); 536 } 537 538 return parent::set_option($options); 539 } 540 541 /** 542 * Get dropbox options 543 * @param string $config 544 * @return mixed 545 */ 546 public function get_option($config = '') { 547 if ($config === 'dropbox_issuerid') { 548 return trim(get_config('dropbox', 'dropbox_issuerid')); 549 } else if ($config === 'dropbox_cachelimit') { 550 return $this->max_cache_bytes(); 551 } else { 552 $options = parent::get_option(); 553 $options['dropbox_issuerid'] = trim(get_config('dropbox', 'dropbox_issuerid')); 554 $options['dropbox_cachelimit'] = $this->max_cache_bytes(); 555 } 556 557 return $options; 558 } 559 560 /** 561 * Return the OAuth 2 Redirect URI. 562 * 563 * @return moodle_url 564 */ 565 public static function get_oauth2callbackurl() { 566 global $CFG; 567 568 return new moodle_url('/admin/oauth2callback.php'); 569 } 570 571 /** 572 * Option names of dropbox plugin. 573 * 574 * @inheritDocs 575 */ 576 public static function get_type_option_names() { 577 return [ 578 'dropbox_issuerid', 579 'pluginname', 580 'dropbox_cachelimit', 581 ]; 582 } 583 584 /** 585 * Performs synchronisation of an external file if the previous one has expired. 586 * 587 * This function must be implemented for external repositories supporting 588 * FILE_REFERENCE, it is called for existing aliases when their filesize, 589 * contenthash or timemodified are requested. It is not called for internal 590 * repositories (see {@link repository::has_moodle_files()}), references to 591 * internal files are updated immediately when source is modified. 592 * 593 * Referenced files may optionally keep their content in Moodle filepool (for 594 * thumbnail generation or to be able to serve cached copy). In this 595 * case both contenthash and filesize need to be synchronized. Otherwise repositories 596 * should use contenthash of empty file and correct filesize in bytes. 597 * 598 * Note that this function may be run for EACH file that needs to be synchronised at the 599 * moment. If anything is being downloaded or requested from external sources there 600 * should be a small timeout. The synchronisation is performed to update the size of 601 * the file and/or to update image and re-generated image preview. There is nothing 602 * fatal if syncronisation fails but it is fatal if syncronisation takes too long 603 * and hangs the script generating a page. 604 * 605 * Note: If you wish to call $file->get_filesize(), $file->get_contenthash() or 606 * $file->get_timemodified() make sure that recursion does not happen. 607 * 608 * Called from {@link stored_file::sync_external_file()} 609 * 610 * @inheritDocs 611 */ 612 public function sync_reference(stored_file $file) { 613 global $CFG; 614 615 if ($file->get_referencelastsync() + DAYSECS > time()) { 616 // Only synchronise once per day. 617 return false; 618 } 619 620 $reference = $this->unpack_reference($file->get_reference()); 621 if (!isset($reference->url)) { 622 // The URL to sync with is missing. 623 return false; 624 } 625 626 $c = new curl; 627 $url = $this->get_file_download_link($reference->url); 628 if (file_extension_in_typegroup($reference->path, 'web_image')) { 629 $saveas = $this->prepare_file(''); 630 try { 631 $result = $c->download_one($url, [], [ 632 'filepath' => $saveas, 633 'timeout' => $CFG->repositorysyncimagetimeout, 634 'followlocation' => true, 635 ]); 636 $info = $c->get_info(); 637 if ($result === true && isset($info['http_code']) && $info['http_code'] == 200) { 638 $file->set_synchronised_content_from_file($saveas); 639 return true; 640 } 641 } catch (Exception $e) { 642 // IF the download_one fails, we will attempt to download 643 // again with get() anyway. 644 } 645 } 646 647 $c->get($url, null, array('timeout' => $CFG->repositorysyncimagetimeout, 'followlocation' => true, 'nobody' => true)); 648 $info = $c->get_info(); 649 if (isset($info['http_code']) && $info['http_code'] == 200 && 650 array_key_exists('download_content_length', $info) && 651 $info['download_content_length'] >= 0) { 652 $filesize = (int)$info['download_content_length']; 653 $file->set_synchronized(null, $filesize); 654 return true; 655 } 656 $file->set_missingsource(); 657 return true; 658 } 659 660 /** 661 * Process a standard entries list. 662 * 663 * @param array $entries The list of entries returned from the API 664 * @return array The manipulated entries for display in the file picker 665 */ 666 protected function process_entries(array $entries) { 667 global $OUTPUT; 668 669 $dirslist = []; 670 $fileslist = []; 671 foreach ($entries as $entry) { 672 $entrydata = $entry; 673 if (isset($entrydata->metadata)) { 674 // If this is metadata, fetch the metadata content. 675 // We only use the consistent parts of the file, folder, and metadata. 676 $entrydata = $entrydata->metadata; 677 } 678 679 // Due to a change in the api, the actual content is in a nested metadata tree. 680 if ($entrydata->{".tag"} == "metadata" && isset($entrydata->metadata)) { 681 $entrydata = $entrydata->metadata; 682 } 683 684 if ($entrydata->{".tag"} === "folder") { 685 $dirslist[] = [ 686 'title' => $entrydata->name, 687 // Use the display path here rather than lower. 688 // Dropbox is case insensitive but this leads to more accurate breadcrumbs. 689 'path' => file_correct_filepath($entrydata->path_display), 690 'thumbnail' => $OUTPUT->image_url(file_folder_icon())->out(false), 691 'thumbnail_height' => 64, 692 'thumbnail_width' => 64, 693 'children' => array(), 694 ]; 695 } else if ($entrydata->{".tag"} === "file") { 696 $fileslist[] = [ 697 'title' => $entrydata->name, 698 // Use the path_lower here to make life easier elsewhere. 699 'source' => $entrydata->path_lower, 700 'size' => $entrydata->size, 701 'date' => strtotime($entrydata->client_modified), 702 'thumbnail' => $OUTPUT->image_url(file_extension_icon($entrydata->path_lower))->out(false), 703 'realthumbnail' => $this->get_thumbnail_url($entrydata), 704 'thumbnail_height' => 64, 705 'thumbnail_width' => 64, 706 ]; 707 } 708 } 709 710 $fileslist = array_filter($fileslist, array($this, 'filter')); 711 712 return array_merge($dirslist, array_values($fileslist)); 713 } 714 715 /** 716 * Process the breadcrumbs for a listing. 717 * 718 * @param string $path The path to create breadcrumbs for 719 * @return array 720 */ 721 protected function process_breadcrumbs($path) { 722 // Process breadcrumb trail. 723 // Note: Dropbox is case insensitive. 724 // Without performing an additional API call, it isn't possible to get the path_display. 725 // As a result, the path here is the path_lower. 726 $breadcrumbs = [ 727 [ 728 'path' => '/', 729 'name' => get_string('dropbox', 'repository_dropbox'), 730 ], 731 ]; 732 733 $path = rtrim($path, '/'); 734 $directories = explode('/', $path); 735 $pathtodate = ''; 736 foreach ($directories as $directory) { 737 if ($directory === '') { 738 continue; 739 } 740 $pathtodate .= '/' . $directory; 741 $breadcrumbs[] = [ 742 'path' => $pathtodate, 743 'name' => $directory, 744 ]; 745 } 746 747 return $breadcrumbs; 748 } 749 750 /** 751 * Grab the thumbnail URL for the specified entry. 752 * 753 * @param object $entry The file entry as retrieved from the API 754 * @return moodle_url 755 */ 756 protected function get_thumbnail_url($entry) { 757 if ($this->dropbox->supports_thumbnail($entry)) { 758 $thumburl = new moodle_url('/repository/dropbox/thumbnail.php', [ 759 // The id field in dropbox is unique - no need to specify a revision. 760 'source' => $entry->id, 761 'path' => $entry->path_lower, 762 763 'repo_id' => $this->id, 764 'ctx_id' => $this->context->id, 765 ]); 766 return $thumburl->out(false); 767 } 768 769 return ''; 770 } 771 772 /** 773 * Returns the maximum size of the Dropbox files to cache in moodle. 774 * 775 * Note that {@link repository_dropbox::sync_reference()} will try to cache images even 776 * when they are bigger in order to generate thumbnails. However there is 777 * a small timeout for downloading images for synchronisation and it will 778 * probably fail if the image is too big. 779 * 780 * @return int 781 */ 782 public function max_cache_bytes() { 783 if ($this->cachelimit === null) { 784 $this->cachelimit = (int) get_config('dropbox', 'dropbox_cachelimit'); 785 } 786 return $this->cachelimit; 787 } 788 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body