random question editing: Don't show permission information when editing a random...
[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');
9bdd9eee 42require_once(dirname(dirname(__FILE__)) . '/lib/filelib.php');
43require_once(dirname(dirname(__FILE__)) . '/lib/formslib.php');
44// File picker javascript code
45require_once(dirname(dirname(__FILE__)) . '/repository/javascript.php');
1cf56396 46
a6600395 47/**
48 * A repository_type is a repository plug-in. It can be Box.net, Flick-r, ...
49 * A repository type can be edited, sorted and hidden. It is mandatory for an
50 * administrator to create a repository type in order to be able to create
51 * some instances of this type.
52 *
53 * Coding note:
54 * - a repository_type object is mapped to the "repository" database table
55 * - "typename" attibut maps the "type" database field. It is unique.
56 * - general "options" for a repository type are saved in the config_plugin table
eb239694 57 * - when you delete a repository, all instances are deleted, and general
58 * options are also deleted from database
a6600395 59 * - When you create a type for a plugin that can't have multiple instances, a
60 * instance is automatically created.
61 */
62class repository_type {
63
64
65 /**
66 * Type name (no whitespace) - A type name is unique
67 * Note: for a user-friendly type name see get_readablename()
68 * @var String
69 */
70 private $_typename;
71
72
73 /**
74 * Options of this type
75 * They are general options that any instance of this type would share
76 * e.g. API key
77 * These options are saved in config_plugin table
78 * @var array
79 */
7a3b93c1 80 private $_options;
a6600395 81
82
83 /**
84 * Is the repository type visible or hidden
85 * If false (hidden): no instances can be created, edited, deleted, showned , used...
86 * @var boolean
87 */
7a3b93c1 88 private $_visible;
a6600395 89
90
91 /**
92 * 0 => not ordered, 1 => first position, 2 => second position...
93 * A not order type would appear in first position (should never happened)
94 * @var integer
95 */
96 private $_sortorder;
97
f48fb4d6 98 /**
99 * Return if the instance is visible in a context
100 * TODO: check if the context visibility has been overwritten by the plugin creator
101 * (need to create special functions to be overvwritten in repository class)
102 * @param objet $contextlevel - context level
103 * @return boolean
104 */
105 public function get_contextvisibility($contextlevel) {
106
107 if ($contextlevel == CONTEXT_COURSE) {
108 return $this->_options['enablecourseinstances'];
109 }
110
111 if ($contextlevel == CONTEXT_USER) {
112 return $this->_options['enableuserinstances'];
113 }
114
115 //the context is SITE
116 return true;
117 }
118
119
120
a6600395 121 /**
122 * repository_type constructor
123 * @global <type> $CFG
124 * @param integer $typename
125 * @param array $typeoptions
126 * @param boolean $visible
127 * @param integer $sortorder (don't really need set, it will be during create() call)
128 */
7a3b93c1 129 public function __construct($typename = '', $typeoptions = array(), $visible = false, $sortorder = 0) {
a6600395 130 global $CFG;
131
132 //set type attributs
133 $this->_typename = $typename;
134 $this->_visible = $visible;
135 $this->_sortorder = $sortorder;
46dd6bb0 136
a6600395 137 //set options attribut
138 $this->_options = array();
1b79955a 139 $options = repository_static_function($typename,'get_type_option_names');
a6600395 140 //check that the type can be setup
06e65e1e 141 if (!empty($options)) {
a6600395 142 //set the type options
143 foreach ($options as $config) {
7a3b93c1 144 if (array_key_exists($config,$typeoptions)) {
145 $this->_options[$config] = $typeoptions[$config];
a6600395 146 }
147 }
148 }
f48fb4d6 149
150 //retrieve visibility from option
151 if (array_key_exists('enablecourseinstances',$typeoptions)) {
152 $this->_options['enablecourseinstances'] = $typeoptions['enablecourseinstances'];
9f7c761a 153 } else {
154 $this->_options['enablecourseinstances'] = 0;
f48fb4d6 155 }
156
157 if (array_key_exists('enableuserinstances',$typeoptions)) {
158 $this->_options['enableuserinstances'] = $typeoptions['enableuserinstances'];
9f7c761a 159 } else {
160 $this->_options['enableuserinstances'] = 0;
f48fb4d6 161 }
162
a6600395 163 }
164
165 /**
166 * Get the type name (no whitespace)
167 * For a human readable name, use get_readablename()
168 * @return String the type name
169 */
7a3b93c1 170 public function get_typename() {
a6600395 171 return $this->_typename;
172 }
173
174 /**
175 * Return a human readable and user-friendly type name
176 * @return string user-friendly type name
177 */
7a3b93c1 178 public function get_readablename() {
a6600395 179 return get_string('repositoryname','repository_'.$this->_typename);
180 }
181
182 /**
183 * Return general options
184 * @return array the general options
185 */
7a3b93c1 186 public function get_options() {
a6600395 187 return $this->_options;
188 }
189
190 /**
191 * Return visibility
192 * @return boolean
193 */
7a3b93c1 194 public function get_visible() {
a6600395 195 return $this->_visible;
196 }
197
198 /**
199 * Return order / position of display in the file picker
200 * @return integer
201 */
7a3b93c1 202 public function get_sortorder() {
a6600395 203 return $this->_sortorder;
204 }
205
206 /**
207 * Create a repository type (the type name must not already exist)
208 * @global object $DB
209 */
7a3b93c1 210 public function create() {
a6600395 211 global $DB;
212
213 //check that $type has been set
214 $timmedtype = trim($this->_typename);
215 if (empty($timmedtype)) {
7a3b93c1 216 throw new repository_exception('emptytype', 'repository');
a6600395 217 }
218
219 //set sortorder as the last position in the list
7a3b93c1 220 if (!isset($this->_sortorder) || $this->_sortorder == 0 ) {
a6600395 221 $sql = "SELECT MAX(sortorder) FROM {repository}";
222 $this->_sortorder = 1 + $DB->get_field_sql($sql);
223 }
224
225 //only create a new type if it doesn't already exist
226 $existingtype = $DB->get_record('repository', array('type'=>$this->_typename));
7a3b93c1 227 if (!$existingtype) {
228 //create the type
229 $newtype = new stdclass;
230 $newtype->type = $this->_typename;
231 $newtype->visible = $this->_visible;
232 $newtype->sortorder = $this->_sortorder;
233 $DB->insert_record('repository', $newtype);
234
235 //save the options in DB
236 $this->update_options();
237
edb50637 238 //if the plugin type has no multiple instance (e.g. has no instance option name) so it wont
7a3b93c1 239 //be possible for the administrator to create a instance
240 //in this case we need to create an instance
edb50637 241 $instanceoptionnames = repository_static_function($this->_typename, 'get_instance_option_names');
242 if (empty($instanceoptionnames)) {
7a3b93c1 243 $instanceoptions = array();
244 $instanceoptions['name'] = $this->_typename;
245 repository_static_function($this->_typename, 'create', $this->_typename, 0, get_system_context(), $instanceoptions);
246 }
948c2860 247
248 //run init function
3e0794ed 249 if (!repository_static_function($this->_typename, 'plugin_init')) {
250 throw new repository_exception('cannotcreatetype', 'repository');
251 }
948c2860 252
7a3b93c1 253 } else {
a6600395 254 throw new repository_exception('existingrepository', 'repository');
255 }
256 }
257
258
259 /**
260 * Update plugin options into the config_plugin table
261 * @param array $options
262 * @return boolean
263 */
7a3b93c1 264 public function update_options($options = null) {
265 if (!empty($options)) {
a6600395 266 $this->_options = $options;
267 }
268
269 foreach ($this->_options as $name => $value) {
270 set_config($name,$value,$this->_typename);
271 }
272
273 return true;
274 }
275
276 /**
277 * Update visible database field with the value given as parameter
278 * or with the visible value of this object
279 * This function is private.
280 * For public access, have a look to switch_and_update_visibility()
281 * @global object $DB
282 * @param boolean $visible
283 * @return boolean
284 */
7a3b93c1 285 private function update_visible($visible = null) {
a6600395 286 global $DB;
287
7a3b93c1 288 if (!empty($visible)) {
a6600395 289 $this->_visible = $visible;
290 }
7a3b93c1 291 else if (!isset($this->_visible)) {
a6600395 292 throw new repository_exception('updateemptyvisible', 'repository');
293 }
294
295 return $DB->set_field('repository', 'visible', $this->_visible, array('type'=>$this->_typename));
296 }
297
298 /**
299 * Update database sortorder field with the value given as parameter
300 * or with the sortorder value of this object
301 * This function is private.
302 * For public access, have a look to move_order()
303 * @global object $DB
304 * @param integer $sortorder
305 * @return boolean
306 */
7a3b93c1 307 private function update_sortorder($sortorder = null) {
a6600395 308 global $DB;
309
7a3b93c1 310 if (!empty($sortorder) && $sortorder!=0) {
a6600395 311 $this->_sortorder = $sortorder;
312 }
313 //if sortorder is not set, we set it as the ;ast position in the list
7a3b93c1 314 else if (!isset($this->_sortorder) || $this->_sortorder == 0 ) {
a6600395 315 $sql = "SELECT MAX(sortorder) FROM {repository}";
316 $this->_sortorder = 1 + $DB->get_field_sql($sql);
317 }
318
319 return $DB->set_field('repository', 'sortorder', $this->_sortorder, array('type'=>$this->_typename));
320 }
321
322 /**
323 * Change order of the type with its adjacent upper or downer type
324 * (database fields are updated)
325 * Algorithm details:
326 * 1. retrieve all types in an array. This array is sorted by sortorder,
327 * and the array keys start from 0 to X (incremented by 1)
328 * 2. switch sortorder values of this type and its adjacent type
329 * @global object $DB
330 * @param string $move "up" or "down"
331 */
332 public function move_order($move) {
333 global $DB;
a6600395 334
7a3b93c1 335 $types = repository_get_types(); // retrieve all types
336
337 /// retrieve this type into the returned array
338 $i = 0;
339 while (!isset($indice) && $i<count($types)) {
340 if ($types[$i]->get_typename() == $this->_typename) {
a6600395 341 $indice = $i;
342 }
343 $i++;
344 }
345
7a3b93c1 346 /// retrieve adjacent indice
a6600395 347 switch ($move) {
348 case "up":
349 $adjacentindice = $indice - 1;
7a3b93c1 350 break;
a6600395 351 case "down":
352 $adjacentindice = $indice + 1;
7a3b93c1 353 break;
a6600395 354 default:
7a3b93c1 355 throw new repository_exception('movenotdefined', 'repository');
a6600395 356 }
357
358 //switch sortorder of this type and the adjacent type
359 //TODO: we could reset sortorder for all types. This is not as good in performance term, but
360 //that prevent from wrong behaviour on a screwed database. As performance are not important in this particular case
361 //it worth to change the algo.
7a3b93c1 362 if ($adjacentindice>=0 && !empty($types[$adjacentindice])) {
a6600395 363 $DB->set_field('repository', 'sortorder', $this->_sortorder, array('type'=>$types[$adjacentindice]->get_typename()));
364 $this->update_sortorder($types[$adjacentindice]->get_sortorder());
365 }
366 }
367
368 /**
369 * 1. Switch the visibility OFF if it's ON, and ON if it's OFF.
370 * 2. Update the type
371 * @return <type>
372 */
7a3b93c1 373 public function switch_and_update_visibility() {
a6600395 374 $this->_visible = !$this->_visible;
375 return $this->update_visible();
376 }
377
378
379 /**
eb239694 380 * Delete a repository_type (general options are removed from config_plugin
381 * table, and all instances are deleted)
a6600395 382 * @global object $DB
383 * @return boolean
384 */
7a3b93c1 385 public function delete() {
a6600395 386 global $DB;
46dd6bb0 387
388 //delete all instances of this type
12c79bfd 389 $instances = repository_get_instances(array(),null,false,$this->_typename);
7a3b93c1 390 foreach ($instances as $instance) {
46dd6bb0 391 $instance->delete();
392 }
393
eb239694 394 //delete all general options
7a3b93c1 395 foreach ($this->_options as $name => $value) {
eb239694 396 set_config($name, null, $this->_typename);
397 }
398
a6600395 399 return $DB->delete_records('repository', array('type' => $this->_typename));
400 }
401}
402
403/**
404 * Return a type for a given type name.
405 * @global object $DB
406 * @param string $typename the type name
407 * @return integer
408 */
7a3b93c1 409function repository_get_type_by_typename($typename) {
a6600395 410 global $DB;
411
7a3b93c1 412 if (!$record = $DB->get_record('repository',array('type' => $typename))) {
a6600395 413 return false;
414 }
415
416 return new repository_type($typename, (array)get_config($typename), $record->visible, $record->sortorder);
417}
418
419/**
420 * Return a type for a given type id.
421 * @global object $DB
422 * @param string $typename the type name
423 * @return integer
424 */
7a3b93c1 425function repository_get_type_by_id($id) {
a6600395 426 global $DB;
427
7a3b93c1 428 if (!$record = $DB->get_record('repository',array('id' => $id))) {
a6600395 429 return false;
430 }
431
432 return new repository_type($record->type, (array)get_config($record->type), $record->visible, $record->sortorder);
433}
434
435/**
436 * Return all repository types ordered by sortorder
437 * first type in returnedarray[0], second type in returnedarray[1], ...
438 * @global object $DB
bbcd4860 439 * @param boolean $visible can return types by visiblity, return all types if null
a6600395 440 * @return array Repository types
441 */
7a3b93c1 442function repository_get_types($visible=null) {
a6600395 443 global $DB;
444
445 $types = array();
bbcd4860 446 $params = null;
447 if (!empty($visible)) {
448 $params = array('visible' => $visible);
449 }
7a3b93c1 450 if ($records = $DB->get_records('repository',$params,'sortorder')) {
a6600395 451 foreach($records as $type) {
46dd6bb0 452 $types[] = new repository_type($type->type, (array)get_config($type->type), $type->visible, $type->sortorder);
a6600395 453 }
454 }
455
456 return $types;
457}
458
459/**
8d419e59 460 * This is the base class of the repository class
461 *
462 * To use repository plugin, see:
463 * http://docs.moodle.org/en/Development:Repository_How_to_Create_Plugin
464 *
465 * class repository is an abstract class, some functions must be implemented in subclass.
466 *
467 * See an example: repository/boxnet/repository.class.php
468 *
469 * A few notes:
470 * // for ajax file picker, this will print a json string to tell file picker
471 * // how to build a login form
472 * $repo->print_login();
473 * // for ajax file picker, this will return a files list.
474 * $repo->get_listing();
475 * // this function will be used for non-javascript version.
476 * $repo->print_listing();
477 * // print a search box
478 * $repo->print_search();
479 *
480 * @package repository
481 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
a6600395 482 */
fca079c5 483abstract class repository {
efe018b4 484 // $disabled can be set to true to disable a plugin by force
485 // example: self::$disabled = true
486 public $disabled = false;
4a65c39a 487 public $id;
488 public $context;
489 public $options;
948c2860 490 public $readonly;
1cf56396 491
492 /**
3f24ea1e 493 * 1. Initialize context and options
494 * 2. Accept necessary parameters
495 *
8dcd5deb 496 * @param integer $repositoryid
497 * @param integer $contextid
498 * @param array $options
1cf56396 499 */
948c2860 500 public function __construct($repositoryid, $contextid = SITEID, $options = array(), $readonly = 0) {
4a65c39a 501 $this->id = $repositoryid;
502 $this->context = get_context_instance_by_id($contextid);
948c2860 503 $this->readonly = $readonly;
4a65c39a 504 $this->options = array();
fca079c5 505 if (is_array($options)) {
4a65c39a 506 $options = array_merge($this->get_option(), $options);
507 } else {
508 $options = $this->get_option();
509 }
b1339e98 510 $this->options = array();
4a65c39a 511 foreach ($options as $n => $v) {
512 $this->options[$n] = $v;
82669dc4 513 }
d31af46a 514 $this->name = $this->get_name();
1cf56396 515 }
516
8dcd5deb 517 /**
3f24ea1e 518 * set options for repository instance
519 *
8dcd5deb 520 * @param string $name
3f24ea1e 521 * @param mixed $value
8dcd5deb 522 */
fca079c5 523 public function __set($name, $value) {
82669dc4 524 $this->options[$name] = $value;
525 }
1cf56396 526
8dcd5deb 527 /**
3f24ea1e 528 * get options for repository instance
529 *
530 * @param string $name
531 * @return mixed
8dcd5deb 532 */
fca079c5 533 public function __get($name) {
7a3b93c1 534 if (array_key_exists($name, $this->options)) {
82669dc4 535 return $this->options[$name];
536 }
537 trigger_error('Undefined property: '.$name, E_USER_NOTICE);
538 return null;
539 }
1cf56396 540
8dcd5deb 541 /**
3f24ea1e 542 * test option name
543 *
544 * @param string name
8dcd5deb 545 */
fca079c5 546 public function __isset($name) {
82669dc4 547 return isset($this->options[$name]);
1cf56396 548 }
549
8dcd5deb 550 /**
3f24ea1e 551 * Return the name of the repository class
8dcd5deb 552 * @return <type>
553 */
fca079c5 554 public function __toString() {
82669dc4 555 return 'Repository class: '.__CLASS__;
556 }
4a65c39a 557
c425472d 558 /**
66dc47bc 559 * Download a file, this function can be overridden by
560 * subclass.
3f24ea1e 561 *
8dcd5deb 562 * @global object $CFG
c425472d 563 * @param string $url the url of file
564 * @param string $file save location
3f24ea1e 565 * @return string the location of the file
b1339e98 566 * @see curl package
c425472d 567 */
bb2c046d 568 public function get_file($url, $file = '') {
c425472d 569 global $CFG;
c9260130 570 if (!file_exists($CFG->dataroot.'/temp/download')) {
571 mkdir($CFG->dataroot.'/temp/download/', 0777, true);
1e28c767 572 }
7a3b93c1 573 if (is_dir($CFG->dataroot.'/temp/download')) {
c9260130 574 $dir = $CFG->dataroot.'/temp/download/';
1e28c767 575 }
7a3b93c1 576 if (empty($file)) {
84df43de 577 $file = uniqid('repo').'_'.time().'.tmp';
578 }
7a3b93c1 579 if (file_exists($dir.$file)) {
84df43de 580 $file = uniqid('m').$file;
c425472d 581 }
84df43de 582 $fp = fopen($dir.$file, 'w');
583 $c = new curl;
584 $c->download(array(
7a3b93c1 585 array('url'=>$url, 'file'=>$fp)
586 ));
84df43de 587 return $dir.$file;
82669dc4 588 }
1cf56396 589
1cf56396 590 /**
66dc47bc 591 * Print a list or return formatted string, can be overridden by subclass
82669dc4 592 *
593 * @param string $list
3f24ea1e 594 * @param boolean $print false, return html, otherwise, print it directly
8dcd5deb 595 * @return <type>
596 */
fca079c5 597 public function print_listing($listing = array(), $print=true) {
7a3b93c1 598 if (empty($listing)) {
0f59046f 599 $listing = $this->get_listing();
600 }
fca079c5 601 if (empty($listing)) {
602 $str = '';
603 } else {
604 $count = 0;
605 $str = '<table>';
7a3b93c1 606 foreach ($listing as $v) {
fca079c5 607 $str .= '<tr id="entry_'.$count.'">';
608 $str .= '<td><input type="checkbox" /></td>';
609 $str .= '<td>'.$v['name'].'</td>';
610 $str .= '<td>'.$v['size'].'</td>';
611 $str .= '<td>'.$v['date'].'</td>';
612 $str .= '</tr>';
613 $count++;
614 }
d1fe3452 615 $str .= '</table>';
82669dc4 616 }
7a3b93c1 617 if ($print) {
82669dc4 618 echo $str;
619 return null;
620 } else {
621 return $str;
622 }
1cf56396 623 }
eb239694 624
f48fb4d6 625 /**
626 * Return is the instance is visible
627 * (is the type visible ? is the context enable ?)
628 * @return boolean
629 */
630 public function is_visible() {
631 $type = repository_get_type_by_id($this->typeid);
632 $instanceoptions = repository_static_function($type->get_typename(), 'get_instance_option_names');
633
634 if ($type->get_visible()) {
635 //if the instance is unique so it's visible, otherwise check if the instance has a enabled context
636 if (empty($instanceoptions) || $type->get_contextvisibility($this->context->contextlevel)) {
637 return true;
638 }
639 }
640
641 return false;
642 }
643
eb239694 644 /**
66dc47bc 645 * Return the name of this instance, can be overridden.
eb239694 646 * @global <type> $DB
647 * @return <type>
648 */
7a3b93c1 649 public function get_name() {
d31af46a 650 global $DB;
651 // We always verify instance id from database,
652 // so we always know repository name before init
653 // a repository, so we don't enquery repository
654 // name from database again here.
655 if (isset($this->options['name'])) {
656 return $this->options['name'];
657 } else {
658 if ( $repo = $DB->get_record('repository_instances', array('id'=>$this->id)) ) {
659 return $repo->name;
660 } else {
661 return '';
662 }
663 }
664 }
aa754fe3 665
b318bb6d 666 /**
667 * what kind of files will be in this repository?
668 * @return array return '*' means this repository support any files, otherwise
669 * return mimetypes of files, it can be an array
670 */
671 public function supported_mimetype() {
672 // return array('text/plain', 'image/gif');
673 return '*';
674 }
675
676 /**
677 * does it return a file url or a item_id
678 * @return string
679 */
680 public function supported_return_value() {
681 // return 'link';
682 // return 'ref_id';
683 return '*';
684 }
685
82669dc4 686 /**
3f24ea1e 687 * Provide repository instance information for Ajax
8dcd5deb 688 * @global object $CFG
4a65c39a 689 * @return object
82669dc4 690 */
b1339e98 691 final public function ajax_info() {
4a65c39a 692 global $CFG;
693 $repo = new stdclass;
27051e43 694 $repo->id = $this->id;
d31af46a 695 $repo->name = $this->get_name();
4a65c39a 696 $repo->type = $this->options['type'];
6fe8b022 697 $repo->icon = $CFG->httpswwwroot.'/repository/'.$repo->type.'/icon.png';
4a65c39a 698 return $repo;
699 }
1cf56396 700
b1339e98 701 /**
702 * Create an instance for this plug-in
8dcd5deb 703 * @global object $CFG
704 * @global object $DB
705 * @param string $type the type of the repository
706 * @param integer $userid the user id
707 * @param object $context the context
708 * @param array $params the options for this instance
709 * @return <type>
b1339e98 710 */
948c2860 711 final public static function create($type, $userid, $context, $params, $readonly=0) {
b1339e98 712 global $CFG, $DB;
713 $params = (array)$params;
714 require_once($CFG->dirroot . '/repository/'. $type . '/repository.class.php');
715 $classname = 'repository_' . $type;
3023078f 716 if ($repo = $DB->get_record('repository', array('type'=>$type))) {
717 $record = new stdclass;
718 $record->name = $params['name'];
719 $record->typeid = $repo->id;
720 $record->timecreated = time();
721 $record->timemodified = time();
722 $record->contextid = $context->id;
948c2860 723 $record->readonly = $readonly;
3023078f 724 $record->userid = $userid;
725 $id = $DB->insert_record('repository_instances', $record);
0a6221f9 726 $options = array();
edb50637 727 $configs = call_user_func($classname . '::get_instance_option_names');
1e08b5cf 728 if (!empty($configs)) {
729 foreach ($configs as $config) {
730 $options[$config] = $params[$config];
731 }
3023078f 732 }
3a01a46a 733
3023078f 734 if (!empty($id)) {
735 unset($options['name']);
c9f9f911 736 $instance = repository_get_instance($id);
3023078f 737 $instance->set_option($options);
738 return $id;
739 } else {
740 return null;
b1339e98 741 }
b1339e98 742 } else {
743 return null;
744 }
745 }
8dcd5deb 746
82669dc4 747 /**
4a65c39a 748 * delete a repository instance
8dcd5deb 749 * @global object $DB
750 * @return <type>
82669dc4 751 */
7a3b93c1 752 final public function delete() {
4a65c39a 753 global $DB;
122defc5 754 $DB->delete_records('repository_instances', array('id'=>$this->id));
4a65c39a 755 return true;
756 }
8dcd5deb 757
4a65c39a 758 /**
759 * Hide/Show a repository
8dcd5deb 760 * @global object $DB
761 * @param string $hide
762 * @return <type>
4a65c39a 763 */
7a3b93c1 764 final public function hide($hide = 'toggle') {
4a65c39a 765 global $DB;
766 if ($entry = $DB->get_record('repository', array('id'=>$this->id))) {
767 if ($hide === 'toggle' ) {
768 if (!empty($entry->visible)) {
769 $entry->visible = 0;
770 } else {
771 $entry->visible = 1;
772 }
773 } else {
774 if (!empty($hide)) {
775 $entry->visible = 0;
776 } else {
777 $entry->visible = 1;
778 }
779 }
780 return $DB->update_record('repository', $entry);
781 }
782 return false;
783 }
1cf56396 784
785 /**
82669dc4 786 * Cache login details for repositories
8dcd5deb 787 * @global object $DB
82669dc4 788 * @param string $username
789 * @param string $password
8dcd5deb 790 * @param integer $userid The id of specific user
791 * @return integer Id of the record
1cf56396 792 */
b6558c3b 793 public function store_login($username = '', $password = '', $userid = 1) {
fca079c5 794 global $DB;
795
796 $repository = new stdclass;
4a65c39a 797 if (!empty($this->id)) {
798 $repository->id = $this->id;
19add4c0 799 } else {
800 $repository->userid = $userid;
801 $repository->repositorytype = $this->type;
b6558c3b 802 $repository->contextid = $this->context->id;
19add4c0 803 }
fca079c5 804 if ($entry = $DB->get_record('repository', $repository)) {
805 $repository->id = $entry->id;
806 $repository->username = $username;
807 $repository->password = $password;
808 return $DB->update_record('repository', $repository);
809 } else {
810 $repository->username = $username;
811 $repository->password = $password;
812 return $DB->insert_record('repository', $repository);
813 }
1cf56396 814 }
815
1cf56396 816 /**
4a65c39a 817 * Save settings for repository instance
8dcd5deb 818 * $repo->set_option(array('api_key'=>'f2188bde132', 'name'=>'dongsheng'));
819 * @global object $DB
820 * @param array $options settings
4a65c39a 821 * @return int Id of the record
1cf56396 822 */
7a3b93c1 823 public function set_option($options = array()) {
4a65c39a 824 global $DB;
7a3b93c1 825
122defc5 826 if (!empty($options['name'])) {
827 $r = new object();
828 $r->id = $this->id;
829 $r->name = $options['name'];
830 $DB->update_record('repository_instances', $r);
831 unset($options['name']);
832 }
e53a97d1 833 $result = true;
27051e43 834 foreach ($options as $name=>$value) {
835 if ($id = $DB->get_field('repository_instance_config', 'id', array('name'=>$name, 'instanceid'=>$this->id))) {
836 if ($value===null) {
e53a97d1 837 $result = $result && $DB->delete_records('repository_instance_config', array('name'=>$name, 'instanceid'=>$this->id));
27051e43 838 } else {
e53a97d1 839 $result = $result && $DB->set_field('repository_instance_config', 'value', $value, array('id'=>$id));
27051e43 840 }
841 } else {
842 if ($value===null) {
843 return true;
844 }
845 $config = new object();
846 $config->instanceid = $this->id;
847 $config->name = $name;
848 $config->value = $value;
e53a97d1 849 $result = $result && $DB->insert_record('repository_instance_config', $config);
27051e43 850 }
4a65c39a 851 }
e53a97d1 852 return $result;
1cf56396 853 }
1cf56396 854
4a65c39a 855 /**
856 * Get settings for repository instance
8dcd5deb 857 * @global object $DB
858 * @param <type> $config
4a65c39a 859 * @return array Settings
860 */
7a3b93c1 861 public function get_option($config = '') {
4a65c39a 862 global $DB;
27051e43 863 $entries = $DB->get_records('repository_instance_config', array('instanceid'=>$this->id));
864 $ret = array();
865 if (empty($entries)) {
866 return $ret;
4a65c39a 867 }
7a3b93c1 868 foreach($entries as $entry) {
27051e43 869 $ret[$entry->name] = $entry->value;
4a65c39a 870 }
871 if (!empty($config)) {
872 return $ret[$config];
873 } else {
874 return $ret;
875 }
876 }
bf1fccf0 877
4a65c39a 878 /**
879 * Given a path, and perhaps a search, get a list of files.
880 *
e6be3a69 881 * The format of the returned array must be:
f7639c37 882 * array(
f6812a21 883 * 'path' => (string) path for the current folder
f7639c37 884 * 'dynload' => (bool) use dynamic loading,
f6812a21 885 * 'manage' => (string) link to file manager,
f7639c37 886 * 'nologin' => (bool) requires login,
d31af46a 887 * 'nosearch' => (bool) no search link,
f7639c37 888 * 'upload' => array( // upload manager
889 * 'name' => (string) label of the form element,
890 * 'id' => (string) id of the form element
891 * ),
892 * 'list' => array(
893 * array( // file
894 * 'title' => (string) file name,
3c9e53c0 895 * 'date' => (string) file last modification time, usually userdate(...),
f6812a21 896 * 'size' => (int) file size,
3c9e53c0 897 * 'thumbnail' => (string) url to thumbnail for the file,
336bb44b 898 * 'source' => plugin-dependent unique path to the file (id, url, path, etc.),
899 * 'url'=> the accessible url of file
f7639c37 900 * ),
3c9e53c0 901 * array( // folder - same as file, but no 'source'.
f7639c37 902 * 'title' => (string) folder name,
f6812a21 903 * 'path' => (string) path to this folder
3c9e53c0 904 * 'date' => (string) folder last modification time, usually userdate(...),
f6812a21 905 * 'size' => 0,
3c9e53c0 906 * 'thumbnail' => (string) url to thumbnail for the folder,
907 * 'children' => array( // an empty folder needs to have 'children' defined, but empty.
908 * // content (files and folders)
f7639c37 909 * )
e6be3a69 910 * ),
f7639c37 911 * )
912 * )
913 *
4a65c39a 914 * @param string $parent The parent path, this parameter can
915 * a folder name, or a identification of folder
4a65c39a 916 * @return array the list of files, including meta infomation
917 */
353d5cf3 918 abstract public function get_listing($parent = '/');
1cf56396 919
fbd508b4 920 /**
353d5cf3 921 * Search files in repository
922 * When doing global search, $search_text will be used as
923 * keyword.
924 *
fbd508b4 925 * @return mixed, see get_listing()
926 */
353d5cf3 927 public function search($search_text) {
928 $list = array();
929 $list['list'] = array();
930 return false;
fbd508b4 931 }
932
d68c527f 933 /**
934 * Logout from repository instance
935 * By default, this function will return a login form
936 *
937 * @return string
938 */
939 public function logout(){
940 return $this->print_login();
941 }
942
943 /**
944 * To check whether the user is logged in.
945 *
946 * @return boolean
947 */
948 public function check_login(){
949 return true;
950 }
951
1cf56396 952
4a65c39a 953 /**
954 * Show the login screen, if required
955 * This is an abstract function, it must be overriden.
4a65c39a 956 */
1d66f2b2 957 public function print_login(){
958 return $this->get_listing();
959 }
1cf56396 960
4a65c39a 961 /**
962 * Show the search screen, if required
4a65c39a 963 * @return null
964 */
2b9feb5f 965 public function print_search() {
966 echo '<input type="hidden" name="repo_id" value="'.$this->id.'" />';
967 echo '<input type="hidden" name="ctx_id" value="'.$this->context->id.'" />';
968 echo '<input type="hidden" name="seekey" value="'.sesskey().'" />';
8d419e59 969 echo '<label>'.get_string('keyword', 'repository').': </label><br/><input name="s" value="" /><br/>';
2b9feb5f 970 return true;
971 }
4a65c39a 972
455860ce 973 /**
974 * is it possible to do glboal search?
975 * @return boolean
976 */
7a3b93c1 977 public function global_search() {
455860ce 978 return false;
979 }
980
8dcd5deb 981 /**
a6600395 982 * Defines operations that happen occasionally on cron
8dcd5deb 983 * @return <type>
984 */
a6600395 985 public function cron() {
986 return true;
987 }
988
7892948d 989 /**
83a018ed 990 * function which is run when the type is created (moodle administrator add the plugin)
3e0794ed 991 * @return boolean success or fail?
7892948d 992 */
948c2860 993 public static function plugin_init(){
3e0794ed 994 return true;
7892948d 995 }
996
a6600395 997 /**
06e65e1e 998 * Edit/Create Admin Settings Moodle form
999 * @param object $ Moodle form (passed by reference)
a6600395 1000 */
daff8f50 1001 public function type_config_form(&$mform) {
4a65c39a 1002 }
06e65e1e 1003
1004 /**
1005 * Edit/Create Instance Settings Moodle form
1006 * @param object $ Moodle form (passed by reference)
a6600395 1007 */
06e65e1e 1008 public function instance_config_form(&$mform) {
a6600395 1009 }
4a65c39a 1010
a6600395 1011 /**
1012 * Return names of the general options
1013 * By default: no general option name
1014 * @return array
1015 */
1b79955a 1016 public static function get_type_option_names() {
a6600395 1017 return array();
1018 }
1019
1020 /**
1021 * Return names of the instance options
1022 * By default: no instance option name
1023 * @return array
1024 */
7a3b93c1 1025 public static function get_instance_option_names() {
a6600395 1026 return array();
8b65d45c 1027 }
119a4ae1 1028
ce5e846c 1029 /**
1030 * Override it if you need to implement need mnet function
1031 * @return array
1032 */
119a4ae1 1033 public static function mnet_publishes() {
1034 return array();
1035 }
1036
8b65d45c 1037}
837ebb78 1038
1039/**
4a65c39a 1040 * exception class for repository api
837ebb78 1041 */
4a65c39a 1042class repository_exception extends moodle_exception {
8b65d45c 1043}
4ed43890 1044
2057487c 1045/**
1046 * Check context
1047 * @param int $ctx_id
1048 * @return boolean
1049 */
7a3b93c1 1050function repository_check_context($ctx_id) {
2057487c 1051 global $USER;
7a3b93c1 1052
2057487c 1053 $context = get_context_instance_by_id($ctx_id);
1054 $level = $context->contextlevel;
7a3b93c1 1055
2057487c 1056 if ($level == CONTEXT_COURSE) {
1057 if (!has_capability('moodle/course:view', $context)) {
1058 return false;
1059 } else {
1060 return true;
1061 }
7a3b93c1 1062 } else if ($level == CONTEXT_USER) {
2057487c 1063 $c = get_context_instance(CONTEXT_USER, $USER->id);
1064 if ($c->id == $ctx_id) {
1065 return true;
1066 } else {
1067 return false;
1068 }
7a3b93c1 1069 } else if ($level == CONTEXT_SYSTEM) {
2057487c 1070 // it is always ok in system level
70fbd90e 1071 return true;
2057487c 1072 }
1073 return false;
1074}
4a65c39a 1075
bbcd4860 1076/**
1077 * Return all types that you a user can create/edit and which are also visible
8f943eba 1078 * Note: Mostly used in order to know if at least one editable type can be set
f48fb4d6 1079 * @param object $context the context for which we want the editable types
bbcd4860 1080 * @return array types
1081 */
f48fb4d6 1082function repository_get_editable_types($context = null) {
1083
1084 if (empty($context)) {
1085 $context = get_system_context();
1086 }
1087
bbcd4860 1088 $types= repository_get_types(true);
1089 $editabletypes = array();
7a3b93c1 1090 foreach ($types as $type) {
edb50637 1091 $instanceoptionnames = repository_static_function($type->get_typename(), 'get_instance_option_names');
1092 if (!empty($instanceoptionnames)) {
f48fb4d6 1093 if ($type->get_contextvisibility($context->contextlevel)) {
1094 $editabletypes[]=$type;
1095 }
1096 }
bbcd4860 1097 }
1098 return $editabletypes;
1099}
1100
837ebb78 1101/**
4a65c39a 1102 * Return repository instances
8dcd5deb 1103 * @global object $DB
1104 * @global object $CFG
1105 * @global object $USER
12c79bfd 1106 * @param object $contexts contexts for which the instances are set
8dcd5deb 1107 * @param integer $userid
46dd6bb0 1108 * @param boolean $onlyvisible if visible == true, return visible instances only,
4a65c39a 1109 * otherwise, return all instances
a6600395 1110 * @param string $type a type name to retrieve
b318bb6d 1111 * @param string $filetypes supported file types
1112 * @param string $returnvalue supportted returned value
4a65c39a 1113 * @return array repository instances
837ebb78 1114 */
b318bb6d 1115function repository_get_instances($contexts=array(), $userid = null, $onlyvisible = true, $type=null, $filetypes = '*', $returnvalue = '*') {
38e55442 1116 global $DB, $CFG, $USER;
7a3b93c1 1117
38e55442 1118 $params = array();
1265fc59 1119 $sql = 'SELECT i.*, r.type AS repositorytype, r.sortorder, r.visible FROM {repository} r, {repository_instances} i WHERE ';
46dd6bb0 1120 $sql .= 'i.typeid = r.id ';
7a3b93c1 1121
4a65c39a 1122 if (!empty($userid) && is_numeric($userid)) {
46dd6bb0 1123 $sql .= ' AND (i.userid = 0 or i.userid = ?)';
4a65c39a 1124 $params[] = $userid;
1125 }
7a3b93c1 1126
12c79bfd 1127 foreach ($contexts as $context) {
7a3b93c1 1128 if (empty($firstcontext)) {
12c79bfd 1129 $firstcontext = true;
1130 $sql .= ' AND ((i.contextid = ?)';
46dd6bb0 1131 } else {
12c79bfd 1132 $sql .= ' OR (i.contextid = ?)';
46dd6bb0 1133 }
12c79bfd 1134 $params[] = $context->id;
38e55442 1135 }
7a3b93c1 1136
7892948d 1137 if (!empty($firstcontext)) {
1138 $sql .=')';
12c79bfd 1139 }
aca64b79 1140
7a3b93c1 1141 if ($onlyvisible == true) {
4a65c39a 1142 $sql .= ' AND (r.visible = 1)';
1143 }
7a3b93c1 1144
1145 if (isset($type)) {
a6600395 1146 $sql .= ' AND (r.type = ?)';
1147 $params[] = $type;
1148 }
1265fc59 1149 $sql .= ' order by r.sortorder, i.name';
7a3b93c1 1150
1151 if (!$repos = $DB->get_records_sql($sql, $params)) {
38e55442 1152 $repos = array();
1153 }
7a3b93c1 1154
4a65c39a 1155 $ret = array();
7a3b93c1 1156 foreach ($repos as $repo) {
1157 require_once($CFG->dirroot . '/repository/'. $repo->repositorytype.'/repository.class.php');
27051e43 1158 $options['visible'] = $repo->visible;
1159 $options['name'] = $repo->name;
1160 $options['type'] = $repo->repositorytype;
1161 $options['typeid'] = $repo->typeid;
f48fb4d6 1162 $classname = 'repository_' . $repo->repositorytype;//
1163
1164 $repository = new $classname($repo->id, $repo->contextid, $options, $repo->readonly);
b318bb6d 1165 if ($filetypes !== '*' and $repository->supported_mimetype() !== '*') {
1166 $mimetypes = $repository->supported_mimetype();
1167 $is_supported = false;
1168 foreach ($mimetypes as $type) {
1169 if (in_array($type, $filetypes)) {
1170 $is_supported = true;
1171 }
1172 }
1173 if (!$is_supported) {
1174 continue;
1175 }
1176 }
1177 if ($returnvalue !== '*' and $repository->supported_return_value() !== '*') {
1178 $tmp = $repository->supported_return_value();
1179 if ($tmp == $returnvalue) {
1180 continue;
1181 }
1182 }
efe018b4 1183 if (!$onlyvisible || ($repository->is_visible() && !$repository->disabled)) {
f48fb4d6 1184 $ret[] = $repository;
1185 }
4a65c39a 1186 }
1187 return $ret;
38e55442 1188}
4ed43890 1189
837ebb78 1190/**
1191 * Get single repository instance
8dcd5deb 1192 * @global object $DB
1193 * @global object $CFG
1194 * @param integer $id repository id
837ebb78 1195 * @return object repository instance
1196 */
7a3b93c1 1197function repository_get_instance($id) {
19add4c0 1198 global $DB, $CFG;
27051e43 1199 $sql = 'SELECT i.*, r.type AS repositorytype, r.visible FROM {repository} r, {repository_instances} i WHERE ';
1200 $sql .= 'i.typeid = r.id AND ';
1201 $sql .= 'i.id = '.$id;
19add4c0 1202
27051e43 1203 if(!$instance = $DB->get_record_sql($sql)) {
19add4c0 1204 return false;
1205 }
e6be3a69 1206 require_once($CFG->dirroot . '/repository/'. $instance->repositorytype
7a3b93c1 1207 . '/repository.class.php');
19add4c0 1208 $classname = 'repository_' . $instance->repositorytype;
27051e43 1209 $options['typeid'] = $instance->typeid;
1210 $options['type'] = $instance->repositorytype;
1211 $options['name'] = $instance->name;
948c2860 1212 return new $classname($instance->id, $instance->contextid, $options, $instance->readonly);
19add4c0 1213}
837ebb78 1214
8dcd5deb 1215/**
66dc47bc 1216 * call a static function
8dcd5deb 1217 * @global <type> $CFG
1218 * @param <type> $plugin
1219 * @param <type> $function
a6600395 1220 * @param type $nocallablereturnvalue default value if function not found
1221 * it's mostly used when you don't want to display an error but
1222 * return a boolean
8dcd5deb 1223 * @return <type>
1224 */
4a65c39a 1225function repository_static_function($plugin, $function) {
97f7393d 1226 global $CFG;
4a65c39a 1227
a6600395 1228 //check that the plugin exists
1229 $typedirectory = $CFG->dirroot . '/repository/'. $plugin . '/repository.class.php';
7a3b93c1 1230 if (!file_exists($typedirectory)) {
1231 throw new repository_exception('invalidplugin', 'repository');
a6600395 1232 }
1233
4a65c39a 1234 $pname = null;
1235 if (is_object($plugin) || is_array($plugin)) {
1236 $plugin = (object)$plugin;
1237 $pname = $plugin->name;
1238 } else {
1239 $pname = $plugin;
97f7393d 1240 }
4a65c39a 1241
1242 $args = func_get_args();
1243 if (count($args) <= 2) {
1244 $args = array();
1245 }
1246 else {
1247 array_shift($args);
1248 array_shift($args);
1249 }
1250
a6600395 1251 require_once($typedirectory);
4a65c39a 1252 return call_user_func_array(array('repository_' . $plugin, $function), $args);
97f7393d 1253}
d8eb6e18 1254
837ebb78 1255/**
1256 * Move file from download folder to file pool using FILE API
8dcd5deb 1257 * @global object $DB
1258 * @global object $CFG
1259 * @global object $USER
1260 * @param string $path file path in download folder
1261 * @param string $name file name
1262 * @param integer $itemid item id to identify a file in filepool
1263 * @param string $filearea file area
837ebb78 1264 * @return array information of file in file pool
1265 */
c9260130 1266function repository_move_to_filepool($path, $name, $itemid, $filearea = 'user_draft') {
d8eb6e18 1267 global $DB, $CFG, $USER;
1268 $context = get_context_instance(CONTEXT_USER, $USER->id);
313cc398 1269 $now = time();
d8eb6e18 1270 $entry = new object();
55b4bb1d 1271 $entry->filearea = $filearea;
d8eb6e18 1272 $entry->contextid = $context->id;
1273 $entry->filename = $name;
c9260130 1274 $entry->filepath = '/'.uniqid().'/';
313cc398 1275 $entry->timecreated = $now;
1276 $entry->timemodified = $now;
c2762f06 1277 if(is_numeric($itemid)) {
1278 $entry->itemid = $itemid;
1279 } else {
1280 $entry->itemid = 0;
1281 }
d8eb6e18 1282 $entry->mimetype = mimeinfo('type', $path);
1283 $entry->userid = $USER->id;
1284 $fs = get_file_storage();
1285 $browser = get_file_browser();
1286 if ($file = $fs->create_file_from_pathname($entry, $path)) {
c9260130 1287 $delete = unlink($path);
d8eb6e18 1288 $ret = $browser->get_file_info($context, $file->get_filearea(), $file->get_itemid(), $file->get_filepath(), $file->get_filename());
7a3b93c1 1289 if(!empty($ret)) {
c0fa8cba 1290 return array('url'=>$ret->get_url(),'id'=>$file->get_itemid(), 'file'=>$file->get_filename());
3023078f 1291 } else {
1292 return null;
1293 }
d8eb6e18 1294 } else {
1295 return null;
1296 }
1297}
1298
1e08b5cf 1299function repository_download_btn($repo_id, $ctx_id, $sesskey, $title, $src, $returnurl = '') {
1300 global $CFG;
1301 if (empty($returnurl)) {
1302 $returnurl = get_referer();
1303 }
1304 $str = '<form action="'.$CFG->httpswwwroot.'/repository/ws.php">';
1305 $str .= ' <input type="hidden" name="sesskey" value="'.$sesskey.'" />';
1306 $str .= ' <input type="hidden" name="ctx_id" value="'.$ctx_id.'" />';
1307 $str .= ' <input type="hidden" name="repo_id" value="'.$repo_id.'" />';
1308 $str .= ' <input type="hidden" name="file" value="'.$src.'" />';
1309 $str .= ' <input type="hidden" name="action" value="download" />';
1310 $str .= ' <input type="hidden" name="returnurl" value="'.$returnurl.'" />';
1311 $str .= ' <input type="text" name="title" value="'.$title.'" />';
1312 $str .= ' <input type="submit" value="Select it!" />';
1313 $str .= '</form>';
1314 return $str;
1315}
1316
5a3b9db9 1317/**
1318 * Save file to local filesystem pool
1319 * @param string $elname name of element
5a3b9db9 1320 * @param string $filearea
1321 * @param string $filepath
1322 * @param string $filename - use specified filename, if not specified name of uploaded file used
1323 * @param bool $override override file if exists
5a3b9db9 1324 * @return mixed stored_file object or false if error; may throw exception if duplicate found
1325 */
313cc398 1326function repository_store_to_filepool($elname, $filearea='user_draft', $filepath='/', $filename = '', $override = false) {
5a3b9db9 1327 global $USER;
1328 if (!isset($_FILES[$elname])) {
1329 return false;
1330 }
1331
313cc398 1332 if (!$filename) {
1333 $filename = $_FILES[$elname]['name'];
1334 }
5a3b9db9 1335 $context = get_context_instance(CONTEXT_USER, $USER->id);
1336 $itemid = (int)substr(hexdec(uniqid()), 0, 9)+rand(1,100);
1337 $fs = get_file_storage();
1338 $browser = get_file_browser();
1339
1340 if ($file = $fs->get_file($context->id, $filearea, $itemid, $filepath, $filename)) {
1341 if ($override) {
1342 $file->delete();
1343 } else {
1344 return false;
1345 }
1346 }
1347
1348 $file_record = new object();
1349 $file_record->contextid = $context->id;
1350 $file_record->filearea = $filearea;
1351 $file_record->itemid = $itemid;
1352 $file_record->filepath = $filepath;
1353 $file_record->filename = $filename;
1354 $file_record->userid = $USER->id;
1355
1356 $file = $fs->create_file_from_pathname($file_record, $_FILES[$elname]['tmp_name']);
1357 $info = $browser->get_file_info($context, $file->get_filearea(), $file->get_itemid(), $file->get_filepath(), $file->get_filename());
1358 $ret = array('url'=>$info->get_url(),'id'=>$itemid, 'file'=>$file->get_filename());
1359 return $ret;
1360}
1361
e3ca0f3a 1362/**
1363 * Return the user arborescence in a format to be returned by the function get_listing
1364 * @global <type> $CFG
1365 * @param <type> $search
1366 * @return <type>
1367 */
1368function repository_get_user_file_tree($search = ""){
1369 global $CFG;
1370 $ret = array();
1371 $ret['nologin'] = true;
1372 $ret['manage'] = $CFG->wwwroot .'/files/index.php'; // temporary
1373 $browser = get_file_browser();
1374 $itemid = null;
1375 $filename = null;
1376 $filearea = null;
1377 $path = '/';
1378 $ret['dynload'] = false;
1379
1380 if ($fileinfo = $browser->get_file_info(get_system_context(), $filearea, $itemid, $path, $filename)) {
1381
1382 $ret['path'] = array();
1383 $params = $fileinfo->get_params();
1384 $filearea = $params['filearea'];
1385 $ret['path'][] = repository_encode_path($filearea, $path, $fileinfo->get_visible_name());
1386 if ($fileinfo->is_directory()) {
1387 $level = $fileinfo->get_parent();
1388 while ($level) {
1389 $params = $level->get_params();
1390 $ret['path'][] = repository_encode_path($params['filearea'], $params['filepath'], $level->get_visible_name());
1391 $level = $level->get_parent();
1392 }
1393 }
1394 $filecount = repository_build_tree($fileinfo, $search, $ret['dynload'], $ret['list']);
1395 $ret['path'] = array_reverse($ret['path']);
1396 }
1397
1398 if (empty($ret['list'])) {
1399 //exit(mnet_server_fault(9016, get_string('emptyfilelist', 'repository_local')));
1400 throw new Exception('emptyfilelist');
1401 } else {
1402 return $ret;
1403 }
1404
1405}
1406
1407 /**
1408 *
1409 * @param <type> $filearea
1410 * @param <type> $path
1411 * @param <type> $visiblename
1412 * @return <type>
1413 */
1414 function repository_encode_path($filearea, $path, $visiblename) {
1415 return array('path'=>serialize(array($filearea, $path)), 'name'=>$visiblename);
1416 }
1417
1418 /**
1419 * Builds a tree of files This function is
1420 * then called recursively.
1421 *
1422 * @param $fileinfo an object returned by file_browser::get_file_info()
1423 * @param $search searched string
1424 * @param $dynamicmode bool no recursive call is done when in dynamic mode
1425 * @param $list - the array containing the files under the passed $fileinfo
1426 * @returns int the number of files found
1427 *
1428 * todo: take $search into account, and respect a threshold for dynamic loading
1429 */
1430 function repository_build_tree($fileinfo, $search, $dynamicmode, &$list) {
1431 global $CFG;
1432
1433 $filecount = 0;
1434 $children = $fileinfo->get_children();
1435
1436 foreach ($children as $child) {
1437 $filename = $child->get_visible_name();
1438 $filesize = $child->get_filesize();
1439 $filesize = $filesize ? display_size($filesize) : '';
1440 $filedate = $child->get_timemodified();
1441 $filedate = $filedate ? userdate($filedate) : '';
1442 $filetype = $child->get_mimetype();
1443
1444 if ($child->is_directory()) {
1445 $path = array();
1446 $level = $child->get_parent();
1447 while ($level) {
1448 $params = $level->get_params();
1449 $path[] = repository_encode_path($params['filearea'], $params['filepath'], $level->get_visible_name());
1450 $level = $level->get_parent();
1451 }
1452
1453 $tmp = array(
1454 'title' => $child->get_visible_name(),
1455 'size' => 0,
1456 'date' => $filedate,
1457 'path' => array_reverse($path),
1458 'thumbnail' => $CFG->pixpath .'/f/folder.gif'
1459 );
1460
1461 //if ($dynamicmode && $child->is_writable()) {
1462 // $tmp['children'] = array();
1463 //} else {
1464 // if folder name matches search, we send back all files contained.
3a01a46a 1465 $_search = $search;
1466 if ($search && stristr($tmp['title'], $search) !== false) {
1467 $_search = false;
1468 }
1469 $tmp['children'] = array();
1470 $_filecount = repository_build_tree($child, $_search, $dynamicmode, $tmp['children']);
1471 if ($search && $_filecount) {
1472 $tmp['expanded'] = 1;
1473 }
e3ca0f3a 1474
1475 //}
1476
3a01a46a 1477 //Uncomment this following line if you wanna display all directory ()even empty
1478 //if (!$search || $_filecount || (stristr($tmp['title'], $search) !== false)) {
1479 if ($_filecount) {
e3ca0f3a 1480 $filecount += $_filecount;
3a01a46a 1481 $list[] = $tmp;
e3ca0f3a 1482 }
1483
1484 } else { // not a directory
1485 // skip the file, if we're in search mode and it's not a match
1486 if ($search && (stristr($filename, $search) === false)) {
1487 continue;
1488 }
1489 $params = $child->get_params();
1490 $source = serialize(array($params['contextid'], $params['filearea'], $params['itemid'], $params['filepath'], $params['filename']));
1491 $list[] = array(
1492 'title' => $filename,
1493 'size' => $filesize,
1494 'date' => $filedate,
1495 //'source' => $child->get_url(),
1496 'source' => base64_encode($source),
1497 'thumbnail' => $CFG->pixpath .'/f/'. mimeinfo_from_type("icon", $filetype)
1498 );
1499 $filecount++;
1500 }
1501 }
1502
1503 return $filecount;
1504 }
1505
1506
8dcd5deb 1507/**
1508 * TODO: write comment
1509 */
a6600395 1510final class repository_instance_form extends moodleform {
4a65c39a 1511 protected $instance;
1512 protected $plugin;
1513
8dcd5deb 1514 /**
1515 * TODO: write comment
1516 * @global <type> $CFG
1517 */
4a65c39a 1518 public function definition() {
1519 global $CFG;
1520 // type of plugin, string
1521 $this->plugin = $this->_customdata['plugin'];
27051e43 1522 $this->typeid = $this->_customdata['typeid'];
faaa613d 1523 $this->contextid = $this->_customdata['contextid'];
4a65c39a 1524 $this->instance = (isset($this->_customdata['instance'])
1525 && is_subclass_of($this->_customdata['instance'], 'repository'))
1526 ? $this->_customdata['instance'] : null;
1527
1528 $mform =& $this->_form;
1529 $strrequired = get_string('required');
1530
1531 $mform->addElement('hidden', 'edit', ($this->instance) ? $this->instance->id : 0);
1532 $mform->addElement('hidden', 'new', $this->plugin);
1533 $mform->addElement('hidden', 'plugin', $this->plugin);
27051e43 1534 $mform->addElement('hidden', 'typeid', $this->typeid);
faaa613d 1535 $mform->addElement('hidden', 'contextid', $this->contextid);
4a65c39a 1536
1537 $mform->addElement('text', 'name', get_string('name'), 'maxlength="100" size="30"');
1538 $mform->addRule('name', $strrequired, 'required', null, 'client');
1539
1e97f196 1540
f48fb4d6 1541 //add fields
1542 if (!$this->instance) {
1543 $result = repository_static_function($this->plugin, 'instance_config_form', $mform);
1544 }
1545 else {
1546 $data = array();
1547 $data['name'] = $this->instance->name;
1548 if (!$this->instance->readonly) {
1549 $result = $this->instance->instance_config_form($mform);
1550 // and set the data if we have some.
1e97f196 1551 foreach ($this->instance->get_instance_option_names() as $config) {
1552 if (!empty($this->instance->$config)) {
1553 $data[$config] = $this->instance->$config;
1554 } else {
1555 $data[$config] = '';
1556 }
27051e43 1557 }
4a65c39a 1558 }
f48fb4d6 1559 $this->set_data($data);
1e97f196 1560 }
1561
46dd6bb0 1562 $this->add_action_buttons(true, get_string('save','repository'));
4a65c39a 1563 }
1564
8dcd5deb 1565 /**
1566 * TODO: write comment
1567 * @global <type> $DB
1568 * @param <type> $data
1569 * @return <type>
1570 */
4a65c39a 1571 public function validation($data) {
1572 global $DB;
1573
1574 $errors = array();
27051e43 1575 if ($DB->count_records('repository_instances', array('name' => $data['name'], 'typeid' => $data['typeid'])) > 1) {
4a65c39a 1576 $errors = array('name' => get_string('err_uniquename', 'repository'));
1577 }
1578
4a65c39a 1579 return $errors;
1580 }
1581}
a6600395 1582
1583
1584/**
1585 * Display a form with the general option fields of a type
1586 */
c295f9ff 1587final class repository_type_form extends moodleform {
a6600395 1588 protected $instance;
1589 protected $plugin;
1590
1591 /**
1592 * Definition of the moodleform
1593 * @global object $CFG
1594 */
1595 public function definition() {
1596 global $CFG;
1597 // type of plugin, string
1598 $this->plugin = $this->_customdata['plugin'];
1599 $this->instance = (isset($this->_customdata['instance'])
1600 && is_a($this->_customdata['instance'], 'repository_type'))
1601 ? $this->_customdata['instance'] : null;
1602
1603 $mform =& $this->_form;
1604 $strrequired = get_string('required');
4d5948f1 1605
a6600395 1606 $mform->addElement('hidden', 'edit', ($this->instance) ? $this->instance->get_typename() : 0);
1607 $mform->addElement('hidden', 'new', $this->plugin);
1608 $mform->addElement('hidden', 'plugin', $this->plugin);
8f943eba 1609
06e65e1e 1610 // let the plugin add its specific fields
1611 if (!$this->instance) {
daff8f50 1612 $result = repository_static_function($this->plugin, 'type_config_form', $mform);
a6600395 1613 } else {
7a3b93c1 1614 $classname = 'repository_' . $this->instance->get_typename();
daff8f50 1615 $result = call_user_func(array($classname,'type_config_form'),$mform);
a6600395 1616 }
1617
f48fb4d6 1618 //add "enable course/user instances" checkboxes if multiple instances are allowed
1619 $instanceoptionnames = repository_static_function($this->plugin, 'get_instance_option_names');
1620 if (!empty($instanceoptionnames)){
1621 $mform->addElement('checkbox', 'enablecourseinstances', get_string('enablecourseinstances', 'repository'));
1622 $mform->addElement('checkbox', 'enableuserinstances', get_string('enableuserinstances', 'repository'));
1623 }
1624
1625 // set the data if we have some.
a6600395 1626 if ($this->instance) {
1627 $data = array();
1b79955a 1628 $option_names = call_user_func(array($classname,'get_type_option_names'));
f48fb4d6 1629 if (!empty($instanceoptionnames)){
1630 $option_names[] = 'enablecourseinstances';
1631 $option_names[] = 'enableuserinstances';
1632 }
1633
a6600395 1634 $instanceoptions = $this->instance->get_options();
1635 foreach ($option_names as $config) {
1636 if (!empty($instanceoptions[$config])) {
1637 $data[$config] = $instanceoptions[$config];
1638 } else {
1639 $data[$config] = '';
1640 }
1641 }
1642 $this->set_data($data);
1643 }
f48fb4d6 1644
46dd6bb0 1645 $this->add_action_buttons(true, get_string('save','repository'));
a6600395 1646 }
a6600395 1647}
1648
1649
1650/**
1651 * Display a repository instance list (with edit/delete/create links)
1652 * @global object $CFG
1653 * @global object $USER
1654 * @param object $context the context for which we display the instance
a6600395 1655 * @param string $typename if set, we display only one type of instance
1656 */
7a3b93c1 1657function repository_display_instances_list($context, $typename = null) {
1658 global $CFG, $USER;
2a06d06e 1659
7a3b93c1 1660 $output = print_box_start('generalbox','',true);
1661 //if the context is SYSTEM, so we call it from administration page
1662 $admin = ($context->id == SYSCONTEXTID) ? true : false;
1663 if ($admin) {
1664 $baseurl = $CFG->httpswwwroot . '/admin/repositoryinstance.php?sesskey=' . sesskey();
1665 $output .= "<div ><h2 style='text-align: center'>" . get_string('siteinstances', 'repository') . " ";
1666 $output .= "</h2></div>";
1667 } else {
1668 $baseurl = $CFG->httpswwwroot . '/repository/manage_instances.php?contextid=' . $context->id . '&amp;sesskey=' . sesskey();
1669 }
1670
1671 $namestr = get_string('name');
1672 $pluginstr = get_string('plugin', 'repository');
1673 $settingsstr = get_string('settings');
1674 $deletestr = get_string('delete');
1675 $updown = get_string('updown', 'repository');
7a3b93c1 1676 //retrieve list of instances. In administration context we want to display all
1677 //instances of a type, even if this type is not visible. In course/user context we
1678 //want to display only visible instances, but for every type types. The repository_get_instances()
1679 //third parameter displays only visible type.
1680 $instances = repository_get_instances(array($context),null,!$admin,$typename);
1681 $instancesnumber = count($instances);
1682 $alreadyplugins = array();
1683
1684 $table = new StdClass;
1685 $table->head = array($namestr, $pluginstr, $deletestr, $settingsstr);
1686 $table->align = array('left', 'left', 'center','center');
1687 $table->data = array();
1688
1689 $updowncount = 1;
1690
1691 foreach ($instances as $i) {
1692 $settings = '';
948c2860 1693 $delete = '';
1e97f196 1694 $settings .= '<a href="' . $baseurl . '&amp;type='.$typename.'&amp;edit=' . $i->id . '">' . $settingsstr . '</a>' . "\n";
948c2860 1695 if (!$i->readonly) {
948c2860 1696 $delete .= '<a href="' . $baseurl . '&amp;type='.$typename.'&amp;delete=' . $i->id . '">' . $deletestr . '</a>' . "\n";
1697 }
7a3b93c1 1698
1699 $type = repository_get_type_by_id($i->typeid);
1700 $table->data[] = array($i->name, $type->get_readablename(), $delete, $settings);
1701
1702 //display a grey row if the type is defined as not visible
1703 if (isset($type) && !$type->get_visible()) {
1704 $table->rowclass[] = 'dimmed_text';
1705 } else {
1706 $table->rowclass[] = '';
1707 }
1708
1709 if (!in_array($i->name, $alreadyplugins)) {
1710 $alreadyplugins[] = $i->name;
1711 }
1712 }
1713 $output .= print_table($table, true);
1714 $instancehtml = '<div>';
1715 $addable = 0;
1716
1717 //if no type is set, we can create all type of instance
1718 if (!$typename) {
1719 $instancehtml .= '<h3>';
1720 $instancehtml .= get_string('createrepository', 'repository');
1721 $instancehtml .= '</h3><ul>';
f48fb4d6 1722 $types = repository_get_editable_types($context);
1723 foreach ($types as $type) {
7a3b93c1 1724 if (!empty($type) && $type->get_visible()) {
f48fb4d6 1725 $instanceoptionnames = repository_static_function($type->get_typename(), 'get_instance_option_names');
edb50637 1726 if (!empty($instanceoptionnames)) {
f48fb4d6 1727 $instancehtml .= '<li><a href="'.$baseurl.'&amp;new='.$type->get_typename().'">'.get_string('create', 'repository')
1728 .' "'.get_string('repositoryname', 'repository_'.$type->get_typename()).'" '
7a3b93c1 1729 .get_string('instance', 'repository').'</a></li>';
1730 $addable++;
1731 }
a6600395 1732 }
1733 }
7a3b93c1 1734 $instancehtml .= '</ul>';
a6600395 1735
edb50637 1736 } else {
1737 $instanceoptionnames = repository_static_function($typename, 'get_instance_option_names');
1738 if (!empty($instanceoptionnames)) { //create a unique type of instance
7a3b93c1 1739 $addable = 1;
1740 $instancehtml .= "<form action='".$baseurl."&amp;new=".$typename."' method='post'>
1741 <p style='text-align:center'><input type='submit' value='".get_string('createinstance', 'repository')."'/></p>
7892948d 1742 </form>";
edb50637 1743 }
7a3b93c1 1744 }
1745
1746 if ($addable) {
1747 $instancehtml .= '</div>';
1748 $output .= $instancehtml;
1749 }
a6600395 1750
7a3b93c1 1751 $output .= print_box_end(true);
a6600395 1752
7a3b93c1 1753 //print the list + creation links
1754 print($output);
a6600395 1755}