Merge commit 'origin/testing' into 0.9.x
This commit is contained in:
commit
c9c7bb3234
35
README
35
README
|
@ -2,8 +2,8 @@
|
|||
README
|
||||
------
|
||||
|
||||
StatusNet 0.9.0 ("Stand") Release Candidate 2
|
||||
22 Dec 2009
|
||||
StatusNet 0.9.0 ("Stand") Beta 3
|
||||
20 Jan 2010
|
||||
|
||||
This is the README file for StatusNet (formerly Laconica), the Open
|
||||
Source microblogging platform. It includes installation instructions,
|
||||
|
@ -167,6 +167,37 @@ Notable changes this version:
|
|||
- Add support for "repeats" (similar to Twitter's "retweets").
|
||||
- Support for repeats in Twitter API.
|
||||
- Better notification of direct messages.
|
||||
- New plugin to add "powered by StatusNet" to logo.
|
||||
- Returnto works for private sites.
|
||||
- Localisation updates, including new Persian translation.
|
||||
- CAS authentication plugin
|
||||
- Get rid of DB_DataObject native cache (big memory leaker)
|
||||
- setconfig.php script to set configuration variables
|
||||
- Blacklist plugin, to blacklist URLs and nicknames
|
||||
- Users can set flag whether they want to share location
|
||||
both in notice form (for one notice) and profile settings
|
||||
(any notice)
|
||||
- notice inboxes moved from normalized notice_inbox table to
|
||||
denormalized inbox table
|
||||
- Automatic compression of Memcache
|
||||
- Memory caching pluginized
|
||||
- Memcache, XCache, APC and Diskcache plugins
|
||||
- A script to update user locations
|
||||
- cache empty query results
|
||||
- A sample plugin to show best plugin practices
|
||||
- CacheLog plugin to debug cache accesses
|
||||
- Require users to login to view attachments on private sites
|
||||
- Plugin to use Mollom spam detection service
|
||||
- Plugin for RSSCloud
|
||||
- Add an array of default plugins
|
||||
- A version action to give credit to contributors and plugin
|
||||
developers
|
||||
- Daemon to read IMAP mailbox instead of using a mailbox script
|
||||
- Pass session information between SSL and non-SSL server
|
||||
when SSL set to 'sometimes'
|
||||
- Major refactoring of queue handlers to manage very
|
||||
large hosting site (like status.net)
|
||||
- SubscriptionThrottle plugin to prevent subscription spamming
|
||||
|
||||
Prerequisites
|
||||
=============
|
||||
|
|
|
@ -113,4 +113,19 @@ class ApiStatusesRetweetsAction extends ApiAuthAction
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,58 +69,21 @@ class ApiTimelineRetweetedByMeAction extends ApiAuthAction
|
|||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$cnt = $this->int('count', self::DEFAULTCOUNT, self::MAXCOUNT, 1);
|
||||
$this->serverError('Unimplemented', 503);
|
||||
|
||||
$page = $this->int('page', 1, (self::MAXNOTICES/$this->cnt));
|
||||
|
||||
$since_id = $this->int('since_id');
|
||||
|
||||
$max_id = $this->int('max_id');
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
* Return true if read only.
|
||||
*
|
||||
* show a timeline of the user's repeated notices
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
function isReadOnly($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
$offset = ($this->page-1) * $this->cnt;
|
||||
$limit = $this->cnt;
|
||||
|
||||
$strm = $this->auth_user->repeatedByMe($offset, $limit, $this->since_id, $this->max_id);
|
||||
|
||||
switch ($this->format) {
|
||||
case 'xml':
|
||||
$this->showXmlTimeline($strm);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showJsonTimeline($strm);
|
||||
break;
|
||||
case 'atom':
|
||||
$profile = $this->auth_user->getProfile();
|
||||
|
||||
$title = sprintf(_("Repeated by %s"), $this->auth_user->nickname);
|
||||
$taguribase = common_config('integration', 'taguri');
|
||||
$id = "tag:$taguribase:RepeatedByMe:" . $this->auth_user->id;
|
||||
$link = common_local_url('showstream',
|
||||
array('nickname' => $this->auth_user->nickname));
|
||||
|
||||
$this->showAtomTimeline($strm, $title, $id, $link);
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,4 +122,19 @@ class ApiTimelineRetweetedToMeAction extends ApiAuthAction
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,4 +123,19 @@ class ApiTimelineRetweetsOfMeAction extends ApiAuthAction
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if read only.
|
||||
*
|
||||
* MAY override
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean is read only action?
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -315,6 +315,39 @@ class Memcached_DataObject extends DB_DataObject
|
|||
return new ArrayWrapper($cached);
|
||||
}
|
||||
|
||||
/**
|
||||
* sends query to database - this is the private one that must work
|
||||
* - internal functions use this rather than $this->query()
|
||||
*
|
||||
* Overridden to do logging.
|
||||
*
|
||||
* @param string $string
|
||||
* @access private
|
||||
* @return mixed none or PEAR_Error
|
||||
*/
|
||||
function _query($string)
|
||||
{
|
||||
$start = microtime(true);
|
||||
$result = parent::_query($string);
|
||||
$delta = microtime(true) - $start;
|
||||
|
||||
$limit = common_config('db', 'log_slow_queries');
|
||||
if (($limit > 0 && $delta >= $limit) || common_config('db', 'log_queries')) {
|
||||
$clean = $this->sanitizeQuery($string);
|
||||
common_log(LOG_DEBUG, sprintf("DB query (%0.3fs): %s", $delta, $clean));
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Sanitize a query for logging
|
||||
// @fixme don't trim spaces in string literals
|
||||
function sanitizeQuery($string)
|
||||
{
|
||||
$string = preg_replace('/\s+/', ' ', $string);
|
||||
$string = trim($string);
|
||||
return $string;
|
||||
}
|
||||
|
||||
// We overload so that 'SET NAMES "utf8"' is called for
|
||||
// each connection
|
||||
|
||||
|
|
12
js/util.js
12
js/util.js
|
@ -205,8 +205,10 @@ var SN = { // StatusNet
|
|||
cookieValue = JSON.parse(cookieValue);
|
||||
NLat = $('#'+SN.C.S.NoticeLat).val(cookieValue.NLat).val();
|
||||
NLon = $('#'+SN.C.S.NoticeLon).val(cookieValue.NLon).val();
|
||||
NLNS = $('#'+SN.C.S.NoticeLocationNs).val(cookieValue.NLNS).val();
|
||||
NLID = $('#'+SN.C.S.NoticeLocationId).val(cookieValue.NLID).val();
|
||||
if ($('#'+SN.C.S.NoticeLocationNs).val(cookieValue.NLNS)) {
|
||||
NLNS = $('#'+SN.C.S.NoticeLocationNs).val(cookieValue.NLNS).val();
|
||||
NLID = $('#'+SN.C.S.NoticeLocationId).val(cookieValue.NLID).val();
|
||||
}
|
||||
}
|
||||
if (cookieValue == 'disabled') {
|
||||
NDG = $('#'+SN.C.S.NoticeDataGeo).attr('checked', false).attr('checked');
|
||||
|
@ -301,8 +303,10 @@ var SN = { // StatusNet
|
|||
|
||||
$('#'+SN.C.S.NoticeLat).val(NLat);
|
||||
$('#'+SN.C.S.NoticeLon).val(NLon);
|
||||
$('#'+SN.C.S.NoticeLocationNs).val(NLNS);
|
||||
$('#'+SN.C.S.NoticeLocationId).val(NLID);
|
||||
if ($('#'+SN.C.S.NoticeLocationNs)) {
|
||||
$('#'+SN.C.S.NoticeLocationNs).val(NLNS);
|
||||
$('#'+SN.C.S.NoticeLocationId).val(NLID);
|
||||
}
|
||||
$('#'+SN.C.S.NoticeDataGeo).attr('checked', NDG);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -67,7 +67,9 @@ $default =
|
|||
'db_driver' => 'DB', # XXX: JanRain libs only work with DB
|
||||
'quote_identifiers' => false,
|
||||
'type' => 'mysql',
|
||||
'schemacheck' => 'runtime'), // 'runtime' or 'script'
|
||||
'schemacheck' => 'runtime', // 'runtime' or 'script'
|
||||
'log_queries' => false, // true to log all DB queries
|
||||
'log_slow_queries' => 0), // if set, log queries taking over N seconds
|
||||
'syslog' =>
|
||||
array('appname' => 'statusnet', # for syslog
|
||||
'priority' => 'debug', # XXX: currently ignored
|
||||
|
|
|
@ -31,66 +31,152 @@ if (!defined('STATUSNET')) {
|
|||
exit(1);
|
||||
}
|
||||
|
||||
define('DEFAULT_HUB','http://pubsubhubbub.appspot.com');
|
||||
define('DEFAULT_HUB', 'http://pubsubhubbub.appspot.com');
|
||||
|
||||
require_once(INSTALLDIR.'/plugins/PubSubHubBub/publisher.php');
|
||||
require_once INSTALLDIR.'/plugins/PubSubHubBub/publisher.php';
|
||||
|
||||
/**
|
||||
* Plugin to provide publisher side of PubSubHubBub (PuSH)
|
||||
* relationship.
|
||||
*
|
||||
* PuSH is a real-time or near-real-time protocol for Atom
|
||||
* and RSS feeds. More information here:
|
||||
*
|
||||
* http://code.google.com/p/pubsubhubbub/
|
||||
*
|
||||
* To enable, add the following line to your config.php:
|
||||
*
|
||||
* addPlugin('PubSubHubBub');
|
||||
*
|
||||
* This will use the Google default hub. If you'd like to use
|
||||
* another, try:
|
||||
*
|
||||
* addPlugin('PubSubHubBub',
|
||||
* array('hub' => 'http://yourhub.example.net/'));
|
||||
*
|
||||
* @category Plugin
|
||||
* @package StatusNet
|
||||
* @author Craig Andrews <candrews@integralblue.com>
|
||||
* @copyright 2009 Craig Andrews http://candrews.integralblue.com
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class PubSubHubBubPlugin extends Plugin
|
||||
{
|
||||
private $hub;
|
||||
/**
|
||||
* URL of the hub to advertise and publish to.
|
||||
*/
|
||||
|
||||
public $hub = DEFAULT_HUB;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
function onInitializePlugin(){
|
||||
$this->hub = common_config('PubSubHubBub', 'hub');
|
||||
if(empty($this->hub)){
|
||||
$this->hub = DEFAULT_HUB;
|
||||
}
|
||||
/**
|
||||
* Hooks the StartApiAtom event
|
||||
*
|
||||
* Adds the necessary bits to advertise PubSubHubBub
|
||||
* for the Atom feed.
|
||||
*
|
||||
* @param Action $action The API action being shown.
|
||||
*
|
||||
* @return boolean hook value
|
||||
*/
|
||||
|
||||
function onStartApiAtom($action)
|
||||
{
|
||||
$action->element('link', array('rel' => 'hub', 'href' => $this->hub), null);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function onStartApiAtom($action){
|
||||
$action->element('link',array('rel'=>'hub','href'=>$this->hub),null);
|
||||
/**
|
||||
* Hooks the StartApiRss event
|
||||
*
|
||||
* Adds the necessary bits to advertise PubSubHubBub
|
||||
* for the RSS 2.0 feeds.
|
||||
*
|
||||
* @param Action $action The API action being shown.
|
||||
*
|
||||
* @return boolean hook value
|
||||
*/
|
||||
|
||||
function onStartApiRss($action)
|
||||
{
|
||||
$action->element('atom:link', array('rel' => 'hub',
|
||||
'href' => $this->hub),
|
||||
null);
|
||||
return true;
|
||||
}
|
||||
|
||||
function onStartApiRss($action){
|
||||
$action->element('atom:link',array('rel'=>'hub','href'=>$this->hub),null);
|
||||
}
|
||||
/**
|
||||
* Hook for a queued notice.
|
||||
*
|
||||
* When a notice has been queued, will ping the
|
||||
* PuSH hub for each Atom and RSS feed in which
|
||||
* the notice appears.
|
||||
*
|
||||
* @param Notice $notice The notice that's been queued
|
||||
*
|
||||
* @return boolean hook value
|
||||
*/
|
||||
|
||||
function onHandleQueuedNotice($notice){
|
||||
function onHandleQueuedNotice($notice)
|
||||
{
|
||||
$publisher = new Publisher($this->hub);
|
||||
|
||||
$feeds = array();
|
||||
|
||||
//public timeline feeds
|
||||
$feeds[]=common_local_url('ApiTimelinePublic',array('format' => 'rss'));
|
||||
$feeds[]=common_local_url('ApiTimelinePublic',array('format' => 'atom'));
|
||||
$feeds[] = common_local_url('ApiTimelinePublic', array('format' => 'rss'));
|
||||
$feeds[] = common_local_url('ApiTimelinePublic', array('format' => 'atom'));
|
||||
|
||||
//author's own feeds
|
||||
$user = User::staticGet('id',$notice->profile_id);
|
||||
$feeds[]=common_local_url('ApiTimelineUser',array('id' => $user->nickname, 'format'=>'rss'));
|
||||
$feeds[]=common_local_url('ApiTimelineUser',array('id' => $user->nickname, 'format'=>'atom'));
|
||||
$user = User::staticGet('id', $notice->profile_id);
|
||||
|
||||
$feeds[] = common_local_url('ApiTimelineUser',
|
||||
array('id' => $user->nickname,
|
||||
'format' => 'rss'));
|
||||
$feeds[] = common_local_url('ApiTimelineUser',
|
||||
array('id' => $user->nickname,
|
||||
'format' => 'atom'));
|
||||
|
||||
//tag feeds
|
||||
$tag = new Notice_tag();
|
||||
|
||||
$tag->notice_id = $notice->id;
|
||||
if ($tag->find()) {
|
||||
while ($tag->fetch()) {
|
||||
$feeds[]=common_local_url('ApiTimelineTag',array('tag'=>$tag->tag, 'format'=>'rss'));
|
||||
$feeds[]=common_local_url('ApiTimelineTag',array('tag'=>$tag->tag, 'format'=>'atom'));
|
||||
$feeds[] = common_local_url('ApiTimelineTag',
|
||||
array('tag' => $tag->tag,
|
||||
'format' => 'rss'));
|
||||
$feeds[] = common_local_url('ApiTimelineTag',
|
||||
array('tag' => $tag->tag,
|
||||
'format' => 'atom'));
|
||||
}
|
||||
}
|
||||
|
||||
//group feeds
|
||||
$group_inbox = new Group_inbox();
|
||||
|
||||
$group_inbox->notice_id = $notice->id;
|
||||
if ($group_inbox->find()) {
|
||||
while ($group_inbox->fetch()) {
|
||||
$group = User_group::staticGet('id',$group_inbox->group_id);
|
||||
$feeds[]=common_local_url('ApiTimelineGroup',array('id' => $group->nickname,'format'=>'rss'));
|
||||
$feeds[]=common_local_url('ApiTimelineGroup',array('id' => $group->nickname,'format'=>'atom'));
|
||||
$group = User_group::staticGet('id', $group_inbox->group_id);
|
||||
|
||||
$feeds[] = common_local_url('ApiTimelineGroup',
|
||||
array('id' => $group->nickname,
|
||||
'format' => 'rss'));
|
||||
$feeds[] = common_local_url('ApiTimelineGroup',
|
||||
array('id' => $group->nickname,
|
||||
'format' => 'atom'));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,32 +189,63 @@ class PubSubHubBubPlugin extends Plugin
|
|||
if (empty($user)) {
|
||||
continue;
|
||||
}
|
||||
$feeds[]=common_local_url('ApiTimelineUser',array('id' => $user->nickname, 'format'=>'rss'));
|
||||
$feeds[]=common_local_url('ApiTimelineUser',array('id' => $user->nickname, 'format'=>'atom'));
|
||||
$feeds[] = common_local_url('ApiTimelineFriends',
|
||||
array('id' => $user->nickname,
|
||||
'format' => 'rss'));
|
||||
$feeds[] = common_local_url('ApiTimelineFriends',
|
||||
array('id' => $user->nickname,
|
||||
'format' => 'atom'));
|
||||
}
|
||||
|
||||
$replies = $notice->getReplies();
|
||||
|
||||
//feed of user replied to
|
||||
if($notice->reply_to){
|
||||
$user = User::staticGet('id',$notice->reply_to);
|
||||
$feeds[]=common_local_url('ApiTimelineMentions',array('id' => $user->nickname,'format'=>'rss'));
|
||||
$feeds[]=common_local_url('ApiTimelineMentions',array('id' => $user->nickname,'format'=>'atom'));
|
||||
}
|
||||
|
||||
foreach(array_unique($feeds) as $feed){
|
||||
if(! $publisher->publish_update($feed)){
|
||||
common_log_line(LOG_WARNING,$feed.' was not published to hub at '.$this->hub.':'.$publisher->last_response());
|
||||
foreach ($replies as $recipient) {
|
||||
$user = User::staticGet('id', $recipient);
|
||||
if (!empty($user)) {
|
||||
$feeds[] = common_local_url('ApiTimelineMentions',
|
||||
array('id' => $user->nickname,
|
||||
'format' => 'rss'));
|
||||
$feeds[] = common_local_url('ApiTimelineMentions',
|
||||
array('id' => $user->nickname,
|
||||
'format' => 'atom'));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (array_unique($feeds) as $feed) {
|
||||
if (!$publisher->publish_update($feed)) {
|
||||
common_log_line(LOG_WARNING,
|
||||
$feed.' was not published to hub at '.
|
||||
$this->hub.':'.$publisher->last_response());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide version information
|
||||
*
|
||||
* Adds this plugin's version data to the global
|
||||
* version array, for e.g. displaying on the version page.
|
||||
*
|
||||
* @param array &$versions array of array of versions
|
||||
*
|
||||
* @return boolean hook value
|
||||
*/
|
||||
|
||||
function onPluginVersion(&$versions)
|
||||
{
|
||||
$versions[] = array('name' => 'PubSubHubBub',
|
||||
'version' => STATUSNET_VERSION,
|
||||
'author' => 'Craig Andrews',
|
||||
'homepage' => 'http://status.net/wiki/Plugin:PubSubHubBub',
|
||||
'homepage' =>
|
||||
'http://status.net/wiki/Plugin:PubSubHubBub',
|
||||
'rawdescription' =>
|
||||
_m('The PubSubHubBub plugin pushes RSS/Atom updates to a <a href="http://pubsubhubbub.googlecode.com/">PubSubHubBub</a> hub.'));
|
||||
_m('The PubSubHubBub plugin pushes RSS/Atom updates '.
|
||||
'to a <a href = "'.
|
||||
'http://pubsubhubbub.googlecode.com/'.
|
||||
'">PubSubHubBub</a> hub.'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -148,6 +148,7 @@ class XMPPDaemon extends Daemon
|
|||
|
||||
function handle_message(&$pl)
|
||||
{
|
||||
$this->log(LOG_DEBUG, "Received message: " . str_replace("\n", " ", var_export($pl, true)));
|
||||
$from = jabber_normalize_jid($pl['from']);
|
||||
|
||||
if ($pl['type'] != 'chat') {
|
||||
|
|
Loading…
Reference in New Issue
Block a user