Merge branch 'testing' into 0.9.x

This commit is contained in:
Brion Vibber 2010-07-28 11:59:42 -07:00
commit ab2c3686b7
36 changed files with 453 additions and 119 deletions

View File

@ -143,10 +143,10 @@ class AllAction extends ProfileAction
$message .= _('Try subscribing to more people, [join a group](%%action.groups%%) or post something yourself.'); $message .= _('Try subscribing to more people, [join a group](%%action.groups%%) or post something yourself.');
} else { } else {
// TRANS: %1$s is user nickname, %2$s is user nickname, %2$s is user nickname prefixed with "@" // TRANS: %1$s is user nickname, %2$s is user nickname, %2$s is user nickname prefixed with "@"
$message .= sprintf(_('You can try to [nudge %1$s](../%2$s) from his profile or [post something to his or her attention](%%%%action.newnotice%%%%?status_textarea=%3$s).'), $this->user->nickname, $this->user->nickname, '@' . $this->user->nickname); $message .= sprintf(_('You can try to [nudge %1$s](../%2$s) from their profile or [post something to their attention](%%%%action.newnotice%%%%?status_textarea=%3$s).'), $this->user->nickname, $this->user->nickname, '@' . $this->user->nickname);
} }
} else { } else {
$message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to his or her attention.'), $this->user->nickname); $message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to their attention.'), $this->user->nickname);
} }
$this->elementStart('div', 'guide'); $this->elementStart('div', 'guide');

View File

