apitimelinefriends.php 10.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Show the friends 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>
31
 * @copyright 2009-2010 StatusNet, Inc.
32
 * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
33 34 35 36
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
/* External API usage documentation. Please update when you change how this method works. */

/*! @page friendstimeline statuses/friends_timeline

    @section Description
    Returns the 20 most recent statuses posted by the authenticating
    user and that user's friends. This is the equivalent of "You and
    friends" page in the web interface.

    @par URL patterns
    @li /api/statuses/friends_timeline.:format
    @li /api/statuses/friends_timeline/:id.:format

    @par Formats (:format)
    xml, json, rss, atom

    @par ID (:id)
    username, user id

    @par HTTP Method(s)
    GET

    @par Requires Authentication
    Sometimes (see: @ref authentication)

    @param user_id (Optional) Specifies a user by ID
    @param screen_name (Optional) Specifies a user by screename (nickname)
    @param since_id (Optional) Returns only statuses with an ID greater
    than (that is, more recent than) the specified ID.
    @param max_id (Optional) Returns only statuses with an ID less than
    (that is, older than) or equal to the specified ID.
    @param count (Optional) Specifies the number of statuses to retrieve.
    @param page (Optional) Specifies the page of results to retrieve.

    @sa @ref authentication
    @sa @ref apiroot

    @subsection usagenotes Usage notes
    @li The URL pattern is relative to the @ref apiroot.
    @li The XML response uses <a href="http://georss.org/Main_Page">GeoRSS</a>
    to encode the latitude and longitude (see example response below <georss:point>).

    @subsection exampleusage Example usage

    @verbatim
    curl http://identi.ca/api/statuses/friends_timeline/evan.xml?count=1&page=2
    @endverbatim

    @subsection exampleresponse Example response

    @verbatim
    <?xml version="1.0"?>
    <statuses type="array">
      <status>
        <text>back from the !yul !drupal meet with Evolving Web folk, @anarcat, @webchick and others, and an interesting refresher on SQL indexing</text>
        <truncated>false</truncated>
        <created_at>Wed Mar 31 01:33:02 +0000 2010</created_at>
        <in_reply_to_status_id/>
Bob Mottram's avatar
Bob Mottram committed
95
        <source>&lt;a href="http://somesourcecode.net/microblog/"&gt;mbpidgin&lt;/a&gt;</source>
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
        <id>26674201</id>
        <in_reply_to_user_id/>
        <in_reply_to_screen_name/>
        <geo/>
        <favorited>false</favorited>
        <user>
          <id>246</id>
          <name>Mark</name>
          <screen_name>lambic</screen_name>
          <location>Montreal, Canada</location>
          <description>Geek</description>
          <profile_image_url>http://avatar.identi.ca/246-48-20080702141545.png</profile_image_url>
          <url>http://lambic.co.uk</url>
          <protected>false</protected>
          <followers_count>73</followers_count>
          <profile_background_color>#F0F2F5</profile_background_color>
          <profile_text_color/>
          <profile_link_color>#002E6E</profile_link_color>
          <profile_sidebar_fill_color>#CEE1E9</profile_sidebar_fill_color>
          <profile_sidebar_border_color/>
          <friends_count>58</friends_count>
          <created_at>Wed Jul 02 14:12:15 +0000 2008</created_at>
          <favourites_count>2</favourites_count>
          <utc_offset>-14400</utc_offset>
          <time_zone>US/Eastern</time_zone>
          <profile_background_image_url/>
          <profile_background_tile>false</profile_background_tile>
          <statuses_count>933</statuses_count>
          <following>false</following>
          <notifications>false</notifications>
        </user>
      </status>
    </statuses>
    @endverbatim
*/

132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
if (!defined('STATUSNET')) {
    exit(1);
}

/**
 * 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 ApiTimelineFriendsAction extends ApiBareAuthAction
{
    var $notices  = null;

    /**
     * Take arguments for running
     *
     * @param array $args $_REQUEST args
     *
     * @return boolean success flag
     *
     */
164
    protected function prepare(array $args=array())
