We are no longer offering accounts on this server. Consider https://gitlab.freedesktop.org/ as a place to host projects.

Commit a535ccdc authored by Craig Andrews's avatar Craig Andrews

Merge remote branch 'laconica/0.8.x' into 0.9.x

Conflicts:
	lib/common.php
	lib/twitter.php
parents f949c2c9 0c95734a
......@@ -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)) {
......
......@@ -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/
*/
......
......@@ -154,75 +154,126 @@ function broadcast_twitter($notice)
TWITTER_SERVICE);
if (is_twitter_bound($notice, $flink)) {
if (TwitterOAuthClient::isPackedToken($flink->credentials)) {
return broadcast_oauth($notice, $flink);
} else {
return broadcast_basicauth($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);
return true;
}
$token = TwitterOAuthClient::unpackToken($flink->credentials);
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);
}
$client = new TwitterOAuthClient($token->key, $token->secret);
if (empty($status)) {
$status = null;
// This could represent a failure posting,
// or the Twitter API might just be behaving flakey.
try {
$status = $client->statusesUpdate($statustxt);
} catch (OAuthClientCurlException $e) {
$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);
if ($e->getMessage() == 'The requested URL returned error: 401') {
return false;
}
$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);
// Notice crossed the great divide
// Bad auth token! We need to delete the foreign_link
// to Twitter and inform the user.