summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README35
-rw-r--r--actions/apistatusesretweets.php15
-rw-r--r--actions/apitimelineretweetedbyme.php51
-rw-r--r--actions/apitimelineretweetedtome.php15
-rw-r--r--actions/apitimelineretweetsofme.php15
-rw-r--r--classes/Memcached_DataObject.php33
-rw-r--r--js/util.js12
-rw-r--r--lib/default.php4
-rw-r--r--plugins/PubSubHubBub/PubSubHubBubPlugin.php187
-rwxr-xr-xscripts/xmppdaemon.php1
10 files changed, 282 insertions, 86 deletions
diff --git a/README b/README
index 386b3264a..602288789 100644
--- a/README
+++ b/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
=============
diff --git a/actions/apistatusesretweets.php b/actions/apistatusesretweets.php
index f7a3dd60a..a79d43168 100644
--- a/actions/apistatusesretweets.php
+++ b/actions/apistatusesretweets.php
@@ -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;
+ }
}
diff --git a/actions/apitimelineretweetedbyme.php b/actions/apitimelineretweetedbyme.php
index 88652c3fd..564e98619 100644
--- a/actions/apitimelineretweetedbyme.php
+++ b/actions/apitimelineretweetedbyme.php
@@ -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
- *
- * show a timeline of the user's repeated notices
+ * Return true if read only.
*
- * @param array $args $_REQUEST data (unused)
+ * @param array $args other arguments
*
- * @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;
}
}
diff --git a/actions/apitimelineretweetedtome.php b/actions/apitimelineretweetedtome.php
index 113ab96d2..e47bc30b8 100644
--- a/actions/apitimelineretweetedtome.php
+++ b/actions/apitimelineretweetedtome.php
@@ -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;
+ }
}
diff --git a/actions/apitimelineretweetsofme.php b/actions/apitimelineretweetsofme.php
index 6ca2c779c..e4b09e9bd 100644
--- a/actions/apitimelineretweetsofme.php
+++ b/actions/apitimelineretweetsofme.php
@@ -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;
+ }
}
diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php
index 4ecab9db6..6ceb59e8b 100644
--- a/classes/Memcached_DataObject.php
+++ b/classes/Memcached_DataObject.php
@@ -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
diff --git a/js/util.js b/js/util.js
index aeec8d89d..a7339010a 100644
--- a/js/util.js
+++ b/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);
}
});
diff --git a/lib/default.php b/lib/default.php
index ceae0efaa..764d309df 100644
--- a/lib/default.php
+++ b/lib/default.php
@@ -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
diff --git a/plugins/PubSubHubBub/PubSubHubBubPlugin.php b/plugins/PubSubHubBub/PubSubHubBubPlugin.php
index 367b35403..8286cd548 100644
--- a/plugins/PubSubHubBub/PubSubHubBubPlugin.php
+++ b/plugins/PubSubHubBub/PubSubHubBubPlugin.php
@@ -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);
- function onStartApiAtom($action){
- $action->element('link',array('rel'=>'hub','href'=>$this->hub),null);
+ return true;
}
- function onStartApiRss($action){
- $action->element('atom: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 onHandleQueuedNotice($notice){
+ /**
+ * 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)
+ {
$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 ($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());
+ 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;
}
diff --git a/scripts/xmppdaemon.php b/scripts/xmppdaemon.php
index cef9c4bd0..0c118c53d 100755
--- a/scripts/xmppdaemon.php
+++ b/scripts/xmppdaemon.php
@@ -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') {