]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Merge branch '0.9.x' of git@gitorious.org:statusnet/mainline into 0.9.x
authorEvan Prodromou <evan@status.net>
Mon, 14 Dec 2009 21:41:42 +0000 (16:41 -0500)
committerEvan Prodromou <evan@status.net>
Mon, 14 Dec 2009 21:41:42 +0000 (16:41 -0500)
actions/apitimelinefriends.php
actions/apitimelinehome.php [new file with mode: 0644]
classes/Notice.php
classes/User.php
lib/api.php
lib/router.php

index 09ba7a9691d9ef0bb0aa37147d9a402cdb330178..9ec7447e64d317593c87d5bb81a083e5ceaf29bc 100644 (file)
@@ -116,12 +116,12 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
         $taguribase = common_config('integration', 'taguri');
         $id         = "tag:$taguribase:FriendsTimeline:" . $this->user->id;
         $link       = common_local_url(
-            'all', array('nickname' => $this->user->nickname)
-        );
+                                       'all', array('nickname' => $this->user->nickname)
+                                       );
         $subtitle   = sprintf(
-            _('Updates from %1$s and friends on %2$s!'),
-            $this->user->nickname, $sitename
-        );
+                              _('Updates from %1$s and friends on %2$s!'),
+                              $this->user->nickname, $sitename
+                              );
         $logo       = ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_PROFILE_SIZE);
 
         switch($this->format) {
@@ -137,17 +137,17 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
 
             if (isset($target_id)) {
                 $selfuri = common_root_url() .
-                    'api/statuses/friends_timeline/' .
-                    $target_id . '.atom';
+                  'api/statuses/friends_timeline/' .
+                  $target_id . '.atom';
             } else {
                 $selfuri = common_root_url() .
-                    'api/statuses/friends_timeline.atom';
+                  'api/statuses/friends_timeline.atom';
             }
 
             $this->showAtomTimeline(
-                $this->notices, $title, $id, $link,
-                $subtitle, null, $selfuri, $logo
-            );
+                                    $this->notices, $title, $id, $link,
+                                    $subtitle, null, $selfuri, $logo
+                                    );
             break;
         case 'json':
             $this->showJsonTimeline($this->notices);
@@ -169,17 +169,13 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
         $notices = array();
 
         if (!empty($this->auth_user) && $this->auth_user->id == $this->user->id) {
-            $notice = $this->user->noticeInbox(
-                ($this->page-1) * $this->count,
-                $this->count, $this->since_id,
-                $this->max_id, $this->since
-            );
+            $notice = $this->user->ownFriendsTimeline(($this->page-1) * $this->count,
+                                                      $this->count, $this->since_id,
+                                                      $this->max_id, $this->since);
         } else {
-            $notice = $this->user->noticesWithFriends(
-                ($this->page-1) * $this->count,
-                $this->count, $this->since_id,
-                $this->max_id, $this->since
-            );
+            $notice = $this->user->friendsTimeline(($this->page-1) * $this->count,
+                                                   $this->count, $this->since_id,
+                                                   $this->max_id, $this->since);
         }
 
         while ($notice->fetch()) {
@@ -233,14 +229,14 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
             $last = count($this->notices) - 1;
 
             return '"' . implode(
-                ':',
-                array($this->arg('action'),
-                      common_language(),
-                      $this->user->id,
-                      strtotime($this->notices[0]->created),
-                      strtotime($this->notices[$last]->created))
-            )
-            . '"';
+                                 ':',
+                                 array($this->arg('action'),
+                                       common_language(),
+                                       $this->user->id,
+                                       strtotime($this->notices[0]->created),
+                                       strtotime($this->notices[$last]->created))
+                                 )
+              . '"';
         }
 
         return null;
