t('Enabled'), '0' => t('Disabled')); $akismet_wpapikey = variable_get('akismet_wpapikey', ''); if (empty($akismet_wpapikey)) { $service_fieldset_collapsed = FALSE; } else { $service_fieldset_collapsed = $is_valid = (akismet_api_cmd_verify_key($akismet_wpapikey) == AKISMET_API_RESULT_SUCCESS ? TRUE : FALSE); } if ($service_fieldset_collapsed) { $service_fieldset_collapsed = variable_get('akismet_connection_enabled', 1); } $form['service'] = array( '#type' => 'fieldset', '#title' => t('Akismet Service Options'), '#collapsible' => TRUE, '#collapsed' => $service_fieldset_collapsed ); $form['service']['akismet_wpapikey'] = array( '#type' => 'textfield', '#title' => t('WordPress.com API key'), '#size' => 30, '#maxlength' => 60, '#default_value' => $akismet_wpapikey, '#description' => t('Please, enter here your WordPress.com API key. If you don\'t have one already, you can get it by simply signing up for a free account at WordPress.com. Note that this information is required in order to use the Akismet Service. Please, consult the Akismet FAQ for further information.', array( '%wpapikey' => 'http://wordpress.com/api-keys/', '%wordpress-com' => 'http://wordpress.com', '@akismet' => 'http://akismet.com', '@akismet-faq' => 'http://akismet.com/faq/' )) ); if (!empty($akismet_wpapikey) && !$is_valid) { $form['service']['akismet_wpapikey']['#description'] .= '
'. t('WARNING: Your API Key doesn\'t seem to be valid!') .'
'; } $form['service']['akismet_connection_enabled'] = array( '#type' => 'radios', '#title' => t('Akismet connections'), '#options' => $enable_options, '#default_value' => variable_get('akismet_connection_enabled', 1), '#description' => t('This option must be enabled in order to perform real requests to the Akismet Service. You may want to disable this option for testing purposes, however. In this case, the akismet module will operate as normal, except sending real requests to the Akismet Service. ie. no automatic spam detection will be performed and no remote requests will be made when content is manually marked/unmarked as spam.
Note: regardless of this option, the akismet module will still connect, from this panel, to validate your WordPress.com API key, if specified.', array( '@akismet' => 'http://akismet.com', '%wpapikey' => 'http://wordpress.com/api-keys/' )) ); $timeout_options = array(); for ($n = 1; $n <= 30; $n++) { $timeout_options[$n] = $n; } $form['service']['akismet_connection_timeout'] = array( '#type' => 'select', '#title' => t('Connection timeout'), '#default_value' => variable_get('akismet_connection_timeout', 10), '#options' => $timeout_options, '#description' => t('This option allows you to specify the connection timeout in seconds that is used for real time Akismet connections.') ); $form['general'] = array( '#type' => 'fieldset', '#title' => t('General Options'), '#collapsible' => TRUE, '#collapsed' => TRUE ); $age_options = drupal_map_assoc(array(0, 3600, 10800, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 1814400), 'format_interval'); $age_options[0] = t('never'); $age_options[2592000] = t('1 month'); $age_options[5184000] = t('2 months'); $age_options[7776000] = t('3 months'); $age_options[10368000] = t('4 months'); $age_options[15768000] = t('6 months'); $age_options[31536000] = t('1 year'); $form['general']['akismet_remove_spam_age'] = array( '#type' => 'select', '#title' => t('Remove spam older than'), '#default_value' => variable_get('akismet_remove_spam_age', 259200), '#options' => $age_options, '#description' => t('Content marked as spam is still saved into database so it can be reviewed by content administrators. This option allows you to specify how long this information will be kept in the database. Spam older than the age specified here will be automatically removed. Requires crontab.') ); $form['general']['akismet_records_per_page'] = array( '#type' => 'select', '#title' => t('Records per page'), '#default_value' => variable_get('akismet_records_per_page', 50), '#options' => drupal_map_assoc(array(10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 200)), '#description' => t('The maximum number of records per page on moderation queue.') ); $form['general']['akismet_blocks_counter'] = array( '#type' => 'select', '#title' => t('Number of blocks'), '#default_value' => variable_get('akismet_blocks_counter', 1), '#options' => array(0=>t('none'), 1=>1, 2=>2, 3=>3, 4=>4, 5=>5), '#description' => t('The akismet module may generate a number of blocks for you to display the current spam counter anywhere on your site. The number of blocks is variable to help you keep your blocks administration panel as clean as possible. This option allows you to specify how many blocks you wish to use. If you do not plan to show the spam counter to your visitors, set this option to none.', array( '@admin-block' => url('admin/block') )) ); $form['general']['akismet_email_enabled'] = array( '#type' => 'radios', '#title' => t('E-mail notifications'), '#options' => $enable_options, '#default_value' => variable_get('akismet_email_enabled', 1), '#description' => t('Use this option to enable or disable e-mail notifications to content moderators. If enabled, users with proper permissions are allowed to set, from their user profiles, whether they wish to receive e-mail notications for all new (or updated) posts, just for content needing approval or no notifications at all. Users are notified about content types they are allowed to moderate only.') ); $form['node_options'] = array( '#type' => 'fieldset', '#title' => t('Node Options'), '#collapsible' => TRUE, '#collapsed' => TRUE ); $form['node_options']['akismet_check_nodetypes'] = array( '#type' => 'checkboxes', '#title' => t('Check for spam in these node types'), '#options' => node_get_types('names'), '#default_value' => variable_get('akismet_check_nodetypes', NULL), '#description' => t('Use this option to enable or disable spam check for nodes of types specified here. When this option is enabled, a request will be sent to the Akismet Service, in real time. If the Akismet Service was down, nodes would simply be queued for manual moderation. Users with @admin-nodes permission and spam moderators are exempt from this check.', array( '@akismet' => 'http://akismet.com', '@admin-nodes' => t('administer nodes'), '@admin-access' => url('admin/access') )) ); $form['node_options']['akismet_node_publish_links'] = array( '#type' => 'radios', '#title' => t('Show publish/unpublish links'), '#options' => $enable_options, '#default_value' => variable_get('akismet_node_publish_links', 0), '#description' => t('Use this option to enable or disable links for publish/unpublish operations in nodes. If enabled, these links will only be displayed to spam moderators and users with @admin-nodes permission.', array( '@admin-nodes' => t('administer nodes'), '@admin-access' => url('admin/access') )) ); $form['node_options']['akismet_node_spam_links'] = array( '#type' => 'radios', '#title' => t('Show submit spam/ham links'), '#options' => $enable_options, '#default_value' => variable_get('akismet_node_spam_links', 0), '#description' => t('Use this option to enable or disable links for submit spam/ham operations in nodes. If enabled, these links will only be displayed to spam moderators and users with @admin-nodes permission.', array( '@admin-nodes' => t('administer nodes'), '@admin-access' => url('admin/access') )) .'
'. t('Note: To interact fully with the Akismet Service you really should try putting data back into the system as well as just taking it out. If it is at all possible, please use these links to submit missed spam and false positives (ham), otherwise Akismet will never learn from its mistakes. Thank you.', array( '@akismet' => 'http://akismet.com' )) ); if (module_exists('comment')) { $form['comment_options'] = array( '#type' => 'fieldset', '#title' => t('Comment Options'), '#collapsible' => TRUE, '#collapsed' => TRUE ); $form['comment_options']['akismet_check_comments'] = array( '#type' => 'radios', '#title' => t('Check for spam in comments'), '#options' => $enable_options, '#default_value' => variable_get('akismet_check_comments', 1), '#description' => t('Use this option to enable or disable spam check for comments. When this option is enabled, a request will be sent to the Akismet Service, in real time. If the Akismet Service was down, comments would simply be queued for manual moderation. Users with @admin-comments permission and spam moderators are exempt from this check.', array( '@akismet' => 'http://akismet.com', '@admin-comments' => t('administer comments'), '@admin-access' => url('admin/access') )) ); $form['comment_options']['akismet_comment_publish_links'] = array( '#type' => 'radios', '#title' => t('Show publish/unpublish links'), '#options' => $enable_options, '#default_value' => variable_get('akismet_comment_publish_links', 1), '#description' => t('Use this option to enable or disable links for publish/unpublish operations in comments. If enabled, these links will only be displayed to spam moderators and users with @admin-comments permission.', array( '@admin-comments' => t('administer comments'), '@admin-access' => url('admin/access') )) ); $form['comment_options']['akismet_comment_spam_links'] = array( '#type' => 'radios', '#title' => t('Show submit spam/ham links'), '#options' => $enable_options, '#default_value' => variable_get('akismet_comment_spam_links', 1), '#description' => t('Use this option to enable or disable links for submit spam/ham operations in comments. If enabled, these links will only be displayed to spam moderators and users with @admin-comments permission.', array( '@admin-comments' => t('administer comments'), '@admin-access' => url('admin/access') )) .'
'. t('Note: To interact fully with the Akismet Service you really should try putting data back into the system as well as just taking it out. If it is at all possible, please use these links to submit missed spam and false positives (ham), otherwise Akismet will never learn from its mistakes. Thank you.', array( '@akismet' => 'http://akismet.com' )) ); } $date_formats = array( 'F j, Y', 'j F, Y', 'Y, F j', 'M j, Y', 'j M, Y', 'Y, M j', 'Y/m/d', 'm/d/Y', 'd/m/Y', 'Y-m-d', 'm-d-Y', 'd-m-Y' ); $date_options = array(); $now = time(); foreach ($date_formats as $format) { $date_options[$format] = format_date($now, 'custom', $format); } $form['counter_options'] = array( '#type' => 'fieldset', '#title' => t('Spam Counter Options'), '#collapsible' => TRUE, '#collapsed' => TRUE ); $form['counter_options']['akismet_counter_spam'] = array( '#type' => 'textfield', '#title' => t('Spam counter'), '#default_value' => akismet_get_spam_counter(), '#size' => 10, '#maxlength' => 10, '#description' => t('This counter is incremented for every spam caught by Akismet.') ); $form['counter_options']['akismet_counter_since'] = array( '#type' => 'date', '#title' => t('Counting since'), '#default_value' => variable_get('akismet_counter_since', array('day' => date('j'), 'month' => date('n'), 'year' => date('Y'))), '#description' => t('This is the date that will tell your visitors when your Akismet spam counter started to increment.') ); $form['counter_options']['akismet_counter_date_format'] = array( '#type' => 'select', '#title' => t('Date format'), '#default_value' => variable_get('akismet_counter_date_format', $date_formats[0]), '#options' => $date_options, '#description' => t('Date format used to render the Counting since date.') ); $form['anti_spambot'] = array( '#type' => 'fieldset', '#title' => t('Anti-Spambot Options'), '#collapsible' => TRUE, '#collapsed' => TRUE, '#description' => t('The goal of this section is not to replace anything that the Akismet Service itself can do a lot better than us, but to provide a set of simple rules aimed to prevent Denial of Service (DoS) situations that could be caused by certain spambots.', array( '@akismet' => 'http://akismet.com' )) ); $delay_options = drupal_map_assoc(array(0, 30, 60, 90, 120, 150, 180), 'format_interval'); $delay_options[0] = t('none'); $form['anti_spambot']['akismet_antispambot_delay'] = array( '#type' => 'select', '#title' => t('Delay when spam is detected'), '#default_value' => variable_get('akismet_antispambot_delay', 60), '#options' => $delay_options, '#description' => t('Use this option to delay the response when content has been identified as spam or to requests that match the rules defined below.') ); $anti_spambot_rules = array( 'ip' => t('IP addresses used by known spammers.'), 'mail' => t('E-mail addresses used by known spammers.'), 'body' => t('Content that has already been identified as spam.'), ); $form['anti_spambot']['akismet_antispambot_rules'] = array( '#type' => 'checkboxes', '#title' => t('Identify spambots by'), '#options' => $anti_spambot_rules, '#default_value' => variable_get('akismet_antispambot_rules', NULL), '#description' => t('These rules will be applied before sending any request to the Akismet Service. If a request to send content matches any of these rules, the actions defined below will be triggered. Requests to send content are checked against spam that is stored locally (visible from the moderation queue).', array( '@akismet' => 'http://akismet.com', '@moderation-queue' => url('admin/content/akismet') )) ); $anti_spambot_actions = array( 'none' => t('None (only the delay specified above, if any).'), '503' => t('HTTP error 503 (Service Unavailable), showing a simple blank page.'), '403' => t('HTTP error 403 (Forbidden), showing a simple blank page.'), '403d' => t('HTTP error 403 (Forbidden), showing a Drupal generated page.') ); $form['anti_spambot']['akismet_antispambot_action'] = array( '#type' => 'radios', '#title' => t('Actions against spambots'), '#options' => $anti_spambot_actions, '#default_value' => variable_get('akismet_antispambot_action', '503'), '#description' => t('Use this option to specify what to do against spambots identified by any of the above rules. When a HTTP error is generated (403 or 503), no request to the Akismet Service will be made, the request to post content will not be stored into database and no further moderator notifications will be sent. In any case, when a rule matches, a record of the event will be logged for further analysis.', array( '@akismet' => 'http://akismet.com', '@admin-logs' => url('admin/logs') )) ); return system_settings_form($form); } /** * Moderation queue operations. */ function akismet_moderator_operations($mode, $submode) { // Build operations array; based on current mode. if ($mode == 'nodes') { $operations = array( 'submit-spam' => array( 'title' => (variable_get('akismet_connection_enabled', 1) ? t('Submit selected nodes as spam') : t('Mark selected nodes as spam')), 'confirm' => (variable_get('akismet_connection_enabled', 1) ? t('Are you sure you want to submit these nodes as spam?') : t('Are you sure you want to mark these nodes as spam?')), 'button' => (variable_get('akismet_connection_enabled', 1) ? t('Submit nodes as spam') : t('Mark nodes as spam')), ), 'submit-ham' => array( 'title' => (variable_get('akismet_connection_enabled', 1) ? t('Submit selected nodes as ham') : t('Mark selected nodes as ham')), 'confirm' => (variable_get('akismet_connection_enabled', 1) ? t('Are you sure you want to submit these nodes as ham?') : t('Are you sure you want to mark these nodes as ham?')), 'button' => (variable_get('akismet_connection_enabled', 1) ? t('Submit nodes as ham') : t('Mark nodes as ham')), ), 'publish' => array( 'title' => t('Publish selected nodes'), 'confirm' => t('Are you sure you want to publish these nodes?'), 'button' => t('Publish nodes'), ), 'unpublish' => array( 'title' => t('Unpublish selected nodes'), 'confirm' => t('Are you sure you want to unpublish these nodes?'), 'button' => t('Unpublish nodes'), ), 'delete' => array( 'title' => t('Delete selected nodes'), 'confirm' => t('Are you sure you want to delete these nodes and all their comments?'), 'button' => t('Delete nodes'), 'warning' => t('This action cannot be undone.') ) ); } else if ($mode == 'comments') { $operations = array( 'submit-spam' => array( 'title' => (variable_get('akismet_connection_enabled', 1) ? t('Submit selected comments as spam') : t('Mark selected comments as spam')), 'confirm' => (variable_get('akismet_connection_enabled', 1) ? t('Are you sure you want to submit these comments as spam?') : t('Are you sure you want to mark these comments as spam?')), 'button' => (variable_get('akismet_connection_enabled', 1) ? t('Submit comments as spam') : t('Mark comments as spam')), ), 'submit-ham' => array( 'title' => (variable_get('akismet_connection_enabled', 1) ? t('Submit selected comments as ham') : t('Mark selected comments as ham')), 'confirm' => (variable_get('akismet_connection_enabled', 1) ? t('Are you sure you want to submit these comments as ham?') : t('Are you sure you want to mark these comments as ham?')), 'button' => (variable_get('akismet_connection_enabled', 1) ? t('Submit comments as ham') : t('Mark comments as ham')), ), 'publish' => array( 'title' => t('Publish selected comments'), 'confirm' => t('Are you sure you want to publish these comments?'), 'button' => t('Publish comments'), ), 'unpublish' => array( 'title' => t('Unpublish selected comments'), 'confirm' => t('Are you sure you want to unpublish these comments?'), 'button' => t('Unpublish comments'), ), 'delete' => array( 'title' => t('Delete selected comments'), 'confirm' => t('Are you sure you want to delete these comments and all their replies?'), 'button' => t('Delete comments'), 'warning' => t('This action cannot be undone.') ) ); } else { // Unknown mode! return array(); } // Unset redundant operations; based on current submode. if ($submode == 'spam') { unset($operations['submit-spam']); } else if ($submode == 'unpublished') { unset($operations['unpublish']); } else if ($submode == 'published') { unset($operations['publish']); } else { // Unknown submode! return array(); } return $operations; } /** * Menu callback; Moderation queue. * * @param string Mode: overview (default), nodes, comments. * @param string Submode: spam (default), unpublished, published. */ function akismet_callback_queue($mode = '', $submode = '') { // Make sure we're dealing with a valid mode and submode. $valid_modes = array('nodes', 'comments'); $valid_submodes = array( 'spam' => t('Spam'), 'unpublished' => t('Unpublished'), 'published' => t('Published') ); if (empty($mode)) { $mode = 'overview'; } else if (!in_array($mode, $valid_modes)) { drupal_not_found(); return; } if (empty($submode)) { $submode = 'spam'; } else if (!isset($valid_submodes[$submode])) { drupal_not_found(); return; } // Compute exactly what the current user is allowed to moderate. $moderator_types = akismet_get_moderator_types(); $moderator_types_count = count($moderator_types); $allowed_comments = (isset($moderator_types['comments']) ? TRUE : FALSE); $allowed_nodes = $moderator_types; if ($allowed_comments) { unset($allowed_nodes['comments']); } $allowed_nodes_count = count($allowed_nodes); // Make sure the user has some kind of content administration/moderation permission. if ($allowed_nodes_count <= 0 && !$allowed_comments) { drupal_access_denied(); return; } // Dynamically build the queries using a write once method. if ($allowed_nodes_count > 0) { $sql_nodetypes = array(); foreach ($allowed_nodes as $type => $name) { $sql_nodetypes[] = '\''. $type .'\''; } $sql_nodetypes = implode(', ', $sql_nodetypes); $sql_from = 'FROM {node} n LEFT JOIN {akismet_spam_marks} s ON s.content_id = n.nid AND s.content_type = \'node\''; $sql_where = 'WHERE n.type IN ('. $sql_nodetypes .') AND (%cond)'; $sql_nodes_cond = array( 'spam' => 's.content_id IS NOT NULL', 'unpublished' => 'n.status = 0', 'published' => 'n.status = 1' ); $sql_nodes_stmt = 'SELECT n.*, u.name, IFNULL(s.content_id, 0) AS spam_mark '. $sql_from .' INNER JOIN {users} u ON n.uid = u.uid '. $sql_where; $sql_nodes_cnt = 'SELECT COUNT(*) AS cnt '. $sql_from .' '. $sql_where; } if ($allowed_comments) { $sql_from = 'FROM {comments} c LEFT JOIN {akismet_spam_marks} s ON s.content_id = c.cid AND s.content_type = \'comment\''; $sql_where = 'WHERE (%cond)'; $sql_comments_cond = array( 'spam' => 's.content_id IS NOT NULL', 'unpublished' => 'c.status = '. COMMENT_NOT_PUBLISHED, 'published' => 'c.status = '. COMMENT_PUBLISHED ); $sql_comments_stmt = 'SELECT c.*, u.name AS registered_name, IFNULL(s.content_id, 0) AS spam_mark '. $sql_from .' INNER JOIN {users} u ON c.uid = u.uid '. $sql_where; $sql_comments_cnt = 'SELECT COUNT(*) AS cnt '. $sql_from .' '. $sql_where; } $sql = array( 'sql_comments_cnt' => $sql_comments_cnt, 'sql_comments_stmt' => $sql_comments_stmt, 'sql_comments_cond' => $sql_comments_cond, 'sql_nodes_cnt' => $sql_nodes_cnt, 'sql_nodes_stmt' => $sql_nodes_stmt, 'sql_nodes_cond' => $sql_nodes_cond, ); // Present the overview page (default). if ($mode == 'overview') { $items = array(); if ($allowed_nodes_count > 0) { $subitems = array(); foreach ($valid_submodes as $key => $title) { $sql_cnt = str_replace('%cond', $sql_nodes_cond[$key], $sql_nodes_cnt); $count = db_result(db_query(db_rewrite_sql($sql_cnt))); $path = 'admin/content/akismet/nodes'. ($key == 'spam' ? '' : '/'. $key); $label = ($count > 0 ? l($title, $path) : $title); $subitems[] = '

