summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--actions/apiaccountverifycredentials.php33
-rw-r--r--actions/apigroupjoin.php2
-rw-r--r--actions/apigroupleave.php2
-rw-r--r--actions/favorited.php3
-rw-r--r--actions/publictagcloud.php3
-rw-r--r--actions/register.php4
-rw-r--r--actions/userauthorization.php21
-rw-r--r--classes/Inbox.php62
-rw-r--r--classes/Memcached_DataObject.php2
-rw-r--r--classes/User.php14
-rw-r--r--classes/statusnet.ini2
-rw-r--r--db/statusnet.sql2
-rw-r--r--lib/cache.php4
-rw-r--r--lib/default.php6
-rw-r--r--lib/grouptagcloudsection.php1
-rw-r--r--lib/oauthstore.php3
-rw-r--r--lib/personaltagcloudsection.php1
-rw-r--r--lib/popularnoticesection.php7
-rw-r--r--plugins/MemcachePlugin.php18
-rw-r--r--plugins/MobileProfile/MobileProfilePlugin.php10
-rw-r--r--plugins/MobileProfile/mp-screen.css5
-rwxr-xr-xplugins/TwitterBridge/daemons/twitterstatusfetcher.php53
-rw-r--r--plugins/TwitterBridge/twitter.php54
-rw-r--r--plugins/TwitterBridge/twitterauthorization.php2
-rw-r--r--scripts/updateprofileurl.php99
-rw-r--r--theme/base/images/icons/icons-01.gifbin3758 -> 3870 bytes
-rw-r--r--theme/base/images/icons/twotone/green/against.gifbin0 -> 85 bytes
-rw-r--r--theme/base/images/icons/twotone/green/checkmark.gifbin0 -> 76 bytes
-rw-r--r--theme/default/css/display.css9
-rw-r--r--theme/identica/css/display.css9
30 files changed, 319 insertions, 112 deletions
diff --git a/actions/apiaccountverifycredentials.php b/actions/apiaccountverifycredentials.php
index 1095d5162..ea61a3205 100644
--- a/actions/apiaccountverifycredentials.php
+++ b/actions/apiaccountverifycredentials.php
@@ -66,18 +66,21 @@ class ApiAccountVerifyCredentialsAction extends ApiAuthAction
{
parent::handle($args);
- switch ($this->format) {
- case 'xml':
- case 'json':
- $args['id'] = $this->auth_user->id;
- $action_obj = new ApiUserShowAction();
- if ($action_obj->prepare($args)) {
- $action_obj->handle($args);
- }
- break;
- default:
- header('Content-Type: text/html; charset=utf-8');
- print 'Authorized';
+ if (!in_array($this->format, array('xml', 'json'))) {
+ $this->clientError(_('API method not found.'), $code = 404);
+ return;
+ }
+
+ $twitter_user = $this->twitterUserArray($this->auth_user->getProfile(), true);
+
+ if ($this->format == 'xml') {
+ $this->initDocument('xml');
+ $this->showTwitterXmlUser($twitter_user);
+ $this->endDocument('xml');
+ } elseif ($this->format == 'json') {
+ $this->initDocument('json');
+ $this->showJsonObjects($twitter_user);
+ $this->endDocument('json');
}
}
@@ -86,14 +89,14 @@ class ApiAccountVerifyCredentialsAction extends ApiAuthAction
* Is this action read only?
*
* @param array $args other arguments
- *
+ *
* @return boolean true
*
**/
-
+
function isReadOnly($args)
{
return true;
}
-
+
}
diff --git a/actions/apigroupjoin.php b/actions/apigroupjoin.php
index 3309d63e7..374cf83df 100644
--- a/actions/apigroupjoin.php
+++ b/actions/apigroupjoin.php
@@ -145,7 +145,7 @@ class ApiGroupJoinAction extends ApiAuthAction
switch($this->format) {
case 'xml':
- $this->show_single_xml_group($this->group);
+ $this->showSingleXmlGroup($this->group);
break;
case 'json':
$this->showSingleJsonGroup($this->group);
diff --git a/actions/apigroupleave.php b/actions/apigroupleave.php
index 6f8d40527..9848ece05 100644
--- a/actions/apigroupleave.php
+++ b/actions/apigroupleave.php
@@ -131,7 +131,7 @@ class ApiGroupLeaveAction extends ApiAuthAction
switch($this->format) {
case 'xml':
- $this->show_single_xml_group($this->group);
+ $this->showSingleXmlGroup($this->group);
break;
case 'json':
$this->showSingleJsonGroup($this->group);
diff --git a/actions/favorited.php b/actions/favorited.php
index 9ffa5b844..d8980440d 100644
--- a/actions/favorited.php
+++ b/actions/favorited.php
@@ -186,10 +186,13 @@ class FavoritedAction extends Action
function showContent()
{
$weightexpr = common_sql_weight('fave.modified', common_config('popular', 'dropoff'));
+ $cutoff = sprintf("fave.modified > '%s'",
+ common_sql_date(time() - common_config('popular', 'cutoff')));
$qry = 'SELECT notice.*, '.
$weightexpr . ' as weight ' .
'FROM notice JOIN fave ON notice.id = fave.notice_id ' .
+ "WHERE $cutoff " .
'GROUP BY id,profile_id,uri,content,rendered,url,created,notice.modified,reply_to,is_local,source,notice.conversation ' .
'ORDER BY weight DESC';
diff --git a/actions/publictagcloud.php b/actions/publictagcloud.php
index 9e4478dbb..9993b2d3f 100644
--- a/actions/publictagcloud.php
+++ b/actions/publictagcloud.php
@@ -106,7 +106,10 @@ class PublictagcloudAction extends Action
#Add the aggregated columns...
$tags->selectAdd('max(notice_id) as last_notice_id');
$calc = common_sql_weight('created', common_config('tag', 'dropoff'));
+ $cutoff = sprintf("notice_tag.created > '%s'",
+ common_sql_date(time() - common_config('tag', 'cutoff')));
$tags->selectAdd($calc . ' as weight');
+ $tags->addWhere($cutoff);
$tags->groupBy('tag');
$tags->orderBy('weight DESC');
diff --git a/actions/register.php b/actions/register.php
index 698137346..ccab76cf0 100644
--- a/actions/register.php
+++ b/actions/register.php
@@ -280,7 +280,7 @@ class RegisterAction extends Action
function nicknameExists($nickname)
{
$user = User::staticGet('nickname', $nickname);
- return ($user !== false);
+ return is_object($user);
}
/**
@@ -300,7 +300,7 @@ class RegisterAction extends Action
return false;
}
$user = User::staticGet('email', $email);
- return ($user !== false);
+ return is_object($user);
}
// overrrided to add entry-title class
diff --git a/actions/userauthorization.php b/actions/userauthorization.php
index 4321f1302..7f71c60db 100644
--- a/actions/userauthorization.php
+++ b/actions/userauthorization.php
@@ -127,10 +127,10 @@ class UserauthorizationAction extends Action
$location = $params->getLocation();
$avatar = $params->getAvatarURL();
- $this->elementStart('div', array('class' => 'profile'));
$this->elementStart('div', 'entity_profile vcard');
- $this->elementStart('a', array('href' => $profile,
- 'class' => 'url'));
+ $this->elementStart('dl', 'entity_depiction');
+ $this->element('dt', null, _('Photo'));
+ $this->elementStart('dd');
if ($avatar) {
$this->element('img', array('src' => $avatar,
'class' => 'photo avatar',
@@ -138,11 +138,19 @@ class UserauthorizationAction extends Action
'height' => AVATAR_PROFILE_SIZE,
'alt' => $nickname));
}
+ $this->elementEnd('dd');
+ $this->elementEnd('dl');
+
+ $this->elementStart('dl', 'entity_nickname');
+ $this->element('dt', null, _('Nickname'));
+ $this->elementStart('dd');
$hasFN = ($fullname !== '') ? 'nickname' : 'fn nickname';
- $this->elementStart('span', $hasFN);
+ $this->elementStart('a', array('href' => $profile,
+ 'class' => 'url '.$hasFN));
$this->raw($nickname);
- $this->elementEnd('span');
$this->elementEnd('a');
+ $this->elementEnd('dd');
+ $this->elementEnd('dl');
if (!is_null($fullname)) {
$this->elementStart('dl', 'entity_fn');
@@ -214,7 +222,6 @@ class UserauthorizationAction extends Action
$this->elementEnd('li');
$this->elementEnd('ul');
$this->elementEnd('div');
- $this->elementEnd('div');
}
function sendAuthorization()
@@ -350,4 +357,4 @@ class UserauthorizationAction extends Action
}
}
}
-} \ No newline at end of file
+}
diff --git a/classes/Inbox.php b/classes/Inbox.php
index 26b27d2b5..be62611a1 100644
--- a/classes/Inbox.php
+++ b/classes/Inbox.php
@@ -32,6 +32,7 @@ require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
class Inbox extends Memcached_DataObject
{
const BOXCAR = 128;
+ const MAX_NOTICES = 1024;
###START_AUTOCODE
/* the code below is auto generated do not remove the above tag */
@@ -81,7 +82,7 @@ class Inbox extends Memcached_DataObject
$ni->selectAdd();
$ni->selectAdd('notice_id');
$ni->orderBy('notice_id DESC');
- $ni->limit(0, 1024);
+ $ni->limit(0, self::MAX_NOTICES);
if ($ni->find()) {
while($ni->fetch()) {
@@ -115,9 +116,11 @@ class Inbox extends Memcached_DataObject
$result = $inbox->query(sprintf('UPDATE inbox '.
'set notice_ids = concat(cast(0x%08x as binary(4)), '.
- 'substr(notice_ids, 1, 4092)) '.
+ 'substr(notice_ids, 1, %d)) '.
'WHERE user_id = %d',
- $notice_id, $user_id));
+ $notice_id,
+ 4 * (self::MAX_NOTICES - 1),
+ $user_id));
if ($result) {
self::blow('inbox:user_id:%d', $user_id);
@@ -173,4 +176,57 @@ class Inbox extends Memcached_DataObject
return $ids;
}
+
+ /**
+ * Wrapper for Inbox::stream() and Notice::getStreamByIds() returning
+ * additional items up to the limit if we were short due to deleted
+ * notices still being listed in the inbox.
+ *
+ * The fast path (when no items are deleted) should be just as fast; the
+ * offset parameter is applied *before* lookups for maximum efficiency.
+ *
+ * This means offset-based paging may show duplicates, but similar behavior
+ * already exists when new notices are posted between page views, so we
+ * think people will be ok with this until id-based paging is introduced
+ * to the user interface.
+ *
+ * @param int $user_id
+ * @param int $offset skip past the most recent N notices (after since_id checks)
+ * @param int $limit
+ * @param mixed $since_id return only notices after but not including this id
+ * @param mixed $max_id return only notices up to and including this id
+ * @param mixed $since obsolete/ignored
+ * @param mixed $own ignored?
+ * @return array of Notice objects
+ *
+ * @todo consider repacking the inbox when this happens?
+ */
+ function streamNotices($user_id, $offset, $limit, $since_id, $max_id, $since, $own=false)
+ {
+ $ids = self::stream($user_id, $offset, self::MAX_NOTICES, $since_id, $max_id, $since, $own);
+
+ // Do a bulk lookup for the first $limit items
+ // Fast path when nothing's deleted.
+ $firstChunk = array_slice($ids, 0, $limit);
+ $notices = Notice::getStreamByIds($firstChunk);
+
+ $wanted = count($firstChunk); // raw entry count in the inbox up to our $limit
+ if ($notices->N >= $wanted) {
+ return $notices;
+ }
+
+ // There were deleted notices, we'll need to look for more.
+ assert($notices instanceof ArrayWrapper);
+ $items = $notices->_items;
+ $remainder = array_slice($ids, $limit);
+
+ while (count($items) < $wanted && count($remainder) > 0) {
+ $notice = Notice::staticGet(array_shift($remainder));
+ if ($notice) {
+ $items[] = $notice;
+ } else {
+ }
+ }
+ return new ArrayWrapper($items);
+ }
}
diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php
index ab65c30ce..dfd06b57e 100644
--- a/classes/Memcached_DataObject.php
+++ b/classes/Memcached_DataObject.php
@@ -363,7 +363,7 @@ class Memcached_DataObject extends DB_DataObject
$cached[] = clone($inst);
}
$inst->free();
- $c->set($ckey, $cached, MEMCACHE_COMPRESSED, $expiry);
+ $c->set($ckey, $cached, Cache::COMPRESSED, $expiry);
return new ArrayWrapper($cached);
}
diff --git a/classes/User.php b/classes/User.php
index 0ab816b57..72c3f39e9 100644
--- a/classes/User.php
+++ b/classes/User.php
@@ -502,28 +502,22 @@ class User extends Memcached_DataObject
function noticesWithFriends($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
{
- $ids = Inbox::stream($this->id, $offset, $limit, $since_id, $before_id, $since, false);
- return Notice::getStreamByIds($ids);
+ return Inbox::streamNotices($this->id, $offset, $limit, $since_id, $before_id, $since, false);
}
function noticeInbox($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
{
- $ids = Inbox::stream($this->id, $offset, $limit, $since_id, $before_id, $since, true);
- return Notice::getStreamByIds($ids);
+ return Inbox::streamNotices($this->id, $offset, $limit, $since_id, $before_id, $since, true);
}
function friendsTimeline($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
{
- $ids = Inbox::stream($this->id, $offset, $limit, $since_id, $before_id, $since, false);
-
- return Notice::getStreamByIds($ids);
+ return Inbox::streamNotices($this->id, $offset, $limit, $since_id, $before_id, $since, false);
}
function ownFriendsTimeline($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
{
- $ids = Inbox::stream($this->id, $offset, $limit, $since_id, $before_id, $since, true);
-
- return Notice::getStreamByIds($ids);
+ return Inbox::streamNotices($this->id, $offset, $limit, $since_id, $before_id, $since, true);
}
function blowFavesCache()
diff --git a/classes/statusnet.ini b/classes/statusnet.ini
index a535159e8..5f8da7cf5 100644
--- a/classes/statusnet.ini
+++ b/classes/statusnet.ini
@@ -353,7 +353,7 @@ notice_id = K
id = 129
owner = 129
consumer_key = 130
-name = 2
+name = 130
description = 2
icon = 130
source_url = 2
diff --git a/db/statusnet.sql b/db/statusnet.sql
index 8946f4d7e..343464801 100644
--- a/db/statusnet.sql
+++ b/db/statusnet.sql
@@ -214,7 +214,7 @@ create table oauth_application (
id integer auto_increment primary key comment 'unique identifier',
owner integer not null comment 'owner of the application' references profile (id),
consumer_key varchar(255) not null comment 'application consumer key' references consumer (consumer_key),
- name varchar(255) unique key comment 'name of the application',
+ name varchar(255) not null unique key comment 'name of the application',
description varchar(255) comment 'description of the application',
icon varchar(255) not null comment 'application icon',
source_url varchar(255) comment 'application homepage - used for source link',
diff --git a/lib/cache.php b/lib/cache.php
index 635c96ad4..df6fc3649 100644
--- a/lib/cache.php
+++ b/lib/cache.php
@@ -47,6 +47,8 @@ class Cache
var $_items = array();
static $_inst = null;
+ const COMPRESSED = 1;
+
/**
* Singleton constructor
*
@@ -133,7 +135,7 @@ class Cache
*
* @param string $key The key to use for lookups
* @param string $value The value to store
- * @param integer $flag Flags to use, mostly ignored
+ * @param integer $flag Flags to use, may include Cache::COMPRESSED
* @param integer $expiry Expiry value, mostly ignored
*
* @return boolean success flag
diff --git a/lib/default.php b/lib/default.php
index 2bedc4bf0..485a08ba4 100644
--- a/lib/default.php
+++ b/lib/default.php
@@ -144,9 +144,11 @@ $default =
'invite' =>
array('enabled' => true),
'tag' =>
- array('dropoff' => 864000.0),
+ array('dropoff' => 864000.0, # controls weighting based on age
+ 'cutoff' => 86400 * 90), # only look at notices posted in last 90 days
'popular' =>
- array('dropoff' => 864000.0),
+ array('dropoff' => 864000.0, # controls weighting based on age
+ 'cutoff' => 86400 * 90), # only look at notices favorited in last 90 days
'daemon' =>
array('piddir' => '/var/run',
'user' => false,
diff --git a/lib/grouptagcloudsection.php b/lib/grouptagcloudsection.php
index 14ceda085..f1106cc7b 100644
--- a/lib/grouptagcloudsection.php
+++ b/lib/grouptagcloudsection.php
@@ -59,6 +59,7 @@ class GroupTagCloudSection extends TagCloudSection
function getTags()
{
$weightexpr = common_sql_weight('notice_tag.created', common_config('tag', 'dropoff'));
+ // @fixme should we use the cutoff too? Doesn't help with indexing per-group.
$names = $this->group->getAliases();
diff --git a/lib/oauthstore.php b/lib/oauthstore.php
index b30fb49d5..eabe37f9f 100644
--- a/lib/oauthstore.php
+++ b/lib/oauthstore.php
@@ -65,7 +65,7 @@ class StatusNetOAuthDataStore extends OAuthDataStore
{
$n = new Nonce();
$n->consumer_key = $consumer->key;
- $n->ts = $timestamp;
+ $n->ts = common_sql_date($timestamp);
$n->nonce = $nonce;
if ($n->find(true)) {
return true;
@@ -362,7 +362,6 @@ class StatusNetOAuthDataStore extends OAuthDataStore
array('is_local' => Notice::REMOTE_OMB,
'uri' => $omb_notice->getIdentifierURI()));
-
}
/**
diff --git a/lib/personaltagcloudsection.php b/lib/personaltagcloudsection.php
index 091425f92..5ea3f188d 100644
--- a/lib/personaltagcloudsection.php
+++ b/lib/personaltagcloudsection.php
@@ -59,6 +59,7 @@ class PersonalTagCloudSection extends TagCloudSection
function getTags()
{
$weightexpr = common_sql_weight('notice_tag.created', common_config('tag', 'dropoff'));
+ // @fixme should we use the cutoff too? Doesn't help with indexing per-user.
$qry = 'SELECT notice_tag.tag, '.
$weightexpr . ' as weight ' .
diff --git a/lib/popularnoticesection.php b/lib/popularnoticesection.php
index fbf9a60ab..296ddbbb5 100644
--- a/lib/popularnoticesection.php
+++ b/lib/popularnoticesection.php
@@ -59,12 +59,15 @@ class PopularNoticeSection extends NoticeSection
}
}
$weightexpr = common_sql_weight('fave.modified', common_config('popular', 'dropoff'));
+ $cutoff = sprintf("fave.modified > '%s'",
+ common_sql_date(time() - common_config('popular', 'cutoff')));
$qry = "SELECT notice.*, $weightexpr as weight ";
if(isset($tag)) {
$qry .= 'FROM notice_tag, notice JOIN fave ON notice.id = fave.notice_id ' .
- "WHERE notice.id = notice_tag.notice_id and '$tag' = notice_tag.tag";
+ "WHERE $cutoff and notice.id = notice_tag.notice_id and '$tag' = notice_tag.tag";
} else {
- $qry .= 'FROM notice JOIN fave ON notice.id = fave.notice_id';
+ $qry .= 'FROM notice JOIN fave ON notice.id = fave.notice_id ' .
+ "WHERE $cutoff";
}
$qry .= ' GROUP BY notice.id,notice.profile_id,notice.content,notice.uri,' .
'notice.rendered,notice.url,notice.created,notice.modified,' .
diff --git a/plugins/MemcachePlugin.php b/plugins/MemcachePlugin.php
index 2bc4b892b..c5e74fb41 100644
--- a/plugins/MemcachePlugin.php
+++ b/plugins/MemcachePlugin.php
@@ -102,7 +102,7 @@ class MemcachePlugin extends Plugin
*
* @param string &$key in; Key to use for lookups
* @param mixed &$value in; Value to associate
- * @param integer &$flag in; Flag (passed through to Memcache)
+ * @param integer &$flag in; Flag empty or Cache::COMPRESSED
* @param integer &$expiry in; Expiry (passed through to Memcache)
* @param boolean &$success out; Whether the set was successful
*
@@ -115,7 +115,7 @@ class MemcachePlugin extends Plugin
if ($expiry === null) {
$expiry = $this->defaultExpiry;
}
- $success = $this->_conn->set($key, $value, $flag, $expiry);
+ $success = $this->_conn->set($key, $value, $this->flag(intval($flag)), $expiry);
Event::handle('EndCacheSet', array($key, $value, $flag,
$expiry));
return false;
@@ -197,6 +197,20 @@ class MemcachePlugin extends Plugin
}
}
+ /**
+ * Translate general flags to Memcached-specific flags
+ * @param int $flag
+ * @return int
+ */
+ protected function flag($flag)
+ {
+ $out = 0;
+ if ($flag & Cache::COMPRESSED == Cache::COMPRESSED) {
+ $out |= MEMCACHE_COMPRESSED;
+ }
+ return $out;
+ }
+
function onPluginVersion(&$versions)
{
$versions[] = array('name' => 'Memcache',
diff --git a/plugins/MobileProfile/MobileProfilePlugin.php b/plugins/MobileProfile/MobileProfilePlugin.php
index 5c913836d..cd2531fa7 100644
--- a/plugins/MobileProfile/MobileProfilePlugin.php
+++ b/plugins/MobileProfile/MobileProfilePlugin.php
@@ -240,6 +240,8 @@ class MobileProfilePlugin extends WAP20Plugin
return true;
}
+ $action->cssLink('css/display.css');
+
if (file_exists(Theme::file('css/mp-screen.css'))) {
$action->cssLink('css/mp-screen.css', null, 'screen');
} else {
@@ -256,6 +258,14 @@ class MobileProfilePlugin extends WAP20Plugin
}
+ function onStartShowUAStyles($action) {
+ if (!$this->serveMobile) {
+ return true;
+ }
+
+ return false;
+ }
+
function onStartShowHeader($action)
{
if (!$this->serveMobile) {
diff --git a/plugins/MobileProfile/mp-screen.css b/plugins/MobileProfile/mp-screen.css
index 04fa5fb00..0fc801612 100644
--- a/plugins/MobileProfile/mp-screen.css
+++ b/plugins/MobileProfile/mp-screen.css
@@ -1,15 +1,12 @@
/** theme: mobile profile screen
*
* @package StatusNet
- * @author Sarven Capadisli <csarven@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
-@import url(../../theme/base/css/display.css);
-@import url(../../theme/identica/css/display.css);
-
#wrap {
min-width:0;
max-width:100%;
diff --git a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php
index 36732ce46..bff657eb6 100755
--- a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php
+++ b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php
@@ -2,7 +2,7 @@
<?php
/**
* StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
+ * Copyright (C) 2008-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
@@ -262,7 +262,7 @@ class TwitterStatusFetcher extends ParallelizingDaemon
$notice->is_local = Notice::GATEWAY;
if (Event::handle('StartNoticeSave', array(&$notice))) {
- $id = $notice->insert();
+ $notice->insert();
Event::handle('EndNoticeSave', array($notice));
}
@@ -270,17 +270,41 @@ class TwitterStatusFetcher extends ParallelizingDaemon
Inbox::insertNotice($flink->user_id, $notice->id);
- $notice->blowCaches();
+ $notice->blowOnInsert();
return $notice;
}
+ /**
+ * Look up a Profile by profileurl field. Profile::staticGet() was
+ * not working consistently.
+ *
+ * @param string $url the profile url
+ *
+ * @return mixed the first profile with that url, or null
+ */
+
+ function getProfileByUrl($nickname, $profileurl)
+ {
+ $profile = new Profile();
+ $profile->nickname = $nickname;
+ $profile->profileurl = $profileurl;
+ $profile->limit(1);
+
+ if ($profile->find()) {
+ $profile->fetch();
+ return $profile;
+ }
+
+ return null;
+ }
+
function ensureProfile($user)
{
// check to see if there's already a profile for this user
$profileurl = 'http://twitter.com/' . $user->screen_name;
- $profile = Profile::staticGet('profileurl', $profileurl);
+ $profile = $this->getProfileByUrl($user->screen_name, $profileurl);
if (!empty($profile)) {
common_debug($this->name() .
@@ -292,6 +316,7 @@ class TwitterStatusFetcher extends ParallelizingDaemon
return $profile->id;
} else {
+
common_debug($this->name() . ' - Adding profile and remote profile ' .
"for Twitter user: $profileurl.");
@@ -306,7 +331,11 @@ class TwitterStatusFetcher extends ParallelizingDaemon
$profile->profileurl = $profileurl;
$profile->created = common_sql_now();
- $id = $profile->insert();
+ try {
+ $id = $profile->insert();
+ } catch(Exception $e) {
+ common_log(LOG_WARNING, $this->name . ' Couldn\'t insert profile - ' . $e->getMessage());
+ }
if (empty($id)) {
common_log_db_error($profile, 'INSERT', __FILE__);
@@ -326,7 +355,11 @@ class TwitterStatusFetcher extends ParallelizingDaemon
$remote_pro->uri = $profileurl;
$remote_pro->created = common_sql_now();
- $rid = $remote_pro->insert();
+ try {
+ $rid = $remote_pro->insert();
+ } catch (Exception $e) {
+ common_log(LOG_WARNING, $this->name() . ' Couldn\'t save remote profile - ' . $e->getMessage());
+ }
if (empty($rid)) {
common_log_db_error($profile, 'INSERT', __FILE__);
@@ -446,7 +479,7 @@ class TwitterStatusFetcher extends ParallelizingDaemon
if ($this->fetchAvatar($url, $filename)) {
$this->newAvatar($id, $size, $mediatype, $filename);
} else {
- common_log(LOG_WARNING, $this->id() .
+ common_log(LOG_WARNING, $id() .
" - Problem fetching Avatar: $url");
}
}
@@ -507,7 +540,11 @@ class TwitterStatusFetcher extends ParallelizingDaemon
$avatar->created = common_sql_now();
- $id = $avatar->insert();
+ try {
+ $id = $avatar->insert();
+ } catch (Exception $e) {
+ common_log(LOG_WARNING, $this->name() . ' Couldn\'t insert avatar - ' . $e->getMessage());
+ }
if (empty($id)) {
common_log_db_error($avatar, 'INSERT', __FILE__);
diff --git a/plugins/TwitterBridge/twitter.php b/plugins/TwitterBridge/twitter.php
index 33dfb788b..de30d9ebf 100644
--- a/plugins/TwitterBridge/twitter.php
+++ b/plugins/TwitterBridge/twitter.php
@@ -26,38 +26,6 @@ define('TWITTER_SERVICE', 1); // Twitter is foreign_service ID 1
require_once INSTALLDIR . '/plugins/TwitterBridge/twitterbasicauthclient.php';
require_once INSTALLDIR . '/plugins/TwitterBridge/twitteroauthclient.php';
-function updateTwitter_user($twitter_id, $screen_name)
-{
- $uri = 'http://twitter.com/' . $screen_name;
- $fuser = new Foreign_user();
-
- $fuser->query('BEGIN');
-
- // Dropping down to SQL because regular DB_DataObject udpate stuff doesn't seem
- // to work so good with tables that have multiple column primary keys
-
- // Any time we update the uri for a forein user we have to make sure there
- // are no dupe entries first -- unique constraint on the uri column
-
- $qry = 'UPDATE foreign_user set uri = \'\' WHERE uri = ';
- $qry .= '\'' . $uri . '\'' . ' AND service = ' . TWITTER_SERVICE;
-
- $fuser->query($qry);
-
- // Update the user
-
- $qry = 'UPDATE foreign_user SET nickname = ';
- $qry .= '\'' . $screen_name . '\'' . ', uri = \'' . $uri . '\' ';
- $qry .= 'WHERE id = ' . $twitter_id . ' AND service = ' . TWITTER_SERVICE;
-
- $fuser->query('COMMIT');
-
- $fuser->free();
- unset($fuser);
-
- return true;
-}
-
function add_twitter_user($twitter_id, $screen_name)
{
@@ -105,7 +73,6 @@ function add_twitter_user($twitter_id, $screen_name)
// Creates or Updates a Twitter user
function save_twitter_user($twitter_id, $screen_name)
{
-
// Check to see whether the Twitter user is already in the system,
// and update its screen name and uri if so.
@@ -115,25 +82,20 @@ function save_twitter_user($twitter_id, $screen_name)
$result = true;
- // Only update if Twitter screen name has changed
+ // Delete old record if Twitter user changed screen name
if ($fuser->nickname != $screen_name) {
- $result = updateTwitter_user($twitter_id, $screen_name);
-
- common_debug('Twitter bridge - Updated nickname (and URI) for Twitter user ' .
- "$fuser->id to $screen_name, was $fuser->nickname");
+ $oldname = $fuser->nickname;
+ $fuser->delete();
+ common_log(LOG_INFO, sprintf('Twitter bridge - Updated nickname (and URI) ' .
+ 'for Twitter user %1$d - %2$s, was %3$s.',
+ $fuser->id,
+ $screen_name,
+ $oldname));
}
- return $result;
-
- } else {
return add_twitter_user($twitter_id, $screen_name);
}
-
- $fuser->free();
- unset($fuser);
-
- return true;
}
function is_twitter_bound($notice, $flink) {
diff --git a/plugins/TwitterBridge/twitterauthorization.php b/plugins/TwitterBridge/twitterauthorization.php
index b2657ff61..dbef438a4 100644
--- a/plugins/TwitterBridge/twitterauthorization.php
+++ b/plugins/TwitterBridge/twitterauthorization.php
@@ -219,7 +219,7 @@ class TwitterauthorizationAction extends Action
$user = common_current_user();
$this->saveForeignLink($user->id, $twitter_user->id, $atok);
- save_twitter_user($twitter_user->id, $twitter_user->name);
+ save_twitter_user($twitter_user->id, $twitter_user->screen_name);
} else {
diff --git a/scripts/updateprofileurl.php b/scripts/updateprofileurl.php
new file mode 100644
index 000000000..2fc6828e6
--- /dev/null
+++ b/scripts/updateprofileurl.php
@@ -0,0 +1,99 @@
+#!/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:a';
+$longoptions = array('id=', 'nickname=', 'all');
+
+$helptext = <<<END_OF_UPDATEPROFILEURL_HELP
+updateprofileurl.php [options]
+update the URLs of all avatars in the system
+
+ -i --id ID of user to update
+ -n --nickname nickname of the user to update
+ -a --all update all
+
+END_OF_UPDATEPROFILEURL_HELP;
+
+require_once INSTALLDIR.'/scripts/commandline.inc';
+
+try {
+ $user = null;
+
+ if (have_option('i', 'id')) {
+ $id = get_option_value('i', 'id');
+ $user = User::staticGet('id', $id);
+ if (empty($user)) {
+ throw new Exception("Can't find user with id '$id'.");
+ }
+ updateProfileURL($user);
+ } else if (have_option('n', 'nickname')) {
+ $nickname = get_option_value('n', 'nickname');
+ $user = User::staticGet('nickname', $nickname);
+ if (empty($user)) {
+ throw new Exception("Can't find user with nickname '$nickname'");
+ }
+ updateProfileURL($user);
+ } else if (have_option('a', 'all')) {
+ $user = new User();
+ if ($user->find()) {
+ while ($user->fetch()) {
+ updateProfileURL($user);
+ }
+ }
+ } else {
+ show_help();
+ exit(1);
+ }
+} catch (Exception $e) {
+ print $e->getMessage()."\n";
+ exit(1);
+}
+
+function updateProfileURL($user)
+{
+ $profile = $user->getProfile();
+
+ if (empty($profile)) {
+ throw new Exception("Can't find profile for user $user->nickname ($user->id)");
+ }
+
+ $orig = clone($profile);
+
+ $profile->profileurl = common_profile_url($user->nickname);
+
+ if (!have_option('q', 'quiet')) {
+ print "Updating profile url for $user->nickname ($user->id) ".
+ "from $orig->profileurl to $profile->profileurl...";
+ }
+
+ $result = $profile->update($orig);
+
+ if (!$result) {
+ print "FAIL.\n";
+ common_log_db_error($profile, 'UPDATE', __FILE__);
+ throw new Exception("Can't update profile for user $user->nickname ($user->id)");
+ }
+
+ common_broadcast_profile($profile);
+
+ print "OK.\n";
+}
diff --git a/theme/base/images/icons/icons-01.gif b/theme/base/images/icons/icons-01.gif
index 01a729c10..6f284f023 100644
--- a/theme/base/images/icons/icons-01.gif
+++ b/theme/base/images/icons/icons-01.gif
Binary files differ
diff --git a/theme/base/images/icons/twotone/green/against.gif b/theme/base/images/icons/twotone/green/against.gif
new file mode 100644
index 000000000..ca796c8a3
--- /dev/null
+++ b/theme/base/images/icons/twotone/green/against.gif
Binary files differ
diff --git a/theme/base/images/icons/twotone/green/checkmark.gif b/theme/base/images/icons/twotone/green/checkmark.gif
new file mode 100644
index 000000000..892429d48
--- /dev/null
+++ b/theme/base/images/icons/twotone/green/checkmark.gif
Binary files differ
diff --git a/theme/default/css/display.css b/theme/default/css/display.css
index 6954de7ba..82eb13531 100644
--- a/theme/default/css/display.css
+++ b/theme/default/css/display.css
@@ -192,7 +192,8 @@ button.minimize,
.form_reset_key input.submit,
.entity_clear input.submit,
.entity_flag input.submit,
-.entity_flag p {
+.entity_flag p,
+.entity_subscribe input.submit {
background-image:url(../../base/images/icons/icons-01.gif);
background-repeat:no-repeat;
background-color:transparent;
@@ -348,6 +349,12 @@ background-position: 5px -2039px;
.entity_flag p {
background-position: 5px -2105px;
}
+.entity_subscribe input.accept {
+background-position: 5px -2171px;
+}
+.entity_subscribe input.reject {
+background-position: 5px -2237px;
+}
/* NOTICES */
.notice .attachment {
diff --git a/theme/identica/css/display.css b/theme/identica/css/display.css
index 9ac2730bd..44ae4953b 100644
--- a/theme/identica/css/display.css
+++ b/theme/identica/css/display.css
@@ -192,7 +192,8 @@ button.minimize,
.form_reset_key input.submit,
.entity_clear input.submit,
.entity_flag input.submit,
-.entity_flag p {
+.entity_flag p,
+.entity_subscribe input.submit {
background-image:url(../../base/images/icons/icons-01.gif);
background-repeat:no-repeat;
background-color:transparent;
@@ -347,6 +348,12 @@ background-position: 5px -2039px;
.entity_flag p {
background-position: 5px -2105px;
}
+.entity_subscribe input.accept {
+background-position: 5px -2171px;
+}
+.entity_subscribe input.reject {
+background-position: 5px -2237px;
+}
/* NOTICES */
.notice .attachment {