Index: og_user_roles.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/og_user_roles/og_user_roles.info,v
retrieving revision 1.5
diff -u -p -r1.5 og_user_roles.info
--- og_user_roles.info	24 May 2009 05:47:02 -0000	1.5
+++ og_user_roles.info	25 May 2009 08:08:48 -0000
@@ -1,8 +1,7 @@
 ; $Id: og_user_roles.info,v 1.5 2009/05/24 05:47:02 sun Exp $
 name = Organic groups user roles
-description = Dynamically assign user roles to members of organic groups.
+description = Assign additional user roles to members of organic groups within the group context.
 dependencies[] = og
 dependencies[] = og_views
 package = Organic groups
 core = 6.x
-php = 4.3.9 
Index: og_user_roles.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/og_user_roles/og_user_roles.install,v
retrieving revision 1.6
diff -u -p -r1.6 og_user_roles.install
--- og_user_roles.install	24 May 2009 23:40:47 -0000	1.6
+++ og_user_roles.install	25 May 2009 08:21:42 -0000
@@ -7,12 +7,11 @@
 function og_user_roles_schema() {
   $schema['og_users_roles'] = array(
     'fields' => array(
-      'ogr_id' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+      'gid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
       'uid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
       'rid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
-      'gid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
     ),
-    'primary key' => array('uid', 'rid', 'gid'),
+    'primary key' => array('gid', 'uid', 'rid'),
   );
   return $schema;
 }