'. $label .': '. $count .'

'; } $items[] = '

'. t('Nodes') .'

'. theme('item_list', $subitems); } if ($allowed_comments) { $subitems = array(); foreach ($valid_submodes as $key => $title) { $sql_cnt = str_replace('%cond', $sql_comments_cond[$key], $sql_comments_cnt); $count = db_result(db_query(db_rewrite_sql($sql_cnt))); $path = 'admin/content/akismet/comments'. ($key == 'spam' ? '' : '/'. $key); $label = ($count > 0 ? l($title, $path) : $title); $subitems[] = '

'. $label .': '. $count .'

'; } $items[] = '

'. t('Comments') .'

'. theme('item_list', $subitems); } return '

'. t('Summary of content:') .'

'. theme('item_list', $items); } if (isset($_POST) && count($_POST['items']) > 0) { return drupal_get_form('akismet_confirm_multiple_operation'); } else { return drupal_get_form('akismet_moderation_form', $mode, $submode, $sql); } } function akismet_moderation_form($mode = '', $submode = '', $sql = array()) { // Build the moderation queue form. $form = array(); $form['options'] = array( '#type' => 'fieldset', '#title' => t('Moderator actions'), '#prefix' => '
', '#suffix' => '
' ); extract($sql); $options = array('' => t('