]> git.mjollnir.org Git - moodle.git/commitdiff
Initial commit for Bug MDL-7380 "groups" - Juliette White's code. NOTE, for the momen...
authornfreear <nfreear>
Tue, 7 Nov 2006 11:42:49 +0000 (11:42 +0000)
committernfreear <nfreear>
Tue, 7 Nov 2006 11:42:49 +0000 (11:42 +0000)
72 files changed:
group/db/dbbasicgrouplib.php [new file with mode: 0644]
group/db/dbcleanup.php [new file with mode: 0644]
group/db/dbcourselib.php [new file with mode: 0644]
group/db/dbgroupinglib.php [new file with mode: 0644]
group/db/dbmodulelib.php [new file with mode: 0644]
group/db/dbsetup.php [new file with mode: 0644]
group/db/vssver.scc [new file with mode: 0644]
group/groupui/addgroupstogrouping-form.html [new file with mode: 0644]
group/groupui/addgroupstogrouping-form.js [new file with mode: 0644]
group/groupui/addgroupstogrouping-xml.php [new file with mode: 0644]
group/groupui/addmembers-form.html [new file with mode: 0644]
group/groupui/addmembers-form.js [new file with mode: 0644]
group/groupui/addmembers-xml.php [new file with mode: 0644]
group/groupui/ajax.js [new file with mode: 0644]
group/groupui/connection.js [new file with mode: 0644]
group/groupui/createautomaticgrouping-form.html [new file with mode: 0644]
group/groupui/createautomaticgrouping-form.js [new file with mode: 0644]
group/groupui/createautomaticgrouping-xml.php [new file with mode: 0644]
group/groupui/creategroup-form.html [new file with mode: 0644]
group/groupui/creategroup-form.js [new file with mode: 0644]
group/groupui/creategroup-xml.php [new file with mode: 0644]
group/groupui/creategrouping-form.html [new file with mode: 0644]
group/groupui/creategrouping-form.js [new file with mode: 0644]
group/groupui/creategrouping-xml.php [new file with mode: 0644]
group/groupui/deletegroup-xml.php [new file with mode: 0644]
group/groupui/deletegroup.js [new file with mode: 0644]
group/groupui/deletegrouping-xml.php [new file with mode: 0644]
group/groupui/deletegrouping.js [new file with mode: 0644]
group/groupui/editgroupingpermissions-form.html [new file with mode: 0644]
group/groupui/editgroupingpermissions-form.js [new file with mode: 0644]
group/groupui/editgroupingpermissions-xml.php [new file with mode: 0644]
group/groupui/editgroupingsettings-form.html [new file with mode: 0644]
group/groupui/editgroupingsettings-form.js [new file with mode: 0644]
group/groupui/editgroupingsettings-xml.php [new file with mode: 0644]
group/groupui/editgroupsettings-form.html [new file with mode: 0644]
group/groupui/editgroupsettings-form.js [new file with mode: 0644]
group/groupui/editgroupsettings-xml.php [new file with mode: 0644]
group/groupui/form.css [new file with mode: 0644]
group/groupui/form.html [new file with mode: 0644]
group/groupui/getgroupingpermissions-xml.php [new file with mode: 0644]
group/groupui/getgroupings-xml.php [new file with mode: 0644]
group/groupui/getgroupingsettings-xml.php [new file with mode: 0644]
group/groupui/getgroupsettings-xml.php [new file with mode: 0644]
group/groupui/getgroupsingrouping-xml.php [new file with mode: 0644]
group/groupui/getgroupsnotingrouping-xml.php [new file with mode: 0644]
group/groupui/getmembers-xml.php [new file with mode: 0644]
group/groupui/getnonmembers-xml.php [new file with mode: 0644]
group/groupui/index.php [new file with mode: 0644]
group/groupui/main-buttons-form.js [new file with mode: 0644]
group/groupui/main-form.html [new file with mode: 0644]
group/groupui/main-init-form.js [new file with mode: 0644]
group/groupui/main-selects-form.js [new file with mode: 0644]
group/groupui/printgrouping.php [new file with mode: 0644]
group/groupui/removegroupfromgrouping-xml.php [new file with mode: 0644]
group/groupui/removegroupfromgrouping.js [new file with mode: 0644]
group/groupui/removemembers-xml.php [new file with mode: 0644]
group/groupui/removemembers.js [new file with mode: 0644]
group/groupui/util-form.js [new file with mode: 0644]
group/groupui/yahoo.js [new file with mode: 0644]
group/install.php [new file with mode: 0644]
group/install.sql [new file with mode: 0644]
group/lib/automaticgroupinglib.php [new file with mode: 0644]
group/lib/basicgrouplib.php [new file with mode: 0644]
group/lib/courselib.php [new file with mode: 0644]
group/lib/groupinglib.php [new file with mode: 0644]
group/lib/legacylib.php [new file with mode: 0644]
group/lib/lib.php [new file with mode: 0644]
group/lib/modulelib.php [new file with mode: 0644]
group/lib/utillib.php [new file with mode: 0644]
group/onedaymaybe.txt [new file with mode: 0644]
group/overview.txt [new file with mode: 0644]
group/todo.txt [new file with mode: 0644]

