]> git.mxchange.org Git - quix0rs-gnu-social.git/blobdiff - plugins/Share/SharePlugin.php
Merge remote-tracking branch 'upstream/master' into social-master
[quix0rs-gnu-social.git] / plugins / Share / SharePlugin.php
index 18143d5a637e1aa18d3f6b39c6beea4e1dec820e..84174a0440895d597e657d99f014b04bf66e573b 100644 (file)
@@ -40,6 +40,14 @@ class SharePlugin extends ActivityVerbHandlerPlugin
         return array(ActivityVerb::SHARE);
     }
 
+    // Share is a bit special and $act->objects[0] should be an Activity
+    // instead of ActivityObject! Therefore also $act->objects[0]->type is not set.
+    public function isMyActivity(Activity $act) {
+        return (count($act->objects) == 1
+            && ($act->objects[0] instanceof Activity)
+            && $this->isMyVerb($act->verb));
+    }
+
     public function onRouterInitialized(URLMapper $m)
     {
         // Web UI actions
@@ -98,34 +106,35 @@ class SharePlugin extends ActivityVerbHandlerPlugin
             throw new ClientException(_m('Shared activity does not have an id'));
         }
 
-        // First check if we have the shared activity. This has to be done first, because
-        // we can't use these functions to "ensureActivityObjectProfile" of a local user,
-        // who might be the creator of the shared activity in question.
-        $sharedNotice = Notice::getKV('uri', $sharedId);
-        if (!$sharedNotice instanceof Notice) {
+        try {
+            // First check if we have the shared activity. This has to be done first, because
+            // we can't use these functions to "ensureActivityObjectProfile" of a local user,
+            // who might be the creator of the shared activity in question.
+            $sharedNotice = Notice::getByUri($sharedUri);
+        } catch (NoResultException $e) {
             // If no locally stored notice is found, process it!
             // TODO: Remember to check Deleted_notice!
             // TODO: If a post is shared that we can't retrieve - what to do?
-            try {
-                $other = self::ensureActivityObjectProfile($shared->actor);
-                $sharedNotice = $other->processActivity($shared, $method);
-                if (!$sharedNotice instanceof Notice) {
-                    // And if we apparently can't get the shared notice, we'll abort the whole thing.
-                    // TRANS: Client exception thrown when saving an activity share fails.
-                    // TRANS: %s is a share ID.
-                    throw new ClientException(sprintf(_m('Failed to save activity %s.'), $sharedId));
-                }
-            } catch (FeedSubException $e) {
-                // Remote feed could not be found or verified, should we
-                // transform this into an "RT @user Blah, blah, blah..."?
-                common_log(LOG_INFO, __METHOD__ . ' got a ' . get_class($e) . ': ' . $e->getMessage());
-                return null;
-            }
+            $other = Ostatus_profile::ensureActivityObjectProfile($shared->actor);
+            $sharedNotice = Notice::saveActivity($shared, $other->localProfile(), array('source'=>'share'));
+        } catch (FeedSubException $e) {
+            // Remote feed could not be found or verified, should we
+            // transform this into an "RT @user Blah, blah, blah..."?
+            common_log(LOG_INFO, __METHOD__ . ' got a ' . get_class($e) . ': ' . $e->getMessage());
+            return false;
         }
 
+        // Setting this here because when the algorithm gets back to
+        // Notice::saveActivity it will update the Notice object.
+        $stored->repeat_of = $sharedNotice->getID();
+        $stored->conversation = $sharedNotice->conversation;
+        $stored->object_type = ActivityUtils::resolveUri(ActivityObject::ACTIVITY, true);
+
         // We don't have to save a repeat in a separate table, we can
         // find repeats by just looking at the notice.repeat_of field.
 
+        // By returning true here instead of something that evaluates
+        // to false, we show that we have processed everything properly.
         return true;
     }
 