@ -104,7 +104,7 @@ class FavorAction extends Action
} }
/** /**
* Notifies a user when his notice is favorited. * Notifies a user when their notice is favorited.
* *
* @param class $notice favorited notice * @param class $notice favorited notice
* @param class $user user declaring a favorite * @param class $user user declaring a favorite

View File

@ -37,7 +37,7 @@ require_once INSTALLDIR.'/lib/omb.php';
* Handler for remote subscription finish callback * Handler for remote subscription finish callback
* *
* When a remote user subscribes a local user, a redirect to this action is * When a remote user subscribes a local user, a redirect to this action is
* issued after the remote user authorized his service to subscribe. * issued after the remote user authorized their service to subscribe.
* *
* @category Action * @category Action
* @package Laconica * @package Laconica

View File

@ -82,7 +82,7 @@ class NudgeAction extends Action
} }
if (!$other->email || !$other->emailnotifynudge) { if (!$other->email || !$other->emailnotifynudge) {
$this->clientError(_('This user doesn\'t allow nudges or hasn\'t confirmed or set his email yet.')); $this->clientError(_('This user doesn\'t allow nudges or hasn\'t confirmed or set their email yet.'));
return; return;
} }

View File

@ -196,18 +196,18 @@ class RepliesAction extends OwnerDesignAction
function showEmptyListMessage() function showEmptyListMessage()
{ {
$message = sprintf(_('This is the timeline showing replies to %1$s but %2$s hasn\'t received a notice to his attention yet.'), $this->user->nickname, $this->user->nickname) . ' '; $message = sprintf(_('This is the timeline showing replies to %1$s but %2$s hasn\'t received a notice to their attention yet.'), $this->user->nickname, $this->user->nickname) . ' ';
if (common_logged_in()) { if (common_logged_in()) {
$current_user = common_current_user(); $current_user = common_current_user();
if ($this->user->id === $current_user->id) { if ($this->user->id === $current_user->id) {
$message .= _('You can engage other users in a conversation, subscribe to more people or [join groups](%%action.groups%%).'); $message .= _('You can engage other users in a conversation, subscribe to more people or [join groups](%%action.groups%%).');
} else { } else {
$message .= sprintf(_('You can try to [nudge %1$s](../%2$s) or [post something to his or her attention](%%%%action.newnotice%%%%?status_textarea=%3$s).'), $this->user->nickname, $this->user->nickname, '@' . $this->user->nickname); $message .= sprintf(_('You can try to [nudge %1$s](../%2$s) or [post something to their attention](%%%%action.newnotice%%%%?status_textarea=%3$s).'), $this->user->nickname, $this->user->nickname, '@' . $this->user->nickname);
} }
} }
else { else {
$message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to his or her attention.'), $this->user->nickname); $message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to their attention.'), $this->user->nickname);
} }
$this->elementStart('div', 'guide'); $this->elementStart('div', 'guide');

View File

@ -119,7 +119,7 @@ class ShowfavoritesAction extends OwnerDesignAction
if (!empty($cur) && $cur->id == $this->user->id) { if (!empty($cur) && $cur->id == $this->user->id) {
// Show imported/gateway notices as well as local if // Show imported/gateway notices as well as local if
// the user is looking at his own favorites // the user is looking at their own favorites
$this->notice = $this->user->favoriteNotices(true, ($this->page-1)*NOTICES_PER_PAGE, $this->notice = $this->user->favoriteNotices(true, ($this->page-1)*NOTICES_PER_PAGE,
NOTICES_PER_PAGE + 1); NOTICES_PER_PAGE + 1);
@ -205,11 +205,11 @@ class ShowfavoritesAction extends OwnerDesignAction
if ($this->user->id === $current_user->id) { if ($this->user->id === $current_user->id) {
$message = _('You haven\'t chosen any favorite notices yet. Click the fave button on notices you like to bookmark them for later or shed a spotlight on them.'); $message = _('You haven\'t chosen any favorite notices yet. Click the fave button on notices you like to bookmark them for later or shed a spotlight on them.');
} else { } else {
$message = sprintf(_('%s hasn\'t added any notices to his favorites yet. Post something interesting they would add to their favorites :)'), $this->user->nickname); $message = sprintf(_('%s hasn\'t added any favorite notices yet. Post something interesting they would add to their favorites :)'), $this->user->nickname);
} }
} }
else { else {
$message = sprintf(_('%s hasn\'t added any notices to his favorites yet. Why not [register an account](%%%%action.register%%%%) and then post something interesting they would add to their favorites :)'), $this->user->nickname); $message = sprintf(_('%s hasn\'t added any favorite notices yet. Why not [register an account](%%%%action.register%%%%) and then post something interesting they would add to their favorites :)'), $this->user->nickname);
} }
$this->elementStart('div', 'guide'); $this->elementStart('div', 'guide');

View File

@ -204,11 +204,11 @@ class ShowstreamAction extends ProfileAction
if ($this->user->id === $current_user->id) { if ($this->user->id === $current_user->id) {
$message .= _('Seen anything interesting recently? You haven\'t posted any notices yet, now would be a good time to start :)'); $message .= _('Seen anything interesting recently? You haven\'t posted any notices yet, now would be a good time to start :)');
} else { } else {
$message .= sprintf(_('You can try to nudge %1$s or [post something to his or her attention](%%%%action.newnotice%%%%?status_textarea=%2$s).'), $this->user->nickname, '@' . $this->user->nickname); $message .= sprintf(_('You can try to nudge %1$s or [post something to their attention](%%%%action.newnotice%%%%?status_textarea=%2$s).'), $this->user->nickname, '@' . $this->user->nickname);
} }
} }
else { else {
$message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to his or her attention.'), $this->user->nickname); $message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to their attention.'), $this->user->nickname);
} }
$this->elementStart('div', 'guide'); $this->elementStart('div', 'guide');

View File

@ -39,6 +39,22 @@ class Foreign_user extends Memcached_DataObject
return null; return null;
} }
static function getByNickname($nickname, $service)
{
if (empty($nickname) || empty($service)) {
return null;
} else {
$fuser = new Foreign_user();
$fuser->service = $service;
$fuser->nickname = $nickname;
$fuser->limit(1);
$result = $fuser->find(true);
return empty($result) ? null : $fuser;
}
}
function updateKeys(&$orig) function updateKeys(&$orig)
{ {
$this->_connect(); $this->_connect();

View File

@ -593,7 +593,7 @@ class Memcached_DataObject extends Safe_DataObject
return $c->get($cacheKey); return $c->get($cacheKey);
} }
static function cacheSet($keyPart, $value) static function cacheSet($keyPart, $value, $flag=null, $expiry=null)
{ {
$c = self::memcache(); $c = self::memcache();
@ -603,7 +603,7 @@ class Memcached_DataObject extends Safe_DataObject
$cacheKey = common_cache_key($keyPart); $cacheKey = common_cache_key($keyPart);
return $c->set($cacheKey, $value); return $c->set($cacheKey, $value, $flag, $expiry);
} }
static function valueString($v) static function valueString($v)

View File

@ -42,10 +42,10 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
*/ */
require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
/* We keep the first three 20-notice pages, plus one for pagination check, /* We keep 200 notices, the max number of notices available per API request,
* in the memcached cache. */ * in the memcached cache. */
define('NOTICE_CACHE_WINDOW', 61); define('NOTICE_CACHE_WINDOW', 200);
define('MAX_BOXCARS', 128); define('MAX_BOXCARS', 128);
@ -90,7 +90,13 @@ class Notice extends Memcached_DataObject
function getProfile() function getProfile()
{ {
return Profile::staticGet('id', $this->profile_id); $profile = Profile::staticGet('id', $this->profile_id);
if (empty($profile)) {
throw new ServerException(sprintf(_('No such profile (%d) for notice (%d)'), $this->profile_id, $this->id));
}
return $profile;
} }
function delete() function delete()

