]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
checkAuthorship events, Ostatus_profile rewrite to handle it
authorMikael Nordfeldth <mmn@hethane.se>
Tue, 1 Jul 2014 13:48:34 +0000 (15:48 +0200)
committerMikael Nordfeldth <mmn@hethane.se>
Wed, 2 Jul 2014 09:38:45 +0000 (11:38 +0200)
Lost dependency of OStatus plugin for lib/microappplugin.php, whoo!

also noting which plugins should be upgraded to new saveActivity support.

Favorite plugin won't work with the new system just yet, it doesn't have
the necessary functions to extract activity objects, but that's coming
in the next (few) commits.

lib/activityhandlerplugin.php
lib/activityutils.php
plugins/Blog/BlogPlugin.php
plugins/Bookmark/BookmarkPlugin.php
plugins/GNUsocialPhoto/GNUsocialPhotoPlugin.php
plugins/GNUsocialVideo/GNUsocialVideoPlugin.php
plugins/OStatus/OStatusPlugin.php
plugins/OStatus/classes/Ostatus_profile.php
plugins/Poll/PollPlugin.php
plugins/QnA/QnAPlugin.php

index 6e9e23422edbd2d7229d9edc75626d43dda1d27a..c8a46ae5efc4b55d9523a9bf387dc6b7c66adc97 100644 (file)
@@ -109,19 +109,8 @@ abstract class ActivityHandlerPlugin extends Plugin
      * gets to figure out how to actually save it into a notice
      * and any additional data structures you require.
      *
-     * This will handle things received via AtomPub, OStatus
-     * (PuSH and Salmon transports), or ActivityStreams-based
-     * backup/restore of account data.
-     *
-     * You should be able to accept as input the output from your
-     * $this->activityObjectFromNotice(). Where applicable, try to
-     * use existing ActivityStreams structures and object types,
-     * and be liberal in accepting input from what might be other
-     * compatible apps.
-     *
-     * All micro-app classes must override this method.
-     *
-     * @fixme are there any standard options?
+     * This function is deprecated and in the future, Notice::saveActivity
+     * should be called from onStartHandleFeedEntryWithProfile in this class.
      *
      * @param Activity $activity
      * @param Profile $actor
@@ -129,7 +118,36 @@ abstract class ActivityHandlerPlugin extends Plugin
      *
      * @return Notice the resulting notice
      */
-    abstract function saveNoticeFromActivity(Activity $activity, Profile $actor, array $options=array());
+    public function saveNoticeFromActivity(Activity $activity, Profile $actor, array $options=array())
+    {
+        // Any plugin which has not implemented saveObjectFromActivity _must_
+        // override this function (which will be deleted when all plugins are migrated).
+
+        if (isset($this->oldSaveNew)) {
+            throw new ServerException('A function has been called for new saveActivity functionality, but is still set with an oldSaveNew configuration');
+        }
+
+        return Notice::saveActivity($activity, $actor, $options);
+    }
+
+    /*
+     * This usually gets called from Notice::saveActivity after a Notice object has been created,
+     * so it contains a proper id and a uri for the object to be saved.
+     */
+    public function onStoreActivityObject(Activity $act, Notice $stored, array $options=array(), &$object) {
+        // $this->oldSaveNew is there during a migration period of plugins, to start using
+        // Notice::saveActivity instead of Notice::saveNew
+        if (!$this->isMyActivity($act) || isset($this->oldSaveNew)) {
+            return true;
+        }
+        $object = $this->saveObjectFromActivity($act, $stored, $options);
+        try {
+            $act->context->attention = array_merge($act->context->attention, $object->getAttentionArray());
+        } catch (Exception $e) {
+            common_debug('WARNING: Could not get attention list from object '.get_class($object).'!');
+        }
+        return false;
+    }
 
     /**
      * Given an existing Notice object, your plugin gets to
@@ -242,22 +260,18 @@ abstract class ActivityHandlerPlugin extends Plugin
      * Handle a posted object from PuSH
      *
      * @param Activity        $activity activity to handle
-     * @param Ostatus_profile $oprofile Profile for the feed
+     * @param Profile         $actor Profile for the feed
      *
      * @return boolean hook value
      */
