Index: mollom.admin.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/mollom/mollom.admin.inc,v retrieving revision 1.48 diff -u -p -r1.48 mollom.admin.inc --- mollom.admin.inc 7 Nov 2010 18:55:32 -0000 1.48 +++ mollom.admin.inc 10 Feb 2011 18:50:07 -0000 @@ -16,13 +16,14 @@ function mollom_admin_form_list() { mollom_form_cache(TRUE); $modes = array( - MOLLOM_MODE_ANALYSIS => t('Text analysis'), - MOLLOM_MODE_CAPTCHA => t('CAPTCHA'), + 'spam' => t('Spam'), + 'captcha' => t('CAPTCHA'), + 'profanity' => t('Profanity'), ); $header = array( t('Form'), - t('Protection mode'), + t('Checks'), array('data' => t('Operations'), 'colspan' => 2), ); $result = db_query('SELECT form_id FROM {mollom_form}')->fetchCol(); @@ -49,14 +50,15 @@ function mollom_admin_form_list() { foreach ($forms as $form_id => $mollom_form) { $row = array(); $row[] = $mollom_form['title']; - if ($mollom_form['mode'] == MOLLOM_MODE_ANALYSIS) { - $row[] = t('!protection-mode (@discard)', array( - '!protection-mode' => $modes[$mollom_form['mode']], + $checks = array_intersect_key($modes, array_flip($mollom_form['checks'])); + if (isset($checks['spam'])) { + $row[] = t('!checks (@discard)', array( + '!checks' => implode(', ', $checks), '@discard' => $mollom_form['discard'] ? t('discard') : t('retain'), )); } else { - $row[] = $modes[$mollom_form['mode']]; + $row[] = implode(', ', $checks); } $row[] = array('data' => array( '#type' => 'link', @@ -178,19 +180,28 @@ function mollom_admin_configure_form($fo ); $modes = array(); - // Textual analysis, if any elements are available. - if (!empty($mollom_form['elements'])) { - $modes[MOLLOM_MODE_ANALYSIS] = t('Text analysis'); - } - // CAPTCHA-only, always available. - $modes[MOLLOM_MODE_CAPTCHA] = t('CAPTCHA'); - - $form['mollom']['mode'] = array( - '#type' => 'radios', - '#title' => t('Protection mode'), - '#options' => $modes, - '#default_value' => isset($mollom_form['mode']) ? $mollom_form['mode'] : key($modes), + // Text analysis is only possible if there any elements to analyze. + $modes[MOLLOM_MODE_ANALYSIS] = !empty($mollom_form['elements']); + // CAPTCHA is always possible. + $modes[MOLLOM_MODE_CAPTCHA] = TRUE; + + // Textual analysis filters. + $form['mollom']['checks'] = array( + '#type' => 'checkboxes', + '#title' => t('Checks'), + '#default_value' => $mollom_form['checks'], + '#required' => TRUE, ); + if ($modes[MOLLOM_MODE_ANALYSIS]) { + $form['mollom']['checks']['#options']['spam'] = t('Spam'); + } + $form['mollom']['checks']['#options']['captcha'] = t('CAPTCHA'); + $form['mollom']['checks']['captcha']['#description'] = t('Mollom CAPTCHAs are intelligent. When also checking for Spam, a CAPTCHA will only appear if Mollom is unsure.', array( + '@help-url' => url('admin/help/mollom'), + )); + if ($modes[MOLLOM_MODE_ANALYSIS]) { + $form['mollom']['checks']['#options']['profanity'] = t('Profanity'); + } $all_permissions = array(); foreach (module_implements('permission') as $module) { @@ -214,87 +225,99 @@ function mollom_admin_configure_form($fo 'html' => TRUE, ); } - $form['mollom']['mode']['#description'] = t('The protection is omitted for users having any of the permissions: !permission-list', array( + $form['mollom']['checks']['#description'] = t('All checks are omitted for users having any of the permissions: !permission-list', array( '!permission-list' => theme('links', array( 'links' => $permissions, - // @todo D7: Something went entirely wrong: system.menus.css makes ANY - // ul.links appear as if it would have the .inline CSS class. - 'attributes' => array(), )), )); - if (!empty($mollom_form['elements'])) { - // If not re-configuring an existing protection, make it the default. - if (!isset($mollom_form['mode'])) { - $form['mollom']['mode']['#default_value'] = MOLLOM_MODE_ANALYSIS; - } - - // Textual analysis filters. - $form['mollom']['checks'] = array( - '#type' => 'checkboxes', - '#title' => t('Analyze text for'), - '#options' => array( - 'spam' => t('Spam'), - 'profanity' => t('Profanity'), - ), - '#default_value' => $mollom_form['checks'], - '#states' => array( - 'visible' => array( - ':input[name="mollom[mode]"]' => array('value' => (string) MOLLOM_MODE_ANALYSIS), - ), - ), - ); - - // Form elements defined by hook_mollom_form_info() use the - // 'parent][child' syntax, which Form API also uses internally for - // form_set_error(), and which allows us to recurse into nested fields - // during processing of submitted form values. However, since we are using - // those keys also as internal values to configure the fields to use for - // textual analysis, we need to encode them. Otherwise, a nested field key - // would result in the following checkbox attribute: - // '#name' => 'mollom[enabled_fields][parent][child]' - // This would lead to a form validation error, because it is a valid key. - // By encoding them, we prevent this from happening: - // '#name' => 'mollom[enabled_fields][parent%5D%5Bchild]' - $elements = array(); - foreach ($mollom_form['elements'] as $key => $value) { - $elements[rawurlencode($key)] = $value; - } - $enabled_fields = array(); - foreach ($mollom_form['enabled_fields'] as $value) { - $enabled_fields[] = rawurlencode($value); - } - $form['mollom']['enabled_fields'] = array( - '#type' => 'checkboxes', - '#title' => t('Text fields to analyze'), - '#options' => $elements, - '#default_value' => $enabled_fields, - '#states' => array( - 'visible' => array( - ':input[name="mollom[mode]"]' => array('value' => (string) MOLLOM_MODE_ANALYSIS), - ), + // Form elements defined by hook_mollom_form_info() use the + // 'parent][child' syntax, which Form API also uses internally for + // form_set_error(), and which allows us to recurse into nested fields + // during processing of submitted form values. However, since we are using + // those keys also as internal values to configure the fields to use for + // textual analysis, we need to encode them. Otherwise, a nested field key + // would result in the following checkbox attribute: + // '#name' => 'mollom[enabled_fields][parent][child]' + // This would lead to a form validation error, because it is a valid key. + // By encoding them, we prevent this from happening: + // '#name' => 'mollom[enabled_fields][parent%5D%5Bchild]' + $elements = array(); + foreach ($mollom_form['elements'] as $key => $value) { + $elements[rawurlencode($key)] = $value; + } + $enabled_fields = array(); + foreach ($mollom_form['enabled_fields'] as $value) { + $enabled_fields[] = rawurlencode($value); + } + $form['mollom']['enabled_fields'] = array( + '#type' => 'checkboxes', + '#title' => t('Text fields to analyze'), + '#options' => $elements, + '#default_value' => $enabled_fields, + '#access' => $modes[MOLLOM_MODE_ANALYSIS], + // @todo Requires OR support for #states http://drupal.org/node/735528, + // or native OR selector support http://drupal.org/node/1057748. + '#states' => array( + 'visible' => array( + ':input[name="mollom[checks][spam]"], :input[name="mollom[checks][profanity]"]' => array('checked' => TRUE), ), - ); + ), + ); - $form['mollom']['discard'] = array( - '#type' => 'radios', - '#title' => t('When text analysis identifies spam'), - '#default_value' => $mollom_form['discard'], - '#options' => array( - 1 => t('Automatically discard the post'), - 0 => t('Retain the post for manual moderation'), + $form['mollom']['discard'] = array( + '#type' => 'radios', + '#title' => t('When text analysis identifies spam'), + '#default_value' => $mollom_form['discard'], + '#options' => array( + 1 => t('Automatically discard the post'), + 0 => t('Retain the post for manual moderation'), + ), + '#required' => $mollom_form['mode'] == MOLLOM_MODE_ANALYSIS, + // Only possible for forms supporting moderation of unpublished posts. + '#access' => $modes[MOLLOM_MODE_ANALYSIS] && !empty($mollom_form['moderation callback']), + // Only possible for forms protected via text analysis. + '#states' => array( + 'visible' => array( + ':input[name="mollom[checks][spam]"], :input[name="mollom[checks][profanity]"]' => array('checked' => TRUE), ), - '#required' => $mollom_form['mode'] == MOLLOM_MODE_ANALYSIS, - // Only possible for forms supporting moderation of unpublished posts. - '#access' => !empty($mollom_form['moderation callback']), - // Only possible for forms protected via text analysis. - '#states' => array( - 'visible' => array( - ':input[name="mollom[mode]"]' => array('value' => (string) MOLLOM_MODE_ANALYSIS), - ), + ), + ); + $form['mollom']['rate_limit'] = array( + '#type' => 'select', + '#title' => t('Minimum interval between posts of same author'), + '#options' => drupal_map_assoc(array(0, 5, 10, 15, 20, 30, 40, 50, 60, 90, 120, 150, 180), 'format_interval'), + '#empty_value' => '', + '#empty_option' => t('- Default -'), + '#default_value' => isset($mollom_form['rate_limit']) ? $mollom_form['rate_limit'] : NULL, + /* + '#attached' => array( + 'library' => array(array('system', 'ui.slider')), + 'js' => array(array( + 'data' => 'jQuery(function( jQuery("#edit-mollom-rate-limit").slider(); ));', + 'type' => 'inline', + 'scope' => 'footer', + )), + ), + */ + ); + $form['mollom']['strictness'] = array( + '#type' => 'radios', + '#title' => t('Strictness'), + '#options' => array( + 'low' => t('Relaxed'), + 'medium' => t('Normal'), + 'high' => t('Strict'), + ), + '#default_value' => $mollom_form['strictness'], + '#access' => $modes[MOLLOM_MODE_ANALYSIS], + // Only possible for forms protected via text analysis. + '#states' => array( + 'visible' => array( + ':input[name="mollom[checks][spam]"], :input[name="mollom[checks][profanity]"]' => array('checked' => TRUE), ), - ); - } + ), + ); $form['actions']['submit'] = array( '#type' => 'submit', @@ -328,16 +351,13 @@ function mollom_admin_configure_form_val // 'checks' and 'enabled_fields', as their labels do not work with the default // #required form error message. if ($form_state['storage']['step'] == 'configure') { - // Make field checkboxes required, if protection mode is textual analysis. + // Make field checkboxes required, if protection involves text analysis. // @see http://drupal.org/node/875722 - $required = ($form_state['values']['mollom']['mode'] == MOLLOM_MODE_ANALYSIS); - $form['mollom']['checks']['#required'] = $required; + $checks = array_filter($form_state['values']['mollom']['checks']); + $required = (bool) array_diff_key($checks, array('captcha' => 0)); $form['mollom']['enabled_fields']['#required'] = $required; $form['mollom']['discard']['#required'] = $required; - if ($required && !array_filter($form_state['values']['mollom']['checks'])) { - form_error($form['mollom']['checks'], t('At least one text analysis check is required.')); - } if ($required && !array_filter($form_state['values']['mollom']['enabled_fields'])) { form_error($form['mollom']['enabled_fields'], t('At least one field is required for text analysis.')); } @@ -352,8 +372,15 @@ function mollom_admin_configure_form_sub // Merge in form information from $form_state. $mollom_form += $form_state['storage']['mollom_form']; + // Set protection mode to text analysis, in case more than CAPTCHA is enabled + // for 'checks'. + $checks = array_filter($form_state['values']['mollom']['checks']); + $mollom_form['mode'] = MOLLOM_MODE_CAPTCHA; + if (array_diff_key($checks, array('captcha' => 0))) { + $mollom_form['mode'] = MOLLOM_MODE_ANALYSIS; + } // Only store a list of enabled textual analysis checks. - $mollom_form['checks'] = array_keys(array_filter($mollom_form['checks'])); + $mollom_form['checks'] = array_keys($checks); // Prepare selected fields for storage. $enabled_fields = array(); foreach (array_keys(array_filter($mollom_form['enabled_fields'])) as $field) { @@ -361,6 +388,10 @@ function mollom_admin_configure_form_sub } $mollom_form['enabled_fields'] = $enabled_fields; + if ($mollom_form['rate_limit'] === '') { + $mollom_form['rate_limit'] = NULL; + } + $status = mollom_form_save($mollom_form); if ($status === SAVED_NEW) { drupal_set_message(t('The form protection has been added.')); Index: mollom.install =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/mollom/mollom.install,v retrieving revision 1.34 diff -u -p -r1.34 mollom.install --- mollom.install 16 Dec 2010 14:50:04 -0000 1.34 +++ mollom.install 10 Feb 2011 18:03:28 -0000 @@ -194,6 +194,18 @@ function mollom_schema() { 'not null' => FALSE, 'serialize' => TRUE, ), + 'rate_limit' => array( + 'description' => 'Rate limit for form submissions.', + 'type' => 'int', + 'not null' => FALSE, + ), + 'strictness' => array( + 'description' => 'Strictness of Mollom checks.', + 'type' => 'varchar', + 'length' => 8, + 'not null' => TRUE, + 'default' => 'medium', + ), 'module' => array( 'description' => 'Module name owning the form.', 'type' => 'varchar', @@ -791,3 +803,26 @@ function mollom_update_7009() { )); } } + +/** + * Add {mollom_form}.rate_limit and {mollom_form}.strictness columns. + */ +function mollom_update_7010() { + if (!db_field_exists('mollom_form', 'rate_limit')) { + db_add_field('mollom_form', 'rate_limit', array( + 'description' => 'Rate limit for form submissions.', + 'type' => 'int', + 'not null' => FALSE, + )); + } + if (!db_field_exists('mollom_form', 'strictness')) { + db_add_field('mollom_form', 'strictness', array( + 'description' => 'Strictness of Mollom checks.', + 'type' => 'varchar', + 'length' => 8, + 'not null' => TRUE, + 'default' => 'medium', + )); + } + // @todo Update 'checks' column; add 'captcha' to all 'spam' checks. +} Index: mollom.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/mollom/mollom.module,v retrieving revision 1.104 diff -u -p -r1.104 mollom.module --- mollom.module 5 Feb 2011 01:07:06 -0000 1.104 +++ mollom.module 10 Feb 2011 18:03:28 -0000 @@ -851,6 +851,8 @@ function mollom_form_new($form_id = NULL 'mode' => NULL, 'checks' => array(), 'enabled_fields' => array(), + 'rate_limit' => NULL, + 'strictness' => 'medium', ); // Enable all fields for textual analysis by default. if (!empty($mollom_form['elements'])) { @@ -1437,7 +1439,17 @@ function mollom_validate_analysis(&$form unset($data['post_id']); } $data['session_id'] = $form_state['mollom']['response']['session_id']; - $data['checks'] = implode(',', $form_state['mollom']['checks']); + + $checks = drupal_map_assoc($form_state['mollom']['checks']); + $data['unsure'] = isset($checks['captcha']) ? 'yes' : 'no'; + unset($checks['captcha']); + $data['checks'] = implode(',', $checks); + + if (isset($form_state['mollom']['rate_limit'])) { + $data['rate_limit'] = $form_state['mollom']['rate_limit']; + } + $data['strictness'] = $form_state['mollom']['strictness']; + $result = mollom('mollom.checkContent', $data); // Use all available data properties for log messages below. $data += $all_data; @@ -1585,6 +1597,9 @@ function mollom_validate_captcha(&$form, 'captcha_result' => $form_state['values']['mollom']['captcha'], 'author_ip' => $all_data['author_ip'], ); + if (isset($form_state['mollom']['rate_limit'])) { + $data['rate_limit'] = $form_state['mollom']['rate_limit']; + } if (isset($all_data['author_id'])) { $data['author_id'] = $all_data['author_id']; }