View File

@ -27,7 +27,8 @@ class Status_network extends Safe_DataObject
/* the code below is auto generated do not remove the above tag */ /* the code below is auto generated do not remove the above tag */
public $__table = 'status_network'; // table name public $__table = 'status_network'; // table name
public $nickname; // varchar(64) primary_key not_null public $site_id; // int(4) primary_key not_null
public $nickname; // varchar(64) unique_key not_null
public $hostname; // varchar(255) unique_key public $hostname; // varchar(255) unique_key
public $pathname; // varchar(255) unique_key public $pathname; // varchar(255) unique_key
public $dbhost; // varchar(255) public $dbhost; // varchar(255)
@ -39,7 +40,6 @@ class Status_network extends Safe_DataObject
public $logo; // varchar(255) public $logo; // varchar(255)
public $created; // datetime() not_null public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
public $tags; // text
/* Static get */ /* Static get */
function staticGet($k,$v=NULL) { function staticGet($k,$v=NULL) {
@ -308,9 +308,62 @@ class Status_network extends Safe_DataObject
*/ */
function getTags() function getTags()
{ {
return array_filter(explode("|", strval($this->tags))); $result = array();
$tags = new Status_network_tag();
$tags->site_id = $this->site_id;
if ($tags->find()) {
while ($tags->fetch()) {
$result[] = $tags->tag;
}
}
// XXX : for backwards compatibility
if (empty($result)) {
return explode('|', $this->tags);
}
return $result;
} }
/**
* Save a given set of tags
* @param array tags
*/
function setTags($tags)
{
$this->clearTags();
foreach ($tags as $tag) {
if (!empty($tag)) {
$snt = new Status_network_tag();
$snt->site_id = $this->site_id;
$snt->tag = $tag;
$snt->created = common_sql_now();
$id = $snt->insert();
if (!$id) {
throw new Exception(_("Unable to save tag."));
}
}
}
return true;
}
function clearTags()
{
$tag = new Status_network_tag();
$tag->site_id = $this->site_id;
if ($tag->find()) {
while($tag->fetch()) {
$tag->delete();
}
}
$tag->free();
}
/** /**
* Check if this site record has a particular meta-info tag attached. * Check if this site record has a particular meta-info tag attached.
* @param string $tag * @param string $tag

View File

@ -0,0 +1,69 @@
<?php
/*
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2008, 2009, 2010 StatusNet, Inc.
*
* 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/>.
*/
if (!defined('STATUSNET')) { exit(1); }
class Status_network_tag extends Safe_DataObject
{
###START_AUTOCODE
/* the code below is auto generated do not remove the above tag */
public $__table = 'status_network_tag'; // table name
public $site_id; // int(4) primary_key not_null
public $tag; // varchar(64) primary_key not_null
public $created; // datetime() not_null
function __construct()
{
global $config;
global $_DB_DATAOBJECT;
$sn = new Status_network();
$sn->_connect();
$config['db']['table_'. $this->__table] = $sn->_database;
$this->_connect();
}
/* Static get */
function staticGet($k,$v=null)
{
$i = DB_DataObject::staticGet('Status_network_tag',$k,$v);
// Don't use local process cache; if we're fetching multiple
// times it's because we're reloading it in a long-running
// process; we need a fresh copy!
global $_DB_DATAOBJECT;
unset($_DB_DATAOBJECT['CACHE']['status_network_tag']);
return $i;
}
/* the code above is auto generated do not remove the tag below */
###END_AUTOCODE
function pkeyGet($kv)
{
return Memcached_DataObject::pkeyGet('Status_network_tag', $kv);
}
}

View File

@ -524,7 +524,7 @@ class User extends Memcached_DataObject
if ($this->id == $other->id) { if ($this->id == $other->id) {
common_log(LOG_WARNING, common_log(LOG_WARNING,
sprintf( sprintf(
"Profile ID %d (%s) tried to block his or herself.", "Profile ID %d (%s) tried to block themself.",
$this->id, $this->id,
$this->nickname $this->nickname
) )

View File

@ -1,4 +1,5 @@
[status_network] [status_network]
side_id = 129
nickname = 130 nickname = 130
hostname = 2 hostname = 2
pathname = 2 pathname = 2
@ -11,9 +12,19 @@ theme = 2
logo = 2 logo = 2
created = 142 created = 142
modified = 384 modified = 384
tags = 34
[status_network__keys] [status_network__keys]
nickname = K site_id = K
nickname = U
hostname = U hostname = U
pathname = U pathname = U
[status_network_tag]
site_id = 129
tag = 130
created = 142
[status_network_tag__keys]
site_id = K
tag = K

View File

@ -1,8 +1,9 @@
/* For managing multiple sites */ /* For managing multiple sites */
create table status_network ( create table status_network (
nickname varchar(64) primary key comment 'nickname', site_id integer auto_increment primary key comment 'unique id',
nickname varchar(64) unique key comment 'nickname',
hostname varchar(255) unique key comment 'alternate hostname if any', hostname varchar(255) unique key comment 'alternate hostname if any',
pathname varchar(255) unique key comment 'alternate pathname if any', pathname varchar(255) unique key comment 'alternate pathname if any',
@ -21,3 +22,12 @@ create table status_network (
modified timestamp comment 'date this record was modified' modified timestamp comment 'date this record was modified'
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci; ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;
create table status_network_tag (
site_id integer comment 'unique id',
tag varchar(64) comment 'tag name',
created datetime not null comment 'date the record was created',
constraint primary key (site_id, tag)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;

13
db/site_093to094.sql Normal file
View File

@ -0,0 +1,13 @@
alter table status_network
drop primary key,
add column site_id integer auto_increment primary key first,
add unique key (nickname);
create table status_network_tag (
site_id integer comment 'unique id',
tag varchar(64) comment 'tag name',
created datetime not null comment 'date the record was created',
constraint primary key (site_id, tag)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;

View File

@ -374,7 +374,42 @@ class Auth_OpenID_Association {
} }
$calculated_sig = $this->getMessageSignature($message); $calculated_sig = $this->getMessageSignature($message);
return $calculated_sig == $sig;
return $this->constantTimeCompare($calculated_sig, $sig);
}
/**
* String comparison function which will complete in a constant time
* for strings of any given matching length, to help prevent an attacker
* from distinguishing how much of a signature token they have guessed
* correctly.
*
* For this usage, it's assumed that the length of the string is known,
* so we may safely short-circuit on mismatched lengths which will be known
* to be invalid by the attacker.
*
* http://lists.openid.net/pipermail/openid-security/2010-July/001156.html
* http://rdist.root.org/2010/01/07/timing-independent-array-comparison/
*/
private function constantTimeCompare($a, $b)
{
$len = strlen($a);
if (strlen($b) !== $len) {
// Short-circuit on length mismatch; attackers will already know
// the correct target length so this is safe.
return false;
}
if ($len == 0) {
// 0-length valid input shouldn't really happen. :)
return true;
}
$result = 0;
for ($i = 0; $i < strlen($a); $i++) {
// We use scary bitwise operations to avoid logical short-circuits
// in lower-level code.
$result |= ord($a{$i}) ^ ord($b{$i});
}
return ($result == 0);
} }
} }

View File

@ -54,6 +54,24 @@ class OAuthSignatureMethod {/*{{{*/
public function check_signature(&$request, $consumer, $token, $signature) { public function check_signature(&$request, $consumer, $token, $signature) {
$built = $this->build_signature($request, $consumer, $token); $built = $this->build_signature($request, $consumer, $token);
return $built == $signature; return $built == $signature;
// Check for zero length, although unlikely here
if (strlen($built) == 0 || strlen($signature) == 0) {
return false;
}
if (strlen($built) != strlen($signature)) {
return false;
}
$result = 0;
// Avoid a timing leak with a (hopefully) time insensitive compare
for ($i = 0; $i < strlen($signature); $i++) {
$result |= ord($built{$i}) ^ ord($signature{$i});
}
return $result == 0;
} }
}/*}}}*/ }/*}}}*/

View File

@ -257,6 +257,12 @@ class ActivityUtils
*/ */
static function validateUri($uri) static function validateUri($uri)
{ {
// Check mailto: URIs first
if (preg_match('/^mailto:(.*)$/', $uri, $match)) {
return Validate::email($match[1], common_config('email', 'check_domain'));
}
if (Validate::uri($uri)) { if (Validate::uri($uri)) {
return true; return true;
} }

View File

@ -126,6 +126,7 @@ class ApiAction extends Action
var $max_id = null; var $max_id = null;
var $since_id = null; var $since_id = null;
var $source = null; var $source = null;
var $callback = null;
var $access = self::READ_ONLY; // read (default) or read-write var $access = self::READ_ONLY; // read (default) or read-write
@ -145,6 +146,7 @@ class ApiAction extends Action
parent::prepare($args); parent::prepare($args);
$this->format = $this->arg('format'); $this->format = $this->arg('format');
$this->callback = $this->arg('callback');
$this->page = (int)$this->arg('page', 1); $this->page = (int)$this->arg('page', 1);
$this->count = (int)$this->arg('count', 20); $this->count = (int)$this->arg('count', 20);
$this->max_id = (int)$this->arg('max_id', 0); $this->max_id = (int)$this->arg('max_id', 0);
@ -461,6 +463,7 @@ class ApiAction extends Action
function twitterRssEntryArray($notice) function twitterRssEntryArray($notice)
{ {
$profile = $notice->getProfile(); $profile = $notice->getProfile();
$entry = array(); $entry = array();
// We trim() to avoid extraneous whitespace in the output // We trim() to avoid extraneous whitespace in the output
@ -733,14 +736,16 @@ class ApiAction extends Action
'xmlns:statusnet' => 'http://status.net/schema/api/1/')); 'xmlns:statusnet' => 'http://status.net/schema/api/1/'));
if (is_array($notice)) { if (is_array($notice)) {
foreach ($notice as $n) { $notice = new ArrayWrapper($notice);
$twitter_status = $this->twitterStatusArray($n); }
$this->showTwitterXmlStatus($twitter_status);
} while ($notice->fetch()) {
} else { try {
while ($notice->fetch()) {
$twitter_status = $this->twitterStatusArray($notice); $twitter_status = $this->twitterStatusArray($notice);
$this->showTwitterXmlStatus($twitter_status); $this->showTwitterXmlStatus($twitter_status);
} catch (Exception $e) {
common_log(LOG_ERR, $e->getMessage());
continue;
} }
} }
@ -788,14 +793,16 @@ class ApiAction extends Action
$this->element('ttl', null, '40'); $this->element('ttl', null, '40');
if (is_array($notice)) { if (is_array($notice)) {
foreach ($notice as $n) { $notice = new ArrayWrapper($notice);
$entry = $this->twitterRssEntryArray($n); }
$this->showTwitterRssItem($entry);
} while ($notice->fetch()) {
} else { try {
while ($notice->fetch()) {
$entry = $this->twitterRssEntryArray($notice); $entry = $this->twitterRssEntryArray($notice);
$this->showTwitterRssItem($entry); $this->showTwitterRssItem($entry);
} catch (Exception $e) {
common_log(LOG_ERR, $e->getMessage());
// continue on exceptions
} }
} }
@ -831,12 +838,15 @@ class ApiAction extends Action
$this->element('subtitle', null, $subtitle); $this->element('subtitle', null, $subtitle);
if (is_array($notice)) { if (is_array($notice)) {
foreach ($notice as $n) { $notice = new ArrayWrapper($notice);
$this->raw($n->asAtomEntry()); }
}
} else { while ($notice->fetch()) {
while ($notice->fetch()) { try {
$this->raw($notice->asAtomEntry()); $this->raw($notice->asAtomEntry());
} catch (Exception $e) {
common_log(LOG_ERR, $e->getMessage());
continue;
} }
} }
@ -1031,14 +1041,16 @@ class ApiAction extends Action
$statuses = array(); $statuses = array();
if (is_array($notice)) { if (is_array($notice)) {
foreach ($notice as $n) { $notice = new ArrayWrapper($notice);
$twitter_status = $this->twitterStatusArray($n); }
array_push($statuses, $twitter_status);
} while ($notice->fetch()) {
} else { try {
while ($notice->fetch()) {
$twitter_status = $this->twitterStatusArray($notice); $twitter_status = $this->twitterStatusArray($notice);
array_push($statuses, $twitter_status); array_push($statuses, $twitter_status);
} catch (Exception $e) {
common_log(LOG_ERR, $e->getMessage());
continue;
} }
} }
@ -1175,9 +1187,8 @@ class ApiAction extends Action
header('Content-Type: application/json; charset=utf-8'); header('Content-Type: application/json; charset=utf-8');
// Check for JSONP callback // Check for JSONP callback
$callback = $this->arg('callback'); if (isset($this->callback)) {
if ($callback) { print $this->callback . '(';
print $callback . '(';
} }
break; break;
case 'rss': case 'rss':
@ -1206,8 +1217,7 @@ class ApiAction extends Action
case 'json': case 'json':
// Check for JSONP callback // Check for JSONP callback
$callback = $this->arg('callback'); if (isset($this->callback)) {
if ($callback) {
print ')'; print ')';
} }
break; break;
@ -1237,7 +1247,10 @@ class ApiAction extends Action
$status_string = ClientErrorAction::$status[$code]; $status_string = ClientErrorAction::$status[$code];
header('HTTP/1.1 '.$code.' '.$status_string); // Do not emit error header for JSONP
if (!isset($this->callback)) {
header('HTTP/1.1 '.$code.' '.$status_string);
}
if ($format == 'xml') { if ($format == 'xml') {
$this->initDocument('xml'); $this->initDocument('xml');
@ -1270,7 +1283,10 @@ class ApiAction extends Action
$status_string = ServerErrorAction::$status[$code]; $status_string = ServerErrorAction::$status[$code];
header('HTTP/1.1 '.$code.' '.$status_string); // Do not emit error header for JSONP
if (!isset($this->callback)) {
header('HTTP/1.1 '.$code.' '.$status_string);
}
if ($content_type == 'xml') { if ($content_type == 'xml') {
$this->initDocument('xml'); $this->initDocument('xml');

View File

@ -227,7 +227,7 @@ class ApiAuthAction extends ApiAction
} catch (OAuthException $e) { } catch (OAuthException $e) {
common_log(LOG_WARNING, 'API OAuthException - ' . $e->getMessage()); common_log(LOG_WARNING, 'API OAuthException - ' . $e->getMessage());
$this->showAuthError(); $this->clientError($e->getMessage(), 401, $this->format);
exit; exit;
} }
} }
@ -265,7 +265,7 @@ class ApiAuthAction extends ApiAction
// show error if the user clicks 'cancel' // show error if the user clicks 'cancel'
$this->showAuthError(); $this->clientError("Could not authenticate you.", 401, $this->format);
exit; exit;
} else { } else {
@ -298,7 +298,7 @@ class ApiAuthAction extends ApiAction
$proxy, $proxy,
$ip); $ip);
common_log(LOG_WARNING, $msg); common_log(LOG_WARNING, $msg);
$this->showAuthError(); $this->clientError("Could not authenticate you.", 401, $this->format);
exit; exit;
} }
} }
@ -345,36 +345,4 @@ class ApiAuthAction extends ApiAction
} }
} }
} }
/**
* Output an authentication error message. Use XML or JSON if one
* of those formats is specified, otherwise output plain text
*
* @return void
*/
function showAuthError()
{
header('HTTP/1.1 401 Unauthorized');
$msg = 'Could not authenticate you.';
if ($this->format == 'xml') {
header('Content-Type: application/xml; charset=utf-8');
$this->startXML();
$this->elementStart('hash');
$this->element('error', null, $msg);
$this->element('request', null, $_SERVER['REQUEST_URI']);
$this->elementEnd('hash');
$this->endXML();
} elseif ($this->format == 'json') {
header('Content-Type: application/json; charset=utf-8');
$error_array = array('error' => $msg,
'request' => $_SERVER['REQUEST_URI']);
print(json_encode($error_array));
} else {
header('Content-type: text/plain');
print "$msg\n";
}
}
} }

