Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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
}