165 166
    {
        parent::prepare($args);
167
        $this->target = $this->getTargetProfile($this->arg('id'));
168

169
        if (!($this->target instanceof Profile)) {
Siebrand Mazeland's avatar
Siebrand Mazeland committed
170
            // TRANS: Client error displayed when requesting dents of a user and friends for a user that does not exist.
171
            $this->clientError(_('No such user.'), 404);
172 173 174 175 176 177 178 179 180 181 182 183 184 185
        }

        $this->notices = $this->getNotices();

        return true;
    }

    /**
     * Handle the request
     *
     * Just show the notices
     *
     * @return void
     */
186
    protected function handle()
187
    {
188
        parent::handle();
189 190 191 192 193 194 195 196 197 198 199
        $this->showTimeline();
    }

    /**
     * Show the timeline of notices
     *
     * @return void
     */
    function showTimeline()
    {
        $sitename   = common_config('site', 'name');
200 201
        // TRANS: Title of API timeline for a user and friends.
        // TRANS: %s is a username.
202
        $title      = sprintf(_("%s and friends"), $this->target->nickname);
203
        $taguribase = TagURI::base();
204
        $id         = "tag:$taguribase:FriendsTimeline:" . $this->target->id;
205 206

        $subtitle = sprintf(
207
            // TRANS: Message is used as a subtitle. %1$s is a user nickname, %2$s is a site name.
208
            _('Updates from %1$s and friends on %2$s!'),
209
            $this->target->nickname,
210
            $sitename
211 212
        );

213
        $logo = $this->target->avatarUrl(AVATAR_PROFILE_SIZE);
214
        $link = common_local_url('all',
215
                    array('nickname' => $this->target->nickname));
216 217
        $self = $this->getSelfUri();

218 219 220 221 222
        switch($this->format) {
        case 'xml':
            $this->showXmlTimeline($this->notices);
            break;
        case 'rss':
223 224 225 226 227 228 229

            $this->showRssTimeline(
                $this->notices,
                $title,
                $link,
                $subtitle,
                null,
230 231
                $logo,
                $self
232
            );
233 234
            break;
        case 'atom':
235 236
            header('Content-Type: application/atom+xml; charset=utf-8');

237
            $atom = new AtomNoticeFeed($this->auth_user);
238 239 240 241 242 243

            $atom->setId($id);
            $atom->setTitle($title);
            $atom->setSubtitle($subtitle);
            $atom->setLogo($logo);
            $atom->setUpdated('now');
244 245
            $atom->addLink($link);
            $atom->setSelfLink($self);
246 247 248 249 250

            $atom->addEntryFromNotices($this->notices);

            $this->raw($atom->getString());

251 252 253 254
            break;
        case 'json':
            $this->showJsonTimeline($this->notices);
            break;
255
        case 'as':
256
            header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
257 258
            $doc = new ActivityStreamJSONDocument($this->auth_user, $title);
            $doc->addLink($link, 'alternate', 'text/html');
259 260 261
            $doc->addItemsFromNotices($this->notices);
            $this->raw($doc->asString());
            break;
262
        default:
263
            // TRANS: Client error displayed when coming across a non-supported API method.
264
            $this->clientError(_('API method not found.'), 404);
265 266 267 268 269 270 271 272 273 274 275 276
        }
    }

    /**
     * Get notices
     *
     * @return array notices
     */
    function getNotices()
    {
        $notices = array();

277
        $stream = new InboxNoticeStream($this->target, $this->scoped);
Bob Mottram's avatar
Bob Mottram committed
278

279 280 281 282
        $notice = $stream->getNotices(($this->page-1) * $this->count,
                                      $this->count,
                                      $this->since_id,
                                      $this->max_id);
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332

        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'),
333
                                       common_user_cache_hash($this->auth_user),
334
                                       common_language(),
335
                                       $this->target->id,
336 337 338 339 340 341 342 343 344
                                       strtotime($this->notices[0]->created),
                                       strtotime($this->notices[$last]->created))
                                 )
              . '"';
        }

        return null;
    }
}