# This patch file was generated by NetBeans IDE
# This patch can be applied using context Tools: Apply Diff Patch action on respective folder.
# It uses platform neutral UTF-8 encoding.
# Above lines and this line are ignored by the patching process.
Index: moodle/backup/moodle2/backup_course_task.class.php
--- moodle/backup/moodle2/backup_course_task.class.php Base (1.3)
+++ moodle/backup/moodle2/backup_course_task.class.php Locally Modified (Based On 1.3)
@@ -90,6 +90,11 @@
             $this->add_step(new backup_comments_structure_step('course_comments', 'comments.xml'));
         }
 
+        if (backup_plan_dbops::require_gradebook_backup($this->get_courseid(), $this->get_backupid())) {
+            $this->add_step(new backup_gradebook_structure_step('course_gradebook','gradebook.xml'));
+        }
+
+
         // Generate the logs file (conditionally)
         if ($this->get_setting_value('logs')) {
             //$this->add_step(new backup_course_logs_structure_step('course_logs', 'logs.xml'));
Index: moodle/backup/moodle2/backup_stepslib.php
--- moodle/backup/moodle2/backup_stepslib.php Base (1.8)
+++ moodle/backup/moodle2/backup_stepslib.php Locally Modified (Based On 1.8)
@@ -74,7 +74,7 @@
 }
 
 /**
- * Abtract tructure step, parent of all the activity structure steps. Used to wrap the
+ * Abtract structure step, parent of all the activity structure steps. Used to wrap the
  * activity structure definition within the main <activity ...> tag
  */
 abstract class backup_activity_structure_step extends backup_structure_step {
@@ -511,6 +511,122 @@
 }
 
 /**
+ * structure step in charge of constructing the gradebook.xml file for all the gradebook config in the course
+ * NOTE: the backup of the grade items themselves is handled by backup_activity_grades_structure_step
+ */
+class backup_gradebook_structure_step extends backup_structure_step {
+
+    protected function define_structure() {
+
+        // are we including user info?
+        $userinfo = $this->get_setting_value('users');
+
+        $gradebook = new backup_nested_element('gradebook');
+
+        //grade_letters are done in backup_activity_grades_structure_step()
+
+        //calculated grade items
+        $grade_scale = new backup_nested_element('grades_scale', array('id'), array(
+            'courseid', 'userid', 'name', 'scale',
+            'description', 'descriptionformat', 'timemodified'));
+
+        $grade_items = new backup_nested_element('grade_items');
+        $grade_item = new backup_nested_element('grade_item', array('id'), array(
+            'categoryid', 'itemname', 'itemtype', 'itemmodule',
+            'iteminstance', 'itemnumber', 'iteminfo', 'idnumber',
+            'calculation', 'gradetype', 'grademax', 'grademin',
+            'scaleid', 'outcomeid', 'gradepass', 'multfactor',
+            'plusfactor', 'aggregationcoef', 'sortorder', 'display',
+            'decimals', 'hidden', 'locked', 'locktime',
+            'needsupdate', 'timecreated', 'timemodified'));
+
+        $grade_grades = new backup_nested_element('grade_grades');
+        $grade_grade = new backup_nested_element('grade_grade', array('id'), array(
+            'userid', 'rawgrade', 'rawgrademax', 'rawgrademin',
+            'rawscaleid', 'usermodified', 'finalgrade', 'hidden',
+            'locked', 'locktime', 'exported', 'overridden',
+            'excluded', 'feedback', 'feedbackformat', 'information',
+            'informationformat', 'timecreated', 'timemodified'));
+
+        //grade_categories
+        $grade_categories = new backup_nested_element('grade_categories');
+        $grade_category   = new backup_nested_element('grade_category', null, array('courseid', 
+                'parent', 'depth', 'path', 'fullname', 'aggregation', 'keephigh', 
+                'dropload', 'aggregateonlygraded', 'aggregateoutcomes', 'aggregatesubcats',
+                'timecreated', 'timemodified'));
+
+        //outcomes
+        $grade_outcome_courses = new backup_nested_element('grade_outcomes_courses');
+        $grade_outcomes_course = new backup_nested_element('grade_outcomes_course', array('id'), array(
+            'courseid', 'outcomeid'));
+
+        $grade_outcome = new backup_nested_element('grades_outcome', array('id'), array(
+            'courseid', 'shortname', 'fullname', 'scaleid',
+            'description', 'descriptionformat', 'timecreated', 'timemodified', 'usermodified'));
+
+
+        // Build the tree
+
+        $gradebook->add_child($grade_outcome_courses);
+        $grade_outcomes_courses->add_child($grade_outcome_course);
+        $grade_outcomes_course->add_child($grade_outcome);
+
+        $gradebook->add_child($grade_items);
+        $grade_items->add_child($grade_item);
+        $grade_item->add_child($grade_grades);
+        $grade_grades->add_child($grade_grade);
+
+        $grade_item->add_child($grade_scale);
+
+        $gradebook->add_child($grade_categories);
+        $grade_categories->add_child($grade_category);
+
+        // Define sources
+
+        //if itemtype == manual then item is a calculated item so isn't attached to an activity and we need to back it up here
+        $grade_items_array = grade_item::fetch_all(array('itemtype' => 'manual', 'courseid' => $this->get_courseid()));
+        
+        //$grade_items_array==false and not an empty array if no items. set_source_array() fails if you pass a bool
+        if ($grade_items_array) {
+            $grade_item->set_source_array($grade_items_array);
+
+            $scalesql = "SELECT s.* FROM {grade_items} gi JOIN {scale} s ON gi.scaleid=s.id WHERE gi.id=:gid";
+            $grade_scale->set_source_sql($scalesql, array('gid' => backup::VAR_PARENTID));
+
+            //if were backing up the gradebook we want everything so get all outcomes for this course
+
+            //do we need to back up this associative table?
+            $grade_outcomes_course->set_source_table('grade_outcome_courses', array('courseid'=>$this->get_courseid()));
+
+            $outcomesql = "SELECT go.*
+                           FROM {grade_outcomes} go
+                           JOIN {grade_outcomes_courses} goc
+                            ON (goc.outcomeid = go.id)
+                           WHERE goc.courseid = :courseid";
+            $outcomeparams = array('courseid'=>$this->get_courseid());
+            $grade_outcome->set_source_sql($outcomesql, $outcomeparams);
+        }
+
+        if ($userinfo) {
+            $grade_grade->set_source_table('grade_grades', array('itemid' => backup::VAR_PARENTID));
+        }
+
+        $grade_category_sql = "SELECT gc.*, gi.sortorder
+                                   FROM {grade_categories} gc
+                                        JOIN {grade_items} gi
+                                          ON (gi.iteminstance = gc.id)
+                                  WHERE gc.courseid = :courseid
+                                        AND (gi.itemtype='course' OR gi.itemtype='category')
+                               ORDER BY gc.parent ASC";//need parent categories before their children
+        $grade_category_params = array('courseid'=>backup::VAR_COURSEID);
+        $grade_category->set_source_sql($grade_category_sql, $grade_category_params);
+
+        // Return the root element
+        return $gradebook;
+    }
+}
+
+/**
  * structure step in charge if constructing the completion.xml file for all the users completion
  * information in a given activity
  */