@@ -22,6 +21,9 @@ function og_user_roles_schema() {
  */
 function og_user_roles_install() {
   drupal_install_schema('og_user_roles');
+  // Decrease module weight.
+  // @see og_user_roles_init()
+  db_query("UPDATE {system} SET weight = -1 WHERE type = 'module' AND name = 'og_user_roles'");
 }
 
 /**
@@ -44,3 +46,45 @@ function og_user_roles_update_6200() {
   return $ret;
 }
 
+/**
+ * Decrease module weight.
+ *
+ * @see og_user_roles_init()
+ */
+function og_user_roles_update_6201() {
+  $ret = array();
+  $ret[] = update_sql("UPDATE {system} SET weight = -1 WHERE type = 'module' AND name = 'og_user_roles'");
+  return $ret;
+}
+
+/**
+ * Remove obsolete {og_user_test}.ogr_id column.
+ */
+function og_user_roles_update_6202() {
+  $ret = array();
+  db_drop_field($ret, 'og_users_roles', 'ogr_id');
+  variable_del('og_user_roles_counter');
+  return $ret;
+}
+
+/**
+ * Remove obsolete variables.
+ */
+function og_user_roles_update_6203() {
+  $ret = array();
+
+  variable_del('og_user_roles_assign_basicgrouprole');
+  if ($default_role = variable_get('og_user_roles_basicgrouprole_value', NULL)) {
+    variable_set('og_user_roles_default_role', $default_role);
+  }
+  variable_del('og_user_roles_basicgrouprole_value');
+
+  variable_del('og_user_roles_assign_admingrouprole');
+  if ($admin_role = variable_get('og_user_roles_admingrouprole_value', NULL)) {
+    variable_set('og_user_roles_default_admin_role', $admin_role);
+  }
+  variable_del('og_user_roles_admingrouprole_value');
+
+  return $ret;
+}
+
Index: og_user_roles.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/og_user_roles/og_user_roles.module,v
retrieving revision 1.33
diff -u -p -r1.33 og_user_roles.module
--- og_user_roles.module	25 May 2009 03:26:04 -0000	1.33
+++ og_user_roles.module	25 May 2009 08:50:15 -0000
@@ -3,110 +3,34 @@
 
 /**
  * @file
- * Dynamically assign user roles to members of organic groups.
+ * Assign additional user roles to members of organic groups within the group context.
+ *
+ * For detailed documentation:
+ * @see og_user_roles_init()
  */
 
 /**
- * Implementation of hook_perm().
+ * Implementation of hook_help().
  */
-function og_user_roles_perm() {
-  return array(
-    'administer og_user_roles',
-    'configure member roles',
-  );
+function og_user_roles_help($path, $arg) {
+  switch ($path) {
+    case 'admin/og/og_user_roles':
+      $output = '<p>' . t('Group members with the %permission <a href="@permissions-url">permission</a> can assign additional roles to individual users of a group that only apply within the context of a group.', array('%permission' => 'configure member roles', '@permissions-url' => url('admin/user/permissions'))) . '</p>';
+      return $output;
+
+    case 'og/users/%/roles':
+      $output = '<p>' . t('This form allows to grant additional user roles to individual members of this group. Any additional permissions only apply to the context of this group and not globally.') . '</p>';
+      return $output;
+  }
 }
 
 /**
- * Implementation of hook_settings().
+ * Implementation of hook_perm().
  */
-function og_user_roles_admin_settings() {
-  // Get list of all og-enabled node types.
-  $group_types = og_get_types('group');
-  $types = array();
-  foreach ($group_types as $type) {
-    $types[$type] = node_get_types('name', $type);
-  }
-
-  // Get list of roles, not counting authenticated and anonymous user.
-  $all_roles = user_roles();
-  foreach ($all_roles as $rid => $role) {
-    if ($rid > 2) {
-      $roles[$rid] = $role;
-    }
-  }
-  // If no assignable roles, advise user to add some.
-  if (empty($roles)) {
-    $form['og_user_roles'] = array(
-      '#value' => '<p>' . t('No assignable roles were found. Please create at least one role under !roles.', array('!roles' => l(t('Administer >> User management >> Roles'), 'admin/user/roles'))) . '</p>',
-    );
-    return $form;
-  }
-
-  // Create a fieldset for each group type containing role selections.
-  foreach ($types as $type => $name) {
-    $form["og_user_roles_$type"] = array(
-      '#type' => 'fieldset',
-      '#title' => t('%type_name role options', array('%type_name' => $name)),
-    );
-    $form["og_user_roles_$type"]["og_user_roles_roles_$type"] = array(
-      '#type' => 'checkboxes',
-      '#title' => t('Assignable roles'),
-      '#options' => $roles,
-      '#default_value' => variable_get("og_user_roles_roles_$type", array()),
-    );
-  }
-
-  $form['og_user_roles_basicgrouprole'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Default Basic Group Role for new group subscribers.'),
-    '#description' => t('Allows you to select a group role to automatically assign to users who join a group on your site. The role is specific to the group(s) to which the user is subscribing.  That is, the user will only have the privileges of the role in the group he is subscribed to.'),
-    '#collapsible' => TRUE,
-    '#collapsed' => TRUE,
-  );
-  $form['og_user_roles_basicgrouprole']['og_user_roles_assign_basicgrouprole'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Set default basic group (group limited) role for users who join groups?'),
-    '#default_value' => variable_get('og_user_roles_assign_basicgrouprole', 0),
-    '#description' => t('Do you wish to automatically assign a specific "basic group role" to <strong>every new group subscriber</strong> at the time he subscribes to the group? The role is limited to the group that he is subscribed to. This role assignment can be removed by the groups\' admins'),
-  );
-  $form['og_user_roles_basicgrouprole']['og_user_roles_basicgrouprole_value'] = array(
-    '#type' => 'select',
-    '#title' => t('Role to use as a basic group role'),
-    '#options' => $roles,
-    '#default_value' => variable_get('og_user_roles_basicgrouprole_value', 0),
-    '#description' => t('Select the role you wish to use as the "basic group role" for every new groupmember.'),
-  );
-
-  $form['og_user_roles_admingrouprole'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Default Group Role for new group administrator.'),
-    '#description' => t('Allows you to select a group role to automatically assign to users who are elevated to group administrator. The role is specific to the group(s) in which the user is a group administrator.  That is, the user will only have the privileges of the role in the group he is the administrator for.'),
-    '#collapsible' => TRUE,
-    '#collapsed' => TRUE,
-  );
-  $form['og_user_roles_admingrouprole']['og_user_roles_assign_admingrouprole'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Set default group (group limited) administrator role for users who are elevated to group administrator?'),
-    '#default_value' => variable_get('og_user_roles_assign_admingrouprole', 0),
-    '#description' => t('Do you wish to automatically assign a specific "administrator group role" to <strong>every new group administrator</strong> at the time he is elevated to group administrator status? The role is limited to the group that he is the administrator for. This role assignment can only be removed by removing the user as a group administrator.'),
-  );
-  $form['og_user_roles_admingrouprole']['og_user_roles_admingrouprole_value'] = array(
-    '#type' => 'select',
-    '#title' => t('Role to use as group administrator role'),
-    '#options' => $roles,
-    '#default_value' => variable_get('og_user_roles_admingrouprole_value', 0),
-    '#description' => t('Select the role you wish to use as the "group administrator role" for every new group administrator.'),
-  );
-
-  $form['og_user_roles_counter'] = array(
-    '#type' => 'textfield',
-    '#size' => 10,
-    '#title' => t('Counter for <strong>og_users_roles</strong> table'),
-    '#default_value' => variable_get('og_user_roles_counter', 0),
-    '#description' => t('This is the counter for the <strong>og_users_roles</strong> table. You do not need to set this.  It will update itself.  It should NOT be set lower than the number of records currently in the table.'),
+function og_user_roles_perm() {
+  return array(
+    'configure member roles',
   );
-
-  return system_settings_form($form);
 }
 
 /**
@@ -118,852 +42,191 @@ function og_user_roles_menu() {
     'description' => 'Configure user roles in groups.',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('og_user_roles_admin_settings'),
-    'access arguments' => array('administer og_user_roles'),
+    'access arguments' => array('administer organic groups'),
+    'file' => 'og_user_roles.pages.inc',
   );
-  $items['node/ognodeadd'] = array(
-    'title' => 'Create content',
-    'page callback' => 'og_user_roles_ognodeadd',
-    'access callback' => 'user_is_logged_in',
-    'type' => MENU_CALLBACK,
-  );
-
-  // Add another tab to the group subscribers page for admins to
-  // configure member roles
   $items['og/users/%node/roles'] = array(
-    'title' => 'Configure member roles',
+    'title' => 'Configure roles',
     'page callback' => 'og_user_roles_page',
     'page arguments' => array(2),
     'access callback' => 'og_user_roles_is_allowed',
     'access arguments' => array(2),
     'weight' => 5,
     'type' => MENU_LOCAL_TASK,
+    'file' => 'og_user_roles.pages.inc',
   );
-
   return $items;
 }
 
 /**
- * Implementation of hook_menu_alter().
- */
-function og_user_roles_menu_alter(&$menu) {
-  return;
-  // Override OG's node edit access callback.
-  $menu['node/%node/edit']['access callback'] = 'og_user_roles_menu_node_access_edit';
-  $menu['node/%node/edit']['access arguments'] = array(1);
-  // Override node add access callback.
-  foreach (node_get_types('types', NULL, TRUE) as $type) {
-    $type_url_str = str_replace('_', '-', $type->type);
-    $menu['node/add/'. $type_url_str]['access callback'] = 'og_user_roles_menu_node_access_add';
-    $menu['node/add/'. $type_url_str]['access arguments'] = array($type->type);
-  }
-}
-
-/**
- * Menu access callback; Determine access to node edit page.
- */
-function og_user_roles_menu_node_access_edit($node) {
-  static $access;
-
-  // This is called a dozen of times; return cached result.
-  if (isset($access)) {
-    return $access;
-  }
-
-  // This is called from arbitrary functions not respecting the menu system.
-  if (!is_object($node)) {
-    $args = func_get_args();
-    $op = $args[0];
-    $node = $args[1];
-  }
-
-  // Perform regular access check first.
-  $access = og_menu_access_node_edit($node);
-  $access = TRUE;
-  return $access;
-}
-
-/**
- * Menu access callback; Determine access to node add page.
+ * Menu access callback; Determine access to group member role configuration.
  */
-function og_user_roles_menu_node_access_add($node) {
-  static $access;
-
-  // This is called a dozen of times; return cached result.
-  if (isset($access)) {
-    return $access;
+function og_user_roles_is_allowed($node) {
+  if (!user_access('configure member roles')) {
+    return FALSE;
   }
-
-  // This is called from arbitrary functions not respecting the menu system.
-  if (!is_object($node)) {
-    $args = func_get_args();
-    $op = $args[0];
-    $node = $args[1];
+  // Only allow access to member role configuration if there are roles to assign.
+  $roles = array_filter(variable_get("og_user_roles_roles_{$node->type}", NULL));
+  if (og_is_group_type($node->type) && !empty($roles)) {
+    return TRUE;
   }
-
-  // Perform regular access check first.
-  $access = node_access('create', $node);
-
-  $access = TRUE;
-  return $access;
+  return FALSE;
 }
 
 /**
- * Menu callback; displays members and role selection
+ * Implementation of hook_theme().
  */
-function og_user_roles_page($node) {
-  $output = '';
-  // Get roles associated with this group. We rebuild the associative
-  // array because the settings form only passes RID and we need the name.
-  $role_ids = variable_get("og_user_roles_roles_{$node->type}", array());
-  $all_roles = user_roles();
-  foreach ($role_ids as $rid => $checked) {
-    if ($checked != 0) {
-      $roles[$rid] = $all_roles[$rid];
-    }
-  }
-
-  if (is_array($roles)) {
-    // Retrieve list of all group users
-    $sql = og_list_users_sql(0, 0, 'ou.is_admin DESC, ou.is_active ASC, u.name ASC');
-    $result = pager_query($sql, 100, 0, NULL, $node->nid);
-    $output .= theme('pager', NULL, 100);
-    $output .= drupal_get_form('og_user_roles_page_form', $node->nid, $roles, $result);
-  }
-  else {
-    drupal_set_message(t('No roles have been assigned as group roles yet.'));
-  }
-
-  drupal_set_title(t('Subscribers') . ': ' . l($node->title, "node/$node->nid"));
-
-  return $output;
+function og_user_roles_theme() {
+  return array(
+    'og_user_roles_page_form' => array(
+      'arguments' => array('form' => array()),
+      'file' => 'og_user_roles.pages.inc',
+    ),
+  );
 }
 
 /**
- * Form for user roles page.
+ * Implementation of hook_init().
+ *
+ * OG invokes menu_get_item() in og_determine_context() via og_init(), which
+ * performs the very first access check for the current path and is irreversible
+ * (statically cached). Since we want to alter the user's roles, we need to
+ * invoke a fork of og_determine_context(), which does not use the menu system,
+ * but still retrieves the current group context, so we can properly assign
+ * additional roles for the user.
+ *
+ * This is only possible, since we decreased the module weight of og_user_roles
+ * to have our hook run first. hook_boot() cannot be used, because the path is
+ * not yet initialized there.
+ *
+ * @see og_determine_context()
+ * @see og_user_roles_determine_context()
  */
-function og_user_roles_page_form($form_values, $gid, $roles, $result) {
-  // Make sure form array isn't flattened
-  $form['user_roles'] = array('#tree' => TRUE);
-  while ($account = db_fetch_object($result)) {
-    $form['user_roles']['users'][$account->uid] = array(
-      '#type' => 'value',
-      '#value' => $account->uid,
-    );
-
-    $title = theme('username', $account) . ' (' . l(t('unsubscribe'), "og/unsubscribe/$gid/$account->uid", array('query' => "destination=og/users/$gid")) . ')';
-
-    $form['user_roles']['roles'][$account->uid] = array(
-      '#type' => 'checkboxes',
-      '#title' => $title,
-      '#default_value' => _og_user_roles_get_roles($account->uid, $roles),
-      '#columns' => 4,
-      '#options' => $roles,
-      '#suffix' => '<br style="clear: both;" />',
-    );
-  }
-  $form['submit'] = array('#type' => 'submit', '#value' => t('Save changes'));
+function og_user_roles_init() {
+  global $user;
 
-  return $form;
+  // Try to determine group context using customized menu system functions.
+  $group_node = og_user_roles_determine_context();
+  // Assign additional user roles to current user (if any).
+  og_user_roles_grant_roles($user, $group_node);
 }
 
 /**
- * Process the form submission.
+ * @defgroup og_user_roles_privilege_escalation OG user roles privilege escalation
+ * @{
  */
-function og_user_roles_page_form_submit($form, &$form_state) {
-  // Added this to get gid
-  if (is_numeric(arg(2))) {
-    $gid = (int)arg(2);
-  }
-
-  foreach ($form_state['values']['user_roles']['roles'] as $uid => $roles) {
-    foreach ($roles as $rid => $checked) {
-      $exists = db_result(db_query("SELECT * FROM {og_users_roles} WHERE uid = %d AND rid = %d AND gid = %d", $uid, $rid, $gid));
-      if ($checked && !$exists) {
-        $ogr_id = variable_get('og_user_roles_counter', 0) + 1;
-        variable_set('og_user_roles_counter', $ogr_id);
-        db_query("INSERT INTO {og_users_roles} (uid, rid, gid, ogr_id) VALUES (%d, %d, %d, %d)", $uid, $rid, $gid, $ogr_id);
-        $args['rid'] = $rid;
-        $args['ogr_id'] = $ogr_id;
-        module_invoke_all('og', 'user update', $gid, $uid, $args);
-      }
-      elseif (!$checked && $exists) {
-        db_query("DELETE FROM {og_users_roles} WHERE uid = %d AND rid = %d AND gid = %d", $uid, $rid, $gid);
-      }
-    }
-  }
-
-  // Have to rebuild the menu here, in case new menu items were added
-  menu_rebuild();
-
-  drupal_set_message(t('Your changes have been saved'));
-}
 
 /**
- * Return an array of just the roles assignable by this user
+ * Set group context using the menu system.
+ *
+ * The only difference to the original og_determine_context() is that we are
+ * intentionally using our own menu system functions, so we can determine
+ * the group context without setting access for the current menu path (which
+ * is statically cached in menu_get_item()).
  *
  * @return
- *   Array containing roles that this user may assign.
+ *   A group node object, or NULL if not a group page.
+ *
+ * @see og_determine_context()
  */
-function og_user_roles_get_roles() {
-  // If this user has 'configure member roles' permission, then he has
-  // global role access for this group.
-  if (user_access('configure member roles')) {
-    return user_roles();
-  }
-  return array();
-}
+function og_user_roles_determine_context() {
+  $item = og_user_roles_menu_get_item();
+  $object = og_user_roles_menu_get_object();
 
-/**
- * Check to see what roles a current user has against a given set of roles.
- */
-function _og_user_roles_get_roles($uid, $roles = array()) {
-  // Added this to get gid
-  if (is_numeric(arg(2))) {
-    $gid = (int)arg(2);
-  }
+  // Use the menu system to get the path.
+  $path = $item['path'];
 
-  $roles_output = array();
-  if (is_array($roles)) {
-    foreach ($roles as $rid => $role) {
-      $result = db_result(db_query("SELECT * FROM {og_users_roles} WHERE uid = %d AND rid = %d AND gid = %d", $uid, $rid, $gid));
-      if ($result) {
-        $roles_output[$rid] = $rid;
-      }
-    }
+  // Check if this is an existing node.
+  if (!empty($object->nid)) {
+    $node = $object;
   }
-
-  return $roles_output;
-}
-
-/**
- * Theme function to render the table for the og_user_roles form.
- */
-function theme_og_user_roles_page_form($form) {
-  $output = '<div id="og-roles-form">';
-  $output .= '<div id="desc">' . t('Here you can assign group roles to members. This will give that member the permissions of that role in this group. It will apply to all posts within this group and will only apply to posts within this group.') . "</div>\n";
-
-  $header[] = array('data' => t('Roles'), 'colspan' => 2);
-  $rows = array();
-  $i = 0;
-  foreach ($form['user_roles']['users'] as $user_form) {
-    $uid = $user_form['#value'];
-    if ($uid) {
-      $rows[$i][] = drupal_render($form['user_roles']['roles'][$uid]);
-      $i++;
-    }
+  // Check if we are in the node add page.
+  elseif (strpos($path, 'node/add') === 0 && !empty($_REQUEST['gids'])) {
+    // URL pattern: node/add/story?gids[]=1
+    $gid = intval(current($_REQUEST['gids']));
+    $node = node_load($gid);
   }
-  $output .= theme('table', $header, $rows, array('id' => 'og-roles-table'));
-  $output .= drupal_render($form['submit']);
-  $output .= "</div>\n";
-  $output .= drupal_render($form);
-
-  return $output;
-}
-
-/**
- * Menu access callback; Determine access to group member role configuration.
- */
-function og_user_roles_is_allowed($node) {
-  if (!user_access('configure member roles')) {
-    return FALSE;
+  elseif ((!empty($item['map'][0]) && $item['map'][0] == 'og' && !empty($item['map'][2])) || $path == 'comment/reply/%') {
+    $node = og_user_roles_menu_get_object('node', 2);
   }
-  if (in_array($node->type, og_get_types('group')) && variable_get("og_user_roles_roles_$node->type", NULL)) {
-    return TRUE;
+  elseif ($path == 'comment/edit' || $path == 'comment/delete') {
+    // Get the node from the comment object.
+    $comment = _comment_load($item['page_arguments'][0]);
+    $node = node_load($comment->nid);
   }
-  return FALSE;
-}
 
-/**
- * Add role to og_users_roles table.
- *
- * @param $uid
- *   The user ID.
- * @param $rid
- *   The role ID.
- * @param $gid
- *   Node ID of the group for the user in this role.
- *
- * There is no return parameter, but "hook_og()" is invoked with args:
- * 'rid' (role ID) and 'ogr_id' (og_users_roles table ID for the newly created
- * record).
- */
-function og_user_roles_role_join($uid, $rid, $gid) {
-  // Modification.  http://drupal.org/node/174773
-  // Check to see if this user doesn't already have this role in this group;
-  // If not, then assign it.
-  $sql    = "SELECT COUNT(*) FROM {og_users_roles} WHERE uid = %d AND rid = %d and gid = %d";
-  $result = db_query($sql, $uid, $rid, $gid);
-  $output = (db_result($result));
-
-  if ($output == 0) {
-    $ogr_id = variable_get('og_user_roles_counter', 0) + 1;
-    variable_set('og_user_roles_counter', $ogr_id);
-    db_query("INSERT INTO {og_users_roles} (uid, rid, gid, ogr_id) VALUES (%d, %d, %d, %d)", $uid, $rid, $gid, $ogr_id);
-    $args['rid'] = $rid;
-    $args['ogr_id'] = $ogr_id;
-    module_invoke_all('og', 'user update', $gid, $uid, $args);
+  if (!empty($node) && ($group_node = og_determine_context_get_group($node))) {
+    return $group_node;
   }
 }
 
 /**
- * Remove all roles for a user in a group table.
- */
-function og_user_roles_role_leave($uid, $gid) {
-  db_query("DELETE FROM {og_users_roles} WHERE uid = %d AND gid = %d", $uid, $gid);
-}
-
-/**
- * Remove all roles for a group node that has been deleted.
- */
-function og_user_roles_role_remove($gid) {
-  db_query("DELETE FROM {og_users_roles} WHERE gid = %d", $gid);
-}
-
-/**
- * Remove this role from this user in this group.
- */
-function og_user_roles_role_delete($uid, $rid, $gid) {
-  db_query("DELETE FROM {og_users_roles} WHERE uid = %d AND gid = %d AND rid = %d", $uid, $gid, $rid);
-}
-
-/**
- * Implementation of hook_default_view_views().
- */
-function og_user_roles_views_default_views() {
-  $view               = new view;
-  $view->name         = 'OGURRoles';
-  $view->description  = 'OGUR role(s) that current user has in each group';
-  $view->tag          = 'ogur';
-  $view->view_php     = '';
-  $view->base_table   = 'node';
-  $view->is_cacheable = FALSE;
-  $view->api_version  = 2;
-  /* Edit this to true to make a default view disabled initially */
-  $view->disabled = FALSE;
-  $handler = $view->new_display('default', 'Defaults', 'default');
-  $handler->override_option('fields', array(
-      'nid' => array(
-        'label' => 'Group ID',
-        'alter' => array(
-          'alter_text' => 0,
-          'text' => '',
-          'make_link' => 0,
-          'path' => '',
-          'alt' => '',
-          'prefix' => '',
-          'suffix' => '',
-          'help' => '',
-          'trim' => 0,
-          'max_length' => '',
-          'word_boundary' => 1,
-          'ellipsis' => 1,
-          'html' => 0,
-        ),
-        'link_to_node' => 1,
-        'exclude' => 0,
-        'id' => 'nid',
-        'table' => 'node',
-        'field' => 'nid',
-        'relationship' => 'none',
-      ),
-      'title' => array(
-        'label' => 'Title',
-        'alter' => array(
-          'alter_text' => 0,
-          'text' => '',
-          'make_link' => 0,
-          'path' => '',
-          'alt' => '',
-          'prefix' => '',
-          'suffix' => '',
-          'help' => '',
-          'trim' => 0,
-          'max_length' => '',
-          'word_boundary' => 1,
-          'ellipsis' => 1,
-          'html' => 0,
-        ),
-        'link_to_node' => 1,
-        'exclude' => 0,
-        'id' => 'title',
-        'table' => 'node',
-        'field' => 'title',
-        'relationship' => 'none',
-      ),
-      'rid_all' => array(
-        'label' => 'Roles',
-        'alter' => array(
-          'alter_text' => 0,
-          'text' => '',
-          'make_link' => 0,
-          'path' => '',
-          'alt' => '',
-          'prefix' => '',
-          'suffix' => '',
-          'help' => '',
-          'trim' => 0,
-          'max_length' => '',
-          'word_boundary' => 1,
-          'ellipsis' => 1,
-          'html' => 0,
-        ),
-        'type' => 'separator',
-        'separator' => ', ',
-        'empty' => '',
-        'exclude' => 0,
-        'id' => 'rid_all',
-        'table' => 'og_users_roles',
-        'field' => 'rid_all',
-        'relationship' => 'none',
-      ),
-    ));
-  $handler->override_option('filters', array(
-      'type_groups' => array(
-        'operator' => 'in',
-        'value' => array(
-          'group' => 'group',
-        ),
-        'group' => '0',
-        'exposed' => FALSE,
-        'expose' => array(
-          'operator' => FALSE,
-          'label' => '',
-        ),
-        'id' => 'type_groups',
-        'table' => 'og',
-        'field' => 'type_groups',
-        'relationship' => 'none',
-      ),
-      'ricg' => array(
-        'operator' => '=',
-        'value' => '',
-        'group' => '0',
-        'exposed' => FALSE,
-        'expose' => array(
-          'operator' => FALSE,
-          'label' => '',
-        ),
-        'id' => 'ricg',
-        'table' => 'og_users_roles',
-        'field' => 'ricg',
-        'relationship' => 'none',
-      ),
-    ));
-  $handler->override_option('access', array(
-      'type' => 'none',
-    ));
-  $handler->override_option('items_per_page', 0);
-  $handler->override_option('distinct', 0);
-  $handler->override_option('style_plugin', 'table');
-  $handler = $view->new_display('page', 'Page', 'page_1');
-  $handler->override_option('path', 'og/ogurroles');
-  $handler->override_option('menu', array(
-      'type' => 'none',
-      'title' => '',
-      'description' => '',
-      'weight' => 0,
-      'name' => 'navigation',
-    ));
-  $handler->override_option('tab_options', array(
-      'type' => 'none',
-      'title' => '',
-      'description' => '',
-      'weight' => 0,
-    ));
-
-  $views[$view->name] = $view;
-
-  return $views;
-}
-
-/**
- * Implementation of hook_views_data()
+ * Get a router item.
+ *
+ * Due to the static $router_items, our initial query in hook_init() would
+ * perform a real access check for the current path and we would be no longer
+ * be able to grant privileges.
+ *
+ * In Drupal 7, this fork can probably be replaced with
+ * @code
+ * drupal_static_reset('menu_get_item');
+ * @endcode
+ *
+ * @see menu_get_item()
  */
-function og_user_roles_views_data() {
-  $data['og_users_roles']['table']['group'] = t('OGUR Groups');
-  $data['og_users_roles']['table']['join'] = array(
-    'node' => array(
-      'left_field' => 'nid',
-      'field' => 'gid',
-    ),
-    'users' => array(
-      'left_field' => 'uid',
-      'field' => 'uid',
-    ),
-    'role' => array(
-      'left_field' => 'rid',
-      'field' => 'rid',
-    ),
-  );
-  $data['og_users_roles']['gid'] = array(
-    'title' => t('OGUR group'),
-    'help' => t('OGUR group that a member belongs to.'),
-    'relationship' => array(
-      'title' => t('OGUR group node (member)'),
-      'help' => t("Bring in information about the OGUR group node based on a user's membership."),
-      'base' => 'node',
-      'field' => 'nid',
-      'handler' => 'views_handler_relationship',
-      'label' => t('Group node (member)'),
-    ),
-    'argument' => array(
-      'title' => t('Group node'),
-      'handler' => 'ogur_handler_argument_og_users_roles_gid',
-      'help' => t('<strong>Members</strong> are filtered for a specific group.'),
-    ),
-  );
-  $data['og_users_roles']['uid'] = array(
-    'title' => t('OGUR group member'),
-    'filter' => array(
-      'handler' => 'views_handler_filter_user_current',
-      'help' => t("OGUR: Group in user's groups"),
-    ),
-  );
-  $data['og_users_roles']['rid'] = array(
-    'title' => t('OGUR Roles'),
-    'help' => t('OGUR roles that a user belongs to in a specific group.'),
-    'field' => array(
-      'handler' => 'ogur_handler_field_og_users_roles',
-    ),
-    'filter' => array(
-      'handler' => 'ogur_handler_filter_og_users_roles',
-      'numeric' => TRUE,
-    ),
-    'argument' => array(
-      'handler' => 'ogur_handler_argument_og_users_roles_rid',
-      'name table' => 'role',
-      'name field' => 'name',
-      'empty field name' => t('No role'),
-      'numeric' => TRUE,
-    ),
-  );
-  $data['og_users_roles']['rid_all'] = array(
-    'real field' => 'rid',
-    'title' => t('OGUR All Roles'),
-    'help' => t('All OGUR roles that the current user or uid supplied as the <strong>first argument</strong> belongs to.  You can use this to get roles that the user (either current user or argument supplied uid) has in multiple groups.'),
-    'field' => array(
-      'handler' => 'ogur_handler_field_og_users_roles_all',
-    ),
-  );
-  $data['og_users_roles']['picg'] = array(
-    'title' => t('OGUR roles in current group'),
-    'help' => t('Roles in current group. This will make sure that roles returned are for current group only.'),
-    'filter' => array(
-      'handler' => 'ogur_handler_filter_og_users_roles_picg',
-    ),
-  );
-  $data['og_users_roles']['ricg'] = array(
-    'title' => t('OGUR roles in group'),
-    'help' => t('Current user or uid supplied as the <strong>first argument</strong> has roles in groups returned. This will make sure that only groups in which the user (either current user or argument supplied uid) has roles.'),
-    'filter' => array(
-      'handler' => 'ogur_handler_filter_og_users_roles_ricg',
-    ),
-  );
-
-  return $data;
-}
+function og_user_roles_menu_get_item($path = NULL, $router_item = NULL) {
+  static $router_items;
+  if (!isset($path)) {
+    $path = $_GET['q'];
+  }
+  if (isset($router_item)) {
+    $router_items[$path] = $router_item;
+  }
+  if (!isset($router_items[$path])) {
+    $original_map = arg(NULL, $path);
+    $parts = array_slice($original_map, 0, MENU_MAX_PARTS);
+    list($ancestors, $placeholders) = menu_get_ancestors($parts);
 
-/**
- * Implementation of hook_views_handlers() to register all of the basic handlers views uses.
- */
-function og_user_roles_views_handlers() {
-  return array(
-    'info' => array(
-      'path' => drupal_get_path('module', 'og_user_roles') . '/views/handlers',
-    ),
-    'handlers' => array(
-      'ogur_handler_field_og_users_roles' => array(
-        'parent' => 'views_handler_field_prerender_list',
-      ),
-      'ogur_handler_field_og_users_roles_all' => array(
-        'parent' => 'views_handler_field_prerender_list',
-      ),
-      'ogur_handler_filter_og_users_roles' => array(
-        'parent' => 'views_handler_filter_many_to_one',
-      ),
-      'ogur_handler_filter_og_users_roles_picg' => array(
-        'parent' => 'views_handler_filter',
-      ),
-      'ogur_handler_filter_og_users_roles_ricg' => array(
-        'parent' => 'views_handler_filter',
-      ),
-      'ogur_handler_argument_og_users_roles_rid' => array(
-        'parent' => 'views_handler_argument_many_to_one',
-      ),
-      'ogur_handler_argument_og_users_roles_gid' => array(
-        'parent' => 'views_handler_argument_numeric',
-      ),
-    ),
-  );
+    if ($router_item = db_fetch_array(db_query_range('SELECT * FROM {menu_router} WHERE path IN ('. implode (',', $placeholders) .') ORDER BY fit DESC', $ancestors, 0, 1))) {
+      $map = _menu_translate($router_item, $original_map);
+      if ($map === FALSE) {
+        $router_items[$path] = FALSE;
+        return FALSE;
+      }
+      // OGUR: Allow privilege escalation; always load map.
+      //if ($router_item['access']) {
+        $router_item['map'] = $map;
+        $router_item['page_arguments'] = array_merge(menu_unserialize($router_item['page_arguments'], $map), array_slice($map, $router_item['number_parts']));
+      //}
+    }
+    $router_items[$path] = $router_item;
+  }
+  return $router_items[$path];
 }
 
 /**
- * Implementation of hook_init().
+ * Get a loaded object from a router item.
+ *
+ * @see menu_get_object()
+ * @see og_user_roles_menu_get_item()
  */
-function og_user_roles_init() {
-  return;
-
-  global $user;
-
-  // Looking for this format: http://www.scbbs.com/node/add/link?gids[]=29
-  // We only need to process this if the user is logged in
-  if ($user->uid > 0) {
-    // Bootstrap if arg() doesn't exist
-    if ((!function_exists('arg') || !function_exists('node_load')) && $user->uid > 0) {
-      // http://drupal.org/node/273068
-      drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
-    }
-    // Modification as per: http://drupal.org/node/183860
-    // Further modification: changed og_user_roles_theme() to og_user_roles_determine_context()
-    og_user_roles_determine_context();
-
-    /**
-     * Modules exempted from ognodeadd:
-     * Originally for ad module: http://drupal.org/node/183081
-     * Added minutes module: http://drupal.org/node/184102
-     */
-    $exempted = array('ad', 'minutes');
-
-    $orig_query = $_SERVER['QUERY_STRING'];
-
-    // Get rid of Create Content 'node/add?gids[]'
-    $pattern = '/q\=.*node\/add\&gids\[\]\=(\d+)/i';
-    $orig_query = preg_replace($pattern, '', $orig_query);
-    // Get rid of Create Content 'node/ognodeadd&gids[]'
-    $pattern = '/q\=.*node\/ognodeadd\&gids\[\]\=(\d+)/i';
-    $orig_query = preg_replace($pattern, '', $orig_query);
-    // Get rid of Create Content 'node/ognodeadd&type='
-    $pattern = '/q\=.*node\/ognodeadd\&type\=(\w+)/i';
-    $orig_query = preg_replace($pattern, '', $orig_query);
-    // Get rid of 'node/add followed by &'
-    $pattern = '/q\=.*node\/add\/[^\&]+\&/i';
-    $orig_query = preg_replace($pattern, '', $orig_query);
-    // Get rid of 'node/add followed which ends the line'
-    $pattern = '/q\=.*node\/add\/[^\&]+$/i';
-    $orig_query = preg_replace($pattern, '', $orig_query);
-    // Get rid of 'gids[]='
-    // Modified to include original query: http://drupal.org/node/381570
-    //      $pattern = '/.*gids\[\]\=(\d+)[\&]?/i';
-    $pattern = '/[\?|\&]gids\[\]\=(\d+)[\&]?/i';
-    $orig_query = preg_replace($pattern, '', $orig_query);
-    // Get rid of 'node/ognodeadd'
-    $pattern = '/q\=.*node\/ognodeadd/i';
-    $orig_query = preg_replace($pattern, '', $orig_query);
-    // Get rid of '&' if it starts a line
-    $pattern = '/^\&/i';
-    $orig_query = preg_replace($pattern, '', $orig_query);
-
-    // If this is a group node/add, re-direct to ognodeadd
-    if (arg(0) == 'node' && arg(1) == 'add' && isset($_REQUEST['gids']) && (!in_array(arg(2), $exempted))) {
-
-      $gids = $_GET['gids'];
-      $gid  = intval(current($_REQUEST['gids']));
-      $type = arg(2);
-      $path = 'node/ognodeadd';
-
-      $query = 'type=' . $type . '&gids[]=' . $gid;
-
-      // Modification as per: http://drupal.org/node/156568
-      if (arg(0) == 'node' && arg(1) == 'add' && arg(2) == 'forum' && is_numeric(arg(3))) {
-        $query = 'type=' . $type . '&gids[]=' . $gid . '&tid=' . intval(arg(3));
-      }
-
-      // Modification to make it work with module 'Relativity'
-      // http://drupal.org/node/166253
-      if (module_exists('relativity')) {
-        if (arg(3) == 'parent' && is_numeric(arg(4))) {
-          $query .= '&parent_node=' . arg(4);
-        }
-        elseif (!empty($_GET['parent_node'])) {
-          $query .= '&parent_node=' . $_GET['parent_node'];
-        }
-      }
-
-      // Modification for book module - http://drupal.org/node/180243
-      // this: http://www.scbbs.com/node/add/book/parent/225&gids[]=29
-      // becomes this: http://www.scbbs.com/node/ognodeadd/0/parent/225?type=book&gids[]=29
-      if (module_exists('book') && $type == 'book' && arg(3) == 'parent' && is_numeric(arg(4))) {
-        $path .= '/book/parent/' . arg(4);
-      }
-
-      if ($orig_query) {
-        // If the original query and the new query both contain gids[], then
-        // eliminate the one in the new query.
-        if (preg_match('/gids\[\]/', $query) && preg_match('/gids\[\]/', $orig_query)) {
-          $pattern = '/\&gids\[\]\=(\d+)/i';
-          $query = preg_replace($pattern, '', $query);
-        }
-        $query = $query . '&' . $orig_query;
-      }
-      drupal_goto($path, $query);
-    }
-
-    // Modification as per: http://drupal.org/node/156568
-    // If this is a group node/add/forum with no gids, re-direct to ognodeadd and include gids
-    if (arg(0) == 'node' && arg(1) == 'add' && arg(2) == 'forum' && is_numeric(arg(3)) && (!isset($_REQUEST['gids']))) {
-      $type = arg(2);
-      $tid  = intval(arg(3));
-      $gid  = og_user_roles_gid_from_tid($tid);
-      // Hijack only if there is a gid value;
-      // Modificaton as per http://drupal.org/node/194214
-      if (!empty($gid) && $gid != 0) {
-        $path = 'node/ognodeadd';
-        $query = 'type=' . $type . '&gids[]=' . $gid . '&tid=' . $tid;
-        if ($orig_query) {
-          // If the original query and the new query both contain gids[], then
-          // eliminate the one in the new query.
-          if (preg_match('/gids\[\]/', $query) && preg_match('/gids\[\]/', $orig_query)) {
-            $pattern = '/\&gids\[\]\=(\d+)/i';
-            $query = preg_replace($pattern, '', $query);
-          }
-          $query = $query . '&' . $orig_query;
-        }
-        drupal_goto($path, $query);
-      }
-    }
-
-    // Modification as per: http://drupal.org/node/174959
-    // If this is a non-group node/add, but og_last session cookie is set
-    // then re-direct to ognodeadd
-    // But, make sure you don't redirect for omitted nodes.
-    if (arg(0) == 'node' && arg(1) == 'add' && isset($_SESSION['og_last']) && (!is_null(arg(2))) && (!in_array(arg(2), $exempted))) {
-      $gid = $_SESSION['og_last'];
-
-      $type = arg(2);
-      $path = 'node/ognodeadd';
-
-      // Modification as per: http://drupal.org/node/178610
-      // Need to make sure this node $type supports adding a group item
-      $og_audience_required = variable_get('og_audience_required', FALSE);
-      $og_omitted = variable_get('og_omitted', array());
-      // Added re: http://drupal.org/node/178610#comment-1158470
-      // Also: http://drupal.org/node/333860#comment-1119905
-      $og_permitted = og_is_group_post_type($type);
-      if ($og_permitted && $og_audience_required && (!in_array($type, $og_omitted))) {
-        $query = 'type=' . $type . '&gids[]=' . $gid;
-
-        // Modification to make it work with module 'Relativity'
-        // http://drupal.org/node/166253
-        if (module_exists('relativity')) {
-          if (arg(3) == 'parent' && is_numeric(arg(4))) {
-            $query .= '&parent_node=' . arg(4);
-          }
-          elseif (!empty($_GET['parent_node'])) {
-            $query .= '&parent_node=' . $_GET['parent_node'];
-          }
-        }
-
-        // Modification for book module - http://drupal.org/node/180243
-        // this: http://www.scbbs.com/node/add/book/parent/225&gids[]=29
-        // becomes this: http://www.scbbs.com/node/ognodeadd/0/parent/225?type=book&gids[]=29
-        if (module_exists('book') && $type == 'book' && arg(3) == 'parent' && is_numeric(arg(4))) {
-          $path .= '/book/parent/' . arg(4);
-        }
-
-        if ($orig_query) {
-          // If the original query and the new query both contain gids[], then
-          // eliminate the one in the new query.
-          if (preg_match('/gids\[\]/', $query) && preg_match('/gids\[\]/', $orig_query)) {
-            $pattern = '/\&gids\[\]\=(\d+)/i';
-            $query = preg_replace($pattern, '', $query);
-          }
-          $query = $query . '&' . $orig_query;
-        }
-        drupal_goto($path, $query);
-      }
-    }
-
-    // Modification for ad module: http://drupal.org/node/183081
-    // Add groupID if we are in group context.
-    if (module_exists('ad')) {
-      if (arg(0) == 'node' && arg(1) == 'add' && arg(2) == 'ad' && (arg(3) == 'image' || arg(3) == 'text') && isset($_SESSION['og_last']) && (!isset($_REQUEST['gids']))) {
-        $gid            = $_SESSION['og_last'];
-        $uri_request_id = request_uri();
-        $this_url       = parse_url($uri_request_id);
-        $this_path      = $this_url[path];
-        $base_path_len  = strlen(base_path());
-        $this_path2     = substr($this_path, $base_path_len);
-        $path           = $this_path2;
-
-        $query = 'gids[]=' . $gid;
-        // Only add if $gid > 0
-        if ($gid > 0) {
-          drupal_goto($path, $query);
-        }
-      }
-    }
-    // Modification for minutes module: http://drupal.org/node/184102
-    // Add groupID if we are in group context.
-    if (module_exists('minutes')) {
-      if (arg(0) == 'node' && arg(1) == 'add' && arg(2) == 'minutes' && is_numeric(arg(3)) && isset($_SESSION['og_last']) && (!isset($_REQUEST['gids']))) {
-        $gid            = $_SESSION['og_last'];
-        $uri_request_id = request_uri();
-        $this_url       = parse_url($uri_request_id);
-        $this_path      = $this_url[path];
-        $base_path_len  = strlen(base_path());
-        $this_path2     = substr($this_path, $base_path_len);
-        $path           = $this_path2;
-
-        $query = 'gids[]=' . $gid;
-        // Only add if $gid > 0
-        if ($gid > 0) {
-          drupal_goto($path, $query);
-        }
-      }
-    }
-
-    // If this is a group relativity or book module node/add, re-direct to ognodeadd
-    if (arg(0) == 'node' && arg(1) == 'add' && is_numeric(arg(4)) && (!in_array(arg(2), $exempted))) {
-      $type = arg(2);
-      $path = 'node/ognodeadd';
-
-      // Get the gid for this parent
-      $nid = (int)arg(4);
-      $gid = og_user_roles_getgid($nid, $user->uid);
-
-      $query = 'type=' . $type . '&gids[]=' . $gid;
-
-      // Modification to make it work with module 'Relativity'
-      // http://drupal.org/node/166253
-      // http://drupal.org/node/227978
-      if (module_exists('relativity')) {
-        if (arg(3) == 'parent') {
-          $query .= '&parent_node=' . arg(4);
-        }
-        elseif (!empty($_GET['parent_node'])) {
-          $query .= '&parent_node=' . $_GET['parent_node'];
-        }
-      }
-      // Book module as per: http://drupal.org/node/228386
-      if (module_exists('book') && $type == 'book' && arg(3) == 'parent' && is_numeric(arg(4))) {
-        $path .= '/book/parent/' . arg(4);
-      }
-      $query = 'type=' . $type . '&gids[]=' . $gid . '&tid=' . $tid;
-      drupal_goto($path, $query);
-    }
+function og_user_roles_menu_get_object($type = 'node', $position = 1, $path = NULL) {
+  $router_item = og_user_roles_menu_get_item($path);
+  if (isset($router_item['load_functions'][$position]) && !empty($router_item['map'][$position]) && $router_item['load_functions'][$position] == $type .'_load') {
+    return $router_item['map'][$position];
   }
 }
 
-/*
+/**
  * Implementation of hook_user().
  */
 function og_user_roles_user($op, &$edit, &$account, $category = NULL) {
   switch ($op) {
     case 'load':
-      // Skip first call via og_init().
-      og_user_roles_grant_all_roles($account);
-      break;
-
-    case 'view':
-      // Display user's group roles on user account.
-      if (user_access('administer organic groups')) {
-        $view = views_get_view('OGURRoles');
-        $user->content['summary']['og_user_roles'] = array(
-          '#type' => 'item',
-          '#title' => t('Group roles'),
-          '#value' => $view->execute_display('default', array($account->uid)),
-          '#attributes' => array('class' => 'og-user-roles'),
-        );
+      // In case the global user object is reloaded from scratch, re-assign
+      // our additional roles.
+      if ($account->uid == $GLOBALS['user']->uid) {
+        og_user_roles_grant_roles($account);
       }
       break;
 
@@ -982,22 +245,42 @@ function og_user_roles_user($op, &$edit,
 }
 
 /**
- * Retrieve all additional roles for a user, independent of the current group.
+ * Retrieve and assign additional roles for a user in the current group context.
+ *
+ * @param $account
+ *   The user object of the current user.
+ * @param $group_node
+ *   A group context determined by og_user_roles_determine_context()
+ *
+ * @see og_user_roles_init()
  */
-function og_user_roles_grant_all_roles(&$account) {
-  // Nothing to do, if user is not subscribed to any groups.
-  if (empty($account->og_groups)) {
+function og_user_roles_grant_roles(&$account, $group_node = NULL) {
+  static $roles;
+
+  // Sanity check for first and repeated calls.
+  // @see og_user_roles_init()
+  // @see og_user_roles_user()
+  if (!isset($group_node) && !isset($roles)) {
     return array();
   }
 
-  // Grant all additional roles.
-  $args = array_keys($account->og_groups);
-  $placeholders = db_placeholders($args);
-  array_unshift($args, $account->uid);
-  $result = db_query("SELECT ogur.rid, r.name FROM {og_users_roles} ogur INNER JOIN {role} r ON r.rid = ogur.rid WHERE ogur.uid = %d AND ogur.gid IN ($placeholders)", $args);
-  $roles = array();
-  while ($role = db_fetch_object($result)) {
-    $account->roles[$role->rid] = $roles[$role->rid] = $role->name;
+  if (!isset($roles)) {
+    // Retrieve additional roles for current context.
+    $args = array($group_node->nid);
+    $placeholders = db_placeholders($args);
+    array_unshift($args, $account->uid);
+    // INNER JOIN as extra sanity check (not only for role name).
+    $result = db_query("SELECT ogur.rid, r.name FROM {og_users_roles} ogur INNER JOIN {role} r ON r.rid = ogur.rid WHERE ogur.uid = %d AND ogur.gid IN ($placeholders)", $args);
+    while ($role = db_fetch_object($result)) {
+      // Add roles to account first, so we can statically cache all roles
+      // afterwards.
+      $account->roles[$role->rid] = $role->name;
+    }
+    $roles = $account->roles;
+  }
+  else {
+    // Grant all stored roles.
+    $account->roles = $roles;
   }
 
   // Reload user permissions.
@@ -1007,10 +290,14 @@ function og_user_roles_grant_all_roles(&
 }
 
 /**
- * implementation of hook_og().
+ * @} End of "defgroup og_user_roles_privilege_escalation".
+ */
+
+/**
+ * Implementation of hook_og().
  *
  * @param $op
- *   'user insert', 'user update', 'user delete'
+ *   The operation performed; 'user insert', 'user update', 'user delete'.
  * @param $nid
  *   Node ID of the group.
  * @param $uid
@@ -1021,47 +308,37 @@ function og_user_roles_grant_all_roles(&
 function og_user_roles_og($op, $nid, $uid, $args = array()) {
   switch ($op) {
     case 'user insert':
-      // --- Modification - 2007-06-18 - as per: http://drupal.org/node/152442
-      // Adding every user to a basic group role, that all users in the group should have.
-      // I don't know a better way, so I'll do it like this. Every user in the group should automagically get this role.
-      // -Bibo
-      if (variable_get('og_user_roles_assign_basicgrouprole', 0) == 1) {
-        $rid = variable_get('og_user_roles_basicgrouprole_value', 0);
-        // assign user to group role in that group
-        og_user_roles_role_join($uid, $rid, $nid);
+      // Add default role for new group members, if configured.
+      if ($default_role = variable_get('og_user_roles_default_role', 0)) {
+        og_user_roles_role_add($nid, $uid, $default_role);
       }
 
-      // --- Modification - 2008-01-10 - as per: http://drupal.org/node/197489
-      // Places all new group administrators into default group administrator role.
-      $admin = (isset($args['is_admin']) ? $args['is_admin'] : 0);
-      if (variable_get('og_user_roles_assign_admingrouprole', 0) == 1 && $admin == 1) {
-        $rid = variable_get('og_user_roles_admingrouprole_value', 0);
-        // assign user to group role in that group
-        og_user_roles_role_join($uid, $rid, $nid);
+      // Add default role for new group admins, if configured.
+      if (isset($args['is_admin']) && $args['is_admin']) {
+        if (($default_admin_role = variable_get('og_user_roles_default_admin_role', 0)) && $default_admin_role != $default_role) {
+          og_user_roles_role_add($nid, $uid, $default_admin_role);
+        }
       }
-
-      $user = user_load(array('uid' => $uid));
       break;
 
     case 'user update':
-      // --- Modification - 2008-01-10 - as per: http://drupal.org/node/197489
-      // Places all new group administrators into default group administrator role.
-      $admin = (isset($args['is_admin']) ? $args['is_admin'] : NULL);
-      if (variable_get('og_user_roles_assign_admingrouprole', 0) == 1 && $admin === 0) {
-        $rid = variable_get('og_user_roles_admingrouprole_value', 0);
-        // delete this admin role for this user in this group (if it exists)
-        og_user_roles_role_delete($uid, $rid, $nid);
-      }
-      if (variable_get('og_user_roles_assign_admingrouprole', 0) == 1 && $admin === 1) {
-        $rid = variable_get('og_user_roles_admingrouprole_value', 0);
-        // assign user to group role in that group
-        og_user_roles_role_join($uid, $rid, $nid);
+      $default_admin_role = variable_get('og_user_roles_default_admin_role', 0);
+      $default_role = variable_get('og_user_roles_default_role', 0);
+      if ($default_admin_role > 0 && $default_admin_role != $default_role) {
+        // Grant role for new group admin.
+        if (isset($args['is_admin']) && $args['is_admin']) {
+          og_user_roles_role_add($nid, $uid, $default_admin_role);
+        }
+        // Delete role for obsolete group admin.
+        else {
+          og_user_roles_role_delete($nid, $uid, $rid);
+        }
       }
       break;
 
     case 'user delete':
-      // Remove all roles for this user in this group if he is being unsubscribed;
-      og_user_roles_role_leave($uid, $nid);
+      // Remove all group roles for unsubscribed user.
+      og_user_roles_role_delete($nid, $uid);
       break;
   }
 }
@@ -1070,729 +347,17 @@ function og_user_roles_og($op, $nid, $ui
  * Implementation of hook_nodeapi().
  */
 function og_user_roles_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
-  global $user;
-
   switch ($op) {
-    case 'validate':
-      // Check to see if this user can post into other groups
-      if ($node->type) {
-        $type = $node->type;
-      }
-      elseif (arg(1) == 'add') {
-        $type = arg(2);
-      }
-      elseif (arg(1) == 'ognodeadd') {
-        $type = $_GET['type'];
-      }
-      // Check to see if this is a group post;
-      // Do we have group context?
-      if ($group_node = og_get_group_context()) {
-        // If this is a node that can be posted into groups
-        if (og_is_group_post_type($type)) {
-          // Does this node have groups?
-          if ($node->og_groups) {
-            foreach ($node->og_groups as $gid) {
-              if ((arg(1) == 'add' || arg(1) == 'ognodeadd') && $gid > 0) {
-                $access = FALSE;
-                // Get the module
-                $module = node_get_types('module', $type);
-                // Get all permissions for this module
-                $perms = module_invoke($module, 'perm');
-                // Look for the 'create' permission
-                foreach ($perms as $string) {
-                  // If this is a create permission
-                  if (preg_match('/create/', $string) || preg_match('/edit own blog/', $string)) {
-                    // See if the user has this permission in this group
-                    if (og_user_roles_user_access($string, $gid, $user->uid) === TRUE) {
-                      $access = TRUE;
-                    }
-                  }
-                }
-                if ($access === FALSE) {
-                  $temp_node = node_load($gid);
-                  $group_name = $temp_node->title;
-                  form_set_error('og_groups', t('You do not have permission to post this content type (' . $type . ') into Group: <strong>' . $group_name . '</strong> (' . $gid . ')'));
-                }
-              }
-              if ((arg(2) == 'edit' || arg(2) == 'delete') && $gid > 0) {
-                $access = FALSE;
-                $module = node_get_types('module', $type);
-                $perms = module_invoke($module, 'perm');
-                foreach ($perms as $string) {
-                  // If this is an edit string
-                  if (preg_match('/edit/', $string) || preg_match('/manage/', $string)) {
-                    if (og_user_roles_user_access($string, $gid, $user->uid) === TRUE) {
-                      $access = TRUE;
-                    }
-                  }
-                }
-                if ($access === FALSE) {
-                  $temp_node = node_load($gid);
-                  $group_name = $temp_node->title;
-                  form_set_error('og_groups', t('You do not have permission to edit or delete this content type (' . $type . ') in Group: <strong>' . $group_name . '</strong> (' . $gid . ')'));
-                }
-              }
-            }
-          }
-        }
-      }
-      break;
-
     case 'delete':
-      // Remove og_users_roles and variables related to group node if it is deleted;
-      // If this is a group node
+      // Remove all data for a deleted group.
       if (og_is_group_type($node->type)) {
-        og_user_roles_role_remove($node->nid);
-        og_user_roles_variable_remove($node->nid);
+        db_query("DELETE FROM {og_users_roles} WHERE gid = %d", $node->nid);
       }
       break;
   }
 }
 
 /**
- * Use this function to determine whether a user has a given privilege in a particular group.
- *
- * @param $string
- *   The permission, such as 'administer nodes', being checked for.
- * @param $gid
- *   The group id of the OG group.
- * @param $uid
- *   The uid of the user.
- *
- * @return
- *   TRUE if the current user has the requested permission.
- */
-function og_user_roles_user_access($string, $gid, $uid) {
-  $roles = array();
-  $perms = '';
-
-  // User #1 has all privileges:
-  if ($uid == 1) {
-    return TRUE;
-  }
-
-  if ($uid) {
-    $roles[DRUPAL_AUTHENTICATED_RID] = 'authenticated user';
-  }
-  else {
-    $roles[DRUPAL_ANONYMOUS_RID] = 'anonymous user';
-  }
-  // Get the normal roles
-  $result = db_query('SELECT r.rid, r.name FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid = %d', $uid);
-  while ($role = db_fetch_object($result)) {
-    $roles[$role->rid] = $role->name;
-  }
-  // Get the group roles
-  $result = db_query('SELECT r.rid, r.name FROM {role} r INNER JOIN {og_users_roles} ogr ON r.rid = ogr.rid INNER JOIN {og_uid} ogu ON ogu.uid = ogr.uid AND ogu.nid = ogr.gid WHERE ogr.uid = %d AND ogr.gid = %d AND ogu.is_active = 1', $uid, $gid);
-  while ($role = db_fetch_object($result)) {
-    $roles[$role->rid] = $role->name;
-  }
-  $rids         = array_keys($roles);
-  $placeholders = implode(',', array_fill(0, count($rids), '%d'));
-  $result       = db_query("SELECT DISTINCT(p.perm) FROM {role} r INNER JOIN {permission} p ON p.rid = r.rid WHERE r.rid IN ($placeholders)", $rids);
-  while ($row = db_fetch_object($result)) {
-    $perms .= "$row->perm, ";
-  }
-  return strpos($perms, "$string, ") !== FALSE;
-}
-
-/**
- * This function takes the global $user (or $account) value and returns a list
- * of group and non-group roles for this user.
- */
-function og_user_roles_all_roles($account) {
-  return;
-  // This will be the process to get BOTH the group and non-group roles for a user
-  $gid            = 0;
-  $gids           = array();
-  $nid            = 0;
-  $uri_request_id = request_uri();
-  $arg            = explode('/', $uri_request_id);
-  $ogroles        = array();
-  $x1             = 0;
-  // Need to use the referrer to get OG group in some cases;
-  $ref       = referer_uri();
-  $ref_url   = parse_url($ref);
-  $ref_path  = $ref_url['path'];
-  $ref_query = (isset($ref_url['query']) ? $ref_url['query'] : '');
-  $ref_arg   = explode('/', $ref_path);
-
-  // This will by default add the anonymous user role (no need since we merge user->roles)
-  // We get the groupID
-  $group_node = og_get_group_context();
-  $gid02      = (isset($group_node->nid) ? $group_node->nid : NULL);
-  $gid        = $gid02;
-  if ($gid02 === NULL) {
-    $gid = 0;
-  }
-  else {
-    if (isset($_SESSION['og_last'])) {
-      $_SESSION['og_last'] = $group_node->nid;
-    }
-  }
-
-  // If the above doesn't get the groupID, then we start trying stuff
-  if ($gid == 0) {
-    // http://doadance.scbbs.com/drupal03/node/79
-    if (arg(0) == 'node' && is_numeric(arg(1)) && is_null(arg(2))) {
-      $nid      = (int)arg(1);
-      $gid      = og_user_roles_getgid($nid, $account->uid);
-    }
-
-    // Translate pages using i18n translation module as per: http://drupal.org/node/203395
-    if (arg(0) == 'node' && arg(1) == 'add' && isset($_REQUEST['translation'])) {
-      $nid = intval($_REQUEST['translation']);
-      $gid = og_user_roles_getgid($nid, $account->uid);
-      if ($gid) {
-        // inject gid
-        $_GET['gids'] = array($gid);
-      }
-    }
-
-    // http://doadance.scbbs.com/node/79/edit
-    // http://doadance.scbbs.com/node/79/outline
-    // http://doadance.scbbs.com/node/79/track
-
-    // Modified 2007-07-05 for webform 'results';
-    // Modified 2007-07-23 for content_access 'access';
-    // Modified 2007-09-13 for 'galleries';
-    // Modified 2007-09-14 for 'email';
-    // Modified 2007-12-20 for 'revisions': http://drupal.org/node/202196
-    // Modified 2008-01-10 for 'workflow': http://drupal.org/node/208363
-    // Modified 2008-03-21 for 'feedapi': http://drupal.org/node/237258
-    // Modified 2008-12-24: How about just looking for nid in /node/<nid> instead of trying to
-    //                      anticipate each and every module.
-    // if (arg(0) == 'node' && is_numeric(arg(1)) && (arg(2) == 'edit' || arg(2) == 'outline' || arg(2) == 'track' || arg(2) == 'results' || arg(2) == 'access' || arg(2) == 'delete' || arg(2) == 'galleries' || arg(2) == 'email' || arg(2) == 'revisions' || arg(2) == 'signups' || arg(2) == 'agenda' || arg(2) == 'workflow' || arg(2) == 'votes' || arg(2) == 'refresh' || arg(2) == 'purge')) {
-    if (arg(0) == 'node' && is_numeric(arg(1))) {
-      $nid      = (int)arg(1);
-      $gid      = og_user_roles_getgid($nid, $account->uid);
-    }
-
-    // poll.module
-    if (arg(0) == 'poll' && is_numeric(arg(2)) && (arg(1) == 'cancel')) {
-      $nid      = (int)arg(2);
-      $gid      = og_user_roles_getgid($nid, $account->uid);
-    }
-
-    // print.module (printer friendly)
-    // http://www.mysite.com/print/14
-    if (arg(0) == 'print' && is_numeric(arg(1))) {
-      header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
-      header('Cache-Control: no-store, no-cache, must-revalidate');
-      header('Cache-Control: post-check=0, pre-check=0', FALSE);
-      header('Pragma: no-cache');
-
-      cache_clear_all();
-
-      $nid      = (int)arg(1);
-      $gid      = og_user_roles_getgid($nid, $account->uid);
-      // Set group context.
-      $group_node = node_load($gid);
-      og_set_group_context($group_node);
-    }
-
-    // http://www.mysite.com/comment/edit/14
-    if (arg(0) == 'comment' && is_numeric(arg(2)) && arg(1) == 'edit') {
-      $comment  = _comment_load(arg(2));
-      $nid      = $comment->nid;
-      $gid      = og_user_roles_getgid($nid, $account->uid);
-      // Set group context.
-      $group_node = node_load($gid);
-      og_set_group_context($group_node);
-    }
-
-    // http://www.mysite.com/comment/delete/14
-    if (arg(0) == 'comment' && is_numeric(arg(2)) && arg(1) == 'delete') {
-      $comment  = _comment_load(arg(2));
-      $nid      = $comment->nid;
-      $gid      = og_user_roles_getgid($nid, $account->uid);
-    }
-
-    // http://www.mysite.com/comment/reply/128#comment_form
-    if (arg(0) == 'comment' && arg(1) == 'reply') {
-      $subsections = explode('#', arg(2));
-      $nid         = (int)$subsections[0];
-      $gid         = og_user_roles_getgid($nid, $account->uid);
-    }
-
-    // og_term access
-    // http://www.mysite.com/node/add/forum/121
-    if (arg(0) == 'node' && is_numeric(arg(3)) && arg(1) == 'add') {
-      $nid      = (int)arg(3);
-      $gid      = og_user_roles_getgid($nid, $account->uid);
-    }
-
-    // Here we get the gid directly
-    // http://doadance.scbbs.com/node/79/view/tree
-    // http://doadance.scbbs.com/node/79/view/members
-    // http://doadance.scbbs.com/node/79/view
-    if (arg(0) == 'node' && is_numeric(arg(1)) && arg(2) == 'view') {
-      $gid = (int)arg(1);
-    }
-
-    // Here we get the gid directly
-    // http://doadance.scbbs.com/og/users/72
-    // http://doadance.scbbs.com/og/manage/72
-    if (arg(0) == 'og' && is_numeric(arg(2)) && is_null(arg(3))) {
-      $gid = (int)arg(2);
-    }
-
-    // og_theme_settings
-    // http://doadance.scbbs.com/admin/og/themes/edit/72
-    if (arg(1) == 'og' && is_numeric(arg(4)) && arg(2) == 'themes') {
-      $gid = (int)arg(4);
-      // Set group context.
-      $group_node = node_load($gid);
-      og_set_group_context($group_node);
-    }
-
-    // og_user_roles
-    // http://doadance.scbbs.com/og/users/72/roles
-    // http://doadance.scbbs.com/og/users/72/add
-    if (arg(0) == 'og' && arg(1) == 'users' && is_numeric(arg(2)) && is_null(arg(4))) {
-      $gid = (int)arg(2);
-    }
-
-    // og unsubscribe
-    // og_user_roles
-    // This is sort of a catch all for 'og' and gid in this order
-    // og/<whatever>/<gid>
-    // http://doadance.scbbs.com/og/unsubscribe/72
-    // http://doadance.scbbs.com/og/users/72/add
-    if (arg(0) == 'og' && is_numeric(arg(2))) {
-      $gid = (int)arg(2);
-    }
-
-    // og_forum
-    // http://doadance.scbbs.com/og_forum/manage/72
-    if (arg(0) == 'og_forum' && arg(1) == 'manage' && is_numeric(arg(2)) && is_null(arg(3))) {
-      $gid = (int)arg(2);
-    }
-
-    // http://doadance.scbbs.com/og_forum/manage/edit/72
-    // http://doadance.scbbs.com/og_forum/manage/add/72
-    if (arg(0) == 'og_forum' && arg(1) == 'manage' && is_numeric(arg(3))) {
-      $gid = (int)arg(3);
-    }
-
-    // og_calendar
-    // http://www.centralavedance.com/og_calendar/2973/2007/07/01
-    if (arg(0) == 'og_calendar' && is_numeric(arg(1))) {
-      $gid = (int)arg(1);
-    }
-
-    // og_forum
-    // http://www.mysite.com/og_forum/39/72?edit[og_groups][]=72
-    // http://www.mysite.com/og_forum/37/71?sort=asc&order=Replies&edit[og_groups][0]=71
-    // Modification as per: http://drupal.org/node/155882 - replaced $uri_request_id
-    // with arg() values.
-
-    if (arg(0) == 'og_forum' && is_numeric(arg(2)) && isset($_REQUEST['edit'])) {
-      $edit = $_GET['edit'];
-      if ($edit[og_groups][0] > 0) {
-        $gid = arg(2);
-      }
-    }
-
-    // http://www.mysite.com/forum/39
-    // Modification - 2007-07-04.  In the case where this is a forum
-    if (arg(0) == 'forum' && is_numeric(arg(1)) && is_null(arg(2))) {
-      $tid      = (int)arg(1);
-      $gid      = og_user_roles_gid_from_tid($tid);
-      // If no gid returned, then set $gid = 0
-      if (empty($gid)) {
-        $gid = 0;
-      }
-    }
-
-    // og create nodes (version 5.1)
-    // http://sbn.scbbs.com/node/add/forum?gids[]=72
-    // http://sbn.scbbs.com/node/add/simplenews?gids[]=72
-    // http://sbn.scbbs.com/node/add/webform?gids[]=72
-    // http://sbn.scbbs.com/node/add/video?gids[]=72
-    // http://sbn.scbbs.com/node/add/page?gids[]=72
-    // http://sbn.scbbs.com/node/add/blog?gids[]=72
-    // http://sbn.scbbs.com/node/add/event?gids[]=72
-    // http://sbn.scbbs.com/node/add/poll?gids[]=72
-    // http://sbn.scbbs.com/node/add/flexinode-3?gids[]=72
-    // Modification as per: http://drupal.org/node/155882 - replaced $uri_request_id
-    // with arg() values.
-    if (arg(0) == 'node' && arg(1) == 'add' && isset($_REQUEST['gids'])) {
-      $gids     = $_GET['gids'];
-      $gid      = intval(current($_REQUEST['gids']));
-    }
-
-    // og create nodes (custom node/20 aliased to node/ognodeadd)
-    // http://clients.brixrealtyinc.com/node/ognodeadd?type=document&gids[]=12
-    // Modification as per: http://drupal.org/node/155882
-    // We use arg() instead of $arg[] ($uri_request_id)
-    if (arg(0) == 'node' && arg(1) == 'ognodeadd') {
-      // Modification -- Get the gid from the variable instead of trying to calculate it.
-      //        -- In case we need to add 'tid=' to url as per:
-      //        -- http://drupal.org/node/156568
-      if (isset($_REQUEST['gids'])) {
-        $gids     = $_GET['gids'];
-        $gid      = intval(current($_REQUEST['gids']));
-      }
-    }
-
-    // File upload: http://www.scbbs.com/node/135/225#comment-225
-    if ((arg(0) == 'upload' && arg(1) == 'js') || (arg(0) == 'filemanager' && arg(1) == 'active')) {
-      // First, try and get gid from the session cookie
-      if (isset($_SESSION['og_last'])) {
-        $gid = $_SESSION['og_last'];
-      }
-      // If gid is still = 0, then try getting it from referrer
-      if ($gid == 0 || is_null($gid)) {
-        if ($ref_arg[1] == 'node' && is_numeric($ref_arg[2]) && $ref_arg[3] == 'edit') {
-          $nid = (int)$ref_arg[2];
-          $gid = og_user_roles_getgid($nid, $account->uid);
-          // Set group context.
-          $group_node = node_load($gid);
-          og_set_group_context($group_node);
-        }
-        if ($ref_arg[1] == 'node' && $ref_arg[2] == 'ognodeadd') {
-          parse_str($ref_query);
-          $gid = $gids[0];
-          // Set group context.
-          $group_node = node_load($gid);
-          og_set_group_context($group_node);
-        }
-      }
-    }
-    // File upload: comment_upload
-    // http://drupal.org/node/331838
-    if (arg(0) == 'comment-upload' && arg(1) == 'js') {
-      // First, try and get gid from the session cookie
-      if (isset($_SESSION['og_last'])) {
-        $gid = $_SESSION['og_last'];
-      }
-      // If gid is still = 0, then try getting it from referrer
-      if ($gid == 0 || is_null($gid)) {
-        if ($ref_arg[1] == 'node' && is_numeric($ref_arg[3]) && $ref_arg[2] == 'reply') {
-          $nid = (int)$ref_arg[3];
-          $gid = og_user_roles_getgid($nid, $account->uid);
-          // Set group context.
-          $group_node = node_load($gid);
-          og_set_group_context($group_node);
-        }
-      }
-    }
-    // File download
-    if (arg(0) == 'system' && arg(1) == 'files') {
-      if (isset($_SESSION['og_last'])) {
-        $gid = $_SESSION['og_last'];
-      }
-    }
-    // Listing by taxonomy terms
-    if (arg(0) == 'taxonomy' && arg(1) == 'term') {
-      if (isset($_SESSION['og_last'])) {
-        $gid = $_SESSION['og_last'];
-      }
-    }
-
-    // Files
-    if (arg(0) == 'files' || arg(1) == 'files') {
-      // Modification -- Get the gid from the variable instead of trying to calculate it.
-      if (isset($_REQUEST['gids'])) {
-        $gids       = $_GET['gids'];
-        $gid        = intval(current($_REQUEST['gids']));
-        $group_node = node_load($gid);
-        og_set_group_context($group_node);
-      }
-      elseif (isset($_SESSION['og_last'])) {
-        $gid        = $_SESSION['og_last'];
-        $group_node = node_load($gid);
-        og_set_group_context($group_node);
-      }
-      else {
-        // Need to get the file name;
-        $path     = $_SERVER['REQUEST_URI'];
-        $basename = basename($path);
-        $basename = urldecode($basename);
-        $basename = preg_replace('/\+/', ' ', $basename);
-        // Now, get the node associated with this file;
-        // 6.x has different file structure
-        //        $file = db_fetch_object(db_query("SELECT u.nid FROM {files} f INNER JOIN {upload} u ON f.fid = u.fid where f.filepath like '%s'", '%' . $basename));
-        $file       = db_fetch_object(db_query("SELECT u.nid FROM {files} f INNER JOIN {upload} u ON f.fid = u.fid where f.filepath like '%s'", '%' . '/' . $basename));
-        $nid        = $file->nid;
-        $gid        = og_user_roles_getgid($nid, $account->uid);
-        $group_node = node_load($gid);
-        og_set_group_context($group_node);
-      }
-    }
-
-    // Agenda module
-    // http://doadance.scbbs.com/node/agenda/list/279
-    if (arg(0) == 'node' && arg(1) == 'agenda' && arg(2) == 'list' && is_numeric(arg(3))) {
-      $nid      = (int)arg(3);
-      $gid      = og_user_roles_getgid($nid, $account->uid);
-    }
-
-    // Modification as per: http://drupal.org/node/204080
-    // Galleries (view part: The view urls can have 'subdirs' so we may need to check until the nth arg)
-    if (module_exists('og_galleries')) {
-      $og_gal_parts = split('/', og_galleries_get_url());
-      if (!empty($og_gal_parts)) {
-        $is_og_gal_url = TRUE;
-        $arg_num = 0;
-        foreach ($og_gal_parts as $value) {
-          if ($value != arg($arg_num++)) {
-            $is_og_gal_url = FALSE;
-          }
-        }
-        if ($is_og_gal_url && is_numeric(arg($arg_num))) {
-          $gid = (int)arg($arg_num);
-        }
-      }
-    }
-
-    // Book module
-    // As per: http://drupal.org/node/228386
-    // http://doadance.scbbs.com/book/export/html/279
-    if (arg(0) == 'book' && arg(1) == 'export' && arg(2) == 'html' && is_numeric(arg(3))) {
-      $nid      = (int)arg(3);
-      $gid      = og_user_roles_getgid($nid, $account->uid);
-    }
-
-    // Modification. As per: http://drupal.org/node/176390
-    // Present a hook for other modules: hook_og_user_roles_gid()
-    if ($results = module_invoke_all('og_user_roles_gid')) {
-      foreach ($results as $result) {
-        if ($result) {
-          $gid = $result;
-        }
-      }
-    }
-  }
-
-  // Now, using $account->uid and $gid we find out what roles this user has in this group;
-  if (empty($gid)) {
-    // This prevents us from getting error on non-group node/add
-    $gid = 0;
-  }
-  else {
-    if (isset($_SESSION['og_last'])) {
-      $_SESSION['og_last'] = $gid;
-    }
-  }
-
-/**
- * Modification as per http://drupal.org/node/189227
- * Makes sure use is 'active' (not in moderation) before any of these group roles are added.
- * Was: $query = 'SELECT r.rid, r.name FROM {role} r INNER JOIN {og_users_roles} ogr ON r.rid = ogr.rid WHERE ogr.uid = %d AND ogr.gid = %d';
- */
-
-  $query = 'SELECT r.rid, r.name FROM {role} r INNER JOIN {og_users_roles} ogr ON r.rid = ogr.rid INNER JOIN {og_uid} ogu ON ogu.uid = ogr.uid AND ogu.nid = ogr.gid WHERE ogr.uid = %d AND ogr.gid = %d AND ogu.is_active = 1';
-  $results = db_query($query, $account->uid, $gid);
-
-  // Create an array of these roles;
-  while ($row = db_fetch_array($results)) {
-    $x1 = $row['rid'];
-    $ogroles[$x1] = $row['name'];
-  }
-
-  // First, we need to create an array of $account->roles
-  $c = $account->roles;
-
-  // Next, we add the $account->roles array to the $ogroles array, if there is an ogroles array;
-  if ($x1 > 0) {
-    $d = array();
-    $d = $c + $ogroles;
-    $d = array_unique($d);
-  }
-  else {
-    $d = $c;
-  }
-
-  // $d is either the merged results, or just $account->roles;
-  return $d;
-}
-
-/**
- * This will return a $gid based upon the $nid and $uid supplied
- */
-function og_user_roles_getgid($nid, $uid) {
-  $gid = 0;
-
-  // See if this is a group itself
-  $result = db_query("SELECT og.nid from {og} og WHERE og.nid = %d", $nid);
-  while ($t = db_fetch_object($result)) {
-    $gid = $t->nid;
-  }
-
-  // See if our user is a member of this node's group.
-  if ($gid == 0) {
-    $result = db_query("SELECT oga.group_nid from {og_ancestry} oga INNER JOIN {og_uid} ogu ON ogu.nid = oga.group_nid WHERE oga.nid = %d AND ogu.uid = %d", $nid, $uid);
-    while ($t = db_fetch_object($result)) {
-      $gid = $t->group_nid;
-    }
-  }
-
-  // If this user is not a member of this group (fails test above), and this is a public node,
-  // then we just need to find the first group it belongs to.
-  if ($gid == 0) {
-    // See: http://drupal.org/node/432544
-    $result = db_query("SELECT oga.group_nid FROM {og_ancestry} oga WHERE oga.nid = %d", $nid);
-    while ($t = db_fetch_object($result)) {
-      $gid = $t->group_nid;
-    }
-  }
-
-  /**
-   * If $gid still equals 0 then try searching node_access table
-   * Modified as per: http://drupal.org/node/347277
-   */
-  if ($gid == 0) {
-    // modified to check for either the node ID in node_access
-    $result = db_query("SELECT na.gid from {node_access} na INNER JOIN {og_uid} ogu ON na.gid = ogu.nid WHERE na.realm = 'og_subscriber' AND ogu.uid = %d AND (na.nid = %d)", $uid, $nid, $nid);
-    while ($t = db_fetch_object($result)) {
-      $gid = $t->gid;
-    }
-  }
-
-  if ($gid == 0) {
-    // modified to check for group ID in node_access
-    $result = db_query("SELECT na.gid from {node_access} na INNER JOIN {og_uid} ogu ON na.gid = ogu.nid WHERE na.realm = 'og_subscriber' AND ogu.uid = %d AND (na.gid = %d)", $uid, $nid, $nid);
-    while ($t = db_fetch_object($result)) {
-      $gid = $t->gid;
-    }
-  }
-
-  // If $gid still equals 0 then try searching og_term table (if it exists)
-  // og forums will typically be listed here
-  if ($gid == 0 && module_exists('og_forum')) {
-    $result = db_query("SELECT ogt.nid from {og_term} ogt INNER JOIN {og_uid} ogu ON ogt.nid = ogu.nid WHERE ogt.tid = %d AND ogu.uid = %d", $nid, $uid);
-    while ($t = db_fetch_object($result)) {
-      $gid = $t->nid;
-    }
-  }
-
-  // As per: http://drupal.org/node/167180
-  // If gid still not found
-  if ($gid == 0) {
-    $node = db_fetch_object(db_query('SELECT nid, type FROM {node} WHERE nid = %d', $nid));
-    if (og_is_group_type($node->type)) {
-      $gid = $node->nid;
-    }
-    elseif (is_array($groups = og_get_node_groups($node))) {
-      $last_id = 0;
-      foreach ($groups as $id => $group) {
-        if ($group) {
-          // Need some way to determine the group to select in case of
-          // multiple groups.  Going to try using og_last session cookie.
-          // Just not sure if session will be set for current group by now.
-          if ($id == $_SESSION['og_last']) {
-            $gid = $id;
-          }
-          $last_id = $id;
-        }
-      }
-      // If there was no session with og_last session cookie, then set gid to last
-      // id located in groups.  Roll of the dice until we can find something more
-      // certain.
-      if ($gid == 0) {
-        $gid = $last_id;
-      }
-    }
-  }
-
-  return $gid;
-}
-
-/**
- * Create content
- * Format: http://www.scbbs.com/node/ognodeadd?type=link&gids[]=29
- */
-function og_user_roles_ognodeadd() {
-  global $user;
-
-  require ('modules/node/node.pages.inc');
-
-  // This returns normal $user->roles and includes OG roles if any
-  $roles       = og_user_roles_all_roles($user);
-  $user->roles = $roles;
-  $gids        = $_GET['gids'];
-  if ($gids) {
-    $group_node = node_load($gids[0]);
-    og_set_group_context($group_node);
-  }
-
-  $type = $_GET['type'];
-  // Convert the dashes in the URL back to underscores. http://drupal.org/node/349648
-  $type = str_replace('-', '_', $type);
-
-  if ($type) {
-    // Got this from node.module (node_access)
-    // No matter the type, this should return us the create permission.
-    $module = node_get_types('module', $type);
-
-    if ($module == 'node') {
-      // Avoid function name collisions.
-      $module = 'node_content';
-    }
-
-    $access = module_invoke($module, 'access', 'create', $type, $user);
-    if ($access === TRUE) {
-      $content_type = node_get_types('type', $type);
-      $output = '<p>' . filter_xss_admin($content_type->help) . '</p>';
-      $output .= node_add($type);
-    }
-    else {
-      $output = 'Access denied.';
-      watchdog('access denied', 'User can not create this node type:<strong> ' . $type . '</strong>', $variables = array(), WATCHDOG_WARNING, 'node/ognodeadd?type=' . $type . '&gids[]=' . $gids[0]);
-    }
-  }
-  else {
-    /**
-     * Modification: Creates an overview page with the allowed node types for this user and group
-     * when there is no type in the url query. This page is similar to generic node/add page
-     * Taken and modified from node_add() function in node core module and og_og_create_links() in og module
-     * If no (valid) node type has been provided, display a node type overview.
-     * http://drupal.org/node/203875
-     */
-    $exempt = array_merge(og_get_types('group'), variable_get('og_omitted', array()));
-    foreach (node_get_types() as $type) {
-      // we used to check for node_access(create) but then node admins would get a false positive and see node types that they could not create
-      if (!in_array($type->type, $exempt) && module_invoke(node_get_types('module', $type), 'access', 'create', $type, $user)) {
-        // Why is this needed?
-        // $type_url_str = str_replace('_', '-', $type->type);
-        $type_url_str = $type->type;
-        $title        = t('Add a new @s.', array('@s' => $type->name));
-        $out          = '<dt>' . l(drupal_ucfirst($type->name), "node/add/$type_url_str", array('attributes' => array('title' => $title), 'query' => 'gids[]=' . $gids[0])) . '</dt>';
-        $out .= '<dd>' . filter_xss_admin($type->description) . '</dd>';
-        $item[$type->type] = $out;
-      }
-    }
-
-    if (isset($item)) {
-      uksort($item, 'strnatcasecmp');
-      $output = t('Choose the appropriate item from the list:') . '<dl>' . implode('', $item) . '</dl>';
-    }
-    else {
-      $output = t('No content types available.');
-    }
-  }
-
-  return $output;
-}
-
-/**
- * using the og_forum tid, get the group id
- * stolen from og_forum (had to in the case where og_user_roles user doesn't have latest
- * version of og_forum module which includes this)
- */
-function og_user_roles_gid_from_tid($tid = 0) {
-  // Modification as per: http://drupal.org/node/172923
-  if (module_exists('og_forum')) {
-    $sql = "SELECT nid FROM {og_term} WHERE tid = %d";
-    $gid = db_result(db_query($sql, $tid));
-  }
-  // As per http://drupal.org/node/194214
-  return empty($gid) ? 0 : $gid;
-}
-
-/**
  * Implementation of hook_form_FORM_ID_alter().
  */
 function og_user_roles_form_user_admin_role_alter(&$form, $form_state) {
@@ -1803,120 +368,67 @@ function og_user_roles_form_user_admin_r
  * Form submit handler for user role delete button.
  */
 function og_user_roles_user_admin_role_delete_submit($form, &$form_state) {
-  // Remove from og_users_roles table all rows with this rid:
+  // Remove all role assignments for deleted user role.
   db_query('DELETE FROM {og_users_roles} WHERE rid = %d', $form_state['values']['rid']);
 }
 
 /**
- * This is what is in OG.  og_user_roles_theme() was returning error, so decided to
- * try this.
+ * Implementation of hook_link_alter().
+ *
+ * @todo Move into OG.
  */
-function og_user_roles_determine_context() {
-  global $custom_theme;
-  // a node object containing the 'active' group for this request
-  $group_node = NULL;
-
-  $type = (isset($_GET['type']) ? $_GET['type'] : NULL);
-
-  if (arg(0) == 'og' && is_numeric(arg(2))) {
-    $group_node = og_set_theme(arg(2));
-  }
-  elseif (arg(0) == 'node' && is_numeric(arg(1))) {
-    $group_node = og_set_theme(arg(1));
-  }
-  elseif (arg(0) == 'node' && (arg(1) == 'add' || arg(1) == 'ognodeadd') && (arg(2) == 'book' || $type == 'book') && arg(3) == 'parent') {
-    $group_node = og_set_theme(arg(4));
-    // checks the right box on node form
-    $_REQUEST['edit']['og_groups'][] = $group_node->nid;
-  }
-  elseif (arg(0) == 'node' && (arg(1) == 'add' || arg(1) == 'ognodeadd') && isset($_REQUEST['gids'])) {
-    $gid          = intval(current($_REQUEST['gids']));
-    $group_node   = node_load($gid);
-    $custom_theme = $group_node->og_theme;
-  }
-  // As per: http://drupal.org/node/194214
-  elseif (arg(0) == 'forum' && is_numeric(arg(1))) {
-    $tid = intval(arg(1));
-    $gid = og_user_roles_gid_from_tid($tid);
-    if (!empty($gid)) {
-      $group_node = node_load($gid);
-      $custom_theme = $group_node->og_theme;
-    }
-  }
-  elseif (arg(0) == 'og_calendar' && is_numeric(arg(1))) {
-    $gid          = intval(arg(1));
-    $group_node   = node_load($gid);
-    $custom_theme = $group_node->og_theme;
-  }
-  elseif (arg(0) == 'comment' && is_numeric(arg(2))) {
-    if (arg(1) == 'edit') {
-      $comment    = _comment_load(arg(2));
-      $nid        = $comment->nid;
-      $gid        = og_user_roles_getgid($nid, $uid);
-      $group_node = og_set_theme($gid);
-    }
-    else {
-      $group_node = og_set_theme(arg(2));
-    }
-  }
-  elseif (arg(0) == 'user' && arg(1) == 'register' && isset($_REQUEST['gids'])) {
-    $gid          = intval(current($_REQUEST['gids']));
-    $group_node   = node_load($gid);
-    $custom_theme = $group_node->og_theme;
+function og_user_roles_link_alter(&$links, $node) {
+  $group_node = og_get_group_context();
+  if (!empty($group_node->nid) && isset($links['book_add_child'])) {
+    $links['book_add_child']['query'] .= '&gids[]=' . $group_node->nid;
   }
-
-  og_set_group_context($group_node);
 }
 
 /**
- * Implementation of hook_link_alter
+ * Return assigned roles for a user in a group.
  */
-function og_user_roles_link_alter(&$links, $node) {
-  $node = og_get_group_context();
-  if (!empty($node->nid)) {
-    $gid = $node->nid;
-    foreach ($links as $type => $link) {
-      if ($type == 'book_add_child') {
-        $links['book_add_child']['query'] .= '&gids[]=' . $gid;
-      }
-    }
+function og_user_roles_get_roles_by_group($gid, $uid) {
+  $assigned_roles = array();
+  $result = db_query("SELECT rid FROM {og_users_roles} WHERE uid = %d AND gid = %d", $uid, $gid);
+  while ($rid = db_result($result)) {
+    $assigned_roles[$rid] = $rid;
   }
+  return $assigned_roles;
 }
 
-/*
- * Implementation of hook_node_grants().
+/**
+ * Grant a role for a user in a group.
+ *
+ * @param $gid
+ *   The group ID.
+ * @param $uid
+ *   The user ID.
+ * @param $rid
+ *   The role ID to grant.
  */
-function og_user_roles_node_grants($account, $op) {
-  $grants = array('ogr_access' => array());
-  $result = db_query("SELECT ogr_id FROM {og_users_roles} WHERE uid = %d", $account->uid);
-  while ($row = db_fetch_object($result)) {
-    $grants['ogr_access'][] = $row->ogr_id;
+function og_user_roles_role_add($gid, $uid, $rid) {
+  $granted = db_result(db_query_range("SELECT rid FROM {og_users_roles} WHERE gid = %d AND uid = %d AND rid = %d", $gid, $uid, $rid, 0, 1));
+  if (!$granted) {
+    db_query("INSERT INTO {og_users_roles} (uid, gid, rid) VALUES (%d, %d, %d)", $uid, $gid, $rid);
   }
-  return !empty($grants['ogr_access']) ? $grants : NULL;
 }
 
 /**
- * Get the OG roles a user has in a group
- *
- * @param
- *   User ID
- * @param
- *   Group ID
+ * Grant a role or all roles for a user in a group.
  *
- * @return array
- *   An array containing the [roleID => roleName] that the user has in this group
+ * @param $gid
+ *   The group ID.
+ * @param $uid
+ *   The user ID.
+ * @param $rid
+ *   (Optional) The role ID to remove. If omitted, all roles are removed.
  */
-function og_user_roles_get_og_roles($uid, $gid) {
-  $roles = array();
-  // Get the group roles
-  $result = db_query('SELECT r.rid, r.name FROM {role} r INNER JOIN {og_users_roles} ogr ON r.rid = ogr.rid INNER JOIN {og_uid} ogu ON ogu.uid = ogr.uid AND ogu.nid = ogr.gid WHERE ogr.uid = %d AND ogr.gid = %d AND ogu.is_active = 1', $uid, $gid);
-  while ($role = db_fetch_object($result)) {
-    $roles[$role->rid] = $role->name;
+function og_user_roles_role_delete($gid, $uid, $rid = NULL) {
+  if (is_null($rid)) {
+    db_query("DELETE FROM {og_users_roles} WHERE gid = %d AND uid = %d", $gid, $uid);
+  }
+  else {
+    db_query("DELETE FROM {og_users_roles} WHERE gid = %d AND uid = %d AND rid = %d", $gid, $uid, $rid);
   }
-  return $roles;
-}
-
-function og_user_roles_list_users_sql($min_is_active = 1, $min_is_admin = 0, $orderby = 'u.name ASC') {
-  return "SELECT u.uid, u.name, u.mail, u.picture, ou.* FROM {og_uid} ou INNER JOIN {users} u ON ou.uid = u.uid WHERE ou.nid = %d AND u.status > 0 AND ou.is_active >= $min_is_active AND ou.is_admin >= $min_is_admin ORDER BY $orderby";
 }
 
Index: og_user_roles.pages.inc
===================================================================
RCS file: og_user_roles.pages.inc
diff -N og_user_roles.pages.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ og_user_roles.pages.inc	25 May 2009 08:44:45 -0000
@@ -0,0 +1,163 @@
+<?php
+// $Id: og_user_roles.module,v 1.33 2009/05/25 03:26:04 sun Exp $
+
+/**
+ * @file
+ * Page callbacks for OG user roles.
+ */
+
+/**
+ * Form builder for administrative settings.
+ */
+function og_user_roles_admin_settings() {
+  // Get list of all og-enabled node types.
+  $group_types = og_get_types('group');
+  $types = array();
+  foreach ($group_types as $type) {
+    $types[$type] = node_get_types('name', $type);
+  }
+
+  // Get list of roles, not counting authenticated and anonymous user.
+  $all_roles = user_roles();
+  foreach ($all_roles as $rid => $role) {
+    if ($rid > 2) {
+      $roles[$rid] = $role;
+    }
+  }
+  // If no assignable roles, advise user to add some.
+  if (empty($roles)) {
+    $form['og_user_roles'] = array(
+      '#value' => '<p>' . t('No assignable roles were found. User roles can be created on the <a href="@admin-user-roles-url">Roles</a> configuration page.', array('@admin-user-roles-url' => url('admin/user/roles'))) . '</p>',
+    );
+    return $form;
+  }
+
+  // Create a fieldset for each group type containing role selections.
+  $form['og_user_roles'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Assignable roles'),
+  );
+  foreach ($types as $type => $name) {
+    $form['og_user_roles']["og_user_roles_roles_$type"] = array(
+      '#type' => 'checkboxes',
+      '#title' => t('Roles for %name groups', array('%name' => $name)),
+      '#options' => $roles,
+      '#default_value' => variable_get("og_user_roles_roles_$type", array()),
+    );
+  }
+
+  $form['og_user_roles_defaults'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Default role assignments'),
+    '#description' => t('Select a role to automatically assign to users who join a group.'),
+    '#collapsible' => TRUE,
+  );
+  $form['og_user_roles_defaults']['og_user_roles_default_admin_role'] = array(
+    '#type' => 'select',
+    '#title' => t('Default role for new group administrators'),
+    '#options' => array(0 => t('None')) + $roles,
+    '#default_value' => variable_get('og_user_roles_default_admin_role', 0),
+    '#description' => t('This role can only be unassigned by removing a user from the administrators of a group.'),
+  );
+  $form['og_user_roles_defaults']['og_user_roles_default_role'] = array(
+    '#type' => 'select',
+    '#title' => t('Default role for new group members'),
+    '#options' => array(0 => t('None')) + $roles,
+    '#default_value' => variable_get('og_user_roles_default_role', 0),
+  );
+
+  return system_settings_form($form);
+}
+
+/**
+ * Menu callback; displays members and role selection
+ */
+function og_user_roles_page($node) {
+  $output = '';
+
+  drupal_set_title(t('Member roles for !title', array('!title' => l($node->title, "node/$node->nid"))));
+
+  $allowed_roles = array_filter(variable_get("og_user_roles_roles_{$node->type}", array()));
+  $user_roles = user_roles();
+  foreach ($allowed_roles as $rid => $checked) {
+    $roles[$rid] = $user_roles[$rid];
+  }
+
+  // Retrieve list of all group users
+  $sql = og_list_users_sql(0, 0, 'ou.is_admin DESC, ou.is_active ASC, u.name ASC');
+  $result = pager_query($sql, 100, 0, NULL, $node->nid);
+  $output .= theme('pager', NULL, 100, 0);
+  $output .= drupal_get_form('og_user_roles_page_form', $node, $roles, $result);
+
+  return $output;
+}
+
+/**
+ * Form builder for group user roles assignment.
+ */
+function og_user_roles_page_form($form_state, $node, $roles, $result) {
+  $form['#node'] = $node;
+  // Used for theming.
+  $form['#id'] = 'og-user-roles';
+  $form['#roles'] = $roles;
+
+  // Unset role titles.
+  foreach ($roles as $rid => $name) {
+    $roles[$rid] = '';
+  }
+
+  $form['user_roles'] = array('#tree' => TRUE);
+  while ($account = db_fetch_object($result)) {
+    $form['user_roles'][$account->uid]['user'] = array(
+      '#value' => theme('username', $account),
+    );
+    $form['user_roles'][$account->uid]['roles'] = array(
+      '#type' => 'checkboxes',
+      '#default_value' => og_user_roles_get_roles_by_group($node->nid, $account->uid),
+      '#options' => $roles,
+      '#parents' => array('user_roles', $account->uid),
+    );
+  }
+  $form['submit'] = array('#type' => 'submit', '#value' => t('Save'));
+
+  return $form;
+}
+
+/**
+ * Form submit handler for group user roles assignment form.
+ */
+function og_user_roles_page_form_submit($form, &$form_state) {
+  $gid = $form['#node']->nid;
+
+  foreach ($form_state['values']['user_roles'] as $uid => $new_roles) {
+    db_query("DELETE FROM {og_users_roles} WHERE uid = %d AND gid = %d", $uid, $gid);
+    $new_roles = array_filter($new_roles);
+    foreach ($new_roles as $rid => $checked) {
+      db_query("INSERT INTO {og_users_roles} (uid, gid, rid) VALUES (%d, %d, %d)", $uid, $gid, $rid);
+    }
+  }
+
+  drupal_set_message(t('The changes have been saved.'));
+}
+
+/**
+ * Render the group user roles assignment form like user permissions table.
+ */
+function theme_og_user_roles_page_form($form) {
+  $header = array_merge(array(''), $form['#roles']);
+
+  $rows = array();
+  foreach (element_children($form['user_roles']) as $item) {
+    $row = array();
+    $row[] = drupal_render($form['user_roles'][$item]['user']);
+    foreach (element_children($form['user_roles'][$item]['roles']) as $role) {
+      $row[] = drupal_render($form['user_roles'][$item]['roles'][$role]);
+    }
+    $rows[] = $row;
+  }
+
+  $output = theme('table', $header, $rows);
+  $output .= drupal_render($form);
+  return $output;
+}
+
Index: tests/og_user_roles.test
===================================================================
RCS file: tests/og_user_roles.test
diff -N tests/og_user_roles.test
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/og_user_roles.test	25 May 2009 09:10:22 -0000
@@ -0,0 +1,121 @@
+<?php
+// $Id: block.test,v 1.1.2.1.2.2 2009/04/23 05:39:52 sun Exp $
+
+/**
+ * @file
+ * OG User Roles tests.
+ */
+
+require_once drupal_get_path('module', 'og') .'/tests/og_testcase.php';
+
+class OGUserRolesTestCase extends OgTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => t('OG User Roles functionality'),
+      'description' => t('Add, edit and delete custom block. Configure and move a module-defined block.'),
+      'group' => t('Organic groups'),
+    );
+  }
+
+  /**
+   * Implementation of setUp().
+   */
+  function setUp() {
+    parent::setUp('views', 'og', 'og_views', 'og_user_roles');
+
+    // Create and log in an administrative user with all permissions.
+    $permissions = module_invoke_all('perm');
+    $this->admin_user = $this->drupalCreateUser($permissions);
+    $this->drupalLogin($this->admin_user);
+
+    // Create a group node content type.
+    $this->og_group_type = $this->drupalCreateContentType();
+    variable_set('og_content_type_usage_' . $this->og_group_type->name, 'group');
+
+    // Create a group post content type.
+    $this->og_post_type = $this->drupalCreateContentType();
+    variable_set('og_content_type_usage_' . $this->og_post_type->name, 'group_post');
+
+    // Create two groups and a post for each group.
+    $this->gid1 = $this->addOgGroup($this->og_group_type->name);
+    $this->gid2 = $this->addOgGroup($this->og_group_type->name);
+    $this->nid1 = $this->addOgPost($this->og_post_type->name, array($this->gid1));
+    $this->nid2 = $this->addOgPost($this->og_post_type->name, array($this->gid2));
+
+    // Rebuild the menu so the new content types will appear in the menu.
+    menu_rebuild();
+
+    // Create a web user.
+    $web_user = $this->drupalCreateUser(array('access comments', 'access content'));
+    $this->web_user = $web_user;
+
+    // Subscribe web user to first group.
+    $result = module_invoke('og', 'subscribe_user', $this->gid1, $web_user);
+    $this->assertTrue(isset($result['type']) && $result['type'] == 'subscribed', 'Web user subscribed to organic group.');
+
+    // Create a role for OGUR privilege escalation.
+    $this->drupalPost('admin/user/roles', array('name' => 'ogur'), 'Add role');
+    $this->role_ogur = db_result(db_query("SELECT rid FROM {role} WHERE name = '%s'", 'ogur'));
+    $this->assertTrue($this->role_ogur > 0, 'User role for OGUR was created.');
+
+    // Allow group admins to assign 'ogur' role.
+    $edit = array(
+      'og_user_roles_roles_' . $this->og_group_type->name . '[' . $this->role_ogur . ']' => 1,
+    );
+    $this->drupalPost('admin/og/og_user_roles', $edit, 'Save configuration');
+
+    // Allow users in role 'ogur' to alter stories and post comments.
+    $edit = array(
+      $this->role_ogur . '[create ' . $this->og_post_type->name . ' content]' => 1,
+      $this->role_ogur . '[delete any ' . $this->og_post_type->name . ' content]' => 1,
+      $this->role_ogur . '[edit any ' . $this->og_post_type->name . ' content]' => 1,
+      $this->role_ogur . '[post comments]' => 1,
+      $this->role_ogur . '[post comments without approval]' => 1,
+    );
+    $this->drupalPost('admin/user/permissions', $edit, t('Save permissions'));
+  }
+
+  /**
+   * Test user role escalation.
+   */
+  function testUserRoleEscalation() {
+    // Assign role 'ogur' to web user in first group.
+    $edit = array(
+      'user_roles[' . $this->web_user->uid . '][' . $this->role_ogur . ']' => 1,
+    );
+    $this->drupalPost('og/users/' . $this->gid1 . '/roles', $edit, 'Save');
+
+    // Load group posts.
+    $node1 = node_load($this->nid1);
+    $node2 = node_load($this->nid2);
+
+    // Verify that group posts are displayed on front page.
+    $this->drupalGet('');
+    $this->assertText($node1->title, $node1->title . ' found');
+    $this->assertText($node2->title, $node2->title . ' found');
+
+    // Log in web user.
+    $this->drupalLogin($this->web_user);
+
+    // Verify that user is not permitted to create content.
+    $this->assertNoLink('Create content');
+    // Verify that user can access both group posts.
+    $this->drupalGet('');
+    $this->assertText($node1->title, $node1->title . ' found');
+    $this->assertText($node2->title, $node2->title . ' found');
+
+    // Verify that user cannot edit group post belonging to second group.
+    $this->drupalGet('node/' . $node2->nid);
+    $this->assertNoLink('Edit');
+
+    // Verify that user can edit group post belonging to first group.
+    $this->drupalGet('node/' . $node1->nid);
+    $this->assertLink('Edit');
+    $this->clickLink('Edit');
+    $this->drupalPost(NULL, array(), 'Save');
+    $t_args = array('@type' => $this->og_post_type->name, '%title' => $node1->title);
+    $this->assertRaw(t('@type %title has been updated.', $t_args), 'Web user can update post in group.');
+  }
+}
+
Index: views/handlers/ogur_handler_argument_og_users_roles_gid.inc
===================================================================
RCS file: views/handlers/ogur_handler_argument_og_users_roles_gid.inc
diff -N views/handlers/ogur_handler_argument_og_users_roles_gid.inc
--- views/handlers/ogur_handler_argument_og_users_roles_gid.inc	23 May 2009 03:12:57 -0000	1.3
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,27 +0,0 @@
-<?php
-// $Id: ogur_handler_argument_og_users_roles_gid.inc,v 1.3 2009/05/23 03:12:57 sun Exp $
-
-class ogur_handler_argument_og_users_roles_gid extends views_handler_argument_numeric {
-  // Set context based on first node passed.
-  function query() {
-    $args = explode(',', $this->argument);
-    $node = node_load((int)$args[0]);
-    og_set_group_context($node);
-    parent::query();
-  }
-
-  /**
-   * Override the behavior of title(). Get the title of the node.
-   */
-  function title_query() {
-    $titles = array();
-    $placeholders = implode(', ', array_fill(0, sizeof($this->value), '%d'));
-
-    $result = db_query("SELECT n.title FROM {node} n WHERE n.nid IN ($placeholders)", $this->value);
-    while ($term = db_fetch_object($result)) {
-      $titles[] = check_plain($term->title);
-    }
-    return $titles;
-  }
-}
-
Index: views/handlers/ogur_handler_argument_og_users_roles_rid.inc
===================================================================
RCS file: views/handlers/ogur_handler_argument_og_users_roles_rid.inc
diff -N views/handlers/ogur_handler_argument_og_users_roles_rid.inc
--- views/handlers/ogur_handler_argument_og_users_roles_rid.inc	23 May 2009 03:12:57 -0000	1.3
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,19 +0,0 @@
-<?php
-// $Id: ogur_handler_argument_og_users_roles_rid.inc,v 1.3 2009/05/23 03:12:57 sun Exp $
-
-/**
- * Allow role ID(s) as argument
- */
-class ogur_handler_argument_og_users_roles_rid extends views_handler_argument_many_to_one {
-  function title_query() {
-    $titles = array();
-    $placeholders = implode(', ', array_fill(0, sizeof($this->value), '%d'));
-
-    $result = db_query("SELECT name FROM {role} WHERE rid IN ($placeholders)", $this->value);
-    while ($term = db_fetch_object($result)) {
-      $titles[] = check_plain($term->name);
-    }
-    return $titles;
-  }
-}
-
Index: views/handlers/ogur_handler_field_og_users_roles.inc
===================================================================
RCS file: views/handlers/ogur_handler_field_og_users_roles.inc
diff -N views/handlers/ogur_handler_field_og_users_roles.inc
--- views/handlers/ogur_handler_field_og_users_roles.inc	23 May 2009 03:12:57 -0000	1.3
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,44 +0,0 @@
-<?php
-// $Id: ogur_handler_field_og_users_roles.inc,v 1.3 2009/05/23 03:12:57 sun Exp $
-
-/**
- * Field handler to provide a list of roles.
- */
-class ogur_handler_field_og_users_roles extends views_handler_field_prerender_list {
-  function construct() {
-    parent::construct();
-    $this->additional_fields['uid'] = array('table' => 'users', 'field' => 'uid');
-  }
-
-  function query() {
-    $this->add_additional_fields();
-    $this->field_alias = $this->aliases['uid'];
-  }
-
-  function pre_render($values) {
-    $uids = array();
-    $this->items = array();
-    $node = og_get_group_context();
-
-    foreach ($values as $result) {
-      $uids[] = $result->{$this->aliases['uid']};
-    }
-
-    $path = "";
-    // Check to see if user has access to configure member roles site-wide
-    if (user_access('configure restricted member roles')) {
-      $path = 'restricted_roles';
-    }
-    if (user_access('configure member roles')) {
-      $path = 'roles';
-    }
-
-    if ($uids) {
-      $result = db_query("SELECT u.uid, u.rid, r.name FROM {role} r INNER JOIN {og_users_roles} u ON u.rid = r.rid WHERE u.uid IN (" . implode(', ', $uids) . ") AND u.gid = $node->nid ORDER BY r.name");
-      while ($role = db_fetch_object($result)) {
-        $this->items[$role->uid][$role->rid] = l(t($role->name), "og/users/$node->nid/$path", array('query' => drupal_get_destination()));
-      }
-    }
-  }
-}
-
Index: views/handlers/ogur_handler_field_og_users_roles_all.inc
===================================================================
RCS file: views/handlers/ogur_handler_field_og_users_roles_all.inc
diff -N views/handlers/ogur_handler_field_og_users_roles_all.inc
--- views/handlers/ogur_handler_field_og_users_roles_all.inc	23 May 2009 03:12:57 -0000	1.3
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,58 +0,0 @@
-<?php
-// $Id: ogur_handler_field_og_users_roles_all.inc,v 1.3 2009/05/23 03:12:57 sun Exp $
-
-/**
- * Field handler to provide a list of roles.
- */
-class ogur_handler_field_og_users_roles_all extends views_handler_field_prerender_list {
-  function construct() {
-    parent::construct();
-    $this->additional_fields['uid'] = array('table' => 'users', 'field' => 'uid');
-    $this->additional_fields['gid'] = array('table' => 'og', 'field' => 'nid');
-  }
-
-  function query() {
-    $this->add_additional_fields();
-    $this->field_alias = $this->aliases['gid'];
-  }
-
-  function pre_render($values) {
-    global $user;
-    // If there are args for the user, use them, else use the current user info.
-    if ($this->view->args[0]) {
-      $uid = $this->view->args[0];
-    }
-    else {
-      $uid = $user->uid;
-    }
-
-    $this->items = array();
-
-    foreach ($values as $result) {
-      $path = "";
-      // Check to see if user has access to configure member roles site-wide
-      if (user_access('configure restricted member roles')) {
-        $path = 'restricted_roles';
-      }
-      if (user_access('configure member roles')) {
-        $path = 'roles';
-      }
-
-      $group_id = $result->{$this->aliases['gid']};
-
-      // Check to see if user has access to group-limited configure member roles
-      if (og_user_roles_user_access('configure restricted member roles', $group_id, $user->uid)) {
-        $path = 'restricted_roles';
-      }
-      if (og_user_roles_user_access('configure member roles', $group_id, $user->uid)) {
-        $path = 'roles';
-      }
-
-      $result = db_query("SELECT u.uid, u.rid, u.gid, r.name FROM {role} r INNER JOIN {og_users_roles} u ON u.rid = r.rid WHERE u.uid = $uid AND u.gid = {$group_id} ORDER BY r.name");
-      while ($role = db_fetch_object($result)) {
-        $this->items[$role->gid][$role->rid] = l(t($role->name), "og/users/$group_id/$path", array('query' => drupal_get_destination()));
-      }
-    }
-  }
-}
-
Index: views/handlers/ogur_handler_filter_og_users_roles.inc
===================================================================
RCS file: views/handlers/ogur_handler_filter_og_users_roles.inc
diff -N views/handlers/ogur_handler_filter_og_users_roles.inc
--- views/handlers/ogur_handler_filter_og_users_roles.inc	23 May 2009 03:12:57 -0000	1.3
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,13 +0,0 @@
-<?php
-// $Id: ogur_handler_filter_og_users_roles.inc,v 1.3 2009/05/23 03:12:57 sun Exp $
-
-/**
- * Filter handler for og users roles
- */
-class ogur_handler_filter_og_users_roles extends views_handler_filter_many_to_one {
-  function get_value_options() {
-    $this->value_options = user_roles(TRUE);
-    unset($this->value_options[DRUPAL_AUTHENTICATED_RID]);
-  }
-}
-
Index: views/handlers/ogur_handler_filter_og_users_roles_picg.inc
===================================================================
RCS file: views/handlers/ogur_handler_filter_og_users_roles_picg.inc
diff -N views/handlers/ogur_handler_filter_og_users_roles_picg.inc
--- views/handlers/ogur_handler_filter_og_users_roles_picg.inc	23 May 2009 03:12:57 -0000	1.3
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,13 +0,0 @@
-<?php
-// $Id: ogur_handler_filter_og_users_roles_picg.inc,v 1.3 2009/05/23 03:12:57 sun Exp $
-
-/**
- * Lovely filter handler which restricts posts to the current group. Useful for group related blocks.
- **/
-class ogur_handler_filter_og_users_roles_picg extends views_handler_filter {
-  function query() {
-    $table = $this->ensure_my_table();
-    $this->query->add_where($this->options['group'], "$table.gid  = ***CURRENT_GID***");
-  }
-}
-
Index: views/handlers/ogur_handler_filter_og_users_roles_ricg.inc
===================================================================
RCS file: views/handlers/ogur_handler_filter_og_users_roles_ricg.inc
diff -N views/handlers/ogur_handler_filter_og_users_roles_ricg.inc
--- views/handlers/ogur_handler_filter_og_users_roles_ricg.inc	23 May 2009 03:12:57 -0000	1.3
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,21 +0,0 @@
-<?php
-// $Id: ogur_handler_filter_og_users_roles_ricg.inc,v 1.3 2009/05/23 03:12:57 sun Exp $
-
-/**
- * Lovely filter handler which restricts posts to those in which the
- * user has group roles.
- **/
-class ogur_handler_filter_og_users_roles_ricg extends views_handler_filter {
-  function query() {
-    if ($this->view->args[0]) {
-      $uid = $this->view->args[0];
-    }
-    else {
-      $uid = '***CURRENT_USER***';
-    }
-
-    $table = $this->ensure_my_table();
-    $this->query->add_where($this->options['group'], "$table.uid  = $uid");
-  }
-}
-
