MDL-13766
[moodle.git] / repository / lib.php
1 <?php
2  // $Id$
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 ///////////////////////////////////////////////////////////////////////////
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  */
41 /**
42  * This is the base class of the repository class
43  *
44  * To use repository plugin, you need to create a new folder under repository/, named as the remote
45  * repository, the subclass must be defined in  the name
47  *
48  * class repository is an abstract class, some functions must be implemented in subclass.
49  *
50  * See an example of use of this library in repository/boxnet/repository.class.php
51  *
52  * A few notes:
53  *   // print login page or a link to redirect to another page
54  *   $repo->print_login();
55  *   // call get_listing, and print result
56  *   $repo->print_listing();
57  *   // print a search box
58  *   $repo->print_search();
59  *
60  * @version 1.0 dev
61  * @package repository
62  * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
63  */
64 require_once(dirname(dirname(__FILE__)) . '/config.php');
65 require_once(dirname(dirname(__FILE__)).'/lib/filelib.php');
66 require_once(dirname(dirname(__FILE__)).'/lib/formslib.php');
68 /**
69  * A repository_type is a repository plug-in. It can be Box.net, Flick-r, ...
70  * A repository type can be edited, sorted and hidden. It is mandatory for an
71  * administrator to create a repository type in order to be able to create
72  * some instances of this type.
73  *
74  * Coding note:
75  * - a repository_type object is mapped to the "repository" database table
76  * - "typename" attibut maps the "type" database field. It is unique.
77  * - general "options" for a repository type are saved in the config_plugin table
78  * - when you delete a repository, all instances are deleted, and general
79  *   options are also deleted from database
80  * - When you create a type for a plugin that can't have multiple instances, a
81  *   instance is automatically created.
82  */
83 class repository_type {
86     /**
87      * Type name (no whitespace) - A type name is unique
88      * Note: for a user-friendly type name see get_readablename()
89      * @var String
90      */
91     private $_typename;
94     /**
95      * Options of this type
96      * They are general options that any instance of this type would share
97      * e.g. API key
98      * These options are saved in config_plugin table
99      * @var array
100      */
101    private $_options;
104     /**
105      * Is the repository type visible or hidden
106      * If false (hidden): no instances can be created, edited, deleted, showned , used...
107      * @var boolean
108      */
109    private $_visible;
112     /**
113      * 0 => not ordered, 1 => first position, 2 => second position...
114      * A not order type would appear in first position (should never happened)
115      * @var integer
116      */
117     private $_sortorder;
119     /**
120      * repository_type constructor
121      * @global <type> $CFG
122      * @param integer $typename
123      * @param array $typeoptions
124      * @param boolean $visible
125      * @param integer $sortorder (don't really need set, it will be during create() call)
126      */
127     public function __construct($typename = '', $typeoptions = array(), $visible = false, $sortorder = 0){
128         global $CFG;
130         //set type attributs
131         $this->_typename = $typename;
132         $this->_visible = $visible;
133         $this->_sortorder = $sortorder;
135         //set options attribut
136         $this->_options = array();
137         //check that the type can be setup
138         if (repository_static_function($typename,"has_admin_config")){
139             $options = repository_static_function($typename,'get_admin_option_names');
140             //set the type options
141             foreach ($options as $config) {
142                 if (array_key_exists($config,$typeoptions)){
143                         $this->_options[$config] = $typeoptions[$config];
144                 }
145             }
146         }
147     }
149     /**
150      * Get the type name (no whitespace)
151      * For a human readable name, use get_readablename()
152      * @return String the type name
153      */
154     public function get_typename(){
155         return $this->_typename;
156     }
158     /**
159      * Return a human readable and user-friendly type name
160      * @return string user-friendly type name
161      */
162     public function get_readablename(){
163         return get_string('repositoryname','repository_'.$this->_typename);
164     }
166     /**
167      * Return general options
168      * @return array the general options
169      */
170     public function get_options(){
171         return $this->_options;
172     }
174     /**
175      * Return visibility
176      * @return boolean
177      */
178     public function get_visible(){
179         return $this->_visible;
180     }
182     /**
183      * Return order / position of display in the file picker
184      * @return integer
185      */
186     public function get_sortorder(){
187         return $this->_sortorder;
188     }
190     /**
191      * Create a repository type (the type name must not already exist)
192      * @global object $DB
193      */
194     public function create(){
195         global $DB;
197         //check that $type has been set
198         $timmedtype = trim($this->_typename);
199         if (empty($timmedtype)) {
200              throw new repository_exception('emptytype', 'repository');
201         }
203         //set sortorder as the last position in the list
204         if (!isset($this->_sortorder) || $this->_sortorder == 0 ){
205             $sql = "SELECT MAX(sortorder) FROM {repository}";
206             $this->_sortorder = 1 + $DB->get_field_sql($sql);
207         }
209         //only create a new type if it doesn't already exist
210         $existingtype = $DB->get_record('repository', array('type'=>$this->_typename));
211         if(!$existingtype){
212            //create the type
213            $newtype = new stdclass;
214            $newtype->type = $this->_typename;
215            $newtype->visible = $this->_visible;
216            $newtype->sortorder = $this->_sortorder;
217            $DB->insert_record('repository', $newtype);
219            //save the options in DB
220            $this->update_options();
222            //if the plugin type has no multiple and no instance config so it wont
223            //be possible for the administrator to create a instance
224            //in this case we need to create an instance
225            if (!repository_static_function($this->_typename,"has_instance_config")
226            && !repository_static_function($this->_typename,"has_multiple_instances")){
227               $instanceoptions = array();
228               $instanceoptions['name'] = $this->_typename;
229               repository_static_function($this->_typename, 'create', $this->_typename, 0, get_system_context(), $instanceoptions);
230            }
231         }
232         else {
233             throw new repository_exception('existingrepository', 'repository');
234         }
235     }
238     /**
239      * Update plugin options into the config_plugin table
240      * @param array $options
241      * @return boolean
242      */
243     public function update_options($options = null){
244         if (!empty($options)){
245             $this->_options = $options;
246         }
248         foreach ($this->_options as $name => $value) {
249             set_config($name,$value,$this->_typename);
250         }
252         return true;
253     }
255     /**
256      * Update visible database field with the value given as parameter
257      * or with the visible value of this object
258      * This function is private.
259      * For public access, have a look to switch_and_update_visibility()
260      * @global object $DB
261      * @param boolean $visible
262      * @return boolean
263      */
264     private function update_visible($visible = null){
265         global $DB;
267         if (!empty($visible)){
268             $this->_visible = $visible;
269         }
270         else if (!isset($this->_visible)){
271             throw new repository_exception('updateemptyvisible', 'repository');
272         }
274         return $DB->set_field('repository', 'visible', $this->_visible, array('type'=>$this->_typename));
275     }
277     /**
278      * Update database sortorder field with the value given as parameter
279      * or with the sortorder value of this object
280      * This function is private.
281      * For public access, have a look to move_order()
282      * @global object $DB
283      * @param integer $sortorder
284      * @return boolean
285      */
286     private function update_sortorder($sortorder = null){
287         global $DB;
289         if (!empty($sortorder) && $sortorder!=0){
290             $this->_sortorder = $sortorder;
291         }
292         //if sortorder is not set, we set it as the ;ast position in the list
293         else if (!isset($this->_sortorder) || $this->_sortorder == 0 ){
294             $sql = "SELECT MAX(sortorder) FROM {repository}";
295             $this->_sortorder = 1 + $DB->get_field_sql($sql);
296         }
298         return $DB->set_field('repository', 'sortorder', $this->_sortorder, array('type'=>$this->_typename));
299     }
301     /**
302      * Change order of the type with its adjacent upper or downer type
303      * (database fields are updated)
304      * Algorithm details:
305      * 1. retrieve all types in an array. This array is sorted by sortorder,
306      * and the array keys start from 0 to X (incremented by 1)
307      * 2. switch sortorder values of this type and its adjacent type
308      * @global object $DB
309      * @param string $move "up" or "down"
310      */
311     public function move_order($move) {
312         global $DB;
313         //retrieve all types
314         $types = repository_get_types();
316         //retrieve this type into the returned array
317          $i = 0;
318         while (!isset($indice) && $i<count($types)){
319             if ($types[$i]->get_typename() == $this->_typename){
320                 $indice = $i;
321             }
322             $i++;
323         }
325         //retrieve adjacent indice
326         switch ($move) {
327             case "up":
328                 $adjacentindice = $indice - 1;
329                 break;
330             case "down":
331                 $adjacentindice = $indice + 1;
332                 break;
333             default:
334                 throw new repository_exception('movenotdefined', 'repository');
335         }
337         //switch sortorder of this type and the adjacent type
338         //TODO: we could reset sortorder for all types. This is not as good in performance term, but
339         //that prevent from wrong behaviour on a screwed database. As performance are not important in this particular case
340         //it worth to change the algo.
341         if ($adjacentindice>=0 && !empty($types[$adjacentindice])){
342             $DB->set_field('repository', 'sortorder', $this->_sortorder, array('type'=>$types[$adjacentindice]->get_typename()));
343             $this->update_sortorder($types[$adjacentindice]->get_sortorder());
344         }
345     }
347     /**
348      * 1. Switch the visibility OFF if it's ON, and ON if it's OFF.
349      * 2. Update the type
350      * @return <type>
351      */
352     public function switch_and_update_visibility(){
353         $this->_visible = !$this->_visible;
354         return $this->update_visible();
355     }
358     /**
359      * Delete a repository_type (general options are removed from config_plugin
360      * table, and all instances are deleted)
361      * @global object $DB
362      * @return boolean
363      */
364     public function delete(){
365         global $DB;
367         //delete all instances of this type
368         $instances = repository_get_instances(array(),null,false,$this->_typename);
369         foreach($instances as $instance){
370             $instance->delete();
371         }
373         //delete all general options
374         foreach ($this->_options as $name => $value){
375             set_config($name, null, $this->_typename);
376         }
378         return $DB->delete_records('repository', array('type' => $this->_typename));
379     }
382 /**
383  * Return a type for a given type name.
384  * @global object $DB
385  * @param string $typename the type name
386  * @return integer
387  */
388 function repository_get_type_by_typename($typename){
389     global $DB;
391     if(!$record = $DB->get_record('repository',array('type' => $typename))) {
392         return false;
393     }
395     return new repository_type($typename, (array)get_config($typename), $record->visible, $record->sortorder);
398 /**
399  * Return a type for a given type id.
400  * @global object $DB
401  * @param string $typename the type name
402  * @return integer
403  */
404 function repository_get_type_by_id($id){
405     global $DB;
407     if(!$record = $DB->get_record('repository',array('id' => $id))) {
408         return false;
409     }
411     return new repository_type($record->type, (array)get_config($record->type), $record->visible, $record->sortorder);
414 /**
415  * Return all repository types ordered by sortorder
416  * first type in returnedarray[0], second type in returnedarray[1], ...
417  * @global object $DB
418  * @param boolean $visible can return types by visiblity, return all types if null
419  * @return array Repository types
420  */
421 function repository_get_types($visible=null){
422     global $DB;
424     $types = array();
425     $params = null;
426     if (!empty($visible)) {
427         $params = array('visible' => $visible);
428     }
429     if($records = $DB->get_records('repository',$params,'sortorder')) {
430         foreach($records as $type) {
431             $types[] = new repository_type($type->type, (array)get_config($type->type), $type->visible, $type->sortorder);
432         }
433     }
435     return $types;
438 /**
439  * The base class for all repository plugins
440  */
442 abstract class repository {
443     public $id;
444     public $context;
445     public $options;
447     /**
448      * 1. Initialize context and options
449      * 2. Accept necessary parameters
450      *
451      * @param integer $repositoryid
452      * @param integer $contextid
453      * @param array $options
454      */
455     public function __construct($repositoryid, $contextid = SITEID, $options = array()){
456         $this->id = $repositoryid;
457         $this->context = get_context_instance_by_id($contextid);
458         $this->options = array();
459         if (is_array($options)) {
460             $options = array_merge($this->get_option(), $options);
461         } else {
462             $options = $this->get_option();
463         }
464         $this->options = array();
465         foreach ($options as $n => $v) {
466             $this->options[$n] = $v;
467         }
468         $this->name = $this->get_name();
469     }
471     /**
472      * set options for repository instance
473      *
474      * @param string $name
475      * @param mixed $value
476      */
477     public function __set($name, $value) {
478         $this->options[$name] = $value;
479     }
481     /**
482      * get options for repository instance
483      *
484      * @param string $name
485      * @return mixed
486      */
487     public function __get($name) {
488         if (array_key_exists($name, $this->options)){
489             return $this->options[$name];
490         }
491         trigger_error('Undefined property: '.$name, E_USER_NOTICE);
492         return null;
493     }
495     /**
496      * test option name
497      *
498      * @param string name
499      */
500     public function __isset($name) {
501         return isset($this->options[$name]);
502     }
504     /**
505      * Return the name of the repository class
506      * @return <type>
507      */
508     public function __toString() {
509         return 'Repository class: '.__CLASS__;
510     }
512     /**
513      * Download a file, this function can be overridden by
514      * subclass.
515      *
516      * @global object $CFG
517      * @param string $url the url of file
518      * @param string $file save location
519      * @return string the location of the file
520      * @see curl package
521      */
522     public function get_file($url, $file = '') {
523         global $CFG;
524         if (!file_exists($CFG->dataroot.'/temp/download')) {
525             mkdir($CFG->dataroot.'/temp/download/', 0777, true);
526         }
527         if(is_dir($CFG->dataroot.'/temp/download')) {
528             $dir = $CFG->dataroot.'/temp/download/';
529         }
530         if(empty($file)) {
531             $file = uniqid('repo').'_'.time().'.tmp';
532         }
533         if(file_exists($dir.$file)){
534             $file = uniqid('m').$file;
535         }
536         $fp = fopen($dir.$file, 'w');
537         $c = new curl;
538         $c->download(array(
539             array('url'=>$url, 'file'=>$fp)
540         ));
541         return $dir.$file;
542     }
544     /**
545      * Print a list or return formatted string, can be overridden by subclass
546      *
547      * @param string $list
548      * @param boolean $print false, return html, otherwise, print it directly
549      * @return <type>
550      */
551     public function print_listing($listing = array(), $print=true) {
552         if(empty($listing)){
553             $listing = $this->get_listing();
554         }
555         if (empty($listing)) {
556             $str = '';
557         } else {
558             $count = 0;
559             $str = '<table>';
560             foreach ($listing as $v){
561                 $str .= '<tr id="entry_'.$count.'">';
562                 $str .= '<td><input type="checkbox" /></td>';
563                 $str .= '<td>'.$v['name'].'</td>';
564                 $str .= '<td>'.$v['size'].'</td>';
565                 $str .= '<td>'.$v['date'].'</td>';
566                 $str .= '</tr>';
567                 $count++;
568             }
569             $str .= '</table>';
570         }
571         if ($print){
572             echo $str;
573             return null;
574         } else {
575             return $str;
576         }
577     }
579     /**
580      * Return the name of this instance, can be overridden.
581      * @global <type> $DB
582      * @return <type>
583      */
584     public function get_name(){
585         global $DB;
586         // We always verify instance id from database,
587         // so we always know repository name before init
588         // a repository, so we don't enquery repository
589         // name from database again here.
590         if (isset($this->options['name'])) {
591             return $this->options['name'];
592         } else {
593             if ( $repo = $DB->get_record('repository_instances', array('id'=>$this->id)) ) {
594                 return $repo->name;
595             } else {
596                 return '';
597             }
598         }
599     }
601     /**
602      * Provide repository instance information for Ajax
603      * @global object $CFG
604      * @return object
605      */
606     final public function ajax_info() {
607         global $CFG;
608         $repo = new stdclass;
609         $repo->id   = $this->id;
610         $repo->name = $this->get_name();
611         $repo->type = $this->options['type'];
612         $repo->icon = $CFG->httpswwwroot.'/repository/'.$repo->type.'/icon.png';
613         return $repo;
614     }
616     /**
617      * Create an instance for this plug-in
618      * @global object $CFG
619      * @global object $DB
620      * @param string $type the type of the repository
621      * @param integer $userid the user id
622      * @param object $context the context
623      * @param array $params the options for this instance
624      * @return <type>
625      */
626     final public static function create($type, $userid, $context, $params) {
627         global $CFG, $DB;
628         $params = (array)$params;
629         require_once($CFG->dirroot . '/repository/'. $type . '/repository.class.php');
630         $classname = 'repository_' . $type;
631         if ($repo = $DB->get_record('repository', array('type'=>$type))) {
632             $record = new stdclass;
633             $record->name = $params['name'];
634             $record->typeid = $repo->id;
635             $record->timecreated  = time();
636             $record->timemodified = time();
637             $record->contextid = $context->id;
638             $record->userid    = $userid;
639             $id = $DB->insert_record('repository_instances', $record);
640             $options = array();
641             if (call_user_func($classname . '::has_instance_config')) {
642                 $configs = call_user_func($classname . '::get_instance_option_names');
643                 foreach ($configs as $config) {
644                     $options[$config] = $params[$config];
645                 }
646             }
647             if (!empty($id)) {
648                 unset($options['name']);
649                 $instance = repository_get_instance($id);
650                 $instance->set_option($options);
651                 return $id;
652             } else {
653                 return null;
654             }
655         } else {
656             return null;
657         }
658     }
660     /**
661      * delete a repository instance
662      * @global object $DB
663      * @return <type>
664      */
665     final public function delete(){
666         global $DB;
667         $DB->delete_records('repository_instances', array('id'=>$this->id));
668         return true;
669     }
671     /**
672      * Hide/Show a repository
673      * @global object $DB
674      * @param string $hide
675      * @return <type>
676      */
677     final public function hide($hide = 'toggle'){
678         global $DB;
679         if ($entry = $DB->get_record('repository', array('id'=>$this->id))) {
680             if ($hide === 'toggle' ) {
681                 if (!empty($entry->visible)) {
682                     $entry->visible = 0;
683                 } else {
684                     $entry->visible = 1;
685                 }
686             } else {
687                 if (!empty($hide)) {
688                     $entry->visible = 0;
689                 } else {
690                     $entry->visible = 1;
691                 }
692             }
693             return $DB->update_record('repository', $entry);
694         }
695         return false;
696     }
698     /**
699      * Cache login details for repositories
700      * @global object $DB
701      * @param string $username
702      * @param string $password
703      * @param integer $userid The id of specific user
704      * @return integer Id of the record
705      */
706     public function store_login($username = '', $password = '', $userid = 1) {
707         global $DB;
709         $repository = new stdclass;
710         if (!empty($this->id)) {
711             $repository->id = $this->id;
712         } else {
713             $repository->userid         = $userid;
714             $repository->repositorytype = $this->type;
715             $repository->contextid      = $this->context->id;
716         }
717         if ($entry = $DB->get_record('repository', $repository)) {
718             $repository->id = $entry->id;
719             $repository->username = $username;
720             $repository->password = $password;
721             return $DB->update_record('repository', $repository);
722         } else {
723             $repository->username = $username;
724             $repository->password = $password;
725             return $DB->insert_record('repository', $repository);
726         }
727     }
729     /**
730      * Save settings for repository instance
731      * $repo->set_option(array('api_key'=>'f2188bde132', 'name'=>'dongsheng'));
732      * @global object $DB
733      * @param array $options settings
734      * @return int Id of the record
735      */
736     public function set_option($options = array()){
737         global $DB;
738         if (!empty($options['name'])) {
739             $r = new object();
740             $r->id   = $this->id;
741             $r->name = $options['name'];
742             $DB->update_record('repository_instances', $r);
743             unset($options['name']);
744         }
745         foreach ($options as $name=>$value) {
746             if ($id = $DB->get_field('repository_instance_config', 'id', array('name'=>$name, 'instanceid'=>$this->id))) {
747                 if ($value===null) {
748                     return $DB->delete_records('repository_instance_config', array('name'=>$name, 'instanceid'=>$this->id));
749                 } else {
750                     return $DB->set_field('repository_instance_config', 'value', $value, array('id'=>$id));
751                 }
752             } else {
753                 if ($value===null) {
754                     return true;
755                 }
756                 $config = new object();
757                 $config->instanceid = $this->id;
758                 $config->name   = $name;
759                 $config->value  = $value;
760                 return $DB->insert_record('repository_instance_config', $config);
761             }
762         }
763         return true;
764     }
766     /**
767      * Get settings for repository instance
768      * @global object $DB
769      * @param <type> $config
770      * @return array Settings
771      */
772     public function get_option($config = ''){
773         global $DB;
774         $entries = $DB->get_records('repository_instance_config', array('instanceid'=>$this->id));
775         $ret = array();
776         if (empty($entries)) {
777             return $ret;
778         }
779         foreach($entries as $entry){
780             $ret[$entry->name] = $entry->value;
781         }
782         if (!empty($config)) {
783             return $ret[$config];
784         } else {
785             return $ret;
786         }
787     }
789     /**
790      * Given a path, and perhaps a search, get a list of files.
791      *
792      * The format of the returned array must be:
793      * array(
794      *   'path' => (string) path for the current folder
795      *   'dynload' => (bool) use dynamic loading,
796      *   'manage' => (string) link to file manager,
797      *   'nologin' => (bool) requires login,
798      *   'nosearch' => (bool) no search link,
799      *   'upload' => array( // upload manager
800      *     'name' => (string) label of the form element,
801      *     'id' => (string) id of the form element
802      *   ),
803      *   'list' => array(
804      *     array( // file
805      *       'title' => (string) file name,
806      *       'date' => (string) file last modification time, usually userdate(...),
807      *       'size' => (int) file size,
808      *       'thumbnail' => (string) url to thumbnail for the file,
809      *       'source' => plugin-dependent unique path to the file (id, url, path, etc.),
810      *       'url'=> the accessible url of file
811      *     ),
812      *     array( // folder - same as file, but no 'source'.
813      *       'title' => (string) folder name,
814      *       'path' => (string) path to this folder
815      *       'date' => (string) folder last modification time, usually userdate(...),
816      *       'size' => 0,
817      *       'thumbnail' => (string) url to thumbnail for the folder,
818      *       'children' => array( // an empty folder needs to have 'children' defined, but empty.
819      *         // content (files and folders)
820      *       )
821      *     ),
822      *   )
823      * )
824      *
825      * @param string $parent The parent path, this parameter can
826      * a folder name, or a identification of folder
827      * @param string $search The text will be searched.
828      * @return array the list of files, including meta infomation
829      */
830     abstract public function get_listing($parent = '/', $search = '');
833     /**
834      * Show the login screen, if required
835      * This is an abstract function, it must be overriden.
836      */
837     abstract public function print_login();
839     /**
840      * Show the search screen, if required
841      * @return null
842      */
843     abstract public function print_search();
845     /**
846      * is it possible to do glboal search?
847      * @return boolean
848      */
849     public function global_search(){
850         return false;
851     }
853     /**
854      * Defines operations that happen occasionally on cron
855      * @return <type>
856      */
857     public function cron() {
858         return true;
859     }
861     /**
862      * Return true if the plugin type has at least one general option field
863      * By default: false
864      * @return boolean
865      */
866     public static function has_admin_config() {
867         return false;
868     }
870     /**
871      * Return true if a plugin instance has at least one config field
872      * By default: false
873      * @return boolean
874      */
875     public static function has_instance_config() {
876         return false;
877     }
879     /**
880      * Return true if the plugin can have multiple instances
881      * By default: false
882      * @return boolean
883      */
884     public static function has_multiple_instances(){
885         return false;
886     }
888     /**
889      * Return names of the general options
890      * By default: no general option name
891      * @return array
892      */
893     public static function get_admin_option_names(){
894         return array();
895     }
897     /**
898      * Return names of the instance options
899      * By default: no instance option name
900      * @return array
901      */
902     public static function get_instance_option_names(){
903         return array();
904     }
907 /**
908  * exception class for repository api
909  */
910 class repository_exception extends moodle_exception {
913 /**
914  * Check context
915  * @param int $ctx_id
916  * @return boolean
917  */
918 function repository_check_context($ctx_id){
919     global $USER;
920     $context = get_context_instance_by_id($ctx_id);
921     $level = $context->contextlevel;
922     if ($level == CONTEXT_COURSE) {
923         if (!has_capability('moodle/course:view', $context)) {
924             return false;
925         } else {
926             return true;
927         }
928     } elseif ($level == CONTEXT_USER) {
929         $c = get_context_instance(CONTEXT_USER, $USER->id);
930         if ($c->id == $ctx_id) {
931             return true;
932         } else {
933             return false;
934         }
935     } elseif ($level == CONTEXT_SYSTEM) {
936         // it is always ok in system level
937         return true;
938     }
939     return false;
942 /**
943  * Return all types that you a user can create/edit and which are also visible
944  * Note: Mostly used in order to know if at least one editable type has been set
945  * @return array types
946  */
947 function repository_get_editable_types(){
948     $types= repository_get_types(true);
949     $editabletypes = array();
950     foreach ($types as $type){
951          if (repository_static_function($type->get_typename(), 'has_multiple_instances')) {
952             $editabletypes[]=$type;
953         }
954     }
955     return $editabletypes;
958 /**
959  * Return repository instances
960  * @global object $DB
961  * @global object $CFG
962  * @global object $USER
963  * @param object $contexts contexts for which the instances are set
964  * @param integer $userid
965  * @param boolean $onlyvisible if visible == true, return visible instances only,
966  *                otherwise, return all instances
967  * @param string $type a type name to retrieve
968  * @return array repository instances
969  */
970 function repository_get_instances($contexts=array(), $userid = null, $onlyvisible = true, $type=null){
971     global $DB, $CFG, $USER;
972     $params = array();
973     $sql = 'SELECT i.*, r.type AS repositorytype, r.sortorder, r.visible FROM {repository} r, {repository_instances} i WHERE ';
974     $sql .= 'i.typeid = r.id ';
975     if (!empty($userid) && is_numeric($userid)) {
976         $sql .= ' AND (i.userid = 0 or i.userid = ?)';
977         $params[] = $userid;
978     }
979     foreach ($contexts as $context) {
980         if (empty($firstcontext)){
981             $firstcontext = true;
982             $sql .= ' AND ((i.contextid = ?)';
983         } else {
984             $sql .= ' OR (i.contextid = ?)';
985         }
986         $params[] = $context->id;
987     }
988     if ($firstcontext) {
989        $sql .=')';
990     }
992     if($onlyvisible == true) {
993         $sql .= ' AND (r.visible = 1)';
994     }
995     if(isset($type)) {
996         $sql .= ' AND (r.type = ?)';
997         $params[] = $type;
998     }
999     $sql .= ' order by r.sortorder, i.name';
1000     if(!$repos = $DB->get_records_sql($sql, $params)) {
1001         $repos = array();
1002     }
1003     $ret = array();
1004     foreach($repos as $repo) {
1005         require_once($CFG->dirroot . '/repository/'. $repo->repositorytype
1006             . '/repository.class.php');
1007         $options['visible'] = $repo->visible;
1008         $options['name']    = $repo->name;
1009         $options['type']    = $repo->repositorytype;
1010         $options['typeid']  = $repo->typeid;
1011         $classname = 'repository_' . $repo->repositorytype;
1012         $ret[] = new $classname($repo->id, $repo->contextid, $options);
1013     }
1014     return $ret;
1017 /**
1018  * Get single repository instance
1019  * @global object $DB
1020  * @global object $CFG
1021  * @param integer $id repository id
1022  * @return object repository instance
1023  */
1024 function repository_get_instance($id){
1025     global $DB, $CFG;
1026     $sql = 'SELECT i.*, r.type AS repositorytype, r.visible FROM {repository} r, {repository_instances} i WHERE ';
1027     $sql .= 'i.typeid = r.id AND ';
1028     $sql .= 'i.id = '.$id;
1030     if(!$instance = $DB->get_record_sql($sql)) {
1031         return false;
1032     }
1033     require_once($CFG->dirroot . '/repository/'. $instance->repositorytype
1034         . '/repository.class.php');
1035     $classname = 'repository_' . $instance->repositorytype;
1036     $options['typeid'] = $instance->typeid;
1037     $options['type']   = $instance->repositorytype;
1038     $options['name']   = $instance->name;
1039     return new $classname($instance->id, $instance->contextid, $options);
1042 /**
1043  * call a static function
1044  * @global <type> $CFG
1045  * @param <type> $plugin
1046  * @param <type> $function
1047  * @param type $nocallablereturnvalue default value if function not found
1048  *             it's mostly used when you don't want to display an error but
1049  *             return a boolean
1050  * @return <type>
1051  */
1052 function repository_static_function($plugin, $function) {
1053     global $CFG;
1055     //check that the plugin exists
1056     $typedirectory = $CFG->dirroot . '/repository/'. $plugin . '/repository.class.php';
1057         if (!file_exists($typedirectory)) {
1058             throw new repository_exception('invalidplugin', 'repository');
1059     }
1061     $pname = null;
1062     if (is_object($plugin) || is_array($plugin)) {
1063         $plugin = (object)$plugin;
1064         $pname = $plugin->name;
1065     } else {
1066         $pname = $plugin;
1067     }
1069     $args = func_get_args();
1070     if (count($args) <= 2) {
1071         $args = array();
1072     }
1073     else {
1074         array_shift($args);
1075         array_shift($args);
1076     }
1078     require_once($typedirectory);
1079     return call_user_func_array(array('repository_' . $plugin, $function), $args);
1082 /**
1083  * Move file from download folder to file pool using FILE API
1084  * @global object $DB
1085  * @global object $CFG
1086  * @global object $USER
1087  * @param string $path file path in download folder
1088  * @param string $name file name
1089  * @param integer $itemid item id to identify a file in filepool
1090  * @param string $filearea file area
1091  * @return array information of file in file pool
1092  */
1093 function repository_move_to_filepool($path, $name, $itemid, $filearea = 'user_draft') {
1094     global $DB, $CFG, $USER;
1095     $context = get_context_instance(CONTEXT_USER, $USER->id);
1096     $now = time();
1097     $entry = new object();
1098     $entry->filearea  = $filearea;
1099     $entry->contextid = $context->id;
1100     $entry->filename  = $name;
1101     $entry->filepath  = '/'.uniqid().'/';
1102     $entry->timecreated  = $now;
1103     $entry->timemodified = $now;
1104     if(is_numeric($itemid)) {
1105         $entry->itemid = $itemid;
1106     } else {
1107         $entry->itemid = 0;
1108     }
1109     $entry->mimetype     = mimeinfo('type', $path);
1110     $entry->userid       = $USER->id;
1111     $fs = get_file_storage();
1112     $browser = get_file_browser();
1113     if ($file = $fs->create_file_from_pathname($entry, $path)) {
1114         $delete = unlink($path);
1115         $ret = $browser->get_file_info($context, $file->get_filearea(), $file->get_itemid(), $file->get_filepath(), $file->get_filename());
1116         if(!empty($ret)){
1117             return array('url'=>$ret->get_url(),'id'=>$file->get_itemid(), 'file'=>$file->get_filename());
1118         } else {
1119             return null;
1120         }
1121     } else {
1122         return null;
1123     }
1126 /**
1127  * Save file to local filesystem pool
1128  * @param string $elname name of element
1129  * @param string $filearea
1130  * @param string $filepath
1131  * @param string $filename - use specified filename, if not specified name of uploaded file used
1132  * @param bool $override override file if exists
1133  * @return mixed stored_file object or false if error; may throw exception if duplicate found
1134  */
1135 function repository_store_to_filepool($elname, $filearea='user_draft', $filepath='/', $filename = '', $override = false) {
1136     global $USER;
1137     if (!isset($_FILES[$elname])) {
1138         return false;
1139     }
1141     if (!$filename) {
1142         $filename = $_FILES[$elname]['name'];
1143     }
1144     $context = get_context_instance(CONTEXT_USER, $USER->id);
1145     $itemid = (int)substr(hexdec(uniqid()), 0, 9)+rand(1,100);
1146     $fs = get_file_storage();
1147     $browser = get_file_browser();
1149     if ($file = $fs->get_file($context->id, $filearea, $itemid, $filepath, $filename)) {
1150         if ($override) {
1151             $file->delete();
1152         } else {
1153             return false;
1154         }
1155     }
1157     $file_record = new object();
1158     $file_record->contextid = $context->id;
1159     $file_record->filearea  = $filearea;
1160     $file_record->itemid    = $itemid;
1161     $file_record->filepath  = $filepath;
1162     $file_record->filename  = $filename;
1163     $file_record->userid    = $USER->id;
1165     $file = $fs->create_file_from_pathname($file_record, $_FILES[$elname]['tmp_name']);
1166     $info = $browser->get_file_info($context, $file->get_filearea(), $file->get_itemid(), $file->get_filepath(), $file->get_filename());
1167     $ret = array('url'=>$info->get_url(),'id'=>$itemid, 'file'=>$file->get_filename());
1168     return $ret;
1171 /**
1172  * Return javascript to create file picker to browse repositories
1173  * @global object $CFG
1174  * @global object $USER
1175  * @param object $context the context
1176  * @return array
1177  */
1178 function repository_get_client($context){
1179     global $CFG, $USER;
1180     $suffix = uniqid();
1181     $sesskey = sesskey();
1182     $strsaveas    = get_string('saveas', 'repository').': ';
1183     $stradd  = get_string('add', 'repository');
1184     $strback      = get_string('back', 'repository');
1185     $strcancel    = get_string('cancel');
1186     $strclose     = get_string('close', 'repository');
1187     $strccache    = get_string('cleancache', 'repository');
1188     $strcopying   = get_string('copying', 'repository');
1189     $strdownbtn   = get_string('getfile', 'repository');
1190     $strdownload  = get_string('downloadsucc', 'repository');
1191     $strdate      = get_string('date', 'repository').': ';
1192     $strerror     = get_string('error', 'repository');
1193     $strfilenotnull = get_string('filenotnull', 'repository');
1194     $strrefresh   = get_string('refresh', 'repository');
1195     $strinvalidjson = get_string('invalidjson', 'repository');
1196     $strlistview  = get_string('listview', 'repository');
1197     $strlogout    = get_string('logout', 'repository');
1198     $strloading   = get_string('loading', 'repository');
1199     $strthumbview = get_string('thumbview', 'repository');
1200     $strtitle     = get_string('title', 'repository');
1201     $strmgr       = get_string('manageurl', 'repository');
1202     $strnoenter   = get_string('noenter', 'repository');
1203     $strsave      = get_string('save', 'repository');
1204     $strsaved     = get_string('saved', 'repository');
1205     $strsaving    = get_string('saving', 'repository');
1206     $strsize      = get_string('size', 'repository').': ';
1207     $strsync      = get_string('sync', 'repository');
1208     $strsearch    = get_string('search', 'repository');
1209     $strsearching = get_string('searching', 'repository');
1210     $strsubmit    = get_string('submit', 'repository');
1211     $strpreview   = get_string('preview', 'repository');
1212     $strupload    = get_string('upload', 'repository');
1213     $struploading = get_string('uploading', 'repository');
1214     $css = '';
1215     if (!isset($CFG->repo_yui_loaded)) {
1216         $css .= <<<EOD
1217 <style type="text/css">
1218 @import "$CFG->httpswwwroot/lib/yui/resize/assets/skins/sam/resize.css";
1219 @import "$CFG->httpswwwroot/lib/yui/container/assets/skins/sam/container.css";
1220 @import "$CFG->httpswwwroot/lib/yui/layout/assets/skins/sam/layout.css";
1221 @import "$CFG->httpswwwroot/lib/yui/button/assets/skins/sam/button.css";
1222 @import "$CFG->httpswwwroot/lib/yui/assets/skins/sam/treeview.css";
1223 </style>
1224 <style type="text/css">
1225 .file-picker{font-size:12px;}
1226 .file-picker strong{background:#FFFFCC}
1227 .file-picker a{color: #336699}
1228 .file-picker a:hover{background:#003366;color:white}
1229 .fp-panel{padding:0;margin:0; text-align:left;}
1230 .fp-searchbar{float:right}
1231 .fp-viewbar{width:300px;float:left}
1232 .fp-toolbar{padding: .8em;background: #FFFFCC;color:white;text-align:center}
1233 .fp-toolbar a{padding: 0 5px}
1234 .fp-list{list-style-type:none;padding:0}
1235 .fp-list li{border-bottom:1px dotted gray;margin-bottom: 1em;}
1236 .fp-repo-name{display:block;padding: 3px;margin-bottom: 5px}
1237 .fp-pathbar{margin: 4px;border-bottom: 1px dotted gray;}
1238 .fp-pathbar a{padding: 4px;}
1239 .fp-rename-form{text-align:center}
1240 .fp-rename-form p{margin: 1em;}
1241 .fp-upload-form{margin: 2em 0;text-align:center}
1242 .fp-upload-btn a{font-size: 14px;background: #ccc;color:white;padding: 5px}
1243 .fp-upload-btn a:hover {background: grey;color:white}
1244 .fp-paging{margin:10px 5px; clear:both;text-align:center}
1245 .fp-paging a{padding: 4px;border: 1px solid #CCC}
1246 .fp-grid{width:80px; float:left;text-align:center;}
1247 .fp-grid div{width: 80px; overflow: hidden}
1248 .fp-grid p{margin:0;padding:0;background: #FFFFCC}
1249 .fp-grid .label{height:48px}
1250 .fp-grid span{background: #EEF9EB;color:gray}
1251 </style>
1252 EOD;
1254     $js = <<<EOD
1255 <script type="text/javascript" src="$CFG->httpswwwroot/lib/yui/yahoo-dom-event/yahoo-dom-event.js"></script>
1256 <script type="text/javascript" src="$CFG->httpswwwroot/lib/yui/element/element-beta-min.js"></script>
1257 <script type="text/javascript" src="$CFG->httpswwwroot/lib/yui/treeview/treeview-min.js"></script>
1258 <script type="text/javascript" src="$CFG->httpswwwroot/lib/yui/dragdrop/dragdrop-min.js"></script>
1259 <script type="text/javascript" src="$CFG->httpswwwroot/lib/yui/container/container-min.js"></script>
1260 <script type="text/javascript" src="$CFG->httpswwwroot/lib/yui/resize/resize-beta-min.js"></script>
1261 <script type="text/javascript" src="$CFG->httpswwwroot/lib/yui/layout/layout-beta-min.js"></script>
1262 <script type="text/javascript" src="$CFG->httpswwwroot/lib/yui/connection/connection-min.js"></script>
1263 <script type="text/javascript" src="$CFG->httpswwwroot/lib/yui/json/json-min.js"></script>
1264 <script type="text/javascript" src="$CFG->httpswwwroot/lib/yui/button/button-min.js"></script>
1265 <script type="text/javascript" src="$CFG->httpswwwroot/lib/yui/selector/selector-beta-min.js"></script>
1266 EOD;
1267         $CFG->repo_yui_loaded = true;
1268     } else {
1269         $js = '';
1270     }
1272 $js .= <<<EOD
1273 <script type="text/javascript">
1274 //<![CDATA[
1275 var active_instance = null;
1276 function repository_callback(id){
1277     active_instance.req(id, '', 0);
1279 var repository_client_$suffix = (function() {
1280 // private static field
1281 var dver = '1.0';
1282 // private static methods
1283 function alert_version(){
1284     alert(dver);
1286 function _client(){
1287     // public varible
1288     this.name = 'repository_client_$suffix';
1289     // private varible
1290     var Dom = YAHOO.util.Dom, Event = YAHOO.util.Event, layout = null, resize = null;
1291     var IE_QUIRKS = (YAHOO.env.ua.ie && document.compatMode == "BackCompat");
1292     var IE_SYNC = (YAHOO.env.ua.ie == 6 || (YAHOO.env.ua.ie == 7 && IE_QUIRKS));
1293     var PANEL_BODY_PADDING = (10*2);
1294     var btn_list = {label: '$strlistview', value: 'l', checked: true, onclick: {fn: _client.viewlist}};
1295     var btn_thumb = {label: '$strthumbview', value: 't', onclick: {fn: _client.viewthumb}};
1296     var repo_list = null;
1297     var resize = null;
1298     var filepicker = new YAHOO.widget.Panel('file-picker-$suffix', {
1299         draggable: true,
1300         close: true,
1301         modal: true,
1302         underlay: 'none',
1303         zindex: 666666,
1304         xy: [50, Dom.getDocumentScrollTop()+20]
1305     });
1306     // construct code section
1307     {
1308         filepicker.setHeader('$strtitle');
1309         filepicker.setBody('<div id="layout-$suffix"></div>');
1310         filepicker.beforeRenderEvent.subscribe(function() {
1311             Event.onAvailable('layout-$suffix', function() {
1312                 layout = new YAHOO.widget.Layout('layout-$suffix', {
1313                     height: 480, width: 630,
1314                     units: [
1315                         {position: 'top', height: 32, resize: false,
1316                         body:'<div class="yui-buttongroup fp-viewbar" id="repo-viewbar-$suffix"></div><div class="fp-searchbar" id="search-div-$suffix"></div>', gutter: '2'},
1317                         {position: 'left', width: 200, resize: true,
1318                         body:'<ul class="fp-list" id="repo-list-$suffix"></ul>', gutter: '0 5 0 2', minWidth: 150, maxWidth: 300 },
1319                         {position: 'center', body: '<div class="fp-panel" id="panel-$suffix"></div>',
1320                         scroll: true, gutter: '0 2 0 0' }
1321                     ]
1322                 });
1323                 layout.render();
1324             });
1325         });
1326         resize = new YAHOO.util.Resize('file-picker-$suffix', {
1327             handles: ['br'],
1328             autoRatio: true,
1329             status: true,
1330             minWidth: 380,
1331             minHeight: 400
1332         });
1333         resize.on('resize', function(args) {
1334             var panelHeight = args.height;
1335             var headerHeight = this.header.offsetHeight; // Content + Padding + Border
1336             var bodyHeight = (panelHeight - headerHeight);
1337             var bodyContentHeight = (IE_QUIRKS) ? bodyHeight : bodyHeight - PANEL_BODY_PADDING;
1338             Dom.setStyle(this.body, 'height', bodyContentHeight + 'px');
1339             if (IE_SYNC) {
1340                 this.sizeUnderlay();
1341                 this.syncIframe();
1342             }
1343             layout.set('height', bodyContentHeight);
1344             layout.set('width', (args.width - PANEL_BODY_PADDING));
1345             layout.resize();
1347         }, filepicker, true);
1348         _client.viewbar = new YAHOO.widget.ButtonGroup({
1349             id: 'btngroup-$suffix',
1350             name: 'buttons',
1351             disabled: true,
1352             container: 'repo-viewbar-$suffix'
1353             });
1354     }
1355     // public method
1356     this.show = function(){
1357         filepicker.show();
1358     }
1359     this.hide = function(){
1360         filepicker.hide();
1361     }
1362     this.create_picker = function(){
1363         // display UI
1364         filepicker.render();
1365         _client.viewbar.addButtons([btn_list, btn_thumb]);
1366         // init repository list
1367         repo_list = new YAHOO.util.Element('repo-list-$suffix');
1368         repo_list.on('contentReady', function(e){
1369             var searchbar = new YAHOO.util.Element('search-div-$suffix');
1370             searchbar.get('element').innerHTML = '<input id="search-input-$suffix" /><button id="search-btn-$suffix">$strsearch</button>';
1371             var searchbtn = new YAHOO.util.Element('search-btn-$suffix');
1372             searchbtn.callback = {
1373                 success: function(o) {
1374                     var panel = new YAHOO.util.Element('panel-$suffix');
1375                     try {
1376                         if(!o.responseText){
1377                             panel.get('element').innerHTML = 'no';
1378                             return;
1379                         }
1380                         var json = YAHOO.lang.JSON.parse(o.responseText);
1381                     } catch(e) {
1382                         alert('$strinvalidjson - '+o.responseText);
1383                     }
1384                     _client.ds = {};
1385                     if(!json.list || json.list.length<1){
1386                         panel.get('element').innerHTML = 'no';
1387                         return;
1388                     }
1389                     _client.ds.list = json.list;
1390                     if(_client.ds.list) {
1391                         if(_client.viewmode) {
1392                             _client.viewthumb();
1393                         } else {
1394                             _client.viewlist();
1395                         }
1396                         var input_ctl = new YAHOO.util.Element('search-input-$suffix');
1397                         input_ctl.get('element').value='';
1398                     }
1399                 }
1400             }
1401             searchbtn.input_ctl = new YAHOO.util.Element('search-input-$suffix');
1402             searchbtn.on('click', function(e){
1403                 var keyword = this.input_ctl.get('value');
1404                 var params = [];
1405                 params['s'] = keyword;
1406                 params['env']=_client.env;
1407                 params['action']='gsearch';
1408                 params['sesskey']='$sesskey';
1409                 params['ctx_id']=$context->id;
1410                 _client.loading('load');
1411                 var trans = YAHOO.util.Connect.asyncRequest('POST',
1412                     '$CFG->httpswwwroot/repository/ws.php?action=gsearch', this.callback, _client.postdata(params));
1413             });
1414             for(var i=0; i<_client.repos.length; i++) {
1415                 var repo = _client.repos[i];
1416                 var li = document.createElement('li');
1417                 li.id = 'repo-$suffix-'+repo.id;
1418                 var icon = document.createElement('img');
1419                 icon.src = repo.icon;
1420                 icon.width = '16';
1421                 icon.height = '16';
1422                 var link = document.createElement('a');
1423                 link.href = '###';
1424                 link.id = 'repo-call-$suffix-'+repo.id;
1425                 link.appendChild(icon);
1426                 link.className = 'fp-repo-name';
1427                 link.onclick = function(){
1428                     var re = /repo-call-$suffix-(\d+)/i;
1429                     var id = this.id.match(re);
1430                     repository_client_$suffix.req(id[1], '', 0);
1431                 }
1432                 link.innerHTML += ' '+repo.name;
1433                 li.appendChild(link);
1434                 this.appendChild(li);
1435                 repo = null;
1436             }
1437             });
1438     }
1441 // public static varible
1442 _client.repos = [];
1443 _client.repositoryid = 0;
1444 // _client.ds save all data received from server side
1445 _client.ds = null;
1446 _client.viewmode = 0;
1447 _client.viewbar =null;
1449 // public static mehtod
1450 _client.postdata = function(obj) {
1451     var str = '';
1452     for(k in obj) {
1453         if(obj[k] instanceof Array) {
1454             for(i in obj[k]) {
1455                 str += (encodeURIComponent(k) +'[]='+encodeURIComponent(obj[k][i]));
1456                 str += '&';
1457             }
1458         } else {
1459             str += encodeURIComponent(k) +'='+encodeURIComponent(obj[k]);
1460             str += '&';
1461         }
1462     }
1463     return str;
1465 _client.loading = function(type, name){
1466     var panel = new YAHOO.util.Element('panel-$suffix');
1467     panel.get('element').innerHTML = '';
1468     var content = document.createElement('div');
1469     content.style.textAlign='center';
1470     var para = document.createElement('P');
1471     var img = document.createElement('IMG');
1472     if(type=='load'){
1473     img.src = '$CFG->pixpath/i/loading.gif';
1474     para.innerHTML = '$strloading';
1475     }else{
1476     img.src = '$CFG->pixpath/i/progressbar.gif';
1477     para.innerHTML = '$strcopying <strong>'+name+'</strong>';
1478     }
1479     content.appendChild(para);
1480     content.appendChild(img);
1481     //content.innerHTML = '';
1482     panel.get('element').appendChild(content);
1484 _client.rename = function(oldname, url, icon, repo_id){
1485     var panel = new YAHOO.util.Element('panel-$suffix');
1486     var html = '<div class="fp-rename-form">';
1487     _client.repositoryid=repo_id;
1488     html += '<p><img src="'+icon+'" /></p>';
1489     html += '<p><label for="newname-$suffix">$strsaveas</label>';
1490     html += '<input type="text" id="newname-$suffix" value="'+oldname+'" /></p>';
1491     /**
1492     html += '<p><label for="syncfile-$suffix">$strsync</label> ';
1493     html += '<input type="checkbox" id="syncfile-$suffix" /></p>';
1494     */
1495     html += '<p><input type="hidden" id="fileurl-$suffix" value="'+url+'" />';
1496     html += '<a href="###" onclick="repository_client_$suffix.viewfiles()">$strback</a> ';
1497     html += '<input type="button" onclick="repository_client_$suffix.download()" value="$strdownbtn" />';
1498     html += '<input type="button" onclick="repository_client_$suffix.hide()" value="$strcancel" /></p>';
1499     html += '</div>';
1500     panel.get('element').innerHTML = html;
1502 _client.popup = function(url){
1503     active_instance = repository_client_$suffix;
1504     _client.win = window.open(url,'repo_auth', 'location=0,status=0,scrollbars=0,width=500,height=300');
1505     return false;
1507 _client.print_login = function(){
1508     var panel = new YAHOO.util.Element('panel-$suffix');
1509     var data = _client.ds.login;
1510     var str = '';
1511     for(var k in data){
1512         str += '<p>';
1513         if(data[k].type=='popup'){
1514             str += '<a href="###" onclick="repository_client_$suffix.popup(\''+data[k].url+'\')">test</a>';
1515         }else{
1516             var lable_id = '';
1517             var field_id = '';
1518             var field_value = '';
1519             if(data[k].id){
1520                 lable_id = ' for="'+data[k].id+'"';
1521                 field_id = ' id="'+data[k].id+'"';
1522             }
1523             if (data[k].label) {
1524                 str += '<label'+lable_id+'>'+data[k].label+'</label><br/>';
1525             }
1526             if(data[k].value){
1527                 field_value = ' value="'+data[k].value+'"';
1528             }
1529             str += '<input type="'+data[k].type+'"'+' name="'+data[k].name+'"'+field_id+field_value+' />';
1530         }
1531         str += '</p>';
1532     }
1533     str += '<p><input type="button" onclick="repository_client_$suffix.login()" value="$strsubmit" /></p>';
1534     panel.get('element').innerHTML = str;
1537 _client.viewfiles = function(){
1538     if(_client.viewmode) {
1539         _client.viewthumb();
1540     } else {
1541         _client.viewlist();
1542     }
1544 _client.print_header = function(){
1545     var panel = new YAHOO.util.Element('panel-$suffix');
1546     var str = '';
1547     str += '<div class="fp-toolbar" id="repo-tb-$suffix"></div>';
1548     panel.set('innerHTML', str);
1549     _client.makepath();
1551 _client.print_footer = function(){
1552     var panel = new YAHOO.util.Element('panel-$suffix');
1553     panel.get('element').innerHTML += _client.uploadcontrol();
1554     panel.get('element').innerHTML += _client.makepage();
1555     var oDiv = document.getElementById('repo-tb-$suffix');
1556     if(!_client.ds.nosearch){
1557         var search = document.createElement('A');
1558         search.href = '###';
1559         search.innerHTML = '<img src="$CFG->pixpath/a/search.png" /> $strsearch';
1560         oDiv.appendChild(search);
1561         search.onclick = function() {
1562             repository_client_$suffix.search(repository_client_$suffix.repositoryid);
1563         }
1564     }
1565     // weather we use cache for this instance, this button will reload listing anyway
1566     var ccache = document.createElement('A');
1567     ccache.href = '###';
1568     ccache.innerHTML = '<img src="$CFG->pixpath/a/refresh.png" /> $strrefresh';
1569     oDiv.appendChild(ccache);
1570     ccache.onclick = function() {
1571         var params = [];
1572         params['env']=_client.env;
1573         params['sesskey']='$sesskey';
1574         params['ctx_id']=$context->id;
1575         params['repo_id']=repository_client_$suffix.repositoryid;
1576         _client.loading('load');
1577         var trans = YAHOO.util.Connect.asyncRequest('POST',
1578             '$CFG->httpswwwroot/repository/ws.php?action=ccache', repository_client_$suffix.req_cb, _client.postdata(params));
1579     }
1580     if(_client.ds.manage){
1581         var mgr = document.createElement('A');
1582         mgr.innerHTML = '<img src="$CFG->pixpath/a/setting.png" /> $strmgr';
1583         mgr.href = _client.ds.manage;
1584         mgr.target = "_blank";
1585         oDiv.appendChild(mgr);
1586     }
1587     if(!_client.ds.nologin){
1588         var logout = document.createElement('A');
1589         logout.href = '###';
1590         logout.innerHTML = '<img src="$CFG->pixpath/a/logout.png" /> $strlogout';
1591         oDiv.appendChild(logout);
1592         logout.onclick = function() {
1593             repository_client_$suffix.req(repository_client_$suffix.repositoryid, 1, 1);
1594         }
1595     }
1597 _client.viewthumb = function(ds){
1598     _client.viewmode = 1;
1599     var panel = new YAHOO.util.Element('panel-$suffix');
1600     _client.viewbar.check(1);
1601     var list = null;
1602     var args = arguments.length;
1603     if(args == 1){
1604         list = ds;
1605     } else {
1606         // from button
1607         list = _client.ds.list;
1608     }
1609     _client.print_header();
1610     var count = 0;
1611     for(k in list){
1612         var el = document.createElement('div');
1613         el.className='fp-grid';
1614         var frame = document.createElement('DIV');
1615         frame.style.textAlign='center';
1616         var img = document.createElement('img');
1617         img.src = list[k].thumbnail;
1618         var link = document.createElement('A');
1619         link.href='###';
1620         link.id = 'img-id-'+String(count);
1621         link.appendChild(img);
1622         frame.appendChild(link);
1623         var title = document.createElement('div');
1624         if(list[k].children){
1625             title.innerHTML = '<i><u>'+list[k].title+'</i></u>';
1626         } else {
1627             if(list[k].url)
1628                 title.innerHTML = '<p><a target="_blank" href="'+list[k].url+'">$strpreview</a></p>';
1629             title.innerHTML += '<span>'+list[k].title+"</span>";
1630         }
1631         title.className = 'label';
1632         el.appendChild(frame);
1633         el.appendChild(title);
1634         panel.get('element').appendChild(el);
1635         if(list[k].children){
1636             var folder = new YAHOO.util.Element(link.id);
1637             folder.ds = list[k].children;
1638             folder.on('contentReady', function(){
1639                 this.on('click', function(){
1640                     if(_client.ds.dynload){
1641                         // TODO: get file list dymanically
1642                     }else{
1643                         _client.viewthumb(this.ds);
1644                     }
1645                 });
1646             });
1647         } else {
1648             var file = new YAHOO.util.Element(link.id);
1649             file.title = list[k].title;
1650             file.value = list[k].source;
1651             file.icon  = list[k].thumbnail;
1652             if(list[k].repo_id){
1653                 file.repo_id = list[k].repo_id;
1654             }else{
1655                 file.repo_id = _client.repositoryid;
1656             }
1657             file.on('contentReady', function(){
1658                 this.on('click', function(){
1659                     repository_client_$suffix.rename(this.title, this.value, this.icon, this.repo_id);
1660                 });
1661             });
1662         }
1663         count++;
1664     }
1665     _client.print_footer();
1667 _client.buildtree = function(node, level){
1668     if(node.children){
1669         node.title = '<i><u>'+node.title+'</u></i>';
1670     }
1671     var info = {label:node.title, title:"$strdate"+node.date+' '+'$strsize'+node.size};
1672     var tmpNode = new YAHOO.widget.TextNode(info, level, false);
1673     var tooltip = new YAHOO.widget.Tooltip(tmpNode.labelElId, {
1674         context:tmpNode.labelElId, text:info.title});
1675     if(node.repo_id){
1676         tmpNode.repo_id=node.repo_id;
1677     }else{
1678         tmpNode.repo_id=_client.repositoryid;
1679     }
1680     tmpNode.filename = node.title;
1681     tmpNode.value  = node.source;
1682     tmpNode.icon = node.thumbnail;
1683     if(node.children){
1684         tmpNode.isLeaf = false;
1685         if (node.path) {
1686             tmpNode.path = node.path;
1687         } else {
1688             tmpNode.path = '';
1689         }
1690         for(var c in node.children){
1691             _client.buildtree(node.children[c], tmpNode);
1692         }
1693     } else {
1694         tmpNode.isLeaf = true;
1695         tmpNode.onLabelClick = function() {
1696             repository_client_$suffix.rename(this.filename, this.value, this.icon, this.repo_id);
1697         }
1698     }
1700 _client.dynload = function (node, fnLoadComplete){
1701     var callback = {
1702         success: function(o) {
1703             try {
1704                 var json = YAHOO.lang.JSON.parse(o.responseText);
1705             } catch(e) {
1706                 alert('$strinvalidjson - '+o.responseText);
1707             }
1708             for(k in json.list){
1709                 _client.buildtree(json.list[k], node);
1710             }
1711             o.argument.fnLoadComplete();
1712         },
1713         failure:function(oResponse){
1714             alert('$strerror');
1715             oResponse.argument.fnLoadComplete();
1716         },
1717         argument:{"node":node, "fnLoadComplete": fnLoadComplete},
1718         timeout:600
1719     }
1720     var params = [];
1721     params['p']=node.path;
1722     params['env']=_client.env;
1723     params['sesskey']='$sesskey';
1724     params['ctx_id']=$context->id;
1725     params['repo_id']=_client.repositoryid;
1726     var trans = YAHOO.util.Connect.asyncRequest('POST',
1727         '$CFG->httpswwwroot/repository/ws.php?action=list', callback, _client.postdata(params));
1729 _client.viewlist = function(){
1730     _client.viewmode = 0;
1731     var panel = new YAHOO.util.Element('panel-$suffix');
1732     _client.viewbar.check(0);
1733     list = _client.ds.list;
1734     _client.print_header();
1735     panel.get('element').innerHTML += '<div id="treediv-$suffix"></div>';
1736     var tree = new YAHOO.widget.TreeView('treediv-$suffix');
1737     if(_client.ds.dynload) {
1738         tree.setDynamicLoad(_client.dynload, 1);
1739     } else {
1740     }
1741     for(k in list){
1742         _client.buildtree(list[k], tree.getRoot());
1743     }
1744     tree.draw();
1745     _client.print_footer();
1747 _client.upload = function(){
1748     var u = _client.ds.upload;
1749     var aform = document.getElementById(u.id);
1750     var parent = document.getElementById(u.id+'_div');
1751     var d = document.getElementById(_client.ds.upload.id+'-file');
1752     if(d.value!='' && d.value!=null){
1753         var container = document.createElement('DIV');
1754         container.id = u.id+'_loading';
1755         container.style.textAlign='center';
1756         var img = document.createElement('IMG');
1757         img.src = '$CFG->pixpath/i/progressbar.gif';
1758         var para = document.createElement('p');
1759         para.innerHTML = '$struploading';
1760         container.appendChild(para);
1761         container.appendChild(img);
1762         parent.appendChild(container);
1763         YAHOO.util.Connect.setForm(aform, true, true);
1764         var trans = YAHOO.util.Connect.asyncRequest('POST',
1765             '$CFG->httpswwwroot/repository/ws.php?action=upload&sesskey=$sesskey&ctx_id=$context->id&repo_id='
1766                 +_client.repositoryid,
1767             _client.upload_cb);
1768     }else{
1769         alert('$strfilenotnull');
1770     }
1772 _client.upload_cb = {
1773     upload: function(o){
1774         try {
1775             var ret = YAHOO.lang.JSON.parse(o.responseText);
1776         } catch(e) {
1777             alert('$strinvalidjson - '+o.responseText);
1778         }
1779         if(ret && ret.e){
1780             var panel = new YAHOO.util.Element('panel-$suffix');
1781             panel.get('element').innerHTML = ret.e;
1782             return;
1783         }
1784         if(ret){
1785             alert('$strsaved');
1786             repository_client_$suffix.end(ret);
1787         }else{
1788             alert('$strinvalidjson');
1789         }
1790     }
1792 _client.uploadcontrol = function() {
1793     var str = '';
1794     if(_client.ds.upload){
1795         str += '<div id="'+_client.ds.upload.id+'_div" class="fp-upload-form">';
1796         str += '<form id="'+_client.ds.upload.id+'" onsubmit="return false">';
1797         str += '<label for="'+_client.ds.upload.id+'-file">'+_client.ds.upload.label+'</label>';
1798         str += '<input type="file" id="'+_client.ds.upload.id+'-file" name="repo_upload_file" />';
1799         str += '<p class="fp-upload-btn"><a href="###" onclick="return repository_client_$suffix.upload();">$strupload</a></p>';
1800         str += '</form>';
1801         str += '</div>';
1802     }
1803     return str;
1805 _client.makepage = function(){
1806     var str = '';
1807     if(_client.ds.pages){
1808         str += '<div class="fp-paging" id="paging-$suffix">';
1809         for(var i = 1; i <= _client.ds.pages; i++) {
1810             str += '<a onclick="repository_client_$suffix.req('+_client.repositoryid+', '+i+', 0)" href="###">';
1811             str += String(i);
1812             str += '</a> ';
1813         }
1814         str += '</div>';
1815     }
1816     return str;
1818 _client.makepath = function(){
1819     if(_client.viewmode == 0) {
1820         return;
1821     }
1822     var panel = new YAHOO.util.Element('panel-$suffix');
1823     var p = _client.ds.path;
1824     if(p && p.length!=0){
1825         var oDiv = document.createElement('DIV');
1826         oDiv.id = "path-$suffix";
1827         oDiv.className = "fp-pathbar";
1828         panel.get('element').appendChild(oDiv);
1829         for(var i = 0; i < _client.ds.path.length; i++) {
1830             var link = document.createElement('A');
1831             link.href = "###";
1832             link.innerHTML = _client.ds.path[i].name;
1833             link.id = 'path-'+i+'-el';
1834             var sep = document.createElement('SPAN');
1835             sep.innerHTML = '/';
1836             oDiv.appendChild(link);
1837             oDiv.appendChild(sep);
1838             var el = new YAHOO.util.Element(link.id);
1839             el.id = _client.repositoryid;
1840             el.path = _client.ds.path[i].path;
1841             el.on('contentReady', function(){
1842                 this.on('click', function(){
1843                     repository_client_$suffix.req(this.id, this.path, 0);
1844                 })
1845             });
1846         }
1847     }
1849 // send download request
1850 _client.download = function(){
1851     var title = document.getElementById('newname-$suffix').value;
1852     var file = document.getElementById('fileurl-$suffix').value;
1853     _client.loading('download', title);
1854     var params = [];
1855     params['env']=_client.env;
1856     params['file']=file;
1857     params['title']=title;
1858     params['sesskey']='$sesskey';
1859     params['ctx_id']=$context->id;
1860     params['repo_id']=_client.repositoryid;
1861     var trans = YAHOO.util.Connect.asyncRequest('POST',
1862         '$CFG->httpswwwroot/repository/ws.php?action=download', _client.download_cb, _client.postdata(params));
1864 // send login request
1865 _client.login = function(){
1866     var params = [];
1867     var data = _client.ds.login;
1868     for (var k in data) {
1869         if(data[k].type!='popup'){
1870             var el = document.getElementsByName(data[k].name)[0];
1871             params[data[k].name] = '';
1872             if(el.type == 'checkbox') {
1873                 params[data[k].name] = el.checked;
1874             } else {
1875                 params[data[k].name] = el.value;
1876             }
1877         }
1878     }
1879     params['env'] = _client.env;
1880     params['ctx_id'] = $context->id;
1881     params['sesskey']= '$sesskey';
1882     _client.loading('load');
1883     var trans = YAHOO.util.Connect.asyncRequest('POST',
1884         '$CFG->httpswwwroot/repository/ws.php?action=sign', _client.req_cb, _client.postdata(params));
1886 _client.end = function(str){
1887     if(_client.env=='form'){
1888         _client.target.value = str['id'];
1889     }else{
1890         _client.target.value = str['url'];
1891         _client.target.onchange();
1892     }
1893     _client.formcallback(str['file']);
1894     _client.instance.hide();
1895     _client.viewfiles();
1897 _client.hide = function(){
1898     _client.instance.hide();
1899     _client.viewfiles();
1901 // request file list or login
1902 _client.req = function(id, path, reset) {
1903     _client.viewbar.set('disabled', false);
1904     _client.loading('load');
1905     _client.repositoryid = id;
1906     if (reset == 1) {
1907         action = 'logout';
1908     } else {
1909         action = 'list';
1910     }
1911     var params = [];
1912     params['p'] = path;
1913     params['reset']=reset;
1914     params['env']=_client.env;
1915     params['action']=action;
1916     params['sesskey']='$sesskey';
1917     params['ctx_id']=$context->id;
1918     params['repo_id']=id;
1919     var trans = YAHOO.util.Connect.asyncRequest('POST', '$CFG->httpswwwroot/repository/ws.php?action='+action, _client.req_cb, _client.postdata(params));
1921 _client.search = function(id){
1922     var data = window.prompt("$strsearching");
1923     if(data == '') {
1924         alert('$strnoenter');
1925         return;
1926     }else if(data == null){
1927         return;
1928     }
1929     _client.viewbar.set('disabled', false);
1930     _client.loading('load');
1931     var params = [];
1932     params['s']=data;
1933     params['env']=_client.env;
1934     params['sesskey']='$sesskey';
1935     params['ctx_id']=$context->id;
1936     params['repo_id']=id;
1937     var trans = YAHOO.util.Connect.asyncRequest('POST', '$CFG->httpswwwroot/repository/ws.php?action=search', _client.req_cb, _client.postdata(params));
1939 _client.req_cb = {
1940     success: function(o) {
1941         var panel = new YAHOO.util.Element('panel-$suffix');
1942         try {
1943             var ret = YAHOO.lang.JSON.parse(o.responseText);
1944         } catch(e) {
1945             alert('$strinvalidjson - '+o.responseText);
1946         };
1947         if(ret && ret.e){
1948             panel.get('element').innerHTML = ret.e;
1949             return;
1950         }
1951         _client.ds = ret;
1952         if(!_client.ds){
1953             return;
1954         }else if(_client.ds && _client.ds.login){
1955             _client.print_login();
1956         } else if(_client.ds.list) {
1957             if(_client.viewmode) {
1958                 _client.viewthumb();
1959             } else {
1960                 _client.viewlist();
1961             }
1962         }
1963     }
1965 _client.download_cb = {
1966     success: function(o) {
1967         var panel = new YAHOO.util.Element('panel-$suffix');
1968         try {
1969             var ret = YAHOO.lang.JSON.parse(o.responseText);
1970         } catch(e) {
1971             alert('$strinvalidjson - '+o.responseText);
1972         }
1973         if(ret && ret.e){
1974             panel.get('element').innerHTML = ret.e;
1975             return;
1976         }
1977         if(ret){
1978             repository_client_$suffix.end(ret);
1979         }else{
1980             alert('$strinvalidjson');
1981         }
1982     }
1985 return _client;
1986 })();
1987 EOD;
1989     $repos = repository_get_instances(array($context,get_system_context()));
1990     foreach($repos as $repo) {
1991         $js .= "\r\n";
1992         $js .= 'repository_client_'.$suffix.'.repos.push('.json_encode($repo->ajax_info()).');'."\n";
1993     }
1994     $js .= "\r\n";
1996     $js .= <<<EOD
1997 function openpicker_$suffix(params) {
1998     if(!repository_client_$suffix.instance) {
1999         repository_client_$suffix.env = params.env;
2000         repository_client_$suffix.target = params.target;
2001         if(params.type){
2002             repository_client_$suffix.filetype = params.filetype;
2003         } else {
2004             repository_client_$suffix.filetype = 'all';
2005         }
2006         repository_client_$suffix.instance = new repository_client_$suffix();
2007         repository_client_$suffix.instance.create_picker();
2008         if(params.callback){
2009             repository_client_$suffix.formcallback = params.callback;
2010         } else {
2011             repository_client_$suffix.formcallback = function(){};
2012         }
2013     } else {
2014         repository_client_$suffix.instance.show();
2015     }
2017 //]]>
2018 </script>
2019 EOD;
2020     return array('css'=>$css, 'js'=>$js, 'suffix'=>$suffix);
2023 /**
2024  * TODO: write comment
2025  */
2026 final class repository_instance_form extends moodleform {
2027     protected $instance;
2028     protected $plugin;
2030     /**
2031      * TODO: write comment
2032      * @global <type> $CFG
2033      */
2034     public function definition() {
2035         global $CFG;
2036         // type of plugin, string
2037         $this->plugin = $this->_customdata['plugin'];
2038         $this->typeid = $this->_customdata['typeid'];
2039         $this->contextid = $this->_customdata['contextid'];
2040         $this->instance = (isset($this->_customdata['instance'])
2041                 && is_subclass_of($this->_customdata['instance'], 'repository'))
2042             ? $this->_customdata['instance'] : null;
2044         $mform =& $this->_form;
2045         $strrequired = get_string('required');
2047         $mform->addElement('hidden', 'edit',  ($this->instance) ? $this->instance->id : 0);
2048         $mform->addElement('hidden', 'new',   $this->plugin);
2049         $mform->addElement('hidden', 'plugin', $this->plugin);
2050         $mform->addElement('hidden', 'typeid', $this->typeid);
2051         $mform->addElement('hidden', 'contextid', $this->contextid);
2053         $mform->addElement('text', 'name', get_string('name'), 'maxlength="100" size="30"');
2054         $mform->addRule('name', $strrequired, 'required', null, 'client');
2056         // let the plugin add the fields they want (either statically or not)
2057         if (repository_static_function($this->plugin, 'has_instance_config')) {
2058             if (!$this->instance) {
2059                 $result = repository_static_function($this->plugin, 'instance_config_form', $mform);
2060             } else {
2061                 $result = $this->instance->instance_config_form($mform);
2062             }
2063         }
2065         // and set the data if we have some.
2066         if ($this->instance) {
2067             $data = array();
2068             $data['name'] = $this->instance->name;
2069             foreach ($this->instance->get_instance_option_names() as $config) {
2070                 if (!empty($this->instance->$config)) {
2071                     $data[$config] = $this->instance->$config;
2072                 } else {
2073                     $data[$config] = '';
2074                 }
2075             }
2076             $this->set_data($data);
2077         }
2078         $this->add_action_buttons(true, get_string('save','repository'));
2079     }
2081     /**
2082      * TODO: write comment
2083      * @global <type> $DB
2084      * @param <type> $data
2085      * @return <type>
2086      */
2087     public function validation($data) {
2088         global $DB;
2090         $errors = array();
2091         if ($DB->count_records('repository_instances', array('name' => $data['name'], 'typeid' => $data['typeid'])) > 1) {
2092             $errors = array('name' => get_string('err_uniquename', 'repository'));
2093         }
2095         $pluginerrors = array();
2096         if ($this->instance) {
2097             //$pluginerrors = $this->instance->admin_config_validation($data);
2098         } else {
2099             //$pluginerrors = repository_static_function($this->plugin, 'admin_config_validation', $data);
2100         }
2101         if (is_array($pluginerrors)) {
2102             $errors = array_merge($errors, $pluginerrors);
2103         }
2104         return $errors;
2105     }
2109 /**
2110  * Display a form with the general option fields of a type
2111  */
2112 final class repository_admin_form extends moodleform {
2113     protected $instance;
2114     protected $plugin;
2116     /**
2117      * Definition of the moodleform
2118      * @global object $CFG
2119      */
2120     public function definition() {
2121         global $CFG;
2122         // type of plugin, string
2123         $this->plugin = $this->_customdata['plugin'];
2124         $this->instance = (isset($this->_customdata['instance'])
2125                 && is_a($this->_customdata['instance'], 'repository_type'))
2126             ? $this->_customdata['instance'] : null;
2128         $mform =& $this->_form;
2129         $strrequired = get_string('required');
2131         $mform->addElement('hidden', 'edit',  ($this->instance) ? $this->instance->get_typename() : 0);
2132         $mform->addElement('hidden', 'new',   $this->plugin);
2133         $mform->addElement('hidden', 'plugin', $this->plugin);
2134         // let the plugin add the fields they want (either statically or not)
2135         if (repository_static_function($this->plugin, 'has_admin_config')) {
2136             if (!$this->instance) {
2137                 $result = repository_static_function($this->plugin, 'admin_config_form', $mform);
2138             } else {
2139                   $classname = 'repository_' . $this->instance->get_typename();
2140                   $result = call_user_func(array($classname,'admin_config_form'),$mform);
2141             }
2142         }
2144         // and set the data if we have some.
2145         if ($this->instance) {
2146             $data = array();
2147             $option_names = call_user_func(array($classname,'get_admin_option_names'));
2148             $instanceoptions = $this->instance->get_options();
2149             foreach ($option_names as $config) {
2150                 if (!empty($instanceoptions[$config])) {
2151                     $data[$config] = $instanceoptions[$config];
2152                 } else {
2153                     $data[$config] = '';
2154                 }
2155             }
2156             $this->set_data($data);
2157         }
2158         $this->add_action_buttons(true, get_string('save','repository'));
2159     }
2164 /**
2165  * Display a repository instance list (with edit/delete/create links)
2166  * @global object $CFG
2167  * @global object $USER
2168  * @param object $context the context for which we display the instance
2169  * @param string $typename if set, we display only one type of instance
2170  */
2171 function repository_display_instances_list($context, $typename = null){
2172        global $CFG, $USER;
2174         $output = print_box_start('generalbox','',true);
2175         //if the context is SYSTEM, so we call it from administration page
2176         $admin = ($context->id == SYSCONTEXTID) ? true : false;
2177         if($admin) {
2178             $baseurl = $CFG->httpswwwroot . '/admin/repositoryinstance.php?sesskey=' . sesskey();
2179              $output .= "<div ><h2 style='text-align: center'>" . get_string('siteinstances', 'repository') . " ";
2180              $output .= "</h2></div>";
2181         } else {
2182           $baseurl = $CFG->httpswwwroot . '/repository/manage_instances.php?contextid=' . $context->id . '&amp;sesskey=' . sesskey();
2184         }
2186         $namestr = get_string('name');
2187         $pluginstr = get_string('plugin', 'repository');
2188         $settingsstr = get_string('settings');
2189         $deletestr = get_string('delete');
2190         $updown = get_string('updown', 'repository');
2191         $plugins = get_list_of_plugins('repository');
2192         //retrieve list of instances. In administration context we want to display all
2193         //instances of a type, even if this type is not visible. In course/user context we
2194         //want to display only visible instances, but for every type types. The repository_get_instances()
2195         //third parameter displays only visible type.
2196         $instances = repository_get_instances(array($context),null,!$admin,$typename);
2197         $instancesnumber = count($instances);
2198         $alreadyplugins = array();
2199         $table = new StdClass;
2200         $table->head = array($namestr, $pluginstr, $deletestr, $settingsstr);
2201         $table->align = array('left', 'left', 'center','center');
2202         $table->data = array();
2203         $updowncount=1;
2204         foreach ($instances as $i) {
2205             $settings = '';
2206             $settings .= '<a href="' . $baseurl . '&amp;type='.$typename.'&amp;edit=' . $i->id . '">' . $settingsstr . '</a>' . "\n";
2207             $delete = '<a href="' . $baseurl . '&amp;type='.$typename.'&amp;delete=' .  $i->id . '">' . $deletestr . '</a>' . "\n";
2209             $type = repository_get_type_by_id($i->typeid);
2210             $table->data[] = array($i->name, $type->get_readablename(), $delete, $settings);
2212             //display a grey row if the type is defined as not visible
2213             if (isset($type) && !$type->get_visible()){
2214                 $table->rowclass[] = 'dimmed_text';
2215             } else{
2216                 $table->rowclass[] = '';
2217             }
2219             if (!in_array($i->name, $alreadyplugins)) {
2220                 $alreadyplugins[] = $i->name;
2221             }
2222         }
2223         $output .= print_table($table, true);
2224         $instancehtml = '<div>';
2225         $addable = 0;
2227         //if no type is set, we can create all type of instance
2228         if (!$typename) {
2229             $instancehtml .= '<h3>';
2230             $instancehtml .= get_string('createrepository', 'repository');
2231             $instancehtml .= '</h3><ul>';
2232             foreach ($plugins as $p) {
2233                    $type = repository_get_type_by_typename($p);
2234                    if (!empty($type) && $type->get_visible()) {
2235                        if (repository_static_function($p, 'has_multiple_instances')){
2236                             $instancehtml .= '<li><a href="'.$baseurl.'&amp;new='.$p.'">'.get_string('create', 'repository')
2237                                 .' "'.get_string('repositoryname', 'repository_'.$p).'" '
2238                                 .get_string('instance', 'repository').'</a></li>';
2239                             $addable++;
2240                         }
2241                    }
2242             }
2243              $instancehtml .= '</ul>';
2244         }
2245         //create a unique type of instance
2246         else {
2247             if (repository_static_function($typename, 'has_multiple_instances')){
2248                 $addable = 1;
2249                 $instancehtml .= "<form action='".$baseurl."&amp;new=".$typename."' method='post'>
2250                                   <p style='text-align:center'><input type='submit' value='".get_string('createinstance', 'repository')."'/></p>
2251                                   </form>";
2252             }
2253         }
2255         if ($addable) {
2256             $instancehtml .= '</div>';
2257             $output .= $instancehtml;
2258         }
2260         $output .= print_box_end(true);
2262         //print the list + creation links
2263         print($output);