View source
<?php
define('TWITTER_HOST', 'https://twitter.com');
define('TWITTER_API', 'https://api.twitter.com');
define('TWITTER_SEARCH', 'https://search.twitter.com');
define('TWITTER_TINYURL', 'http://tinyurl.com');
define('TWITTER_OAUTH_CALLBACK_URL', 'twitter/oauth');
function twitter_help($path, $arg) {
switch ($path) {
case 'admin/help#twitter':
$output = '';
$output .= '<p>' . t('This module provides API integration with the Twitter microblogging service.') . '</p>';
$output .= '<p>' . t('For more information, please visit the official <a href="@url">project page</a> on Drupal.org.', array(
'@url' => 'https://www.drupal.org/project/twitter',
)) . '</p>';
return $output;
}
}
function twitter_entity_info() {
return array(
'twitter_status' => array(
'label' => t('Twitter Status'),
'module' => 'twitter',
'entity class' => 'TwitterStatus',
'controller class' => 'EntityAPIController',
'base table' => 'twitter',
'entity keys' => array(
'id' => 'twitter_id',
),
'label callback' => 'entity_class_label',
'uri callback' => 'entity_class_uri',
),
'twitter_account' => array(
'label' => t('Twitter Account'),
'module' => 'twitter',
'entity class' => 'TwitterAccount',
'controller class' => 'EntityAPIController',
'base table' => 'twitter_account',
'entity keys' => array(
'id' => 'twitter_uid',
'label' => 'screen_name',
),
'uri callback' => 'entity_class_uri',
),
);
}
function twitter_menu() {
$items[variable_get('twitter_oauth_callback_url', TWITTER_OAUTH_CALLBACK_URL)] = array(
'title' => 'Twitter OAuth',
'access callback' => TRUE,
'page callback' => 'drupal_get_form',
'page arguments' => array(
'twitter_oauth_callback',
),
'type' => MENU_CALLBACK,
'file' => 'twitter.pages.inc',
);
$items['admin/config/services/twitter'] = array(
'title' => 'Twitter',
'description' => 'Twitter accounts and settings.',
'page callback' => 'twitter_user_settings',
'access arguments' => array(
'administer twitter accounts',
),
'file' => 'twitter.pages.inc',
);
$items['admin/config/services/twitter/default'] = array(
'title' => 'Twitter',
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$items['admin/config/services/twitter/settings'] = array(
'title' => 'Settings',
'description' => 'Twitter settings.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'twitter_admin_form',
),
'access arguments' => array(
'administer twitter',
),
'file' => 'twitter.pages.inc',
'type' => MENU_LOCAL_TASK,
);
$items['user/%user/edit/twitter'] = array(
'title' => 'Twitter accounts',
'page callback' => 'twitter_user_settings',
'page arguments' => array(
1,
),
'access callback' => 'twitter_account_access',
'access arguments' => array(
1,
),
'weight' => 10,
'file' => 'twitter.pages.inc',
'type' => MENU_LOCAL_TASK,
);
return $items;
}
function twitter_permission() {
return array(
'administer twitter' => array(
'title' => t('Administer Twitter configuration'),
),
'add twitter accounts' => array(
'title' => t('Add Twitter accounts'),
),
'add authenticated twitter accounts' => array(
'title' => t('Add authenticated Twitter accounts'),
),
'administer twitter accounts' => array(
'title' => t('Administer Twitter accounts'),
),
);
}
function twitter_account_access($account) {
global $user;
if ($user->uid == $account->uid && (user_access('add twitter accounts') || user_access('add authenticated twitter accounts'))) {
return TRUE;
}
if (user_access('administer users')) {
return TRUE;
}
return FALSE;
}
function twitter_theme() {
return array(
'twitter_account_list_form' => array(
'render element' => 'form',
),
'twitter_status' => array(
'variables' => array(
'status' => NULL,
'author' => NULL,
'reply' => NULL,
'retweet' => NULL,
'favorite' => NULL,
),
'template' => 'twitter_status',
'path' => drupal_get_path('module', 'twitter'),
),
'twitter_user_accounts' => array(
'variables' => array(
'accounts' => array(),
),
),
);
}
function template_preprocess_twitter_status(&$variables) {
if (isset($variables['status'])) {
$status =& $variables['status'];
$time_diff = REQUEST_TIME - $status->created_time;
$status->time_ago = t('%time ago', array(
'%time' => format_interval($time_diff, 2),
));
$status->text = twitter_filter_message($status->text);
}
}
function theme_twitter_user_accounts($variables) {
$accounts = $variables['accounts'];
$items = array();
module_load_include('inc', 'twitter');
foreach ($accounts as $twitter_account) {
if (module_exists('views') && twitter_tweets($twitter_account->screen_name)) {
$items[] = l('@' . $twitter_account->screen_name, 'tweets/' . $twitter_account->screen_name);
}
else {
$items[] = _twitter_user_profile($twitter_account->screen_name);
}
}
return theme('item_list', array(
'items' => $items,
));
}
function twitter_shorten_url($url) {
if (module_exists('shorten')) {
return shorten_url($url);
}
else {
$response = drupal_http_request(variable_get('twitter_tinyurl', TWITTER_TINYURL) . "/api-create.php?url=" . $url);
if ($response->code == 200) {
return $response->data;
}
else {
return $url;
}
}
}
function twitter_cron() {
if (!variable_get('twitter_import', TRUE)) {
watchdog('twitter', 'The Twitter module is configured to not download tweets right now.');
return;
}
module_load_include('inc', 'twitter');
$twitter = twitter_connect(NULL, TRUE, TRUE);
if (empty($twitter)) {
watchdog('twitter', 'Unable to find an authenticated account to do API calls from.');
return FALSE;
}
watchdog('twitter', 'Starting to download tweets.');
$query = new EntityFieldQuery();
$query
->entityCondition('entity_type', 'twitter_account')
->propertyCondition('uid', 0, '>')
->propertyCondition('import', 1)
->propertyOrderBy('last_refresh')
->range(0, 20);
$result = $query
->execute();
$ids = !empty($result['twitter_account']) ? array_keys($result['twitter_account']) : array();
if (count($ids)) {
$twitter_accounts = entity_load('twitter_account', $ids);
try {
foreach ($twitter_accounts as $twitter_account) {
twitter_fetch_user_timeline($twitter_account->twitter_uid);
if ($twitter_account
->is_auth() && $twitter_account->mentions) {
twitter_fetch_mentions_timeline($twitter_account->twitter_uid);
}
$twitter_account->last_refresh = REQUEST_TIME;
twitter_account_save($twitter_account);
}
} catch (TwitterException $e) {
watchdog('twitter', 'There was a problem loading tweets during cron.');
}
}
if ($age = variable_get('twitter_expire', 0)) {
$query = new EntityFieldQuery();
$query
->entityCondition('entity_type', 'twitter_status')
->propertyCondition('created_time', REQUEST_TIME - $age, '<');
$result = $query
->execute();
entity_delete_multiple('twitter_status', array_keys($result['twitter_status']));
}
watchdog('twitter', 'Finished downloading tweets.');
}
function twitter_filter_info() {
$filters['twitter_username'] = array(
'title' => t('Twitter @username converter'),
'description' => t('Converts Twitter-style @usernames into links to Twitter account pages.'),
'process callback' => '_twitter_filter_username',
'tips callback' => '_twitter_filter_tip_username',
);
$filters['twitter_hashtag'] = array(
'title' => t('Twitter #hashtag converter'),
'description' => t('Converts Twitter-style #hashtags into links to twitter.com. Note: this converts all text prefixed by a "#" symbol into a hashtag link, so it can cause problems with other text.'),
'process callback' => '_twitter_filter_hashtag',
'tips callback' => '_twitter_filter_tip_hashtag',
);
$filters['twitter_links'] = array(
'title' => t('Twitter link converter'),
'description' => t('Makes links in Twitter messages to be opened in new windows and adds rel="nofollow" so these links do not penalize SEO.'),
'process callback' => '_twitter_filter_link',
'tips callback' => '_twitter_filter_tip_link',
);
$filters['twitter_embed'] = array(
'title' => t('Embed Tweets'),
'description' => t('Converts URLs for Twitter status updates into embedded Tweets. Should be sorted after the "Limit allowed HTML tags" filter, if used.'),
'process callback' => '_twitter_filter_embed_tweet',
'tips callback' => '_twitter_filter_tip_embed_tweet',
);
return $filters;
}
function _twitter_filter_tip_username($filter, $format, $long = FALSE) {
return t('Twitter-style @usernames are linked to their Twitter account pages.');
}
function _twitter_filter_tip_hashtag($format, $long = FALSE) {
return t('Twitter-style #hashtags are linked to !url.', array(
'!url' => '<a href="https://search.twitter.com/">search.twitter.com</a>',
));
}
function _twitter_filter_tip_link($filter, $format, $long = FALSE) {
return t('Twitter message links are opened in new windows and rel="nofollow" is added.');
}
function _twitter_filter_tip_embed_tweet($filter, $format, $long = FALSE) {
return t('Links to Twitter status updates are converted to Embedded Tweets.');
}
function _twitter_filter_username($text, $filter = NULL) {
$prefix = '@';
$destination = variable_get('twitter_host', TWITTER_HOST) . '/';
return _twitter_filter_text($text, $prefix, $destination);
}
function _twitter_filter_hashtag($text, $filter = NULL) {
$prefix = '#';
$destination = variable_get('twitter_search', TWITTER_SEARCH) . '/search?q=%23';
return _twitter_filter_text($text, $prefix, $destination);
}
function _twitter_filter_link($text, $filter = NULL) {
return str_replace('<a ', '<a target="_blank" rel="nofollow" class="twitter-timeline-link" ', $text);
}
function _twitter_filter_text($text, $prefix, $destination, $class = '') {
$match = '/(?<!\\w)' . preg_quote($prefix, '/') . '(\\w+)/ui';
if (!empty($class)) {
$class = " class=\"{$class}\"";
}
$replacement = '<a href="' . $destination . '$1"' . $class . '>' . $prefix . '$1</a>';
return preg_replace($match, $replacement, $text);
}
function twitter_filter_message($message, $usernames = TRUE, $hashtags = TRUE, $attributes = TRUE, $urls = TRUE) {
if ($usernames) {
$message = _twitter_filter_username($message);
}
if ($hashtags) {
$message = _twitter_filter_hashtag($message);
}
if ($attributes) {
$message = _twitter_filter_link($message);
}
if ($urls) {
$filter = new stdClass();
$filter->settings = array(
'filter_url_length' => 496,
);
$message = _filter_url($message, $filter);
}
return filter_xss($message);
}
function _twitter_filter_embed_tweet($text, $filter) {
module_load_include('inc', 'twitter');
$ignore_tags = 'a|script|style|code|pre';
$chunks = preg_split('/(<.+?>)/is', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
$chunk_type = 'text';
$open_tag = '';
foreach ($chunks as $i => $chunk) {
if ($chunk_type == 'text') {
if ($open_tag == '') {
$tweets = array();
preg_match_all('/https?:\\/\\/(www\\.)?twitter.com\\/.+?\\/status(es)?\\/(.*)/i', $chunks[$i], $tweets, PREG_SET_ORDER);
foreach ($tweets as $tweet) {
$url = $tweet[0];
$id = $tweet[3];
$embed = twitter_statuses_oembed($id);
$chunks[$i] = str_replace($url, $embed['html'], $chunks[$i]);
}
}
$chunk_type = 'tag';
}
else {
if ($open_tag == '') {
if (preg_match("`<({$ignore_tags})(?:\\s|>)`i", $chunks[$i], $matches)) {
$open_tag = $matches[1];
}
}
else {
if (preg_match("`<\\/{$open_tag}>`i", $chunks[$i], $matches)) {
$open_tag = '';
}
}
$chunk_type = 'text';
}
}
return implode($chunks);
}
function twitter_views_api() {
return array(
'api' => 2,
);
}
function twitter_user_load($accounts) {
foreach ($accounts as $twitter_uid => $account) {
$accounts[$twitter_uid]->twitter_accounts = module_invoke_all('twitter_accounts', $account);
}
}
function twitter_twitter_accounts($account) {
if ($account->uid == 0) {
return array();
}
$query = new EntityFieldQuery();
$query
->entityCondition('entity_type', 'twitter_account')
->propertyCondition('uid', $account->uid);
$result = $query
->execute();
$ids = !empty($result['twitter_account']) ? array_keys($result['twitter_account']) : array();
$twitter_accounts = entity_load('twitter_account', $ids);
return $twitter_accounts;
}
function twitter_user_delete($account) {
$twitter_accounts = twitter_twitter_accounts($account);
entity_delete_multiple('twitter_account', array_keys($twitter_accounts));
}
function twitter_user_view_alter(&$build) {
$user = $build['#account'];
if (!empty($user->twitter_accounts)) {
$build['twitter'] = array(
'#type' => 'user_profile_item',
'#title' => t('Twitter accounts'),
'#markup' => theme('twitter_user_accounts', array(
'accounts' => $user->twitter_accounts,
)),
'#weight' => 10,
);
}
}
function twitter_api_keys() {
$key = variable_get('twitter_consumer_key');
$secret = variable_get('twitter_consumer_secret');
return !(empty($key) && empty($secret));
}
function _twitter_user_profile($screen_name) {
return l('@' . $screen_name, TWITTER_HOST . '/' . $screen_name);
}
function _twitter_status_url($status) {
if ($status) {
return TWITTER_HOST . '/' . $status->user->screen_name . '/status/' . $status->id;
}
}
class TwitterStatus extends Entity {
public $created_at;
public $id;
public $text;
public $source;
public $truncated;
public $favorited;
public $in_reply_to_status_id;
public $in_reply_to_user_id;
public $in_reply_to_screen_name;
public $user;
public $retweeted_status;
public $retweet_count;
public function __construct($values = array()) {
if (isset($values['user'])) {
$this->user = new TwitterAccount($values['user']);
unset($values['user']);
}
if (isset($values['retweeted_status'])) {
$this->retweeted_status = new TwitterStatus($values['retweeted_status']);
}
parent::__construct($values, 'twitter_status');
}
protected function defaultLabel() {
$label = t('No label defined for this tweet.');
if (isset($this->text)) {
$text = truncate_utf8($this->text, 140, TRUE, TRUE);
if (isset($this->screen_name)) {
$screen_name = t('Tweet by @screen_name', array(
'@screen_name' => $this->screen_name,
));
}
if (isset($this->created_time)) {
$created_time = t('on @created_time', array(
'@created_time' => format_date($this->created_time),
));
}
$label = $text;
if (!empty($screen_name)) {
if (!empty($created_time)) {
$label = $screen_name . ' ' . $created_time . ': ' . $text;
}
else {
$label = $screen_name . ': ' . $text;
}
}
}
elseif (isset($this->screen_name)) {
$label = t('Tweet by @screen_name.', array(
'@screen_name' => $this->screen_name,
));
}
return $label;
}
}
class TwitterAccount extends Entity {
public function __construct($values = array()) {
if (!empty($values['id'])) {
$values['twitter_uid'] = $values['id'];
unset($values['id']);
}
if (!empty($values['created_at']) && ($created_time = strtotime($values['created_at']))) {
$values['created_time'] = $created_time;
}
$values['utc_offset'] = isset($values['utc_offset']) ? $values['utc_offset'] : 0;
if (isset($values['status'])) {
$this->status = new TwitterStatus($values['status']);
unset($values['status']);
}
parent::__construct($values, 'twitter_account');
}
public function get_auth() {
return array(
'oauth_token' => $this->oauth_token,
'oauth_token_secret' => $this->oauth_token_secret,
);
}
public function set_auth($values) {
$this->oauth_token = isset($values['oauth_token']) ? $values['oauth_token'] : NULL;
$this->oauth_token_secret = isset($values['oauth_token_secret']) ? $values['oauth_token_secret'] : NULL;
}
public function is_auth() {
return !empty($this->oauth_token) && !empty($this->oauth_token_secret);
}
}