MDL-33741 file_info: show courses in hidden categories
[moodle.git] / lib / filebrowser / file_info_context_system.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
18 /**
19  * Utility class for browsing of system files.
20  *
21  * @package    core_files
22  * @copyright  2008 Petr Skoda (http://skodak.org)
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
28 /**
29  * Represents the system context in the tree navigated by {@link file_browser}.
30  *
31  * @package    core_files
32  * @copyright  2008 Petr Skoda (http://skodak.org)
33  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
34  */
35 class file_info_context_system extends file_info {
37     /**
38      * Constructor
39      *
40      * @param file_browser $browser file_browser instance
41      * @param stdClass $context context object
42      */
43     public function __construct($browser, $context) {
44         parent::__construct($browser, $context);
45     }
47     /**
48      * Return information about this specific part of context level
49      *
50      * @param string $component component
51      * @param string $filearea file area
52      * @param int $itemid item ID
53      * @param string $filepath file path
54      * @param string $filename file name
55      * @return file_info|null file_info instance or null if not found or access not allowed
56      */
57     public function get_file_info($component, $filearea, $itemid, $filepath, $filename) {
58         if (empty($component)) {
59             return $this;
60         }
62         $methodname = "get_area_{$component}_{$filearea}";
64         if (method_exists($this, $methodname)) {
65             return $this->$methodname($itemid, $filepath, $filename);
66         }
68         return null;
69     }
71     /**
72      * Gets a stored file for the backup course filearea directory.
73      *
74      * @param int $itemid item ID
75      * @param string $filepath file path
76      * @param string $filename file name
77      * @return file_info|null file_info instance or null if not found or access not allowed
78      */
79     protected function get_area_backup_course($itemid, $filepath, $filename) {
80         global $CFG;
82         if (!isloggedin()) {
83             return null;
84         }
86         if (!has_any_capability(array('moodle/backup:backupcourse', 'moodle/restore:restorecourse'), $this->context)) {
87             return null;
88         }
90         if (is_null($itemid)) {
91             return $this;
92         }
94         $fs = get_file_storage();
96         $filepath = is_null($filepath) ? '/' : $filepath;
97         $filename = is_null($filename) ? '.' : $filename;
98         if (!$storedfile = $fs->get_file($this->context->id, 'backup', 'course', 0, $filepath, $filename)) {
99             if ($filepath === '/' && $filename === '.') {
100                 $storedfile = new virtual_root_file($this->context->id, 'backup', 'course', 0);
101             } else {
102                 // Not found.
103                 return null;
104             }
105         }
107         $downloadable = has_capability('moodle/backup:downloadfile', $this->context);
108         $uploadable = has_capability('moodle/restore:uploadfile', $this->context);
110         $urlbase = $CFG->wwwroot . '/pluginfile.php';
111         return new file_info_stored($this->browser, $this->context, $storedfile, $urlbase,
112             get_string('coursebackup', 'repository'), false, $downloadable, $uploadable, false);
113     }
115     /**
116      * Returns localised visible name.
117      *
118      * @return string
119      */
120     public function get_visible_name() {
121         return get_string('arearoot', 'repository');
122     }
124     /**
125      * Whether or not new files or directories can be added
126      *
127      * @return bool
128      */
129     public function is_writable() {
130         return false;
131     }
133     /**
134      * Whether or not this is a directory
135      *
136      * @return bool
137      */
138     public function is_directory() {
139         return true;
140     }
142     /**
143      * Returns list of children.
144      *
145      * @return array of file_info instances
146      */
147     public function get_children() {
148         global $DB;
150         $children = array();
152         // Add course categories on the top level that are either visible or user is able to view hidden categories.
153         $course_cats = $DB->get_records('course_categories', array('parent'=>0), 'sortorder', 'id,visible');
154         foreach ($course_cats as $category) {
155             $context = context_coursecat::instance($category->id);
156             if (!$category->visible and !has_capability('moodle/category:viewhiddencategories', $context)) {
157                 continue;
158             }
159             if ($child = $this->browser->get_file_info($context)) {
160                 $children[] = $child;
161             }
162         }
164         // Add courses where user is enrolled that are located in hidden course categories because they would not
165         // be present in the above tree but user may still be able to access files in them.
166         if ($hiddencontexts = $this->get_inaccessible_coursecat_contexts()) {
167             $courses = enrol_get_my_courses();
168             foreach ($courses as $course) {
169                 $context = context_course::instance($course->id);
170                 $parents = $context->get_parent_context_ids();
171                 if (array_intersect($hiddencontexts, $parents)) {
172                     // This course has hidden parent category.
173                     if ($child = $this->browser->get_file_info($context)) {
174                         $children[] = $child;
175                     }
176                 }
177             }
178         }
180         return $children;
181     }
183     /**
184      * Returns list of course categories contexts that current user can not see
185      *
186      * @return array array of course categories contexts ids
187      */
188     protected function get_inaccessible_coursecat_contexts() {
189         global $DB;
191         $sql = context_helper::get_preload_record_columns_sql('ctx');
192         $records = $DB->get_records_sql("SELECT ctx.id, $sql
193             FROM {course_categories} c
194             JOIN {context} ctx ON c.id = ctx.instanceid AND ctx.contextlevel = ?
195             WHERE c.visible = ?", [CONTEXT_COURSECAT, 0]);
196         $hiddencontexts = [];
197         foreach ($records as $record) {
198             context_helper::preload_from_record($record);
199             $context = context::instance_by_id($record->id);
200             if (!has_capability('moodle/category:viewhiddencategories', $context)) {
201                 $hiddencontexts[] = $record->id;
202             }
203         }
204         return $hiddencontexts;
205     }
207     /**
208      * Returns parent file_info instance
209      *
210      * @return file_info|null file_info instance or null for root
211      */
212     public function get_parent() {
213         return null;
214     }