Index: notifications_group/notifications_group.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/notifications/notifications_group/notifications_group.module,v
retrieving revision 1.3.2.5
diff -u -r1.3.2.5 notifications_group.module
--- notifications_group/notifications_group.module	13 Apr 2008 10:33:04 -0000	1.3.2.5
+++ notifications_group/notifications_group.module	7 May 2008 14:57:50 -0000
@@ -3,7 +3,7 @@
 /**
  * @file
  * Subscriptions to content in groups
- * 
+ *
  * Group subscriptions are allowed for user that have view access to the group node
  * Whether a user can get a notification about a specific post will be decided later
  */
@@ -14,21 +14,30 @@
 function notifications_group_menu($may_cache) {
   global $user;  // we need the user to to build some urls
   $items = array();
-  
+
   if (!$may_cache) {
     if ($user->uid && arg(0) == 'user' && is_numeric(arg(1)) && arg(2) == 'notifications' && ($user->uid == arg(1) || user_access('administer notifications'))) {
       $account = ($user->uid == arg(1)) ? $user : user_load(array('uid' => arg(1)));
       $items[] = array(
         'path' => 'user/'. $account->uid .'/notifications/group',
+        'access' => user_access('subscribe to content in groups'),
+        'title' => t('Groups'),
+        'callback' => 'drupal_get_form',
+        'callback arguments' => array('notifications_group_user_page', $account),
         'type' => MENU_LOCAL_TASK,
-        'access' => user_access('subscribe to content'),
+        'weight' => 10
+      );
+      $items[] = array(
+        'path' => 'user/'. $account->uid .'/notifications/grouptype',
+        'access' => user_access('subscribe to content in groups'),
         'title' => t('Groups'),
-        'callback' => 'notifications_group_user_page',
+        'callback' => 'notifications_grouptype_user_page',
         'callback arguments' => array($account),
-        'weight' => 10,
+        'type' => MENU_CALLBACK
       );
     }
   }
+
   return $items;
 }
 
