3 * StatusNet, the distributed open-source microblogging tool
5 * Show the friends timeline
9 * LICENCE: This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU Affero General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Affero General Public License for more details.
19 * You should have received a copy of the GNU Affero General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 * @author Craig Andrews <candrews@integralblue.com>
25 * @author Evan Prodromou <evan@status.net>
26 * @author Jeffery To <jeffery.to@gmail.com>
27 * @author mac65 <mac65@mac65.com>
28 * @author Mike Cochrane <mikec@mikenz.geek.nz>
29 * @author Robin Millette <robin@millette.info>
30 * @author Zach Copley <zach@status.net>
31 * @copyright 2009-2010 StatusNet, Inc.
32 * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
33 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
34 * @link http://status.net/
37 /* External API usage documentation. Please update when you change how this method works. */
39 /*! @page friendstimeline statuses/friends_timeline
42 Returns the 20 most recent statuses posted by the authenticating
43 user and that user's friends. This is the equivalent of "You and
44 friends" page in the web interface.
47 @li /api/statuses/friends_timeline.:format
48 @li /api/statuses/friends_timeline/:id.:format
50 @par Formats (:format)
59 @par Requires Authentication
60 Sometimes (see: @ref authentication)
62 @param user_id (Optional) Specifies a user by ID
63 @param screen_name (Optional) Specifies a user by screename (nickname)
64 @param since_id (Optional) Returns only statuses with an ID greater
65 than (that is, more recent than) the specified ID.
66 @param max_id (Optional) Returns only statuses with an ID less than
67 (that is, older than) or equal to the specified ID.
68 @param count (Optional) Specifies the number of statuses to retrieve.
69 @param page (Optional) Specifies the page of results to retrieve.
71 @sa @ref authentication
74 @subsection usagenotes Usage notes
75 @li The URL pattern is relative to the @ref apiroot.
76 @li The XML response uses <a href="http://georss.org/Main_Page">GeoRSS</a>
77 to encode the latitude and longitude (see example response below <georss:point>).
79 @subsection exampleusage Example usage
82 curl http://identi.ca/api/statuses/friends_timeline/evan.xml?count=1&page=2
85 @subsection exampleresponse Example response
89 <statuses type="array">
91 <text>back from the !yul !drupal meet with Evolving Web folk, @anarcat, @webchick and others, and an interesting refresher on SQL indexing</text>
92 <truncated>false</truncated>
93 <created_at>Wed Mar 31 01:33:02 +0000 2010</created_at>
94 <in_reply_to_status_id/>
95 <source><a href="http://code.google.com/p/microblog-purple/">mbpidgin</a></source>
97 <in_reply_to_user_id/>
98 <in_reply_to_screen_name/>
100 <favorited>false</favorited>
104 <screen_name>lambic</screen_name>
105 <location>Montreal, Canada</location>
106 <description>Geek</description>
107 <profile_image_url>http://avatar.identi.ca/246-48-20080702141545.png</profile_image_url>
108 <url>http://lambic.co.uk</url>
109 <protected>false</protected>
110 <followers_count>73</followers_count>
111 <profile_background_color>#F0F2F5</profile_background_color>
112 <profile_text_color/>
113 <profile_link_color>#002E6E</profile_link_color>
114 <profile_sidebar_fill_color>#CEE1E9</profile_sidebar_fill_color>
115 <profile_sidebar_border_color/>
116 <friends_count>58</friends_count>
117 <created_at>Wed Jul 02 14:12:15 +0000 2008</created_at>
118 <favourites_count>2</favourites_count>
119 <utc_offset>-14400</utc_offset>
120 <time_zone>US/Eastern</time_zone>
121 <profile_background_image_url/>
122 <profile_background_tile>false</profile_background_tile>
123 <statuses_count>933</statuses_count>
124 <following>false</following>
125 <notifications>false</notifications>
132 if (!defined('STATUSNET')) {
136 require_once INSTALLDIR . '/lib/apibareauth.php';
139 * Returns the most recent notices (default 20) posted by the target user.
140 * This is the equivalent of 'You and friends' page accessed via Web.
144 * @author Craig Andrews <candrews@integralblue.com>
145 * @author Evan Prodromou <evan@status.net>
146 * @author Jeffery To <jeffery.to@gmail.com>
147 * @author mac65 <mac65@mac65.com>
148 * @author Mike Cochrane <mikec@mikenz.geek.nz>
149 * @author Robin Millette <robin@millette.info>
150 * @author Zach Copley <zach@status.net>
151 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
152 * @link http://status.net/
154 class ApiTimelineFriendsAction extends ApiBareAuthAction
159 * Take arguments for running
161 * @param array $args $_REQUEST args
163 * @return boolean success flag
166 function prepare($args)
168 parent::prepare($args);
169 $this->user = $this->getTargetUser($this->arg('id'));
171 if (empty($this->user)) {
172 // TRANS: Client error displayed when requesting dents of a user and friends for a user that does not exist.
173 $this->clientError(_('No such user.'), 404, $this->format);
177 $this->notices = $this->getNotices();
185 * Just show the notices
187 * @param array $args $_REQUEST data (unused)
191 function handle($args)
193 parent::handle($args);
194 $this->showTimeline();
198 * Show the timeline of notices
202 function showTimeline()
204 $profile = $this->user->getProfile();
205 $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
206 $sitename = common_config('site', 'name');
207 $title = sprintf(_("%s and friends"), $this->user->nickname);
208 $taguribase = TagURI::base();
209 $id = "tag:$taguribase:FriendsTimeline:" . $this->user->id;
212 // TRANS: Message is used as a subtitle. %1$s is a user nickname, %2$s is a site name.
213 _('Updates from %1$s and friends on %2$s!'),
214 $this->user->nickname,
218 $link = common_local_url(
220 array('nickname' => $this->user->nickname)
223 $self = $this->getSelfUri();
225 $logo = (!empty($avatar))
226 ? $avatar->displayUrl()
227 : Avatar::defaultImage(AVATAR_PROFILE_SIZE);
229 switch($this->format) {
231 $this->showXmlTimeline($this->notices);
235 $this->showRssTimeline(
246 header('Content-Type: application/atom+xml; charset=utf-8');
248 $atom = new AtomNoticeFeed($this->auth_user);
251 $atom->setTitle($title);
252 $atom->setSubtitle($subtitle);
253 $atom->setLogo($logo);
254 $atom->setUpdated('now');
255 $atom->addLink($link);
256 $atom->setSelfLink($self);
258 $atom->addEntryFromNotices($this->notices);
260 $this->raw($atom->getString());
264 $this->showJsonTimeline($this->notices);
267 header('Content-Type: application/json; charset=utf-8');
268 $doc = new ActivityStreamJSONDocument($this->auth_user);
269 $doc->setTitle($title);
270 $doc->addLink($link,'alternate', 'text/html');
271 $doc->addItemsFromNotices($this->notices);
272 $this->raw($doc->asString());
275 // TRANS: Client error displayed when trying to handle an unknown API method.
276 $this->clientError(_('API method not found.'), $code = 404);
284 * @return array notices
286 function getNotices()
290 if (!empty($this->auth_user) && $this->auth_user->id == $this->user->id) {
291 $notice = $this->user->ownFriendsTimeline(($this->page-1) * $this->count,
292 $this->count, $this->since_id,
295 $notice = $this->user->friendsTimeline(($this->page-1) * $this->count,
296 $this->count, $this->since_id,
300 while ($notice->fetch()) {
301 $notices[] = clone($notice);
308 * Is this action read only?
310 * @param array $args other arguments
312 * @return boolean true
314 function isReadOnly($args)
320 * When was this feed last modified?
322 * @return string datestamp of the latest notice in the stream
324 function lastModified()
326 if (!empty($this->notices) && (count($this->notices) > 0)) {
327 return strtotime($this->notices[0]->created);
334 * An entity tag for this stream
336 * Returns an Etag based on the action name, language, user ID, and
337 * timestamps of the first and last notice in the timeline
339 * @return string etag
343 if (!empty($this->notices) && (count($this->notices) > 0)) {
344 $last = count($this->notices) - 1;
346 return '"' . implode(
348 array($this->arg('action'),
349 common_user_cache_hash($this->auth_user),
352 strtotime($this->notices[0]->created),
353 strtotime($this->notices[$last]->created))