manage.php 29.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
18
 * Allows the admin to create, delete and rename course categories rearrange courses
19
20
21
22
23
24
25
26
 *
 * @package   core
 * @copyright 2013 Marina Glancy
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

require_once("../config.php");
require_once($CFG->dirroot.'/course/lib.php');
27
require_once($CFG->libdir.'/coursecatlib.php');
28

29
30
31
32
33
34
// Category id.
$id = optional_param('id', 0, PARAM_INT);
// Which page to show.
$page = optional_param('page', 0, PARAM_INT);
// How many per page.
$perpage = optional_param('perpage', $CFG->coursesperpage, PARAM_INT);
35

36
// Actions to manage courses.
37
38
39
40
41
42
43
$hide = optional_param('hide', 0, PARAM_INT);
$show = optional_param('show', 0, PARAM_INT);
$moveup = optional_param('moveup', 0, PARAM_INT);
$movedown = optional_param('movedown', 0, PARAM_INT);
$moveto = optional_param('moveto', 0, PARAM_INT);
$resort = optional_param('resort', 0, PARAM_BOOL);

44
45
46
47
48
49
50
51
// Actions to manage categories.
$deletecat = optional_param('deletecat', 0, PARAM_INT);
$hidecat = optional_param('hidecat', 0, PARAM_INT);
$showcat = optional_param('showcat', 0, PARAM_INT);
$movecat = optional_param('movecat', 0, PARAM_INT);
$movetocat = optional_param('movetocat', -1, PARAM_INT);
$moveupcat = optional_param('moveupcat', 0, PARAM_INT);
$movedowncat = optional_param('movedowncat', 0, PARAM_INT);
52
53

require_login();
54

55
56
57
58
// Retrieve coursecat object
// This will also make sure that category is accessible and create default category if missing
$coursecat = coursecat::get($id);

59
60
if ($id) {
    $PAGE->set_category_by_id($id);
61
62
    $PAGE->set_url(new moodle_url('/course/manage.php', array('id' => $id)));
    // This is sure to be the category context.
63
    $context = $PAGE->context;
64
65
    if (!can_edit_in_category($coursecat->id)) {
        redirect(new moodle_url('/course/category.php', array('id' => $coursecat->id)));
66
    }
67
68
69
} else {
    $context = context_system::instance();
    $PAGE->set_context($context);
70
71
    $PAGE->set_url(new moodle_url('/course/manage.php'));
    if (!can_edit_in_category()) {
72
73
74
75
76
77
78
79
        redirect(new moodle_url('/course/index.php'));
    }
}

$canmanage = has_capability('moodle/category:manage', $context);

// Process any category actions.
if (!empty($deletecat) and confirm_sesskey()) {
80
    // Delete a category.
81
    $cattodelete = coursecat::get($deletecat);
82
83
84
85
86
87
    $context = context_coursecat::instance($deletecat);
    require_capability('moodle/category:manage', $context);
    require_capability('moodle/category:manage', get_category_or_system_context($cattodelete->parent));

    $heading = get_string('deletecategory', 'moodle', format_string($cattodelete->name, true, array('context' => $context)));

88
89
    require_once($CFG->dirroot.'/course/delete_category_form.php');
    $mform = new delete_category_form(null, $cattodelete);
90
    if ($mform->is_cancelled()) {
91
        redirect(new moodle_url('/course/manage.php'));
92
93
    }

94
    // Start output.
95
96
97
    echo $OUTPUT->header();
    echo $OUTPUT->heading($heading);

98
99
    if ($data = $mform->get_data()) {
        // The form has been submit handle it.
100
101
102
        if ($data->fulldelete == 1 && $cattodelete->can_delete_full()) {
            $cattodeletename = $cattodelete->get_formatted_name();
            $deletedcourses = $cattodelete->delete_full(true);
103
104
105
            foreach ($deletedcourses as $course) {
                echo $OUTPUT->notification(get_string('coursedeleted', '', $course->shortname), 'notifysuccess');
            }
Dan Poltawski's avatar
Dan Poltawski committed
106
            echo $OUTPUT->notification(get_string('coursecategorydeleted', '', $cattodeletename), 'notifysuccess');
107
            echo $OUTPUT->continue_button(new moodle_url('/course/manage.php'));
108

109
110
111
        } else if ($data->fulldelete == 0 && $cattodelete->can_move_content_to($data->newparent)) {
            $cattodelete->delete_move($data->newparent, true);
            echo $OUTPUT->continue_button(new moodle_url('/course/manage.php'));
112
        } else {
113
114
            // Some error in parameters (user is cheating?)
            $mform->display();
115
116
        }
    } else {
117
118
        // Display the form.
        $mform->display();
119
    }
120
    // Finish output and exit.
121
    echo $OUTPUT->footer();
122
    exit();
123
124
125
}