@@ -40,31 +49,57 @@
 }
 
 /**
- * Admin settings form
+ * Implementation of hook_form_alter().
  */
 function notifications_group_form_alter($form_id, &$form) {
-  if ($form_id == 'notifications_content_settings_form') {
-    $form['group'] = array(
-      '#type' => 'fieldset',
-      '#title' => t('Group subscriptions'),
-      '#collapsible' => TRUE,
-      '#weight' => 0,
-    );
-    // General content settings
-    $select = array();
-    $nodetypes = node_get_types();
-    foreach ($nodetypes as $ntype => $nname) {
-      $select[$ntype] = $nname->name;
-    }
-  
-    $form['group']['notifications_group_content_types'] = array(
-      '#type'          => 'checkboxes',
-      '#title'         => t('Allowed content types'),
-      '#default_value' => variable_get('notifications_group_content_types', array()),
-      '#options'       => $select,
-      '#description'   => t('Select specific content types which should be <em>allowed</em> for subscriptions to <em>group + content type</em>.'),
-      '#multiple'      => TRUE,
-    );
+  switch ($form_id) {
+    case 'notifications_content_settings_form':
+      $form['group'] = array(
+        '#type' => 'fieldset',
+        '#title' => t('Group subscriptions'),
+        '#collapsible' => TRUE,
+        '#weight' => 0,
+      );
+      // General content settings
+      $select = array();
+      $nodetypes = node_get_types();
+      foreach ($nodetypes as $ntype => $nname) {
+        $select[$ntype] = $nname->name;
+      }
+
+      $form['group']['notifications_group_content_types'] = array(
+        '#type'          => 'checkboxes',
+        '#title'         => t('Allowed content types'),
+        '#default_value' => variable_get('notifications_group_content_types', array()),
+        '#options'       => $select,
+        '#description'   => t('Select specific content types which should be <em>allowed</em> for subscriptions to <em>group + content type</em>.'),
+        '#multiple'      => TRUE,
+      );
+      break;
+    case 'user_edit':
+      // TODO: Is perm checking necessary here?
+      // Insert autosubscribe option into the messaging section of the user edit
+      // form.
+      $account = $form['_account']['#value'];
+      // TODO: Strings need to conform with OG and notifications terminology.
+      $form['messaging']['notifications_group_autosubscribe'] = array(
+        '#type' => 'checkbox',
+        '#title' => t('Automatically enable notifications for any organic groups that I join.'),
+        '#description' => t('Group notifications can be <a href="!manage-url">customised</a> in greater detail if necessary.', array('!manage-url' => url('user/'. $account->uid .'/notifications/group'))),
+        '#default_value' => isset($account->notifications_group_autosubscribe) ? $account->notifications_group_autosubscribe : variable_get('notifications_group_autosubscribe', 1)
+      );
+      break;
+    case 'og_admin_settings':
+      // Insert the global autosubsribe checkbox into the OG administration
+      // page. The fieldset should probably be renamed?
+      $form['og_settings']['email']['notifications_group_autosubscribe'] = array(
+        '#type' => 'checkbox',
+        '#title' => t('Autosubscribe users to any groups that they join.'),
+        '#description' => t('Automatically enable notifications by default. Users can override this via their account page.'),
+        '#default_value' => variable_get('notifications_group_autosubscribe', 1),
+        '#weight' => -1
+      );
+      break;
   }
 }
 
@@ -81,6 +116,30 @@
 }
 
 /**
+ * Implementation of hook_og().
+ */
+function notifications_group_og($op, $gid, $uid, $args) {
+  switch ($op) {
+    case 'user insert':
+      $account = user_load(array('uid' => $uid));
+      notifications_group_user_autosubscribe($account, $gid);
+      break;
+    case 'user delete':
+      $account = user_load(array('uid' => $uid));
+      notifications_group_user_unsubscribe($account, $gid);
+      break;
+  }
+}
+
+/**
+ * Temporary implementation of hook_og_notify() to override og's inbuilt
+ * notification system.
+ */
+function notifications_group_og_notify() {
+  return TRUE;
+}
+
+/**
  * Implementation of hook_notifications().
  */
 function notifications_group_notifications($op, &$arg0, $arg1 = NULL, $arg2 = NULL) {
@@ -115,7 +174,7 @@
         $query = array();
         if ($node->og_groups) {
           $query[] = array(
-            'join' => "LEFT JOIN {og_ancestry} og ON f.field = 'group' AND f.value = CAST(og.group_nid AS CHAR)",
+            'join' => "LEFT JOIN {og_ancestry} og ON f.field = 'group' AND f.value = CAST(og.group_nid AS CHAR(255))",
             'where' => 'og.nid = %d',
             'args' => array($node->nid),
           );
@@ -129,7 +188,7 @@
     case 'node options':
       return _notifications_group_node_options($arg0, $arg1);
     case 'event load': // $arg0 is event
-      // Nothing to load here, the user may be subscribed through one of many parent groups      
+      // Nothing to load here, the user may be subscribed through one of many parent groups
       break;
     case 'event types':
       // Event types for this are defined in notifications_content module
@@ -151,7 +210,277 @@
 }
 
 /**
- * Options to display for node subscriptions
+ * Menu callback: Group and grouptype subscription management form. This should
+ * ideally play nicer with notifications_user_form. However, due to issues with
+ * support for multi-field subscriptions, it is currently going about things in
+ * a roundabout manner.
+ *
+ * @param Object $account
+ *   User object of the user whose page is to be displayed.
+ * @return Array $form
+ *   Form array.
+ */
+function notifications_group_user_page($account = NULL) {
+  global $user;
+
+  $account = $account ? $account : $user;
+
+  if (!empty($user->og_groups)) {
+    $ngroups = _notifications_group_user_groups($account->uid);
+    $ngrouptypes = _notifications_group_user_grouptypes($account->uid);
+
+    // Tap into notifications_user_form to retrieve variables and defaults.
+    $group_form = notifications_user_form($account, 'group', $ngroups, $user->og_groups, array('type' => 'group', 'event_type' => 'node'), array('title' => t('Group')));
+    // Grouptype uses multiple fields which are not addressed adequately by
+    // notifications_user_form.
+    $grouptype_form = notifications_user_form($account, 'grouptype', $ngrouptypes, variable_get('notifications_group_content_types', array()), array('type' => 'grouptype', 'event_type' => 'node'), array('title' => t('Group Type')));
+
+    // TODO: Trim unnecessary items.
+    $form = array(
+      'account' => $group_form['account'],
+      'group_defaults' => $group_form['defaults'],
+      'group_current' => $group_form['current'],
+      'group_subscription_fields' => $group_form['subscription_fields'],
+      'grouptype_defaults' => $grouptype_form['defaults'],
+      'grouptype_current' => $grouptype_form['current'],
+      'grouptype_subscription_fields' => $grouptype_form['subscription_fields']
+    );
+
+    $content_types = array_filter(variable_get('notifications_group_content_types', array()));
+    foreach ($user->og_groups as $gid => $group) {
+      $group_index = 'groups-'. $gid;
+
+      $types = array();
+      foreach ($content_types as $type => $title) {
+        // Check if value exists; Only enable node type subscriptions if the
+        // group is not already subscribed to (for all posts).
+        $bool = isset($ngrouptypes[$gid]) && isset($ngrouptypes[$gid][$type]);
+        $types[$type] = array(
+          'title' => $title,
+          'checkbox' => $bool,
+          'send_interval' => $bool ? $ngrouptypes[$gid][$type]->send_interval : $grouptype_form['defaults']['#value']['send_interval'],
+          'send_method' => $bool ? $ngrouptypes[$gid][$type]->send_method : $grouptype_form['defaults']['#value']['send_method']
+        );
+      }
+      $all = array(
+        'all' => array(
+          'title' => t('All'),
+          'checkbox' => isset($ngroups[$gid]),
+          'send_interval' => isset($ngroups[$gid]) ? $ngroups[$gid]->send_interval : $group_form['defaults']['#value']['send_interval'],
+          'send_method' => $ngroups[$gid]->send_method
+        )
+      );
+      $types = $all + $types;
+
+      $form[$group_index] = array(
+        '#type' => 'fieldset',
+        '#title' => check_plain($group['title']),
+        '#collapsible' => TRUE,
+        '#collapsed' => !isset($ngroups[$gid]) && empty($ngrouptypes[$gid])
+      );
+
+      // Reuse theme function.
+      $form[$group_index]['subscriptions'] = array(
+        '#tree' => TRUE,
+        '#parents' => array('groups', $gid),
+        '#theme' => 'notifications_form_table',
+        '#header' => array(theme('table_select_header_cell'), t('Type'), t('Send interval'), t('Send method'))
+      );
+
+      foreach ($types as $key => $value) {
+        $form[$group_index]['subscriptions']['checkbox'][$key] = array(
+          '#type' => 'checkbox',
+          '#default_value' => $value['checkbox'],
+        );
+        $form[$group_index]['subscriptions']['title'][$key] = array(
+          '#value' => t('%type posts in this group', array('%type' => $value['title']))
+        );
+        $form[$group_index]['subscriptions']['send_interval'][$key] = array(
+          '#type' => 'select',
+          '#options' => _notifications_send_intervals(),
+          '#default_value' => $value['send_interval'],
+        );
+        $form[$group_index]['subscriptions']['send_method'][$key] = array(
+          '#type' => 'select',
+          '#options' => _notifications_send_methods(),
+          '#default_value' => $value['send_method'],
+        );
+      }
+    }
+
+    $form['submit'] = array('#type' => 'submit', '#value' => t('Save'));
+  }
+  else {
+    drupal_set_message(t('There are no active group subscriptions available.'));
+  }
+
+  return $form;
+}
+
+/**
+ * Process notifications_group_user_page form submission.
+ *
+ * @todo Decide on whether to allow contenttype and "all" subscriptions for the
+ * same group.
+ */
+function notifications_group_user_page_submit($form, $form_values) {
+  $groups = $grouptypes = array();
+  $current = $form_values['grouptype_current'];
+
+  foreach ($form_values['groups'] as $gid => $values) {
+    $groups['checkbox'][$gid] = $values['checkbox']['all'];
+    $groups['send_interval'][$gid] = $values['send_interval']['all'];
+    $groups['send_method'][$gid] = $values['send_method']['all'];
+    unset($form_values['groups'][$gid]['checkbox']['all'], $form_values['groups'][$gid]['send_interval']['all'], $form_values['groups'][$gid]['send_method']['all']);
+
+    // Save grouptype subscriptions directly as notifications_user_form_submit
+    // does not handle multiple-field notifications very well.
+    foreach ($form_values['groups'][$gid]['checkbox'] as $type => $check) {
+      $subscription = NULL;
+      if ($check == 1) {
+        if (!isset($current[$gid]) || !isset($current[$gid][$type])) {
+          $subscription = $form_values['grouptype_defaults'] + array('uid' => $form_values['account']->uid);
+        }
+        elseif ($current[$gid][$type]->send_interval != $values['send_interval'][$type] || $current[$gid][$type]->send_method != $values['send_method'][$type]) {
+          $subscription = (array)($current[$gid][$type]);
+        }
+        if ($subscription) {
+          $subscription['send_interval'] = $values['send_interval'][$type];
+          $subscription['send_method'] = $values['send_method'][$type];
+          $subscription['fields'] = array('group' => $gid, 'type' => $type);
+          notifications_save_subscription($subscription);
+        }
+      }
+      elseif (isset($current[$gid]) && isset($current[$gid][$type])) {
+        notifications_delete_subscription($current[$gid][$type]->sid);
+      }
+    }
+  }
+
+  // Save group changes.
+  $group_submit = array(
+    'account' => $form_values['account'],
+    'current' => $form_values['group_current'],
+    'defaults' => $form_values['group_defaults'],
+    'subscription_fields' => $form_values['group_subscription_fields'],
+    'subscriptions' => $groups
+  );
+  notifications_user_form_submit('notifications_group_user_page', $group_submit);
+}
+
+/**
+ * Menu callback: Since the default notifications UI lists group and grouptype
+ * as separate entries, redirect the grouptype management link to the group
+ * management page.
+ *
+ * @param Object $account
+ *   User object of the user whose grouptypes are to be managed.
+ */
+function notifications_grouptype_user_page($account) {
+  drupal_goto('user/'. $account->uid .'/notifications/group');
+}
+
+/**
+ * Handle autosubscriptions for users when they join a group.
+ *
+ * @param Object $account
+ *   The user account object.
+ * @param Integer $gid
+ *   The node ID of the group being subscribed to.
+ */
+function notifications_group_user_autosubscribe($account, $gid) {
+  if (isset($account->notifications_group_autosubscribe) ? $account->notifications_group_autosubscribe : variable_get('notifications_group_autosubscribe', 1)) {
+    notifications_group_user_subscribe($account, $gid);
+  }
+}
+
+/**
+ * Subscribe a user to a group.
+ *
+ * @param Object $account
+ *   The user account object.
+ * @param Integer $gid
+ *   The node ID of the group being subscribed to.
+ */
+function notifications_group_user_subscribe($account, $gid) {
+  $subscription = _notifications_subscription_defaults($account);
+
+  $subscription['uid'] = $account->uid;
+  $subscription['type'] = 'group';
+  $subscription['event_type'] = 'node';
+  $subscription['fields'] = array('group' => $gid);
+
+  notifications_save_subscription($subscription);
+}
+
+/**
+ * Unsubscribe a user from a group. This also unsunscribes the user from any
+ * grouptype subscriptions within the group.
+ *
+ * @param Object $account
+ *   The user account object.
+ * @param Integer $gid
+ *   The node ID of the group being subscribed to.
+ */
+function notifications_group_user_unsubscribe($account, $gid) {
+  // @todo: Handle direct node subscriptions for private groups.
+  // Niche cases include multi-group nodes.
+  notifications_delete_subscriptions(array('uid' => $account->uid, 'type' => 'grouptype'), array('group' => $gid));
+  notifications_delete_subscriptions(array('uid' => $account->uid, 'type' => 'group'), array('group' => $gid));
+}
+
+/**
+ * Retrieve a list of organic groups that a user is subscribed (via
+ * notifications) to.
+ *
+ * @param Integer $uid
+ *   The user ID of the user whose groups are to be retrieved.
+ * @return Array $ngroups
+ *   An associative array of the resulting groups.
+ */
+function _notifications_group_user_groups($uid) {
+  // No checks for group published or not?
+  $query = "SELECT no.*, nof.value AS nid, n.type AS node_type, n.title FROM {notifications} no
+    INNER JOIN {notifications_fields} nof ON no.sid = nof.sid LEFT JOIN {node} n ON nof.value = CAST(n.nid AS CHAR(255))
+    WHERE no.uid = %d AND (no.type = 'group') AND no.conditions = 1 AND nof.field = 'group'
+    ORDER BY node_type, n.title";
+  $results = db_query($query, $uid);
+
+  $ngroups = array();
+  while ($sub = db_fetch_object($results)) {
+    $ngroups[$sub->nid] = $sub;
+  }
+
+  return $ngroups;
+}
+
+/**
+ * Retrieve a list of organic group content types that a user is subscribed (via
+ * notifications) to.
+ *
+ * @param Integer $uid
+ *   The user ID of the user whose groups are to be retrieved.
+ * @return Array $ngrouptypes
+ *   An associative array of the resulting content types sorted by groups.
+ */
+function _notifications_group_user_grouptypes($uid) {
+  $query = "SELECT no.*, nof1.value AS group_nid, nof2.value AS node_type FROM {notifications} no
+    INNER JOIN {notifications_fields} nof1 ON no.sid = nof1.sid
+    INNER JOIN {notifications_fields} nof2 ON no.sid = nof2.sid
+    WHERE no.uid = %d AND (no.type = 'grouptype') AND no.conditions = 2 AND nof1.field = 'group' AND nof2.field = 'type'
+    ORDER BY group_nid, node_type";
+  $results = db_query($query, $uid);
+
+  $ngrouptypes = array();
+  while ($sub = db_fetch_object($results)) {
+    $ngrouptypes[$sub->group_nid][$sub->node_type] = $sub;
+  }
+
+  return $ngrouptypes;
+}
+
+/**
+ * Options to display for node subscriptions.
  */
 function _notifications_group_node_options($account, $node) {
   // If node is a group type
@@ -188,36 +517,3 @@
   }
   return $options;
 }