diff --git a/actions/apitimelinehome.php b/actions/apitimelinehome.php
new file mode 100644 (file)
index 0000000..5f5ea37
--- /dev/null
@@ -0,0 +1,249 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show the home timeline
+ *
+ * PHP version 5
+ *
+ * LICENCE: 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/>.
+ *
+ * @category  API
+ * @package   StatusNet
+ * @author    Craig Andrews <candrews@integralblue.com>
+ * @author    Evan Prodromou <evan@status.net>
+ * @author    Jeffery To <jeffery.to@gmail.com>
+ * @author    mac65 <mac65@mac65.com>
+ * @author    Mike Cochrane <mikec@mikenz.geek.nz>
+ * @author    Robin Millette <robin@millette.info>
+ * @author    Zach Copley <zach@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+require_once INSTALLDIR . '/lib/apibareauth.php';
+
+/**
+ * Returns the most recent notices (default 20) posted by the target user.
+ * This is the equivalent of 'You and friends' page accessed via Web.
+ *
+ * @category API
+ * @package  StatusNet
+ * @author   Craig Andrews <candrews@integralblue.com>
+ * @author   Evan Prodromou <evan@status.net>
+ * @author   Jeffery To <jeffery.to@gmail.com>
+ * @author   mac65 <mac65@mac65.com>
+ * @author   Mike Cochrane <mikec@mikenz.geek.nz>
+ * @author   Robin Millette <robin@millette.info>
+ * @author   Zach Copley <zach@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ */
+
+class ApiTimelineHomeAction extends ApiBareAuthAction
+{
+    var $notices  = null;
+
+    /**
+     * Take arguments for running
+     *
+     * @param array $args $_REQUEST args
+     *
+     * @return boolean success flag
+     *
+     */
+
+    function prepare($args)
+    {
+        parent::prepare($args);
+        common_debug("api home_timeline");
+        $this->user = $this->getTargetUser($this->arg('id'));
+
+        if (empty($this->user)) {
+            $this->clientError(_('No such user.'), 404, $this->format);
+            return;
+        }
+
+        $this->notices = $this->getNotices();
+
+        return true;
+    }
+
+    /**
+     * Handle the request
+     *
+     * Just show the notices
+     *
+     * @param array $args $_REQUEST data (unused)
+     *
+     * @return void
+     */
+
+    function handle($args)
+    {
+        parent::handle($args);
+        $this->showTimeline();
+    }
+
+    /**
+     * Show the timeline of notices
+     *
+     * @return void
+     */
+
+    function showTimeline()
+    {
+        $profile    = $this->user->getProfile();
+        $avatar     = $profile->getAvatar(AVATAR_PROFILE_SIZE);
+        $sitename   = common_config('site', 'name');
+        $title      = sprintf(_("%s and friends"), $this->user->nickname);
+        $taguribase = common_config('integration', 'taguri');
+        $id         = "tag:$taguribase:HomeTimeline:" . $this->user->id;
+        $link       = common_local_url(
+            'all', array('nickname' => $this->user->nickname)
+        );
+        $subtitle   = sprintf(
+            _('Updates from %1$s and friends on %2$s!'),
+            $this->user->nickname, $sitename
+        );
+        $logo       = ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_PROFILE_SIZE);
+
+        switch($this->format) {
+        case 'xml':
+            $this->showXmlTimeline($this->notices);
+            break;
+        case 'rss':
+            $this->showRssTimeline($this->notices, $title, $link, $subtitle, null, $logo);
+            break;
+        case 'atom':
+
+            $target_id = $this->arg('id');
+
+            if (isset($target_id)) {
+                $selfuri = common_root_url() .
+                    'api/statuses/home_timeline/' .
+                    $target_id . '.atom';
+            } else {
+                $selfuri = common_root_url() .
+                    'api/statuses/home_timeline.atom';
+            }
+
+            $this->showAtomTimeline(
+                $this->notices, $title, $id, $link,
+                $subtitle, null, $selfuri, $logo
+            );
+            break;
+        case 'json':
+            $this->showJsonTimeline($this->notices);
+            break;
+        default:
+            $this->clientError(_('API method not found!'), $code = 404);
+            break;
+        }
+    }
+
+    /**
+     * Get notices
+     *
+     * @return array notices
+     */
+
+    function getNotices()
+    {
+        $notices = array();
+
+        if (!empty($this->auth_user) && $this->auth_user->id == $this->user->id) {
+            $notice = $this->user->noticeInbox(
+                ($this->page-1) * $this->count,
+                $this->count, $this->since_id,
+                $this->max_id, $this->since
+            );
+        } else {
+            $notice = $this->user->noticesWithFriends(
+                ($this->page-1) * $this->count,
+                $this->count, $this->since_id,
+                $this->max_id, $this->since
+            );
+        }
+
+        while ($notice->fetch()) {
+            $notices[] = clone($notice);
+        }
+
+        return $notices;
+    }
+
+    /**
+     * Is this action read only?
+     *
+     * @param array $args other arguments
+     *
+     * @return boolean true
+     */
+
+    function isReadOnly($args)
+    {
+        return true;
+    }
+
+    /**
+     * When was this feed last modified?
+     *
+     * @return string datestamp of the latest notice in the stream
+     */
+
+    function lastModified()
+    {
+        if (!empty($this->notices) && (count($this->notices) > 0)) {
+            return strtotime($this->notices[0]->created);
+        }
+
+        return null;
+    }
+
+    /**
+     * An entity tag for this stream
+     *
+     * Returns an Etag based on the action name, language, user ID, and
+     * timestamps of the first and last notice in the timeline
+     *
+     * @return string etag
+     */
+
+    function etag()
+    {
+        if (!empty($this->notices) && (count($this->notices) > 0)) {
+
+            $last = count($this->notices) - 1;
+
+            return '"' . implode(
+                ':',
+                array($this->arg('action'),
+                      common_language(),
+                      $this->user->id,
+                      strtotime($this->notices[0]->created),
+                      strtotime($this->notices[$last]->created))
+            )
+            . '"';
+        }
+
+        return null;
+    }
+
+}
index 66d9cf5d4794f55852ee66bc1e2bdb1cc1a46845..4aec4ed55cde43e5f9f6424c1091c79978fb2239 100644 (file)
@@ -530,8 +530,18 @@ class Notice extends Memcached_DataObject
                     if ($member->find()) {
                         while ($member->fetch()) {
                             $cache->delete(common_cache_key('notice_inbox:by_user:' . $member->profile_id));
+                            $cache->delete(common_cache_key('notice_inbox:by_user_own:' . $member->profile_id));
+                            if (empty($this->repeat_of)) {
+                                $cache->delete(common_cache_key('user:friends_timeline:' . $member->profile_id));
+                                $cache->delete(common_cache_key('user:friends_timeline_own:' . $member->profile_id));
+                            }
                             if ($blowLast) {
                                 $cache->delete(common_cache_key('notice_inbox:by_user:' . $member->profile_id . ';last'));
+                                $cache->delete(common_cache_key('notice_inbox:by_user_own:' . $member->profile_id . ';last'));
+                                if (empty($this->repeat_of)) {
+                                    $cache->delete(common_cache_key('user:friends_timeline:' . $member->profile_id . ';last'));
+                                    $cache->delete(common_cache_key('user:friends_timeline_own:' . $member->profile_id . ';last'));
+                                }
                             }
                         }
                     }