if (!empty($movecat) and ($movetocat >= 0) and confirm_sesskey()) {
126
    // Move a category to a new parent if required.
127
128
129
130
131
132
    $cattomove = coursecat::get($movecat);
    if ($cattomove->parent != $movetocat) {
        if ($cattomove->can_change_parent($movetocat)) {
            $cattomove->change_parent($movetocat);
        } else {
            print_error('cannotmovecategory');
133
134
135
136
        }
    }
}

137
// Hide or show a category.
138
if ($hidecat and confirm_sesskey()) {
139
140
141
    $cattohide = coursecat::get($hidecat);
    require_capability('moodle/category:manage', get_category_or_system_context($cattohide->parent));
    $cattohide->hide();
142
} else if ($showcat and confirm_sesskey()) {
143
144
145
    $cattoshow = coursecat::get($showcat);
    require_capability('moodle/category:manage', get_category_or_system_context($cattoshow->parent));
    $cattoshow->show();
146
147
148
}

if ((!empty($moveupcat) or !empty($movedowncat)) and confirm_sesskey()) {
149
    // Move a category up or down.
150
    fix_course_sortorder();
151
152
    $swapcategory = null;

153
154
    if (!empty($moveupcat)) {
        require_capability('moodle/category:manage', context_coursecat::instance($moveupcat));
155
        if ($movecategory = $DB->get_record('course_categories', array('id' => $moveupcat))) {
156
            $params = array($movecategory->sortorder, $movecategory->parent);
157
            if ($swapcategory = $DB->get_records_select('course_categories', "sortorder<? AND parent=?", $params, 'sortorder DESC', '*', 0, 1)) {
158
159
160
161
162
                $swapcategory = reset($swapcategory);
            }
        }
    } else {
        require_capability('moodle/category:manage', context_coursecat::instance($movedowncat));
163
        if ($movecategory = $DB->get_record('course_categories', array('id' => $movedowncat))) {
164
            $params = array($movecategory->sortorder, $movecategory->parent);
165
            if ($swapcategory = $DB->get_records_select('course_categories', "sortorder>? AND parent=?", $params, 'sortorder ASC', '*', 0, 1)) {
166
167
168
169
170
                $swapcategory = reset($swapcategory);
            }
        }
    }
    if ($swapcategory and $movecategory) {
171
172
        $DB->set_field('course_categories', 'sortorder', $swapcategory->sortorder, array('id' => $movecategory->id));
        $DB->set_field('course_categories', 'sortorder', $movecategory->sortorder, array('id' => $swapcategory->id));
173
174
175
        add_to_log(SITEID, "category", "move", "editcategory.php?id=$movecategory->id", $movecategory->id);
    }

176
    // Finally reorder courses.
177
178
179
    fix_course_sortorder();
}

180
if ($coursecat->id && $canmanage && $resort && confirm_sesskey()) {
181
    // Resort the category.
182
    if ($courses = get_courses($coursecat->id, '', 'c.id,c.fullname,c.sortorder')) {
183
184
185
        collatorlib::asort_objects_by_property($courses, 'fullname', collatorlib::SORT_NATURAL);
        $i = 1;
        foreach ($courses as $course) {
186
            $DB->set_field('course', 'sortorder', $coursecat->sortorder + $i, array('id' => $course->id));
187
188
            $i++;
        }
189
190
        // This should not be needed but we do it just to be safe.
        fix_course_sortorder();
191
        cache_helper::purge_by_event('changesincourse');
192
193
194
    }
}