Index: moodle/backup/util/dbops/backup_plan_dbops.class.php
--- moodle/backup/util/dbops/backup_plan_dbops.class.php Base (1.2)
+++ moodle/backup/util/dbops/backup_plan_dbops.class.php Locally Modified (Based On 1.2)
@@ -172,4 +172,25 @@
         return $backupword . '-' . $format . '-' . $type . '-' .
                $name . '-' . $date . $info . '.zip';
     }
+
+    /**
+    * Returns a flag indicating the need to backup gradebook elements like calculated grade items and category visibility
+    * If all activity related grade items are being backed up we can also backup calculated grade items and categories
+    */
+    public static function require_gradebook_backup($courseid, $backupid) {
+        global $DB;
+
+        $backupgradebook = true;
+
+        $sql = "SELECT count(id)
+FROM {grade_items}
+WHERE courseid=:courseid AND itemtype = 'mod'
+AND id NOT IN (SELECT bi.id FROM {backup_ids_temp} bi WHERE bi.itemname = 'grade_item_final' AND bi.backupid = :backupid)";
+        $params = array('courseid'=>$courseid, 'backupid'=>$backupid);
+
+        $count = $DB->count_records_sql($sql, $params);
+
+        //if there are 0 activity grade items not already included in the backup
+        return $count==0;
 }
+}