--- /dev/null
+<?php
+/*
+ * GNU Social - a federating social network
+ * Copyright (C) 2014, Free Software Foundation, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+if (!defined('GNUSOCIAL')) { exit(1); }
+
+/**
+ * @package Activity
+ * @maintainer Mikael Nordfeldth <mmn@hethane.se>
+ */
+class ActivityVerbPostPlugin extends ActivityVerbHandlerPlugin
+{
+ public function tag()
+ {
+ return 'post';
+ }
+
+ public function types()
+ {
+ return array(ActivityObject::ARTICLE,
+ ActivityObject::BLOGENTRY,
+ ActivityObject::NOTE,
+ ActivityObject::STATUS,
+ ActivityObject::COMMENT,
+ // null, // if we want to follow the original Ostatus_profile::processActivity code
+ );
+ }
+
+ public function verbs()
+ {
+ return array(ActivityVerb::POST);
+ }
+
+ // FIXME: Set this to abstract public in lib/activityhandlerplugin.php when all plugins have migrated!
+ protected function saveObjectFromActivity(Activity $act, Notice $stored, array $options=array())
+ {
+ assert($this->isMyActivity($act));
+
+ $stored->object_type = ActivityUtils::resolveUri($act->objects[0]->type);
+
+ // We don't have to do just about anything for a new, remote notice since the fields
+ // are handled in the main Notice::saveActivity function. Such as content, attachments,
+ // parent/conversation etc.
+
+ // By returning true here instead of something that evaluates
+ // to false, we show that we have processed everything properly.
+ return true;
+ }
+
+ public function activityObjectFromNotice(Notice $notice)
+ {
+ $object = new ActivityObject();
+
+ $object->type = $notice->object_type ?: ActivityObject::NOTE;
+ $object->id = $notice->getUri();
+ $object->title = sprintf('New %1$s by %2$s', ActivityObject::canonicalType($object->type), $notice->getProfile()->getNickname());
+ $object->content = $notice->rendered;
+ $object->link = $notice->getUrl();
+
+ $object->extra[] = array('status_net', array('notice_id' => $notice->getID()));
+
+ return $object;
+ }
+
+ public function deleteRelated(Notice $notice)
+ {
+ // No action needed as the table for data storage _is_ the notice table.
+ return true;
+ }
+
+
+ /**
+ * Command stuff
+ */
+
+ // FIXME: Move stuff from lib/command.php to here just as with Share etc.
+
+
+ /**
+ * Layout stuff
+ */
+
+ protected function showNoticeContent(Notice $stored, HTMLOutputter $out, Profile $scoped=null)
+ {
+ $out->raw($stored->rendered);
+ }
+
+ protected function getActionTitle(ManagedAction $action, $verb, Notice $target, Profile $scoped)
+ {
+ // return page title
+ }
+
+ protected function doActionPreparation(ManagedAction $action, $verb, Notice $target, Profile $scoped)
+ {
+ // prepare Action?
+ }
+
+ protected function doActionPost(ManagedAction $action, $verb, Notice $target, Profile $scoped)
+ {
+ // handle repeat POST
+ }
+
+ protected function getActivityForm(ManagedAction $action, $verb, Notice $target, Profile $scoped)
+ {
+ return new NoticeForm($action, array());
+ }
+
+ public function onPluginVersion(array &$versions)
+ {
+ $versions[] = array('name' => 'Post verb',
+ 'version' => GNUSOCIAL_VERSION,
+ 'author' => 'Mikael Nordfeldth',
+ 'homepage' => 'https://gnu.io/',
+ 'rawdescription' =>
+ // TRANS: Plugin description.
+ _m('Post handling with ActivityStreams.'));
+
+ return true;
+ }
+}
if (Event::handle('StartHandleFeedEntryWithProfile', array($activity, $this->localProfile(), &$notice)) &&
Event::handle('StartHandleFeedEntry', array($activity))) {
- switch ($activity->verb) {
- case ActivityVerb::POST:
- // @todo process all activity objects
- switch ($activity->objects[0]->type) {
- case ActivityObject::ARTICLE:
- case ActivityObject::BLOGENTRY:
- case ActivityObject::NOTE:
- case ActivityObject::STATUS:
- case ActivityObject::COMMENT:
- case null:
- $notice = $this->processPost($activity, $source);
- break;
- default:
- // TRANS: Client exception.
- throw new ClientException(_m('Cannot handle that kind of post.'));
- }
- break;
- default:
- common_log(LOG_INFO, "Ignoring activity with unrecognized verb $activity->verb");
- }
+ common_log(LOG_INFO, "Ignoring activity with unrecognized verb $activity->verb");
Event::handle('EndHandleFeedEntry', array($activity));
Event::handle('EndHandleFeedEntryWithProfile', array($activity, $this, $notice));
* @param Activity $activity
* @param string $method 'push' or 'salmon'
* @return mixed saved Notice or false
- * @todo FIXME: Break up this function, it's getting nasty long
*/
public function processPost($activity, $method)
{
- $notice = null;
-
- $profile = ActivityUtils::checkAuthorship($activity, $this->localProfile());
-
- // It's not always an ActivityObject::NOTE, but... let's just say it is.
-
- $note = $activity->objects[0];
-
- // The id URI will be used as a unique identifier for the notice,
- // protecting against duplicate saves. It isn't required to be a URL;
- // tag: URIs for instance are found in Google Buzz feeds.
- $sourceUri = $note->id;
- $dupe = Notice::getKV('uri', $sourceUri);
- if ($dupe instanceof Notice) {
- common_log(LOG_INFO, "OStatus: ignoring duplicate post: $sourceUri");
- return $dupe;
- }
-
- // We'll also want to save a web link to the original notice, if provided.
- $sourceUrl = null;
- if ($note->link) {
- $sourceUrl = $note->link;
- } else if ($activity->link) {
- $sourceUrl = $activity->link;
- } else if (preg_match('!^https?://!', $note->id)) {
- $sourceUrl = $note->id;
- }
-
- // Use summary as fallback for content
-
- if (!empty($note->content)) {
- $sourceContent = $note->content;
- } else if (!empty($note->summary)) {
- $sourceContent = $note->summary;
- } else if (!empty($note->title)) {
- $sourceContent = $note->title;
- } else {
- // @todo FIXME: Fetch from $sourceUrl?
- // TRANS: Client exception. %s is a source URI.
- throw new ClientException(sprintf(_m('No content for notice %s.'),$sourceUri));
- }
-
- // Get (safe!) HTML and text versions of the content
-
- $rendered = common_purify($sourceContent);
- $content = common_strip_html($rendered);
-
- $shortened = common_shorten_links($content);
-
- // If it's too long, try using the summary, and make the
- // HTML an attachment.
-
- $attachment = null;
-
- if (Notice::contentTooLong($shortened)) {
- $attachment = $this->saveHTMLFile($note->title, $rendered);
- $summary = common_strip_html($note->summary);
- if (empty($summary)) {
- $summary = $content;
- }
- $shortSummary = common_shorten_links($summary);
- if (Notice::contentTooLong($shortSummary)) {
- $url = common_shorten_url($sourceUrl);
- $shortSummary = substr($shortSummary,
- 0,
- Notice::maxContent() - (mb_strlen($url) + 2));
- $content = $shortSummary . ' ' . $url;
-
- // We mark up the attachment link specially for the HTML output
- // so we can fold-out the full version inline.
-
- // @todo FIXME i18n: This tooltip will be saved with the site's default language
- // TRANS: Shown when a notice is longer than supported and/or when attachments are present. At runtime
- // TRANS: this will usually be replaced with localised text from StatusNet core messages.
- $showMoreText = _m('Show more');
- $attachUrl = common_local_url('attachment',
- array('attachment' => $attachment->id));
- $rendered = common_render_text($shortSummary) .
- '<a href="' . htmlspecialchars($attachUrl) .'"'.
- ' class="attachment more"' .
- ' title="'. htmlspecialchars($showMoreText) . '">' .
- '…' .
- '</a>';
- }
- }
-
- $options = array('is_local' => Notice::REMOTE,
- 'url' => $sourceUrl,
- 'uri' => $sourceUri,
- 'rendered' => $rendered,
- 'replies' => array(),
- 'groups' => array(),
- 'peopletags' => array(),
- 'tags' => array(),
- 'urls' => array());
-
- // Check for optional attributes...
-
- if (!empty($activity->time)) {
- $options['created'] = common_sql_date($activity->time);
- }
-
- if ($activity->context) {
- // TODO: context->attention
- list($options['groups'], $options['replies'])
- = self::filterAttention($profile, $activity->context->attention);
-
- // Maintain direct reply associations
- // @todo FIXME: What about conversation ID?
- if (!empty($activity->context->replyToID)) {
- $orig = Notice::getKV('uri', $activity->context->replyToID);
- if ($orig instanceof Notice) {
- $options['reply_to'] = $orig->id;
- }
- }
- if (!empty($activity->context->conversation)) {
- // we store the URI here, Notice class can look it up later
- $options['conversation'] = $activity->context->conversation;
- }
-
- $location = $activity->context->location;
- if ($location) {
- $options['lat'] = $location->lat;
- $options['lon'] = $location->lon;
- if ($location->location_id) {
- $options['location_ns'] = $location->location_ns;
- $options['location_id'] = $location->location_id;
- }
- }
- }
-
- if ($this->isPeopletag()) {
- $options['peopletags'][] = $this->localPeopletag();
- }
-
- // Atom categories <-> hashtags
- foreach ($activity->categories as $cat) {
- if ($cat->term) {
- $term = common_canonical_tag($cat->term);
- if ($term) {
- $options['tags'][] = $term;
- }
- }
- }
+ $actor = ActivityUtils::checkAuthorship($activity, $this->localProfile());
- // Atom enclosures -> attachment URLs
- foreach ($activity->enclosures as $href) {
- // @todo FIXME: Save these locally or....?
- $options['urls'][] = $href;
- }
+ $options = array('is_local' => Notice::REMOTE);
try {
- $saved = Notice::saveNew($profile->id,
- $content,
- 'ostatus',
- $options);
- if ($saved instanceof Notice) {
- Ostatus_source::saveNew($saved, $this, $method);
- if ($attachment instanceof File) {
- File_to_post::processNew($attachment, $saved);
- }
- }
+ $stored = Notice::saveActivity($activity, $actor, $options);
+ Ostatus_source::saveNew($stored, $this, $method);
} catch (Exception $e) {
common_log(LOG_ERR, "OStatus save of remote message $sourceUri failed: " . $e->getMessage());
throw $e;
}
- common_log(LOG_INFO, "OStatus saved remote message $sourceUri as notice id $saved->id");
- return $saved;
+ return $stored;
}
/**