195
if (!empty($moveto) && ($data = data_submitted()) && confirm_sesskey()) {
196
197
198
199
    // Move a specified course to a new category.
    // User must have category update in both cats to perform this.
    require_capability('moodle/category:manage', $context);
    require_capability('moodle/category:manage', context_coursecat::instance($moveto));
200

201
202
203
    if (!$destcategory = $DB->get_record('course_categories', array('id' => $data->moveto))) {
        print_error('cannotfindcategory', '', '', $data->moveto);
    }
204

205
206
207
208
209
210
211
212
213
    $courses = array();
    foreach ($data as $key => $value) {
        if (preg_match('/^c\d+$/', $key)) {
            $courseid = substr($key, 1);
            array_push($courses, $courseid);
            // Check this course's category.
            if ($movingcourse = $DB->get_record('course', array('id' => $courseid))) {
                if ($movingcourse->category != $id ) {
                    print_error('coursedoesnotbelongtocategory');
214
                }
215
216
            } else {
                print_error('cannotfindcourse');
217
218
219
            }
        }
    }
220
221
    move_courses($courses, $data->moveto);
}
222

223
224
225
226
227
228
229
230
if ((!empty($hide) or !empty($show)) && confirm_sesskey()) {
    // Hide or show a course.
    if (!empty($hide)) {
        $course = $DB->get_record('course', array('id' => $hide), '*', MUST_EXIST);
        $visible = 0;
    } else {
        $course = $DB->get_record('course', array('id' => $show), '*', MUST_EXIST);
        $visible = 1;
231
    }
232
233
234
235
236
    $coursecontext = context_course::instance($course->id);
    require_capability('moodle/course:visibility', $coursecontext);
    // Set the visibility of the course. we set the old flag when user manually changes visibility of course.
    $params = array('id' => $course->id, 'visible' => $visible, 'visibleold' => $visible, 'timemodified' => time());
    $DB->update_record('course', $params);
237
    cache_helper::purge_by_event('changesincourse');
238
239
    add_to_log($course->id, "course", ($visible ? 'show' : 'hide'), "edit.php?id=$course->id", $course->id);
}
240

241
242
243
if ((!empty($moveup) or !empty($movedown)) && confirm_sesskey()) {
    // Move a course up or down.
    require_capability('moodle/category:manage', $context);
244

245
246
247
    // Ensure the course order has continuous ordering.
    fix_course_sortorder();
    $swapcourse = null;
248

249
250
251
    if (!empty($moveup)) {
        if ($movecourse = $DB->get_record('course', array('id' => $moveup))) {
            $swapcourse = $DB->get_record('course', array('sortorder' => $movecourse->sortorder - 1));
252
        }
253
254
255
    } else {
        if ($movecourse = $DB->get_record('course', array('id' => $movedown))) {
            $swapcourse = $DB->get_record('course', array('sortorder' => $movecourse->sortorder + 1));
256
257
        }
    }
258
259
260
261
262
263
264
    if ($swapcourse and $movecourse) {
        // Check course's category.
        if ($movecourse->category != $id) {
            print_error('coursedoesnotbelongtocategory');
        }
        $DB->set_field('course', 'sortorder', $swapcourse->sortorder, array('id' => $movecourse->id));
        $DB->set_field('course', 'sortorder', $movecourse->sortorder, array('id' => $swapcourse->id));
265
        cache_helper::purge_by_event('changesincourse');
266
267
268
        add_to_log($movecourse->id, "course", "move", "edit.php?id=$movecourse->id", $movecourse->id);
    }
}
269
270
271
272
273
274
275
276
277
278
279

// Prepare the standard URL params for this page. We'll need them later.
$urlparams = array('id' => $id);
if ($page) {
    $urlparams['page'] = $page;
}
if ($perpage) {
    $urlparams['perpage'] = $perpage;
}

