? .DS_Store ? twitter_views_and_cron.patch Index: twitter.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/twitter/twitter.inc,v retrieving revision 1.2 diff -u -p -r1.2 twitter.inc --- twitter.inc 8 Jun 2008 04:56:45 -0000 1.2 +++ twitter.inc 8 Jun 2008 22:35:07 -0000 @@ -2,18 +2,30 @@ // $Id: twitter.inc,v 1.2 2008/06/08 04:56:45 walkah Exp $ /** + * @file + * A wrapper API for the Twitter microblogging service. + * + * Provides functions for retrieving public and authenticated messages from + * Twitter, helper code for locally caching Twitter data and account + * information, and utility functions for associating Drupal site users with + * their Twitter accounts. + */ + + +/** * Generate a twitter posting form for the given user. * - * @param object $account user account object. + * @param $account + * A Drupal user object. */ function twitter_form($account = NULL) { drupal_add_js(drupal_get_path('module', 'twitter') .'/twitter.js', 'module'); - + if (empty($account)) { global $user; $account = $user; } - + $twitter_accounts = drupal_map_assoc(array_keys(twitter_get_user_accounts($account->uid))); if (count($twitter_accounts)) { $form = array(); @@ -22,7 +34,7 @@ function twitter_form($account = NULL) { '#rows' => 1, '#id' => 'twitter-textarea', ); - + if (count($twitter_accounts) > 1) { $form['account'] = array( '#type' => 'select', @@ -42,23 +54,35 @@ function twitter_form($account = NULL) { } } + + /** * Twitter API functions */ -function twitter_set_status($screen_name, $password, $text = '', $source = NULL) { - $url = "http://twitter.com/statuses/update.xml"; - - $headers = array('Authorization' => 'Basic '. base64_encode($screen_name .':'. $password), - 'Content-type' => 'application/x-www-form-urlencoded'); - $data = 'status='. urlencode($text); - if (!empty($source)) { - $data .= 'source='. urlencode($source); - } - return drupal_http_request($url, $headers, 'POST', $data); -} - -function twitter_fetch_user_timeline($screen_name, $filter_since = TRUE, $cache = TRUE) { +/** + * Fetch the public timeline for a Twitter.com account. + * + * Note that this function only requires a screen name, and not a password. As + * such, it can only retrieve statuses for publically visible Twitter accounts. + * Because it doesn't require authentication, it is also easier on the Twitter + * servers. Be kind, use this version whenever you can. + * + * @param $screen_name + * The screen name of a Twitter.com user. + * @param $filter_since + * A boolean indicating that Twitter should only return statuses that have not + * been locally cached. This incurs an extra database hit, to retrieve the date + * of the most recent locally cached twitter message for the screen name. + * @param $cache + * A boolean indicating whether the statuses should be cached in the local + * site's database after they're retrieved. + * @return + * An array of Twitter statuses. + * + * @see twitter_fetch_statuses() + */ +function twitter_fetch_timeline($screen_name, $filter_since = TRUE, $cache = TRUE) { if ($filter_since) { $sql = "SELECT t.created_at FROM {twitter} t WHERE t.screen_name = '%s' ORDER BY t.created_at DESC"; $since = db_result(db_query($sql, $screen_name)); @@ -71,7 +95,7 @@ function twitter_fetch_user_timeline($sc } $results = drupal_http_request($url, array(), 'GET'); - if ($results->code == 304) { + if (_twitter_request_failure($results)) { return array(); } else { @@ -80,45 +104,177 @@ function twitter_fetch_user_timeline($sc foreach($results as $status) { twitter_cache_status($status); } + twitter_touch_account($screen_name); } return $results; } } -function twitter_fetch_user_friends($screen_name, $cache = TRUE) { - $url = "http://twitter.com/statuses/friends/$screen_name.xml"; - $results = drupal_http_request($url, array(), 'GET'); - return _twitter_convert_xml_to_array($results->data); + +/** + * Post a message to a Twitter.com account. + * + * @param $screen_name + * The screen name of a Twitter.com user. + * @param $password + * The password of a Twitter.com user. + * @param $text + * The text to post. Strings longer than 140 characters will be truncated by + * Twitter. + * @param $source + * A string indicating the program or site used to post the message. This is + * not cleanly supported yet by Twitter, and should probably be ignored. + * @return + * The full results of the Drupal HTTP request, including the HTTP response + * code returned by Twitter.com. + */ +function twitter_set_status($screen_name, $password, $text, $source = NULL) { + $url = "http://twitter.com/statuses/update.xml"; + + $headers = array('Authorization' => 'Basic '. base64_encode($screen_name .':'. $password), + 'Content-type' => 'application/x-www-form-urlencoded'); + $data = 'status='. urlencode($text); + if (!empty($source)) { + $data .= 'source='. urlencode($source); + } + + return drupal_http_request($url, $headers, 'POST', $data); } -function twitter_fetch_user_followers($screen_name, $password, $cache = TRUE) { - $url = "http://twitter.com/statuses/followers/$screen_name.xml"; +/** + * Fetch the full information for a Twitter.com account. + * + * This function requires an authenticated connection for the account in + * question. + * + * @param $screen_name + * The screen name of a Twitter.com user. + * @param $password + * The password of a Twitter.com user. + * @param $cache + * A boolean indicating whether the account info should be cached in the local + * site's database after it's retrieved. + * @return + * An single Twitter account. + */ +function twitter_fetch_account_info($screen_name, $password, $cache = TRUE) { + $url = "http://twitter.com/users/show/$screen_name.xml"; $headers = array('Authorization' => 'Basic '. base64_encode($screen_name .':'. $password), 'Content-type' => 'application/x-www-form-urlencoded'); $results = drupal_http_request($url, $headers, 'GET'); + + if (_twitter_request_failure($results)) { + return array(); + } + $results = _twitter_convert_xml_to_array($results->data); if ($cache) { - foreach($results as $status) { - twitter_cache_status($status); + foreach($results as $user) { + twitter_cache_account($user); } } return $results; } -function twitter_fetch_status($screen_name, $cache = TRUE) { +/** + * Fetch the latest statuses for a Twitter.com account, regardless of privacy. + * + * This function is the authenticated version of twitter_fetch_timeline(), and + * is the only way to retrieve statuses for a 'private' account. + * + * @param $screen_name + * The screen name of a Twitter.com user. + * @param $password + * The password of a Twitter.com user. + * @param $cache + * A boolean indicating whether the statuses should be cached in the local + * site's database after they're retrieved. + * @return + * An array of Twitter statuses. + * + * @see twitter_fetch_timeline() + */ +function twitter_fetch_statuses($screen_name, $password, $cache = TRUE) { $url = "http://twitter.com/statuses/$screen_name.xml"; - $results = drupal_http_request($url, array(), 'GET'); + $headers = array('Authorization' => 'Basic '. base64_encode($screen_name .':'. $password), + 'Content-type' => 'application/x-www-form-urlencoded'); + + $results = drupal_http_request($url, $headers, 'GET'); + if (_twitter_request_failure($results)) { + return array(); + } $results = _twitter_convert_xml_to_array($results->data); if ($cache && !empty($results)) { foreach($results as $status) { twitter_cache_status($status); - return $status; } + twitter_touch_account($screen_name); } + return $results; } +/** + * Fetch information about Twitter.com accounts followed by a given user. + * + * This function does not require authentication. It is mostly useful for mining + * information about connections, and locating existing Twitter friends who have + * signed up for the same Drupal site. + * + * @param $screen_name + * The screen name of a Twitter.com user. + * @return + * An array of Twitter accounts. + * + * @see twitter_fetch_followers() + */ +function twitter_fetch_friends($screen_name) { + $url = "http://twitter.com/statuses/friends/$screen_name.xml"; + $results = drupal_http_request($url, array(), 'GET'); + if (_twitter_request_failure($results)) { + return array(); + } + return _twitter_convert_xml_to_array($results->data); +} + +/** + * Fetch information about users following a given Twitter.com account. + * + * This function is mostly useful for mining information about connections, and + * locating existing Twitter friends who have also signed up for the same Drupal + * site. + * + * @param $screen_name + * The screen name of a Twitter.com user. + * @param $password + * The password of a Twitter.com user. + * @return + * An array of Twitter accounts. + * + * @see twitter_fetch_friends() + */ +function twitter_fetch_followers($screen_name, $password) { + $url = "http://twitter.com/statuses/followers/$screen_name.xml"; + $headers = array('Authorization' => 'Basic '. base64_encode($screen_name .':'. $password), + 'Content-type' => 'application/x-www-form-urlencoded'); + $results = drupal_http_request($url, $headers, 'GET'); + if (_twitter_request_failure($results)) { + return array(); + } + return _twitter_convert_xml_to_array($results->data); +} + +/** + * Attempts to authenticate a username/password on Twitter.com. + * + * @param $screen_name + * The screen name of a Twitter.com user. + * @param $password + * The password of a Twitter.com user. + * @return + * A boolean indicating success or failure. + */ function twitter_authenticate($screen_name, $password) { $url = "http://twitter.com/account/verify_credentials.xml"; $headers = array('Authorization' => 'Basic '. base64_encode($screen_name .':'. $password), @@ -128,33 +284,82 @@ function twitter_authenticate($screen_na return ($results->code == '200'); } -function twitter_fetch_user_details($screen_name, $password, $cache = TRUE) { - $url = "http://twitter.com/users/show/$screen_name.xml"; - $headers = array('Authorization' => 'Basic '. base64_encode($screen_name .':'. $password), - 'Content-type' => 'application/x-www-form-urlencoded'); - $results = drupal_http_request($url, $headers, 'GET'); - if ($results->code == 401) { - return array(); - } - $results = _twitter_convert_xml_to_array($results->data); +/** + * Internal helper function to deal cleanly with various HTTP response codes. + */ +function _twitter_request_failure($results) { + switch ($results->code) { + case '304': + // Not modified, nothing to do. + return TRUE; + case 401: + case 403: + // Twitter returns both of these for different classes of auth failure. + watchdog('twitter', 'Twitter account %screen_name could not be authenticated.', array('%screen_name' => $screen_name)); + return TRUE; + case 404: + // Probably a bogus username. + watchdog('twitter', 'Twitter account %screen_name could not be retrieved.', array('%screen_name' => $screen_name)); + return TRUE; - if ($cache) { - foreach($results as $user) { - twitter_cache_user($user); - } } - return $results; + return FALSE; } + + +/** + * Caching functions + */ + + /** - * Helper functions + * Saves Twitter account information to the database. + * + * @param $twitter_account + * A Twitter user account in array form. + * + * @see twitter_touch_account() + * @see twitter_cache_status() */ -function twitter_cache_user($twitter_user = array()) { - db_query("DELETE FROM {twitter_account} WHERE twitter_uid = %d", $twitter_user['twitter_uid']); - drupal_write_record('twitter_account', $twitter_user); +function twitter_cache_account($twitter_account = array()) { + db_query("DELETE FROM {twitter_account} WHERE twitter_uid = %d", $twitter_account['twitter_uid']); + drupal_write_record('twitter_account', $twitter_account); } + +/** + * Updates the 'last refreshed on' timestamp of a given locally cached Twitter + * account. + * + * @param $screen_name + * A Twitter screen name.. + * + * @see twitter_cache_account() + * @see twitter_cache_status() + */ +function twitter_touch_account($screen_name = '') { + db_query("UPDATE {twitter_account} SET last_refresh = %d WHERE screen_name = '%s'", time(), $screen_name); +} + + +/** + * Saves Twitter status message to the database. + * + * If the $silent parameter is set to TRUE, this function will also notify other + * modules via hook_twitter_status_update() that a new stauts has been retrieved + * and saved. This is normally set to FALSE, but may be useful when integrating + * Twitter into complex workflows. + * + * @param $status + * A Twitter status updated in array form. + * @param $silent + * A boolean indicating whether hook_twitter_status_update should be fired. + * + * @see twitter_touch_account() + * @see twitter_cache_status() + */ function twitter_cache_status($status = array(), $silent = FALSE) { db_query("DELETE FROM {twitter} WHERE twitter_id = %d", $status['twitter_id']); drupal_write_record('twitter', $status); @@ -164,6 +369,12 @@ function twitter_cache_status($status = } + + +/** + * User/account relationship code + */ + function twitter_get_user_accounts($uid) { $sql = "SELECT *, tu.screen_name AS screen_name FROM {twitter_user} tu LEFT JOIN {twitter_account} ta ON (tu.screen_name = ta.screen_name) WHERE tu.uid = %d"; $args = array($uid); @@ -186,7 +397,7 @@ function twitter_user_save($user = array 'announce_types' => array(), 'announce_message' => '', ); - + $user['announce_types'] = serialize($user['announce_types']); if (db_result(db_query("SELECT 1 FROM {twitter_user} WHERE uid = %d AND screen_name = '%s'", $user['uid'], $user['screen_name']))) { drupal_write_record('twitter_user', $user, array('uid', 'screen_name')); @@ -196,7 +407,7 @@ function twitter_user_save($user = array } $user['announce_types'] = unserialize($user['announce_types']); - twitter_fetch_user_details($user['screen_name'], $user['password']); + twitter_fetch_account_info($user['screen_name'], $user['password']); } function twitter_user_delete($uid, $screen_name = NULL) { @@ -209,6 +420,7 @@ function twitter_user_delete($uid, $scre db_query($sql, $args); } + /** * Internal XML munging code */ @@ -254,9 +466,6 @@ function _twitter_convert_user($user) { if (!empty($result['status']) && is_object($result['status'])) { $result['status'] = _twitter_convert_status($result['status']); } - else { - $result['twitter_uid'] = NULL; - } return $result; } Index: twitter.install =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/twitter/twitter.install,v retrieving revision 1.1 diff -u -p -r1.1 twitter.install --- twitter.install 8 Jun 2008 04:48:33 -0000 1.1 +++ twitter.install 8 Jun 2008 22:35:07 -0000 @@ -55,23 +55,34 @@ function twitter_schema() { 'type' => 'int', 'not null' => TRUE ), - 'name' => array( + 'screen_name' => array( 'description' => t("The unique login name of the {twitter_account} user."), 'type' => 'varchar', + 'length' => 255 + ), + 'name' => array( + 'description' => t("The full name of the {twitter_account} user."), + 'type' => 'varchar', 'length' => 64, 'not null' => TRUE, 'default' => '' ), - 'screen_name' => array( - 'description' => t("The full name of the {twitter_account} user."), + 'description' => array( + 'description' => t("The description/biography associated with the {twitter_account}."), 'type' => 'varchar', 'length' => 255 ), - 'description' => array( - 'description' => t("The description/biography associated with the {twitter_account}."), + 'location' => array( + 'description' => t("The location of the {twitter_account}'s owner."), 'type' => 'varchar', 'length' => 255 ), + 'followers_count' => array( + 'description' => t("The number of users following this {twitter_account}."), + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0 + ), 'profile_image_url' => array( 'description' => t("The url of the {twitter_account}'s profile image."), 'type' => 'varchar', @@ -92,7 +103,7 @@ function twitter_schema() { 'description' => t("A UNIX timestamp marking the date Twitter statuses were last fetched on."), 'type' => 'int', 'not null' => TRUE - ), + ), ), 'indexes' => array('screen_name' => array('screen_name')), 'primary key' => array('twitter_uid'), @@ -114,9 +125,16 @@ function twitter_schema() { 'description' => t("The password for the Twitter account."), 'type' => 'varchar', 'length' => 64 - ), + ), + 'import' => array( + 'description' => t("Boolean flag indicating whether the {twitter_user}'s posts should be pulled in by the site."), + 'type' => 'int', + 'not null' => TRUE, + 'default' => 1 + ), ), 'primary key' => array('uid', 'screen_name'), + 'indexes' => array('screen_name' => array('screen_name'), 'uid' => array('uid'), 'update' => array('update')), ); return $schema; @@ -134,10 +152,34 @@ function twitter_install() { * Previous versions of the Twitter module had no database schema. * We're safe just running the basic install for update_1. */ -function twitter_update_1() { +function twitter_update_6000() { twitter_install(); } +function twitter_update_6001() { + $ret = array(); + $attributes = array( + 'description' => t("Boolean flag indicating whether the {twitter_user}'s posts should be pulled in by the site."), + 'not null' => TRUE, + 'default' => 1, + ); + db_add_column($ret, 'twitter_user', 'import', 'int', $attributes); + + $attributes = array( + 'description' => t("The location of the {twitter_account}'s owner."), + 'length' => 255 + ); + db_add_column($ret, 'twitter_account', 'location', 'varchar(255)', $attributes); + + $attributes = array( + 'description' => t("The number of users following this {twitter_account}."), + 'default' => 0 + ); + db_add_column($ret, 'twitter_account', 'followers_count', 'int', $attributes); + + return $ret; +} + function twitter_uninstall() { // Remove tables. drupal_uninstall_schema('twitter'); Index: twitter.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/twitter/twitter.module,v retrieving revision 1.2 diff -u -p -r1.2 twitter.module --- twitter.module 8 Jun 2008 04:48:33 -0000 1.2 +++ twitter.module 8 Jun 2008 22:35:07 -0000 @@ -25,7 +25,7 @@ function twitter_menu() { 'file' => 'twitter.pages.inc', 'type' => MENU_LOCAL_TASK, ); - + return $items; } @@ -65,12 +65,12 @@ function twitter_form_alter(&$form, $for $form['twitter'] += $twitter_form; $form['twitter']['status']['#default_value'] = variable_get('twitter_default_format', 'New post: !title (!url)'); $form['twitter']['status']['#description'] = t('The given text will be posted to twitter.com. You can use !url, !title and !user as replacement text.'); - } + } } function twitter_nodeapi(&$node, $op, $a1) { module_load_include('inc', 'twitter'); - + switch ($op) { case 'insert': case 'update': @@ -86,4 +86,50 @@ function twitter_nodeapi(&$node, $op, $a } break; } -} \ No newline at end of file +} + +/** + * Implementation of hook_cron() + * + * Imports new Twitter statuses for site users, and deletes expired tweets. + */ +function twitter_cron() { + if (!variable_get('twitter_import', TRUE)) { + return; + } + + module_load_include('inc', 'twitter'); + + // Pull up a list of Twitter accounts that are flagged for updating, + // sorted by how long it's been since we last updated them. This ensures + // that the most out-of-date accounts get updated first. + + $sql = "SELECT tu.screen_name, tu.password, ta.protected FROM {twitter_user} tu "; + $sql .= "LEFT JOIN {twitter_account} ta ON tu.screen_name = ta.screen_name "; + $sql .= "WHERE tu.import = 1 ORDER BY ta.last_refresh ASC"; + + $results = db_query_range($sql, 0, 20); + while ($account = db_fetch_array($results)) { + // Use the 'cheaper' unauthenticated version if the account isn't protected. + if (empty($account['protected'])) { + $statuses = twitter_fetch_timeline($account['screen_name']); + } + else { + $statuses = twitter_fetch_statuses($account['screen_name'], $account['password']); + } + + // If we got results back, update the account information with the latest + // follower count, location, user picture, etc. Also, touch the account's + // last_refreshed timestamp so it won't get thrashed before other, staler + // accounts. + if (!empty($statuses)) { + twitter_cache_account($statuses[0]['account']); + } + twitter_touch_account($account['screen_name']); + } + + // Nuke old statuses. + if ($age = variable_get('twitter_expire', 0)) { + db_query('DELETE {twitter} WHERE created_time < %d', time() - $age); + } +} Index: twitter.pages.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/twitter/twitter.pages.inc,v retrieving revision 1.1 diff -u -p -r1.1 twitter.pages.inc --- twitter.pages.inc 8 Jun 2008 04:48:33 -0000 1.1 +++ twitter.pages.inc 8 Jun 2008 22:35:07 -0000 @@ -6,34 +6,66 @@ */ function twitter_admin_form() { $form = array(); - - $form['twitter_default_format'] = array( + + $form['import'] = array( + '#type' => 'fieldset', + '#title' => t('Twitter import'), + '#description' => t('Import and display the Twitter statuses of site users who have entered their Twitter account information.'), + ); + + $form['import']['twitter_import'] = array( + '#type' => 'checkbox', + '#title' => t('Import Twitter statuses'), + '#default_value' => variable_get('twitter_import', TRUE), + ); + + $periods = array(0 => t('Never')); + $periods += drupal_map_assoc(array(604800, 2419200, 7257600, 31449600), 'format_interval'); + $form['import']['twitter_expire'] = array( + '#type' => 'select', + '#title' => t('Delete old statuses'), + '#default_value' => variable_get('amazon_refresh_schedule', 0), + '#options' => $periods + ); + + $form['posting'] = array( + '#type' => 'fieldset', + '#title' => t('Twitter posting'), + '#description' => t('Users with proper permissions will be given the option to post announcements to their Twitter accounts when they create new content.'), + ); + + $form['posting']['twitter_types'] = array( + '#type' => 'checkboxes', + '#title' => t('Node types'), + '#options' => node_get_types('names'), + '#default_value' => variable_get('twitter_types', array('story' => 'story', 'blog' => 'blog')), + ); + + $form['posting']['twitter_default_format'] = array( '#type' => 'textfield', '#title' => t('Default format string'), '#maxlength' => 140, - '#description' => t('The given text will be posted to twitter.com. You can use !url, !title and !user as replacement text.') + '#description' => t('The given text will be posted to twitter.com. You can use !url, !title and !user as replacement text.'), + '#default_value' => variable_get('twitter_default_format', 'New post: !title (!url)'), ); - - $form['twitter_types'] = array( - - ); - - return system_settings_form($form); + + return system_settings_form($form); } function twitter_user_settings($account) { module_load_include('inc', 'twitter'); - + $twitter_accounts = twitter_get_user_accounts($account->uid); - - $header = array('', t('Name'), t('Description')); + + $header = array('', t('Name'), t('Description'), t('Import')); $rows = array(); - + foreach ($twitter_accounts as $twitter_account) { $rows[] = array( - '', + theme('image', $twitter_account['profile_image_url'], '', '', array(), FALSE), $twitter_account['screen_name'], $twitter_account['description'], + empty($twitter_account['import']) ? t('No') : t('Yes'), ); } @@ -47,7 +79,7 @@ function twitter_add_account($form_state global $user; $account = $user; } - + $form['uid'] = array( '#type' => 'value', '#value' => $account->uid, @@ -63,17 +95,23 @@ function twitter_add_account($form_state '#title' => t('Password'), ); + $form['import'] = array( + '#type' => 'checkbox', + '#title' => t('Import statuses from this account'), + '#default_value' => TRUE, + ); + $form['submit'] = array( '#type' => 'submit', '#value' => t('Add account'), ); - return $form; + return $form; } function twitter_add_account_validate($form, &$form_state) { module_load_include('inc', 'twitter'); - + $verify = FALSE; $pass = $form_state['values']['password']; @@ -93,7 +131,7 @@ function twitter_add_account_validate($f function twitter_add_account_submit($form, &$form_state) { module_load_include('inc', 'twitter'); - + if (!empty($form_state['values']['screen_name'])) { twitter_user_save($form_state['values']); } Index: twitter.views.inc =================================================================== RCS file: twitter.views.inc diff -N twitter.views.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ twitter.views.inc 8 Jun 2008 22:35:07 -0000 @@ -0,0 +1,340 @@ + 'twitter_id', + 'title' => t('Twitter message'), + 'help' => t('Stores Twitter status messages.'), + 'weight' => 10, + ); + + // Twitter screen name + $data['twitter']['screen_name'] = array( + 'title' => t('Login name'), + 'help' => t('The login account of the Twitter user.'), + 'field' => array( + 'handler' => 'views_handler_field', + 'click sortable' => TRUE, + ), + 'filter' => array( + 'handler' => 'views_handler_filter_string', + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + 'argument' => array( + 'handler' => 'views_handler_argument_string', + ), + ); + + // Twitter message timestamp + $data['twitter']['created_time'] = array( + 'title' => t('Created time'), + 'help' => t('The time the Twitter message was posted.'), + 'field' => array( + 'handler' => 'views_handler_field_date', + 'click sortable' => TRUE, + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_date', + ), + ); + + // Twitter text + $data['twitter']['text'] = array( + 'title' => t('Message text'), + 'help' => t('The text of the Twitter message.'), + 'field' => array( + 'handler' => 'views_handler_field_xss', + 'click sortable' => TRUE, + ), + 'filter' => array( + 'handler' => 'views_handler_filter_string', + ), + ); + + // Twitter source + $data['twitter']['source'] = array( + 'title' => t('Source'), + 'help' => t('The name of the application that posted the Twitter message.'), + 'field' => array( + 'handler' => 'views_handler_field_xss', + 'click sortable' => TRUE, + ), + 'filter' => array( + 'handler' => 'views_handler_filter_string', + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + ); + + + + + $data['twitter_account']['table']['group'] = t('Twitter'); + + $data['twitter_account']['table']['join'] = array( + 'twitter' => array( + 'left_field' => 'screen_name', + 'field' => 'screen_name', + ), + 'users' => array( + 'field' => 'screen_name', + 'left_table' => 'twitter_user', + 'left_field' => 'screen_name', + ), + ); + + // Twitter screen name + $data['twitter_account']['screen_name'] = array( + 'title' => t('Login name'), + 'help' => t('The login account of the Twitter user.'), + 'field' => array( + 'handler' => 'views_handler_field', + 'click sortable' => TRUE, + ), + 'filter' => array( + 'handler' => 'views_handler_filter_string', + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + 'argument' => array( + 'handler' => 'views_handler_argument_string', + ), + ); + + + // Twitter account full name + $data['twitter_account']['name'] = array( + 'title' => t('Full name'), + 'help' => t('The full name Twitter account user.'), + 'field' => array( + 'handler' => 'views_handler_field', + 'click sortable' => TRUE, + ), + 'filter' => array( + 'handler' => 'views_handler_filter_string', + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + 'argument' => array( + 'handler' => 'views_handler_argument_string', + ), + ); + + // Twitter account description + $data['twitter_account']['description'] = array( + 'title' => t('Description'), + 'help' => t('The description of the Twitter account.'), + 'field' => array( + 'handler' => 'views_handler_field', + 'click sortable' => TRUE, + ), + 'filter' => array( + 'handler' => 'views_handler_field_xss', + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + ); + + // Twitter account location + $data['twitter_account']['location'] = array( + 'title' => t('Location'), + 'help' => t('The location of the Twitter account.'), + 'field' => array( + 'handler' => 'views_handler_field', + 'click sortable' => TRUE, + ), + 'filter' => array( + 'handler' => 'views_handler_field_xss', + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + ); + + // Twitter account description + $data['twitter_account']['followers_count'] = array( + 'title' => t('Location'), + 'help' => t('The number of users following this Twitter account.'), + 'field' => array( + 'handler' => 'views_handler_field_numeric', + 'click sortable' => TRUE, + ), + 'filter' => array( + 'handler' => 'views_handler_filter_numeric', + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + ); + + // Twitter account profile image + $data['twitter_account']['profile_image_url'] = array( + 'title' => t('Profile image'), + 'help' => t('The image used by the Twitter account.'), + 'field' => array( + 'handler' => 'twitter_views_handler_profile_image', + 'click sortable' => TRUE, + ), + ); + + // Twitter account url + $data['twitter_account']['url'] = array( + 'title' => t('URL'), + 'help' => t('The URL given by the Twitter account user.'), + 'field' => array( + 'handler' => 'views_handler_field_url', + 'click sortable' => TRUE, + ), + 'filter' => array( + 'handler' => 'views_handler_filter_string', + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + ); + + // Twitter account protected + $data['twitter_account']['protected'] = array( + 'title' => t('Protected status'), + 'help' => t('Whether posts from this Twitter account should be visible to the general public.'), + 'field' => array( + 'handler' => 'views_handler_field_boolean', + 'click sortable' => TRUE, + ), + 'filter' => array( + 'handler' => 'views_handler_filter_boolean_operator', + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + ); + + // Twitter message timestamp + $data['twitter_account']['last_refresh'] = array( + 'title' => t('Last refresh'), + 'help' => t('The time the Twitter account statuses were retrieved.'), + 'field' => array( + 'handler' => 'views_handler_field_date', + 'click sortable' => TRUE, + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + 'filter' => array( + 'handler' => 'views_handler_filter_date', + ), + ); + + + $data['twitter_user']['table']['group'] = t('Twitter'); + + $data['twitter_user']['table']['join'] = array( + 'users' => array( + 'left_field' => 'uid', + 'field' => 'uid', + ), + 'twitter_account' => array( + 'left_field' => 'screen_name', + 'field' => 'screen_name', + ), + 'twitter' => array( + 'left_table' => 'twitter_account', + 'left_field' => 'screen_name', + 'field' => 'screen_name', + ), + ); + + // Twitter account description + $data['twitter_user']['uid'] = array( + 'title' => t('User ID'), + 'help' => t('The UID of the Twitter account.'), + ); + + // Twitter account description + $data['twitter_user']['screen_name'] = array( + 'title' => t('Screen name'), + 'help' => t('The screen name of the Twitter account.'), + ); + + // Twitter account protected + $data['twitter_user']['import'] = array( + 'title' => t('Import status'), + 'help' => t('Whether posts from this Twitter account should be imported automatically.'), + 'field' => array( + 'handler' => 'views_handler_field_boolean', + 'click sortable' => TRUE, + ), + 'filter' => array( + 'handler' => 'views_handler_filter_boolean_operator', + ), + 'sort' => array( + 'handler' => 'views_handler_sort', + ), + ); + + + return $data; +} + + +function twitter_views_data_alter(&$data) { + $data['users']['table']['join']['twitter'] = array( + 'left_table' => 'twitter_user', + 'left_field' => 'uid', + 'field' => 'uid', + ); + $data['users']['table']['join']['twitter_account'] = array( + 'left_table' => 'twitter_user', + 'left_field' => 'uid', + 'field' => 'uid', + ); + $data['users']['table']['join']['twitter_user'] = array( + 'left_field' => 'uid', + 'field' => 'uid', + ); +} + + +/** + * Field handler to provide simple renderer that turns a URL into a clickable link. + */ +class twitter_views_handler_profile_image extends views_handler_field { + function render($values) { + $value = $values->{$this->field_alias}; + return theme('image', $value, '', '', array(), FALSE); + } +} + + +/** + * @} + */ Index: twitter.views_default.inc =================================================================== RCS file: twitter.views_default.inc diff -N twitter.views_default.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ twitter.views_default.inc 8 Jun 2008 22:35:07 -0000 @@ -0,0 +1,211 @@ +name = 'tweets'; + $view->description = 'Displays Twitter.com status messages for users who have associated Twitter accounts.'; + $view->tag = ''; + $view->view_php = ''; + $view->base_table = 'twitter'; + $view->is_cacheable = '0'; + $view->api_version = 2; + $view->disabled = FALSE; // Edit this to true to make a default view disabled initially + $view->display = array(); + $display = new views_display; + $display->id = 'default'; + $display->display_title = 'Tweets'; + $display->display_plugin = 'default'; + $display->position = '1'; + $display->display_options = array( + 'sorts' => array( + 'created_time' => array( + 'order' => 'DESC', + 'id' => 'created_time', + 'table' => 'twitter', + 'field' => 'created_time', + 'relationship' => 'none', + ), + ), + 'fields' => array( + 'profile_image_url' => array( + 'label' => '', + 'exclude' => 0, + 'id' => 'profile_image_url', + 'table' => 'twitter_account', + 'field' => 'profile_image_url', + 'relationship' => 'none', + ), + 'text' => array( + 'label' => '', + 'exclude' => 0, + 'id' => 'text', + 'table' => 'twitter', + 'field' => 'text', + 'relationship' => 'none', + ), + 'created_time' => array( + 'label' => '', + 'date_format' => 'time ago', + 'custom_date_format' => '', + 'exclude' => 0, + 'id' => 'created_time', + 'table' => 'twitter', + 'field' => 'created_time', + 'relationship' => 'none', + ), + ), + 'filters' => array( + 'protected' => array( + 'operator' => '=', + 'value' => 0, + 'group' => '0', + 'exposed' => FALSE, + 'expose' => array( + 'operator' => FALSE, + 'label' => '', + ), + 'id' => 'protected', + 'table' => 'twitter_account', + 'field' => 'protected', + 'relationship' => 'none', + ), + ), + 'style_plugin' => 'table', + 'style_options' => array( + 'grouping' => '', + 'override' => 1, + 'sticky' => 0, + 'order' => 'asc', + 'columns' => array( + 'profile_image_url' => 'profile_image_url', + 'text' => 'text', + 'created_time' => 'text', + ), + 'info' => array( + 'profile_image_url' => array( + 'sortable' => 0, + 'separator' => '', + ), + 'text' => array( + 'sortable' => 0, + 'separator' => ' — ', + ), + 'created_time' => array( + 'sortable' => 0, + 'separator' => '', + ), + ), + 'default' => '-1', + ), + 'use_pager' => 'mini', + 'pager_element' => 0, + 'arguments' => array( + 'uid' => array( + 'default_action' => 'default', + 'style_plugin' => 'default_summary', + 'style_options' => array(), + 'wildcard' => 'all', + 'wildcard_substitution' => 'All author', + 'title' => '%1\'s tweets', + 'default_argument_type' => 'user', + 'default_argument' => '', + 'validate_type' => 'none', + 'validate_fail' => 'not found', + 'break_phrase' => 0, + 'not' => 0, + 'id' => 'uid', + 'table' => 'users', + 'field' => 'uid', + 'relationship' => 'none', + 'default_argument_user' => 1, + 'default_argument_fixed' => '', + 'default_argument_php' => '', + 'validate_argument_node_type' => array( + 'poll' => 0, + 'page' => 0, + 'review' => 0, + 'story' => 0, + ), + 'validate_argument_node_access' => 0, + 'validate_argument_nid_type' => 'nid', + 'validate_argument_vocabulary' => array(), + 'validate_argument_type' => 'tid', + 'validate_argument_php' => '', + ), + ), + ); + $view->display['default'] = $display; + $display = new views_display; + $display->id = 'page'; + $display->display_title = 'Page'; + $display->display_plugin = 'page'; + $display->position = '2'; + $display->display_options = array( + 'menu' => array( + 'type' => 'tab', + 'title' => 'Twitter', + 'weight' => '1', + ), + 'path' => 'user/%/tweets', + ); + $view->display['page'] = $display; + $display = new views_display; + $display->id = 'block'; + $display->display_title = 'Block'; + $display->display_plugin = 'block'; + $display->position = '3'; + $display->display_options = array( + 'fields' => array( + 'text' => array( + 'label' => '', + 'exclude' => 0, + 'id' => 'text', + 'table' => 'twitter', + 'field' => 'text', + 'relationship' => 'none', + ), + 'created_time' => array( + 'label' => '', + 'date_format' => 'time ago', + 'custom_date_format' => '', + 'exclude' => 0, + 'id' => 'created_time', + 'table' => 'twitter', + 'field' => 'created_time', + 'relationship' => 'none', + ), + ), + 'defaults' => array( + 'fields' => FALSE, + 'style_plugin' => FALSE, + 'style_options' => FALSE, + 'row_plugin' => FALSE, + 'row_options' => FALSE, + 'items_per_page' => FALSE, + 'offset' => FALSE, + 'use_pager' => FALSE, + 'pager_element' => FALSE, + 'use_more' => FALSE, + ), + 'style_plugin' => 'list', + 'style_options' => array(), + 'row_plugin' => 'fields', + 'row_options' => array( + 'inline' => array( + 'text' => 'text', + 'created_time' => 'created_time', + ), + 'separator' => ' — ', + ), + 'items_per_page' => 5, + 'offset' => 0, + 'use_pager' => '0', + 'pager_element' => 0, + 'use_more' => 1, + 'block_description' => 'User Tweets', + ); + $view->display['block'] = $display; + + return array('tweets' => $view); +}