Merge branch '0.8.x' of git@gitorious.org:~brion/statusnet/brion-fixes into 0.8.x

This commit is contained in:
Brion Vibber 2009-10-13 16:45:26 +00:00
commit 834ac7aa11
22 changed files with 390 additions and 142 deletions

View File

@ -142,6 +142,7 @@ class ApiAction extends Action
static $bareauth = array('statuses/user_timeline',
'statuses/friends_timeline',
'statuses/home_timeline',
'statuses/friends',
'statuses/replies',
'statuses/mentions',

View File

@ -250,7 +250,6 @@ class EditgroupAction extends GroupDesignAction
$this->group->homepage = $homepage;
$this->group->description = $description;
$this->group->location = $location;
$this->group->created = common_sql_now();
$result = $this->group->update($orig);

View File

@ -106,7 +106,7 @@ class GroupSearchResults extends GroupList
function __construct($user_group, $terms, $action)
{
parent::__construct($user_group, $terms, $action);
parent::__construct($user_group, null, $action);
$this->terms = array_map('preg_quote',
array_map('htmlspecialchars', $terms));
$this->pattern = '/('.implode('|',$terms).')/i';

View File

@ -297,7 +297,7 @@ class TwitapistatusesAction extends TwitterapiAction
$source, 1, $reply_to);
if (is_string($notice)) {
$this->serverError($notice);
$this->serverError($notice, 500, $apidata['content-type']);
return;
}
@ -454,7 +454,7 @@ class TwitapistatusesAction extends TwitterapiAction
function friends($args, $apidata)
{
parent::handle($args);
$includeStatuses=! (boolean) $args['lite'];
$includeStatuses= !(array_key_exists('lite', $args) and $args['lite']);
return $this->subscriptions($apidata, 'subscribed', 'subscriber', false, $includeStatuses);
}
@ -467,7 +467,7 @@ class TwitapistatusesAction extends TwitterapiAction
function followers($args, $apidata)
{
parent::handle($args);
$includeStatuses=! (boolean) $args['lite'];
$includeStatuses= !(array_key_exists('lite', $args) and $args['lite']);
return $this->subscriptions($apidata, 'subscriber', 'subscribed', false, $includeStatuses);
}

View File

@ -461,4 +461,79 @@ class Profile extends Memcached_DataObject
$c->delete(common_cache_key('profile:notice_count:'.$this->id));
}
}
function delete()
{
$this->_deleteNotices();
$this->_deleteSubscriptions();
$this->_deleteMessages();
$this->_deleteTags();
$this->_deleteBlocks();
$related = array('Avatar',
'Reply',
'Group_member',
);
foreach ($related as $cls) {
$inst = new $cls();
$inst->profile_id = $this->id;
$inst->delete();
}
parent::delete();
}
function _deleteNotices()
{
$notice = new Notice();
$notice->profile_id = $this->id;
if ($notice->find()) {
while ($notice->fetch()) {
$other = clone($notice);
$other->delete();
}
}
}
function _deleteSubscriptions()
{
$sub = new Subscription();
$sub->subscriber = $this->id;
$sub->delete();
$subd = new Subscription();
$subd->subscribed = $this->id;
$subd->delete();
}
function _deleteMessages()
{
$msg = new Message();
$msg->from_profile = $this->id;
$msg->delete();
$msg = new Message();
$msg->to_profile = $this->id;
$msg->delete();
}
function _deleteTags()
{
$tag = new Profile_tag();
$tag->tagged = $this->id;
$tag->delete();
}
function _deleteBlocks()
{
$block = new Profile_block();
$block->blocked = $this->id;
$block->delete();
$block = new Group_block();
$block->blocked = $this->id;
$block->delete();
}
}

View File

@ -85,9 +85,18 @@ class Session extends Memcached_DataObject
return $session->insert();
} else {
$session->session_data = $session_data;
if (strcmp($session->session_data, $session_data) == 0) {
self::logdeb("Not writing session '$id'; unchanged");
return true;
} else {
self::logdeb("Session '$id' data changed; updating");
return $session->update();
$orig = clone($session);
$session->session_data = $session_data;
return $session->update($orig);
}
}
}

View File