$PAGE->set_pagelayout('coursecategory');
280

281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
if (can_edit_in_category()) {
    // Integrate into the admin tree only if the user can edit categories at the top level,
    // otherwise the admin block does not appear to this user, and you get an error.
    require_once($CFG->libdir . '/adminlib.php');
    if ($id) {
        navigation_node::override_active_url(new moodle_url('/course/category.php', array('id' => $id)));
    }
    admin_externalpage_setup('coursemgmt', '', $urlparams, $CFG->wwwroot . '/course/manage.php');
    $settingsnode = $PAGE->settingsnav->find_active_node();
    if ($id && $settingsnode) {
        $settingsnode->make_inactive();
        $settingsnode->force_open();
        $PAGE->navbar->add($settingsnode->text, $settingsnode->action);
    }
} else {
    $site = get_site();
297
    $PAGE->set_title("$site->shortname: $coursecat->name");
298
299
300
301
    $PAGE->set_heading($site->fullname);
    $PAGE->set_button(print_course_search('', true, 'navbar'));
}

302
$displaylist[0] = get_string('top');
303

304
305
// Start output.
echo $OUTPUT->header();
306

307
if (!$coursecat->id) {
308
309
310
311
312
313
314
315
    // Print out the categories with all the knobs.
    $table = new html_table;
    $table->id = 'coursecategories';
    $table->attributes['class'] = 'admintable generaltable editcourse';
    $table->head = array(
        get_string('categories'),
        get_string('courses'),
        get_string('edit'),
316
        get_string('movecategoryto'),
317
318
319
320
321
322
323
324
    );
    $table->colclasses = array(
        'leftalign name',
        'centeralign count',
        'centeralign icons',
        'leftalign actions'
    );
    $table->data = array();
325

326
    print_category_edit($table, $coursecat);
327

328
    echo html_writer::table($table);
329
} else {
330
    // Print the category selector.
331
    $select = new single_select(new moodle_url('/course/manage.php'), 'id', $displaylist, $coursecat->id, null, 'switchcategory');
332
    $select->set_label(get_string('categories').':');
333
334

    echo html_writer::start_tag('div', array('class' => 'categorypicker'));
335
    echo $OUTPUT->render($select);
336
    echo html_writer::end_tag('div');
337
338
339
340
}

if ($canmanage) {
    echo $OUTPUT->container_start('buttons');
341
342
343
    // Print button to update this category.
    if ($id) {
        $url = new moodle_url('/course/editcategory.php', array('id' => $id));
344
345
346
        echo $OUTPUT->single_button($url, get_string('editcategorythis'), 'get');
    }

347
348
    // Print button for creating new categories.
    $url = new moodle_url('/course/editcategory.php', array('parent' => $id));
349
350
351
352
353
354
    if ($id) {
        $title = get_string('addsubcategory');
    } else {
        $title = get_string('addnewcategory');
    }
    echo $OUTPUT->single_button($url, $title, 'get');
355
356
357
    echo $OUTPUT->container_end();
}