@@ -146,7 +155,7 @@ class SharePlugin extends ActivityVerbHandlerPlugin
     public function extendActivity(Notice $stored, Activity $act, Profile $scoped=null)
     {
         // TODO: How to handle repeats of deleted notices?
-        $target = Notice::getById($stored->repeat_of);
+        $target = Notice::getByID($stored->repeat_of);
         // TRANS: A repeat activity's title. %1$s is repeater's nickname
         //        and %2$s is the repeated user's nickname.
         $act->title = sprintf(_('%1$s repeated a notice by %2$s'),
@@ -155,129 +164,95 @@ class SharePlugin extends ActivityVerbHandlerPlugin
         $act->objects[] = $target->asActivity($scoped);
     }
 
-    public function activityObjectFromNotice(Notice $notice)
+    public function activityObjectFromNotice(Notice $stored)
     {
         // Repeat is a little bit special. As it's an activity, our
         // ActivityObject is instead turned into an Activity
         $object          = new Activity();
+        $object->actor   = $stored->getProfile()->asActivityObject();
         $object->verb    = ActivityVerb::SHARE;
-        $object->type    = $notice->object_type;
-        $object->title   = sprintf(_('%1$s repeated a notice by %2$s'),
-                              $object->getProfile()->getNickname(),
-                              $target->getProfile()->getNickname());
-        $object->content = $notice->rendered;
+        $object->content = $stored->rendered;
+        $this->extendActivity($stored, $object);
+
         return $object;
     }
 
     public function deleteRelated(Notice $notice)
     {
-        try {
-            $fave = Fave::fromStored($notice);
-            $fave->delete();
-        } catch (NoResultException $e) {
-            // Cool, no problem. We wanted to get rid of it anyway.
-        }
+        // No action needed as we don't have a separate table for share objects.
+        return true;
     }
 
-    // API stuff
+    // Layout stuff
 
     /**
-     * Typically just used to fill out Twitter-compatible API status data.
+     * show a link to the author of repeat
      *
-     * FIXME: Make all the calls before this end up with a Notice instead of ArrayWrapper please...
+     * FIXME: Some repeat stuff still in lib/noticelistitem.php! ($nli->repeat etc.)
      */
-    public function onNoticeSimpleStatusArray($notice, array &$status, Profile $scoped=null, array $args=array())
-    {
-        if ($scoped instanceof Profile) {
-            $status['favorited'] = Fave::existsForProfile($notice, $scoped);
-        } else {
-            $status['favorited'] = false;
-        }
-        return true;
-    }
-
-    public function onTwitterUserArray(Profile $profile, array &$userdata, Profile $scoped=null, array $args=array())
+    public function onEndShowNoticeInfo(NoticeListItem $nli)
     {
-        $userdata['favourites_count'] = Fave::countByProfile($profile);
-    }
+        if (!empty($nli->repeat)) {
+            $repeater = $nli->repeat->getProfile();
 
-    /**
-     * Typically just used to fill out StatusNet specific data in API calls in the referenced $info array.
-     */
-    public function onStatusNetApiNoticeInfo(Notice $notice, array &$info, Profile $scoped=null, array $args=array())
-    {
-        if ($scoped instanceof Profile) {
-            $info['favorite'] = Fave::existsForProfile($notice, $scoped) ? 'true' : 'false';
-        }
-        return true;
-    }
+            $attrs = array('href' => $repeater->getUrl(),
+                           'class' => 'h-card p-author',
+                           'title' => $repeater->getFancyName());
 
-    public function onNoticeDeleteRelated(Notice $notice)
-    {
-        parent::onNoticeDeleteRelated($notice);
+            $nli->out->elementStart('span', 'repeat');
 
-        // The below algorithm is because we want to delete fave
-        // activities on any notice which _has_ faves, and not as
-        // in the parent function only ones that _are_ faves.
+            // TRANS: Addition in notice list item if notice was repeated. Followed by a span with a nickname.
+            $nli->out->raw(_('Repeated by').' ');
 
-        $fave = new Fave();
-        $fave->notice_id = $notice->id;
+            $nli->out->element('a', $attrs, $repeater->getNickname());
 
-        if ($fave->find()) {
-            while ($fave->fetch()) {
-                $fave->delete();
-            }
+            $nli->out->elementEnd('span');
         }
-
-        $fave->free();
     }
 
-    public function onProfileDeleteRelated(Profile $profile, array &$related)
+    public function onEndShowThreadedNoticeTailItems(NoticeListItem $nli, Notice $notice, &$threadActive)
     {
-        $fave = new Fave();
-        $fave->user_id = $profile->id;
-        $fave->delete();    // Will perform a DELETE matching "user_id = {$user->id}"
-        $fave->free();
-
-        Fave::blowCacheForProfileId($profile->id);
-        return true;
-    }
-
-    public function onStartNoticeListPrefill(array &$notices, array $notice_ids, Profile $scoped=null)
-    {
-        // prefill array of objects, before pluginfication it was Notice::fillFaves($notices)
-        Fave::fillFaves($notice_ids);
-
-        // DB caching
-        if ($scoped instanceof Profile) {
-            Fave::pivotGet('notice_id', $notice_ids, array('user_id' => $scoped->id));
+        if ($nli instanceof ThreadedNoticeListSubItem) {
+            // The sub-items are replies to a conversation, thus we use different HTML elements etc.
+            $item = new ThreadedNoticeListInlineRepeatsItem($notice, $nli->out);
+        } else {
+            $item = new ThreadedNoticeListRepeatsItem($notice, $nli->out);
         }
+        $threadActive = $item->show() || $threadActive;
+        return true;
     }
 
     /**
-     * show the "favorite" form in the notice options element
+     * show the "repeat" form in the notice options element
      * FIXME: Don't let a NoticeListItemAdapter slip in here (or extend that from NoticeListItem)
      *
      * @return void
      */
-    public function onStartShowNoticeOptionItems($nli)
+    public function onEndShowNoticeOptionItems($nli)
     {
-        if (Event::handle('StartShowFaveForm', array($nli))) {
+        // FIXME: Use bitmasks (but be aware that PUBLIC_SCOPE is 0!)
+        // Also: AHHH, $scope and $scoped are scarily similar looking.
+        $scope = $nli->notice->getScope();
+        if ($scope === Notice::PUBLIC_SCOPE || $scope === Notice::SITE_SCOPE) {
             $scoped = Profile::current();
-            if ($scoped instanceof Profile) {
-                if (Fave::existsForProfile($nli->notice, $scoped)) {
-                    $disfavor = new DisfavorForm($nli->out, $nli->notice);
-                    $disfavor->show();
+            if ($scoped instanceof Profile &&
+                    $scoped->getID() !== $nli->notice->getProfile()->getID()) {
+
+                if ($scoped->hasRepeated($nli->notice)) {
+                    $nli->out->element('span', array('class' => 'repeated',
+                                                      // TRANS: Title for repeat form status in notice list when a notice has been repeated.
+                                                      'title' => _('Notice repeated.')),
+                                        // TRANS: Repeat form status in notice list when a notice has been repeated.
+                                        _('Repeated'));
                 } else {
-                    $favor = new FavorForm($nli->out, $nli->notice);
-                    $favor->show();
+                    $repeat = new RepeatForm($nli->out, $nli->notice);
+                    $repeat->show();
                 }
             }
-            Event::handle('EndShowFaveForm', array($nli));
         }
     }
 
-    public function showNoticeListItem(NoticeListItem $nli)
+    protected function showNoticeListItem(NoticeListItem $nli)
     {
         // pass
     }
@@ -290,55 +265,38 @@ class SharePlugin extends ActivityVerbHandlerPlugin
         // pass
     }
 
-    public function onAppendUserActivityStreamObjects(UserActivityStream $uas, array &$objs)
+    // API stuff
+
+    /**
+     * Typically just used to fill out Twitter-compatible API status data.
+     *
+     * FIXME: Make all the calls before this end up with a Notice instead of ArrayWrapper please...
+     */
+    public function onNoticeSimpleStatusArray($notice, array &$status, Profile $scoped=null, array $args=array())
     {
-        $fave = new Fave();
-        $fave->user_id = $uas->getUser()->id;
+        $status['repeated'] = $scoped instanceof Profile
+                            ? $scoped->hasRepeated($notice)
+                            : false;
 
-        if (!empty($uas->after)) {
-            $fave->whereAdd("modified > '" . common_sql_date($uas->after) . "'");
+        if ($status['repeated'] === true) {
+            // Qvitter API wants the "repeated_id" value set too.
+            $repeated = Notice::pkeyGet(array('profile_id' => $scoped->getID(),
+                                              'repeat_of' => $notice->getID(),
+                                              'verb' => ActivityVerb::SHARE));
+            $status['repeated_id'] = $repeated->getID();
         }
-
-        if ($fave->find()) {
-            while ($fave->fetch()) {
-                $objs[] = clone($fave);
-            }
-        }
-
-        return true;
     }
 
-    public function onStartShowThreadedNoticeTailItems(NoticeListItem $nli, Notice $notice, &$threadActive)
+    public function onTwitterUserArray(Profile $profile, array &$userdata, Profile $scoped=null, array $args=array())
     {
-        if ($nli instanceof ThreadedNoticeListSubItem) {
-            // The sub-items are replies to a conversation, thus we use different HTML elements etc.
-            $item = new ThreadedNoticeListInlineFavesItem($notice, $nli->out);
-        } else {
-            $item = new ThreadedNoticeListFavesItem($notice, $nli->out);
-        }
-        $threadActive = $item->show() || $threadActive;
-        return true;
+        $userdata['favourites_count'] = Fave::countByProfile($profile);
     }
 
-    public function onEndFavorNotice(Profile $actor, Notice $target)
-    {
-        try {
-            $notice_author = $target->getProfile();
-            // Don't notify ourselves of our own favorite on our own notice,
-            // or if it's a remote user (since we don't know their email addresses etc.)
-            if ($notice_author->id == $actor->id || !$notice_author->isLocal()) {
-                return true;
-            }
-            $local_user = $notice_author->getUser();
-            mail_notify_fave($local_user, $actor, $target);
-        } catch (Exception $e) {
-            // Mm'kay, probably not a local user. Let's skip this favor notification.
-        }
-    }
+    // Command stuff
 
     /**
-     * EndInterpretCommand for FavoritePlugin will handle the 'fav' command
-     * using the class FavCommand.
+     * EndInterpretCommand for RepeatPlugin will handle the 'repeat' command
+     * using the class RepeatCommand.
      *
      * @param string  $cmd     Command being run
      * @param string  $arg     Rest of the message (including address)
@@ -367,10 +325,10 @@ class SharePlugin extends ActivityVerbHandlerPlugin
 
     public function onHelpCommandMessages(HelpCommand $help, array &$commands)
     {
-        // TRANS: Help message for IM/SMS command "fav <nickname>".
-        $commands['fav <nickname>'] = _m('COMMANDHELP', "add user's last notice as a 'fave'");
-        // TRANS: Help message for IM/SMS command "fav #<notice_id>".
-        $commands['fav #<notice_id>'] = _m('COMMANDHELP', "add notice with the given id as a 'fave'");
+        // TRANS: Help message for IM/SMS command "repeat #<notice_id>".
+        $commands['repeat #<notice_id>'] = _m('COMMANDHELP', "repeat a notice with a given id");
+        // TRANS: Help message for IM/SMS command "repeat <nickname>".
+        $commands['repeat <nickname>']   = _m('COMMANDHELP', "repeat the last notice from user");
     }
 
     /**
@@ -381,130 +339,24 @@ class SharePlugin extends ActivityVerbHandlerPlugin
         $supported = $supported || $cmd instanceof RepeatCommand;
     }
 
-    // Form stuff (settings etc.)
-
-    public function onEndEmailFormData(Action $action, Profile $scoped)
-    {
-        $emailfave = $scoped->getConfigPref('email', 'notify_fave') ? 1 : 0;
-
-        $action->elementStart('li');
-        $action->checkbox('email-notify_fave',
-                        // TRANS: Checkbox label in e-mail preferences form.
-                        _('Send me email when someone adds my notice as a favorite.'),
-                        $emailfave);
-        $action->elementEnd('li');
-
-        return true;
-    }
-
-    public function onStartEmailSaveForm(Action $action, Profile $scoped)
-    {
-        $emailfave = $action->booleanintstring('email-notify_fave');
-        try {
-            if ($emailfave == $scoped->getPref('email', 'notify_fave')) {
-                // No need to update setting
-                return true;
-            }
-        } catch (NoResultException $e) {
-            // Apparently there's no previously stored setting, then continue to save it as it is now.
-        }
-
-        $scoped->setPref('email', 'notify_fave', $emailfave);
-
-        return true;
-    }
-
-    // Layout stuff
-
-    public function onEndPersonalGroupNav(Menu $menu, Profile $target, Profile $scoped=null)
-    {
-        $menu->out->menuItem(common_local_url('showfavorites', array('nickname' => $target->getNickname())),
-                             // TRANS: Menu item in personal group navigation menu.
-                             _m('MENU','Favorites'),
-                             // @todo i18n FIXME: Need to make this two messages.
-                             // TRANS: Menu item title in personal group navigation menu.
-                             // TRANS: %s is a username.
-                             sprintf(_('%s\'s favorite notices'), $target->getBestName()),
-                             $scoped instanceof Profile && $target->id === $scoped->id && $menu->actionName =='showfavorites',
-                            'nav_timeline_favorites');
-    }
-
-    public function onEndPublicGroupNav(Menu $menu)
-    {
-        if (!common_config('singleuser', 'enabled')) {
-            // TRANS: Menu item in search group navigation panel.
-            $menu->out->menuItem(common_local_url('favorited'), _m('MENU','Popular'),
-                                 // TRANS: Menu item title in search group navigation panel.
-                                 _('Popular notices'), $menu->actionName == 'favorited', 'nav_timeline_favorited');
-        }
-    }
-
-    public function onEndShowSections(Action $action)
-    {
-        if (!$action->isAction(array('all', 'public'))) {
-            return true;
-        }
-
-        if (!common_config('performance', 'high')) {
-            $section = new PopularNoticeSection($action, $action->getScoped());
-            $section->show();
-        }
-    }
-
     protected function getActionTitle(ManagedAction $action, $verb, Notice $target, Profile $scoped)
     {
-        return Fave::existsForProfile($target, $scoped)
-                // TRANS: Page/dialog box title when a notice is marked as favorite already
-                ? _m('TITLE', 'Unmark notice as favorite')
-                // TRANS: Page/dialog box title when a notice is not marked as favorite
-                : _m('TITLE', 'Mark notice as favorite');
+        // return page title
     }
 
     protected function doActionPreparation(ManagedAction $action, $verb, Notice $target, Profile $scoped)
     {
-        if ($action->isPost()) {
-            // The below tests are only for presenting to the user. POSTs which inflict
-            // duplicate favorite entries are handled with AlreadyFulfilledException. 
-            return false;
-        }
-
-        $exists = Fave::existsForProfile($target, $scoped);
-        $expected_verb = $exists ? ActivityVerb::UNFAVORITE : ActivityVerb::FAVORITE;
-
-        switch (true) {
-        case $exists && ActivityUtils::compareTypes($verb, array(ActivityVerb::FAVORITE, ActivityVerb::LIKE)):
-        case !$exists && ActivityUtils::compareTypes($verb, array(ActivityVerb::UNFAVORITE, ActivityVerb::UNLIKE)):
-            common_redirect(common_local_url('activityverb',
-                                array('id'   => $target->getID(),
-                                      'verb' => ActivityUtils::resolveUri($expected_verb, true))));
-            break;
-        default:
-            // No need to redirect as we are on the correct action already.
-        }
-
-        return false;
+        // prepare Action?
     }
 
     protected function doActionPost(ManagedAction $action, $verb, Notice $target, Profile $scoped)
     {
-        switch (true) {
-        case ActivityUtils::compareTypes($verb, array(ActivityVerb::FAVORITE, ActivityVerb::LIKE)):
-            Fave::addNew($scoped, $target);
-            break;
-        case ActivityUtils::compareTypes($verb, array(ActivityVerb::UNFAVORITE, ActivityVerb::UNLIKE)):
-            Fave::removeEntry($scoped, $target);
-            break;
-        default:
-            throw new ServerException('ActivityVerb POST not handled by plugin that was supposed to do it.');
-        }
-        return false;
+        // handle repeat POST
     }
 
     protected function getActivityForm(ManagedAction $action, $verb, Notice $target, Profile $scoped)
     {
-        return Fave::existsForProfile($target, $scoped)
-                ? new DisfavorForm($action, $target)
-                : new FavorForm($action, $target);
+        return new RepeatForm($action, $target);
     }
 
     public function onPluginVersion(array &$versions)