]> git.mjollnir.org Git - moodle.git/commitdiff
course categories: Fix many bugs with category editing and permissions. Clean up...
authortjhunt <tjhunt>
Thu, 4 Dec 2008 08:53:10 +0000 (08:53 +0000)
committertjhunt <tjhunt>
Thu, 4 Dec 2008 08:53:10 +0000 (08:53 +0000)
Bugs: MDL-17479, MDL-16426, MDL-16063, MDL-16013, MDL-15658, MDL-15556, MDL-15161, MDL-14925, MDL-13742, MDL-11557.

* Simplify category editing permissions to just moodle/category:manage and moodle/category:seehiddencategories.
* Enforce those correctly. (Note MDL 17502 is still outstanding.)
* Don't screw up category sort order when you just edit name or description.
* Niceties like where redirects go when you cancel or submit forms.
* Make sure a global course creator can see the site admin block.
* Don't allow a category to be made the child of one of its children!
* General code cleanup to bring key files more in line with best pracitice.

Apologies for the fact it is one big patch, rather than a series of smaller patches. However, categoryedit.php, category.php and index.php where in pretty bad shape and needed significant cleaning up. categoryedit.php, in particular, was almost completely rewritten.

Merged from MOODLE_19_STABLE.

18 files changed:
admin/settings/courses.php
course/category.php
course/delete_category_form.php
course/edit_form.php
course/editcategory.php
course/editcategory_form.php
course/index.php
course/lib.php
course/search.php
lang/en_utf8/error.php
lang/en_utf8/moodle.php
lang/en_utf8/role.php
lib/accesslib.php
lib/datalib.php
lib/db/access.php
lib/weblib.php
theme/standard/styles_layout.css
version.php

index 9608e741bfd4d5d07fac809ca118954743b3057a..d0d7013c46406d52bb34cee05f5fb369c3709bca 100644 (file)
@@ -4,10 +4,11 @@
 
 if ($hassiteconfig
  or has_capability('moodle/site:backup', $systemcontext)
- or has_capability('moodle/category:update', $systemcontext)) { // speedup for non-admins, add all caps used on this page
+ or has_capability('moodle/category:manage', $systemcontext)
+ or has_capability('moodle/course:create', $systemcontext)) { // speedup for non-admins, add all caps used on this page
 
-
-    $ADMIN->add('courses', new admin_externalpage('coursemgmt', get_string('coursemgmt', 'admin'), $CFG->wwwroot . '/course/index.php?categoryedit=on','moodle/category:update'));
+    $ADMIN->add('courses', new admin_externalpage('coursemgmt', get_string('coursemgmt', 'admin'), $CFG->wwwroot . '/course/index.php?categoryedit=on',
+            array('moodle/category:manage', 'moodle/course:create')));
 
     $ADMIN->add('courses', new admin_enrolment_page());
 
index b30cb9fb73f2fef4dd0e8222587187bb875e18ad..8bcbfd5acf5f9b58d0d4eaf15295530b7b03cc24 100644 (file)
@@ -6,25 +6,23 @@
     require_once("../config.php");
     require_once("lib.php");
 
-    $id           = required_param('id', PARAM_INT);          // Category id
-    $page         = optional_param('page', 0, PARAM_INT);     // which page to show
-    $perpage      = optional_param('perpage', $CFG->coursesperpage, PARAM_INT); // how many per page
+    $id = required_param('id', PARAM_INT); // Category id
+    $page = optional_param('page', 0, PARAM_INT); // which page to show
+    $perpage = optional_param('perpage', $CFG->coursesperpage, PARAM_INT); // how many per page
     $categoryedit = optional_param('categoryedit', -1, PARAM_BOOL);
-    $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);
-    $rename       = optional_param('rename', '', PARAM_TEXT);
-    $resort       = optional_param('resort', 0, PARAM_BOOL);
-    $categorytheme= optional_param('categorytheme', false, PARAM_SAFEDIR);
+    $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);
 
     if ($CFG->forcelogin) {
         require_login();
     }
 
     if (!$site = get_site()) {
-        print_error("siteisnotdefined", 'debug');
+        print_error('siteisnotdefined', 'debug');
     }
 
     if (empty($id)) {
     if (!$category = $DB->get_record("course_categories", array("id"=>$id))) {
         print_error("unknowcategory");
     }
+    if (!$category->visible) {
+        require_capability('moodle/category:viewhiddencategories', $context);
+    }
 
-    if (has_capability('moodle/course:create', $context)) {
+    if (update_category_button($category->id)) {
         if ($categoryedit !== -1) {
             $USER->categoryediting = $categoryedit;
         }
-        $navbaritem = update_category_button($category->id);
-        $creatorediting = !empty($USER->categoryediting);
-        $adminediting = (has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM)) and $creatorediting);
-
+        $editingon = !empty($USER->categoryediting);
+        $navbaritem = update_category_button($category->id); // Must call this again after updating the state.
     } else {
-        if (!$category->visible) {
-            print_error('notavailable', 'error');
-        }
-        $navbaritem = print_course_search("", true, "navbar");
-        $adminediting = false;
-        $creatorediting = false;
+        $navbaritem = print_course_search('', true, 'navbar');
+        $editingon = false;
     }
 
