'Content', 'description' => 'Content subscriptions', 'type' => MENU_LOCAL_TASK, 'page callback' => 'drupal_get_form', 'page arguments' => array('notifications_content_settings_form'), 'access arguments' => array('administer site configuration'), 'file' => 'notifications_content.pages.inc', ); // User pages, will be disabled by default $items['user/%user/notifications/thread'] = array( 'type' => MENU_LOCAL_TASK, 'access callback' => FALSE, 'title' => 'Thread', 'page callback' => 'notifications_user_subscription_list_page', 'page arguments' => array('thread', 1), 'weight' => 10, ); $items['user/%user/notifications/nodetype'] = array( 'type' => MENU_LOCAL_TASK, 'access callback' => FALSE, 'title' => 'Content type', 'page callback' => 'notifications_user_subscription_list_page', 'page arguments' => array('nodetype', 1), 'weight' => 10, ); $items['user/%user/notifications/author'] = array( 'type' => MENU_LOCAL_TASK, 'access callback' => FALSE, 'title' => t('Author'), 'page callback' => 'notifications_user_subscription_list_page', 'page arguments' => array('author', 1), 'weight' => 10, ); $items['user/%user/notifications/typeauthor'] = array( 'type' => MENU_LOCAL_TASK, 'access callback' => FALSE, 'title' => t('Content type by author'), 'page callback' => 'notifications_user_subscription_list_page', 'page arguments' => array('typeauthor', 1), 'weight' => 10, ); $items['admin/messaging/notifications/events/configure'] = array( 'title' => 'Configure', 'type' => MENU_DEFAULT_LOCAL_TASK, 'access arguments' => array('administer site configuration'), 'file' => 'notifications.admin.inc', ); $items['admin/messaging/notifications/events/test'] = array( 'title' => 'Test', 'description' => 'Test event templates.', 'page callback' => 'drupal_get_form', 'page arguments' => array('notifications_content_test_template_form'), 'type' => MENU_LOCAL_TASK, 'access arguments' => array('administer notifications'), 'file' => 'notifications_content.pages.inc', ); return $items; } /** * Menu access callback */ function notifications_content_access($account, $perm) { global $user; return ($account->uid && $account->uid == $user->uid && user_access($perm)) || (user_access('administer notifications') && user_access($perm, $account)); } /** * Implementation of hook_perm() */ function notifications_content_perm() { return array( 'subscribe to content', 'subscribe to content type', 'subscribe to author', 'subscribe to content type and author', 'skip notifications' ); } /** * Implementation of hook_help() */ function notifications_content_help($path, $arg) { if ($path == 'admin/messaging/notifications/content') { $output = '
' . t('Content subscriptions are subscriptions to nodes that will produce notifications when a node is posted or updated or when a comment is posted for that nodes. Notifications will be sent only for published content so if you need to be notified of unpublished content waiting for approval you better use Triggers and Actions or some other module for that.') . '
'; $output .= ''. t('On this page you can set which of the available subscription types are allowed. Alternatively you can select the Set up for each content type option and use the Administer Content types page. These settings will be combined with permissions and other options (See user interface options if enabled) to determine which subscriptions will be finally available for users.', array('@content-type-settings' => url( 'admin/content/types'))) .'
'; return $output; } elseif (array($arg[0], $arg[1], $arg[2], $arg[3]) == array('admin', 'messaging', 'template', 'edit') && ($group = $arg[4])) { switch ($group) { case 'notifications-digest-node-nid': case 'notifications-digest-node-type': $help = '' . t('This is the format for each digest group. A message may consist on one or many of these groups:') . '
'; $help .= ''; $help .= t('Group title') . "\n"; $help .= '- ' . t('Digest line.'). "\n"; $help .= '- ' . t('Digest line.'). "\n"; $help .= '- ...'. "\n"; $help .= t('Group footer') . "\n"; $help .= ''; return $help; } } } /** * Implementation of hook_form_alter(). */ function notifications_content_form_alter(&$form, &$form_state, $form_id) { switch ($form_id) { case 'comment_form': // Load the node which is possibly cached to get the node type $node = node_load($form['nid']['#value']); if (notifications_content_type_enabled($node->type)) { if (notifications_event_enabled('node-comment')) { _notifications_content_add_disable_field($form); } // If editing the comment, add values to remember if (!empty($form['cid']['#value']) && !empty($form['admin']['status'])) { $form['notifications_comment_status'] = array('#type' => 'value', '#value' => $form['admin']['status']['#default_value']); } } break; case 'node_type_form': if (isset($form['identity']['type'])) { // Hack for modules with different weights to add options here if (!isset($form['notifications'])) $form['notifications'] = array(); $form['notifications'] += array( '#type' => 'fieldset', '#title' => t('Subscription settings'), '#collapsible' => TRUE, '#collapsed' => TRUE, ); $form['notifications']['notifications_content_type'] = array( '#type' => 'checkboxes', '#title' => t('Allowed subscription types'), '#default_value' => notifications_content_type_enabled($form['#node_type']->type), '#options' => _notifications_content_type_options(), '#description' => t('Enable different subscription options for this content type.'), '#weight' => -10, ); if (!variable_get('notifications_content_per_type', 0)) { $form['notifications']['notifications_content_type']['#disabled'] = TRUE; $form['notifications']['notifications_content_type']['#description'] .= ' ' . t('To enable these options check the Notifications content settings', array('@notifications-settings' => url('admin/messaging/notifications/content'))) . ''; } } break; default: // Node form. Option to disable notifications if (isset($form['type']) && isset($form['#node']) && $form['type']['#value'] .'_node_form' == $form_id) { $node = $form['#node']; // Do not add if content type disabled, creating and create events disabled, updating and update events disabled if (notifications_content_type_enabled($node->type) && (empty($node->nid) && notifications_event_enabled('node-insert') || !empty($node->nid) && notifications_event_enabled('node-update'))) { _notifications_content_add_disable_field($form, !empty($node->notifications_content_disable)); } } } } /** * Add disable (skip notifications) field set */ function _notifications_content_add_disable_field(&$form, $default = 0) { if (user_access('skip notifications')) { // Add fieldset without affecting any other elements there $form['notifications']['#type'] = 'fieldset'; $form['notifications']['#title'] = t('Notifications'); $form['notifications']['#collapsible'] = TRUE; $form['notifications']['notifications_content_disable'] = array( '#type' => 'checkbox', '#title' => t('Do not send notifications for this update.'), '#default_value' => $default, ); } } /** * Implementation of hook hook_content_extra_fields(). * * Enables CCK (admin/content/types/CONTENT_TYPE/fields) to configure the * position of the notifications fieldset within the node. * * @ingroup hooks */ function notifications_content_content_extra_fields($type_name) { $extra = array(); if (notifications_content_type_enabled($type_name) && (notifications_event_enabled('node-insert') || notifications_event_enabled('node-update'))) { $extra['notifications'] = array( 'label' => t('Notifications'), 'description' => t('Notifications module form.'), 'weight' => 100, ); } return $extra; } /** * Implementation of hook_theme() */ function notifications_content_theme() { return array( 'notifications_content_type_settings' => array( 'arguments' => array('element' => NULL), 'file' => 'notifications_content.pages.inc', ), ); } /** * Implementation of hook_notifications() */ function notifications_content_notifications($op) { switch ($op) { case 'subscription types': // Some types may be globally disabled (for all content types), mark as such $disabled = !variable_get('notifications_content_per_type', 0); $types['thread'] = array( 'event_type' => 'node', 'object_type' => 'node', 'title' => t('Thread'), 'access' => 'subscribe to content', 'page callback' => 'notifications_content_page_thread', 'user page' => 'user/%user/notifications/thread', 'fields' => array('nid'), 'description' => t('Subscribe to all changes and comments for a thread.'), 'name callback' => 'notifications_content_subscription_name', ); $types['nodetype'] = array( 'event_type' => 'node', 'object_type' => 'node', 'title' => t('Content type'), 'access' => 'subscribe to content type', 'page callback' => 'notifications_content_page_nodetype', 'user page' => 'user/%user/notifications/nodetype', 'fields' => array('type'), 'description' => t('Subscribe to all content of a given type.'), 'name callback' => 'notifications_content_subscription_name', ); $types['author'] = array( 'event_type' => 'node', 'object_type' => 'user', 'title' => t('Author'), 'access' => 'subscribe to author', 'page callback' => 'notifications_content_page_author', 'user page' => 'user/%user/notifications/author', 'fields' => array('author'), 'description' => t('Subscribe to all content submitted by a user.'), 'name callback' => 'notifications_content_subscription_name', ); // This is a complex type, combining two fields $types['typeauthor'] = array( 'event_type' => 'node', 'object_type' => array('node', 'user'), // This makes sense per node and per user 'title' => t('Content type by author'), 'access' => 'subscribe to content type and author', 'page callback' => 'notifications_content_page_typeauthor', 'user page' => 'user/%user/notifications/typeauthor', 'fields' => array('author', 'type'), 'description' => t('Subscribe to all content of a given type submitted by a user.'), 'name callback' => 'notifications_content_subscription_name', ); return $types; case 'subscription fields': // Information about available fields for subscriptions // - format callback => will be used to convert the value into a displayable output // - value callback => will be used to convert autocomplete name into field value // - autocomplete path => path for autocomplete field // - options callback / arguments => used to produce a drop down field $fields['nid'] = array( 'name' => t('Node'), 'field' => 'nid', 'type' => 'int', 'object_type' => 'node', ); $fields['author'] = array( 'name' => t('Author'), 'field' => 'author', 'type' => 'int', 'object_type' => 'user', ); $fields['type'] = array( 'name' => t('Node type'), 'field' => 'type', 'type' => 'string', 'options callback' => 'notifications_content_types_callback', ); return $fields; case 'object types': // Define object types for use by events and subscriptions // Node and user are defined in the main notifications module $types['comment'] = array( 'name' => t('Comment'), 'key_field' => 'cid', 'load callback' => 'notifications_content_comment_load', 'format callback' => 'notifications_content_comment_cid2title', 'access callback' => 'notifications_content_comment_access', ); return $types; case 'event types': // Node inserts are not grouped by node but all together. The digest will look like: // New content has been submitted // - Story Title1 by Author1 // - Event Title2 by Author2 $types['node-insert'] = array( 'type' => 'node', 'action' => 'insert', 'name' => t('New content of type [type-name] has been submitted'), 'line' => t('[type-name] [title] by [author-name]'), 'digest' => array('node', 'type'), 'description' => t('Node creation'), 'template' => 'notifications-event-node-insert', ); // These other events are grouped for each node. The digest will look like: // Story: Title of the story // - The story has been updated // - New comment by User: Comment title $types['node-update'] = array( 'type' => 'node', 'action' => 'update', 'name' => t('[type-name]: [title]'), 'line' => t('The [type-name] has been updated'), 'digest' => array('node', 'nid'), 'description' => t('Node update'), 'template' => 'notifications-event-node-update', ); $types['node-comment'] = array( 'type' => 'node', 'action' => 'comment', 'name' => t('[type-name]: [title]'), 'line' => t('New comment by [comment-author-name]: [comment-title]'), 'digest' => array('node', 'nid'), 'description' => t('Node comment'), 'template' => 'notifications-event-node-comment', ); return $types; case 'event classes': return array('node' => t('Node')); case 'event actions': return array( 'insert' => t('Creation'), 'update' => t('Update'), 'comment' => t('Comment'), ); } } /** * Implementation of hook notifications_subscription() */ function notifications_content_notifications_subscription($op, $subscription = NULL) { switch ($op) { case 'access': // Check access control for subscription if (($conditions = $subscription->get_conditions()) && !empty($conditions['type'])) { // It seems to be a subscription for a content type return notifications_content_type_enabled($conditions['type'], $subscription->type); } break; case 'page objects': // Return objects on current page to which we can subscribe if (arg(0) == 'node' && is_numeric(arg(1)) && ($node = menu_get_object('node'))) { return array('node' => $node); } break; } } /** * Implementation of hook_notifications_object_node() */ function notifications_content_notifications_object_node($op, $node, $account = NULL) { switch ($op) { case 'conditions': return array( 'nid' => $node->nid, 'type' => $node->type, 'author' => $node->uid, ); case 'subscriptions': // Return available subscription options for this node and this user account $options = array(); // Thread if (notifications_content_type_enabled($node->type, 'thread')) { $options[] = array( 'name' => t('This post'), 'type' => 'thread', 'fields' => array('nid' => $node->nid), ); } // Content type subscriptions if (notifications_content_type_enabled($node->type, 'nodetype')) { $options[] = array( 'name' => t('Posts of type @type', array('@type' => notifications_content_type_name($node->type))), 'type' => 'nodetype', 'fields' => array('type' => $node->type), ); } // Node author subscriptions if (notifications_content_type_enabled($node->type, 'author')) { $options[] = array( 'name' => t('Posts by @name', array('@name' => _notifications_content_node_username($node))), 'type' => 'author', 'fields' => array('author' => $node->uid), ); } // Subscribe to content type by author if (notifications_content_type_enabled($node->type, 'typeauthor')) { $options[] = array( 'name' => t('@type posts by @name', array('@name' => _notifications_content_node_username($node), '@type' => notifications_content_type_name($node->type))), 'type' => 'typeauthor', 'fields' => array('author' => $node->uid, 'type' => $node->type), ); } return $options; break; } } /** * Implementation of hook_notifications_object_user() */ function notifications_content_notifications_object_user($op, $user, $account = NULL) { switch ($op) { case 'conditions': // Condition fields for subscriptions to this object type (user) return array( 'uid' => $user->uid, 'author' => $user->uid, ); case 'subscriptions': // Option subscriptions to user account. Checking permissions here will save some processing. $options = array(); // All posts by author if (!$account || user_access('subscribe to author', $account)) { $options[] = array( 'name' => t('All posts by @name', array('@name' => $user->name)), 'type' => 'author', 'fields' => array('author' => $user->uid), ); } // Content types with author subscriptions if (!$account || user_access('subscribe to content type and author', $account)) { foreach (notifications_content_types('typeauthor') as $type => $type_name) { $options[] = array( 'name' => t('@type posts by @name', array('@name' => $user->name, '@type' => $type_name)), 'type' => 'typeauthor', 'fields' => array('author' => $author->uid, 'type' => $type), ); } } return $options; } } /** * Implementation of hook_notifications_templates() */ function notifications_content_notifications_templates($op, $type = 'all', $language = NULL) { switch ($op) { case 'help': if (strpos($type, 'notifications-event') === 0) { $help[] = t('The Header and Footer will be taken from Notification events.'); $help[] = t('The Digest line will be used when composing Short digests on which each event will be just a line.'); return $help; } break; case 'info': $info = array(); if ($type == 'all' || $type == 'notifications-event-node') { // Generic notifications event $info['notifications-event-node'] = array( 'module' => 'notifications_content', 'name' => t('Notifications for node events'), 'description' => t('Defaults for all notifications related to node events.'), 'fallback' => 'notifications-event', ); } if ($type == 'all' || $type == 'notifications-event-node-insert') { $info['notifications-event-node-insert'] = array( 'module' => 'notifications_content', 'name' => t('Notifications for node creation'), 'description' => t('Notifications produced when a new node is created.'), 'fallback' => 'notifications-event-node', ); } if ($type == 'all' || $type == 'notifications-event-node-update') { $info['notifications-event-node-update'] = array( 'module' => 'notifications_content', 'name' => t('Notifications for node updates'), 'description' => t('Notifications produced when a node is updated.'), 'fallback' => 'notifications-event-node', ); } if ($type == 'all' || $type == 'notifications-event-node-comment') { $info['notifications-event-node-comment'] = array( 'module' => 'notifications_content', 'name' => t('Notifications for node comments'), 'description' => t('Notifications produced when a comment is posted to a node.'), 'fallback' => 'notifications-event-node', ); } if ($type == 'digest' || $type == 'notifications-digest-node-nid') { // Node group digests, will have specific help text in hook_help() $info['notifications-digest-node-nid'] = array( 'module' => 'notifications_content', 'name' => t('Groups digests per node'), 'description' => t('Group of events digested for each node.'), 'fallback' => 'notifications-digest', ); } if ($type == 'digest' || $type == 'notifications-digest-node-type') { $info['notifications-digest-node-type'] = array( 'module' => 'notifications_content', 'name' => t('Groups digests per node type'), 'description' => t('Group of events digested for each node type.'), 'fallback' => 'notifications-digest', ); } return $info; case 'parts': switch ($type) { case 'notifications-event-node': case 'notifications-event-node-insert': case 'notifications-event-node-update': case 'notifications-event-node-comment': // Some parts will be re-used from 'notifications-event' group // So we specify only subject and main message return array( 'subject' => t('Subject'), 'main' => t('Content'), 'digest' => t('Digest line'), ); case 'notifications-digest-node-nid': case 'notifications-digest-node-type': $parts['title'] = t('Group title'); $parts['closing'] = t('Group footer'); return $parts; } break; case 'defaults': // Event notifications switch ($type) { case 'notifications-event-node': case 'notifications-event-node-update': return array( 'subject' => t('Update for [type-name]: [title]', array(), $language->language), 'main' => array( '[node-teaser]', t('Read more [node-url]', array(), $language->language), ), 'digest' => array( '[title]', t('Read more [node-url]', array(), $language->language), ), ); case 'notifications-event-node-insert': return array( 'subject' => t('New [type-name]: [title]', array(), $language->language), 'main' => array( '[node-teaser]', t('Read more [node-url]', array(), $language->language), ), 'digest' => array( '[title]', t('Read more [node-url]', array(), $language->language), ), ); case 'notifications-event-node-comment': return array( 'subject' => t('Comment for [type-name]: [title]', array(), $language->language), 'main' => array( t('Comment by [comment-author-name]: [comment-title]', array(), $language->language), '[comment-body]', t('Read more [comment-url]', array(), $language->language), ), 'digest' => array( t('New Comment on [title] by [comment-author-name] titled [comment-title]'), t('Read more [comment-url]', array(), $language->language), ), ); case 'notifications-digest-node-nid': // Define only group title and group footer (closing) // The 'closing' statement is typically a 'read more' link return array( 'title' => t('Updates for [type-name]: [title]', array(), $language->language), 'closing' => t('Read more [node-url]', array(), $language->language), ); case 'notifications-digest-node-type': return array( 'title' => t('New content of type [type-name] has been submitted', array(), $language->language), 'closing' => '