358
if ($coursecat->id) {
359
360
361
    // Print out all the sub-categories (plain mode).
    // In order to view hidden subcategories the user must have the viewhiddencategories.
    // capability in the current category..
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
    if (has_capability('moodle/category:viewhiddencategories', $context)) {
        $categorywhere = '';
    } else {
        $categorywhere = 'AND cc.visible = 1';
    }
    // We're going to preload the context for the subcategory as we know that we
    // need it later on for formatting.
    $ctxselect = context_helper::get_preload_record_columns_sql('ctx');
    $sql = "SELECT cc.*, $ctxselect
              FROM {course_categories} cc
              JOIN {context} ctx ON cc.id = ctx.instanceid
             WHERE cc.parent = :parentid AND
                   ctx.contextlevel = :contextlevel
                   $categorywhere
          ORDER BY cc.sortorder ASC";
377
    $subcategories = $DB->get_recordset_sql($sql, array('parentid' => $coursecat->id, 'contextlevel' => CONTEXT_COURSECAT));
378
379
    // Prepare a table to display the sub categories.
    $table = new html_table;
380
381
382
383
384
385
    $table->attributes = array(
        'border' => '0',
        'cellspacing' => '2',
        'cellpadding' => '4',
        'class' => 'generalbox boxaligncenter category_subcategories'
    );
386
387
388
389
390
391
392
    $table->head = array(new lang_string('subcategories'));
    $table->data = array();
    $baseurl = new moodle_url('/course/manage.php');
    foreach ($subcategories as $subcategory) {
        // Preload the context we will need it to format the category name shortly.
        context_helper::preload_from_record($subcategory);
        $context = context_coursecat::instance($subcategory->id);
393
        // Prepare the things we need to create a link to the subcategory.
394
395
        $attributes = $subcategory->visible ? array() : array('class' => 'dimmed');
        $text = format_string($subcategory->name, true, array('context' => $context));
396
        // Add the subcategory to the table.
397
398
399
400
401
402
403
404
405
        $baseurl->param('id', $subcategory->id);
        $table->data[] = array(html_writer::link($baseurl, $text, $attributes));
    }

    $subcategorieswereshown = (count($table->data) > 0);
    if ($subcategorieswereshown) {
        echo html_writer::table($table);
    }

406
    $courses = get_courses_page($coursecat->id, 'c.sortorder ASC',
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
            'c.id,c.sortorder,c.shortname,c.fullname,c.summary,c.visible',
            $totalcount, $page*$perpage, $perpage);
    $numcourses = count($courses);
} else {
    $subcategorieswereshown = true;
    $courses = array();
    $numcourses = $totalcount = 0;
}

