? og_groups_within_groups.patch
Index: og.module
===================================================================
RCS file: /cvs/drupal/contributions/modules/og/og.module,v
retrieving revision 1.298.2.26
diff -u -r1.298.2.26 og.module
--- og.module	7 Jan 2007 04:20:03 -0000	1.298.2.26
+++ og.module	23 Feb 2007 11:11:41 -0000
@@ -677,8 +677,14 @@
   if ($account->uid != $user->uid && !node_access('update', $node)) {
     drupal_access_denied();
   }
+  
+  elseif (!node_access('view', $node)) {
+    // if user can't view the group, he can't subscribe either
+    drupal_access_denied();
+  }
+  
   // user is already subscribed to this group, redirect to group homepage
-  else if (isset($account->og_groups[$node->nid])) {
+  elseif (isset($account->og_groups[$node->nid])) {
     drupal_set_message(t('@user is already subscribed to the group @group', array('@user' => $account->name, '@group' => $node->title)));
     drupal_goto('node/'. $node->nid);
   }
@@ -1165,13 +1171,11 @@
 // returns all the group affiliations for a given node.
 function og_get_node_groups($node) {
   $groups = array();
-  if (!og_is_group_type($node->type)) {
-    $result = og_get_node_groups_result($node->nid);
-    while ($row = db_fetch_object($result)) {
-      $groups[$row->group_nid] = $row->title;
-    }
-    return $groups;
+  $result = og_get_node_groups_result($node->nid);
+  while ($row = db_fetch_object($result)) {
+    $groups[$row->group_nid] = $row->title;
   }
+  return $groups;
 }
 
 // just the query for the get_node_groups function. is reused in og_views.inc
@@ -1246,12 +1250,8 @@
       }
       break;
     case 'load':
-      if (!og_is_group_type($node->type)) {
-        $node->og_public = db_result(db_query_range("SELECT is_public FROM {og_ancestry} WHERE nid = %d", $node->nid, 0, 1));
-      }
-      else {
-        og_load_group($node);
-      }
+      $node->og_public = db_result(db_query_range("SELECT is_public FROM {og_ancestry} WHERE nid = %d", $node->nid, 0, 1));
+      og_load_group($node);
       if ($grps = og_get_node_groups($node)) {
         // TODO: Refactor so we don't need 2 arrays.
         $node->og_groups = array_keys($grps);
@@ -1305,7 +1305,7 @@
         $from = variable_get('site_mail', ini_get('sendmail_from'));
         drupal_mail('og_new_admin', $account->mail, _og_user_mail_text('og_new_admin_subject', $variables), _og_user_mail_text('og_new_admin_body', $variables), $from);      
       }
-      elseif (!og_is_omitted_type($node->type)) {
+      if (!og_is_omitted_type($node->type)) {
         og_save_ancestry($node);
       }
       
@@ -1324,7 +1324,7 @@
         // make sure the node owner is a full powered subscriber
         og_save_subscription($node->nid, $node->uid, array('is_active' => 1, 'is_admin' => 1));
       }
-      elseif (!og_is_omitted_type($node->type)) {
+      if (!og_is_omitted_type($node->type)) {
         og_save_ancestry($node);
       }
       break;
@@ -1364,10 +1364,8 @@
   // Add audience selection to node forms
   if (strpos($form_id, 'node_form')) {
     $node = $form['#node'];
-    if (og_is_group_type($node->type)) {
-      $form = array_merge($form, og_group_form($node));
-    }
-    elseif (!in_array($node->type, variable_get('og_omitted', array()))) {
+    // type is not omitted even if is a node-group
+    if (!in_array($node->type, variable_get('og_omitted', array()))) {
       if (!$node->nid) {
         if ($group_node = og_get_group_context()) {
           $bc[] = array('path' => 'og', 'title' => t('Groups'));
@@ -1376,9 +1374,18 @@
           // TODO: not working for unknown reason
           // menu_set_location($bc);
         }
-      } 
+      }
+      // permit groups whitin groups we want to show group setting form and also the audience checkboxes
+      if (og_is_group_type($node->type)) {
+        $form = array_merge($form, og_group_form($node));
+      }
       og_form_add_og_audience($form_id, $form);
     }
+    
+    // type is omitted but is also a node-group so we want to show only the group setting form and not the audience
+    elseif (og_is_group_type($node->type) && in_array($node->type, variable_get('og_omitted', array()))) {
+      $form = array_merge($form, og_group_form($node));
+    }
   }
   
   if ($form_id == 'node_delete_confirm') {
@@ -1455,9 +1462,13 @@
   // determine the list of groups that are shown. node admins see all of them
   if (user_access('administer nodes')) {
     $options = og_all_groups_options();
+    // remove the current node-group from the audience list
+    unset($options[$form['nid']['#value']]);
   }
   else {
     $subs = og_get_subscriptions($node->uid);
+    // remove the current node-group from the audience list
+    unset($subs[$form['nid']['#value']]);
     foreach ($subs as $key => $val) {
       $options[$key] = $val['title'];
     }
@@ -1470,7 +1481,7 @@
   if (user_access('administer organic groups') && $vis < 2) {
     $vis = $vis == OG_VISIBLE_GROUPONLY ? OG_VISIBLE_CHOOSE_PRIVATE : OG_VISIBLE_CHOOSE_PUBLIC;
   }
-  elseif (!count($subs)) {
+  elseif (!count($subs) && !og_is_group_type($node->type)) {
     // don't show checkbox if no subscriptions. must be public.
     $vis = OG_VISIBLE_BOTH;
   }
@@ -1888,10 +1899,12 @@
 
 function og_node_grants($account, $op) {
   if (variable_get('og_enabled', FALSE)) {
+    
+    // everyone can see a public node
     if ($op == 'view') {
-      $grants['og_public'][] = 0; // everyone can see a public node
+      $grants['og_public'][] = 0; 
     }
-
+    
     // get subscriptions
     if ($subscriptions = og_get_subscriptions($account->uid)) {
       foreach ($subscriptions as $key => $val) {
@@ -1903,7 +1916,10 @@
         }
       }
     }
-    return $grants ? $grants : array();
+    
+    // no audience, no public so the post is private to the author.
+    $grants['og_private'] = array($account->uid);
+    return $grants;
   }
 }
 
@@ -1911,36 +1927,56 @@
   if (!og_is_omitted_type($node->type)) {
     $sql = "DELETE FROM {og_ancestry} WHERE nid = %d";
     db_query($sql, $node->nid);
-    if (is_array($node->og_groups)) {
+    
+    if (og_is_group_type($node->type)) {
+      $sql = "INSERT INTO {og_ancestry} (nid, group_nid, is_public) VALUES (%d, %d, %d)";
+      db_query($sql, $node->nid, $node->nid, $node->og_public);
+    }
+    
+    if ($node->og_groups) {
       foreach ($node->og_groups as $gid) {
-        $sql = "INSERT INTO {og_ancestry} (nid, group_nid, is_public) VALUES (%d, %d, %d)";
-        db_query($sql, $node->nid, $gid, $node->og_public);
+        if ($gid != $node->nid) {
+          $sql = "INSERT INTO {og_ancestry} (nid, group_nid, is_public) VALUES (%d, %d, %d)";
+          db_query($sql, $node->nid, $gid, $node->og_public);
+        }
       }
     }
+    // saves the public state to populate the checkbox on edit even if the node is either assigned to a group or not
+    elseif ($node->og_public) {
+      $sql = "INSERT INTO {og_ancestry} (nid, group_nid, is_public) VALUES (%d, %d, %d)";
+      db_query($sql, $node->nid, 0, $node->og_public);
+    }
   }
 }
 
 function og_node_access_records($node) {
   // don't write records if og access control is disabled or the node type is omitted or node is a group
   // if you want group nodes to be protected too, perhaps write a complementary node_access module. lets discuss.
-  if (og_is_omitted_type($node->type) || !variable_get('og_enabled', FALSE) || og_is_group_type($node->type)) {
+  if (og_is_omitted_type($node->type) || !variable_get('og_enabled', FALSE)) {
     return;
   }
   
-  if (is_array($node->og_groups)) {
+  if ($node->og_groups) {
     foreach ($node->og_groups as $gid) {
-      // we write a broad grant here but og_node_grants() only issues it selectively.
-      $grants[] = array('realm' => 'og_subscriber', 'gid' => $gid, 'grant_view' => 1, 'grant_update' => 1, 'grant_delete' => 1);
+      // always save permissions for the current node if it's a node-group
+      if ($gid != $node->nid) { 
+        // we write a broad grant here but og_node_grants() only issues it selectively.
+        $grants[] = array('realm' => 'og_subscriber', 'gid' => $gid, 'grant_view' => 1, 'grant_update' => 1, 'grant_delete' => 1);
+      }
     }
   }
   
+  if (og_is_group_type($node->type)) {
+    $grants[] = array('realm' => 'og_subscriber', 'gid' => $node->nid, 'grant_view' => 1, 'grant_update' => 1, 'grant_delete' => 1);
+  }
+  
   if ($node->og_public) {
     $grants[] = array('realm' => 'og_public', 'gid' => 0, 'grant_view' => 1, 'grant_update' => 0, 'grant_delete' => 0);
   }
   
-  // propose a deny for non public nodes whose type matters to og and aren't in a group
+  // if a post is not a group, is not assigned to any group and is not public, so it is private to the node author
   if (!count($grants)) {
-    $grants[] = array('priority' => 10, 'realm' => 'og_public', 'gid' => 0, 'grant_view' => 0, 'grant_update' => 0, 'grant_delete' => 0);
+    $grants[] = array('priority' => 0, 'realm' => 'og_private', 'gid' => $node->uid, 'grant_view' => 1, 'grant_update' => 1, 'grant_delete' => 1);
   }
 
   return $grants;
@@ -2106,57 +2142,62 @@
 
 function og_block_details() {
   global $user;
-
-  if ($node = og_get_group_context()) {
-    $result = db_query(og_list_users_sql(0), $node->nid);
-    $cntall = db_num_rows($result);
-    $cntpending = 0;
-    while ($row = db_fetch_object($result)) {
-      if ($row->is_active == 0) {
-        $cntpending++;
+  
+  $node = og_get_group_context();
+  
+  // users can see group details only if they are subscribed to parent group or the group is set as public
+  if (node_access('view', $node)) {
+    if ($node) {
+      $result = db_query(og_list_users_sql(0), $node->nid);
+      $cntall = db_num_rows($result);
+      $cntpending = 0;
+      while ($row = db_fetch_object($result)) {
+        if ($row->is_active == 0) {
+          $cntpending++;
+        }
+        if ($row->uid == $user->uid) {
+          if ($row->is_active) {
+            $subscription = 'active';
+          }
+          else {
+            $subscription = 'requested';
+          }
+        }
       }
-      if ($row->uid == $user->uid) {
-        if ($row->is_active) {
-          $subscription = 'active';
+      
+      if ($subscription == 'active' || user_access('administer nodes')) {
+        $links = module_invoke_all('og_create_links', $node);
+        if ($node->og_selective < OG_INVITE_ONLY) {
+          $links[] = l(t('Invite friend'), "og/invite/$node->nid");
         }
-        else {
-          $subscription = 'requested';
+        $txt = format_plural($cntall-$cntpending, '1 subscriber', '@count subscribers');
+        $txt = og_is_picture() ? l($txt, "og/users/$node->nid/faces") : l($txt, "og/users/$node->nid");
+        $txt .= $cntpending ? " ($cntpending)" : '';
+        $links[] = $txt;
+        $links[] =  t('Manager: '). theme('username', $node);
+        $links[] = isset($subscription) ? l(t('My subscription'), "og/manage/$node->nid") : og_subscribe_link($node);
+        if (isset($node->og_website) && !empty($node->og_website)) {
+          $links[] = l(t('website'), $node->og_website);
         }
       }
-    }
-
-    if ($subscription == 'active' || user_access('administer nodes')) {
-      $links = module_invoke_all('og_create_links', $node);
-      if ($node->og_selective < OG_INVITE_ONLY) {
-        $links[] = l(t('Invite friend'), "og/invite/$node->nid");
+      elseif ($subscription == 'requested') {
+        $links[] = t('Your subscription request awaits approval.');
+        $links[] = l(t('delete request'), "og/unsubscribe/$node->nid", array(), 'destination=og');
       }
-      $txt = format_plural($cntall-$cntpending, '1 subscriber', '@count subscribers');
-      $txt = og_is_picture() ? l($txt, "og/users/$node->nid/faces") : l($txt, "og/users/$node->nid");
-      $txt .= $cntpending ? " ($cntpending)" : '';
-      $links[] = $txt;
-      $links[] =  t('Manager: '). theme('username', $node);
-      $links[] = isset($subscription) ? l(t('My subscription'), "og/manage/$node->nid") : og_subscribe_link($node);
-      if (isset($node->og_website) && !empty($node->og_website)) {
-        $links[] = l(t('website'), $node->og_website);
+      elseif (!$user->uid) {
+        $links[] = t('You must login/register in order to contribute to this group.');
       }
+      elseif ($node->og_selective < OG_INVITE_ONLY) {
+        $links[] = og_subscribe_link($node);
+      }
+      else {
+        $links[] = t('This is a @closed group. The group administrators add/remove subscribers as needed.', array('@closed' => t('closed')));
+      }
+      
+      $block['content'] = theme('item_list', $links);
+      $block['subject'] = $node->title;
+      return $block;
     }
-    elseif ($subscription == 'requested') {
-      $links[] = t('Your subscription request awaits approval.');
-      $links[] = l(t('delete request'), "og/unsubscribe/$node->nid", array(), 'destination=og');
-    }
-    elseif (!$user->uid) {
-      $links[] = t('You must login/register in order to contribute to this group.');
-    }
-    elseif ($node->og_selective < OG_INVITE_ONLY) {
-      $links[] = og_subscribe_link($node);
-    }
-    else {
-      $links[] = t('This is a @closed group. The group administrators add/remove subscribers as needed.', array('@closed' => t('closed')));
-    }
-
-    $block['content'] = theme('item_list', $links);
-    $block['subject'] = $node->title;
-    return $block;
   }
 }
 
@@ -2173,7 +2214,7 @@
 // $group is an object containing the group node
 function og_og_create_links($group) {
   foreach (node_get_types() as $type) {
-    $exempt = array_merge(variable_get('og_node_types', array('og')), variable_get('og_omitted', array()));
+    $exempt = variable_get('og_omitted', array());
     if (!in_array($type->type, $exempt) && node_access('create', $type->type)) {
       $links[] = l(t('Create !type', array('!type' => $type->name)), "node/add/$type->type", array('title' => t('Add a new !s in this group.', array('!s' => $type->name))), "gids[]=$group->nid");
     }
@@ -2249,10 +2290,7 @@
     $options[$type->type] = t($type->name);
   }
   $og_node_type_options = $options;   // save this for og_node_types
-  // hide node types which are already serving as a group node
-  foreach (variable_get('og_node_types', array('og')) as $val) {
-    unset($options[$val]);
-  }
+  
   $form['og_settings']['node_form']['og_omitted'] = array('#type' => 'select', '#title' => t('Omitted content types'), '#default_value' => variable_get('og_omitted', array()), '#options' => $options, '#description' => t('Select any node types which should <em>not</em> participate in the Audience targetting system. Node types which are designated as group home page node types (see below) will be automatically excluded.'), '#multiple' => TRUE);
 
   $form['og_settings']['home'] = array('#type' => 'fieldset', '#title' => t('Group home page'), '#collapsible' => TRUE, '#collapsed' => TRUE);
Index: og_views.inc
===================================================================
RCS file: /cvs/drupal/contributions/modules/og/og_views.inc,v
retrieving revision 1.12.2.10
diff -u -r1.12.2.10 og_views.inc
--- og_views.inc	3 Jan 2007 06:28:21 -0000	1.12.2.10
+++ og_views.inc	23 Feb 2007 11:11:42 -0000
@@ -249,7 +249,7 @@
     case 'filter':
       // TODO: maybe there is a nicer syntax for this?
       $query->ensure_table('og_ancestry');
-      $query->add_where('og_ancestry.group_nid = %d', $arg);
+      $query->add_where('og_ancestry.group_nid = %d AND og_ancestry.nid != %d', $arg, $arg);
       break;
     case 'title':
       return db_result(db_query_range('SELECT title FROM {node} WHERE nid = %d', $query, 0, 1));;
