uid .'/notifications/group': return t('Customise notifications for each of your groups along with their frequency and delivery method. If so desired, you can also restrict notifications only for certain content types in each group.'); } } /** * Implementation of hook_menu(). */ function og_notifications_menu($may_cache) { global $user; $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('og_notifications_user_page', $account), 'type' => MENU_LOCAL_TASK, 'weight' => 10 ); // grouptype redirects to group. $items[] = array( 'path' => 'user/'. $account->uid .'/notifications/grouptype', 'access' => user_access('subscribe to content in groups'), 'callback' => 'og_notifications_grouptype_user_page', 'callback arguments' => array($account), 'type' => MENU_CALLBACK ); } } return $items; } /** * Implementation of hook_perm(). */ function og_notifications_perm() { return array('subscribe to content in groups'); } /** * Implementation of hook_user(). * Handle uid entry in the og_notifications table. */ function og_notifications_user($type, &$edit, &$user, $category = NULL) { switch ($type) { case 'insert': db_query("INSERT INTO {og_notifications} (uid) VALUES (%d)", $user->uid); break; case 'update': if (isset($edit['og_notifications_autosubscribe'])) { og_notifications_user_autosubscribe_set($user->uid, $edit['og_notifications_autosubscribe']); unset($edit['og_notifications_autosubscribe']); } break; case 'delete': db_query("DELETE FROM {og_notifications} WHERE uid = %d", $user->uid); break; } } /** * Implementation of hook_form_alter(). */ function og_notifications_form_alter($form_id, &$form) { 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(); $ogtypes = og_get_types('group_post'); foreach ($ogtypes as $ntype) { $select[$ntype] = $nodetypes[$ntype]->name; } $form['group']['og_notifications_content_types'] = array( '#type' => 'checkboxes', '#title' => t('Allowed content types'), '#default_value' => variable_get('og_notifications_content_types', array()), '#options' => $select, '#description' => t('Select specific content types which should be allowed for subscriptions to group + content type.'), '#multiple' => TRUE ); break; case 'user_edit': // Insert autosubscribe option into the messaging section of the user edit // form. // user_edit is, oddly enough, also the form_id for forms in other // sub-tabs such as those added by the profile module. if (!arg(3)) { $account = $form['_account']['#value']; $form['messaging']['og_notifications_autosubscribe'] = array( '#type' => 'checkbox', '#title' => t('Automatically enable notifications for any groups that I join.'), '#description' => t('Group notifications can also be customised in greater detail if required.', array('!manage-url' => url('user/'. $account->uid .'/notifications/group'))), '#default_value' => og_notifications_user_autosubscribe_get($account->uid) ); } break; case 'og_admin_settings': // Default autosubscription setting. $form['og_settings']['notifications']['og_notifications_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. Changing this setting will only affect new users and those who have not overridden the system default.'), '#default_value' => variable_get('og_notifications_autosubscribe', 1), '#weight' => -5 ); break; } } /** * Implementation of hook_nodeapi(). */ function og_notifications_nodeapi(&$node, $op, $arg = 0) { switch ($op) { case 'delete': // Remove all group subscriptions for this node. notifications_delete_subscriptions(array('type' => 'group'), array('group' => $node->nid)); notifications_delete_subscriptions(array('type' => 'grouptype'), array('group' => $node->nid)); break; } } /** * Implementation of hook_og(). */ function og_notifications_og($op, $gid, $uid, $args) { switch ($op) { case 'user insert': $account = user_load(array('uid' => $uid)); og_notifications_user_autosubscribe($account, $gid); break; case 'user delete': $account = user_load(array('uid' => $uid)); og_notifications_user_unsubscribe($account, $gid); break; case 'user request': // This and other notifications related ops drop down to the same case. // These different ops have been provided for consistency and flexibility // during use by other modules. case 'user approve': case 'admin create': case 'admin new': case 'user broadcast': $destinations = is_array($uid) ? $uid : array($uid); foreach ($destinations as $uid) { notifications_lite_send($uid, $args['subject'], $args['body']); } break; } } /** * Implementation of hook_messaging(). */ function og_notifications_messaging($op, $arg1 = NULL, $arg2 = NULL, $arg3 = NULL, $arg4 = NULL) { switch ($op) { case 'message groups': // Generic notifications event $info['og-notifications'] = array( 'module' => 'og_notifications', 'name' => t('OG notifications'), 'help' => t('Most fields will be provided during the event.') ); return $info; case 'message keys': $type = $arg1; switch ($type) { case 'og-notifications': return array( 'subject' => t('Subject for event notifications'), 'header' => t('Body header for event notifications'), 'main' => t('Body for event notifications'), 'footer' => t('Body footer for event notifications') ); break; } break; case 'messages': $type = $arg1; switch ($type) { case 'og-notifications': return array( 'subject' => t('[site-name] subscription update for [user]'), 'header' => t("Greetings, [user].\n\nThese are your messages"), 'main' => t("A [type] has been updated: [title]\n\n[event_list]"), 'footer' => array( t('This is an automatic message from [site-name]'), t('To manage your subscriptions, browse to [subscriptions-manage]') ) ); } break; case 'tokens': $tokens = array(); if ($arg1 == 'og-notifications') { $tokens = array('global', 'subscription', 'user', 'node'); } return $tokens; } } /** * Implementation of hook_notifications(). */ function og_notifications_notifications($op, &$arg0, $arg1 = NULL, $arg2 = NULL) { switch ($op) { case 'names': $subs = &$arg0; if ($subs->event_type == 'node') { if (!empty($subs->fields['group']) && ($group = node_load($subs->fields['group']))) { $subs->names['group'] = t('Group: %name', array('%name' => $group->title)); } } break; case 'subscription types': $types['group'] = array( 'event_type' => 'node', 'title' => t('Groups'), 'access' => 'subscribe to content in groups', 'page' => 'og_notifications_user_page', 'fields' => array('group') ); $types['grouptype'] = array( 'event_type' => 'node', 'title' => t('Content type in group'), 'access' => 'subscribe to content in groups', 'page' => 'og_notifications_user_page', 'fields' => array('group', 'type') ); return $types; case 'subscription fields': // Information about available fields for subscriptions $fields['group'] = array( 'name' => t('Group'), 'field' => 'group', 'type' => 'int', ); return $fields; case 'query': if ($arg0 == 'event' && $arg1 == 'node' && ($node = $arg2->node) || $arg0 == 'user' && $arg1 == 'node' && ($node = $arg2)) { $query = array(); if ($node->og_groups) { $query[]['fields']['group'] = $node->og_groups; } if ($arg0 == 'user' && og_is_group_type($node->type)) { $query[]['fields']['group'] = $node->nid; } return $query; } break; case 'node options': return _og_notifications_node_options($arg0, $arg1); case 'event load': // 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 break; case 'access': $type = $arg0; $account = &$arg1; $object = &$arg2; if ($type == 'subscription' && !empty($object->fields['group'])) { if (($group = node_load($object->fields['group'])) && og_is_group_type($group->type) && notifications_content_node_allow($account, $group)) { return array(TRUE); } else { return array(FALSE); } } break; } } /** * 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 og_notifications_user_page($account = NULL) { global $user; $account = $account ? $account : $user; if (!empty($account->og_groups)) { $ngroups = _og_notifications_user_groups($account->uid); $ngrouptypes = _og_notifications_user_grouptypes($account->uid); // Tap into notifications_user_form to retrieve variables and defaults. $group_form = notifications_user_form($account, 'group', $ngroups, $account->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('og_notifications_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('og_notifications_content_types', array())); $content_names = node_get_types('names'); foreach ($account->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' => check_plain($content_names[$type]), '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'] ); } $bool = isset($ngroups[$gid]); $all = array( 'all' => array( 'title' => t('All'), 'checkbox' => $bool, 'send_interval' => $bool ? $ngroups[$gid]->send_interval : $group_form['defaults']['#value']['send_interval'], 'send_method' => $bool ? $ngroups[$gid]->send_method : $group_form['defaults']['#value']['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 { $form = array(); drupal_set_message(t('There are no active group subscriptions available.')); } return $form; } /** * Process og_notifications_user_page form submission. * * @todo Decide on whether to allow contenttype and "all" subscriptions for the * same group. */ function og_notifications_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]; // String cast due to notifications requiring it as the value field is // a varchar. $subscription['fields'] = array('group' => (string) $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('og_notifications_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 og_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 og_notifications_user_autosubscribe($account, $gid) { if (og_notifications_user_autosubscribe_get($account->uid)) { og_notifications_user_subscribe($account, $gid); } } /** * Retrieve autosubscription setting for a particular user. -1 in the * og_notifications table indicates that the site default is to be used. * * @param Integer $uid * The uid of the user. * @return Integer * 1 or 0 as per the autosubscribe preference. */ function og_notifications_user_autosubscribe_get($uid) { $autosubscribe = db_result(db_query("SELECT autosubscribe FROM {og_notifications} WHERE uid = %d", $uid)); return $autosubscribe == -1 ? variable_get('og_notifications_autosubscribe', 1) : $autosubscribe; } /** * Retrieve autosubscription setting for a particular user. * * @param Integer $uid * The uid of the user. * @param Integer $autosubscribe * Autosubscription option: 0 or 1. */ function og_notifications_user_autosubscribe_set($uid, $autosubscribe) { return db_query("UPDATE {og_notifications} SET autosubscribe = %d WHERE uid = %d", $autosubscribe, $uid); } /** * 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 og_notifications_user_subscribe($account, $gid) { $subscription = _notifications_subscription_defaults($account); $subscription['uid'] = $account->uid; $subscription['type'] = 'group'; $subscription['event_type'] = 'node'; // String cast due to notifications requiring it as the value field is // a varchar. $subscription['fields'] = array('group' => (string) $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 og_notifications_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 _og_notifications_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 _og_notifications_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 _og_notifications_node_options($account, $node) { $options = array(); // If node is a group type and the user is subscribed to this group. if (og_is_group_type($node->type) && isset($account->og_groups[$node->nid])) { $options[] = array( 'name' => t('All posts in %group', array('%group' => $node->title)), 'type' => 'group', 'fields' => array('group' => $node->nid) ); foreach (array_filter(variable_get('og_notifications_content_types', array())) as $type) { $options[] = array( 'name' => t('%type posts in %group', array('%group' => $node->title, '%type' => node_get_types('name', $type))), 'type' => 'grouptype', 'fields' => array('group' => $node->nid, 'type' => $type) ); } } // If node is part of a group user may be subscribed to the node through one // of the groups. if ($node->og_groups) { foreach ($node->og_groups as $index => $gid) { // Only members get to see subscription options. if (isset($account->og_groups[$gid])) { // Content type $options[] = array( 'name' => t('Posts in group %name', array('%name' => $node->og_groups_both[$gid])), 'type' => 'group', 'fields' => array('group' => $gid) ); $options[] = array( 'name' => t('%type posts in %group', array('%group' => $node->og_groups_both[$gid], '%type' => node_get_types('name', $node->type))), 'type' => 'grouptype', 'fields' => array('group' => $gid, 'type' => $node->type) ); } } } return $options; }