summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README91
-rw-r--r--actions/twitapiusers.php7
-rw-r--r--classes/Notice.php2
-rw-r--r--classes/Profile.php128
-rw-r--r--classes/User.php2
-rw-r--r--lib/command.php15
-rw-r--r--lib/common.php37
-rw-r--r--lib/profileaction.php21
-rw-r--r--lib/profilesection.php2
-rw-r--r--lib/subs.php13
-rw-r--r--lib/twitterapi.php20
11 files changed, 289 insertions, 49 deletions
diff --git a/README b/README
index 97432e566..40e526355 100644
--- a/README
+++ b/README
@@ -535,6 +535,11 @@ All the daemons write their process IDs (pids) to /var/run/ by
default. This can be useful for starting, stopping, and monitoring the
daemons.
+With version 0.8.0, it's now possible to use a STOMP server instead of
+our kind of hacky home-grown DB-based queue solution. See the "queues"
+config section below for how to configure to use STOMP. As of this
+writing, the software has been tested with ActiveMQ (
+
Twitter Friends Syncing
-----------------------
@@ -892,6 +897,8 @@ fancy: whether or not your site uses fancy URLs (see Fancy URLs
logfile: full path to a file for Laconica to save logging
information to. You may want to use this if you don't have
access to syslog.
+logdebug: whether to log additional debug info like backtraces on
+ hard errors. Default false.
locale_path: full path to the directory for locale data. Unless you
store all your locale data in one place, you probably
don't need to use this.
@@ -946,6 +953,15 @@ sslserver: use an alternate server name for SSL URLs, like
shorturllength: Length of URL at which URLs in a message exceeding 140
characters will be sent to the user's chosen
shortening service.
+<<<<<<< HEAD:README
+design: a default design (colors and background) for the site.
+ Sub-items are: backgroundcolor, contentcolor, sidebarcolor,
+ textcolor, linkcolor, backgroundimage, disposition.
+dupelimit: minimum time allowed for one person to say the same thing
+ twice. Default 60s. Anything lower is considered a user
+ or UI error.
+=======
+>>>>>>> 0.7.x:README
db
--
@@ -996,6 +1012,10 @@ appname: The name that Laconica uses to log messages. By default it's
"laconica", but if you have more than one installation on the
server, you may want to change the name for each instance so
you can track log messages more easily.
+priority: level to log at. Currently ignored.
+facility: what syslog facility to used. Defaults to LOG_USER, only
+ reset if you know what syslog is and have a good reason
+ to change it.
queue
-----
@@ -1005,7 +1025,19 @@ sending out SMS email or XMPP messages, for off-line processing. See
'Queues and daemons' above for how to set this up.
enabled: Whether to uses queues. Defaults to false.
-
+subsystem: Which kind of queueserver to use. Values include "db" for
+ our hacked-together database queuing (no other server
+ required) and "stomp" for a stomp server.
+stomp_server: "broker URI" for stomp server. Something like
+ "tcp://hostname:61613". More complicated ones are
+ possible; see your stomp server's documentation for
+ details.
+queue_basename: a root name to use for queues (stomp only). Typically
+ something like '/queue/sitename/' makes sense.
+stomp_username: username for connecting to the stomp server; defaults
+ to null.
+stomp_password: password for connecting to the stomp server; defaults
+ to null.
license
-------
@@ -1075,6 +1107,8 @@ localonly: If set to true, only messages posted by users of this
blacklist: An array of IDs of users to hide from the public stream.
Useful if you have someone making excessive Twitterfeed posts
to the site, other kinds of automated posts, testing bots, etc.
+autosource: Sources of notices that are from automatic posters, and thus
+ should be kept off the public timeline. Default empty.
theme
-----
@@ -1137,6 +1171,15 @@ dropoff: Decay factor for tag listing, in seconds.
Defaults to exponential decay over ten days; you can twiddle
with it to try and get better results for your site.
+popular
+-------
+
+Settings for the "popular" section of the site.
+
+dropoff: Decay factor for popularity listing, in seconds.
+ Defaults to exponential decay over ten days; you can twiddle
+ with it to try and get better results for your site.
+
daemon
------
@@ -1190,6 +1233,7 @@ source: The name to use for the source of posts to Twitter. Defaults
Twitter <http://twitter.com/help/request_source>, you can use
that here instead. Status updates on Twitter will then have
links to your site.
+taguri: base for tag:// URIs. Defaults to site-server + ',2009'.
inboxes
-------
@@ -1276,7 +1320,7 @@ detection.
supported: an array of mime types you accept to store and distribute,
like 'image/gif', 'video/mpeg', 'audio/mpeg', etc. Make sure you
- setup your server to properly reckognize the types you want to
+ setup your server to properly recognize the types you want to
support.
uploads: false to disable uploading files with notices (true by default).
filecommand: The required MIME_Type library may need to use the 'file'
@@ -1297,6 +1341,17 @@ user_quota: total size in bytes a user can store on this server. Each user
not exceed the user_quota.
monthly_quota: total size permitted in the current month. This is the total
size in bytes that a user can upload each month.
+dir: directory accessible to the Web process where uploads should go.
+ Defaults to the 'file' subdirectory of the install directory, which
+ should be writeable by the Web user.
+server: server name to use when creating URLs for uploaded files.
+ Defaults to null, meaning to use the default Web server. Using
+ a virtual server here can speed up Web performance.
+path: URL path, relative to the server, to find files. Defaults to
+ main path + '/file/'.
+filecommand: command to use for determining the type of a file. May be
+ skipped if fileinfo extension is installed. Defaults to
+ '/usr/bin/file'.
group
-----
@@ -1337,6 +1392,38 @@ handle: boolean. Whether we should register our own PHP session-handling
debug: whether to output debugging info for session storage. Can help
with weird session bugs, sometimes. Default false.
+background
+----------
+
+Users can upload backgrounds for their pages; this section defines
+their use.
+
+server: the server to use for background. Using a separate (even
+ virtual) server for this can speed up load times. Default is
+ null; same as site server.
+dir: directory to write backgrounds too. Default is '/background/'
+ subdir of install dir.
+path: path to backgrounds. Default is sub-path of install path; note
+ that you may need to change this if you change site-path too.
+
+twitterbridge
+-------------
+
+A bi-direction bridge to Twitter (http://twitter.com/).
+
+enabled: default false. If true, will show user's Twitter friends'
+ notices in their inbox and faves pages, only to the user. You
+ must also run the twitterstatusfetcher.php script.
+
+ping
+----
+
+Using the "XML-RPC Ping" method initiated by weblogs.com, the site can
+notify third-party servers of updates.
+
+notify: an array of URLs for ping endpoints. Default is the empty
+ array (no notification).
+
Troubleshooting
===============
diff --git a/actions/twitapiusers.php b/actions/twitapiusers.php
index de8326e3a..fea41b397 100644
--- a/actions/twitapiusers.php
+++ b/actions/twitapiusers.php
@@ -51,6 +51,13 @@ class TwitapiusersAction extends TwitterapiAction
return;
}
+ $profile = $user->getProfile();
+
+ if (!$profile) {
+ common_server_error(_('User has no profile.'));
+ return;
+ }
+
$twitter_user = $this->twitter_user_array($user->getProfile(), true);
if ($apidata['content-type'] == 'xml') {
diff --git a/classes/Notice.php b/classes/Notice.php
index e975cab93..75044cf63 100644
--- a/classes/Notice.php
+++ b/classes/Notice.php
@@ -356,6 +356,8 @@ class Notice extends Memcached_DataObject
$this->blowTagCache($blowLast);
$this->blowGroupCache($blowLast);
$this->blowConversationCache($blowLast);
+ $profile = Profile::staticGet($this->profile_id);
+ $profile->blowNoticeCount();
}
function blowConversationCache($blowLast=false)
diff --git a/classes/Profile.php b/classes/Profile.php
index a0ed6b3ca..224b61bd2 100644
--- a/classes/Profile.php
+++ b/classes/Profile.php
@@ -337,4 +337,132 @@ class Profile extends Memcached_DataObject
return $profile;
}
+
+ function subscriptionCount()
+ {
+ $c = common_memcache();
+
+ if (!empty($c)) {
+ $cnt = $c->get(common_cache_key('profile:subscription_count:'.$this->id));
+ if (is_integer($cnt)) {
+ return (int) $cnt;
+ }
+ }
+
+ $sub = new Subscription();
+ $sub->subscriber = $this->id;
+
+ $cnt = (int) $sub->count('distinct subscribed');
+
+ $cnt = ($cnt > 0) ? $cnt - 1 : $cnt;
+
+ if (!empty($c)) {
+ $c->set(common_cache_key('profile:subscription_count:'.$this->id), $cnt);
+ }
+
+ common_debug("subscriptionCount == $cnt");
+ return $cnt;
+ }
+
+ function subscriberCount()
+ {
+ $c = common_memcache();
+ if (!empty($c)) {
+ $cnt = $c->get(common_cache_key('profile:subscriber_count:'.$this->id));
+ if (is_integer($cnt)) {
+ return (int) $cnt;
+ }
+ }
+
+ $sub = new Subscription();
+ $sub->subscribed = $this->id;
+
+ $cnt = (int) $sub->count('distinct subscriber');
+
+ $cnt = ($cnt > 0) ? $cnt - 1 : $cnt;
+
+ if (!empty($c)) {
+ $c->set(common_cache_key('profile:subscriber_count:'.$this->id), $cnt);
+ }
+
+ common_debug("subscriberCount == $cnt");
+ return $cnt;
+ }
+
+ function faveCount()
+ {
+ $c = common_memcache();
+ if (!empty($c)) {
+ $cnt = $c->get(common_cache_key('profile:fave_count:'.$this->id));
+ if (is_integer($cnt)) {
+ return (int) $cnt;
+ }
+ }
+
+ $faves = new Fave();
+ $faves->user_id = $this->id;
+ $cnt = (int) $faves->count('distinct notice_id');
+
+ if (!empty($c)) {
+ $c->set(common_cache_key('profile:fave_count:'.$this->id), $cnt);
+ }
+
+ common_debug("faveCount == $cnt");
+ return $cnt;
+ }
+
+ function noticeCount()
+ {
+ $c = common_memcache();
+
+ if (!empty($c)) {
+ $cnt = $c->get(common_cache_key('profile:notice_count:'.$this->id));
+ if (is_integer($cnt)) {
+ return (int) $cnt;
+ }
+ }
+
+ $notices = new Notice();
+ $notices->profile_id = $this->id;
+ $cnt = (int) $notices->count('distinct id');
+
+ if (!empty($c)) {
+ $c->set(common_cache_key('profile:notice_count:'.$this->id), $cnt);
+ }
+
+ common_debug("noticeCount == $cnt");
+ return $cnt;
+ }
+
+ function blowSubscriberCount()
+ {
+ $c = common_memcache();
+ if (!empty($c)) {
+ $c->delete(common_cache_key('profile:subscriber_count:'.$this->id));
+ }
+ }
+
+ function blowSubscriptionCount()
+ {
+ $c = common_memcache();
+ if (!empty($c)) {
+ $c->delete(common_cache_key('profile:subscription_count:'.$this->id));
+ }
+ }
+
+ function blowFaveCount()
+ {
+ $c = common_memcache();
+ if (!empty($c)) {
+ $c->delete(common_cache_key('profile:fave_count:'.$this->id));
+ }
+ }
+
+ function blowNoticeCount()
+ {
+ $c = common_memcache();
+ if (!empty($c)) {
+ $c->delete(common_cache_key('profile:notice_count:'.$this->id));
+ }
+ }
}
diff --git a/classes/User.php b/classes/User.php
index 04b38a0d2..6c1f149e4 100644
--- a/classes/User.php
+++ b/classes/User.php
@@ -494,6 +494,8 @@ class User extends Memcached_DataObject
$cache->delete(common_cache_key('fave:ids_by_user_own:'.$this->id));
$cache->delete(common_cache_key('fave:ids_by_user_own:'.$this->id.';last'));
}
+ $profile = $this->getProfile();
+ $profile->blowFaveCount();
}
function getSelfTags()
diff --git a/lib/command.php b/lib/command.php
index 564661382..4e2280bc8 100644
--- a/lib/command.php
+++ b/lib/command.php
@@ -97,18 +97,11 @@ class StatsCommand extends Command
{
function execute($channel)
{
+ $profile = $this->user->getProfile();
- $subs = new Subscription();
- $subs->subscriber = $this->user->id;
- $subs_count = (int) $subs->count() - 1;
-
- $subbed = new Subscription();
- $subbed->subscribed = $this->user->id;
- $subbed_count = (int) $subbed->count() - 1;
-
- $notices = new Notice();
- $notices->profile_id = $this->user->id;
- $notice_count = (int) $notices->count();
+ $subs_count = $profile->subscriptionCount();
+ $subbed_count = $profile->subscriberCount();
+ $notice_count = $profile->noticeCount();
$channel->output($this->user, sprintf(_("Subscriptions: %1\$s\n".
"Subscribers: %2\$s\n".
diff --git a/lib/common.php b/lib/common.php
index 14be747bc..c47702779 100644
--- a/lib/common.php
+++ b/lib/common.php
@@ -19,7 +19,7 @@
if (!defined('LACONICA')) { exit(1); }
-define('LACONICA_VERSION', '0.8.0dev');
+define('LACONICA_VERSION', '0.8.0');
define('AVATAR_PROFILE_SIZE', 96);
define('AVATAR_STREAM_SIZE', 48);
@@ -206,7 +206,7 @@ $config =
'inboxes' =>
array('enabled' => true), # on by default for new sites
'newuser' =>
- array('subscribe' => null,
+ array('default' => null,
'welcome' => null),
'snapshot' =>
array('run' => 'web',
@@ -282,6 +282,39 @@ if (function_exists('date_default_timezone_set')) {
date_default_timezone_set('UTC');
}
+function addPlugin($name, $attrs = null)
+{
+ $name = ucfirst($name);
+ $pluginclass = "{$name}Plugin";
+
+ if (!class_exists($pluginclass)) {
+
+ $files = array("local/plugins/{$pluginclass}.php",
+ "local/plugins/{$name}/{$pluginclass}.php",
+ "local/{$pluginclass}.php",
+ "local/{$name}/{$pluginclass}.php",
+ "plugins/{$pluginclass}.php",
+ "plugins/{$name}/{$pluginclass}.php");
+
+ foreach ($files as $file) {
+ $fullpath = INSTALLDIR.'/'.$file;
+ if (@file_exists($fullpath)) {
+ include_once($fullpath);
+ break;
+ }
+ }
+ }
+
+ $inst = new $pluginclass();
+
+ if (!empty($attrs)) {
+ foreach ($attrs as $aname => $avalue) {
+ $inst->$aname = $avalue;
+ }
+ }
+ return $inst;
+}
+
// From most general to most specific:
// server-wide, then vhost-wide, then for a path,
// finally for a dir (usually only need one of the last two).
diff --git a/lib/profileaction.php b/lib/profileaction.php
index eeb5dbe48..9e9c79c78 100644
--- a/lib/profileaction.php
+++ b/lib/profileaction.php
@@ -163,18 +163,9 @@ class ProfileAction extends OwnerDesignAction
function showStatistics()
{
- // XXX: WORM cache this
- $subs = new Subscription();
- $subs->subscriber = $this->profile->id;
- $subs_count = (int) $subs->count() - 1;
-
- $subbed = new Subscription();
- $subbed->subscribed = $this->profile->id;
- $subbed_count = (int) $subbed->count() - 1;
-
- $notices = new Notice();
- $notices->profile_id = $this->profile->id;
- $notice_count = (int) $notices->count();
+ $subs_count = $this->profile->subscriptionCount();
+ $subbed_count = $this->profile->subscriberCount();
+ $notice_count = $this->profile->noticeCount();
$this->elementStart('div', array('id' => 'entity_statistics',
'class' => 'section'));
@@ -199,7 +190,7 @@ class ProfileAction extends OwnerDesignAction
array('nickname' => $this->profile->nickname))),
_('Subscriptions'));
$this->elementEnd('dt');
- $this->element('dd', null, (is_int($subs_count)) ? $subs_count : '0');
+ $this->element('dd', null, $subs_count);
$this->elementEnd('dl');
$this->elementStart('dl', 'entity_subscribers');
@@ -208,12 +199,12 @@ class ProfileAction extends OwnerDesignAction
array('nickname' => $this->profile->nickname))),
_('Subscribers'));
$this->elementEnd('dt');
- $this->element('dd', 'subscribers', (is_int($subbed_count)) ? $subbed_count : '0');
+ $this->element('dd', 'subscribers', $subbed_count);
$this->elementEnd('dl');
$this->elementStart('dl', 'entity_notices');
$this->element('dt', null, _('Notices'));
- $this->element('dd', null, (is_int($notice_count)) ? $notice_count : '0');
+ $this->element('dd', null, $notice_count);
$this->elementEnd('dl');
$this->elementEnd('div');
diff --git a/lib/profilesection.php b/lib/profilesection.php
index 8ed290e03..9ff243fb5 100644
--- a/lib/profilesection.php
+++ b/lib/profilesection.php
@@ -94,8 +94,8 @@ class ProfileSection extends Section
$profile->fullname :
$profile->nickname));
$this->out->element('span', 'fn nickname', $profile->nickname);
- $this->out->elementEnd('span');
$this->out->elementEnd('a');
+ $this->out->elementEnd('span');
$this->out->elementEnd('td');
if ($profile->value) {
$this->out->element('td', 'value', $profile->value);
diff --git a/lib/subs.php b/lib/subs.php
index 3bd67b39c..e76023752 100644
--- a/lib/subs.php
+++ b/lib/subs.php
@@ -44,7 +44,6 @@ function subs_subscribe_user($user, $other_nickname)
function subs_subscribe_to($user, $other)
{
-
if ($user->isSubscribed($other)) {
return _('Already subscribed!.');
}
@@ -60,12 +59,16 @@ function subs_subscribe_to($user, $other)
subs_notify($other, $user);
- $cache = common_memcache();
+ $cache = common_memcache();
if ($cache) {
$cache->delete(common_cache_key('user:notices_with_friends:' . $user->id));
}
+ $profile = $user->getProfile();
+
+ $profile->blowSubscriptionsCount();
+ $other->blowSubscribersCount();
if ($other->autosubscribe && !$other->isSubscribed($user) && !$user->hasBlocked($other)) {
if (!$other->subscribeTo($user)) {
@@ -117,7 +120,6 @@ function subs_unsubscribe_user($user, $other_nickname)
function subs_unsubscribe_to($user, $other)
{
-
if (!$user->isSubscribed($other))
return _('Not subscribed!.');
@@ -139,6 +141,11 @@ function subs_unsubscribe_to($user, $other)
$cache->delete(common_cache_key('user:notices_with_friends:' . $user->id));
}
+ $profile = $user->getProfile();
+
+ $profile->blowSubscriptionsCount();
+ $other->blowSubscribersCount();
+
return true;
}
diff --git a/lib/twitterapi.php b/lib/twitterapi.php
index 8f902cbca..f48513e67 100644
--- a/lib/twitterapi.php
+++ b/lib/twitterapi.php
@@ -89,7 +89,7 @@ class TwitterapiAction extends Action
$twitter_user['url'] = ($profile->homepage) ? $profile->homepage : null;
$twitter_user['protected'] = false; # not supported by Laconica yet
- $twitter_user['followers_count'] = $this->count_subscriptions($profile);
+ $twitter_user['followers_count'] = $profile->subscriberCount();
// To be supported soon...
$twitter_user['profile_background_color'] = '';
@@ -98,17 +98,11 @@ class TwitterapiAction extends Action
$twitter_user['profile_sidebar_fill_color'] = '';
$twitter_user['profile_sidebar_border_color'] = '';
- $subbed = DB_DataObject::factory('subscription');
- $subbed->subscriber = $profile->id;
- $subbed_count = (int) $subbed->count() - 1;
- $twitter_user['friends_count'] = (is_int($subbed_count)) ? $subbed_count : 0;
+ $twitter_user['friends_count'] = $profile->subscriptionCount();
$twitter_user['created_at'] = $this->date_twitter($profile->created);
- $faves = DB_DataObject::factory('fave');
- $faves->user_id = $user->id;
- $faves_count = (int) $faves->count();
- $twitter_user['favourites_count'] = $faves_count; // British spelling!
+ $twitter_user['favourites_count'] = $profile->faveCount(); // British spelling!
// Need to pull up the user for some of this
$user = User::staticGet($profile->id);
@@ -129,11 +123,7 @@ class TwitterapiAction extends Action
$twitter_user['profile_background_image_url'] = '';
$twitter_user['profile_background_tile'] = false;
- $notices = DB_DataObject::factory('notice');
- $notices->profile_id = $profile->id;
- $notice_count = (int) $notices->count();
-
- $twitter_user['statuses_count'] = (is_int($notice_count)) ? $notice_count : 0;
+ $twitter_user['statuses_count'] = $profile->noticeCount();
// Is the requesting user following this user?
$twitter_user['following'] = false;
@@ -396,7 +386,7 @@ class TwitterapiAction extends Action
$enclosure = $entry['enclosures'][0];
$this->element('enclosure', array('url'=>$enclosure['url'],'type'=>$enclosure['mimetype'],'length'=>$enclosure['size']), null);
}
-
+
$this->elementEnd('item');
}