2c1acf23579ba48ca42e4f28c17c19ef42bb9fa1
[moodle.git] / repository / recent / lib.php
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
18 /**
19  * This plugin is used to access recent used files
20  *
21  * @since 2.0
22  * @package    repository_recent
23  * @copyright  2010 Dongsheng Cai {@link http://dongsheng.org}
24  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25  */
26 require_once($CFG->dirroot . '/repository/lib.php');
28 /**
29  * repository_recent class is used to browse recent used files
30  *
31  * @since 2.0
32  * @package    repository_recent
33  * @copyright  2010 Dongsheng Cai {@link http://dongsheng.org}
34  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35  */
36 define('DEFAULT_RECENT_FILES_NUM', 50);
37 class repository_recent extends repository {
39     /**
40      * Initialize recent plugin
41      * @param int $repositoryid
42      * @param int $context
43      * @param array $options
44      */
45     public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {
46         parent::__construct($repositoryid, $context, $options);
47         $number = get_config('recent', 'recentfilesnumber');
48         $number = (int)$number;
49         if (empty($number)) {
50             $this->number = DEFAULT_RECENT_FILES_NUM;
51         } else {
52             $this->number = $number;
53         }
54     }
56     /**
57      * recent plugin doesn't require login, so list all files
58      * @return mixed
59      */
60     public function print_login() {
61         return $this->get_listing();
62     }
64     private function get_recent_files($limitfrom = 0, $limit = DEFAULT_RECENT_FILES_NUM) {
65         // XXX: get current itemid
66         global $USER, $DB, $itemid;
67         // This SQL will ignore draft files if not owned by current user.
68         // Ignore all file references.
69         $sql = 'SELECT files1.*
70                   FROM {files} files1
71              LEFT JOIN {files_reference} r
72                        ON files1.referencefileid = r.id
73                   JOIN (
74                       SELECT contenthash, filename, MAX(id) AS id
75                         FROM {files}
76                        WHERE userid = :userid
77                          AND filename != :filename
78                          AND ((filearea = :filearea1 AND itemid = :itemid) OR filearea != :filearea2)
79                     GROUP BY contenthash, filename
80                   ) files2 ON files1.id = files2.id
81                  WHERE r.repositoryid is NULL
82               ORDER BY files1.timemodified DESC';
83         $params = array(
84             'userid' => $USER->id,
85             'filename' => '.',
86             'filearea1' => 'draft',
87             'itemid' => $itemid,
88             'filearea2' => 'draft');
89         $rs = $DB->get_recordset_sql($sql, $params, $limitfrom, $limit);
90         $result = array();
91         foreach ($rs as $file_record) {
92             $info = array();
93             $info['contextid'] = $file_record->contextid;
94             $info['itemid'] = $file_record->itemid;
95             $info['filearea'] = $file_record->filearea;
96             $info['component'] = $file_record->component;
97             $info['filepath'] = $file_record->filepath;
98             $info['filename'] = $file_record->filename;
99             $result[$file_record->pathnamehash] = $info;
100         }
101         $rs->close();
102         return $result;
103     }
105     /**
106      * Get file listing
107      *
108      * @param string $encodedpath
109      * @param string $path not used by this plugin
110      * @return mixed
111      */
112     public function get_listing($encodedpath = '', $page = '') {
113         global $OUTPUT;
114         $ret = array();
115         $ret['dynload'] = true;
116         $ret['nosearch'] = true;
117         $ret['nologin'] = true;
118         $list = array();
119         $files = $this->get_recent_files(0, $this->number);
121         try {
122             foreach ($files as $file) {
123                 // Check that file exists and accessible, retrieve size/date info
124                 $browser = get_file_browser();
125                 $context = get_context_instance_by_id($file['contextid']);
126                 $fileinfo = $browser->get_file_info($context, $file['component'],
127                         $file['filearea'], $file['itemid'], $file['filepath'], $file['filename']);
128                 if ($fileinfo) {
129                     $params = base64_encode(serialize($file));
130                     $node = array(
131                         'title' => $fileinfo->get_visible_name(),
132                         'size' => $fileinfo->get_filesize(),
133                         'datemodified' => $fileinfo->get_timemodified(),
134                         'datecreated' => $fileinfo->get_timecreated(),
135                         'author' => $fileinfo->get_author(),
136                         'license' => $fileinfo->get_license(),
137                         'source'=> $params,
138                         'icon' => $OUTPUT->pix_url(file_file_icon($fileinfo, 24))->out(false),
139                         'thumbnail' => $OUTPUT->pix_url(file_file_icon($fileinfo, 90))->out(false),
140                     );
141                     if ($imageinfo = $fileinfo->get_imageinfo()) {
142                         $fileurl = new moodle_url($fileinfo->get_url());
143                         $node['realthumbnail'] = $fileurl->out(false, array('preview' => 'thumb', 'oid' => $fileinfo->get_timemodified()));
144                         $node['realicon'] = $fileurl->out(false, array('preview' => 'tinyicon', 'oid' => $fileinfo->get_timemodified()));
145                         $node['image_width'] = $imageinfo['width'];
146                         $node['image_height'] = $imageinfo['height'];
147                     }
148                     $list[] = $node;
149                 }
150             }
151         } catch (Exception $e) {
152             throw new repository_exception('emptyfilelist', 'repository_recent');
153         }
154         $ret['list'] = array_filter($list, array($this, 'filter'));
155         return $ret;
156     }
158     public static function get_type_option_names() {
159         return array('recentfilesnumber', 'pluginname');
160     }
162     public static function type_config_form($mform, $classname = 'repository') {
163         parent::type_config_form($mform, $classname);
164         $number = get_config('repository_recent', 'recentfilesnumber');
165         if (empty($number)) {
166             $number = DEFAULT_RECENT_FILES_NUM;
167         }
168         $mform->addElement('text', 'recentfilesnumber', get_string('recentfilesnumber', 'repository_recent'));
169         $mform->setDefault('recentfilesnumber', $number);
170     }
172     /**
173      * This plugin doesn't support to link to external links
174      *
175      * @return int
176      */
177     public function supported_returntypes() {
178         return FILE_INTERNAL;
179     }
180     /**
181      * This function overwrite the default implement to copying file using file_storage
182      *
183      * @param string $encoded The information of file, it is base64 encoded php serialized data
184      * @param stdClass|array $filerecord contains itemid, filepath, filename and optionally other
185      *      attributes of the new file
186      * @param int $maxbytes maximum allowed size of file, -1 if unlimited. If size of file exceeds
187      *      the limit, the file_exception is thrown.
188      * @return array The information of file
189      */
190     public function copy_to_area($encoded, $filerecord, $maxbytes = -1) {
191         global $USER;
193         $user_context = get_context_instance(CONTEXT_USER, $USER->id);
195         $filerecord = (array)$filerecord;
196         // make sure the new file will be created in user draft area
197         $filerecord['component'] = 'user'; // make sure
198         $filerecord['filearea'] = 'draft'; // make sure
199         $filerecord['contextid'] = $user_context->id;
200         $filerecord['sortorder'] = 0;
201         $draftitemid = $filerecord['itemid'];
202         $new_filepath = $filerecord['filepath'];
203         $new_filename = $filerecord['filename'];
205         $fs = get_file_storage();
207         $params = unserialize(base64_decode($encoded));
209         $contextid  = clean_param($params['contextid'], PARAM_INT);
210         $fileitemid = clean_param($params['itemid'],    PARAM_INT);
211         $filename   = clean_param($params['filename'],  PARAM_FILE);
212         $filepath   = clean_param($params['filepath'],  PARAM_PATH);;
213         $filearea   = clean_param($params['filearea'],  PARAM_AREA);
214         $component  = clean_param($params['component'], PARAM_COMPONENT);
216         // XXX:
217         // When user try to pick a file from other filearea, normally file api will use file browse to
218         // operate the files with capability check, but in some areas, users don't have permission to
219         // browse the files (for example, forum_attachment area).
220         //
221         // To get 'recent' plugin working, we need to use lower level file_stoarge class to bypass the
222         // capability check, we will use a better workaround to improve it.
223         // TODO MDL-33297 apply here
224         if ($stored_file = $fs->get_file($contextid, $component, $filearea, $fileitemid, $filepath, $filename)) {
225             // verify user id
226             if ($USER->id != $stored_file->get_userid()) {
227                 throw new moodle_exception('errornotyourfile', 'repository');
228             }
229             if ($maxbytes !== -1 && $stored_file->get_filesize() > $maxbytes) {
230                 throw new file_exception('maxbytes');
231             }
233             // test if file already exists
234             if (repository::draftfile_exists($draftitemid, $new_filepath, $new_filename)) {
235                 // create new file
236                 $unused_filename = repository::get_unused_filename($draftitemid, $new_filepath, $new_filename);
237                 $filerecord['filename'] = $unused_filename;
238                 // create a tmp file
239                 $fs->create_file_from_storedfile($filerecord, $stored_file);
240                 $event = array();
241                 $event['event'] = 'fileexists';
242                 $event['newfile'] = new stdClass;
243                 $event['newfile']->filepath = $new_filepath;
244                 $event['newfile']->filename = $unused_filename;
245                 $event['newfile']->url = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $unused_filename)->out();
246                 $event['existingfile'] = new stdClass;
247                 $event['existingfile']->filepath = $new_filepath;
248                 $event['existingfile']->filename = $new_filename;
249                 $event['existingfile']->url      = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $new_filename)->out();;
250                 return $event;
251             } else {
252                 $fs->create_file_from_storedfile($filerecord, $stored_file);
253                 $info = array();
254                 $info['title']  = $new_filename;
255                 $info['file']  = $new_filename;
256                 $info['itemid'] = $draftitemid;
257                 $info['filesize']  = $stored_file->get_filesize();
258                 $info['url'] = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $new_filename)->out();;
259                 $info['contextid'] = $user_context->id;
260                 return $info;
261             }
262         }
263         return false;
265     }
267     /**
268      * Does this repository used to browse moodle files?
269      *
270      * @return boolean
271      */
272     public function has_moodle_files() {
273         return true;
274     }