Commit c038164c authored by Brion Vibber's avatar Brion Vibber

Merge branch '0.9.x' of gitorious.org:statusnet/mainline into 0.9.x

parents 7b7f0919 45212391
......@@ -2,8 +2,8 @@
README
------
StatusNet 0.9.2 ("King of Birds")
3 May 2010
StatusNet 0.9.3 ("Half a World Away")
29 June 2010
This is the README file for StatusNet, the Open Source microblogging
platform. It includes installation instructions, descriptions of
......@@ -77,40 +77,27 @@ for additional terms.
New this version
================
This is a minor bug and feature release since version 0.9.1 released 28
March 2010.
This is a minor bug and feature release since version 0.9.2 released on
4 May 2010.
Because of fixes to OStatus bugs, it is highly recommended that all
public sites upgrade to the new version immediately.
For best compatibility with client software and site federation, and a lot of
bug fixes, it is highly recommended that all public sites upgrade to the new
version.
Notable changes this version:
- Installer no longer fails with a PHP fatal error when trying to set up the
subscription to update@status.net
- Fixed email notifications for @-replies that come in via OStatus
- OStatus related Fixes to the cloudy theme
- Pass geo locations over Twitter bridge (will only be used if enabled on the
Twitter side)
- scripts/showplugins.php - script to dump the list of activated plugins and
their settings
- scripts/fixup_blocks.php - script to finds any stray subscriptions in
violation of blocks, and removes them
- Allow blocking someone who's not currently subscribed to you (prevents
seeing @-replies from them, or them subbing to you in future)
- Default 2-second timeout on Geonames web service lookups
- Improved localization for plugins
- New anti-spam measures: added nofollow rels to group members list,
subscribers list
- Shared cache key option for Geonames plugin (lets multi-instance sites
share their cached geoname lookups)
- Stability fixes to the TwitterStatusFetcher
- If user allows location sharing but turned off browser location use profile
location
- Improved group listing via the API
- Improved FOAF output
- Several other bugfixes
A full changelog is available at http://status.net/wiki/StatusNet_0.9.2.
- Enhanced API output to aid StatusNet-specific clients
- Many updates to user interface translation from TranslateWiki
- OStatus now works subscribing to SSL-protected sites by default
- OpenID now works on PHP 5.3, supports closer site integration.
- Numerous API and FOAF output fixes.
- Fixes to Facebook integration for FB API behavior changes
- PostgreSQL support updates
- Initial version of a custom theme uploader (disabled by default)
- LDAP auth plugins cleanup
- Many other bugfixes
A full changelog is available at http://status.net/wiki/StatusNet_0.9.3.
Prerequisites
=============
......@@ -121,8 +108,8 @@ run correctly.
- PHP 5.2.3+. It may be possible to run this software on earlier
versions of PHP, but many of the functions used are only available
in PHP 5.2 or above. 5.2.6 or later is needed for XMPP background
daemons on 64-bit platforms. PHP 5.3.x should work but is known
to cause some failures for OpenID.
daemons on 64-bit platforms. PHP 5.3.x should work correctly in this
release, but problems with some plugins are possible.
- MySQL 5.x. The StatusNet database is stored, by default, in a MySQL
server. It has been primarily tested on 5.x servers, although it may
be possible to install on earlier (or later!) versions. The server
......
......@@ -75,7 +75,7 @@ class ApiAccountVerifyCredentialsAction extends ApiAuthAction
if ($this->format == 'xml') {
$this->initDocument('xml');
$this->showTwitterXmlUser($twitter_user);
$this->showTwitterXmlUser($twitter_user, 'user', true);
$this->endDocument('xml');
} elseif ($this->format == 'json') {
$this->initDocument('json');
......
......@@ -23,7 +23,7 @@
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009-2010 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/
*/
......@@ -65,7 +65,7 @@ class ApiBlockCreateAction extends ApiAuthAction
parent::prepare($args);
$this->user = $this->auth_user;
$this->other = $this->getTargetUser($this->arg('id'));
$this->other = $this->getTargetProfile($this->arg('id'));
return true;
}
......
......@@ -23,7 +23,7 @@
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009-2010 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/
*/
......@@ -64,7 +64,7 @@ class ApiBlockDestroyAction extends ApiAuthAction
parent::prepare($args);
$this->user = $this->auth_user;
$this->other = $this->getTargetUser($this->arg('id'));
$this->other = $this->getTargetProfile($this->arg('id'));
return true;
}
......
......@@ -24,7 +24,7 @@
* @author Dan Moore <dan@moore.cx>
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009-2010 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/
*/
......@@ -67,7 +67,7 @@ class ApiFriendshipsCreateAction extends ApiAuthAction
parent::prepare($args);
$this->user = $this->auth_user;
$this->other = $this->getTargetUser($id);
$this->other = $this->getTargetProfile($this->arg('id'));
return true;
}
......@@ -106,7 +106,7 @@ class ApiFriendshipsCreateAction extends ApiAuthAction
if (empty($this->other)) {
$this->clientError(
_('Could not follow user: User not found.'),
_('Could not follow user: profile not found.'),
403,
$this->format
);
......
......@@ -24,7 +24,7 @@
* @author Dan Moore <dan@moore.cx>
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009-2010 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/
*/
......@@ -67,7 +67,7 @@ class ApiFriendshipsDestroyAction extends ApiAuthAction
parent::prepare($args);
$this->user = $this->auth_user;
$this->other = $this->getTargetUser($id);
$this->other = $this->getTargetProfile($this->arg('id'));
return true;
}
......@@ -125,8 +125,7 @@ class ApiFriendshipsDestroyAction extends ApiAuthAction
}
// throws an exception on error
Subscription::cancel($this->user->getProfile(),
$this->other->getProfile());
Subscription::cancel($this->user->getProfile(), $this->other);
$this->initDocument($this->format);
$this->showProfile($this->other, $this->format);
......
......@@ -24,7 +24,7 @@
* @author Dan Moore <dan@moore.cx>
* @author Evan Prodromou <evan@status.net>
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009-2010 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/
*/
......@@ -50,8 +50,8 @@ require_once INSTALLDIR . '/lib/apiprivateauth.php';
class ApiFriendshipsExistsAction extends ApiPrivateAuthAction
{
var $user_a = null;
var $user_b = null;
var $profile_a = null;
var $profile_b = null;
/**
* Take arguments for running
......@@ -66,11 +66,8 @@ class ApiFriendshipsExistsAction extends ApiPrivateAuthAction
{
parent::prepare($args);
$user_a_id = $this->trimmed('user_a');
$user_b_id = $this->trimmed('user_b');
$this->user_a = $this->getTargetUser($user_a_id);
$this->user_b = $this->getTargetUser($user_b_id);
$this->profile_a = $this->getTargetProfile($this->trimmed('user_a'));
$this->profile_b = $this->getTargetProfile($this->trimmed('user_b'));
return true;
}
......@@ -89,16 +86,16 @@ class ApiFriendshipsExistsAction extends ApiPrivateAuthAction
{
parent::handle($args);
if (empty($this->user_a) || empty($this->user_b)) {
if (empty($this->profile_a) || empty($this->profile_b)) {
$this->clientError(
_('Two user ids or screen_names must be supplied.'),
_('Two valid IDs or screen_names must be supplied.'),
400,
$this->format
);
return;
}
$result = $this->user_a->isSubscribed($this->user_b);
$result = Subscription::exists($this->profile_a, $this->profile_b);
switch ($this->format) {
case 'xml':
......
......@@ -22,7 +22,7 @@
* @category Search
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @copyright 2008-2009 StatusNet, Inc.
* @copyright 2008-2010 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/
*/
......@@ -31,6 +31,8 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
require_once INSTALLDIR.'/lib/apiprivateauth.php';
/**
* Action for outputting search results in Twitter compatible Atom
* format.
......@@ -44,10 +46,10 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*
* @see ApiAction
* @see ApiPrivateAuthAction
*/
class TwitapisearchatomAction extends ApiAction
class ApiSearchAtomAction extends ApiPrivateAuthAction
{
var $cnt;
......@@ -96,8 +98,11 @@ class TwitapisearchatomAction extends ApiAction
function prepare($args)
{
common_debug("in apisearchatom prepare()");
parent::prepare($args);
$this->query = $this->trimmed('q');
$this->lang = $this->trimmed('lang');
$this->rpp = $this->trimmed('rpp');
......@@ -138,6 +143,7 @@ class TwitapisearchatomAction extends ApiAction
function handle($args)
{
parent::handle($args);
common_debug("In apisearchatom handle()");
$this->showAtom();
}
......
......@@ -22,7 +22,7 @@
* @category Search
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @copyright 2008-2009 StatusNet, Inc.
* @copyright 2008-2010 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/
*/
......@@ -31,6 +31,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
require_once INSTALLDIR.'/lib/apiprivateauth.php';
require_once INSTALLDIR.'/lib/jsonsearchresultslist.php';
/**
......@@ -44,7 +45,7 @@ require_once INSTALLDIR.'/lib/jsonsearchresultslist.php';
* @see ApiAction
*/
class TwitapisearchjsonAction extends ApiAction
class ApiSearchJSONAction extends ApiPrivateAuthAction
{
var $query;
var $lang;
......@@ -64,6 +65,8 @@ class TwitapisearchjsonAction extends ApiAction
function prepare($args)
{
common_debug("apisearchjson prepare()");
parent::prepare($args);
$this->query = $this->trimmed('q');
......
......@@ -206,7 +206,8 @@ class ApiSubscriptionsAction extends ApiBareAuthAction
{
switch ($this->format) {
case 'xml':
$this->elementStart('users', array('type' => 'array'));
$this->elementStart('users', array('type' => 'array',
'xmlns:statusnet' => 'http://status.net/schema/api/1/'));
foreach ($this->profiles as $profile) {
$this->showProfile(
$profile,
......
......@@ -22,7 +22,7 @@
* @category Search
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @copyright 2008-2009 StatusNet, Inc.
* @copyright 2008-2010 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/
*/
......@@ -31,6 +31,8 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
require_once INSTALLDIR.'/lib/apiprivateauth.php';
/**
* Returns the top ten queries that are currently trending
*
......@@ -43,7 +45,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
* @see ApiAction
*/
class TwitapitrendsAction extends ApiAction
class ApiTrendsAction extends ApiPrivateAuthAction
{
var $callback;
......@@ -82,7 +84,7 @@ class TwitapitrendsAction extends ApiAction
*/
function showTrends()
{
$this->serverError(_('API method under construction.'), $code = 501);
$this->serverError(_('API method under construction.'), 501);
}
}
\ No newline at end of file
......@@ -430,14 +430,6 @@ class ShowgroupAction extends GroupDesignAction
function showStatistics()
{
// XXX: WORM cache this
$members = $this->group->getMembers();
$members_count = 0;
/** $member->count() doesn't work. */
while ($members->fetch()) {
$members_count++;
}
$this->elementStart('div', array('id' => 'entity_statistics',
'class' => 'section'));
......@@ -451,7 +443,7 @@ class ShowgroupAction extends GroupDesignAction
$this->elementStart('dl', 'entity_members');
$this->element('dt', null, _('Members'));
$this->element('dd', null, (is_int($members_count)) ? $members_count : '0');
$this->element('dd', null, $this->group->getMemberCount());
$this->elementEnd('dl');
$this->elementEnd('div');
......
......@@ -302,6 +302,7 @@ class File extends Memcached_DataObject
if(! isset($this->filename)){
$notEnclosureMimeTypes = array(null,'text/html','application/xhtml+xml');
$mimetype = $this->mimetype;
if($mimetype != null){
$mimetype = strtolower($this->mimetype);
}
......
......@@ -1192,7 +1192,7 @@ class Notice extends Memcached_DataObject
'xmlns:media' => 'http://purl.org/syndication/atommedia',
'xmlns:poco' => 'http://portablecontacts.net/spec/1.0',
'xmlns:ostatus' => 'http://ostatus.org/schema/1.0',
'xmlns:statusnet' => 'http://status.net/ont/');
'xmlns:statusnet' => 'http://status.net/schema/api/1/');
} else {
$attrs = array();
}
......@@ -1227,7 +1227,7 @@ class Notice extends Memcached_DataObject
$xs->element('title', null, common_xml_safe_str($this->content));
if ($author) {
$xs->raw($profile->asAtomAuthor());
$xs->raw($profile->asAtomAuthor($cur));
$xs->raw($profile->asActivityActor());
}
......@@ -1240,9 +1240,25 @@ class Notice extends Memcached_DataObject
$xs->element('published', null, common_date_w3dtf($this->created));
$xs->element('updated', null, common_date_w3dtf($this->created));
$source = null;
$ns = $this->getSource();
if ($ns) {
if (!empty($ns->name) && !empty($ns->url)) {
$source = '<a href="'
. htmlspecialchars($ns->url)
. '" rel="nofollow">'
. htmlspecialchars($ns->name)
. '</a>';
} else {
$source = $ns->code;
}
}
$noticeInfoAttr = array(
'local_id' => $this->id, // local notice ID (useful to clients for ordering)
'source' => $this->source, // the client name (source attribution)
'local_id' => $this->id, // local notice ID (useful to clients for ordering)
'source' => $source, // the client name (source attribution)
);
$ns = $this->getSource();
......@@ -1254,8 +1270,8 @@ class Notice extends Memcached_DataObject
if (!empty($cur)) {
$noticeInfoAttr['favorite'] = ($cur->hasFave($this)) ? "true" : "false";
$profile = $cur->getProfile();
$noticeInfoAttr['repeated'] = ($profile->hasRepeated($this->id)) ? "true" : "false";
$profile = $cur->getProfile();
$noticeInfoAttr['repeated'] = ($profile->hasRepeated($this->id)) ? "true" : "false";
}
if (!empty($this->repeat_of)) {
......
......@@ -849,15 +849,23 @@ class Profile extends Memcached_DataObject
*
* Assumes that Atom has been previously set up as the base namespace.
*
* @param Profile $cur the current authenticated user
*
* @return string
*/
function asAtomAuthor()
function asAtomAuthor($cur = null)
{
$xs = new XMLStringer(true);
$xs->elementStart('author');
$xs->element('name', null, $this->nickname);
$xs->element('uri', null, $this->getUri());
if ($cur != null) {
$attrs = Array();
$attrs['following'] = $cur->isSubscribed($this) ? 'true' : 'false';
$attrs['blocking'] = $cur->hasBlocked($this) ? 'true' : 'false';
$xs->element('statusnet:profile_info', $attrs, null);
}
$xs->elementEnd('author');
return $xs->getString();
......
......@@ -64,4 +64,17 @@ class Queue_item extends Memcached_DataObject
$qi = null;
return null;
}
/**
* Release a claimed item.
*/
function releaseCLaim()
{
// DB_DataObject doesn't let us save nulls right now
$sql = sprintf("UPDATE queue_item SET claimed=NULL WHERE id=%d", $this->id);
$this->query($sql);
$this->claimed = null;
$this->encache();
}
}
......@@ -144,6 +144,35 @@ class Status_network extends Safe_DataObject
return parent::update($orig);
}
/**
* DB_DataObject doesn't allow updating keys (even non-primary)
*/
function updateKeys(&$orig)
{
$this->_connect();
foreach (array('hostname', 'pathname') as $k) {
if (strcmp($this->$k, $orig->$k) != 0) {
$parts[] = $k . ' = ' . $this->_quote($this->$k);
}
}
if (count($parts) == 0) {
// No changes
return true;
}
$toupdate = implode(', ', $parts);
$table = common_database_tablename($this->tableName());
$qry = 'UPDATE ' . $table . ' SET ' . $toupdate .
' WHERE nickname = ' . $this->_quote($this->nickname);
$orig->decache();
$result = $this->query($qry);
if ($result) {
$this->encache();
}
return $result;
}
function delete()
{
$this->decache(); # while we still have the values!
......
......@@ -154,6 +154,21 @@ class User_group extends Memcached_DataObject
return $members;
}
function getMemberCount()
{
// XXX: WORM cache this
$members = $this->getMembers();
$member_count = 0;
/** $member->count() doesn't work. */
while ($members->fetch()) {
$member_count++;
}
return $member_count;
}
function getAdmins($offset=0, $limit=null)
{
$qry =
......
......@@ -51,6 +51,7 @@ VALUES
('smob','SMOB','http://smob.sioc-project.org/', now()),
('socialoomphBfD4pMqz31', 'SocialOomph', 'http://www.socialoomph.com/', now()),
('spaz','Spaz','http://funkatron.com/spaz', now()),
('StatusNet Desktop', 'StatusNet Desktop', 'http://status.net/desktop', now()),
('tarpipe','tarpipe','http://tarpipe.com/', now()),
('tjunar','Tjunar','http://nederflash.nl/boek/titels/tjunar-air', now()),
('tr.im','tr.im','http://tr.im/', now()),
......
......@@ -20,7 +20,7 @@
/**
* The library version string
*/
define('Auth_OpenID_VERSION', '2.1.3');
define('Auth_OpenID_VERSION', '2.2.2');
/**
* Require the fetcher code.
......@@ -102,9 +102,7 @@ define('Auth_OpenID_digits',
define('Auth_OpenID_punct',
"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~");
if (Auth_OpenID_getMathLib() === null) {
Auth_OpenID_setNoMathSupport();
}
Auth_OpenID_include_init();
/**
* The OpenID utility function class.
......@@ -120,7 +118,7 @@ class Auth_OpenID {
*
* @access private
*/
function isFailure($thing)
static function isFailure($thing)
{
return is_a($thing, 'Auth_OpenID_FailureResponse');
}
......@@ -139,9 +137,12 @@ class Auth_OpenID {
* Returns an empty array if neither GET nor POST was used, or if
* POST was used but php://input cannot be opened.
*
* See background:
* http://lists.openidenabled.com/pipermail/dev/2007-March/000395.html
*
* @access private
*/
function getQuery($query_str=null)
static function getQuery($query_str=null)
{
$data = array();
......@@ -177,7 +178,7 @@ class Auth_OpenID {
return $data;
}
function params_from_string($str)
static function params_from_string($str)
{
$chunks = explode("&", $str);
......@@ -190,7 +191,7 @@ class Auth_OpenID {
}
list($k, $v) = $parts;
$data[$k] = urldecode($v);
$data[urldecode($k)] = urldecode($v);
}
return $data;
......@@ -203,7 +204,7 @@ class Auth_OpenID {
*
* @access private
*/
function ensureDir($dir_name)
static function ensureDir($dir_name)
{
if (is_dir($dir_name) || @mkdir($dir_name)) {
return true;
......@@ -225,7 +226,7 @@ class Auth_OpenID {
*
* @access private
*/
function addPrefix($values, $prefix)
static function addPrefix($values, $prefix)
{
$new_values = array();
foreach ($values as $s) {
......@@ -241,7 +242,7 @@ class Auth_OpenID {
*
* @access private
*/
function arrayGet($arr, $key, $fallback = null)
static function arrayGet($arr, $key, $fallback = null)
{
if (is_array($arr)) {
if (array_key_exists($key, $arr)) {
......@@ -261,7 +262,7 @@ class Auth_OpenID {
/**
* Replacement for PHP's broken parse_str.
*/
function parse_str($query)
static function parse_str($query)
{
if ($query === null) {
return null;
......@@ -278,7 +279,7 @@ class Auth_OpenID {
}
list($key, $value) = $pair;
$new_parts[$key] = urldecode($value);
$new_parts[urldecode($key)] = urldecode($value);
}
return $new_parts;
......@@ -295,7 +296,7 @@ class Auth_OpenID {
* pairs from $data into a URL query string
* (e.g. "username=bob&id=56").
*/
function httpBuildQuery($data)
static function httpBuildQuery($data)
{
$pairs = array();
foreach ($data as $key => $value) {
......@@ -323,7 +324,7 @@ class Auth_OpenID {
* @return string $url The original URL with the new parameters added.
*
*/
function appendArgs($url, $args)
static function appendArgs($url, $args)
{
if (count($args) == 0) {
return $url;
......@@ -367,7 +368,7 @@ class Auth_OpenID {