FavorAction now uses Notice::saveActivity

This commit is contained in:
Mikael Nordfeldth 2014-07-05 23:39:17 +02:00
parent aa33b7f21c
commit fffacaa27c
9 changed files with 166 additions and 187 deletions

View File

@ -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;
}

View File

@ -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();

View File

@ -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));
}
}

View File

@ -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('<a href="%1$s">%2$s</a> liked <a href="%3$s">%4$s\'s update</a>.'),
$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

View File

@ -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;
}

View File

@ -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.

View File

@ -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);
}
/**

View File

@ -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();

View File

@ -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);