View File

@ -125,12 +125,17 @@ class AtomNoticeFeed extends Atom10Feed
*/ */
function addEntryFromNotice($notice) function addEntryFromNotice($notice)
{ {
$source = $this->showSource(); try {
$author = $this->showAuthor(); $source = $this->showSource();
$author = $this->showAuthor();
$cur = empty($this->cur) ? common_current_user() : $this->cur; $cur = empty($this->cur) ? common_current_user() : $this->cur;
$this->addEntryRaw($notice->asAtomEntry(false, $source, $author, $cur)); $this->addEntryRaw($notice->asAtomEntry(false, $source, $author, $cur));
} catch (Exception $e) {
common_log(LOG_ERR, $e->getMessage());
// we continue on exceptions
}
} }
function showSource() function showSource()

View File

@ -96,8 +96,14 @@ class NoticeList extends Widget
break; break;
} }
$item = $this->newListItem($this->notice); try {
$item->show(); $item = $this->newListItem($this->notice);
$item->show();
} catch (Exception $e) {
// we log exceptions and continue
common_log(LOG_ERR, $e->getMessage());
continue;
}
} }
$this->out->elementEnd('ol'); $this->out->elementEnd('ol');

View File

@ -178,7 +178,13 @@ class Rss10Action extends Action
if (count($this->notices)) { if (count($this->notices)) {
foreach ($this->notices as $n) { foreach ($this->notices as $n) {
$this->showItem($n); try {
$this->showItem($n);
} catch (Exception $e) {
// log exceptions and continue
common_log(LOG_ERR, $e->getMessage());
continue;
}
} }
} }
@ -232,7 +238,7 @@ class Rss10Action extends Action
function showItem($notice) function showItem($notice)
{ {
$profile = Profile::staticGet($notice->profile_id); $profile = $notice->getProfile();
$nurl = common_local_url('shownotice', array('notice' => $notice->id)); $nurl = common_local_url('shownotice', array('notice' => $notice->id));
$creator_uri = common_profile_uri($profile); $creator_uri = common_profile_uri($profile);
$this->elementStart('item', array('rdf:about' => $notice->uri, $this->elementStart('item', array('rdf:about' => $notice->uri,

View File

@ -202,6 +202,12 @@ class SitemapPlugin extends Plugin
null, false), null, false),
new ColumnDef('modified', 'timestamp'))); new ColumnDef('modified', 'timestamp')));
$userCreated = $schema->getColumnDef('user', 'created');
if (empty($userCreated) || $userCreated->key != 'MUL') {
$schema->createIndex('user', 'created');
}
return true; return true;
} }

