From: Evan Prodromou Date: Sat, 20 Feb 2010 16:12:43 +0000 (-0500) Subject: Move some salmon processing to a superclass X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=2df3bbc80b6c9dd44134bcf3b5b4a09ea1a803d1;p=quix0rs-gnu-social.git Move some salmon processing to a superclass Moved some salmon processing to a superclass so we could handle group salmon posts, too. --- diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 1b58d3c356..e1f3fd9d37 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -63,10 +63,10 @@ class OStatusPlugin extends Plugin // Salmon endpoint $m->connect('main/salmon/user/:id', - array('action' => 'salmon'), + array('action' => 'usersalmon'), array('id' => '[0-9]+')); $m->connect('main/salmon/group/:id', - array('action' => 'salmongroup'), + array('action' => 'groupsalmon'), array('id' => '[0-9]+')); return true; } diff --git a/plugins/OStatus/actions/groupsalmon.php b/plugins/OStatus/actions/groupsalmon.php new file mode 100644 index 0000000000..64ae9f3cc0 --- /dev/null +++ b/plugins/OStatus/actions/groupsalmon.php @@ -0,0 +1,108 @@ +. + */ + +/** + * @package OStatusPlugin + * @author James Walker + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +class GroupsalmonAction extends SalmonAction +{ + var $group = null; + + function prepare($args) + { + parent::prepare($args); + + $id = $this->trimmed('id'); + + if (!$id) { + $this->clientError(_('No ID.')); + } + + $this->group = User_group::staticGet('id', $id); + + if (empty($this->group)) { + $this->clientError(_('No such group.')); + } + + return true; + } + + /** + * We've gotten a post event on the Salmon backchannel, probably a reply. + */ + + function handlePost() + { + switch ($this->act->object->type) { + case ActivityObject::ARTICLE: + case ActivityObject::BLOGENTRY: + case ActivityObject::NOTE: + case ActivityObject::STATUS: + case ActivityObject::COMMENT: + break; + default: + throw new ClientException("Can't handle that kind of post."); + } + + // Notice must be to the attention of this group + + $context = $this->act->context; + + if (empty($context->attention)) { + throw new ClientException("Not to the attention of anyone."); + } else { + $uri = common_local_url('groupbyid', array('id' => $this->group->id)); + if (!in_array($context->attention, $uri)) { + throw new ClientException("Not to the attention of this group."); + } + } + + $profile = $this->ensureProfile(); + // @fixme save the post + } + + /** + * We've gotten a follow/subscribe notification from a remote user. + * Save a subscription relationship for them. + */ + + function handleFollow() + { + $this->handleJoin(); // ??? + } + + function handleUnfollow() + { + } + + /** + * A remote user joined our group. + */ + + function handleJoin() + { + } + +} diff --git a/plugins/OStatus/actions/salmon.php b/plugins/OStatus/actions/salmon.php deleted file mode 100644 index f7c86dc0ce..0000000000 --- a/plugins/OStatus/actions/salmon.php +++ /dev/null @@ -1,341 +0,0 @@ -. - */ - -/** - * @package OStatusPlugin - * @author James Walker - */ - -if (!defined('STATUSNET')) { - exit(1); -} - -class SalmonAction extends Action -{ - var $user = null; - var $xml = null; - var $activity = null; - - function prepare($args) - { - StatusNet::setApi(true); // Send smaller error pages - - parent::prepare($args); - - if ($_SERVER['REQUEST_METHOD'] != 'POST') { - $this->clientError(_('This method requires a POST.')); - } - - if ($_SERVER['CONTENT_TYPE'] != 'application/atom+xml') { - $this->clientError(_('Salmon requires application/atom+xml')); - } - - $id = $this->trimmed('id'); - - if (!$id) { - $this->clientError(_('No ID.')); - } - - $this->user = User::staticGet($id); - - if (empty($this->user)) { - $this->clientError(_('No such user.')); - } - - $xml = file_get_contents('php://input'); - - $dom = DOMDocument::loadXML($xml); - - if ($dom->documentElement->namespaceURI != Activity::ATOM || - $dom->documentElement->localName != 'entry') { - $this->clientError(_m('Salmon post must be an Atom entry.')); - } - // XXX: check the signature - - $this->act = new Activity($dom->documentElement); - return true; - } - - /** - * Check the posted activity type and break out to appropriate processing. - */ - - function handle($args) - { - StatusNet::setApi(true); // Send smaller error pages - common_log(LOG_INFO, 'Salmon: incoming post for user '. $this->user->id); - common_log(LOG_DEBUG, "Received salmon bit: " . var_export($this->act, true)); - - // TODO : Insert new $xml -> notice code - - if (Event::handle('StartHandleSalmon', array($this->user, $this->activity))) { - switch ($this->act->verb) - { - case ActivityVerb::POST: - $this->handlePost(); - break; - case ActivityVerb::SHARE: - $this->handleShare(); - break; - case ActivityVerb::FAVORITE: - $this->handleFavorite(); - break; - case ActivityVerb::FOLLOW: - case ActivityVerb::FRIEND: - $this->handleFollow(); - break; - case ActivityVerb::UNFOLLOW: - $this->handleUnfollow(); - break; - } - Event::handle('EndHandleSalmon', array($this->user, $this->activity)); - } - } - - /** - * 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() - { - switch ($this->act->object->type) { - case ActivityObject::ARTICLE: - case ActivityObject::BLOGENTRY: - case ActivityObject::NOTE: - case ActivityObject::STATUS: - case ActivityObject::COMMENT: - break; - default: - throw new ClientException("Can't handle that kind of post."); - } - - // Notice must either be a) in reply to a notice by this user - // or b) to the attention of this user - - $context = $this->act->context; - - if (!empty($context->replyToID)) { - $notice = Notice::staticGet('uri', $context->replyToID); - if (empty($notice)) { - throw new ClientException("In reply to unknown notice"); - } - if ($notice->profile_id != $this->user->id) { - throw new ClientException("In reply to a notice not by this user"); - } - } else if (!empty($context->attention)) { - if (!in_array($context->attention, $this->user->uri)) { - throw new ClientException("To the attention of user(s) not including this one!"); - } - } else { - throw new ClientException("Not to anyone in reply to anything!"); - } - - $profile = $this->ensureProfile(); - // @fixme do something with the post - } - - /** - * 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."); - } - } - - /** - * 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() - { - // WORST VARIABLE NAME EVER - $object = $this->act->object; - - switch ($this->act->object->type) { - case ActivityObject::ARTICLE: - case ActivityObject::BLOGENTRY: - case ActivityObject::NOTE: - case ActivityObject::STATUS: - case ActivityObject::COMMENT: - break; - default: - throw new ClientException("Can't handle that kind of object for liking/faving."); - } - - $notice = Notice::staticGet('uri', $object->id); - - if (empty($notice)) { - throw new ClientException("Notice with ID $object->id unknown."); - } - - if ($notice->profile_id != $this->user->id) { - throw new ClientException("Notice with ID $object->id not posted by $this->user->id."); - } - - $profile = $this->ensureProfile(); - - $old = Fave::pkeyGet(array('user_id' => $profile->id, - 'notice_id' => $notice->id)); - - if (!empty($old)) { - throw new ClientException("We already know that's a fave!"); - } - - $fave = new Fave(); - - // @fixme need to change this attribute name, maybe references - $fave->user_id = $profile->id; - $fave->notice_id = $notice->id; - - $result = $fave->insert(); - - if (!$result) { - common_log_db_error($fave, 'INSERT', __FILE__); - throw new ServerException('Could not save new favorite.'); - } - } - - /** - * 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; - if (empty($actor->id)) { - common_log(LOG_ERR, "broken actor: " . var_export($actor, true)); - throw new Exception("Received a salmon slap from unidentified actor."); - } - - return Ostatus_profile::ensureActorProfile($this->act); - } - - /** - * @fixme merge into Ostatus_profile::ensureActorProfile and friends - */ - function createProfile() - { - $actor = $this->act->actor; - - $profile = new Profile(); - - $profile->nickname = $this->nicknameFromURI($actor->id); - - if (empty($profile->nickname)) { - $profile->nickname = common_nicknamize($actor->title); - } - - $profile->fullname = $actor->title; - $profile->bio = $actor->summary; // XXX: is that right? - $profile->profileurl = $actor->link; // XXX: is that right? - $profile->created = common_sql_now(); - - $id = $profile->insert(); - - if (empty($id)) { - common_log_db_error($profile, 'INSERT', __FILE__); - throw new Exception("Couldn't save new profile for $actor->id\n"); - } - - // XXX: add avatars - - $op = new Ostatus_profile(); - - $op->profile_id = $id; - $op->homeuri = $actor->id; - $op->created = $profile->created; - - // XXX: determine feed URI from source or Webfinger or whatever - - $id = $op->insert(); - - if (empty($id)) { - common_log_db_error($op, 'INSERT', __FILE__); - throw new Exception("Couldn't save new ostatus profile for $actor->id\n"); - } - - return $profile; - } - - /** - * @fixme should be merged into Ostatus_profile - */ - function nicknameFromURI($uri) - { - preg_match('/(\w+):/', $uri, $matches); - - $protocol = $matches[1]; - - switch ($protocol) { - case 'acct': - case 'mailto': - if (preg_match("/^$protocol:(.*)?@.*\$/", $uri, $matches)) { - return common_canonical_nickname($matches[1]); - } - return null; - case 'http': - return common_url_to_nickname($uri); - break; - default: - return null; - } - } -} diff --git a/plugins/OStatus/actions/usersalmon.php b/plugins/OStatus/actions/usersalmon.php new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugins/OStatus/lib/salmonaction.php b/plugins/OStatus/lib/salmonaction.php new file mode 100644 index 0000000000..7085e4583e --- /dev/null +++ b/plugins/OStatus/lib/salmonaction.php @@ -0,0 +1,231 @@ +. + */ + +/** + * @package OStatusPlugin + * @author James Walker + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +class SalmonAction extends Action +{ + var $xml = null; + var $activity = null; + + function prepare($args) + { + StatusNet::setApi(true); // Send smaller error pages + + parent::prepare($args); + + if ($_SERVER['REQUEST_METHOD'] != 'POST') { + $this->clientError(_('This method requires a POST.')); + } + + if ($_SERVER['CONTENT_TYPE'] != 'application/atom+xml') { + $this->clientError(_('Salmon requires application/atom+xml')); + } + + $xml = file_get_contents('php://input'); + + $dom = DOMDocument::loadXML($xml); + + if ($dom->documentElement->namespaceURI != Activity::ATOM || + $dom->documentElement->localName != 'entry') { + $this->clientError(_m('Salmon post must be an Atom entry.')); + } + // XXX: check the signature + + $this->act = new Activity($dom->documentElement); + return true; + } + + /** + * Check the posted activity type and break out to appropriate processing. + */ + + function handle($args) + { + StatusNet::setApi(true); // Send smaller error pages + + // TODO : Insert new $xml -> notice code + + if (Event::handle('StartHandleSalmon', array($this->activity))) { + switch ($this->act->verb) + { + case ActivityVerb::POST: + $this->handlePost(); + break; + case ActivityVerb::SHARE: + $this->handleShare(); + break; + case ActivityVerb::FAVORITE: + $this->handleFavorite(); + break; + case ActivityVerb::FOLLOW: + case ActivityVerb::FRIEND: + $this->handleFollow(); + break; + case ActivityVerb::UNFOLLOW: + $this->handleUnfollow(); + break; + case ActivityVerb::JOIN: + $this->handleJoin(); + break; + default: + throw new ClientException(_("Unimplemented.")); + } + Event::handle('EndHandleSalmon', array($this->activity)); + } + } + + function handlePost() + { + throw new ClientException(_("Unimplemented!")); + } + + function handleFollow() + { + throw new ClientException(_("Unimplemented!")); + } + + function handleUnfollow() + { + throw new ClientException(_("Unimplemented!")); + } + + function handleFavorite() + { + throw new ClientException(_("Unimplemented!")); + } + + /** + * Remote user doesn't like one of our posts after all! + * Confirm the post is ours, and delete a local favorite event. + */ + + function handleUnfavorite() + { + throw new ClientException(_("Unimplemented!")); + } + + /** + * Hmmmm + */ + function handleShare() + { + throw new ClientException(_("Unimplemented!")); + } + + /** + * Hmmmm + */ + function handleJoin() + { + throw new ClientException(_("Unimplemented!")); + } + + /** + * @return Ostatus_profile + */ + function ensureProfile() + { + $actor = $this->act->actor; + if (empty($actor->id)) { + common_log(LOG_ERR, "broken actor: " . var_export($actor, true)); + throw new Exception("Received a salmon slap from unidentified actor."); + } + + return Ostatus_profile::ensureActorProfile($this->act); + } + + /** + * @fixme merge into Ostatus_profile::ensureActorProfile and friends + */ + function createProfile() + { + $actor = $this->act->actor; + + $profile = new Profile(); + + $profile->nickname = $this->nicknameFromURI($actor->id); + + if (empty($profile->nickname)) { + $profile->nickname = common_nicknamize($actor->title); + } + + $profile->fullname = $actor->title; + $profile->bio = $actor->summary; // XXX: is that right? + $profile->profileurl = $actor->link; // XXX: is that right? + $profile->created = common_sql_now(); + + $id = $profile->insert(); + + if (empty($id)) { + common_log_db_error($profile, 'INSERT', __FILE__); + throw new Exception("Couldn't save new profile for $actor->id\n"); + } + + // XXX: add avatars + + $op = new Ostatus_profile(); + + $op->profile_id = $id; + $op->homeuri = $actor->id; + $op->created = $profile->created; + + // XXX: determine feed URI from source or Webfinger or whatever + + $id = $op->insert(); + + if (empty($id)) { + common_log_db_error($op, 'INSERT', __FILE__); + throw new Exception("Couldn't save new ostatus profile for $actor->id\n"); + } + + return $profile; + } + + /** + * @fixme should be merged into Ostatus_profile + */ + function nicknameFromURI($uri) + { + preg_match('/(\w+):/', $uri, $matches); + + $protocol = $matches[1]; + + switch ($protocol) { + case 'acct': + case 'mailto': + if (preg_match("/^$protocol:(.*)?@.*\$/", $uri, $matches)) { + return common_canonical_nickname($matches[1]); + } + return null; + case 'http': + return common_url_to_nickname($uri); + break; + default: + return null; + } + } +}