@@ -579,9 +589,17 @@ class Notice extends Memcached_DataObject
             while ($user->fetch()) {
                 $cache->delete(common_cache_key('notice_inbox:by_user:'.$user->id));
                 $cache->delete(common_cache_key('notice_inbox:by_user_own:'.$user->id));
+                if (empty($this->repeat_of)) {
+                    $cache->delete(common_cache_key('user:friends_timeline:'.$user->id));
+                    $cache->delete(common_cache_key('user:friends_timeline_own:'.$user->id));
+                }
                 if ($blowLast) {
                     $cache->delete(common_cache_key('notice_inbox:by_user:'.$user->id.';last'));
                     $cache->delete(common_cache_key('notice_inbox:by_user_own:'.$user->id.';last'));
+                    if (empty($this->repeat_of)) {
+                        $cache->delete(common_cache_key('user:friends_timeline:'.$user->id.';last'));
+                        $cache->delete(common_cache_key('user:friends_timeline_own:'.$user->id.';last'));
+                    }
                 }
             }
             $user->free();
index 9c071e06b0fe1ebad7eeb26e0bf47c2f0ce10d04..d04f7d679ffca7abbd3858b377053cd88d42a1a5 100644 (file)
@@ -473,6 +473,77 @@ class User extends Memcached_DataObject
         return Notice::getStreamByIds($ids);
     }
 
