View source
<?php
define('NOTIFICATIONS_CONTENT_PAGER', 20);
require_once drupal_get_path('module', 'notifications') . '/notifications.node.inc';
function notifications_content_menu() {
$items['admin/messaging/notifications/content'] = array(
'title' => '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',
);
$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',
'page arguments' => array(
1,
),
'weight' => 10,
'file' => 'notifications_content.pages.inc',
);
return $items;
}
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);
}
function notifications_content_perm() {
return array(
'subscribe to content',
'subscribe to content type',
'subscribe to author',
'skip notifications',
);
}
function notifications_content_help($path, $arg) {
if ($path == 'admin/messaging/notifications/content') {
$output = '<p>' . 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.') . '</p>';
$output .= '<p>' . t('On this page you can set which of the available subscription types are allowed. Alternatively you can select the <em>Set up for each content type</em> option and use the <a href="@content-type-settings">Administer Content types</a> 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'),
)) . '</p>';
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 = '<p>' . t('This is the format for each digest group. A message may consist on one or many of these groups:') . '</p>';
$help .= '<small><pre>';
$help .= t('Group title') . "\n";
$help .= '- ' . t('Digest line.') . "\n";
$help .= '- ' . t('Digest line.') . "\n";
$help .= '- ...' . "\n";
$help .= t('Group footer') . "\n";
$help .= '</pre></small>';
return $help;
}
}
}
function notifications_content_form_alter(&$form, &$form_state, $form_id) {
switch ($form_id) {
case 'comment_form':
$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 (!empty($form['cid']['#value'])) {
$form['notifications_comment_status'] = array(
'#type' => 'value',
'#value' => !empty($form['admin']['status']) ? $form['admin']['status']['#default_value'] : COMMENT_PUBLISHED,
);
}
}
break;
case 'node_type_form':
if (isset($form['identity']['type'])) {
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'] .= ' <strong>' . t('To enable these options check the <a href="@notifications-settings">Notifications content settings</a>', array(
'@notifications-settings' => url('admin/messaging/notifications/content'),
)) . '</strong>';
}
}
break;
default:
if (isset($form['type']) && isset($form['#node']) && $form['type']['#value'] . '_node_form' == $form_id) {
$types = notifications_content_types(NULL);
$node = $form['#node'];
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));
}
}
}
}
function _notifications_content_add_disable_field(&$form, $default = 0) {
if (user_access('skip notifications')) {
$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,
);
}
}
function notifications_content_theme() {
return array(
'notifications_content_type_settings' => array(
'arguments' => array(
'element' => NULL,
),
'file' => 'notifications_content.pages.inc',
),
);
}
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' => notifications_translate('type:' . $subs->fields['type'] . ':name', node_get_types('name', $subs->fields['type']), NULL, 'nodetype'),
));
}
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':
$disabled = !variable_get('notifications_content_per_type', 0);
$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.'),
'disabled' => $disabled && !notifications_content_type_enabled(NULL, '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.'),
'disabled' => $disabled && !notifications_content_type_enabled(NULL, 'nodetype'),
);
$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.'),
'disabled' => $disabled && !notifications_content_type_enabled(NULL, 'author'),
);
$types['typeauthor'] = array(
'event_type' => 'node',
'title' => t('Content type and Author'),
'access' => 'subscribe to content type and author',
'fields' => array(
'author',
'type',
),
'description' => t('Subscribe to all content of a given type submitted by a user.'),
'disabled' => $disabled && !notifications_content_type_enabled(NULL, 'typeauthor'),
);
return $types;
case 'subscription fields':
$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_callback',
'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_callback',
);
return $fields;
case 'query':
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':
return _notifications_content_node_options($arg0, $arg1);
case 'user options':
return _notifications_content_user_options($arg0, $arg1);
case 'event load':
$event =& $arg0;
$load = array();
if ($event->type == 'node') {
if (!empty($event->params['nid']) && empty($event->objects['node'])) {
if ($node = node_load($event->params['nid'])) {
$event->objects['node'] = $node;
}
else {
$event->delete = TRUE;
}
}
if (!empty($event->params['cid']) && empty($event->objects['comment'])) {
if ($comment = notifications_content_comment_load($event->params['cid'])) {
$event->objects['comment'] = $comment;
}
else {
$event->delete = TRUE;
}
}
}
break;
case 'event objects':
return array(
'node' => t('Node'),
);
case 'event types':
$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'),
);
$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':
$type = $arg0;
$account =& $arg1;
$object =& $arg2;
$access = TRUE;
if ($type == 'event' && $object->type == 'node') {
if (!empty($object->objects['node'])) {
$access = notifications_content_node_allow($account, $object->objects['node']);
}
if ($access && !empty($object->objects['comment'])) {
$access = $access && notifications_content_comment_allow($account, $object->objects['comment']);
}
}
elseif ($type == 'subscription') {
$access = TRUE;
if (!empty($object->fields['nid'])) {
if ($node = node_load($object->fields['nid'])) {
$access = notifications_content_node_allow($account, $node) && notifications_content_type_enabled($node->type, $object->type);
}
else {
$access = FALSE;
}
}
if (!empty($object->fields['type'])) {
$access = $access && notifications_content_type_enabled($object->fields['type'], $object->type);
}
}
return array(
$access,
);
break;
}
}
function notifications_content_author_name_callback($uid, $subs_type = '') {
return notifications_content_author_name($uid);
}
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.'));
}
}
function notifications_content_messaging($op, $arg1 = NULL, $arg2 = NULL, $arg3 = NULL, $arg4 = NULL) {
switch ($op) {
case 'message groups':
$help = t('The <em>Header</em> and <em>Footer</em> will be taken from Notification events.');
$help_digest = $help . ' ' . t('The <em>Digest line</em> will be used when composing Short digests on which each event will be just a line.');
$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',
);
$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':
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 'messages':
$type = $arg1;
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]'),
'closing' => t('Read more [node-url]'),
);
case 'notifications-digest-node-type':
return array(
'title' => t('New content of type [type-name] has been submitted'),
'closing' => '<none>',
);
}
break;
case 'tokens':
$type = explode('-', $arg1) + array(
2 => '',
3 => '',
);
$tokens = array();
if ($type[0] == 'notifications' && $type[2] == 'node') {
if ($type[1] == 'event') {
$tokens[] = 'node';
if ($type[3] == 'comment') {
$tokens[] = 'comment';
}
}
elseif ($type[1] == 'digest') {
if ($type[3] == 'nid') {
$tokens[] = 'node';
}
elseif ($type[3] == 'type') {
$tokens[] = array(
'node',
'type-name',
);
}
}
}
return $tokens;
}
}
function _notifications_content_node_options($account, $node) {
$options = array();
if (notifications_content_type_enabled($node->type, 'thread')) {
$options[] = array(
'name' => t('This post'),
'type' => 'thread',
'fields' => array(
'nid' => $node->nid,
),
);
}
if (notifications_content_type_enabled($node->type, 'nodetype')) {
$options[] = array(
'name' => t('Posts of type @type', array(
'@type' => notifications_translate("type:{$node->type}:name", node_get_types('name', $node->type), NULL, 'nodetype'),
)),
'type' => 'nodetype',
'fields' => array(
'type' => $node->type,
),
);
}
if (notifications_content_type_enabled($node->type, 'author')) {
$options[] = array(
'name' => t('Posts by @name', array(
'@name' => $node->name,
)),
'type' => 'author',
'fields' => array(
'author' => $node->uid,
),
);
}
return $options;
}
function _notifications_content_user_options($account, $author) {
$options = array();
$options[] = array(
'name' => t('All posts by @name', array(
'@name' => $author->name,
)),
'type' => 'author',
'fields' => array(
'author' => $author->uid,
),
);
foreach (notifications_content_types('name', 'typeauthor') as $type => $name) {
$options[] = array(
'name' => t('@type posts by @name', array(
'@name' => $author->name,
'@type' => $name,
)),
'type' => 'typeauthor',
'fields' => array(
'author' => $author->uid,
'type' => $type,
),
);
}
return $options;
}
function _notifications_content_type_options() {
return _notifications_subscription_types('long', array(
'event_type' => 'node',
));
}
function notifications_content_nodeapi(&$node, $op, $arg = 0) {
global $user;
static $done;
switch ($op) {
case 'load':
$node->old_status = $node->status;
break;
case 'update':
case 'insert':
if (!isset($done[$node->nid]) && $node->status && empty($node->notifications_content_disable) && notifications_content_type_enabled($node->type)) {
$done[$node->nid] = TRUE;
$event = array(
'module' => 'node',
'oid' => $node->nid,
'type' => 'node',
'action' => $op,
'node' => $node,
'params' => array(
'nid' => $node->nid,
),
);
if ($op == 'update') {
if (!isset($node->old_status)) {
$oldnode = node_load($node->nid);
$node->old_status = $oldnode->status;
}
if (!$node->old_status) {
$event['uid'] = $node->uid;
$event['action'] = 'insert';
}
if (variable_get('notifications_send_immediate', 0)) {
node_load(0, NULL, TRUE);
}
}
notifications_event($event);
}
break;
case 'delete':
notifications_delete_subscriptions(array(
'event_type' => 'node',
), array(
'nid' => $node->nid,
), FALSE);
break;
case 'notifications reset':
$done = array();
break;
}
}
function notifications_content_comment($comment, $op) {
$comment = (object) $comment;
if ($op == 'publish' && empty($comment->notifications_content_disable) && (!isset($comment->notifications_comment_status) || !empty($comment->notifications_comment_status))) {
$node = node_load($comment->nid);
if ($node->status && notifications_content_type_enabled($node->type)) {
$event = array(
'uid' => $comment->uid,
'module' => 'node',
'type' => 'node',
'action' => 'comment',
'node' => $node,
'comment' => $comment,
'params' => array(
'nid' => $comment->nid,
'cid' => $comment->cid,
),
);
notifications_event($event);
}
}
}
function notifications_content_node_type($op, $info) {
switch ($op) {
case 'delete':
notifications_delete_subscriptions(array(
'event_type' => 'node',
), array(
'type' => $info->type,
));
break;
case 'update':
if (!empty($info->old_type) && $info->old_type != $info->type) {
db_query("UPDATE {notifications_fields} SET value = '%s' WHERE field = 'type' AND value = '%s'", $info->type, $info->old_type);
}
break;
}
}
function notifications_content_comment_load($cid) {
static $cache = array();
if (!array_key_exists($cid, $cache)) {
$comment = db_fetch_object(db_query('SELECT c.*, u.uid, u.name AS registered_name, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d', $cid));
if ($comment) {
$comment = drupal_unpack($comment);
$comment->name = $comment->uid ? $comment->registered_name : $comment->name;
}
$cache[$cid] = $comment;
}
return $cache[$cid];
}
function notifications_content_types_callback($subs_type = 'nodetype') {
return notifications_content_types('name', $subs_type);
}
function notifications_content_types($field = 'name', $subs_type = 'nodetype') {
$types = array();
foreach (node_get_types() as $key => $data) {
if (notifications_content_type_enabled($key, $subs_type)) {
$types[$key] = $data;
}
}
if ($field) {
foreach (array_keys($types) as $type) {
$types[$type] = $types[$type]->{$field};
}
}
return $types;
}
function notifications_content_type_enabled($type = NULL, $option = NULL) {
$defaults = variable_get('notifications_content_type', array());
if ($type && variable_get('notifications_content_per_type', 0)) {
$settings = variable_get('notifications_content_type_' . $type, $defaults);
}
else {
$settings = $defaults;
}
if ($option) {
return in_array($option, $settings, TRUE);
}
else {
return array_filter($settings);
}
}
function notifications_content_token_list($type = 'all') {
$tokens = array();
if ($type == 'node' || $type == 'all') {
$tokens['node']['node-teaser'] = t('The node teaser.');
$tokens['node']['node-body'] = t('The node body.');
$tokens['node']['node-teaser-raw'] = t('Unfiltered node teaser. WARNING - raw user input.');
$tokens['node']['node-body-raw'] = t('Unfiltered node body. WARNING - raw user input.');
}
if ($type == 'comment' || $type == 'all') {
$tokens['comment']['comment-url'] = t('The comment view url.');
$tokens['comment']['comment-reply-url'] = t('The comment reply url.');
}
return $tokens;
}
function notifications_content_token_values($type, $object = NULL, $options = array()) {
switch ($type) {
case 'node':
if ($node = $object) {
$values['node-teaser'] = !empty($node->teaser) ? check_markup($node->teaser, $node->format, FALSE) : '';
$values['node-body'] = !empty($node->body) ? check_markup($node->body, $node->format, FALSE) : '';
$values['node-teaser-raw'] = !empty($node->teaser) ? $node->teaser : '';
$values['node-body-raw'] = !empty($node->body) ? $node->body : '';
return $values;
}
break;
case 'comment':
if ($comment = (object) $object) {
$values['comment-url'] = url('node/' . $comment->nid, array(
'fragment' => 'comment-' . $comment->cid,
'absolute' => TRUE,
));
$values['comment-reply-url'] = url('comment/reply/' . $comment->nid . '/' . $comment->cid, array(
'absolute' => TRUE,
));
return $values;
}
break;
}
}
function notifications_content_node_allow($account, $node) {
static $access;
if (!$node) {
return FALSE;
}
if (!isset($access[$account->uid][$node->nid])) {
$access[$account->uid][$node->nid] = node_access('view', $node, $account);
}
return $access[$account->uid][$node->nid];
}
function notifications_content_comment_allow($account, $comment) {
static $access;
$comment = is_object($comment) ? $comment : db_fetch_object(db_query("SELECT * FROM {comments} WHERE cid = %d", $comment));
if (!isset($access[$account->uid][$comment->cid])) {
if (($account->uid == $comment->uid || $comment->status == COMMENT_PUBLISHED) && user_access('access comments', $account) || user_access('administer comments', $account)) {
$access[$account->uid][$comment->cid] = TRUE;
}
else {
$access[$account->uid][$comment->cid] = FALSE;
}
}
return $access[$account->uid][$comment->cid];
}