@ -689,4 +689,48 @@ class User extends Memcached_DataObject
{
return Design::staticGet('id', $this->design_id);
}
function delete()
{
$profile = $this->getProfile();
$profile->delete();
$related = array('Fave',
'User_openid',
'Confirm_address',
'Remember_me',
'Foreign_link',
'Invitation',
);
if (common_config('inboxes', 'enabled')) {
$related[] = 'Notice_inbox';
}
foreach ($related as $cls) {
$inst = new $cls();
$inst->user_id = $this->id;
$inst->delete();
}
$this->_deleteTags();
$this->_deleteBlocks();
parent::delete();
}
function _deleteTags()
{
$tag = new Profile_tag();
$tag->tagger = $this->id;
$tag->delete();
}
function _deleteBlocks()
{
$block = new Profile_block();
$block->blocker = $this->id;
$block->delete();
// XXX delete group block? Reset blocker?
}
}

View File

@ -46,28 +46,28 @@ require_once INSTALLDIR.'/lib/error.php';
*/
class ClientErrorAction extends ErrorAction
{
static $status = array(400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
407 => 'Proxy Authentication Required',
408 => 'Request Timeout',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Request Entity Too Large',
414 => 'Request-URI Too Long',
415 => 'Unsupported Media Type',
416 => 'Requested Range Not Satisfiable',
417 => 'Expectation Failed');
function __construct($message='Error', $code=400)
{
parent::__construct($message, $code);
$this->status = array(400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
407 => 'Proxy Authentication Required',
408 => 'Request Timeout',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Request Entity Too Large',
414 => 'Request-URI Too Long',
415 => 'Unsupported Media Type',
416 => 'Requested Range Not Satisfiable',
417 => 'Expectation Failed');
$this->default = 400;
}
@ -91,9 +91,4 @@ class ClientErrorAction extends ErrorAction
$this->showPage();
}
function title()
{
return $this->status[$this->code];
}
}

View File

