You are here

function discussthis_create_form_submit in Discuss This! 6

\brief Save the new comment.

This function creates a new forum topic if this is the first comment on this node. Otherwise, it just adds the comment to the existing forum.

\todo We've got a problem here, if the administrator wants to moderate these comments, then we should not create the forum node. This is a similar problem to the one we see in creating the forum node before the comment is even posted to us.

I guess that the biggest problem is that a comment, to exist, needs to be attached to a node.

I see two potential solutions:

1) we handle our own comments

2) we create the comment on the node being discussed and move it later to the forum

\param[in] $form The form info \param[in] $form_state The current state of the form, including the values

1 string reference to 'discussthis_create_form_submit'
discussthis_create_form in ./discussthis.module
\brief Create a comment form.

File

./discussthis.module, line 960
Associations discussions in forums with specific nodes

Code

function discussthis_create_form_submit($form, &$form_state) {
  global $user;

  // we got a post, so we want to create the forum node
  // load the node being discussed
  $node = node_load($form_state['values']['discussthis_nid']);
  if (!$node) {

    // what shall we do here? the admin could delete the node while
    // a user is trying to discuss it...
    drupal_set_message(t('The node being discussed is not available anymore. (nid: @nid)', array(
      '@nid' => $form_state['values']['discussthis_nid'],
    )), 'error');
    drupal_goto('');
  }

  // TODO:

  //if (!user_access('post comments without approval')) {

  //  // The comment needs to be approved, save it in our discussthis_comment table
  //  // (this is annoying, but otherwise we get a post in the way?! maybe we could
  //  // have a flag in the settings of discussthis so users can choose how to handle
  //  // this case?)
  //  $sql = "INSERT INTO {discussthis_comment} (...) VALUES (...)";
  //  db_query($sql, ...);

  //}

  // some of the functions used to create a node require node pages include
  module_load_include('inc', 'node', 'node.pages');

  // The core defines a way to create a node which is to fill a form
  // and then call drupal_execute() from includes/form.inc.
  $sub_form_state = array();

  // get the author of the node and pass that to the token_replace() call
  $author = user_load(array(
    'uid' => $node->uid,
  ));

  // TITLE
  $sub_form_state['values']['title'] = token_replace(variable_get('discussthis_newsubject', '[node-title]'), 'discussthis', $node);
  if ($author) {
    $sub_form_state['values']['title'] = token_replace($sub_form_state['values']['title'], 'user', $author);
  }

  // BODY
  $default_body = DISCUSSTHIS_DEFAULT_NODE_MESSAGE;
  $sub_form_state['values']['body'] = token_replace(variable_get('discussthis_newtemplate', $default_body), 'discussthis', $node);
  if ($author) {
    $sub_form_state['values']['body'] = token_replace($sub_form_state['values']['body'], 'user', $author);
  }

  // FORMAT
  $sub_form_state['values']['format'] = NULL;

  // FORUM TERM
  $forum_vid = variable_get('forum_nav_vocabulary', 1);
  $vocabulary = taxonomy_vocabulary_load($forum_vid);
  $discussthis_forum = _discussthis_get_forum($node->nid, $node->type);
  $tid = $discussthis_forum['forum_tid'];
  if ($vocabulary->tags) {

    // tags are a special case, also you cannot choose tags for a forum...
    $sub_form_state['values']['taxonomy']['tags'][$vid] = taxonomy_implode_tags($tid, $forum_vid);
  }
  elseif ($vocabulary->multiple) {

    // forums should never use multiple either
    $sub_form_state['values']['taxonomy'][$forum_vid][$tid] = $tid;
  }
  else {
    $sub_form_state['values']['taxonomy'][$forum_vid] = $tid;
  }

  // LOG
  $sub_form_state['values']['log'] = t('Node automatically created by discussthis for comment @subject', array(
    '@subject' => $form_state['values']['subject'],
  ));

  // OPERATION
  $sub_form_state['values']['op'] = t('Save');

  // STATUS
  // Although it would be better to keep the status to the default of the forum
  // 1) the post here will include data that is under control (i.e. data from
  //    another node that was already agreed upon)
  // 2) the post needs to be published for a comment to be appended
  $sub_form_state['values']['status'] = 1;

  // Values that will get proper defaults automatically

  //$sub_form_state['values']['date'] = date('Y-m-d H:i:s O', time());

  // A special value to recognize this form in the discussthis_form_alter() function
  $sub_form_state['discussthis']['post'] = 1;

  // FORUM POST
  $topic = (object) array(
    'type' => 'forum',
  );

  // IMPORTANT NOTE:
  // This call generates a form for the current user, not the future user of
  // the new topic. This is an important distinction since some parameters
  // just cannot be passed to this function if we want it to work. For instance,
  // the format is set to default so it works. Any other format could fail and
  // the creation of the topic would fail. ("default" is available to all users!)
  drupal_execute('forum_node_form', $sub_form_state, $topic);
  $topic->nid = $sub_form_state['nid'];
  if (!$topic->nid) {

    // it did not work... hmmm...
    drupal_set_message('Forum post could not be created for your comment to be published.', 'error');
    drupal_goto();
  }

  // Now we can save the author in the new post as expected by the
  // administrator; when we try to set the UID in the node info
  // before calling drupal_execute() it is reset for security reason
  // and the result is that the UID is set to 0 (anonymous)
  //
  // load the user that was setup by the admin for this post,
  // if it fails, use the anonymous user
  $format = NULL;
  $author_name = variable_get('discussthis_author', $user->name);
  if (!$author_name || $user->name == $author_name) {
    $author = $user;
  }
  elseif ($author_name == '*') {
    $author = user_load(array(
      'uid' => $node->uid,
    ));

    // if we keep the same author, we can keep the same format
    // (although that author may not be authorized to use that
    // format anymore, we consider this node as safe at this
    // point...)
    $format = $node->format;
  }
  else {
    $author = user_load(array(
      'name' => $author_name,
    ));
  }
  if (!$author) {
    $author = array(
      'uid' => 0,
    );
  }
  $sql = "UPDATE {node} SET uid = %d WHERE nid = %d";
  db_query($sql, $author->uid, $topic->nid);

  // now that we have the right author, compute the right format
  // note that we leave the format alone if the offered format
  // is not otherwise allowed
  if (is_null($format)) {

    // get the format selected by the admin and verify its validity
    $format = (int) variable_get('discussthis_format_' . $node->type, 0);
    if ($format > 0) {
      $allowed = user_access('administer filters', $author);
      if (!$allowed) {

        // make sure the new author role has permission for this format
        $query = 'SELECT roles FROM {filter_formats} WHERE format = %d';
        $result = db_query($query, $format);
        $format_roles = db_fetch_array($result);
        $allowed = count(array_intersect($author->roles, explode(',', $format_roles))) > 0;
      }
      if ($allowed) {

        // allowed, make it the format for this node
        $sql = "UPDATE {node_revisions} SET format = %d" . " WHERE nid = %d" . " AND vid = (SELECT vid FROM {node} WHERE nid = %d)";
        db_query($sql, $format, $topic->nid, $topic->nid);
      }
    }
  }

  // now that we created the topic node, we want to link it to the
  // node being discussed ($topic and $node)
  //
  // here we use a LOCK to make sure we can create the new row all
  // alone, if the row actually exists, we actually had another user
  // create a post ahead of us! so we're going to add the comment
  // to that other node and we can delete the node we just created.
  // make sure we INSERT alone!
  db_lock_table('discussthis');
  $sql = "SELECT topic_nid FROM {discussthis} WHERE nid = %d";
  $other_topic_nid = db_result(db_query($sql, $node->nid));
  if (!$other_topic_nid) {

    // this is a new topic, we're the first to post!
    // so attach the new forum post to the node being discussed
    $sql = "INSERT INTO {discussthis} (nid, topic_nid) VALUES (%d, %d)";
    db_query($sql, $node->nid, $topic->nid);
  }

  // COMMIT the result, no insert if a topic existed anyway...
  db_unlock_tables();
  if ($other_topic_nid) {

    // What a waste! but I don't see any way around it.
    // Plus if you have signals on node creation, you'll get an email
    // and this deletes right after... so the email will point to
    // a non-existant node... Argh!
    node_delete($topic->nid);

    // hmmm... should we add an alias from $topic->nid to $topic_nid?!
    // we'll assume that this will be particularly rare!
    // So, the new topic nid is really the other topic nid...
    $topic->nid = $other_topic_nid;
  }

  // now we want to save the comment
  $form_state['values']['nid'] = $topic->nid;

  // before calling comment_save() they call this one:
  _comment_form_submit($form_state['values']);
  comment_form_submit($form, $form_state);
  $form_state['redirect'] = 'node/' . $topic->nid;

  // if you have boost, we want to reset the discussed node since
  // now it will look "different" (the link and eventually the new
  // comment)
  if (function_exists('boost_expire_node')) {
    boost_expire_node($node);
  }
}