apitimelinepublic.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. <?php
  2. /**
  3. * StatusNet, the distributed open-source microblogging tool
  4. *
  5. * Show the public 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 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. if (!defined('STATUSNET')) {
  37. exit(1);
  38. }
  39. /**
  40. * Returns the most recent notices (default 20) posted by everybody
  41. *
  42. * @category API
  43. * @package StatusNet
  44. * @author Craig Andrews <candrews@integralblue.com>
  45. * @author Evan Prodromou <evan@status.net>
  46. * @author Jeffery To <jeffery.to@gmail.com>
  47. * @author mac65 <mac65@mac65.com>
  48. * @author Mike Cochrane <mikec@mikenz.geek.nz>
  49. * @author Robin Millette <robin@millette.info>
  50. * @author Zach Copley <zach@status.net>
  51. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
  52. * @link http://status.net/
  53. */
  54. /* External API usage documentation. Please update when you change how this method works. */
  55. /*! @page publictimeline statuses/public_timeline
  56. @section Description
  57. Returns the 20 most recent notices from users throughout the system who have
  58. uploaded their own avatars. Depending on configuration, it may or may not
  59. not include notices from automatic posting services.
  60. @par URL patterns
  61. @li /api/statuses/public_timeline.:format
  62. @par Formats (:format)
  63. xml, json, rss, atom
  64. @par HTTP Method(s)
  65. GET
  66. @par Requires Authentication
  67. No
  68. @param since_id (Optional) Returns only statuses with an ID greater
  69. than (that is, more recent than) the specified ID.
  70. @param max_id (Optional) Returns only statuses with an ID less than
  71. (that is, older than) or equal to the specified ID.
  72. @param count (Optional) Specifies the number of statuses to retrieve.
  73. @param page (Optional) Specifies the page of results to retrieve.
  74. @sa @ref apiroot
  75. @subsection usagenotes Usage notes
  76. @li The URL pattern is relative to the @ref apiroot.
  77. @li The XML response uses <a href="http://georss.org/Main_Page">GeoRSS</a>
  78. to encode the latitude and longitude (see example response below <georss:point>).
  79. @subsection exampleusage Example usage
  80. @verbatim
  81. curl http://identi.ca/api/statuses/friends_timeline/evan.xml?count=1&page=2
  82. @endverbatim
  83. @subsection exampleresponse Example response
  84. @verbatim
  85. <?xml version="1.0" encoding="UTF-8"?>
  86. <statuses type="array">
  87. <status>
  88. <text>@skwashd oh, commbank reenabled me super quick both times. but disconcerting when you don't expect it though</text>
  89. <truncated>false</truncated>
  90. <created_at>Sat Apr 17 00:49:12 +0000 2010</created_at>
  91. <in_reply_to_status_id>28838393</in_reply_to_status_id>
  92. <source>xmpp</source>
  93. <id>28838456</id>
  94. <in_reply_to_user_id>39303</in_reply_to_user_id>
  95. <in_reply_to_screen_name>skwashd</in_reply_to_screen_name>
  96. <geo></geo>
  97. <favorited>false</favorited>
  98. <user>
  99. <id>44517</id>
  100. <name>joshua may</name>
  101. <screen_name>notjosh</screen_name>
  102. <location></location>
  103. <description></description>
  104. <profile_image_url>http://avatar.identi.ca/44517-48-20090321004106.jpeg</profile_image_url>
  105. <url></url>
  106. <protected>false</protected>
  107. <followers_count>17</followers_count>
  108. <profile_background_color></profile_background_color>
  109. <profile_text_color></profile_text_color>
  110. <profile_link_color></profile_link_color>
  111. <profile_sidebar_fill_color></profile_sidebar_fill_color>
  112. <profile_sidebar_border_color></profile_sidebar_border_color>
  113. <friends_count>20</friends_count>
  114. <created_at>Sat Mar 21 00:40:25 +0000 2009</created_at>
  115. <favourites_count>0</favourites_count>
  116. <utc_offset>0</utc_offset>
  117. <time_zone>UTC</time_zone>
  118. <profile_background_image_url></profile_background_image_url>
  119. <profile_background_tile>false</profile_background_tile>
  120. <statuses_count>100</statuses_count>
  121. <following>false</following>
  122. <notifications>false</notifications>
  123. </user>
  124. </status>
  125. [....]
  126. </statuses>
  127. @endverbatim
  128. */
  129. class ApiTimelinePublicAction extends ApiPrivateAuthAction
  130. {
  131. var $notices = null;
  132. /**
  133. * Take arguments for running
  134. *
  135. * @param array $args $_REQUEST args
  136. *
  137. * @return boolean success flag
  138. *
  139. */
  140. protected function prepare(array $args=array())
  141. {
  142. parent::prepare($args);
  143. $this->notices = $this->getNotices();
  144. return true;
  145. }
  146. /**
  147. * Handle the request
  148. *
  149. * Just show the notices
  150. *
  151. * @return void
  152. */
  153. protected function handle()
  154. {
  155. parent::handle();
  156. $this->showTimeline();
  157. }
  158. function title()
  159. {
  160. // TRANS: Title for site timeline. %s is the GNU social sitename.
  161. return sprintf(_("%s public timeline"), common_config('site', 'name'));
  162. }
  163. /**
  164. * Show the timeline of notices
  165. *
  166. * @return void
  167. */
  168. function showTimeline()
  169. {
  170. $nonapi_action = substr($this->action, strlen('apitimeline')); // Just so we don't need to set this explicitly
  171. $sitelogo = (common_config('site', 'logo')) ? common_config('site', 'logo') : Theme::path('logo.png');
  172. $title = $this->title();
  173. $taguribase = TagURI::base();
  174. $id = "tag:$taguribase:" . ucfirst($nonapi_action) . 'Timeline'; // Public or Networkpublic probably
  175. $link = common_local_url($nonapi_action);
  176. $self = $this->getSelfUri();
  177. // TRANS: Subtitle for site timeline. %s is the GNU social sitename.
  178. $subtitle = sprintf(_("%s updates from everyone!"), common_config('site', 'name'));
  179. switch($this->format) {
  180. case 'xml':
  181. $this->showXmlTimeline($this->notices);
  182. break;
  183. case 'rss':
  184. $this->showRssTimeline(
  185. $this->notices,
  186. $title,
  187. $link,
  188. $subtitle,
  189. null,
  190. $sitelogo,
  191. $self
  192. );
  193. break;
  194. case 'atom':
  195. header('Content-Type: application/atom+xml; charset=utf-8');
  196. $atom = new AtomNoticeFeed($this->auth_user);
  197. $atom->setId($id);
  198. $atom->setTitle($title);
  199. $atom->setSubtitle($subtitle);
  200. $atom->setLogo($sitelogo);
  201. $atom->setUpdated('now');
  202. $atom->addLink(common_local_url($nonapi_action));
  203. $atom->setSelfLink($self);
  204. $atom->addEntryFromNotices($this->notices);
  205. $this->raw($atom->getString());
  206. break;
  207. case 'json':
  208. $this->showJsonTimeline($this->notices);
  209. break;
  210. case 'as':
  211. header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
  212. $doc = new ActivityStreamJSONDocument($this->auth_user);
  213. $doc->setTitle($title);
  214. $doc->addLink($link, 'alternate', 'text/html');
  215. $doc->addItemsFromNotices($this->notices);
  216. $this->raw($doc->asString());
  217. break;
  218. default:
  219. // TRANS: Client error displayed when coming across a non-supported API method.
  220. $this->clientError(_('API method not found.'), $code = 404);
  221. break;
  222. }
  223. }
  224. /**
  225. * Get notices
  226. *
  227. * @return array notices
  228. */
  229. function getNotices()
  230. {
  231. $notices = array();
  232. $stream = $this->getStream();
  233. $notice = $stream->getNotices(($this->page - 1) * $this->count,
  234. $this->count,
  235. $this->since_id,
  236. $this->max_id);
  237. $notices = $notice->fetchAll();
  238. NoticeList::prefill($notices);
  239. return $notices;
  240. }
  241. protected function getStream()
  242. {
  243. return new PublicNoticeStream($this->scoped);
  244. }
  245. /**
  246. * Is this action read only?
  247. *
  248. * @param array $args other arguments
  249. *
  250. * @return boolean true
  251. */
  252. function isReadOnly($args)
  253. {
  254. return true;
  255. }
  256. /**
  257. * When was this feed last modified?
  258. *
  259. * @return string datestamp of the latest notice in the stream
  260. */
  261. function lastModified()
  262. {
  263. if (!empty($this->notices) && (count($this->notices) > 0)) {
  264. return strtotime($this->notices[0]->created);
  265. }
  266. return null;
  267. }
  268. /**
  269. * An entity tag for this stream
  270. *
  271. * Returns an Etag based on the action name, language, and
  272. * timestamps of the first and last notice in the timeline
  273. *
  274. * @return string etag
  275. */
  276. function etag()
  277. {
  278. if (!empty($this->notices) && (count($this->notices) > 0)) {
  279. $last = count($this->notices) - 1;
  280. return '"' . implode(
  281. ':',
  282. array($this->arg('action'),
  283. common_user_cache_hash($this->auth_user),
  284. common_language(),
  285. strtotime($this->notices[0]->created),
  286. strtotime($this->notices[$last]->created))
  287. )
  288. . '"';
  289. }
  290. return null;
  291. }
  292. }