diff --git a/group/db/dbbasicgrouplib.php b/group/db/dbbasicgrouplib.php
new file mode 100644 (file)
index 0000000..5cf6117
--- /dev/null
@@ -0,0 +1,402 @@
+<?php 
+/*******************************************************************************
+ * Functions to make changes to groups in the database i.e. functions that 
+ * access the groups_courses_groups, 
+ * groups_groups and groups_groups_users.
+ ******************************************************************************/
+
+include_once($CFG->dirroot.'/lib/datalib.php');
+include_once($CFG->dirroot.'/course/groups/lib/lib.php');
+
+
+/*******************************************************************************
+ * Utility functions
+ ******************************************************************************/
+
+/**
+ * Returns the user record for a given userid - I can't seem to find a function 
+ * anywhere else to do this
+ * (and we need it to use the fullname() function). 
+ * @param int $userid The id of the user to get the record for
+ * @return object The user record
+ */
+function groups_db_get_user($userid) {
+       $query = get_record('user', 'id', $userid);
+       return $query;
+       
+}
+
+
+/******************************************************************************* 
+    List functions  
+ ******************************************************************************/
+
+
+/**
+ * Returns all the ids of all the groups for the specified course.
+ * @uses $CFG
+ * @param int $courseid The courseid to get the groups for.
+ * @return array|false Returns an array of the group ids or false if no groups
+ * or an error returned
+ */
+ function groups_db_get_groups($courseid) {
+    if (!$courseid) {
+        $groupid = false;
+    } else {
+        $groups = get_records('groups_courses_groups', 'courseid', $courseid, 
+                              '', $fields='id, groupid');
+        // Put the results into an array
+        $groupids = array();
+        if (!$groups) {
+               $groupids = false;
+        } else {
+               foreach ($groups as $group) {
+                   array_push($groupids, $group->groupid);
+               }
+        }
+    }
+    
+    return $groupids;
+}
+
+
+/**
+ * Returns the ids of the users in the specified group.
+ * @param int $groupid The groupid to get the users for
+ * @return array| false Returns an array of the user ids for the specified
+ * group or false if no users or an error returned.
+ */
+function groups_db_get_members($groupid) {
+    if (!$groupid) {
+        $userids = false;
+    } else {
+        $users = get_records('groups_groups_users', 'groupid ', $groupid, '', 
+                             $fields='id, userid');
+        if (!$users) {
+               $userids = false;
+        } else {
+               $userids = array();
+               foreach ($users as $user) {
+                   array_push($userids, $user->userid);
+               }
+        }
+    }
+    return $userids;
+}
+
+
+/**
+ * Gets the groups to which a user belongs for a specified course. 
+ * @uses $CFG
+ * @param int $userid The id of the specified user
+ * @param int $courseid The id of the course. 
+ * @return array | false An array of the group ids of the groups to which the
+ * user belongs or false if there are no groups or an error occurred.
+ */
+function groups_db_get_groups_for_user($userid, $courseid) {
+    if (!$userid or !$courseid) {
+        $groupid = false;
+    } else {  
+        global $CFG;
+        $table_prefix = $CFG->prefix;
+        $sql = "SELECT g.id, userid 
+                FROM {$table_prefix}groups_groups_users AS gm 
+                INNER JOIN {$table_prefix}groups_groups AS g
+                ON gm.groupid = g.id
+                INNER JOIN {$table_prefix}groups_courses_groups AS cg
+                ON g.id = cg.groupid
+                WHERE cg.courseid  = $courseid AND gm.userid=$userid";
+                
+        $groups = get_records_sql($sql);
+        
+        if (!$groups) {
+               $groupids = false;
+        } else { 
+               // Put the results into an array
+               $groupids = array();
+               foreach ($groups as $group) {
+                   array_push($groupids, $group->id);    
+               }
+        }
+    }
+       
+    return $groupids;
+}
+
+/**
+ * Get the group settings object for a group - this contains the following 
+ * properties:
+ * name, description, lang, theme, picture, hidepicture
+ * @param int $groupid The id of the gruop
+ * @return object The group settings object 
+ */
+function groups_db_get_group_settings($groupid) {
+   if (!$groupid) {
+        $groupsettings = false;
+    } else {
+        global $CFG;
+        $tableprefix = $CFG->prefix;
+        $sql = "SELECT id, name, description, lang, theme, picture, hidepicture 
+                FROM {$tableprefix}groups_groups
+                WHERE id = $groupid";
+        $groupsettings = get_record_sql($sql);
+    }
+  
+    return $groupsettings;     
+
+}
+
+/**
+ * Given two users, determines if there exists a group to which they both belong
+ * @param int $userid1 The id of the first user
+ * @param int $userid2 The id of the second user
+ * @return boolean True if the users are in a common group, false otherwise or 
+ * if an error occurred. 
+ */
+function groups_db_users_in_common_group($userid1, $userid2) {
+       $havecommongroup = false;
+       $sql = "SELECT gm1.groupid, 1 FROM {$tableprefix}groups_members AS gm1 " .
+                       "INNER JOIN {$tableprefix}groups_members AS gm2 " .
+                       "ON gm1.groupid =gm2.groupid" .
+                       "WHERE gm1.userid = $userid1 AND gm2.userid = $userid2";
+    $commonggroups = get_record_sql($sql);
+    if ($commongroups) {
+       $havecommongroup = true;
+    }
+    
+    return $havecommongroup;           
+}
+
+
+
+/******************************************************************************* 
+   Membership functions  
+ ******************************************************************************/
+
+
+/**
+ * Determines if a group with a given groupid exists. 
+ * @param int $groupid The groupid to check for
+ * @return boolean True if the group exists, false otherwise or if an error 
+ * occurred. 
+ */
+function groups_db_group_exists($groupid) {
+    if (!$groupid) {
+        $exists = false;
+    } else {
+        $exists = record_exists($table = 'groups_groups', 'id', $groupid);
+    }
+    
+    return $exists;
+}
+
+
+/**
+ * Determines if a specified user is a member of a specified group
+ * @param int $groupid The group about which the request has been made
+ * @param int $userid The user about which the request has been made
+ * @return boolean True if the user is a member of the group, false otherwise
+ */
+function groups_db_is_member($groupid, $userid) {
+    if (!$groupid or !$userid) {
+        $ismember = false;
+    } else {
+        $ismember = record_exists($table = 'groups_groups_users', 'groupid', 
+                                  $groupid, 'userid', $userid);
+    }
+    
+    return $ismember;
+}
+
+
+/**
+ * Determines if a specified group is a group for a specified course
+ * @param int $groupid The group about which the request has been made
+ * @param int $courseid The course for which the request has been made
+ * @return boolean True if the group belongs to the course, false otherwise
+ */
+function groups_db_group_belongs_to_course($groupid, $courseid) {   
+    if (!$groupid or !$courseid) {
+        $ismember = false;
+    } else {
+        $ismember = record_exists($table = 'groups_courses_groups', 
+                                  'groupid', $groupid, 
+                                  'courseid', $courseid);
+    }
+    
+    return $ismember;
+}
+
+
+/*******************************************************************************
+   Creation functions  
+ ******************************************************************************/
+
+
+/** 
+ * Creates a group for a specified course
+ * @param int $courseid The course to create the group for
+ * @return int The id of the group created or false if the create failed.
+ */
+function groups_db_create_group($courseid, $groupsettings = false) {
+       // Check we have a valid course id
+    if (!$courseid) {
+        $groupid = false; 
+    } else {      
+       $groupsettings = groups_set_default_group_settings($groupsettings);
+               
+       $record = $groupsettings;
+        $record->timecreated = time();
+        $record->timemodified = time();
+        print_r($record);
+        $groupid = insert_record('groups_groups', $record);
+
+        
+        if ($groupid != false) {
+               $record2->courseid = $courseid;
+               $record2->groupid = $groupid;
+               $record2->timeadded = time();
+               $groupadded = insert_record('groups_courses_groups', $record2);
+               if (!$groupadded) {
+                       $groupid = false;
+               }
+        }
+    }
+    return $groupid;
+}
+
+
+/**
+ * Adds a specified user to a group
+ * @param int $groupid  The group id
+ * @param int $userid   The user id
+ * @return boolean True if user added successfully, false otherwise. 
+ */
+function groups_db_add_member($userid, $groupid) {
+       // Check that the user and group are valid
+    if (!$userid or !$groupid or !groups_db_group_exists($groupid)) {
+        $useradded = false;
+    // If the user is already a member of the group, just return success
+    } elseif (groups_is_member($groupid, $userid)) {
+               $useradded = true;
+       } else {
+        // Add the user to the group
+               $record->groupid = $groupid;
+               $record->userid = $userid;
+               $record->timeadded = time();
+               $useradded = insert_record($table = 'groups_groups_users', $record);
+       }
+       
+       return $useradded;
+}
+
+
+/**
+ * Sets the information about a group
+ * @param object $groupsettings An object containing some or all of the 
+ * following properties:
+ * name, description, lang, theme, picture, hidepicture
+ * @return boolean True if info was added successfully, false otherwise. 
+ */
+function groups_db_set_group_settings($groupid, $groupsettings) {
+       $success = true;
+    if (!$groupid or !$groupsettings or !groups_db_group_exists($groupid)) {
+        $success = false; 
+    } else {
+       $record = $groupsettings;
+        $record->id = $groupid;
+        $record->timemodified = time();
+        $result = update_record('groups_groups', $record);
+        if (!$result) {
+            $success = false;
+        }
+    }
+     
+    return $success;
+       
+}
+
+/******************************************************************************* 
+    Deletion functions  
+ ******************************************************************************/
+
+
+/**
+ * Deletes the specified user from the specified group
+ * @param int $userid The user to delete
+ * @param int $groupid The group to delete the user from
+ * @return boolean True if deletion was successful, false otherwise
+ */
+function groups_db_remove_member($userid, $groupid) {
+    if (!$userid or !$groupid) {
+        $success = false;
+    } else {
+        $results = delete_records('groups_groups_users', 
+                                  'groupid', $groupid, 'userid', $userid);
+        // delete_records returns an array of the results from the sql call, 
+        // not a boolean, so we have to set our return variable
+        if ($results == false) {
+            $success = false;
+        } else {
+            $success = true;
+        }
+    }
+    
+    return $success;
+}
+
+
+/** 
+ * Deletes a specified group
+ * @param int $groupid The group to delete
+ * @return boolean True if deletion was successful, false otherwise
+ */
+function groups_db_delete_group($groupid) {
+    if (!$groupid) {
+        $success = false;
+    } else {
+        $success = true;
+        // Get a list of the users for the group and delete them all from the 
+        // group
+
+        $userids = groups_db_get_members($groupid);
+        if ($userids != false) {
+               foreach($userids as $userid) {
+                   $userdeleted = groups_db_remove_member($userid, $groupid);
+                   if (!$userdeleted) {
+                       $success = false;
+                   }
+               }
+        }
+       
+       // Remove any groupings that the group belongs to     
+          $groupingids = groups_get_groupings_for_group($groupid); 
+          if ($groupingids != false) {
+                  foreach($groupingids as $groupingid) {
+                      $groupremoved = groups_remove_group_from_grouping($groupid, 
+                                                                        $groupingid);
+                      if(!$groupremoved) {
+                               $success = false; 
+                      }
+                  }
+          }
+               
+               $results = delete_records('groups_courses_groups', 'groupid', $groupid);
+               if ($results == false) {
+                       $success = false;
+               }
+               
+        // Delete the group itself
+        $results = delete_records($table = 'groups_groups', $field1 = 'id', 
+                                  $value1 = $groupid);
+        // delete_records returns an array of the results from the sql call, 
+        // not a boolean, so we have to set our return variable
+        if ($results == false) {
+            $success = false;
+        }
+    }
+    
+    return $success;
+}
+?>
diff --git a/group/db/dbcleanup.php b/group/db/dbcleanup.php
new file mode 100644 (file)
index 0000000..35c61b5
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+
+// @@@ TO DO Need to write these functions because they are needed by parts of
+// the current moodle code where courses are deleted etc. 
+
+/**
+ * @param int $courseid If false, removes the user from all groups for all 
+ * course
+ */
+function groups_remove_user_from_all_groups($userid, $courseid) {
+       // @@@ TO DO 
+}
+
+function groups_remove_all_group_members($courseid, $showfeedback) {
+       // @@@ TO DO 
+}
+
+function groups_remove_all_groups($courseid, $removemembers, $showfeedback) {
+       // @@@ TO DO 
+}
+
+/**
+ * Cleans up all the groups and groupings in a course (it does this best-effort 
+ * i.e. if one deletion fails, it still attempts further deletions).
+ * IMPORTANT: Note that if the groups and groupings are used by other courses 
+ * somehow, they will still be deleted - it doesn't protect against this. 
+ * @param int $courseid The id of the course
+ * @return boolean True if the clean up was successful, false otherwise. 
+ */
+function groups_cleanup_groups($courseid) {
+       $success = true;
+
+       // Delete all the groupings 
+       $groupings = groups_get_groupings($courseid);
+    if ($groupings != false) {
+        foreach($groupings as $groupingid) {
+            $groupingdeleted = groups_delete_grouping($groupingid);
+            if (!$groupingdeleted) {
+                $success = false;
+            }
+        }
+    }
+
+    // Delete all the groups
+    $groupids = groups_get_groups($courseid);
+    if ($groupids != false) {
+           foreach($groupids as $groupid) {
+               $groupdeleted = groups_delete_group($groupid);
+
+               if (!$groupdeleted) {
+                   $success = false;
+               }
+           }
+    }
+
+       return $success;
+}
+
+?>
diff --git a/group/db/dbcourselib.php b/group/db/dbcourselib.php
new file mode 100644 (file)
index 0000000..f87d8ed
--- /dev/null
@@ -0,0 +1,10 @@
+<?php
+// @@@ TO DO 
+function groups_db_get_forced_grouping($courseid) {
+}
+
+function groups__db_set_forced_grouping($courseid, $groupingid) {
+}
+
+
+?>
diff --git a/group/db/dbgroupinglib.php b/group/db/dbgroupinglib.php
new file mode 100644 (file)
index 0000000..90e241f
--- /dev/null
@@ -0,0 +1,425 @@
+<?php
+/*******************************************************************************
+ * Functions to make changes to groupings in the database. In general these 
+ * access the groups_groupings, groups_courses_groupings and 
+ * groups_groupings_groups tables, although some all access the groups
+ * tables that store information about groups.
+ ******************************************************************************/
+
+include_once($CFG->dirroot.'/lib/datalib.php');
+
+/*******************************************************************************
+        Access/List functions  
+ ******************************************************************************/
+
+/**
+ * Gets a list of the groupings for a specified course
+ * @param int $courseid The id of the course
+ * @return array | false An array of the ids of the groupings, or false if there 
+ * are none or there was an error. 
+ */
+function groups_db_get_groupings($courseid) {
+    if (!$courseid) {
+        $groupingid = false;
+    } else {
+        $groupings = get_records('groups_courses_groupings', 'courseid ', 
+                                 $courseid, '', $fields='id, groupingid');
+               if (!$groupings) {
+                       $groupingsids = false;
+               } else {
+               // Put the results into an array
+               $groupingids = array();
+               foreach ($groupings as $grouping) {
+                   array_push($groupingids, $grouping->groupingid);
+               }
+               }
+    }
+    
+    return $groupingids;
+}
+
+
+/**
+ * Gets a list of the groups in a specified grouping
+ * @param int $groupingid The id of the grouping
+ * @return array | false. An array of the ids of the groups, or false if there
+ * are none or an error occurred.
+ */
+function groups_db_get_groups_in_grouping($groupingid) {
+    if (!$groupingid) {
+        $groupid = false;
+    } else {
+
+        $groups = get_records('groups_groupings_groups', 'groupingid ', 
+                              $groupingid, '', $fields='id, groupid');
+        if (!$groups) {
+                       $groupids = false;
+               } else {
+                       // Put the results into an array
+                       $groupids = array();
+                       foreach ($groups as $group) {
+                               array_push($groupids, $group->groupid);
+                       }
+               }
+    }
+    
+    return $groupids;
+}
+
+
+/*
+ * Gets the groupings that a group belongs to 
+ * @param int $groupid The id of the group
+ * @return array An array of the ids of the groupings that the group belongs to, 
+ * or false if there are none or if an error occurred. 
+ */
+function groups_db_get_groupings_for_group($groupid) {
+       if (!$groupid) {
+               $groupingids = false;
+       } else {
+               $groupings = get_records('groups_groupings_groups', 'groupid ', 
+                                        $groupid, '', $fields='id, groupingid');
+               if (!$groupings) {
+                               $groupingids = false;
+               } else {
+                       // Put the results into an array
+               $groupingids = array();
+               foreach ($groupings as $grouping) {
+                   array_push($groupingids, $grouping->groupingid);
+               }
+               } 
+       }
+       
+       return $groupingids;
+}
+
+
+/**
+ * Gets the information about a specified grouping
+ * @param int $groupingid
+ * @return object The grouping settings object - properties are name and 
+ * description. 
+ */
+function groups_db_get_grouping_settings($groupingid) {
+   if (!$groupingid) {
+        $groupingsettings = false;
+    } else {
+        global $CFG;
+        $tableprefix = $CFG->prefix;
+        $sql = "SELECT *
+                FROM {$tableprefix}groups_groupings
+                WHERE id = $groupingid";
+        $groupingsettings = get_record_sql($sql);
+    }
+        
+    return $groupingsettings;
+}
+
+/**
+ * Gets the grouping to use for a particular instance of a module in a course
+ * @param int $coursemoduleid The id of the instance of the module in the course
+ * @return int The id of the grouping or false if there is no such id recorded 
+ * or if an error occurred. 
+ */
+function groups_db_get_grouping_for_coursemodule($coursemoduleid) {
+       if (!$coursemoduleid) {
+               $groupingid = false;
+       } else {
+               $record = get_record('course_modules', 'id', $coursemoduleid, 'id, ' .
+                                            'groupingid');
+               if (!$record) {
+                       $groupingid = false;
+               } else {
+                       $groupingid = $record->groupingid;
+               }
+       }
+       
+       return $groupingid;
+}
+
+
+/*******************************************************************************
+        Membership functions  
+ ******************************************************************************/
+ /**
+ * Determines if a grouping with a specified id exists
+ * @param int $groupingid The grouping id. 
+ * @return True if the grouping exists, false otherwise or if an error occurred. 
+ */  
+function groups_db_grouping_exists($groupingid) {
+    if (!$groupingid) {
+        $exists = false;
+    } else {
+        $exists = record_exists('groups_groupings', 'id', 
+                                  $groupingid);
+    }
+    
+    return $exists;
+}
+
+
+ /**
+  * Determines if a group belongs to any grouping for the course that it belongs
+  * to
+  * @param int $groupid The id of the group
+  * @return boolean. True if the group belongs to a grouping, false otherwise or
+  * if an error has occurred.
+  */
+ function groups_db_belongs_to_any_grouping($groupid) {
+    if (!$groupid) {
+        $isingrouping = false;
+    } else {
+        $isingrouping = record_exists('groups_groupings_groups', 'groupid', 
+                                  $groupid);
+    }
+    
+    return $isingrouping;
+ }
+
+ /**
+  * Determines if a group belongs to a specified grouping
+  * @param int $groupid The id of the group
+  * @param int $groupingid The id of the grouping
+  * @return boolean. True if the group belongs to a grouping, false otherwise or
+  * if an error has occurred.
+  */
+ function groups_db_belongs_to_grouping($groupid, $groupingid) {
+    if (!$groupid or !$groupingid) {
+        $isingrouping = false;
+    } else {
+        $isingrouping = record_exists('groups_groupings_groups', 'groupid', 
+                                  $groupid, 'groupingid', $groupingid);
+    }
+    
+    return $isingrouping;
+ }
+  /**
+  * Detemines if a specified user belongs to any group of a specified grouping.
+  * @param int $userid The id of the user
+  * @param int $groupingid The id of the grouping
+  * @return boolean True if the user belongs to some group in the grouping,
+  * false otherwise or if an error occurred. 
+  */
+ function groups_db_is_member_of_some_group_in_grouping($userid, $groupingid) {
+    if (!$userid or !$groupingid) {
+        $belongstogroup = false;
+    } else {
+        global $CFG;
+        $tableprefix = $CFG->prefix;
+        $sql = "SELECT gm.id
+        FROM {$tableprefix}groups_groupings_groups AS gg
+        INNER JOIN {$tableprefix}groups_groups_users AS gm
+        ON gg.groupid = gm.groupid
+        WHERE gm.userid = $userid AND gg.groupingid = $groupingid";
+        $belongstogroup = record_exists_sql($sql);
+    }
+    return $belongstogroup;
+ }
+  /** 
+  * Determines if a grouping belongs to a specified course
+  * @param int $groupingid The id of the grouping
+  * @param int $courseid The id of the course
+  * @return boolean True if the grouping belongs to the course, false otherwise, 
+  * or if an error occurred. 
+  */
+ function groups_db_grouping_belongs_to_course($groupingid, $courseid) {
+    if (!$groupingid or !$courseid) {
+        $belongstocourse = false;
+    } else {
+        $belongstocourse = record_exists('groups_courses_groupings', 
+                                         'groupingid', $groupingid, 'courseid', 
+                                         $courseid);
+    }
+    
+    return $belongstocourse;
+ }
+
+
+
+
+/*******************************************************************************
+        Creation/Update functions  
+ ******************************************************************************/
+
+
+/**
+ * Marks a set of groups as a grouping. 
+ * 
+ * @param array $groupidarray An array of the ids of the groups to marks as a
+ * grouping. 
+ * @param int $courseid The id of the course for which the groups should form
+ * a grouping
+ * @return int | false The id of the grouping, or false if an error occurred. 
+ * Also returns false if any of the groups specified do not belong to the 
+ * course. 
+ */
+function groups_db_create_grouping($courseid, $groupingsettings = false) {
+    if (!$courseid or !groups_get_course_info($courseid)) {
+        $groupingid = false; 
+    } else {
+       // Replace any empty groupsettings
+        $groupingsettings = groups_set_default_grouping_settings($groupingsettings);
+        $record = $groupingsettings;
+        $record->timecreated = time();
+
+        $groupingid = insert_record('groups_groupings', $record);
+        if ($groupingid != false) {
+               $record2->courseid = $courseid;
+               $record2->groupingid = $groupingid;
+               $record2->timeadded = time();
+               $id= insert_record('groups_courses_groupings', $record2);
+               if (!$id) {
+                       $groupingid = false;
+               }
+        } 
+    }
+    
+    return $groupingid;
+}
+
+
+/**
+ * Adds a specified group to a specified grouping. 
+ * @param int $groupid The id of the group
+ * @param int $groupingid The id of the grouping
+ * @return boolean True if the group was added successfully, false otherwise
+ */
+function groups_db_add_group_to_grouping($groupid, $groupingid) {
+   if (!$groupid or !$groupingid or !groups_db_group_exists($groupid) 
+       or !groups_db_grouping_exists($groupingid)) {
+        $success = false;
+    } else {
+        $success = true;
+        $record->groupingid = $groupingid;
+        $record->groupid = $groupid;
+        $record->timeadded = time();
+        $results = insert_record('groups_groupings_groups', $record);
+        if (!$results) {
+            $success = false;
+        }
+    }
+    
+    return $groupingid;   
+}
+
+
+/**
+ * Set information about a grouping
+ * @param int $groupingid The grouping to update the info for.
+ * @param object $groupingsettings 
+ */
+function groups_db_set_grouping_settings($groupingid, $groupingsettings) {
+       $success = true;
+    if (!$groupingid or !$groupingsettings 
+        or !groups_db_grouping_exists($groupingid)) {
+        $success = false; 
+    } else {
+       // Replace any empty group settings. 
+       $record = $groupingsettings;
+        $record->id = $groupingid;
+        $record->timemodified = time();
+        $result = update_record('groups_groupings', $record);
+        if (!$result) {
+            $success = false;
+        }
+    }
+    
+    return $success;
+}
+
+
+/**
+ * Sets a grouping to use for a particular instance of a module in a course
+ * @param int $groupingid The id of the grouping
+ * @param int $coursemoduleid The id of the instance of the module in the course
+ * @return boolean True if the operation was successful, false otherwise
+ */
+function groups_db_set_grouping_for_coursemodule($groupingid, $coursemoduleid) {
+       $success = true;
+       if (!$groupingid or !$coursemoduleid) {
+               $success = false;
+       } else {
+               $record->id = $coursemoduleid;
+               $record->groupingid = $groupingid;
+               $result = update_record('course_modules', $record);
+               if (!$result) {
+                       $success = false;
+               } 
+       }
+       return $success;
+}
+
+
+/*******************************************************************************
+        Deletion functions  
+ ******************************************************************************/
+
+
+/** 
+ * Removes a specified group from a specified grouping. Note that this does 
+ * not delete the group. 
+ * @param int $groupid The id of the group.
+ * @param int $groupingid The id of the grouping
+ * @return boolean True if the deletion was successful, false otherwise. 
+ */
+function groups_db_remove_group_from_grouping($groupid, $groupingid) {
+       $success = true;
+    if (!$groupingid or !$groupid) {
+        $success = false;
+    } else {
+        $results = delete_records('groups_groupings_groups', 'groupid', 
+                                  $groupid, 'groupingid', $groupingid);
+        // delete_records returns an array of the results from the sql call, 
+        // not a boolean, so we have to set our return variable
+        if ($results == false) {
+            $success = false;
+        } 
+    }
+    
+    return $success;
+}
+
+
+/** 
+ * Removes a grouping from a course - note that this function removes but does 
+ * not delete any of the groups in the grouping.  
+ * @param int $groupingid The id of the grouping
+ * @return boolean True if the deletion was successful, false otherwise.
+ */ 
+function groups_db_delete_grouping($groupingid) {
+       $success = true;
+    if (!$groupingid) {
+        $success = false;
+    } else {
+
+        $results = delete_records('groups_courses_groupings', 'groupingid', 
+                                  $groupingid);
+        if ($results == false) {
+            $success = false;
+        }                           
+               
+        $results = delete_records('groups_groupings_groups', 'groupingid', 
+                                  $groupingid);
+        if ($results == false) {
+            $success = false;
+        } 
+        
+       $results = delete_records('groups_groupings', 'id', $groupingid);
+        if ($results == false) {
+            $success = false;
+        } 
+    }
+    
+    return $success;
+    
+}
+
+?>
+
diff --git a/group/db/dbmodulelib.php b/group/db/dbmodulelib.php
new file mode 100644 (file)
index 0000000..5ad604f
--- /dev/null
@@ -0,0 +1,46 @@
+<?php
+/*******************************************************************************
+ * modulelib.php
+ * 
+ * This file contains functions to be used by modules to support groups. More
+ * documentation is available on the Developer's Notes section of the Moodle 
+ * wiki. 
+ * 
+ * For queries, suggestions for improvements etc. please post on the Groups 
+ * forum on the moodle.org site.
+ ******************************************************************************/
+// @@@ Lots TO DO in this file
+
+
+/**
+ * Gets the groupingid for a particular course module instance returning
+ * false if it is null. 
+ * @param int  $cmid The id of the module instance.
+ * @return int The grouping id (or false if it is null or an error occurred)
+ */
+function groups_db_m_get_groupingid($cmid) {
+       // @@@ Check nulls are turned into false
+       $query = get_record('course_modules', 'groupingid', $userid);
+       return $query;
+}
+
+/**
+ * Gets the groupingid for a particular course module instance 
+ */
+function groups_db_m_set_groupingid($cmid) {
+       // @@@ TO DO    
+}
+
+
+/**
+ * Gets the group object associated with a group id. This group object can be 
+ * used to get information such as the name of the group and the file for the 
+ * group icon if it exists. (Look at the groups table in the database to see
+ * the fields). 
+ * @param int $groupid The id of the group
+ * @return group The group object 
+ */
+function groups_db_m_get_group($groupid) {
+}
+
+?>
\ No newline at end of file
diff --git a/group/db/dbsetup.php b/group/db/dbsetup.php
new file mode 100644 (file)
index 0000000..7e6b500
--- /dev/null
@@ -0,0 +1,177 @@
+<?php
+
+/***************************************************************************
+ * Functions required for setting up the database to use the new groups
+ **************************************************************************/
+include_once('../../../config.php');
+include_once($CFG->dirroot.'/lib/datalib.php');
+
+
+// @@@ TO DO Needs lots of sorting out so proper install/upgrade and also 
+// so used new db stuff. In practice we probably don't actually want to rename 
+// the tables (the group_member table in particular as this is basically 
+// unchanged)that already exist on the whole if we can help it so this and the 
+// the other dblib files should really be sorted out to do this. 
+
+// Database changes
+// New tables - the SQL for creating the tables is below (though should be 
+// foreign keys!) - however it might be more sensible to modify the existing 
+// tables instead as much as we can so that we don't need to copy data over and 
+// that any existing code that does assume the existence of those tables
+// might still work.
+// Another caveat - the code below doesn't contain the new fields in the
+// groupings table - viewowngroup, viewallgroupsmemebers, viewallgroupsactivities,
+// teachersgroupmark, teachersgroupview, teachersoverride, teacherdeletetable.
+// Other changes:
+// * course currently contains groupmode and groupmodeforce - we need to change
+// this to groupingid which is either null or a forced groupingid - need to
+// copy over existing data sensibly. 
+// * course_modules needs groupingid (think it previously had groupmode)
+
+
+// Change database tables - course table need to remove two fields add groupingid field
+// Move everything over
+// Course module instance need to add groupingid field
+// Module table - add group support field. 
+// Add deletable by teacher field. 
+
+
+/**
+ * Creates the database tables required
+ */
+function groups_create_database_tables() {
+       global $CFG;
+       $table_prefix = $CFG->prefix;
+
+       $createcoursegrouptablesql = "CREATE TABLE IF NOT EXISTS  `{$table_prefix}groups_courses_groups`
+                                                                (`id` int(10) unsigned NOT NULL auto_increment,
+                                                      `courseid` int(10) unsigned NOT NULL default '0',
+                                                              `groupid` int(11) NOT NULL,
+                                                               PRIMARY KEY  (`id`),
+                                                           UNIQUE KEY `id` (`id`),  KEY `courseid` (`courseid`))";
+                                                           
+       $creategroupstablesql = "CREATE TABLE IF NOT EXISTS `{$table_prefix}groups_groups` (
+                                                       `id` int(10) unsigned NOT NULL auto_increment,
+                                                       `name` varchar(254) collate latin1_general_ci NOT NULL default '',
+                                                       `description` text collate latin1_general_ci NOT NULL,
+                                                       `enrolmentkey` varchar(50) collate latin1_general_ci NOT NULL default '',
+                                                       `lang` varchar(10) collate latin1_general_ci NOT NULL default 'en',
+                                                       `theme` varchar(50) collate latin1_general_ci NOT NULL default '',
+                                                       `picture` int(10) unsigned NOT NULL default '0',
+                                                       `hidepicture` int(2) unsigned NOT NULL default '0',
+                                                       `timecreated` int(10) unsigned NOT NULL default '0',
+                                                       `timemodified` int(10) unsigned NOT NULL default '0',
+                                                       PRIMARY KEY  (`id`), UNIQUE KEY `id` (`id`))";
+
+
+       $creategroupsuserstablesql = "CREATE TABLE IF NOT EXISTS `{$table_prefix}groups_groups_users` (
+                                                                 `id` int(10) unsigned NOT NULL auto_increment,
+                                                                 `groupid` int(10) unsigned NOT NULL default '0',
+                                                                 `userid` int(10) unsigned NOT NULL default '0',
+                                                                 `timeadded` int(10) unsigned NOT NULL default '0',
+                                                                 PRIMARY KEY  (`id`), UNIQUE KEY `id` (`id`),
+                                                                 KEY `groupid` (`groupid`), KEY `userid` (`userid`))  ";
+       
+       $createcoursesgroupingtablesql = "CREATE TABLE IF NOT EXISTS `{$table_prefix}groups_courses_groupings` (
+                                                                         `id` int(10) unsigned NOT NULL auto_increment,
+                                                                         `courseid` int(10) unsigned NOT NULL default '0',
+                                                                         `groupingid` mediumint(9) NOT NULL,
+                                                                         PRIMARY KEY  (`id`),
+                                                                         UNIQUE KEY `id` (`id`),
+                                                                         KEY `courseid` (`courseid`)
+                                                                       )";
+                                                                         
+       $creategroupingstablesql = "CREATE TABLE `{$table_prefix}groups_groupings` (
+                                                                 `id` int(10) unsigned NOT NULL auto_increment,
+                                                                 `name` varchar(254) collate latin1_general_ci NOT NULL default '',
+                                                                 `description` text collate latin1_general_ci NOT NULL,
+                                                                 `timecreated` int(10) unsigned NOT NULL default '0',
+                                                                 PRIMARY KEY  (`id`),
+                                                                 UNIQUE KEY `id` (`id`)
+                                                               )  ";
+                                                                                                                                          
+       $creategroupingsgroupstablesql = "CREATE TABLE IF NOT EXISTS `{$table_prefix}groups_groupings_groups` (
+                                                                         `id` int(10) unsigned NOT NULL auto_increment,
+                                                                         `groupingid` int(10) unsigned default '0',
+                                                                         `groupid` int(10) NOT NULL,
+                                                                         `timecreated` int(10) unsigned NOT NULL default '0',                                                            `viewowngroup` binary(1) NOT NULL,
+                                                                         `viewallgroupsmembers` binary(1) NOT NULL,
+                                                                         `viewallgroupsactivities` binary(1) NOT NULL,
+                                                                         `teachersgroupmark` binary(1) NOT NULL,
+                                                                         `teachersgroupview` binary(1) NOT NULL,
+                                                                         `teachersoverride` binary(1) NOT NULL, .
+                                                                         PRIMARY KEY  (`id`),
+                                                                         UNIQUE KEY `id` (`id`),
+                                                                         KEY `courseid` (`groupingid`)
+                                                                       )  ";                                                             
+       
+       modify_database('',$createcoursegrouptablesql );
+       modify_database('',$creategroupstablesql );
+       modify_database('',$creategroupsuserstablesql);
+       modify_database('',$createcoursesgroupingtablesql);
+       modify_database('',$creategroupingstablesql);
+       modify_database('',$creategroupingsgroupstablesql );
+                       
+}
+
+
+/**
+ * Copies any old style moodle group to a new style moodle group - we'll need this for any upgrade code
+ * @param int $groupid The 'old moodle groups' id of the group to copy
+ * @param int $courseid The course id 
+ * @param boolean True if the operation was successful, false otherwise. 
+ */
+function groups_db_copy_moodle_group_to_imsgroup($groupid, $courseid) {
+       
+       $success = true;
+       
+       $groupsettings = get_record('groups', 'id ', $groupid, '');
+       
+       // Only copy the group if the group exists. 
+       if ($groupsettings != false) {
+               $record->name = $groupsettings->name;
+               $record->description = $groupsettings->description;
+               $record->password = $groupsettings->password;
+               $record->lang = $groupsettings->lang;
+               $record->theme = $groupsettings->theme;
+               $record->picture = $groupsettings->picture;
+               $record->hidepicture = $groupsettings->hidepicture;
+               $record->timecreated = $groupsettings->timecreated;
+               $record->timemodified = $groupsettings->timemodified;
+               $newgroupid = insert_record('groups_groups', $record);
+           if (!$newgroupid) {
+               $success = false;
+           }
+               
+               $courserecord->courseid = $groupsettings->courseid;
+               $courserecord->groupid = $newgroupid;
+               
+               $added = insert_record('groups_courses_groups', $courserecord);
+                                   
+            if (!$added) {
+               $success = false;
+            }  
+            
+            // Copy over the group members
+               $groupmembers = get_records('groups_users', 'groupid', $groupid);
+               if ($groupmembers != false) {
+                       foreach($groupmembers as $member) {
+                               $record->groupid = $newgroupid;
+                               $record->userid = $member->userid;
+                               $useradded = insert_record('groups_groups_users', $record);
+                               if (!$useradded) {
+                                       $success = false;
+                               }
+                       }
+               }
+
+       } 
+       
+       if (!$success) {
+               notify('Copy operations from Moodle groups to IMS Groups failed');
+       }
+     
+    return $success;
+}
+
+?>
\ No newline at end of file
diff --git a/group/db/vssver.scc b/group/db/vssver.scc
new file mode 100644 (file)
index 0000000..24b8503
Binary files /dev/null and b/group/db/vssver.scc differ
diff --git a/group/groupui/addgroupstogrouping-form.html b/group/groupui/addgroupstogrouping-form.html
new file mode 100644 (file)
index 0000000..c199ad6
--- /dev/null
@@ -0,0 +1,9 @@
+<div id="addgroupstogroupingform" class="popup">
+    <h3><?php print_string('addgroupstogrouping', 'groups'); ?> <span id="selectedgroupingforaddinggroups"></span>
+    </h3>
+    <form action="">
+        <p><select id="groupsnotingrouping" size="15" multiple="multiple" class="select"></select></p>
+        <p><input type="button" id="addgroupstogrouping" value="<?php print_string('addgroupstogrouping', 'groups'); ?>" /></p>
+        <p><input type="button" id="canceladdgroupstogrouping" value="<?php print_string('cancel', 'groups'); ?>" /></p>
+    </form>
+</div>
diff --git a/group/groupui/addgroupstogrouping-form.js b/group/groupui/addgroupstogrouping-form.js
new file mode 100644 (file)
index 0000000..c9bf969
--- /dev/null
@@ -0,0 +1,73 @@
+
+
+function onAddGroupsToGrouping() {
+       hideAllForms();
+       showElement("groupeditform");
+       addGroupsToGrouping();
+       setText('selectedgroupingforaddinggroups', "");
+       return false;
+}
+
+
+/*
+ * Adds the selected groups to the selected groupings
+ */
+function addGroupsToGrouping() {
+       //alert("Called addGroupsToGrouping");
+       selectedgroups = getMultipleSelect("groupsnotingrouping");
+       if (selectedgroups != '') {     
+               var url = "addgroupstogrouping-xml.php";
+       var requeststring = "groupingid="+selectedgroupingid
+                                       +"&groups="+selectedgroups;
+       sendPostRequest(request, url, requeststring, addGroupsToGroupingResponse);
+    }
+}
+
+
+/**
+ * The callback for the response to the request sent in addGroupsToGrouping() 
+ */
+function addGroupsToGroupingResponse() {
+    if (checkAjaxResponse(request)) {
+       //alert("addGroupsToGrouping called");
+       //alert(request.responseText);
+       // Need XML sent back with groupingid
+       // Really want to set this to be the grouping before
+       error = getFromXML(request.responseXML, 'error');
+       if (error != null) {
+               alert(error);   
+       }       
+       updateGroupings();
+       hideElement("addgroupstogroupingform");
+    }
+}
+
+
+/**
+ * Updates the groups not in the selected grouping for the form for adding groups to a grouping
+ */
+function updateGroupsNotInGrouping() {
+       //alert("updateNonMembers called");
+       var url="getgroupsnotingrouping-xml.php";
+    var requeststring = "groupingid="+selectedgroupingid;      
+    sendPostRequest(request, url, requeststring, updateGroupsNotInGroupingResponse);   
+}
+
+
+/**
+ * The callback for the response to the request sent in updateGroupsNotInGrouping() 
+ */
+function updateGroupsNotInGroupingResponse() {
+    if (checkAjaxResponse(request)) {
+       //alert("updateGroupsNotInGroupingResponse");
+       var xmlDoc = request.responseXML;
+       //alert(request.responseText);
+       error = getFromXML(request.responseXML, 'error');
+       if (error != null) {
+               alert(error);   
+       }       
+       addOptionsFromXML("groupsnotingrouping", xmlDoc);
+    }
+}
+
+
diff --git a/group/groupui/addgroupstogrouping-xml.php b/group/groupui/addgroupstogrouping-xml.php
new file mode 100644 (file)
index 0000000..82f98e3
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+/**********************************************
+ * Adds an existing group to a grouping
+ **********************************************/
+header("Content-Type: text/xml");
+echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
+echo '<groupsresponse>';
+
+include_once('../../../config.php');
+include('../lib/lib.php');
+
+$groupingid = required_param('groupingid', PARAM_INT);
+$groups = required_param('groups');
+$courseid = required_param('courseid', PARAM_INT);
+
+require_login($courseid);
+       
+if (confirm_sesskey() and isteacheredit($courseid)) {
+       $groupids = explode(',', $groups); 
+       
+       if ($groupids != false) {
+               foreach($groupids as $groupid) {
+                       $groupadded = groups_add_group_to_grouping($groupid, $groupingid);
+                       if (!$groupadded) {
+                               echo '<error>Failed to add group $groupid to grouping</error>';
+                       }
+               } 
+       }
+}
+
+echo '</groupsresponse>';
+?>
diff --git a/group/groupui/addmembers-form.html b/group/groupui/addmembers-form.html
new file mode 100644 (file)
index 0000000..cfa98ab
--- /dev/null
@@ -0,0 +1,9 @@
+<div id="addmembersform" class="popup">
+    <h3><?php print_string('adduserstogroup', 'groups'); ?> <span id="selectedgroup"></span></h3>
+    <form action="">
+        <p><input type="checkbox" id="showall" /><?php print_string('showusersalreadyingroup', 'groups'); ?> </p>
+        <p><select id="nonmembers" size="15" multiple="multiple" class="select"></select></p>
+               <p><input type="button" id="addmembers" value="<?php print_string('adduserstogroup', 'groups'); ?>" /></p>
+           <p><input type="button" id="canceladdmembers" value="<?php print_string('cancel', 'groups'); ?>" /></p>
+    </form>
+</div>
diff --git a/group/groupui/addmembers-form.js b/group/groupui/addmembers-form.js
new file mode 100644 (file)
index 0000000..fc3019d
--- /dev/null
@@ -0,0 +1,81 @@
+
+
+function onAddMembers() {
+       hideAllForms();
+       showElement("groupeditform");
+       addMembers();
+       return false;
+}
+
+function onShowAll() {
+       updateNonMembers();
+       return false;
+}
+
+
+
+/*
+ * Adds the selected users to the selected group
+ */
+function addMembers() {
+       //alert("Called addMembers");
+       users = getMultipleSelect("nonmembers");
+       if (users != '') {
+               var url = "addmembers-xml.php";
+       var requeststring = "groupid="+selectedgroupid+"&users="+users;
+       sendPostRequest(request, url, requeststring, addMembersResponse);
+    }
+}
+
+/**
+ * The callback for the response to the request sent in addMembers() 
+ */
+function addMembersResponse() {
+    if (checkAjaxResponse(request)) {
+       //alert("addMembersResponse called");
+       //alert(request.responseText);
+       // Need XML sent back with groupingid
+       // Really want to set this to be the grouping before
+       error = getFromXML(request.responseXML, 'error');
+       if (error != null) {
+               alert(error);   
+       }       
+       updateSelectedGrouping();
+       hideElement("addmembersform");
+    }
+}
+
+
+/**
+ * Updates the list of non members of a group in the form for adding members to a group
+ */
+function updateNonMembers() {
+       //alert("updateNonMembers called");
+       var url="getnonmembers-xml.php";
+       // showall indicates if we should show users already in groups in the grouping
+       // we have to turn it into a variable that we can put in a post
+       var showall = getCheckBoxValue('showall');;
+       var requeststring = "groupid="+selectedgroupid
+                                               +"&groupingid="+selectedgroupingid
+                                               +"&showall="+showall;
+                               
+    sendPostRequest(request, url, requeststring, updateNonMembersResponse);    
+}
+
+/**
+ * The callback for the response to the request sent in updateNonMembers() 
+ */
+function updateNonMembersResponse() {
+    if (checkAjaxResponse(request)) {
+       //alert("updateNonMembersResponse");
+       var xmlDoc = request.responseXML;
+       // alert(request.responseText);
+       error = getFromXML(request.responseXML, 'error');
+       if (error != null) {
+               alert(error);   
+       }
+       addOptionsFromXML("nonmembers", xmlDoc);
+    }
+}
+
+
diff --git a/group/groupui/addmembers-xml.php b/group/groupui/addmembers-xml.php
new file mode 100644 (file)
index 0000000..834ca29
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+/**********************************************
+ * Adds users to a group
+ **********************************************/
+header("Content-Type: text/xml");
+echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
+echo '<groupsresponse>';
+
+include_once('../../../config.php');
+include('../lib/lib.php');
+
+$groupid = required_param('groupid', PARAM_INT);
+$users = required_param('users');
+$courseid = required_param('courseid', PARAM_INT);
+
+require_login($courseid);
+       
+if (confirm_sesskey() and isteacheredit($courseid)) {
+       $userids = explode(',', $users); 
+       
+       if ($userids != false) {
+               foreach($userids as $userid) {
+                       $useradded = groups_add_member($userid, $groupid);
+                       if (!$useradded) {
+                               echo '<error>Failed to add user $userid to group</error>';
+                       }
+               }
+       }
+}
+
+echo '</groupsresponse>';
+?>
\ No newline at end of file
diff --git a/group/groupui/ajax.js b/group/groupui/ajax.js
new file mode 100644 (file)
index 0000000..ff7e904
--- /dev/null
@@ -0,0 +1,77 @@
+/***********************************************************************************************************
+ * Contains functions for creating and sending Ajax requests.
+ * This code needs to be a bit more careful about creating separate requests for different events - if 
+ * somebody presses a button several times in quick succession (such as the delete grouping button) then 
+ * we get an error. 
+ * There also seems to a problem with IE - need to check this out
+ ***********************************************************************************************************/
+
+
+<?php
+       echo "var courseid = $courseid;"; 
+       echo "var sesskey = '$sesskey';";
+?>
+
+/*
+ * Creates an XMLHttpRequest object 
+ * @return The XMLHttpRequest object created. 
+ */
+function createRequest() {
+       var newrequest = null;
+       try {
+           newrequest = new XMLHttpRequest();
+       } catch (trymicrosoft) {
+               // Deal with Microsoft browsers 
+           try {
+               newrequest = new ActiveXObject("Msxml2.XMLHTTP");
+           } catch (othermicrosoft) {
+                       try {
+                           newrequest = new ActiveXObject("Microsoft.XMLHTTP");
+                   } catch (failed) {
+                       newrequest = null;
+                   }
+           }
+       }
+
+       if (newrequest == null) {
+               alert("Error creating request object!");
+       } else {
+               return newrequest;
+       }
+}
+
+/*
+ * Sends an Ajax post request 
+ * @param request - The XMLHttpRequest object
+ * @param url - The URL to send the request to 
+ * @param requeststring - The string containing the variables to send in the post request - the format
+ * is basically the same as a GET string
+ * @callbackfunction  - The function to call when the response to the request is received 
+*/
+function sendPostRequest(postrequest, url, requeststring, callbackfunction) {
+       // Add on the date and time to get round caching problem
+       url = url + "?dummy=" + new Date().getTime();
+       // Add the course id and sesskey so we can check these on the server 
+       requeststring = 'courseid='+courseid+'&'+'sesskey='+sesskey+'&'+requeststring;
+       postrequest.abort();
+       postrequest.open('post',  url, true);
+       postrequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
+       postrequest.onreadystatechange = callbackfunction;
+       postrequest.send(requeststring);
+}
+
+function checkAjaxResponse(request) {
+       process = false;
+       
+       if (request.readyState == 4 && request.status == 200) {
+               process = true;
+       }       
+    if (request.readyState == 4 && request.status != 200) {
+       alert('An error has occurred - the page returned a '+ request.status + ' error');
+    }
+    return process;    
+}
+
+var responseFailure = function(o){ 
+       alert("Failure callback");
+}
diff --git a/group/groupui/connection.js b/group/groupui/connection.js
new file mode 100644 (file)
index 0000000..670a106
--- /dev/null
@@ -0,0 +1,775 @@
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 0.11.0
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response, returning the results to a pre-defined
+ * callback you create.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+/**
+   * Array of MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+       _msxml_progid:[
+                       'MSXML2.XMLHTTP.3.0',
+                       'MSXML2.XMLHTTP',
+                       'Microsoft.XMLHTTP'
+                       ],
+
+  /**
+   * Object literal of HTTP header(s)
+   * @private
+   * @type object
+   */
+       _http_header:{},
+
+  /**
+   * Determines if HTTP headers are set.
+   * @private
+   * @type boolean
+   */
+       _has_http_headers:false,
+
+ /**
+  * Determines if a default header of
+  * Content-Type of 'application/x-www-form-urlencoded'
+  * will be added to any client HTTP headers sent for POST
+  * transactions.
+  * @private
+  * @type boolean
+  */
+    _default_post_header:true,
+
+ /**
+  * Property modified by setForm() to determine if the data
+  * should be submitted as an HTML form.
+  * @private
+  * @type boolean
+  */
+    _isFormSubmit:false,
+
+ /**
+  * Property modified by setForm() to determine if a file(s)
+  * upload is expected.
+  * @private
+  * @type boolean
+  */
+    _isFileUpload:false,
+
+ /**
+  * Property modified by setForm() to set a reference to the HTML
+  * form node if the desired action is file upload.
+  * @private
+  * @type object
+  */
+    _formNode:null,
+
+ /**
+  * Property modified by setForm() to set the HTML form data
+  * for each transaction.
+  * @private
+  * @type string
+  */
+    _sFormData:null,
+
+ /**
+  * Collection of polling references to the polling mechanism in handleReadyState.
+  * @private
+  * @type string
+  */
+    _poll:[],
+
+ /**
+  * Queue of timeout values for each transaction callback with a defined timeout value.
+  * @private
+  * @type string
+  */
+    _timeOut:[],
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR readyState.
+   * The default is 50 milliseconds.
+   * @private
+   * @type int
+   */
+     _polling_interval:50,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+     _transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+       setProgId:function(id)
+       {
+               this._msxml_progid.unshift(id);
+       },
+
+  /**
+   * Member to enable or disable the default POST header.
+   * @public
+   * @param boolean b Set and use default header - true or false .
+   * @return void
+   */
+       setDefaultPostHeader:function(b)
+       {
+               this._default_post_header = b;
+       },
+
+  /**
+   * Member to modify the default polling interval.
+   * @public
+   * @param {int} i The polling interval in milliseconds.
+   * @return void
+   */
+       setPollingInterval:function(i)
+       {
+               if(typeof i == 'number' && isFinite(i)){
+                               this._polling_interval = i;
+               }
+       },
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   */
+       createXhrObject:function(transactionId)
+       {
+               var obj,http;
+               try
+               {
+                       // Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+                       http = new XMLHttpRequest();
+                       //  Object literal with http and tId properties
+                       obj = { conn:http, tId:transactionId };
+               }
+               catch(e)
+               {
+                       for(var i=0; i<this._msxml_progid.length; ++i){
+                               try
+                               {
+                                       // Instantiates XMLHttpRequest for IE and assign to http.
+                                       http = new ActiveXObject(this._msxml_progid[i]);
+                                       //  Object literal with http and tId properties
+                                       obj = { conn:http, tId:transactionId };
+                                       break;
+                               }
+                               catch(e){}
+                       }
+               }
+               finally
+               {
+                       return obj;
+               }
+       },
+
+  /**
+   * This method is called by asyncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+       getConnectionObject:function()
+       {
+               var o;
+               var tId = this._transaction_id;
+
+               try
+               {
+                       o = this.createXhrObject(tId);
+                       if(o){
+                               this._transaction_id++;
+                       }
+               }
+               catch(e){}
+               finally
+               {
+                       return o;
+               }
+       },
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+       asyncRequest:function(method, uri, callback, postData)
+       {
+               var o = this.getConnectionObject();
+
+               if(!o){
+                       return null;
+               }
+               else{
+                       if(this._isFormSubmit){
+                               if(this._isFileUpload){
+                                       this.uploadFile(o.tId, callback, uri);
+                                       this.releaseObject(o);
+                                       return;
+                               }
+
+                               //If the specified HTTP method is GET, setForm() will return an
+                               //encoded string that is concatenated to the uri to
+                               //create a querystring.
+                               if(method == 'GET'){
+                                       uri += "?" +  this._sFormData;
+                               }
+                               else if(method == 'POST'){
+                                       postData =  this._sFormData;
+                               }
+                               this._sFormData = '';
+                       }
+
+                       o.conn.open(method, uri, true);
+
+                       if(this._isFormSubmit || (postData && this._default_post_header)){
+                               this.initHeader('Content-Type','application/x-www-form-urlencoded');
+                               if(this._isFormSubmit){
+                                       this._isFormSubmit = false;
+                               }
+                       }
+
+                       //Verify whether the transaction has any user-defined HTTP headers
+                       //and set them.
+                       if(this._has_http_headers){
+                               this.setHeader(o);
+                       }
+
+                       this.handleReadyState(o, callback);
+                       postData?o.conn.send(postData):o.conn.send(null);
+
+                       return o;
+               }
+       },
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @return void
+   */
+    handleReadyState:function(o, callback)
+    {
+        var timeOut = callback.timeout;
+        var oConn = this;
+
+        try
+        {
+            if(timeOut !== undefined){
+               this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true) }, timeOut);
+            }
+            this._poll[o.tId] = window.setInterval(
+                function(){
+                                       if(o.conn && o.conn.readyState == 4){
+                                               window.clearInterval(oConn._poll[o.tId]);
+                                               oConn._poll.splice(o.tId);
+                                               if(timeOut){
+                                                       oConn._timeOut.splice(o.tId);
+                                               }
+
+                                               oConn.handleTransactionResponse(o, callback);
+                    }
+                }
+            ,this._polling_interval);
+        }
+        catch(e)
+        {
+            window.clearInterval(oConn._poll[o.tId]);
+            oConn._poll.splice(o.tId);
+                       if(timeOut){
+                               oConn._timeOut.splice(o.tId);
+                       }
+
+            oConn.handleTransactionResponse(o, callback);
+        }
+    },
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {object} callback - User-defined callback object
+   * @param {boolean} determines if the transaction was aborted.
+   * @return void
+   */
+    handleTransactionResponse:function(o, callback, isAbort)
+    {
+               // If no valid callback is provided, then do not process any callback handling.
+               if(!callback){
+                       this.releaseObject(o);
+                       return;
+               }
+
+               var httpStatus, responseObject;
+
+               try
+               {
+                       if(o.conn.status !== undefined && o.conn.status != 0){
+                               httpStatus = o.conn.status;
+                       }
+                       else{
+                               httpStatus = 13030;
+                       }
+               }
+               catch(e){
+                       // 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+                       // when the o object's status and statusText properties are
+                       // unavailable, and a query attempt throws an exception.
+                       httpStatus = 13030;
+               }
+
+               if(httpStatus >= 200 && httpStatus < 300){
+                       responseObject = this.createResponseObject(o, callback.argument);
+                       if(callback.success){
+                               if(!callback.scope){
+                                       callback.success(responseObject);
+                               }
+                               else{
+                                       // If a scope property is defined, the callback will be fired from
+                                       // the context of the object.
+                                       callback.success.apply(callback.scope, [responseObject]);
+                               }
+                       }
+               }
+               else{
+                       switch(httpStatus){
+                               // The following case labels are wininet.dll error codes that may be encountered.
+                               // Server timeout
+                               case 12002:
+                               // 12029 to 12031 correspond to dropped connections.
+                               case 12029:
+                               case 12030:
+                               case 12031:
+                               // Connection closed by server.
+                               case 12152:
+                               // See above comments for variable status.
+                               case 13030:
+                                       responseObject = this.createExceptionObject(o.tId, callback.argument, isAbort);
+                                       if(callback.failure){
+                                               if(!callback.scope){
+                                                       callback.failure(responseObject);
+                                               }
+                                               else{
+                                                       callback.failure.apply(callback.scope, [responseObject]);
+                                               }
+                                       }
+                                       break;
+                               default:
+                                       responseObject = this.createResponseObject(o, callback.argument);
+                                       if(callback.failure){
+                                               if(!callback.scope){
+                                                       callback.failure(responseObject);
+                                               }
+                                               else{
+                                                       callback.failure.apply(callback.scope, [responseObject]);
+                                               }
+                                       }
+                       }
+               }
+
+               this.releaseObject(o);
+    },
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases will differ in the response
+   * object's property values.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined argument or arguments to be passed to the callback
+   * @return object
+   */
+    createResponseObject:function(o, callbackArg)
+    {
+               var obj = {};
+               var headerObj = {};
+
+               try
+               {
+                       var headerStr = o.conn.getAllResponseHeaders();
+                       var header = headerStr.split('\n');
+                       for(var i=0; i < header.length; i++){
+                               var delimitPos = header[i].indexOf(':');
+                               if(delimitPos != -1){
+                                       headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos+1);
+                               }
+                       }
+               }
+               catch(e){}
+
+               obj.tId = o.tId;
+               obj.status = o.conn.status;
+               obj.statusText = o.conn.statusText;
+               obj.getResponseHeader = headerObj;
+               obj.getAllResponseHeaders = headerStr;
+               obj.responseText = o.conn.responseText;
+               obj.responseXML = o.conn.responseXML;
+
+               if(typeof callbackArg !== undefined){
+                       obj.argument = callbackArg;
+               }
+
+               return obj;
+    },
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The failure callback will be fired and this specific condition can be identified
+   * by a status property value of 0.
+   *
+   * If an abort was successful, the status property will report a value of -1.
+   *
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param isAbort Determines if the exception is an abort.
+   * @return object
+   */
+    createExceptionObject:function(tId, callbackArg, isAbort)
+    {
+               var COMM_CODE = 0;
+               var COMM_ERROR = 'communication failure';
+               var ABORT_CODE = -1;
+               var ABORT_ERROR = 'transaction aborted';
+
+               var obj = {};
+
+               obj.tId = tId;
+               if(isAbort){
+                       obj.status = ABORT_CODE;
+                       obj.statusText = ABORT_ERROR;
+               }
+               else{
+                       obj.status = COMM_CODE;
+                       obj.statusText = COMM_ERROR;
+               }
+
+               if(callbackArg){
+                       obj.argument = callbackArg;
+               }
+
+               return obj;
+    },
+
+  /**
+   * Public method that stores the custom HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+       initHeader:function(label,value)
+       {
+               if(this._http_header[label] === undefined){
+                       this._http_header[label] = value;
+               }
+               else{
+                       this._http_header[label] =  value + "," + this._http_header[label];
+               }
+
+               this._has_http_headers = true;
+       },
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+       setHeader:function(o)
+       {
+               for(var prop in this._http_header){
+                       if(this._http_header.propertyIsEnumerable){
+                               o.conn.setRequestHeader(prop, this._http_header[prop]);
+                       }
+               }
+               delete this._http_header;
+
+               this._http_header = {};
+               this._has_http_headers = false;
+       },
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded string.
+   * asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string || object} form id or name attribute, or form object.
+   * @param {string} optional boolean to indicate SSL environment.
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+       setForm:function(formId, isUpload, secureUri)
+       {
+               this._sFormData = '';
+               if(typeof formId == 'string'){
+                       // Determine if the argument is a form id or a form name.
+                       // Note form name usage is deprecated by supported
+                       // here for legacy reasons.
+                       var oForm = (document.getElementById(formId) || document.forms[formId]);
+               }
+               else if(typeof formId == 'object'){
+                       var oForm = formId;
+               }
+               else{
+                       return;
+               }
+
+               // If the isUpload argument is true, setForm will call createFrame to initialize
+               // an iframe as the form target.
+               //
+               // The argument secureURI is also required by IE in SSL environments
+               // where the secureURI string is a fully qualified HTTP path, used to set the source
+               // of the iframe, to a stub resource in the same domain.
+               if(isUpload){
+                       (typeof secureUri == 'string')?this.createFrame(secureUri):this.createFrame();
+                       this._isFormSubmit = true;
+                       this._isFileUpload = true;
+                       this._formNode = oForm;
+
+                       return;
+               }
+
+               var oElement, oName, oValue, oDisabled;
+               var hasSubmit = false;
+
+               // Iterate over the form elements collection to construct the
+               // label-value pairs.
+               for (var i=0; i<oForm.elements.length; i++){
+                       oDisabled = oForm.elements[i].disabled;
+
+                       // If the name attribute is not populated, the form field's
+                       // value will not be submitted.
+                       oElement = oForm.elements[i];
+                       oName = oForm.elements[i].name;
+                       oValue = oForm.elements[i].value;
+
+                       // Do not submit fields that are disabled or
+                       // do not have a name attribute value.
+                       if(!oDisabled && oName)
+                       {
+                               switch (oElement.type)
+                               {
+                                       case 'select-one':
+                                       case 'select-multiple':
+                                               for(var j=0; j<oElement.options.length; j++){
+                                                       if(oElement.options[j].selected){
+                                                                       this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].value || oElement.options[j].text) + '&';
+                                                       }
+                                               }
+                                               break;
+                                       case 'radio':
+                                       case 'checkbox':
+                                               if(oElement.checked){
+                                                       this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+                                               }
+                                               break;
+                                       case 'file':
+                                               // stub case as XMLHttpRequest will only send the file path as a string.
+                                       case undefined:
+                                               // stub case for fieldset element which returns undefined.
+                                       case 'reset':
+                                               // stub case for input type reset button.
+                                       case 'button':
+                                               // stub case for input type button elements.
+                                               break;
+                                       case 'submit':
+                                               if(hasSubmit == false){
+                                                       this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+                                                       hasSubmit = true;
+                                               }
+                                               break;
+                                       default:
+                                               this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+                                               break;
+                               }
+                       }
+               }
+
+               this._isFormSubmit = true;
+               this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+       },
+
+  /**
+   * Creates an iframe to be used for form file uploads.  It is remove from the
+   * document upon completion of the upload transaction.
+   *
+   * @private
+   * @param {string} optional qualified path of iframe resource for SSL in IE.
+   * @return void
+   */
+       createFrame:function(secureUri){
+
+               // IE does not allow the setting of id and name attributes as DOM
+               // properties.  A different iframe creation pattern is required for IE.
+               if(window.ActiveXObject){
+                       var io = document.createElement('<IFRAME name="ioFrame" id="ioFrame">');
+                       if(secureUri){
+                               // IE will throw a security exception in an SSL environment if the
+                               // iframe source isn't set to a valid resource.
+                               io.src = secureUri;
+                       }
+               }
+               else{
+                       var io = document.createElement('IFRAME');
+                       io.id = 'ioFrame';
+                       io.name = 'ioFrame';
+               }
+
+               io.style.position = 'absolute';
+               io.style.top = '-1000px';
+               io.style.left = '-1000px';
+
+               document.body.appendChild(io);
+       },
+
+  /**
+   * Uploads HTML form, including files/attachments,  targeting the
+   * iframe created in createFrame.
+   *
+   * @private
+   * @param {int} id The transaction id.
+   * @param {object} callback - User-defined callback object.
+   * @param {string} uri Fully qualified path of resource.
+   * @return void
+   */
+       uploadFile:function(id, callback, uri){
+               // Initialize the HTML form properties in case they are
+               // not defined in the HTML form.
+               this._formNode.action = uri;
+               this._formNode.enctype = 'multipart/form-data';
+               this._formNode.method = 'POST';
+               this._formNode.target = 'ioFrame';
+               this._formNode.submit();
+
+               // Reset form status properties.
+               this._formNode = null;
+               this._isFileUpload = false;
+               this._isFormSubmit = false;
+
+               // Create the upload callback handler that fires when the iframe
+               // receives the load event.  Subsequently, the event handler is detached
+               // and the iframe removed from the document.
+
+               var uploadCallback = function()
+               {
+                       var oResponse =
+                       {
+                               tId: id,
+                               responseText: document.getElementById("ioFrame").contentWindow.document.body.innerHTML,
+                               argument: callback.argument
+                       }
+
+                       if(callback.upload && !callback.scope){
+                               callback.upload(oResponse);
+                       }
+                       else{
+                               callback.upload.apply(callback.scope, [oResponse]);
+                       }
+
+                       YAHOO.util.Event.removeListener("ioFrame", "load", uploadCallback);
+                       window.ioFrame.location.replace('#');
+                       setTimeout("document.body.removeChild(document.getElementById('ioFrame'))",100);
+               };
+
+               // Bind the onload handler to the iframe to detect the file upload response.
+               YAHOO.util.Event.addListener("ioFrame", "load", uploadCallback);
+       },
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @param {object} callback  User-defined callback object.
+   * @param {string} isTimeout boolean to indicate if abort was a timeout.
+   * @return void
+   */
+       abort:function(o, callback, isTimeout)
+       {
+               if(this.isCallInProgress(o)){
+                       window.clearInterval(this._poll[o.tId]);
+                       this._poll.splice(o.tId);
+                       if(isTimeout){
+                               this._timeOut.splice(o.tId);
+                       }
+                       o.conn.abort();
+                       this.handleTransactionResponse(o, callback, true);
+
+                       return true;
+               }
+               else{
+                       return false;
+               }
+       },
+
+  /**
+   * Public method to check if the transaction is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+       isCallInProgress:function(o)
+       {
+               // if the XHR object assigned to the transaction has not been dereferenced,
+               // then check its readyState status.  Otherwise, return false.
+               if(o.conn){
+                       return o.conn.readyState != 4 && o.conn.readyState != 0;
+               }
+               else{
+                       //The XHR object has been destroyed.
+                       return false;
+               }
+       },
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+       releaseObject:function(o)
+       {
+               //dereference the XHR instance.
+               o.conn = null;
+               //dereference the connection object.
+               o = null;
+       }
+};
diff --git a/group/groupui/createautomaticgrouping-form.html b/group/groupui/createautomaticgrouping-form.html
new file mode 100644 (file)
index 0000000..001bb5d
--- /dev/null
@@ -0,0 +1,54 @@
+<div id="createautomaticgroupingform" class="popupwide">
+<h3><?php print_string('createautomaticgrouping', 'groups'); ?></h3>
+<form name="automaticgroupingform" action="">
+    
+<table cellpadding="10">
+    <tr>
+       <td valign="top">
+               <p><?php print_string('groupingname', 'groups'); ?></p>
+               <p><input id="automaticgroupingname" type="text" size="40" value="<?php print_string('defaultgroupingname', 'groups'); ?>" /></p>
+               <p><?php print_string('groupingdescription', 'groups'); ?></p>
+               <p><?php print_textarea($usehtmleditor,  4, 45, 150, 400, 'automaticgroupingdescription'); ?></p>
+               <p> <?php print_string('prefixforgroupnames', 'groups'); ?> </p>
+               <p><input id="groupprefix" type="text" size="40 " value="<?php print_string('defaultgroupname', 'groups'); ?> " /></p>
+               <p><?php print_string('defaultgroupdescription', 'groups'); ?></p>
+               <p><?php print_textarea($usehtmleditor,  4, 45, 150, 400, 'defaultgroupdescription'); ?></p>
+           </td>
+               <td valign="top">
+               <p><input type="checkbox" id="alphabetical" /> <?php print_string('distributealphabetically', 'groups'); ?></p>
+               <table>
+                   <tr>
+                       <td><input type="radio" name ="generationtype" id="nostudents" value="nostudents" checked />
+                       </td>
+                       <td> <?php print_string('selectnumberineachgroup', 'groups'); ?>
+                       </td>
+                   </tr>
+                   <tr>
+                       <td>&nbsp;</td>
+                       <td>
+                               <p><?php print_string('numberofstudents', 'groups'); ?> </p><p><input id="noofstudents" type="text" size="5" /></p>
+                           <p><input type="checkbox" id="distribevenly" checked /> <?php print_string('distributeevenly', 'groups'); ?></p>
+                       </td>
+                   </tr>
+               </table>
+               
+               <table>
+                   <tr>
+                       <td><input type="radio" name ="generationtype" id="nogroups" value="nogroups" /></td>
+                       <td><?php print_string('selectnumberofgroups', 'groups'); ?></td>
+                   </tr>
+                   <tr>
+                       <td>&nbsp;</td>
+                       <td>
+                               <p><?php print_string('numberofgroups', 'groups'); ?></p><p> <input id="noofgroups" type="text" size="5" /></p>
+                       </td>
+                   </tr>
+               </table>
+               
+               <p><input type="button" id="createautomaticgrouping" value=" <?php print_string('creategrouping', 'groups'); ?>" />&nbsp;
+               <input type="button" id="cancelcreateautomaticgrouping" value=" <?php print_string('cancel', 'groups'); ?>" /></p>
+           </td>
+    </tr>
+</table>
+</form>
+</div>
diff --git a/group/groupui/createautomaticgrouping-form.js b/group/groupui/createautomaticgrouping-form.js
new file mode 100644 (file)
index 0000000..4f77920
--- /dev/null
@@ -0,0 +1,81 @@
+function onCreateAutomaticGrouping() {
+       valid =  validateAutomaticGroupingForm();
+       if (valid) {
+               hideAllForms();
+               showElement("groupeditform");
+               createAutomaticGrouping();
+       }
+       
+       return false;
+}
+
+
+/**
+ * Adds an automatically generated grouping with the details as specified in the form
+ */
+function createAutomaticGrouping() {
+       //alert("Called createAutomaticGrouping");      
+       var url = "createautomaticgrouping-xml.php";
+    var requeststring = "noofstudents="+getTextInputValue('noofstudents')
+                                       +"&noofgroups="+getTextInputValue('noofgroups')
+                                       +"&distribevenly="+getCheckBoxValue('distribevenly')
+                                       +"&alphabetical="+getCheckBoxValue('alphabetical')
+                                       +"&generationtype="+getRadioValue(document.automaticgroupingform.generationtype)
+                                       +"&name="+getTextInputValue('automaticgroupingname')
+                                       +"&description="+getTextInputValue('edit-automaticgroupingdescription')
+                                       +"&prefix="+getTextInputValue('groupprefix')
+                                       +"&defaultgroupdescription="+getTextInputValue('edit-defaultgroupdescription');
+       
+       // alert(requeststring);
+    sendPostRequest(request, url, requeststring, createAutomaticGroupingResponse);
+ }
+
+
+ /**
+  * The callback for the response to the request sent in createAutomaticGrouping() 
+  * It sets the new grouping to be selected in the form. 
+  */
+ function createAutomaticGroupingResponse() {
+    if (checkAjaxResponse(request)) {
+       //alert("createAutomaticGroupingResponse");
+       //alert(request.responseText);
+       error = getFromXML(request.responseXML, 'error');
+       if (error != null) {
+               alert(error);   
+       }       
+       selectedgroupingid = getFromXML(request.responseXML, 'groupingid');
+       selectedgroupid = null;
+       updateGroupings();
+       hideElement("createautomaticgroupingform");
+    }
+}
+
+function validateAutomaticGroupingForm() {
+       valid = true;
+       generationtype = getRadioValue(document.automaticgroupingform.generationtype);
+       noofstudents = getTextInputValue('noofstudents');
+       noofgroups = getTextInputValue('noofgroups');
+       groupingname = getTextInputValue('automaticgroupingname');
+       
+       if (generationtype == 'nostudents') {
+               if (!isPositiveInt(noofstudents)) {
+                       alert('The number of students is not valid.');
+                       valid = false;
+               } 
+       } else {                
+               if (!isPositiveInt(noofgroups)) {
+                       alert('The number of groups is not valid.');
+                       valid = false;
+               } 
+       }
+       
+       if (groupingname == '') {
+                       alert('You must enter a name for the new grouping');
+                       valid = false;
+       } 
+       
+       return valid;
+}
+
+
diff --git a/group/groupui/createautomaticgrouping-xml.php b/group/groupui/createautomaticgrouping-xml.php
new file mode 100644 (file)
index 0000000..775c6c2
--- /dev/null
@@ -0,0 +1,46 @@
+<?php
+/**********************************************
+ * Sets up an automatic grouping 
+ **********************************************/
+header("Content-Type: text/xml");
+echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
+echo '<groupsresponse>';
+
+
+include_once("../../../config.php");
+include("../lib/lib.php");
+
+require_login($courseid);
+
+groups_seed_random_number_generator();
+
+$courseid     = required_param('courseid', PARAM_INT);
+
+$noofstudents   = required_param('noofstudents', PARAM_INT);
+$noofgroups     = required_param('noofgroups', PARAM_INT);
+$distribevenly  = required_param('distribevenly');
+$alphabetical   = required_param('alphabetical');
+$generationtype = required_param('generationtype');
+
+$groupingsettings->name =required_param('name');
+$groupingsettings->description = required_param('description');
+$groupingsettings->prefix = required_param('prefix');
+$groupingsettings->defaultgroupdescription = required_param('defaultgroupdescription');
+       
+if (confirm_sesskey() and isteacheredit($courseid)) {
+       if ($generationtype == 'nogroups') {
+               $noofstudents = false;
+       }
+       
+       $groupingid = groups_create_automatic_grouping($courseid, $noofstudents, $noofgroups, 
+                                                      $distribevenly, $groupingsettings, false, $alphabetical); 
+       if (!$groupingid) {
+               echo '<error>Failed to create grouping</error>';
+       } else {
+               echo '<groupingid>'.$groupingid.'</groupingid>';
+       }
+}
+
+echo '</groupsresponse>';
+?>
\ No newline at end of file
diff --git a/group/groupui/creategroup-form.html b/group/groupui/creategroup-form.html
new file mode 100644 (file)
index 0000000..a76f185
--- /dev/null
@@ -0,0 +1,30 @@
+<div id="creategroupform" class="popup">
+    <h3><?php print_string('creategroup', 'groups'); ?> <span id="selectedgroupingforcreatinggroup"></span></h3>
+    <form action="">
+        <p><?php print_string('groupname', 'groups');?></p>
+        <p><input id="newgroupname" type="text" size="40" value="<?php print_string('defaultgroupname', 'groups'); ?>" />
+        <p><?php print_string("groupingdescription", 'groups') ?><br />
+                    <?php helpbutton("text", get_string("helptext")) ?></p>
+        <p><?php print_textarea($usehtmleditor, 5, 45, 200, 400, "newgroupdescription");?></p>
+        <p><?php print_string('enrolmentkey', 'groups') ?></p>
+        <p><input type="text" id="newgroupenrolmentkey" size="25" /></p>
+        <?php if ($printuploadpicture) {  ?>
+        <p><?php print_string('hidepicture', 'groups') ?></p>
+        <p><?php $options = NULL; $options[0] = get_string("no"); $options[1] = get_string("yes"); 
+                 choose_from_menu ($options, "newgrouphidepicture", $group->hidepicture, "");?>
+                ></p>
+
+            <p><?php print_string("newpicture", 'groups') ?></p>
+            <p><?php upload_print_form_fragment(1,array('newgroupicon'),null,false,null,0,0,false);
+                                    helpbutton("picture", get_string("helppicture"));
+                                    print_string("maxsize", "", display_size($maxbytes), 'groups'); ?>
+               </p>
+            <?php 
+               }  
+            ?>
+            </table>
+            
+            <p><input type="button" id="creategroup" value="<?php print_string('creategroup', 'groups'); ?>" /></p>
+            <p><input type="button" id="cancelcreategroup" value="<?php print_string('cancel', 'groups'); ?>" /></p>      
+    </form>
+</div>
diff --git a/group/groupui/creategroup-form.js b/group/groupui/creategroup-form.js
new file mode 100644 (file)
index 0000000..76d0af8
--- /dev/null
@@ -0,0 +1,61 @@
+
+function onCreateGroup() {
+       valid =  validateCreateGroupForm();
+       
+       if (valid) {
+               hideAllForms();
+               showElement("groupeditform");
+               createGroup();
+               replaceText('selectedgroupingforcreatinggroup', "");
+       }
+       
+       return false;
+}
+
+/*
+ * Adds a group with the name specified in the form to the selected grouping. 
+ */
+function createGroup() {
+       //alert("Called createGroup");
+       var url = "creategroup-xml.php";
+    var requeststring = "groupname="+getTextInputValue('newgroupname')
+                                       +"&groupingid="+selectedgroupingid
+                        +"&description="+getTextInputValue('edit-newgroupdescription')
+                        +"&enrolmentkey="+getTextInputValue('newgroupenrolmentkey');
+    // The picture fields aren't displayed if the right library isn't present
+    if (document.getElementById('menunewgrouphidepicture')) {
+       requeststring = requeststring+"&hidepicture="+getTextInputValue('menunewgrouphidepicture');
+    }
+    sendPostRequest(request, url, requeststring, createGroupResponse);
+}
+
+/**
+ * The callback for the response to the request sent in  createGroup() 
+ * The function sets the new group as selected in the form. 
+ */
+function createGroupResponse() {
+    if (checkAjaxResponse(request)) {
+       //alert("createGroupResponse called");
+       //alert(request.responseText);
+       error = getFromXML(request.responseXML, 'error');
+       if (error != null) {
+               alert(error);   
+       }       
+       selectedgroupid = getFromXML(request.responseXML, 'groupid');
+       updateGroupings();
+       hideElement("creategroupform");
+    }
+}
+
+
+function validateCreateGroupForm() {
+       valid = true;
+       groupname = getTextInputValue('newgroupname');
+
+       if (groupname == '') {
+                       alert('You must enter a name for the new group');
+                       valid = false;
+       } 
+       return valid;
+}
+
diff --git a/group/groupui/creategroup-xml.php b/group/groupui/creategroup-xml.php
new file mode 100644 (file)
index 0000000..5336b62
--- /dev/null
@@ -0,0 +1,53 @@
+<?php
+/**********************************************
+ * Adds a new group to a grouping
+ **********************************************/
+header("Content-Type: text/xml");
+echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
+echo '<groupsresponse>';
+
+include_once('../../../config.php');
+include('../lib/lib.php');
+$groupingid = required_param('groupingid', PARAM_INT);
+
+$groupsettings->name = required_param('groupname');
+$courseid = required_param('courseid', PARAM_INT);
+$groupsettings->description  = required_param('description');
+$groupsettings->enrolmentkey  = required_param('enrolmentkey', PARAM_ALPHANUM);
+$groupsettings->hidepicture = optional_param('hidepicture');
+
+require_login($courseid);
+       
+if (confirm_sesskey() and isteacheredit($courseid)) {
+       $groupid = groups_create_group($courseid, $groupsettings);
+       
+       if (!$groupid) {
+               echo '<error>Failed to create group</error>';
+       } else {
+               $groupadded = groups_add_group_to_grouping($groupid, $groupingid);
+               
+               if (!$groupadded) {
+                       echo '<error>Failed to add group to grouping</error>';
+               } else {
+                       // Upload a picture file if there was one - note that we don't remove any previous icons        
+                       require_once($CFG->dirroot.'/lib/uploadlib.php');
+                   $um = new upload_manager('newgroupicon', false, false, null, false, 0, true, true);
+                   if ($um->preprocess_files()) {
+                       require_once("$CFG->libdir/gdlib.php");
+                       if (save_profile_image($groupid, $um, 'groups')) {
+                               $groupsettings->picture = 1;
+                               $infoset = groups_set_group_settings($groupid, $groupsettings);
+                               if (!$infoset) {
+                                       echo '<error>Failed to save the fact that the group image was uploaded</error>';
+                               }
+                       } 
+                   }
+                   
+                       echo '<groupid>'.$groupid.'</groupid>';
+               }
+       }
+}
+
+echo '</groupsresponse>';
+?>
diff --git a/group/groupui/creategrouping-form.html b/group/groupui/creategrouping-form.html
new file mode 100644 (file)
index 0000000..5c8b4c4
--- /dev/null
@@ -0,0 +1,11 @@
+<div id="creategroupingform" class="popup">
+<h3><?php print_string('creategrouping', 'groups'); ?></h3>
+<form action="">
+<p><?php print_string('groupingname', 'groups'); ?></p>
+<p><input id="newgroupingname" type="text" size="40" value="<?php print_string('defaultgroupingname', 'groups'); ?>" /></p>
+<p><?php print_string('groupingdescription', 'groups'); ?></p>
+<p><?php print_textarea($usehtmleditor,5, 45, 200, 400, "newgroupingdescription");?></p>
+<p><input type="button" id="creategrouping" value="<?php print_string('creategrouping', 'groups'); ?>" /></p>
+<p><input type="button" id="cancelcreategrouping" value="<?php print_string('cancel', 'groups'); ?>" /></p>
+</form>
+</div>
diff --git a/group/groupui/creategrouping-form.js b/group/groupui/creategrouping-form.js
new file mode 100644 (file)
index 0000000..8263f45
--- /dev/null
@@ -0,0 +1,56 @@
+
+
+function onCreateGrouping() {
+       valid =  validateCreateGroupingForm();
+       if (valid) {
+               hideAllForms();
+               showElement("groupeditform");
+               createGrouping();
+       }
+       
+       return false;
+}
+
+/**
+ * Creates a new grouping for the course. 
+ */
+function createGrouping() {
+       // alert("Called createGrouping");
+       var url = "creategrouping-xml.php";
+    var requeststring = "groupingname="+getTextInputValue('newgroupingname')
+                                       +"&description="+getTextInputValue('edit-newgroupingdescription');
+    sendPostRequest(request, url, requeststring, createGroupingResponse);
+ }
+ /**
+  * The callback for the response to the request sent in createGrouping() 
+  * It sets the new grouping as selected in the form. 
+  */
+ function createGroupingResponse() {
+    if (checkAjaxResponse(request)) {
+    // alert("createGroupingResponse");
+    // alert(request.responseText);
+       error = getFromXML(request.responseXML, 'error');
+       if (error != null) {
+               alert(error);   
+       }
+               selectedgroupingid = getFromXML(request.responseXML, 'groupingid');
+       selectedgroupid = null;
+       updateGroupings();
+       hideElement("creategroupingform");
+    }
+}
+
+function validateCreateGroupingForm() {
+       valid = true;
+       groupingname = getTextInputValue('newgroupingname');
+
+       if (groupingname == '') {
+                       alert('You must enter a name for the new grouping');
+                       valid = false;
+       } 
+       return valid;
+}
+
+
+
diff --git a/group/groupui/creategrouping-xml.php b/group/groupui/creategrouping-xml.php
new file mode 100644 (file)
index 0000000..bac4b49
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+/**********************************************
+ * Adds a new grouping
+ **********************************************/
+header("Content-Type: text/xml");
+echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
+echo '<groupsresponse>';
+
+include_once('../../../config.php');
+include('../lib/lib.php');
+
+$courseid= required_param('courseid', PARAM_INT);
+
+$groupingsettings->name =required_param('groupingname');
+$groupingsettings->description = required_param('description');
+
+require_login($courseid);
+
+if (confirm_sesskey() and isteacheredit($courseid)) {
+       $groupingid = groups_create_grouping($courseid, $groupingsettings);
+       
+       if (!$groupingid) {
+               echo '<error>Failed to create grouping</error>';
+       } else {
+               echo '<groupingid>'.$groupingid.'</groupingid>';
+       }
+}
+
+echo '</groupsresponse>';
+?>
\ No newline at end of file
diff --git a/group/groupui/deletegroup-xml.php b/group/groupui/deletegroup-xml.php
new file mode 100644 (file)
index 0000000..6ff439f
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+/**********************************************
+ * Deletes a group
+ **********************************************/
+header("Content-Type: text/xml");
+echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
+echo '<groupsresponse>';
+
+include_once('../../../config.php');
+include("../lib/lib.php");
+
+$groupid = required_param('groupid', PARAM_INT);
+$courseid = required_param('courseid', PARAM_INT);
+
+require_login($courseid);
+       
+if (confirm_sesskey() and isteacheredit($courseid)) {
+       $groupremoved = groups_delete_group($groupid);
+       
+       if ($groupremoved == false) {
+               echo "<error>Could not delete group $groupid</error>";
+       } 
+}
+
+echo '</groupsresponse>';
+?>
diff --git a/group/groupui/deletegroup.js b/group/groupui/deletegroup.js
new file mode 100644 (file)
index 0000000..888e21f
--- /dev/null
@@ -0,0 +1,35 @@
+function onDeleteGroup() {
+       hideAllForms()
+       showElement("groupeditform");
+       deleteGroup();
+       return false;
+}
+
+
+/**
+ * Deletes the selected group
+ */
+function deleteGroup() {
+       //alert("Called deleteGroup");
+       var url = "deletegroup-xml.php";
+    var requeststring = "groupid="+selectedgroupid;
+    sendPostRequest(request, url, requeststring, deleteGroupResponse);
+}
+/**
+ * The callback for the response to the request sent in updateSelectedGrouping() 
+ */ 
+function deleteGroupResponse() {
+    if (checkAjaxResponse(request)) {
+       //alert("deleteGroupResponse called");
+       // alert(request.responseText);
+       error = getFromXML(request.responseXML, 'error');
+       if (error != null) {
+               alert(error);   
+       }       
+       // Need XML sent back with groupingid
+       // Really want to set this to be the grouping before
+       selectedgroupid = null;
+       updateGroupings();
+    }
+}
diff --git a/group/groupui/deletegrouping-xml.php b/group/groupui/deletegrouping-xml.php
new file mode 100644 (file)
index 0000000..863a316
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+/**********************************************
+ * Deletes a specified grouping
+ **********************************************/
+header("Content-Type: text/xml");
+echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
+echo '<groupsresponse>';
+
+include_once("../../../config.php");
+include("../lib/lib.php");
+
+$groupingid = required_param('groupingid', PARAM_INT);
+$courseid = required_param('courseid', PARAM_INT);
+
+require_login($courseid);
+       
+if (confirm_sesskey() and isteacheredit($courseid)) {
+       $groupingremoved = groups_delete_grouping($groupingid);
+       if (!$groupingremoved) {
+               echo '<error>Failed to delete grouping</error>';
+       }
+}
+
+echo '</groupsresponse>';
+?>
diff --git a/group/groupui/deletegrouping.js b/group/groupui/deletegrouping.js
new file mode 100644 (file)
index 0000000..23952fd
--- /dev/null
@@ -0,0 +1,37 @@
+
+function onDeleteGrouping() {
+       hideAllForms()
+       showElement("groupeditform");
+       deleteGrouping();
+       return false;
+}
+
+
+/*
+ * Deletes the selected grouping
+ */
+function deleteGrouping() {
+       //alert("Called deleteGrouping");
+       var url = "deletegrouping-xml.php";
+    var requeststring = "groupingid="+selectedgroupingid;
+    confirm('Are you sure you want to delete this grouping and the groups that it contains?');
+    sendPostRequest(request, url, requeststring, deleteGroupingResponse);
+ }
+ /**
+ * The callback for the response to the request sent in deleteGrouping() 
+ */
+ function deleteGroupingResponse() {
+    if (checkAjaxResponse(request)) {
+       //alert("deleteGroupingResponse called");
+       //alert(request.responseText);
+       error = getFromXML(request.responseXML, 'error');
+       if (error != null) {
+               alert(error);   
+       }               
+       selectedgroupingid = null;
+       selectedgroupid = null;
+       updateGroupings();
+    }
+}
+
diff --git a/group/groupui/editgroupingpermissions-form.html b/group/groupui/editgroupingpermissions-form.html
new file mode 100644 (file)
index 0000000..e776423
--- /dev/null
@@ -0,0 +1,13 @@
+<div id="editgroupingpermissionsform" class="popup">
+<h3><?php print_string('editgroupingpermissions', 'groups'); ?> for <span id="editperm-groupingname"></span></h3>
+<form action="">
+<p><input type="checkbox" id="edit-viewowngroup" checked /><?php print_string('viewowngroup', 'groups'); ?></p>
+<p><input type="checkbox" id="edit-viewallgroupsmembers" checked /><?php print_string('viewallgroupsmembers', 'groups'); ?></p>
+<p><input type="checkbox" id="edit-viewallgroupsactivities" checked /><?php print_string('viewallgroupsactivities', 'groups'); ?></p>
+<p><input type="checkbox" id="edit-teachersgroupmark"  /><?php print_string('teachersgroupmark', 'groups'); ?></p>         
+<p><input type="checkbox" id="edit-teachersgroupview"  /><?php print_string('teachersgroupview', 'groups'); ?></p>  
+<p><input type="checkbox" id="edit-teachersoverride"  /><?php print_string('teachersoverride', 'groups'); ?></p>  
+<p><input type="button" id="editgroupingpermissions" value="<?php print_string('save', 'groups'); ?>" /></p>
+<p><input type="button" id="canceleditgroupingpermissions" value="<?php print_string('cancel', 'groups'); ?>" /></p>
+</form>
+</div>
diff --git a/group/groupui/editgroupingpermissions-form.js b/group/groupui/editgroupingpermissions-form.js
new file mode 100644 (file)
index 0000000..e33ab93
--- /dev/null
@@ -0,0 +1,66 @@
+
+function onEditGroupingPermissionsSave() {
+       hideAllForms();
+       showElement("groupeditform");
+       editGroupingPermissions() ;
+       return false;
+}
+
+
+/**
+ * Creates a new grouping for the course. 
+ */
+function editGroupingPermissions() {
+       var url = "editgroupingpermissions-xml.php";
+    var requeststring = "groupingid=" + selectedgroupingid
+                                               +"&viewowngroup=" + getCheckBoxValue('edit-viewowngroup')
+                                       +"&viewallgroupsmembers=" + getCheckBoxValue('edit-viewallgroupsmembers')
+                                       +"&viewallgroupsactivities=" + getCheckBoxValue('edit-viewallgroupsactivities')
+                                       +"&teachersgroupmark=" + getCheckBoxValue('edit-teachersgroupmark')
+                                               +"&teachersgroupview=" + getCheckBoxValue('edit-teachersgroupview')
+                                               +"&teachersoverride=" + getCheckBoxValue('edit-teachersoverride');
+    sendPostRequest(request, url, requeststring, editGroupingPermissionsResponse);
+ }
+ /**
+  * The callback for the response to the request sent in editgroupingpermissions() 
+  * It sets the new grouping as selected in the form. 
+  */
+ function editGroupingPermissionsResponse() {
+    if (checkAjaxResponse(request)) {
+       //alert("editGroupingPermissionsResponse called");
+       //alert(request.responseText);
+       error = getFromXML(request.responseXML, 'error');
+       if (error != null) {
+               alert(error);   
+       }
+       updateGroupings();
+       hideElement("editgroupingpermissionsform");
+    }
+}
+
+function getGroupingPermissions() {
+       //alert("Called getgroupingpermissions");
+       var url = "getgroupingpermissions-xml.php";
+    var requeststring = "groupingid="+selectedgroupingid;
+    sendPostRequest(request, url, requeststring, getGroupingPermissionsResponse);
+}
+
+function getGroupingPermissionsResponse() {
+    if (checkAjaxResponse(request)) {
+       //alert("getgroupingpermissionsResponse");
+       //alert(request.responseText);
+       error = getFromXML(request.responseXML, 'error');
+       if (error != null) {
+               alert(error);   
+       }               
+       xml = request.responseXML;
+       replaceText('editperm-groupingname', getFromXML(xml, 'name'));
+       setCheckBoxValue('edit-viewowngroup', boolStringToBool(getFromXML(xml, 'viewowngroup')));
+       setCheckBoxValue('edit-viewallgroupsmembers', boolStringToBool(getFromXML(xml, 'viewallgroupsmembers')));
+       setCheckBoxValue('edit-viewallgroupsactivities', boolStringToBool(getFromXML(xml, 'viewallgroupsactivities')));
+       setCheckBoxValue('edit-teachersgroupmark', boolStringToBool(getFromXML(xml, 'teachersgroupmark')));
+               setCheckBoxValue('edit-teachersgroupview', boolStringToBool(getFromXML(xml, 'teachersgroupview')));
+               setCheckBoxValue('edit-teachersoverride', boolStringToBool(getFromXML(xml, 'teachersoverride')));
+    }
+}
diff --git a/group/groupui/editgroupingpermissions-xml.php b/group/groupui/editgroupingpermissions-xml.php
new file mode 100644 (file)
index 0000000..2531ed0
--- /dev/null
@@ -0,0 +1,29 @@
+<?php
+/**********************************************
+ * Adds a new grouping
+ **********************************************/
+header("Content-Type: text/xml");
+echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
+echo '<groupsresponse>';
+
+include_once('../../../config.php');
+include('../lib/lib.php');
+$groupingid = required_param('groupingid');
+$courseid = required_param('courseid', PARAM_INT);
+
+$groupingsettings->viewowngroup = required_param('viewowngroup');
+$groupingsettings->viewallgroupsmembers = required_param('viewallgroupsmembers');
+$groupingsettings->viewallgroupsactivities = required_param('viewallgroupsactivities');
+$groupingsettings->teachersgroupmark = required_param('teachersgroupmark');
+$groupingsettings->teachersgroupview = required_param('teachersgroupview');
+$groupingsettings->teachersoverride = required_param('teachersoverride');
+
+require_login($courseid);
+       
+if (confirm_sesskey() and isteacheredit($courseid)) {
+       $groupingid = groups_set_grouping_settings($groupingid, $groupingsettings);
+}
+
+echo '</groupsresponse>';
+?>
\ No newline at end of file
diff --git a/group/groupui/editgroupingsettings-form.html b/group/groupui/editgroupingsettings-form.html
new file mode 100644 (file)
index 0000000..b4b16df
--- /dev/null
@@ -0,0 +1,11 @@
+<div id="editgroupingsettingsform" class="popup">
+<h3><?php print_string('editgroupingsettings', 'groups'); ?></h3>
+<form action="">
+<p><?php print_string('groupingname', 'groups'); ?></p>
+<p><input id="edit-groupingname" type="text" size="40" /></p>
+<p><?php print_string('groupingdescription', 'groups'); ?></p>
+<p><?php print_textarea($usehtmleditor,  5, 45, 200, 400, "edit-groupingdescription");?></p>
+<p><input type="button" id="editgroupingsettings" value="<?php print_string('save', 'groups'); ?>" /></p>
+<p><input type="button" id="canceleditgroupingsettings" value="<?php print_string('cancel', 'groups'); ?>" /></p>
+</form>
+</div>
diff --git a/group/groupui/editgroupingsettings-form.js b/group/groupui/editgroupingsettings-form.js
new file mode 100644 (file)
index 0000000..ca7ca0a
--- /dev/null
@@ -0,0 +1,75 @@
+
+function onEditGroupingSettingsSave() {
+       valid = validateEditGroupingSettingsForm();
+       if (valid) {
+               hideAllForms();
+               showElement("groupeditform");
+               editGroupingSettings() ;
+               return false;
+       }
+}
+
+
+/**
+ * Creates a new grouping for the course. 
+ */
+function editGroupingSettings() {
+       var url = "editgroupingsettings-xml.php";
+    var requeststring = "groupingid="+selectedgroupingid
+                                               +"&groupingname="+getTextInputValue('edit-groupingname')
+                                               +"&description="+getTextInputValue('edit-edit-groupingdescription');
+    sendPostRequest(request, url, requeststring, editGroupingSettingsResponse);
+ }
+ /**
+  * The callback for the response to the request sent in editgroupingsettings() 
+  * It sets the new grouping as selected in the form. 
+  */
+ function editGroupingSettingsResponse() {
+    if (checkAjaxResponse(request)) {
+       //alert("editGroupingSettingsResponse called");
+       //alert(request.responseText);
+       error = getFromXML(request.responseXML, 'error');
+       if (error != null) {
+               alert(error);   
+       }
+       updateGroupings();
+       hideElement("editgroupingsettingsform");
+    }
+}
+
+function getGroupingSettings() {
+       //alert("Called getgroupingsettings");
+       var url = "getgroupingsettings-xml.php";
+    var requeststring = "groupingid="+selectedgroupingid;
+    sendPostRequest(request, url, requeststring, getGroupingSettingsResponse);
+}
+
+function getGroupingSettingsResponse() {
+    if (checkAjaxResponse(request)) {
+       //alert("getgroupingsettingsResponse");
+       //alert(request.responseText);
+       error = getFromXML(request.responseXML, 'error');
+       if (error != null) {
+               alert(error);   
+       }               
+       xml = request.responseXML;
+       setTextInputValue('edit-groupingname', getFromXML(xml, 'name'));
+       setTextInputValue('edit-edit-groupingdescription', getFromXML(xml, 'description'));
+    }
+}
+
+
+function validateEditGroupingSettingsForm() {
+       valid = true;
+       groupingname = getTextInputValue('edit-groupingname');
+
+       if (groupingname == '') {
+                       alert('You must enter a name for the new grouping');
+                       valid = false;
+       } 
+       return valid;
+}
+
+
+
diff --git a/group/groupui/editgroupingsettings-xml.php b/group/groupui/editgroupingsettings-xml.php
new file mode 100644 (file)
index 0000000..0ffc0d2
--- /dev/null
@@ -0,0 +1,25 @@
+<?php
+/**********************************************
+ * Adds a new grouping
+ **********************************************/
+header("Content-Type: text/xml");
+echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
+echo '<groupsresponse>';
+
+include_once('../../../config.php');
+include('../lib/lib.php');
+$groupingid = required_param('groupingid');
+$courseid = required_param('courseid', PARAM_INT);
+
+$groupingsettings->name =required_param('groupingname');
+$groupingsettings->description = required_param('description');
+
+require_login($courseid);
+       
+if (confirm_sesskey() and isteacheredit($courseid)) {
+       $groupingid = groups_set_grouping_settings($groupingid, $groupingsettings);
+}
+
+echo '</groupsresponse>';
+?>
\ No newline at end of file
diff --git a/group/groupui/editgroupsettings-form.html b/group/groupui/editgroupsettings-form.html
new file mode 100644 (file)
index 0000000..35bbdae
--- /dev/null
@@ -0,0 +1,22 @@
+<div id="editgroupsettingsform" class="popup">
+    <h3><?php print_string('editgroupsettings', 'groups'); ?></h3>
+    <form action="">
+        <p><?php print_string('groupname', 'groups'); ?></p>
+        <p><input id="groupname" type="text" size="40" /></p>
+        <p><?php print_string("description") ?><br />
+                    <?php helpbutton("text", get_string("helptext")) ?></p>
+        <p><?php print_textarea($usehtmleditor, 5, 45, 200, 400, "groupdescription");?> </p>
+        <p><?php print_string('enrolmentkey') ?></p>
+        <p><input type="text" id="enrolmentkey" size="25" /></p>
+        <?php if ($printuploadpicture) {  ?>
+               <p><?php print_string("hidepicture") ?></p>
+        <p><?php $options = NULL; $options[0] = get_string("no"); $options[1] = get_string("yes");
+                                choose_from_menu ($options, "hidepicture", $group->hidepicture, ""); ?></p>
+            <p><?php print_string("newpicture") ?></p>
+            <p><?php upload_print_form_fragment(1,array('groupicon'),null,false,null,0,0,false);
+                                    helpbutton("picture", get_string("helppicture"));
+                                    print_string("maxsize", "", display_size($maxbytes), 'groups'); ?></p>
+            <?php } ?>
+            <p><input type="button" id="editgroupsettings" value="<?php print_string('save', 'groups'); ?>" />&nbsp;<input type="button" id="canceleditgroupsettings" value="<?php print_string('cancel', 'groups'); ?>" /></p>
+    </form>
+</div>
diff --git a/group/groupui/editgroupsettings-form.js b/group/groupui/editgroupsettings-form.js
new file mode 100644 (file)
index 0000000..7bd9e22
--- /dev/null
@@ -0,0 +1,79 @@
+
+function onEditGroupSettingsSave() {
+       valid =  validateEditgroupsettingsForm();
+       if (valid) {
+               editgroupsettings() ;
+               hideAllForms();
+               showElement("groupeditform");
+       }
+       return false;
+}
+
+/**
+ * Creates a new group for the course. 
+ */
+function editGroupSettings() {
+       // alert("Called editgroupsettings");
+       var url = "editgroupsettings-xml.php";
+    var requeststring = "groupid="+selectedgroupid
+                                       +"&groupname="+getTextInputValue('groupname')
+                                       +"&description="+getTextInputValue('edit-groupdescription')
+                                       +"&enrolmentkey="+getTextInputValue('enrolmentkey')
+                                       +"&hidepicture="+hidepicture;
+        // The picture fields aren't displayed if the right library isn't present
+    if (document.getElementById('menuhidepicture')) {
+       requeststring = requeststring+"&hidepicture="+getTextInputValue('menuhidepicture');
+    }
+    sendPostRequest(request, url, requeststring, editGroupSettingsResponse);
+ }
+ /**
+  * The callback for the response to the request sent in editgroupsettings(() 
+  */
+ function editGroupSettingsResponse() {
+    if (checkAjaxResponse(request)) {
+       // alert("editgroupsettingsResponse");
+       // alert(request.responseText);
+       error = getFromXML(request.responseXML, 'error');
+       if (error != null) {
+               alert(error);   
+       }               
+       updateSelectedGrouping();
+       hideElement("editgroupsettingsform");
+    }
+}
+
+function getGroupSettings() {
+       // alert("Called getgroupsettings");
+       groupid = getSelectedGroup();
+       var url = "getgroupsettings-xml.php";
+    var requeststring = "groupid="+groupid;
+    sendPostRequest(request, url, requeststring, getGroupSettingsResponse);
+}
+
+function getGroupSettingsResponse() {
+    if (checkAjaxResponse(request)) {
+       // alert("getgroupsettingsResponse");
+       // alert(request.responseText);
+       error = getFromXML(request.responseXML, 'error');
+       if (error != null) {
+               alert(error);   
+       }               
+               xml = request.responseXML;
+       setTextInputValue('groupname', getFromXML(xml, 'name'));
+       setTextInputValue('edit-groupdescription', getFromXML(xml, 'description'));
+       setTextInputValue('enrolmentkey', getFromXML(xml, 'enrolmentkey'));     
+    }
+}
+
+function validateEditgroupsettingsForm() {
+       valid = true;
+       groupname = getTextInputValue('groupname');
+
+       if (groupname == '') {
+                       alert('You must enter a name for the new group');
+                       valid = false;
+       } 
+       return valid;
+}
+
diff --git a/group/groupui/editgroupsettings-xml.php b/group/groupui/editgroupsettings-xml.php
new file mode 100644 (file)
index 0000000..f9baae0
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+/**********************************************
+ * Adds a new grouping
+ **********************************************/
+header("Content-Type: text/xml");
+echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
+echo '<groupsresponse>';
+
+include_once('../../../config.php');
+include('../lib/lib.php');
+$groupid = required_param('groupid');
+$groupname = required_param('groupname');
+$description = required_param('description');
+$enrolmentkey = required_param('enrolmentkey');
+$hidepicture = required_param('hidepicture');
+$courseid = required_param('courseid', PARAM_INT);
+
+require_login($courseid);
+       
+if (confirm_sesskey() and isteacheredit($courseid)) {
+       $groupsettings->name = $groupname;
+       $groupsettings->description = $description;
+       $groupsettings->enrolmentkey = $enrolmentkey;
+       $groupsettings->hidepicture = $hidepicture;
+       
+       // Upload the group icon if there is one - note that we don't remove any previous icons 
+       require_once($CFG->dirroot.'/lib/uploadlib.php');
+    $um = new upload_manager('groupicon', false, false, null, false, 0, true, true);
+    if ($um->preprocess_files()) {
+       require_once("$CFG->libdir/gdlib.php");
+        if (save_profile_image($groupid, $um, 'groups')) {
+               $groupsettings->picture = 1;
+        } else {
+               echo '<error>Failed to save group image</error>';
+        }
+    } else {
+       $groupsettings->picture = 0;
+    }
+       
+       $infoset = groups_set_group_settings($groupid, $groupsettings);
+       if (!$infoset) {
+               echo "<error>Failed to set new group settings</error>";
+       } 
+}
+
+echo '</groupsresponse>';
+?>
\ No newline at end of file
diff --git a/group/groupui/form.css b/group/groupui/form.css
new file mode 100644 (file)
index 0000000..e8e92f0
--- /dev/null
@@ -0,0 +1,52 @@
+.popup
+{
+   position:absolute; 
+   left:300px; 
+   top:80px; 
+   width:550px;
+   border-style:solid;
+   border-color: grey;
+   border-width: 1px;
+   background-color: white;
+   padding:10px;
+   z-index:1;
+   visibility: hidden;
+}
+
+.popupwide
+{
+   position:absolute; 
+   left:200px; 
+   top:80px; 
+   width:900px;
+   border-style:solid;
+   border-color: grey;
+   border-width: 1px;
+   background-color: white;
+   padding:10px;
+   z-index:1;
+   visibility: hidden;
+}      
+
+.select
+{
+       overflow: visible;
+       clip: auto;
+       width:200px;
+}
+
+.groupmanagementtable
+{
+       padding: 10px;
+       margin-left: auto;
+       margin-right: auto; 
+       text-align: center; 
+}
+
+.groupmanagementtableheader
+{
+       width: 300px;
+}
+
+
+
diff --git a/group/groupui/form.html b/group/groupui/form.html
new file mode 100644 (file)
index 0000000..e193f66
--- /dev/null
@@ -0,0 +1,42 @@
+<link rel="stylesheet" type="text/css" href="form.css" />
+
+
+<script type="text/javascript" src="yahoo.js"></script>         
+<script type="text/javascript" src="connection.js"></script> 
+
+<script type="text/javascript">
+<!-- Begin
+<?php include('ajax.js'); ?>
+// end hiding script -->
+</script>
+<script type="text/javascript" src="util-form.js"></script>
+<script type="text/javascript" src="main-buttons-form.js"></script>
+<script type="text/javascript" src="main-selects-form.js"></script>
+<script type="text/javascript" src="creategroup-form.js"></script>
+<script type="text/javascript" src="creategrouping-form.js"></script>
+<script type="text/javascript" src="editgroupingsettings-form.js"></script>
+<script type="text/javascript" src="editgroupingpermissions-form.js"></script>
+<script type="text/javascript" src="editgroupsettings-form.js"></script>
+<script type="text/javascript" src="createautomaticgrouping-form.js"></script>
+<script type="text/javascript" src="addmembers-form.js"></script>
+<script type="text/javascript" src="addgroupstogrouping-form.js"></script>
+<script type="text/javascript" src="main-init-form.js"></script>
+<script type="text/javascript" src="deletegroup.js"></script>
+<script type="text/javascript" src="deletegrouping.js"></script>
+<script type="text/javascript" src="removegroupfromgrouping.js"></script>
+<script type="text/javascript" src="removemembers.js"></script>
+
+
+<noscript>
+       <?php notify(get_string('javascriptrequired')); ?>
+</noscript>
+
+<?php include('main-form.html'); ?>
+<?php include('creategroup-form.html'); ?>
+<?php include('editgroupsettings-form.html'); ?>
+<?php include('creategrouping-form.html'); ?>
+<?php include('editgroupingsettings-form.html'); ?>
+<?php include('editgroupingpermissions-form.html'); ?>
+<?php include('addgroupstogrouping-form.html'); ?>
+<?php include('addmembers-form.html'); ?>
+<?php include('createautomaticgrouping-form.html'); ?>
diff --git a/group/groupui/getgroupingpermissions-xml.php b/group/groupui/getgroupingpermissions-xml.php
new file mode 100644 (file)
index 0000000..eecd903
--- /dev/null
@@ -0,0 +1,64 @@
+<?php
+/**********************************************
+ * Fetches the settings of a grouping and returns 
+ * them in an XML format
+ **********************************************/
+header("Content-Type: text/xml");
+echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
+echo '<groupsresponse>';
+
+include_once("../../../config.php");
+include("../lib/lib.php");
+
+
+
+$courseid = required_param('courseid', PARAM_INT);
+$groupingid = required_param('groupingid', PARAM_INT);
+
+require_login($courseid);
+       
+if (confirm_sesskey() and isteacheredit($courseid)) {
+       $groupingsettings = groups_get_grouping_settings($groupingid);
+       echo '<name>'.$groupingsettings->name.'</name>';
+
+       if ($groupingsettings->viewowngroup) {
+               echo '<viewowngroup>true</viewowngroup>';
+       } else {
+               echo '<viewowngroup>false</viewowngroup>';
+       }
+       
+       if ($groupingsettings->viewallgroupsmembers) {
+               echo '<viewallgroupsmembers>true</viewallgroupsmembers>';
+       } else {
+               echo '<viewallgroupsmembers>false</viewallgroupsmembers>';
+       }
+       
+       if ($groupingsettings->viewallgroupsactivities) {
+               echo '<viewallgroupsactivities>true</viewallgroupsactivities>';
+       } else {
+               echo '<viewallgroupsactivities>false</viewallgroupsactivities>';
+       }
+       
+       if ($groupingsettings->teachersgroupmark) {
+               echo '<teachersgroupmark>true</teachersgroupmark>';             
+       } else {
+               echo '<teachersgroupmark>false</teachersgroupmark>';    
+       }       
+       
+       if ($groupingsettings->teachersgroupview) {
+               echo '<teachersgroupview>true</teachersgroupview>';             
+       } else {
+               echo '<teachersgroupview>false</teachersgroupview>';    
+       }       
+
+       if ($groupingsettings->teachersoverride) {
+               echo '<teachersoverride>true</teachersoverride>';               
+       } else {
+               echo '<teachersoverride>false</teachersoverride>';      
+       }               
+       
+}
+
+echo '</groupsresponse>';
+?>
\ No newline at end of file
diff --git a/group/groupui/getgroupings-xml.php b/group/groupui/getgroupings-xml.php
new file mode 100644 (file)
index 0000000..13ab917
--- /dev/null
@@ -0,0 +1,41 @@
+<?php
+/**********************************************
+ * Fetches the settings of the groupings for a course
+ * and returns them in an XML format
+ **********************************************/
+header("Content-Type: text/xml");
+echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
+echo '<groupsresponse>';
+
+include_once("../../../config.php");
+include("../lib/lib.php");
+
+$courseid = required_param('courseid', PARAM_INT);
+
+require_login($courseid);
+       
+if (confirm_sesskey() and isteacheredit($courseid)) {
+       $groupingids = groups_get_groupings($courseid);
+       if ($groupingids != false) {    
+               // Put the groupings into a hash and sort them
+               foreach($groupingids as $groupingid) {
+                   $listgroupings[$groupingid] = groups_get_grouping_displayname($groupingid);       
+               }
+               natcasesort($listgroupings);
+               
+               // Print out the XML 
+               echo '<option>';
+               foreach($listgroupings as $value=>$name) {
+                       echo "<name>$name</name>";
+                       echo "<value>$value</value>";
+               }
+               echo '</option>';
+       }
+}
+
+echo '</groupsresponse>';
+?>
+
+
+
diff --git a/group/groupui/getgroupingsettings-xml.php b/group/groupui/getgroupingsettings-xml.php
new file mode 100644 (file)
index 0000000..5c4d51f
--- /dev/null
@@ -0,0 +1,29 @@
+<?php
+/**********************************************
+ * Fetches the settings of a grouping and returns 
+ * them in an XML format
+ **********************************************/
+header("Content-Type: text/xml");
+echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
+echo '<groupsresponse>';
+
+include_once("../../../config.php");
+include("../lib/lib.php");
+
+
+
+$courseid = required_param('courseid', PARAM_INT);
+$groupingid = required_param('groupingid', PARAM_INT);
+
+require_login($courseid);
+       
+if (confirm_sesskey() and isteacheredit($courseid)) {
+       $groupingsettings = groups_get_grouping_settings($groupingid);
+       echo '<name>'.$groupingsettings->name.'</name>';
+       echo '<description>'.$groupingsettings->description.'</description>';
+       
+}
+
+echo '</groupsresponse>';
+?>
\ No newline at end of file
diff --git a/group/groupui/getgroupsettings-xml.php b/group/groupui/getgroupsettings-xml.php
new file mode 100644 (file)
index 0000000..1a4f3ba
--- /dev/null
@@ -0,0 +1,37 @@
+<?php
+/**********************************************
+ * Fetches the settings of a grouping and returns 
+ * them in an XML format
+ **********************************************/
+header("Content-Type: text/xml");
+echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
+echo '<groupsresponse>';
+
+include_once("../../../config.php");
+include("../lib/lib.php");
+
+
+
+$courseid = required_param('courseid', PARAM_INT);
+$groupid = required_param('groupid', PARAM_INT);
+require_login($courseid);
+       
+if (confirm_sesskey() and isteacheredit($courseid)) {
+
+       $groupsettings = groups_get_group_settings($groupid);
+       if (!$groupsettings) {
+               echo '<error>Failed to get group details</error>';
+       } else {
+               echo '<name>'.$groupsettings->name.'</name>';
+               echo '<description>'.$groupsettings->description.'</description>';
+               echo '<enrolmentkey>'.$groupsettings->enrolmentkey.'</enrolmentkey>';
+               echo '<hidepicture>'.$groupsettings->hidepicture.'</hidepicture>';
+               echo '<picture>'.$groupsettings->picture.'</picture>';
+               echo '<lang>'.$groupinkfo->lang.'</lang>';
+               echo '<theme>'.$groupsettings->theme.'</theme>';
+       }       
+}
+
+echo '</groupsresponse>';
+?>
\ No newline at end of file
diff --git a/group/groupui/getgroupsingrouping-xml.php b/group/groupui/getgroupsingrouping-xml.php
new file mode 100644 (file)
index 0000000..c7d210c
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+/**********************************************
+ * Adds an existing group to a grouping
+ **********************************************/
+header("Content-Type: text/xml");
+echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
+echo '<groupsresponse>';
+
+include_once("../../../config.php");
+include_once("../lib/lib.php");
+
+$groupingid = required_param('groupingid', PARAM_INT);
+$courseid = required_param('courseid', PARAM_INT);
+
+require_login($courseid);
+       
+if (confirm_sesskey() and isteacheredit($courseid)) {
+       $groupids = groups_get_groups_in_grouping($groupingid);
+       
+       if ($groupids != false) {
+               // Put the groupings into a hash and sort them
+               foreach($groupids as $groupid) {
+                   $listgroups[$groupid] = groups_get_group_displayname($groupid);  
+               }
+               
+               natcasesort($listgroups);
+               
+               // Print out the XML 
+               echo "<option>";
+               foreach($listgroups as $value=>$name) {
+                       echo "<name>$name</name>";
+                       echo "<value>$value</value>";
+               }
+               echo "</option>";
+       }
+}
+
+echo '</groupsresponse>';
+?>
diff --git a/group/groupui/getgroupsnotingrouping-xml.php b/group/groupui/getgroupsnotingrouping-xml.php
new file mode 100644 (file)
index 0000000..9adcb00
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+/**********************************************
+ * Gets the groups not in a grouping for a course
+ * and returns them in an XML format
+ **********************************************/
+header("Content-Type: text/xml");
+echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
+echo '<groupsresponse>';
+
+include_once("../lib/lib.php");
+include_once("../../../config.php");
+
+$groupingid = required_param('groupingid');
+$courseid = required_param('courseid');
+
+require_login($courseid);
+       
+if (confirm_sesskey() and isteacheredit($courseid)) {
+       $groupids = groups_get_groups_not_in_grouping($groupingid, $courseid);
+       if ($groupids != false) {
+               // Put the groupings into a hash and sort them
+               foreach($groupids as $groupid) {
+                   $listgroups[$groupid] = groups_get_group_displayname($groupid);       
+               }
+               
+               natcasesort($listgroups);
+               
+               // Print out the XML 
+               echo "<option>";
+               foreach($listgroups as $value=>$name) {
+                       echo "<name>$name</name>";
+                       echo "<value>$value</value>";
+               }
+               echo "</option>";
+       }
+}
+
+echo '</groupsresponse>';
+?>
diff --git a/group/groupui/getmembers-xml.php b/group/groupui/getmembers-xml.php
new file mode 100644 (file)
index 0000000..fa66958
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+/**********************************************
+ * Gets the members of a group and returns them
+ * in an XMl format
+ **********************************************/
+header("Content-Type: text/xml");
+echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
+echo '<groupsresponse>';
+
+include_once("../../../config.php");
+include_once("../lib/lib.php");
+
+
+$groupid = required_param('groupid', PARAM_INT);
+$courseid = required_param('courseid', PARAM_INT);
+
+require_login($courseid);
+       
+if (confirm_sesskey() and isteacheredit($courseid)) {
+
+       $userids = groups_get_members($groupid);
+       
+       if ($userids != false) {                
+               // Put the groupings into a hash and sort them
+               foreach($userids as $userid) {
+                   $listmembers[$userid] = groups_get_user_displayname($userid, $courseid);       
+               }
+               natcasesort($listmembers);
+               
+               
+               // Print out the XML 
+               
+               echo "<option>";
+               foreach($listmembers as $value=>$name) {
+                       echo "<name>$name</name>";
+                       echo "<value>$value</value>";
+               }
+               echo "</option>";
+       }
+}
+
+echo '</groupsresponse>';
+?>
diff --git a/group/groupui/getnonmembers-xml.php b/group/groupui/getnonmembers-xml.php
new file mode 100644 (file)
index 0000000..5ec6457
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+/**********************************************
+ * Gets the users registered for a course that
+ * don't belong to a specified group and prints
+ * their detailsin an XML format. 
+ **********************************************/
+
+header("Content-Type: text/xml");
+echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
+echo '<groupsresponse>';
+include_once("../../../config.php");
+include_once("../lib/lib.php");
+
+
+$groupid = required_param('groupid', PARAM_INT);
+$groupingid = required_param('groupingid', PARAM_INT);
+$courseid = required_param('courseid', PARAM_INT);
+$showall = required_param('showall', PARAM_INT);
+
+require_login($courseid);
+       
+if (confirm_sesskey() and isteacheredit($courseid)) {
+       echo "$groupingid $groupid";
+       if ($showall == 0) {
+               $userids = groups_get_users_not_in_any_group_in_grouping($courseid,$groupingid, $groupid);
+       } else {
+               $userids = groups_get_users_not_in_group($courseid, $groupid);
+       }
+       
+       if ($userids != false) {
+               // Put the groupings into a hash and sorts them
+               foreach($userids as $userid) {
+                   $listmembers[$userid] = groups_get_user_displayname($userid, $courseid);       
+               }
+               natcasesort($listmembers);
+               
+               
+               // Print out the XML 
+               echo "<option>";
+               foreach($listmembers as $value=>$name) {
+                       echo "<name>$name</name>";
+                       echo "<value>$value</value>";
+               }
+               echo "</option>";
+               }
+       }
+
+echo '</groupsresponse>';
+?>
diff --git a/group/groupui/index.php b/group/groupui/index.php
new file mode 100644 (file)
index 0000000..d6d3a6e
--- /dev/null
@@ -0,0 +1,59 @@
+<?php // $Id$
+
+/**********************************************
+ * The main group management user interface
+ ************************************************/
+
+require_once('../../../config.php');
+require_once('../../lib.php');
+require_once('../../../lib/moodlelib.php');
+require_once('../lib/lib.php');
+require_once($CFG->dirroot.'/lib/uploadlib.php');
+
+$error = false;
+$courseid = required_param('id');         
+
+// Get the course information so we can print the header and check the course id
+// is valid
+$course = groups_get_course_info($courseid);
+if (!$course) {
+    $error = true;
+    print_error('The course id is invalid');
+}
+
+
+if (!$error) {
+       // Make sure that the user is a teacher with edit permission for this course
+       require_login($courseid);
+       if (!isteacheredit($courseid)) {
+           redirect();  
+       }
+
+       // Set the session key so we can check this later
+       $sesskey = !empty($USER->id) ? $USER->sesskey : '';
+       
+       if (!empty($CFG->gdversion) and $maxbytes) {
+               $printuploadpicture = true;
+       } else {
+               $printuploadpicture = false;
+       }
+               
+       
+       $maxbytes = get_max_upload_file_size($CFG->maxbytes, $course->maxbytes);
+       $strgroups = get_string('groups');
+       $strparticipants = get_string('participants');
+       // Print the page and form
+       print_header("$course->shortname: $strgroups", 
+                 "$course->fullname", 
+                    "<a href=\"$CFG->wwwroot/course/view.php?id=$courseid\">$course->shortname</a> ".
+                    "-> <a href=\"$CFG->wwwroot/user/index.php?id=$courseid\">$strparticipants</a> ".
+                    "-> $strgroups", "", "", true, '', user_login_string($course, $USER));
+                    
+       include('form.html');
+       
+       print_footer($course);
+
+}
+
+?>
diff --git a/group/groupui/main-buttons-form.js b/group/groupui/main-buttons-form.js
new file mode 100644 (file)
index 0000000..c13880b
--- /dev/null
@@ -0,0 +1,66 @@
+
+
+function onShowAddMembersForm() {
+       hideAllForms();
+       showElement("addmembersform");
+       updateNonMembers();
+       groupname = getSelectedGroupName();
+       replaceText('selectedgroup', groupname);
+       return false;
+}
+
+function onShowAddGroupsToGroupingForm() {
+       hideAllForms();
+       showElement("addgroupstogroupingform");
+       updateGroupsNotInGrouping();
+       groupingname = getSelectedGroupingName();
+       replaceText('selectedgroupingforaddinggroups', groupingname);
+       return false;
+}
+
+function onShowCreateGroupingForm() {
+       hideAllForms();
+       showElement("creategroupingform");
+       return false;
+}
+
+function onShowCreateGroupForm() {
+       hideAllForms();
+       showElement("creategroupform");
+       groupingname = getSelectedGroupingName();
+       replaceText('selectedgroupingforcreatinggroup', groupingname);
+       return false;
+}
+
+function onShowEditGroupSettingsForm() {
+       hideAllForms();
+       showElement("editgroupsettingsform");
+       getGroupSettings();
+       return false;
+}
+
+function onShowEditGroupingPermissionsForm() {
+       hideAllForms();
+       showElement("editgroupingpermissionsform");
+       getGroupingPermissions();
+       return false;
+}
+
+function onShowEditGroupingSettingsForm() {
+       hideAllForms();
+       showElement("editgroupingsettingsform");
+       getGroupingSettings();
+       return false;
+}
+
+
+function onShowAutomaticGroupingForm() {
+       hideAllForms();
+       showElement("createautomaticgroupingform");
+       return false;
+}
+
+function onPrinterFriendly() {
+       document.location.href = "printgrouping.php?courseid="+courseid+"&groupingid="+selectedgroupingid;
+       return false;
+}
diff --git a/group/groupui/main-form.html b/group/groupui/main-form.html
new file mode 100644 (file)
index 0000000..af48f44
--- /dev/null
@@ -0,0 +1,41 @@
+<form name="groupeditform" id="groupeditform" action="">
+    <table cellpadding="10" class="generaltable generalbox groupmanagementtable">
+        <tr>
+            <th class="header groupmanagementtableheader"><?php print_string('groupings', 'groups'); ?></th>
+            <th class="header groupmanagementtableheader"><?php print_string('groupsinselectedgrouping', 'groups'); ?></th>
+            <th class="header groupmanagementtableheader"><?php print_string('membersofselectedgroup', 'groups'); ?></th>
+        </tr>
+        <tr>
+            <td class="generalboxcontent">
+               <select id="groupings" size="15" class="select"></select>
+            </td>
+            <td>
+               <select id="groups" size="15" class="select"></select>
+            </td>
+            <td>
+               <select id="members" size="15" multiple="multiple" class="select"></select>
+            </td>
+        </tr>
+        <tr>
+            <td>
+               <p><input type="button" id="showeditgroupingsettingsform" value="<?php print_string('editgroupingsettings', 'groups'); ?>" /></p>
+                <p><input type="button" id="showeditgroupingpermissionsform" value="<?php print_string('editgroupingpermissions', 'groups'); ?>" /></p>
+                <p><input type="button" id="deletegrouping" value="<?php print_string('deletegrouping', 'groups'); ?>" /></p>
+                <p><input type="button" id="showcreategroupingform" value="<?php print_string('creategrouping', 'groups'); ?>" /></p>
+                <p><input type="button" id="showcreateautomaticgroupingform" value="<?php print_string('createautomaticgrouping', 'groups'); ?>" /></p>
+                <p><input type="button" id="printerfriendly" value="<?php print_string('printerfriendly', 'groups'); ?>" /></p>
+            </td>
+            <td>
+               <p><input type="button" id="showeditgroupsettingsform" value="<?php print_string('editgroupsettings', 'groups'); ?>" /></p>
+                <p><input type="button" id="deletegroup" value="<?php print_string('deleteselectedgroup', 'groups'); ?>" /></p>
+                <p><input type="button" id="removegroup" value="<?php print_string('removegroupfromselectedgrouping', 'groups'); ?>" /></p>
+                <p><input type="button" id="showcreategroupform" value="<?php print_string('creategroupinselectedgrouping', 'groups'); ?>" /></p>
+                <p><input type="button" id="showaddgroupstogroupingform" value="<?php print_string('addexistinggroupstogrouping', 'groups'); ?>" /></p>
+            </td>
+            <td>
+               <p><input type="button" id="removemembers" value="<?php print_string('removeselectedusers', 'groups'); ?>"/></p>
+                <p><input type="button" id="showaddmembersform" value="<?php print_string('adduserstogroup', 'groups'); ?>" /></p>
+            </td>
+        </tr>
+    </table>
+</form>
diff --git a/group/groupui/main-init-form.js b/group/groupui/main-init-form.js
new file mode 100644 (file)
index 0000000..b4914e5
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * This file contains all the functions called when the pages loads and also all the functions that are called
+ * on events such as clicking buttons in the forms for the form.html page. 
+ * 
+ * This script requires functions from ajax.js and form-access.js
+ * 
+ * This code also assumes you have a basic understanding of how Ajax works - if
+ * you don't, it won't make much sense! 
+*/
+
+
+
+// Create XMLHttpRequest objects to use 
+var request = createRequest();
+var updategroupingsrequest = createRequest();
+var updateselectedgroupingsrequest = createRequest();
+var updateselectedgrouprequest = createRequest();
+
+// The selectedgroupingid should always be set to the current selected groupingid and the
+// selectedgroupid should always be set to the current selected groupid. We initialise them to 
+// be null at the start, but they'll get set when the page loads. 
+var selectedgroupingid = null;
+var selectedgroupid = null;
+
+// When the page has loaded called the initPage function
+window.onload = initPage;
+
+/**
+ *  The initPage function updates the groupings, groups and members in all the selects appropriately 
+ *and adds the right javascript events to all the buttons etc. 
+ */
+function initPage() {
+       // Check that we're using a recent enough version of javascript
+       if (!document.getElementById) {
+               return false;
+       }
+       updateGroupings();
+
+       addEvent('groupings', 'change', onGroupingChange);      
+       addEvent('groups', 'change', onGroupChange);
+       addEvent('deletegrouping', 'click', onDeleteGrouping);
+       addEvent('deletegroup', 'click', onDeleteGroup);
+       addEvent('removegroup', 'click', onRemoveGroup);
+       addEvent('removemembers', 'click', onRemoveMembers);
+       addEvent('showaddmembersform', 'click', onShowAddMembersForm);
+       addEvent('showaddgroupstogroupingform', 'click', onShowAddGroupsToGroupingForm);
+       addEvent('showcreategroupingform', 'click', onShowCreateGroupingForm);
+       addEvent('showcreategroupform', 'click', onShowCreateGroupForm);
+       addEvent('showeditgroupsettingsform', 'click', onShowEditGroupSettingsForm);    
+       addEvent('showeditgroupingsettingsform', 'click', onShowEditGroupingSettingsForm);
+       addEvent('showeditgroupingpermissionsform', 'click', onShowEditGroupingPermissionsForm);        
+       addEvent('showcreateautomaticgroupingform', 'click', onShowAutomaticGroupingForm);
+       addEvent('printerfriendly', 'click', onPrinterFriendly);        
+       addEvent('createautomaticgrouping', 'click', onCreateAutomaticGrouping);
+       addEvent('cancelcreateautomaticgrouping', 'click', onCancel);   
+       addEvent('addgroupstogrouping', 'click', onAddGroupsToGrouping);
+       addEvent('canceladdgroupstogrouping', 'click', onCancel);
+       addEvent('creategroup', 'click', onCreateGroup);        
+       addEvent('cancelcreategroup', 'click', onCancel);       
+       addEvent('creategrouping', 'click', onCreateGrouping);
+       addEvent('cancelcreategrouping', 'click', onCancel);    
+       addEvent('addmembers', 'click', onAddMembers);
+       addEvent('canceladdmembers', 'click', onCancel);
+       addEvent('showall', 'change', onShowAll);
+       addEvent('editgroupsettings', 'click', onEditGroupSettingsSave);        
+       addEvent('canceleditgroupsettings', 'click', onCancel);
+       addEvent('editgroupingsettings', 'click', onEditGroupingSettingsSave);  
+       addEvent('canceleditgroupingsettings', 'click', onCancel);      
+       addEvent('editgroupingpermissions', 'click', onEditGroupingPermissionsSave);    
+       addEvent('canceleditgroupingpermissions', 'click', onCancel);                                                           
+}
+
+
+
diff --git a/group/groupui/main-selects-form.js b/group/groupui/main-selects-form.js
new file mode 100644 (file)
index 0000000..3b5c08e
--- /dev/null
@@ -0,0 +1,255 @@
+/**
+ * This file contains various utility functions, primarily to get and set information on form.html
+ * and to take information from XML documents and either return information from them or modifiy the 
+ * form appropriately. 
+ */
+function onGroupingChange() {
+       hideAllForms();
+       showElement("groupeditform");
+       if (!document.getElementById('groupings')) {
+               alert('No groupings id element');       
+       } else {
+               groupingselect = document.getElementById('groupings');
+               selectedgroupingid = groupingselect.value;
+               selectedgroupid = null;
+               updateSelectedGrouping();
+       }
+       return false;
+}
+
+function onGroupChange() {
+       hideAllForms();
+       showElement("groupeditform");
+       selectedgroupid = getSelectedGroup();
+       updateSelectedGroup();
+       return false;
+}
+
+
+function getSelectedGroupingName() {
+       if (!document.getElementById('groupings')) {
+               alert('No groupings id element');       
+               value = null;
+       } else {
+               groupingselect = document.getElementById('groupings');
+               value = groupingselect.options[groupingselect.selectedIndex].firstChild.nodeValue;
+       }
+       return value;
+}
+
+function getSelectedGroupName() {
+       if (!document.getElementById('groups')) {
+               alert('No groups id element');  
+               value = null;
+       } else {
+               groupselect = document.getElementById('groups');
+               value = groupselect.options[groupselect.selectedIndex].firstChild.nodeValue;
+       }
+       return value;
+}
+
+/*
+ * Set the selected grouping on the form to the grouping whose id is selectedgroupingid
+ */
+function setSelectedGrouping() {
+       if (selectedgroupingid == null) {
+               selectedgroupingid = getFirstOption("groupings");
+       }
+       
+       if (selectedgroupingid != null) {
+               if (!document.getElementById('groupings')) {
+                       alert('No groupings id element');
+               } else {
+                       groupingselect = document.getElementById('groupings');
+                       groupingselect.value = selectedgroupingid
+               }
+       }
+}
+
+/*
+ * Get the id of the group that is currently selected
+ */
+function getSelectedGroup() {
+       if (!document.getElementById('groups')) {
+               alert('No groups id element');
+               value = null;
+       } else {
+               groupselect = document.getElementById('groups');
+               value = groupselect.value;
+       }
+       return value;
+}
+
+/*
+ * Set the selected group on the form to the group whose id is selectedgroupid
+ */
+function setSelectedGroup() {
+    if (selectedgroupid == null) {
+               selectedgroupid = getFirstOption("groups");
+       }
+       
+       if (selectedgroupid != null) {
+               if (!document.getElementById('groups')) {
+                       alert('No groups id element');
+               } else {
+                       groupselect = document.getElementById('groups');
+                       groupselect.value = selectedgroupid;
+               }
+       }
+}
+
+
+/*
+ * Get the selected users to delete 
+ */
+function getSelectedUsers() {
+       return getMultipleSelect("members")
+}
+
+
+/***************************************************************
+ * Functions that just display information (and don't change the data in the database)
+ **********************************************/ 
+
+/**
+ *  Updates the list of groupings, setting either a specified grouping as selected or 
+ * the first grouping as selected. 
+ */
+function updateGroupings() {
+       alert("updateGroupings called");
+       var url = "getgroupings-xml.php";
+       requeststring = 'courseid='+courseid+'&'+'sesskey='+sesskey;
+       var transaction = YAHOO.util.Connect.asyncRequest('POST', url, 
+                                          updateGroupingsResponseCallback, requeststring); 
+       //sendPostRequest(updategroupingsrequest, url, requeststring, updateGroupingsResponse);
+}
+
+var updateGroupingsResponseCallback = 
+{ 
+  success:updateGroupingsResponse, 
+  failure:responseFailure, 
+};
+
+
+/**
+ *  The callback function for updateGroupings()
+ * Takes the XML containing the grouping details that has been sent back and updates the display. 
+ */
+function updateGroupingsResponse() {
+       
+       alert("Called updateGroupingsResponse");        
+    if (updategroupingsrequest.readyState == 4 && updategroupingsrequest.status == 200) {
+        alert("updateGroupingsResponse called");
+       var xmlDoc = updategroupingsrequest.responseXML;
+       error = getFromXML(updategroupingsrequest.responseXML, 'error');
+       if (error != null) {
+               alert(error);   
+       }               
+       alert(updategroupingsrequest.responseText);
+       var noofoptions = addOptionsFromXML("groupings", xmlDoc);
+       
+       // If the selected grouping is not set, set it to the first grouping in the list
+               if(selectedgroupingid == null) {
+                       selectedgroupingid = getFirstOption("groupings");
+                       selectedgroupid = null;
+               }
+               
+               // If there are no groupings, make sure the rest of the form is set up appropriately 
+               // i.e. there should be any groups or members shown and various buttons should be disabled
+               // If there are groupings, update the one that is selected and enable any buttons that
+               // might have been disabled.
+               if (noofoptions == 0) {
+                       removeOptions("groups");
+               removeOptions("members");
+               disableButton("showaddmembersform");
+               disableButton("showcreategroupform");
+               disableButton("showaddgroupstogroupingform");
+       } else {
+               updateSelectedGrouping();
+               enableButton("showaddmembersform");
+               enableButton("showcreategroupform");
+               enableButton("showaddgroupstogroupingform");
+       }
+    }
+}
+
+/** 
+ * Updates the list of groups when groupingid is marked as selected
+ * groupid can be null or a specified group - this is the group that gets marked as 
+ * selectedgroupingid cannot be null. 
+ */
+function updateSelectedGrouping() {
+       //alert("UpdateSelectedGrouping called");
+       setSelectedGrouping();  
+    var url = "getgroupsingrouping-xml.php";
+    requeststring = "groupingid="+selectedgroupingid;
+       sendPostRequest(updateselectedgroupingsrequest, url, requeststring, updateSelectedGroupingResponse);
+}
+
+/**
+ * The callback for the response to the request sent in updateSelectedGrouping() 
+ */
+function updateSelectedGroupingResponse() {
+    if (checkAjaxResponse(updateselectedgroupingsrequest)) {
+       //alert("updateSelectedGroupingResponse called");
+       var xmlDoc = updateselectedgroupingsrequest.responseXML;
+       error = getFromXML(updateselectedgroupingsrequest.responseXML, 'error');
+       if (error != null) {
+               alert(error);   
+       }               
+       // alert(updateselectedgroupingsrequest.responseText);
+       var noofoptions = addOptionsFromXML("groups", xmlDoc);
+       if (selectedgroupid == null) {
+                       selectedgroupid = getFirstOption("groups");
+               }
+               
+       if (noofoptions == 0) {
+               removeOptions("members");
+               disableButton("showaddmembersform");
+       } else {
+               updateSelectedGroup(selectedgroupid);
+               enableButton("showaddmembersform");
+       }       
+    } 
+}
+
+/**
+ *  Updates the members for the selected group - currently none marked as selected
+ */
+function updateSelectedGroup() {
+       //alert("updateSelectedGroup");
+    setSelectedGroup();
+    var url = "getmembers-xml.php";
+    var requeststring = "groupid="+selectedgroupid;
+    sendPostRequest(updateselectedgrouprequest, url, requeststring, updateSelectedGroupResponse);
+}
+
+/**
+ * The callback for the response to the request sent in updateSelectedGroup() 
+ */
+function updateSelectedGroupResponse() {
+    if (checkAjaxResponse(updateselectedgrouprequest)) {
+       var xmlDoc = updateselectedgrouprequest.responseXML;    
+       //alert("updateSelectedGroupResponse");
+       error = getFromXML(xmlDoc, 'error');
+       if (error != null) {
+               alert(error);   
+       }       
+
+       //alert(request.responseText);
+       var noofoptions = addOptionsFromXML("members", xmlDoc);         
+    } 
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/group/groupui/printgrouping.php b/group/groupui/printgrouping.php
new file mode 100644 (file)
index 0000000..2f19275
--- /dev/null
@@ -0,0 +1,64 @@
+<?php
+include_once("../../../config.php");
+include("../lib/lib.php");
+
+$courseid     = required_param('courseid', PARAM_INT);
+$groupingid = required_param('groupingid', PARAM_INT);
+
+
+require_login($courseid);
+
+// confirm_sesskey checks that this is a POST request  
+if (isteacheredit($courseid)) {
+       
+       // Print the page and form
+       $strgroups = get_string('groups');
+       $strparticipants = get_string('participants');
+       print_header("$course->shortname: $strgroups", "$course->fullname", 
+                    "<a href=\"$CFG->wwwroot/course/view.php?id=$courseid\">$course->shortname</a> ".
+                    "-> <a href=\"$CFG->wwwroot/user/index.php?id=$courseid\">$strparticipants</a> ".
+                    "-> <a href=\"$CFG->wwwroot/course/groups/groupui/index.php?id=$courseid\">$strgroups</a>".
+                    "-> Display grouping", "", "", true, '', user_login_string($course, $USER));
+       
+       $groupingsettings = groups_get_grouping_settings($groupingid);
+       
+       // Print the name of the grouping
+       $name = $groupingsettings->name;
+       print("<h1>$name</h1>");
+       
+       // Get the groups and group members for the grouping
+       $groupids = groups_get_groups_in_grouping($groupingid);
+       
+       if ($groupids != false) {
+               
+               // Make sure the groups are in the right order 
+               foreach($groupids as $groupid) {
+                   $listgroups[$groupid] = groups_get_group_displayname($groupid);  
+               }
+               
+               natcasesort($listgroups);
+       
+               // Go through each group in turn and print the group name and then the members  
+               foreach($listgroups as $groupid=>$groupname) {
+                       print "<h2>$groupname</h2>";
+                       $userids = groups_get_members($groupid);
+                       if ($userids != false) {
+                               // Make sure the users are in the right order
+                               unset($listmembers);
+                               foreach($userids as $userid) {
+                               $listmembers[$userid] = groups_get_user_displayname($userid, $courseid);       
+                               }
+                               natcasesort($listmembers);
+                                       
+                               foreach($listmembers as $userid=>$name) {
+                                       print("$name<br>");
+                               }
+                       }
+               }
+       }
+       
+       print_footer($course);
+       
+}
+
+?>
diff --git a/group/groupui/removegroupfromgrouping-xml.php b/group/groupui/removegroupfromgrouping-xml.php
new file mode 100644 (file)
index 0000000..604ed7e
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+/**********************************************
+ * Removes a specified group from a specified grouping
+ * (but does not delete the group)
+ **********************************************/
+
+header("Content-Type: text/xml");
+echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
+echo '<groupsresponse>';
+
+include_once("../../../config.php");
+include("../lib/lib.php");
+
+$groupid = required_param('groupid', PARAM_INT);
+$groupingid = required_param('groupingid', PARAM_INT);
+$courseid = required_param('courseid', PARAM_INT);
+
+require_login($courseid);
+       
+if (confirm_sesskey() and isteacheredit($courseid)) {
+       $groupingremoved = groups_remove_group_from_grouping($groupid, $groupingid);
+       if (!$groupingremoved) {
+               echo '<error>Failed to remove group from grouping</error>';
+       }
+}
+
+echo '</groupsresponse>';
+?>
diff --git a/group/groupui/removegroupfromgrouping.js b/group/groupui/removegroupfromgrouping.js
new file mode 100644 (file)
index 0000000..df4b383
--- /dev/null
@@ -0,0 +1,34 @@
+
+function onRemoveGroup() {
+       hideAllForms();
+       showElement("groupeditform");
+       removeGroupFromGrouping();
+       return false;
+}
+
+/**
+ * Removes the selected group from the selected grouping, does not delete the group (so it can e.g. be added to
+ * another grouping
+ */
+function removeGroupFromGrouping() {
+       //alert("Called removeGroupFromGrouping");
+       var url = "removegroupfromgrouping-xml.php";
+    var requeststring = "groupid="+selectedgroupid+"&groupingid="+selectedgroupingid;
+    sendPostRequest(request, url, requeststring, removeGroupFromGroupingResponse);
+}
+/**
+ * The callback for the response to the request sent in removeGroupFromGrouping() 
+ */ 
+function removeGroupFromGroupingResponse() {
+    if (checkAjaxResponse(request)) {
+       //alert("removeGroupFromGroupingResponse called");
+       var xmlDoc= request.responseXML;
+       // Need XML sent back with groupingid
+       // Really want to set this to be the grouping before
+       selectedgroupid = null;
+       updateGroupings();
+    }
+}
+
+
diff --git a/group/groupui/removemembers-xml.php b/group/groupui/removemembers-xml.php
new file mode 100644 (file)
index 0000000..2da3188
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+
+/**********************************************
+ * Takes a groupid and comma-separated list of 
+ * userids, and removes each of those userids 
+ * from the specified group
+ **********************************************/
+
+header("Content-Type: text/xml");
+echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
+echo '<groupsresponse>';
+
+include_once("../../../config.php");
+include("../lib/lib.php");
+
+$groupid = required_param('groupid', PARAM_INT);
+$users = required_param('users');
+$courseid = required_param('courseid', PARAM_INT);
+
+require_login($courseid);
+       
+if (confirm_sesskey() and isteacheredit($courseid)) {
+       // Change the comma-separated string of the userids into an array of the userids
+       $userids = explode(',', $users); 
+       if ($userids != false) {
+               // Remove each user in turn from the group. 
+               foreach($userids as $userid) {
+                       $useradded = groups_remove_member($userid, $groupid);
+                       if (!$useradded) {
+                               echo "<error>Failed to adduser $userid</error>";
+                       }
+               }
+       }
+}
+
+
+echo '</groupsresponse>';
+
+?>
diff --git a/group/groupui/removemembers.js b/group/groupui/removemembers.js
new file mode 100644 (file)
index 0000000..ef16b9b
--- /dev/null
@@ -0,0 +1,33 @@
+
+
+
+function onRemoveMembers() {
+       hideAllForms();
+       showElement("groupeditform");
+       removeMembers();
+       return false;
+}
+
+
+
+/**
+ * Removes the selected members from the selected group
+ */
+function removeMembers() {
+       //alert("Called removeMembers");
+       users = getSelectedUsers();
+       var url = "removemembers-xml.php";
+    var requeststring = "groupid="+selectedgroupid+"&users="+users;
+    sendPostRequest(request, url, requeststring, removeMembersResponse);
+}
+
+/**
+ * The callback for the response to the request sent in removeMembers() 
+ */
+function removeMembersResponse() {
+    if (checkAjaxResponse(request)) {
+       //alert("removeMembersResponse called");
+       //alert(request.responseText);
+       updateSelectedGroup();
+    }
+}
diff --git a/group/groupui/util-form.js b/group/groupui/util-form.js
new file mode 100644 (file)
index 0000000..84be35e
--- /dev/null
@@ -0,0 +1,358 @@
+/**
+ * This file contains various utility functions, primarily to get and set information on form.html
+ * and to take information from XML documents and either return information from them or modifiy the 
+ * form appropriately. 
+ */
+
+/*
+ * Disable the button with the specified id
+ */
+function disableButton(id) {
+       if (!document.getElementById(id)) {
+               showNoElementError(id) 
+       } else {
+               var node = document.getElementById(id);
+               node.disabled = true;
+       }
+}
+
+/**
+ * Enable the button with the specified id
+ */
+function enableButton(id) {
+       if (!document.getElementById(id)) {
+               showNoElementError(id) 
+       } else {
+               var node = document.getElementById(id);
+               node.disabled = false;
+       }
+}
+
+/**
+ * Show the form with the specified id
+ */
+function showElement(id) {
+       if (!document.getElementById(id)) {
+               showNoElementError(id) 
+       } else {
+               document.getElementById(id).style.visibility = "visible";
+       }
+}
+
+/** 
+ * Hide the form with the specified id
+ */
+function hideElement(id) {
+       if (!document.getElementById(id)) {
+               showNoElementError(id) 
+       } else {
+               var node = document.getElementById(id);
+               node.style.visibility = "hidden";
+       }
+}
+
+
+/**
+ * Hides all the extra forms in form.html
+ */
+function hideAllForms() {
+       hideElement("addmembersform");
+       hideElement("addgroupstogroupingform");
+       hideElement("creategroupingform");
+       hideElement("createautomaticgroupingform");
+       hideElement("creategroupform");
+       hideElement("editgroupingsettingsform");
+       hideElement("editgroupingpermissionsform");
+       hideElement("editgroupsettingsform");
+       hideElement("groupeditform");
+}
+
+function onCancel() {
+       hideAllForms();
+       showElement("groupeditform");
+       return false;
+}
+
+
+function addEvent(id, eventtype, fn){ 
+       if (!document.getElementById(id)) {
+               alert('No ' + id + ' element');
+               return false;
+       } else {
+               obj = document.getElementById(id); 
+       }
+       
+       if (obj.addEventListener) {
+               obj.addEventListener(eventtype, fn, false );
+       } else if (obj.attachEvent) {
+               obj["e"+ eventtype +fn] = fn;
+               obj[eventtype+fn] = function() { obj["e"+ eventtype +fn]( window.event ); }
+               obj.attachEvent( "on"+ eventtype , obj[eventtype+fn] );
+       } else {
+               obj["on"+type] = obj["e"+ eventtype +fn];
+       } 
+}
+
+/**
+ * Gets the value of the first option in a select
+ */
+function getFirstOption(id) {
+       if (document.getElementById(id)) {
+               var node = document.getElementById(id);
+               if (node.hasChildNodes()) {
+                       var children 
+                       firstoption = node.firstChild;
+                       if (firstoption.value) {
+                               value = firstoption.value;
+                       } else {
+                               value = null;
+                       }
+               } else {
+                       value = null;
+               }
+       } else {
+               value = null;
+       }
+       return value;
+}
+
+/* 
+ *Turn the values from a multiple select to a comma-separated list
+*/
+function getMultipleSelect(id) {
+       if (!document.getElementById(id)) {
+               showNoElementError(id) 
+       } else {
+       node = document.getElementById(id);
+       }
+       var selected = ""       
+
+       for (var i = 0; i < node.options.length; i++) {
+               if (node.options[i].selected) { 
+                       selected = selected + node.options[ i ].value + ",";
+               }
+       }
+       // Remove the last comma - there must be a nicer way of doing this!
+       // Maybe easier with regular expressions?
+       var length = selected.length;
+       if (selected.charAt(length - 1) == ',') {
+               selected = selected.substring(0, length -1);
+       }
+       
+       return selected;
+}
+
+/*
+ * Creates an option in a select element with the specified id with the given name and value.
+*/
+function createOption(id, value, name) {
+       var node = document.getElementById(id);
+       var option = document.createElement("option");
+       option.setAttribute("value", value);
+       node.appendChild(option);
+       var namenode = document.createTextNode(name);
+       option.appendChild(namenode);
+}
+
+/*
+ * Removes all the options from a select with a given id
+*/
+function removeOptions(id) {
+       var node = document.getElementById(id);
+
+       while (node.hasChildNodes())
+       {
+         node.removeChild(node.firstChild);
+       }
+}
+
+/*
+ * Takes an XML doc of the form <option><name></name><value></value><name></name><value></value></option>
+ * And adds an option to the selected with the specified id
+ * @param id The id of the select
+ * @param xmlDoc The XML document
+ * @return The number of options added
+ */
+function addOptionsFromXML(id, xmlDoc) {
+       // Clear any options that are already there. 
+       removeOptions(id);
+
+       var optionelements = xmlDoc.getElementsByTagName('option');
+       var nameelements = xmlDoc.getElementsByTagName('name');
+       var valueelements = xmlDoc.getElementsByTagName('value');
+
+       if (nameelements != null) {
+               for (var i = 0; i < nameelements.length; i++) {
+                       var name = nameelements[i].firstChild.nodeValue;
+                       var value = valueelements[i].firstChild.nodeValue;
+                       createOption(id, value, name);
+               }
+               noofoptions = nameelements.length;
+       } else {
+               noofoptions = 0;
+       }
+       return noofoptions;
+}
+
+/*
+ * Gets an error from an XML doc contain a tag of the form <error></error>
+ * If it contains more than one such tag, it only return the value from the first one. 
+ */
+function getErrorFromXML(xmlDoc) {
+       alert(xmlDoc.getElementsByTagName('error'));
+       if (!xmlDoc.getElementsByTagName('error')) {
+               value = null;
+       } else {
+               var errorelement = xmlDoc.getElementsByTagName('error')[0];
+               var value = errorelement.firstChild.nodeValue;
+       }
+       return value;
+}
+
+
+function addChildrenFromXML(parentnode, xmlparentnode) {
+       xmlChildNodes = xmlparentnode.childNodes;
+       length = xmlChildNodes.length;
+       for (i = 0; i < length; i++) {
+               child = parentnode.appendChild(parentnode, xmlChildNodes[i]);
+               addChildrenFromXML(child, xmlChildNodes[i])
+       }
+}
+
+function getTextInputValue(id) {
+       if (!document.getElementById(id)) {
+               showNoElementError(id) 
+               value = null;
+       } else {
+               textinput = document.getElementById(id);
+               value = textinput.value;
+       }
+       return value;
+}
+
+function setTextInputValue(id, value) {
+       if (!document.getElementById(id)) {
+               showNoElementError(id); 
+               value = null;
+       } else {
+               textinput = document.getElementById(id);
+               textinput.value = value;
+       }
+}
+
+function getCheckBoxValue(id) {
+       if (!document.getElementById(id)) {
+               showNoElementError(id); 
+               value= null;
+       } else {
+               checkbox = document.getElementById(id);
+               value = checkbox.checked;
+       }
+       return  boolToInt(value);
+}
+
+function boolStringToBool(boolstring) {
+       if (boolstring == 'true') {
+        return true;
+        } else {
+        return false;
+        }
+}
+
+function boolToInt(boolean) {
+       if (boolean) {
+               return '1';
+       } else if (boolean == false) {
+               return '0';
+       } else {
+       return boolean;
+       }
+}
+
+function setCheckBoxValue(id, checked) {
+       if (!document.getElementById(id)) {
+               showNoElementError(id); 
+       } else {
+               checkbox = document.getElementById(id);
+               checkbox.checked = checked;
+       }
+}
+
+function replaceText(id, text) {
+       if (!document.getElementById(id)) {
+               showNoElementError(id) 
+               value = null;
+       } else {
+               element = document.getElementById(id);
+                   if (element.childNodes) {
+      for (var i = 0; i < element.childNodes.length; i++) {
+        var childNode = element.childNodes[i];
+        element.removeChild(childNode);
+      }
+    }
+               var textnode = document.createTextNode(text);
+               element.appendChild(textnode);
+       }
+}
+
+
+ function getRadioValue(radioelement) {
+       value = "";
+       if (!radioelement) {
+               value = "";
+       }
+       
+
+       for(var i = 0; i < radioelement.length; i++) {
+               if(radioelement[i].checked) {
+                       value =  radioelement[i].value;
+               }
+       }
+       return value;
+}
+
+/*
+ * Gets the groupid from an XML doc contain a tag of the form <groupid></groupid>
+ * If it contains more than one such tag, it only return the value from the first one. 
+ */
+function getFromXML(xmlDoc, id) {
+       if (!xmlDoc.getElementsByTagName(id)) {
+               var value = null;
+       } else if (xmlDoc.getElementsByTagName(id).length == 0) {
+               var value = null;
+       } else {
+               var element = xmlDoc.getElementsByTagName(id)[0];
+               if (!element.firstChild) {
+                       var value = '';
+               } else {
+                       var value = element.firstChild.nodeValue;
+               }
+       }
+       
+       return value;
+}
+
+function showNoElementError(id) {
+       alert('Error: No ' + id +' element');
+}
+
+function isPositiveInt(str) {
+       isPosInt = true;
+       
+       var i = parseInt (str);
+
+       if (isNaN (i)) {
+               isPosInt = false;
+       } 
+       
+       if (i < 0) {
+               isPosInt = false;
+               // Check not characters at the end of the number
+       } 
+       
+       if (i.toString() != str) {
+               isPosInt = false;
+       }
+       return isPosInt ;
+}
+
diff --git a/group/groupui/yahoo.js b/group/groupui/yahoo.js
new file mode 100644 (file)
index 0000000..e285bc3
--- /dev/null
@@ -0,0 +1,84 @@
+/*                                                                                                                                                      
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.                                                                                                    
+Code licensed under the BSD License:                                                                                                                    
+http://developer.yahoo.net/yui/license.txt                                                                                                              
+version: 0.11.0                                                                                                                                         
+*/ 
+
+/**
+ * The Yahoo global namespace
+ * @constructor
+ */
+var YAHOO = window.YAHOO || {};
+
+/**
+ * Returns the namespace specified and creates it if it doesn't exist
+ *
+ * YAHOO.namespace("property.package");
+ * YAHOO.namespace("YAHOO.property.package");
+ *
+ * Either of the above would create YAHOO.property, then
+ * YAHOO.property.package
+ *
+ * @param  {String} ns The name of the namespace
+ * @return {Object}    A reference to the namespace object
+ */
+YAHOO.namespace = function(ns) {
+
+    if (!ns || !ns.length) {
+        return null;
+    }
+
+    var levels = ns.split(".");
+    var nsobj = YAHOO;
+
+    // YAHOO is implied, so it is ignored if it is included
+    for (var i=(levels[0] == "YAHOO") ? 1 : 0; i<levels.length; ++i) {
+        nsobj[levels[i]] = nsobj[levels[i]] || {};
+        nsobj = nsobj[levels[i]];
+    }
+
+    return nsobj;
+};
+
+/**
+ * Uses YAHOO.widget.Logger to output a log message, if the widget is available.
+ *
+ * @param  {string}  sMsg       The message to log.
+ * @param  {string}  sCategory  The log category for the message.  Default
+ *                              categories are "info", "warn", "error", time".
+ *                              Custom categories can be used as well. (opt)
+ * @param  {string}  sSource    The source of the the message (opt)
+ * @return {boolean}            True if the log operation was successful.
+ */
+YAHOO.log = function(sMsg, sCategory, sSource) {
+    var l = YAHOO.widget.Logger;
+    if(l && l.log) {
+        return l.log(sMsg, sCategory, sSource);
+    } else {
+        return false;
+    }
+};
+
+/**
+ * Utility to set up the prototype, constructor and superclass properties to
+ * support an inheritance strategy that can chain constructors and methods.
+ *
+ * @param {Function} subclass   the object to modify
+ * @param {Function} superclass the object to inherit
+ */
+YAHOO.extend = function(subclass, superclass) {
+    var f = function() {};
+    f.prototype = superclass.prototype;
+    subclass.prototype = new f();
+    subclass.prototype.constructor = subclass;
+    subclass.superclass = superclass.prototype;
+    if (superclass.prototype.constructor == Object.prototype.constructor) {
+        superclass.prototype.constructor = superclass;
+    }
+};
+
+YAHOO.namespace("util");
+YAHOO.namespace("widget");
+YAHOO.namespace("example");
+
diff --git a/group/install.php b/group/install.php
new file mode 100644 (file)
index 0000000..512446d
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+
+include_once('../../config.php');
+include_once($CFG->dirroot.'/course/groups/lib/configlib.php');
+include_once($CFG->dirroot.'/course/groups/db/dbsetup.php');
+include_once($CFG->dirroot.'/course/groups/lib/utillib.php');
+
+// Set up the database 
+groups_create_database_tables();
+
+
+// Change database tables - course table need to remove two fields add groupingid field
+// Move everything over
+// Course module instance need to add groupingid field
+// Module table - add group support field. 
+// Add deletable by teacher field. 
+
+/**
+ * Copies the moodle groups to a new grouping within IMS groups
+ * @param int $courseid The id of the course
+ * @return int The id of the grouping to which the groups have been copied, or false if an error occurred. 
+ */
+function groups_copy_moodle_groups_to_groups($courseid) {
+       $groupingsettings->name = 'Old moodle groups';
+       $groupingid = groups_create_grouping($courseid, $groupingsettings);
+
+       $groupids = groups_get_moodle_groups($courseid);
+       if (!$groupids) {
+               $groupingid = false;
+       } else {
+               
+               foreach($groupids as $groupid) {
+                       $groupcopied = groups_db_copy_moodle_group_to_imsgroup($groupid, $courseid);
+                       if (!$groupcopied) {
+                               $groupingid = false;
+                       }
+                       
+                       $groupadded = groups_add_group_to_grouping($groupid, $groupingid);
+                       if (!$groupadded) {
+                               $groupingid = false;
+                       }
+               }
+       }
+       
+       return $groupingid;
+}      
+
+?>
diff --git a/group/install.sql b/group/install.sql
new file mode 100644 (file)
index 0000000..22feae9
--- /dev/null
@@ -0,0 +1,199 @@
+-- phpMyAdmin SQL Dump
+-- version 2.8.1
+-- http://www.phpmyadmin.net
+-- 
+-- Host: localhost
+-- Generation Time: Oct 24, 2006 at 05:23 PM
+-- Server version: 5.0.21
+-- PHP Version: 4.4.2-pl1
+-- 
+-- Database: `moodle`
+-- 
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `mdl_course`
+-- 
+
+CREATE TABLE `mdl_course` (
+  `id` int(10) unsigned NOT NULL auto_increment,
+  `category` int(10) unsigned NOT NULL default '0',
+  `sortorder` int(10) unsigned NOT NULL default '0',
+  `password` varchar(50) collate utf8_unicode_ci NOT NULL default '',
+  `fullname` varchar(254) collate utf8_unicode_ci NOT NULL default '',
+  `shortname` varchar(100) collate utf8_unicode_ci NOT NULL default '',
+  `idnumber` varchar(100) collate utf8_unicode_ci NOT NULL default '',
+  `summary` text collate utf8_unicode_ci NOT NULL,
+  `format` varchar(10) collate utf8_unicode_ci NOT NULL default 'topics',
+  `showgrades` smallint(2) unsigned NOT NULL default '1',
+  `modinfo` longtext collate utf8_unicode_ci NOT NULL,
+  `newsitems` smallint(5) unsigned NOT NULL default '1',
+  `teacher` varchar(100) collate utf8_unicode_ci NOT NULL default 'Teacher',
+  `teachers` varchar(100) collate utf8_unicode_ci NOT NULL default 'Teachers',
+  `student` varchar(100) collate utf8_unicode_ci NOT NULL default 'Student',
+  `students` varchar(100) collate utf8_unicode_ci NOT NULL default 'Students',
+  `guest` tinyint(2) unsigned NOT NULL default '0',
+  `startdate` int(10) unsigned NOT NULL default '0',
+  `enrolperiod` int(10) unsigned NOT NULL default '0',
+  `numsections` smallint(5) unsigned NOT NULL default '1',
+  `marker` int(10) unsigned NOT NULL default '0',
+  `maxbytes` int(10) unsigned NOT NULL default '0',
+  `showreports` int(4) unsigned NOT NULL default '0',
+  `visible` int(1) unsigned NOT NULL default '1',
+  `hiddensections` int(2) unsigned NOT NULL default '0',
+  `groupmode` int(4) unsigned NOT NULL default '0',
+  `groupmodeforce` int(4) unsigned NOT NULL default '0',
+  `lang` varchar(10) collate utf8_unicode_ci NOT NULL default '',
+  `theme` varchar(50) collate utf8_unicode_ci NOT NULL default '',
+  `cost` varchar(10) collate utf8_unicode_ci NOT NULL default '',
+  `currency` char(3) collate utf8_unicode_ci NOT NULL default 'USD',
+  `timecreated` int(10) unsigned NOT NULL default '0',
+  `timemodified` int(10) unsigned NOT NULL default '0',
+  `metacourse` int(1) unsigned NOT NULL default '0',
+  `requested` int(1) unsigned NOT NULL default '0',
+  `restrictmodules` int(1) unsigned NOT NULL default '0',
+  `expirynotify` tinyint(1) unsigned NOT NULL default '0',
+  `expirythreshold` int(10) unsigned NOT NULL default '0',
+  `notifystudents` tinyint(1) unsigned NOT NULL default '0',
+  `enrollable` tinyint(1) unsigned NOT NULL default '1',
+  `enrolstartdate` int(10) unsigned NOT NULL default '0',
+  `enrolenddate` int(10) unsigned NOT NULL default '0',
+  `enrol` varchar(20) collate utf8_unicode_ci NOT NULL default '',
+  PRIMARY KEY  (`id`),
+  KEY `category` (`category`),
+  KEY `idnumber` (`idnumber`),
+  KEY `shortname` (`shortname`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=7 ;
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `mdl_course_modules`
+-- 
+
+CREATE TABLE `mdl_course_modules` (
+  `id` int(10) unsigned NOT NULL auto_increment,
+  `course` int(10) unsigned NOT NULL default '0',
+  `module` int(10) unsigned NOT NULL default '0',
+  `instance` int(10) unsigned NOT NULL default '0',
+  `section` int(10) unsigned NOT NULL default '0',
+  `added` int(10) unsigned NOT NULL default '0',
+  `score` tinyint(4) NOT NULL default '0',
+  `indent` int(5) unsigned NOT NULL default '0',
+  `visible` tinyint(1) NOT NULL default '1',
+  `visibleold` tinyint(1) NOT NULL default '1',
+  `groupingid` int(10) NOT NULL default '0',
+  PRIMARY KEY  (`id`),
+  UNIQUE KEY `id` (`id`),
+  KEY `visible` (`visible`),
+  KEY `course` (`course`),
+  KEY `module` (`module`),
+  KEY `instance` (`instance`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=2 ;
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `mdl_groups_courses_groupings`
+-- 
+
+CREATE TABLE `mdl_groups_courses_groupings` (
+  `id` int(10) unsigned NOT NULL auto_increment,
+  `courseid` int(10) unsigned NOT NULL default '0',
+  `groupingid` mediumint(9) NOT NULL,
+  PRIMARY KEY  (`id`),
+  UNIQUE KEY `id` (`id`),
+  KEY `courseid` (`courseid`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=87 ;
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `mdl_groups_courses_groups`
+-- 
+
+CREATE TABLE `mdl_groups_courses_groups` (
+  `id` int(10) unsigned NOT NULL auto_increment,
+  `courseid` int(10) unsigned NOT NULL default '0',
+  `groupid` int(11) NOT NULL,
+  PRIMARY KEY  (`id`),
+  UNIQUE KEY `id` (`id`),
+  KEY `courseid` (`courseid`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=132 ;
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `mdl_groups_groupings`
+-- 
+
+CREATE TABLE `mdl_groups_groupings` (
+  `id` int(10) unsigned NOT NULL auto_increment,
+  `name` varchar(254) character set latin1 collate latin1_general_ci NOT NULL default '',
+  `description` text character set latin1 collate latin1_general_ci NOT NULL,
+  `timecreated` int(10) unsigned NOT NULL default '0',
+  `viewowngroup` tinyint(1) NOT NULL,
+  `viewallgroupsmembers` tinyint(1) NOT NULL,
+  `viewallgroupsactivities` tinyint(1) NOT NULL,
+  `teachersgroupmark` tinyint(1) NOT NULL,
+  `teachersgroupview` binary(1) NOT NULL,
+  `teachersoverride` binary(1) NOT NULL,
+  `teacherdeletable` binary(1) NOT NULL,
+  PRIMARY KEY  (`id`),
+  UNIQUE KEY `id` (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=87 ;
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `mdl_groups_groupings_groups`
+-- 
+
+CREATE TABLE `mdl_groups_groupings_groups` (
+  `id` int(10) unsigned NOT NULL auto_increment,
+  `groupingid` int(10) unsigned default '0',
+  `groupid` int(10) NOT NULL,
+  `timecreated` int(10) unsigned NOT NULL default '0',
+  PRIMARY KEY  (`id`),
+  UNIQUE KEY `id` (`id`),
+  KEY `courseid` (`groupingid`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=67 ;
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `mdl_groups_groups`
+-- 
+
+CREATE TABLE `mdl_groups_groups` (
+  `id` int(10) unsigned NOT NULL auto_increment,
+  `name` varchar(254) character set latin1 collate latin1_general_ci NOT NULL default '',
+  `description` text character set latin1 collate latin1_general_ci NOT NULL,
+  `enrolmentkey` varchar(50) character set latin1 collate latin1_general_ci NOT NULL default '',
+  `lang` varchar(10) character set latin1 collate latin1_general_ci NOT NULL default 'en',
+  `theme` varchar(50) character set latin1 collate latin1_general_ci NOT NULL default '',
+  `picture` int(10) unsigned NOT NULL default '0',
+  `hidepicture` int(1) unsigned NOT NULL default '0',
+  `timecreated` int(10) unsigned NOT NULL default '0',
+  `timemodified` int(10) unsigned NOT NULL default '0',
+  PRIMARY KEY  (`id`),
+  UNIQUE KEY `id` (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=132 ;
+
+-- --------------------------------------------------------
+
+-- 
+-- Table structure for table `mdl_groups_groups_users`
+-- 
+
+CREATE TABLE `mdl_groups_groups_users` (
+  `id` int(10) unsigned NOT NULL auto_increment,
+  `groupid` int(10) unsigned NOT NULL default '0',
+  `userid` int(10) unsigned NOT NULL default '0',
+  `timeadded` int(10) unsigned NOT NULL default '0',
+  PRIMARY KEY  (`id`),
+  UNIQUE KEY `id` (`id`),
+  KEY `groupid` (`groupid`),
+  KEY `userid` (`userid`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=175 ;
diff --git a/group/lib/automaticgroupinglib.php b/group/lib/automaticgroupinglib.php
new file mode 100644 (file)
index 0000000..7158436
--- /dev/null
@@ -0,0 +1,250 @@
+<?PHP  
+
+/************************************
+ * Automatic group generataion
+ ************************************/
+ // @@@ TO DO - Some of this code could be simplified a lot I realised 
+ // after I wrote it and got it working! 
+/**
+ * Seeds the random number generator used by groups_create_automatic_grouping. 
+ * This must be called before using groups_create_automatic_grouping and should 
+ * only be called once in each script even if you are calling 
+ * groups_create_automatic_grouping more than once.
+ */ 
+function groups_seed_random_number_generator() { 
+       $seed = (double)microtime()*1234567 ;
+       srand($seed);
+}
+
+/**
+ * Distributes students into groups randomly and creates a grouping with those 
+ * groups.
+ * 
+ * You need to call groups_seed_random_number_generator() at some point in your 
+ * script before calling this function. 
+ * 
+ * Note that this function does not distribute teachers into groups - this still 
+ * needs to be done manually. 
+ * 
+ * @param int $courseid The id of the course that the grouping should belong to
+ * @param int $nostudentspergroup The number of students to put in each group - 
+ * this can be set to false if you prefer to specify the number of groups 
+ * instead
+ * @param int $nogroups The number of groups - this can be set to false if you 
+ * prefer to specify the number of student in each group. If both are specified 
+ * then $nostudentspergroup takes precedence. If neither is
+ * specified then the function does nothing and returns false. 
+ * @param boolean $distribevenly If $noofstudentspergroup is specified, then 
+ * if this is set to true, any leftover students are distributed evenly among 
+ * the groups, whereas if it is set to false then they are put in a separate 
+ * group. 
+ * @param object $groupsettings The default settings to give each group. 
+ * This should contain prefix and defaultgroupdescription fields. The groups 
+ * are named with the prefix followed by 1, 2, etc. and given the
+ * default group description set. 
+ * @param int $groupid If this is not set to false, then only students in the 
+ * specified group are distributed into groups, not all the students enrolled on 
+ * the course. 
+ * @param boolean $alphabetical If this is set to true, then the students are 
+ * not distributed randomly but in alphabetical order of last name. 
+ * @return int The id of the grouping
+ */
+function groups_create_automatic_grouping($courseid, $nostudentspergroup, 
+                                          $nogroups, $distribevenly, 
+                                          $groupingsettings, 
+                                          $groupid = false, 
+                                          $alphabetical = false) {
+       
+       if (!$nostudentspergroup and !$noteacherspergroup and !$nogroups) {
+               $groupingid = false;
+       } else {
+               // Set $userids to the list of students that we want to put into groups 
+               // in the grouping
+               if (!$groupid) {
+                       $users = get_course_students($courseid);
+               $userids = groups_users_to_userids($users); 
+               } else {
+                       $userids = groups_get_members($groupid);
+               }
+               
+               // Distribute the users into sets according to the parameters specified    
+           $userarrays = groups_distribute_in_random_sets($userids, 
+                   $nostudentspergroup, $nogroups, $distribevenly, !$alphabetical);  
+
+           if (!$userarrays) {
+               $groupingid = false;
+           } else { 
+               // Create the grouping that the groups we create will go into   
+               $groupingid = groups_create_grouping($courseid, $groupingsettings);
+                                                         
+               // Get the prefix for the names of each group and default group 
+               // description to give each group
+               if (!$groupingsettings->prefix) {
+                       $prefix = get_string('defaultgroupprefix', 'groups');
+               } else {
+                       $prefix = $groupingsettings->prefix;
+               }
+               
+               if (!$groupingsettings->defaultgroupdescription) {
+                       $defaultgroupdescription = '';
+               } else {
+                       $defaultgroupdescription = $groupingsettings->defaultgroupdescription;
+               }
+               
+               // Now create a group for each set of students, add the group to the 
+               // grouping and then add the students   
+               $i = 1;
+                   foreach ($userarrays as $userids) {
+                       $groupsettings->name = $prefix.' '.$i;
+                       $groupsettings->description = $defaultgroupdescription;
+                       $i++;
+                       $groupid = groups_create_group($courseid, $groupsettings);
+                       $groupadded = groups_add_group_to_grouping($groupid, 
+                                                                  $groupingid);
+                       if (!$groupid or !$groupadded) {
+                               $groupingid = false;
+                       } else {
+                                       if ($userids) {
+                                               foreach($userids as $userid) {
+                                               $usersadded = groups_add_member($userid, $groupid);
+                                                       // If unsuccessful just carry on I guess
+                                               }
+                                       }
+                       }
+                   }
+           }
+       }
+    return $groupingid;
+}
+
+
+/**
+ * Takes an array and a set size, puts the elements of the array into an array 
+ * of arrays of size $setsize randomly. 
+ * @param array $array The array to distribute into random sets
+ * @param int $setsize The size of each set - this can be set to false, if you 
+ * would prefer to specify the number of sets.  
+ * @param int $nosets The number of sets - this can be set to false if you would 
+ * prefer to specify the setsize. 
+ * If both $setsize and $nosets are set then $setsize takes precedence. If both 
+ * are set to false then the function does nothing and returns false.  
+ * @param $distribevenly boolean Determines how extra elements are distributed 
+ * if $setsize doesn't divide exactly into the number of elements if $setsize is 
+ * specified. If it is true then extra elements will be distributed evenly 
+ * amongst the sets, whereas if it is set to false then the remaining elements 
+ * will be put into a separate set. 
+ * @param boolean $randomise If this is true then the elements of array will be 
+ * put into the arrays in a random order, otherwise they will be put into the 
+ * array in the same order as the original array. 
+ * @return array The array of arrays of elements generated. 
+ */
+function groups_distribute_in_random_sets($array, $setsize, $nosets, 
+                                          $distribevenly = true, 
+                                          $randomise = true) {
+    $noelements = count($array);    
+       
+       // Create a list of the numbers 1,..., $noelements, in either random order 
+       // or in numerical order depending on whether $randomise has been set.    
+    if ($randomise) {
+               $orderarray = groups_random_list($noelements);
+    } else {
+       // Just create the array (1,2,3,....)
+       $orderarray = array();
+       for($i = 0; $i < $noelements; $i++) {
+               array_push($orderarray, $i);
+       }       
+    }
+    
+    // Now use the ordering in $orderarray to generate the new arrays
+    $arrayofrandomsets = array(); // 
+
+    for ($i = 0; $i < $noelements; $i++) {      
+       $arrayofrandomsets[$arrayno][$i] = $array[$orderarray[$i]];
+        if (groups_last_element_in_set($noelements, $setsize, $nosets, 
+                                       $distribevenly, $i) 
+            and $i != $noelements - 1) {               
+               $arrayno++;
+            $arrayofrandomsets[$arrayno] = array(); 
+       }
+        
+    }
+    
+    return  $arrayofrandomsets;
+}
+
+/**
+ * Returns an array of the numbers 0,..,$size - 1 in random order 
+ * @param int $size the number of numbers to return in a random order 
+ * @return array The array of numbers in a random order
+ */
+function groups_random_list($size) {
+       $orderarray = array();
+    $noelementsset = 0;
+    while($noelementsset != $size) {
+        $newelement = rand() % $size;
+        // If the array doesn't already contain the element, add it.
+        if (array_search($newelement, $orderarray) === false) {
+            array_push($orderarray, $newelement);
+            $noelementsset++;
+        }
+    }
+
+    return $orderarray;
+}
+
+/**
+ * A helper function for groups_distribute_in_random_sets(). 
+ * When distributing elements into sets, determines if a given element is the 
+ * last element in the set. 
+ * @param int $totalnoelements The total number of elements being distributed. 
+ * @param int $setsize See groups_distribute_in_random_sets()
+ * @param int $nosets See groups_distribute_in_random_sets()
+ * @param boolean $distribevenly  See groups_distribute_in_random_sets()
+ * @param int $elementno The element number that we are considering i.e. if this 
+ * is the 15th element then this would be 15. 
+ * @return boolean True if the element under consideration would be the last 
+ * element in the set, fals otherwise. 
+ */
+function groups_last_element_in_set($totalnoelements, $setsize, $nosets, 
+                                    $distribevenly, $elementno) {
+       $lastelement = false;
+       $elementno = $elementno + 1; // Counting from zero is just too confusing! 
+       
+       // If $nosets has been specified, make sure $setsize is set to the right 
+       // value, so that we can treat the two cases identically. Then work out how 
+       // many extra elements will be left over. 
+       if (!$setsize) {
+               $setsize = floor($totalnoelements / $nosets);
+               $noextra = $totalnoelements % $nosets;
+       } else {
+               $noextra = $totalnoelements % $setsize;
+       }
+       
+    if (!$distribevenly) {
+       // If we're putting our extra elements in a set at the end, everything 
+       // is easy!
+       if ($elementno % $setsize == 0) {
+               $lastelement = true;
+       }
+    } else {
+       // Work out the number of elements that will be in the bigger sets that 
+       // have the leftover elements in 
+       // them.
+       $noinbiggersets = $noextra * ($setsize + 1);
+       // Work out if this element is a last element in a set or not - we need 
+       // to separate the case where the element is one of the ones that goes 
+       // into the bigger sets at the beginning 
+       // and the case where it's one of the elements in the normal sized sets. 
+       if (($elementno <= $noinbiggersets and $elementno % ($setsize + 1) == 0) 
+           or ($elementno > $noinbiggersets  and 
+           ($elementno - $noinbiggersets ) % $setsize == 0) ) {
+               $lastelement = true;
+       }
+    }  
+
+    return $lastelement;
+}
+?>
\ No newline at end of file
diff --git a/group/lib/basicgrouplib.php b/group/lib/basicgrouplib.php
new file mode 100644 (file)
index 0000000..e46030d
--- /dev/null
@@ -0,0 +1,312 @@
+<?PHP  
+/*******************************************************************************
+ * Library of basic group functions. 
+ * 
+ * These functions are essentially just wrappers for the equivalent database
+ * functions in db/dbgrouplib.php
+ * 
+ * It is advised that you do not create groups that do not belong to a grouping, 
+ * although to allow maximum 
+ * flexibility, functions are provided that allow you to do this. 
+ * Note that groups (and groupings - see groupinglib.php) must belong to a 
+ * course. There is no reason why
+ * a group cannot belong to more than one course, although this might cause 
+ * problems when group members are not
+ * users of one of the courses. 
+ * At the moment, there are no checks that group members are also users of a 
+ * course.  
+ ******************************************************************************/
+
+include_once($CFG->dirroot.'/course/groups/db/dbbasicgrouplib.php');
+
+
+/***************************** 
+    List functions  
+ *****************************/
+
+/**
+ * Gets a list of the group ids for a specified course id 
+ * @param int $courseid The id of the course. 
+ * @return array | false Returns an array of the userids or false if no records
+ * or an error occurred. 
+ */
+function groups_get_groups($courseid) {
+       $groupids = groups_db_get_groups($courseid);
+    return $groupids;
+}
+
+
+/**
+ * Returns the ids of the users in the specified group.
+ * @param int $groupid The groupid to get the users for
+ * @param string $membertype Either 'student', 'teacher' or false. The function 
+ * only returns these
+ * types of group members. If set to false, returns all group members. 
+ * @return array | false Returns an array of the user ids for the specified
+ * group or false if no users or an error returned.
+ */
+function groups_get_members($groupid, $membertype = false) {
+       $userids = groups_db_get_members($groupid);
+    return $userids;
+}
+
+
+/**
+ * Gets the groups to which a user belongs for a specified course. 
+ * @param int $userid The id of the specified user
+ * @param int $courseid The id of the course.
+ * @param boolean $usedatabase. If true, gets the information from  
+ * @return array | false An array of the group ids of the groups to which the
+ * user belongs or false if there are no groups or an error occurred.
+ */
+function groups_get_groups_for_user($userid, $courseid) {  
+    $groupids = groups_db_get_groups_for_user($userid, $courseid);
+    return $groupids;
+}
+
+/**
+ * Gets the groups for the current user and specified course 
+ * @param int $courseid The id of the course
+ * @param int $usedatabase Set to true if the information is to be obtained 
+ * directly
+ * from the database, false if it is to be obtained from the $USER object. 
+ * @return array An array of the groupids. 
+ */
+function groups_get_groups_for_current_user($courseid) {
+       global $USER;
+       $groupids = groups_get_groups_for_user($USER->id, $courseid);
+       return $groupids;
+}
+
+
+/**
+ * Get the group settings object for a group - this contains the following 
+ * properties:
+ * name, description, lang, theme, picture, hidepicture
+ * @param int $groupid The id of the gruop
+ * @return object The group settings object 
+ */
+function groups_get_group_settings($groupid) {
+       return groups_db_get_group_settings($groupid);
+}
+
+/**
+ * Gets the path where the image for a particular group can be found (if it 
+ * exists)
+ * @param int $groupid The id of the group
+ * @return string The path of the image for the group
+ */
+function groups_get_group_image_path($groupid) {
+       return $CFG->dataroot.'/groups/'.$groupid.'/'.$image;
+}
+
+/**
+ * Gets the name of a group with a specified id
+ * @param int $groupid The id of the group
+ * @return string The name of the group
+ */
+function groups_get_group_name($groupid) {
+       $settings = groups_get_group_settings($groupid);
+       return $settings->name;
+}
+
+/**
+ * Gets the users for a course who are not in a specified group
+ * @param int $groupid The id of the group
+ * @return array An array of the userids of the non-group members,  or false if 
+ * an error occurred. 
+ */
+function groups_get_users_not_in_group($courseid, $groupid) {
+       $users = get_course_users($courseid);
+    $userids = groups_users_to_userids($users);   
+    $nongroupmembers = array();
+    
+    foreach($userids as $userid) {     
+       if (!groups_is_member($groupid, $userid)) {
+               array_push($nongroupmembers, $userid);
+       }
+    }
+
+    return $nongroupmembers;
+}
+
+/**
+ * Given two users, determines if there exists a group to which they both belong
+ * @param int $userid1 The id of the first user
+ * @param int $userid2 The id of the second user
+ * @return boolean True if the users are in a common group, false otherwise or 
+ * if an error occurred. 
+ */
+function groups_users_in_common_group($userid1, $userid2) {
+       return groups_db_users_in_common_group($userid1, $userid1); 
+}
+
+
+
+
+
+/*****************************
+   Membership functions 
+ *****************************/
+
+
+/**
+ * Determines if a group with a given groupid exists. 
+ * @param int $groupid The groupid to check for
+ * @return boolean True if the group exists, false otherwise or if an error 
+ * occurred. 
+ */
+function groups_group_exists($groupid) {
+       return groups_db_group_exists($groupid);
+}
+
+/**
+ * Determines if a specified user is a member of a specified group
+ * @param int $groupid The group about which the request has been made
+ * @param int $userid The user about which the request has been made
+ * @return boolean True if the user is a member of the group, false otherwise
+ */
+ function groups_is_member($groupid, $userid) { 
+       $ismember = groups_db_is_member($groupid, $userid);
+       return $ismember;
+}
+
+
+/**
+ * Determines if a specified group is a group for a specified course
+ * @param int $groupid The group about which the request has been made
+ * @param int $courseid The course for which the request has been made
+ * @return boolean True if the group belongs to the course, false otherwise
+ */
+function groups_group_belongs_to_course($groupid, $courseid) {
+    $belongstocourse = groups_db_group_belongs_to_course($groupid, $courseid);
+    return $belongstocourse;
+}
+
+/**
+ * Returns an object with the default group info values - these can of course be 
+ * overridden if desired.
+ * Can also be used to set the default for any values not set
+ * @return object The group info object. 
+ */
+function groups_set_default_group_settings($groupinfo = null) {
+        
+    if (!isset($groupinfo->name)) {
+        $groupinfo->name = 'Temporary Group Name';
+    }
+    
+    if (!isset($groupinfo->description)) {
+        $groupinfo->description = '';
+    }
+   
+    if (!isset($groupinfo->lang)) {
+        $groupinfo->lang = current_language();
+    }
+    
+    if (!isset($groupinfo->theme)) {
+        $groupinfo->theme = '';
+    }
+    
+    if (!isset($groupinfo->picture)) {
+        $groupinfo->picture = '';
+    }
+
+    if (!isset($groupinfo->hidepicture)) {
+        $groupinfo->hidepicture = '1';
+    }
+    
+    if (isset($groupinfo->hidepicture)) {
+       if ($groupinfo->hidepicture != '0' and $groupinfo->hidepicture != '1') {
+               $groupinfo->hidepicture = '1';
+       }
+    }
+
+       return $groupinfo;
+}
+
+/***************************** 
+      Creation functions  
+ *****************************/
+
+/**
+ * Creates a group for a specified course
+ * All groups should really belong to a grouping (though there is nothing in 
+ * this API that stops them not doing
+ * so, to allow plenty of flexibility) so you should be using this in 
+ * conjunction with the function to add a group to
+ *  a grouping. 
+ * @param int $courseid The course to create the group for
+ * @return int | false The id of the group created or false if the group was
+ * not created successfully. 
+ * See comment above on web service autoupdating. 
+ */
+function groups_create_group($courseid, $groupsettings = false) {      
+       return groups_db_create_group($courseid, $groupsettings);
+}
+
+
+/**
+ * Sets the information about a group
+ * Only sets the string for the picture - does not upload the picture! 
+ * @param object $groupsettings An object containing some or all of the 
+ * following properties: name, description, lang, theme, picture, hidepicture
+ * @return boolean True if info was added successfully, false otherwise. 
+ */
+function groups_set_group_settings($groupid, $groupsettings) { 
+       return  groups_db_set_group_settings($groupid, $groupsettings);
+}
+
+
+/**
+ * Adds a specified user to a group
+ * @param int $groupid  The group id
+ * @param int $userid   The user id
+ * @return boolean True if user added successfully or the user is already a 
+ * member of the group, false otherwise. 
+ * See comment above on web service autoupdating. 
+ */
+function groups_add_member($userid, $groupid) {
+       $useradded = false;
+    
+    $alreadymember = groups_is_member($groupid, $userid);
+    if (!groups_group_exists($groupid)) {
+       $useradded = false;
+    } elseif ($alreadymember) {
+       $useradded = true;
+    } else {
+               $useradded = groups_db_add_member($userid, $groupid);
+    }
+
+       return $useradded;
+}
+
+
+/*****************************
+        Deletion functions  
+ *****************************/
+
+
+/**
+ * Deletes a group best effort
+ * @param int $groupid The group to delete
+ * @return boolean True if deletion was successful, false otherwise
+ * See comment above on web service autoupdating. 
+ */
+function groups_delete_group($groupid) {
+       $groupdeleted = groups_db_delete_group($groupid);
+
+    return $groupdeleted;
+}
+
+
+/**
+ * Deletes the specified user from the specified group
+ * @param int $userid The user to delete
+ * @param int $groupid The group to delete the user from
+ * @return boolean True if deletion was successful, false otherwise
+ * See comment above on web service autoupdating. 
+ */
+function groups_remove_member($userid, $groupid) {
+       return  groups_db_remove_member($userid, $groupid);
+}
+?>
\ No newline at end of file
diff --git a/group/lib/courselib.php b/group/lib/courselib.php
new file mode 100644 (file)
index 0000000..b257b56
--- /dev/null
@@ -0,0 +1,12 @@
+<?php
+// @@@ TO DO 
+function groups_get_forced_grouping($courseid) {
+}
+
+function groups_set_forced_grouping($courseid, $groupingid) {
+}
+
+function groups_course_print_group_selector($userid, $courseid, $permissiontype) {
+}
+
+?>
diff --git a/group/lib/groupinglib.php b/group/lib/groupinglib.php
new file mode 100644 (file)
index 0000000..b8ebd3f
--- /dev/null
@@ -0,0 +1,347 @@
+<?PHP 
+/******************************************************************************
+ * A grouping is a set of groups that belong to a course. 
+ * There may be any number of groupings for a course and a group may belong to 
+ * more than one grouping.
+ ******************************************************************************/ 
+
+include_once($CFG->dirroot.'/course/groups/lib/basicgrouplib.php');
+include_once($CFG->dirroot.'/course/groups/db/dbgroupinglib.php');
+
+/*****************************
+        Access/List functions  
+ *****************************/
+
+
+
+/**
+ * Gets a list of the groupings for a specified course
+ * @param int $courseid The id of the course
+ * @return array | false An array of the ids of the groupings, or false if there 
+ * are none or there was an error. 
+ */
+function groups_get_groupings($courseid) {
+    return groups_db_get_groupings($courseid);
+}
+
+
+/**
+ * Gets a list of the groups in a specified grouping
+ * @param int $groupingid The id of the grouping
+ * @return array | false. An array of the ids of the groups, or false if there
+ * are none or an error occurred.
+ */
+function groups_get_groups_in_grouping($groupingid) {
+    return groups_db_get_groups_in_grouping($groupingid);
+}
+
+/** 
+ * Gets the groupings that a group belongs to 
+ * @param int $groupid The id of the group
+ * @return array An array of the ids of the groupings that the group belongs to, 
+ * or false if there are none or if an error occurred. 
+ */
+function groups_get_groupings_for_group($groupid) {
+       return groups_db_get_groupings_for_group($groupid);
+}
+
+/**
+ * Gets the information about a specified grouping
+ * @param int $groupingid
+ * @return object The grouping settings object - properties are name and 
+ * description. 
+ */
+function groups_get_grouping_settings($groupingid) {
+       return groups_db_get_grouping_settings($groupingid);
+}
+
+/**
+ * Set information about a grouping
+ * @param int $groupingid The grouping to update the info for.
+ * @param object $groupingsettings 
+ */
+function groups_set_grouping_settings($groupingid, $groupingsettings) {
+       return groups_db_set_grouping_settings($groupingid, $groupingsettings);
+}
+
+// TO DO 
+function groups_get_groups_for_user_in_grouping($userid, $groupingid) {
+}
+
+/**
+ * Gets a list of the groups not a specified grouping
+ * @param int $groupingid The grouping specified
+ * @return array An array of the group ids
+ */
+function groups_get_groups_not_in_grouping($groupingid, $courseid) {
+    $allgroupids = groups_get_groups($courseid);
+    $groupids = array();
+    foreach($allgroupids as $groupid) {
+        if (!groups_belongs_to_grouping($groupid, $groupingid)) {
+            array_push($groupids, $groupid);
+        }
+    }
+    return $groupids;
+}
+
+/**
+ * Gets the users for the course who are not in any group of a grouping.
+ * @param int $courseid The id of the course
+ * @param int $groupingid The id of the grouping
+ * @param int $groupid Excludes members of a particular group
+ * @return array An array of the userids of the users not in any group of 
+ * the grouping or false if an error occurred. 
+ */
+function groups_get_users_not_in_any_group_in_grouping($courseid, $groupingid, 
+                                                       $groupid = false) {
+       $users = get_course_users($courseid);
+    $userids = groups_users_to_userids($users); 
+    $nongroupmembers = array();
+    if ($userids) {
+           foreach($userids as $userid) {
+               if (!groups_is_member_of_some_group_in_grouping($userid, 
+                                                               $groupingid)) {
+                       // If a group has been specified don't include members of that 
+                       // group
+                       if ($groupid  and !groups_is_member($userid, $groupid)) {
+                       array_push($nongroupmembers, $userid);
+                       } else {
+                               array_push($nongroupmembers, $userid);
+                       }
+               }
+           }
+    }
+    return $nongroupmembers;
+}
+
+
+/**
+ * Determines if a user is in more than one group in a grouping
+ * @param int $userid The id of the user
+ * @param int $groupingid The id of the grouping
+ * @return boolean True if the user is in more than one group, false otherwise 
+ * or if an error occurred. 
+ */
+function groups_user_is_in_multiple_groups($userid, $groupingid) {
+       $inmultiplegroups = false;
+       $groupids = groups_get_groups_for_user($courseid);
+       if ($groupids != false) {
+               $groupinggroupids = array();
+               foreach($groupids as $groupid) {
+                       if (groups_belongs_to_grouping($groupid, $groupingid)) {
+                               array_push($groupinggroupids, $groupid);
+                       }
+               }
+               
+               if (count($groupinggroupids) > 1) {
+                       $inmultiplegroups = true;
+               }
+       }
+       
+       return $inmultiplegroups;
+}
+
+
+/**
+ * Returns an object with the default grouping settings values - these can of 
+ * course be overridden if desired.
+ * Can also be used to set the default for any values not set
+ * @return object The grouping settings object. 
+ */
+function groups_set_default_grouping_settings($groupingsettings = null) {
+        
+    if (!isset($groupingsettings->name)) {
+        $groupingsettings->name = 'Temporary Grouping Name';
+    }
+    
+    if (!isset($groupingsettings->description)) {
+        $groupingsettings->description = '';
+    }
+    
+    if (!isset($groupsettings->viewowngroup)) {
+       $groupsettings->viewowngroup = 1;
+    }
+    
+    if (!isset($groupsettings->viewgroupsmembers)) {
+       $groupsettings->viewgroupsmembers = 0;
+    }
+    
+    if (!isset($groupsettings->viewgroupsactivities)) {
+       $groupsettings->viewgroupsactivities = 0;
+    }
+    
+    if (!isset($groupsettings->teachersgroupmark)) {
+       $groupsettings->teachersgroupmark = 0;
+    }  
+    
+    if (!isset($groupsettings->teachersgroupview)) {
+       $groupsettings->teachersgroupview = 0;
+    }               
+    
+    if (!isset($groupsettings->teachersoverride)) {
+       $groupsettings->teachersoverride = 1;
+    }  
+    
+       return $groupingsettings;
+}
+
+
+/**
+ * Gets the grouping to use for a particular instance of a module in a course
+ * @param int $coursemoduleid The id of the instance of the module in the course
+ * @return int The id of the grouping or false if there is no such id recorded 
+ * or if an error occurred. 
+ */
+function groups_get_grouping_for_coursemodule($coursemoduleid) {
+       return groups_db_get_grouping_for_coursemodule($coursemoduleid);
+}
+
+/*****************************
+        Membership functions  
+ *****************************/
+
+
+/**
+ * Determines if a grouping with a specified id exists
+ * @param int $groupingid The grouping id. 
+ * @return True if the grouping exists, false otherwise or if an error occurred. 
+ */  
+function groups_grouping_exists($groupingid) {
+       return groups_db_grouping_exists($groupingid);
+}
+ /**
+  * Determines if a group belongs to a specified grouping
+  * @param int $groupid The id of the group
+  * @param int $groupingid The id of the grouping
+  * @return boolean. True if the group belongs to a grouping, false otherwise or
+  * if an error has occurred.
+  */
+ function groups_belongs_to_grouping($groupid, $groupingid) {
+     return groups_db_belongs_to_grouping($groupid, $groupingid);
+ }
+
+ /**
+  * Detemines if a specified user belongs to any group of a specified grouping.
+  * @param int $userid The id of the user
+  * @param int $groupingid The id of the grouping
+  * @return boolean True if the user belongs to some group in the grouping,
+  * false otherwise or if an error occurred. 
+  */
+ function groups_is_member_of_some_group_in_grouping($userid, $groupingid) {
+     return groups_db_is_member_of_some_group_in_grouping($userid, $groupingid);
+ }
+ /** 
+  * Determines if a grouping belongs to a specified course
+  * @param int $groupingid The id of the grouping
+  * @param int $courseid The id of the course
+  * @return boolean True if the grouping belongs to the course, false otherwise, 
+  * or if an error occurred. 
+  */
+ function groups_grouping_belongs_to_course($groupingid, $courseid) {
+       return groups_db_grouping_belongs_to_course($groupingid, $courseid);
+ }
+
+
+/*****************************
+        Creation functions  
+ *****************************/
+
+
+/**
+ * Marks a set of groups as a grouping. This is a best effort operation.
+ * It can also be used to create an 'empty' grouping to which
+ * groups can be added by passing an empty array for the group ids.
+ * @param array $groupids An array of the ids of the groups to marks as a
+ * grouping. 
+ * @param int $courseid The id of the course for which the groups should form
+ * a grouping
+ * @return int | false The id of the grouping, or false if an error occurred. 
+ * Also returns false if any of the groups specified do not belong to the 
+ * course. 
+ */
+function groups_create_grouping($courseid, $groupingsettings = false) {
+    $groupingid = groups_db_create_grouping($courseid, $groupingsettings);
+
+    return $groupingid;
+}
+
+
+/**
+ * Adds a specified group to a specified grouping.
+ * @param int $groupid The id of the group
+ * @param int $groupingid The id of the grouping
+ * @return boolean True if the group was added successfully or the group already 
+ * belonged to the grouping, false otherwise. Also returns false if the group 
+ * doesn't belong to the same course as the grouping. 
+ */
+function groups_add_group_to_grouping($groupid, $groupingid) {
+       $belongstogrouping = groups_belongs_to_grouping($groupid, $groupingid);
+       if (!groups_grouping_exists($groupingid)) {
+               $groupadded = false;
+       } elseif (!$belongstogrouping) {
+               $groupadded = groups_db_add_group_to_grouping($groupid, $groupingid); 
+       } else {
+               $groupadded = true;
+       }
+               
+    return $groupadded;  
+}
+
+
+/**
+ * Sets the name of a grouping overwriting any current name that the grouping 
+ * has
+ * @param int $groupingid The id of the grouping specified
+ * @param string $name The name to give the grouping
+ * @return boolean True if the grouping settings was added successfully, false 
+ * otherwise.
+ */
+function groups_set_grouping_name($groupingid, $name) {
+    return groups_db_set_grouping_name($groupingid, $name);
+}
+
+
+
+/**
+ * Sets a grouping to use for a particular instance of a module in a course
+ * @param int $groupingid The id of the grouping
+ * @param int $coursemoduleid The id of the instance of the module in the course
+ * @return boolean True if the operation was successful, false otherwise
+ */
+function groups_set_grouping_for_coursemodule($groupingid, $coursemoduleid) {
+       return groups_db_set_grouping_for_coursemodule($groupingid, 
+                                                      $coursemoduleid);
+}
+
+
+/*****************************
+        Deletion functions  
+ *****************************/
+
+/** 
+ * Removes a specified group from a specified grouping. Note that this does 
+ * not delete the group. 
+ * @param int $groupid The id of the group.
+ * @param int $groupingid The id of the grouping
+ * @return boolean True if the deletion was successful, false otherwise. 
+ */
+function groups_remove_group_from_grouping($groupid, $groupingid) {
+    return groups_db_remove_group_from_grouping($groupid, $groupingid);
+}
+
+/** 
+ * Removes a grouping from a course - note that this function does not delete 
+ * any of the groups in the grouping. 
+ * @param int $groupingid The id of the grouping
+ * @return boolean True if the deletion was successful, false otherwise.
+ */ 
+function groups_delete_grouping($groupingid) {
+    return groups_db_delete_grouping($groupingid);
+    
+}
+?>
\ No newline at end of file
diff --git a/group/lib/legacylib.php b/group/lib/legacylib.php
new file mode 100644 (file)
index 0000000..cb3a035
--- /dev/null
@@ -0,0 +1,380 @@
+<?php
+
+// @@@ Don't look at this file - still tons to do! 
+/**
+ * Returns the groupid of a group with the name specified for the course 
+ * specified. If there's more than one with the name specified it returns the 
+ * first one it finds it the database, so you need to be careful how you use it! 
+ * This is needed to support upload of users into the database
+ * @param int $courseid The id of the course
+ * @param string $groupname
+ * @return int $groupname
+ */
+function groups_get_group_by_name($courseid, $groupname) {
+       // TO DO                                 
+}
+
+/**
+ * Returns an array of group objects that the user is a member of
+ * in the given course.  If userid isn't specified, then return a
+ * list of all groups in the course.
+ *
+ * @uses $CFG
+ * @param int $courseid The id of the course in question.
+ * @param int $userid The id of the user in question as found in the 'user' 
+ * table 'id' field.
+ * @return object
+ */
+function get_groups($courseid, $userid=0) {
+       if ($userid) {
+               $groupids = groups_get_groups_for_user($userid, $courseid);
+       } else {
+               $groupids = groups_get_groups($courseid);
+       }
+       
+       return groups_groupids_to_groups($groupids);
+}
+
+
+/**
+ * Returns the user's group in a particular course
+ *
+ * @uses $CFG
+ * @param int $courseid The course in question.
+ * @param int $userid The id of the user as found in the 'user' table.
+ * @param int $groupid The id of the group the user is in.
+ * @return object
+ */
+function user_group($courseid, $userid) {
+    $groupids = groups_get_groups_for_user($userid, $courseid);
+    return groups_groupids_to_groups($groupids);
+}
+
+
+/**
+ * Determines if the user a member of the given group
+ *
+ * @uses $USER
+ * @param int $groupid The group to check the membership of
+ * @param int $userid The user to check against the group
+ * @return bool
+ */
+function ismember($groupid, $userid=0) {
+       if (!$userid) {
+       }
+       return groups_is_member($groupid, $userid);
+}
+
+/**
+ * Returns an array of user objects
+ *
+ * @uses $CFG
+ * @param int $groupid The group in question.
+ * @param string $sort ?
+ * @param string $exceptions ?
+ * @return object
+ * @todo Finish documenting this function
+ */
+function get_group_users($groupid, $sort='u.lastaccess DESC', $exceptions='', 
+                         $fields='u.*') {
+    global $CFG;
+    if (!empty($exceptions)) {
+        $except = ' AND u.id NOT IN ('. $exceptions .') ';
+    } else {
+        $except = '';
+    }
+    // in postgres, you can't have things in sort that aren't in the select, so...
+    $extrafield = str_replace('ASC','',$sort);
+    $extrafield = str_replace('DESC','',$extrafield);
+    $extrafield = trim($extrafield);
+    if (!empty($extrafield)) {
+        $extrafield = ','.$extrafield;
+    }
+    return get_records_sql("SELECT DISTINCT $fields $extrafield
+                              FROM {$CFG->prefix}user u,
+                                   {$CFG->prefix}groups_members m
+                             WHERE m.groupid = '$groupid'
+                               AND m.userid = u.id $except
+                          ORDER BY $sort");
+}
+
+
+
+/**
+ * Returns an array of user objects
+ *
+ * @uses $CFG
+ * @param int $groupid The group(s) in question.
+ * @param string $sort How to sort the results
+ * @return object (changed to groupids)
+ */
+function get_group_students($groupids, $sort='u.lastaccess DESC') {
+
+    global $CFG;
+
+    if (is_array($groupids)){
+        $groups = $groupids;
+        $groupstr = '(m.groupid = '.array_shift($groups);
+        foreach ($groups as $index => $value){
+            $groupstr .= ' OR m.groupid = '.$value;
+        }
+        $groupstr .= ')';
+    }
+    else {
+        $groupstr = 'm.groupid = '.$groupids;
+    }
+
+    return get_records_sql("SELECT DISTINCT u.*
+                              FROM {$CFG->prefix}user u,
+                                   {$CFG->prefix}groups_members m,
+                                   {$CFG->prefix}groups g,
+                                   {$CFG->prefix}user_students s
+                             WHERE $groupstr
+                               AND m.userid = u.id
+                               AND m.groupid = g.id
+                               AND g.courseid = s.course
+                               AND s.userid = u.id
+                          ORDER BY $sort");
+}
+
+/**
+ * Returns list of all the teachers who can access a group
+ *
+ * @uses $CFG
+ * @param int $courseid The course in question.
+ * @param int $groupid The group in question.
+ * @return object
+ */
+function get_group_teachers($courseid, $groupid) {
+/// Returns a list of all the teachers who can access a group
+    if ($teachers = get_course_teachers($courseid)) {
+        foreach ($teachers as $key => $teacher) {
+            if ($teacher->editall) {             // These can access anything
+                continue;
+            }
+            if (($teacher->authority > 0) and ismember($groupid, $teacher->id)) 
+            {  // Specific group teachers
+                continue;
+            }
+            unset($teachers[$key]);
+        }
+    }
+    return $teachers;
+}
+
+
+/**
+ * Add a user to a group, return true upon success or if user already a group 
+ * member
+ *
+ * @param int $groupid  The group id to add user to
+ * @param int $userid   The user id to add to the group
+ * @return bool
+ */
+function add_user_to_group ($groupid, $userid) {
+    return groups_add_member($userid, $groupid) ;
+}
+
+
+/**
+ * Get the group ID of the current user in the given course
+ *
+ * @uses $USER
+ * @param int $courseid The course being examined - relates to id field in 
+ * 'course' table.
+ * @return array An array of the groupids that the user belongs to. 
+ */
+function mygroupid($courseid) {
+       // TO DO - check whether needs to be groups or groupids. 
+       $groupids = groups_get_groups_for_user($USER, $courseid);
+       return $groupids[0];
+}
+
+/**
+ * This now returns either false or SEPARATEGROUPS. If you want VISIBLE GROUPS 
+ * with legacy code, you'll need to upgrade. 
+ */
+function groupmode($course, $cm=null) {
+
+    if ($cm and !$course->groupingid) {
+        return groups_has_groups_setup_for_instance($coursemodule);
+    } else {
+       return groups_has_groups_setup($course->id);
+    }
+}
+
+
+
+
+
+/**
+ * Sets the current group in the session variable
+ * When $SESSION->currentgroup[$courseid] is set to 0 it means, show all groups. 
+ * Sets currentgroup[$courseid] in the session variable appropriately.
+ * Does not do any permission checking. 
+ * @uses $SESSION
+ * @param int $courseid The course being examined - relates to id field in 
+ * 'course' table.
+ * @param int $groupid The group being examined.
+ * @return int Current group id which was set by this function
+ */
+function set_current_group($courseid, $groupid) {
+    global $SESSION;
+    return $SESSION->currentgroup[$courseid] = $groupid;
+}
+
+
+/**
+ * Gets the current group - either from the session variable or from the database. 
+ *
+ * @uses $USER
+ * @uses $SESSION
+ * @param int $courseid The course being examined - relates to id field in 
+ * 'course' table.
+ * @param bool $full If true, the return value is a full record object. 
+ * If false, just the id of the record.
+ */
+function get_current_group($courseid, $full = false) {
+    global $SESSION;
+    
+    if (isset($SESSION->currentgroup[$courseid])) {
+       $currentgroup = $SESSION->currentgroup[$courseid];
+    } else {
+       $currentgroup = mygroupid($courseid);
+    }
+    
+    if ($currentgroup) {
+       $SESSION->currentgroup[$courseid] = mygroupid($courseid);
+    }
+
+    if ($full) {
+        return groups_groupid_to_group($currentgroup);
+    } else {
+        return $currentgroup;
+    }
+}
+
+
+/**
+ * A combination function to make it easier for modules
+ * to set up groups.
+ *
+ * It will use a given "groupid" parameter and try to use
+ * that to reset the current group for the user.
+ *
+ * @uses VISIBLEGROUPS
+ * @param course $course A {@link $COURSE} object
+ * @param int $groupmode Either NOGROUPS, SEPARATEGROUPS or VISIBLEGROUPS
+ * @param int $groupid Will try to use this optional parameter to
+ *            reset the current group for the user
+ * @return int|false Returns the current group id or false if error.
+ */
+function get_and_set_current_group($course, $groupmode, $groupid=-1) {
+       groups_has_permission($userid, $groupingid, $courseid, $groupid, $permissiontype);
+       // Sets to the specified group, provided the current user has view permission 
+    if (!$groupmode) {   // Groups don't even apply
+        return false;
+    }
+
+    $currentgroupid = get_current_group($course->id);
+
+    if ($groupid < 0) {  // No change was specified
+        return $currentgroupid;
+    }
+
+    if ($groupid) {      // Try to change the current group to this groupid
+        if ($group = get_record('groups', 'id', $groupid, 'courseid', $course->id)) { // Exists
+            if (isteacheredit($course->id)) {          // Sets current default group
+                $currentgroupid = set_current_group($course->id, $group->id);
+
+            } else if ($groupmode == VISIBLEGROUPS) {
+                  // All groups are visible
+                //if (ismember($group->id)){
+                    $currentgroupid = set_current_group($course->id, $group->id);//set this since he might post
+                /*)}else {
+                    $currentgroupid = $group->id;*/
+            } else if ($groupmode == SEPARATEGROUPS) { // student in separate groups switching
+                if (ismember($group->id)){//check if is a member
+                    $currentgroupid = set_current_group($course->id, $group->id); //might need to set_current_group?
+                }
+                else {
+                    echo ($group->id);
+                    notify('you do not belong to this group!',error);
+                }
+            }
+        }
+    } else {             // When groupid = 0 it means show ALL groups
+        //this is changed, non editting teacher needs access to group 0 as well, for viewing work in visible groups (need to set current group for multiple pages)
+        if (isteacheredit($course->id) OR (isteacher($course->id) AND ($groupmode == VISIBLEGROUPS))) {          // Sets current default group
+            $currentgroupid = set_current_group($course->id, 0);
+
+        } else if ($groupmode == VISIBLEGROUPS) {  // All groups are visible
+            $currentgroupid = 0;
+        }
+    }
+
+    return $currentgroupid;
+}
+
+
+/**
+ * A big combination function to make it easier for modules
+ * to set up groups.
+ *
+ * Terminates if the current user shouldn't be looking at this group
+ * Otherwise returns the current group if there is one
+ * Otherwise returns false if groups aren't relevant
+ *
+ * @uses SEPARATEGROUPS
+ * @uses VISIBLEGROUPS
+ * @param course $course A {@link $COURSE} object
+ * @param int $groupmode Either NOGROUPS, SEPARATEGROUPS or VISIBLEGROUPS
+ * @param string $urlroot ?
+ * @return int|false
+ */
+function setup_and_print_groups($course, $groupmode, $urlroot) {
+
+    global $USER, $SESSION; //needs his id, need to hack his groups in session
+
+    $changegroup = optional_param('group', -1, PARAM_INT);
+
+    $currentgroup = get_and_set_current_group($course, $groupmode, $changegroup);
+    if ($currentgroup === false) {
+        return false;
+    }
+
+    if ($groupmode == VISIBLEGROUPS or ($groupmode and isteacheredit($course->id))) {
+        groups_instance_print_grouping_selector();
+    }//added code here to allow non-editting teacher to swap in-between his own groups
+    //added code for students in separategrous to swtich groups
+    else if ($groupmode == SEPARATEGROUPS and (isteacher($course->id) or isstudent($course->id))) {
+        groups_instance_print_group_selector();
+    }
+
+    return $currentgroup;
+}
+
+
+
+function oldgroups_print_user_group_info($currentgroup, $isseparategroups, $courseid) {
+       global $CFG;
+           if ($currentgroup and (!$isseparategroups or isteacheredit($courseid))) {    /// Display info about the group
+        if ($group = get_record('groups', 'id', $currentgroup)) {              
+            if (!empty($group->description) or (!empty($group->picture) and empty($group->hidepicture))) { 
+                echo '<table class="groupinfobox"><tr><td class="left side picture">';
+                print_group_picture($group, $course->id, true, false, false);
+                echo '</td><td class="content">';
+                echo '<h3>'.$group->name;
+                if (isteacheredit($courseid)) {
+                    echo '&nbsp;<a title="'.get_string('editgroupprofile').'" href="../course/groups.php?id='.$course->id.'&amp;group='.$group->id.'">';
+                    echo '<img src="'.$CFG->pixpath.'/t/edit.gif" alt="" border="0">';
+                    echo '</a>';
+                }
+                echo '</h3>';
+                echo format_text($group->description);
+                echo '</td></tr></table>';
+            }
+        }
+    }
+}
+?>
diff --git a/group/lib/lib.php b/group/lib/lib.php
new file mode 100644 (file)
index 0000000..7cff573
--- /dev/null
@@ -0,0 +1,10 @@
+<?php
+
+include_once($CFG->dirroot.'/course/groups/lib/basicgrouplib.php');
+
+include_once($CFG->dirroot.'/course/groups/lib/groupinglib.php');
+
+include_once($CFG->dirroot.'/course/groups/lib/utillib.php');
+
+include_once($CFG->dirroot.'/course/groups/lib/automaticgroupinglib.php');
+?>
\ No newline at end of file
diff --git a/group/lib/modulelib.php b/group/lib/modulelib.php
new file mode 100644 (file)
index 0000000..22ec458
--- /dev/null
@@ -0,0 +1,400 @@
+<?php
+
+// @@@ TO DO Still tons to do here! Most of this isn't done or just copied
+// and pasted so far and needs to be sorted out. 
+
+/*******************************************************************************
+ * modulelib.php
+ * 
+ * This file contains functions to be used by modules to support groups. More
+ * documentation is available on the Developer's Notes section of the Moodle 
+ * wiki. 
+ * 
+ * For queries, suggestions for improvements etc. please post on the Groups 
+ * forum on the moodle.org site.
+ ******************************************************************************/
+
+/*******************************************************************************
+ * Permission types
+ * 
+ * There are six types of permission that a user can hold for a particular
+ * group - 'student view', 'student contribute', 'teacher view', 
+ * 'teacher contribute', 'view members list' and 'view group existence'. 
+ * 
+ * A particular user need not to be a member of the group to have a specific 
+ * permission and may have more than one permission type. The permission that a 
+ * particular user has for a group used by an particular instance of the module 
+ * depends on whether the student is a teacher or student for the course and on 
+ * the settings for the set of groups (the 'grouping') being used by the 
+ * instance of the module  
+ * 
+ * It is up to each module to decide how to interpret the different permission 
+ * types. The only exception is with 'view members list' and 'view group 
+ * existence'. The former means that the user can view the members of the group 
+ * while the latter means that the user can view information such as the group 
+ * name and description. It is possible that a user may have 'view members list' 
+ * permission without 'view group existence' permission - the members would just 
+ * appear as the other users on the course. 
+ * 
+ * Permission types can be combined with boolean expressions where they are used 
+ * if necessary. 
+ * 
+ * @name GROUPS_STUDENT Either 'student view' or 'student contribute' permission
+ * @name GROUPS_TEACHER Either 'teacher view' or 'teacher contribute' permission
+ * @name GROUPS_VIEW Either 'teacher view' or 'student view' permission
+ * @name GROUPS_CONTRIBUTE Either 'teacher contribute' or 'student contribute' 
+ * permission
+ * @name GROUPS_VIEW_GROUP_EXISTENCE 'view group existence' permission
+ * @name GROUPS_VIEW_MEMBERS_LIST 'view members list' permission
+ * @name GROUPS_STUDENT_VIEW 'student view' permission
+ * @name GROUPS_STUDENT_CONTRIBUTE 'student contribute' permission
+ * @name GROUPS_TEACHER_VIEW 'teacher view' permission
+ * @name GROUPS_TEACHER_CONTRIBUTE 'teacher contribute' permission
+ ******************************************************************************/
+define('GROUPS_STUDENT', 1);
+define('GROUPS_TEACHER', 2);
+define('GROUPS_VIEW', 4);
+define('GROUPS_CONTRIBUTE', 8);
+define('GROUPS_VIEW_GROUP_EXISTENCE', 16);
+define('GROUPS_VIEW_MEMBERS_LIST', 48);
+define('GROUPS_STUDENT_VIEW', 5);
+define('GROUPS_STUDENT_CONTRIBUTE', 9);
+define('GROUPS_TEACHER_VIEW', 6);
+define('GROUPS_TEACHER_CONTRIBUTE', 10);
+
+/**
+ * Indicates if the instance of the module has been set up by an editor of the 
+ * course to use groups. This functionality can also be obtained using the 
+ * groups_m_get_groups() function, however it is sufficiently commonly needed 
+ * that this separate function has been provided and should be used instead. 
+ * @param int $cmid The id of the module instance
+ * @return boolean True if the instance is set up to use groups, false otherwise
+ */
+function groups_m_uses_groups($cmid) {
+       $usesgroups = false;
+       $groupingid = groups_db_get_groupingid($cmid);
+       if (!$groupingid) {
+               $usesgroups = true;
+       }
+       
+       return $usesgroups;
+}
+
+/**
+ * Prints a dropdown box to enable a user to select between the groups for the 
+ * module instance of which they are a member. If a user belongs to 0 or 1 
+ * groups, no form is printed. The dropdown box belongs to a form and when a 
+ * user clicks on the box this form is automatically submitted so that the page 
+ * knows about the change. 
+ * @param int $cmid The id of the module instance
+ * @param string $urlroot The url of the page - this is necessary so the form 
+ * can submit to the correct page. 
+ * @param int $permissiontype - see note on permissiontypes above. 
+ * @return boolean True unless an error occurred or the module instance does not 
+ * use groups in which case returns false. 
+ */
+function groups_m_print_group_selector($cmid, $urlroot, $permissiontype) {
+       // Get the groups for the cmid
+       // Produce an array to put into the $groupsmenu array. 
+       // Add an all option if necessary. 
+       $groupids = groups_module_get_groups_for_current_user($cmid, $permissiontype);
+       
+       // Need a line to check if current group selected. 
+       if ($groupids) {
+                       $currentgroup = groups_module_get_current_group($cmid);
+                       if ($allgroupsoption) {
+                               $groupsmenu[0] = get_string('allparticipants');
+                       }
+               
+               foreach ($groupids as $groupid) {
+                       $groupsmenu[$groupid] = groups_get_group_name($groupid);
+                       popup_form($urlroot.'&amp;group=', $groupsmenu, 'selectgroup', 
+                       $currentgroup, '', '', '', false, 'self');
+               }
+       }       
+}
+
+/**
+ * Gets the group that a student has selected from the drop-down menu printed
+ * by groups_m_print_group_selector and checks that the student has the 
+ * specified permission for the group and that the group is one of the groups
+ * assigned for this module instance.
+ * 
+ * Groups selected are saved between page changes within the module instance but 
+ * not necessarily if the user leaves the instance e.g. returns to the main 
+ * course page. If the selector has not been printed anywhere during the user's 
+ * 'visit' to the module instance, then the function returns false. This means 
+ * that you need to be particularly careful about pages that might be 
+ * bookmarked by the user.  
+ * 
+ * @uses $USER   
+ * @param int $cmid The id of the module instance
+ * @param int $permissiontype The permission type - see note on permission types 
+ * above
+ * @param int $userid The id of the user, defaults to the current user 
+ * @return boolean True if no error occurred, false otherwise.
+ * 
+ * TO DO - make this and other functions default to current user  
+ */
+function groups_m_get_selected_group($cmid, $permissiontype, $userid) {
+       $currentgroup = optional_param('group');
+       if (!$currentgroup) {
+               $groupids = groups_get_groups_for_user();
+       }
+       // Get it from the session variable, otherwise get it from the form, otherwise
+       // Get it from the database as the first group. 
+       // Then set the  group in the session variable to make it easier to get next time.      
+}
+        
+/**
+ * Gets an array of the groupids of all the groups that the specified user has
+ * particular permission for in this particular instance of the module
+ * @uses $USER     
+ * @param int $cmid The id of the module instance
+ * @param int $permissiontype The permission type - see note on permission types 
+ * above
+ * @param int $userid The id of the user, defaults to the current user 
+ * @return array An array of the group ids 
+ */    
+function groups_m_get_groups_for_user($cmid, $permissiontype, $userid) {
+       $groupingid = groups_db_get_groupingid($cmid);
+       $groupids = groups_get_groups_in_grouping($groupingid);
+       if (!$groupids) {
+               $groupidsforuser = false;
+       } else {
+               $groupidsforuser = array();
+               foreach($groupids as $groupid) {
+                       if (groups_m_has_permission($cmid, $groupid, $permissiontype, $userid) ) {
+                               array_push($groupidsforuser, $groupid);
+                       }
+               }
+       }
+       
+       return $groupidsforuser;
+}  
+
+/**
+ * Indicates if a specified user has a particular type of permission for a 
+ * particular group for this module instance.
+ * @uses $USER      
+ * @param int $cmid The id of the module instance. This is necessary because the 
+ * same group can be used in different module instances with different 
+ * permission setups. 
+ * @param int $groupid The id of the group
+ * @param int $permissiontype The permission type - see note on permission types 
+ * above
+ * @userid int $userid The id of the user, defaults to the current user
+ * @return boolean True if the user has the specified permission type, false 
+ * otherwise or if an error occurred. 
+ */
+ function groups_m_has_permission($cmid, $groupid, $permissiontype, $userid) {
+       $groupingid = groups_get_grouping_for_coursemodule($coursemoduleid);
+       $isstudent = isstudent($courseid, $userid);
+       $isteacher = isteacher($courseid, $userid);
+       $groupmember = groups_is_member($groupid, $userid);
+       $memberofsomegroup = groups_is_member_of_some_group_in_grouping($userid, $groupingid);
+       
+       $groupingsettings = groups_get_grouping_settings($groupingid);
+       $viewowngroup = $groupingsettings->viewowngroup;
+       $viewallgroupsmembers = $groupingsettings->viewallgroupmembers;
+       $viewallgroupsactivities = $groupingsettings->viewallgroupsactivities;
+       $teachersgroupsmark = $groupingsettings->teachersgroupsmark;
+       $teachersgroupsview = $groupingsettings->teachersgroupsview;
+       $teachersgroupmark = $groupingsettings->teachersgroupmark;
+       $teachersgroupview = $groupingsettings->teachersgroupview;
+       $teachersoverride = $groupingsettings->teachersoverride;
+               
+       $permission = false;
+       
+       switch ($permissiontype) {
+               case 'view':
+                       if (($isstudent and $groupmember) or 
+                           ($isteacher and $groupmember) or 
+                           ($isstudent and $viewallgroupsactivities) or 
+                           ($isteacher and !$teachersgroupview) or 
+                           ($isteacher and !$memberofsomegroup and $teachersoverride)) {
+                               $permission = true;
+                       } 
+                       break;
+                       
+               case 'studentcontribute':
+                       if (($isstudent and $groupmember) or 
+                           ($isteacher and $groupmember) or 
+                           ($isteacher and !$memberofsomegroup and $teachersoverride)) {
+                               $permission = true;
+                       } 
+                       break;
+               case 'teachermark':
+                       if (($isteacher and $groupmember) or 
+                               ($isteacher and !$teachersgroupmark) or
+                           ($isteacher and !$memberofsomegroup and $teachersoverride)) {
+                               $permission = true;
+                       }  
+                       break;
+               
+               case 'viewmembers':     
+                       if (($isstudent and $groupmember and $viewowngroup) or 
+                           ($isstudent and $viewallgroupsmembers) or 
+                               ($isteacher and $groupmember) or 
+                           ($isteacher and !$teachersgroupview) or 
+                           ($isteacher and !$memberofsomegroup and $teachersoverride) or 
+                           $isteacheredit) {
+                               $permission = true;
+                       }  
+                       break;
+       }
+       return $permission;     
+}
+
+/**
+ * Gets an array of members of a group that have a particular permission type 
+ * for this instance of the module and that are enrolled on the course that
+ * the module instance belongs to. 
+ * 
+ * @param int $cmid The id of the module instance. This is necessary because the 
+ * same group can be used in different module instances with different 
+ * permission setups. 
+ * @param int $groupid The id of the group
+ * @param int $permissiontype The permission type - see note on permission types 
+ * above
+ * @return array An array containing the ids of the users with the specified 
+ * permission. 
+ */
+function groups_m_get_members_with_permission($cmid, $groupid, 
+                                              $permissiontype) {
+       // Get all the users as $userid
+       $validuserids = array();        
+       foreach($userids as $userid) {
+               $haspermission = groups_m_has_permission($cmid, $groupid, 
+                                                                               $permissiontype, $userid);
+               if ($haspermission) {
+                       array_push($validuserids, $userid);
+               }
+       }
+       return $validuserids;
+}
+
+/**
+ * Gets the group object associated with a group id. This group object can be 
+ * used to get information such as the name of the group and the file for the 
+ * group icon if it exists. (Look at the groups table in the database to see
+ * the fields). 
+ * @param int $groupid The id of the group
+ * @return group The group object 
+ */
+function groups_m_get_group($groupid) {
+       return groups_db_m_get_group($groupid);
+}
+
+/**
+ * Gets the groups for the module instance. In general, you should use 
+ * groups_m_get_groups_for_user, however this function is provided for 
+ * circumstances where this function isn't sufficient for some reason. 
+ * @param int $cmid The id of the module instance. 
+ * @return array An array of the ids of the groups for the module instance 
+ */
+function groups_m_get_groups($cmid) {
+       $groupingid = groups_db_get_groupingid($cmid);
+       $groupids = groups_get_groups_in_grouping($groupingid);
+       return $groupids;       
+}
+
+/**
+ * Gets the members of group that are enrolled on the course that the specified
+ * module instance belongs to. 
+ * @param int $cmid The id of the module instance
+ * @param int $groupid The id of the group
+ * @return array An array of the userids of the members. 
+ */
+function groups_m_get_members($cmid, $groupid) {
+       $userids = groups_get_members($groupid, $membertype);
+       if (!$userids) {
+               $memberids = false;
+       } else {
+               // Check if each user is enrolled on the course @@@ TO DO 
+       }
+}
+
+/**
+ * Indicates if a user is a member of a particular group. In general you should 
+ * use groups_m_has_permission, however this function is provided for 
+ * circumstances where this function isn't sufficient for some reason. 
+ * @param int $groupid The id of the group
+ * @param int $userid The id of the user 
+ * @return boolean True if the user is a member of the group, false otherwise 
+ */
+function groups_m_is_member($groupid, $userid) {
+       return groups_is_member($groupid, $userid);
+}
+
+/**
+ * Determines if a user has a particular permission type for a particular group. Permissions
+ * are set at grouping level and are set via the grouping settings. This is the function
+ * to check, if somebody can't access something that you think they ought to be able to!
+ * This is for the current user. What about for general user?
+ * @param int $courseid The id of the course
+ * @param int $groupid The id of the group
+ * @param string $permissiontype The permission type: 'view', 'studentcontribute', 
+ * 'teacherview', 'teachercontribute', 'viewmembers', 'contribute', 'all'
+ */
+function groups_m_has_permission($courseid, $groupid, $permissiontype) {
+       $userid = $USER->id;
+       $groupingid = groups_get_grouping_for_coursemodule($coursemoduleid);
+       $isstudent = isstudent($courseid, $userid);
+       $isteacher = isteacher($courseid, $userid);
+       $groupmember = groups_is_member($groupid, $userid);
+       $memberofsomegroup = groups_is_member_of_some_group_in_grouping($userid, $groupingid);
+       
+       $groupingsettings = groups_get_grouping_settings($groupingid);
+       $viewowngroup = $groupingsettings->viewowngroup;
+       $viewallgroupsmembers = $groupingsettings->viewallgroupmembers;
+       $viewallgroupsactivities = $groupingsettings->viewallgroupsactivities;
+       $teachersgroupsmark = $groupingsettings->teachersgroupsmark;
+       $teachersgroupsview = $groupingsettings->teachersgroupsview;
+       $teachersgroupmark = $groupingsettings->teachersgroupmark;
+       $teachersgroupview = $groupingsettings->teachersgroupview;
+       $teachersoverride = $groupingsettings->teachersoverride;
+               
+       $permission = false;
+       
+       switch ($permissiontype) {
+               case 'view':
+                       if (($isstudent and $groupmember) or 
+                           ($isteacher and $groupmember) or 
+                           ($isstudent and $viewallgroupsactivities) or 
+                           ($isteacher and !$teachersgroupview) or 
+                           ($isteacher and !$memberofsomegroup and $teachersoverride)) {
+                               $permission = true;
+                       } 
+                       break;
+                       
+               case 'studentcontribute':
+                       if (($isstudent and $groupmember) or 
+                           ($isteacher and $groupmember) or 
+                           ($isteacher and !$memberofsomegroup and $teachersoverride)) {
+                               $permission = true;
+                       } 
+                       break;
+               case 'teachermark':
+                       if (($isteacher and $groupmember) or 
+                               ($isteacher and !$teachersgroupmark) or
+                           ($isteacher and !$memberofsomegroup and $teachersoverride)) {
+                               $permission = true;
+                       }  
+                       break;
+               
+               case 'viewmembers':     
+                       if (($isstudent and $groupmember and $viewowngroup) or 
+                           ($isstudent and $viewallgroupsmembers) or 
+                               ($isteacher and $groupmember) or 
+                           ($isteacher and !$teachersgroupview) or 
+                           ($isteacher and !$memberofsomegroup and $teachersoverride) or 
+                           $isteacheredit) {
+                               $permission = true;
+                       }  
+                       break;
+       }
+       return $permission;     
+}
+
+?>
\ No newline at end of file
diff --git a/group/lib/utillib.php b/group/lib/utillib.php
new file mode 100644 (file)
index 0000000..a79d6a3
--- /dev/null
@@ -0,0 +1,179 @@
+<?php
+
+/******************************************************
+ * Functions to get information about users and courses that we could do with 
+ * that don't use any of the groups and that I can't find anywhere else!
+ ********************************************************/
+
+
+include_once($CFG->dirroot.'/lib/moodlelib.php');
+
+
+/**********************************
+ * Functions to get display names
+ **********************************
+ */
+
+
+/**
+ * Gets the number of members of a group
+ * @param int $groupid The group specified
+ * @return int The number of members of the group
+ */
+function groups_get_no_group_members($groupid) {
+    $userids = groups_get_members($groupid);
+    if (!$userids) {
+       $nomembers = 0;
+    } else {
+       $nomembers = count($userids);
+    }
+
+    return $nomembers;
+}
+
+
+/**
+ * Gets the number of groups in a specified grouping
+ * @param int $groupingid The grouping specified
+ * @return int The number of groups in the grouping
+ */
+function groups_get_no_groups_in_grouping($groupingid) {
+    $groupids = groups_get_groups_in_grouping($groupingid);
+    if (!$groupids) {
+       $nogroups = 0;
+    } else {
+       $nogroups = count($groupids);
+    }
+    return $nogroups;
+}
+
+
+/**
+ * Returns the display name of a user. This is the full name which if the user 
+ * is a teacher, is prefixed by if the teacher has edit permission and - 
+ * otherwise.
+ * @param int $userid The id of the user specified
+ * @param boolean $teacher True if the user is a teacher, false otherwise
+ * @return string The display name of the user 
+ */
+function groups_get_user_displayname($userid, $courseid) {
+       if ($courseid == false) {
+               $fullname = false; 
+       } else {
+               $user = groups_get_user($userid);
+           $fullname = fullname($user, true);
+           if (isteacher($courseid, $userid)) {
+               if (isteacheredit($courseid, $userid)) {
+                   $prefix = '# ';
+               } else {
+                    $prefix = '- ';
+               }
+               
+               $fullname = $prefix.$fullname;
+           }
+       }
+    
+    return $fullname;
+}
+
+
+/**
+ * Returns the display name of a group - this is the group name followed by the 
+ * number of group members in brackets
+ * @param int $groupid The groupid
+ * @return string The display name of the group
+ */
+function groups_get_group_displayname($groupid) {
+       $groupsettings = groups_get_group_settings($groupid);
+    $groupname = $groupsettings->name;
+       $nogroupmembers = groups_get_no_group_members($groupid);
+       $displayname= "$groupname ($nogroupmembers)"; 
+       return $displayname;
+}
+
+
+/**
+ * Returns the display name of a grouping - this is the grouping name followed 
+ * by the number of groups in the
+ * grouping in brackets
+ * @param int $groupingid The grouping id
+ * @return string The display name of the grouping
+ */
+function groups_get_grouping_displayname($groupingid) {
+       $groupingsettings = groups_get_grouping_settings($groupingid);
+       $groupingname = $groupingsettings->name;
+    $nogroups= groups_get_no_groups_in_grouping($groupingid);
+    $displayname = "$groupingname ($nogroups)";
+    return $displayname;
+}
+
+
+/**
+ * Takes an array of users (i.e of objects) and converts it in the corresponding 
+ * array of userids. 
+ * @param $users array The array of users
+ * @return array The array of user ids, or false if an error occurred 
+ */
+function groups_users_to_userids($users) {
+       if (!$users) {
+               $userids = false;
+       } else {        
+               $userids = array();
+               foreach($users as $user) {
+                       array_push($userids, $user->id);
+               }
+       }
+       return $userids;
+}
+
+/**
+ * Takes an array of groups (i.e of objects) and converts it in the 
+ * corresponding array of groupids. 
+ * @param $groups array The array of group
+ * @return array The array of group ids, or false if an error occurred 
+ */
+function groups_groups_to_groupids($groups) {
+       $groupids = array();
+       foreach ($groups as $group) {
+               array_push($groupids, $group->id);
+       }
+       return $groupids;
+}
+
+// @@@ TO DO 
+function groups_groupid_to_group($groupid) {
+}
+
+// @@@ TO DO 
+function groups_groupids_to_groups($groupids) {
+}
+
+
+/**
+ * Gets the user object for a given userid. Can't find a function anywhere to 
+ * do this and we need this
+ * for fullname()
+ * 
+ * @param $userid int The userid
+ * @return object The corresponding user object, or false if an error occurred
+ */
+function groups_get_user($userid) {
+       return groups_db_get_user($userid);
+}
+
+
+/**
+ * Gets the course information object for a given course id  
+ * @param $courseid int The course id
+ * @return object The course info object, or false if an error occurred. 
+ * @@@ TO DO - need to put the database bit into a db file 
+ */
+function groups_get_course_info($courseid){
+       if (!$courseid) {
+               $courseinfo = false;
+       } else {
+               $courseinfo = get_record('course', 'id', $courseid);
+       }
+    return $courseinfo;
+}
+?>
\ No newline at end of file
diff --git a/group/onedaymaybe.txt b/group/onedaymaybe.txt
new file mode 100644 (file)
index 0000000..a84ff3a
--- /dev/null
@@ -0,0 +1,34 @@
+List of nice to haves 
+---------------------
+
+- A way for modules to register the extent to which they support groups. Warn
+people who try to set up groups with a module with legacy group support that it
+might not work if more than one grouping exists. 
+- A proper user interface for using the same groups in more than one course
+- The option of view names by last name rather than first name. 
+- Option of only showing students/teachers - having teachers mixed up with
+students is confusing
+- Maybe a nice way to see which users are in more than one group in a grouping?
+- When adding users it would be nice to see the current users. 
+- Think about metacourses and how groups relate to these 
+
+Global groups - I want it to be possible to set up groupings for course 1 and 
+for these to be visible for all course on the site, but not editable or 
+deletable. I think this code should actually be quite easy to write now and I 
+might even do it before this code is put in, just haven't done it yet.
+# A nicer user interface (that doesn't break the back button :-) Ajax separates 
+the back and front end of the code really well, so if anyone has good ideas on 
+this, it should be quite easy for someone else to do without having to know how 
+the internals of the groups code work.
+# Integration with roles and permissions
+# Sign up sheets for groups
+# Proper support for blocks and global features.
+# A way for modules and blocks to declare whether they support groups or not.
+# Putting in search_users functionality for group permissions as well as just 
+members of groups.
+# Cool ways to set up groups automatically for particular pedagogical reasons - 
+things like minimising overlap with groups in another grouping, creating groups 
+just from the users all in another group and creating groups which merge pairs 
+of groups from another grouping.
+# Allow settings for groupings which restrict users from being in more than one 
+group, number of people per group, etc. 
\ No newline at end of file
diff --git a/group/overview.txt b/group/overview.txt
new file mode 100644 (file)
index 0000000..fcb2301
--- /dev/null
@@ -0,0 +1,54 @@
+Quick summary!
+
+See the wiki too - 
+
+http://docs.moodle.org/en/How_groups_work_in_Moodle
+http://docs.moodle.org/en/Groups_documentation_for_module_developers
+
+To install - run install.php. This create the appropriate database tables and 
+sets some default config for using an IMS Enterprise web service (in particular 
+the default setting is that such a web service is not called).
+
+The user interface for managing groups for a course is groupsui/index.php. 
+A grouping is just a set of groups - the idea is that you can have several 
+groupings for a course, and then choose different groupings for different 
+activities. 
+
+Note that installing this code does not enable you to actually use the groupings 
+with activity modules - this is coming :-)
+
+configui - This contains the user interface for changing the IMS Enterprise web 
+service config
+
+db - all the functions that access the database, only used internally. There are 
+basically six tables that this code deals with  groups_groups, 
+groups_courses_groups,groups_groups_users, groups_groupings  
+
+groupui - the user interface for managing the groups and groupings of a course. 
+This uses Ajax so most of the code for the user interface is in the javascript 
+files - the PHP files just send back an appropriate XML response to specific
+POST requests. You'll probably need to know the basics of how Ajax works to 
+understand the Javascript. 
+
+lib - The main libraries for the user interface and other moodle code to user. 
+-- basicgrouplib.php contains the basic functions for  adding users to groups, 
+deleting groups etc.
+-- groupinglib.php contains the basic function for groupings e.g. creating 
+groupings, adding groups to groupings
+-- extendedgrouplib.php contains other functions that are useful and use the 
+basic group and grouping functions
+-- lib.php is just there to let you include all the libraries more easily
+-- utillib.php contains functions that are handy but don't use any of the group 
+or grouping library function e.g. 
+things like getting the names of users 
+-- configlib.php - Contains wrapper functions for getting and setting config
+
+unittests - This directory needs a bit of sorting out, and I've just discovered 
+that I've broken one of the main 
+tests...
+
+strings.php - This is stuff that will need to go in the language files - it's 
+here for convenience while I'm doing the
+development. 
+
diff --git a/group/todo.txt b/group/todo.txt
new file mode 100644 (file)
index 0000000..fec7040
--- /dev/null
@@ -0,0 +1,80 @@
+Things I know needs doing!
+--------------------------
+
+0) The main thing is to sort out how permissions are going to work... 
+
+1) Write proper code for creating the database - I left this knowing there were 
+changes planned here. db/dbsetup.php obviously isn't what you'd want in the end.
+No foreign keys at the moment either and there ought to be. I've also been 
+leaving this until the database structure is reasonably settled. If you've done 
+this sort of thing elsewhere, I suspect this will be fine. Also need to delete
+the two Yahoo files and reference the ones in lib/yui instead - copied them
+over when I was trying to debug stuff. 
+
+2) Move all the Ajax over to use the Yahoo User Interface library - this
+is straightforward but tedious! I've done one example - UpdateGroupings in 
+main-selects-form.js, everything else needs doing. You'll need
+to do something sensible with errors, and eventually delete the current 
+functions for doing Ajax requests and responses which aren't very good anyway. 
+
+2) Move unit tests over to simple test and improve them -  we could also do with 
+some automated tests for the interface too - Selenium?
+
+3)  Security - Need to do a check of this. In particular in the functions
+giving the XML for the Ajax stuff, I think there was something I remember I 
+needed to do... 
+
+4) Check complies with the Moodle coding standards. I think I may have
+used tabs by accident because I didn't realise that the PHPEclipse settings
+overrode the main Eclipse ones. Also line lengths are too long all over the 
+place. 
+
+5) The CSS stuff needs to be moved to where it's supposed to be /rationalised
+etc. 
+
+6) The whole issue of permissions - talk to me about this
+
+7) Enrolment keys and user pics - haven't tested these out properly. 
+
+8) The automatic grouping code could be a lot simpler I realised afterwards, 
+but it works so have been loathe to change it! 
+
+9) Interesting question as to whether we should somehow record the extent to 
+which modules support groups...
+
+10) Who do we let edit/delete what? If a grouping is used by more than one 
+course. Maybe we need an 'owning' course in the database structure. Site-wide 
+groupings - making these appear in people's lists, but not editable
+
+11) Check I've done the bits with objects ok - need to check how PHP does OO. 
+
+12) Check I've done the PHP docs right - just copied other people's! 
+
+13) Check all the strings are in the lang file 
+
+14) Make sure everything works on Postgres as well as MySQL.
+
+15) One thing that needs to be thought about is if it shoudl be possible to 
+turn a module from not using groups to using groups once students have accessed
+it and if so how this should work. 
+
+16) Make sure all references to IMS Enterprise stuff/web services are gone. 
+
+
+Other parts of the code that will need changing 
+------------------------------------------------
+
+1) All the modules - I started doing these and then roles and permissions
+happen. 
+2) Lots of the code in user - if we keep the group_member table the same 
+can we avoid modifiying some of this 
+3) The form where course settings are chosen. We still want it to be possible
+to set a forced grouping for the whole course still and need to remove the
+current options. 
+4) For each module, you need to be able to set a grouping. 
+5) Blocks, blogs and calendar also need to be dealt with 
+6) Backup code - there are bugs in the groups parts of this at the moment 
+so be careful here :-) 
+7) Code to delete courses etc.
+8) Need to make sure grouped acitivities only display to people in the group.  
+