From a1a3ab1c58cf8636c4e9ac6b9d44bdc18946a547 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Fri, 19 Feb 2010 12:08:07 -0800 Subject: [PATCH] OStatus: hooked up follow/unfollow events on Salmon endpoint to create/destroy remote subscriber relationships --- plugins/OStatus/OStatusPlugin.php | 9 ++- plugins/OStatus/actions/feedsubsettings.php | 8 --- plugins/OStatus/actions/salmon.php | 66 ++++++++++++++++++--- plugins/OStatus/classes/Ostatus_profile.php | 22 +++++-- 4 files changed, 81 insertions(+), 24 deletions(-) diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 4ebe4551ec..4c43d8a303 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -253,17 +253,22 @@ class OStatusPlugin extends Plugin */ function onEndUnsubscribe($user, $other) { + if ($user instanceof Profile) { + $profile = $user; + } else if ($user instanceof Profile) { + $profile = $user->getProfile(); + } $oprofile = Ostatus_profile::staticGet('profile_id', $other->id); if ($oprofile) { // Notify the remote server of the unsub, if supported. - $oprofile->notify($user->getProfile(), ActivityVerb::UNFOLLOW, $oprofile); + $oprofile->notify($profile, ActivityVerb::UNFOLLOW, $oprofile); // Drop the PuSH subscription if there are no other subscribers. $sub = new Subscription(); $sub->subscribed = $other->id; $sub->limit(1); if (!$sub->find(true)) { - common_log(LOG_INFO, "Unsubscribing from now-unused feed $oprofile->feeduri on hub $oprofile->huburi"); + common_log(LOG_INFO, "Unsubscribing from now-unused feed $oprofile->feeduri"); $oprofile->unsubscribe(); } } diff --git a/plugins/OStatus/actions/feedsubsettings.php b/plugins/OStatus/actions/feedsubsettings.php index 3e1d0aa823..aee4cee9af 100644 --- a/plugins/OStatus/actions/feedsubsettings.php +++ b/plugins/OStatus/actions/feedsubsettings.php @@ -68,14 +68,6 @@ class FeedSubSettingsAction extends ConnectSettingsAction $profile = $user->getProfile(); - $fuser = null; - - $flink = Foreign_link::getByUserID($user->id, FEEDSUB_SERVICE); - - if (!empty($flink)) { - $fuser = $flink->getForeignUser(); - } - $this->elementStart('form', array('method' => 'post', 'id' => 'form_settings_feedsub', 'class' => 'form_settings', diff --git a/plugins/OStatus/actions/salmon.php b/plugins/OStatus/actions/salmon.php index 2da9db9eb7..1ed322ed28 100644 --- a/plugins/OStatus/actions/salmon.php +++ b/plugins/OStatus/actions/salmon.php @@ -63,13 +63,17 @@ class SalmonAction extends Action // XXX: check that document element is Atom entry // XXX: check the signature - $this->act = new Activity($dom->documentElement); + $entries = $dom->getElementsByTagNameNS(Activity::ATOM, 'entry'); + if ($entries && $entries->length) { + // @fixme is it legit to have multiple entries? + $this->act = new Activity($entries->item(0), $dom->documentElement); + } return true; } /** - * @fixme probably call Ostatus_profile::processFeed + * Check the posted activity type and break out to appropriate processing. */ function handle($args) @@ -94,13 +98,19 @@ class SalmonAction extends Action case ActivityVerb::FRIEND: $this->handleFollow(); break; + case ActivityVerb::UNFOLLOW: + $this->handleUnfollow(); + break; } Event::handle('EndHandleSalmon', array($this->user, $this->activity)); } } /** - * @fixme probably call Ostatus_profile::processFeed + * We've gotten a post event on the Salmon backchannel, probably a reply. + * + * @todo validate if we need to handle this post, then call into + * ostatus_profile's general incoming-post handling. */ function handlePost() { @@ -116,43 +126,81 @@ class SalmonAction extends Action } $profile = $this->ensureProfile(); + // @fixme do something with the post } /** - * @fixme probably call Ostatus_profile::processFeed + * We've gotten a follow/subscribe notification from a remote user. + * Save a subscription relationship for them. */ function handleFollow() { + $oprofile = $this->ensureProfile(); + if ($oprofile) { + common_log(LOG_INFO, "Setting up subscription from remote {$oprofile->uri} to local {$this->user->nickname}"); + $oprofile->subscribeRemoteToLocal($this->user); + } else { + common_log(LOG_INFO, "Can't set up subscription from remote; missing profile."); + } } /** - * @fixme probably call Ostatus_profile::processFeed + * We've gotten an unfollow/unsubscribe notification from a remote user. + * Check if we have a subscription relationship for them and kill it. + * + * @fixme probably catch exceptions on fail? + */ + function handleUnfollow() + { + $oprofile = $this->ensureProfile(); + if ($oprofile) { + common_log(LOG_INFO, "Canceling subscription from remote {$oprofile->uri} to local {$this->user->nickname}"); + Subscription::cancel($oprofile->localProfile(), $this->user->getProfile()); + } else { + common_log(LOG_ERR, "Can't cancel subscription from remote, didn't find the profile"); + } + } + + /** + * Remote user likes one of our posts. + * Confirm the post is ours, and save a local favorite event. */ function handleFavorite() { } /** - * @fixme probably call Ostatus_profile::processFeed + * Remote user doesn't like one of our posts after all! + * Confirm the post is ours, and save a local favorite event. + */ + function handleUnfavorite() + { + } + + /** + * Hmmmm */ function handleShare() { } + /** + * @return Ostatus_profile + */ function ensureProfile() { $actor = $this->act->actor; common_log(LOG_DEBUG, "Received salmon bit: " . var_export($this->act, true)); if (empty($actor->id)) { + common_log(LOG_ERR, "broken actor: " . var_export($actor, true)); throw new Exception("Received a salmon slap from unidentified actor."); } - $ostatusProfile = Ostatus_profile::ensureActorProfile($this->act); - return $oprofile->localProfile(); + return Ostatus_profile::ensureActorProfile($this->act); } /** - * @fixme anything new in here probably should be merged into Ostatus_profile::ensureActorProfile and friends + * @fixme merge into Ostatus_profile::ensureActorProfile and friends */ function createProfile() { diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 319b76a661..97d8eec101 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -310,8 +310,15 @@ class Ostatus_profile extends Memcached_DataObject * @param $verb eg Activity::SUBSCRIBE or Activity::JOIN * @param $object object of the action; if null, the remote entity itself is assumed */ - public function notify(Profile $actor, $verb, $object=null) + public function notify($actor, $verb, $object=null) { + if (!($actor instanceof Profile)) { + $type = gettype($actor); + if ($type == 'object') { + $type = get_class($actor); + } + throw new ServerException("Invalid actor passed to " . __METHOD__ . ": " . $type); + } if ($object == null) { $object = $this; } @@ -340,7 +347,7 @@ class Ostatus_profile extends Memcached_DataObject $feed->addEntry($entry); $xml = $feed->getString(); - common_log(LOG_INFO, "Posting to Salmon endpoint $salmon: $xml"); + common_log(LOG_INFO, "Posting to Salmon endpoint $this->salmonuri: $xml"); $salmon = new Salmon(); // ? $salmon->post($this->salmonuri, $xml); @@ -531,9 +538,14 @@ class Ostatus_profile extends Memcached_DataObject $temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar'); copy($url, $temp_filename); + if ($this->isGroup()) { + $id = $this->group_id; + } else { + $id = $this->profile_id; + } // @fixme should we be using different ids? - $imagefile = new ImageFile($this->id, $temp_filename); - $filename = Avatar::filename($this->id, + $imagefile = new ImageFile($id, $temp_filename); + $filename = Avatar::filename($id, image_type_to_extension($imagefile->type), null, common_timestamp()); @@ -646,7 +658,7 @@ class Ostatus_profile extends Memcached_DataObject $actor = $activity->actor; $homeuri = self::getActorProfileURI($activity); $nickname = self::getAuthorNick($activity); - $avatar = self::getAvatar($actor, $feed); + $avatar = self::getAvatar($actor, $activity->feed); if (!$homeuri) { common_log(LOG_DEBUG, __METHOD__ . " empty actor profile URI: " . var_export($activity, true));