if (!$courses) {
    // There is no course to display.
    if (empty($subcategorieswereshown)) {
        echo $OUTPUT->heading(get_string("nocoursesyet"));
    }
} else {
422
423
424
425
426
427
428
429
430
431
    // Display a basic list of courses with paging/editing options.
    $table = new html_table;
    $table->attributes = array('border' => 0, 'cellspacing' => 0, 'cellpadding' => '4', 'class' => 'generalbox boxaligncenter');
    $table->head = array(
        get_string('courses'),
        get_string('edit'),
        get_string('select')
    );
    $table->colclasses = array(null, null, 'mdl-align');
    $table->data = array();
432
433

    $count = 0;
434
    $abletomovecourses = false;
435
436

    // Checking if we are at the first or at the last page, to allow courses to
437
    // be moved up and down beyond the paging border.
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
    if ($totalcount > $perpage) {
        $atfirstpage = ($page == 0);
        if ($perpage > 0) {
            $atlastpage = (($page + 1) == ceil($totalcount / $perpage));
        } else {
            $atlastpage = true;
        }
    } else {
        $atfirstpage = true;
        $atlastpage = true;
    }

    $baseurl = new moodle_url('/course/manage.php', $urlparams + array('sesskey' => sesskey()));
    foreach ($courses as $acourse) {
        $coursecontext = context_course::instance($acourse->id);

        $count++;
        $up = ($count > 1 || !$atfirstpage);
        $down = ($count < $numcourses || !$atlastpage);

458
459
460
        $courseurl = new moodle_url('/course/view.php', array('id' => $acourse->id));
        $attributes = array();
        $attributes['class'] = $acourse->visible ? '' : 'dimmed';
461
        $coursename = get_course_display_name_for_list($acourse);
462
463
464
465
466
        $coursename = format_string($coursename, true, array('context' => $coursecontext));
        $coursename = html_writer::link($courseurl, $coursename, $attributes);

        $icons = array();
        // Update course icon.
467
468
        if (has_capability('moodle/course:update', $coursecontext)) {
            $url = new moodle_url('/course/edit.php', array('id' => $acourse->id, 'category' => $id, 'returnto' => 'catmanage'));
469
            $icons[] = $OUTPUT->action_icon($url, new pix_icon('t/edit', get_string('settings')));
470
471
        }

472
        // Role assignment icon.
473
474
        if (has_capability('moodle/course:enrolreview', $coursecontext)) {
            $url = new moodle_url('/enrol/users.php', array('id' => $acourse->id));
475
            $icons[] = $OUTPUT->action_icon($url, new pix_icon('t/enrolusers', get_string('enrolledusers', 'enrol')));
476
477
        }

478
        // Delete course icon.
479
480
        if (can_delete_course($acourse->id)) {
            $url = new moodle_url('/course/delete.php', array('id' => $acourse->id));
481
            $icons[] = $OUTPUT->action_icon($url, new pix_icon('t/delete', get_string('delete')));
482
483
        }

484
485
        // Change visibility.
        // Users with no capability to view hidden courses, should not be able to lock themselves out.
486
        if (has_any_capability(array('moodle/course:visibility', 'moodle/course:viewhiddencourses'), $coursecontext)) {
487
488
            if (!empty($acourse->visible)) {
                $url = new moodle_url($baseurl, array('hide' => $acourse->id));
489
                $icons[] = $OUTPUT->action_icon($url, new pix_icon('t/hide', get_string('hide')));
490
491
            } else {
                $url = new moodle_url($baseurl, array('show' => $acourse->id));
492
                $icons[] = $OUTPUT->action_icon($url, new pix_icon('t/show', get_string('show')));
493
494
495
            }
        }

496
        // Backup course icon.
497
498
        if (has_capability('moodle/backup:backupcourse', $coursecontext)) {
            $url = new moodle_url('/backup/backup.php', array('id' => $acourse->id));
499
            $icons[] = $OUTPUT->action_icon($url, new pix_icon('t/backup', get_string('backup')));
500
501
        }

502
        // Restore course icon.
503
504
        if (has_capability('moodle/restore:restorecourse', $coursecontext)) {
            $url = new moodle_url('/backup/restorefile.php', array('contextid' => $coursecontext->id));
505
            $icons[] = $OUTPUT->action_icon($url, new pix_icon('t/restore', get_string('restore')));
506
507
508
509
510
        }

        if ($canmanage) {
            if ($up) {
                $url = new moodle_url($baseurl, array('moveup' => $acourse->id));
511
                $icons[] = $OUTPUT->action_icon($url, new pix_icon('t/up', get_string('moveup')));
512
513
514
            }
            if ($down) {
                $url = new moodle_url($baseurl, array('movedown' => $acourse->id));
515
                $icons[] = $OUTPUT->action_icon($url, new pix_icon('t/down', get_string('movedown')));
516
517
518
519
            }
            $abletomovecourses = true;
        }

520
521
522
523
524
        $table->data[] = new html_table_row(array(
            new html_table_cell($coursename),
            new html_table_cell(join('', $icons)),
            new html_table_cell(html_writer::empty_tag('input', array('type' => 'checkbox', 'name' => 'c'.$acourse->id)))
        ));
525
526
527
    }

    if ($abletomovecourses) {
528
        $movetocategories = coursecat::make_categories_list('moodle/category:manage');
529
530
531
532
533
534
535
536
        $movetocategories[$id] = get_string('moveselectedcoursesto');

        $cell = new html_table_cell();
        $cell->colspan = 3;
        $cell->attributes['class'] = 'mdl-right';
        $cell->text = html_writer::label(get_string('moveselectedcoursesto'), 'movetoid', false, array('class' => 'accesshide'));
        $cell->text .= html_writer::select($movetocategories, 'moveto', $id, null, array('id'=>'movetoid', 'class' => 'autosubmit'));
        $cell->text .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'id', 'value' => $id));
537
538
        $PAGE->requires->yui_module('moodle-core-formautosubmit',
            'M.core.init_formautosubmit',
539
            array(array('selectid' => 'movetoid', 'nothing' => $id))
540
        );
541
        $table->data[] = new html_table_row(array($cell));
542
543
    }