View File

@ -153,7 +153,9 @@ class Sitemap_notice_count extends Memcached_DataObject
$noticeCounts[$snc->notice_date] = $snc->notice_count; $noticeCounts[$snc->notice_date] = $snc->notice_count;
} }
self::cacheSet('sitemap:notice:counts', $noticeCounts); // Cache notice counts for 4 hours.
self::cacheSet('sitemap:notice:counts', $noticeCounts, null, time() + 4 * 60 * 60);
} }
return $noticeCounts; return $noticeCounts;

View File

@ -154,7 +154,9 @@ class Sitemap_user_count extends Memcached_DataObject
$userCounts[$suc->registration_date] = $suc->user_count; $userCounts[$suc->registration_date] = $suc->user_count;
} }
self::cacheSet('sitemap:user:counts', $userCounts); // Cache user counts for 4 hours.
self::cacheSet('sitemap:user:counts', $userCounts, null, time() + 4 * 60 * 60);
} }
return $userCounts; return $userCounts;

View File

@ -0,0 +1,36 @@
#!/usr/bin/env php
<?php
/*
* StatusNet - a distributed open-source microblogging tool
* Copyright (C) 2010, StatusNet, Inc.
*
* 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/>.
*/
define('INSTALLDIR', realpath(dirname(__FILE__) . '/../../..'));
$helptext = <<<END_OF_UPDATECOUNTS_HELP
updatecounts.php [options]
Update the notice and user counts cached in the database.
END_OF_UPDATECOUNTS_HELP;
require_once INSTALLDIR.'/scripts/commandline.inc';
// Will fill the cache
$userCounts = Sitemap_user_count::getAll();
$noticeCounts = Sitemap_notice_count::getAll();
echo "Done.\n";

