Index: mollom.admin.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/mollom/mollom.admin.inc,v retrieving revision 1.41 diff -u -p -r1.41 mollom.admin.inc --- mollom.admin.inc 26 Sep 2010 19:42:55 -0000 1.41 +++ mollom.admin.inc 26 Sep 2010 20:08:37 -0000 @@ -13,9 +13,8 @@ function mollom_admin_form_list() { _mollom_testing_mode_warning(); $modes = array( - MOLLOM_MODE_DISABLED => t('None'), - MOLLOM_MODE_CAPTCHA => t('CAPTCHA'), MOLLOM_MODE_ANALYSIS => t('Text analysis'), + MOLLOM_MODE_CAPTCHA => t('CAPTCHA'), ); $header = array( @@ -29,7 +28,10 @@ function mollom_admin_form_list() { $mollom_form = mollom_form_load($form_id); $rows[] = array( $mollom_form['title'], - $modes[$mollom_form['mode']], + t('!protection-mode (@reject)', array( + '!protection-mode' => $modes[$mollom_form['mode']], + '@reject' => $mollom_form['reject'] ? t('reject') : t('unpublish'), + )), l(t('Configure'), 'admin/config/content/mollom/manage/' . $form_id), l(t('Unprotect'), 'admin/config/content/mollom/unprotect/' . $form_id), ); @@ -153,6 +155,27 @@ function mollom_admin_configure_form($fo ); if (!empty($mollom_form['elements'])) { + // By default, Mollom module rejects all posts that did not successfully + // pass mollom.checkContent. Instead of rejecting posts, site admins + // can optionally configure that posts shall be unpublished instead, so + // they can go through manual moderation. The negated form widget may + // look odd, but users can rather relate to more common terms like + // "unpublish" or "moderation". Furthermore, this setting should stay + // optional and disabled by default, as Mollom should reject bad posts. + $form['mollom']['reject'] = array( + '#type' => 'checkbox', + '#title' => t('Reject bad posts'), + '#default_value' => $mollom_form['reject'], + '#description' => t('Disable to manually moderate all posts.'), + // Only possible for forms supporting moderation of unpublished posts. + '#access' => !empty($mollom_form['reject callback']), + '#states' => array( + 'visible' => array( + ':input[name="mollom[mode]"]' => array('value' => (string) MOLLOM_MODE_ANALYSIS), + ), + ), + ); + // If not re-configuring an existing protection, make it the default. if (!isset($mollom_form['mode'])) { $form['mollom']['mode']['#default_value'] = MOLLOM_MODE_ANALYSIS; Index: mollom.api.php =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/mollom/mollom.api.php,v retrieving revision 1.6 diff -u -p -r1.6 mollom.api.php --- mollom.api.php 12 Sep 2010 22:05:55 -0000 1.6 +++ mollom.api.php 26 Sep 2010 20:08:37 -0000 @@ -150,6 +150,9 @@ * $form_info = array( * // Optional: User permission list to skip Mollom's protection for. * 'bypass access' => array('administer instant messages'), + * // Optional: Function to invoke to unpublish a bad form submission + * // instead of rejecting it. + * 'reject callback' => 'im_mollom_reject', * // Optional: To allow textual analysis of the form values, the form * // elements needs to be registered individually. The keys are the * // field keys in $form_state['values']. Sub-keys are noted using "][" @@ -205,6 +208,16 @@ * Additionally, the "post_id" data property always needs to be mapped to a form * element that holds the entity id. * + * When registering a 'reject callback', then the registered function needs to + * be available when the form is validated, and it is responsible for changing + * the submitted form values in a way that results in an unpublished post ending + * up in a moderation queue: + * @code + * function im_mollom_reject(&$form, &$form_state) { + * $form_state['values']['status'] = 0; + * } + * @endcode + * * @see mollom_node * @see mollom_comment * @see mollom_user @@ -276,6 +289,10 @@ function hook_mollom_form_list() { * current user to determine whether to protect the form with Mollom or do * not validate submitted form values. If the current user has at least one * of the listed permissions, the form will not be protected. + * - reject callback: (optional) A function name to invoke when a form + * submission would normally be rejected. This allows modules to put such + * posts into a moderation queue (i.e., accept but not publish them) by + * altering the $form or $form_state information being passed by reference. * - mail ids: (optional) An array of mail IDs that will be sent as a result * of this form being submitted. When these mails are sent, a 'report to * Mollom' link will be included at the bottom of the mail body. Be sure to Index: mollom.install =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/mollom/mollom.install,v retrieving revision 1.28 diff -u -p -r1.28 mollom.install --- mollom.install 25 Sep 2010 01:05:41 -0000 1.28 +++ mollom.install 26 Sep 2010 20:08:37 -0000 @@ -174,6 +174,13 @@ function mollom_schema() { 'not null' => FALSE, 'serialize' => TRUE, ), + 'reject' => array( + 'description' => 'Whether to reject (1) or unpublish (0) bad form submissions.', + 'type' => 'int', + 'size' => 'tiny', + 'not null' => TRUE, + 'default' => 1, + ), 'enabled_fields' => array( 'description' => 'Form elements to analyze.', 'type' => 'text', @@ -723,3 +730,17 @@ function mollom_update_7007() { } } } + +/** + * Add {mollom_form}.reject column to form configuration. + */ +function mollom_update_7007() { + if (!db_field_exists('mollom_form', 'reject')) { + db_add_field('mollom_form', 'reject', array( + 'type' => 'int', + 'size' => 'tiny', + 'not null' => TRUE, + 'default' => 1, + )); + } +} Index: mollom.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/mollom/mollom.module,v retrieving revision 1.85 diff -u -p -r1.85 mollom.module --- mollom.module 25 Sep 2010 01:05:41 -0000 1.85 +++ mollom.module 26 Sep 2010 20:34:02 -0000 @@ -399,6 +399,22 @@ function mollom_cron() { db_delete('mollom') ->condition('changed', $expired, '<') ->execute(); + + // Delete all bad posts older than two weeks, which have not been published. + $form_list = mollom_form_list(); + $query = db_select('mollom', 'm') + ->fields('m') + ->condition('changed', REQUEST_TIME - 86400 * 14, '<'); + $delete = array(); + foreach ($query->execute() as $data) { + if (isset($form_list[$data->form_id]['entity delete multiple callback'])) { + $function = $form_list[$data->form_id]['entity delete multiple callback']; + $delete[$function][] = $data->did; + } + } + foreach ($delete as $function => $ids) { + $function($ids); + } } /** @@ -627,6 +643,7 @@ function mollom_form_alter(&$form, &$for // Add Mollom form validation handlers. $form['#validate'][] = 'mollom_validate_analysis'; $form['#validate'][] = 'mollom_validate_captcha'; + $form['#validate'][] = 'mollom_validate_post'; // Add a submit handler to remove form state storage. $form['#submit'][] = 'mollom_form_submit'; @@ -755,6 +772,7 @@ function mollom_form_info($form_id, $mod 'module' => $module, 'entity' => NULL, 'mode' => NULL, + 'reject' => TRUE, 'bypass access' => array(), 'elements' => array(), 'mapping' => array(), @@ -1223,6 +1241,13 @@ function mollom_process_mollom($element, } $form_state['mollom'] += $element['#mollom_form']; + // By default, bad form submissions are rejected, unless the form was + // configured to unpublish bad posts. 'reject' may only be FALSE, if there is + // a valid 'reject callback'. Otherwise, it must be TRUE. + if (empty($form_state['mollom']['reject callback']) || !function_exists($form_state['mollom']['reject callback'])) { + $form_state['mollom']['reject'] = TRUE; + } + // Add the Mollom session element. $element['session_id'] = array( '#type' => 'hidden', @@ -1349,7 +1374,9 @@ function mollom_validate_analysis(&$form case MOLLOM_ANALYSIS_SPAM: $form_state['mollom']['require_captcha'] = FALSE; - form_set_error('mollom', t('Your submission has triggered the spam filter and will not be accepted.')); + if ($form_state['mollom']['reject']) { + form_set_error('mollom', t('Your submission has triggered the spam filter and will not be accepted.')); + } _mollom_watchdog(array( 'Spam: %teaser' => array('%teaser' => $teaser), 'Data:
@data
' => array('@data' => $data), @@ -1475,6 +1502,26 @@ function mollom_validate_captcha(&$form, } /** + * Form validation handler to perform post-validation tasks. + * + * Since our individual form validation handlers are not re-run after positive + * validation, any changes applied to form values will not persist across + * multiple form submission attempts and rebuilds. + */ +function mollom_validate_post(&$form, &$form_state) { + // Unpublish a post instead of rejecting it. If 'reject' is not TRUE, then + // the 'reject callback' is responsible for altering $form_state in a way that + // the post ends up unpublished in a moderation queue. Most callbacks will + // only want to set a value in $form_state. Technically, modules do not need + // to implement a 'reject callback' to achieve this, they may simply add a + // custom form validation handler (or use an existing one). + if (!$form_state['mollom']['reject']) { + $function = $form_state['mollom']['reject callback']; + $function($form, $form_state); + } +} + +/** * Form submit handler to flush Mollom session and form information from cache. */ function mollom_form_submit($form, &$form_state) { @@ -1979,6 +2026,7 @@ function node_mollom_form_list() { 'entity' => 'node', 'bundle' => $type->type, 'delete form' => 'node_delete_confirm', + 'entity delete multiple callback' => 'node_delete_multiple', ); } return $forms; @@ -2003,6 +2051,7 @@ function node_mollom_form_info($form_id) // @todo This is incompatible with node access. 'bypass access' => array('bypass node access', 'edit any ' . $type->type . ' content'), 'bundle' => $type->type, + 'reject callback' => 'node_mollom_reject', 'elements' => array(), 'mapping' => array( 'post_id' => 'nid', @@ -2027,6 +2076,13 @@ function node_mollom_form_info($form_id) } /** + * Mollom reject callback. + */ +function node_mollom_reject(&$form, &$form_state) { + $form_state['values']['status'] = 0; +} + +/** * Implements hook_form_FORMID_alter(). */ function mollom_form_node_multiple_delete_confirm_alter(&$form, &$form_state) { @@ -2069,6 +2125,7 @@ function comment_mollom_form_list() { 'entity' => 'comment', 'bundle' => 'comment_node_' . $type->type, 'delete form' => 'comment_confirm_delete', + 'entity delete multiple callback' => 'comment_delete_multiple', ); } return $forms; @@ -2081,6 +2138,7 @@ function comment_mollom_form_info($form_ $form_info = array( 'mode' => MOLLOM_MODE_ANALYSIS, 'bypass access' => array('administer comments'), + 'reject callback' => 'comment_mollom_reject', 'elements' => array( 'subject' => t('Subject'), // @todo Update for Field API. @@ -2106,6 +2164,26 @@ function mollom_comment_delete($comment) } /** + * Mollom reject callback. + */ +function comment_mollom_reject(&$form, &$form_state) { + $form_state['values']['status'] = COMMENT_NOT_PUBLISHED; +} + +/** + * Implements hook_comment_presave(). + */ +function mollom_comment_presave($comment) { + // If an existing comment is published and we have session data stored for it, + // send 'ham' feedback to Mollom. + if (!empty($comment->cid) && $comment->status == COMMENT_PUBLISHED) { + if ($data = mollom_data_load('comment', $comment->cid)) { + _mollom_send_feedback($data->session, 'ham'); + } + } +} + +/** * Implements hook_form_FORMID_alter(). */ function mollom_form_comment_multiple_delete_confirm_alter(&$form, &$form_state) { @@ -2144,11 +2222,10 @@ function user_mollom_form_list() { 'title' => t('User registration form'), 'entity' => 'user', 'delete form' => 'user_cancel_confirm_form', + 'entity delete multiple callback' => 'user_delete_multiple', ); $forms['user_pass'] = array( 'title' => t('User password request form'), - 'entity' => 'user', - 'delete form' => 'user_cancel_confirm_form', ); return $forms; } @@ -2162,6 +2239,7 @@ function user_mollom_form_info($form_id) $form_info = array( 'mode' => MOLLOM_MODE_CAPTCHA, 'bypass access' => array('administer users'), + 'reject callback' => 'user_mollom_reject', 'mapping' => array( 'post_id' => 'uid', 'author_name' => 'name', @@ -2208,6 +2286,13 @@ function mollom_form_user_multiple_cance } /** + * Mollom reject callback. + */ +function user_mollom_reject(&$form, &$form_state) { + $form_state['values']['status'] = 0; +} + +/** * @} End of "name mollom_user". */