+    function friendsTimeline($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
+    {
+        $ids = Notice::stream(array($this, '_friendsTimelineDirect'),
+                              array(false),
+                              'user:friends_timeline:'.$this->id,
+                              $offset, $limit, $since_id, $before_id, $since);
+
+        return Notice::getStreamByIds($ids);
+    }
+
+    function ownFriendsTimeline($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
+    {
+        $ids = Notice::stream(array($this, '_friendsTimelineDirect'),
+                              array(true),
+                              'user:friends_timeline_own:'.$this->id,
+                              $offset, $limit, $since_id, $before_id, $since);
+
+        return Notice::getStreamByIds($ids);
+    }
+
+    function _friendsTimelineDirect($own, $offset, $limit, $since_id, $max_id, $since)
+    {
+        $qry =
+          'SELECT notice.id AS id ' .
+          'FROM notice JOIN notice_inbox ON notice.id = notice_inbox.notice_id ' .
+          'WHERE notice_inbox.user_id = ' . $this->id . ' ' .
+          'AND notice.repeat_of IS NULL ';
+
+        if (!$own) {
+            // XXX: autoload notice inbox for constant
+            $inbox = new Notice_inbox();
+
+            $qry .= 'AND notice_inbox.source != ' . NOTICE_INBOX_SOURCE_GATEWAY . ' ';
+        }
+
+        if ($since_id != 0) {
+            $qry .= 'AND notice.id > ' . $since_id . ' ';
+        }
+
+        if ($max_id != 0) {
+            $qry .= 'AND notice.id <= ' . $max_id . ' ';
+        }
+
+        if (!is_null($since)) {
+            $qry .= 'AND notice.modified > \'' . date('Y-m-d H:i:s', $since) . '\' ';
+        }
+
+        // NOTE: we sort by fave time, not by notice time!
+
+        $qry .= 'ORDER BY notice.id DESC ';
+
+        if (!is_null($offset)) {
+            $qry .= "LIMIT $limit OFFSET $offset";
+        }
+
+        $ids = array();
+
+        $notice = new Notice();
+
+        $notice->query($qry);
+
+        while ($notice->fetch()) {
+            $ids[] = $notice->id;
+        }
+
+        $notice->free();
+        $notice = NULL;
+
+        return $ids;
+    }
+
     function blowFavesCache()
     {
         $cache = common_memcache();
index 0c66501116313226159841ae8cd1d956eeff2b7f..833bc1c5fcc7f66c4d16c644e43d01cb94f53379 100644 (file)
@@ -224,9 +224,13 @@ class ApiAction extends Action
             return $base;
         } else {
             $original = Notice::staticGet('id', $notice->repeat_of);
-            $original_array = $this->twitterSimpleStatusArray($original, $include_user);
-            $original_array['retweeted_status'] = $base;
-            return $original_array;
+            if (empty($original)) {
+                return $base;
+            } else {
+                $original_array = $this->twitterSimpleStatusArray($original, $include_user);
+                $original_array['retweeted_status'] = $base;
+                return $original_array;
+            }
         }
     }
 
index 8f68f86ac74f7b3929f696a2de8b8772d8a4c5ea..474e05996f24811a33d39ffec2265447950338b5 100644 (file)
@@ -283,12 +283,13 @@ class Router
                         array('action' => 'ApiTimelineFriends',
                               'id' => '[a-zA-Z0-9]+',
                               'format' => '(xml|json|rss|atom)'));
+
             $m->connect('api/statuses/home_timeline.:format',
-                        array('action' => 'ApiTimelineFriends',
+                        array('action' => 'ApiTimelineHome',
                               'format' => '(xml|json|rss|atom)'));
 
             $m->connect('api/statuses/home_timeline/:id.:format',
-                        array('action' => 'ApiTimelineFriends',
+                        array('action' => 'ApiTimelineHome',
                               'id' => '[a-zA-Z0-9]+',
                               'format' => '(xml|json|rss|atom)'));