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