From 67e7bc55eac3977f60c76563fcd25dad17822a61 Mon Sep 17 00:00:00 2001 From: Mikael Nordfeldth Date: Mon, 12 Oct 2015 17:48:23 +0200 Subject: [PATCH] Bookmarks are almost migrated Now they are just not being saved in the bookmark table. --- classes/Managed_DataObject.php | 35 ++++ plugins/Bookmark/BookmarkPlugin.php | 90 +++------ plugins/Bookmark/actions/newbookmark.php | 126 ++----------- plugins/Bookmark/classes/Bookmark.php | 230 +++++++++++------------ 4 files changed, 192 insertions(+), 289 deletions(-) diff --git a/classes/Managed_DataObject.php b/classes/Managed_DataObject.php index 8d9bca11b0..5f8445d81e 100644 --- a/classes/Managed_DataObject.php +++ b/classes/Managed_DataObject.php @@ -346,6 +346,41 @@ abstract class Managed_DataObject extends Memcached_DataObject return $object; } + /** + * Returns an object by looking at given unique key columns. + * + * Will NOT accept NULL values for a unique key column. Ignores non-key values. + * + * @param array $vals All array keys which are set must be non-null. + * + * @return Managed_DataObject of the get_called_class() type + * @throws NoResultException if no object with that primary key + */ + static function getByKeys(array $vals) + { + $classname = get_called_class(); + + $object = new $classname(); + + $keys = $object->keys(); + if (is_null($keys)) { + throw new ServerException("Failed to get key columns for class '{$classname}'"); + } + + foreach ($keys as $col) { + if (!array_key_exists($col, $vals)) { + continue; + } elseif (is_null($vals[$col])) { + throw new ServerException("NULL values not allowed in getByPK for column '{$col}'"); + } + $object->$col = $vals[$col]; + } + if (!$object->find(true)) { + throw new NoResultException($object); + } + return $object; + } + static function getByID($id) { if (empty($id)) { diff --git a/plugins/Bookmark/BookmarkPlugin.php b/plugins/Bookmark/BookmarkPlugin.php index e79b4bdec1..1b2f461855 100644 --- a/plugins/Bookmark/BookmarkPlugin.php +++ b/plugins/Bookmark/BookmarkPlugin.php @@ -297,79 +297,37 @@ class BookmarkPlugin extends MicroAppPlugin */ protected function saveObjectFromActivity(Activity $activity, Notice $stored, array $options=array()) { - $actobj = $activity->objects[0]; + return Bookmark::saveActivityObject($activity->objects[0], $stored); + } - $relLinkEls = ActivityUtils::getLinks($actobj->element, 'related'); - - if (count($relLinkEls) !== 1) { - // TRANS: Client exception thrown when a bookmark is formatted incorrectly. - throw new ClientException(sprintf(_m('Expected exactly 1 link rel=related in a Bookmark, got %1$d.'), count($relLinkEls))); + public function onEndNoticeAsActivity(Notice $stored, Activity $act, Profile $scoped=null) + { + if (!$this->isMyNotice($stored)) { + return true; } - return Bookmark::addNew($stored, - $actobj->title, - $relLinkEls[0]->getAttribute('href'), - $actobj->summary); + common_debug('Extending activity '.$stored->id.' with '.get_called_class()); + $this->extendActivity($stored, $act, $scoped); + return false; + } + + public function extendActivity(Notice $stored, Activity $act, Profile $scoped=null) + { + /*$hashtags = array(); + $taglinks = array(); + + foreach ($tags as $tag) { + $hashtags[] = '#'.$tag; + $attrs = array('href' => Notice_tag::url($tag), + 'rel' => $tag, + 'class' => 'tag'); + $taglinks[] = XMLStringer::estring('a', $attrs, $tag); + }*/ } function activityObjectFromNotice(Notice $notice) { - assert($this->isMyNotice($notice)); - - common_log(LOG_INFO, - "Formatting notice {$notice->uri} as a bookmark."); - - $object = new ActivityObject(); - $nb = Bookmark::fromStored($notice); - - $object->id = $notice->uri; - $object->type = ActivityObject::BOOKMARK; - $object->title = $nb->getTitle(); - $object->summary = $nb->getDescription(); - $object->link = $notice->getUrl(); - - // Attributes of the URL - - $attachments = $notice->attachments(); - - if (count($attachments) != 1) { - // TRANS: Server exception thrown when a bookmark has multiple attachments. - throw new ServerException(_m('Bookmark notice with the '. - 'wrong number of attachments.')); - } - - $target = $attachments[0]; - - $attrs = array('rel' => 'related', - 'href' => $target->getUrl()); - - if (!empty($target->title)) { - $attrs['title'] = $target->title; - } - - $object->extra[] = array('link', $attrs, null); - - // Attributes of the thumbnail, if any - - try { - $thumbnail = $target->getThumbnail(); - $tattrs = array('rel' => 'preview', - 'href' => $thumbnail->getUrl()); - - if (!empty($thumbnail->width)) { - $tattrs['media:width'] = $thumbnail->width; - } - - if (!empty($thumbnail->height)) { - $tattrs['media:height'] = $thumbnail->height; - } - - $object->extra[] = array('link', $tattrs, null); - } catch (UnsupportedMediaException $e) { - // No image thumbnail metadata available - } - - return $object; + return Bookmark::fromStored($notice)->asActivityObject(); } function entryForm($out) diff --git a/plugins/Bookmark/actions/newbookmark.php b/plugins/Bookmark/actions/newbookmark.php index 823b7cfbb6..470ad417a4 100644 --- a/plugins/Bookmark/actions/newbookmark.php +++ b/plugins/Bookmark/actions/newbookmark.php @@ -43,54 +43,22 @@ if (!defined('STATUSNET')) { * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @link http://status.net/ */ -class NewbookmarkAction extends Action +class NewbookmarkAction extends FormAction { - protected $user = null; - protected $error = null; protected $complete = null; protected $title = null; protected $url = null; protected $tags = null; protected $description = null; - /** - * Returns the title of the action - * - * @return string Action title - */ function title() { // TRANS: Title for action to create a new bookmark. return _m('New bookmark'); } - /** - * For initializing members of the class. - * - * @param array $argarray misc. arguments - * - * @return boolean true - */ - function prepare($argarray) + protected function doPreparation() { - parent::prepare($argarray); - - if ($this->boolean('ajax')) { - GNUsocial::setApi(true); - } - - $this->user = common_current_user(); - - if (empty($this->user)) { - // TRANS: Client exception thrown when trying to create a new bookmark while not logged in. - throw new ClientException(_m('Must be logged in to post a bookmark.'), - 403); - } - - if ($this->isPost()) { - $this->checkSessionToken(); - } - $this->title = $this->trimmed('title'); $this->url = $this->trimmed('url'); $this->tags = preg_split('/[\s,]+/', $this->trimmed('tags'), null, PREG_SPLIT_NO_EMPTY); @@ -99,87 +67,33 @@ class NewbookmarkAction extends Action return true; } - /** - * Handler method - * - * @param array $argarray is ignored since it's now passed in in prepare() - * - * @return void - */ - function handle($argarray=null) - { - parent::handle($argarray); - - if ($this->isPost()) { - $this->newBookmark(); - } else { - $this->showPage(); - } - - return; - } - /** * Add a new bookmark * * @return void */ - function newBookmark() + function handlePost() { - try { - if (empty($this->title)) { - // TRANS: Client exception thrown when trying to create a new bookmark without a title. - throw new ClientException(_m('Bookmark must have a title.')); - } - - if (empty($this->url)) { - // TRANS: Client exception thrown when trying to create a new bookmark without a URL. - throw new ClientException(_m('Bookmark must have an URL.')); - } - - $options = array(); - - ToSelector::fillOptions($this, $options); - - $saved = Bookmark::saveNew($this->user->getProfile(), - $this->title, - $this->url, - $this->tags, - $this->description, - $options); - - } catch (ClientException $ce) { - if ($this->boolean('ajax')) { - $this->startHTML('text/xml;charset=utf-8'); - $this->elementStart('head'); - // TRANS: Page title after an AJAX error occurs - $this->element('title', null, _('Ajax Error')); - $this->elementEnd('head'); - $this->elementStart('body'); - $this->element('p', array('id' => 'error'), $ce->getMessage()); - $this->elementEnd('body'); - $this->endHTML(); - return; - } else { - $this->error = $ce->getMessage(); - $this->showPage(); - return; - } + if (empty($this->title)) { + // TRANS: Client exception thrown when trying to create a new bookmark without a title. + throw new ClientException(_m('Bookmark must have a title.')); } - if ($this->boolean('ajax')) { - $this->startHTML('text/xml;charset=utf-8'); - $this->elementStart('head'); - // TRANS: Page title after posting a bookmark. - $this->element('title', null, _m('Bookmark posted')); - $this->elementEnd('head'); - $this->elementStart('body'); - $this->showNotice($saved); - $this->elementEnd('body'); - $this->endHTML(); - } else { - common_redirect($saved->getUrl(), 303); + if (empty($this->url)) { + // TRANS: Client exception thrown when trying to create a new bookmark without a URL. + throw new ClientException(_m('Bookmark must have an URL.')); } + + $options = array(); + + ToSelector::fillOptions($this, $options); + + $saved = Bookmark::addNew($this->scoped, + $this->title, + $this->url, + $this->tags, + $this->description, + $options); } /** diff --git a/plugins/Bookmark/classes/Bookmark.php b/plugins/Bookmark/classes/Bookmark.php index 87e81240d0..11c37fefa9 100644 --- a/plugins/Bookmark/classes/Bookmark.php +++ b/plugins/Bookmark/classes/Bookmark.php @@ -97,6 +97,11 @@ class Bookmark extends Managed_DataObject return self::getByPK(array('uri' => $stored->getUri())); } + public function getStored() + { + return Notice::getByKeys(array('uri' => $this->getUri())); + } + public function getDescription() { return $this->description; @@ -107,6 +112,11 @@ class Bookmark extends Managed_DataObject return $this->title; } + public function getUri() + { + return $this->uri; + } + public function getUrl() { if (empty($this->url)) { @@ -147,9 +157,18 @@ class Bookmark extends Managed_DataObject * * @return Bookmark the Bookmark object */ - static function addNew(Notice $stored, $title, $url, $description) + static function saveActivityObject(ActivityObject $actobj, Notice $stored) { - if ($title === '' or is_null($title)) { + $relLinkEls = ActivityUtils::getLinks($actobj->element, 'related'); + + if (count($relLinkEls) !== 1) { + // TRANS: Client exception thrown when a bookmark is formatted incorrectly. + throw new ClientException(sprintf(_m('Expected exactly 1 link rel=related in a Bookmark, got %1$d.'), count($relLinkEls))); + } + + $url = $relLinkEls[0]->getAttribute('href'); + + if (!strlen($actobj->title)) { throw new ClientException(_m('You must provide a non-empty title.')); } if (!common_valid_http_url($url)) { @@ -166,11 +185,11 @@ class Bookmark extends Managed_DataObject $nb = new Bookmark(); $nb->id = UUID::gen(); - $nb->uri = $stored->uri; + $nb->uri = $stored->getUri(); $nb->profile_id = $stored->getProfile()->getID(); - $nb->title = $title; + $nb->title = $actobj->title; $nb->url = $url; - $nb->description = $description; + $nb->description = $actobj->summary; $nb->created = $stored->created; $result = $nb->insert(); @@ -178,20 +197,65 @@ class Bookmark extends Managed_DataObject throw new ServerException('Could not insert Bookmark into database!'); } - /*$hashtags = array(); - $taglinks = array(); - - foreach ($tags as $tag) { - $hashtags[] = '#'.$tag; - $attrs = array('href' => Notice_tag::url($tag), - 'rel' => $tag, - 'class' => 'tag'); - $taglinks[] = XMLStringer::estring('a', $attrs, $tag); - }*/ - return $nb; } + public function asActivityObject() + { + $stored = $this->getStored(); + + $object = new ActivityObject(); + $object->id = $this->getUri(); + $object->type = ActivityObject::BOOKMARK; + $object->title = $this->getTitle(); + $object->summary = $this->getDescription(); + $object->link = $stored->getUrl(); + $object->content = $stored->getRendered(); + + // Attributes of the URL + + $attachments = $stored->attachments(); + + if (count($attachments) != 1) { + // TRANS: Server exception thrown when a bookmark has multiple attachments. + throw new ServerException(_m('Bookmark notice with the '. + 'wrong number of attachments.')); + } + + $bookmarkedurl = $attachments[0]; + + $attrs = array('rel' => 'related', + 'href' => $bookmarkedurl->getUrl()); + + if (!strlen($bookmarkedurl->title)) { + $attrs['title'] = $bookmarkedurl->title; + } + + $object->extra[] = array('link', $attrs, null); + + // Attributes of the thumbnail, if any + + try { + $thumbnail = $bookmarkedurl->getThumbnail(); + $tattrs = array('rel' => 'preview', + 'href' => $thumbnail->getUrl()); + + if (!empty($thumbnail->width)) { + $tattrs['media:width'] = $thumbnail->width; + } + + if (!empty($thumbnail->height)) { + $tattrs['media:height'] = $thumbnail->height; + } + + $object->extra[] = array('link', $tattrs, null); + } catch (UnsupportedMediaException $e) { + // No image thumbnail metadata available + } + + return $object; + } + /** * Save a new notice bookmark * @@ -204,78 +268,32 @@ class Bookmark extends Managed_DataObject * * @return Notice saved notice */ - static function saveNew(Profile $profile, $title, $url, $rawtags, $description, - array $options=array()) + static function addNew(Profile $actor, $title, $url, array $rawtags, $description, array $options=array()) { - if (!common_valid_http_url($url)) { - throw new ClientException(_m('Only web bookmarks can be posted (HTTP or HTTPS).')); - } + $act = new Activity(); + $act->verb = ActivityVerb::POST; + $act->time = time(); + $act->actor = $actor->asActivityObject(); - try { - $object = self::getByURL($profile, $url); - return $object; - } catch (NoResultException $e) { - // Alright, so then we have to create it. - } + $actobj = new ActivityObject(); + $actobj->type = ActivityObject::BOOKMARK; + $actobj->title = $title; + $actobj->summary = $description; + $actobj->extra[] = array('link', $attrs, null); + $act->objects[] = $actobj; - if (array_key_exists('uri', $options)) { - $other = Bookmark::getKV('uri', $options['uri']); - if (!empty($other)) { - // TRANS: Client exception thrown when trying to save a new bookmark that already exists. - throw new ClientException(_m('Bookmark already exists.')); - } - } - - $nb = new Bookmark(); - - $nb->id = UUID::gen(); - $nb->profile_id = $profile->id; - $nb->url = $url; - $nb->title = $title; - $nb->description = $description; - - if (array_key_exists('created', $options)) { - $nb->created = $options['created']; - } else { - $nb->created = common_sql_now(); - } - - if (array_key_exists('uri', $options)) { - $nb->uri = $options['uri']; - } else { - // FIXME: hacks to work around router bugs in - // queue daemons - - $r = Router::get(); - - $path = $r->build('showbookmark', - array('id' => $nb->id)); - - if (empty($path)) { - $nb->uri = common_path('bookmark/'.$nb->id, false, false); - } else { - $nb->uri = common_local_url('showbookmark', - array('id' => $nb->id), - null, - null, - false); - } - } - - $nb->insert(); + $act->enclosures[] = $url; $tags = array(); $replies = array(); // filter "for:nickname" tags - foreach ($rawtags as $tag) { if (strtolower(mb_substr($tag, 0, 4)) == 'for:') { // skip if done by caller if (!array_key_exists('replies', $options)) { $nickname = mb_substr($tag, 4); - $other = common_relative_profile($profile, - $nickname); + $other = common_relative_profile($actor, $nickname); if (!empty($other)) { $replies[] = $other->getUri(); } @@ -297,38 +315,33 @@ class Bookmark extends Managed_DataObject } // Use user's preferences for short URLs, if possible - + // FIXME: Should be possible to with the Profile object... try { - $user = User::getKV('id', $profile->id); - - $shortUrl = File_redirection::makeShort($url, - empty($user) ? null : $user); + $user = $actor->getUser(); + $shortUrl = File_redirection::makeShort($url, empty($user) ? null : $user); } catch (Exception $e) { // Don't let this stop us. $shortUrl = $url; } - // TRANS: Bookmark content. - // TRANS: %1$s is a title, %2$s is a short URL, %3$s is the bookmark description, - // TRANS: %4$s is space separated list of hash tags. - $content = sprintf(_m('"%1$s" %2$s %3$s %4$s'), - $title, - $shortUrl, - $description, - implode(' ', $hashtags)); - // TRANS: Rendered bookmark content. // TRANS: %1$s is a URL, %2$s the bookmark title, %3$s is the bookmark description, - // TRANS: %4$s is space separated list of hash tags. - $rendered = sprintf(_m(''. - '%2$s '. - '%3$s '. - '%4$s'. - ''), - htmlspecialchars($url), - htmlspecialchars($title), - htmlspecialchars($description), - implode(' ', $taglinks)); + // TRANS: %4$s is space separated list of hash tags. + $actobj->content = sprintf(_m(''. + '%2$s '. + '%3$s '. + '%4$s'. + ''), + htmlspecialchars($url), + htmlspecialchars($title), + htmlspecialchars($description), + implode(' ', $taglinks)); + + foreach ($tags as $term) { + $catEl = new AtomCategory(); + $catEl->term = $term; + $activity->categories[] = $catEl; + } $options = array_merge(array('urls' => array($url), 'rendered' => $rendered, @@ -337,23 +350,6 @@ class Bookmark extends Managed_DataObject 'object_type' => ActivityObject::BOOKMARK), $options); - $options['uri'] = $nb->uri; - - try { - $saved = Notice::saveNew($profile->id, - $content, - array_key_exists('source', $options) ? - $options['source'] : 'web', - $options); - } catch (Exception $e) { - $nb->delete(); - throw $e; - } - - if (empty($saved)) { - $nb->delete(); - } - - return $saved; + return Notice::saveActivity($act, $actor, $options); } }