*/ /** * Implementation of hook_menu(). */ function moderation_menu($may_cache) { $items = array(); if ($may_cache) { $items[] = array( 'path' => 'admin/content/node/moderation', 'title' => t('Moderation'), 'callback' => 'moderation_node_queue', 'access' => user_access('administer nodes'), 'type' => MENU_LOCAL_TASK, ); $items[] = array( 'path' => 'admin/content/comment/list/moderation', 'title' => t('Moderation'), 'callback' => 'moderation_comment_queue', 'access' => user_access('administer comments'), 'type' => MENU_LOCAL_TASK, ); $items[] = array( 'path' => 'admin/content/node/log', 'title' => t('Log'), 'callback' => 'moderation_log', 'callback arguments' => array('node'), 'access' => user_access('administer nodes'), 'type' => MENU_LOCAL_TASK, 'weight' => 1, ); $items[] = array( 'path' => 'admin/content/comment/list/log', 'title' => t('Log'), 'callback' => 'moderation_log', 'callback arguments' => array('comment'), 'access' => user_access('administer comments'), 'type' => MENU_LOCAL_TASK, 'weight' => 1, ); $items[] = array( 'path' => 'admin/settings/moderation', 'title' => 'Content moderation', 'description' => 'Configure the moderation queue.', 'callback' => 'drupal_get_form', 'callback arguments' => array('moderation_admin_settings'), 'access' => user_access('administer site configuration'), ); } else { if (arg(0) == 'node' AND is_numeric(arg(1))) { $items[] = array( 'path' => 'node/'. arg(1) .'/log', 'title' => 'Log', 'description' => 'Configure the moderation queue.', 'callback' => 'moderation_log', 'callback arguments' => array('node', arg(1)), 'access' => user_access('administer nodes'), 'type' => MENU_LOCAL_TASK, ); } $access = (arg(1) == 'node' AND user_access('administer nodes')) || (arg(1) == 'comment' AND user_access('administer comments')) ? TRUE : FALSE; $items[] = array( 'path' => 'moderation', 'callback' => 'moderation_callback_switch', 'callback arguments' => array(arg(1), arg(2), arg(3), arg(4)), 'access' => $access, 'type' => MENU_CALLBACK, ); } return $items; } /** * Menu callback; */ function moderation_callback_switch($obj_type, $obj_id, $op, $attribute) { $js = isset($_REQUEST['js']); $token = $_REQUEST['token']; // Check for valid token // We don't need a token if $op is get if (!drupal_valid_token($token, $obj_type .'-'. $obj_id) && $op != 'get') { drupal_access_denied(); exit(); } $attributes = array('status', 'promote', 'sticky', 'moderate', 'preview'); $types = array('node', 'comment'); if (!is_numeric($obj_id) OR !in_array($obj_type, $types) OR !in_array($attribute, $attributes)) { return drupal_not_found(); } if ($op == 'get') { if ($attribute == 'preview') { if ($js) { // Return content for preview if js is available moderation_get_preview($obj_id, $obj_type); } else { // Redirect to node/comment if js is not available moderation_goto($obj_id, $obj_type); } } else { // Return the current value for an attribute moderation_get_attribute($obj_id, $obj_type, $attribute); } exit(); } if ($op == 'set') { switch ($attribute) { case 'status': case 'promote': case 'sticky': $result = moderation_switch_attribute($obj_id, $obj_type, $attribute); break; case 'moderate': $result = moderation_switch_moderation($obj_id, $obj_type); break; } if ($js) { print drupal_to_js($result); exit(); } else { drupal_set_message(t('The changes have been saved.')); drupal_goto(); } } return drupal_not_found(); } /** * Implementation of hook_nodeapi(). */ function moderation_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) { switch ($op) { case 'load': if (in_array($node->type, variable_get('moderation_moderated_types', array()))) { return db_fetch_array(db_query("SELECT status as moderate FROM {moderation_moderation} mm WHERE mm.obj_type = 'node' AND mm.obj_id = %d", $node->nid)); } case 'update' : case 'insert' : if (moderation_is_moderated_type($node->type)) { db_query("DELETE FROM {moderation_moderation} WHERE obj_id=%d AND obj_type='node'", $node->nid); db_query("INSERT INTO {moderation_moderation} (obj_id, obj_type, status) VALUES (%d, 'node', %d)", $node->nid, $node->moderate); } break; case 'delete': db_query("DELETE FROM {moderation} WHERE obj_type='node' AND obj_id=%d", $node->nid); db_query("DELETE FROM {moderation_moderation} WHERE obj_type='node' AND obj_id=%d", $node->nid); break; } } /** * Implementation of hook_comment(). */ function moderation_comment(&$a1, $op) { switch ($op) { case 'insert': case 'update': db_query("DELETE FROM {moderation_moderation} WHERE obj_id=%d AND obj_type='comment'", $a1['cid']); db_query("INSERT INTO {moderation_moderation} (obj_id, obj_type, status) VALUES (%d, 'comment', %d)", $a1['cid'], $a1['moderate']); break; case 'delete': db_query("DELETE FROM {moderation} WHERE obj_type='comment' AND obj_id=%d", $a1->cid); db_query("DELETE FROM {moderation_moderation} WHERE obj_type='comment' AND obj_id=%d", $a1->cid); break; } } /** * Implementation of hook_form_alter(). */ function moderation_form_alter($form_id, &$form) { if (isset($form['type']) && $form['type']['#value'] .'_node_form' == $form_id) { if (moderation_is_moderated_type($form['type']['#value'])) { if (user_access('administer nodes')) { $form['options']['moderate'] = array( '#type' => 'checkbox', '#title' => t('Has been moderated'), '#default_value' => $form['#node']->moderate, '#weight' => -10, '#description' => t('Check to remove from moderation queue, uncheck to add it to the queue.'), ); } } } if ($form_id == 'comment_form') { if (user_access('administer nodes')) { $status = db_result(db_query("SELECT status FROM {moderation_moderation} WHERE obj_id=%d AND obj_type='comment'", $form['cid']['#value'])); $form['admin']['moderate'] = array( '#type' => 'checkbox', '#title' => 'Has been moderated', '#default_value' => $status, '#weight' => -10, '#description' => t('Check to remove from moderation queue, uncheck to add it to the queue.'), ); } } } /** * Menu callback: content administration. */ function moderation_node_queue() { global $base_path; drupal_add_css(drupal_get_path('module', 'moderation') .'/moderation.css'); $settings = array('moderationType' => 'node', 'moderationBasePath' => $base_path); drupal_add_js('jQuery.extend(Drupal, '. drupal_to_js($settings) .')', 'inline'); drupal_add_js(drupal_get_path('module', 'moderation') .'/moderation.js'); $query = "SELECT n.*, u.name, u.uid, mm.status as moderate FROM {node} n INNER JOIN {users} u ON n.uid = u.uid LEFT JOIN {moderation_moderation} mm ON n.nid = mm.obj_id WHERE mm.obj_type = 'node' AND (mm.status IS NULL OR mm.status=0) AND n.type IN ('" . implode('\' ,\'', variable_get('moderation_moderated_types', array())) ."') ORDER BY n.created DESC, n.title ASC"; $result = pager_query(db_rewrite_sql($query), 50); $destination = drupal_get_destination(); while ($node = db_fetch_object($result)) { $query = "SELECT m.*, u.name FROM {moderation} m LEFT JOIN {users} u ON m.uid = u.uid WHERE m.obj_id=%d AND m.obj_type='node' ORDER BY m.created DESC LIMIT 1"; $moderation = db_fetch_object(db_query($query, $node->nid)); $token = drupal_get_token('node-'. $node->nid); $item = '
'; $item .= '
'; $item .= format_date($node->created, 'small') .' '; $item .= l($node->title, 'moderation/node/'. $node->nid .'/get/preview'); $item .= theme('mark', node_mark($node->nid, $node->changed)); if ($moderation) { $item .= '
'. t('(!user - !action - !date)', array('!user' => theme('username', (object) array('uid' => $moderation->uid, 'name' => $moderation->name)), '!action' => moderation_log_message($moderation->attribute, $moderation->status, $moderation->obj_type), '!date' => format_date($moderation->created, 'small'))) .'
'; } $item .= '
'; $item .= '
'; $item .= '
'; $item .= ' '. l(t('edit'), 'node/'. $node->nid .'/edit', array(), drupal_get_destination()) .''; $item .= ' '. t('By !user', array('!user' => theme('username', $node))) .''; $item .= ' '. check_plain(node_get_types('name', $node)) .''; $item .= ' '. l(($node->status ? t('Unpublish') : t('Publish')), 'moderation/node/'. $node->nid .'/set/status', array('id' => 'moderation-status-link-'. $node->nid, 'class' => 'moderation-status-link'), drupal_get_destination() .'&token='. $token) .''; $item .= ' '. l(($node->promote ? t('Demote') : t('Promote')), 'moderation/node/'. $node->nid .'/set/promote', array('id' => 'moderation-promote-link-'. $node->nid, 'class' => 'moderation-promote-link'), drupal_get_destination() .'&token='. $token) .''; $item .= ' '. l(($node->sticky ? t('Remove stickiness') : t('Make sticky')), 'moderation/node/'. $node->nid .'/set/sticky', array('id' => 'moderation-sticky-link-'. $node->nid, 'class' => 'moderation-sticky-link'), drupal_get_destination() .'&token='. $token) .''; $item .= ' '. l(($node->moderate ? t('Unmoderate') : t('Moderate')), 'moderation/node/'. $node->nid .'/set/moderate', array('id' => 'moderation-moderate-link-'. $node->nid, 'class' => 'moderation-moderate-link'), drupal_get_destination() .'&token='. $token) .''; $item .= '
'; $rows[] = array('data' => array( array( 'data' => $item, ), ) ); } if (!db_num_rows($result)) { $output = t('No posts available.'); } $output .= theme('table', array(), $rows); $output .= theme('pager', NULL, 50); return $output; } /** * Menu callback; present an administrative comment listing. */ function moderation_comment_queue() { global $base_path; drupal_add_css(drupal_get_path('module', 'moderation') .'/moderation.css'); $settings = array('moderationType' => 'comment', 'moderationBasePath' => $base_path); drupal_add_js('jQuery.extend(Drupal, '. drupal_to_js($settings) .')', 'inline'); drupal_add_js(drupal_get_path('module', 'moderation') .'/moderation.js'); $query = "SELECT c.*, mm.status as moderate FROM {comments} c LEFT JOIN {moderation_moderation} mm ON c.cid = mm.obj_id WHERE mm.obj_type = 'comment' AND (mm.status IS NULL OR mm.status=0) ORDER BY c.timestamp DESC, c.subject ASC"; $result = pager_query(db_rewrite_sql($query), 50); $destination = drupal_get_destination(); while ($comment = db_fetch_object($result)) { $query = "SELECT m.*, u.name FROM {moderation} m LEFT JOIN {users} u ON m.uid = u.uid WHERE m.obj_id=%d AND m.obj_type='comment' ORDER BY m.created DESC LIMIT 1"; $moderation = db_fetch_object(db_query($query, $comment->cid)); $token = drupal_get_token('comment-'. $comment->cid); $item = '
'; $item .= '
'; $item .= format_date($comment->timestamp, 'small') .' '; $item .= l($comment->subject, 'moderation/comment/'. $comment->cid .'/get/preview'); $item .= theme('mark', node_mark($comment->cid, $comment->changed)); if ($moderation) { $item .= '
'. t('(!user - !action - !date)', array('!user' => theme('username', (object) array('uid' => $moderation->uid, 'name' => $moderation->name)), '!action' => moderation_log_message($moderation->attribute, $moderation->status, $moderation->obj_type), '!date' => format_date($moderation->created, 'small'))) .'
'; } $item .= '
'; $item .= '
'; $item .= '
'; $item .= ' '. l(t('edit'), 'comment/edit/'. $comment->cid, array(), drupal_get_destination()) .''; $item .= ' '. t('By !user', array('!user' => theme('username', $comment))) .''; $item .= ' '. t('Show !node', array('!node' => l('Node', 'node/'. $comment->nid, array('attributes' => array('title' => check_plain($node_title)))))) .''; $item .= ' '. l(($comment->moderate ? t('Unmoderate') : t('Moderate')), 'moderation/comment/'. $comment->cid .'/set/moderate', array('id' => 'moderation-moderate-link-'. $comment->cid, 'class' => 'moderation-moderate-link'), drupal_get_destination() .'&token='. $token) .''; $item .= ' '. l(($comment->status ? t('Publish') : t('Unpublish')), 'moderation/comment/'. $comment->cid .'/set/status', array('id' => 'moderation-status-link-'. $comment->cid, 'class' => 'moderation-status-link'), drupal_get_destination() .'&token='. $token) .''; $item .= '
'; $rows[] = array('data' => array( array( 'data' => $item, ), ) ); } if (!db_num_rows($result)) { $output = t('No comments available.'); } $output .= theme('table', array(), $rows); $output .= theme('pager', NULL, 50); return $output; } /** * Switch moderation flag * * @param string $obj_type one of 'node', 'comment' * @param integer $obj_id */ function moderation_switch_moderation($obj_id, $obj_type) { global $user; $status = db_result(db_query("SELECT status FROM {moderation_moderation} WHERE obj_id=%d AND obj_type='%s'", $obj_id, $obj_type)); db_query("INSERT INTO {moderation} (obj_id, obj_type, uid, attribute, status, created) VALUES (%d, '%s', %d, '%s', %d, %d)", $obj_id, $obj_type, $user->uid, 'moderate', !$status, time()); db_query("DELETE FROM {moderation_moderation} WHERE obj_id=%d AND obj_type='%s'", $obj_id, $obj_type); if ($obj_type == 'node') { // Theres a core moderate attribute // we update it here, to support modules that use on it moderation_switch_attribute($obj_id, $obj_type, 'moderate'); } return array(db_query("INSERT INTO {moderation_moderation} (obj_id, obj_type, status) VALUES (%d, '%s', %d)", $obj_id, $obj_type, !$status), !$status, 'moderate'); } /** * Switch an attribute * * @param integer $obj_id * @param string $obj_type one of 'node', 'comment' * @param string $attribute one of 'status', 'promote', 'sticky' */ function moderation_switch_attribute($obj_id, $obj_type, $attribute) { global $user; if ($obj_type == 'node') { $status_new = !db_result(db_query("SELECT %s FROM {node} WHERE nid=%d", $attribute, $obj_id)); $success = db_query("UPDATE {node} SET %s=%d WHERE nid=%d", $attribute, $status_new, $obj_id); } else if ($obj_type == 'comment') { $status_new = !db_result(db_query("SELECT %s FROM {comments} WHERE cid=%d", $attribute, $obj_id)); $success = db_query("UPDATE {comments} SET %s=%d WHERE cid=%d", $attribute, $status_new, $obj_id); } db_query("INSERT INTO {moderation} (obj_id, obj_type, uid, attribute, status, created) VALUES (%d, '%s', %d, '%s', %d, %d)", $obj_id, $obj_type, $user->uid, $attribute, $status_new, time()); return array($success, $status_new, $attribute); } /** * Get the preview markup for a node or a comment * * @param integer $obj_id * @param string $obj_type */ function moderation_get_preview($obj_id, $obj_type) { if ($obj_type == 'node') { if ($node = node_load($obj_id)) { $data = theme('moderation_node_preview', $node); } } else if ($obj_type == 'comment') { if ($comment = _comment_load($obj_id)) { $_GET['q'] = 'node/'. $comment->nid; $data = theme('comment_preview', $comment); } } print drupal_to_js($data); exit(); } /** * Get an objects attribute * * @param integer $obj_id * @param string $obj_type * @param string $attribute one of 'status', 'promote', 'sticky', 'moderate' */ function moderation_get_attribute($obj_id, $obj_type, $attribute) { $table = ($obj_type == 'comment') ? 'comments' : 'node'; $id = ($obj_type == 'comment') ? 'cid' : 'nid'; if ($attribute == 'moderate') { print drupal_to_js(array(db_result(db_query("SELECT status FROM {moderation_moderation} WHERE obj_id=%d AND obj_type='%s'", $obj_id, $obj_type)))); } else { print drupal_to_js(array(db_result(db_query("SELECT %s FROM {%s} WHERE %s=%d", $attribute , $table, $id, $obj_id)))); } exit(); } /** * Display a node preview for display during node creation and editing. * * @param $node * The node object which is being previewed. */ function theme_moderation_node_preview($node) { $output = '
'; if ($node->teaser && $node->teaser != $node->body) { $output .= '

'. t('Preview trimmed version') .'

'; $output .= node_view(drupal_clone($node), 1, FALSE, 0); $output .= '

'. t('Preview full version') .'

'; $output .= node_view($node, 0, FALSE, 0); } else { $output .= node_view($node, 0, FALSE, 0); } $output .= "
\n"; return $output; } function moderation_admin_settings() { $form['moderation_moderated_types'] = array( '#type' => 'checkboxes', '#options' => node_get_types('names'), '#default_value' => variable_get('moderation_moderated_types', array()), '#title' => t('Set nodetypes shown which are moderated'), ); return system_settings_form($form); } function moderation_is_moderated_type($type) { $types = variable_get('moderation_moderated_types', array()); return ($types[$type]); } function moderation_log($type = 'node', $obj_id = NULL) { switch ($type) { case 'comment': $sql = "SELECT m.*, c.nid, c.cid, c.subject, u.uid, u.name FROM {moderation} m LEFT JOIN {comments} c ON c.cid = m.obj_id LEFT JOIN {users} u ON u.uid = m.uid WHERE m.obj_type = 'comment' ". ($obj_id ? 'AND m.obj_id = '. $obj_id : '') ." ORDER BY m.created DESC"; break; case 'node': $sql = "SELECT m.*, n.title, n.nid, u.uid, u.name FROM {moderation} m LEFT JOIN {node} n ON n.nid = m.obj_id LEFT JOIN {users} u ON u.uid = m.uid WHERE m.obj_type = 'node' ". ($obj_id ? 'AND m.obj_id = '. $obj_id : '') ." ORDER BY m.created DESC"; break; } $result = pager_query($sql, 25, 0, NULL); while ($moderation = db_fetch_object($result)) { $title = $moderation->subject ? $moderation->subject : $moderation->title; $fragment = $moderation->cid ? 'comment-'. $moderation->cid : NULL; $user->uid = $moderation->uid; $user->name = $moderation->name; $moderations[] = array( l($title, 'node/'. $moderation->nid, array(), NULL, $fragment), theme('username', $user), moderation_log_message($moderation->attribute, $moderation->status, $type), format_date($moderation->created), ); } $header = array( t('Title'), t('User'), t('Action'), t('Date'), ); $output = theme('table', $header, $moderations); $output .= theme('pager'); return $output; } function moderation_log_message($attribute, $status, $type) { switch ($attribute) { case 'status': $message = $status ? t('Published') : t('Unpublished'); break; case 'moderate': $message = $status ? t('Moderated') : t('Unmoderated'); break; case 'sticky': $message = $status ? t('Made sticky') : t('Removed stickiness'); break; case 'promote': $message = $status ? t('Promoted') : t('Not promoted'); break; } return $message; } /** * Redirect to a node/comment */ function moderation_goto($obj_id, $obj_type) { if ($obj_type == 'node') { drupal_goto('node/'. $obj_id); } else { if ($comment = _comment_load($obj_id)) { drupal_goto('node/'. $comment->nid, NULL, 'comment-'. $comment->cid); } } }