From 6046a6cc6ae72edfde90719d6e1f9dc39e0fa7ab Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Mon, 29 Mar 2010 16:27:50 -0700 Subject: [PATCH 1/9] Include meta charset header in saved HTML file for long OStatus messages; without, DOMDocument::loadHTML assumed Latin-1 instead of UTF-8. --- plugins/OStatus/classes/Ostatus_profile.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 34bff548db..8ba2ce0c31 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -1685,7 +1685,11 @@ class Ostatus_profile extends Memcached_DataObject */ function saveHTMLFile($title, $rendered) { - $final = sprintf("\n%s". + $final = sprintf("\n" . + '' . + '' . + '%s' . + '' . '%s', htmlspecialchars($title), $rendered); From d38ce90fa12fcda80fb24d6366406d7b03f6a71b Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Mon, 29 Mar 2010 17:53:31 -0700 Subject: [PATCH 2/9] Fix to profile location in FOAF output: longitude was repeating the latitude by mistake --- actions/foaf.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/actions/foaf.php b/actions/foaf.php index fc56e19b4f..9cb65a8856 100644 --- a/actions/foaf.php +++ b/actions/foaf.php @@ -126,7 +126,7 @@ class FoafAction extends Action $this->element('geo:lat', null, $location->lat); } if ($location->lon) { - $this->element('geo:long', null, $location->lat); + $this->element('geo:long', null, $location->lon); } if ($location->getURL()) { $this->element('page', array('rdf:resource'=>$location->getURL())); From 0284e1315cc95d94e1e348a0af3ac88f1abcd5ff Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 30 Mar 2010 11:07:01 -0700 Subject: [PATCH 3/9] Quick fixes for grouplistall: * respect count instead of listing all groups * respect page parameter * don't spew notice on undefined $id * don't spew notice on undefined $group->homepage_url (dropped the element since there's nothing to go in it) --- actions/apigrouplistall.php | 11 +++++++++-- lib/apiaction.php | 1 - 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/actions/apigrouplistall.php b/actions/apigrouplistall.php index e1b54a8322..f7677970f8 100644 --- a/actions/apigrouplistall.php +++ b/actions/apigrouplistall.php @@ -66,7 +66,7 @@ class ApiGroupListAllAction extends ApiPrivateAuthAction { parent::prepare($args); - $this->user = $this->getTargetUser($id); + $this->user = $this->getTargetUser(null); $this->groups = $this->getGroups(); return true; @@ -137,11 +137,18 @@ class ApiGroupListAllAction extends ApiPrivateAuthAction $qry = 'SELECT user_group.* '. 'from user_group join local_group on user_group.id = local_group.group_id '. 'order by created desc '; - + $offset = intval($this->page - 1) * intval($this->count); + $limit = intval($this->count); + if (common_config('db', 'type') == 'pgsql') { + $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; + } else { + $qry .= ' LIMIT ' . $offset . ', ' . $limit; + } $group = new User_group(); $group->query($qry); + $groups = array(); while ($group->fetch()) { $groups[] = clone($group); } diff --git a/lib/apiaction.php b/lib/apiaction.php index 9fc1a07799..59dc47c23b 100644 --- a/lib/apiaction.php +++ b/lib/apiaction.php @@ -318,7 +318,6 @@ class ApiAction extends Action $twitter_group['url']=$group->permalink(); $twitter_group['nickname']=$group->nickname; $twitter_group['fullname']=$group->fullname; - $twitter_group['homepage_url']=$group->homepage_url; $twitter_group['original_logo']=$group->original_logo; $twitter_group['homepage_logo']=$group->homepage_logo; $twitter_group['stream_logo']=$group->stream_logo; From 034e88bcbceafd47753d4368ce74df85c432abb6 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 30 Mar 2010 11:44:13 -0700 Subject: [PATCH 4/9] Fixes for apigrouplist - notice spew from undefined var, notice spew from missing escape in sprintf format --- actions/apigrouplist.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/actions/apigrouplist.php b/actions/apigrouplist.php index 98fdb0497a..a6f5d03ccf 100644 --- a/actions/apigrouplist.php +++ b/actions/apigrouplist.php @@ -66,7 +66,7 @@ class ApiGroupListAction extends ApiBareAuthAction { parent::prepare($args); - $this->user = $this->getTargetUser($id); + $this->user = $this->getTargetUser(null); $this->groups = $this->getGroups(); return true; @@ -100,7 +100,7 @@ class ApiGroupListAction extends ApiBareAuthAction array('nickname' => $this->user->nickname) ); $subtitle = sprintf( - _("Groups %1$s is a member of on %2$s."), + _("Groups %1\$s is a member of on %2\$s."), $this->user->nickname, $sitename ); From f694f254a452cf44a7bce0d22f2559e0e3f5fd66 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 30 Mar 2010 11:47:23 -0700 Subject: [PATCH 5/9] Fix for error output on invalid user ID to api groups list --- actions/apigrouplist.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/actions/apigrouplist.php b/actions/apigrouplist.php index a6f5d03ccf..dd2a68c66e 100644 --- a/actions/apigrouplist.php +++ b/actions/apigrouplist.php @@ -67,6 +67,12 @@ class ApiGroupListAction extends ApiBareAuthAction parent::prepare($args); $this->user = $this->getTargetUser(null); + + if (empty($this->user)) { + $this->clientError(_('No such user.'), 404, $this->format); + return false; + } + $this->groups = $this->getGroups(); return true; @@ -86,11 +92,6 @@ class ApiGroupListAction extends ApiBareAuthAction { parent::handle($args); - if (empty($this->user)) { - $this->clientError(_('No such user.'), 404, $this->format); - return; - } - $sitename = common_config('site', 'name'); $title = sprintf(_("%s's groups"), $this->user->nickname); $taguribase = TagURI::base(); From 804182e0fea025b80282b45a1c3205e39a63e3d6 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Sat, 27 Mar 2010 23:36:04 +0000 Subject: [PATCH 6/9] Some fixes to make the twitterstatusfetcher behave better in a multi-site configuration --- .../daemons/twitterstatusfetcher.php | 141 ++++++++++++------ 1 file changed, 94 insertions(+), 47 deletions(-) diff --git a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php index bff657eb68..7c624fdb3b 100755 --- a/plugins/TwitterBridge/daemons/twitterstatusfetcher.php +++ b/plugins/TwitterBridge/daemons/twitterstatusfetcher.php @@ -44,10 +44,17 @@ require_once INSTALLDIR . '/plugins/TwitterBridge/twitterbasicauthclient.php'; require_once INSTALLDIR . '/plugins/TwitterBridge/twitteroauthclient.php'; /** - * Fetcher for statuses from Twitter + * Fetch statuses from Twitter * - * Fetches statuses from Twitter and inserts them as notices in local - * system. + * Fetches statuses from Twitter and inserts them as notices + * + * NOTE: an Avatar path MUST be set in config.php for this + * script to work, e.g.: + * $config['avatar']['path'] = $config['site']['path'] . '/avatar/'; + * + * @todo @fixme @gar Fix the above. For some reason $_path is always empty when + * this script is run, so the default avatar path is always set wrong in + * default.php. Therefore it must be set explicitly in config.php. --Z * * @category Twitter * @package StatusNet @@ -57,9 +64,6 @@ require_once INSTALLDIR . '/plugins/TwitterBridge/twitteroauthclient.php'; * @link http://status.net/ */ -// NOTE: an Avatar path MUST be set in config.php for this -// script to work: e.g.: $config['avatar']['path'] = '/statusnet/avatar'; - class TwitterStatusFetcher extends ParallelizingDaemon { /** @@ -195,6 +199,8 @@ class TwitterStatusFetcher extends ParallelizingDaemon return; } + common_debug(LOG_INFO, $this->name() . ' - Retrieved ' . sizeof($timeline) . ' statuses from Twitter.'); + // Reverse to preserve order foreach (array_reverse($timeline) as $status) { @@ -209,13 +215,7 @@ class TwitterStatusFetcher extends ParallelizingDaemon continue; } - $notice = null; - - $notice = $this->saveStatus($status, $flink); - - if (!empty($notice)) { - common_broadcast_notice($notice); - } + $this->saveStatus($status, $flink); } // Okay, record the time we synced with Twitter for posterity @@ -226,50 +226,77 @@ class TwitterStatusFetcher extends ParallelizingDaemon function saveStatus($status, $flink) { - $id = $this->ensureProfile($status->user); - - $profile = Profile::staticGet($id); + $profile = $this->ensureProfile($status->user); if (empty($profile)) { common_log(LOG_ERR, $this->name() . ' - Problem saving notice. No associated Profile.'); - return null; + return; } - // XXX: change of screen name? - - $uri = 'http://twitter.com/' . $status->user->screen_name . - '/status/' . $status->id; + $statusUri = 'http://twitter.com/' + . $status->user->screen_name + . '/status/' + . $status->id; // check to see if we've already imported the status - $notice = Notice::staticGet('uri', $uri); + $dupe = $this->checkDupe($profile, $statusUri); - if (empty($notice)) { + if (!empty($dupe)) { + common_log( + LOG_INFO, + $this->name() . + " - Ignoring duplicate import: $statusUri" + ); + return; + } - // XXX: transaction here? + $notice = new Notice(); - $notice = new Notice(); + $notice->profile_id = $profile->id; + $notice->uri = $statusUri; + $notice->url = $statusUri; + $notice->created = strftime( + '%Y-%m-%d %H:%M:%S', + strtotime($status->created_at) + ); - $notice->profile_id = $id; - $notice->uri = $uri; - $notice->created = strftime('%Y-%m-%d %H:%M:%S', - strtotime($status->created_at)); - $notice->content = common_shorten_links($status->text); // XXX - $notice->rendered = common_render_content($notice->content, $notice); - $notice->source = 'twitter'; - $notice->reply_to = null; // XXX: lookup reply - $notice->is_local = Notice::GATEWAY; + $notice->source = 'twitter'; + $notice->reply_to = null; + $notice->is_local = Notice::GATEWAY; - if (Event::handle('StartNoticeSave', array(&$notice))) { - $notice->insert(); - Event::handle('EndNoticeSave', array($notice)); + $notice->content = common_shorten_links($status->text); + $notice->rendered = common_render_content( + $notice->content, + $notice + ); + + if (Event::handle('StartNoticeSave', array(&$notice))) { + + $id = $notice->insert(); + + if (!$id) { + common_log_db_error($notice, 'INSERT', __FILE__); + common_log(LOG_ERR, $this->name() . + ' - Problem saving notice.'); } + Event::handle('EndNoticeSave', array($notice)); + } + + $orig = clone($notice); + $conv = Conversation::create(); + + $notice->conversation = $conv->id; + + if (!$notice->update($orig)) { + common_log_db_error($notice, 'UPDATE', __FILE__); + common_log(LOG_ERR, $this->name() . + ' - Problem saving notice.'); } Inbox::insertNotice($flink->user_id, $notice->id); - $notice->blowOnInsert(); return $notice; @@ -279,9 +306,10 @@ class TwitterStatusFetcher extends ParallelizingDaemon * Look up a Profile by profileurl field. Profile::staticGet() was * not working consistently. * - * @param string $url the profile url + * @param string $nickname local nickname of the Twitter user + * @param string $profileurl the profile url * - * @return mixed the first profile with that url, or null + * @return mixed value the first Profile with that url, or null */ function getProfileByUrl($nickname, $profileurl) @@ -299,6 +327,30 @@ class TwitterStatusFetcher extends ParallelizingDaemon return null; } + /** + * Check to see if this Twitter status has already been imported + * + * @param Profile $profile Twitter user's local profile + * @param string $statusUri URI of the status on Twitter + * + * @return mixed value a matching Notice or null + */ + + function checkDupe($profile, $statusUri) + { + $notice = new Notice(); + $notice->uri = $statusUri; + $notice->profile_id = $profile->id; + $notice->limit(1); + + if ($notice->find()) { + $notice->fetch(); + return $notice; + } + + return null; + } + function ensureProfile($user) { // check to see if there's already a profile for this user @@ -313,7 +365,7 @@ class TwitterStatusFetcher extends ParallelizingDaemon // Check to see if the user's Avatar has changed $this->checkAvatar($user, $profile); - return $profile->id; + return $profile; } else { @@ -372,7 +424,7 @@ class TwitterStatusFetcher extends ParallelizingDaemon $this->saveAvatars($user, $id); - return $id; + return $profile; } } @@ -403,7 +455,6 @@ class TwitterStatusFetcher extends ParallelizingDaemon $this->updateAvatars($twitter_user, $profile); } - } function updateAvatars($twitter_user, $profile) { @@ -428,17 +479,13 @@ class TwitterStatusFetcher extends ParallelizingDaemon } function missingAvatarFile($profile) { - foreach (array(24, 48, 73) as $size) { - $filename = $profile->getAvatar($size)->filename; $avatarpath = Avatar::path($filename); - if (file_exists($avatarpath) == FALSE) { return true; } } - return false; } From f19b95d9b7daa82e73ca2ebf23ca55712de73107 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Tue, 30 Mar 2010 12:19:25 -0700 Subject: [PATCH 7/9] Shared cache key option for Geonames plugin, lets multi-instance sites share their cached geoname lookups. Example: unset($config['plugins']['default']['Geonames']); addPlugin('Geonames', array('cachePrefix' => 'statusnet:shared')); --- plugins/GeonamesPlugin.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/plugins/GeonamesPlugin.php b/plugins/GeonamesPlugin.php index 589462ed99..f018e26943 100644 --- a/plugins/GeonamesPlugin.php +++ b/plugins/GeonamesPlugin.php @@ -55,6 +55,8 @@ class GeonamesPlugin extends Plugin public $username = null; public $token = null; public $expiry = 7776000; // 90-day expiry + public $cachePrefix = null; // Optional shared memcache prefix override + // to share lookups between local instances. /** * convert a name into a Location object @@ -408,9 +410,14 @@ class GeonamesPlugin extends Plugin function cacheKey($attrs) { - return common_cache_key('geonames:'. - implode(',', array_keys($attrs)) . ':'. - common_keyize(implode(',', array_values($attrs)))); + $key = 'geonames:' . + implode(',', array_keys($attrs)) . ':'. + common_keyize(implode(',', array_values($attrs))); + if ($this->cachePrefix) { + return $this->cachePrefix . ':' . $key; + } else { + return common_cache_key($key); + } } function wsUrl($method, $params) From c1c7feedbd11cc291a0fb68ea8c4d322eb8bf538 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 31 Mar 2010 15:02:19 -0400 Subject: [PATCH 8/9] do complete unsubscribe process when deleting a user --- classes/Profile.php | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/classes/Profile.php b/classes/Profile.php index eded1ff71f..5de35c191a 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -577,11 +577,41 @@ class Profile extends Memcached_DataObject { $sub = new Subscription(); $sub->subscriber = $this->id; - $sub->delete(); + + $sub->find(); + + while ($sub->fetch()) { + $other = Profile::staticGet('id', $sub->subscribed); + if (empty($other)) { + continue; + } + if ($other->id == $this->id) { + continue; + } + Subscription::cancel($this, $other); + } $subd = new Subscription(); $subd->subscribed = $this->id; - $subd->delete(); + $subd->find(); + + while ($subd->fetch()) { + $other = Profile::staticGet('id', $subd->subscriber); + if (empty($other)) { + continue; + } + if ($other->id == $this->id) { + continue; + } + Subscription::cancel($other, $this); + } + + $self = new Subscription(); + + $self->subscriber = $this->id; + $self->subscribed = $this->id; + + $self->delete(); } function _deleteMessages() From d3f995846b2a849bc53eb965eb2607d8d1d6dd34 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 31 Mar 2010 15:20:16 -0400 Subject: [PATCH 9/9] use Subscription::cancel() to cancel all subscriptions on block --- classes/User.php | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/classes/User.php b/classes/User.php index 659ec9467b..2c256301c2 100644 --- a/classes/User.php +++ b/classes/User.php @@ -525,8 +525,8 @@ class User extends Memcached_DataObject common_log(LOG_WARNING, sprintf( "Profile ID %d (%s) tried to block his or herself.", - $profile->id, - $profile->nickname + $this->id, + $this->nickname ) ); return false; @@ -548,13 +548,7 @@ class User extends Memcached_DataObject return false; } - // Cancel their subscription, if it exists - - $otherUser = User::staticGet('id', $other->id); - - if (!empty($otherUser)) { - subs_unsubscribe_to($otherUser, $this->getProfile()); - } + Subscription::cancel($other, $this->getProfile()); $block->query('COMMIT');