544
545
546
547
548
549
550
551
552
553
554
    $actionurl = new moodle_url('/course/manage.php');
    $pagingurl = new moodle_url('/course/manage.php', array('id' => $id, 'perpage' => $perpage));

    echo $OUTPUT->paging_bar($totalcount, $page, $perpage, $pagingurl);
    echo html_writer::start_tag('form', array('id' => 'movecourses', 'action' => $actionurl, 'method' => 'post'));
    echo html_writer::start_tag('div');
    echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()));
    echo html_writer::table($table);
    echo html_writer::end_tag('div');
    echo html_writer::end_tag('form');
    echo html_writer::empty_tag('br');
555
556
}

557
echo html_writer::start_tag('div', array('class' => 'buttons'));
558
if ($canmanage and $numcourses > 1) {
559
560
    // Print button to re-sort courses by name.
    $url = new moodle_url('/course/manage.php', array('id' => $id, 'resort' => 'name', 'sesskey' => sesskey()));
561
562
563
564
    echo $OUTPUT->single_button($url, get_string('resortcoursesbyname'), 'get');
}

if (has_capability('moodle/course:create', $context)) {
565
    // Print button to create a new course.
566
    $url = new moodle_url('/course/edit.php');
567
568
    if ($coursecat->id) {
        $url->params(array('category' => $coursecat->id, 'returnto' => 'catmanage'));
569
    } else {
570
        $url->params(array('category' => $CFG->defaultrequestcategory, 'returnto' => 'topcatmanage'));
571
572
573
574
    }
    echo $OUTPUT->single_button($url, get_string('addnewcourse'), 'get');
}

575
if (!empty($CFG->enablecourserequests) && $id == $CFG->defaultrequestcategory) {
576
577
    print_course_request_buttons(context_system::instance());
}
578
echo html_writer::end_tag('div');
579
580
581
582
583

print_course_search();

echo $OUTPUT->footer();

584
585
586
587
/**
 * Recursive function to print all the categories ready for editing.
 *
 * @param html_table $table The table to add data to.
588
 * @param coursecat $category The category to render
589
590
591
592
 * @param int $depth The depth of the category.
 * @param bool $up True if this category can be moved up.
 * @param bool $down True if this category can be moved down.
 */
