forked from GNUsocial/gnu-social
Merge remote branch 'laconica/0.8.x' into 0.9.x
Conflicts: lib/common.php lib/twitter.php
This commit is contained in:
commit
a535ccdc4e
1
README
1
README
@ -146,6 +146,7 @@ Your PHP installation must include the following PHP extensions:
|
||||
- GD. For scaling down avatar images.
|
||||
- mbstring. For handling Unicode (UTF-8) encoded strings.
|
||||
- gettext. For multiple languages. Default on many PHP installs.
|
||||
- tidy. Used to clean up HTML/URLs for the URL shortener to consume.
|
||||
|
||||
For some functionality, you will also need the following extensions:
|
||||
|
||||
|
@ -133,6 +133,8 @@ class ApiAction extends Action
|
||||
'groups/show',
|
||||
'groups/timeline',
|
||||
'groups/list_all',
|
||||
'groups/membership',
|
||||
'groups/is_member',
|
||||
'groups/timeline');
|
||||
|
||||
static $bareauth = array('statuses/user_timeline',
|
||||
|
@ -146,8 +146,10 @@ class FoafAction extends Action
|
||||
while ($sub->fetch()) {
|
||||
if ($sub->token) {
|
||||
$other = Remote_profile::staticGet('id', $sub->subscriber);
|
||||
$profile = Profile::staticGet('id', $sub->subscriber);
|
||||
} else {
|
||||
$other = User::staticGet('id', $sub->subscriber);
|
||||
$profile = Profile::staticGet('id', $sub->subscriber);
|
||||
}
|
||||
if (!$other) {
|
||||
common_debug('Got a bad subscription: '.print_r($sub,true));
|
||||
@ -158,12 +160,15 @@ class FoafAction extends Action
|
||||
} else {
|
||||
$person[$other->uri] = array(LISTENER,
|
||||
$other->id,
|
||||
$other->nickname,
|
||||
$profile->nickname,
|
||||
(empty($sub->token)) ? 'User' : 'Remote_profile');
|
||||
}
|
||||
$other->free();
|
||||
$other = null;
|
||||
unset($other);
|
||||
$profile->free();
|
||||
$profile = null;
|
||||
unset($profile);
|
||||
}
|
||||
}
|
||||
|
||||
@ -254,8 +259,10 @@ class FoafAction extends Action
|
||||
while ($sub->fetch()) {
|
||||
if (!empty($sub->token)) {
|
||||
$other = Remote_profile::staticGet('id', $sub->subscribed);
|
||||
$profile = Profile::staticGet('id', $sub->subscribed);
|
||||
} else {
|
||||
$other = User::staticGet('id', $sub->subscribed);
|
||||
$profile = Profile::staticGet('id', $sub->subscribed);
|
||||
}
|
||||
if (empty($other)) {
|
||||
common_debug('Got a bad subscription: '.print_r($sub,true));
|
||||
@ -264,11 +271,14 @@ class FoafAction extends Action
|
||||
$this->element('sioc:follows', array('rdf:resource' => $other->uri.'#acct'));
|
||||
$person[$other->uri] = array(LISTENEE,
|
||||
$other->id,
|
||||
$other->nickname,
|
||||
$profile->nickname,
|
||||
(empty($sub->token)) ? 'User' : 'Remote_profile');
|
||||
$other->free();
|
||||
$other = null;
|
||||
unset($other);
|
||||
$profile->free();
|
||||
$profile = null;
|
||||
unset($profile);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
*
|
||||
* @category Twitter
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
@ -41,7 +41,7 @@ require_once INSTALLDIR.'/lib/twitterapi.php';
|
||||
*
|
||||
* @category Twitter
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
@ -233,4 +233,97 @@ require_once INSTALLDIR.'/lib/twitterapi.php';
|
||||
}
|
||||
}
|
||||
|
||||
function membership($args, $apidata)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
common_debug("in groups api action");
|
||||
|
||||
$this->auth_user = $apidata['user'];
|
||||
$group = $this->get_group($apidata['api_arg'], $apidata);
|
||||
|
||||
if (empty($group)) {
|
||||
$this->clientError('Not Found', 404, $apidata['content-type']);
|
||||
return;
|
||||
}
|
||||
|
||||
$sitename = common_config('site', 'name');
|
||||
$title = sprintf(_("Members of %s group"), $group->nickname);
|
||||
$taguribase = common_config('integration', 'taguri');
|
||||
$id = "tag:$taguribase:GroupMembership:".$group->id;
|
||||
$link = common_local_url('showgroup',
|
||||
array('nickname' => $group->nickname));
|
||||
$subtitle = sprintf(_('Members of %1$s on %2$s'),
|
||||
$group->nickname, $sitename);
|
||||
|
||||
$page = (int)$this->arg('page', 1);
|
||||
$count = (int)$this->arg('count', 20);
|
||||
$max_id = (int)$this->arg('max_id', 0);
|
||||
$since_id = (int)$this->arg('since_id', 0);
|
||||
$since = $this->arg('since');
|
||||
|
||||
$member = $group->getMembers(($page-1)*$count,
|
||||
$count, $since_id, $max_id, $since);
|
||||
|
||||
switch($apidata['content-type']) {
|
||||
case 'xml':
|
||||
$this->show_twitter_xml_users($member);
|
||||
break;
|
||||
//TODO implement the RSS and ATOM content types
|
||||
/*case 'rss':
|
||||
$this->show_rss_users($member, $title, $link, $subtitle);
|
||||
break;*/
|
||||
/*case 'atom':
|
||||
if (isset($apidata['api_arg'])) {
|
||||
$selfuri = common_root_url() .
|
||||
'api/statusnet/groups/membership/' .
|
||||
$apidata['api_arg'] . '.atom';
|
||||
} else {
|
||||
$selfuri = common_root_url() .
|
||||
'api/statusnet/groups/membership.atom';
|
||||
}
|
||||
$this->show_atom_users($member, $title, $id, $link,
|
||||
$subtitle, null, $selfuri);
|
||||
break;*/
|
||||
case 'json':
|
||||
$this->show_json_users($member);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(_('API method not found!'), $code = 404);
|
||||
}
|
||||
}
|
||||
|
||||
function is_member($args, $apidata)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
common_debug("in groups api action");
|
||||
|
||||
$this->auth_user = $apidata['user'];
|
||||
$group = User_group::staticGet($args['group_id']);
|
||||
if(! $group){
|
||||
$this->clientError(_('Group not found'), $code = 500);
|
||||
}
|
||||
$user = User::staticGet('id', $args['user_id']);
|
||||
if(! $user){
|
||||
$this->clientError(_('User not found'), $code = 500);
|
||||
}
|
||||
|
||||
$is_member=$user->isMember($group);
|
||||
|
||||
switch($apidata['content-type']) {
|
||||
case 'xml':
|
||||
$this->init_document('xml');
|
||||
$this->element('is_member', null, $is_member);
|
||||
$this->end_document('xml');
|
||||
break;
|
||||
case 'json':
|
||||
$this->init_document('json');
|
||||
$this->show_json_objects(array('is_member'=>$is_member));
|
||||
$this->end_document('json');
|
||||
break;
|
||||
default:
|
||||
$this->clientError(_('API method not found!'), $code = 404);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@
|
||||
*
|
||||
* @category Twitter
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
@ -41,7 +41,7 @@ require_once INSTALLDIR.'/lib/twitterapi.php';
|
||||
*
|
||||
* @category Twitter
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
|
@ -165,7 +165,7 @@ class TwittersettingsAction extends ConnectSettingsAction
|
||||
($flink->noticesync & FOREIGN_NOTICE_RECV) :
|
||||
false);
|
||||
$this->elementEnd('li');
|
||||
|
||||
} else {
|
||||
// preserve setting even if bidrection bridge toggled off
|
||||
|
||||
if ($flink && ($flink->noticesync & FOREIGN_NOTICE_RECV)) {
|
||||
|
@ -78,14 +78,14 @@ class File extends Memcached_DataObject
|
||||
$file_id = $x->insert();
|
||||
|
||||
if (isset($redir_data['type'])
|
||||
&& ('text/html' === substr($redir_data['type'], 0, 9))
|
||||
&& (('text/html' === substr($redir_data['type'], 0, 9) || 'application/xhtml+xml' === substr($redir_data['type'], 0, 21)))
|
||||
&& ($oembed_data = File_oembed::_getOembed($given_url))) {
|
||||
File_oembed::saveNew($oembed_data, $file_id);
|
||||
}
|
||||
return $x;
|
||||
}
|
||||
|
||||
function processNew($given_url, $notice_id) {
|
||||
function processNew($given_url, $notice_id=null) {
|
||||
if (empty($given_url)) return -1; // error, no url to process
|
||||
$given_url = File_redirection::_canonUrl($given_url);
|
||||
if (empty($given_url)) return -1; // error, no url to process
|
||||
@ -96,7 +96,7 @@ class File extends Memcached_DataObject
|
||||
$redir_data = File_redirection::where($given_url);
|
||||
$redir_url = $redir_data['url'];
|
||||
// TODO: max field length
|
||||
if ($redir_url === $given_url || strlen($redir_url) > 255) {
|
||||
if ($redir_url === $given_url || strlen($redir_url) > 255) {
|
||||
$x = File::saveNew($redir_data, $given_url);
|
||||
$file_id = $x->id;
|
||||
} else {
|
||||
@ -119,7 +119,9 @@ class File extends Memcached_DataObject
|
||||
}
|
||||
}
|
||||
|
||||
File_to_post::processNew($file_id, $notice_id);
|
||||
if (!empty($notice_id)) {
|
||||
File_to_post::processNew($file_id, $notice_id);
|
||||
}
|
||||
return $x;
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ class Notice extends Memcached_DataObject
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
/* Notice types */
|
||||
/* Notice types */
|
||||
const LOCAL_PUBLIC = 1;
|
||||
const REMOTE_OMB = 0;
|
||||
const LOCAL_NONPUBLIC = -1;
|
||||
@ -260,17 +260,6 @@ class Notice extends Memcached_DataObject
|
||||
|
||||
$notice->saveUrls();
|
||||
|
||||
// FIXME: why do we have to re-render the content?
|
||||
// Remove this if it's not necessary.
|
||||
|
||||
$orig2 = clone($notice);
|
||||
|
||||
$notice->rendered = common_render_content($final, $notice);
|
||||
if (!$notice->update($orig2)) {
|
||||
common_log_db_error($notice, 'UPDATE', __FILE__);
|
||||
return _('Problem saving notice.');
|
||||
}
|
||||
|
||||
$notice->query('COMMIT');
|
||||
|
||||
Event::handle('EndNoticeSave', array($notice));
|
||||
|
@ -54,7 +54,7 @@ class Status_network extends DB_DataObject
|
||||
global $config;
|
||||
|
||||
$config['db']['database_'.$dbname] = "mysqli://$dbuser:$dbpass@$dbhost/$dbname";
|
||||
$config['db']['ini_'.$dbname] = INSTALLDIR.'/classes/statusnet.ini';
|
||||
$config['db']['ini_'.$dbname] = INSTALLDIR.'/classes/status_network.ini';
|
||||
$config['db']['table_status_network'] = $dbname;
|
||||
|
||||
self::$cache = new Memcache();
|
||||
|
@ -13,7 +13,7 @@ Bugs
|
||||
----
|
||||
|
||||
If you think you've found a bug in the [StatusNet](http://status.net/) software,
|
||||
or if there's a new feature you'd like to see, add it into the [StatusNet bug database](http://status.net/PITS/HomePage). Don't forget to check the list of
|
||||
or if there's a new feature you'd like to see, add it into the [StatusNet bug database](http://status.net/bugs/). Don't forget to check the list of
|
||||
existing bugs to make sure it hasn't already been reported!
|
||||
|
||||
Email
|
||||
|
@ -256,7 +256,7 @@ class Services_oEmbed
|
||||
|
||||
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
if (substr($code, 0, 1) != '2') {
|
||||
throw new Services_oEmbed_Exception('Non-200 code returned');
|
||||
throw new Services_oEmbed_Exception('Non-200 code returned. Got code ' . $code);
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
@ -302,8 +302,8 @@ class Services_oEmbed
|
||||
|
||||
// Find all <link /> tags that have a valid oembed type set. We then
|
||||
// extract the href attribute for each type.
|
||||
$regexp = '#<link([^>]*)type="' .
|
||||
'(application/json|text/xml)\+oembed"([^>]*)>#i';
|
||||
$regexp = '#<link([^>]*)type[\s\n]*=[\s\n]*"' .
|
||||
'(application/json|text/xml)\+oembed"([^>]*)>#im';
|
||||
|
||||
$m = $ret = array();
|
||||
if (!preg_match_all($regexp, $body, $m)) {
|
||||
@ -314,7 +314,7 @@ class Services_oEmbed
|
||||
|
||||
foreach ($m[0] as $i => $link) {
|
||||
$h = array();
|
||||
if (preg_match('/href="([^"]+)"/i', $link, $h)) {
|
||||
if (preg_match('/[\s\n]+href[\s\n]*=[\s\n]*"([^"]+)"/im', $link, $h)) {
|
||||
$ret[$m[2][$i]] = $h[1];
|
||||
}
|
||||
}
|
||||
@ -347,7 +347,7 @@ class Services_oEmbed
|
||||
|
||||
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
if (substr($code, 0, 1) != '2') {
|
||||
throw new Services_oEmbed_Exception('Non-200 code returned');
|
||||
throw new Services_oEmbed_Exception('Non-200 code returned. Got code ' . $code);
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
@ -454,7 +454,7 @@ class Stomp
|
||||
*/
|
||||
public function disconnect ()
|
||||
{
|
||||
$header = array();
|
||||
$headers = array();
|
||||
|
||||
if ($this->clientId != null) {
|
||||
$headers["client-id"] = $this->clientId;
|
||||
|
@ -230,7 +230,7 @@ function checkPrereqs()
|
||||
}
|
||||
|
||||
$reqs = array('gd', 'curl',
|
||||
'xmlwriter', 'mbstring');
|
||||
'xmlwriter', 'mbstring','tidy');
|
||||
|
||||
foreach ($reqs as $req) {
|
||||
if (!checkExtension($req)) {
|
||||
|
105
lib/command.php
105
lib/command.php
@ -114,7 +114,6 @@ class StatsCommand extends Command
|
||||
|
||||
class FavCommand extends Command
|
||||
{
|
||||
|
||||
var $other = null;
|
||||
|
||||
function __construct($user, $other)
|
||||
@ -158,6 +157,108 @@ class FavCommand extends Command
|
||||
|
||||
$channel->output($this->user, _('Notice marked as fave.'));
|
||||
}
|
||||
|
||||
}
|
||||
class JoinCommand extends Command
|
||||
{
|
||||
var $other = null;
|
||||
|
||||
function __construct($user, $other)
|
||||
{
|
||||
parent::__construct($user);
|
||||
$this->other = $other;
|
||||
}
|
||||
|
||||
function execute($channel)
|
||||
{
|
||||
|
||||
$nickname = common_canonical_nickname($this->other);
|
||||
$group = User_group::staticGet('nickname', $nickname);
|
||||
$cur = $this->user;
|
||||
|
||||
if (!$group) {
|
||||
$channel->error($cur, _('No such group.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($cur->isMember($group)) {
|
||||
$channel->error($cur, _('You are already a member of that group'));
|
||||
return;
|
||||
}
|
||||
if (Group_block::isBlocked($group, $cur->getProfile())) {
|
||||
$channel->error($cur, _('You have been blocked from that group by the admin.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$member = new Group_member();
|
||||
|
||||
$member->group_id = $group->id;
|
||||
$member->profile_id = $cur->id;
|
||||
$member->created = common_sql_now();
|
||||
|
||||
$result = $member->insert();
|
||||
if (!$result) {
|
||||
common_log_db_error($member, 'INSERT', __FILE__);
|
||||
$channel->error($cur, sprintf(_('Could not join user %s to group %s'),
|
||||
$cur->nickname, $group->nickname));
|
||||
return;
|
||||
}
|
||||
|
||||
$channel->output($cur, sprintf(_('%s joined group %s'),
|
||||
$cur->nickname,
|
||||
$group->nickname));
|
||||
}
|
||||
|
||||
}
|
||||
class DropCommand extends Command
|
||||
{
|
||||
var $other = null;
|
||||
|
||||
function __construct($user, $other)
|
||||
{
|
||||
parent::__construct($user);
|
||||
$this->other = $other;
|
||||
}
|
||||
|
||||
function execute($channel)
|
||||
{
|
||||
|
||||
$nickname = common_canonical_nickname($this->other);
|
||||
$group = User_group::staticGet('nickname', $nickname);
|
||||
$cur = $this->user;
|
||||
|
||||
if (!$group) {
|
||||
$channel->error($cur, _('No such group.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$cur->isMember($group)) {
|
||||
$channel->error($cur, _('You are not a member of that group.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$member = new Group_member();
|
||||
|
||||
$member->group_id = $group->id;
|
||||
$member->profile_id = $cur->id;
|
||||
|
||||
if (!$member->find(true)) {
|
||||
$channel->error($cur,_('Could not find membership record.'));
|
||||
return;
|
||||
}
|
||||
$result = $member->delete();
|
||||
if (!$result) {
|
||||
common_log_db_error($member, 'INSERT', __FILE__);
|
||||
$channel->error($cur, sprintf(_('Could not remove user %s to group %s'),
|
||||
$cur->nickname, $group->nickname));
|
||||
return;
|
||||
}
|
||||
|
||||
$channel->output($cur, sprintf(_('%s left group %s'),
|
||||
$cur->nickname,
|
||||
$group->nickname));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class WhoisCommand extends Command
|
||||
@ -396,6 +497,8 @@ class HelpCommand extends Command
|
||||
"get <nickname> - get last notice from user\n".
|
||||
"whois <nickname> - get profile info on user\n".
|
||||
"fav <nickname> - add user's last notice as a 'fave'\n".
|
||||
"join <group> - join group\n".
|
||||
"drop <group> - leave group\n".
|
||||
"stats - get your stats\n".
|
||||
"stop - same as 'off'\n".
|
||||
"quit - same as 'off'\n".
|
||||
|
@ -70,6 +70,26 @@ class CommandInterpreter
|
||||
} else {
|
||||
return new OffCommand($user);
|
||||
}
|
||||
case 'join':
|
||||
if (!$arg) {
|
||||
return null;
|
||||
}
|
||||
list($other, $extra) = explode(' ', $arg, 2);
|
||||
if ($extra) {
|
||||
return null;
|
||||
} else {
|
||||
return new JoinCommand($user, $other);
|
||||
}
|
||||
case 'drop':
|
||||
if (!$arg) {
|
||||
return null;
|
||||
}
|
||||
list($other, $extra) = explode(' ', $arg, 2);
|
||||
if ($extra) {
|
||||
return null;
|
||||
} else {
|
||||
return new DropCommand($user, $other);
|
||||
}
|
||||
case 'follow':
|
||||
case 'sub':
|
||||
if (!$arg) {
|
||||
|
@ -213,26 +213,20 @@ class MailboxAction extends CurrentUserDesignAction
|
||||
}
|
||||
|
||||
$this->elementStart('div', 'entry-content');
|
||||
$this->elementStart('dl', 'timestamp');
|
||||
$this->element('dt', null, _('Published'));
|
||||
$this->elementStart('dd', null);
|
||||
$dt = common_date_iso8601($message->created);
|
||||
$this->elementStart('a', array('rel' => 'bookmark',
|
||||
'class' => 'timestamp',
|
||||
'href' => $messageurl));
|
||||
$dt = common_date_iso8601($message->created);
|
||||
$this->element('abbr', array('class' => 'published',
|
||||
'title' => $dt),
|
||||
common_date_string($message->created));
|
||||
$this->elementEnd('a');
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
|
||||
if ($message->source) {
|
||||
$this->elementStart('dl', 'device');
|
||||
$this->elementStart('dt');
|
||||
$this->text(_('From'));
|
||||
$this->elementEnd('dt');
|
||||
$this->showSource($message->source);
|
||||
$this->elementEnd('dl');
|
||||
$this->elementStart('span', 'source');
|
||||
$this->text(_('from'));
|
||||
$this->element('span', 'device', $this->showSource($message->source));
|
||||
$this->elementEnd('span');
|
||||
}
|
||||
$this->elementEnd('div');
|
||||
|
||||
@ -277,18 +271,18 @@ class MailboxAction extends CurrentUserDesignAction
|
||||
case 'mail':
|
||||
case 'omb':
|
||||
case 'api':
|
||||
$this->element('dd', null, $source_name);
|
||||
$this->element('span', 'device', $source_name);
|
||||
break;
|
||||
default:
|
||||
$ns = Notice_source::staticGet($source);
|
||||
if ($ns) {
|
||||
$this->elementStart('dd', null);
|
||||
$this->elementStart('span', 'device');
|
||||
$this->element('a', array('href' => $ns->url,
|
||||
'rel' => 'external'),
|
||||
$ns->name);
|
||||
$this->elementEnd('dd');
|
||||
'rel' => 'external'),
|
||||
$ns->name);
|
||||
$this->elementEnd('span');
|
||||
} else {
|
||||
$this->element('dd', null, $source_name);
|
||||
$this->out->element('span', 'device', $source_name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
* @category Action
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2008 StatusNet, Inc.
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
169
lib/twitter.php
169
lib/twitter.php
@ -154,83 +154,134 @@ function broadcast_twitter($notice)
|
||||
TWITTER_SERVICE);
|
||||
|
||||
if (is_twitter_bound($notice, $flink)) {
|
||||
|
||||
$user = $flink->getUser();
|
||||
|
||||
// XXX: Hack to get around PHP cURL's use of @ being a a meta character
|
||||
$statustxt = preg_replace('/^@/', ' @', $notice->content);
|
||||
|
||||
// Convert !groups to #hashes
|
||||
$statustxt = preg_replace('/(^|\s)!([A-Za-z0-9]{1,64})/', "\\1#\\2", $statustxt);
|
||||
|
||||
$token = TwitterOAuthClient::unpackToken($flink->credentials);
|
||||
|
||||
$client = new TwitterOAuthClient($token->key, $token->secret);
|
||||
|
||||
$status = null;
|
||||
|
||||
try {
|
||||
$status = $client->statusesUpdate($statustxt);
|
||||
} catch (OAuthClientCurlException $e) {
|
||||
|
||||
if ($e->getMessage() == 'The requested URL returned error: 401') {
|
||||
|
||||
$errmsg = sprintf('User %1$s (user id: %2$s) has an invalid ' .
|
||||
'Twitter OAuth access token.',
|
||||
$user->nickname, $user->id);
|
||||
common_log(LOG_WARNING, $errmsg);
|
||||
|
||||
// Bad auth token! We need to delete the foreign_link
|
||||
// to Twitter and inform the user.
|
||||
|
||||
remove_twitter_link($flink);
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
||||
// Some other error happened, so we should probably
|
||||
// try to send again later.
|
||||
|
||||
$errmsg = sprintf('cURL error trying to send notice to Twitter ' .
|
||||
'for user %1$s (user id: %2$s) - ' .
|
||||
'code: %3$s message: $4$s.',
|
||||
$user->nickname, $user->id,
|
||||
$e->getCode(), $e->getMessage());
|
||||
common_log(LOG_WARNING, $errmsg);
|
||||
|
||||
return false;
|
||||
}
|
||||
if (TwitterOAuthClient::isPackedToken($flink->credentials)) {
|
||||
return broadcast_oauth($notice, $flink);
|
||||
} else {
|
||||
return broadcast_basicauth($notice, $flink);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($status)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// This could represent a failure posting,
|
||||
// or the Twitter API might just be behaving flakey.
|
||||
function broadcast_oauth($notice, $flink) {
|
||||
$user = $flink->getUser();
|
||||
$statustxt = format_status($notice);
|
||||
// Convert !groups to #hashes
|
||||
$statustxt = preg_replace('/(^|\s)!([A-Za-z0-9]{1,64})/', "\\1#\\2", $statustxt);
|
||||
$token = TwitterOAuthClient::unpackToken($flink->credentials);
|
||||
$client = new TwitterOAuthClient($token->key, $token->secret);
|
||||
$status = null;
|
||||
|
||||
try {
|
||||
$status = $client->statusesUpdate($statustxt);
|
||||
} catch (OAuthClientCurlException $e) {
|
||||
return process_error($e, $flink);
|
||||
}
|
||||
|
||||
if (empty($status)) {
|
||||
|
||||
// This could represent a failure posting,
|
||||
// or the Twitter API might just be behaving flakey.
|
||||
|
||||
$errmsg = sprintf('Twitter bridge - No data returned by Twitter API when ' .
|
||||
'trying to send update for %1$s (user id %2$s).',
|
||||
$user->nickname, $user->id);
|
||||
common_log(LOG_WARNING, $errmsg);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Notice crossed the great divide
|
||||
|
||||
$msg = sprintf('Twitter bridge - posted notice %s to Twitter using OAuth.',
|
||||
$notice->id);
|
||||
common_log(LOG_INFO, $msg);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function broadcast_basicauth($notice, $flink)
|
||||
{
|
||||
$user = $flink->getUser();
|
||||
|
||||
$statustxt = format_status($notice);
|
||||
|
||||
$client = new TwitterBasicAuthClient($flink);
|
||||
$status = null;
|
||||
|
||||
try {
|
||||
$status = $client->statusesUpdate($statustxt);
|
||||
} catch (BasicAuthCurlException $e) {
|
||||
return process_error($e, $flink);
|
||||
}
|
||||
|
||||
if (empty($status)) {
|
||||
|
||||
$errmsg = sprintf('Twitter bridge - No data returned by Twitter API when ' .
|
||||
'trying to send update for %1$s (user id %2$s).',
|
||||
$user->nickname, $user->id);
|
||||
common_log(LOG_WARNING, $errmsg);
|
||||
|
||||
$errmsg = sprintf('No data returned by Twitter API when ' .
|
||||
'trying to send update for %1$s (user id %2$s).',
|
||||
$user->nickname, $user->id);
|
||||
common_log(LOG_WARNING, $errmsg);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Notice crossed the great divide
|
||||
|
||||
$msg = sprintf('Twitter bridge posted notice %s to Twitter.',
|
||||
$notice->id);
|
||||
common_log(LOG_INFO, $msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
$msg = sprintf('Twitter bridge - posted notice %s to Twitter using basic auth.',
|
||||
$notice->id);
|
||||
common_log(LOG_INFO, $msg);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function process_error($e, $flink)
|
||||
{
|
||||
$user = $flink->getUser();
|
||||
$errmsg = $e->getMessage();
|
||||
$delivered = false;
|
||||
|
||||
switch($errmsg) {
|
||||
case 'The requested URL returned error: 401':
|
||||
$logmsg = sprintf('Twiter bridge - User %1$s (user id: %2$s) has an invalid ' .
|
||||
'Twitter screen_name/password combo or an invalid acesss token.',
|
||||
$user->nickname, $user->id);
|
||||
$delivered = true;
|
||||
remove_twitter_link($flink);
|
||||
break;
|
||||
case 'The requested URL returned error: 403':
|
||||
$logmsg = sprintf('Twitter bridge - User %1$s (user id: %2$s) has exceeded ' .
|
||||
'his/her Twitter request limit.',
|
||||
$user->nickname, $user->id);
|
||||
break;
|
||||
default:
|
||||
$logmsg = sprintf('Twitter bridge - cURL error trying to send notice to Twitter ' .
|
||||
'for user %1$s (user id: %2$s) - ' .
|
||||
'code: %3$s message: %4$s.',
|
||||
$user->nickname, $user->id,
|
||||
$e->getCode(), $e->getMessage());
|
||||
break;
|
||||
}
|
||||
|
||||
common_log(LOG_WARNING, $logmsg);
|
||||
|
||||
return $delivered;
|
||||
}
|
||||
|
||||
function format_status($notice)
|
||||
{
|
||||
// XXX: Hack to get around PHP cURL's use of @ being a a meta character
|
||||
return preg_replace('/^@/', ' @', $notice->content);
|
||||
}
|
||||
|
||||
function remove_twitter_link($flink)
|
||||
{
|
||||
$user = $flink->getUser();
|
||||
|
||||
common_log(LOG_INFO, 'Removing Twitter bridge Foreign link for ' .
|
||||
"user $user->nickname (user id: $user->id).");
|
||||
"user $user->nickname (user id: $user->id).");
|
||||
|
||||
$result = $flink->delete();
|
||||
|
||||
|
@ -788,6 +788,52 @@ class TwitterapiAction extends Action
|
||||
$this->end_document('xml');
|
||||
}
|
||||
|
||||
function show_twitter_xml_users($user)
|
||||
{
|
||||
|
||||
$this->init_document('xml');
|
||||
$this->elementStart('users', array('type' => 'array'));
|
||||
|
||||
if (is_array($user)) {
|
||||
foreach ($group as $g) {
|
||||
$twitter_user = $this->twitter_user_array($g);
|
||||
$this->show_twitter_xml_user($twitter_user,'user');
|
||||
}
|
||||
} else {
|
||||
while ($user->fetch()) {
|
||||
$twitter_user = $this->twitter_user_array($user);
|
||||
$this->show_twitter_xml_user($twitter_user);
|
||||
}
|
||||
}
|
||||
|
||||
$this->elementEnd('users');
|
||||
$this->end_document('xml');
|
||||
}
|
||||
|
||||
function show_json_users($user)
|
||||
{
|
||||
|
||||
$this->init_document('json');
|
||||
|
||||
$users = array();
|
||||
|
||||
if (is_array($user)) {
|
||||
foreach ($user as $u) {
|
||||
$twitter_user = $this->twitter_user_array($u);
|
||||
array_push($users, $twitter_user);
|
||||
}
|
||||
} else {
|
||||
while ($user->fetch()) {
|
||||
$twitter_user = $this->twitter_user_array($user);
|
||||
array_push($users, $twitter_user);
|
||||
}
|
||||
}
|
||||
|
||||
$this->show_json_objects($users);
|
||||
|
||||
$this->end_document('json');
|
||||
}
|
||||
|
||||
function show_single_json_group($group)
|
||||
{
|
||||
$this->init_document('json');
|
||||
|
236
lib/twitterbasicauthclient.php
Normal file
236
lib/twitterbasicauthclient.php
Normal file
@ -0,0 +1,236 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Class for doing OAuth calls against Twitter
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category Integration
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception wrapper for cURL errors
|
||||
*
|
||||
* @category Integration
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*
|
||||
*/
|
||||
class BasicAuthCurlException extends Exception
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for talking to the Twitter API with HTTP Basic Auth.
|
||||
*
|
||||
* @category Integration
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*
|
||||
*/
|
||||
class TwitterBasicAuthClient
|
||||
{
|
||||
var $screen_name = null;
|
||||
var $password = null;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
* @param Foreign_link $flink a Foreign_link storing the
|
||||
* Twitter user's password, etc.
|
||||
*/
|
||||
function __construct($flink)
|
||||
{
|
||||
$fuser = $flink->getForeignUser();
|
||||
$this->screen_name = $fuser->nickname;
|
||||
$this->password = $flink->credentials;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls Twitter's /statuses/update API method
|
||||
*
|
||||
* @param string $status text of the status
|
||||
* @param int $in_reply_to_status_id optional id of the status it's
|
||||
* a reply to
|
||||
*
|
||||
* @return mixed the status
|
||||
*/
|
||||
function statusesUpdate($status, $in_reply_to_status_id = null)
|
||||
{
|
||||
$url = 'https://twitter.com/statuses/update.json';
|
||||
$params = array('status' => $status,
|
||||
'source' => common_config('integration', 'source'),
|
||||
'in_reply_to_status_id' => $in_reply_to_status_id);
|
||||
$response = $this->httpRequest($url, $params);
|
||||
$status = json_decode($response);
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls Twitter's /statuses/friends_timeline API method
|
||||
*
|
||||
* @param int $since_id show statuses after this id
|
||||
* @param int $max_id show statuses before this id
|
||||
* @param int $cnt number of statuses to show
|
||||
* @param int $page page number
|
||||
*
|
||||
* @return mixed an array of statuses
|
||||
*/
|
||||
function statusesFriendsTimeline($since_id = null, $max_id = null,
|
||||
$cnt = null, $page = null)
|
||||
{
|
||||
$url = 'https://twitter.com/statuses/friends_timeline.json';
|
||||
$params = array('since_id' => $since_id,
|
||||
'max_id' => $max_id,
|
||||
'count' => $cnt,
|
||||
'page' => $page);
|
||||
$qry = http_build_query($params);
|
||||
|
||||
if (!empty($qry)) {
|
||||
$url .= "?$qry";
|
||||
}
|
||||
|
||||
$response = $this->httpRequest($url);
|
||||
$statuses = json_decode($response);
|
||||
return $statuses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls Twitter's /statuses/friends API method
|
||||
*
|
||||
* @param int $id id of the user whom you wish to see friends of
|
||||
* @param int $user_id numerical user id
|
||||
* @param int $screen_name screen name
|
||||
* @param int $page page number
|
||||
*
|
||||
* @return mixed an array of twitter users and their latest status
|
||||
*/
|
||||
function statusesFriends($id = null, $user_id = null, $screen_name = null,
|
||||
$page = null)
|
||||
{
|
||||
$url = "https://twitter.com/statuses/friends.json";
|
||||
|
||||
$params = array('id' => $id,
|
||||
'user_id' => $user_id,
|
||||
'screen_name' => $screen_name,
|
||||
'page' => $page);
|
||||
$qry = http_build_query($params);
|
||||
|
||||
if (!empty($qry)) {
|
||||
$url .= "?$qry";
|
||||
}
|
||||
|
||||
$response = $this->httpRequest($url);
|
||||
$friends = json_decode($response);
|
||||
return $friends;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls Twitter's /statuses/friends/ids API method
|
||||
*
|
||||
* @param int $id id of the user whom you wish to see friends of
|
||||
* @param int $user_id numerical user id
|
||||
* @param int $screen_name screen name
|
||||
* @param int $page page number
|
||||
*
|
||||
* @return mixed a list of ids, 100 per page
|
||||
*/
|
||||
function friendsIds($id = null, $user_id = null, $screen_name = null,
|
||||
$page = null)
|
||||
{
|
||||
$url = "https://twitter.com/friends/ids.json";
|
||||
|
||||
$params = array('id' => $id,
|
||||
'user_id' => $user_id,
|
||||
'screen_name' => $screen_name,
|
||||
'page' => $page);
|
||||
$qry = http_build_query($params);
|
||||
|
||||
if (!empty($qry)) {
|
||||
$url .= "?$qry";
|
||||
}
|
||||
|
||||
$response = $this->httpRequest($url);
|
||||
$ids = json_decode($response);
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a HTTP request using cURL.
|
||||
*
|
||||
* @param string $url Where to make the request
|
||||
* @param array $params post parameters
|
||||
*
|
||||
* @return mixed the request
|
||||
*/
|
||||
function httpRequest($url, $params = null, $auth = true)
|
||||
{
|
||||
$options = array(
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_FAILONERROR => true,
|
||||
CURLOPT_HEADER => false,
|
||||
CURLOPT_FOLLOWLOCATION => true,
|
||||
CURLOPT_USERAGENT => 'StatusNet',
|
||||
CURLOPT_CONNECTTIMEOUT => 120,
|
||||
CURLOPT_TIMEOUT => 120,
|
||||
CURLOPT_HTTPAUTH => CURLAUTH_ANY,
|
||||
CURLOPT_SSL_VERIFYPEER => false,
|
||||
|
||||
// Twitter is strict about accepting invalid "Expect" headers
|
||||
|
||||
CURLOPT_HTTPHEADER => array('Expect:')
|
||||
);
|
||||
|
||||
if (isset($params)) {
|
||||
$options[CURLOPT_POST] = true;
|
||||
$options[CURLOPT_POSTFIELDS] = $params;
|
||||
}
|
||||
|
||||
if ($auth) {
|
||||
$options[CURLOPT_USERPWD] = $this->screen_name .
|
||||
':' . $this->password;
|
||||
}
|
||||
|
||||
$ch = curl_init($url);
|
||||
curl_setopt_array($ch, $options);
|
||||
$response = curl_exec($ch);
|
||||
|
||||
if ($response === false) {
|
||||
$msg = curl_error($ch);
|
||||
$code = curl_errno($ch);
|
||||
throw new BasicAuthCurlException($msg, $code);
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
}
|
@ -22,7 +22,7 @@
|
||||
* @category Integration
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2008 StatusNet, Inc.
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
@ -81,6 +81,15 @@ class TwitterOAuthClient extends OAuthClient
|
||||
return new OAuthToken($vals[0], $vals[1]);
|
||||
}
|
||||
|
||||
static function isPackedToken($str)
|
||||
{
|
||||
if (strpos($str, chr(0)) === false) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a link to Twitter's endpoint for authorizing a request token
|
||||
*
|
||||
|
93
lib/util.php
93
lib/util.php
@ -413,7 +413,7 @@ function common_replace_urls_callback($text, $callback, $notice_id = null) {
|
||||
// Start off with a regex
|
||||
$regex = '#'.
|
||||
'(?:^|[\s\(\)\[\]\{\}\\\'\\\";]+)(?![\@\!\#])'.
|
||||
'(?P<url>'.
|
||||
'('.
|
||||
'(?:'.
|
||||
'(?:'. //Known protocols
|
||||
'(?:'.
|
||||
@ -421,7 +421,7 @@ function common_replace_urls_callback($text, $callback, $notice_id = null) {
|
||||
'|'.
|
||||
'(?:(?:mailto|aim|tel|xmpp):)'.
|
||||
')'.
|
||||
'(?:[\pN\pL\-\_\+]+(?::[\pN\pL\-\_\+]+)?\@)?'. //user:pass@
|
||||
'(?:[\pN\pL\-\_\+\%\~]+(?::[\pN\pL\-\_\+\%\~]+)?\@)?'. //user:pass@
|
||||
'(?:'.
|
||||
'(?:'.
|
||||
'\[[\pN\pL\-\_\:\.]+(?<![\.\:])\]'. //[dns]
|
||||
@ -434,7 +434,7 @@ function common_replace_urls_callback($text, $callback, $notice_id = null) {
|
||||
'|(?:'. //IPv6
|
||||
'\[?(?:(?:(?:[0-9A-Fa-f]{1,4}:){7}(?:(?:[0-9A-Fa-f]{1,4})|:))|(?:(?:[0-9A-Fa-f]{1,4}:){6}(?::|(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})|(?::[0-9A-Fa-f]{1,4})))|(?:(?:[0-9A-Fa-f]{1,4}:){5}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){4}(?::[0-9A-Fa-f]{1,4}){0,1}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){3}(?::[0-9A-Fa-f]{1,4}){0,2}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){2}(?::[0-9A-Fa-f]{1,4}){0,3}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:)(?::[0-9A-Fa-f]{1,4}){0,4}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?::(?::[0-9A-Fa-f]{1,4}){0,5}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})))\]?'.
|
||||
')|(?:'. //DNS
|
||||
'(?:[\pN\pL\-\_\+]+(?:\:[\pN\pL\-\_\+]+)?\@)?'. //user:pass@
|
||||
'(?:[\pN\pL\-\_\+\%\~]+(?:\:[\pN\pL\-\_\+\%\~]+)?\@)?'. //user:pass@
|
||||
'[\pN\pL\-\_]+(?:\.[\pN\pL\-\_]+)*\.'.
|
||||
//tld list from http://data.iana.org/TLD/tlds-alpha-by-domain.txt, also added local, loc, and onion
|
||||
'(?:AC|AD|AE|AERO|AF|AG|AI|AL|AM|AN|AO|AQ|AR|ARPA|AS|ASIA|AT|AU|AW|AX|AZ|BA|BB|BD|BE|BF|BG|BH|BI|BIZ|BJ|BM|BN|BO|BR|BS|BT|BV|BW|BY|BZ|CA|CAT|CC|CD|CF|CG|CH|CI|CK|CL|CM|CN|CO|COM|COOP|CR|CU|CV|CX|CY|CZ|DE|DJ|DK|DM|DO|DZ|EC|EDU|EE|EG|ER|ES|ET|EU|FI|FJ|FK|FM|FO|FR|GA|GB|GD|GE|GF|GG|GH|GI|GL|GM|GN|GOV|GP|GQ|GR|GS|GT|GU|GW|GY|HK|HM|HN|HR|HT|HU|ID|IE|IL|IM|IN|INFO|INT|IO|IQ|IR|IS|IT|JE|JM|JO|JOBS|JP|KE|KG|KH|KI|KM|KN|KP|KR|KW|KY|KZ|LA|LB|LC|LI|LK|LR|LS|LT|LU|LV|LY|MA|MC|MD|ME|MG|MH|MIL|MK|ML|MM|MN|MO|MOBI|MP|MQ|MR|MS|MT|MU|MUSEUM|MV|MW|MX|MY|MZ|NA|NAME|NC|NE|NET|NF|NG|NI|NL|NO|NP|NR|NU|NZ|OM|ORG|PA|PE|PF|PG|PH|PK|PL|PM|PN|PR|PRO|PS|PT|PW|PY|QA|RE|RO|RS|RU|RW|SA|SB|SC|SD|SE|SG|SH|SI|SJ|SK|SL|SM|SN|SO|SR|ST|SU|SV|SY|SZ|TC|TD|TEL|TF|TG|TH|TJ|TK|TL|TM|TN|TO|TP|TR|TRAVEL|TT|TV|TW|TZ|UA|UG|UK|US|UY|UZ|VA|VC|VE|VG|VI|VN|VU|WF|WS|XN--0ZWM56D|测试|XN--11B5BS3A9AJ6G|परीक्षा|XN--80AKHBYKNJ4F|испытание|XN--9T4B11YI5A|테스트|XN--DEBA0AD|טעסט|XN--G6W251D|測試|XN--HGBK6AJ7F53BBA|آزمایشی|XN--HLCJ6AYA9ESC7A|பரிட்சை|XN--JXALPDLP|δοκιμή|XN--KGBECHTV|إختبار|XN--ZCKZAH|テスト|YE|YT|YU|ZA|ZM|ZW|local|loc|onion)'.
|
||||
@ -442,22 +442,22 @@ function common_replace_urls_callback($text, $callback, $notice_id = null) {
|
||||
')'.
|
||||
'(?:'.
|
||||
'(?:\:\d+)?'. //:port
|
||||
'(?:/[\pN\pL$\[\]\,\!\(\)\.\-\_\+\/\=\&\;]*)?'. // /path
|
||||
'(?:\?[\pN\pL\$\[\]\,\!\(\)\.\-\_\+\/\=\&\;\/]*)?'. // ?query string
|
||||
'(?:\#[\pN\pL$\[\]\,\!\(\)\.\-\_\+\/\=\&\;\/\?\#]*)?'. // #fragment
|
||||
'(?:/[\pN\pL$\[\]\,\!\(\)\.\:\-\_\+\/\=\&\;\%\~]*)?'. // /path
|
||||
'(?:\?[\pN\pL\$\[\]\,\!\(\)\.\:\-\_\+\/\=\&\;\%\~\/]*)?'. // ?query string
|
||||
'(?:\#[\pN\pL$\[\]\,\!\(\)\.\:\-\_\+\/\=\&\;\%\~\/\?\#]*)?'. // #fragment
|
||||
')(?<![\?\.\,\#\,])'.
|
||||
')'.
|
||||
'#ixu';
|
||||
preg_match_all($regex,$text,$matches);
|
||||
//print_r($matches);
|
||||
return preg_replace_callback($regex, curry(callback_helper,$callback,$notice_id) ,$text);
|
||||
return preg_replace_callback($regex, curry('callback_helper',$callback,$notice_id) ,$text);
|
||||
}
|
||||
|
||||
function callback_helper($matches, $callback, $notice_id) {
|
||||
$url=$matches['url'];
|
||||
$url=$matches[1];
|
||||
$left = strpos($matches[0],$url);
|
||||
$right = $left+strlen($url);
|
||||
|
||||
|
||||
$groupSymbolSets=array(
|
||||
array(
|
||||
'left'=>'(',
|
||||
@ -491,13 +491,11 @@ function callback_helper($matches, $callback, $notice_id) {
|
||||
$url=substr($url,0,-1);
|
||||
}
|
||||
}while($original_url!=$url);
|
||||
|
||||
|
||||
|
||||
|
||||
if(empty($notice_id)){
|
||||
$result = call_user_func_array($callback,$url);
|
||||
}else{
|
||||
$result = call_user_func_array($callback, array($url,$notice_id) );
|
||||
$result = call_user_func_array($callback, array(array($url,$notice_id)) );
|
||||
}
|
||||
return substr($matches[0],0,$left) . $result . substr($matches[0],$right);
|
||||
}
|
||||
@ -508,16 +506,13 @@ function curry($fn) {
|
||||
array_shift($args);
|
||||
$id = uniqid('_partial');
|
||||
$GLOBALS[$id] = array($fn, $args);
|
||||
return create_function(
|
||||
'',
|
||||
'
|
||||
$args = func_get_args();
|
||||
return call_user_func_array(
|
||||
$GLOBALS["'.$id.'"][0],
|
||||
array_merge(
|
||||
$args,
|
||||
$GLOBALS["'.$id.'"][1]));
|
||||
');
|
||||
return create_function('',
|
||||
'$args = func_get_args(); '.
|
||||
'return call_user_func_array('.
|
||||
'$GLOBALS["'.$id.'"][0],'.
|
||||
'array_merge('.
|
||||
'$args,'.
|
||||
'$GLOBALS["'.$id.'"][1]));');
|
||||
}
|
||||
|
||||
function common_linkify($url) {
|
||||
@ -525,7 +520,7 @@ function common_linkify($url) {
|
||||
// functions
|
||||
$url = htmlspecialchars_decode($url);
|
||||
|
||||
if(strpos($url, '@')!==false && strpos($url, ':')===false){
|
||||
if(strpos($url, '@') !== false && strpos($url, ':') === false) {
|
||||
//url is an email address without the mailto: protocol
|
||||
return XMLStringer::estring('a', array('href' => "mailto:$url", 'rel' => 'external'), $url);
|
||||
}
|
||||
@ -547,42 +542,30 @@ function common_linkify($url) {
|
||||
$attachment_id = null;
|
||||
$has_thumb = false;
|
||||
|
||||
// Check to see whether there's a filename associated with this URL.
|
||||
// If there is, it's an upload and qualifies as an attachment
|
||||
// Check to see whether this is a known "attachment" URL.
|
||||
|
||||
$localfile = File::staticGet('url', $longurl);
|
||||
$f = File::staticGet('url', $longurl);
|
||||
|
||||
if (!empty($localfile)) {
|
||||
if (isset($localfile->filename)) {
|
||||
$is_attachment = true;
|
||||
$attachment_id = $localfile->id;
|
||||
}
|
||||
if (empty($f)) {
|
||||
// XXX: this writes to the database. :<
|
||||
$f = File::processNew($longurl);
|
||||
}
|
||||
|
||||
// if this URL is an attachment, then we set class='attachment' and id='attahcment-ID'
|
||||
// where ID is the id of the attachment for the given URL.
|
||||
//
|
||||
// we need a better test telling what can be shown as an attachment
|
||||
// we're currently picking up oembeds only.
|
||||
// I think the best option is another file_view table in the db
|
||||
// and associated dbobject.
|
||||
if (!empty($f)) {
|
||||
if (isset($f->filename)) {
|
||||
$is_attachment = true;
|
||||
$attachment_id = $f->id;
|
||||
} else { // if it has OEmbed info, it's an attachment, too
|
||||
$foe = File_oembed::staticGet('file_id', $f->id);
|
||||
if (!empty($foe)) {
|
||||
$is_attachment = true;
|
||||
$attachment_id = $f->id;
|
||||
|
||||
$query = "select file_oembed.file_id as file_id from file join file_oembed on file.id = file_oembed.file_id where file.url='$longurl'";
|
||||
$file = new File;
|
||||
$file->query($query);
|
||||
$file->fetch();
|
||||
|
||||
if (!empty($file->file_id)) {
|
||||
$is_attachment = true;
|
||||
$attachment_id = $file->file_id;
|
||||
|
||||
$query = "select file_thumbnail.file_id as file_id from file join file_thumbnail on file.id = file_thumbnail.file_id where file.url='$longurl'";
|
||||
$file2 = new File;
|
||||
$file2->query($query);
|
||||
$file2->fetch();
|
||||
|
||||
if (!empty($file2)) {
|
||||
$has_thumb = true;
|
||||
$thumb = File_thumbnail::staticGet('file_id', $f->id);
|
||||
if (!empty($thumb)) {
|
||||
$has_thumb = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,13 +142,20 @@ class SyncTwitterFriendsDaemon extends ParallelizingDaemon
|
||||
{
|
||||
$friends = array();
|
||||
|
||||
$token = TwitterOAuthClient::unpackToken($flink->credentials);
|
||||
$client = null;
|
||||
|
||||
$client = new TwitterOAuthClient($token->key, $token->secret);
|
||||
if (TwitterOAuthClient::isPackedToken($flink->credentials)) {
|
||||
$token = TwitterOAuthClient::unpackToken($flink->credentials);
|
||||
$client = new TwitterOAuthClient($token->key, $token->secret);
|
||||
common_debug($this->name() . '- Grabbing friends IDs with OAuth.');
|
||||
} else {
|
||||
$client = new TwitterBasicAuthClient($flink);
|
||||
common_debug($this->name() . '- Grabbing friends IDs with basic auth.');
|
||||
}
|
||||
|
||||
try {
|
||||
$friends_ids = $client->friendsIds();
|
||||
} catch (OAuthCurlException $e) {
|
||||
} catch (Exception $e) {
|
||||
common_log(LOG_WARNING, $this->name() .
|
||||
' - cURL error getting friend ids ' .
|
||||
$e->getCode() . ' - ' . $e->getMessage());
|
||||
@ -177,7 +184,7 @@ class SyncTwitterFriendsDaemon extends ParallelizingDaemon
|
||||
|
||||
try {
|
||||
$more_friends = $client->statusesFriends(null, null, null, $i);
|
||||
} catch (OAuthCurlException $e) {
|
||||
} catch (Exception $e) {
|
||||
common_log(LOG_WARNING, $this->name() .
|
||||
' - cURL error getting Twitter statuses/friends ' .
|
||||
"page $i - " . $e->getCode() . ' - ' .
|
||||
|
@ -148,9 +148,9 @@ class TwitterStatusFetcher extends ParallelizingDaemon
|
||||
|
||||
function getTimeline($flink)
|
||||
{
|
||||
if (empty($flink)) {
|
||||
if (empty($flink)) {
|
||||
common_log(LOG_WARNING, $this->name() .
|
||||
" - Can't retrieve Foreign_link for foreign ID $fid");
|
||||
" - Can't retrieve Foreign_link for foreign ID $fid");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -161,17 +161,24 @@ class TwitterStatusFetcher extends ParallelizingDaemon
|
||||
// to start importing? How many statuses? Right now I'm going
|
||||
// with the default last 20.
|
||||
|
||||
$token = TwitterOAuthClient::unpackToken($flink->credentials);
|
||||
$client = null;
|
||||
|
||||
$client = new TwitterOAuthClient($token->key, $token->secret);
|
||||
if (TwitterOAuthClient::isPackedToken($flink->credentials)) {
|
||||
$token = TwitterOAuthClient::unpackToken($flink->credentials);
|
||||
$client = new TwitterOAuthClient($token->key, $token->secret);
|
||||
common_debug($this->name() . ' - Grabbing friends timeline with OAuth.');
|
||||
} else {
|
||||
$client = new TwitterBasicAuthClient($flink);
|
||||
common_debug($this->name() . ' - Grabbing friends timeline with basic auth.');
|
||||
}
|
||||
|
||||
$timeline = null;
|
||||
|
||||
try {
|
||||
$timeline = $client->statusesFriendsTimeline();
|
||||
} catch (OAuthClientCurlException $e) {
|
||||
} catch (Exception $e) {
|
||||
common_log(LOG_WARNING, $this->name() .
|
||||
' - OAuth client unable to get friends timeline for user ' .
|
||||
' - Twitter client unable to get friends timeline for user ' .
|
||||
$flink->user_id . ' - code: ' .
|
||||
$e->getCode() . 'msg: ' . $e->getMessage());
|
||||
}
|
||||
|
@ -31,8 +31,12 @@ class URLDetectionTest extends PHPUnit_Framework_TestCase
|
||||
'<a href="http://127.0.0.1/" rel="external">127.0.0.1</a>'),
|
||||
array('127.0.0.1:99',
|
||||
'<a href="http://127.0.0.1:99/" rel="external">127.0.0.1:99</a>'),
|
||||
array('127.0.0.1/test.php',
|
||||
'<a href="http://127.0.0.1/test.php" rel="external">127.0.0.1/test.php</a>'),
|
||||
array('127.0.0.1/Name:test.php',
|
||||
'<a href="http://127.0.0.1/Name:test.php" rel="external">127.0.0.1/Name:test.php</a>'),
|
||||
array('127.0.0.1/~test',
|
||||
'<a href="http://127.0.0.1/~test" rel="external">127.0.0.1/~test</a>'),
|
||||
array('127.0.0.1/test%20stuff',
|
||||
'<a href="http://127.0.0.1/test%20stuff" rel="external">127.0.0.1/test%20stuff</a>'),
|
||||
array('http://[::1]:99/test.php',
|
||||
'<a href="http://[::1]:99/test.php" rel="external">http://[::1]:99/test.php</a>'),
|
||||
array('http://::1/test.php',
|
||||
|
Loading…
Reference in New Issue
Block a user