"MDL-13766, add extra yui images for yui treeview, this will display folder-style...
[moodle.git] / repository / lib.php
CommitLineData
12c79bfd 1<?php
2 // $Id$
1cf56396 3
4///////////////////////////////////////////////////////////////////////////
5// //
6// NOTICE OF COPYRIGHT //
7// //
8// Moodle - Modular Object-Oriented Dynamic Learning Environment //
9// http://moodle.com //
10// //
11// Copyright (C) 2008 onwards Moodle Pty Ltd http://moodle.com //
12// //
13// This program is free software; you can redistribute it and/or modify //
14// it under the terms of the GNU General Public License as published by //
15// the Free Software Foundation; either version 2 of the License, or //
16// (at your option) any later version. //
17// //
18// This program is distributed in the hope that it will be useful, //
19// but WITHOUT ANY WARRANTY; without even the implied warranty of //
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
21// GNU General Public License for more details: //
22// //
23// http://www.gnu.org/copyleft/gpl.html //
24// //
25///////////////////////////////////////////////////////////////////////////
26
aca64b79 27/**
28 * About repository/lib.php:
29 * two main classes:
30 * 1. repository_type => a repository plugin, You can activate a plugin into
31 * Moodle. You also can set some general settings/options for this type of repository.
32 * All instances would share the same options (for example: a API key for the connection
33 * to the repository)
34 * 2. repository => an instance of a plugin. You can also call it an access or
35 * an account. An instance has specific settings (for example: a public url) and a specific
36 * name. That's this name which is displayed in the file picker.
37 */
38
39
40
19add4c0 41require_once(dirname(dirname(__FILE__)) . '/config.php');
c19f8e7d 42require_once($CFG->libdir . '/filelib.php');
43require_once($CFG->libdir . '/formslib.php');
9bdd9eee 44// File picker javascript code
1cf56396 45
a6600395 46/**
47 * A repository_type is a repository plug-in. It can be Box.net, Flick-r, ...
48 * A repository type can be edited, sorted and hidden. It is mandatory for an
49 * administrator to create a repository type in order to be able to create
50 * some instances of this type.
51 *
52 * Coding note:
53 * - a repository_type object is mapped to the "repository" database table
54 * - "typename" attibut maps the "type" database field. It is unique.
55 * - general "options" for a repository type are saved in the config_plugin table
eb239694 56 * - when you delete a repository, all instances are deleted, and general
57 * options are also deleted from database
a6600395 58 * - When you create a type for a plugin that can't have multiple instances, a
59 * instance is automatically created.
60 */
61class repository_type {
62
63
64 /**
65 * Type name (no whitespace) - A type name is unique
66 * Note: for a user-friendly type name see get_readablename()
67 * @var String
68 */
69 private $_typename;
70
71
72 /**
73 * Options of this type
74 * They are general options that any instance of this type would share
75 * e.g. API key
76 * These options are saved in config_plugin table
77 * @var array
78 */
7a3b93c1 79 private $_options;
a6600395 80
81
82 /**
83 * Is the repository type visible or hidden
84 * If false (hidden): no instances can be created, edited, deleted, showned , used...
85 * @var boolean
86 */
7a3b93c1 87 private $_visible;
a6600395 88
89
90 /**
91 * 0 => not ordered, 1 => first position, 2 => second position...
92 * A not order type would appear in first position (should never happened)
93 * @var integer
94 */
95 private $_sortorder;
96
f48fb4d6 97 /**
98 * Return if the instance is visible in a context
99 * TODO: check if the context visibility has been overwritten by the plugin creator
100 * (need to create special functions to be overvwritten in repository class)
101 * @param objet $contextlevel - context level
102 * @return boolean
103 */
104 public function get_contextvisibility($contextlevel) {
dbc01944 105
f48fb4d6 106 if ($contextlevel == CONTEXT_COURSE) {
107 return $this->_options['enablecourseinstances'];
108 }
109
110 if ($contextlevel == CONTEXT_USER) {
111 return $this->_options['enableuserinstances'];
112 }
113
114 //the context is SITE
115 return true;
116 }
dbc01944 117
f48fb4d6 118
119
a6600395 120 /**
121 * repository_type constructor
2b8beee3 122 * @global object $CFG
a6600395 123 * @param integer $typename
124 * @param array $typeoptions
125 * @param boolean $visible
126 * @param integer $sortorder (don't really need set, it will be during create() call)
127 */
7a3b93c1 128 public function __construct($typename = '', $typeoptions = array(), $visible = false, $sortorder = 0) {
a6600395 129 global $CFG;
130
131 //set type attributs
132 $this->_typename = $typename;
133 $this->_visible = $visible;
134 $this->_sortorder = $sortorder;
46dd6bb0 135
a6600395 136 //set options attribut
137 $this->_options = array();
dbc01944 138 $options = repository::static_function($typename,'get_type_option_names');
a6600395 139 //check that the type can be setup
06e65e1e 140 if (!empty($options)) {
a6600395 141 //set the type options
142 foreach ($options as $config) {
7a3b93c1 143 if (array_key_exists($config,$typeoptions)) {
144 $this->_options[$config] = $typeoptions[$config];
a6600395 145 }
146 }
147 }
f48fb4d6 148
149 //retrieve visibility from option
150 if (array_key_exists('enablecourseinstances',$typeoptions)) {
151 $this->_options['enablecourseinstances'] = $typeoptions['enablecourseinstances'];
9f7c761a 152 } else {
153 $this->_options['enablecourseinstances'] = 0;
f48fb4d6 154 }
dbc01944 155
f48fb4d6 156 if (array_key_exists('enableuserinstances',$typeoptions)) {
157 $this->_options['enableuserinstances'] = $typeoptions['enableuserinstances'];
9f7c761a 158 } else {
159 $this->_options['enableuserinstances'] = 0;
f48fb4d6 160 }
dbc01944 161
a6600395 162 }
163
164 /**
165 * Get the type name (no whitespace)
166 * For a human readable name, use get_readablename()
167 * @return String the type name
168 */
7a3b93c1 169 public function get_typename() {
a6600395 170 return $this->_typename;
171 }
172
173 /**
174 * Return a human readable and user-friendly type name
175 * @return string user-friendly type name
176 */
7a3b93c1 177 public function get_readablename() {
a6600395 178 return get_string('repositoryname','repository_'.$this->_typename);
179 }
180
181 /**
182 * Return general options
183 * @return array the general options
184 */
7a3b93c1 185 public function get_options() {
a6600395 186 return $this->_options;
187 }
188
189 /**
190 * Return visibility
191 * @return boolean
192 */
7a3b93c1 193 public function get_visible() {
a6600395 194 return $this->_visible;
195 }
196
197 /**
198 * Return order / position of display in the file picker
199 * @return integer
200 */
7a3b93c1 201 public function get_sortorder() {
a6600395 202 return $this->_sortorder;
203 }
204
205 /**
206 * Create a repository type (the type name must not already exist)
a75c78d3 207 * @param boolean throw exception?
208 * @return mixed return int if create successfully, return false if
209 * any errors
a6600395 210 * @global object $DB
211 */
a75c78d3 212 public function create($silent = false) {
a6600395 213 global $DB;
214
215 //check that $type has been set
216 $timmedtype = trim($this->_typename);
217 if (empty($timmedtype)) {
7a3b93c1 218 throw new repository_exception('emptytype', 'repository');
a6600395 219 }
220
221 //set sortorder as the last position in the list
7a3b93c1 222 if (!isset($this->_sortorder) || $this->_sortorder == 0 ) {
a6600395 223 $sql = "SELECT MAX(sortorder) FROM {repository}";
224 $this->_sortorder = 1 + $DB->get_field_sql($sql);
225 }
226
227 //only create a new type if it doesn't already exist
228 $existingtype = $DB->get_record('repository', array('type'=>$this->_typename));
7a3b93c1 229 if (!$existingtype) {
230 //create the type
231 $newtype = new stdclass;
232 $newtype->type = $this->_typename;
233 $newtype->visible = $this->_visible;
234 $newtype->sortorder = $this->_sortorder;
a75c78d3 235 $plugin_id = $DB->insert_record('repository', $newtype);
7a3b93c1 236 //save the options in DB
237 $this->update_options();
238
edb50637 239 //if the plugin type has no multiple instance (e.g. has no instance option name) so it wont
7a3b93c1 240 //be possible for the administrator to create a instance
241 //in this case we need to create an instance
dbc01944 242 $instanceoptionnames = repository::static_function($this->_typename, 'get_instance_option_names');
edb50637 243 if (empty($instanceoptionnames)) {
7a3b93c1 244 $instanceoptions = array();
245 $instanceoptions['name'] = $this->_typename;
dbc01944 246 repository::static_function($this->_typename, 'create', $this->_typename, 0, get_system_context(), $instanceoptions);
7a3b93c1 247 }
60c366e8 248 //run plugin_init function
249 if (!repository::static_function($this->_typename, 'plugin_init')) {
250 if (!$silent) {
251 throw new repository_exception('cannotinitplugin', 'repository');
252 }
253 }
254
a75c78d3 255 if(!empty($plugin_id)) {
256 // return plugin_id if create successfully
257 return $plugin_id;
258 } else {
259 return false;
260 }
948c2860 261
7a3b93c1 262 } else {
a75c78d3 263 if (!$silent) {
264 throw new repository_exception('existingrepository', 'repository');
265 }
266 // If plugin existed, return false, tell caller no new plugins were created.
267 return false;
a6600395 268 }
269 }
270
271
272 /**
273 * Update plugin options into the config_plugin table
274 * @param array $options
275 * @return boolean
276 */
7a3b93c1 277 public function update_options($options = null) {
278 if (!empty($options)) {
a6600395 279 $this->_options = $options;
280 }
281
282 foreach ($this->_options as $name => $value) {
283 set_config($name,$value,$this->_typename);
284 }
285
286 return true;
287 }
288
289 /**
290 * Update visible database field with the value given as parameter
291 * or with the visible value of this object
292 * This function is private.
293 * For public access, have a look to switch_and_update_visibility()
294 * @global object $DB
295 * @param boolean $visible
296 * @return boolean
297 */
7a3b93c1 298 private function update_visible($visible = null) {
a6600395 299 global $DB;
300
7a3b93c1 301 if (!empty($visible)) {
a6600395 302 $this->_visible = $visible;
303 }
7a3b93c1 304 else if (!isset($this->_visible)) {
a6600395 305 throw new repository_exception('updateemptyvisible', 'repository');
306 }
307
308 return $DB->set_field('repository', 'visible', $this->_visible, array('type'=>$this->_typename));
309 }
310
311 /**
312 * Update database sortorder field with the value given as parameter
313 * or with the sortorder value of this object
314 * This function is private.
315 * For public access, have a look to move_order()
316 * @global object $DB
317 * @param integer $sortorder
318 * @return boolean
319 */
7a3b93c1 320 private function update_sortorder($sortorder = null) {
a6600395 321 global $DB;
322
7a3b93c1 323 if (!empty($sortorder) && $sortorder!=0) {
a6600395 324 $this->_sortorder = $sortorder;
325 }
326 //if sortorder is not set, we set it as the ;ast position in the list
7a3b93c1 327 else if (!isset($this->_sortorder) || $this->_sortorder == 0 ) {
a6600395 328 $sql = "SELECT MAX(sortorder) FROM {repository}";
329 $this->_sortorder = 1 + $DB->get_field_sql($sql);
330 }
331
332 return $DB->set_field('repository', 'sortorder', $this->_sortorder, array('type'=>$this->_typename));
333 }
334
335 /**
336 * Change order of the type with its adjacent upper or downer type
337 * (database fields are updated)
338 * Algorithm details:
339 * 1. retrieve all types in an array. This array is sorted by sortorder,
340 * and the array keys start from 0 to X (incremented by 1)
341 * 2. switch sortorder values of this type and its adjacent type
342 * @global object $DB
343 * @param string $move "up" or "down"
344 */
345 public function move_order($move) {
346 global $DB;
a6600395 347
dbc01944 348 $types = repository::get_types(); // retrieve all types
7a3b93c1 349
350 /// retrieve this type into the returned array
351 $i = 0;
352 while (!isset($indice) && $i<count($types)) {
353 if ($types[$i]->get_typename() == $this->_typename) {
a6600395 354 $indice = $i;
355 }
356 $i++;
357 }
358
7a3b93c1 359 /// retrieve adjacent indice
a6600395 360 switch ($move) {
361 case "up":
362 $adjacentindice = $indice - 1;
7a3b93c1 363 break;
a6600395 364 case "down":
365 $adjacentindice = $indice + 1;
7a3b93c1 366 break;
a6600395 367 default:
7a3b93c1 368 throw new repository_exception('movenotdefined', 'repository');
a6600395 369 }
370
371 //switch sortorder of this type and the adjacent type
372 //TODO: we could reset sortorder for all types. This is not as good in performance term, but
373 //that prevent from wrong behaviour on a screwed database. As performance are not important in this particular case
374 //it worth to change the algo.
7a3b93c1 375 if ($adjacentindice>=0 && !empty($types[$adjacentindice])) {
a6600395 376 $DB->set_field('repository', 'sortorder', $this->_sortorder, array('type'=>$types[$adjacentindice]->get_typename()));
377 $this->update_sortorder($types[$adjacentindice]->get_sortorder());
378 }
379 }
380
381 /**
382 * 1. Switch the visibility OFF if it's ON, and ON if it's OFF.
383 * 2. Update the type
2b8beee3 384 * @return boolean
a6600395 385 */
7a3b93c1 386 public function switch_and_update_visibility() {
a6600395 387 $this->_visible = !$this->_visible;
388 return $this->update_visible();
389 }
390
391
392 /**
eb239694 393 * Delete a repository_type (general options are removed from config_plugin
394 * table, and all instances are deleted)
a6600395 395 * @global object $DB
396 * @return boolean
397 */
7a3b93c1 398 public function delete() {
a6600395 399 global $DB;
46dd6bb0 400
401 //delete all instances of this type
dbc01944 402 $instances = repository::get_instances(array(),null,false,$this->_typename);
7a3b93c1 403 foreach ($instances as $instance) {
46dd6bb0 404 $instance->delete();
405 }
406
eb239694 407 //delete all general options
7a3b93c1 408 foreach ($this->_options as $name => $value) {
eb239694 409 set_config($name, null, $this->_typename);
410 }
411
a6600395 412 return $DB->delete_records('repository', array('type' => $this->_typename));
413 }
414}
415
a6600395 416/**
8d419e59 417 * This is the base class of the repository class
418 *
419 * To use repository plugin, see:
420 * http://docs.moodle.org/en/Development:Repository_How_to_Create_Plugin
421 *
422 * class repository is an abstract class, some functions must be implemented in subclass.
423 *
424 * See an example: repository/boxnet/repository.class.php
425 *
426 * A few notes:
427 * // for ajax file picker, this will print a json string to tell file picker
428 * // how to build a login form
429 * $repo->print_login();
430 * // for ajax file picker, this will return a files list.
431 * $repo->get_listing();
432 * // this function will be used for non-javascript version.
433 * $repo->print_listing();
434 * // print a search box
435 * $repo->print_search();
436 *
437 * @package repository
438 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
a6600395 439 */
fca079c5 440abstract class repository {
efe018b4 441 // $disabled can be set to true to disable a plugin by force
442 // example: self::$disabled = true
443 public $disabled = false;
4a65c39a 444 public $id;
445 public $context;
446 public $options;
948c2860 447 public $readonly;
1cf56396 448
dbc01944 449 /**
450 * Return a type for a given type name.
451 * @global object $DB
452 * @param string $typename the type name
453 * @return integer
454 */
455 public static function get_type_by_typename($typename) {
456 global $DB;
457
458 if (!$record = $DB->get_record('repository',array('type' => $typename))) {
459 return false;
460 }
461
462 return new repository_type($typename, (array)get_config($typename), $record->visible, $record->sortorder);
463 }
464
465 /**
466 * Return a type for a given type id.
467 * @global object $DB
468 * @param string $typename the type name
469 * @return integer
470 */
471 public static function get_type_by_id($id) {
472 global $DB;
473
474 if (!$record = $DB->get_record('repository',array('id' => $id))) {
475 return false;
476 }
477
478 return new repository_type($record->type, (array)get_config($record->type), $record->visible, $record->sortorder);
479 }
480
481 /**
482 * Return all repository types ordered by sortorder
483 * first type in returnedarray[0], second type in returnedarray[1], ...
484 * @global object $DB
485 * @param boolean $visible can return types by visiblity, return all types if null
486 * @return array Repository types
487 */
488 public static function get_types($visible=null) {
489 global $DB;
490
491 $types = array();
492 $params = null;
493 if (!empty($visible)) {
494 $params = array('visible' => $visible);
495 }
496 if ($records = $DB->get_records('repository',$params,'sortorder')) {
497 foreach($records as $type) {
498 $types[] = new repository_type($type->type, (array)get_config($type->type), $type->visible, $type->sortorder);
499 }
500 }
501
502 return $types;
503 }
504
505 /**
506 * Check context
507 * @param int $ctx_id
508 * @return boolean
509 */
510 public static function check_context($ctx_id) {
511 global $USER;
512
513 $context = get_context_instance_by_id($ctx_id);
514 $level = $context->contextlevel;
515
516 if ($level == CONTEXT_COURSE) {
517 if (!has_capability('moodle/course:view', $context)) {
518 return false;
519 } else {
520 return true;
521 }
522 } else if ($level == CONTEXT_USER) {
523 $c = get_context_instance(CONTEXT_USER, $USER->id);
524 if ($c->id == $ctx_id) {
525 return true;
526 } else {
527 return false;
528 }
529 } else if ($level == CONTEXT_SYSTEM) {
530 // it is always ok in system level
531 return true;
532 }
533 return false;
534 }
535
536 /**
537 * Return all types that you a user can create/edit and which are also visible
538 * Note: Mostly used in order to know if at least one editable type can be set
539 * @param object $context the context for which we want the editable types
540 * @return array types
541 */
542 public static function get_editable_types($context = null) {
543
544 if (empty($context)) {
545 $context = get_system_context();
546 }
547
548 $types= repository::get_types(true);
549 $editabletypes = array();
550 foreach ($types as $type) {
551 $instanceoptionnames = repository::static_function($type->get_typename(), 'get_instance_option_names');
552 if (!empty($instanceoptionnames)) {
553 if ($type->get_contextvisibility($context->contextlevel)) {
554 $editabletypes[]=$type;
555 }
556 }
557 }
558 return $editabletypes;
559 }
560
561 /**
562 * Return repository instances
563 * @global object $DB
564 * @global object $CFG
565 * @global object $USER
566 * @param object $contexts contexts for which the instances are set
567 * @param integer $userid
568 * @param boolean $onlyvisible if visible == true, return visible instances only,
569 * otherwise, return all instances
570 * @param string $type a type name to retrieve
571 * @return array repository instances
572 */
c167aa26 573 public static function get_instances($contexts=array(), $userid = null, $onlyvisible = true, $type=null, $accepted_types = '*', $returnvalue = '*') {
dbc01944 574 global $DB, $CFG, $USER;
575
576 $params = array();
577 $sql = 'SELECT i.*, r.type AS repositorytype, r.sortorder, r.visible FROM {repository} r, {repository_instances} i WHERE ';
578 $sql .= 'i.typeid = r.id ';
579
580 if (!empty($userid) && is_numeric($userid)) {
581 $sql .= ' AND (i.userid = 0 or i.userid = ?)';
582 $params[] = $userid;
583 }
584
585 foreach ($contexts as $context) {
586 if (empty($firstcontext)) {
587 $firstcontext = true;
588 $sql .= ' AND ((i.contextid = ?)';
589 } else {
590 $sql .= ' OR (i.contextid = ?)';
591 }
592 $params[] = $context->id;
593 }
594
595 if (!empty($firstcontext)) {
596 $sql .=')';
597 }
598
599 if ($onlyvisible == true) {
600 $sql .= ' AND (r.visible = 1)';
601 }
602
603 if (isset($type)) {
604 $sql .= ' AND (r.type = ?)';
605 $params[] = $type;
606 }
607 $sql .= ' order by r.sortorder, i.name';
608
609 if (!$repos = $DB->get_records_sql($sql, $params)) {
610 $repos = array();
611 }
612
613 $ret = array();
c167aa26 614 $ft = new file_type_to_ext();
dbc01944 615 foreach ($repos as $repo) {
616 require_once($CFG->dirroot . '/repository/'. $repo->repositorytype.'/repository.class.php');
617 $options['visible'] = $repo->visible;
618 $options['name'] = $repo->name;
619 $options['type'] = $repo->repositorytype;
620 $options['typeid'] = $repo->typeid;
c167aa26 621 // tell instance what file types will be accepted by file picker
622 $options['accepted_types'] = $ft->get_file_ext($accepted_types);
dbc01944 623 $classname = 'repository_' . $repo->repositorytype;//
014c1ca0 624 $is_supported = true;
dbc01944 625
626 $repository = new $classname($repo->id, $repo->contextid, $options, $repo->readonly);
271bd2e0 627 if (empty($repository->super_called)) {
628 debugging('parent::__construct must be called by '.$repo->repositorytype.' plugin.');
629 } else {
630 if ($accepted_types !== '*' and $repository->supported_filetypes() !== '*') {
631 $accepted_types = $ft->get_file_ext($accepted_types);
632 $supported_filetypes = $ft->get_file_ext($repository->supported_filetypes());
633 $is_supported = false;
634 foreach ($supported_filetypes as $type) {
635 if (in_array($type, $accepted_types)) {
636 $is_supported = true;
637 }
014c1ca0 638 }
639 }
271bd2e0 640 if ($returnvalue !== '*' and $repository->supported_return_value() !== '*') {
641 $tmp = $repository->supported_return_value();
642 if ($tmp != $returnvalue) {
643 $is_supported = false;
644 }
014c1ca0 645 }
271bd2e0 646 if (!$onlyvisible || ($repository->is_visible() && !$repository->disabled)) {
647 // super_called will make sure the parent construct function is called
648 // by repository construct function
649 if ($is_supported) {
650 $ret[] = $repository;
651 }
014c1ca0 652 }
dbc01944 653 }
654 }
655 return $ret;
656 }
657
658 /**
659 * Get single repository instance
660 * @global object $DB
661 * @global object $CFG
662 * @param integer $id repository id
663 * @return object repository instance
664 */
665 public static function get_instance($id) {
666 global $DB, $CFG;
667 $sql = 'SELECT i.*, r.type AS repositorytype, r.visible FROM {repository} r, {repository_instances} i WHERE ';
668 $sql .= 'i.typeid = r.id AND ';
669 $sql .= 'i.id = '.$id;
670
671 if(!$instance = $DB->get_record_sql($sql)) {
672 return false;
673 }
674 require_once($CFG->dirroot . '/repository/'. $instance->repositorytype
675 . '/repository.class.php');
676 $classname = 'repository_' . $instance->repositorytype;
677 $options['typeid'] = $instance->typeid;
678 $options['type'] = $instance->repositorytype;
679 $options['name'] = $instance->name;
271bd2e0 680 $obj = new $classname($instance->id, $instance->contextid, $options, $instance->readonly);
681 if (empty($obj->super_called)) {
682 debugging('parent::__construct must be called by '.$classname.' plugin.');
683 }
684 return $obj;
dbc01944 685 }
686
687 /**
688 * call a static function
2b8beee3 689 * @global object $CFG
690 * @param string $plugin
691 * @param string $function
dbc01944 692 * @param type $nocallablereturnvalue default value if function not found
693 * it's mostly used when you don't want to display an error but
694 * return a boolean
2b8beee3 695 * @return mixed
dbc01944 696 */
697 public static function static_function($plugin, $function) {
698 global $CFG;
699
700 //check that the plugin exists
701 $typedirectory = $CFG->dirroot . '/repository/'. $plugin . '/repository.class.php';
702 if (!file_exists($typedirectory)) {
f1cfe56e 703 //throw new repository_exception('invalidplugin', 'repository');
704 return false;
dbc01944 705 }
706
707 $pname = null;
708 if (is_object($plugin) || is_array($plugin)) {
709 $plugin = (object)$plugin;
710 $pname = $plugin->name;
711 } else {
712 $pname = $plugin;
713 }
714
715 $args = func_get_args();
716 if (count($args) <= 2) {
717 $args = array();
718 }
719 else {
720 array_shift($args);
721 array_shift($args);
722 }
723
724 require_once($typedirectory);
725 return call_user_func_array(array('repository_' . $plugin, $function), $args);
726 }
727
728 /**
729 * Move file from download folder to file pool using FILE API
730 * @global object $DB
731 * @global object $CFG
732 * @global object $USER
733 * @param string $path file path in download folder
734 * @param string $name file name
735 * @param integer $itemid item id to identify a file in filepool
736 * @param string $filearea file area
737 * @return array information of file in file pool
738 */
739 public static function move_to_filepool($path, $name, $itemid, $filearea = 'user_draft') {
740 global $DB, $CFG, $USER;
741 $context = get_context_instance(CONTEXT_USER, $USER->id);
742 $now = time();
743 $entry = new object();
744 $entry->filearea = $filearea;
745 $entry->contextid = $context->id;
746 $entry->filename = $name;
b423b4af 747 //$entry->filepath = '/'.uniqid().'/';
748 $entry->filepath = '/';
dbc01944 749 $entry->timecreated = $now;
750 $entry->timemodified = $now;
b423b4af 751 $entry->userid = $USER->id;
752 $entry->mimetype = mimeinfo('type', $path);
dbc01944 753 if(is_numeric($itemid)) {
754 $entry->itemid = $itemid;
755 } else {
756 $entry->itemid = 0;
757 }
dbc01944 758 $fs = get_file_storage();
759 $browser = get_file_browser();
b423b4af 760 if ($existingfile = $fs->get_file($context->id, $filearea, $itemid, $path, $name)) {
761 $existingfile->delete();
762 }
dbc01944 763 if ($file = $fs->create_file_from_pathname($entry, $path)) {
88b126a5 764 if (empty($CFG->repository_no_delete)) {
765 $delete = unlink($path);
766 unset($CFG->repository_no_delete);
767 }
dbc01944 768 $ret = $browser->get_file_info($context, $file->get_filearea(), $file->get_itemid(), $file->get_filepath(), $file->get_filename());
769 if(!empty($ret)) {
b423b4af 770 return array('url'=>$ret->get_url(),
771 'id'=>$file->get_itemid(),
772 'file'=>$file->get_filename(),
0ef98843 773 'icon'=>$CFG->pixpath.'/f/'.mimeinfo('icon32', $path)
b423b4af 774 );
dbc01944 775 } else {
776 return null;
777 }
778 } else {
779 return null;
780 }
781 }
782
dbc01944 783 /**
784 * Save file to local filesystem pool
785 * @param string $elname name of element
786 * @param string $filearea
787 * @param string $filepath
788 * @param string $filename - use specified filename, if not specified name of uploaded file used
789 * @param bool $override override file if exists
790 * @return mixed stored_file object or false if error; may throw exception if duplicate found
791 */
b423b4af 792 public static function store_to_filepool($elname, $filearea='user_draft', $filepath='/', $itemid='', $filename = '', $override = false) {
dbc01944 793 global $USER;
794 if (!isset($_FILES[$elname])) {
795 return false;
796 }
797
798 if (!$filename) {
799 $filename = $_FILES[$elname]['name'];
800 }
801 $context = get_context_instance(CONTEXT_USER, $USER->id);
b423b4af 802 if (empty($itemid)) {
803 $itemid = (int)substr(hexdec(uniqid()), 0, 9)+rand(1,100);
804 }
dbc01944 805 $fs = get_file_storage();
806 $browser = get_file_browser();
807
808 if ($file = $fs->get_file($context->id, $filearea, $itemid, $filepath, $filename)) {
809 if ($override) {
810 $file->delete();
811 } else {
812 return false;
813 }
814 }
815
816 $file_record = new object();
817 $file_record->contextid = $context->id;
818 $file_record->filearea = $filearea;
819 $file_record->itemid = $itemid;
820 $file_record->filepath = $filepath;
821 $file_record->filename = $filename;
822 $file_record->userid = $USER->id;
823
824 $file = $fs->create_file_from_pathname($file_record, $_FILES[$elname]['tmp_name']);
825 $info = $browser->get_file_info($context, $file->get_filearea(), $file->get_itemid(), $file->get_filepath(), $file->get_filename());
826 $ret = array('url'=>$info->get_url(),'id'=>$itemid, 'file'=>$file->get_filename());
827 return $ret;
828 }
829
830 /**
b81ebefd 831 * Return the user files tree in a format to be returned by the function get_listing
2b8beee3 832 * @global object $CFG
833 * @param string $search
834 * @return array
dbc01944 835 */
836 public static function get_user_file_tree($search = ""){
837 global $CFG;
fc3ec2ca 838 $ret = array();
839 $ret['nologin'] = true;
840 $ret['manage'] = $CFG->wwwroot .'/files/index.php'; // temporary
841 $browser = get_file_browser();
842 $itemid = null;
843 $filename = null;
844 $filearea = null;
845 $path = '/';
846 $ret['dynload'] = false;
847
848 if ($fileinfo = $browser->get_file_info(get_system_context(), $filearea, $itemid, $path, $filename)) {
849
850 $ret['path'] = array();
851 $params = $fileinfo->get_params();
852 $filearea = $params['filearea'];
853 $ret['path'][] = repository::encode_path($filearea, $path, $fileinfo->get_visible_name());
854 if ($fileinfo->is_directory()) {
855 $level = $fileinfo->get_parent();
856 while ($level) {
857 $params = $level->get_params();
858 $ret['path'][] = repository::encode_path($params['filearea'], $params['filepath'], $level->get_visible_name());
859 $level = $level->get_parent();
dbc01944 860 }
dbc01944 861 }
fc3ec2ca 862 $filecount = repository::build_tree($fileinfo, $search, $ret['dynload'], $ret['list']);
863 $ret['path'] = array_reverse($ret['path']);
864 }
dbc01944 865
fc3ec2ca 866 if (empty($ret['list'])) {
867 //exit(mnet_server_fault(9016, get_string('emptyfilelist', 'repository_local')));
868 throw new Exception('emptyfilelist');
869 } else {
870 return $ret;
871 }
dbc01944 872
873 }
874
875 /**
876 *
2b8beee3 877 * @param string $filearea
878 * @param string $path
879 * @param string $visiblename
880 * @return array
dbc01944 881 */
882 public static function encode_path($filearea, $path, $visiblename) {
883 return array('path'=>serialize(array($filearea, $path)), 'name'=>$visiblename);
884 }
885
886 /**
887 * Builds a tree of files This function is
888 * then called recursively.
889 *
890 * @param $fileinfo an object returned by file_browser::get_file_info()
891 * @param $search searched string
892 * @param $dynamicmode bool no recursive call is done when in dynamic mode
893 * @param $list - the array containing the files under the passed $fileinfo
894 * @returns int the number of files found
895 *
896 * todo: take $search into account, and respect a threshold for dynamic loading
897 */
898 public static function build_tree($fileinfo, $search, $dynamicmode, &$list) {
899 global $CFG;
900
901 $filecount = 0;
902 $children = $fileinfo->get_children();
903
904 foreach ($children as $child) {
905 $filename = $child->get_visible_name();
906 $filesize = $child->get_filesize();
907 $filesize = $filesize ? display_size($filesize) : '';
908 $filedate = $child->get_timemodified();
909 $filedate = $filedate ? userdate($filedate) : '';
910 $filetype = $child->get_mimetype();
911
912 if ($child->is_directory()) {
913 $path = array();
914 $level = $child->get_parent();
915 while ($level) {
916 $params = $level->get_params();
917 $path[] = repository::encode_path($params['filearea'], $params['filepath'], $level->get_visible_name());
918 $level = $level->get_parent();
919 }
920
921 $tmp = array(
922 'title' => $child->get_visible_name(),
923 'size' => 0,
924 'date' => $filedate,
925 'path' => array_reverse($path),
fc3ec2ca 926 'thumbnail' => $CFG->pixpath .'/f/folder-32.png'
dbc01944 927 );
928
929 //if ($dynamicmode && $child->is_writable()) {
930 // $tmp['children'] = array();
931 //} else {
932 // if folder name matches search, we send back all files contained.
933 $_search = $search;
934 if ($search && stristr($tmp['title'], $search) !== false) {
935 $_search = false;
936 }
937 $tmp['children'] = array();
938 $_filecount = repository::build_tree($child, $_search, $dynamicmode, $tmp['children']);
939 if ($search && $_filecount) {
940 $tmp['expanded'] = 1;
941 }
942
943 //}
944
945 //Uncomment this following line if you wanna display all directory ()even empty
fc3ec2ca 946 if (!$search || $_filecount || (stristr($tmp['title'], $search) !== false)) {
dbc01944 947 $filecount += $_filecount;
948 $list[] = $tmp;
949 }
950
951 } else { // not a directory
952 // skip the file, if we're in search mode and it's not a match
953 if ($search && (stristr($filename, $search) === false)) {
954 continue;
955 }
956 $params = $child->get_params();
957 $source = serialize(array($params['contextid'], $params['filearea'], $params['itemid'], $params['filepath'], $params['filename']));
958 $list[] = array(
959 'title' => $filename,
960 'size' => $filesize,
961 'date' => $filedate,
962 //'source' => $child->get_url(),
963 'source' => base64_encode($source),
0ef98843 964 'thumbnail' => $CFG->pixpath .'/f/'. mimeinfo('icon32', $filename)
dbc01944 965 );
966 $filecount++;
967 }
968 }
969
970 return $filecount;
971 }
972
973
974 /**
975 * Display a repository instance list (with edit/delete/create links)
976 * @global object $CFG
977 * @global object $USER
978 * @param object $context the context for which we display the instance
979 * @param string $typename if set, we display only one type of instance
980 */
981 public static function display_instances_list($context, $typename = null) {
982 global $CFG, $USER;
983
984 $output = print_box_start('generalbox','',true);
985 //if the context is SYSTEM, so we call it from administration page
986 $admin = ($context->id == SYSCONTEXTID) ? true : false;
987 if ($admin) {
d1aa1e48 988 $baseurl = "$CFG->httpswwwroot/$CFG->admin/repositoryinstance.php?sesskey=" . sesskey();
dbc01944 989 $output .= "<div ><h2 style='text-align: center'>" . get_string('siteinstances', 'repository') . " ";
990 $output .= "</h2></div>";
991 } else {
992 $baseurl = $CFG->httpswwwroot . '/repository/manage_instances.php?contextid=' . $context->id . '&amp;sesskey=' . sesskey();
993 }
994
995 $namestr = get_string('name');
996 $pluginstr = get_string('plugin', 'repository');
997 $settingsstr = get_string('settings');
998 $deletestr = get_string('delete');
999 $updown = get_string('updown', 'repository');
1000 //retrieve list of instances. In administration context we want to display all
1001 //instances of a type, even if this type is not visible. In course/user context we
1002 //want to display only visible instances, but for every type types. The repository_get_instances()
1003 //third parameter displays only visible type.
1004 $instances = repository::get_instances(array($context),null,!$admin,$typename);
1005 $instancesnumber = count($instances);
1006 $alreadyplugins = array();
1007
1008 $table = new StdClass;
1009 $table->head = array($namestr, $pluginstr, $deletestr, $settingsstr);
1010 $table->align = array('left', 'left', 'center','center');
1011 $table->data = array();
1012
1013 $updowncount = 1;
1014
1015 foreach ($instances as $i) {
1016 $settings = '';
1017 $delete = '';
1018 $settings .= '<a href="' . $baseurl . '&amp;type='.$typename.'&amp;edit=' . $i->id . '">' . $settingsstr . '</a>' . "\n";
1019 if (!$i->readonly) {
1020 $delete .= '<a href="' . $baseurl . '&amp;type='.$typename.'&amp;delete=' . $i->id . '">' . $deletestr . '</a>' . "\n";
1021 }
1022
1023 $type = repository::get_type_by_id($i->typeid);
1024 $table->data[] = array($i->name, $type->get_readablename(), $delete, $settings);
1025
1026 //display a grey row if the type is defined as not visible
1027 if (isset($type) && !$type->get_visible()) {
1028 $table->rowclass[] = 'dimmed_text';
1029 } else {
1030 $table->rowclass[] = '';
1031 }
1032
1033 if (!in_array($i->name, $alreadyplugins)) {
1034 $alreadyplugins[] = $i->name;
1035 }
1036 }
1037 $output .= print_table($table, true);
1038 $instancehtml = '<div>';
1039 $addable = 0;
1040
1041 //if no type is set, we can create all type of instance
1042 if (!$typename) {
1043 $instancehtml .= '<h3>';
1044 $instancehtml .= get_string('createrepository', 'repository');
1045 $instancehtml .= '</h3><ul>';
1046 $types = repository::get_editable_types($context);
1047 foreach ($types as $type) {
1048 if (!empty($type) && $type->get_visible()) {
1049 $instanceoptionnames = repository::static_function($type->get_typename(), 'get_instance_option_names');
1050 if (!empty($instanceoptionnames)) {
8af334cd 1051 $instancehtml .= '<li><a href="'.$baseurl.'&amp;new='.$type->get_typename().'">'.get_string('createxxinstance', 'repository', get_string('repositoryname', 'repository_'.$type->get_typename()))
1052 .'</a></li>';
dbc01944 1053 $addable++;
1054 }
1055 }
1056 }
1057 $instancehtml .= '</ul>';
1058
1059 } else {
1060 $instanceoptionnames = repository::static_function($typename, 'get_instance_option_names');
1061 if (!empty($instanceoptionnames)) { //create a unique type of instance
1062 $addable = 1;
1063 $instancehtml .= "<form action='".$baseurl."&amp;new=".$typename."' method='post'>
1064 <p style='text-align:center'><input type='submit' value='".get_string('createinstance', 'repository')."'/></p>
1065 </form>";
1066 }
1067 }
1068
1069 if ($addable) {
1070 $instancehtml .= '</div>';
1071 $output .= $instancehtml;
1072 }
1073
1074 $output .= print_box_end(true);
1075
1076 //print the list + creation links
1077 print($output);
1078 }
1cf56396 1079 /**
3f24ea1e 1080 * 1. Initialize context and options
1081 * 2. Accept necessary parameters
1082 *
8dcd5deb 1083 * @param integer $repositoryid
1084 * @param integer $contextid
1085 * @param array $options
1cf56396 1086 */
948c2860 1087 public function __construct($repositoryid, $contextid = SITEID, $options = array(), $readonly = 0) {
4a65c39a 1088 $this->id = $repositoryid;
1089 $this->context = get_context_instance_by_id($contextid);
948c2860 1090 $this->readonly = $readonly;
4a65c39a 1091 $this->options = array();
fca079c5 1092 if (is_array($options)) {
4a65c39a 1093 $options = array_merge($this->get_option(), $options);
1094 } else {
1095 $options = $this->get_option();
1096 }
b1339e98 1097 $this->options = array();
4a65c39a 1098 foreach ($options as $n => $v) {
1099 $this->options[$n] = $v;
82669dc4 1100 }
d31af46a 1101 $this->name = $this->get_name();
271bd2e0 1102 $this->super_called = true;
1cf56396 1103 }
1104
8dcd5deb 1105 /**
3f24ea1e 1106 * set options for repository instance
1107 *
8dcd5deb 1108 * @param string $name
3f24ea1e 1109 * @param mixed $value
8dcd5deb 1110 */
fca079c5 1111 public function __set($name, $value) {
82669dc4 1112 $this->options[$name] = $value;
1113 }
1cf56396 1114
8dcd5deb 1115 /**
3f24ea1e 1116 * get options for repository instance
1117 *
1118 * @param string $name
1119 * @return mixed
8dcd5deb 1120 */
fca079c5 1121 public function __get($name) {
7a3b93c1 1122 if (array_key_exists($name, $this->options)) {
82669dc4 1123 return $this->options[$name];
1124 }
1125 trigger_error('Undefined property: '.$name, E_USER_NOTICE);
1126 return null;
1127 }
1cf56396 1128
8dcd5deb 1129 /**
3f24ea1e 1130 * test option name
1131 *
1132 * @param string name
8dcd5deb 1133 */
fca079c5 1134 public function __isset($name) {
82669dc4 1135 return isset($this->options[$name]);
1cf56396 1136 }
1137
8dcd5deb 1138 /**
3f24ea1e 1139 * Return the name of the repository class
2b8beee3 1140 * @return string
8dcd5deb 1141 */
fca079c5 1142 public function __toString() {
82669dc4 1143 return 'Repository class: '.__CLASS__;
1144 }
4a65c39a 1145
c425472d 1146 /**
a53d4f45 1147 * Decide where to save the file, can be
1148 * reused by sub class
1149 * @param string filename
c425472d 1150 */
a53d4f45 1151 public function prepare_file($file) {
c425472d 1152 global $CFG;
c9260130 1153 if (!file_exists($CFG->dataroot.'/temp/download')) {
1154 mkdir($CFG->dataroot.'/temp/download/', 0777, true);
1e28c767 1155 }
7a3b93c1 1156 if (is_dir($CFG->dataroot.'/temp/download')) {
c9260130 1157 $dir = $CFG->dataroot.'/temp/download/';
1e28c767 1158 }
7a3b93c1 1159 if (empty($file)) {
84df43de 1160 $file = uniqid('repo').'_'.time().'.tmp';
1161 }
7a3b93c1 1162 if (file_exists($dir.$file)) {
84df43de 1163 $file = uniqid('m').$file;
c425472d 1164 }
a53d4f45 1165 return $dir.$file;
1166 }
1167
1168 /**
1169 * Download a file, this function can be overridden by
1170 * subclass.
1171 *
1172 * @global object $CFG
1173 * @param string $url the url of file
1174 * @param string $file save location
1175 * @return string the location of the file
1176 * @see curl package
1177 */
1178 public function get_file($url, $file = '') {
1179 global $CFG;
1180
1181 $path = $this->prepare_file($file);
1182 $fp = fopen($path, 'w');
84df43de 1183 $c = new curl;
1184 $c->download(array(
7a3b93c1 1185 array('url'=>$url, 'file'=>$fp)
1186 ));
a53d4f45 1187 return $path;
82669dc4 1188 }
1cf56396 1189
f48fb4d6 1190 /**
1191 * Return is the instance is visible
1192 * (is the type visible ? is the context enable ?)
1193 * @return boolean
1194 */
dbc01944 1195 public function is_visible() {
1196 $type = repository::get_type_by_id($this->typeid);
1197 $instanceoptions = repository::static_function($type->get_typename(), 'get_instance_option_names');
f48fb4d6 1198
1199 if ($type->get_visible()) {
1200 //if the instance is unique so it's visible, otherwise check if the instance has a enabled context
1201 if (empty($instanceoptions) || $type->get_contextvisibility($this->context->contextlevel)) {
1202 return true;
1203 }
1204 }
1205
1206 return false;
1207 }
1208
eb239694 1209 /**
66dc47bc 1210 * Return the name of this instance, can be overridden.
2b8beee3 1211 * @global object $DB
1212 * @return string
eb239694 1213 */
7a3b93c1 1214 public function get_name() {
d31af46a 1215 global $DB;
1216 // We always verify instance id from database,
1217 // so we always know repository name before init
1218 // a repository, so we don't enquery repository
1219 // name from database again here.
1220 if (isset($this->options['name'])) {
1221 return $this->options['name'];
1222 } else {
1223 if ( $repo = $DB->get_record('repository_instances', array('id'=>$this->id)) ) {
1224 return $repo->name;
1225 } else {
1226 return '';
1227 }
1228 }
1229 }
aa754fe3 1230
b318bb6d 1231 /**
1232 * what kind of files will be in this repository?
1233 * @return array return '*' means this repository support any files, otherwise
1234 * return mimetypes of files, it can be an array
1235 */
014c1ca0 1236 public function supported_filetypes() {
b318bb6d 1237 // return array('text/plain', 'image/gif');
1238 return '*';
1239 }
1240
1241 /**
1242 * does it return a file url or a item_id
1243 * @return string
1244 */
1245 public function supported_return_value() {
1246 // return 'link';
1247 // return 'ref_id';
014c1ca0 1248 return 'ref_id';
b318bb6d 1249 }
1250
82669dc4 1251 /**
3f24ea1e 1252 * Provide repository instance information for Ajax
8dcd5deb 1253 * @global object $CFG
4a65c39a 1254 * @return object
82669dc4 1255 */
b1339e98 1256 final public function ajax_info() {
4a65c39a 1257 global $CFG;
fc11edbf 1258 $ft = new file_type_to_ext;
4a65c39a 1259 $repo = new stdclass;
27051e43 1260 $repo->id = $this->id;
d31af46a 1261 $repo->name = $this->get_name();
4a65c39a 1262 $repo->type = $this->options['type'];
6fe8b022 1263 $repo->icon = $CFG->httpswwwroot.'/repository/'.$repo->type.'/icon.png';
c167aa26 1264 $repo->supported_types = $ft->get_file_ext($this->supported_filetypes());
1265 $repo->accepted_types = $this->accepted_types;
4a65c39a 1266 return $repo;
1267 }
1cf56396 1268
b1339e98 1269 /**
1270 * Create an instance for this plug-in
8dcd5deb 1271 * @global object $CFG
1272 * @global object $DB
1273 * @param string $type the type of the repository
1274 * @param integer $userid the user id
1275 * @param object $context the context
1276 * @param array $params the options for this instance
2b8beee3 1277 * @return mixed
b1339e98 1278 */
948c2860 1279 final public static function create($type, $userid, $context, $params, $readonly=0) {
b1339e98 1280 global $CFG, $DB;
1281 $params = (array)$params;
1282 require_once($CFG->dirroot . '/repository/'. $type . '/repository.class.php');
1283 $classname = 'repository_' . $type;
3023078f 1284 if ($repo = $DB->get_record('repository', array('type'=>$type))) {
1285 $record = new stdclass;
1286 $record->name = $params['name'];
1287 $record->typeid = $repo->id;
1288 $record->timecreated = time();
1289 $record->timemodified = time();
1290 $record->contextid = $context->id;
948c2860 1291 $record->readonly = $readonly;
3023078f 1292 $record->userid = $userid;
1293 $id = $DB->insert_record('repository_instances', $record);
0a6221f9 1294 $options = array();
edb50637 1295 $configs = call_user_func($classname . '::get_instance_option_names');
1e08b5cf 1296 if (!empty($configs)) {
1297 foreach ($configs as $config) {
1298 $options[$config] = $params[$config];
1299 }
3023078f 1300 }
3a01a46a 1301
3023078f 1302 if (!empty($id)) {
1303 unset($options['name']);
dbc01944 1304 $instance = repository::get_instance($id);
3023078f 1305 $instance->set_option($options);
1306 return $id;
1307 } else {
1308 return null;
b1339e98 1309 }
b1339e98 1310 } else {
1311 return null;
1312 }
1313 }
8dcd5deb 1314
82669dc4 1315 /**
4a65c39a 1316 * delete a repository instance
8dcd5deb 1317 * @global object $DB
2b8beee3 1318 * @return mixed
82669dc4 1319 */
7a3b93c1 1320 final public function delete() {
4a65c39a 1321 global $DB;
122defc5 1322 $DB->delete_records('repository_instances', array('id'=>$this->id));
2b0b3626 1323 $DB->delete_records('repository_instance_config', array('instanceid'=>$this->id));
4a65c39a 1324 return true;
1325 }
8dcd5deb 1326
4a65c39a 1327 /**
1328 * Hide/Show a repository
8dcd5deb 1329 * @global object $DB
1330 * @param string $hide
2b8beee3 1331 * @return boolean
4a65c39a 1332 */
7a3b93c1 1333 final public function hide($hide = 'toggle') {
4a65c39a 1334 global $DB;
1335 if ($entry = $DB->get_record('repository', array('id'=>$this->id))) {
1336 if ($hide === 'toggle' ) {
1337 if (!empty($entry->visible)) {
1338 $entry->visible = 0;
1339 } else {
1340 $entry->visible = 1;
1341 }
1342 } else {
1343 if (!empty($hide)) {
1344 $entry->visible = 0;
1345 } else {
1346 $entry->visible = 1;
1347 }
1348 }
1349 return $DB->update_record('repository', $entry);
1350 }
1351 return false;
1352 }
1cf56396 1353
1354 /**
82669dc4 1355 * Cache login details for repositories
8dcd5deb 1356 * @global object $DB
82669dc4 1357 * @param string $username
1358 * @param string $password
8dcd5deb 1359 * @param integer $userid The id of specific user
1360 * @return integer Id of the record
1cf56396 1361 */
b6558c3b 1362 public function store_login($username = '', $password = '', $userid = 1) {
fca079c5 1363 global $DB;
1364
1365 $repository = new stdclass;
4a65c39a 1366 if (!empty($this->id)) {
1367 $repository->id = $this->id;
19add4c0 1368 } else {
1369 $repository->userid = $userid;
1370 $repository->repositorytype = $this->type;
b6558c3b 1371 $repository->contextid = $this->context->id;
19add4c0 1372 }
fca079c5 1373 if ($entry = $DB->get_record('repository', $repository)) {
1374 $repository->id = $entry->id;
1375 $repository->username = $username;
1376 $repository->password = $password;
1377 return $DB->update_record('repository', $repository);
1378 } else {
1379 $repository->username = $username;
1380 $repository->password = $password;
1381 return $DB->insert_record('repository', $repository);
1382 }
1cf56396 1383 }
1384
1cf56396 1385 /**
4a65c39a 1386 * Save settings for repository instance
8dcd5deb 1387 * $repo->set_option(array('api_key'=>'f2188bde132', 'name'=>'dongsheng'));
1388 * @global object $DB
1389 * @param array $options settings
4a65c39a 1390 * @return int Id of the record
1cf56396 1391 */
7a3b93c1 1392 public function set_option($options = array()) {
4a65c39a 1393 global $DB;
7a3b93c1 1394
122defc5 1395 if (!empty($options['name'])) {
1396 $r = new object();
1397 $r->id = $this->id;
1398 $r->name = $options['name'];
1399 $DB->update_record('repository_instances', $r);
1400 unset($options['name']);
1401 }
e53a97d1 1402 $result = true;
27051e43 1403 foreach ($options as $name=>$value) {
1404 if ($id = $DB->get_field('repository_instance_config', 'id', array('name'=>$name, 'instanceid'=>$this->id))) {
1405 if ($value===null) {
e53a97d1 1406 $result = $result && $DB->delete_records('repository_instance_config', array('name'=>$name, 'instanceid'=>$this->id));
27051e43 1407 } else {
e53a97d1 1408 $result = $result && $DB->set_field('repository_instance_config', 'value', $value, array('id'=>$id));
27051e43 1409 }
1410 } else {
1411 if ($value===null) {
1412 return true;
1413 }
1414 $config = new object();
1415 $config->instanceid = $this->id;
1416 $config->name = $name;
1417 $config->value = $value;
e53a97d1 1418 $result = $result && $DB->insert_record('repository_instance_config', $config);
27051e43 1419 }
4a65c39a 1420 }
e53a97d1 1421 return $result;
1cf56396 1422 }
1cf56396 1423
4a65c39a 1424 /**
1425 * Get settings for repository instance
8dcd5deb 1426 * @global object $DB
2b8beee3 1427 * @param string $config
4a65c39a 1428 * @return array Settings
1429 */
7a3b93c1 1430 public function get_option($config = '') {
4a65c39a 1431 global $DB;
27051e43 1432 $entries = $DB->get_records('repository_instance_config', array('instanceid'=>$this->id));
1433 $ret = array();
1434 if (empty($entries)) {
1435 return $ret;
4a65c39a 1436 }
7a3b93c1 1437 foreach($entries as $entry) {
27051e43 1438 $ret[$entry->name] = $entry->value;
4a65c39a 1439 }
1440 if (!empty($config)) {
1441 return $ret[$config];
1442 } else {
1443 return $ret;
1444 }
1445 }
bf1fccf0 1446
c167aa26 1447 public function filter(&$value) {
1448 $pass = false;
1449 $accepted_types = optional_param('accepted_types', '', PARAM_RAW);
1450 $ft = new file_type_to_ext;
1451 $ext = $ft->get_file_ext($this->supported_filetypes());
b81ebefd 1452 if (isset($value['children'])) {
c167aa26 1453 $pass = true;
b81ebefd 1454 if (!empty($value['children'])) {
b81ebefd 1455 $value['children'] = array_filter($value['children'], array($this, 'filter'));
537d44e8 1456 }
c167aa26 1457 } else {
46ee50dc 1458 if ($accepted_types == '*' or empty($accepted_types)
1459 or (is_array($accepted_types) and in_array('*', $accepted_types))) {
c167aa26 1460 $pass = true;
1461 } elseif (is_array($accepted_types)) {
1462 foreach ($accepted_types as $type) {
1463 if (preg_match('#'.$type.'$#', $value['title'])) {
1464 $pass = true;
1465 }
1466 }
1467 }
1468 }
1469 return $pass;
1470 }
1471
4a65c39a 1472 /**
1473 * Given a path, and perhaps a search, get a list of files.
1474 *
2b8beee3 1475 * See details on http://docs.moodle.org/en/Development:Repository_plugins
f7639c37 1476 *
4a65c39a 1477 * @param string $parent The parent path, this parameter can
1478 * a folder name, or a identification of folder
4a65c39a 1479 * @return array the list of files, including meta infomation
1480 */
9d6aa286 1481 public function get_listing($path = '', $page = '') {
1482 }
1cf56396 1483
fbd508b4 1484 /**
353d5cf3 1485 * Search files in repository
1486 * When doing global search, $search_text will be used as
dbc01944 1487 * keyword.
353d5cf3 1488 *
fbd508b4 1489 * @return mixed, see get_listing()
1490 */
353d5cf3 1491 public function search($search_text) {
1492 $list = array();
1493 $list['list'] = array();
1494 return false;
fbd508b4 1495 }
1496
d68c527f 1497 /**
1498 * Logout from repository instance
1499 * By default, this function will return a login form
1500 *
1501 * @return string
1502 */
1503 public function logout(){
1504 return $this->print_login();
1505 }
1506
1507 /**
1508 * To check whether the user is logged in.
1509 *
1510 * @return boolean
1511 */
1512 public function check_login(){
1513 return true;
1514 }
1515
1cf56396 1516
4a65c39a 1517 /**
1518 * Show the login screen, if required
4a65c39a 1519 */
1d66f2b2 1520 public function print_login(){
1521 return $this->get_listing();
1522 }
1cf56396 1523
4a65c39a 1524 /**
1525 * Show the search screen, if required
4a65c39a 1526 * @return null
1527 */
2b9feb5f 1528 public function print_search() {
b763c2d9 1529 $str = '';
1530 $str .= '<input type="hidden" name="repo_id" value="'.$this->id.'" />';
1531 $str .= '<input type="hidden" name="ctx_id" value="'.$this->context->id.'" />';
1532 $str .= '<input type="hidden" name="seekey" value="'.sesskey().'" />';
1533 $str .= '<label>'.get_string('keyword', 'repository').': </label><br/><input name="s" value="" /><br/>';
1534 return $str;
2b9feb5f 1535 }
4a65c39a 1536
455860ce 1537 /**
1538 * is it possible to do glboal search?
1539 * @return boolean
1540 */
7a3b93c1 1541 public function global_search() {
455860ce 1542 return false;
1543 }
1544
8dcd5deb 1545 /**
a6600395 1546 * Defines operations that happen occasionally on cron
2b8beee3 1547 * @return boolean
8dcd5deb 1548 */
a6600395 1549 public function cron() {
1550 return true;
1551 }
1552
7892948d 1553 /**
83a018ed 1554 * function which is run when the type is created (moodle administrator add the plugin)
3e0794ed 1555 * @return boolean success or fail?
7892948d 1556 */
f1cfe56e 1557 public static function plugin_init() {
3e0794ed 1558 return true;
7892948d 1559 }
1560
a6600395 1561 /**
06e65e1e 1562 * Edit/Create Admin Settings Moodle form
1563 * @param object $ Moodle form (passed by reference)
a6600395 1564 */
daff8f50 1565 public function type_config_form(&$mform) {
4a65c39a 1566 }
dbc01944 1567
06e65e1e 1568 /**
1569 * Edit/Create Instance Settings Moodle form
1570 * @param object $ Moodle form (passed by reference)
a6600395 1571 */
06e65e1e 1572 public function instance_config_form(&$mform) {
a6600395 1573 }
4a65c39a 1574
a6600395 1575 /**
1576 * Return names of the general options
1577 * By default: no general option name
1578 * @return array
1579 */
1b79955a 1580 public static function get_type_option_names() {
a6600395 1581 return array();
1582 }
1583
1584 /**
1585 * Return names of the instance options
1586 * By default: no instance option name
1587 * @return array
1588 */
7a3b93c1 1589 public static function get_instance_option_names() {
a6600395 1590 return array();
8b65d45c 1591 }
119a4ae1 1592
ce5e846c 1593 /**
1594 * Override it if you need to implement need mnet function
1595 * @return array
1596 */
119a4ae1 1597 public static function mnet_publishes() {
1598 return array();
1599 }
1600
8b65d45c 1601}
837ebb78 1602
1603/**
4a65c39a 1604 * exception class for repository api
837ebb78 1605 */
4a65c39a 1606class repository_exception extends moodle_exception {
8b65d45c 1607}
4ed43890 1608
e3ca0f3a 1609
1610
8dcd5deb 1611/**
1612 * TODO: write comment
1613 */
a6600395 1614final class repository_instance_form extends moodleform {
4a65c39a 1615 protected $instance;
1616 protected $plugin;
1617
8dcd5deb 1618 /**
1619 * TODO: write comment
2b8beee3 1620 * @global object $CFG
8dcd5deb 1621 */
4a65c39a 1622 public function definition() {
1623 global $CFG;
1624 // type of plugin, string
1625 $this->plugin = $this->_customdata['plugin'];
27051e43 1626 $this->typeid = $this->_customdata['typeid'];
faaa613d 1627 $this->contextid = $this->_customdata['contextid'];
4a65c39a 1628 $this->instance = (isset($this->_customdata['instance'])
1629 && is_subclass_of($this->_customdata['instance'], 'repository'))
1630 ? $this->_customdata['instance'] : null;
1631
1632 $mform =& $this->_form;
1633 $strrequired = get_string('required');
1634
1635 $mform->addElement('hidden', 'edit', ($this->instance) ? $this->instance->id : 0);
1636 $mform->addElement('hidden', 'new', $this->plugin);
1637 $mform->addElement('hidden', 'plugin', $this->plugin);
27051e43 1638 $mform->addElement('hidden', 'typeid', $this->typeid);
faaa613d 1639 $mform->addElement('hidden', 'contextid', $this->contextid);
4a65c39a 1640
1641 $mform->addElement('text', 'name', get_string('name'), 'maxlength="100" size="30"');
1642 $mform->addRule('name', $strrequired, 'required', null, 'client');
1643
1e97f196 1644
f48fb4d6 1645 //add fields
1646 if (!$this->instance) {
dbc01944 1647 $result = repository::static_function($this->plugin, 'instance_config_form', $mform);
f48fb4d6 1648 }
1649 else {
1650 $data = array();
1651 $data['name'] = $this->instance->name;
1652 if (!$this->instance->readonly) {
1653 $result = $this->instance->instance_config_form($mform);
1654 // and set the data if we have some.
1e97f196 1655 foreach ($this->instance->get_instance_option_names() as $config) {
1656 if (!empty($this->instance->$config)) {
1657 $data[$config] = $this->instance->$config;
1658 } else {
1659 $data[$config] = '';
1660 }
27051e43 1661 }
4a65c39a 1662 }
f48fb4d6 1663 $this->set_data($data);
1e97f196 1664 }
1665
46dd6bb0 1666 $this->add_action_buttons(true, get_string('save','repository'));
4a65c39a 1667 }
1668
8dcd5deb 1669 /**
1670 * TODO: write comment
2b8beee3 1671 * @global object $DB
1672 * @param mixed $data
1673 * @return mixed
8dcd5deb 1674 */
4a65c39a 1675 public function validation($data) {
1676 global $DB;
1677
1678 $errors = array();
09bff8e8 1679 $sql = "SELECT count('x') FROM {repository_instances} i, {repository} r WHERE r.type=:plugin AND r.id=i.typeid AND i.name=:name";
1680 if ($DB->count_records_sql($sql, array('name' => $data['name'], 'plugin' => $data['plugin'])) > 1) {
4a65c39a 1681 $errors = array('name' => get_string('err_uniquename', 'repository'));
1682 }
1683
4a65c39a 1684 return $errors;
1685 }
1686}
a6600395 1687
1688
1689/**
1690 * Display a form with the general option fields of a type
1691 */
c295f9ff 1692final class repository_type_form extends moodleform {
a6600395 1693 protected $instance;
1694 protected $plugin;
1695
1696 /**
1697 * Definition of the moodleform
1698 * @global object $CFG
1699 */
1700 public function definition() {
1701 global $CFG;
1702 // type of plugin, string
1703 $this->plugin = $this->_customdata['plugin'];
1704 $this->instance = (isset($this->_customdata['instance'])
1705 && is_a($this->_customdata['instance'], 'repository_type'))
1706 ? $this->_customdata['instance'] : null;
1707
1708 $mform =& $this->_form;
1709 $strrequired = get_string('required');
4d5948f1 1710
a6600395 1711 $mform->addElement('hidden', 'edit', ($this->instance) ? $this->instance->get_typename() : 0);
1712 $mform->addElement('hidden', 'new', $this->plugin);
1713 $mform->addElement('hidden', 'plugin', $this->plugin);
8f943eba 1714
06e65e1e 1715 // let the plugin add its specific fields
1716 if (!$this->instance) {
88b126a5 1717 $result = repository::static_function($this->plugin, 'type_config_form', $mform);
1718 } else {
1719 $classname = 'repository_' . $this->instance->get_typename();
1720 $result = call_user_func(array($classname, 'type_config_form'), $mform);
a6600395 1721 }
1722
f48fb4d6 1723 //add "enable course/user instances" checkboxes if multiple instances are allowed
dbc01944 1724 $instanceoptionnames = repository::static_function($this->plugin, 'get_instance_option_names');
f48fb4d6 1725 if (!empty($instanceoptionnames)){
1726 $mform->addElement('checkbox', 'enablecourseinstances', get_string('enablecourseinstances', 'repository'));
1727 $mform->addElement('checkbox', 'enableuserinstances', get_string('enableuserinstances', 'repository'));
1728 }
1729
1730 // set the data if we have some.
a6600395 1731 if ($this->instance) {
1732 $data = array();
1b79955a 1733 $option_names = call_user_func(array($classname,'get_type_option_names'));
f48fb4d6 1734 if (!empty($instanceoptionnames)){
1735 $option_names[] = 'enablecourseinstances';
1736 $option_names[] = 'enableuserinstances';
1737 }
1738
a6600395 1739 $instanceoptions = $this->instance->get_options();
1740 foreach ($option_names as $config) {
1741 if (!empty($instanceoptions[$config])) {
1742 $data[$config] = $instanceoptions[$config];
1743 } else {
1744 $data[$config] = '';
1745 }
1746 }
1747 $this->set_data($data);
1748 }
dbc01944 1749
46dd6bb0 1750 $this->add_action_buttons(true, get_string('save','repository'));
a6600395 1751 }
a6600395 1752}
1753
a75c78d3 1754function repository_setup_default_plugins() {
1755 //if the plugin type has no multiple instance (e.g. has no instance option name)
1756 //repository_type::create will create an instance automatically
1757 $local_plugin = new repository_type('local', array(), true);
1758 $local_plugin_id = $local_plugin->create(true);
1759 $upload_plugin = new repository_type('upload', array(), true);
1760 $upload_plugin_id = $upload_plugin->create(true);
1761 if (is_int($local_plugin_id) or is_int($upload_plugin_id)) {
1762 print_box(get_string('setupdefaultplugins', 'repository'));
1763 }
8763ab76 1764 return true;
a75c78d3 1765}
e189ec00 1766/**
1767 * Return javascript to create file picker to browse repositories
1768 * @global object $CFG
1769 * @global object $USER
1770 * @param object $context the context
1771 * @param string $id unique id for every file picker
1772 * @param string $accepted_filetypes
1773 * @param string $returnvalue the return value of file picker
1774 * @return array
1775 */
1776function repository_get_client($context, $id = '', $accepted_filetypes = '*', $returnvalue = '*') {
1777 global $CFG, $USER;
1778
1779 $ft = new file_type_to_ext();
1780 $image_file_ext = json_encode($ft->get_file_ext(array('image')));
1781 $video_file_ext = json_encode($ft->get_file_ext(array('video')));
1782 $accepted_file_ext = json_encode($ft->get_file_ext($accepted_filetypes));
1783
1784 $css = '';
1785 $js = '';
1786 if (!isset($CFG->filepickerjsloaded)) {
1787 $css .= <<<EOD
1788<style type="text/css">
1789@import "$CFG->httpswwwroot/lib/yui/resize/assets/skins/sam/resize.css";
1790@import "$CFG->httpswwwroot/lib/yui/container/assets/skins/sam/container.css";
1791@import "$CFG->httpswwwroot/lib/yui/layout/assets/skins/sam/layout.css";
1792@import "$CFG->httpswwwroot/lib/yui/button/assets/skins/sam/button.css";
1793@import "$CFG->httpswwwroot/lib/yui/assets/skins/sam/treeview.css";
1794</style>
1795<style type="text/css">
c19f8e7d 1796/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
1797/* copy from yui/examples/treeview/assets/css/folders/tree.css */
1798/* first or middle sibling, no children */
1799.ygtvtn { background: url($CFG->pixpath/y/tn.gif) 0 0 no-repeat; width:17px; height:22px; }
1800/* first or middle sibling, collapsable */
1801.ygtvtm { background: url($CFG->pixpath/y/tm.gif) 0 0 no-repeat; width:34px; height:22px; cursor:pointer }
1802/* first or middle sibling, collapsable, hover */
1803.ygtvtmh { background: url($CFG->pixpath/y/tmh.gif) 0 0 no-repeat; width:34px; height:22px; cursor:pointer }
1804/* first or middle sibling, expandable */
1805.ygtvtp { background: url($CFG->pixpath/y/tp.gif) 0 0 no-repeat; width:34px; height:22px; cursor:pointer }
1806/* first or middle sibling, expandable, hover */
1807.ygtvtph { background: url($CFG->pixpath/y/tph.gif) 0 0 no-repeat; width:34px; height:22px; cursor:pointer }
1808/* last sibling, no children */
1809.ygtvln { background: url($CFG->pixpath/y/ln.gif) 0 0 no-repeat; width:17px; height:22px; }
1810/* Last sibling, collapsable */
1811.ygtvlm { background: url($CFG->pixpath/y/lm.gif) 0 0 no-repeat; width:34px; height:22px; cursor:pointer }
1812/* Last sibling, collapsable, hover */
1813.ygtvlmh { background: url($CFG->pixpath/y/lmh.gif) 0 0 no-repeat; width:34px; height:22px; cursor:pointer }
1814/* Last sibling, expandable */
1815.ygtvlp { background: url($CFG->pixpath/y/lp.gif) 0 0 no-repeat; width:34px; height:22px; cursor:pointer }
1816/* Last sibling, expandable, hover */
1817.ygtvlph { background: url($CFG->pixpath/y/lph.gif) 0 0 no-repeat; width:34px; height:22px; cursor:pointer }
1818/* Loading icon */
1819.ygtvloading { background: url($CFG->pixpath/y/loading.gif) 0 0 no-repeat; width:16px; height:22px; }
1820/* the style for the empty cells that are used for rendering the depth
1821 * of the node */
1822.ygtvdepthcell { background: url($CFG->pixpath/y/vline.gif) 0 0 no-repeat; width:17px; height:22px; }
1823.ygtvblankdepthcell { width:17px; height:22px; }
1824/* the style of the div around each node */
1825.ygtvitem { }
1826.ygtvitem table{ margin-bottom:0; }
1827.ygtvitem td { border:none;padding:0; }
1828/* the style of the div around each node's collection of children */
1829.ygtvchildren { }
1830* html .ygtvchildren { height:1%; }
1831/* the style of the text label in ygTextNode */
1832.ygtvlabel, .ygtvlabel:link, .ygtvlabel:visited, .ygtvlabel:hover { margin-left:2px; text-decoration: none; }
1833
1834
e189ec00 1835.file-picker{font-size:12px;}
1836.file-picker strong{background:#FFFFCC}
1837.file-picker a{color: #336699}
1838.file-picker a:hover{background:#003366;color:white}
1839.fp-panel{padding:0;margin:0; text-align:left;}
1840.fp-login-form{text-align:center}
1841.fp-searchbar{float:right}
1842.fp-viewbar{width:300px;float:left}
fc3ec2ca 1843.fp-toolbar{padding: .8em;background: #FFFFCC;color:white;text-align:center;margin: 3px}
e189ec00 1844.fp-toolbar a{padding: 0 .5em}
1845.fp-list{list-style-type:none;padding:0;float:left;width:100%;margin:0;}
1846.fp-list li{border-bottom:1px dotted gray;margin-bottom: 1em;}
1847.fp-repo-name{display:block;padding: .5em;margin-bottom: .5em}
1848.fp-pathbar{margin: .4em;border-bottom: 1px dotted gray;}
1849.fp-pathbar a{padding: .4em;}
1850.fp-rename-form{text-align:center}
1851.fp-rename-form p{margin: 1em;}
1852.fp-upload-form{margin: 2em 0;text-align:center}
1853.fp-upload-btn a{cursor: default;background: white;border:1px solid gray;color:black;padding: .5em}
1854.fp-upload-btn a:hover {background: grey;color:white}
1855.fp-paging{margin:1em .5em; clear:both;text-align:center;line-height: 2.5em;}
1856.fp-paging a{padding: .5em;border: 1px solid #CCC}
1857.fp-paging a.cur_page{border: 1px solid blue}
1858.fp-popup{text-align:center}
1859.fp-grid{float:left;text-align:center;}
1860.fp-grid div{overflow: hidden}
1861.fp-grid p{margin:0;padding:0;background: #FFFFCC}
1862.fp-grid .label{height:48px;text-align:center}
1863.fp-grid span{color:gray}
1864</style>
1865
1866<!--[if IE 6]>
2b8beee3 1867<style type="text/css">
1868/* Fix for IE6 */
1869.yui-skin-sam .yui-panel .hd{}
1870</style>
e189ec00 1871<![endif]-->
1872EOD;
1873
1874 require_js(array(
1875 'yui_yahoo',
1876 'yui_dom',
1877 'yui_event',
1878 'yui_element',
1879 'yui_treeview',
1880 'yui_dragdrop',
1881 'yui_container',
1882 'yui_resize',
1883 'yui_layout',
1884 'yui_connection',
1885 'yui_json',
1886 'yui_button',
1887 'yui_selector',
fc3ec2ca 1888 'repository/repository.src.js'
e189ec00 1889 ));
1890 $lang = array();
1891 $lang['title'] = get_string('title', 'repository');
1892 $lang['preview'] = get_string('preview', 'repository');
1893 $lang['add'] = get_string('add', 'repository');
1894 $lang['back'] = get_string('back', 'repository');
1895 $lang['cancel'] = get_string('cancel');
1896 $lang['close'] = get_string('close', 'repository');
1897 $lang['ccache'] = get_string('cleancache', 'repository');
1898 $lang['copying'] = get_string('copying', 'repository');
1899 $lang['downbtn'] = get_string('getfile', 'repository');
1900 $lang['download'] = get_string('downloadsucc', 'repository');
1901 $lang['date'] = get_string('date', 'repository').': ';
1902 $lang['error'] = get_string('error', 'repository');
1903 $lang['filenotnull'] = get_string('filenotnull', 'repository');
1904 $lang['federatedsearch'] = get_string('federatedsearch', 'repository');
1905 $lang['help'] = get_string('help');
1906 $lang['refresh'] = get_string('refresh', 'repository');
1907 $lang['invalidjson'] = get_string('invalidjson', 'repository');
1908 $lang['listview'] = get_string('listview', 'repository');
1909 $lang['login'] = get_string('login', 'repository');
1910 $lang['logout'] = get_string('logout', 'repository');
1911 $lang['loading'] = get_string('loading', 'repository');
1912 $lang['thumbview'] = get_string('thumbview', 'repository');
1913 $lang['title'] = get_string('title', 'repository');
1914 $lang['noresult'] = get_string('noresult', 'repository');
1915 $lang['mgr'] = get_string('manageurl', 'repository');
1916 $lang['noenter'] = get_string('noenter', 'repository');
1917 $lang['save'] = get_string('save', 'repository');
1918 $lang['saveas'] = get_string('saveas', 'repository').': ';
1919 $lang['saved'] = get_string('saved', 'repository');
1920 $lang['saving'] = get_string('saving', 'repository');
1921 $lang['size'] = get_string('size', 'repository').': ';
1922 $lang['sync'] = get_string('sync', 'repository');
1923 $lang['search'] = get_string('search', 'repository');
1924 $lang['searching'] = get_string('searching', 'repository');
1925 $lang['submit'] = get_string('submit', 'repository');
1926 $lang['preview'] = get_string('preview', 'repository');
1927 $lang['popup'] = get_string('popup', 'repository');
1928 $lang['upload'] = get_string('upload', 'repository').'...';
1929 $lang['uploading'] = get_string('uploading', 'repository');
2b8beee3 1930 // fp_lang includes language strings
e189ec00 1931 $js .= print_js_config($lang, 'fp_lang', true);
1932
1933 $options = array();
1934 $context = get_system_context();
1935 $options['contextid'] = $context->id;
2b8beee3 1936 // fp_config includes filepicker options
e189ec00 1937 $js .= print_js_config($options, 'fp_config', true);
1938
1939 $accepted_file_ext = json_encode($ft->get_file_ext($accepted_filetypes));
1940 $js .= <<<EOD
1941<script>
2b8beee3 1942file_extensions.image = $image_file_ext;
1943file_extensions.media = $video_file_ext;
e189ec00 1944</script>
1945EOD;
1946
1947 $CFG->filepickerjsloaded = true;
1948 } else {
1949 // if yui and repository javascript libs are loaded
1950 $js = '';
1951 }
1952
1953 // print instances listing
1954 $user_context = get_context_instance(CONTEXT_USER, $USER->id);
1955 if (is_array($accepted_filetypes) && in_array('*', $accepted_filetypes)) {
1956 $accepted_filetypes = '*';
1957 }
1958 $repos = repository::get_instances(array($user_context, $context, get_system_context()), null, true, null, $accepted_filetypes, $returnvalue);
2b8beee3 1959
1960 // print repository instances listing
e189ec00 1961 $js .= <<<EOD
1962<script>
2b8beee3 1963repository_listing['$id'] = {};
e189ec00 1964EOD;
1965 foreach ($repos as $repo) {
1966 $info = $repo->ajax_info();
1967 $js .= "\r\n";
1968 $js .= 'repository_listing[\''.$id.'\'][\''.$info->id.'\']='.json_encode($repo->ajax_info()).';';
1969 $js .= "\n";
1970 }
1971 $js .= "\r\n";
1972 $js .= "</script>";
1973
1974 return array('css'=>$css, 'js'=>$js);
1975}