diff --git a/mollom.module b/mollom.module index 784e5a2..5b9b784 100644 --- a/mollom.module +++ b/mollom.module @@ -625,7 +625,7 @@ function mollom_data_delete_form_submit($form, &$form_state) { $id = $data['postId']; if (!empty($form_state['values']['mollom']['feedback'])) { - if (mollom_data_report($entity, $id, $form_state['values']['mollom']['feedback'])) { + if (mollom_data_report($entity, $id, $form_state['values']['mollom']['feedback'], 'moderate', 'mollom_data_delete_form_submit')) { drupal_set_message(t('The content was successfully reported as inappropriate.')); } } @@ -641,9 +641,17 @@ function mollom_data_delete_form_submit($form, &$form_state) { * The entity type to send feedback for. * @param $id * The entity id to send feedback for. + * @param $feedback + * The feedback reason for reporting content. + * @param $type + * The type of feedback, one of 'moderate' or 'flag'. + * @param $source + * An optional single word string identifier for the user interface source. + * This is tracked along with the feedback to provide a more complete picture + * of how feedback is used and submitted on the site. */ -function mollom_data_report($entity, $id, $feedback) { - return mollom_data_report_multiple($entity, array($id), $feedback); +function mollom_data_report($entity, $id, $feedback, $type = 'moderate', $source = 'mollom_data_report') { + return mollom_data_report_multiple($entity, array($id), $feedback, $type, $source); } /** @@ -653,15 +661,23 @@ function mollom_data_report($entity, $id, $feedback) { * The entity type to send feedback for. * @param $ids * An array of entity ids to send feedback for. + * @param $feedback + * The feedback reason for reporting content. + * @param $type + * The type of feedback, one of 'moderate' or 'flag'. + * @param $source + * An optional single word string identifier for the user interface source. + * This is tracked along with the feedback to provide a more complete picture + * of how feedback is used and submitted on the site. */ -function mollom_data_report_multiple($entity, array $ids, $feedback) { +function mollom_data_report_multiple($entity, array $ids, $feedback, $type = 'moderate', $source = 'mollom_data_report_multiple') { $return = TRUE; foreach ($ids as $id) { // Load the Mollom session data. $data = mollom_data_load($entity, $id); // Send feedback, if we have session data. if (!empty($data->contentId) || !empty($data->captchaId)) { - $result = _mollom_send_feedback($data, $feedback, 'moderate', 'mollom_data_report_multiple'); + $result = _mollom_send_feedback($data, $feedback, $type, $source); $return = $return && $result; } } @@ -4245,6 +4261,179 @@ function profile_mollom_form_info_alter(&$form_info, $form_id) { * @} End of "name mollom_profile". */ +/** + * @name mollom_action Actions module integration for Mollom. + * @{ + */ + +/** + * Implements hook_action_info(). + */ +function mollom_action_info() { + return array( + // Unpublish comment action. + 'mollom_action_unpublish_comment' => array( + 'description' => t('Report comment to Mollom as spam and unpublish'), + 'type' => 'comment', + 'configurable' => FALSE, + 'triggers' => array( + 'comment_insert', + 'comment_update', + ), + 'aggregate' => TRUE, + ), + // Unpublish node action. + 'mollom_action_unpublish_node' => array( + 'description' => t('Report node to Mollom as spam and unpublish'), + 'type' => 'node', + 'configurable' => FALSE, + 'triggers' => array( + 'node_insert', + 'node_update', + ), + 'aggregate' => TRUE, + ), + ); +} + +/** + * Action callback to report a comment to mollom and unpublish. + */ +function mollom_action_unpublish_comment($comments, $context = array()) { + _mollom_action_unpublish('comment', $comments); +} + +/** + * Action callback to report a node to mollom and unpublish. + */ +function mollom_action_unpublish_node($nodes, $context = array()) { + _mollom_action_unpublish('node', $nodes); +} + +/** + * Unpublish content and report to Mollom as spam. + * + * @param $entity_type + * The type of entity; one of "comment" or "node". + * @param $entities + * An array of entities to perform the action upon. + */ +function _mollom_action_unpublish($entity_type, $entities) { + // Make sure this is a supported entity type. + if (!in_array($entity_type, array('node', 'comment'))) { + watchdog('Mollom', 'Called unpublish action for an unsupported entity type: @type', array('@type' => $entity_type), WATCHDOG_ERROR); + return; + } + + // Determine the entities for which moderation is allowed. + list($allowed, $nids, $cids) = _mollom_actions_access_callbacks($entity_type, $entities); + + // Send feedback to Mollom. + $ids = $entity_type === 'comment' ? $cids : $nids; + mollom_data_report_multiple($entity_type, $ids, 'spam', 'moderate', "mollom_action_unpublish_{$entity_type}"); + + if ($entity_type === 'comment') { + // Unpublish the comment. + db_query('UPDATE {comments} set status = %d WHERE cid IN (' . db_placeholders($cids) . ')', array_merge((array) COMMENT_NOT_PUBLISHED, $cids)); + + foreach ($nids as $nid) { + _comment_update_node_statistics($nid); + } + } + else if ($entity_type === 'node') { + // Unpublish the node. + db_query('UPDATE {node} set status = 0 WHERE nid IN (' . db_placeholders($nids) . ')', $nids); + } +} + +/** + * Gets all callbacks and checks permissions for entities. + * + * @param $entity_type + * The type of entity to check. + * @param $entities + * An array of entities to check. + * + * @return array + * An indexed array of allowed entities + * - 0 An array of allowed entities objects + * - 1 An array of node ids + * - 2 An array of comment ids (if entity_type is comment). + */ +function _mollom_actions_access_callbacks($entity_type, $entities) { + $cids = array(); + $nids = array(); + + // Retrieve any relevant callback for comments + $report_access_callbacks = array(); + $access_permissions = array(); + $entity_access_callbacks = array(); + + $allowed = array(); + foreach (mollom_form_list() as $form_id => $info) { + if (!isset($info['entity']) || $info['entity'] != $entity_type) { + continue; + } + // If there is a 'report access callback' add it to the list. + if (isset($info['report access callback']) + && function_exists($info['report access callback']) + && !in_array($info['report access callback'], $report_access_callbacks)) { + $report_access_callbacks[] = $info['report access callback']; + } + // Otherwise add any access permissions. + else if (isset($info['report access']) && !in_array($info['report access'], $access_permissions)) { + $access_permissions[] = $info['report access']; + } + // Check for entity report access callbacks. + if (isset($info['entity report access callback']) + && function_exists($info['entity report access callback']) + && !in_array($info['entity report access callback'], $entity_access_callbacks)) { + $entity_access_callbacks[] = $info['entity report access callback']; + } + } + + // Check access for this comment. + foreach ($entities as $entity) { + if ($entity_type === 'comment') { + $entity_id = $entity->cid; + $cids[$entity->cid] = $entity->cid; + $nids[$entity->nid] = $entity->nid; + } + else if ($entity_type === 'node') { + $entity_id = $entity->nid; + $nids[$entity->nid] = $entity->nid; + } + + // Check reporting callbacks. + foreach($report_access_callbacks as $callback) { + if (!$callback($entity_type, $entity_id)) { + break; + } + } + + // Check reporting user permissions. + foreach($access_permissions as $permission) { + if (!user_access($permission)) { + break; + } + } + + // Check entity reporting callbacks. + foreach($report_access_callbacks as $callback) { + if (!$callback($entity)) { + break; + } + } + + // If still here, then user has access to report this entity. + $allowed[] = $entity; + } + return array($allowed, $nids, $cids); +} + +/** + * @} End of "name mollom_action". + */ /** * @name mollom_flag Flag as inappropriate diff --git a/tests/mollom.test b/tests/mollom.test index 5de28c2..be26de8 100644 --- a/tests/mollom.test +++ b/tests/mollom.test @@ -3179,6 +3179,144 @@ class MollomCommentFormTestCase extends MollomWebTestCase { } /** + * Tests Mollom actions. + */ +class MollomActionsTestCase extends MollomWebTestCase { + // Keep track of nodes and comments for actions. + protected $nodes = array(); + protected $comments = array(); + // Re-route Mollom communication to this testing site. + protected $mollomClass = 'MollomDrupalTestLocal'; + + public static function getInfo() { + return array( + 'name' => 'Actions integration', + 'description' => 'Tests actions provided for comments and nodes.', + 'group' => 'Mollom', + ); + } + + function setUp() { + parent::setUp(array('comment')); + $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article')); + $this->web_user = $this->drupalCreateUser(array('create article content', 'access comments', 'post comments', 'post comments without approval')); + + variable_set('comment_preview_article', COMMENT_PREVIEW_OPTIONAL); + $this->drupalLogin($this->admin_user); + $this->setProtectionUI('article_node_form'); + $this->setProtectionUI('comment_form'); + $this->drupalLogout(); + + // Login and submit a node. + $this->nodes = array(); + $this->comments = array(); + $this->drupalLogin($this->web_user); + for ($i = 0; $i < 2; $i++) { + // Create a test node. + $edit = array( + 'title' => 'ham node ' . $i, + ); + $this->drupalPost('node/add/article', $edit, t('Save')); + $node = $this->drupalGetNodeByTitle($edit['title']); + + $this->drupalGet('comment/reply/' . $node->nid); + $edit = array( + 'comment' => 'ham', + ); + $this->drupalPost(NULL, $edit, t('Save')); + $this->comments[] = db_fetch_object(db_query("SELECT * FROM {comments} WHERE comment = '%s' AND nid = %d", array($edit['comment'], $node->nid))); + $this->nodes[] = $node; + } + } + + /** + * Test that calling the mollom action function triggers the unpublish of + * comments and marking as spam. + */ + function testCommentActions() { + // Load the comment entity objects. + $cids = array(); + $contentIds = array(); + foreach($this->comments as $comment) { + $cids[] = $comment->cid; + $data = mollom_data_load('comment', $comment->cid); + $contentIds[] = $data->contentId; + } + + // Verify that all comments are currently published. + $published = array(); + $result = db_query('SELECT cid FROM {comments} WHERE cid IN (' . db_placeholders($cids, 'int') . ') AND status = %d', $cids, COMMENT_PUBLISHED); + while ($row = db_fetch_array($result)) { + $published[] = $row['cid']; + } + $this->assertEqual(count($published), count($this->comments)); + + // Call the unpublish action. + mollom_action_unpublish_comment($this->comments); + + // Verify that all comments are now unpublished. + $published = array(); + $result = db_query('SELECT cid FROM {comments} WHERE cid IN (' . db_placeholders($cids, 'int') . ') AND status = %d', $cids, COMMENT_PUBLISHED); + while ($row = db_fetch_array($result)) { + $published[] = $row['cid']; + } + $this->assertEqual(count($published), 0); + + // Verify that all comments have been marked as spam. + foreach ($cids as $cid) { + $server = $this->getServerRecord('feedback'); + $this->assertTrue(in_array($server['contentId'], $contentIds)); + $this->assertEqual($server['source'], 'mollom_action_unpublish_comment'); + $this->assertEqual($server['reason'], 'spam'); + $this->assertEqual($server['type'], 'moderate'); + } + } + + /** + * Test that calling the mollom action function triggers the unpublish of + * nodes and marking as spam. + */ + function testNodeActions() { + // Load the comment entity objects. + $nids = array(); + $contentIds = array(); + foreach($this->nodes as $node) { + $nids[] = $node->nid; + $data = mollom_data_load('node', $node->nid); + $contentIds[] = $data->contentId; + } + + // Verify that all nodes are currently published. + $published = array(); + $result = db_query('SELECT nid FROM {node} WHERE nid IN (' . db_placeholders($nids, 'int') . ') AND status = 1', $nids); + while ($row = db_fetch_array($result)) { + $published[] = $row['nid']; + } + $this->assertEqual(count($published), count($this->nodes)); + + // Call the unpublish action. + mollom_action_unpublish_node($this->nodes); + + // Verify that all comments are now unpublished. + $published = array(); + $result = db_query('SELECT nid FROM {node} WHERE nid IN (' . db_placeholders($nids, 'int') . ') AND status = 1', $nids); + while ($row = db_fetch_array($result)) { + $published[] = $result['nid']; + } + $this->assertEqual(count($published), 0); + + // Verify that all nodes have been marked as spam. + foreach ($nids as $nid) { + $server = $this->getServerRecord('feedback'); + $this->assertTrue(in_array($server['contentId'], $contentIds)); + $this->assertEqual($server['source'], 'mollom_action_unpublish_node'); + $this->assertEqual($server['reason'], 'spam'); + $this->assertEqual($server['type'], 'moderate'); + } + } +} + +/** * Tests protection of Contact module forms. */ class MollomContactFormTestCase extends MollomWebTestCase {