-    if (has_capability('moodle/category:update', $context)) {
-        /// Rename the category if requested
-        if (!empty($rename) and confirm_sesskey()) {
-            if (!$DB->set_field("course_categories", "name", $rename, array("id"=>$category->id))) {
-                notify("An error occurred while renaming the category");
-            }
-            $category->name = $rename;
-            //trigger events
-            events_trigger('course_category_updated', $category);
-        }
-
-        /// Set the category theme if requested
-        if (($categorytheme !== false) and confirm_sesskey()) {
-            $category->theme = $categorytheme;
-            if (!$DB->set_field('course_categories', 'theme', $category->theme, array('id'=>$category->id))) {
-                notify('An error occurred while setting the theme');
-            }
-        }
-
+    // Process any category actions.
+    if (has_capability('moodle/category:manage', $context)) {
         /// Resort the category if requested
-
         if ($resort and confirm_sesskey()) {
             if ($courses = get_courses($category->id, "fullname ASC", 'c.id,c.fullname,c.sortorder')) {
                 $i = 1;
         }
     }
 
-    if(! empty($CFG->allowcategorythemes) ){
-        if(isset($category->theme)){
-            // specifying theme here saves us some dbqs
-            theme_setup($category->theme);
-        }
+    if(!empty($CFG->allowcategorythemes) && isset($category->theme)) {
+        // specifying theme here saves us some dbqs
+        theme_setup($category->theme);
     }
 
 /// Print headings
+    $numcategories = $DB->count_records('course_categories');
 
-    $numcategories = $DB->count_records("course_categories");
-
-    $stradministration = get_string("administration");
-    $strcategories = get_string("categories");
-    $strcategory = get_string("category");
-    $strcourses = get_string("courses");
+    $stradministration = get_string('administration');
+    $strcategories = get_string('categories');
+    $strcategory = get_string('category');
+    $strcourses = get_string('courses');
 
     $navlinks = array();
     $navlinks[] = array('name' => $strcategories, 'link' => 'index.php', 'type' => 'misc');
     $navlinks[] = array('name' => format_string($category->name), 'link' => null, 'type' => 'misc');
     $navigation = build_navigation($navlinks);
 
-    if ($creatorediting) {
-        if ($adminediting) {
-            // modify this to treat this as an admin page
-
-            require_once($CFG->libdir.'/adminlib.php');
-            admin_externalpage_setup('coursemgmt');
-            admin_externalpage_print_header();
-        } else {
-            print_header("$site->shortname: $category->name", "$site->fullname: $strcourses", $navigation, "", "", true, $navbaritem);
-        }
+    if ($editingon && update_category_button()) {
+        // 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');
+        admin_externalpage_setup('coursemgmt');
+        admin_externalpage_print_header();
     } else {
-        print_header("$site->shortname: $category->name", "$site->fullname: $strcourses", $navigation, "", "", true, $navbaritem);
+        print_header("$site->shortname: $category->name", "$site->fullname: $strcourses", $navigation, '', '', true, $navbaritem);
     }
 
 /// Print button to turn editing off
-    if ($adminediting) {
+    if ($editingon) {
         echo '<div class="categoryediting button">'.update_category_button($category->id).'</div>';
     }
 
 /// Print link to roles
-
     if (has_capability('moodle/role:assign', $context)) {
         echo '<div class="rolelink"><a href="'.$CFG->wwwroot.'/'.$CFG->admin.'/roles/assign.php?contextid='.
          $context->id.'">'.get_string('assignroles','role').'</a></div>';
     }
-/// Print the category selector
 
+/// Print the category selector
     $displaylist = array();
-    $parentlist = array();
-
-    make_categories_list($displaylist, $parentlist, "");
+    $notused = array();
+    make_categories_list($displaylist, $notused);
 
     echo '<div class="categorypicker">';
     popup_form('category.php?id=', $displaylist, 'switchcategory', $category->id, '', '', '', false, 'self', $strcategories.':');
     echo '</div>';
 
 /// Print current category description
-    if (!$creatorediting && $category->description) {
+    if (!$editingon && $category->description) {
         print_box_start();
         echo format_text($category->description); // for multilang filter
         print_box_end();
     }
 
-/// Editing functions
-
-    if ($creatorediting) {
+/// Process any course actions.
+    if ($editingon) {
     /// Move a specified course to a new category
-
         if (!empty($moveto) and $data = data_submitted() and confirm_sesskey()) {   // Some courses are being moved
-
             // user must have category update in both cats to perform this
-            require_capability('moodle/category:update', $context);
-            require_capability('moodle/category:update', get_context_instance(CONTEXT_COURSECAT, $moveto));
+            require_capability('moodle/category:manage', $context);
+            require_capability('moodle/category:manage', get_context_instance(CONTEXT_COURSECAT, $moveto));
 
-            if (! $destcategory = $DB->get_record("course_categories", array("id"=>$data->moveto))) {
-                print_error("cannotfindcategory", '', '', $data->moveto);
+            if (!$destcategory = $DB->get_record('course_categories', array('id' => $data->moveto))) {
+                print_error('cannotfindcategory', '', '', $data->moveto);
             }
 
-
             $courses = array();
-            foreach ( $data as $key => $value ) {
+            foreach ($data as $key => $value) {
                 if (preg_match('/^c\d+$/', $key)) {
                     array_push($courses, substr($key, 1));
                 }
         }
 
     /// Hide or show a course
-
         if ((!empty($hide) or !empty($show)) and confirm_sesskey()) {
             require_capability('moodle/course:visibility', $context);
             if (!empty($hide)) {
-                $course = $DB->get_record("course", array("id"=>$hide));
+                $course = $DB->get_record('course', array('id' => $hide));
                 $visible = 0;
             } else {
-                $course = $DB->get_record("course", array("id"=>$show));
+                $course = $DB->get_record('course', array('id' => $show));
                 $visible = 1;
             }
             if ($course) {
-                if (!$DB->set_field("course", "visible", $visible, array("id"=>$course->id))) {
-                    notify("Could not update that course!");
+                if (!$DB->set_field('course', 'visible', $visible, array('id' => $course->id))) {
+                    print_error('errorupdatingcoursevisibility');
                 }
             }
         }
 
 
     /// Move a course up or down
-
         if ((!empty($moveup) or !empty($movedown)) and confirm_sesskey()) {
-            require_capability('moodle/category:update', $context);
+            require_capability('moodle/category:manage', $context);
 
-            // ensure the course order has continuous ordering
+            // Ensure the course order has continuous ordering
             fix_course_sortorder();
             $swapcourse = NULL;
 
             if (!empty($moveup)) {
-                if ($movecourse = $DB->get_record('course', array('id'=>$moveup))) {
-                    $swapcourse = $DB->get_record('course', array('sortorder'=>$movecourse->sortorder-1));
+                if ($movecourse = $DB->get_record('course', array('id' => $moveup))) {
+                    $swapcourse = $DB->get_record('course', array('sortorder' => $movecourse->sortorder - 1));
                 }
             } else {
-                if ($movecourse = $DB->get_record('course', array('id'=>$movedown))) {
-                    $swapcourse = $DB->get_record('course', array('sortorder'=>$movecourse->sortorder+1));
+                if ($movecourse = $DB->get_record('course', array('id' => $movedown))) {
+                    $swapcourse = $DB->get_record('course', array('sortorder' => $movecourse->sortorder + 1));
                 }
             }
             if ($swapcourse and $movecourse) {
-                $DB->set_field('course', 'sortorder', $swapcourse->sortorder, array('id'=>$movecourse->id));
-                $DB->set_field('course', 'sortorder', $movecourse->sortorder, array('id'=>$swapcourse->id));
+                $DB->set_field('course', 'sortorder', $swapcourse->sortorder, array('id' => $movecourse->id));
+                $DB->set_field('course', 'sortorder', $movecourse->sortorder, array('id' => $swapcourse->id));
             }
         }
 
     } // End of editing stuff
 
+    if ($editingon && has_capability('moodle/category:manage', $context)) {
+        echo '<div class="buttons">';
 
-    if ($creatorediting) {   
-        echo '<div class="buttons">'; 
-        if (has_capability('moodle/category:update', $context)) {   // Print button to update this category
-            unset($options);
-            $options['id'] = $category->id;
-            print_single_button('editcategory.php', $options, get_string('editcategorythis'), 'get');
-        }
+        // Print button to update this category
+        $options = array('id' => $category->id);
+        print_single_button($CFG->wwwroot.'/course/editcategory.php', $options, get_string('editcategorythis'), 'get');
+
+        // Print button for creating new categories
+        $options = array('parent' => $category->id);
+        print_single_button($CFG->wwwroot.'/course/editcategory.php', $options, get_string('addsubcategory'), 'get');
 
-        if (has_capability('moodle/category:create', $context)) {   // Print button for creating new categories
-            unset($options);
-            $options['categoryadd'] = 1;
-            $options['id'] = $id;
-            print_single_button('editcategory.php', $options, get_string('addsubcategory'), 'get');
-        }
         echo '</div>';
     }
 
 /// Print out all the sub-categories
-    if ($subcategories = $DB->get_records("course_categories", array("parent"=>$category->id), "sortorder ASC")) {
+    if ($subcategories = $DB->get_records('course_categories', array('parent' => $category->id), 'sortorder ASC')) {
         $firstentry = true;
         foreach ($subcategories as $subcategory) {
-            if ($subcategory->visible or has_capability('moodle/course:create', $context)) {
+            if ($subcategory->visible || has_capability('moodle/category:viewhiddencategories', $context)) {
                 $subcategorieswereshown = true;
                 if ($firstentry) {
                     echo '<table border="0" cellspacing="2" cellpadding="4" class="generalbox boxaligncenter">';
                     echo '<tr><td style="white-space: nowrap">';
                     $firstentry = false;
                 }
-                $catlinkcss = $subcategory->visible ? "" : " class=\"dimmed\" ";
+                $catlinkcss = $subcategory->visible ? '' : ' class="dimmed" ';
                 echo '<a '.$catlinkcss.' href="category.php?id='.$subcategory->id.'">'.
                      format_string($subcategory->name).'</a><br />';
             }
         }
         if (!$firstentry) {
-            echo "</td></tr></table>";
-            echo "<br />";
+            echo '</td></tr></table>';
+            echo '<br />';
         }
     }
 
-
 /// Print out all the courses
-    unset($course);    // To avoid unwanted language effects later
-
     $courses = get_courses_page($category->id, 'c.sortorder ASC',
-                                'c.id,c.sortorder,c.shortname,c.fullname,c.summary,c.visible,c.guest,c.password',
-                                $totalcount, $page*$perpage, $perpage);
+            'c.id,c.sortorder,c.shortname,c.fullname,c.summary,c.visible,c.guest,c.password',
+            $totalcount, $page*$perpage, $perpage);
     $numcourses = count($courses);
 
     if (!$courses) {
             print_heading(get_string("nocoursesyet"));
         }
 
-    } else if ($numcourses <= COURSE_MAX_SUMMARIES_PER_PAGE and !$page and !$creatorediting) {
+    } else if ($numcourses <= COURSE_MAX_SUMMARIES_PER_PAGE and !$page and !$editingon) {
         print_box_start('courseboxes');
         print_courses($category);
         print_box_end();
     } else {
         print_paging_bar($totalcount, $page, $perpage, "category.php?id=$category->id&amp;perpage=$perpage&amp;");
 
-        $strcourses  = get_string("courses");
-        $strselect   = get_string("select");
-        $stredit     = get_string("edit");
-        $strdelete   = get_string("delete");
-        $strbackup   = get_string("backup");
-        $strrestore  = get_string("restore");
-        $strmoveup   = get_string("moveup");
-        $strmovedown = get_string("movedown");
-        $strupdate   = get_string("update");
-        $strhide     = get_string("hide");
-        $strshow     = get_string("show");
-        $strsummary  = get_string("summary");
-        $strsettings = get_string("settings");
-        $strassignteachers  = get_string("assignteachers");
-        $strallowguests     = get_string("allowguests");
-        $strrequireskey     = get_string("requireskey");
+        $strcourses = get_string('courses');
+        $strselect = get_string('select');
+        $stredit = get_string('edit');
+        $strdelete = get_string('delete');
+        $strbackup = get_string('backup');
+        $strrestore = get_string('restore');
+        $strmoveup = get_string('moveup');
+        $strmovedown = get_string('movedown');
+        $strupdate = get_string('update');
+        $strhide = get_string('hide');
+        $strshow = get_string('show');
+        $strsummary = get_string('summary');
+        $strsettings = get_string('settings');
+        $strassignteachers = get_string('assignteachers');
+        $strallowguests = get_string('allowguests');
+        $strrequireskey = get_string('requireskey');
 
 
         echo '<form id="movecourses" action="category.php" method="post"><div>';
         echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
         echo '<table border="0" cellspacing="2" cellpadding="4" class="generalbox boxaligncenter"><tr>';
         echo '<th class="header" scope="col">'.$strcourses.'</th>';
-        if ($creatorediting) {
+        if ($editingon) {
             echo '<th class="header" scope="col">'.$stredit.'</th>';
-            if ($adminediting) {
-                echo '<th class="header" scope="col">'.$strselect.'</th>';
-            }
+            echo '<th class="header" scope="col">'.$strselect.'</th>';
         } else {
             echo '<th class="header" scope="col">&nbsp;</th>';
         }
             $atlastpage = true;
         }
 
+        $spacer = '<img src="'.$CFG->wwwroot.'/pix/spacer.gif" class="iconsmall" alt="" /> ';
         foreach ($courses as $acourse) {
             if (isset($acourse->context)) {
                 $coursecontext = $acourse->context;
             $up = ($count > 1 || !$atfirstpage);
             $down = ($count < $numcourses || !$atlastpage);
 
-            $linkcss = $acourse->visible ? "" : ' class="dimmed" ';
+            $linkcss = $acourse->visible ? '' : ' class="dimmed" ';
             echo '<tr>';
             echo '<td><a '.$linkcss.' href="view.php?id='.$acourse->id.'">'. format_string($acourse->fullname) .'</a></td>';
-            if ($creatorediting) {
-                echo "<td>";
+            if ($editingon) {
+                echo '<td>';
                 if (has_capability('moodle/course:update', $coursecontext)) {
-                    echo '<a title="'.$strsettings.'" href="'.$CFG->wwwroot.'/course/edit.php?id='.
-                         $acourse->id.'">'.
-                         '<img src="'.$CFG->pixpath.'/t/edit.gif" class="iconsmall" alt="'.$stredit.'" /></a> ';        }
+                    echo '<a title="'.$strsettings.'" href="'.$CFG->wwwroot.'/course/edit.php?id='.$acourse->id.'">'.
+                            '<img src="'.$CFG->pixpath.'/t/edit.gif" class="iconsmall" alt="'.$stredit.'" /></a> ';
+                } else {
+                    echo $spacer;
+                }
 
                 // role assignment link
                 if (has_capability('moodle/role:assign', $coursecontext)) {
-                    echo'<a title="'.get_string('assignroles', 'role').'" href="'.$CFG->wwwroot.'/'.$CFG->admin.'/roles/assign.php?contextid='.$coursecontext->id.'"><img src="'.$CFG->pixpath.'/i/roles.gif" class="iconsmall" alt="'.get_string('assignroles', 'role').'" /></a>';
+                    echo '<a title="'.get_string('assignroles', 'role').'" href="'.$CFG->wwwroot.'/'.$CFG->admin.'/roles/assign.php?contextid='.$coursecontext->id.'">'.
+                            '<img src="'.$CFG->pixpath.'/i/roles.gif" class="iconsmall" alt="'.get_string('assignroles', 'role').'" /></a> ';
+                } else {
+                    echo $spacer;
                 }
 
                 if (can_delete_course($acourse->id)) {
                     echo '<a title="'.$strdelete.'" href="delete.php?id='.$acourse->id.'">'.
                             '<img src="'.$CFG->pixpath.'/t/delete.gif" class="iconsmall" alt="'.$strdelete.'" /></a> ';
+                } else {
+                    echo $spacer;
                 }
 
                 // MDL-8885, users with no capability to view hidden courses, should not be able to lock themselves out
                             '&amp;perpage='.$perpage.'&amp;show='.$acourse->id.'&amp;sesskey='.$USER->sesskey.'">'.
                             '<img src="'.$CFG->pixpath.'/t/show.gif" class="iconsmall" alt="'.$strshow.'" /></a> ';
                     }
+                } else {
+                    echo $spacer;
                 }
 
                 if (has_capability('moodle/site:backup', $coursecontext)) {
                     echo '<a title="'.$strbackup.'" href="../backup/backup.php?id='.$acourse->id.'">'.
                             '<img src="'.$CFG->pixpath.'/t/backup.gif" class="iconsmall" alt="'.$strbackup.'" /></a> ';
+                } else {
+                    echo $spacer;
                 }
 
                 if (has_capability('moodle/site:restore', $coursecontext)) {
                     echo '<a title="'.$strrestore.'" href="../files/index.php?id='.$acourse->id.
                          '&amp;wdir=/backupdata">'.
                          '<img src="'.$CFG->pixpath.'/t/restore.gif" class="iconsmall" alt="'.$strrestore.'" /></a> ';
+                } else {
+                    echo $spacer;
                 }
 
-                if (has_capability('moodle/category:update', $context)) {
+                if (has_capability('moodle/category:manage', $context)) {
                     if ($up) {
                         echo '<a title="'.$strmoveup.'" href="category.php?id='.$category->id.'&amp;page='.$page.
                              '&amp;perpage='.$perpage.'&amp;moveup='.$acourse->id.'&amp;sesskey='.$USER->sesskey.'">'.
                              '<img src="'.$CFG->pixpath.'/t/up.gif" class="iconsmall" alt="'.$strmoveup.'" /></a> ';
                     } else {
-                        echo '<img src="'.$CFG->wwwroot.'/pix/spacer.gif" class="iconsmall" alt="" /> ';
+                        echo $spacer;
                     }
 
                     if ($down) {
                              '&amp;perpage='.$perpage.'&amp;movedown='.$acourse->id.'&amp;sesskey='.$USER->sesskey.'">'.
                              '<img src="'.$CFG->pixpath.'/t/down.gif" class="iconsmall" alt="'.$strmovedown.'" /></a> ';
                     } else {
-                        echo '<img src="'.$CFG->wwwroot.'/pix/spacer.gif" class="iconsmall" alt="" /> ';
+                        echo $spacer;
                     }
                     $abletomovecourses = true;
+                } else {
+                    echo $spacer, $spacer;
                 }
 
                 echo '</td>';
         }
 
         if ($abletomovecourses) {
+            $movetocategories = array();
+            $notused = array();
+            make_categories_list($movetocategories, $notused, 'moodle/category:manage');
+            $movetocategories[$category->id] = get_string('moveselectedcoursesto');
             echo '<tr><td colspan="3" align="right">';
-            echo '<br />';
-            unset($displaylist[$category->id]);
-
-            // loop and unset categories the user can't move into
-
-            foreach ($displaylist as $did=>$dlist) {
-                if (!has_capability('moodle/category:update', get_context_instance(CONTEXT_COURSECAT, $did))) {
-                    unset($displaylist[$did]);
-                }
-            }
-
-            choose_from_menu ($displaylist, "moveto", "", get_string("moveselectedcoursesto"), "javascript: submitFormById('movecourses')");
+            choose_from_menu($movetocategories, 'moveto', $category->id, '', "javascript:submitFormById('movecourses')");
             echo '<input type="hidden" name="id" value="'.$category->id.'" />';
             echo '</td></tr>';
         }
         echo '<br />';
     }
 
-    echo '<div class="buttons">'; 
-    if (has_capability('moodle/category:update', get_context_instance(CONTEXT_SYSTEM)) and $numcourses > 1) {           /// Print button to re-sort courses by name
+    echo '<div class="buttons">';
+    if (has_capability('moodle/category:manage', $context) and $numcourses > 1) {
+    /// Print button to re-sort courses by name
         unset($options);
         $options['id'] = $category->id;
         $options['resort'] = 'name';
         print_single_button('category.php', $options, get_string('resortcoursesbyname'), 'get');
     }
 
-    if (has_capability('moodle/course:create', $context)) {         /// Print button to create a new course
+    if (has_capability('moodle/course:create', $context)) {
+    /// Print button to create a new course
         unset($options);
         $options['category'] = $category->id;
         print_single_button('edit.php', $options, get_string('addnewcourse'), 'get');
     }
-    echo '</div>'; 
-
-
+    echo '</div>';
 
     print_course_search();
 
index f25194fedfa700e66ef18099871653a4e03cf78a..82eb305c7c920ce43c4b56b25c37ef0db258c938 100644 (file)
@@ -11,36 +11,30 @@ class delete_category_form extends moodleform {
 
         $mform    =& $this->_form;
         $category = $this->_customdata;
+        ensure_context_subobj_present($category, CONTEXT_COURSECAT);
         $this->_category = $category;
 
         $mform->addElement('header','general', get_string('categorycurrentcontents', '', format_string($category->name)));
 
         $displaylist = array();
-        $parentlist = array();
-        $children = array();
-        make_categories_list($displaylist, $parentlist);
-        unset($displaylist[$category->id]);
-        foreach ($displaylist as $catid=>$unused) {
-            // remove all children of $category
-            if (isset($parentlist[$catid]) and in_array($category->id, $parentlist[$catid])) {
-                $children[] = $catid;
-                unset($displaylist[$catid]);
-                continue;
-            }
-            if (!has_capability('moodle/course:create', get_context_instance(CONTEXT_COURSECAT, $catid))) {
-                unset($displaylist[$catid]);
-            }
-        }
+        $notused = array();
+        make_categories_list($displaylist, $notused, 'moodle/course:create', $category->id);
 
+        // Check permissions, to see if it OK to give the option to delete
+        // the contents, rather than move elsewhere.
         $candeletecontent = true;
-        foreach ($children as $catid) {
-            $context = get_context_instance(CONTEXT_COURSECAT, $catid);
-            if (!has_capability('moodle/category:delete', $context)) {
+        $tocheck = array($category);
+        while (!empty($tocheck)) {
+            $checkcat = array_pop($tocheck);
+            $tocheck = $tocheck + get_child_categories($checkcat->id);
+            if (!has_capability('moodle/category:manage', $checkcat->context)) {
                 $candeletecontent = false;
                 break;
             }
         }
 
+        // TODO check that the user is allowed to delete all the courses MDL-17502!
+
         $options = array();
 
         if ($displaylist) {
@@ -48,7 +42,7 @@ class delete_category_form extends moodleform {
         }
 
         if ($candeletecontent) {
-            $options[1] =get_string('delete');
+            $options[1] = get_string('delete');
         }
 
         if (empty($options)) {
index 627b9a0190e20308494fc7b79f89c17f8739aef8..66cda9f7b26f54b962ad264867fd47e3952688a0 100644 (file)
@@ -57,16 +57,11 @@ class course_edit_form extends moodleform {
 //--------------------------------------------------------------------------------
         $mform->addElement('header','general', get_string('general', 'form'));
 
-        //must have create course capability in both categories in order to move course
+        // Must have create course capability in both categories in order to move course
         if (has_capability('moodle/course:create', $categorycontext)) {
             $displaylist = array();
             $parentlist = array();
-            make_categories_list($displaylist, $parentlist);
-            foreach ($displaylist as $key=>$val) {
-                if (!has_capability('moodle/course:create', get_context_instance(CONTEXT_COURSECAT, $key))) {
-                    unset($displaylist[$key]);
-                }
-            }
+            make_categories_list($displaylist, $parentlist, 'moodle/course:create');
             $mform->addElement('select', 'category', get_string('category'), $displaylist);
         } else {
             $mform->addElement('hidden', 'category', null);
index 70977ad8b4728a88d821c06d570ce10ddf09cb64..4759f540367428bfcaa6766ebcdb5124c8ab015d 100644 (file)
 <?php // $Id$
 /**
- * Displays a category and all its sub-categories.
- * In editing mode, allows admins to move/delete/hide categories
+ * Page for creating or editing course category name/parent/description.
+ * When called with an id parameter, edits the category with that id.
+ * Otherwise it creates a new category with default parent from the parent
+ * parameter, which may be 0.
  */
 
-require_once("../config.php");
-require_once("lib.php");
+require_once('../config.php');
+require_once('lib.php');
 require_once('editcategory_form.php');
 
-$id             = optional_param('id', 0, PARAM_INT);            // Category id: if not given, show Add a Category form. If given and 'categoryupdate': show edit form
-$page           = optional_param('page', 0, PARAM_INT);          // which page to show
-$perpage        = optional_param('perpage', $CFG->coursesperpage, PARAM_INT); // how many per page
-$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);
-$categoryedit   = optional_param('categoryedit', -1, PARAM_BOOL);    // Enables Move/Delete/Hide icons near each category in the list
-$categoryadd    = optional_param('categoryadd', 0, PARAM_BOOL);  // Enables the Add Category form
-$categoryupdate = optional_param('categoryupdate', 0, PARAM_BOOL); // Enables the Edit Category form
-$resort         = optional_param('resort', 0, PARAM_BOOL);
-$parent         = optional_param('parent', 0, PARAM_INT );
+require_login();
 
-if (!$site = get_site()) {
-    print_error("siteisnotdefined");
-}
-
-if ($categoryadd and !$parent) { // Show Add category form: if $id is given, it is used as the parent category 
-    $strtitle = get_string("addnewcategory");
-    $context = get_context_instance(CONTEXT_SYSTEM);
-    $category = null;
-} elseif ($categoryadd and $parent) {
-       $strtitle = get_string("addnewcategory");
-       $context = get_context_instance(CONTEXT_COURSECAT,$parent);
-       $category = null;
-} elseif (!is_null($id) && !$categoryadd) { // Show Edit category form: $id is given as the identifier of the category being edited
-    $strtitle = get_string("editcategorysettings");
-    $context = get_context_instance(CONTEXT_COURSECAT, $id); 
-    if (!$category = $DB->get_record("course_categories", array("id"=>$id))) {
-        print_error("unknowcategory");
+$id = optional_param('id', 0, PARAM_INT);
+if ($id) {
+    if (!$category = $DB->get_record('course_categories', array('id' => $id))) {
+        print_error('unknowcategory');
     }
+    require_capability('moodle/category:manage', get_context_instance(CONTEXT_COURSECAT, $id));
+    $strtitle = get_string('editcategorysettings');
+} else {
+    $parent = required_param('parent', PARAM_INT);
+    if ($parent) {
+        if (!$DB->record_exists('course_categories', array('id' => $parent))) {
+            print_error('unknowcategory');
+        }
+        $context = get_context_instance(CONTEXT_COURSECAT, $parent);
+    } else {
+        $context = get_system_context();
+    }
+    $category = new stdClass();
+    $category->id = 0;
+    $category->parent = $parent;
+    require_capability('moodle/category:manage', $context);
+    $strtitle = get_string("addnewcategory");
 }
 
-$mform = new editcategory_form('editcategory.php', compact(array('category', 'id')));
+$mform = new editcategory_form('editcategory.php', $category);
+$mform->set_data($category);
 
-if (!empty($category)) {
-    $mform->set_data($category); 
-} elseif (!is_null($id)) {
-    $data = new stdClass();
-    $data->parent = $id;
-    $data->categoryadd = 1;
-    $mform->set_data($data);
-}
-    
-if ($mform->is_cancelled()){
-    if (empty($category)) {
-        redirect($CFG->wwwroot .'/course/index.php?categoryedit=on');
+if ($mform->is_cancelled()) {
+    if ($id) {
+        redirect($CFG->wwwroot . '/course/category.php?id=' . $id . '&categoryedit=on');
+    } else if ($parent) {
+        redirect($CFG->wwwroot .'/course/category.php?id=' . $parent . '&categoryedit=on');
     } else {
-        redirect($CFG->wwwroot.'/course/category.php?categoryedit=on&id='.$category->id);
-    } 
-} else if (($data = $mform->get_data())) {
+        redirect($CFG->wwwroot .'/course/index.php?categoryedit=on');
+    }
+} else if ($data = $mform->get_data()) {
     $newcategory = new stdClass();
-    $newcategory->name        = $data->name;
+    $newcategory->name = $data->name;
     $newcategory->description = $data->description;
-    $newcategory->parent      = $data->parent; // if $id = 0, the new category will be a top-level category
+    $newcategory->parent = $data->parent; // if $data->parent = 0, the new category will be a top-level category
 
     if (isset($data->theme) && !empty($CFG->allowcategorythemes)) {
         $newcategory->theme = $data->theme;
-        theme_setup(); /// TODO: Do we really want the theme to be changed here? Doesn't look ok IMO. Eloy - 20080828
     }
 
-    if (empty($category) && has_capability('moodle/category:create', $context)) { // Create a new category
-        $newcategory->sortorder   = MAX_COURSES_IN_CATEGORY*MAX_COURSE_CATEGORIES; // put as last category in any parent cat 
-        if (!$newcategory->id = $DB->insert_record('course_categories', $newcategory)) {
-            notify( "Could not insert the new category '$newcategory->name' ");
-        } else {
-            $newcategory->context = get_context_instance(CONTEXT_COURSECAT, $newcategory->id);
-            mark_context_dirty($newcategory->context->path);
-            fix_course_sortorder();
-            redirect('index.php?categoryedit=on');
-        }
-    } elseif (has_capability('moodle/category:update', $context)) {
+    if ($id) {
+        // Update an existing category.
         $newcategory->id = $category->id;
-
         if ($newcategory->parent != $category->parent) {
-            $parent_cat = $DB->get_record('course_categories', array('id'=>$newcategory->parent));
-            move_category($newcategory, $parent_cat); // includes sortorder fix
+            $parent_cat = $DB->get_record('course_categories', array('id' => $newcategory->parent));
+            move_category($newcategory, $parent_cat);
         }
-
         if (!$DB->update_record('course_categories', $newcategory)) {
             print_error( "cannotupdatecategory", '', '', $newcategory->name);
-        } else {
-            if ($newcategory->parent == 0) {
-                $redirect_link = 'index.php?categoryedit=on';
-            } else {
-                $redirect_link = 'category.php?id='.$newcategory->id.'&categoryedit=on'; 
-            }
-            redirect($redirect_link);
-        }
-    } 
-}
-
-
-
-// If id is given, but not categoryadd or categoryupdate, we show the category with its list of subcategories
-if ($id && !$categoryadd && !$categoryupdate && false) { 
-    /* TODO implement
-
-    if ($CFG->forcelogin) {
-        require_login();
-    }
-
-    // Determine whether to allow user to see this category
-    if (has_capability('moodle/course:create', $context)) {
-        if ($categoryedit !== -1) {
-            $USER->categoryediting = $categoryedit;
         }
-        $navbaritem = update_category_button($category->id);
-        $creatorediting = !empty($USER->categoryediting);
-        $adminediting = (has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM)) and $creatorediting);
-
-    } else {
-        if (!$category->visible) {
-            print_error('notavailable', 'error');
-        }
-        $navbaritem = print_course_search("", true, "navbar");
-        $adminediting = false;
-        $creatorediting = false;
-    }
-
-    // Resort the category if requested 
-    if ($resort and confirm_sesskey()) {
-        if ($courses = get_courses($id, "fullname ASC", 'c.id,c.fullname,c.sortorder')) {
-            // move it off the range
-            $count = $DB->get_record_sql('SELECT MAX(sortorder) AS max, 1
-                                     FROM {course} WHERE category=' . $category->id);
-            $count = $count->max + 100;
-            $DB->begin_sql();
-            foreach ($courses as $course) {
-                $DB->set_field('course', 'sortorder', $count, array('id'=>$course->id));
-                $count++;
-            }
-            $DB->commit_sql();
-            fix_course_sortorder($category->id);
-        }
-    }
-    
-    // Print headings 
-    $numcategories = $DB->count_records("course_categories");
-
-    $stradministration = get_string("administration");
-    $strcategories = get_string("categories");
-    $strcategory = get_string("category");
-    $strcourses = get_string("courses");
-
-    $navlinks = array();
-    $navlinks[] = array('name' => $strcategories, 'link' => 'index.php', 'type' => 'misc');
-    $navlinks[] = array('name' => $category->name, 'link' => null, 'type' => 'misc');
-    $navigation = build_navigation($navlinks);
-
-    if ($creatorediting) {
-        if ($adminediting) {
-            // modify this to treat this as an admin page
+        fix_course_sortorder();
 
-            require_once($CFG->libdir.'/adminlib.php');
-            admin_externalpage_setup('categorymgmt');
-            admin_externalpage_print_header();
-        } else {
-            print_header("$site->shortname: $category->name", "$site->fullname: $strcategories", $navigation, "", "", true, $navbaritem);
-        }
     } else {
-        print_header("$site->shortname: $category->name", "$site->fullname: $strcategories", $navigation, "", "", true, $navbaritem);
-    }
-
-    // Print button to turn editing off
-    if ($adminediting) {
-        echo '<div class="categoryediting button" align="right">'.update_category_button($category->id).'</div>';
-    }
-
-    // Print link to roles
-
-    if (has_capability('moodle/role:assign', $context)) {
-        echo '<div class="rolelink"><a href="'.$CFG->wwwroot.'/'.$CFG->admin.'/roles/assign.php?contextid='.
-         $context->id.'">'.get_string('assignroles','role').'</a></div>';
-    }
-    
-    // Print the category selector
-
-    $displaylist = array();
-    $parentlist = array();
-
-    make_categories_list($displaylist, $parentlist, "");
-
-    echo '<div class="categorypicker">';
-    popup_form('category.php?id=', $displaylist, 'switchcategory', $category->id, '', '', '', false, 'self', $strcategories.':');
-    echo '</div>';
-
-    // Print current category description
-    if ($category->description) {
-        print_box_start();
-        print_heading(get_string('description'));
-        echo $category->description;
-        print_box_end();
-    }
-    
-    // Editing functions 
-    if ($creatorediting) {
-    // Move a specified category to a new category
-
-        if (!empty($moveto) and $data = data_submitted() and confirm_sesskey()) {   // Some courses are being moved
-
-            // user must have category update in both cats to perform this
-            require_capability('moodle/category:update', $context);
-            require_capability('moodle/category:update', get_context_instance(CONTEXT_COURSECAT, $moveto));
-
-            if (!$destcategory = $DB->get_record("course_categories", array("id"=>$data->moveto))) {
-                pritn_error("unknowcategory");
-            } 
-            // TODO function to move the category
-        }
-
-        // Hide or show a category 
-        if ((!empty($hide) or !empty($show)) and confirm_sesskey()) {
-            require_capability('moodle/category:visibility', $context);
-            if (!empty($hide)) {
-                $category = $DB->get_record("course_categories", array("id"=>$hide));
-                $visible = 0;
-            } else {
-                $category = $DB->get_record("course_categories", array("id"=>$show));
-                $visible = 1;
-            }
-            if ($category) {
-                if (! $DB->set_field("course_categories", "visible", $visible, array("id"=>$category->id))) {
-                    notify("Could not update that category!");
-                }
-            }
-        }
-
-
-        // Move a category up or down 
-        if ((!empty($moveup) or !empty($movedown)) and confirm_sesskey()) {
-            require_capability('moodle/category:update', $context);
-            $movecategory = NULL;
-            $swapcategory = NULL;
-
-            // TODO something like fix_course_sortorder() ?
-
-            // we are going to need to know the range
-            $max = $DB->get_record_sql('SELECT MAX(sortorder) AS max, 1 FROM {course_categories} WHERE id=' . $category->id);
-            $max = $max->max + 100;
-
-            if (!empty($moveup)) {
-                $movecategory = $DB->get_record('course_categories', array('id'=>$moveup));
-                $swapcategory = $DB->get_record('course_categories',
-                                         array('category'=>$category->id,
-                                         'sortorder'=>$movecategory->sortorder - 1));
-            } else {
-                $movecategory = $DB->get_record('course_categories', array('id'=>$movedown));
-                $swapcategory = $DB->get_record('course_categories',
-                                         array('category'=> $category->id,
-                                         'sortorder'=>$movecategory->sortorder + 1));
-            }
-
-            if ($swapcourse and $movecourse) {        // Renumber everything for robustness
-                $DB->begin_sql();
-                if (!(    $DB->set_field("course", "sortorder", $max, aray("id"=>$swapcourse->id))
-                       && $DB->set_field("course", "sortorder", $swapcourse->sortorder, array("id"=>$movecourse->id))
-                       && $DB->set_field("course", "sortorder", $movecourse->sortorder, array("id"=>$swapcourse->id))
-                    )) {
-                    notify("Could not update that course!");
-                }
-                $DB->commit_sql();
-            }
-
-        }
-
-    } // End of editing stuff
-
-    // Print out all the sub-categories
-    if ($subcategories = $DB->get_records("course_categories", array("parent"=>$category->id), "sortorder ASC")) {
-        $firstentry = true;
-        foreach ($subcategories as $subcategory) {
-            if ($subcategory->visible or has_capability('moodle/course:create', $context)) {
-                $subcategorieswereshown = true;
-                if ($firstentry) {
-                    echo '<table border="0" cellspacing="2" cellpadding="4" class="generalbox boxaligncenter">';
-                    echo '<tr><th scope="col">'.get_string('subcategories').'</th></tr>';
-                    echo '<tr><td style="white-space: nowrap">';
-                    $firstentry = false;
-                }
-                $catlinkcss = $subcategory->visible ? "" : " class=\"dimmed\" ";
-                echo '<a '.$catlinkcss.' href="category.php?id='.$subcategory->id.'">'.
-                     format_string($subcategory->name).'</a><br />';
-            }
-        }
-        if (!$firstentry) {
-            echo "</td></tr></table>";
-            echo "<br />";
+        // Create a new category.
+        $newcategory->sortorder = 999;
+        if (!$newcategory->id = $DB->insert_record('course_categories', $newcategory)) {
+            print_error('cannotcreatecategory', '', '', format_string($newcategory->name));
         }
+        $newcategory->context = get_context_instance(CONTEXT_COURSECAT, $newcategory->id);
+        mark_context_dirty($newcategory->context->path);
     }
+    redirect('category.php?id='.$newcategory->id.'&categoryedit=on');
+}
 
-    // print option to add a subcategory
-    if (has_capability('moodle/category:create', $context) && $creatorediting) {
-        $cat->id = $id;
-        $mform->set_data($cat);
-        $mform->display();
-    }
-    */
-} 
 // Print the form
-
-$site = get_site();
-
-$straddnewcategory = get_string("addnewcategory");
-$stradministration = get_string("administration");
-$strcategories = get_string("categories");
+$straddnewcategory = get_string('addnewcategory');
+$stradministration = get_string('administration');
+$strcategories = get_string('categories');
 $navlinks = array();
 
-if (!empty($category->name)) {
+if ($id) {
     $navlinks[] = array('name' => $strtitle,
                         'link' => null,
                         'type' => 'misc');
@@ -333,8 +103,8 @@ if (!empty($category->name)) {
     $navlinks[] = array('name' => $straddnewcategory,
                         'link' => null,
                         'type' => 'misc');
-    $title = "$site->shortname: $straddnewcategory";
-    $fullname = $site->fullname;
+    $title = "$SITE->shortname: $straddnewcategory";
+    $fullname = $SITE->fullname;
 }
 
 $navigation = build_navigation($navlinks);
index 73b54dbd7d9715c7ae56d5d7474a1f128cba487d..2973e927738ae693eb281e71ae123752c632ffd0 100644 (file)
@@ -6,15 +6,24 @@ class editcategory_form extends moodleform {
     function definition() {
         global $CFG;
         $mform =& $this->_form;
-        
+        $category = $this->_customdata;
+
         // get list of categories to use as parents, with site as the first one
         $options = array(get_string('top'));
         $parents = array();
-        make_categories_list($options, $parents);
-        
+        if ($category->id) {
+            // Editing an existing category.
+            make_categories_list($options, $parents, 'moodle/category:manage', $category->id);
+            $strsubmit = get_string('savechanges');
+        } else {
+            // Making a new category
+            make_categories_list($options, $parents, 'moodle/category:manage');
+            $strsubmit = get_string('createcategory');
+        }
+
         $mform->addElement('select', 'parent', get_string('parentcategory'), $options);
-        $mform->addElement('text', 'name', get_string('categoryname'), array('size'=>'30'));    
-        $mform->addRule('name', get_string('required'), 'required', null);        
+        $mform->addElement('text', 'name', get_string('categoryname'), array('size'=>'30'));
+        $mform->addRule('name', get_string('required'), 'required', null);
         $mform->addElement('htmleditor', 'description', get_string('description'));
         $mform->setType('description', PARAM_RAW);
         if (!empty($CFG->allowcategorythemes)) {
@@ -24,11 +33,12 @@ class editcategory_form extends moodleform {
             $mform->addElement('select', 'theme', get_string('forcetheme'), $themes);
         }
         $mform->setHelpButton('description', array('writing', 'richtext2'), false, 'editorhelpbutton');
-        
-        $mform->addElement('hidden', 'id', null);
-        $mform->addElement('hidden', 'categoryadd', 0);
+
+        $mform->addElement('hidden', 'id', 0);
         $mform->setType('id', PARAM_INT);
-        $this->add_action_buttons(true, get_string('savechanges'));
+        $mform->setDefault('id', $category->id);
+
+        $this->add_action_buttons(true, $strsubmit);
     }
 } 
 ?>
index db389f752d93405303d45542429c2892553cc1ea..8ca6f2594030f3a62a4f9ab7160612047017f332 100644 (file)
     $moveup   = optional_param('moveup',0,PARAM_INT);
     $movedown = optional_param('movedown',0,PARAM_INT);
 
-    $sysctx  = get_context_instance(CONTEXT_SYSTEM);
-    $context = $sysctx;
+    if ($CFG->forcelogin) {
+        require_login();
+    }
 
     if (!$site = get_site()) {
         print_error('siteisnotdefined', 'debug');
     }
 
-    if ($CFG->forcelogin) {
-        require_login();
-    }
+    $systemcontext = get_context_instance(CONTEXT_SYSTEM);
 
-    if (has_capability('moodle/category:update', $sysctx)) {
+    if (update_category_button()) {
         if ($categoryedit !== -1) {
             $USER->categoryediting = $categoryedit;
         }
 
 
 /// Unless it's an editing admin, just print the regular listing of courses/categories
-
     if (!$adminediting) {
 
-      /// Print form for creating new categories
-
+    /// Print form for creating new categories
         $countcategories = $DB->count_records('course_categories');
 
         if ($countcategories > 1 || ($countcategories == 1 && $DB->count_records('course') > 200)) {
@@ -58,7 +55,7 @@
             $navlinks = array();
             $navlinks[] = array('name'=>$strcategories,'link'=>'','type'=>'misc');
             $navigation = build_navigation($navlinks);
-            print_header("$site->shortname: $strcategories", $strcourses, $navigation, '', '', true, update_categories_button());
+            print_header("$site->shortname: $strcategories", $strcourses, $navigation, '', '', true, update_category_button());
             print_heading($strcategories);
             echo skip_main_destination();
             print_box_start('categorybox');
             $strfulllistofcourses = get_string('fulllistofcourses');
             print_header("$site->shortname: $strfulllistofcourses", $strfulllistofcourses,
                     build_navigation(array(array('name'=>$strfulllistofcourses, 'link'=>'','type'=>'misc'))),
-                         '', '', true, update_categories_button());
+                         '', '', true, update_category_button());
             echo skip_main_destination();
             print_box_start('courseboxes');
             print_courses(0);
             print_box_end();
         }
 
-        /// I am not sure this context in the next has_capability call is correct.
-        if (isloggedin() and !isguest() and !has_capability('moodle/course:create', $sysctx) and $CFG->enablecourserequests) {  // Print link to request a new course
+        echo '<div class="buttons">';
+        if ($CFG->enablecourserequests and isloggedin() and !isguest() and !has_capability('moodle/course:create', $systemcontext)) {
+        /// Print link to request a new course
             print_single_button('request.php', NULL, get_string('courserequest'), 'get');
         }
-        if (has_capability('moodle/course:create', $sysctx)) {       // Print link to create a new course
+        if (has_capability('moodle/course:create', $systemcontext)) {
+        /// Print link to create a new course
         /// Get the 1st available category
-            $options = array('category' => $DB->get_field('course_categories', 'id', array('parent'=>'0')));
+            $options = array('category' => $CFG->defaultrequestcategory);
             print_single_button('edit.php', $options, get_string('addnewcourse'), 'get');
         }
-        if (has_capability('moodle/site:approvecourse', $sysctx)  and !empty($CFG->enablecourserequests)) {
+        if (has_capability('moodle/site:approvecourse', $systemcontext) and !empty($CFG->enablecourserequests)) {
             print_single_button('pending.php',NULL, get_string('coursespending'),'get');
         }
+        echo '</div>';
         print_footer();
         exit;
     }
+/// Everything else is editing on mode.
 
-/// From now on is all the admin/course creator functions
-
-/// Delete a category if necessary
-
+/// Delete a category.
     if (!empty($delete) and confirm_sesskey()) {
-        require_once('delete_category_form.php');
-
         if (!$deletecat = $DB->get_record('course_categories', array('id'=>$delete))) {
             print_error('invalidcategoryid');
         }
-
-        $heading = get_string('deletecategory', '', format_string($deletecat->name));
-
         $context = get_context_instance(CONTEXT_COURSECAT, $delete);
-        require_capability('moodle/category:delete', $context);
+        require_capability('moodle/category:manage', $context);
+        require_capability('moodle/category:manage', get_category_or_system_context($deletecat->parent));
 
+        $heading = get_string('deletecategory', '', format_string($deletecat->name));
+        require_once('delete_category_form.php');
         $mform = new delete_category_form(null, $deletecat);
         $mform->set_data(array('delete'=>$delete));
 
                         'generalbox boxwidthnormal boxaligncenter');
             }
             $mform->display();
-            print_footer();
+            admin_externalpage_print_footer();
             exit();
         }
 
             category_delete_move($deletecat, $data->newparent, true);
         }
 
+        // If we deleted $CFG->defaultrequestcategory, make it point somewhere else.
+        if ($delete == $CFG->defaultrequestcategory) {
+            set_config('defaultrequestcategory', get_field('course_categories', 'MIN(id)', 'parent', 0));
+        }
+
         print_continue('index.php');
 
-        print_footer();
+        admin_externalpage_print_footer();
         die;
     }
 
     print_category_edit_header();
     print_heading($strcategories);
 
-
 /// Create a default category if necessary
     if (!$categories = get_categories()) {    /// No category yet!
         // Try and make one
         mark_context_dirty('/'.SYSCONTEXTID);
     }
 
-
 /// Move a category to a new parent if required
-
-    if (!empty($move) and ($moveto>=0) and confirm_sesskey()) {
-        if ($tempcat = $DB->get_record('course_categories', array('id'=>$move))) {
-            if ($tempcat->parent != $moveto) {
-                $newp = $DB->get_record('course_categories', array('id'=>$moveto));
-                if (! move_category($tempcat, $newp)) {
-                    notify('Could not update that category!');
+    if (!empty($move) and ($moveto >= 0) and confirm_sesskey()) {
+        if ($cattomove = $DB->get_record('course_categories', array('id'=>$move))) {
+            require_capability('moodle/category:manage', get_category_or_system_context($cattomove->parent));
+            if ($cattomove->parent != $moveto) {
+                $newparent = $DB->get_record('course_categories', array('id'=>$moveto));
+                require_capability('moodle/category:manage', get_category_or_system_context($moveto));
+                if (!move_category($cattomove, $newparent)) {
+                    print_error('cannotupdatecategory', '', '', format_string($cattomove->name));
                 }
             }
         }
     }
 
-
 /// Hide or show a category
     if ((!empty($hide) or !empty($show)) and confirm_sesskey()) {
         if (!empty($hide)) {
             $tempcat = $DB->get_record('course_categories', array('id'=>$show));
             $visible = 1;
         }
+        require_capability('moodle/category:manage', get_category_or_system_context($tempcat->parent));
         if ($tempcat) {
             if (!$DB->set_field('course_categories', 'visible', $visible, array('id'=>$tempcat->id))) {
-                notify('Could not update that category!');
+                print_error('cannotupdatecategory', '', '', format_string($tempcat->name));
             }
-            if (!$DB->set_field('course', 'visible', $visible, array('category'=>$tempcat->id))) {
-                notify('Could not hide/show any courses in this category !');
+            if (!$DB->set_field('course', 'visible', $visible, array('category' => $tempcat->id))) {
+                print_error('cannotshowhidecoursesincategory', '', '', format_string($tempcat->name));
             }
         }
     }
 
-
 /// Move a category up or down
-
     if ((!empty($moveup) or !empty($movedown)) and confirm_sesskey()) {
-
         fix_course_sortorder();
         $swapcategory = NULL;
 
         if (!empty($moveup)) {
+            require_capability('moodle/category:manage', get_context_instance(CONTEXT_COURSECAT, $moveup));
             if ($movecategory = $DB->get_record('course_categories', array('id'=>$moveup))) {
                 if ($swapcategory = $DB->get_records_select('course_categories', "sortorder<? AND parent=?", array($movecategory->sortorder, $movecategory->parent), 'sortorder ASC', '*', 0, 1)) {
                     $swapcategory = reset($swapcategory);
                 }
             }
         } else {
+            require_capability('moodle/category:manage', get_context_instance(CONTEXT_COURSECAT, $movedown));
             if ($movecategory = $DB->get_record('course_categories', array('id'=>$movedown))) {
                 if ($swapcategory = $DB->get_records_select('course_categories', "sortorder>? AND parent=?", array($movecategory->sortorder, $movecategory->parent), 'sortorder ASC', '*', 0, 1)) {
                     $swapcategory = reset($swapcategory);
         fix_course_sortorder();
     }
 
-/// This should not be needed anymore
-    //fix_course_sortorder();
-
 /// Print out the categories with all the knobs
-
     $strcategories = get_string('categories');
     $strcourses = get_string('courses');
     $strmovecategoryto = get_string('movecategoryto');
     $parentlist = array();
 
     $displaylist[0] = get_string('top');
-    make_categories_list($displaylist, $parentlist, '');
+    make_categories_list($displaylist, $parentlist);
 
     echo '<table class="generalbox editcourse boxaligncenter"><tr class="header">';
     echo '<th class="header" scope="col">'.$strcategories.'</th>';
 
     echo '<div class="buttons">';
 
-    if (!empty($category->id)) {
-        // Print link to create a new course in current category
-        if (has_capability('moodle/course:create', $context)) {
-            $options = array();
-            $options['category'] = $category->id;
-            print_single_button('edit.php', $options, get_string('addnewcourse'), 'get');
-        }
-    }else{
-        if (has_capability('moodle/course:create', $sysctx)) {
-            // print create course link to first category
-            $options = array();
-            $options = array('category' => $DB->get_field('course_categories', 'id', array('parent'=>'0')));
-            print_single_button('edit.php', $options, get_string('addnewcourse'), 'get');
-        }
+    if (has_capability('moodle/course:create', $systemcontext)) {
+        // print create course link to first category
+        $options = array();
+        $options = array('category' => $CFG->defaultrequestcategory);
+        print_single_button('edit.php', $options, get_string('addnewcourse'), 'get');
     }
 
     // Print button for creating new categories
-    if (has_capability('moodle/category:create', $context)) {
-        unset($options);
-        if (!empty($category->id)) {
-            $options['id'] = $category->id;
-        } else {
-            $options['id'] = 0;
-        }
-        $options['categoryadd'] = 1;
+    if (has_capability('moodle/category:manage', $systemcontext)) {
+        $options = array();
+        $options['parent'] = 0;
         print_single_button('editcategory.php', $options, get_string('addnewcategory'), 'get');
     }
 
-    if (has_capability('moodle/site:approvecourse', $sysctx)  and !empty($CFG->enablecourserequests)) {
+    if (has_capability('moodle/site:approvecourse', $systemcontext)  and !empty($CFG->enablecourserequests)) {
         print_single_button('pending.php',NULL, get_string('coursespending'), 'get');
     }
     // admin page does not allow custom buttons in the navigation bar
     echo '<div class="singlebutton">';
-    echo update_categories_button();
+    echo update_category_button();
     echo '</div></div>';
 
-    print_footer();
+    admin_externalpage_print_footer();
 
 function print_category_edit($category, $displaylist, $parentslist, $depth=-1, $up=false, $down=false) {
 /// Recursive function to print all the categories ready for editing
 
     global $CFG, $USER;
 
-    static $str = '';
+    static $str = NULL;
 
-    if (empty($str)) {
+    if (is_null($str)) {
+        $str = new stdClass;
         $str->edit     = get_string('edit');
         $str->delete   = get_string('delete');
         $str->moveup   = get_string('moveup');
@@ -306,9 +288,10 @@ function print_category_edit($category, $displaylist, $parentslist, $depth=-1, $
         $str->edit     = get_string('editthiscategory');
         $str->hide     = get_string('hide');
         $str->show     = get_string('show');
+        $str->spacer = '<img src="'.$CFG->wwwroot.'/pix/spacer.gif" class="iconsmall" alt="" /> ';
     }
 
-    if ($category) {
+    if (!empty($category)) {
 
         if (!isset($category->context)) {
             $category->context = get_context_instance(CONTEXT_COURSECAT, $category->id);
@@ -328,17 +311,13 @@ function print_category_edit($category, $displaylist, $parentslist, $depth=-1, $
 
         echo '<td class="icons">';    /// Print little icons
 
-        if (has_capability('moodle/category:update', $category->context)) {
-            echo '<a title="'.$str->edit.'" href="editcategory.php?id='.$category->id.'&amp;sesskey='.sesskey().'"><img'.
+        if (has_capability('moodle/category:manage', $category->context)) {
+            echo '<a title="'.$str->edit.'" href="editcategory.php?id='.$category->id.'"><img'.
                  ' src="'.$CFG->pixpath.'/t/edit.gif" class="iconsmall" alt="'.$str->edit.'" /></a> ';
-        }
 
-        if (has_capability('moodle/category:delete', $category->context)) {
             echo '<a title="'.$str->delete.'" href="index.php?delete='.$category->id.'&amp;sesskey='.sesskey().'"><img'.
                  ' src="'.$CFG->pixpath.'/t/delete.gif" class="iconsmall" alt="'.$str->delete.'" /></a> ';
-        }
 
-        if (has_capability('moodle/category:visibility', $category->context)) {
             if (!empty($category->visible)) {
                 echo '<a title="'.$str->hide.'" href="index.php?hide='.$category->id.'&amp;sesskey='.sesskey().'"><img'.
                      ' src="'.$CFG->pixpath.'/t/hide.gif" class="iconsmall" alt="'.$str->hide.'" /></a> ';
@@ -346,27 +325,33 @@ function print_category_edit($category, $displaylist, $parentslist, $depth=-1, $
                 echo '<a title="'.$str->show.'" href="index.php?show='.$category->id.'&amp;sesskey='.sesskey().'"><img'.
                      ' src="'.$CFG->pixpath.'/t/show.gif" class="iconsmall" alt="'.$str->show.'" /></a> ';
             }
-        }
 
-        if ($up) {
-            echo '<a title="'.$str->moveup.'" href="index.php?moveup='.$category->id.'&amp;sesskey='.sesskey().'"><img'.
-                 ' src="'.$CFG->pixpath.'/t/up.gif" class="iconsmall" alt="'.$str->moveup.'" /></a> ';
-        }
-        if ($down) {
-            echo '<a title="'.$str->movedown.'" href="index.php?movedown='.$category->id.'&amp;sesskey='.sesskey().'"><img'.
-                 ' src="'.$CFG->pixpath.'/t/down.gif" class="iconsmall" alt="'.$str->movedown.'" /></a> ';
+            if ($up) {
+                echo '<a title="'.$str->moveup.'" href="index.php?moveup='.$category->id.'&amp;sesskey='.sesskey().'"><img'.
+                     ' src="'.$CFG->pixpath.'/t/up.gif" class="iconsmall" alt="'.$str->moveup.'" /></a> ';
+            } else {
+                echo $str->spacer;
+            }
+            if ($down) {
+                echo '<a title="'.$str->movedown.'" href="index.php?movedown='.$category->id.'&amp;sesskey='.sesskey().'"><img'.
+                     ' src="'.$CFG->pixpath.'/t/down.gif" class="iconsmall" alt="'.$str->movedown.'" /></a> ';
+            } else {
+                echo $str->spacer;
+            }
         }
         echo '</td>';
 
         echo '<td align="left">';
-        $tempdisplaylist = $displaylist;
-        unset($tempdisplaylist[$category->id]);
-        foreach ($parentslist as $key => $parents) {
-            if (in_array($category->id, $parents)) {
-                unset($tempdisplaylist[$key]);
+        if (has_capability('moodle/category:manage', $category->context)) {
+            $tempdisplaylist = $displaylist;
+            unset($tempdisplaylist[$category->id]);
+            foreach ($parentslist as $key => $parents) {
+                if (in_array($category->id, $parents)) {
+                    unset($tempdisplaylist[$key]);
+                }
             }
+            popup_form ("index.php?move=$category->id&amp;sesskey=$USER->sesskey&amp;moveto=", $tempdisplaylist, "moveform$category->id", $category->parent, '', '', '', false);
         }
-        popup_form ("index.php?move=$category->id&amp;sesskey=$USER->sesskey&amp;moveto=", $tempdisplaylist, "moveform$category->id", $category->parent, '', '', '', false);
         echo '</td>';
         echo '</tr>';
     } else {
@@ -396,13 +381,8 @@ function print_category_edit_header() {
     global $CFG;
     global $SITE;
 
-    if (has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) {
-        require_once($CFG->libdir.'/adminlib.php');
-        admin_externalpage_setup('coursemgmt');
-        admin_externalpage_print_header();
-    } else {
-        print_header("$SITE->shortname:". get_string('categories'), get_string('courses'),
-            build_navigation(array(array('name'=>get_string('categories'),'link'=>'','type'=>'misc'))), '', '', true, update_categories_button());
-    }
+    require_once($CFG->libdir.'/adminlib.php');
+    admin_externalpage_setup('coursemgmt');
+    admin_externalpage_print_header();
 }
 ?>
index a608c5e9c3af98cf5f2c007597cd4808485b90f8..f4fb9792f591a1d793087dbcf930862ff51640af 100644 (file)
@@ -1625,6 +1625,21 @@ function print_section_add_menus($course, $section, $modnames, $vertical=false,
     }
 }
 
+/**
+ * Return the course category context for the category with id $categoryid, except
+ * that if $categoryid is 0, return the system context.
+ *
+ * @param integer $categoryid a category id or 0.
+ * @return object the corresponding context
+ */
+function get_category_or_system_context($categoryid) {
+    if ($categoryid) {
+        return get_context_instance(CONTEXT_COURSECAT, $categoryid);
+    } else {
+        return get_context_instance(CONTEXT_SYSTEM);
+    }
+}
+
 /**
  * Rebuilds the cached list of course activities stored in the database
  * @param int $courseid - id of course to rebuil, empty means all
@@ -1676,10 +1691,13 @@ function rebuild_course_cache($courseid=0, $clearonly=false) {
 }
 
 /**
- * Returns an array of the children categories for the given category
- * ID by caching all of the categories in a static hash
+ * Gets the child categories of a given coures category. Uses a static cache
+ * to make repeat calls efficient.
+ *
+ * @param unknown_type $parentid the id of a course category.
+ * @return array all the child course categories.
  */
-function get_child_categories($parent) {
+function get_child_categories($parentid) {
     static $allcategories = null;
 
     // only fill in this variable the first time
@@ -1695,19 +1713,51 @@ function get_child_categories($parent) {
         }
     }
 
-    if (empty($allcategories[$parent])) {
+    if (empty($allcategories[$parentid])) {
         return array();
     } else {
-        return $allcategories[$parent];
+        return $allcategories[$parentid];
     }
 }
 
 /**
- * Given an empty array, this function recursively travels the
- * categories, building up a nice list for display.  It also makes
- * an array that list all the parents for each category.
+ * This function recursively travels the categories, building up a nice list
+ * for display. It also makes an array that list all the parents for each
+ * category.
+ *
+ * For example, if you have a tree of categories like:
+ *   Miscellaneous (id = 1)
+ *      Subcategory (id = 2)
+ *         Sub-subcategory (id = 4)
+ *   Other category (id = 3)
+ * Then after calling this function you will have
+ * $list = array(1 => 'Miscellaneous', 2 => 'Miscellaneous / Subcategory',
+ *      4 => 'Miscellaneous / Subcategory / Sub-subcategory',
+ *      3 => 'Other category');
+ * $parents = array(2 => array(1), 4 => array(1, 2));
+ *
+ * If you specify $requiredcapability, then only categories where the current
+ * user has that capability will be added to $list, although all categories
+ * will still be added to $parents, and if you only have $requiredcapability
+ * in a child category, not the parent, then the child catgegory will still be
+ * included.
+ *
+ * If you specify the option $excluded, then that category, and all its children,
+ * are omitted from the tree. This is useful when you are doing something like
+ * moving categories, where you do not want to allow people to move a category
+ * to be the child of itself.
+ *
+ * @param array $list For output, accumulates an array categoryid => full category path name
+ * @param array $parents For output, accumulates an array categoryid => list of parent category ids.
+ * @param string $requiredcapability if given, only categories where the current
+ *      user has this capability will be added to $list.
+ * @param integer $excludeid Omit this category and its children from the lists built.
+ * @param object $category Build the tree starting at this category - otherwise starts at the top level.
+ * @param string $path For internal use, as part of recursive calls.
  */
-function make_categories_list(&$list, &$parents, $category=NULL, $path="") {
+function make_categories_list(&$list, &$parents, $requiredcapability = '',
+        $excludeid = 0, $category = NULL, $path = "") {
+
     // initialize the arrays if needed
     if (!is_array($list)) {
         $list = array();
@@ -1716,18 +1766,34 @@ function make_categories_list(&$list, &$parents, $category=NULL, $path="") {
         $parents = array();
     }
 
-    if ($category) {
+    if (empty($category)) {
+        // Start at the top level.
+        $category = new stdClass;
+        $category->id = 0;
+    } else {
+        // This is the excluded category, don't include it.
+        if ($excludeid > 0 && $excludeid == $category->id) {
+            return;
+        }
+
+        // Update $path.
         if ($path) {
             $path = $path.' / '.format_string($category->name);
         } else {
             $path = format_string($category->name);
         }
-        $list[$category->id] = $path;
-    } else {
-        $category->id = 0;
+
+        // Add this category to $list, if the permissions check out.
+        if ($requiredcapability) {
+            ensure_context_subobj_present($category, CONTEXT_COURSECAT);
+        }
+        if (!$requiredcapability || has_capability($requiredcapability, $category->context)) {
+            $list[$category->id] = $path;
+        }
     }
 
-    if ($categories = get_child_categories($category->id)) {   // Print all the children recursively
+    // Add all the children recursively, while updating the parents array.
+    if ($categories = get_child_categories($category->id)) {
         foreach ($categories as $cat) {
             if (!empty($category->id)) {
                 if (isset($parents[$category->id])) {
@@ -1735,7 +1801,7 @@ function make_categories_list(&$list, &$parents, $category=NULL, $path="") {
                 }
                 $parents[$cat->id][] = $category->id;
             }
-            make_categories_list($list, $parents, $cat, $path);
+            make_categories_list($list, $parents, $requiredcapability, $excludeid, $cat, $path);
         }
     }
 }
@@ -1745,7 +1811,7 @@ function make_categories_list(&$list, &$parents, $category=NULL, $path="") {
  * Recursive function to print out all the categories in a nice format
  * with or without courses included
  */
-function print_whole_category_list($category=NULL, $displaylist=NULL, $parentslist=NULL, $depth=-1, $files = true) {
+function print_whole_category_list($category=NULL, $displaylist=NULL, $parentslist=NULL, $depth=-1, $showcourses = true) {
     global $CFG;
 
     if (isset($CFG->max_category_depth) && ($depth >= $CFG->max_category_depth)) {
@@ -1757,8 +1823,8 @@ function print_whole_category_list($category=NULL, $displaylist=NULL, $parentsli
     }
 
     if ($category) {
-        if ($category->visible or has_capability('moodle/course:update', get_context_instance(CONTEXT_SYSTEM))) {
-            print_category_info($category, $depth, $files);
+        if ($category->visible or has_capability('moodle/category:viewhiddencategories', get_context_instance(CONTEXT_SYSTEM))) {
+            print_category_info($category, $depth, $showcourses);
         } else {
             return;  // Don't bother printing children of invisible categories
         }
@@ -1781,7 +1847,7 @@ function print_whole_category_list($category=NULL, $displaylist=NULL, $parentsli
             $down = $last ? false : true;
             $first = false;
 
-            print_whole_category_list($cat, $displaylist, $parentslist, $depth + 1, $files);
+            print_whole_category_list($cat, $displaylist, $parentslist, $depth + 1, $showcourses);
         }
     }
 }
@@ -1807,7 +1873,7 @@ function make_categories_options() {
  * Prints the category info in indented fashion
  * This function is only used by print_whole_category_list() above
  */
-function print_category_info($category, $depth, $files = false) {
+function print_category_info($category, $depth, $showcourses = false) {
     global $CFG, $DB;
     static $strallowguests, $strrequireskey, $strsummary;
 
@@ -1820,7 +1886,7 @@ function print_category_info($category, $depth, $files = false) {
     $catlinkcss = $category->visible ? '' : ' class="dimmed" ';
 
     $coursecount = $DB->count_records('course') <= FRONTPAGECOURSELIMIT;
-    if ($files and $coursecount) {
+    if ($showcourses and $coursecount) {
         $catimage = '<img src="'.$CFG->pixpath.'/i/course.gif" alt="" />';
     } else {
         $catimage = "&nbsp;";
@@ -1829,7 +1895,7 @@ function print_category_info($category, $depth, $files = false) {
     echo "\n\n".'<table class="categorylist">';
 
     $courses = get_courses($category->id, 'c.sortorder ASC', 'c.id,c.sortorder,c.visible,c.fullname,c.shortname,c.password,c.summary,c.guest,c.cost,c.currency');
-    if ($files and $coursecount) {
+    if ($showcourses and $coursecount) {
 
         echo '<tr>';
 
@@ -1900,7 +1966,42 @@ function print_category_info($category, $depth, $files = false) {
     echo '</table>';
 }
 
+/**
+ * Prints the turn editing on/off button on course/index.php or course/category.php.
+ *
+ * @param integer $categoryid The id of the category we are showing, or 0 for system context.
+ * @return string HTML of the editing button, or empty string, if this user is not allowed
+ *      to see it.
+ */
+function update_category_button($categoryid = 0) {
+    global $CFG, $USER;
+
+    // Check permissions.
+    $context = get_category_or_system_context($categoryid);
+    if (!has_any_capability(array('moodle/category:manage', 'moodle/course:create'), $context)) {
+        return '';
+    }
 
+    // Work out the appropriate action.
+    if (!empty($USER->categoryediting)) {
+        $label = get_string('turneditingoff');
+        $edit = 'off';
+    } else {
+        $label = get_string('turneditingon');
+        $edit = 'on';
+    }
+
+    // Generate the button HTML.
+    $options = array('categoryedit' => $edit, 'sesskey' => sesskey());
+    if ($categoryid) {
+        $options['id'] = $categoryid;
+        $page = 'category.php';
+    } else {
+        $page = 'index.php';
+    }
+    return print_single_button($CFG->wwwroot . '/course/' . $page, $options,
+            $label, 'get', '', true);
+}
 
 /**
  * Category is 0 (for all courses) or an object
index 3295bef3485cfcccd06343d049f3eca4dd56fed2..e8576481f571f950a32c3a74843fb226e3f9213f 100644 (file)
@@ -72,7 +72,7 @@
 
     $displaylist = array();
     $parentlist = array();
-    make_categories_list($displaylist, $parentlist, "");
+    make_categories_list($displaylist, $parentlist);
 
     $strcourses = get_string("courses");
     $strsearch = get_string("search");
 
                 // this is ok since this will get inherited from course category context
                 // if it is set
-                if (has_capability('moodle/category:update', $coursecontext)) {
+                if (has_capability('moodle/category:manage', $coursecontext)) {
                     echo "<input type=\"checkbox\" name=\"c$course->id\" />\n";
                 } else {
                     echo "<input type=\"checkbox\" name=\"c$course->id\" disabled=\"disabled\" />\n";
index f1c71f72e8032235ed62b0b00300f8a7e3f1e3c5..42fa1fe70dc4c7a1bdd5b56d74974a1535522f25 100644 (file)
@@ -127,6 +127,7 @@ $string['cannotsetupcategory'] = 'Serious error! Could not set up a default cour
 $string['cannotsetupcapforplugin'] = 'Could not set up the capabilities for $a';
 $string['cannotsetupcapformod'] = 'Could not set up the capabilities for $a';
 $string['cannotsetupsite'] = 'Serious error! Could not set up the site!';
+$string['cannotshowhidecoursesincategory'] = 'Cannot show/hide the courses in category $a.';
 $string['cannotunzipfile'] = 'Cannot unzip file';
 $string['cannotupgradeblock'] = 'Upgrade of blocks system failed! (Could not update version in config table.)';
 $string['cannotupgradecaps'] = 'Had difficulties upgrading the core capabilities for the Roles system';
@@ -211,6 +212,7 @@ $string['errorcreatingrole'] = 'Error creating role';
 $string['erroronline'] = 'Error on line $a';
 $string['errorreadingfile'] = 'Error reading file \"$a\"';
 $string['errorunzippingfiles'] = 'Error unzipping files';
+$string['errorupdatingcoursevisibility'] = 'Error updating the course visibility';
 $string['errorsettinguserpref'] = 'Error setting user preference';
 $string['expiredkey'] = 'Expired key';
 $string['failtoloadblocks'] = 'One or more blocks are registered in the database, but they all failed to load!';
index ebb3a054d3746bbeadd45f9801c34a65d50163fd..a6ae1f7acb88a72e01143e6de64b5c750798be80 100644 (file)
@@ -329,6 +329,7 @@ $string['courseupdates'] = 'Course updates';
 $string['courseuploadlimit'] = 'Course upload limit';
 $string['create'] = 'Create';
 $string['createaccount'] = 'Create my new account';
+$string['createcategory'] = 'Create category';
 $string['createfolder'] = 'Create a folder in $a';
 $string['createuserandpass'] = 'Choose your username and password';
 $string['createziparchive'] = 'Create zip archive';
index b176faab4ef5e12e42796806659fc0b198db296c..67122ac4d570869adad427a122386bebeaf0b2f6 100644 (file)
@@ -35,7 +35,9 @@ $string['capabilities'] = 'Capabilities';
 $string['capability'] = 'Capability';
 $string['category:create'] = 'Create categories';
 $string['category:delete'] = 'Delete categories';
+$string['category:manage'] = 'Manage categories';
 $string['category:update'] = 'Update categories';
+$string['category:viewhiddencategories'] = 'See hidden categories';
 $string['category:visibility'] = 'See hidden categories';
 $string['checkglobalpermissions'] = 'Check system permissions';
 $string['checkpermissions'] = 'Check permissions';
index 8d8ead369404419ddbe9b7124507e0a8ed50dd12..3b64ae596605b6eee7f0b2498835eeaa6f663af1 100755 (executable)
@@ -5848,6 +5848,37 @@ function make_context_subobj($rec) {
     return $rec;
 }
 
+/**
+ * Do some basic, quick checks to see whether $rec->context looks like a
+ * valid context object.
+ *
+ * @param object $rec a think that has a context, for example a course, 
+ *      course category, course modules, etc.
+ * @param integer $contextlevel the type of thing $rec is, one of the CONTEXT_... constants.
+ * @return boolean whether $rec->context looks like the correct context object
+ *      for this thing.
+ */
+function is_context_subobj_valid($rec, $contextlevel) {
+    return isset($rec->context) && isset($rec->context->id) &&
+            isset($rec->context->path) && isset($rec->context->depth) &&
+            isset($rec->context->contextlevel) && isset($rec->context->instanceid) &&
+            $rec->context->contextlevel == $contextlevel && $rec->context->instanceid == $rec->id;
+}
+
+/**
+ * When you have a record (for example a $category, $course, $user or $cm that may,
+ * or may not, have come from a place that does make_context_subobj, you can use
+ * this method to ensure that $rec->context is present and correct before you continue.
+ *
+ * @param object $rec a thing that has an associated context.
+ * @param integer $contextlevel the type of thing $rec is, one of the CONTEXT_... constants.
+ */
+function ensure_context_subobj_present(&$rec, $contextlevel) {
+    if (!is_context_subobj_valid($rec, $contextlevel)) {
+        $rec->context = get_context_instance($contextlevel, $rec->id);
+    }
+}
+
 /**
  * Fetch recent dirty contexts to know cheaply whether our $USER->access
  * is stale and needs to be reloaded.
index 5396ae137fc25d3197139544e6ae903d269249a7..272aa5bcdc0301a5b0246994934d28a1676a2575 100644 (file)
@@ -941,14 +941,14 @@ function get_my_courses($userid, $sort='visible DESC,sortorder ASC', $fields=NUL
 
             //
             // Perhaps it's actually visible to $USER
-            // check moodle/category:visibility
+            // check moodle/category:viewhiddencategories
             //
             // The name isn't obvious, but the description says
             // "See hidden categories" so the user shall see...
             // But also check if the allowvisiblecoursesinhiddencategories setting is true, and check for course visibility
             if ($viscat === false) {
                 $catctx = $cats[$courses[$n]->category]->context;
-                if (has_capability('moodle/category:visibility', $catctx, $USER->id)) {
+                if (has_capability('moodle/category:viewhiddencategories', $catctx, $USER->id)) {
                     $vcatpaths[$courses[$n]->categorypath] = true;
                     $viscat = true;
                 } elseif ($CFG->allowvisiblecoursesinhiddencategories && $courses[$n]->visible == true) {
@@ -1160,7 +1160,7 @@ function get_categories($parent='none', $sort=NULL, $shallow=true) {
     if( $rs = $DB->get_recordset_sql($sql, $params) ){
         foreach($rs as $cat) {
             $cat = make_context_subobj($cat);
-            if ($cat->visible || has_capability('moodle/category:visibility',$cat->context)) {
+            if ($cat->visible || has_capability('moodle/category:viewhiddencategories',$cat->context)) {
                 $categories[$cat->id] = $cat;
             }
         }
@@ -1332,7 +1332,7 @@ function fix_course_sortorder() {
     }
 
     // now make sure that sortorders in course table are withing the category sortorder ranges
-    $sql = "SELECT cc.id, cc.sortorder
+    $sql = "SELECT DISTINCT cc.id, cc.sortorder
               FROM {course_categories} cc
               JOIN {course} c ON c.category = cc.id
              WHERE c.sortorder < cc.sortorder OR c.sortorder > cc.sortorder + ".MAX_COURSES_IN_CATEGORY;
@@ -2184,7 +2184,7 @@ function print_object($object) {
  *   we'll save a dbquery
  *
  * - If we return false, you'll still need to check if
- *   the user can has the 'moodle/category:visibility'
+ *   the user can has the 'moodle/category:viewhiddencategories'
  *   capability...
  *
  * - Will generate 2 DB calls.
index 8fc3555dca9187305d531898b580ae4d6fcd021a..fafd9632e00164ec0164037dca522def58f4e81d 100644 (file)
@@ -452,7 +452,11 @@ $moodle_capabilities = array(
         )
     ),
 
-    'moodle/category:create' => array(
+    // Create, update and delete course categories. (Deleting a course category
+    // does not let you delete the courses it contains, unless you also have
+    // moodle/course: delete.) Creating and deleting requires this permission in
+    // the parent category.
+    'moodle/category:manage' => array(
 
         'riskbitmask' => RISK_XSS,
 
@@ -460,38 +464,19 @@ $moodle_capabilities = array(
         'contextlevel' => CONTEXT_COURSECAT,
         'legacy' => array(
             'admin' => CAP_ALLOW
-        )
-    ),
-
-    'moodle/category:delete' => array(
-
-        'riskbitmask' => RISK_DATALOSS,
-
-        'captype' => 'write',
-        'contextlevel' => CONTEXT_COURSECAT,
-        'legacy' => array(
-            'admin' => CAP_ALLOW
-        )
-    ),
-
-    'moodle/category:update' => array(
-
-        'riskbitmask' => RISK_XSS,
-
-        'captype' => 'write',
-        'contextlevel' => CONTEXT_COURSECAT,
-        'legacy' => array(
-            'admin' => CAP_ALLOW
-        )
+        ),
+        'clonepermissionsfrom' => 'moodle/category:update'
     ),
 
-    'moodle/category:visibility' => array(
+    'moodle/category:viewhiddencategories' => array(
 
-        'captype' => 'write',
+        'captype' => 'read',
         'contextlevel' => CONTEXT_COURSECAT,
         'legacy' => array(
+            'coursecreator' => CAP_ALLOW,
             'admin' => CAP_ALLOW
-        )
+        ),
+        'clonepermissionsfrom' => 'moodle/category:visibility'
     ),
 
     'moodle/course:create' => array(
index 7a5a0b7fe9fbc20fac64468735950934287be371..5cd606f35ac344ab9b8b05e5fc175fe98ec23eb1 100644 (file)
@@ -5290,63 +5290,6 @@ function update_module_button($moduleid, $courseid, $string) {
     }
 }
 
-/**
- * Prints the editing button on a category page
- *
- * @uses $CFG
- * @uses $USER
- * @param int $categoryid ?
- * @return string
- * @todo Finish documenting this function
- */
-function update_category_button($categoryid) {
-    global $CFG, $USER;
-
-    if (has_capability('moodle/category:update', get_context_instance(CONTEXT_COURSECAT, $categoryid))) {
-        if (!empty($USER->categoryediting)) {
-            $string = get_string('turneditingoff');
-            $edit = 'off';
-        } else {
-            $string = get_string('turneditingon');
-            $edit = 'on';
-        }
-
-        return "<form $CFG->frametarget method=\"get\" action=\"$CFG->wwwroot/course/category.php\">".
-               '<div>'.
-               "<input type=\"hidden\" name=\"id\" value=\"$categoryid\" />".
-               "<input type=\"hidden\" name=\"categoryedit\" value=\"$edit\" />".
-               "<input type=\"hidden\" name=\"sesskey\" value=\"$USER->sesskey\" />".
-               "<input type=\"submit\" value=\"$string\" /></div></form>";
-    }
-}
-
-/**
- * Prints the editing button on categories listing
- *
- * @uses $CFG
- * @uses $USER
- * @return string
- */
-function update_categories_button() {
-    global $CFG, $USER;
-
-    if (has_capability('moodle/category:update', get_context_instance(CONTEXT_SYSTEM))) {
-        if (!empty($USER->categoryediting)) {
-            $string = get_string('turneditingoff');
-            $categoryedit = 'off';
-        } else {
-            $string = get_string('turneditingon');
-            $categoryedit = 'on';
-        }
-
-        return "<form $CFG->frametarget method=\"get\" action=\"$CFG->wwwroot/course/index.php\">".
-               '<div>'.
-               '<input type="hidden" name="categoryedit" value="'. $categoryedit .'" />'.
-               '<input type="hidden" name="sesskey" value="'.$USER->sesskey.'" />'.
-               '<input type="submit" value="'. $string .'" /></div></form>';
-    }
-}
-
 /**
  * Prints the editing button on search results listing
  * For bulk move courses to another category
index 186824e851f11053180daf678fd420f3c29a4812..c3fe009c6ec1aca7aa90d8d25df2a6b7514e7500 100644 (file)
@@ -2229,10 +2229,12 @@ body#course-category .addcategory {
   padding: 10px;
 }
 
+body#course-index .buttons .singlebutton,
 body#course-category .buttons .singlebutton {
   display: inline;
 }
 
+body#course-index .buttons,
 body#course-category .buttons {
   text-align: center;
   margin-bottom: 15px;
@@ -2329,6 +2331,7 @@ body#course-info .generalbox.info {
 
 #coursesearch,
 #coursesearch2 {
+  margin-top: 1em;
   text-align:center;
 }
 
index e820c20bc6820c00c03c91e292308b7bb4a2b817..a30dc58d105f6fcdab6489a864797187b3aa01f4 100644 (file)
@@ -6,7 +6,7 @@
 // This is compared against the values stored in the database to determine
 // whether upgrades should be performed (see lib/db/*.php)
 
-    $version = 2008120100;  // YYYYMMDD   = date of the last version bump
+    $version = 2008120400;  // YYYYMMDD   = date of the last version bump
                             //         XX = daily increments
 
     $release = '2.0 dev (Build: 20081204)';  // Human-friendly version name