The official, canonical postActiv repository. http://www.postactiv.com

apitimelinefriends.php 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. <?php
  2. /* ============================================================================
  3. * Title: APITimelineFriends
  4. * Show the friends timeline
  5. *
  6. * postActiv:
  7. * the micro-blogging software
  8. *
  9. * Copyright:
  10. * Copyright (C) 2016-2018, Maiyannah Bishop
  11. *
  12. * Derived from code copyright various sources:
  13. * o GNU Social (C) 2013-2016, Free Software Foundation, Inc
  14. * o StatusNet (C) 2008-2012, StatusNet, Inc
  15. * ----------------------------------------------------------------------------
  16. * License:
  17. * This program is free software: you can redistribute it and/or modify
  18. * it under the terms of the GNU Affero General Public License as published by
  19. * the Free Software Foundation, either version 3 of the License, or
  20. * (at your option) any later version.
  21. *
  22. * This program is distributed in the hope that it will be useful,
  23. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  25. * GNU Affero General Public License for more details.
  26. *
  27. * You should have received a copy of the GNU Affero General Public License
  28. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  29. *
  30. * <https://www.gnu.org/licenses/agpl.html>
  31. * ----------------------------------------------------------------------------
  32. * About:
  33. * Show the friends timeline
  34. *
  35. * Returns the 20 most recent statuses posted by the authenticating
  36. * user and that user's friends. This is the equivalent of "You and
  37. * friends" page in the web interface.
  38. *
  39. * URL patterns:
  40. * o /api/statuses/friends_timeline.:format
  41. * o /api/statuses/friends_timeline/:id.:format
  42. *
  43. * Formats:
  44. * o xml
  45. * o json
  46. * o rss
  47. * o atom
  48. *
  49. * ID:
  50. * o username
  51. * o user id
  52. *
  53. * HTTP Method:
  54. * o GET
  55. *
  56. * Requires Authentication:
  57. * Sometimes (see: @ref authentication)
  58. *
  59. * o user_id - (Optional) Specifies a user by ID
  60. * o screen_name - (Optional) Specifies a user by screename (nickname)
  61. * o since_id - (Optional) Returns only statuses with an ID greater
  62. * than (that is, more recent than) the specified ID.
  63. * o max_id - (Optional) Returns only statuses with an ID less than
  64. * (that is, older than) or equal to the specified ID.
  65. * o count - (Optional) Specifies the number of statuses to retrieve.
  66. * o page - (Optional) Specifies the page of results to retrieve.
  67. *
  68. * Usage notes:
  69. * o The URL pattern is relative to the @ref apiroot.
  70. * o The XML response uses <a href="http://georss.org/Main_Page">GeoRSS</a>
  71. * to encode the latitude and longitude (see example response below <georss:point>).
  72. *
  73. * Example usage:
  74. * curl http://myinstance.com/api/statuses/friends_timeline/maiyannah.xml?count=1&page=2
  75. *
  76. * Example response:
  77. * <?xml version="1.0"?>
  78. * <statuses type="array">
  79. * <status>
  80. * <text>back from the !yul !drupal meet with Evolving Web folk, @anarcat, @webchick and others, and an interesting refresher on SQL indexing</text>
  81. * <truncated>false</truncated>
  82. * <created_at>Wed Mar 31 01:33:02 +0000 2010</created_at>
  83. * <in_reply_to_status_id/>
  84. * <source>&lt;a href="http://somesourcecode.net/microblog/"&gt;mbpidgin&lt;/a&gt;</source>
  85. * <id>26674201</id>
  86. * <in_reply_to_user_id/>
  87. * <in_reply_to_screen_name/>
  88. * <geo/>
  89. * <favorited>false</favorited>
  90. * <user>
  91. * <id>246</id>
  92. * <name>Mark</name>
  93. * <screen_name>lambic</screen_name>
  94. * <location>Montreal, Canada</location>
  95. * <description>Geek</description>
  96. * <profile_image_url>http://avatar.identi.ca/246-48-20080702141545.png</profile_image_url>
  97. * <url>http://lambic.co.uk</url>
  98. * <protected>false</protected>
  99. * <followers_count>73</followers_count>
  100. * <profile_background_color>#F0F2F5</profile_background_color>
  101. * <profile_text_color/>
  102. * <profile_link_color>#002E6E</profile_link_color>
  103. * <profile_sidebar_fill_color>#CEE1E9</profile_sidebar_fill_color>
  104. * <profile_sidebar_border_color/>
  105. * <friends_count>58</friends_count>
  106. * <created_at>Wed Jul 02 14:12:15 +0000 2008</created_at>
  107. * <favourites_count>2</favourites_count>
  108. * <utc_offset>-14400</utc_offset>
  109. * <time_zone>US/Eastern</time_zone>
  110. * <profile_background_image_url/>
  111. * <profile_background_tile>false</profile_background_tile>
  112. * <statuses_count>933</statuses_count>
  113. * <following>false</following>
  114. * <notifications>false</notifications>
  115. * </user>
  116. * </status>
  117. * </statuses>
  118. *
  119. * PHP version:
  120. * Tested with PHP 7.0
  121. * ----------------------------------------------------------------------------
  122. * File Authors:
  123. * o Zach Copley
  124. * o Evan Prodromou
  125. * o Robin Millette <robin@millette.info>
  126. * o Siebrand Mazeland <s.mazeland@xs4all.nl>
  127. * o Brion Vibber <brion@pobox.com>
  128. * o Craig Andrews <candrews@integralblue.com>
  129. * o Mikael Nordfeldth <mmn@hethane.se>
  130. * o Bob Mottram <bob@robotics.co.uk>
  131. * o Maiyannah Bishop <maiyannah.bishop@postactiv.com>
  132. *
  133. * Web:
  134. * o postActiv <http://www.postactiv.com>
  135. * o GNU social <https://www.gnu.org/s/social/>
  136. * ============================================================================
  137. */
  138. // This file is formatted so that it provides useful documentation output in
  139. // NaturalDocs. Please be considerate of this before changing formatting.
  140. if (!defined('POSTACTIV')) { exit(1); }
  141. /**
  142. * Returns the most recent notices (default 20) posted by the target user.
  143. * This is the equivalent of 'You and friends' page accessed via Web.
  144. */
  145. class ApiTimelineFriendsAction extends ApiBareAuthAction
  146. {
  147. var $notices = null;
  148. /**
  149. * Take arguments for running
  150. *
  151. * @param array $args $_REQUEST args
  152. *
  153. * @return boolean success flag
  154. *
  155. */
  156. protected function prepare(array $args=array())
  157. {
  158. parent::prepare($args);
  159. $this->target = $this->getTargetProfile($this->arg('id'));
  160. if (!($this->target instanceof Profile)) {
  161. // TRANS: Client error displayed when requesting dents of a user and friends for a user that does not exist.
  162. $this->clientError(_('No such user.'), 404);
  163. }
  164. $this->notices = $this->getNotices();
  165. return true;
  166. }
  167. /**
  168. * Handle the request
  169. *
  170. * Just show the notices
  171. *
  172. * @return void
  173. */
  174. protected function handle()
  175. {
  176. parent::handle();
  177. $this->showTimeline();
  178. }
  179. /**
  180. * Show the timeline of notices
  181. *
  182. * @return void
  183. */
  184. function showTimeline()
  185. {
  186. $sitename = common_config('site', 'name');
  187. // TRANS: Title of API timeline for a user and friends.
  188. // TRANS: %s is a username.
  189. $title = sprintf(_("%s and friends"), $this->target->nickname);
  190. $taguribase = TagURI::base();
  191. $id = "tag:$taguribase:FriendsTimeline:" . $this->target->id;
  192. $subtitle = sprintf(
  193. // TRANS: Message is used as a subtitle. %1$s is a user nickname, %2$s is a site name.
  194. _('Updates from %1$s and friends on %2$s!'),
  195. $this->target->nickname,
  196. $sitename
  197. );
  198. $logo = $this->target->avatarUrl(AVATAR_PROFILE_SIZE);
  199. $link = common_local_url('all',
  200. array('nickname' => $this->target->nickname));
  201. $self = $this->getSelfUri();
  202. switch($this->format) {
  203. case 'xml':
  204. $this->showXmlTimeline($this->notices);
  205. break;
  206. case 'rss':
  207. $this->showRssTimeline(
  208. $this->notices,
  209. $title,
  210. $link,
  211. $subtitle,
  212. null,
  213. $logo,
  214. $self
  215. );
  216. break;
  217. case 'atom':
  218. header('Content-Type: application/atom+xml; charset=utf-8');
  219. $atom = new AtomNoticeFeed($this->auth_user);
  220. $atom->setId($id);
  221. $atom->setTitle($title);
  222. $atom->setSubtitle($subtitle);
  223. $atom->setLogo($logo);
  224. $atom->setUpdated('now');
  225. $atom->addLink($link);
  226. $atom->setSelfLink($self);
  227. $atom->addEntryFromNotices($this->notices);
  228. $this->raw($atom->getString());
  229. break;
  230. case 'json':
  231. $this->showJsonTimeline($this->notices);
  232. break;
  233. case 'as':
  234. header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
  235. $doc = new ActivityStreamJSONDocument($this->auth_user, $title);
  236. $doc->addLink($link, 'alternate', 'text/html');
  237. $doc->addItemsFromNotices($this->notices);
  238. $this->raw($doc->asString());
  239. break;
  240. default:
  241. // TRANS: Client error displayed when coming across a non-supported API method.
  242. $this->clientError(_('API method not found.'), 404);
  243. }
  244. }
  245. /**
  246. * Get notices
  247. *
  248. * @return array notices
  249. */
  250. function getNotices()
  251. {
  252. $notices = array();
  253. $stream = new InboxNoticeStream($this->target, $this->scoped);
  254. $notice = $stream->getNotices(($this->page-1) * $this->count,
  255. $this->count,
  256. $this->since_id,
  257. $this->max_id);
  258. while ($notice->fetch()) {
  259. $notices[] = clone($notice);
  260. }
  261. return $notices;
  262. }
  263. /**
  264. * Is this action read only?
  265. *
  266. * @param array $args other arguments
  267. *
  268. * @return boolean true
  269. */
  270. function isReadOnly($args)
  271. {
  272. return true;
  273. }
  274. /**
  275. * When was this feed last modified?
  276. *
  277. * @return string datestamp of the latest notice in the stream
  278. */
  279. function lastModified()
  280. {
  281. if (!empty($this->notices) && (count($this->notices) > 0)) {
  282. return strtotime($this->notices[0]->created);
  283. }
  284. return null;
  285. }
  286. /**
  287. * An entity tag for this stream
  288. *
  289. * Returns an Etag based on the action name, language, user ID, and
  290. * timestamps of the first and last notice in the timeline
  291. *
  292. * @return string etag
  293. */
  294. function etag()
  295. {
  296. if (!empty($this->notices) && (count($this->notices) > 0)) {
  297. $last = count($this->notices) - 1;
  298. return '"' . implode(
  299. ':',
  300. array($this->arg('action'),
  301. common_user_cache_hash($this->auth_user),
  302. common_language(),
  303. $this->target->id,
  304. strtotime($this->notices[0]->created),
  305. strtotime($this->notices[$last]->created))
  306. )
  307. . '"';
  308. }
  309. return null;
  310. }
  311. }
  312. // END OF FILE
  313. // ============================================================================
  314. ?>