? d7 ? sites/default/settings.php ? sites/default/files/.htaccess ? sites/default/files/simpletest Index: modules/comment/comment.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/comment/comment.admin.inc,v retrieving revision 1.11 diff -u -p -r1.11 comment.admin.inc --- modules/comment/comment.admin.inc 11 Nov 2008 21:44:01 -0000 1.11 +++ modules/comment/comment.admin.inc 25 Nov 2008 18:18:55 -0000 @@ -34,7 +34,7 @@ function comment_admin($type = 'new') { * @see comment_admin_overview_submit() * @see theme_comment_admin_overview() */ -function comment_admin_overview($type = 'new', $arg) { +function comment_admin_overview($type = 'new', $arg = NULL) { // Build an 'Update options' form. $form['options'] = array( '#type' => 'fieldset', @@ -319,3 +319,47 @@ function _comment_delete_thread($comment _comment_delete_thread($comment); } } + +/** + * + */ +function comment_admin_subscribe() { + $form = array(); + $form['comment_subscribe_enabled'] = array( + '#type' => 'checkbox', + '#title' => t('Enable subscription to comments'), + '#default_value' => variable_get('comment_subscribe_enabled', 0), + '#description' => t('Enable subscription to comments.'), + ); + $form['comment_notify_mailtext'] = array( + '#type' => 'textarea', + '#title' => t('Default mail text for sending out notifications to commenters'), + '#description' => t( + 'You can use the following variables to be replaced: + ' + ), + '#default_value' => variable_get('comment_subscribe_mailtext', t(COMMENT_SUBSCRIBE_MAILTEXT)), + '#return_value' => 1, + '#cols' => 80, + '#rows' => 15 + ); + + return system_settings_form($form); +} \ No newline at end of file Index: modules/comment/comment.install =================================================================== RCS file: /cvs/drupal/drupal/modules/comment/comment.install,v retrieving revision 1.27 diff -u -p -r1.27 comment.install --- modules/comment/comment.install 15 Nov 2008 13:01:05 -0000 1.27 +++ modules/comment/comment.install 25 Nov 2008 18:19:48 -0000 @@ -2,6 +2,21 @@ // $Id: comment.install,v 1.27 2008/11/15 13:01:05 dries Exp $ /** + * Implementation of hook_install(). + */ +function comment_install() { + // Create tables. + drupal_install_schema('comment'); +} + +/** + * Implementation of hook_uninstall(). + */ +function comment_uninstall() { + drupal_uninstall_schema('comment'); +} + +/** * Implementation of hook_enable(). */ function comment_enable() { @@ -260,5 +275,40 @@ function comment_schema() { ), ); + $schema['comments_subscribe'] = array( + 'description' => 'Stores subscribe data.', + 'fields' => array( + 'cid' => array( + 'type' => 'serial', + 'not null' => TRUE, + 'description' => 'Unique comment ID.', + ), + 'nid' => array( + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'description' => 'The {node}.nid to which this comment is a reply.', + ), + 'uid' => array( + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'description' => 'The {users}.uid who authored the comment. If set to 0, this comment was created by an anonymous user.', + ), + 'hash' => array( + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + 'default' => '', + 'description' => 'The hash provided in notify email to create an unsubscribe link.', + ), + ), + 'indexes' => array( + 'nid' => array('nid'), + 'cid' => array('cid'), + 'uid' => array('uid'), + ), + ); + return $schema; -} +} \ No newline at end of file Index: modules/comment/comment.module =================================================================== RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v retrieving revision 1.666 diff -u -p -r1.666 comment.module --- modules/comment/comment.module 23 Nov 2008 16:04:41 -0000 1.666 +++ modules/comment/comment.module 25 Nov 2008 18:18:00 -0000 @@ -91,6 +91,36 @@ define('COMMENT_PREVIEW_OPTIONAL', 0); define('COMMENT_PREVIEW_REQUIRED', 1); /** + * A comment notify email default text. + */ +define('COMMENT_SUBSCRIBE_MAILTEXT', +'Hi !name, + +!commname has commented on: "!node_title" + +The post is about +---- +!node_teaser +---- + +You can view the comment at the following url +!comment_url + +You can stop receiving emails when someone replies to this post, +by going to !link1 + +If you have auto-following enabled in your account, you will receive emails like this for all replies to a blog post you commented on. You can disable this by logging in and going to your account settings or unchecking the flag at the time you post the comment. + +You can set up auto-following feature for all future posts +by creating your own user with a few clicks here !uri/user/register + +Thanks for your feedback, + +Webmaster of !site +!mission +!uri'); + +/** * Implementation of hook_help(). */ function comment_help($path, $arg) { @@ -182,6 +212,13 @@ function comment_menu() { 'access arguments' => array('administer comments'), 'type' => MENU_LOCAL_TASK, ); + $items['admin/content/comment/subscribe'] = array( + 'title' => 'Subscribe', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('comment_admin_subscribe'), + 'access arguments' => array('administer comments'), + 'type' => MENU_LOCAL_TASK, + ); $items['comment/delete'] = array( 'title' => 'Delete comment', 'page callback' => 'comment_delete', @@ -209,6 +246,22 @@ function comment_menu() { 'access arguments' => array('administer comments'), 'type' => MENU_CALLBACK, ); + $items['comment/subscribe/%node'] = array( + 'title' => 'Subscribe to comments', + 'page callback' => 'comment_subscribe_immediate', + 'page arguments' => array(1, 2), + 'access callback' => 'comment_subscribe_immediate_access', + 'access arguments' => array(2, TRUE), + 'type' => MENU_CALLBACK, + ); + $items['comment/unsubscribe/%node'] = array( + 'title' => 'Unsubscribe to comments', + 'page callback' => 'comment_subscribe_immediate', + 'page arguments' => array(1, 2), + 'access callback' => 'comment_subscribe_immediate_access', + 'access arguments' => array(2, FALSE), + 'type' => MENU_CALLBACK, + ); return $items; } @@ -257,6 +310,10 @@ function comment_perm() { 'title' => t('Post comments without approval'), 'description' => t('Add comments to content (no approval required).'), ), + 'subscribe to comments' => array( + 'title' => t('Subscribe to comments'), + 'description' => t('Subscribe to comments.'), + ), ); } @@ -476,6 +533,25 @@ function comment_link($type, $node = NUL } } } + + if (comment_subscribe_enabled() && user_is_logged_in() && user_access('subscribe to comments')) { + if (comment_subscribe_is_subscriber(array('nid' => $node->nid))) { + $links['subscribe'] = array( + 'title' => t('Unsubscribe to comments'), + 'href' => 'comment/unsubscribe/' . $node->nid, + 'query' => drupal_get_destination(), + 'attributes' => array('title' => t('Unsubscribe to comments.')), + ); + } + else { + $links['subscribe'] = array( + 'title' => t('Subscribe to comments'), + 'href' => 'comment/subscribe/' . $node->nid, + 'query' => drupal_get_destination(), + 'attributes' => array('title' => t('Subscribe to comments.')), + ); + } + } } if ($type == 'comment') { @@ -619,6 +695,9 @@ function comment_nodeapi_delete(&$node, db_delete('node_comment_statistics') ->condition('nid', $node->nid) ->execute(); + db_delete('comments_subscribe') + ->condition('nid', $node->nid) + ->execute(); } /** @@ -814,6 +893,7 @@ function comment_save($edit) { watchdog('content', 'Comment: added %subject.', array('%subject' => $edit['subject']), WATCHDOG_NOTICE, l(t('view'), 'node/' . $edit['nid'], array('fragment' => 'comment-' . $edit['cid']))); } _comment_update_node_statistics($edit['nid']); + // Clear the cache so an anonymous user can see his comment being added. cache_clear_all(); @@ -827,6 +907,12 @@ function comment_save($edit) { else { drupal_set_message(t('Your comment has been posted.')); comment_invoke_comment($edit, 'publish'); + + // Handle subscribe. + if (comment_subscribe_enabled()) { + comment_subscribe_manage($edit); + comment_subscribe_mail($edit); + } } return $edit['cid']; @@ -844,6 +930,211 @@ function comment_save($edit) { } /** + * Actually add subscribe data into the table. + */ +function comment_subscribe_subscribe($comment) { + db_insert('comments_subscribe') + ->fields(array( + 'hash' => comment_subscribe_hash($comment['nid'], comment_user_mail($comment)), + 'nid' => (int)$comment['nid'], + 'uid' => (int)$comment['uid'], + 'cid' => array_key_exists('cid', $comment)?(int)$comment['cid']:0, + )) + ->execute(); + drupal_set_message(t('Comment: You are subscribed to comments.')); +} + +/** + * Actually remove subscribe data from the table. + */ +function comment_subscribe_unsubscribe($comment, $hash = NULL) { + $query = db_delete('comments_subscribe')->condition('nid', $comment['nid']); + if ($hash) { + $query->condition('hash', $hash); + } + else { + $query->condition('uid', $comment['uid']); + } + $query->execute(); + drupal_set_message(t('Comment: You are unsubscribed to comments.')); +} + +/** + * Check if an user is subscriber of comments of the node. + */ +function comment_subscribe_is_subscriber($comment) { + global $user; + if ($user->uid) { + return (bool)db_query("SELECT 1 FROM {comments_subscribe} WHERE nid = :nid AND uid = :uid", array(':nid' => $comment['nid'], ':uid' => $user->uid))->fetchField(); + } + + if ((isset($comment['mail']) && $comment['mail'] && $mail = $comment['mail']) || + (isset($_COOKIE['comment_info_mail']) && $mail = $_COOKIE['comment_info_mail'])) { + return (bool)db_query("SELECT 1 FROM {comments_subscribe} cs LEFT JOIN {comments} c ON c.cid = cs.cid WHERE cs.nid = :nid AND c.mail = :mail", array(':nid' => $comment['nid'], ':mail' => $mail))->fetchField(); + } + + return FALSE; +} + +/** + * Make a subscribe logic depended on 'subscribe' checkbox. + */ +function comment_subscribe_manage($comment, $hash = NULL) { + if (!$hash) { + $is_subscriber = comment_subscribe_is_subscriber($comment); + if (array_key_exists('subscribe', $comment) && $comment['subscribe']) { + return $is_subscriber || comment_subscribe_subscribe($comment); + } + else { + return $is_subscriber && comment_subscribe_unsubscribe($comment); + } + } + return comment_subscribe_unsubscribe($comment, $hash); +} + +/** + * A callback for immediate subscribe/unsubscribe to comments. + */ +function comment_subscribe_immediate($op, $node, $hash = NULL) { + global $user; + $comment = array(); + $comment['nid'] = $node->nid; + $comment['uid'] = $user->uid; + $comment['subscribe'] = ($op == 'subscribe'); + comment_subscribe_manage($comment, $hash); + drupal_goto(); +} + +/** + * Send notificatins. + * It's taken from comment_notify module. + */ +function comment_subscribe_mail($comment) { + $comment = (object) $comment; + global $language; + global $base_url; + global $user; + + $initial_language = $language; + + if (function_exists('locale')) { + $languages = locale_language_list(); + $languages = $languages['name']; + } + + $nid = $comment->nid; + $cid = $comment->cid; + $node = node_load($nid); + if (!isset($comment->mail)) { + $comment_account = user_load(array('name' => $comment->name)); + $comment_mail = $comment_account->mail; + } + else { + $comment_mail = $comment->mail; + } + $sent_to = array(); + + //Get the list of commenters to notify. + $result = db_query("SELECT cs.uid, c.name, c.mail AS cmail, u.mail AS umail, u.init AS uinit, cs.hash as hash + FROM {comments_subscribe} cs LEFT JOIN users u ON cs.uid = u.uid + LEFT JOIN {comments} c ON c.cid = cs.cid + WHERE cs.nid = %d", $nid + ); + + while ($alert = db_fetch_object($result)) { + $umail = empty($alert->umail) ? $alert->uinit : $alert->umail; + $mail = empty($alert->cmail) ? $umail : $alert->cmail; + + if ($mail != $comment_mail && !in_array($mail, $sent_to) && $alert->uid != $comment->uid) { + $message = array(); + if (!empty($alert->uid)) { + $recipient_user = user_load(array('uid' => $alert->uid)); + $language = user_preferred_language($recipient_user); + } + else { + $language = language_default(); + } + + $message['subject'] = t('!site :: new comment for your post.', array('!site' => variable_get('site_name', 'drupal'))); + $message['body'] = t( + variable_get('comment_subscribe_mailtext', DEFAULT_MAILTEXT), + array( + '!commname' => $comment->name, + '!commtext' => $comment->comment, + '!commsubj' => $comment->subject, + '!comment_url' => url('node/'. $nid, array('absolute' => TRUE, 'fragment' => 'comment-'. $cid)), + '!node_title' => $node->title, + '!node_teaser' => $node->teaser, + '!mission' => variable_get('site_mission', ''), + '!node_body' => $node->body, + '!name' => $alert->name, + '!site' => variable_get('site_name', 'drupal'), + '!uri' => $base_url, + '!uri_brief' => preg_replace('!^https?://!', '', $base_url), + '!date' => format_date(time()), + '!login_uri' => url('user', array('absolute' => TRUE)), + '!edit_uri' => url('user/'. $alert->uid .'/edit', array('absolute' => TRUE)), + '!link1' => url('comment/unsubscribe/' . $nid . '/'. $alert->hash , array('absolute' => TRUE)) + ) + ); + drupal_mail('comment', 'comment_mail', $mail, $language, $message); + $sent_to[] = $mail; + + // Revert to previous (site default) locale. + $language = $initial_language; + } + } +} + +/** + * Implementation of hook_mail(). + */ +function comment_mail($key, &$message, $params) { + $message['subject'] = $params['subject']; + $message['body'][] = $params['body']; +} + +/** + * Access callback for immediate subscribe/unsubscribe to comments. + */ +function comment_subscribe_immediate_access($node, $subscribe = TRUE) { + $access = comment_subscribe_enabled() && user_access('subscribe to comments') && node_access('view', $node); + return $access && ($subscribe?user_is_logged_in():TRUE); +} + +/** + * Access callback for subscribe/unsubscribe to comments. + */ +function comment_subscribe_access($node) { + return (variable_get('comment_subscribtion_enable', 0) && user_access('subscribe to comments') && node_access('view', $node)); +} + +/** + * Returns a hash provided in notify emails to unsubscribe (used for anonymous unsubscribe). + */ +function comment_subscribe_hash($nid, $mail) { + return drupal_get_token($nid . $mail); +} + +/** + * + */ +function comment_subscribe_enabled() { + return (bool)variable_get('comment_subscribe_enabled', 0); +} + +/** + * Returns an email of the comment's user. + */ +function comment_user_mail($comment) { + if ($comment['uid']) { + $account = user_load($comment['uid']); + return empty($account->mail) ? $account->init : $account->mail; + } + return $comment['mail']; +} + +/** * Build command links for a comment (e.g.\ edit, reply, delete) with respect to the current user's access permissions. * * @param $comment @@ -1243,6 +1534,10 @@ function comment_validate($edit) { elseif (variable_get('comment_anonymous_' . $node->type, COMMENT_ANONYMOUS_MAYNOT_CONTACT) == COMMENT_ANONYMOUS_MUST_CONTACT) { form_set_error('mail', t('You have to leave an e-mail address.')); } + + if (isset($edit['subscribe']) && $edit['subscribe'] && !$edit['mail']) { + form_set_error('mail', t('You have to leave an e-mail address if you want to subscribe to comments.')); + } if ($edit['homepage']) { if (!valid_url($edit['homepage'], TRUE)) { @@ -1453,7 +1748,20 @@ function comment_form(&$form_state, $edi '#input_format' => isset($edit['format']) ? $edit['format'] : FILTER_FORMAT_DEFAULT, '#required' => TRUE, ); - + + if (comment_subscribe_access($node)) { + $form['subscribe_fieldset'] = array( + '#type' => 'fieldset', + '#title' => t('Subscribe to comments'), + ); + $form['subscribe_fieldset']['subscribe'] = array( + '#type' => 'checkbox', + '#title' => t('Recieve notifications for all comments on this post'), + '#default_value' => comment_subscribe_is_subscriber(array('nid' => $node->nid)), + '#description' => t('Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.'), + ); + } + $form['cid'] = array( '#type' => 'value', '#value' => !empty($edit['cid']) ? $edit['cid'] : NULL,