From fffacaa27c45db37196cfaac5b7e098c5afcf952 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Sat, 5 Jul 2014 23:39:17 +0200 Subject: [PATCH] FavorAction now uses Notice::saveActivity --- classes/Notice.php | 132 +++++++++++------- lib/activityobject.php | 26 ---- lib/activityutils.php | 10 ++ plugins/Activity/ActivityPlugin.php | 44 ------ plugins/Favorite/FavoritePlugin.php | 3 +- .../Favorite/actions/atompubfavoritefeed.php | 2 +- plugins/Favorite/actions/favor.php | 75 ++++++---- plugins/Favorite/classes/Fave.php | 59 ++++---- plugins/OStatus/OStatusPlugin.php | 2 +- 9 files changed, 166 insertions(+), 187 deletions(-) diff --git a/classes/Notice.php b/classes/Notice.php index 258652639a..2ae4584ab8 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -647,54 +647,21 @@ class Notice extends Managed_DataObject // XXX: some of these functions write to the DB - $id = $notice->insert(); - - if (!$id) { - common_log_db_error($notice, 'INSERT', __FILE__); - // TRANS: Server exception thrown when a notice cannot be saved. - throw new ServerException(_('Problem saving notice.')); - } - - // Update ID-dependent columns: URI, conversation - - $orig = clone($notice); - - $changed = false; - - // We can only get here if it's a local notice, since remote notices - // should've bailed out earlier due to lacking a URI. - if (empty($notice->uri)) { - $notice->uri = sprintf('%s%s=%d:%s=%s', - TagURI::mint(), - 'noticeId', $notice->id, - 'objectType', $notice->get_object_type(true)); - $changed = true; - } - - // If it's not part of a conversation, it's - // the beginning of a new conversation. - - if (empty($notice->conversation)) { - $conv = Conversation::create($notice); - $notice->conversation = $conv->id; - $changed = true; - } - - if ($changed) { - if ($notice->update($orig) === false) { - common_log_db_error($notice, 'UPDATE', __FILE__); - // TRANS: Server exception thrown when a notice cannot be updated. - throw new ServerException(_('Problem saving notice.')); + try { + $notice->insert(); // throws exception on failure + } catch (Exception $e) { + // Let's test if we managed initial insert, which would imply + // failing on some update-part (check 'insert()'). Delete if + // something had been stored to the database. + if (!empty($notice->id)) { + $notice->delete(); } } - } // Clear the cache for subscribed users, so they'll update at next request // XXX: someone clever could prepend instead of clearing the cache - $notice->blowOnInsert(); - // Save per-notice metadata... if (isset($replies)) { @@ -905,6 +872,9 @@ class Notice extends Managed_DataObject throw $e; } } + if (!$stored instanceof Notice) { + throw new ServerException('StartNoticeSave did not give back a Notice'); + } // Save per-notice metadata... $mentions = array(); @@ -1798,7 +1768,7 @@ class Notice extends Managed_DataObject $act->objects[] = $repeated->asActivity($cur); } } else { - $act->objects[] = ActivityObject::fromNotice($this); + $act->objects[] = $this->asActivityObject(); } // XXX: should this be handled by default processing for object entry? @@ -2005,10 +1975,29 @@ class Notice extends Managed_DataObject function asActivityNoun($element) { - $noun = ActivityObject::fromNotice($this); + $noun = $this->asActivityObject(); return $noun->asString('activity:' . $element); } + public function asActivityObject() + { + $object = new ActivityObject(); + + if (Event::handle('StartActivityObjectFromNotice', array($this, &$object))) { + $object->type = $this->object_type ?: ActivityObject::NOTE; + $object->id = $this->getUri(); + $object->title = sprintf('New %1$s by %2$s', $object->type, $this->getProfile()->getNickname()); + $object->content = $this->rendered; + $object->link = $this->getUrl(); + + $object->extra[] = array('status_net', array('notice_id' => $this->id)); + + Event::handle('EndActivityObjectFromNotice', array($this, &$object)); + } + + return $object; + } + /** * Determine which notice, if any, a new notice is in reply to. * @@ -2335,20 +2324,55 @@ class Notice extends Managed_DataObject { $result = parent::insert(); - if ($result !== false) { - // Profile::hasRepeated() abuses pkeyGet(), so we - // have to clear manually - if (!empty($this->repeat_of)) { - $c = self::memcache(); - if (!empty($c)) { - $ck = self::multicacheKey('Notice', - array('profile_id' => $this->profile_id, - 'repeat_of' => $this->repeat_of)); - $c->delete($ck); - } + if ($result === false) { + common_log_db_error($this, 'INSERT', __FILE__); + // TRANS: Server exception thrown when a stored object entry cannot be saved. + throw new ServerException('Could not save Notice'); + } + + // Profile::hasRepeated() abuses pkeyGet(), so we + // have to clear manually + if (!empty($this->repeat_of)) { + $c = self::memcache(); + if (!empty($c)) { + $ck = self::multicacheKey('Notice', + array('profile_id' => $this->profile_id, + 'repeat_of' => $this->repeat_of)); + $c->delete($ck); } } + // Update possibly ID-dependent columns: URI, conversation + // (now that INSERT has added the notice's local id) + $orig = clone($this); + $changed = false; + + // We can only get here if it's a local notice, since remote notices + // should've bailed out earlier due to lacking a URI. + if (empty($this->uri)) { + $this->uri = sprintf('%s%s=%d:%s=%s', + TagURI::mint(), + 'noticeId', $this->id, + 'objectType', $this->get_object_type(true)); + $changed = true; + } + + // If it's not part of a conversation, it's + // the beginning of a new conversation. + if (empty($this->conversation)) { + $conv = Conversation::create($this); + $this->conversation = $conv->id; + $changed = true; + } + + if ($changed && $this->update($orig) === false) { + common_log_db_error($notice, 'UPDATE', __FILE__); + // TRANS: Server exception thrown when a notice cannot be updated. + throw new ServerException(_('Problem saving notice.')); + } + + $this->blowOnInsert(); + return $result; } diff --git a/lib/activityobject.php b/lib/activityobject.php index b3940be824..d0b929245e 100644 --- a/lib/activityobject.php +++ b/lib/activityobject.php @@ -431,32 +431,6 @@ class ActivityObject } } - static function fromNotice(Notice $notice) - { - $object = new ActivityObject(); - - if (Event::handle('StartActivityObjectFromNotice', array($notice, &$object))) { - - $object->type = (empty($notice->object_type)) ? ActivityObject::NOTE : $notice->object_type; - - $object->id = $notice->uri; - $object->title = 'New ' . self::canonicalType($object->type) . ' by '; - try { - $object->title .= $notice->getProfile()->getAcctUri(); - } catch (ProfileNoAcctUriException $e) { - $object->title .= $e->profile->nickname; - } - $object->content = $notice->rendered; - $object->link = $notice->getUrl(); - - $object->extra[] = array('status_net', array('notice_id' => $notice->id)); - - Event::handle('EndActivityObjectFromNotice', array($notice, &$object)); - } - - return $object; - } - static function fromGroup(User_group $group) { $object = new ActivityObject(); diff --git a/lib/activityutils.php b/lib/activityutils.php index feb74f303f..d4c01232ec 100644 --- a/lib/activityutils.php +++ b/lib/activityutils.php @@ -433,4 +433,14 @@ class ActivityUtils return $profile; } + + static public function typeToTitle($type) + { + return ucfirst(self::resolveUri($type, true)); + } + + static public function verbToTitle($verb) + { + return ucfirst(self::resolveUri($verb, true)); + } } diff --git a/plugins/Activity/ActivityPlugin.php b/plugins/Activity/ActivityPlugin.php index ce6f114bfb..99c0a246c6 100644 --- a/plugins/Activity/ActivityPlugin.php +++ b/plugins/Activity/ActivityPlugin.php @@ -142,50 +142,6 @@ class ActivityPlugin extends Plugin return true; } - function onEndFavorNotice($profile, $notice) - { - // Only do this if config is enabled - if(!$this->StartLike) return true; - - if (!$profile->isLocal()) { - return true; - } - - $author = $notice->getProfile(); - $fave = Fave::pkeyGet(array('user_id' => $profile->id, - 'notice_id' => $notice->id)); - - // TRANS: Text for "liked" item in activity plugin. - // TRANS: %1$s is a profile URL, %2$s is a profile name, - // TRANS: %3$s is a notice URL, %4$s is an author name. - $rendered = sprintf(_m('%2$s liked %4$s\'s update.'), - $profile->getUrl(), - $profile->getBestName(), - $notice->getUrl(), - $author->getBestName()); - // TRANS: Text for "liked" item in activity plugin. - // TRANS: %1$s is a profile name, %2$s is a profile URL, - // TRANS: %3$s is an author name, %4$s is a notice URL. - $content = sprintf(_m('%1$s (%2$s) liked %3$s\'s status (%4$s).'), - $profile->getBestName(), - $profile->getUrl(), - $author->getBestName(), - $notice->getUrl()); - - $notice = Notice::saveNew($profile->id, - $content, - ActivityPlugin::SOURCE, - array('rendered' => $rendered, - 'urls' => array(), - 'replies' => array($author->getUri()), - 'uri' => $fave->getURI(), - 'verb' => ActivityVerb::FAVORITE, - 'object_type' => (($notice->verb == ActivityVerb::POST) ? - $notice->object_type : ActivityObject::ACTIVITY))); - - return true; - } - function onEndDisfavorNotice($profile, $notice) { // Only do this if config is enabled diff --git a/plugins/Favorite/FavoritePlugin.php b/plugins/Favorite/FavoritePlugin.php index 4a0dd806ca..61efe21027 100644 --- a/plugins/Favorite/FavoritePlugin.php +++ b/plugins/Favorite/FavoritePlugin.php @@ -63,7 +63,7 @@ class FavoritePlugin extends ActivityHandlerPlugin ' modified = "%s" '. 'WHERE user_id = %d '. 'AND notice_id = %d', - Fave::newURI($fave->user_id, $fave->notice_id, $fave->modified), + Fave::newUri($fave->user_id, $fave->notice_id, $fave->modified), common_sql_date(strtotime($fave->modified)), $fave->user_id, $fave->notice_id)); @@ -171,7 +171,6 @@ class FavoritePlugin extends ActivityHandlerPlugin // more explicit catch-statement. return null; } - common_debug(get_called_class().' returning '.get_class($object).' object with uri: '.$object->uri); return $object; } diff --git a/plugins/Favorite/actions/atompubfavoritefeed.php b/plugins/Favorite/actions/atompubfavoritefeed.php index 69ae442a41..cbbe91ae55 100644 --- a/plugins/Favorite/actions/atompubfavoritefeed.php +++ b/plugins/Favorite/actions/atompubfavoritefeed.php @@ -133,7 +133,7 @@ class AtompubfavoritefeedAction extends ApiAuthAction $feed->setUpdated('now'); $feed->addAuthor($this->_profile->getBestName(), - $this->_profile->getURI()); + $this->_profile->getUri()); // TRANS: Title for Atom favorites feed. // TRANS: %s is a user nickname. diff --git a/plugins/Favorite/actions/favor.php b/plugins/Favorite/actions/favor.php index 8db8f9f013..7df0c4febe 100644 --- a/plugins/Favorite/actions/favor.php +++ b/plugins/Favorite/actions/favor.php @@ -48,40 +48,61 @@ class FavorAction extends FormAction { protected $needPost = true; + protected $object = null; + + protected function prepare(array $args=array()) + { + parent::prepare($args); + + $this->target = Notice::getKV($this->trimmed('notice')); + if (!$this->target instanceof Notice) { + throw new ServerException(_m('No such notice.')); + } + if (!$this->target->inScope($this->scoped)) { + // TRANS: Client error displayed when trying to reply to a notice a the target has no access to. + // TRANS: %1$s is a user nickname, %2$d is a notice ID (number). + throw new ClientException(sprintf(_m('%1$s has no right to reply to notice %2$d.'), $this->scoped->getNickname(), $this->target->id), 403); + } + + return true; + } + protected function handlePost() { - $id = $this->trimmed('notice'); - $notice = Notice::getKV($id); - if (!($notice instanceof Notice)) { - $this->serverError(_('Notice not found')); - } - if (Fave::existsForProfile($notice, $this->scoped)) { + parent::handlePost(); + + if (Fave::existsForProfile($this->target, $this->scoped)) { // TRANS: Client error displayed when trying to mark a notice as favorite that already is a favorite. - throw new AlreadyFulfilledException(_('This notice is already a favorite!')); + throw new AlreadyFulfilledException(_('You have already favorited this!')); } - $fave = Fave::addNew($this->scoped, $notice); - if (!$fave instanceof Fave) { - // TRANS: Server error displayed when trying to mark a notice as favorite fails in the database. - $this->serverError(_('Could not create favorite.')); - } - $this->notify($notice, $this->scoped->getUser()); + + $now = common_sql_now(); + + $act = new Activity(); + $act->id = Fave::newUri($this->scoped, $this->target, $now); + $act->type = Fave::getObjectType(); + $act->actor = $this->scoped->asActivityObject(); + $act->target = $this->target->asActivityObject(); + $act->objects = array(clone($act->target)); + $act->verb = ActivityVerb::FAVORITE; + $act->title = ActivityUtils::verbToTitle($act->verb); + $act->time = strtotime($now); + + $stored = Notice::saveActivity($act, $this->scoped, + array('uri'=>$act->id)); + + $this->notify($stored, $this->scoped->getUser()); Fave::blowCacheForProfileId($this->scoped->id); - if (StatusNet::isAjax()) { - $this->startHTML('text/xml;charset=utf-8'); - $this->elementStart('head'); - // TRANS: Page title for page on which favorite notices can be unfavourited. - $this->element('title', null, _('Disfavor favorite.')); - $this->elementEnd('head'); - $this->elementStart('body'); - $disfavor = new DisFavorForm($this, $notice); + + return _('Favorited the notice'); + } + + protected function showContent() + { + if ($this->target instanceof Notice) { + $disfavor = new DisfavorForm($this, $this->target); $disfavor->show(); - $this->elementEnd('body'); - $this->endHTML(); - exit; } - common_redirect(common_local_url('showfavorites', - array('nickname' => $this->scoped->nickname)), - 303); } /** diff --git a/plugins/Favorite/classes/Fave.php b/plugins/Favorite/classes/Fave.php index 5ed53d160a..a66ad0ce89 100644 --- a/plugins/Favorite/classes/Fave.php +++ b/plugins/Favorite/classes/Fave.php @@ -58,7 +58,7 @@ class Fave extends Managed_DataObject $fave->notice_id = $notice->id; $fave->created = common_sql_now(); $fave->modified = common_sql_now(); - $fave->uri = self::newURI($profile, + $fave->uri = self::newUri($profile, $notice, $fave->created); @@ -128,17 +128,8 @@ class Fave extends Managed_DataObject function asActivity() { - $notice = Notice::getKV('id', $this->notice_id); - - if (!$notice) { - throw new Exception("Fave for non-existent notice: " . $this->notice_id); - } - - $profile = Profile::getKV('id', $this->user_id); - - if (!$profile) { - throw new Exception("Fave by non-existent profile: " . $this->user_id); - } + $notice = $this->getTarget(); + $profile = $this->getActor(); $act = new Activity(); @@ -146,7 +137,7 @@ class Fave extends Managed_DataObject // FIXME: rationalize this with URL below - $act->id = $this->getURI(); + $act->id = $this->getUri(); $act->time = strtotime($this->modified); // TRANS: Activity title when marking a notice as favorite. @@ -158,11 +149,13 @@ class Fave extends Managed_DataObject $notice->getUrl()); $act->actor = $profile->asActivityObject(); - $act->objects[] = ActivityObject::fromNotice($notice); + // $act->target = $notice->asActivityObject(); + // $act->objects = array(clone($act->target)); + $act->objects[] = $notice->asActivityObject(); $url = common_local_url('AtomPubShowFavorite', - array('profile' => $this->user_id, - 'notice' => $this->notice_id)); + array('profile' => $profile->id, + 'notice' => $notice->id)); $act->selfLink = $url; $act->editLink = $url; @@ -283,11 +276,6 @@ class Fave extends Managed_DataObject return $object; } - static public function verbToTitle($verb) - { - return ucfirst($verb); - } - static public function getObjectType() { return 'activity'; @@ -297,22 +285,22 @@ class Fave extends Managed_DataObject { $actobj = new ActivityObject(); $actobj->id = $this->getUri(); - $actobj->type = ActivityUtils::resolveUri($this->getObjectType()); + $actobj->type = ActivityUtils::resolveUri(self::getObjectType()); $actobj->actor = $this->getActorObject(); $actobj->target = $this->getTarget()->asActivityObject(); $actobj->objects = array(clone($actobj->target)); - $actobj->title = Stored_ActivityVerb::verbToTitle($this->verb); $actobj->verb = ActivityVerb::FAVORITE; + $actobj->title = ActivityUtils::verbToTitle($actobj->verb); return $actobj; } + /** + * @param ActivityObject $actobj The _favored_ notice (which we're "in-reply-to") + * @param Notice $stored The _activity_ notice, i.e. the favor itself. + */ 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); + $local = ActivityUtils::findLocalObject($actobj->getIdentifiers()); 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'); @@ -332,6 +320,7 @@ class Fave extends Managed_DataObject { $object = self::parseActivityObject($actobj, $stored); $object->insert(); // exception throwing! + Event::handle('EndFavorNotice', array($stored->getProfile(), $object->getTarget())); return $object; } @@ -339,7 +328,13 @@ class Fave extends Managed_DataObject public function getTarget() { // throws exception on failure - return ActivityUtils::findLocalObject(array($this->uri)); + $target = new Notice(); + $target->id = $this->notice_id; + if (!$target->find(true)) { + throw new NoResultException($target); + } + + return $target; } public function getTargetObject() @@ -377,17 +372,17 @@ class Fave extends Managed_DataObject return $this->getActor()->asActivityObject(); } - public function getURI() + public function getUri() { if (!empty($this->uri)) { return $this->uri; } // We (should've in this case) created it ourselves, so we tag it ourselves - return self::newURI($this->getActor(), $this->getTarget(), $this->created); + return self::newUri($this->getActor(), $this->getTarget(), $this->created); } - static function newURI(Profile $actor, Managed_DataObject $target, $created=null) + static function newUri(Profile $actor, Managed_DataObject $target, $created=null) { if (is_null($created)) { $created = common_sql_now(); diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index da5aa7adb2..31ea94bef1 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -1044,7 +1044,7 @@ class OStatusPlugin extends Plugin $notice->getUrl()); $act->actor = $profile->asActivityObject(); - $act->object = ActivityObject::fromNotice($notice); + $act->object = $notice->asActivityObject(); $oprofile->notifyActivity($act, $profile);