-    function onStartHandleFeedEntryWithProfile(Activity $activity, $oprofile, &$notice)
+    function onStartHandleFeedEntryWithProfile(Activity $activity, Profile $profile, &$notice)
     {
         if (!$this->isMyActivity($activity)) {
             return true;
         }
 
-        $actor = $oprofile->checkAuthorship($activity);
-
-        if (!$actor instanceof Ostatus_profile) {
-            // TRANS: Client exception thrown when no author for an activity was found.
-            throw new ClientException(_('Cannot get author for activity.'));
-        }
+        // We are guaranteed to get a Profile back from checkAuthorship (or it throws an exception)
+        $profile = ActivityUtils::checkAuthorship($activity, $profile);
 
         $object = $activity->objects[0];
 
@@ -266,8 +280,7 @@ abstract class ActivityHandlerPlugin extends Plugin
                          'is_local' => Notice::REMOTE,
                          'source' => 'ostatus');
 
-        // $actor is an ostatus_profile
-        $notice = $this->saveNoticeFromActivity($activity, $actor->localProfile(), $options);
+        $notice = $this->saveNoticeFromActivity($activity, $profile, $options);
 
         return false;
     }
index 07d8a86141a9456458bc73043cd753af40dd056b..e9d5d1fba5711adf8adbb33670c669a3e3d81048 100644 (file)
@@ -402,4 +402,35 @@ class ActivityUtils
         }
         return $object;
     }
+
+    // Check authorship by supplying a Profile as a default and letting plugins
+    // set it to something else if the activity's author is actually someone
+    // else (like with a group or peopletag feed as handled in OStatus).
+    //
+    // NOTE: Returned is not necessarily the supplied profile! For example,
+    // the "feed author" may be a group, but the "activity author" is a person!
+    static function checkAuthorship(Activity $activity, Profile $profile)
+    {
+        if (Event::handle('CheckActivityAuthorship', array($activity, &$profile))) {
+            // if (empty($activity->actor)), then we generated this Activity ourselves and can trust $profile
+
+            $actor_uri = $profile->getUri();
+
+            if (!in_array($actor_uri, array($activity->actor->id, $activity->actor->link))) {
+                // A mismatch between our locally stored URI and the supplied author?
+                // Probably not more than a blog feed or something (with multiple authors or so)
+                // but log it for future inspection.
+                common_log(LOG_WARNING, "Got an actor '{$activity->actor->title}' ({$activity->actor->id}) on single-user feed for " . $actor_uri);
+            } elseif (empty($activity->actor->id)) {
+                // Plain <author> without ActivityStreams actor info.
+                // We'll just ignore this info for now and save the update under the feed's identity.
+            }
+        }
+
+        if (!$profile instanceof Profile) {
+            throw new ServerException('Could not get an author Profile for activity');
+        }
+
+        return $profile;
+    }
 }
