'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, 'access arguments' => FALSE, 'title' => 'Thread', 'page callback' => 'notifications_content_page_thread', 'page arguments' => array(1), 'weight' => 10, 'file' => 'notifications_content.pages.inc', ); $items['user/%user/notifications/nodetype'] = array( 'type' => MENU_LOCAL_TASK, 'access callback' => FALSE, 'title' => 'Content type', 'page callback' => 'notifications_content_page_nodetype', 'page arguments' => array(1), 'weight' => 10, 'file' => 'notifications_content.pages.inc', ); $items['user/%user/notifications/author'] = array( 'type' => MENU_LOCAL_TASK, 'access callback' => FALSE, 'title' => t('Author'), 'page callback' => 'notifications_content_page_author', 'pàge arguments' => array(1), 'weight' => 10, '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', 'skip notifications'); } /** * Implementation of hook_help() */ function notifications_content_help($path, $arg) { if ($path == 'admin/messaging/notifications/content') { $output .= '
'. t('To determine the available subscription types for each content type you can also use the !content-type-settings', array('!content-type-settings' => l(t('content types settings page'), '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)) {
$form['notifications']['notifications_content_disable'] = array(
'#type' => 'checkbox',
'#title' => t('Do not send notifications for this comment.'),
'#default_value' => 0,
'#access' => user_access('skip notifications'),
);
}
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) {
$types = notifications_content_types(NULL);
if (notifications_content_type_enabled($node->type)) {
$noprevious = !isset($form['notifications']);
$form['notifications']['#type'] = 'fieldset';
$form['notifications']['#title'] = t('Notifications');
$form['notifications']['#collapsible'] = TRUE;
$form['notifications']['#weight'] = 1;
//don't want to hide/change access on modules that already used the notifications fieldset for something
if ($noprevious) {
$form['notifications']['#collapsed'] = TRUE;
$form['notifications']['#access'] = user_access('skip notifications');
}
$form['notifications']['notifications_content_disable'] = array(
'#type' => 'checkbox',
'#title' => t('Do not send notifications for this update.'),
'#default_value' => 0,
'#access' => user_access('skip notifications'),
);
}
}
}
}
/**
* 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, &$arg0, $arg1 = NULL, $arg2 = NULL) {
switch ($op) {
case 'names':
$subs = &$arg0;
if ($subs->event_type == 'node') {
$subs->type_name = t('Content');
if (!empty($subs->fields['type'])) {
$subs->names['type'] = t('Content type: @type', array('@type' => node_get_types('name', $subs->fields['type'])));
}
if (!empty($subs->fields['author']) && ($author = user_load(array('uid' => $subs->fields['author'])))) {
$subs->names['author'] = t('Author: @name', array('@name' => $author->name));
}
if (!empty($subs->fields['nid']) && ($node = node_load($subs->fields['nid']))) {
$subs->names['thread'] = t('Thread: @title', array('@title' => $node->title));
}
}
break;
case 'subscription types':
$types['thread'] = array(
'event_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.')
);
$types['nodetype'] = array(
'event_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.')
);
$types['author'] = array(
'event_type' => 'node',
'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.')
);
// This is a complex type, combining two fields
$types['typeauthor'] = array(
'event_type' => 'node',
'title' => t('Content type and Author'),
'access' => 'subscribe to content type and author',
//'page callback' => 'notifications_content_page_author',
'fields' => array('author', 'type'),
'description' => t('Subscribe to all content of a given type submitted by a user.')
);
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',
'autocomplete path' => 'notifications/autocomplete/node/title',
'autocomplete callback' => 'notifications_node_nid2autocomplete',
'format callback' => 'notifications_node_nid2title',
'value callback' => 'notifications_node_title2nid',
);
$fields['author'] = array(
'name' => t('Author'),
'field' => 'author',
'type' => 'int',
'autocomplete path' => 'user/autocomplete',
'autocomplete callback' => 'notifications_content_author_name',
'format callback' => 'notifications_content_author_name',
'value callback' => 'notifications_content_author_uid',
);
$fields['type'] = array(
'name' => t('Node type'),
'field' => 'type',
'type' => 'string',
'options callback' => 'notifications_content_types',
);
return $fields;
case 'query':
// $arg2 is $event array.
if ($arg0 == 'event' && $arg1 == 'node' && ($node = $arg2->node) ||
$arg0 == 'user' && $arg1 == 'node' && ($node = $arg2)) {
$query[]['fields'] = array(
'nid' => $node->nid,
'type' => $node->type,
'author' => $node->uid,
);
return $query;
}
break;
case 'node options':
// Subscription options for a node, args will be account and node
return _notifications_content_node_options($arg0, $arg1);
case 'user options':
// Subscription options for a user account, args will be account and author
return _notifications_content_user_options($arg0, $arg1);
case 'event load': // $arg0 is event
$event = &$arg0;
$load = array();
if ($event->type == 'node') {
if (!empty($event->params['nid'])) {
$event->objects['node'] = node_load($event->params['nid']);
}
if (!empty($event->params['cid'])) {
$event->objects['comment'] = notifications_content_comment_load($event->params['cid']);
}
}
break;
case 'event objects':
return array('node' => t('Node'));
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[] = 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'),
);
// 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[] = 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'),
);
$types[] = 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'),
);
return $types;
case 'access':
// Return an array with some TRUE value if the user has access to this event objects or subscription type
$type = $arg0;
$account = &$arg1;
$object = &$arg2;
$access = TRUE;
// For events we check that node and comment are allowed
if ($type == 'event' && $object->type == 'node') {
if (!empty($object->objects['node'])) {
$access = notifications_content_node_allow($account, $object->objects['node']);
}
// If no access to node, we don't check more
if ($access && !empty($object->objects['comment'])) {
$access = $access && notifications_content_comment_allow($account, $object->objects['comment']);
}
// For node subscriptions we check that user can view the node
}
elseif ($type == 'subscription') {
$access = TRUE;
if (!empty($object->fields['nid'])) {
if ($node = node_load($object->fields['nid'])) {
$access = notifications_content_node_allow($account, $node);
}
else {
$access = FALSE;
}
}
if (!empty($object->fields['type'])) {
$access = $access && array_key_exists($object->fields['type'], notifications_content_types());
}
}
// We return an array that will be merged with the ones from other modules
return array($access);
break;
}
}
/**
* Field name callback, author uid to user name
*/
function notifications_content_author_name($uid, $html = FALSE) {
if ($account = user_load($uid)) {
return $html ? theme('username', $account) : check_plain($account->name);
}
}
function notifications_content_author_uid($name, $field = NULL) {
if ($account = user_load(array('name' => $name))) {
return $account->uid;
}
elseif ($field) {
form_set_error($field, t('User name not found.'));
}
}
/**
* Implementation of hook_messaging()
*/
function notifications_content_messaging($op, $arg1 = NULL, $arg2 = NULL, $arg3 = NULL, $arg4 = NULL) {
switch ($op) {
case 'message groups':
$help = t('The Header and Footer will be taken from Notification events.');
$help_digest = $help . ' ' . t('The Digest line will be used when composing Short digests on which each event will be just a line.');
// 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.'),
'help' => $help_digest,
'fallback' => 'notifications-event',
);
$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.'),
'help' => $help_digest,
'fallback' => 'notifications-event-node',
);
$info['notifications-event-node-update'] = array(
'module' => 'notifications_content',
'name' => t('Notifications for node updates'),
'description' => t('Notifications produced when a node is updated.'),
'help' => $help_digest,
'fallback' => 'notifications-event-node',
);
$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.'),
'help' => $help_digest,
'fallback' => 'notifications-event-node',
);
// 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',
);
$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 'message keys':
$type = $arg1;
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['footer'] = t('Group footer');
return $parts;
}
break;
case 'messages':
$type = $arg1;
// Event notifications
switch ($type) {
case 'notifications-event-node':
case 'notifications-event-node-update':
return array(
'subject' => t('Update for [type-name]: [title]'),
'main' => array(
'[node-teaser]',
t('Read more [node-url]'),
),
'digest' => array(
'[title]',
'Read more [node-url]',
),
);
case 'notifications-event-node-insert':
return array(
'subject' => t('New [type-name]: [title]'),
'main' => array(
'[node-teaser]',
t('Read more [node-url]'),
),
'digest' => array(
'[title]',
'Read more [node-url]',
),
);
case 'notifications-event-node-comment':
return array(
'subject' => t('Comment for [type-name]: [title]'),
'main' => array(
t('Comment by [comment-author-name]: [comment-title]'),
'[comment-body]',
t('Read more [comment-url]'),
),
'digest' => array(
t('New Comment on [title] by [comment-author-name] titled [comment-title]'),
t('Read more [comment-url]'),
),
);
case 'notifications-digest-node-nid':
return array(
'title' => t('Updates for [type-name]: [title]'),
'footer' => t('Read more [node-url]'),
);
case 'notifications-digest-node-type':
return array(
'title' => t('New content of type [type-name] has been submitted'),
'footer' => '