diff --git a/twitter_post/twitter_post.module b/twitter_post/twitter_post.module index 0c59bcb..1ddace9 100644 --- a/twitter_post/twitter_post.module +++ b/twitter_post/twitter_post.module @@ -17,7 +17,6 @@ function twitter_post_menu() { 'file' => 'twitter_post.pages.inc', 'type' => MENU_LOCAL_TASK, 'weight' => 3 - ); return $items; @@ -32,6 +31,8 @@ function twitter_post_form_alter(&$form, $form_state, $form_id) { // If we haven't enabled Twitter posting on this node type, nothing to do // here. $type = $form['#node']->type; + $tweet_time = $form['#node']->twitter['tweet_time']; + $allowed_types = variable_get('twitter_post_types', array('story' => 'story', 'blog' => 'blog')); if (empty($allowed_types[$type])) { return; @@ -50,14 +51,28 @@ function twitter_post_form_alter(&$form, $form_state, $form_id) { '#collapsed' => FALSE, '#tree' => TRUE, ); + + if ($tweet_time) { + $description = t('This post was previously tweeted on %time.', array('%time' => format_date($tweet_time, 'short'))); + } + else { + $description = t('Checking this option will queue this post for Twitter. NOTE: You can only tweet each node once per Twitter account.'); + } + $form['twitter']['post'] = array( '#type' => 'checkbox', '#title' => t('Announce this post on Twitter'), '#default_value' => (empty($form['nid']['#value'])), + '#description' => $description, '#id' => 'twitter-toggle', ); $form['twitter'] += $twitter_form; - $form['twitter']['status']['#default_value'] = variable_get('twitter_post_default_format', 'New post: !title !tinyurl'); + + $tweet = $form['#node']->twitter['status']; + + $default_message = $tweet ? $tweet : variable_get('twitter_post_default_format', 'New post: !title !tinyurl'); + + $form['twitter']['status']['#default_value'] = $default_message; $form['twitter']['status']['#description'] = t('The given text will be posted to twitter.com. You can use !url, !url-alias, !tinyurl, !title and !user as replacement text. If the token module is enabled, you may also choose from the tokens listed in the replacement patterns section.'); if (module_exists('token')) { $form['twitter']['token_help'] = array( @@ -73,6 +88,7 @@ function twitter_post_form_alter(&$form, $form_state, $form_id) { ); } } + //////dsm($form); } /** @@ -81,45 +97,43 @@ function twitter_post_form_alter(&$form, $form_state, $form_id) { * Intercepts newly published nodes and posts noticed to Twitter. */ function twitter_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) { - + switch ($op) { - case 'insert': - case 'update': - if (!empty($node->status) && !empty($node->twitter) && !empty($node->twitter['post'])) { - module_load_include('inc', 'twitter'); - - $twitter_account = twitter_account_load($node->twitter['account']); - $replacements = array('!title' => $node->title, - '!url' => url('node/'. $node->nid, array('absolute' => TRUE, 'alias' => TRUE)), - '!url-alias' => url('node/'. $node->nid, array('absolute' => TRUE)), - '!user' => $node->name); - // Only generate the shortened URL if it's going to be used. No sense - // burning through TinyURLs without a good reason. - if (strstr($node->twitter['status'], '!tinyurl') !== FALSE) { - $replacements['!tinyurl'] = twitter_shorten_url(url('node/'. $node->nid, array('absolute' => TRUE))); - } + case 'load': + // See if there is a pending Twitter status. + $tweets = db_query("SELECT * from {twitter_post_nids} WHERE nid = %d AND vid = %d", $node->nid, $node->vid); - $status = strtr($node->twitter['status'], $replacements); + $accounts = array(); - // If token module is available, process status to do the token replacement - if (module_exists('token')) { - $status = token_replace($status, 'node', $node); - } + while ($saved = db_fetch_array($tweets)) { + $message = $saved['message']; + $post = $saved['status']; + $accounts[] = $saved['account']; - try { - $result = twitter_set_status($twitter_account, $status); - - // // TODO: resolve this failure, see http://drupal.org/node/335459 - // if (!$result) { - // $result = new stdClass; - // $result->error = 'Sorry, there was an unkown error connecting to Twitter!'; - // throw new TwitterException(); - // } - drupal_set_message(t('Successfully posted to Twitter')); - } - catch (TwitterException $e) { - drupal_set_message(t('An error occurred when posting to twitter: %code %error', - array('%code' => $result->code, '%error' => $result->error)), 'warning'); + // If this post was already tweeted, get the time of the previous posting. + if (isset($saved['tweet_time'])) $tweet_time = $saved['tweet_time']; + } + + if (count($accounts) > 0) { + $output['twitter'] = array( + 'post' => $post, + 'account' => $accounts, + 'status' => $message, + 'tweet_time' => $tweet_time, + ); + return $output; + } + break; + + case 'insert': + case 'update': + //dsm($op); + //dsm($node); + + // If the "Post to Twitter" checkbox is active, save the post. + if ($node->twitter['status'] && $node->twitter['post']) { + if (twitter_post_update_post($node)) { + //dsm('!! Saved a NBW Twitter status during '.$op); } } break; @@ -142,6 +156,7 @@ function twitter_post_form($account = NULL) { } $twitter_accounts = twitter_get_user_accounts($account->uid); + $options = array(); foreach ($twitter_accounts as $twitter_account) { $options[$twitter_account->id] = $twitter_account->screen_name; @@ -153,21 +168,127 @@ function twitter_post_form($account = NULL) { '#type' => 'textfield', '#id' => 'twitter-textfield', ); + // @todo: Setup a config to store each default on/off status per account + $form['account'] = array( + '#type' => 'checkboxes', + '#title' => t('Account'), + '#options' => $options, + '#default_value' => array_keys($options), + '#id' => 'twitter-account', + ); - if (count($options) > 1) { - $form['account'] = array( - '#type' => 'select', - '#title' => t('Account'), - '#options' => $options, - '#id' => 'twitter-account', - ); - } - else { - $form['account'] = array( - '#type' => 'value', - '#value' => array_pop(array_keys($options)) - ); - } return $form; } } + + +/** + * Function to insert or update a post in the database, or tweet it if scheduled to. + * + * NOTE: This function should only get fired upon Node creation (if $node->twitter['post'] + is true) or upon Node update if ... + + */ + +function twitter_post_update_post($node) { + //dsm('--- in twitter_post_update_post ----'); + //dsm('node ::: '); + //dsm($node); + + // Cycle through the accounts that are attached to this tweet. + foreach ($node->twitter['account'] as $twitter_uid) { + if ($twitter_uid > 0) { + ////dsm('updating for account: '.$twitter_uid); + + // Sanitize the message, and replace its tokens + $status = twitter_post_sanitize_message($node); + + // ONLY if the node is published and hasn't been tweeted, but is queued, try to post it + if ($node->status && $node->twitter['post'] && !$node->twitter['tweet_time']) { + + + // If we are able to post it to Twitter, update the status to TRUE, and set a time. + if ($posted = twitter_post_tweet($twitter_uid, $status)) { + db_query("UPDATE {twitter_post_nids} SET status = %d, tweet_time = %d WHERE vid = %d and account = %d", $node->twitter['post'], time(), $node->vid, $twitter_uid); + + return TRUE; + } + } + // Or if the node is unpublished, perhaps we are making changes. + else { + // We only want to update a tweet if it has not already been posted to Twitter! + if ($test = db_result(db_query("SELECT message FROM {twitter_post_nids} WHERE account = %d AND vid = %d AND status = 0", + $twitter_uid, $node->vid))) { + + // Update the status since we're not ready to post it to Twitter yet + db_query("UPDATE {twitter_post_nids} SET message = '%s', status = %d WHERE vid = %d AND account = %d", + $status, $node->twitter['post'], $node->vid, $twitter_uid); + + drupal_set_message("Tweet was queued in the database."); + return FALSE; + } + else { + // Insert a new item into the database. + db_query("INSERT INTO {twitter_post_nids} (nid, message, account, vid, status) VALUES (%d, '%s', %d, %d, %d)", + $node->nid, $status, $twitter_uid, $node->vid, $node->twitter['post']); + + drupal_set_message("Tweet was queued in the database."); + return FALSE; + } + } + } + } +} + + +// Post a Twitter status to Twitter via their API. +function twitter_post_tweet($twitter_uid, $status) { + module_load_include('inc', 'twitter'); + + $twitter_account = twitter_account_load($twitter_uid); + + try { + $result = twitter_set_status($twitter_account, $status); + + //watchdog('twitter_post', 'tweeting: acct '.$twitter_account.' status: '.$status); + // // TODO: resolve this failure, see http://drupal.org/node/335459 + // if (!$result) { + // $result = new stdClass; + // $result->error = 'Sorry, there was an unkown error connecting to Twitter!'; + // throw new TwitterException(); + // } + drupal_set_message(t('Successfully posted to Twitter')); + } + catch (TwitterException $e) { + drupal_set_message(t('An error occurred when posting to twitter: %code %error', + array('%code' => $result->code, '%error' => $result->error)), 'warning'); + } + return TRUE; +} + + +// Helper function to sanitize the tweet and replace tokens. +function twitter_post_sanitize_message($node) { + $replacements = array('!title' => $node->title, + '!url' => url('node/'. $node->nid, array('absolute' => TRUE, 'alias' => TRUE)), + '!url-alias' => url('node/'. $node->nid, array('absolute' => TRUE)), + '!user' => $node->name); + + // Only generate the shortened URL if it's going to be used. No sense + // burning through TinyURLs without a good reason. + if (strstr($node->twitter['status'], '!tinyurl') !== FALSE) { + $replacements['!tinyurl'] = twitter_shorten_url(url('node/'. $node->nid, array('absolute' => TRUE))); + } + + $status = strtr($node->twitter['status'], $replacements); + + // If token module is available, process status to do the token replacement + if (module_exists('token')) { + $status = token_replace($status, 'node', $node); + } + + // Get rid of any htmlentities + $status = html_entity_decode($status, ENT_QUOTES); + + return $status; +}