index 4ff904db0b4c07735d5c78cc8a85f72db290f297..c192909d6792396d0248b36662e6fe94561d4bf9 100644 (file)
@@ -50,6 +50,9 @@ if (!defined('STATUSNET')) {
 
 class BlogPlugin extends MicroAppPlugin
 {
+
+    var $oldSaveNew = true;
+
     /**
      * Database schema setup
      *
index 1093b435aa39534c8d4195cedee35aaff6e9d67c..0e3db1ed829c15fc161867eea069db59ab2ccde8 100644 (file)
@@ -48,6 +48,8 @@ class BookmarkPlugin extends MicroAppPlugin
     const VERSION         = '0.1';
     const IMPORTDELICIOUS = 'BookmarkPlugin:IMPORTDELICIOUS';
 
+    var $oldSaveNew = true;
+
     /**
      * Authorization for importing delicious bookmarks
      *
index 7b5c73d09fc3803d4cba16ac45f760f014264e50..4f4f4af827486f76b30528bc43d9fd731bb37172 100644 (file)
@@ -33,6 +33,8 @@ if (!defined('STATUSNET')) {
 class GNUsocialPhotoPlugin extends MicroAppPlugin
 {
 
+    var $oldSaveNew = true;
+
     function onCheckSchema()
     {
         $schema = Schema::get();
index ae44ee7a2dca3904699e1d589f58337061958a76..b78ed84c42e29ce6472b0c433e7cdcdd0db29b8d 100644 (file)
@@ -33,6 +33,8 @@ if (!defined('STATUSNET')) {
 class GNUsocialVideoPlugin extends MicroAppPlugin
 {
 
+    var $oldSaveNew = true;
+
     function onCheckSchema()
     {
         $schema = Schema::get();
index f799b4033d9829aff70c85d0ff898d5fe99d20da..cebf5597d31c0c4f1154d2fe0081180ed62f1f86 100644 (file)
@@ -1365,4 +1365,19 @@ class OStatusPlugin extends Plugin
     {
         list($mentions, $groups) = Ostatus_profile::filterAttention($actor, $attention_uris);
     }
+
+    // FIXME: Maybe this shouldn't be so authoritative that it breaks other remote profile lookups?
+    static public function onCheckActivityAuthorship(Activity $activity, Profile &$profile)
+    {
+        try {
+            $oprofile = Ostatus_profile::getFromProfile($profile);
+            $oprofile = $oprofile->checkAuthorship($activity);
+            $profile = $oprofile->localProfile();
+        } catch (Exception $e) {
+            common_log(LOG_ERR, 'Could not get a profile or check authorship ('.get_class($e).': "'.$e->getMessage().'")');
+            $profile = null;
+            return false;
+        }
+        return true;
+    }
 }
index 3d550872d625e8874594bc39b5ea84887320886b..0629d73a7524e95f26faa8c8eb5c5bf5ff626c4c 100644 (file)
@@ -478,7 +478,7 @@ class Ostatus_profile extends Managed_DataObject
 
         // The "WithProfile" events were added later.
 
-        if (Event::handle('StartHandleFeedEntryWithProfile', array($activity, $this, &$notice)) &&
+        if (Event::handle('StartHandleFeedEntryWithProfile', array($activity, $this->localProfile(), &$notice)) &&
             Event::handle('StartHandleFeedEntry', array($activity))) {
 
             switch ($activity->verb) {
@@ -516,10 +516,9 @@ class Ostatus_profile extends Managed_DataObject
     {
         $notice = null;
 
-        $oprofile = $this->checkAuthorship($activity);
-
-        if (!$oprofile instanceof Ostatus_profile) {
-            common_log(LOG_INFO, "No author matched share activity");
+        try {
+            $profile = ActivityUtils::checkAuthorship($activity, $this->localProfile());
+        } catch (ServerException $e) {
             return null;
         }
 
@@ -670,7 +669,7 @@ class Ostatus_profile extends Managed_DataObject
         if ($activity->context) {
             // TODO: context->attention
             list($options['groups'], $options['replies'])
-                = self::filterAttention($oprofile->localProfile(), $activity->context->attention);
+                = self::filterAttention($profile, $activity->context->attention);
 
             // Maintain direct reply associations
             // @todo FIXME: What about conversation ID?
@@ -713,7 +712,7 @@ class Ostatus_profile extends Managed_DataObject
             $options['urls'][] = $href;
         }
 
-        $notice = Notice::saveNew($oprofile->profile_id,
+        $notice = Notice::saveNew($profile->id,
                                   $content,
                                   'ostatus',
                                   $options);
@@ -732,11 +731,7 @@ class Ostatus_profile extends Managed_DataObject
     {
         $notice = null;
 
-        $oprofile = $this->checkAuthorship($activity);
-
-        if (!$oprofile instanceof Ostatus_profile) {
-            return null;
-        }
+        $profile = $this->checkAuthorship($activity, $this->localProfile());
 
         // It's not always an ActivityObject::NOTE, but... let's just say it is.
 
@@ -839,7 +834,7 @@ class Ostatus_profile extends Managed_DataObject
         if ($activity->context) {
             // TODO: context->attention
             list($options['groups'], $options['replies'])
-                = self::filterAttention($oprofile->localProfile(), $activity->context->attention);
+                = self::filterAttention($profile, $activity->context->attention);
 
             // Maintain direct reply associations
             // @todo FIXME: What about conversation ID?
@@ -882,7 +877,7 @@ class Ostatus_profile extends Managed_DataObject
         }
 
         try {
-            $saved = Notice::saveNew($oprofile->profile_id,
+            $saved = Notice::saveNew($profile->id,
                                      $content,
                                      'ostatus',
                                      $options);
@@ -1077,17 +1072,17 @@ class Ostatus_profile extends Managed_DataObject
             return null;
         }
 
-        // Is it a known Ostatus profile?
-        $oprofile = Ostatus_profile::getKV('profile_id', $profile->id);
-        if ($oprofile instanceof Ostatus_profile) {
+        try {
+            $oprofile = self::getFromProfile($profile);
+            // We found the profile, return it!
             return $oprofile;
-        }
-
-        // Is it a local user?
-        $user = User::getKV('id', $profile->id);
-        if ($user instanceof User) {
-            // @todo i18n FIXME: use sprintf and add i18n (?)
-            throw new OStatusShadowException($profile, "'$profile_url' is the profile for local user '{$user->nickname}'.");
+        } catch (NoResultException $e) {
+            // Could not find an OStatus profile, is it instead a local user?
+            $user = User::getKV('id', $profile->id);
+            if ($user instanceof User) {
+                // @todo i18n FIXME: use sprintf and add i18n (?)
+                throw new OStatusShadowException($profile, "'$profile_url' is the profile for local user '{$user->nickname}'.");
+            }
         }
 
         // Continue discovery; it's a remote profile
@@ -1097,6 +1092,16 @@ class Ostatus_profile extends Managed_DataObject
         return null;
     }
 
+    static function getFromProfile(Profile $profile)
+    {
+        $oprofile = new Ostatus_profile();
+        $oprofile->profile_id = $profile->id;
+        if (!$oprofile->find(true)) {
+            throw new NoResultException($oprofile);
+        }
+        return $oprofile;
+    }
+
     /**
      * Look up and if necessary create an Ostatus_profile for remote entity
      * with the given update feed. This should never return null -- you will
@@ -2130,7 +2135,7 @@ class Ostatus_profile extends Managed_DataObject
         return $oprofile;
     }
 
-    function checkAuthorship($activity)
+    public function checkAuthorship(Activity $activity)
     {
         if ($this->isGroup() || $this->isPeopletag()) {
             // A group or propletag feed will contain posts from multiple authors.
@@ -2165,7 +2170,7 @@ class Ostatus_profile extends Managed_DataObject
             $oprofile = $this;
         }
 
-        return $oprofile;
+        return $oprofile->localProfile();
     }
 }
 
index de882fdf741eb34572365615aef01556ae9e328e..d52e69aabe6899a7076d77a9d1fc128e206073c0 100644 (file)
@@ -51,6 +51,8 @@ class PollPlugin extends MicroAppPlugin
     const POLL_OBJECT          = 'http://activityschema.org/object/poll';
     const POLL_RESPONSE_OBJECT = 'http://activityschema.org/object/poll-response';
 
+    var $oldSaveNew = true;
+
     /**
      * Database schema setup
      *
index beae1cb6b20a0381fbca794d2ad0f636a42bbbaf..6542e95f98f08b8ab72d7485e1378501b86b4a3a 100644 (file)
@@ -46,6 +46,9 @@ if (!defined('STATUSNET')) {
  */
 class QnAPlugin extends MicroAppPlugin
 {
+
+    var $oldSaveNew = true;
+
     /**
      * Set up our tables (question and answer)
      *