-
-/**
- * Menu callback. User subscriptions to groups.
- */
-function notifications_group_user_page($account = NULL) {
-  global $user;
-  $account = $account ? $account : $user;
-
-  // Query for group subscriptions. 
-  // @ TO DO Retrieve also grouptype subscriptions
-  $query = "SELECT s.*, f.value AS nid, n.type AS node_type, n.title FROM {notifications} s 
-    INNER JOIN {notifications_fields} f ON s.sid = f.sid LEFT JOIN {node} n ON f.value = CAST(n.nid AS CHAR)
-    WHERE s.uid = %d AND s.type = 'group' AND s.conditions = 1 AND f.field = 'group'
-    ORDER BY node_type, n.title";
-  $results = db_query($query, $account->uid);
-
-  $subscriptions = $list = array();
-
-  while ($sub = db_fetch_object($results)) {
-    $subscriptions[$sub->nid] = $sub;
-    $list[$sub->nid] = $sub->title;
-  }  
-
-  if (!$subscriptions) {
-    $output = t('There are no active group subscriptions.');    
-  }
-  else {
-    $defaults = array('type' => 'group', 'event_type' => 'node');
-    $options = array('title' => t('Group'));
-    $output = drupal_get_form('notifications_user_form', $account, 'group', $subscriptions, $list, $defaults, $options);
-  }
-  return $output;
-}
