MDL-31830 course: improvements to JS coding style
[moodle.git] / course / management.php
CommitLineData
5dc361e1
SH
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/>.
16
17/**
18 * Course and category management interfaces.
19 *
20 * @package core_course
21 * @copyright 2013 Sam Hemelryk
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24
25require_once('../config.php');
26require_once($CFG->dirroot.'/lib/coursecatlib.php');
27require_once($CFG->dirroot.'/course/lib.php');
28
29$categoryid = optional_param('categoryid', null, PARAM_INT);
30$courseid = optional_param('courseid', null, PARAM_INT);
31$action = optional_param('action', false, PARAM_ALPHA);
32$page = optional_param('page', 0, PARAM_INT);
33$perpage = optional_param('perpage', null, PARAM_INT);
34$viewmode = optional_param('view', 'default', PARAM_ALPHA); // Can be one of default, combined, courses, or categories.
35
36// Search related params.
37$search = optional_param('search', '', PARAM_RAW); // Search words. Shortname, fullname, idnumber and summary get searched.
38$blocklist = optional_param('blocklist', 0, PARAM_INT); // Find courses containing this block.
39$modulelist = optional_param('modulelist', '', PARAM_PLUGIN); // Find courses containing the given modules.
40
41$issearching = ($search !== '' || $blocklist !== 0 || $modulelist !== '');
42if ($issearching) {
43 $viewmode = 'courses';
44}
45
46$url = new moodle_url('/course/management.php');
47navigation_node::override_active_url($url);
b488058f 48$systemcontext = $context = context_system::instance();
5dc361e1
SH
49if ($courseid) {
50 $record = get_course($courseid);
51 $course = new course_in_list($record);
52 $category = coursecat::get($course->category);
53 $categoryid = $category->id;
b488058f 54 $context = context_coursecat::instance($category->id);
5dc361e1
SH
55 $url->param('courseid', $course->id);
56} else if ($categoryid) {
57 $courseid = null;
58 $course = null;
59 $category = coursecat::get($categoryid);
b488058f 60 $context = context_coursecat::instance($category->id);
5dc361e1
SH
61 $url->param('categoryid', $category->id);
62} else {
63 $course = null;
64 $courseid = null;
65 $category = null;
66 $categoryid = null;
67 if ($viewmode === 'default') {
68 $viewmode = 'categories';
69 }
b488058f 70 $context = $systemcontext;
5dc361e1
SH
71}
72if ($page !== 0) {
73 $url->param('page', $page);
74}
75if ($viewmode !== 'default') {
76 $url->param('view', $viewmode);
77}
78if ($search !== '') {
79 $url->param('search', $search);
80}
81if ($blocklist !== 0) {
82 $url->param('blocklist', $search);
83}
84if ($modulelist !== '') {
85 $url->param('modulelist', $search);
86}
87
b488058f 88$title = format_string($SITE->fullname, true, array('context' => $systemcontext));
5dc361e1
SH
89
90$PAGE->set_context($context);
91$PAGE->set_url($url);
92$PAGE->set_pagelayout('admin');
93$PAGE->set_title($title);
94$PAGE->set_heading($title);
95
b488058f
SH
96// If the user poses any of these capabilities then they will be able to see the admin
97// tree and the management link within it.
98// This is the most accurate form of navigation.
99$capabilities = array(
100 'moodle/site:config',
101 'moodle/backup:backupcourse',
102 'moodle/category:manage',
103 'moodle/course:create',
104 'moodle/site:approvecourse'
105);
106if ($category && !has_any_capability($capabilities, $systemcontext)) {
107 // If the user doesn't poses any of these system capabilities then we're going to trigger
108 // the page to set the specific category being viewed.
109 // This will at least give the page some relevant navigation.
110 $PAGE->set_category_by_id($category->id);
111 navigation_node::override_active_url(new moodle_url('/course/management.php', array('categoryid' => $category->id)));
112} else if (!$issearching && $category !== null) {
5dc361e1
SH
113 $parents = coursecat::get_many($category->get_parents());
114 foreach ($parents as $parent) {
115 $PAGE->navbar->add($parent->get_formatted_name());
116 }
117 $PAGE->navbar->add($category->get_formatted_name());
118 if ($course instanceof course_in_list) {
119 // Use the list name so that it matches whats being displayed below.
120 $PAGE->navbar->add($course->get_formatted_name());
121 }
122}
123
b488058f 124// This is a system level page that operates on other contexts.
5dc361e1
SH
125require_login();
126
127$notificationspass = array();
128$notificationsfail = array();
129
130if ($action !== false && confirm_sesskey()) {
131 // Actions:
132 // - resortcategories : Resort the courses in the given category.
133 // - resortcourses : Resort courses
134 // - showcourse : make a course visible.
135 // - hidecourse : make a course hidden.
136 // - movecourseup : move the selected course up one.
137 // - movecoursedown : move the selected course down.
138 // - showcategory : make a category visible.
139 // - hidecategory : make a category hidden.
140 // - movecategoryup : move category up.
141 // - movecategorydown : move category down.
142 // - deletecategory : delete the category either in full, or moving contents.
143 // - bulkaction : performs bulk actions:
144 // - bulkmovecourses.
145 // - bulkmovecategories.
146 // - bulkresortcategories.
147 $redirectback = false;
148 switch ($action) {
149 case 'resortcategories' :
150 $sort = required_param('resort', PARAM_ALPHA);
b488058f
SH
151 $cattosort = coursecat::get((int)optional_param('categoryid', 0, PARAM_INT));
152 $redirectback = \core_course\management\helper::action_category_resort_subcategories($cattosort, $sort);
5dc361e1
SH
153 break;
154 case 'resortcourses' :
155 // They must have specified a category.
156 required_param('categoryid', PARAM_INT);
157 $sort = required_param('resort', PARAM_ALPHA);
158 \core_course\management\helper::action_category_resort_courses($category, $sort);
159 break;
160 case 'showcourse' :
161 $redirectback = \core_course\management\helper::action_course_show($course);
162 break;
163 case 'hidecourse' :
164 $redirectback = \core_course\management\helper::action_course_hide($course);
165 break;
166 case 'movecourseup' :
167 // They must have specified a category and a course.
168 required_param('categoryid', PARAM_INT);
169 required_param('courseid', PARAM_INT);
5aff38e4 170 $redirectback = \core_course\management\helper::action_course_change_sortorder_up_one($course, $category);
5dc361e1
SH
171 break;
172 case 'movecoursedown' :
173 // They must have specified a category and a course.
174 required_param('categoryid', PARAM_INT);
175 required_param('courseid', PARAM_INT);
5aff38e4 176 $redirectback = \core_course\management\helper::action_course_change_sortorder_down_one($course, $category);
5dc361e1
SH
177 break;
178 case 'showcategory' :
179 // They must have specified a category.
180 required_param('categoryid', PARAM_INT);
181 $redirectback = \core_course\management\helper::action_category_show($category);
182 break;
183 case 'hidecategory' :
184 // They must have specified a category.
185 required_param('categoryid', PARAM_INT);
186 $redirectback = \core_course\management\helper::action_category_hide($category);
187 break;
188 case 'movecategoryup' :
189 // They must have specified a category.
190 required_param('categoryid', PARAM_INT);
5aff38e4 191 $redirectback = \core_course\management\helper::action_category_change_sortorder_up_one($category);
5dc361e1
SH
192 break;
193 case 'movecategorydown' :
194 // They must have specified a category.
195 required_param('categoryid', PARAM_INT);
5aff38e4 196 $redirectback = \core_course\management\helper::action_category_change_sortorder_down_one($category);
5dc361e1
SH
197 break;
198 case 'deletecategory':
199 // They must have specified a category.
200 required_param('categoryid', PARAM_INT);
201 if (!$category->can_delete()) {
202 throw new moodle_exception('permissiondenied', 'error', '', null, 'coursecat::can_resort');
203 }
204 require_once($CFG->dirroot.'/course/delete_category_form.php');
67e1f268 205 $mform = new core_course_deletecategory_form(null, $category);
5dc361e1
SH
206 if ($mform->is_cancelled()) {
207 redirect(new moodle_url('/course/management.php'));
208 }
209 // Start output.
210 /* @var core_course_management_renderer|core_renderer $renderer */
211 $renderer = $PAGE->get_renderer('core_course', 'management');
212 echo $renderer->header();
213 echo $renderer->heading(get_string('deletecategory', 'moodle', $category->get_formatted_name()));
214
215 if ($data = $mform->get_data()) {
216 // The form has been submit handle it.
217 if ($data->fulldelete == 1 && $category->can_delete_full()) {
218 $continueurl = new moodle_url('/course/management.php', array('categoryid' => $category->parent));
219 $notification = get_string('coursecategorydeleted', '', $category->get_formatted_name());
220 $deletedcourses = $category->delete_full(true);
221 foreach ($deletedcourses as $course) {
222 echo $renderer->notification(get_string('coursedeleted', '', $course->shortname), 'notifysuccess');
223 }
224 echo $renderer->notification($notification, 'notifysuccess');
225 echo $renderer->continue_button($continueurl);
226 } else if ($data->fulldelete == 0 && $category->can_move_content_to($data->newparent)) {
227 $continueurl = new moodle_url('/course/management.php', array('categoryid' => $data->newparent));
228 $category->delete_move($data->newparent, true);
229 echo $renderer->continue_button($continueurl);
230 } else {
231 // Some error in parameters (user is cheating?)
232 $mform->display();
233 }
234 } else {
235 // Display the form.
236 $mform->display();
237 }
238 // Finish output and exit.
239 echo $renderer->footer();
240 exit();
241 break;
242 case 'bulkaction':
243 $bulkmovecourses = optional_param('bulkmovecourses', false, PARAM_BOOL);
244 $bulkmovecategories = optional_param('bulkmovecategories', false, PARAM_BOOL);
245 $bulkresortcategories = optional_param('bulkresortcategories', false, PARAM_BOOL);
246
247 if ($bulkmovecourses) {
248 // Move courses out of the current category and into a new category.
249 // They must have specified a category.
250 required_param('categoryid', PARAM_INT);
251 $movetoid = required_param('movecoursesto', PARAM_INT);
252 $courseids = optional_param_array('bc', false, PARAM_INT);
253 if ($courseids === false) {
254 break;
255 }
256 $moveto = coursecat::get($movetoid);
67e1f268
SH
257 try {
258 // If this fails we want to catch the exception and report it.
259 $redirectback = \core_course\management\helper::action_category_move_courses_into($category, $moveto,
260 $courseids);
261 } catch (moodle_exception $ex) {
262 $redirectback = false;
263 $notificationsfail[] = $ex->getMessage();
264 }
5dc361e1
SH
265 } else if ($bulkmovecategories) {
266 $categoryids = optional_param_array('bcat', false, PARAM_INT);
267 $movetocatid = required_param('movecategoriesto', PARAM_INT);
268 $movetocat = coursecat::get($movetocatid);
269 $movecount = 0;
270 foreach ($categoryids as $id) {
271 $cattomove = coursecat::get($id);
272 if ($id == $movetocatid) {
273 $notificationsfail[] = get_string('movecategoryownparent', 'error', $cattomove->get_formatted_name());
274 continue;
275 }
276 if (strpos($movetocat->path, $cattomove->path) === 0) {
277 $notificationsfail[] = get_string('movecategoryparentconflict', 'error', $cattomove->get_formatted_name());
278 continue;
279 }
280 if ($cattomove->parent != $movetocatid) {
281 if ($cattomove->can_change_parent($movetocatid)) {
282 $cattomove->change_parent($movetocatid);
283 $movecount++;
284 } else {
285 $notificationsfail[] = get_string('movecategorynotpossible', 'error', $cattomove->get_formatted_name());
286 }
287 }
288 }
289 if ($movecount > 1) {
290 $a = new stdClass;
291 $a->count = $movecount;
292 $a->to = $movetocat->get_formatted_name();
293 $notificationspass[] = get_string('movecategoriessuccess', 'moodle', $a);
294 } else if ($movecount === 1) {
295 $a = new stdClass;
296 $a->moved = $cattomove->get_formatted_name();
297 $a->to = $movetocat->get_formatted_name();
298 $notificationspass[] = get_string('movecategorysuccess', 'moodle', $a);
299 }
300 } else if ($bulkresortcategories) {
301 // Bulk resort selected categories.
302 $categoryids = optional_param_array('bcat', false, PARAM_INT);
303 $sort = required_param('resortcategoriesby', PARAM_ALPHA);
304 if ($categoryids === false) {
305 break;
306 }
307 $categories = coursecat::get_many($categoryids);
308 foreach ($categories as $cat) {
309 // Don't clean up here, we'll do it once we're all done.
310 \core_course\management\helper::action_category_resort_subcategories($cat, $sort, false);
311 }
312 coursecat::resort_categories_cleanup();
b488058f
SH
313 if ($category === null && count($categoryids) === 1) {
314 // They're bulk sorting just a single category and they've not selected a category.
315 // Lets for convenience sake auto-select the category that has been resorted for them.
316 redirect(new moodle_url($PAGE->url, array('categoryid' => reset($categoryids))));
317 }
5dc361e1
SH
318 }
319 }
320 if ($redirectback) {
321 redirect($PAGE->url);
322 }
323}
324
325if (!is_null($perpage)) {
326 set_user_preference('coursecat_management_perpage', $perpage);
327} else {
328 $perpage = get_user_preferences('coursecat_management_perpage', $CFG->coursesperpage);
329}
330if ((int)$perpage != $perpage || $perpage < 2) {
331 $perpage = $CFG->coursesperpage;
332}
333
334$categorysize = 4;
335$coursesize = 4;
336$detailssize = 4;
337if ($viewmode === 'default' || $viewmode === 'combined') {
338 if (isset($courseid)) {
339 $class = 'columns-3';
340 } else {
341 $categorysize = 5;
342 $coursesize = 7;
343 $class = 'columns-2';
344 }
345} else if ($viewmode === 'categories') {
346 $categorysize = 12;
347 $class = 'columns-1';
348} else if ($viewmode === 'courses') {
349 if (isset($courseid)) {
350 $coursesize = 6;
351 $detailssize = 6;
352 $class = 'columns-2';
353 } else {
354 $coursesize = 12;
355 $class = 'columns-1';
356 }
357}
358
359/* @var core_course_management_renderer|core_renderer $renderer */
360$renderer = $PAGE->get_renderer('core_course', 'management');
361$renderer->enhance_management_interface();
362
363echo $renderer->header();
364
365if (!$issearching) {
366 echo $renderer->management_heading(new lang_string('coursecatmanagement'), $viewmode, $categoryid);
367} else {
368 echo $renderer->management_heading(new lang_string('searchresults'));
369}
370
371if (count($notificationspass) > 0) {
372 echo $renderer->notification(join('<br />', $notificationspass), 'notifysuccess');
373}
374if (count($notificationsfail) > 0) {
375 echo $renderer->notification(join('<br />', $notificationsfail));
376}
377
378// Start the management form.
379echo $renderer->management_form_start();
380
381echo $renderer->grid_start('course-category-listings', $class);
382if ($viewmode === 'default' || $viewmode === 'combined' || $viewmode === 'categories') {
383 echo $renderer->grid_column_start($categorysize, 'category-listing');
384 echo $renderer->category_listing($category);
385 echo $renderer->grid_column_end();
386}
387if ($viewmode === 'default' || $viewmode === 'combined' || $viewmode === 'courses') {
388 echo $renderer->grid_column_start($coursesize, 'course-listing');
389 if (!$issearching) {
390 echo $renderer->course_listing($category, $course, $page, $perpage);
391 } else {
392 list($courses, $coursescount, $coursestotal) =
393 \core_course\management\helper::search_courses($search, $blocklist, $modulelist, $page, $perpage);
394 echo $renderer->search_listing($courses, $coursestotal, $course, $page, $perpage);
395 }
396 echo $renderer->grid_column_end();
397 if (isset($courseid)) {
398 echo $renderer->grid_column_start($detailssize, 'course-detail');
399 echo $renderer->course_detail($course);
400 echo $renderer->grid_column_end();
401 }
402}
403echo $renderer->grid_end();
404
405if (!empty($CFG->enablecourserequests) && $id == $CFG->defaultrequestcategory) {
406 print_course_request_buttons(context_system::instance());
407}
408
409// End of the management form.
410echo $renderer->management_form_end();
411echo $renderer->footer();