@ -196,15 +196,14 @@ $config =
array('enabled' => true),
'sms' =>
array('enabled' => true),
'twitter' =>
array('enabled' => true),
'twitterbridge' =>
array('enabled' => false),
'integration' =>
array('source' => 'StatusNet', # source attribute for Twitter
'taguri' => $_server.',2009'), # base for tag URIs
'twitter' =>
array('consumer_key' => null,
array('enabled' => true,
'consumer_key' => null,
'consumer_secret' => null),
'memcached' =>
array('enabled' => false,

View File

@ -44,9 +44,10 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
*/
class ErrorAction extends Action
{
static $status = array();
var $code = null;
var $message = null;
var $status = null;
var $default = null;
function __construct($message, $code, $output='php://output', $indent=true)
@ -88,9 +89,10 @@ class ErrorAction extends Action
*
* @return page title
*/
function title()
{
return $this->message;
return self::$status[$this->code];
}
function isReadOnly($args)

View File

@ -106,14 +106,16 @@ class HTMLOutputter extends XMLOutputter
}
}
header('Content-Type: '.$type);
header('Content-Type: '.$type.'; charset=UTF-8');
$this->extraHeaders();
if( ! substr($type,0,strlen('text/html'))=='text/html' ){
// Browsers don't like it when <?xml it output for non-xhtml documents
if (preg_match("/.*\/.*xml/", $type)) {
// Required for XML documents
$this->xw->startDocument('1.0', 'UTF-8');
}
$this->xw->writeDTD('html');
$this->xw->writeDTD('html',
'-//W3C//DTD XHTML 1.0 Strict//EN',
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
$language = $this->getLanguage();
@ -425,16 +427,12 @@ class HTMLOutputter extends XMLOutputter
function autofocus($id)
{
$this->elementStart('script', array('type' => 'text/javascript'));
$this->raw('
<!--
$(document).ready(function() {
var el = $("#' . $id . '");
if (el.length) {
el.focus();
}
});
-->
');
$this->raw('/*<![CDATA[*/'.
' $(document).ready(function() {'.
' var el = $("#' . $id . '");'.
' if (el.length) { el.focus(); }'.
' });'.
' /*]]>*/');
$this->elementEnd('script');
}
}

View File

@ -135,16 +135,21 @@ class SearchAction extends Action
}
function searchSuggestions($q) {
$qe = urlencode($q);
$message = sprintf(_(<<<E_O_T
$message = _(<<<E_O_T
* Make sure all words are spelled correctly.
* Try different keywords.
* Try more general keywords.
* Try fewer keywords.
E_O_T
);
if (!common_config('site', 'private')) {
$qe = urlencode($q);
$message .= sprintf(_(<<<E_O_T
You can also try your search on other engines:
* [Twingly](http://www.twingly.com/search?q=%s&content=microblog&site=identi.ca)
* [Twingly](http://www.twingly.com/search?q=%s&content=microblog&site=%%%%site.server%%%%)
* [Tweet scan](http://www.tweetscan.com/indexi.php?s=%s)
* [Google](http://www.google.com/search?q=site%%3A%%%%site.server%%%%+%s)
* [Yahoo](http://search.yahoo.com/search?p=site%%3A%%%%site.server%%%%+%s)
@ -152,6 +157,7 @@ You can also try your search on other engines:
E_O_T
), $qe, $qe, $qe, $qe, $qe);
}
$this->elementStart('dl', array('id' => 'help_search', 'class' => 'help'));
$this->element('dt', null, _('Search help'));
$this->elementStart('dd', 'instructions');

View File

@ -55,17 +55,17 @@ require_once INSTALLDIR.'/lib/error.php';
class ServerErrorAction extends ErrorAction
{
static $status = array(500 => 'Internal Server Error',
501 => 'Not Implemented',
502 => 'Bad Gateway',
503 => 'Service Unavailable',
504 => 'Gateway Timeout',
505 => 'HTTP Version Not Supported');
function __construct($message='Error', $code=500)
{
parent::__construct($message, $code);
$this->status = array(500 => 'Internal Server Error',
501 => 'Not Implemented',
502 => 'Bad Gateway',
503 => 'Service Unavailable',
504 => 'Gateway Timeout',
505 => 'HTTP Version Not Supported');
$this->default = 500;
// Server errors must be logged.
@ -93,9 +93,4 @@ class ServerErrorAction extends ErrorAction
$this->showPage();
}
function title()
{
return $this->status[$this->code];
}
}

View File

@ -939,35 +939,16 @@ class TwitterapiAction extends Action
function clientError($msg, $code = 400, $content_type = 'json')
{
static $status = array(400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
407 => 'Proxy Authentication Required',
408 => 'Request Timeout',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Request Entity Too Large',
414 => 'Request-URI Too Long',
415 => 'Unsupported Media Type',
416 => 'Requested Range Not Satisfiable',
417 => 'Expectation Failed');
$action = $this->trimmed('action');
common_debug("User error '$code' on '$action': $msg", __FILE__);
if (!array_key_exists($code, $status)) {
if (!array_key_exists($code, ClientErrorAction::$status)) {
$code = 400;
}
$status_string = $status[$code];
$status_string = ClientErrorAction::$status[$code];
header('HTTP/1.1 '.$code.' '.$status_string);
if ($content_type == 'xml') {
@ -986,6 +967,35 @@ class TwitterapiAction extends Action
}
function serverError($msg, $code = 500, $content_type = 'json')
{
$action = $this->trimmed('action');
common_debug("Server error '$code' on '$action': $msg", __FILE__);
if (!array_key_exists($code, ServerErrorAction::$status)) {
$code = 400;
}
$status_string = ServerErrorAction::$status[$code];
header('HTTP/1.1 '.$code.' '.$status_string);
if ($content_type == 'xml') {
$this->init_document('xml');
$this->elementStart('hash');
$this->element('error', null, $msg);
$this->element('request', null, $_SERVER['REQUEST_URI']);
$this->elementEnd('hash');
$this->end_document('xml');
} else {
$this->init_document('json');
$error_array = array('error' => $msg, 'request' => $_SERVER['REQUEST_URI']);
print(json_encode($error_array));
$this->end_document('json');
}
}
function init_twitter_rss()
{
$this->startXML();

View File

@ -981,7 +981,7 @@ function common_set_returnto($url)
function common_get_returnto()
{
common_ensure_session();
return $_SESSION['returnto'];
return (array_key_exists('returnto', $_SESSION)) ? $_SESSION['returnto'] : null;
}
function common_timestamp()
@ -1148,7 +1148,7 @@ function common_negotiate_type($cprefs, $sprefs)
}
if ('text/html' === $besttype) {
return "text/html; charset=utf-8";
return "text/html";
}
return $besttype;
}

View File

@ -78,16 +78,20 @@ class FBCLoginGroupNav extends Widget
// action => array('prompt', 'title')
$menu = array();
$menu['login'] = array(_('Login'),
_('Login with a username and password'));
if (!common_config('site','openidonly')) {
$menu['login'] = array(_('Login'),
_('Login with a username and password'));
if (!(common_config('site','closed') || common_config('site','inviteonly'))) {
$menu['register'] = array(_('Register'),
_('Sign up for a new account'));
if (!(common_config('site','closed') || common_config('site','inviteonly'))) {
$menu['register'] = array(_('Register'),
_('Sign up for a new account'));
}
}
$menu['openidlogin'] = array(_('OpenID'),
_('Login or register with OpenID'));
if (common_config('openid', 'enabled')) {
$menu['openidlogin'] = array(_('OpenID'),
_('Login or register with OpenID'));
}
$menu['FBConnectLogin'] = array(_('Facebook'),
_('Login or register using Facebook'));

View File

@ -77,32 +77,34 @@ class FBCSettingsNav extends Widget
$this->action->elementStart('dd');
# action => array('prompt', 'title')
$menu =
array('imsettings' =>
array(_('IM'),
_('Updates by instant messenger (IM)')),
'smssettings' =>
array(_('SMS'),
_('Updates by SMS')),
'twittersettings' =>
array(_('Twitter'),
_('Twitter integration options')),
'FBConnectSettings' =>
array(_('Facebook'),
_('Facebook Connect settings')));
$menu = array();
if (common_config('xmpp', 'enabled')) {
$menu['imsettings'] =
array(_('IM'),
_('Updates by instant messenger (IM)'));
}
if (common_config('sms', 'enabled')) {
$menu['smssettings'] =
array(_('SMS'),
_('Updates by SMS'));
}
if (common_config('twitter', 'enabled')) {
$menu['twittersettings'] =
array(_('Twitter'),
_('Twitter integration options'));
}
$menu['FBConnectSettings'] =
array(_('Facebook'),
_('Facebook Connect settings'));
$action_name = $this->action->trimmed('action');
$this->action->elementStart('ul', array('class' => 'nav'));
foreach ($menu as $menuaction => $menudesc) {
if ($menuaction == 'imsettings' &&
!common_config('xmpp', 'enabled')) {
continue;
}
$this->action->menuItem(common_local_url($menuaction),
$menudesc[0],
$menudesc[1],
$action_name === $menuaction);
$menudesc[0],
$menudesc[1],
$action_name === $menuaction);
}
$this->action->elementEnd('ul');

View File

@ -232,6 +232,14 @@ class FBConnectPlugin extends Plugin
{
$user = common_current_user();
$connect = 'FBConnectSettings';
if (common_config('xmpp', 'enabled')) {
$connect = 'imsettings';
} else if (common_config('sms', 'enabled')) {
$connect = 'smssettings';
} else if (common_config('twitter', 'enabled')) {
$connect = 'twittersettings';
}
if (!empty($user)) {
@ -266,13 +274,8 @@ class FBConnectPlugin extends Plugin
_('Home'), _('Personal profile and friends timeline'), false, 'nav_home');
$action->menuItem(common_local_url('profilesettings'),
_('Account'), _('Change your email, avatar, password, profile'), false, 'nav_account');
if (common_config('xmpp', 'enabled')) {
$action->menuItem(common_local_url('imsettings'),
_('Connect'), _('Connect to IM, SMS, Twitter'), false, 'nav_connect');
} else {
$action->menuItem(common_local_url('smssettings'),
_('Connect'), _('Connect to SMS, Twitter'), false, 'nav_connect');
}
$action->menuItem(common_local_url($connect),
_('Connect'), _('Connect to services'), false, 'nav_connect');
if (common_config('invite', 'enabled')) {
$action->menuItem(common_local_url('invite'),
_('Invite'),
@ -300,18 +303,30 @@ class FBConnectPlugin extends Plugin
}
}
else {
if (!common_config('site', 'closed')) {
$action->menuItem(common_local_url('register'),
_('Register'), _('Create an account'), false, 'nav_register');
if (!common_config('site', 'openidonly')) {
if (!common_config('site', 'closed')) {
$action->menuItem(common_local_url('register'),
_('Register'), _('Create an account'), false, 'nav_register');
}
$action->menuItem(common_local_url('login'),
_('Login'), _('Login to the site'), false, 'nav_login');
} else {
$this->menuItem(common_local_url('openidlogin'),
_('OpenID'), _('Login with OpenID'), false, 'nav_openid');
}
$action->menuItem(common_local_url('login'),
_('Login'), _('Login to the site'), false, 'nav_login');
}
$action->menuItem(common_local_url('doc', array('title' => 'help')),
_('Help'), _('Help me!'), false, 'nav_help');
$action->menuItem(common_local_url('peoplesearch'),
_('Search'), _('Search for people or text'), false, 'nav_search');
if ($user || !common_config('site', 'private')) {
$action->menuItem(common_local_url('peoplesearch'),
_('Search'), _('Search for people or text'), false, 'nav_search');
}
// We are replacing the primary nav entirely; give other
// plugins a chance to handle it here.
Event::handle('EndPrimaryNav', array($action));
return false;
}

View File

@ -216,8 +216,6 @@ class RealtimePlugin extends Plugin
'class' => 'user_in')
: array('id' => $action->trimmed('action')));
$action->elementStart('div', array('id' => 'header'));
// XXX hack to deal with JS that tries to get the
// root url from page output
@ -230,7 +228,6 @@ class RealtimePlugin extends Plugin
if (common_logged_in()) {
$action->showNoticeForm();
}
$action->elementEnd('div');
$action->showContentBlock();
$action->elementEnd('body');

View File

@ -14,6 +14,18 @@ RealtimeUpdate = {
RealtimeUpdate._replyurl = replyurl;
RealtimeUpdate._favorurl = favorurl;
RealtimeUpdate._deleteurl = deleteurl;
$(window).blur(function() {
$('#notices_primary .notice').css({
'border-top-color':$('#notices_primary .notice:last').css('border-top-color'),
'border-top-style':'dotted'
});
$('#notices_primary .notice:first').css({
'border-top-color':'#AAAAAA',
'border-top-style':'solid'
});
});
},
receive: function(data)
@ -27,7 +39,7 @@ RealtimeUpdate = {
}
var noticeItem = RealtimeUpdate.makeNoticeItem(data);
$("#notices_primary .notices").prepend(noticeItem, true);
$("#notices_primary .notices").prepend(noticeItem);
$("#notices_primary .notice:first").css({display:"none"});
$("#notices_primary .notice:first").fadeIn(1000);
NoticeReply();
@ -113,7 +125,7 @@ RealtimeUpdate = {
addPopup: function(url, timeline, iconurl)
{
$('#content').prepend('<button id="realtime_timeline" title="Realtime window">Realtime</button>');
$('#content').prepend('<button id="realtime_timeline" title="Pop up in a window">Pop up</button>');
$('#realtime_timeline').css({
'margin':'0 0 18px 0',
@ -139,9 +151,26 @@ RealtimeUpdate = {
initPopupWindow: function()
{
window.resizeTo(575, 640);
window.resizeTo(500, 550);
$('address').hide();
$('#content').css({'width':'92%'});
$('#content').css({'width':'93.5%'});
$('#form_notice').css({
'margin':'18px 0 18px 1.795%',
'width':'93%',
'max-width':'451px'
});
$('#form_notice label[for=notice_data-text], h1').css({'display': 'none'});
$('.notices li:first-child').css({'border-top-color':'transparent'});
$('#form_notice label[for="notice_data-attach"], #form_notice #notice_data-attach').css({'top':'0'});
$('#form_notice #notice_data-attach').css({
'left':'auto',
'right':'0'
});
}
}

68
scripts/deleteuser.php Normal file
View File

@ -0,0 +1,68 @@
#!/usr/bin/env php
<?php
/*
* StatusNet - a 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__) . '/..'));
$shortoptions = 'i::n::y';
$longoptions = array('id::nickname::yes');
$helptext = <<<END_OF_DELETEUSER_HELP
deleteuser.php [options]
deletes a user from the database
-i --id ID of the user
-n --nickname nickname of the user
-y --yes do not wait for confirmation
END_OF_DELETEUSER_HELP;
require_once INSTALLDIR.'/scripts/commandline.inc';
if (have_option('i', 'id')) {
$id = get_option_value('i', 'id');
$user = User::staticGet('id', $id);
if (empty($user)) {
print "Can't find user with ID $id\n";
exit(1);
}
} else if (have_option('n', 'nickname')) {
$nickname = get_option_value('n', 'nickname');
$user = User::staticGet('nickname', $nickname);
if (empty($user)) {
print "Can't find user with nickname '$nickname'\n";
exit(1);
}
} else {
print "You must provide either an ID or a nickname.\n";
exit(1);
}
if (!have_option('y', 'yes')) {
print "About to PERMANENTLY delete user '{$user->nickname}' ({$user->id}). Are you sure? [y/N] ";
$response = fgets(STDIN);
if (strtolower(trim($response)) != 'y') {
print "Aborting.\n";
exit(0);
}
}
print "Deleting...";
$user->delete();
print "DONE.\n";

View File

@ -484,7 +484,7 @@ height:16px;
#form_notice .form_note {
position:absolute;
bottom:2px;
right:98px;
right:21.715%;
z-index:9;
}
#form_notice .form_note dt {