diff --git a/classes/Notice.php b/classes/Notice.php index f11c670603..e71500145d 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -721,8 +721,8 @@ class Notice extends Managed_DataObject return $notice; } - static function saveActivity(Activity $act, Profile $actor, array $options=array()) { - + static function saveActivity(Activity $act, Profile $actor, array $options=array()) + { // First check if we're going to let this Activity through from the specific actor if (!$actor->hasRight(Right::NEWNOTICE)) { common_log(LOG_WARNING, "Attempted post from user disallowed to post: " . $actor->getNickname()); @@ -737,6 +737,7 @@ class Notice extends Managed_DataObject 'and post again in a few minutes.')); } +/* This interferes with stuff like Favorites from old StatusNet installations (first object in objects is the favored notice) // Get ActivityObject properties $actobj = count($act->objects)==1 ? $act->objects[0] : null; if (!is_null($actobj) && $actobj->id) { @@ -753,6 +754,7 @@ class Notice extends Managed_DataObject $options['uri'] = $act->id; $options['url'] = $act->link; } +*/ $defaults = array( 'groups' => array(), @@ -883,7 +885,7 @@ class Notice extends Managed_DataObject throw new ServerException('No object from StoreActivityObject '.$stored->uri . ': '.$act->asString()); } $orig = clone($stored); - $stored->object_type = ActivityUtils::resolveUri($object->type, true); + $stored->object_type = ActivityUtils::resolveUri($object->getObjectType(), true); $stored->update($orig); } catch (Exception $e) { if (empty($stored->id)) { @@ -896,7 +898,7 @@ class Notice extends Managed_DataObject } } - + common_debug(get_called_class().' looking up mentions metadata etc.'); // Save per-notice metadata... $mentions = array(); $groups = array(); @@ -933,6 +935,8 @@ class Notice extends Managed_DataObject // Prepare inbox delivery, may be queued to background. $stored->distribute(); } + + common_debug(get_called_class().' returning stored activity - success!'); return $stored; } diff --git a/lib/activityhandlerplugin.php b/lib/activityhandlerplugin.php index d972d17552..113b7eab1e 100644 --- a/lib/activityhandlerplugin.php +++ b/lib/activityhandlerplugin.php @@ -158,7 +158,7 @@ abstract class ActivityHandlerPlugin extends Plugin * * @return Notice the resulting notice */ - public function saveObjectFromActivity(Activity $activity, Notice $stored, array $options=array()) + protected function saveObjectFromActivity(Activity $activity, Notice $stored, array $options=array()) { throw new ServerException('This function should be abstract when all plugins have migrated to saveObjectFromActivity'); } @@ -317,7 +317,11 @@ abstract class ActivityHandlerPlugin extends Plugin 'is_local' => Notice::REMOTE, 'source' => 'ostatus'); - $notice = $this->saveNoticeFromActivity($activity, $profile, $options); + if (!isset($this->oldSaveNew)) { + $notice = Notice::saveActivity($activity, $profile, $options); + } else { + $notice = $this->saveNoticeFromActivity($activity, $profile, $options); + } return false; } @@ -339,22 +343,28 @@ abstract class ActivityHandlerPlugin extends Plugin $this->log(LOG_INFO, "Checking {$activity->id} as a valid Salmon slap."); - if ($target instanceof User_group) { + if ($target instanceof User_group || $target->isGroup()) { $uri = $target->getUri(); if (!array_key_exists($uri, $activity->context->attention)) { // @todo FIXME: please document (i18n). // TRANS: Client exception thrown when ... throw new ClientException(_('Object not posted to this group.')); } - } else if ($target instanceof User) { - $uri = $target->uri; + } elseif ($target instanceof Profile && $target->isLocal()) { + common_debug(get_called_class() . ' got a salmon slap against target profile ID: '.$target->id); $original = null; + // FIXME: Shouldn't favorites show up with a 'target' activityobject? + if (!ActivityUtils::compareTypes($activity->verb, array(ActivityVerb::POST)) && isset($activity->objects[0])) { + // If this is not a post, it's a verb targeted at something (such as a Favorite attached to a note) + if (!empty($activity->objects[0]->id)) { + $activity->context->replyToID = $activity->objects[0]->id; + } + } if (!empty($activity->context->replyToID)) { $original = Notice::getKV('uri', $activity->context->replyToID); } - if (!array_key_exists($uri, $activity->context->attention) && - (empty($original) || - $original->profile_id != $target->id)) { + if ((!$original instanceof Notice || $original->profile_id != $target->id) + && !array_key_exists($target->getUri(), $activity->context->attention)) { // @todo FIXME: Please document (i18n). // TRANS: Client exception when ... throw new ClientException(_('Object not posted to this user.')); @@ -364,9 +374,15 @@ abstract class ActivityHandlerPlugin extends Plugin throw new ServerException(_('Do not know how to handle this kind of target.')); } + common_debug(get_called_class() . ' ensuring ActivityObject profile for '.$activity->actor->id); $actor = Ostatus_profile::ensureActivityObjectProfile($activity->actor); - $object = $activity->objects[0]; + // FIXME: will this work in all cases? I made it work for Favorite... + if (ActivityUtils::compareTypes($activity->verb, array(ActivityVerb::POST))) { + $object = $activity->objects[0]; + } else { + $object = $activity; + } $options = array('uri' => $object->id, 'url' => $object->link, @@ -374,7 +390,12 @@ abstract class ActivityHandlerPlugin extends Plugin 'source' => 'ostatus'); // $actor is an ostatus_profile - $this->saveNoticeFromActivity($activity, $actor->localProfile(), $options); + common_debug(get_called_class() . ' going to save notice from activity!'); + if (!isset($this->oldSaveNew)) { + $notice = Notice::saveActivity($activity, $target, $options); + } else { + $notice = $this->saveNoticeFromActivity($activity, $target, $options); + } return false; } diff --git a/lib/activityutils.php b/lib/activityutils.php index e9d5d1fba5..feb74f303f 100644 --- a/lib/activityutils.php +++ b/lib/activityutils.php @@ -398,7 +398,7 @@ class ActivityUtils if (!empty($object)) { Event::handle('EndFindLocalActivityObject', array($object->getUri(), $type, $object)); } else { - throw new Exception('Could not find any activityobject stored locally with given URI'); + throw new ServerException('Could not find any activityobject stored locally with given URI'); } return $object; } diff --git a/plugins/Favorite/FavoritePlugin.php b/plugins/Favorite/FavoritePlugin.php index 18aa32738b..3d27d24a7f 100644 --- a/plugins/Favorite/FavoritePlugin.php +++ b/plugins/Favorite/FavoritePlugin.php @@ -147,39 +147,31 @@ class FavoritePlugin extends ActivityHandlerPlugin 'format' => '(xml|json)')); } - public function saveNoticeFromActivity(Activity $activity, Profile $actor, array $options=array()) - { - } - - // FIXME: Set this to abstract public when all plugins have migrated! - public function saveObjectFromActivity(Activity $activity, Notice $stored, array $options=array()) + // FIXME: Set this to abstract public in lib/activityhandlerplugin.php ddwhen all plugins have migrated! + protected function saveObjectFromActivity(Activity $act, Notice $stored, array $options=array()) { assert($this->isMyActivity($act)); - $actor = $stored->getProfile(); - $uris = array(); - if (count($act->objects) != 1) { - // TRANS: Exception thrown when a favor activity has anything but 1 object - throw new ClientException(_('Favoring activites can only be done one at a time')); + + // If empty, we should've created it ourselves on our node. + if (!isset($options['created'])) { + $options['created'] = !empty($act->time) ? common_sql_date($act->time) : common_sql_now(); + } + if (!isset($options['uri'])) { + $options['uri'] = !empty($act->id) ? $act->id : $act->selfLink; } - $obj = $act->objects[0]; - $type = isset($obj->type) ? ActivityUtils::resolveUri($obj->type, true) : ActivityObject::NOTE; - $uris = $obj->getIdentifiers(); + // We must have an objects[0] here because in isMyActivity we require the count to be == 1 + $actobj = $act->objects[0]; + try { - $local = ActivityUtils::findLocalObject($uris, $type); - } catch (Exception $e) { - // TODO: if it's not available locally, we should import the favorited object! - common_debug('Could not find favored notice locally: '.var_export($uris,true)); + $object = Fave::saveActivityObject($actobj, $stored); + } catch (ServerException $e) { + // Probably that the favored notice doesn't exist in our local database + // but may also be some missing profile or so, which we could catch in a + // more explicit catch-statement. return null; } - - if (!empty($act->time)) { - // This should reasonably mean that it was created on our instance. - $options['created'] = common_sql_date($act->time); - } - - $options['uri'] = !empty($act->id) ? $act->id : $act->selfLink; - $object = Fave::saveNew($actor, $local, $type, $options); + common_debug(get_called_class().' returning '.get_class($object).' object with uri: '.$object->uri); return $object; } diff --git a/plugins/Favorite/classes/Fave.php b/plugins/Favorite/classes/Fave.php index 0801ef8717..3ec5fadd7b 100644 --- a/plugins/Favorite/classes/Fave.php +++ b/plugins/Favorite/classes/Fave.php @@ -79,7 +79,8 @@ class Fave extends Managed_DataObject } // exception throwing takeover! - public function insert() { + public function insert() + { if (!parent::insert()) { throw new ServerException(sprintf(_m('Could not store new object of type %s'), get_called_class())); } @@ -169,7 +170,8 @@ class Fave extends Managed_DataObject return $act; } - static function existsForProfile($notice, Profile $scoped) { + static function existsForProfile($notice, Profile $scoped) + { $fave = self::pkeyGet(array('user_id'=>$scoped->id, 'notice_id'=>$notice->id)); return ($fave instanceof Fave); @@ -270,7 +272,8 @@ class Fave extends Managed_DataObject // Remember that we want the _activity_ notice here, not faves applied // to the supplied Notice (as with byNotice)! - static public function fromStored(Notice $stored) { + static public function fromStored(Notice $stored) + { $class = get_called_class(); $object = new $class; $object->uri = $stored->uri; @@ -280,16 +283,18 @@ class Fave extends Managed_DataObject return $object; } - static public function verbToTitle($verb) { + static public function verbToTitle($verb) + { return ucfirst($verb); } - static public function object_type() + static public function getObjectType() { return 'activity'; } - public function asActivityObject(Profile $scoped=null) { + public function asActivityObject(Profile $scoped=null) + { $actobj = new ActivityObject(); $actobj->id = $this->getUri(); $actobj->type = ActivityUtils::resolveUri(ActivityObject::ACTIVITY); @@ -301,35 +306,51 @@ class Fave extends Managed_DataObject return $actobj; } - static public function parseActivityObject(ActivityObject $actobj, Notice $stored) { + static public function parseActivityObject(ActivityObject $actobj, Notice $stored) + { + // The ActivityObject we get here is the _favored_ notice (kind of what we're "in-reply-to") + // The Notice we get is the _activity_ stored in our Notice table + + $type = isset($actobj->type) ? ActivityUtils::resolveUri($actobj->type, true) : ActivityObject::NOTE; + $local = ActivityUtils::findLocalObject($actobj->getIdentifiers(), $type); + if (!$local instanceof Notice) { + // $local always returns something, but this was not what we expected. Something is wrong. + throw new Exception('Something other than a Notice was returned from findLocalObject'); + } + $actor = $stored->getProfile(); $object = new Fave(); - $object->user_id = $actor->id; - $object->notice_id = $stored->id; - $object->object_uri = $stored->uri; + $object->user_id = $stored->getProfile()->id; + $object->notice_id = $local->id; + $object->uri = $stored->uri; $object->created = $stored->created; + $object->modified = $stored->modified; return $object; } - static function saveActivityObject(ActivityObject $actobj, Notice $stored) { + static function saveActivityObject(ActivityObject $actobj, Notice $stored) + { $object = self::parseActivityObject($actobj, $stored); $object->insert(); // exception throwing! return $object; } - public function getTarget() { + public function getTarget() + { // throws exception on failure return ActivityUtils::findLocalObject(array($this->uri), $this->type); } - public function getTargetObject() { + public function getTargetObject() + { return $this->getTarget()->asActivityObject(); } protected $_stored = array(); - public function getStored() { + public function getStored() + { if (!isset($this->_stored[$this->uri])) { $stored = new Notice(); $stored->uri = $this->uri; @@ -341,7 +362,8 @@ class Fave extends Managed_DataObject return $this->_stored[$this->uri]; } - public function getActor() { + public function getActor() + { $profile = new Profile(); $profile->id = $this->user_id; if (!$profile->find(true)) { @@ -350,7 +372,8 @@ class Fave extends Managed_DataObject return $profile; } - public function getActorObject() { + public function getActorObject() + { return $this->getActor()->asActivityObject(); } @@ -371,7 +394,7 @@ class Fave extends Managed_DataObject } return TagURI::mint(strtolower(get_called_class()).':%d:%s:%d:%s', $actor->id, - ActivityUtils::resolveUri(self::object_type(), true), + ActivityUtils::resolveUri(self::getObjectType(), true), $target->id, common_date_iso8601($created)); } diff --git a/plugins/OStatus/actions/usersalmon.php b/plugins/OStatus/actions/usersalmon.php index 8b0ab2f83c..7fce6c808c 100644 --- a/plugins/OStatus/actions/usersalmon.php +++ b/plugins/OStatus/actions/usersalmon.php @@ -130,47 +130,6 @@ class UsersalmonAction extends SalmonAction } } - /** - * Remote user likes one of our posts. - * Confirm the post is ours, and save a local favorite event. - */ - - function handleFavorite() - { - $notice = $this->getNotice($this->activity->objects[0]); - - $old = Fave::pkeyGet(array('user_id' => $this->actor->id, - 'notice_id' => $notice->id)); - - if ($old instanceof Fave) { - // TRANS: Client exception. - throw new AlreadyFulfilledException(_m('This is already a favorite.')); - } - - if (!Fave::addNew($this->actor, $notice)) { - // TRANS: Client exception. - throw new ClientException(_m('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() - { - $notice = $this->getNotice($this->activity->objects[0]); - - $fave = Fave::pkeyGet(array('user_id' => $this->actor->id, - 'notice_id' => $notice->id)); - if (!$fave instanceof Fave) { - // TRANS: Client exception. - throw new AlreadyFulfilledException(_m('Notice was not favorited!')); - } - - $fave->delete(); - } - function handleTag() { if ($this->activity->target->type == ActivityObject::_LIST) { diff --git a/plugins/OStatus/lib/salmonaction.php b/plugins/OStatus/lib/salmonaction.php index 186d5acfbb..d26c1f949b 100644 --- a/plugins/OStatus/lib/salmonaction.php +++ b/plugins/OStatus/lib/salmonaction.php @@ -91,12 +91,6 @@ class SalmonAction extends Action case ActivityVerb::SHARE: $this->handleShare(); break; - case ActivityVerb::FAVORITE: - $this->handleFavorite(); - break; - case ActivityVerb::UNFAVORITE: - $this->handleUnfavorite(); - break; case ActivityVerb::FOLLOW: case ActivityVerb::FRIEND: $this->handleFollow(); @@ -152,18 +146,6 @@ class SalmonAction extends Action throw new ClientException(_m('This target does not understand unfollows.')); } - function handleFavorite() - { - // TRANS: Client exception. - throw new ClientException(_m('This target does not understand favorites.')); - } - - function handleUnfavorite() - { - // TRANS: Client exception. - throw new ClientException(_m('This target does not understand unfavorites.')); - } - function handleShare() { // TRANS: Client exception.