apitimelinefriends.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. <?php
  2. /**
  3. * StatusNet, the distributed open-source microblogging tool
  4. *
  5. * Show the friends timeline
  6. *
  7. * PHP version 5
  8. *
  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.
  13. *
  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.
  18. *
  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/>.
  21. *
  22. * @category API
  23. * @package StatusNet
  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/
  35. */
  36. /* External API usage documentation. Please update when you change how this method works. */
  37. /*! @page friendstimeline statuses/friends_timeline
  38. @section Description
  39. Returns the 20 most recent statuses posted by the authenticating
  40. user and that user's friends. This is the equivalent of "You and
  41. friends" page in the web interface.
  42. @par URL patterns
  43. @li /api/statuses/friends_timeline.:format
  44. @li /api/statuses/friends_timeline/:id.:format
  45. @par Formats (:format)
  46. xml, json, rss, atom
  47. @par ID (:id)
  48. username, user id
  49. @par HTTP Method(s)
  50. GET
  51. @par Requires Authentication
  52. Sometimes (see: @ref authentication)
  53. @param user_id (Optional) Specifies a user by ID
  54. @param screen_name (Optional) Specifies a user by screename (nickname)
  55. @param since_id (Optional) Returns only statuses with an ID greater
  56. than (that is, more recent than) the specified ID.
  57. @param max_id (Optional) Returns only statuses with an ID less than
  58. (that is, older than) or equal to the specified ID.
  59. @param count (Optional) Specifies the number of statuses to retrieve.
  60. @param page (Optional) Specifies the page of results to retrieve.
  61. @sa @ref authentication
  62. @sa @ref apiroot
  63. @subsection usagenotes Usage notes
  64. @li The URL pattern is relative to the @ref apiroot.
  65. @li The XML response uses <a href="http://georss.org/Main_Page">GeoRSS</a>
  66. to encode the latitude and longitude (see example response below <georss:point>).
  67. @subsection exampleusage Example usage
  68. @verbatim
  69. curl http://identi.ca/api/statuses/friends_timeline/evan.xml?count=1&page=2
  70. @endverbatim
  71. @subsection exampleresponse Example response
  72. @verbatim
  73. <?xml version="1.0"?>
  74. <statuses type="array">
  75. <status>
  76. <text>back from the !yul !drupal meet with Evolving Web folk, @anarcat, @webchick and others, and an interesting refresher on SQL indexing</text>
  77. <truncated>false</truncated>
  78. <created_at>Wed Mar 31 01:33:02 +0000 2010</created_at>
  79. <in_reply_to_status_id/>
  80. <source>&lt;a href="http://somesourcecode.net/microblog/"&gt;mbpidgin&lt;/a&gt;</source>
  81. <id>26674201</id>
  82. <in_reply_to_user_id/>
  83. <in_reply_to_screen_name/>
  84. <geo/>
  85. <favorited>false</favorited>
  86. <user>
  87. <id>246</id>
  88. <name>Mark</name>
  89. <screen_name>lambic</screen_name>
  90. <location>Montreal, Canada</location>
  91. <description>Geek</description>
  92. <profile_image_url>http://avatar.identi.ca/246-48-20080702141545.png</profile_image_url>
  93. <url>http://lambic.co.uk</url>
  94. <protected>false</protected>
  95. <followers_count>73</followers_count>
  96. <profile_background_color>#F0F2F5</profile_background_color>
  97. <profile_text_color/>
  98. <profile_link_color>#002E6E</profile_link_color>
  99. <profile_sidebar_fill_color>#CEE1E9</profile_sidebar_fill_color>
  100. <profile_sidebar_border_color/>
  101. <friends_count>58</friends_count>
  102. <created_at>Wed Jul 02 14:12:15 +0000 2008</created_at>
  103. <favourites_count>2</favourites_count>
  104. <utc_offset>-14400</utc_offset>
  105. <time_zone>US/Eastern</time_zone>
  106. <profile_background_image_url/>
  107. <profile_background_tile>false</profile_background_tile>
  108. <statuses_count>933</statuses_count>
  109. <following>false</following>
  110. <notifications>false</notifications>
  111. </user>
  112. </status>
  113. </statuses>
  114. @endverbatim
  115. */
  116. if (!defined('STATUSNET')) {
  117. exit(1);
  118. }
  119. /**
  120. * Returns the most recent notices (default 20) posted by the target user.
  121. * This is the equivalent of 'You and friends' page accessed via Web.
  122. *
  123. * @category API
  124. * @package StatusNet
  125. * @author Craig Andrews <candrews@integralblue.com>
  126. * @author Evan Prodromou <evan@status.net>
  127. * @author Jeffery To <jeffery.to@gmail.com>
  128. * @author mac65 <mac65@mac65.com>
  129. * @author Mike Cochrane <mikec@mikenz.geek.nz>
  130. * @author Robin Millette <robin@millette.info>
  131. * @author Zach Copley <zach@status.net>
  132. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
  133. * @link http://status.net/
  134. */
  135. class ApiTimelineFriendsAction extends ApiBareAuthAction
  136. {
  137. var $notices = null;
  138. /**
  139. * Take arguments for running
  140. *
  141. * @param array $args $_REQUEST args
  142. *
  143. * @return boolean success flag
  144. *
  145. */
  146. protected function prepare(array $args=array())
  147. {
  148. parent::prepare($args);
  149. $this->target = $this->getTargetProfile($this->arg('id'));
  150. if (!($this->target instanceof Profile)) {
  151. // TRANS: Client error displayed when requesting dents of a user and friends for a user that does not exist.
  152. $this->clientError(_('No such user.'), 404);
  153. }
  154. $this->notices = $this->getNotices();
  155. return true;
  156. }
  157. /**
  158. * Handle the request
  159. *
  160. * Just show the notices
  161. *
  162. * @return void
  163. */
  164. protected function handle()
  165. {
  166. parent::handle();
  167. $this->showTimeline();
  168. }
  169. /**
  170. * Show the timeline of notices
  171. *
  172. * @return void
  173. */
  174. function showTimeline()
  175. {
  176. $sitename = common_config('site', 'name');
  177. // TRANS: Title of API timeline for a user and friends.
  178. // TRANS: %s is a username.
  179. $title = sprintf(_("%s and friends"), $this->target->nickname);
  180. $taguribase = TagURI::base();
  181. $id = "tag:$taguribase:FriendsTimeline:" . $this->target->id;
  182. $subtitle = sprintf(
  183. // TRANS: Message is used as a subtitle. %1$s is a user nickname, %2$s is a site name.
  184. _('Updates from %1$s and friends on %2$s!'),
  185. $this->target->nickname,
  186. $sitename
  187. );
  188. $logo = $this->target->avatarUrl(AVATAR_PROFILE_SIZE);
  189. $link = common_local_url('all',
  190. array('nickname' => $this->target->nickname));
  191. $self = $this->getSelfUri();
  192. switch($this->format) {
  193. case 'xml':
  194. $this->showXmlTimeline($this->notices);
  195. break;
  196. case 'rss':
  197. $this->showRssTimeline(
  198. $this->notices,
  199. $title,
  200. $link,
  201. $subtitle,
  202. null,
  203. $logo,
  204. $self
  205. );
  206. break;
  207. case 'atom':
  208. header('Content-Type: application/atom+xml; charset=utf-8');
  209. $atom = new AtomNoticeFeed($this->auth_user);
  210. $atom->setId($id);
  211. $atom->setTitle($title);
  212. $atom->setSubtitle($subtitle);
  213. $atom->setLogo($logo);
  214. $atom->setUpdated('now');
  215. $atom->addLink($link);
  216. $atom->setSelfLink($self);
  217. $atom->addEntryFromNotices($this->notices);
  218. $this->raw($atom->getString());
  219. break;
  220. case 'json':
  221. $this->showJsonTimeline($this->notices);
  222. break;
  223. case 'as':
  224. header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
  225. $doc = new ActivityStreamJSONDocument($this->auth_user, $title);
  226. $doc->addLink($link, 'alternate', 'text/html');
  227. $doc->addItemsFromNotices($this->notices);
  228. $this->raw($doc->asString());
  229. break;
  230. default:
  231. // TRANS: Client error displayed when coming across a non-supported API method.
  232. $this->clientError(_('API method not found.'), 404);
  233. }
  234. }
  235. /**
  236. * Get notices
  237. *
  238. * @return array notices
  239. */
  240. function getNotices()
  241. {
  242. $notices = array();
  243. $stream = new InboxNoticeStream($this->target, $this->scoped);
  244. $notice = $stream->getNotices(($this->page-1) * $this->count,
  245. $this->count,
  246. $this->since_id,
  247. $this->max_id);
  248. while ($notice->fetch()) {
  249. $notices[] = clone($notice);
  250. }
  251. return $notices;
  252. }
  253. /**
  254. * Is this action read only?
  255. *
  256. * @param array $args other arguments
  257. *
  258. * @return boolean true
  259. */
  260. function isReadOnly($args)
  261. {
  262. return true;
  263. }
  264. /**
  265. * When was this feed last modified?
  266. *
  267. * @return string datestamp of the latest notice in the stream
  268. */
  269. function lastModified()
  270. {
  271. if (!empty($this->notices) && (count($this->notices) > 0)) {
  272. return strtotime($this->notices[0]->created);
  273. }
  274. return null;
  275. }
  276. /**
  277. * An entity tag for this stream
  278. *
  279. * Returns an Etag based on the action name, language, user ID, and
  280. * timestamps of the first and last notice in the timeline
  281. *
  282. * @return string etag
  283. */
  284. function etag()
  285. {
  286. if (!empty($this->notices) && (count($this->notices) > 0)) {
  287. $last = count($this->notices) - 1;
  288. return '"' . implode(
  289. ':',
  290. array($this->arg('action'),
  291. common_user_cache_hash($this->auth_user),
  292. common_language(),
  293. $this->target->id,
  294. strtotime($this->notices[0]->created),
  295. strtotime($this->notices[$last]->created))
  296. )
  297. . '"';
  298. }
  299. return null;
  300. }
  301. }