593
function print_category_edit(html_table $table, coursecat $category, $depth = -1, $up = false, $down = false) {
594
    global $OUTPUT;
595

596
    static $str = null;
597
598
599

    if (is_null($str)) {
        $str = new stdClass;
600
601
602
603
604
605
606
607
        $str->edit = new lang_string('edit');
        $str->delete = new lang_string('delete');
        $str->moveup = new lang_string('moveup');
        $str->movedown = new lang_string('movedown');
        $str->edit = new lang_string('editthiscategory');
        $str->hide = new lang_string('hide');
        $str->show = new lang_string('show');
        $str->cohorts = new lang_string('cohorts', 'cohort');
608
609
610
        $str->spacer = $OUTPUT->spacer().' ';
    }

611
    if ($category->id) {
612

613
        $categorycontext = context_coursecat::instance($category->id);
614

615
616
617
618
        $attributes = array();
        $attributes['class'] = $category->visible ? '' : 'dimmed';
        $attributes['title'] = $str->edit;
        $categoryurl = new moodle_url('/course/manage.php', array('id' => $category->id, 'sesskey' => sesskey()));
619
        $categoryname = $category->get_formatted_name();
620
621
        $categorypadding = str_repeat('&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;', $depth);
        $categoryname = $categorypadding . html_writer::link($categoryurl, $categoryname, $attributes);
622

623
        $icons = array();
624
        if (has_capability('moodle/category:manage', $categorycontext)) {
625
626
627
628
629
630
631
632
633
634
635
636
637
            // Edit category.
            $icons[] = $OUTPUT->action_icon(
                new moodle_url('/course/editcategory.php', array('id' => $category->id)),
                new pix_icon('t/edit', $str->edit, 'moodle', array('class' => 'iconsmall')),
                null, array('title' => $str->edit)
            );
            // Delete category.
            $icons[] = $OUTPUT->action_icon(
                new moodle_url('/course/manage.php', array('deletecat' => $category->id, 'sesskey' => sesskey())),
                new pix_icon('t/delete', $str->delete, 'moodle', array('class' => 'iconsmall')),
                null, array('title' => $str->delete)
            );
            // Change visibility.
638
            if (!empty($category->visible)) {
639
640
641
642
643
                $icons[] = $OUTPUT->action_icon(
                    new moodle_url('/course/manage.php', array('hidecat' => $category->id, 'sesskey' => sesskey())),
                    new pix_icon('t/hide', $str->hide, 'moodle', array('class' => 'iconsmall')),
                    null, array('title' => $str->hide)
                );
644
            } else {
645
646
647
648
649
                $icons[] = $OUTPUT->action_icon(
                    new moodle_url('/course/manage.php', array('showcat' => $category->id, 'sesskey' => sesskey())),
                    new pix_icon('t/show', $str->show, 'moodle', array('class' => 'iconsmall')),
                    null, array('title' => $str->show)
                );
650
            }
651
            // Cohorts.
652
            if (has_any_capability(array('moodle/cohort:manage', 'moodle/cohort:view'), $categorycontext)) {
653
                $icons[] = $OUTPUT->action_icon(
654
                    new moodle_url('/cohort/index.php', array('contextid' => $categorycontext->id)),
655
656
657
                    new pix_icon('t/cohort', $str->cohorts, 'moodle', array('class' => 'iconsmall')),
                    null, array('title' => $str->cohorts)
                );
658
            }
659
            // Move up/down.
660
            if ($up) {
661
662
663
664
665
                $icons[] = $OUTPUT->action_icon(
                    new moodle_url('/course/manage.php', array('moveupcat' => $category->id, 'sesskey' => sesskey())),
                    new pix_icon('t/up', $str->moveup, 'moodle', array('class' => 'iconsmall')),
                    null, array('title' => $str->moveup)
                );
666
            } else {
667
                $icons[] = $str->spacer;
668
669
            }
            if ($down) {
670
671
672
673
674
                $icons[] = $OUTPUT->action_icon(
                    new moodle_url('/course/manage.php', array('movedowncat' => $category->id, 'sesskey' => sesskey())),
                    new pix_icon('t/down', $str->movedown, 'moodle', array('class' => 'iconsmall')),
                    null, array('title' => $str->movedown)
                );
675
            } else {
676
                $icons[] = $str->spacer;
677
678
679
            }
        }

680
        $actions = '';
681
        if (has_capability('moodle/category:manage', $categorycontext)) {
682
            $popupurl = new moodle_url("manage.php?movecat=$category->id&sesskey=".sesskey());
683
            $tempdisplaylist = array(0 => get_string('top')) + coursecat::make_categories_list('moodle/category:manage', $category->id);
684
685
            $select = new single_select($popupurl, 'movetocat', $tempdisplaylist, $category->parent, null, "moveform$category->id");
            $select->set_label(get_string('frontpagecategorynames'), array('class' => 'accesshide'));
686
            $actions = $OUTPUT->render($select);
687
        }
688
689
690
691
692
693
694
695
696
697
698

        $table->data[] = new html_table_row(array(
            // Category name.
            new html_table_cell($categoryname),
            // Course count.
            new html_table_cell($category->coursecount),
            // Icons.
            new html_table_cell(join(' ', $icons)),
            // Actions.
            new html_table_cell($actions)
        ));
699
700
    }

701
    if ($categories = $category->get_children()) {
702
        // Print all the children recursively.
703
704
705
706
707
708
709
710
711
712
713
714
715
        $countcats = count($categories);
        $count = 0;
        $first = true;
        $last = false;
        foreach ($categories as $cat) {
            $count++;
            if ($count == $countcats) {
                $last = true;
            }
            $up = $first ? false : true;
            $down = $last ? false : true;
            $first = false;

716
            print_category_edit($table, $cat, $depth+1, $up, $down);
717
718
        }
    }
719
}