View File

@ -75,8 +75,6 @@ function save_twitter_user($twitter_id, $screen_name)
if (!empty($fuser)) { if (!empty($fuser)) {
$result = true;
// Delete old record if Twitter user changed screen name // Delete old record if Twitter user changed screen name
if ($fuser->nickname != $screen_name) { if ($fuser->nickname != $screen_name) {
@ -88,6 +86,25 @@ function save_twitter_user($twitter_id, $screen_name)
$screen_name, $screen_name,
$oldname)); $oldname));
} }
} else {
// Kill any old, invalid records for this screen name
$fuser = Foreign_user::getByNickname($screen_name, TWITTER_SERVICE);
if (!empty($fuser)) {
$fuser->delete();
common_log(
LOG_INFO,
sprintf(
'Twitter bridge - deteted old record for Twitter ' .
'screen name "%s" belonging to Twitter ID %d.',
$screen_name,
$fuser->id
)
);
}
} }
return add_twitter_user($twitter_id, $screen_name); return add_twitter_user($twitter_id, $screen_name);

View File

@ -0,0 +1,37 @@
#!/usr/bin/env php
<?php
/*
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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/>.
*/
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
require_once INSTALLDIR.'/scripts/commandline.inc';
common_log(LOG_INFO, 'Beginning status_network conversion...');
$sn = new Status_network();
$sn->find();
while ($sn->fetch()) {
try {
$sn->setTags(explode('|', $sn->tags));
} catch (Exception $e) {
common_log(LOG_ERR, $e->getMessage());
}
}
common_log(LOG_INFO, 'Completed status_network conversion...');

