notify.module in Notify 6
Same filename and directory in other branches
Notify module sends email digests of new content and comments.
The notification module allows users to subscribe to periodic e-mails which include all new or revised content and/or comments much like the daily news letters sent by some websites. Even if this feature is not configured for normal site users, it can be a useful feature for an administrator of a site to monitor content submissions and comment posts.
File
notify.moduleView source
<?php
/**
* @file
* Notify module sends email digests of new content and comments.
*
* The notification module allows users to subscribe to periodic e-mails which
* include all new or revised content and/or comments much like the daily news
* letters sent by some websites. Even if this feature is not configured for
* normal site users, it can be a useful feature for an administrator of a site
* to monitor content submissions and comment posts.
*/
define('NOTIFY_NODE_TYPE', 'notify_node_type_');
/**
* Implementation of hook_help().
*/
function notify_help($section) {
switch ($section) {
case 'admin/help#notify':
$output = '<p>' . t('The notification module allows users to subscribe to periodic e-mails which include all new or revised content and/or comments much like the daily news letters sent by some websites. Even if this feature is not configured for normal site users, it can be a useful feature for an administrator of a site to monitor content submissions and comment posts.') . '</p>';
$output .= '<p>' . t('The administrator sets the frequency of the e-mails in the notify administration interface. They can also set how many e-mail failures should occur before notify stops sending notifications. Note that cron must be enabled for notifications to be sent out.') . '</p>';
$output .= t('<p>You can</p><ul><li>set up your site to run tasks automatically at required intervals. For more information, see <a href="@admin-help-system">cron</a>.</li><li>administer notify <a href="@admin-settings-notify">administer >> settings >> notify</a>.</li></ul>', array(
'@admin-help-system' => url('admin/help/system'),
'@admin-settings-notify' => url('admin/settings/notify'),
));
$output .= '<p>' . t('For more information please read the configuration and customization handbook <a href="@notify">Notify page</a>.', array(
'@notify' => 'http://www.drupal.org/handbook/modules/notify/',
)) . '</p>';
return $output;
}
}
/**
* Menu callback; display notify settings page.
*/
function notify_admin_settings() {
$period = array(
900 => format_interval(900),
1800 => format_interval(1800),
3600 => format_interval(3600),
10800 => format_interval(10800),
21600 => format_interval(21600),
32400 => format_interval(32400),
43200 => format_interval(43200),
86400 => format_interval(86400),
172800 => format_interval(172800),
259200 => format_interval(259200),
604800 => format_interval(604800),
1209600 => format_interval(1209600),
2419200 => format_interval(2419200),
-1 => t('Never'),
);
$form = array();
$form['notify_settings'] = array(
'#type' => 'fieldset',
'#title' => t('E-mail notification settings'),
'#collapsible' => TRUE,
);
$form['notify_settings']['notify_send'] = array(
'#type' => 'select',
'#title' => t('Send notifications every'),
'#default_value' => variable_get('notify_send', array(
86400,
)),
'#options' => $period,
'#description' => t('How often should new content notifications be sent? Requires cron to be running at least this often.'),
);
$form['notify_settings']['notify_send_hour'] = array(
'#type' => 'select',
'#title' => t('Hour to Send Notifications'),
'#description' => t('Specify the hour (24-hour clock) in which notifications should be sent, if the frequency is one day or greater.'),
'#default_value' => variable_get('notify_send_hour', 9),
'#options' => array(
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
),
);
$form['notify_settings']['notify_attempts'] = array(
'#type' => 'select',
'#title' => t('Number of failed sends after which notifications are disabled'),
'#default_value' => variable_get('notify_attempts', array(
5,
)),
'#options' => array(
t('Disabled'),
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
15,
20,
),
);
$form['notify_settings']['notify_reg_default'] = array(
'#type' => 'checkbox',
'#title' => t('Notification checkbox default on new user registration form'),
'#return_value' => 1,
'#default_value' => variable_get('notify_reg_default', 1),
);
$form['notify_settings']['notify_include_updates'] = array(
'#type' => 'checkbox',
'#title' => t('Include updated posts in notifications'),
'#return_value' => 1,
'#default_value' => variable_get('notify_include_updates', 1),
);
$set = 'ntype';
$form[$set] = array(
'#type' => 'fieldset',
'#title' => t('Notification by node type'),
'#collapsible' => TRUE,
'#collapsed' => FALSE,
'#description' => t('Having nothing checked defaults to sending notifications about all node types.'),
);
foreach (node_get_types('types', array()) as $type => $object) {
$form[$set][NOTIFY_NODE_TYPE . $type] = array(
'#type' => 'checkbox',
'#title' => $object->name,
'#return_value' => 1,
'#default_value' => variable_get(NOTIFY_NODE_TYPE . $type, 0),
);
}
return system_settings_form($form);
}
/**
* Implementation of hook_cron().
*/
function notify_cron() {
$send_last = variable_get('notify_send_last', 0);
$send_interval = variable_get('notify_send', 86400);
$send_hour = variable_get('notify_send_hour', 9);
$send_start = time();
if ($send_start - $send_last > $send_interval && (date('G', $send_start) >= $send_hour || $send_interval < 86400) && $send_interval != -1) {
_notify_send($send_start);
variable_set('notify_send_last', $send_start);
}
}
/**
* Implementation of hook_user().
*/
function notify_user($type, &$edit, &$user, $category = NULL) {
switch ($type) {
case 'delete':
db_query('DELETE FROM {notify} WHERE uid = %d', $user->uid);
break;
case 'register':
return _notify_user_reg_fields();
break;
case 'insert':
if (isset($edit['notify_decision']) && $edit['notify_decision'] == 1) {
db_query('INSERT INTO {notify} (uid, status, node, teasers, comment) VALUES (%d, %d, %d, %d, %d)', $user->uid, 1, 1, 0, 0);
$edit['notify_decision'] = NULL;
}
break;
}
}
/**
* Returns form fields to be added to User Regsitration form
*/
function _notify_user_reg_fields() {
if (!user_access('access notify')) {
return;
}
// Get the variable for how often the notifications are sent out
$period = variable_get("notify_send", 86400);
// Add a fieldset containing a checkbox for users to accept
// getting updates on the registration form.
$fields['notify_agree'] = array(
'#type' => 'fieldset',
'#title' => t('Email Notifications'),
);
// Add the checkbox to the fieldset
$fields['notify_agree']['notify_decision'] = array(
'#type' => 'checkbox',
'#title' => t('Receive e-mail notifications of new content posted to this site. Notifications are sent every @interval.', array(
'@interval' => format_interval($period),
)),
'#return_value' => 1,
'#default_value' => variable_get('notify_reg_default', 1),
);
return $fields;
}
/**
* Implementation of hook_perm().
*/
function notify_perm() {
return array(
'access notify',
'administer notify',
);
}
/**
* Implementation of hook_menu().
*
* @return array
*/
function notify_menu() {
$items = array();
$items['admin/settings/notify'] = array(
'title' => 'Notification settings',
'description' => 'Adjust settings for new content notifications sent by e-mail.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'notify_admin_settings',
),
'access callback' => 'user_access',
'access arguments' => array(
'administer notify',
),
'type' => MENU_NORMAL_ITEM,
);
$items['user/%user/notify'] = array(
'title' => 'Notification settings',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'notify_user_settings_form',
1,
),
'access callback' => 'notify_user_access',
'access arguments' => array(
1,
),
'type' => MENU_LOCAL_TASK,
);
$items['admin/user/user/notify'] = array(
'title' => 'Notifications',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'notify_admin_users',
),
'access callback' => 'user_access',
'access arguments' => array(
'administer notify',
),
'type' => MENU_LOCAL_TASK,
);
return $items;
}
/**
* Checks access to notifications settings tab
*/
function notify_user_access($account = NULL) {
return $account->uid && ($GLOBALS['user']->uid == $account->uid && user_access('access notify') || user_access('administer notify'));
}
/**
* Register the themeing the form data into a table at
* admin/user/user/notify
*
* @return array
*/
function notify_theme() {
return array(
'notify_admin_users' => array(
'arguments' => array(
'form' => NULL,
),
),
);
}
/**
* Menu callback; show user notification options.
*/
function notify_user_settings_form(&$form_state, $arg) {
global $user;
if ($user->uid != $arg->uid && !user_access('administer notify')) {
drupal_access_denied();
return;
}
$account = user_load(array(
'uid' => $arg->uid,
));
if (!is_object($account)) {
drupal_not_found();
return;
}
$result = db_query('SELECT u.uid, u.name, u.mail, n.status, n.node, n.teasers, n.comment FROM {users} u LEFT JOIN {notify} n ON u.uid = n.uid WHERE u.uid = %d AND u.status = 1', $account->uid);
$notify = db_fetch_object($result);
$form = array();
if (!$notify->mail) {
drupal_set_message(t('Your e-mail address must be specified on your <a href="@url">my account</a> page.', array(
'@url' => url('user/' . $account->uid . '/edit'),
)), 'error');
}
$form['notify_page_master'] = array(
'#type' => 'fieldset',
'#title' => t('Master switch'),
);
$form['notify_page_master']['status'] = array(
'#type' => 'radios',
'#title' => t('Notify status'),
'#default_value' => $notify->status,
'#options' => array(
t('Disabled'),
t('Enabled'),
),
'#description' => t('Do you wish to receive periodic e-mails when new content is posted?'),
);
$form['notify_page_detailed'] = array(
'#type' => 'fieldset',
'#title' => t('Detailed settings'),
);
$form['notify_page_detailed']['node'] = array(
'#type' => 'radios',
'#title' => t('Notify new content'),
'#default_value' => $notify->node,
'#options' => array(
t('Disabled'),
t('Enabled'),
),
'#description' => t('Include new posts in the notification mail.'),
);
$form['notify_page_detailed']['teasers'] = array(
'#type' => 'radios',
'#title' => t('Content'),
'#default_value' => $notify->teasers,
'#options' => array(
t('Title only'),
t('Title + Teaser'),
t('Title + Body'),
),
'#description' => t('Select the amount of each post that you would like to see in your notification e-mails.'),
);
$form['notify_page_detailed']['comment'] = array(
'#type' => 'radios',
'#title' => t('Notify new comments'),
'#default_value' => $notify->comment,
'#options' => array(
t('Disabled'),
t('Enabled'),
),
'#description' => t('Include new comments in the notification mail.'),
);
$form['uid'] = array(
'#type' => 'value',
'#value' => $account->uid,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save settings'),
);
return $form;
}
function notify_user_settings_form_submit($form, &$form_state) {
unset($form);
db_query('DELETE FROM {notify} WHERE uid = %d', $form_state['values']['uid']);
db_query('INSERT INTO {notify} (uid, status, node, teasers, comment) VALUES (%d, %d, %d, %d, %d)', $form_state['values']['uid'], $form_state['values']['status'], $form_state['values']['node'], $form_state['values']['teasers'], $form_state['values']['comment']);
drupal_set_message(t('Notify settings saved.'));
}
/**
* Menu callback; show admininster user notification settings form.
*/
function notify_admin_users() {
$form = array();
$form['#tree'] = TRUE;
$form['info'] = array(
'#value' => t('The following table shows all users that have notifications enabled.'),
);
$form['users'] = array();
$result = db_query('SELECT u.uid, u.name, u.mail, n.* FROM {users} u LEFT JOIN {notify} n ON u.uid = n.uid WHERE n.status = 1 AND u.status = 1 ORDER BY u.name');
while ($notify = db_fetch_object($result)) {
$form['users'][$notify->uid] = array();
$form['users'][$notify->uid]['name'] = array(
'#type' => 'markup',
'#value' => theme('username', $notify),
);
$form['users'][$notify->uid]['mail'] = array(
'#type' => 'markup',
'#value' => $notify->mail,
);
$form['users'][$notify->uid]['node'] = array(
'#type' => 'checkbox',
'#default_value' => $notify->node,
);
$form['users'][$notify->uid]['teasers'] = array(
'#type' => 'select',
'#default_value' => $notify->teasers,
'#options' => array(
t('Title only'),
t('Title + Teaser'),
t('Title + Body'),
),
);
$form['users'][$notify->uid]['comment'] = array(
'#type' => 'checkbox',
'#default_value' => $notify->comment,
);
$form['users'][$notify->uid]['attempts'] = array(
'#type' => 'textfield',
'#size' => 2,
'#default_value' => $notify->attempts ? intval($notify->attempts) : 0,
);
}
$form['flush'] = array(
'#title' => t('Flush e-mail queue'),
'#type' => 'checkbox',
'#default_value' => FALSE,
'#description' => t('Send out any pending notification e-mails currently in queue.'),
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save settings'),
);
return $form;
}
/**
* Submit for the notify_admin form.
*/
function notify_admin_users_submit($form, &$form_state) {
unset($form);
if ($form_state['values']['users']) {
foreach ($form_state['values']['users'] as $uid => $settings) {
db_query('UPDATE {notify} SET node = %d, teasers = %d, comment = %d, attempts = %d WHERE uid = %d', $settings['node'], $settings['teasers'], $settings['comment'], $settings['attempts'], $uid);
}
}
drupal_set_message(t('Notify settings saved.'));
if ($form_state['values']['flush']) {
$send_start = time();
list($num_sent, $num_failed) = _notify_send($send_start);
variable_set('notify_send_last', $send_start);
if ($num_sent > 0) {
drupal_set_message(t('!count pending notification e-mails have been sent.', array(
'!count' => $num_sent,
)));
}
elseif ($num_failed > 0) {
drupal_set_message(t('!count notification e-mails could not be sent.', array(
'!count' => $num_failed,
)), 'error');
}
else {
drupal_set_message(t('No notification e-mails needed to be sent.'));
}
}
}
/**
* Theme function to theme the admin user settings form in a table format.
*/
function theme_notify_admin_users($form) {
$output = drupal_render($form['info']);
$header = array(
t('Username'),
t('E-mail address'),
t('Content'),
t('Teasers'),
t('Comment'),
t('Failed attempts'),
);
$rows = array();
foreach (element_children($form['users']) as $uid) {
$row = array();
foreach (element_children($form['users'][$uid]) as $entry_key) {
unset($form['users'][$uid][$entry_key]['#title']);
$row[] = drupal_render($form['users'][$uid][$entry_key]);
}
$rows[] = $row;
}
if (!$rows) {
$rows[] = array(
array(
'data' => t('No users have notifications enabled.'),
'colspan' => 6,
),
);
}
$output .= theme('table', $header, $rows);
$output .= drupal_render($form);
return $output;
}
/**
* Formatting of outgoing mail, taken from mail.inc, part of project.module
*/
function _notify_content($node, $notify) {
static $i = 0;
switch ($notify->teasers) {
case 0:
return;
case 1:
$txt = check_markup($node->teaser, $node->format, FALSE);
break;
case 2:
$txt = check_markup($node->body, $node->format, FALSE);
}
return drupal_html_to_text($txt);
}
/**
* Helper function to send the notification email.
*
* TODO: Needs some cleanup and themability.
*/
function _notify_send($send_start = NULL) {
$send_start = $send_start ? $send_start : time();
$period = variable_get('notify_send_last', $send_start - variable_get('notify_send', 86400));
$separator = '------------------------------------------------------------------------------';
$mini_separator = '---';
$num_sent = 0;
$num_failed = 0;
_notify_switch_user();
// Store current user
// Fetch all node type authorized by notify settings
//Note that queries use 'nn' alias to avoid conflicts when query is rewritten by access control modules
$ntype = array();
foreach (node_get_types() as $type => $name) {
if (variable_get(NOTIFY_NODE_TYPE . $type, 0)) {
$ntype[] = $type;
}
if (count($ntype) >= 1) {
$nodetypes_query = "AND (nn.type = '" . implode("' OR nn.type = '", $ntype) . "') ";
}
else {
$nodetypes_query = '';
}
}
// build query to fetch desired nodes.
$q = 'SELECT nn.nid FROM {node} nn WHERE (nn.status = 1 OR nn.moderate = 1) ' . $nodetypes_query . ' AND ((nn.created > %d AND nn.created <= %d)';
//include updated nodes?
$q .= variable_get('notify_include_updates', 1) ? ' OR (nn.changed > %d AND nn.changed <= %d))' : ')';
$q .= ' ORDER BY nn.created ASC';
//Run the query, and load the nodes
_notify_switch_user(1);
//Query as if user 1, we check for individual user access later.
$nresult = db_query(db_rewrite_sql($q, 'nn'), $period, $send_start, $period, $send_start);
$nodes = array();
while ($node = db_fetch_object($nresult)) {
$nodes[$node->nid] = node_load($node->nid);
}
// Fetch new comments.
$comments = array();
if (module_exists('comment')) {
$cresult = db_query(db_rewrite_sql('SELECT c.nid, c.cid, c.subject, c.name, c.status FROM {comments} c INNER JOIN {node} nn ON c.nid = nn.nid WHERE c.timestamp > %d AND c.timestamp <= %d ' . $nodetypes_query . ' ORDER BY c.nid, c.timestamp', 'c'), $period, $send_start);
while ($comment = db_fetch_object($cresult)) {
$comments[$comment->nid][] = $comment;
}
}
if (count($nodes) || count($comments)) {
// Fetch users with notify enabled
$uresult = db_query('SELECT u.uid, u.name, u.mail, u.language, n.status, n.node, n.teasers, n.comment FROM {notify} n INNER JOIN {users} u ON n.uid = u.uid WHERE n.status = 1 AND u.status = 1 AND n.attempts <= %d', variable_get('notify_attempts', 5));
while ($user = db_fetch_object($uresult)) {
// Switch current user to this account to use node_access functions, etc.
_notify_switch_user($user->uid);
$node_body = '';
$comment_body = '';
// Write new node content to e-mail if user has permissions and nodes are
// ready to be sent. @TODO - cache by role
if ($user->node && user_access('access content') && count($nodes)) {
$node_count = 0;
foreach ($nodes as $node) {
// Skip to next if this user is NOT allowed to view this node.
if (!node_access('view', $node)) {
continue;
}
// @TODO: Add functionality to hook into moderation modules?
if ($node->moderate == 1) {
$status = t('Queued');
}
elseif ($node->status == 1) {
$status = t('Published');
}
elseif ($node->status == 0) {
$status = t('Unpublished');
}
if ($node_count > 0) {
$node_body .= $mini_separator . "\n\n";
}
$node_body .= ++$node_count . '. ' . $node->title . "\n";
$node_body .= t('!status !type by !author', array(
'!status' => $status,
'!type' => node_get_types('name', $node),
'!author' => $node->name ? $node->name : variable_get('anonymous', 'Anonymous'),
)) . "\n";
$node_body .= '[ ' . url('node/' . $node->nid, array(
'absolute' => TRUE,
)) . ' ]' . "\n\n";
$node_body .= _notify_content($node, $user) . "\n";
}
// Prepend node e-mail header as long as user could access at least one node.
if ($node_count > 0) {
$node_body = $separator . "\n" . t('Recent content - !count', array(
'!count' => format_plural(count($nodes), '1 new post', '@count new posts'),
)) . "\n" . $separator . "\n\n" . $node_body;
}
}
// Write new comments to e-mail if user has permissions and there are
// comments to be sent.
if ($user->comment && user_access('access comments') && count($comments)) {
$total_comment_count = 0;
foreach ($comments as $nid => $comment) {
// If we don't already have the node, fetch it.
if (!isset($nodes[$nid])) {
$node = node_load($nid);
}
else {
$node = $nodes[$nid];
}
// Don't show comments if we're not allowed to view this node.
if (!node_access('view', $node)) {
continue;
}
if ($comment_body) {
$comment_body .= $mini_separator . "\n\n";
}
$comment_body .= t('!count attached to !type posted by !author: !title', array(
'!count' => format_plural(count($comment), '1 new comment', '@count new comments'),
'!title' => $node->title,
'!type' => node_get_types('name', $node),
'!author' => $node->name ? $node->name : variable_get('anonymous', 'Anonymous'),
)) . "\n";
$comment_count = 0;
foreach ($comment as $c) {
//Determine whether to show comment status
if (user_access('administer comments')) {
$status = $c->status == COMMENT_PUBLISHED ? t('Published') : t('Unpublished');
$status = " [{$status}]";
}
$comment_body .= ' ' . ++$comment_count . '.' . t('!status !title by !author', array(
'!status' => $status,
'!title' => $c->subject,
'!author' => $c->name ? $c->name : variable_get('anonymous', 'Anonymous'),
)) . "\n" . ' ' . url('node/' . $nid, array(
'fragment' => 'comment-' . $c->cid,
'absolute' => TRUE,
)) . "\n\n";
$total_comment_count++;
}
}
if ($total_comment_count > 0) {
$comment_body = $separator . "\n" . t('Recent comments - !count', array(
'!count' => format_plural($total_comment_count, '1 new comment', '@count new comments'),
)) . "\n" . $separator . "\n\n" . $comment_body;
}
}
$body = $node_body . $comment_body;
// If there was anything new, send mail.
if ($body) {
// Set up initial values for e-mail.
$headers = array();
//'From' => "$from_name <$from>");
if (!drupal_mail('notify', 'send', $user->mail, user_preferred_language($user), array(
'content' => $body,
))) {
$num_failed++;
db_query('UPDATE {notify} SET attempts = attempts + 1 WHERE uid = %d', $user->uid);
watchdog('notify', 'User %name (%mail) could not be notified. Mail error.', array(
'%name' => $user->name,
'%mail' => $user->mail,
), WATCHDOG_ERROR);
}
else {
$num_sent++;
watchdog('notify', 'User %name (%mail) notified successfully.', array(
'%name' => $user->name,
'%mail' => $user->mail,
), WATCHDOG_INFO);
}
}
}
}
// Restore user.
_notify_switch_user();
return array(
$num_sent,
$num_failed,
);
}
function notify_mail($key, &$message, $params) {
global $user;
$message['subject'] = t('!sitename new content notification for !username', array(
'!username' => $user->name,
'!sitename' => variable_get('site_name', 'Drupal'),
));
$message['body'] = t('Greetings !user,', array(
'!user' => $user->name,
)) . "\n\n";
$message['body'] .= $params['content'];
$message['body'] .= "-- \n" . t('This is an automatic e-mail from !sitename.', array(
'!sitename' => variable_get('site_name', 'Drupal'),
)) . "\n" . t('To stop receiving these e-mails, change your notification preferences at !notify-url', array(
'!notify-url' => url("user/{$user->uid}/notify", array(
'absolute' => TRUE,
)),
)) . "\n";
}
/**
* Switch from original user to mail submission user and back.
*
* NOTE: Copied from mailhandler
*
* Note: You first need to run _notify_switch_user without
* argument to store the current user. Call _notify_switch_user
* without argument to set the user back to the original user.
*
* @param $uid The user ID to switch to
*/
function _notify_switch_user($uid = NULL) {
global $user;
static $orig_user = array();
if (isset($uid)) {
// Should a user visit cron.php, or should this module be invoked via poormanscron and _notify_send() does not complete,
// the visitor will end up logged in as the "switched to user" for subsequent requests unless we disable saving the session
// until we are sure we're the invoking user again.
session_save_session(FALSE);
$user = user_load(array(
'uid' => $uid,
));
}
elseif (count($orig_user)) {
$user = array_shift($orig_user);
array_unshift($orig_user, $user);
session_save_session(TRUE);
}
else {
$orig_user[] = $user;
}
}
Functions
Name | Description |
---|---|
notify_admin_settings | Menu callback; display notify settings page. |
notify_admin_users | Menu callback; show admininster user notification settings form. |
notify_admin_users_submit | Submit for the notify_admin form. |
notify_cron | Implementation of hook_cron(). |
notify_help | Implementation of hook_help(). |
notify_mail | |
notify_menu | Implementation of hook_menu(). |
notify_perm | Implementation of hook_perm(). |
notify_theme | Register the themeing the form data into a table at admin/user/user/notify |
notify_user | Implementation of hook_user(). |
notify_user_access | Checks access to notifications settings tab |
notify_user_settings_form | Menu callback; show user notification options. |
notify_user_settings_form_submit | |
theme_notify_admin_users | Theme function to theme the admin user settings form in a table format. |
_notify_content | Formatting of outgoing mail, taken from mail.inc, part of project.module |
_notify_send | Helper function to send the notification email. |
_notify_switch_user | Switch from original user to mail submission user and back. |
_notify_user_reg_fields | Returns form fields to be added to User Regsitration form |
Constants
Name | Description |
---|---|
NOTIFY_NODE_TYPE | @file Notify module sends email digests of new content and comments. |