View File

@ -39,11 +39,10 @@ if (count($args) < 1) {
} }
$nickname = $args[0]; $nickname = $args[0];
$sn = Status_network::memGet('nickname', $nickname); $sn = Status_network::memGet('nickname', $nickname);
if (empty($sn)) { if (empty($sn)) {
print "No such site.\n"; print "No such site ($nickname).\n";
exit(-1); exit(-1);
} }
@ -54,16 +53,13 @@ if (count($args) == 1) {
exit(0); exit(0);
} }
$tag = $args[1]; $tag = $args[1];
$i = array_search($tag, $tags); $i = array_search($tag, $tags);
if ($i !== false) { if ($i !== false) {
if (have_option('d', 'delete')) { // Delete if (have_option('d', 'delete')) { // Delete
unset($tags[$i]); unset($tags[$i]);
$orig = clone($sn); $result = $sn->setTags($tags);
$sn->tags = implode('|', $tags);
$result = $sn->update($orig);
if (!$result) { if (!$result) {
print "Couldn't update.\n"; print "Couldn't update.\n";
exit(-1); exit(-1);
@ -78,9 +74,7 @@ if ($i !== false) {
exit(-1); exit(-1);
} else { } else {
$tags[] = $tag; $tags[] = $tag;
$orig = clone($sn); $result = $sn->setTags($tags);
$sn->tags = implode('|', $tags);
$result = $sn->update($orig);
if (!$result) { if (!$result) {
print "Couldn't update.\n"; print "Couldn't update.\n";
exit(-1); exit(-1);

View File

@ -44,8 +44,8 @@ mysql -h $DBHOST -u $ADMIN --password=$ADMINPASS $SITEDB << ENDOFCOMMANDS
GRANT ALL ON $database.* TO '$username'@'localhost' IDENTIFIED BY '$password'; GRANT ALL ON $database.* TO '$username'@'localhost' IDENTIFIED BY '$password';
GRANT ALL ON $database.* TO '$username'@'%' IDENTIFIED BY '$password'; GRANT ALL ON $database.* TO '$username'@'%' IDENTIFIED BY '$password';
INSERT INTO status_network (nickname, dbhost, dbuser, dbpass, dbname, sitename, created, tags) INSERT INTO status_network (nickname, dbhost, dbuser, dbpass, dbname, sitename, created)
VALUES ('$nickname', '$DBHOSTNAME', '$username', '$password', '$database', '$sitename', now(), '$tags'); VALUES ('$nickname', '$DBHOSTNAME', '$username', '$password', '$database', '$sitename', now());
ENDOFCOMMANDS ENDOFCOMMANDS
@ -56,6 +56,8 @@ done
php $PHPBASE/scripts/checkschema.php -s"$server" php $PHPBASE/scripts/checkschema.php -s"$server"
php $PHPBASE/scripts/settag.php -s"$server" "$nickname" "$tags"
php $PHPBASE/scripts/registeruser.php \ php $PHPBASE/scripts/registeruser.php \
-s"$server" \ -s"$server" \
-n"$nickname" \ -n"$nickname" \

View File

@ -7,7 +7,7 @@
* @link http://status.net/ * @link http://status.net/
*/ */
@import url(base.css) screen, projection, tv, print; @import url(base.css);
@media screen, projection, tv { @media screen, projection, tv {
html { html {

View File

@ -7,7 +7,7 @@
* @link http://status.net/ * @link http://status.net/
*/ */
@import url(../../base/css/display.css) screen, projection, tv, print; @import url(../../base/css/display.css);
@media screen, projection, tv { @media screen, projection, tv {
body, body,

View File

@ -7,7 +7,7 @@
* @link http://status.net/ * @link http://status.net/
*/ */
@import url(../../base/css/display.css) screen, projection, tv, print; @import url(../../base/css/display.css);
@media screen, projection, tv { @media screen, projection, tv {
body, body,

View File

@ -7,7 +7,7 @@
* @link http://status.net/ * @link http://status.net/
*/ */
@import url(base.css) screen, projection, tv, print; @import url(base.css);
@media screen, projection, tv { @media screen, projection, tv {
html { html {