+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Add a notice to a user's list of favorite notices via the API
- *
- * 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 Zach Copley <zach@status.net>
- * @copyright 2009 StatusNet, Inc.
- * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Favorites the status specified in the ID parameter as the authenticating user.
- * Returns the favorite status when successful.
- *
- * @category API
- * @package StatusNet
- * @author Craig Andrews <candrews@integralblue.com>
- * @author Evan Prodromou <evan@status.net>
- * @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 ApiFavoriteCreateAction extends ApiAuthAction
-{
- var $notice = null;
-
- /**
- * Take arguments for running
- *
- * @param array $args $_REQUEST args
- *
- * @return boolean success flag
- */
- function prepare($args)
- {
- parent::prepare($args);
-
- $this->user = $this->auth_user;
- $this->notice = Notice::getKV($this->arg('id'));
- if ($this->notice->repeat_of != '' ) {
- common_log(LOG_DEBUG, 'Trying to Fave '.$this->notice->id.', repeat of '.$this->notice->repeat_of);
- common_log(LOG_DEBUG, 'Will Fave '.$this->notice->repeat_of.' instead');
- $real_notice_id = $this->notice->repeat_of;
- $this->notice = Notice::getKV($real_notice_id);
- }
-
- return true;
- }
-
- /**
- * Handle the request
- *
- * Check the format and show the user info
- *
- * @param array $args $_REQUEST data (unused)
- *
- * @return void
- */
- function handle($args)
- {
- parent::handle($args);
-
- if ($_SERVER['REQUEST_METHOD'] != 'POST') {
- $this->clientError(
- // TRANS: Client error. POST is a HTTP command. It should not be translated.
- _('This method requires a POST.'),
- 400,
- $this->format
- );
- return;
- }
-
- if (!in_array($this->format, array('xml', 'json'))) {
- $this->clientError(
- // TRANS: Client error displayed when coming across a non-supported API method.
- _('API method not found.'),
- 404,
- $this->format
- );
- return;
- }
-
- if (empty($this->notice)) {
- $this->clientError(
- // TRANS: Client error displayed when requesting a status with a non-existing ID.
- _('No status found with that ID.'),
- 404,
- $this->format
- );
- return;
- }
-
- // Note: Twitter lets you fave things repeatedly via API.
-
- if ($this->user->hasFave($this->notice)) {
- $this->clientError(
- // TRANS: Client error displayed when trying to mark a notice favourite that already is a favourite.
- _('This status is already a favorite.'),
- 403,
- $this->format
- );
- return;
- }
-
- $fave = Fave::addNew($this->user->getProfile(), $this->notice);
-
- if (empty($fave)) {
- $this->clientError(
- // TRANS: Client error displayed when marking a notice as favourite fails.
- _('Could not create favorite.'),
- 403,
- $this->format
- );
- return;
- }
-
- $this->notify($fave, $this->notice, $this->user);
- $this->user->blowFavesCache();
-
- if ($this->format == 'xml') {
- $this->showSingleXmlStatus($this->notice);
- } elseif ($this->format == 'json') {
- $this->show_single_json_status($this->notice);
- }
- }
-
- /**
- * Notify the author of the favorite that the user likes their notice
- *
- * @param Favorite $fave the favorite in question
- * @param Notice $notice the notice that's been faved
- * @param User $user the user doing the favoriting
- *
- * @return void
- */
- function notify($fave, $notice, $user)
- {
- $other = User::getKV('id', $notice->profile_id);
- if ($other && $other->id != $user->id) {
- if ($other->email && $other->emailnotifyfav) {
- mail_notify_fave($other, $user, $notice);
- }
- // XXX: notify by IM
- // XXX: notify by SMS
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Remote a notice from a user's list of favorite notices via the API
- *
- * 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 Zach Copley <zach@status.net>
- * @copyright 2009 StatusNet, Inc.
- * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Un-favorites the status specified in the ID parameter as the authenticating user.
- * Returns the un-favorited status in the requested format when successful.
- *
- * @category API
- * @package StatusNet
- * @author Craig Andrews <candrews@integralblue.com>
- * @author Evan Prodromou <evan@status.net>
- * @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 ApiFavoriteDestroyAction extends ApiAuthAction
-{
- var $notice = null;
-
- /**
- * Take arguments for running
- *
- * @param array $args $_REQUEST args
- *
- * @return boolean success flag
- */
- function prepare($args)
- {
- parent::prepare($args);
-
- $this->user = $this->auth_user;
- $this->notice = Notice::getKV($this->arg('id'));
- if ($this->notice->repeat_of != '' ) {
- common_log(LOG_DEBUG, 'Trying to unFave '.$this->notice->id);
- common_log(LOG_DEBUG, 'Will unFave '.$this->notice->repeat_of.' instead');
- $real_notice_id = $this->notice->repeat_of;
- $this->notice = Notice::getKV($real_notice_id);
- }
-
- return true;
- }
-
- /**
- * Handle the request
- *
- * Check the format and show the user info
- *
- * @param array $args $_REQUEST data (unused)
- *
- * @return void
- */
- function handle($args)
- {
- parent::handle($args);
-
- if ($_SERVER['REQUEST_METHOD'] != 'POST') {
- $this->clientError(
- // TRANS: Client error. POST is a HTTP command. It should not be translated.
- _('This method requires a POST.'),
- 400,
- $this->format
- );
- return;
- }
-
- if (!in_array($this->format, array('xml', 'json'))) {
- $this->clientError(
- // TRANS: Client error displayed when coming across a non-supported API method.
- _('API method not found.'),
- 404,
- $this->format
- );
- return;
- }
-
- if (empty($this->notice)) {
- $this->clientError(
- // TRANS: Client error displayed when trying to remove a favourite with an invalid ID.
- _('No status found with that ID.'),
- 404,
- $this->format
- );
- return;
- }
-
- $fave = new Fave();
- $fave->user_id = $this->user->id;
- $fave->notice_id = $this->notice->id;
-
- if (!$fave->find(true)) {
- $this->clientError(
- // TRANS: Client error displayed when trying to remove a favourite that was not a favourite.
- _('That status is not a favorite.'),
- 403,
- $this->favorite
- );
- return;
- }
-
- $result = $fave->delete();
-
- if (!$result) {
- common_log_db_error($fave, 'DELETE', __FILE__);
- $this->clientError(
- // TRANS: Client error displayed when removing a favourite has failed.
- _('Could not delete favorite.'),
- 404,
- $this->format
- );
- return;
- }
-
- $this->user->blowFavesCache();
-
- if ($this->format == 'xml') {
- $this->showSingleXmlStatus($this->notice);
- } elseif ($this->format == 'json') {
- $this->show_single_json_status($this->notice);
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Show up to 100 favs of a notice
- *
- * 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 GNUsocial
- * @author Hannes Mannerheim <h@nnesmannerhe.im>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://www.gnu.org/software/social/
- */
-
-if (!defined('GNUSOCIAL')) { exit(1); }
-
-/**
- * Show up to 100 favs of a notice
- *
- */
-class ApiStatusesFavsAction extends ApiAuthAction
-{
- const MAXCOUNT = 100;
-
- var $original = null; // Notice object for which to retrieve favs
- var $cnt = self::MAXCOUNT;
-
- /**
- * Take arguments for running
- *
- * @param array $args $_REQUEST args
- *
- * @return boolean success flag
- */
- protected function prepare(array $args=array())
- {
- parent::prepare($args);
-
- if ($this->format !== 'json') {
- $this->clientError('This method currently only serves JSON.', 415);
- }
-
- $id = $this->trimmed('id');
-
- $this->original = Notice::getKV('id', $id);
-
- if (!($this->original instanceof Notice)) {
- // TRANS: Client error displayed trying to display redents of a non-exiting notice.
- $this->clientError(_('No such notice.'), 400);
- }
-
- $cnt = $this->trimmed('count');
-
- if (empty($cnt) || !is_integer($cnt)) {
- $cnt = 100;
- } else {
- $this->cnt = min((int)$cnt, self::MAXCOUNT);
- }
-
- return true;
- }
-
- /**
- * Handle the request
- *
- * Get favs and return them as json object
- *
- * @param array $args $_REQUEST data (unused)
- *
- * @return void
- */
- protected function handle()
- {
- parent::handle();
-
- $fave = new Fave();
- $fave->selectAdd();
- $fave->selectAdd('user_id');
- $fave->notice_id = $this->original->id;
- $fave->orderBy('modified');
- if (!is_null($this->cnt)) {
- $fave->limit(0, $this->cnt);
- }
-
- $ids = $fave->fetchAll('user_id');
-
- // get nickname and profile image
- $ids_with_profile_data = array();
- $i=0;
- foreach($ids as $id) {
- $profile = Profile::getKV('id', $id);
- $ids_with_profile_data[$i]['user_id'] = $id;
- $ids_with_profile_data[$i]['nickname'] = $profile->nickname;
- $ids_with_profile_data[$i]['fullname'] = $profile->fullname;
- $ids_with_profile_data[$i]['profileurl'] = $profile->profileurl;
- $profile = new Profile();
- $profile->id = $id;
- $avatarurl = $profile->avatarUrl(24);
- $ids_with_profile_data[$i]['avatarurl'] = $avatarurl;
- $i++;
- }
-
- $this->initDocument('json');
- $this->showJsonObjects($ids_with_profile_data);
- $this->endDocument('json');
- }
-
- /**
- * Return true if read only.
- *
- * MAY override
- *
- * @param array $args other arguments
- *
- * @return boolean is read only action?
- */
-
- function isReadOnly($args)
- {
- return true;
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Show a user's favorite notices
- *
- * 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 Zach Copley <zach@status.net>
- * @copyright 2009-2010 StatusNet, Inc.
- * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Returns the 20 most recent favorite notices for the authenticating user or user
- * specified by the ID parameter in the requested format.
- *
- * @category API
- * @package StatusNet
- * @author Craig Andrews <candrews@integralblue.com>
- * @author Evan Prodromou <evan@status.net>
- * @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 ApiTimelineFavoritesAction extends ApiBareAuthAction
-{
- var $notices = null;
-
- /**
- * Take arguments for running
- *
- * @param array $args $_REQUEST args
- *
- * @return boolean success flag
- */
- protected function prepare(array $args=array())
- {
- parent::prepare($args);
-
- $this->target = $this->getTargetProfile($this->arg('id'));
-
- if (!($this->target instanceof Profile)) {
- // TRANS: Client error displayed when requesting most recent favourite notices by a user for a non-existing user.
- $this->clientError(_('No such user.'), 404);
- }
-
- $this->notices = $this->getNotices();
-
- return true;
- }
-
- /**
- * Handle the request
- *
- * Just show the notices
- *
- * @return void
- */
- protected function handle()
- {
- parent::handle();
- $this->showTimeline();
- }
-
- /**
- * Show the timeline of notices
- *
- * @return void
- */
- function showTimeline()
- {
- $sitename = common_config('site', 'name');
- $title = sprintf(
- // TRANS: Title for timeline of most recent favourite notices by a user.
- // TRANS: %1$s is the StatusNet sitename, %2$s is a user nickname.
- _('%1$s / Favorites from %2$s'),
- $sitename,
- $this->target->nickname
- );
-
- $taguribase = TagURI::base();
- $id = "tag:$taguribase:Favorites:" . $this->target->id;
-
- $subtitle = sprintf(
- // TRANS: Subtitle for timeline of most recent favourite notices by a user.
- // TRANS: %1$s is the StatusNet sitename, %2$s is a user's full name,
- // TRANS: %3$s is a user nickname.
- _('%1$s updates favorited by %2$s / %3$s.'),
- $sitename,
- $this->target->getBestName(),
- $this->target->nickname
- );
-
- $logo = $this->target->avatarUrl(AVATAR_PROFILE_SIZE);
- $link = common_local_url('showfavorites',
- array('nickname' => $this->target->nickname));
- $self = $this->getSelfUri();
-
- switch($this->format) {
- case 'xml':
- $this->showXmlTimeline($this->notices);
- break;
- case 'rss':
- $this->showRssTimeline(
- $this->notices,
- $title,
- $link,
- $subtitle,
- null,
- $logo,
- $self
- );
- break;
- case 'atom':
- header('Content-Type: application/atom+xml; charset=utf-8');
-
- $atom = new AtomNoticeFeed($this->auth_user);
-
- $atom->setId($id);
- $atom->setTitle($title);
- $atom->setSubtitle($subtitle);
- $atom->setLogo($logo);
- $atom->setUpdated('now');
-
- $atom->addLink($link);
- $atom->setSelfLink($self);
-
- $atom->addEntryFromNotices($this->notices);
-
- $this->raw($atom->getString());
- break;
- case 'json':
- $this->showJsonTimeline($this->notices);
- break;
- case 'as':
- header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
- $doc = new ActivityStreamJSONDocument($this->auth_user);
- $doc->setTitle($title);
- $doc->addLink($link,'alternate', 'text/html');
- $doc->addItemsFromNotices($this->notices);
- $this->raw($doc->asString());
- break;
- default:
- // TRANS: Client error displayed when coming across a non-supported API method.
- $this->clientError(_('API method not found.'), 404);
- }
- }
-
- /**
- * Get notices
- *
- * @return array notices
- */
- function getNotices()
- {
- $notices = array();
-
- common_debug("since id = " . $this->since_id . " max id = " . $this->max_id);
-
- if (!empty($this->auth_user) && $this->auth_user->id == $this->target->id) {
- $notice = $this->target->favoriteNotices(
- true,
- ($this->page-1) * $this->count,
- $this->count,
- $this->since_id,
- $this->max_id
- );
- } else {
- $notice = $this->target->favoriteNotices(
- false,
- ($this->page-1) * $this->count,
- $this->count,
- $this->since_id,
- $this->max_id
- );
- }
-
- 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'),
- common_user_cache_hash($this->auth_user),
- common_language(),
- $this->target->id,
- strtotime($this->notices[0]->created),
- strtotime($this->notices[$last]->created))
- )
- . '"';
- }
-
- return null;
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * Feed of ActivityStreams 'favorite' actions
- *
- * PHP version 5
- *
- * 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 AtomPub
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Feed of ActivityStreams 'favorite' actions
- *
- * @category AtomPub
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class AtompubfavoritefeedAction extends ApiAuthAction
-{
- private $_profile = null;
- private $_faves = null;
-
- /**
- * For initializing members of the class.
- *
- * @param array $argarray misc. arguments
- *
- * @return boolean true
- */
- function prepare($argarray)
- {
- parent::prepare($argarray);
-
- $this->_profile = Profile::getKV('id', $this->trimmed('profile'));
-
- if (empty($this->_profile)) {
- // TRANS: Client exception thrown when requesting a favorite feed for a non-existing profile.
- throw new ClientException(_('No such profile.'), 404);
- }
-
- $offset = ($this->page-1) * $this->count;
- $limit = $this->count + 1;
-
- $this->_faves = Fave::byProfile($this->_profile->id,
- $offset,
- $limit);
-
- return true;
- }
-
- /**
- * Handler method
- *
- * @param array $argarray is ignored since it's now passed in in prepare()
- *
- * @return void
- */
- function handle($argarray=null)
- {
- parent::handle($argarray);
-
- switch ($_SERVER['REQUEST_METHOD']) {
- case 'HEAD':
- case 'GET':
- $this->showFeed();
- break;
- case 'POST':
- $this->addFavorite();
- break;
- default:
- // TRANS: Client exception thrown when using an unsupported HTTP method.
- throw new ClientException(_('HTTP method not supported.'), 405);
- return;
- }
-
- return;
- }
-
- /**
- * Show a feed of favorite activity streams objects
- *
- * @return void
- */
- function showFeed()
- {
- header('Content-Type: application/atom+xml; charset=utf-8');
-
- $url = common_local_url('AtomPubFavoriteFeed',
- array('profile' => $this->_profile->id));
-
- $feed = new Atom10Feed(true);
-
- $feed->addNamespace('activity',
- 'http://activitystrea.ms/spec/1.0/');
-
- $feed->addNamespace('poco',
- 'http://portablecontacts.net/spec/1.0');
-
- $feed->addNamespace('media',
- 'http://purl.org/syndication/atommedia');
-
- $feed->id = $url;
-
- $feed->setUpdated('now');
-
- $feed->addAuthor($this->_profile->getBestName(),
- $this->_profile->getURI());
-
- // TRANS: Title for Atom favorites feed.
- // TRANS: %s is a user nickname.
- $feed->setTitle(sprintf(_("%s favorites"),
- $this->_profile->getBestName()));
-
- // TRANS: Subtitle for Atom favorites feed.
- // TRANS: %1$s is a user nickname, %2$s is the StatusNet sitename.
- $feed->setSubtitle(sprintf(_('Notices %1$s has favorited on %2$s'),
- $this->_profile->getBestName(),
- common_config('site', 'name')));
-
- $feed->addLink(common_local_url('showfavorites',
- array('nickname' =>
- $this->_profile->nickname)));
-
- $feed->addLink($url,
- array('rel' => 'self',
- 'type' => 'application/atom+xml'));
-
- // If there's more...
-
- if ($this->page > 1) {
- $feed->addLink($url,
- array('rel' => 'first',
- 'type' => 'application/atom+xml'));
-
- $feed->addLink(common_local_url('AtomPubFavoriteFeed',
- array('profile' =>
- $this->_profile->id),
- array('page' =>
- $this->page - 1)),
- array('rel' => 'prev',
- 'type' => 'application/atom+xml'));
- }
-
- if ($this->_faves->N > $this->count) {
-
- $feed->addLink(common_local_url('AtomPubFavoriteFeed',
- array('profile' =>
- $this->_profile->id),
- array('page' =>
- $this->page + 1)),
- array('rel' => 'next',
- 'type' => 'application/atom+xml'));
- }
-
- $i = 0;
-
- while ($this->_faves->fetch()) {
-
- // We get one more than needed; skip that one
-
- $i++;
-
- if ($i > $this->count) {
- break;
- }
-
- $act = $this->_faves->asActivity();
- $feed->addEntryRaw($act->asString(false, false, false));
- }
-
- $this->raw($feed->getString());
- }
-
- /**
- * add a new favorite
- *
- * @return void
- */
- function addFavorite()
- {
- // XXX: Refactor this; all the same for atompub
-
- if (empty($this->auth_user) ||
- $this->auth_user->id != $this->_profile->id) {
- // TRANS: Client exception thrown when trying to set a favorite for another user.
- throw new ClientException(_("Cannot add someone else's".
- " subscription."), 403);
- }
-
- $xml = file_get_contents('php://input');
-
- $dom = DOMDocument::loadXML($xml);
-
- if ($dom->documentElement->namespaceURI != Activity::ATOM ||
- $dom->documentElement->localName != 'entry') {
- // TRANS: Client error displayed when not using an Atom entry.
- throw new ClientException(_('Atom post must be an Atom entry.'));
- return;
- }
-
- $activity = new Activity($dom->documentElement);
-
- $fave = null;
-
- if (Event::handle('StartAtomPubNewActivity', array(&$activity))) {
-
- if ($activity->verb != ActivityVerb::FAVORITE) {
- // TRANS: Client exception thrown when trying use an incorrect activity verb for the Atom pub method.
- throw new ClientException(_('Can only handle favorite activities.'));
- return;
- }
-
- $note = $activity->objects[0];
-
- if (!in_array($note->type, array(ActivityObject::NOTE,
- ActivityObject::BLOGENTRY,
- ActivityObject::STATUS))) {
- // TRANS: Client exception thrown when trying favorite an object that is not a notice.
- throw new ClientException(_('Can only fave notices.'));
- return;
- }
-
- $notice = Notice::getKV('uri', $note->id);
-
- if (empty($notice)) {
- // XXX: import from listed URL or something
- // TRANS: Client exception thrown when trying favorite a notice without content.
- throw new ClientException(_('Unknown notice.'));
- }
-
- $old = Fave::pkeyGet(array('user_id' => $this->auth_user->id,
- 'notice_id' => $notice->id));
-
- if (!empty($old)) {
- // TRANS: Client exception thrown when trying favorite an already favorited notice.
- throw new ClientException(_('Already a favorite.'));
- }
-
- $profile = $this->auth_user->getProfile();
-
- $fave = Fave::addNew($profile, $notice);
-
- if (!empty($fave)) {
- $this->_profile->blowFavesCache();
- $this->notify($fave, $notice, $this->auth_user);
- }
-
- Event::handle('EndAtomPubNewActivity', array($activity, $fave));
- }
-
- if (!empty($fave)) {
- $act = $fave->asActivity();
-
- header('Content-Type: application/atom+xml; charset=utf-8');
- header('Content-Location: ' . $act->selfLink);
-
- $this->startXML();
- $this->raw($act->asString(true, true, true));
- $this->endXML();
- }
- }
-
- /**
- * Return true if read only.
- *
- * MAY override
- *
- * @param array $args other arguments
- *
- * @return boolean is read only action?
- */
- function isReadOnly($args)
- {
- if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
- $_SERVER['REQUEST_METHOD'] == 'HEAD') {
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * Return last modified, if applicable.
- *
- * MAY override
- *
- * @return string last modified http header
- */
- function lastModified()
- {
- // For comparison with If-Last-Modified
- // If not applicable, return null
- return null;
- }
-
- /**
- * Return etag, if applicable.
- *
- * MAY override
- *
- * @return string etag http header
- */
- function etag()
- {
- return null;
- }
-
- /**
- * Does this require authentication?
- *
- * @return boolean true if delete, else false
- */
- function requiresAuth()
- {
- if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
- $_SERVER['REQUEST_METHOD'] == 'HEAD') {
- return false;
- } else {
- return true;
- }
- }
-
- /**
- * Notify the author of the favorite that the user likes their notice
- *
- * @param Favorite $fave the favorite in question
- * @param Notice $notice the notice that's been faved
- * @param User $user the user doing the favoriting
- *
- * @return void
- */
- function notify($fave, $notice, $user)
- {
- $other = User::getKV('id', $notice->profile_id);
- if ($other && $other->id != $user->id) {
- if ($other->email && $other->emailnotifyfav) {
- mail_notify_fave($other, $user, $notice);
- }
- // XXX: notify by IM
- // XXX: notify by SMS
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * Show a single favorite in Atom Activity Streams format
- *
- * PHP version 5
- *
- * 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 AtomPub
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Show a single favorite in Atom Activity Streams format.
- *
- * Can also be used to delete a favorite.
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class AtompubshowfavoriteAction extends ApiAuthAction
-{
- private $_profile = null;
- private $_notice = null;
- private $_fave = null;
-
- /**
- * For initializing members of the class.
- *
- * @param array $argarray misc. arguments
- *
- * @return boolean true
- */
- function prepare($argarray)
- {
- parent::prepare($argarray);
-
- $profileId = $this->trimmed('profile');
- $noticeId = $this->trimmed('notice');
-
- $this->_profile = Profile::getKV('id', $profileId);
-
- if (empty($this->_profile)) {
- // TRANS: Client exception.
- throw new ClientException(_('No such profile.'), 404);
- }
-
- $this->_notice = Notice::getKV('id', $noticeId);
-
- if (empty($this->_notice)) {
- // TRANS: Client exception thrown when referencing a non-existing notice.
- throw new ClientException(_('No such notice.'), 404);
- }
-
- $this->_fave = Fave::pkeyGet(array('user_id' => $profileId,
- 'notice_id' => $noticeId));
-
- if (empty($this->_fave)) {
- // TRANS: Client exception thrown when referencing a non-existing favorite.
- throw new ClientException(_('No such favorite.'), 404);
- }
-
- return true;
- }
-
- /**
- * Handler method
- *
- * @param array $argarray is ignored since it's now passed in in prepare()
- *
- * @return void
- */
- function handle($argarray=null)
- {
- parent::handle($argarray);
-
- switch ($_SERVER['REQUEST_METHOD']) {
- case GET:
- case HEAD:
- $this->showFave();
- break;
- case DELETE:
- $this->deleteFave();
- break;
- default:
- // TRANS: Client exception thrown using an unsupported HTTP method.
- throw new ClientException(_('HTTP method not supported.'),
- 405);
- }
- return true;
- }
-
- /**
- * Show a single favorite, in ActivityStreams format
- *
- * @return void
- */
- function showFave()
- {
- $activity = $this->_fave->asActivity();
-
- header('Content-Type: application/atom+xml; charset=utf-8');
-
- $this->startXML();
- $this->raw($activity->asString(true, true, true));
- $this->endXML();
-
- return;
- }
-
- /**
- * Delete the favorite
- *
- * @return void
- */
- function deleteFave()
- {
- if (empty($this->auth_user) ||
- $this->auth_user->id != $this->_profile->id) {
- // TRANS: Client exception thrown when trying to remove a favorite notice of another user.
- throw new ClientException(_("Cannot delete someone else's".
- " favorite."), 403);
- }
-
- $this->_fave->delete();
-
- return;
- }
-
- /**
- * Return true if read only.
- *
- * MAY override
- *
- * @param array $args other arguments
- *
- * @return boolean is read only action?
- */
- function isReadOnly($args)
- {
- if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
- $_SERVER['REQUEST_METHOD'] == 'HEAD') {
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * Return last modified, if applicable.
- *
- * MAY override
- *
- * @return string last modified http header
- */
- function lastModified()
- {
- return max(strtotime($this->_profile->modified),
- strtotime($this->_notice->modified),
- strtotime($this->_fave->modified));
- }
-
- /**
- * Return etag, if applicable.
- *
- * MAY override
- *
- * @return string etag http header
- */
- function etag()
- {
- $mtime = strtotime($this->_fave->modified);
-
- return 'W/"' . implode(':', array('AtomPubShowFavorite',
- $this->_profile->id,
- $this->_notice->id,
- $mtime)) . '"';
- }
-
- /**
- * Does this require authentication?
- *
- * @return boolean true if delete, else false
- */
- function requiresAuth()
- {
- if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
- $_SERVER['REQUEST_METHOD'] == 'HEAD') {
- return false;
- } else {
- return true;
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * Disfavor action.
- *
- * PHP version 5
- *
- * @category Action
- * @package GNUsocial
- * @author Evan Prodromou <evan@status.net>
- * @author Robin Millette <millette@status.net>
- * @author Mikael Nordfeldth <mmn@hethane.se>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://www.gnu.org/software/social/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('GNUSOCIAL')) { exit(1); }
-
-/**
- * DisfavorAction class.
- *
- * @category Action
- * @package GNUsocial
- * @author Evan Prodromou <evan@status.net>
- * @author Robin Millette <millette@status.net>
- * @author Mikael Nordfeldth <mmn@hethane.se>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://www.gnu.org/software/social/
- */
-class DisfavorAction extends FormAction
-{
- public function showForm($msg=null, $success=false)
- {
- if ($success) {
- common_redirect(common_local_url('showfavorites',
- array('nickname' => $this->scoped->nickname)), 303);
- }
- parent::showForm($msg, $success);
- }
-
- protected function handlePost()
- {
- $id = $this->trimmed('notice');
- $notice = Notice::getKV($id);
- if (!$notice instanceof Notice) {
- $this->serverError(_('Notice not found'));
- }
-
- $fave = new Fave();
- $fave->user_id = $this->scoped->id;
- $fave->notice_id = $notice->id;
- if (!$fave->find(true)) {
- throw new NoResultException($fave);
- }
- $result = $fave->delete();
- if (!$result) {
- common_log_db_error($fave, 'DELETE', __FILE__);
- // TRANS: Server error displayed when removing a favorite from the database fails.
- $this->serverError(_('Could not delete favorite.'));
- }
- $this->scoped->blowFavesCache();
- if (StatusNet::isAjax()) {
- $this->startHTML('text/xml;charset=utf-8');
- $this->elementStart('head');
- // TRANS: Title for page on which favorites can be added.
- $this->element('title', null, _('Add to favorites'));
- $this->elementEnd('head');
- $this->elementStart('body');
- $favor = new FavorForm($this, $notice);
- $favor->show();
- $this->elementEnd('body');
- $this->endHTML();
- exit;
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * Favor action.
- *
- * PHP version 5
- *
- * @category Action
- * @package GNUsocial
- * @author Evan Prodromou <evan@status.net>
- * @author Robin Millette <millette@status.net>
- * @author Mikael Nordfeldth <mmn@hethane.se>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://www.gnu.org/software/social/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('GNUSOCIAL')) { exit(1); }
-
-require_once INSTALLDIR.'/lib/mail.php';
-
-/**
- * FavorAction class.
- *
- * @category Action
- * @package GNUsocial
- * @author Evan Prodromou <evan@status.net>
- * @author Robin Millette <millette@status.net>
- * @author Mikael Nordfeldth <mmn@hethane.se>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://www.gnu.org/software/social/
- */
-class FavorAction extends FormAction
-{
- protected $needPost = true;
-
- protected function handlePost()
- {
- $id = $this->trimmed('notice');
- $notice = Notice::getKV($id);
- if (!($notice instanceof Notice)) {
- $this->serverError(_('Notice not found'));
- }
- if ($this->scoped->hasFave($notice)) {
- // TRANS: Client error displayed when trying to mark a notice as favorite that already is a favorite.
- $this->clientError(_('This notice is already a favorite!'));
- }
- $fave = Fave::addNew($this->scoped, $notice);
- if (!$fave) {
- // TRANS: Server error displayed when trying to mark a notice as favorite fails in the database.
- $this->serverError(_('Could not create favorite.'));
- }
- $this->notify($notice, $this->scoped->getUser());
- $this->scoped->blowFavesCache();
- if (StatusNet::isAjax()) {
- $this->startHTML('text/xml;charset=utf-8');
- $this->elementStart('head');
- // TRANS: Page title for page on which favorite notices can be unfavourited.
- $this->element('title', null, _('Disfavor favorite.'));
- $this->elementEnd('head');
- $this->elementStart('body');
- $disfavor = new DisFavorForm($this, $notice);
- $disfavor->show();
- $this->elementEnd('body');
- $this->endHTML();
- exit;
- }
- common_redirect(common_local_url('showfavorites',
- array('nickname' => $this->scoped->nickname)),
- 303);
- }
-
- /**
- * Notifies a user when their notice is favorited.
- *
- * @param class $notice favorited notice
- * @param class $user user declaring a favorite
- *
- * @return void
- */
- function notify($notice, $user)
- {
- $other = User::getKV('id', $notice->profile_id);
- if ($other && $other->id != $user->id) {
- if ($other->email && $other->emailnotifyfav) {
- mail_notify_fave($other, $user, $notice);
- }
- // XXX: notify by IM
- // XXX: notify by SMS
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * List of popular notices
- *
- * 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 Public
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2008-2009 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-require_once INSTALLDIR.'/lib/publicgroupnav.php';
-require_once INSTALLDIR.'/lib/noticelist.php';
-
-/**
- * List of popular notices
- *
- * We provide a list of the most popular notices. Popularity
- * is measured by
- *
- * @category Personal
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @author Evan Prodromou <evan@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 FavoritedAction extends Action
-{
- var $page = null;
-
- /**
- * Title of the page
- *
- * @return string Title of the page
- */
-
- function title()
- {
- if ($this->page == 1) {
- // TRANS: Page title for first page of favorited notices.
- return _('Popular notices');
- } else {
- // TRANS: Page title for all but first page of favorited notices.
- // TRANS: %d is the page number being displayed.
- return sprintf(_('Popular notices, page %d'), $this->page);
- }
- }
-
- /**
- * Instructions for use
- *
- * @return instructions for use
- */
- function getInstructions()
- {
- // TRANS: Description on page displaying favorited notices.
- return _('The most popular notices on the site right now.');
- }
-
- /**
- * Is this page read-only?
- *
- * @return boolean true
- */
- function isReadOnly($args)
- {
- return true;
- }
-
- /**
- * Take arguments for running
- *
- * @param array $args $_REQUEST args
- *
- * @return boolean success flag
- *
- * @todo move queries from showContent() to here
- */
- function prepare($args)
- {
- parent::prepare($args);
- $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
-
- common_set_returnto($this->selfUrl());
-
- return true;
- }
-
- /**
- * Handle request
- *
- * Shows a page with list of favorite notices
- *
- * @param array $args $_REQUEST args; handled in prepare()
- *
- * @return void
- */
- function handle($args)
- {
- parent::handle($args);
-
- $this->showPage();
- }
-
- /**
- * Show the page notice
- *
- * Shows instructions for the page
- *
- * @return void
- */
- function showPageNotice()
- {
- $instr = $this->getInstructions();
- $output = common_markup_to_html($instr);
-
- $this->elementStart('div', 'instructions');
- $this->raw($output);
- $this->elementEnd('div');
- }
-
- function showEmptyList()
- {
- // TRANS: Text displayed instead of a list when a site does not yet have any favourited notices.
- $message = _('Favorite notices appear on this page but no one has favorited one yet.') . ' ';
-
- if (common_logged_in()) {
- // TRANS: Additional text displayed instead of a list when a site does not yet have any favourited notices for logged in users.
- $message .= _('Be the first to add a notice to your favorites by clicking the fave button next to any notice you like.');
- }
- else {
- // TRANS: Additional text displayed instead of a list when a site does not yet have any favourited notices for not logged in users.
- // TRANS: %%action.register%% is a registration link. "[link text](link)" is Mark Down. Do not change the formatting.
- $message .= _('Why not [register an account](%%action.register%%) and be the first to add a notice to your favorites!');
- }
-
- $this->elementStart('div', 'guide');
- $this->raw(common_markup_to_html($message));
- $this->elementEnd('div');
- }
-
- /**
- * Content area
- *
- * Shows the list of popular notices
- *
- * @return void
- */
- function showContent()
- {
- $stream = new PopularNoticeStream(Profile::current());
- $notice = $stream->getNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE+1);
-
- $nl = new NoticeList($notice, $this);
-
- $cnt = $nl->show();
-
- if ($cnt == 0) {
- $this->showEmptyList();
- }
-
- $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
- $this->page, 'favorited');
- }
-}
+++ /dev/null
-<?php
-/**
- * RSS feed for user favorites action class.
- *
- * PHP version 5
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @author Robin Millette <millette@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-require_once INSTALLDIR.'/lib/rssaction.php';
-
-/**
- * RSS feed for user favorites action class.
- *
- * Formatting of RSS handled by Rss10Action
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @author Robin Millette <millette@status.net>
- * @author Zach Copley <zach@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- */
-class FavoritesrssAction extends Rss10Action
-{
- /** The user whose favorites to display */
-
- var $user = null;
-
- /**
- * Find the user to display by supplied nickname
- *
- * @param array $args Arguments from $_REQUEST
- *
- * @return boolean success
- */
- function prepare($args)
- {
- parent::prepare($args);
-
- $nickname = $this->trimmed('nickname');
- $this->user = User::getKV('nickname', $nickname);
-
- if (!$this->user) {
- // TRANS: Client error displayed when trying to get the RSS feed with favorites of a user that does not exist.
- $this->clientError(_('No such user.'));
- } else {
- $this->notices = $this->getNotices($this->limit);
- return true;
- }
- }
-
- /**
- * Get notices
- *
- * @param integer $limit max number of notices to return
- *
- * @return array notices
- */
- function getNotices($limit=0)
- {
- $user = $this->user;
- $notice = $user->favoriteNotices(false, 0, $limit);
- $notices = array();
- while ($notice->fetch()) {
- $notices[] = clone($notice);
- }
- return $notices;
- }
-
- /**
- * Get channel.
- *
- * @return array associative array on channel information
- */
- function getChannel()
- {
- $user = $this->user;
- $c = array('url' => common_local_url('favoritesrss',
- array('nickname' =>
- $user->nickname)),
- // TRANS: Title of RSS feed with favourite notices of a user.
- // TRANS: %s is a user's nickname.
- 'title' => sprintf(_("%s's favorite notices"), $user->nickname),
- 'link' => common_local_url('showfavorites',
- array('nickname' =>
- $user->nickname)),
- // TRANS: Desciption of RSS feed with favourite notices of a user.
- // TRANS: %1$s is a user's nickname, %2$s is the name of the StatusNet site.
- 'description' => sprintf(_('Updates favored by %1$s on %2$s!'),
- $user->nickname, common_config('site', 'name')));
- return $c;
- }
-
- /**
- * Get image.
- *
- * @return void
- */
- function getImage()
- {
- return null;
- }
-
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * List of replies
- *
- * 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 Personal
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2008-2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-require_once INSTALLDIR.'/lib/personalgroupnav.php';
-require_once INSTALLDIR.'/lib/noticelist.php';
-require_once INSTALLDIR.'/lib/feedlist.php';
-
-/**
- * List of replies
- *
- * @category Personal
- * @package StatusNet
- * @author Evan Prodromou <evan@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 ShowfavoritesAction extends Action
-{
- /** User we're getting the faves of */
- var $user = null;
- /** Page of the faves we're on */
- var $page = null;
-
- /**
- * Is this a read-only page?
- *
- * @return boolean true
- */
- function isReadOnly($args)
- {
- return true;
- }
-
- /**
- * Title of the page
- *
- * Includes name of user and page number.
- *
- * @return string title of page
- */
- function title()
- {
- if ($this->page == 1) {
- // TRANS: Title for first page of favourite notices of a user.
- // TRANS: %s is the user for whom the favourite notices are displayed.
- return sprintf(_('%s\'s favorite notices'), $this->user->nickname);
- } else {
- // TRANS: Title for all but the first page of favourite notices of a user.
- // TRANS: %1$s is the user for whom the favourite notices are displayed, %2$d is the page number.
- return sprintf(_('%1$s\'s favorite notices, page %2$d'),
- $this->user->nickname,
- $this->page);
- }
- }
-
- /**
- * Prepare the object
- *
- * Check the input values and initialize the object.
- * Shows an error page on bad input.
- *
- * @param array $args $_REQUEST data
- *
- * @return boolean success flag
- */
- function prepare($args)
- {
- parent::prepare($args);
-
- $nickname = common_canonical_nickname($this->arg('nickname'));
-
- $this->user = User::getKV('nickname', $nickname);
-
- if (!$this->user) {
- // TRANS: Client error displayed when trying to display favourite notices for a non-existing user.
- $this->clientError(_('No such user.'));
- }
-
- $this->page = $this->trimmed('page');
-
- if (!$this->page) {
- $this->page = 1;
- }
-
- common_set_returnto($this->selfUrl());
-
- $cur = common_current_user();
-
- if (!empty($cur) && $cur->id == $this->user->id) {
-
- // Show imported/gateway notices as well as local if
- // the user is looking at their own favorites
-
- $this->notice = $this->user->favoriteNotices(true, ($this->page-1)*NOTICES_PER_PAGE,
- NOTICES_PER_PAGE + 1);
- } else {
- $this->notice = $this->user->favoriteNotices(false, ($this->page-1)*NOTICES_PER_PAGE,
- NOTICES_PER_PAGE + 1);
- }
-
- if (empty($this->notice)) {
- // TRANS: Server error displayed when favourite notices could not be retrieved from the database.
- $this->serverError(_('Could not retrieve favorite notices.'));
- }
-
- if($this->page > 1 && $this->notice->N == 0){
- // TRANS: Server error when page not found (404)
- $this->serverError(_('No such page.'),$code=404);
- }
-
- return true;
- }
-
- /**
- * Handle a request
- *
- * Just show the page. All args already handled.
- *
- * @param array $args $_REQUEST data
- *
- * @return void
- */
- function handle($args)
- {
- parent::handle($args);
- $this->showPage();
- }
-
- /**
- * Feeds for the <head> section
- *
- * @return array Feed objects to show
- */
- function getFeeds()
- {
- return array(new Feed(Feed::JSON,
- common_local_url('ApiTimelineFavorites',
- array(
- 'id' => $this->user->nickname,
- 'format' => 'as')),
- // TRANS: Feed link text. %s is a username.
- sprintf(_('Feed for favorites of %s (Activity Streams JSON)'),
- $this->user->nickname)),
- new Feed(Feed::RSS1,
- common_local_url('favoritesrss',
- array('nickname' => $this->user->nickname)),
- // TRANS: Feed link text. %s is a username.
- sprintf(_('Feed for favorites of %s (RSS 1.0)'),
- $this->user->nickname)),
- new Feed(Feed::RSS2,
- common_local_url('ApiTimelineFavorites',
- array(
- 'id' => $this->user->nickname,
- 'format' => 'rss')),
- // TRANS: Feed link text. %s is a username.
- sprintf(_('Feed for favorites of %s (RSS 2.0)'),
- $this->user->nickname)),
- new Feed(Feed::ATOM,
- common_local_url('ApiTimelineFavorites',
- array(
- 'id' => $this->user->nickname,
- 'format' => 'atom')),
- // TRANS: Feed link text. %s is a username.
- sprintf(_('Feed for favorites of %s (Atom)'),
- $this->user->nickname)));
- }
-
- function showEmptyListMessage()
- {
- if (common_logged_in()) {
- $current_user = common_current_user();
- if ($this->user->id === $current_user->id) {
- // TRANS: Text displayed instead of favourite notices for the current logged in user that has no favourites.
- $message = _('You haven\'t chosen any favorite notices yet. Click the fave button on notices you like to bookmark them for later or shed a spotlight on them.');
- } else {
- // TRANS: Text displayed instead of favourite notices for a user that has no favourites while logged in.
- // TRANS: %s is a username.
- $message = sprintf(_('%s hasn\'t added any favorite notices yet. Post something interesting they would add to their favorites :)'), $this->user->nickname);
- }
- }
- else {
- // TRANS: Text displayed instead of favourite notices for a user that has no favourites while not logged in.
- // TRANS: %s is a username, %%%%action.register%%%% is a link to the user registration page.
- // TRANS: (link text)[link] is a Mark Down link.
- $message = sprintf(_('%s hasn\'t added any favorite notices yet. Why not [register an account](%%%%action.register%%%%) and then post something interesting they would add to their favorites :)'), $this->user->nickname);
- }
-
- $this->elementStart('div', 'guide');
- $this->raw(common_markup_to_html($message));
- $this->elementEnd('div');
- }
-
- /**
- * Show the content
- *
- * A list of notices that this user has marked as a favorite
- *
- * @return void
- */
- function showContent()
- {
- $nl = new FavoritesNoticeList($this->notice, $this);
-
- $cnt = $nl->show();
- if (0 == $cnt) {
- $this->showEmptyListMessage();
- }
-
- $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
- $this->page, 'showfavorites',
- array('nickname' => $this->user->nickname));
- }
-
- function showPageNotice() {
- // TRANS: Page notice for show favourites page.
- $this->element('p', 'instructions', _('This is a way to share what you like.'));
- }
-}
-
-class FavoritesNoticeList extends NoticeList
-{
- function newListItem($notice)
- {
- return new FavoritesNoticeListItem($notice, $this->out);
- }
-}
-
-// All handled by superclass
-class FavoritesNoticeListItem extends DoFollowListItem
-{
-}
+++ /dev/null
-<?php
-/**
- * Table Definition for fave
- */
-require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
-
-class Fave extends Managed_DataObject
-{
- ###START_AUTOCODE
- /* the code below is auto generated do not remove the above tag */
-
- public $__table = 'fave'; // table name
- public $notice_id; // int(4) primary_key not_null
- public $user_id; // int(4) primary_key not_null
- public $uri; // varchar(255)
- public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
-
- /* the code above is auto generated do not remove the tag below */
- ###END_AUTOCODE
-
- public static function schemaDef()
- {
- return array(
- 'fields' => array(
- 'notice_id' => array('type' => 'int', 'not null' => true, 'description' => 'notice that is the favorite'),
- 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user who likes this notice'),
- 'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universally unique identifier, usually a tag URI'),
- 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
- ),
- 'primary key' => array('notice_id', 'user_id'),
- 'unique keys' => array(
- 'fave_uri_key' => array('uri'),
- ),
- 'foreign keys' => array(
- 'fave_notice_id_fkey' => array('notice', array('notice_id' => 'id')),
- 'fave_user_id_fkey' => array('profile', array('user_id' => 'id')), // note: formerly referenced notice.id, but we can now record remote users' favorites
- ),
- 'indexes' => array(
- 'fave_notice_id_idx' => array('notice_id'),
- 'fave_user_id_idx' => array('user_id', 'modified'),
- 'fave_modified_idx' => array('modified'),
- ),
- );
- }
-
- /**
- * Save a favorite record.
- * @fixme post-author notification should be moved here
- *
- * @param Profile $profile the local or remote user who likes
- * @param Notice $notice the notice that is liked
- * @return mixed false on failure, or Fave record on success
- */
- static function addNew(Profile $profile, Notice $notice) {
-
- $fave = null;
-
- if (Event::handle('StartFavorNotice', array($profile, $notice, &$fave))) {
-
- $fave = new Fave();
-
- $fave->user_id = $profile->id;
- $fave->notice_id = $notice->id;
- $fave->modified = common_sql_now();
- $fave->uri = self::newURI($fave->user_id,
- $fave->notice_id,
- $fave->modified);
- if (!$fave->insert()) {
- common_log_db_error($fave, 'INSERT', __FILE__);
- return false;
- }
- self::blow('fave:list-ids:notice_id:%d', $fave->notice_id);
- self::blow('popular');
-
- Event::handle('EndFavorNotice', array($profile, $notice));
- }
-
- return $fave;
- }
-
- function delete($useWhere=false)
- {
- $profile = Profile::getKV('id', $this->user_id);
- $notice = Notice::getKV('id', $this->notice_id);
-
- $result = null;
-
- if (Event::handle('StartDisfavorNotice', array($profile, $notice, &$result))) {
-
- $result = parent::delete($useWhere);
- self::blow('fave:list-ids:notice_id:%d', $this->notice_id);
- self::blow('popular');
-
- if ($result) {
- Event::handle('EndDisfavorNotice', array($profile, $notice));
- }
- }
-
- return $result;
- }
-
- function stream($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $own=false, $since_id=0, $max_id=0)
- {
- $stream = new FaveNoticeStream($user_id, $own);
-
- return $stream->getNotices($offset, $limit, $since_id, $max_id);
- }
-
- function idStream($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $own=false, $since_id=0, $max_id=0)
- {
- $stream = new FaveNoticeStream($user_id, $own);
-
- return $stream->getNoticeIds($offset, $limit, $since_id, $max_id);
- }
-
- function asActivity()
- {
- $notice = Notice::getKV('id', $this->notice_id);
-
- if (!$notice) {
- throw new Exception("Fave for non-existent notice: " . $this->notice_id);
- }
-
- $profile = Profile::getKV('id', $this->user_id);
-
- if (!$profile) {
- throw new Exception("Fave by non-existent profile: " . $this->user_id);
- }
-
- $act = new Activity();
-
- $act->verb = ActivityVerb::FAVORITE;
-
- // FIXME: rationalize this with URL below
-
- $act->id = $this->getURI();
-
- $act->time = strtotime($this->modified);
- // TRANS: Activity title when marking a notice as favorite.
- $act->title = _("Favor");
- // TRANS: Ntofication given when a user marks a notice as favorite.
- // TRANS: %1$s is a user nickname or full name, %2$s is a notice URI.
- $act->content = sprintf(_('%1$s marked notice %2$s as a favorite.'),
- $profile->getBestName(),
- $notice->getUrl());
-
- $act->actor = ActivityObject::fromProfile($profile);
- $act->objects[] = ActivityObject::fromNotice($notice);
-
- $url = common_local_url('AtomPubShowFavorite',
- array('profile' => $this->user_id,
- 'notice' => $this->notice_id));
-
- $act->selfLink = $url;
- $act->editLink = $url;
-
- return $act;
- }
-
- /**
- * Fetch a stream of favorites by profile
- *
- * @param integer $profileId Profile that faved
- * @param integer $offset Offset from last
- * @param integer $limit Number to get
- *
- * @return mixed stream of faves, use fetch() to iterate
- *
- * @todo Cache results
- * @todo integrate with Fave::stream()
- */
-
- static function byProfile($profileId, $offset, $limit)
- {
- $fav = new Fave();
-
- $fav->user_id = $profileId;
-
- $fav->orderBy('modified DESC');
-
- $fav->limit($offset, $limit);
-
- $fav->find();
-
- return $fav;
- }
-
- function getURI()
- {
- if (!empty($this->uri)) {
- return $this->uri;
- } else {
- return self::newURI($this->user_id, $this->notice_id, $this->modified);
- }
- }
-
- static function newURI($profile_id, $notice_id, $modified)
- {
- return TagURI::mint('favor:%d:%d:%s',
- $profile_id,
- $notice_id,
- common_date_iso8601($modified));
- }
-}
array('core' => array(
'AuthCrypt' => array(),
'Cronish' => array(),
+ 'Favorite' => array(),
'LRDD' => array(),
'StrictTransportSecurity' => array(),
),
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Form for disfavoring a notice
- *
- * 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 Form
- * @package GNUsocial
- * @author Evan Prodromou <evan@status.net>
- * @author Sarven Capadisli <csarven@status.net>
- * @author Mikael Nordfeldth <mmn@hethane.se>
- * @copyright 2009 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://www.gnu.org/software/social/
- */
-
-if (!defined('GNUSOCIAL')) { exit(1); }
-
-/**
- * Form for disfavoring a notice
- *
- * @category Form
- * @package GNUsocial
- * @author Evan Prodromou <evan@status.net>
- * @author Sarven Capadisli <csarven@status.net>
- * @author Mikael Nordfeldth <mmn@hethane.se>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://www.gnu.org/software/social/
- *
- * @see FavorForm
- */
-class DisfavorForm extends Form
-{
- /**
- * Notice to disfavor
- */
- var $notice = null;
-
- /**
- * Constructor
- *
- * @param HTMLOutputter $out output channel
- * @param Notice $notice notice to disfavor
- */
- function __construct($out=null, $notice=null)
- {
- parent::__construct($out);
-
- $this->notice = $notice;
- }
-
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'disfavor-' . $this->notice->id;
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('disfavor');
- }
-
- /**
- * Legend of the Form
- *
- * @return void
- */
- function formLegend()
- {
- // TRANS: Form legend for removing the favourite status for a favourite notice.
- $this->out->element('legend', null, _('Disfavor this notice'));
- }
-
- /**
- * Data elements
- *
- * @return void
- */
-
- function formData()
- {
- if (Event::handle('StartDisFavorNoticeForm', array($this, $this->notice))) {
- $this->out->hidden('notice-n'.$this->notice->id,
- $this->notice->id,
- 'notice');
- Event::handle('EndDisFavorNoticeForm', array($this, $this->notice));
- }
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- $this->out->submit('disfavor-submit-' . $this->notice->id,
- // TRANS: Button text for removing the favourite status for a favourite notice.
- _m('BUTTON','Disfavor favorite'),
- 'submit',
- null,
- // TRANS: Button title for removing the favourite status for a favourite notice.
- _('Remove this notice from your list of favorite notices.'));
- }
-
- /**
- * Class of the form.
- *
- * @return string the form's class
- */
- function formClass()
- {
- return 'form_disfavor ajax';
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Notice stream for favorites
- *
- * PHP version 5
- *
- * 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 Stream
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Notice stream for favorites
- *
- * @category Stream
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class FaveNoticeStream extends ScopingNoticeStream
-{
- function __construct($user_id, $own, $profile = -1)
- {
- $stream = new RawFaveNoticeStream($user_id, $own);
- if ($own) {
- $key = 'fave:ids_by_user_own:'.$user_id;
- } else {
- $key = 'fave:ids_by_user:'.$user_id;
- }
- if (is_int($profile) && $profile == -1) {
- $profile = Profile::current();
- }
- parent::__construct(new CachingNoticeStream($stream, $key),
- $profile);
- }
-}
-
-/**
- * Raw notice stream for favorites
- *
- * @category Stream
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class RawFaveNoticeStream extends NoticeStream
-{
- protected $user_id;
- protected $own;
-
- function __construct($user_id, $own)
- {
- $this->user_id = $user_id;
- $this->own = $own;
- }
-
- /**
- * Note that the sorting for this is by order of *fave* not order of *notice*.
- *
- * @fixme add since_id, max_id support?
- *
- * @param <type> $user_id
- * @param <type> $own
- * @param <type> $offset
- * @param <type> $limit
- * @param <type> $since_id
- * @param <type> $max_id
- * @return <type>
- */
- function getNoticeIds($offset, $limit, $since_id, $max_id)
- {
- $fav = new Fave();
- $qry = null;
-
- if ($this->own) {
- $qry = 'SELECT fave.* FROM fave ';
- $qry .= 'WHERE fave.user_id = ' . $this->user_id . ' ';
- } else {
- $qry = 'SELECT fave.* FROM fave ';
- $qry .= 'INNER JOIN notice ON fave.notice_id = notice.id ';
- $qry .= 'WHERE fave.user_id = ' . $this->user_id . ' ';
- $qry .= 'AND notice.is_local != ' . Notice::GATEWAY . ' ';
- }
-
- if ($since_id != 0) {
- $qry .= 'AND notice_id > ' . $since_id . ' ';
- }
-
- if ($max_id != 0) {
- $qry .= 'AND notice_id <= ' . $max_id . ' ';
- }
-
- // NOTE: we sort by fave time, not by notice time!
-
- $qry .= 'ORDER BY modified DESC ';
-
- if (!is_null($offset)) {
- $qry .= "LIMIT $limit OFFSET $offset";
- }
-
- $fav->query($qry);
-
- $ids = array();
-
- while ($fav->fetch()) {
- $ids[] = $fav->notice_id;
- }
-
- $fav->free();
- unset($fav);
-
- return $ids;
- }
-}
-
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Form for favoring a notice
- *
- * 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 Form
- * @package GNUsocial
- * @author Evan Prodromou <evan@status.net>
- * @author Sarven Capadisli <csarven@status.net>
- * @author Mikael Nordfeldth <mmn@hethane.se>
- * @copyright 2009 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://www.gnu.org/software/social/
- */
-
-if (!defined('GNUSOCIAL')) { exit(1); }
-
-/**
- * Form for favoring a notice
- *
- * @category Form
- * @package GNUsocial
- * @author Evan Prodromou <evan@status.net>
- * @author Sarven Capadisli <csarven@status.net>
- * @author Mikael Nordfeldth <mmn@hethane.se>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://www.gnu.org/software/social/
- *
- * @see DisfavorForm
- */
-class FavorForm extends Form
-{
- /**
- * Notice to favor
- */
- var $notice = null;
-
- /**
- * Constructor
- *
- * @param HTMLOutputter $out output channel
- * @param Notice $notice notice to favor
- */
- function __construct($out=null, $notice=null)
- {
- parent::__construct($out);
-
- $this->notice = $notice;
- }
-
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'favor-' . $this->notice->id;
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('favor');
- }
-
- /**
- * Legend of the Form
- *
- * @return void
- */
- function formLegend()
- {
- // TRANS: Form legend for adding the favourite status to a notice.
- $this->out->element('legend', null, _('Favor this notice'));
- }
-
- /**
- * Data elements
- *
- * @return void
- */
- function formData()
- {
- if (Event::handle('StartFavorNoticeForm', array($this, $this->notice))) {
- $this->out->hidden('notice-n'.$this->notice->id,
- $this->notice->id,
- 'notice');
- Event::handle('EndFavorNoticeForm', array($this, $this->notice));
- }
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- $this->out->submit('favor-submit-' . $this->notice->id,
- // TRANS: Button text for adding the favourite status to a notice.
- _m('BUTTON','Favor'),
- 'submit',
- null,
- // TRANS: Button title for adding the favourite status to a notice.
- _('Add this notice to your list of favorite notices.'));
- }
-
- /**
- * Class of the form.
- *
- * @return string the form's class
- */
- function formClass()
- {
- return 'form_favor ajax';
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Base class for sections showing lists of notices
- *
- * 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 Widget
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2009,2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-/**
- * Base class for sections showing lists of notices
- *
- * These are the widgets that show interesting data about a person
- * group, or site.
- *
- * @category Widget
- * @package StatusNet
- * @author Evan Prodromou <evan@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 PopularNoticeSection extends NoticeSection
-{
- protected $viewer;
-
- function __construct($out, $viewer)
- {
- parent::__construct($out);
- $this->viewer = $viewer;
- }
-
- function getNotices()
- {
- $stream = new PopularNoticeStream($this->viewer);
- return $stream->getNotices(0, NOTICES_PER_SECTION + 1);
- }
-
- function title()
- {
- // TRANS: Title for favourited notices section.
- return _('Popular notices');
- }
-
- function divId()
- {
- return 'popular_notices';
- }
-
- function moreUrl()
- {
- if (common_config('singleuser', 'enabled')) {
- $user = User::singleUser();
- common_local_url('showfavorites', array('nickname' =>
- $user->nickname));
- } else {
- return common_local_url('favorited');
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Stream of notices sorted by popularity
- *
- * PHP version 5
- *
- * 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 Popular
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Stream of notices sorted by popularity
- *
- * @category Popular
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-class PopularNoticeStream extends ScopingNoticeStream
-{
- function __construct($profile=null)
- {
- parent::__construct(new CachingNoticeStream(new RawPopularNoticeStream(),
- 'popular',
- false),
- $profile);
- }
-}
-
-class RawPopularNoticeStream extends NoticeStream
-{
- function getNoticeIds($offset, $limit, $since_id, $max_id)
- {
- $weightexpr = common_sql_weight('modified', common_config('popular', 'dropoff'));
- $cutoff = sprintf("modified > '%s'",
- common_sql_date(time() - common_config('popular', 'cutoff')));
-
- $fave = new Fave();
- $fave->selectAdd();
- $fave->selectAdd('notice_id');
- $fave->selectAdd("$weightexpr as weight");
- $fave->whereAdd($cutoff);
- $fave->orderBy('weight DESC');
- $fave->groupBy('notice_id');
-
- if (!is_null($offset)) {
- $fave->limit($offset, $limit);
- }
-
- // FIXME: $since_id, $max_id are ignored
-
- $ids = array();
-
- if ($fave->find()) {
- while ($fave->fetch()) {
- $ids[] = $fave->notice_id;
- }
- }
-
- return $ids;
- }
-}
-
$main = array('login', 'logout', 'register', 'subscribe',
'unsubscribe', 'cancelsubscription', 'approvesub',
'confirmaddress', 'recoverpassword',
- 'invite', 'favor', 'disfavor', 'sup',
+ 'invite', 'sup',
'block', 'unblock', 'subedit',
'groupblock', 'groupunblock',
'sandbox', 'unsandbox',
'format' => '(xml|json)'));
// START qvitter API additions
-
- $m->connect('api/statuses/favs/:id.:format',
- array('action' => 'ApiStatusesFavs',
- 'id' => '[0-9]+',
- 'format' => '(xml|json)'));
$m->connect('api/attachment/:id.:format',
array('action' => 'ApiAttachment',
$m->connect('api/account/rate_limit_status.:format',
array('action' => 'ApiAccountRateLimitStatus'));
- // favorites
-
- $m->connect('api/favorites/create.:format',
- array('action' => 'ApiFavoriteCreate',
- 'format' => '(xml|json)'));
-
- $m->connect('api/favorites/destroy.:format',
- array('action' => 'ApiFavoriteDestroy',
- 'format' => '(xml|json)'));
-
- $m->connect('api/favorites/list.:format',
- array('action' => 'ApiTimelineFavorites',
- 'format' => '(xml|json|rss|atom|as)'));
-
- $m->connect('api/favorites/:id.:format',
- array('action' => 'ApiTimelineFavorites',
- 'id' => Nickname::INPUT_FMT,
- 'format' => '(xml|json|rss|atom|as)'));
-
- $m->connect('api/favorites.:format',
- array('action' => 'ApiTimelineFavorites',
- 'format' => '(xml|json|rss|atom|as)'));
-
- $m->connect('api/favorites/create/:id.:format',
- array('action' => 'ApiFavoriteCreate',
- 'id' => '[0-9]+',
- 'format' => '(xml|json)'));
-
- $m->connect('api/favorites/destroy/:id.:format',
- array('action' => 'ApiFavoriteDestroy',
- 'id' => '[0-9]+',
- 'format' => '(xml|json)'));
-
// blocks
$m->connect('api/blocks/create/:id.:format',
'nickname' => $nickname));
}
- foreach (array('all', 'replies', 'favorites') as $a) {
+ foreach (array('all', 'replies') as $a) {
$m->connect($a.'/rss',
array('action' => $a.'rss',
'nickname' => $nickname));
}
- $m->connect('favorites',
- array('action' => 'showfavorites',
- 'nickname' => $nickname));
-
$m->connect('avatar',
array('action' => 'avatarbynickname',
'nickname' => $nickname));
$m->connect('', array('action' => 'public'));
$m->connect('rss', array('action' => 'publicrss'));
$m->connect('featuredrss', array('action' => 'featuredrss'));
- $m->connect('favoritedrss', array('action' => 'favoritedrss'));
$m->connect('featured/', array('action' => 'featured'));
$m->connect('featured', array('action' => 'featured'));
- $m->connect('favorited/', array('action' => 'favorited'));
- $m->connect('favorited', array('action' => 'favorited'));
$m->connect('rsd.xml', array('action' => 'rsd'));
foreach (array('subscriptions', 'subscribers',
array('nickname' => Nickname::DISPLAY_FMT));
}
- foreach (array('all', 'replies', 'favorites') as $a) {
+ foreach (array('all', 'replies') as $a) {
$m->connect(':nickname/'.$a.'/rss',
array('action' => $a.'rss'),
array('nickname' => Nickname::DISPLAY_FMT));
}
- $m->connect(':nickname/favorites',
- array('action' => 'showfavorites'),
- array('nickname' => Nickname::DISPLAY_FMT));
-
$m->connect(':nickname/avatar',
array('action' => 'avatarbynickname'),
array('nickname' => Nickname::DISPLAY_FMT));
array('action' => 'AtomPubSubscriptionFeed'),
array('subscriber' => '[0-9]+'));
- $m->connect('api/statusnet/app/favorites/:profile/:notice.atom',
- array('action' => 'AtomPubShowFavorite'),
- array('profile' => '[0-9]+',
- 'notice' => '[0-9]+'));
-
- $m->connect('api/statusnet/app/favorites/:profile.atom',
- array('action' => 'AtomPubFavoriteFeed'),
- array('profile' => '[0-9]+'));
-
$m->connect('api/statusnet/app/memberships/:profile/:group.atom',
array('action' => 'AtomPubShowMembership'),
array('profile' => '[0-9]+',
--- /dev/null
+<?php
+/*
+ * GNU Social - a federating social network
+ * Copyright (C) 2014, Free Software Foundation, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('GNUSOCIAL')) { exit(1); }
+
+/**
+ * @package UI
+ * @maintainer Mikael Nordfeldth <mmn@hethane.se>
+ */
+class FavoritePlugin extends Plugin
+{
+ public function onRouterInitialized(URLMapper $m)
+ {
+ // Web UI actions
+ $m->connect('main/favor', array('action' => 'favor'));
+ $m->connect('main/disfavor', array('action' => 'disfavor'));
+
+ if (common_config('singleuser', 'enabled')) {
+ $nickname = User::singleUserNickname();
+
+ $m->connect('favorites',
+ array('action' => 'showfavorites',
+ 'nickname' => $nickname));
+ $m->connect('favoritesrss',
+ array('action' => 'favoritesrss',
+ 'nickname' => $nickname));
+ } else {
+ $m->connect('favoritedrss', array('action' => 'favoritedrss'));
+ $m->connect('favorited/', array('action' => 'favorited'));
+ $m->connect('favorited', array('action' => 'favorited'));
+
+ $m->connect(':nickname/favorites',
+ array('action' => 'showfavorites'),
+ array('nickname' => Nickname::DISPLAY_FMT));
+ $m->connect(':nickname/favorites/rss',
+ array('action' => 'favoritesrss'),
+ array('nickname' => Nickname::DISPLAY_FMT));
+ }
+
+ // Favorites for API
+ $m->connect('api/favorites/create.:format',
+ array('action' => 'ApiFavoriteCreate',
+ 'format' => '(xml|json)'));
+ $m->connect('api/favorites/destroy.:format',
+ array('action' => 'ApiFavoriteDestroy',
+ 'format' => '(xml|json)'));
+ $m->connect('api/favorites/list.:format',
+ array('action' => 'ApiTimelineFavorites',
+ 'format' => '(xml|json|rss|atom|as)'));
+ $m->connect('api/favorites/:id.:format',
+ array('action' => 'ApiTimelineFavorites',
+ 'id' => Nickname::INPUT_FMT,
+ 'format' => '(xml|json|rss|atom|as)'));
+ $m->connect('api/favorites.:format',
+ array('action' => 'ApiTimelineFavorites',
+ 'format' => '(xml|json|rss|atom|as)'));
+ $m->connect('api/favorites/create/:id.:format',
+ array('action' => 'ApiFavoriteCreate',
+ 'id' => '[0-9]+',
+ 'format' => '(xml|json)'));
+ $m->connect('api/favorites/destroy/:id.:format',
+ array('action' => 'ApiFavoriteDestroy',
+ 'id' => '[0-9]+',
+ 'format' => '(xml|json)'));
+
+ // AtomPub API
+ $m->connect('api/statusnet/app/favorites/:profile/:notice.atom',
+ array('action' => 'AtomPubShowFavorite'),
+ array('profile' => '[0-9]+',
+ 'notice' => '[0-9]+'));
+
+ $m->connect('api/statusnet/app/favorites/:profile.atom',
+ array('action' => 'AtomPubFavoriteFeed'),
+ array('profile' => '[0-9]+'));
+
+ // Required for qvitter API
+ $m->connect('api/statuses/favs/:id.:format',
+ array('action' => 'ApiStatusesFavs',
+ 'id' => '[0-9]+',
+ 'format' => '(xml|json)'));
+ }
+
+ public function onPluginVersion(array &$versions)
+ {
+ $versions[] = array('name' => 'Favorite',
+ 'version' => GNUSOCIAL_VERSION,
+ 'author' => 'Mikael Nordfeldth',
+ 'homepage' => 'http://gnu.io/',
+ 'rawdescription' =>
+ // TRANS: Plugin description.
+ _m('Favorites (likes) using ActivityStreams.'));
+
+ return true;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Add a notice to a user's list of favorite notices via the API
+ *
+ * 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 Zach Copley <zach@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Favorites the status specified in the ID parameter as the authenticating user.
+ * Returns the favorite status when successful.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @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 ApiFavoriteCreateAction extends ApiAuthAction
+{
+ var $notice = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ */
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->user = $this->auth_user;
+ $this->notice = Notice::getKV($this->arg('id'));
+ if ($this->notice->repeat_of != '' ) {
+ common_log(LOG_DEBUG, 'Trying to Fave '.$this->notice->id.', repeat of '.$this->notice->repeat_of);
+ common_log(LOG_DEBUG, 'Will Fave '.$this->notice->repeat_of.' instead');
+ $real_notice_id = $this->notice->repeat_of;
+ $this->notice = Notice::getKV($real_notice_id);
+ }
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Check the format and show the user info
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+ $this->clientError(
+ // TRANS: Client error. POST is a HTTP command. It should not be translated.
+ _('This method requires a POST.'),
+ 400,
+ $this->format
+ );
+ return;
+ }
+
+ if (!in_array($this->format, array('xml', 'json'))) {
+ $this->clientError(
+ // TRANS: Client error displayed when coming across a non-supported API method.
+ _('API method not found.'),
+ 404,
+ $this->format
+ );
+ return;
+ }
+
+ if (empty($this->notice)) {
+ $this->clientError(
+ // TRANS: Client error displayed when requesting a status with a non-existing ID.
+ _('No status found with that ID.'),
+ 404,
+ $this->format
+ );
+ return;
+ }
+
+ // Note: Twitter lets you fave things repeatedly via API.
+
+ if ($this->user->hasFave($this->notice)) {
+ $this->clientError(
+ // TRANS: Client error displayed when trying to mark a notice favourite that already is a favourite.
+ _('This status is already a favorite.'),
+ 403,
+ $this->format
+ );
+ return;
+ }
+
+ $fave = Fave::addNew($this->user->getProfile(), $this->notice);
+
+ if (empty($fave)) {
+ $this->clientError(
+ // TRANS: Client error displayed when marking a notice as favourite fails.
+ _('Could not create favorite.'),
+ 403,
+ $this->format
+ );
+ return;
+ }
+
+ $this->notify($fave, $this->notice, $this->user);
+ $this->user->blowFavesCache();
+
+ if ($this->format == 'xml') {
+ $this->showSingleXmlStatus($this->notice);
+ } elseif ($this->format == 'json') {
+ $this->show_single_json_status($this->notice);
+ }
+ }
+
+ /**
+ * Notify the author of the favorite that the user likes their notice
+ *
+ * @param Favorite $fave the favorite in question
+ * @param Notice $notice the notice that's been faved
+ * @param User $user the user doing the favoriting
+ *
+ * @return void
+ */
+ function notify($fave, $notice, $user)
+ {
+ $other = User::getKV('id', $notice->profile_id);
+ if ($other && $other->id != $user->id) {
+ if ($other->email && $other->emailnotifyfav) {
+ mail_notify_fave($other, $user, $notice);
+ }
+ // XXX: notify by IM
+ // XXX: notify by SMS
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Remote a notice from a user's list of favorite notices via the API
+ *
+ * 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 Zach Copley <zach@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Un-favorites the status specified in the ID parameter as the authenticating user.
+ * Returns the un-favorited status in the requested format when successful.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @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 ApiFavoriteDestroyAction extends ApiAuthAction
+{
+ var $notice = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ */
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->user = $this->auth_user;
+ $this->notice = Notice::getKV($this->arg('id'));
+ if ($this->notice->repeat_of != '' ) {
+ common_log(LOG_DEBUG, 'Trying to unFave '.$this->notice->id);
+ common_log(LOG_DEBUG, 'Will unFave '.$this->notice->repeat_of.' instead');
+ $real_notice_id = $this->notice->repeat_of;
+ $this->notice = Notice::getKV($real_notice_id);
+ }
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Check the format and show the user info
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+ $this->clientError(
+ // TRANS: Client error. POST is a HTTP command. It should not be translated.
+ _('This method requires a POST.'),
+ 400,
+ $this->format
+ );
+ return;
+ }
+
+ if (!in_array($this->format, array('xml', 'json'))) {
+ $this->clientError(
+ // TRANS: Client error displayed when coming across a non-supported API method.
+ _('API method not found.'),
+ 404,
+ $this->format
+ );
+ return;
+ }
+
+ if (empty($this->notice)) {
+ $this->clientError(
+ // TRANS: Client error displayed when trying to remove a favourite with an invalid ID.
+ _('No status found with that ID.'),
+ 404,
+ $this->format
+ );
+ return;
+ }
+
+ $fave = new Fave();
+ $fave->user_id = $this->user->id;
+ $fave->notice_id = $this->notice->id;
+
+ if (!$fave->find(true)) {
+ $this->clientError(
+ // TRANS: Client error displayed when trying to remove a favourite that was not a favourite.
+ _('That status is not a favorite.'),
+ 403,
+ $this->favorite
+ );
+ return;
+ }
+
+ $result = $fave->delete();
+
+ if (!$result) {
+ common_log_db_error($fave, 'DELETE', __FILE__);
+ $this->clientError(
+ // TRANS: Client error displayed when removing a favourite has failed.
+ _('Could not delete favorite.'),
+ 404,
+ $this->format
+ );
+ return;
+ }
+
+ $this->user->blowFavesCache();
+
+ if ($this->format == 'xml') {
+ $this->showSingleXmlStatus($this->notice);
+ } elseif ($this->format == 'json') {
+ $this->show_single_json_status($this->notice);
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show up to 100 favs of a notice
+ *
+ * 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 GNUsocial
+ * @author Hannes Mannerheim <h@nnesmannerhe.im>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://www.gnu.org/software/social/
+ */
+
+if (!defined('GNUSOCIAL')) { exit(1); }
+
+/**
+ * Show up to 100 favs of a notice
+ *
+ */
+class ApiStatusesFavsAction extends ApiAuthAction
+{
+ const MAXCOUNT = 100;
+
+ var $original = null; // Notice object for which to retrieve favs
+ var $cnt = self::MAXCOUNT;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ */
+ protected function prepare(array $args=array())
+ {
+ parent::prepare($args);
+
+ if ($this->format !== 'json') {
+ $this->clientError('This method currently only serves JSON.', 415);
+ }
+
+ $id = $this->trimmed('id');
+
+ $this->original = Notice::getKV('id', $id);
+
+ if (!($this->original instanceof Notice)) {
+ // TRANS: Client error displayed trying to display redents of a non-exiting notice.
+ $this->clientError(_('No such notice.'), 400);
+ }
+
+ $cnt = $this->trimmed('count');
+
+ if (empty($cnt) || !is_integer($cnt)) {
+ $cnt = 100;
+ } else {
+ $this->cnt = min((int)$cnt, self::MAXCOUNT);
+ }
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Get favs and return them as json object
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+ protected function handle()
+ {
+ parent::handle();
+
+ $fave = new Fave();
+ $fave->selectAdd();
+ $fave->selectAdd('user_id');
+ $fave->notice_id = $this->original->id;
+ $fave->orderBy('modified');
+ if (!is_null($this->cnt)) {
+ $fave->limit(0, $this->cnt);
+ }
+
+ $ids = $fave->fetchAll('user_id');
+
+ // get nickname and profile image
+ $ids_with_profile_data = array();
+ $i=0;
+ foreach($ids as $id) {
+ $profile = Profile::getKV('id', $id);
+ $ids_with_profile_data[$i]['user_id'] = $id;
+ $ids_with_profile_data[$i]['nickname'] = $profile->nickname;
+ $ids_with_profile_data[$i]['fullname'] = $profile->fullname;
+ $ids_with_profile_data[$i]['profileurl'] = $profile->profileurl;
+ $profile = new Profile();
+ $profile->id = $id;
+ $avatarurl = $profile->avatarUrl(24);
+ $ids_with_profile_data[$i]['avatarurl'] = $avatarurl;
+ $i++;
+ }
+
+ $this->initDocument('json');
+ $this->showJsonObjects($ids_with_profile_data);
+ $this->endDocument('json');
+ }
+
+ /**
+ * Return true if read only.
+ *
+ * MAY override
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean is read only action?
+ */
+
+ function isReadOnly($args)
+ {
+ return true;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show a user's favorite notices
+ *
+ * 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 Zach Copley <zach@status.net>
+ * @copyright 2009-2010 StatusNet, Inc.
+ * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Returns the 20 most recent favorite notices for the authenticating user or user
+ * specified by the ID parameter in the requested format.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @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 ApiTimelineFavoritesAction extends ApiBareAuthAction
+{
+ var $notices = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ */
+ protected function prepare(array $args=array())
+ {
+ parent::prepare($args);
+
+ $this->target = $this->getTargetProfile($this->arg('id'));
+
+ if (!($this->target instanceof Profile)) {
+ // TRANS: Client error displayed when requesting most recent favourite notices by a user for a non-existing user.
+ $this->clientError(_('No such user.'), 404);
+ }
+
+ $this->notices = $this->getNotices();
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Just show the notices
+ *
+ * @return void
+ */
+ protected function handle()
+ {
+ parent::handle();
+ $this->showTimeline();
+ }
+
+ /**
+ * Show the timeline of notices
+ *
+ * @return void
+ */
+ function showTimeline()
+ {
+ $sitename = common_config('site', 'name');
+ $title = sprintf(
+ // TRANS: Title for timeline of most recent favourite notices by a user.
+ // TRANS: %1$s is the StatusNet sitename, %2$s is a user nickname.
+ _('%1$s / Favorites from %2$s'),
+ $sitename,
+ $this->target->nickname
+ );
+
+ $taguribase = TagURI::base();
+ $id = "tag:$taguribase:Favorites:" . $this->target->id;
+
+ $subtitle = sprintf(
+ // TRANS: Subtitle for timeline of most recent favourite notices by a user.
+ // TRANS: %1$s is the StatusNet sitename, %2$s is a user's full name,
+ // TRANS: %3$s is a user nickname.
+ _('%1$s updates favorited by %2$s / %3$s.'),
+ $sitename,
+ $this->target->getBestName(),
+ $this->target->nickname
+ );
+
+ $logo = $this->target->avatarUrl(AVATAR_PROFILE_SIZE);
+ $link = common_local_url('showfavorites',
+ array('nickname' => $this->target->nickname));
+ $self = $this->getSelfUri();
+
+ switch($this->format) {
+ case 'xml':
+ $this->showXmlTimeline($this->notices);
+ break;
+ case 'rss':
+ $this->showRssTimeline(
+ $this->notices,
+ $title,
+ $link,
+ $subtitle,
+ null,
+ $logo,
+ $self
+ );
+ break;
+ case 'atom':
+ header('Content-Type: application/atom+xml; charset=utf-8');
+
+ $atom = new AtomNoticeFeed($this->auth_user);
+
+ $atom->setId($id);
+ $atom->setTitle($title);
+ $atom->setSubtitle($subtitle);
+ $atom->setLogo($logo);
+ $atom->setUpdated('now');
+
+ $atom->addLink($link);
+ $atom->setSelfLink($self);
+
+ $atom->addEntryFromNotices($this->notices);
+
+ $this->raw($atom->getString());
+ break;
+ case 'json':
+ $this->showJsonTimeline($this->notices);
+ break;
+ case 'as':
+ header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
+ $doc = new ActivityStreamJSONDocument($this->auth_user);
+ $doc->setTitle($title);
+ $doc->addLink($link,'alternate', 'text/html');
+ $doc->addItemsFromNotices($this->notices);
+ $this->raw($doc->asString());
+ break;
+ default:
+ // TRANS: Client error displayed when coming across a non-supported API method.
+ $this->clientError(_('API method not found.'), 404);
+ }
+ }
+
+ /**
+ * Get notices
+ *
+ * @return array notices
+ */
+ function getNotices()
+ {
+ $notices = array();
+
+ common_debug("since id = " . $this->since_id . " max id = " . $this->max_id);
+
+ if (!empty($this->auth_user) && $this->auth_user->id == $this->target->id) {
+ $notice = $this->target->favoriteNotices(
+ true,
+ ($this->page-1) * $this->count,
+ $this->count,
+ $this->since_id,
+ $this->max_id
+ );
+ } else {
+ $notice = $this->target->favoriteNotices(
+ false,
+ ($this->page-1) * $this->count,
+ $this->count,
+ $this->since_id,
+ $this->max_id
+ );
+ }
+
+ 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'),
+ common_user_cache_hash($this->auth_user),
+ common_language(),
+ $this->target->id,
+ strtotime($this->notices[0]->created),
+ strtotime($this->notices[$last]->created))
+ )
+ . '"';
+ }
+
+ return null;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * Feed of ActivityStreams 'favorite' actions
+ *
+ * PHP version 5
+ *
+ * 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 AtomPub
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Feed of ActivityStreams 'favorite' actions
+ *
+ * @category AtomPub
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class AtompubfavoritefeedAction extends ApiAuthAction
+{
+ private $_profile = null;
+ private $_faves = null;
+
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+ function prepare($argarray)
+ {
+ parent::prepare($argarray);
+
+ $this->_profile = Profile::getKV('id', $this->trimmed('profile'));
+
+ if (empty($this->_profile)) {
+ // TRANS: Client exception thrown when requesting a favorite feed for a non-existing profile.
+ throw new ClientException(_('No such profile.'), 404);
+ }
+
+ $offset = ($this->page-1) * $this->count;
+ $limit = $this->count + 1;
+
+ $this->_faves = Fave::byProfile($this->_profile->id,
+ $offset,
+ $limit);
+
+ return true;
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+ function handle($argarray=null)
+ {
+ parent::handle($argarray);
+
+ switch ($_SERVER['REQUEST_METHOD']) {
+ case 'HEAD':
+ case 'GET':
+ $this->showFeed();
+ break;
+ case 'POST':
+ $this->addFavorite();
+ break;
+ default:
+ // TRANS: Client exception thrown when using an unsupported HTTP method.
+ throw new ClientException(_('HTTP method not supported.'), 405);
+ return;
+ }
+
+ return;
+ }
+
+ /**
+ * Show a feed of favorite activity streams objects
+ *
+ * @return void
+ */
+ function showFeed()
+ {
+ header('Content-Type: application/atom+xml; charset=utf-8');
+
+ $url = common_local_url('AtomPubFavoriteFeed',
+ array('profile' => $this->_profile->id));
+
+ $feed = new Atom10Feed(true);
+
+ $feed->addNamespace('activity',
+ 'http://activitystrea.ms/spec/1.0/');
+
+ $feed->addNamespace('poco',
+ 'http://portablecontacts.net/spec/1.0');
+
+ $feed->addNamespace('media',
+ 'http://purl.org/syndication/atommedia');
+
+ $feed->id = $url;
+
+ $feed->setUpdated('now');
+
+ $feed->addAuthor($this->_profile->getBestName(),
+ $this->_profile->getURI());
+
+ // TRANS: Title for Atom favorites feed.
+ // TRANS: %s is a user nickname.
+ $feed->setTitle(sprintf(_("%s favorites"),
+ $this->_profile->getBestName()));
+
+ // TRANS: Subtitle for Atom favorites feed.
+ // TRANS: %1$s is a user nickname, %2$s is the StatusNet sitename.
+ $feed->setSubtitle(sprintf(_('Notices %1$s has favorited on %2$s'),
+ $this->_profile->getBestName(),
+ common_config('site', 'name')));
+
+ $feed->addLink(common_local_url('showfavorites',
+ array('nickname' =>
+ $this->_profile->nickname)));
+
+ $feed->addLink($url,
+ array('rel' => 'self',
+ 'type' => 'application/atom+xml'));
+
+ // If there's more...
+
+ if ($this->page > 1) {
+ $feed->addLink($url,
+ array('rel' => 'first',
+ 'type' => 'application/atom+xml'));
+
+ $feed->addLink(common_local_url('AtomPubFavoriteFeed',
+ array('profile' =>
+ $this->_profile->id),
+ array('page' =>
+ $this->page - 1)),
+ array('rel' => 'prev',
+ 'type' => 'application/atom+xml'));
+ }
+
+ if ($this->_faves->N > $this->count) {
+
+ $feed->addLink(common_local_url('AtomPubFavoriteFeed',
+ array('profile' =>
+ $this->_profile->id),
+ array('page' =>
+ $this->page + 1)),
+ array('rel' => 'next',
+ 'type' => 'application/atom+xml'));
+ }
+
+ $i = 0;
+
+ while ($this->_faves->fetch()) {
+
+ // We get one more than needed; skip that one
+
+ $i++;
+
+ if ($i > $this->count) {
+ break;
+ }
+
+ $act = $this->_faves->asActivity();
+ $feed->addEntryRaw($act->asString(false, false, false));
+ }
+
+ $this->raw($feed->getString());
+ }
+
+ /**
+ * add a new favorite
+ *
+ * @return void
+ */
+ function addFavorite()
+ {
+ // XXX: Refactor this; all the same for atompub
+
+ if (empty($this->auth_user) ||
+ $this->auth_user->id != $this->_profile->id) {
+ // TRANS: Client exception thrown when trying to set a favorite for another user.
+ throw new ClientException(_("Cannot add someone else's".
+ " subscription."), 403);
+ }
+
+ $xml = file_get_contents('php://input');
+
+ $dom = DOMDocument::loadXML($xml);
+
+ if ($dom->documentElement->namespaceURI != Activity::ATOM ||
+ $dom->documentElement->localName != 'entry') {
+ // TRANS: Client error displayed when not using an Atom entry.
+ throw new ClientException(_('Atom post must be an Atom entry.'));
+ return;
+ }
+
+ $activity = new Activity($dom->documentElement);
+
+ $fave = null;
+
+ if (Event::handle('StartAtomPubNewActivity', array(&$activity))) {
+
+ if ($activity->verb != ActivityVerb::FAVORITE) {
+ // TRANS: Client exception thrown when trying use an incorrect activity verb for the Atom pub method.
+ throw new ClientException(_('Can only handle favorite activities.'));
+ return;
+ }
+
+ $note = $activity->objects[0];
+
+ if (!in_array($note->type, array(ActivityObject::NOTE,
+ ActivityObject::BLOGENTRY,
+ ActivityObject::STATUS))) {
+ // TRANS: Client exception thrown when trying favorite an object that is not a notice.
+ throw new ClientException(_('Can only fave notices.'));
+ return;
+ }
+
+ $notice = Notice::getKV('uri', $note->id);
+
+ if (empty($notice)) {
+ // XXX: import from listed URL or something
+ // TRANS: Client exception thrown when trying favorite a notice without content.
+ throw new ClientException(_('Unknown notice.'));
+ }
+
+ $old = Fave::pkeyGet(array('user_id' => $this->auth_user->id,
+ 'notice_id' => $notice->id));
+
+ if (!empty($old)) {
+ // TRANS: Client exception thrown when trying favorite an already favorited notice.
+ throw new ClientException(_('Already a favorite.'));
+ }
+
+ $profile = $this->auth_user->getProfile();
+
+ $fave = Fave::addNew($profile, $notice);
+
+ if (!empty($fave)) {
+ $this->_profile->blowFavesCache();
+ $this->notify($fave, $notice, $this->auth_user);
+ }
+
+ Event::handle('EndAtomPubNewActivity', array($activity, $fave));
+ }
+
+ if (!empty($fave)) {
+ $act = $fave->asActivity();
+
+ header('Content-Type: application/atom+xml; charset=utf-8');
+ header('Content-Location: ' . $act->selfLink);
+
+ $this->startXML();
+ $this->raw($act->asString(true, true, true));
+ $this->endXML();
+ }
+ }
+
+ /**
+ * Return true if read only.
+ *
+ * MAY override
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean is read only action?
+ */
+ function isReadOnly($args)
+ {
+ if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
+ $_SERVER['REQUEST_METHOD'] == 'HEAD') {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Return last modified, if applicable.
+ *
+ * MAY override
+ *
+ * @return string last modified http header
+ */
+ function lastModified()
+ {
+ // For comparison with If-Last-Modified
+ // If not applicable, return null
+ return null;
+ }
+
+ /**
+ * Return etag, if applicable.
+ *
+ * MAY override
+ *
+ * @return string etag http header
+ */
+ function etag()
+ {
+ return null;
+ }
+
+ /**
+ * Does this require authentication?
+ *
+ * @return boolean true if delete, else false
+ */
+ function requiresAuth()
+ {
+ if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
+ $_SERVER['REQUEST_METHOD'] == 'HEAD') {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Notify the author of the favorite that the user likes their notice
+ *
+ * @param Favorite $fave the favorite in question
+ * @param Notice $notice the notice that's been faved
+ * @param User $user the user doing the favoriting
+ *
+ * @return void
+ */
+ function notify($fave, $notice, $user)
+ {
+ $other = User::getKV('id', $notice->profile_id);
+ if ($other && $other->id != $user->id) {
+ if ($other->email && $other->emailnotifyfav) {
+ mail_notify_fave($other, $user, $notice);
+ }
+ // XXX: notify by IM
+ // XXX: notify by SMS
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * Show a single favorite in Atom Activity Streams format
+ *
+ * PHP version 5
+ *
+ * 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 AtomPub
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Show a single favorite in Atom Activity Streams format.
+ *
+ * Can also be used to delete a favorite.
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class AtompubshowfavoriteAction extends ApiAuthAction
+{
+ private $_profile = null;
+ private $_notice = null;
+ private $_fave = null;
+
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+ function prepare($argarray)
+ {
+ parent::prepare($argarray);
+
+ $profileId = $this->trimmed('profile');
+ $noticeId = $this->trimmed('notice');
+
+ $this->_profile = Profile::getKV('id', $profileId);
+
+ if (empty($this->_profile)) {
+ // TRANS: Client exception.
+ throw new ClientException(_('No such profile.'), 404);
+ }
+
+ $this->_notice = Notice::getKV('id', $noticeId);
+
+ if (empty($this->_notice)) {
+ // TRANS: Client exception thrown when referencing a non-existing notice.
+ throw new ClientException(_('No such notice.'), 404);
+ }
+
+ $this->_fave = Fave::pkeyGet(array('user_id' => $profileId,
+ 'notice_id' => $noticeId));
+
+ if (empty($this->_fave)) {
+ // TRANS: Client exception thrown when referencing a non-existing favorite.
+ throw new ClientException(_('No such favorite.'), 404);
+ }
+
+ return true;
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+ function handle($argarray=null)
+ {
+ parent::handle($argarray);
+
+ switch ($_SERVER['REQUEST_METHOD']) {
+ case GET:
+ case HEAD:
+ $this->showFave();
+ break;
+ case DELETE:
+ $this->deleteFave();
+ break;
+ default:
+ // TRANS: Client exception thrown using an unsupported HTTP method.
+ throw new ClientException(_('HTTP method not supported.'),
+ 405);
+ }
+ return true;
+ }
+
+ /**
+ * Show a single favorite, in ActivityStreams format
+ *
+ * @return void
+ */
+ function showFave()
+ {
+ $activity = $this->_fave->asActivity();
+
+ header('Content-Type: application/atom+xml; charset=utf-8');
+
+ $this->startXML();
+ $this->raw($activity->asString(true, true, true));
+ $this->endXML();
+
+ return;
+ }
+
+ /**
+ * Delete the favorite
+ *
+ * @return void
+ */
+ function deleteFave()
+ {
+ if (empty($this->auth_user) ||
+ $this->auth_user->id != $this->_profile->id) {
+ // TRANS: Client exception thrown when trying to remove a favorite notice of another user.
+ throw new ClientException(_("Cannot delete someone else's".
+ " favorite."), 403);
+ }
+
+ $this->_fave->delete();
+
+ return;
+ }
+
+ /**
+ * Return true if read only.
+ *
+ * MAY override
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean is read only action?
+ */
+ function isReadOnly($args)
+ {
+ if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
+ $_SERVER['REQUEST_METHOD'] == 'HEAD') {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Return last modified, if applicable.
+ *
+ * MAY override
+ *
+ * @return string last modified http header
+ */
+ function lastModified()
+ {
+ return max(strtotime($this->_profile->modified),
+ strtotime($this->_notice->modified),
+ strtotime($this->_fave->modified));
+ }
+
+ /**
+ * Return etag, if applicable.
+ *
+ * MAY override
+ *
+ * @return string etag http header
+ */
+ function etag()
+ {
+ $mtime = strtotime($this->_fave->modified);
+
+ return 'W/"' . implode(':', array('AtomPubShowFavorite',
+ $this->_profile->id,
+ $this->_notice->id,
+ $mtime)) . '"';
+ }
+
+ /**
+ * Does this require authentication?
+ *
+ * @return boolean true if delete, else false
+ */
+ function requiresAuth()
+ {
+ if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
+ $_SERVER['REQUEST_METHOD'] == 'HEAD') {
+ return false;
+ } else {
+ return true;
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Disfavor action.
+ *
+ * PHP version 5
+ *
+ * @category Action
+ * @package GNUsocial
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
+ * @author Mikael Nordfeldth <mmn@hethane.se>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://www.gnu.org/software/social/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('GNUSOCIAL')) { exit(1); }
+
+/**
+ * DisfavorAction class.
+ *
+ * @category Action
+ * @package GNUsocial
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
+ * @author Mikael Nordfeldth <mmn@hethane.se>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://www.gnu.org/software/social/
+ */
+class DisfavorAction extends FormAction
+{
+ public function showForm($msg=null, $success=false)
+ {
+ if ($success) {
+ common_redirect(common_local_url('showfavorites',
+ array('nickname' => $this->scoped->nickname)), 303);
+ }
+ parent::showForm($msg, $success);
+ }
+
+ protected function handlePost()
+ {
+ $id = $this->trimmed('notice');
+ $notice = Notice::getKV($id);
+ if (!$notice instanceof Notice) {
+ $this->serverError(_('Notice not found'));
+ }
+
+ $fave = new Fave();
+ $fave->user_id = $this->scoped->id;
+ $fave->notice_id = $notice->id;
+ if (!$fave->find(true)) {
+ throw new NoResultException($fave);
+ }
+ $result = $fave->delete();
+ if (!$result) {
+ common_log_db_error($fave, 'DELETE', __FILE__);
+ // TRANS: Server error displayed when removing a favorite from the database fails.
+ $this->serverError(_('Could not delete favorite.'));
+ }
+ $this->scoped->blowFavesCache();
+ if (StatusNet::isAjax()) {
+ $this->startHTML('text/xml;charset=utf-8');
+ $this->elementStart('head');
+ // TRANS: Title for page on which favorites can be added.
+ $this->element('title', null, _('Add to favorites'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ $favor = new FavorForm($this, $notice);
+ $favor->show();
+ $this->elementEnd('body');
+ $this->endHTML();
+ exit;
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Favor action.
+ *
+ * PHP version 5
+ *
+ * @category Action
+ * @package GNUsocial
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
+ * @author Mikael Nordfeldth <mmn@hethane.se>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://www.gnu.org/software/social/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('GNUSOCIAL')) { exit(1); }
+
+require_once INSTALLDIR.'/lib/mail.php';
+
+/**
+ * FavorAction class.
+ *
+ * @category Action
+ * @package GNUsocial
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
+ * @author Mikael Nordfeldth <mmn@hethane.se>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://www.gnu.org/software/social/
+ */
+class FavorAction extends FormAction
+{
+ protected $needPost = true;
+
+ protected function handlePost()
+ {
+ $id = $this->trimmed('notice');
+ $notice = Notice::getKV($id);
+ if (!($notice instanceof Notice)) {
+ $this->serverError(_('Notice not found'));
+ }
+ if ($this->scoped->hasFave($notice)) {
+ // TRANS: Client error displayed when trying to mark a notice as favorite that already is a favorite.
+ $this->clientError(_('This notice is already a favorite!'));
+ }
+ $fave = Fave::addNew($this->scoped, $notice);
+ if (!$fave) {
+ // TRANS: Server error displayed when trying to mark a notice as favorite fails in the database.
+ $this->serverError(_('Could not create favorite.'));
+ }
+ $this->notify($notice, $this->scoped->getUser());
+ $this->scoped->blowFavesCache();
+ if (StatusNet::isAjax()) {
+ $this->startHTML('text/xml;charset=utf-8');
+ $this->elementStart('head');
+ // TRANS: Page title for page on which favorite notices can be unfavourited.
+ $this->element('title', null, _('Disfavor favorite.'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ $disfavor = new DisFavorForm($this, $notice);
+ $disfavor->show();
+ $this->elementEnd('body');
+ $this->endHTML();
+ exit;
+ }
+ common_redirect(common_local_url('showfavorites',
+ array('nickname' => $this->scoped->nickname)),
+ 303);
+ }
+
+ /**
+ * Notifies a user when their notice is favorited.
+ *
+ * @param class $notice favorited notice
+ * @param class $user user declaring a favorite
+ *
+ * @return void
+ */
+ function notify($notice, $user)
+ {
+ $other = User::getKV('id', $notice->profile_id);
+ if ($other && $other->id != $user->id) {
+ if ($other->email && $other->emailnotifyfav) {
+ mail_notify_fave($other, $user, $notice);
+ }
+ // XXX: notify by IM
+ // XXX: notify by SMS
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * List of popular notices
+ *
+ * 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 Public
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+require_once INSTALLDIR.'/lib/publicgroupnav.php';
+require_once INSTALLDIR.'/lib/noticelist.php';
+
+/**
+ * List of popular notices
+ *
+ * We provide a list of the most popular notices. Popularity
+ * is measured by
+ *
+ * @category Personal
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @author Evan Prodromou <evan@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 FavoritedAction extends Action
+{
+ var $page = null;
+
+ /**
+ * Title of the page
+ *
+ * @return string Title of the page
+ */
+
+ function title()
+ {
+ if ($this->page == 1) {
+ // TRANS: Page title for first page of favorited notices.
+ return _('Popular notices');
+ } else {
+ // TRANS: Page title for all but first page of favorited notices.
+ // TRANS: %d is the page number being displayed.
+ return sprintf(_('Popular notices, page %d'), $this->page);
+ }
+ }
+
+ /**
+ * Instructions for use
+ *
+ * @return instructions for use
+ */
+ function getInstructions()
+ {
+ // TRANS: Description on page displaying favorited notices.
+ return _('The most popular notices on the site right now.');
+ }
+
+ /**
+ * Is this page read-only?
+ *
+ * @return boolean true
+ */
+ function isReadOnly($args)
+ {
+ return true;
+ }
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ * @todo move queries from showContent() to here
+ */
+ function prepare($args)
+ {
+ parent::prepare($args);
+ $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
+
+ common_set_returnto($this->selfUrl());
+
+ return true;
+ }
+
+ /**
+ * Handle request
+ *
+ * Shows a page with list of favorite notices
+ *
+ * @param array $args $_REQUEST args; handled in prepare()
+ *
+ * @return void
+ */
+ function handle($args)
+ {
+ parent::handle($args);
+
+ $this->showPage();
+ }
+
+ /**
+ * Show the page notice
+ *
+ * Shows instructions for the page
+ *
+ * @return void
+ */
+ function showPageNotice()
+ {
+ $instr = $this->getInstructions();
+ $output = common_markup_to_html($instr);
+
+ $this->elementStart('div', 'instructions');
+ $this->raw($output);
+ $this->elementEnd('div');
+ }
+
+ function showEmptyList()
+ {
+ // TRANS: Text displayed instead of a list when a site does not yet have any favourited notices.
+ $message = _('Favorite notices appear on this page but no one has favorited one yet.') . ' ';
+
+ if (common_logged_in()) {
+ // TRANS: Additional text displayed instead of a list when a site does not yet have any favourited notices for logged in users.
+ $message .= _('Be the first to add a notice to your favorites by clicking the fave button next to any notice you like.');
+ }
+ else {
+ // TRANS: Additional text displayed instead of a list when a site does not yet have any favourited notices for not logged in users.
+ // TRANS: %%action.register%% is a registration link. "[link text](link)" is Mark Down. Do not change the formatting.
+ $message .= _('Why not [register an account](%%action.register%%) and be the first to add a notice to your favorites!');
+ }
+
+ $this->elementStart('div', 'guide');
+ $this->raw(common_markup_to_html($message));
+ $this->elementEnd('div');
+ }
+
+ /**
+ * Content area
+ *
+ * Shows the list of popular notices
+ *
+ * @return void
+ */
+ function showContent()
+ {
+ $stream = new PopularNoticeStream(Profile::current());
+ $notice = $stream->getNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE+1);
+
+ $nl = new NoticeList($notice, $this);
+
+ $cnt = $nl->show();
+
+ if ($cnt == 0) {
+ $this->showEmptyList();
+ }
+
+ $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
+ $this->page, 'favorited');
+ }
+}
--- /dev/null
+<?php
+/**
+ * RSS feed for user favorites action class.
+ *
+ * PHP version 5
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+require_once INSTALLDIR.'/lib/rssaction.php';
+
+/**
+ * RSS feed for user favorites action class.
+ *
+ * Formatting of RSS handled by Rss10Action
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ */
+class FavoritesrssAction extends Rss10Action
+{
+ /** The user whose favorites to display */
+
+ var $user = null;
+
+ /**
+ * Find the user to display by supplied nickname
+ *
+ * @param array $args Arguments from $_REQUEST
+ *
+ * @return boolean success
+ */
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $nickname = $this->trimmed('nickname');
+ $this->user = User::getKV('nickname', $nickname);
+
+ if (!$this->user) {
+ // TRANS: Client error displayed when trying to get the RSS feed with favorites of a user that does not exist.
+ $this->clientError(_('No such user.'));
+ } else {
+ $this->notices = $this->getNotices($this->limit);
+ return true;
+ }
+ }
+
+ /**
+ * Get notices
+ *
+ * @param integer $limit max number of notices to return
+ *
+ * @return array notices
+ */
+ function getNotices($limit=0)
+ {
+ $user = $this->user;
+ $notice = $user->favoriteNotices(false, 0, $limit);
+ $notices = array();
+ while ($notice->fetch()) {
+ $notices[] = clone($notice);
+ }
+ return $notices;
+ }
+
+ /**
+ * Get channel.
+ *
+ * @return array associative array on channel information
+ */
+ function getChannel()
+ {
+ $user = $this->user;
+ $c = array('url' => common_local_url('favoritesrss',
+ array('nickname' =>
+ $user->nickname)),
+ // TRANS: Title of RSS feed with favourite notices of a user.
+ // TRANS: %s is a user's nickname.
+ 'title' => sprintf(_("%s's favorite notices"), $user->nickname),
+ 'link' => common_local_url('showfavorites',
+ array('nickname' =>
+ $user->nickname)),
+ // TRANS: Desciption of RSS feed with favourite notices of a user.
+ // TRANS: %1$s is a user's nickname, %2$s is the name of the StatusNet site.
+ 'description' => sprintf(_('Updates favored by %1$s on %2$s!'),
+ $user->nickname, common_config('site', 'name')));
+ return $c;
+ }
+
+ /**
+ * Get image.
+ *
+ * @return void
+ */
+ function getImage()
+ {
+ return null;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * List of replies
+ *
+ * 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 Personal
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+require_once INSTALLDIR.'/lib/personalgroupnav.php';
+require_once INSTALLDIR.'/lib/noticelist.php';
+require_once INSTALLDIR.'/lib/feedlist.php';
+
+/**
+ * List of replies
+ *
+ * @category Personal
+ * @package StatusNet
+ * @author Evan Prodromou <evan@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 ShowfavoritesAction extends Action
+{
+ /** User we're getting the faves of */
+ var $user = null;
+ /** Page of the faves we're on */
+ var $page = null;
+
+ /**
+ * Is this a read-only page?
+ *
+ * @return boolean true
+ */
+ function isReadOnly($args)
+ {
+ return true;
+ }
+
+ /**
+ * Title of the page
+ *
+ * Includes name of user and page number.
+ *
+ * @return string title of page
+ */
+ function title()
+ {
+ if ($this->page == 1) {
+ // TRANS: Title for first page of favourite notices of a user.
+ // TRANS: %s is the user for whom the favourite notices are displayed.
+ return sprintf(_('%s\'s favorite notices'), $this->user->nickname);
+ } else {
+ // TRANS: Title for all but the first page of favourite notices of a user.
+ // TRANS: %1$s is the user for whom the favourite notices are displayed, %2$d is the page number.
+ return sprintf(_('%1$s\'s favorite notices, page %2$d'),
+ $this->user->nickname,
+ $this->page);
+ }
+ }
+
+ /**
+ * Prepare the object
+ *
+ * Check the input values and initialize the object.
+ * Shows an error page on bad input.
+ *
+ * @param array $args $_REQUEST data
+ *
+ * @return boolean success flag
+ */
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $nickname = common_canonical_nickname($this->arg('nickname'));
+
+ $this->user = User::getKV('nickname', $nickname);
+
+ if (!$this->user) {
+ // TRANS: Client error displayed when trying to display favourite notices for a non-existing user.
+ $this->clientError(_('No such user.'));
+ }
+
+ $this->page = $this->trimmed('page');
+
+ if (!$this->page) {
+ $this->page = 1;
+ }
+
+ common_set_returnto($this->selfUrl());
+
+ $cur = common_current_user();
+
+ if (!empty($cur) && $cur->id == $this->user->id) {
+
+ // Show imported/gateway notices as well as local if
+ // the user is looking at their own favorites
+
+ $this->notice = $this->user->favoriteNotices(true, ($this->page-1)*NOTICES_PER_PAGE,
+ NOTICES_PER_PAGE + 1);
+ } else {
+ $this->notice = $this->user->favoriteNotices(false, ($this->page-1)*NOTICES_PER_PAGE,
+ NOTICES_PER_PAGE + 1);
+ }
+
+ if (empty($this->notice)) {
+ // TRANS: Server error displayed when favourite notices could not be retrieved from the database.
+ $this->serverError(_('Could not retrieve favorite notices.'));
+ }
+
+ if($this->page > 1 && $this->notice->N == 0){
+ // TRANS: Server error when page not found (404)
+ $this->serverError(_('No such page.'),$code=404);
+ }
+
+ return true;
+ }
+
+ /**
+ * Handle a request
+ *
+ * Just show the page. All args already handled.
+ *
+ * @param array $args $_REQUEST data
+ *
+ * @return void
+ */
+ function handle($args)
+ {
+ parent::handle($args);
+ $this->showPage();
+ }
+
+ /**
+ * Feeds for the <head> section
+ *
+ * @return array Feed objects to show
+ */
+ function getFeeds()
+ {
+ return array(new Feed(Feed::JSON,
+ common_local_url('ApiTimelineFavorites',
+ array(
+ 'id' => $this->user->nickname,
+ 'format' => 'as')),
+ // TRANS: Feed link text. %s is a username.
+ sprintf(_('Feed for favorites of %s (Activity Streams JSON)'),
+ $this->user->nickname)),
+ new Feed(Feed::RSS1,
+ common_local_url('favoritesrss',
+ array('nickname' => $this->user->nickname)),
+ // TRANS: Feed link text. %s is a username.
+ sprintf(_('Feed for favorites of %s (RSS 1.0)'),
+ $this->user->nickname)),
+ new Feed(Feed::RSS2,
+ common_local_url('ApiTimelineFavorites',
+ array(
+ 'id' => $this->user->nickname,
+ 'format' => 'rss')),
+ // TRANS: Feed link text. %s is a username.
+ sprintf(_('Feed for favorites of %s (RSS 2.0)'),
+ $this->user->nickname)),
+ new Feed(Feed::ATOM,
+ common_local_url('ApiTimelineFavorites',
+ array(
+ 'id' => $this->user->nickname,
+ 'format' => 'atom')),
+ // TRANS: Feed link text. %s is a username.
+ sprintf(_('Feed for favorites of %s (Atom)'),
+ $this->user->nickname)));
+ }
+
+ function showEmptyListMessage()
+ {
+ if (common_logged_in()) {
+ $current_user = common_current_user();
+ if ($this->user->id === $current_user->id) {
+ // TRANS: Text displayed instead of favourite notices for the current logged in user that has no favourites.
+ $message = _('You haven\'t chosen any favorite notices yet. Click the fave button on notices you like to bookmark them for later or shed a spotlight on them.');
+ } else {
+ // TRANS: Text displayed instead of favourite notices for a user that has no favourites while logged in.
+ // TRANS: %s is a username.
+ $message = sprintf(_('%s hasn\'t added any favorite notices yet. Post something interesting they would add to their favorites :)'), $this->user->nickname);
+ }
+ }
+ else {
+ // TRANS: Text displayed instead of favourite notices for a user that has no favourites while not logged in.
+ // TRANS: %s is a username, %%%%action.register%%%% is a link to the user registration page.
+ // TRANS: (link text)[link] is a Mark Down link.
+ $message = sprintf(_('%s hasn\'t added any favorite notices yet. Why not [register an account](%%%%action.register%%%%) and then post something interesting they would add to their favorites :)'), $this->user->nickname);
+ }
+
+ $this->elementStart('div', 'guide');
+ $this->raw(common_markup_to_html($message));
+ $this->elementEnd('div');
+ }
+
+ /**
+ * Show the content
+ *
+ * A list of notices that this user has marked as a favorite
+ *
+ * @return void
+ */
+ function showContent()
+ {
+ $nl = new FavoritesNoticeList($this->notice, $this);
+
+ $cnt = $nl->show();
+ if (0 == $cnt) {
+ $this->showEmptyListMessage();
+ }
+
+ $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
+ $this->page, 'showfavorites',
+ array('nickname' => $this->user->nickname));
+ }
+
+ function showPageNotice() {
+ // TRANS: Page notice for show favourites page.
+ $this->element('p', 'instructions', _('This is a way to share what you like.'));
+ }
+}
+
+class FavoritesNoticeList extends NoticeList
+{
+ function newListItem($notice)
+ {
+ return new FavoritesNoticeListItem($notice, $this->out);
+ }
+}
+
+// All handled by superclass
+class FavoritesNoticeListItem extends DoFollowListItem
+{
+}
--- /dev/null
+<?php
+/**
+ * Table Definition for fave
+ */
+require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
+
+class Fave extends Managed_DataObject
+{
+ ###START_AUTOCODE
+ /* the code below is auto generated do not remove the above tag */
+
+ public $__table = 'fave'; // table name
+ public $notice_id; // int(4) primary_key not_null
+ public $user_id; // int(4) primary_key not_null
+ public $uri; // varchar(255)
+ public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
+
+ /* the code above is auto generated do not remove the tag below */
+ ###END_AUTOCODE
+
+ public static function schemaDef()
+ {
+ return array(
+ 'fields' => array(
+ 'notice_id' => array('type' => 'int', 'not null' => true, 'description' => 'notice that is the favorite'),
+ 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user who likes this notice'),
+ 'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universally unique identifier, usually a tag URI'),
+ 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
+ ),
+ 'primary key' => array('notice_id', 'user_id'),
+ 'unique keys' => array(
+ 'fave_uri_key' => array('uri'),
+ ),
+ 'foreign keys' => array(
+ 'fave_notice_id_fkey' => array('notice', array('notice_id' => 'id')),
+ 'fave_user_id_fkey' => array('profile', array('user_id' => 'id')), // note: formerly referenced notice.id, but we can now record remote users' favorites
+ ),
+ 'indexes' => array(
+ 'fave_notice_id_idx' => array('notice_id'),
+ 'fave_user_id_idx' => array('user_id', 'modified'),
+ 'fave_modified_idx' => array('modified'),
+ ),
+ );
+ }
+
+ /**
+ * Save a favorite record.
+ * @fixme post-author notification should be moved here
+ *
+ * @param Profile $profile the local or remote user who likes
+ * @param Notice $notice the notice that is liked
+ * @return mixed false on failure, or Fave record on success
+ */
+ static function addNew(Profile $profile, Notice $notice) {
+
+ $fave = null;
+
+ if (Event::handle('StartFavorNotice', array($profile, $notice, &$fave))) {
+
+ $fave = new Fave();
+
+ $fave->user_id = $profile->id;
+ $fave->notice_id = $notice->id;
+ $fave->modified = common_sql_now();
+ $fave->uri = self::newURI($fave->user_id,
+ $fave->notice_id,
+ $fave->modified);
+ if (!$fave->insert()) {
+ common_log_db_error($fave, 'INSERT', __FILE__);
+ return false;
+ }
+ self::blow('fave:list-ids:notice_id:%d', $fave->notice_id);
+ self::blow('popular');
+
+ Event::handle('EndFavorNotice', array($profile, $notice));
+ }
+
+ return $fave;
+ }
+
+ function delete($useWhere=false)
+ {
+ $profile = Profile::getKV('id', $this->user_id);
+ $notice = Notice::getKV('id', $this->notice_id);
+
+ $result = null;
+
+ if (Event::handle('StartDisfavorNotice', array($profile, $notice, &$result))) {
+
+ $result = parent::delete($useWhere);
+ self::blow('fave:list-ids:notice_id:%d', $this->notice_id);
+ self::blow('popular');
+
+ if ($result) {
+ Event::handle('EndDisfavorNotice', array($profile, $notice));
+ }
+ }
+
+ return $result;
+ }
+
+ function stream($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $own=false, $since_id=0, $max_id=0)
+ {
+ $stream = new FaveNoticeStream($user_id, $own);
+
+ return $stream->getNotices($offset, $limit, $since_id, $max_id);
+ }
+
+ function idStream($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $own=false, $since_id=0, $max_id=0)
+ {
+ $stream = new FaveNoticeStream($user_id, $own);
+
+ return $stream->getNoticeIds($offset, $limit, $since_id, $max_id);
+ }
+
+ function asActivity()
+ {
+ $notice = Notice::getKV('id', $this->notice_id);
+
+ if (!$notice) {
+ throw new Exception("Fave for non-existent notice: " . $this->notice_id);
+ }
+
+ $profile = Profile::getKV('id', $this->user_id);
+
+ if (!$profile) {
+ throw new Exception("Fave by non-existent profile: " . $this->user_id);
+ }
+
+ $act = new Activity();
+
+ $act->verb = ActivityVerb::FAVORITE;
+
+ // FIXME: rationalize this with URL below
+
+ $act->id = $this->getURI();
+
+ $act->time = strtotime($this->modified);
+ // TRANS: Activity title when marking a notice as favorite.
+ $act->title = _("Favor");
+ // TRANS: Ntofication given when a user marks a notice as favorite.
+ // TRANS: %1$s is a user nickname or full name, %2$s is a notice URI.
+ $act->content = sprintf(_('%1$s marked notice %2$s as a favorite.'),
+ $profile->getBestName(),
+ $notice->getUrl());
+
+ $act->actor = ActivityObject::fromProfile($profile);
+ $act->objects[] = ActivityObject::fromNotice($notice);
+
+ $url = common_local_url('AtomPubShowFavorite',
+ array('profile' => $this->user_id,
+ 'notice' => $this->notice_id));
+
+ $act->selfLink = $url;
+ $act->editLink = $url;
+
+ return $act;
+ }
+
+ /**
+ * Fetch a stream of favorites by profile
+ *
+ * @param integer $profileId Profile that faved
+ * @param integer $offset Offset from last
+ * @param integer $limit Number to get
+ *
+ * @return mixed stream of faves, use fetch() to iterate
+ *
+ * @todo Cache results
+ * @todo integrate with Fave::stream()
+ */
+
+ static function byProfile($profileId, $offset, $limit)
+ {
+ $fav = new Fave();
+
+ $fav->user_id = $profileId;
+
+ $fav->orderBy('modified DESC');
+
+ $fav->limit($offset, $limit);
+
+ $fav->find();
+
+ return $fav;
+ }
+
+ function getURI()
+ {
+ if (!empty($this->uri)) {
+ return $this->uri;
+ } else {
+ return self::newURI($this->user_id, $this->notice_id, $this->modified);
+ }
+ }
+
+ static function newURI($profile_id, $notice_id, $modified)
+ {
+ return TagURI::mint('favor:%d:%d:%s',
+ $profile_id,
+ $notice_id,
+ common_date_iso8601($modified));
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Form for disfavoring a notice
+ *
+ * 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 Form
+ * @package GNUsocial
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @author Mikael Nordfeldth <mmn@hethane.se>
+ * @copyright 2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://www.gnu.org/software/social/
+ */
+
+if (!defined('GNUSOCIAL')) { exit(1); }
+
+/**
+ * Form for disfavoring a notice
+ *
+ * @category Form
+ * @package GNUsocial
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @author Mikael Nordfeldth <mmn@hethane.se>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://www.gnu.org/software/social/
+ *
+ * @see FavorForm
+ */
+class DisfavorForm extends Form
+{
+ /**
+ * Notice to disfavor
+ */
+ var $notice = null;
+
+ /**
+ * Constructor
+ *
+ * @param HTMLOutputter $out output channel
+ * @param Notice $notice notice to disfavor
+ */
+ function __construct($out=null, $notice=null)
+ {
+ parent::__construct($out);
+
+ $this->notice = $notice;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'disfavor-' . $this->notice->id;
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('disfavor');
+ }
+
+ /**
+ * Legend of the Form
+ *
+ * @return void
+ */
+ function formLegend()
+ {
+ // TRANS: Form legend for removing the favourite status for a favourite notice.
+ $this->out->element('legend', null, _('Disfavor this notice'));
+ }
+
+ /**
+ * Data elements
+ *
+ * @return void
+ */
+
+ function formData()
+ {
+ if (Event::handle('StartDisFavorNoticeForm', array($this, $this->notice))) {
+ $this->out->hidden('notice-n'.$this->notice->id,
+ $this->notice->id,
+ 'notice');
+ Event::handle('EndDisFavorNoticeForm', array($this, $this->notice));
+ }
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ $this->out->submit('disfavor-submit-' . $this->notice->id,
+ // TRANS: Button text for removing the favourite status for a favourite notice.
+ _m('BUTTON','Disfavor favorite'),
+ 'submit',
+ null,
+ // TRANS: Button title for removing the favourite status for a favourite notice.
+ _('Remove this notice from your list of favorite notices.'));
+ }
+
+ /**
+ * Class of the form.
+ *
+ * @return string the form's class
+ */
+ function formClass()
+ {
+ return 'form_disfavor ajax';
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Form for favoring a notice
+ *
+ * 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 Form
+ * @package GNUsocial
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @author Mikael Nordfeldth <mmn@hethane.se>
+ * @copyright 2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://www.gnu.org/software/social/
+ */
+
+if (!defined('GNUSOCIAL')) { exit(1); }
+
+/**
+ * Form for favoring a notice
+ *
+ * @category Form
+ * @package GNUsocial
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @author Mikael Nordfeldth <mmn@hethane.se>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://www.gnu.org/software/social/
+ *
+ * @see DisfavorForm
+ */
+class FavorForm extends Form
+{
+ /**
+ * Notice to favor
+ */
+ var $notice = null;
+
+ /**
+ * Constructor
+ *
+ * @param HTMLOutputter $out output channel
+ * @param Notice $notice notice to favor
+ */
+ function __construct($out=null, $notice=null)
+ {
+ parent::__construct($out);
+
+ $this->notice = $notice;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'favor-' . $this->notice->id;
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('favor');
+ }
+
+ /**
+ * Legend of the Form
+ *
+ * @return void
+ */
+ function formLegend()
+ {
+ // TRANS: Form legend for adding the favourite status to a notice.
+ $this->out->element('legend', null, _('Favor this notice'));
+ }
+
+ /**
+ * Data elements
+ *
+ * @return void
+ */
+ function formData()
+ {
+ if (Event::handle('StartFavorNoticeForm', array($this, $this->notice))) {
+ $this->out->hidden('notice-n'.$this->notice->id,
+ $this->notice->id,
+ 'notice');
+ Event::handle('EndFavorNoticeForm', array($this, $this->notice));
+ }
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ $this->out->submit('favor-submit-' . $this->notice->id,
+ // TRANS: Button text for adding the favourite status to a notice.
+ _m('BUTTON','Favor'),
+ 'submit',
+ null,
+ // TRANS: Button title for adding the favourite status to a notice.
+ _('Add this notice to your list of favorite notices.'));
+ }
+
+ /**
+ * Class of the form.
+ *
+ * @return string the form's class
+ */
+ function formClass()
+ {
+ return 'form_favor ajax';
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Notice stream for favorites
+ *
+ * PHP version 5
+ *
+ * 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 Stream
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Notice stream for favorites
+ *
+ * @category Stream
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class FaveNoticeStream extends ScopingNoticeStream
+{
+ function __construct($user_id, $own, $profile = -1)
+ {
+ $stream = new RawFaveNoticeStream($user_id, $own);
+ if ($own) {
+ $key = 'fave:ids_by_user_own:'.$user_id;
+ } else {
+ $key = 'fave:ids_by_user:'.$user_id;
+ }
+ if (is_int($profile) && $profile == -1) {
+ $profile = Profile::current();
+ }
+ parent::__construct(new CachingNoticeStream($stream, $key),
+ $profile);
+ }
+}
+
+/**
+ * Raw notice stream for favorites
+ *
+ * @category Stream
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class RawFaveNoticeStream extends NoticeStream
+{
+ protected $user_id;
+ protected $own;
+
+ function __construct($user_id, $own)
+ {
+ $this->user_id = $user_id;
+ $this->own = $own;
+ }
+
+ /**
+ * Note that the sorting for this is by order of *fave* not order of *notice*.
+ *
+ * @fixme add since_id, max_id support?
+ *
+ * @param <type> $user_id
+ * @param <type> $own
+ * @param <type> $offset
+ * @param <type> $limit
+ * @param <type> $since_id
+ * @param <type> $max_id
+ * @return <type>
+ */
+ function getNoticeIds($offset, $limit, $since_id, $max_id)
+ {
+ $fav = new Fave();
+ $qry = null;
+
+ if ($this->own) {
+ $qry = 'SELECT fave.* FROM fave ';
+ $qry .= 'WHERE fave.user_id = ' . $this->user_id . ' ';
+ } else {
+ $qry = 'SELECT fave.* FROM fave ';
+ $qry .= 'INNER JOIN notice ON fave.notice_id = notice.id ';
+ $qry .= 'WHERE fave.user_id = ' . $this->user_id . ' ';
+ $qry .= 'AND notice.is_local != ' . Notice::GATEWAY . ' ';
+ }
+
+ if ($since_id != 0) {
+ $qry .= 'AND notice_id > ' . $since_id . ' ';
+ }
+
+ if ($max_id != 0) {
+ $qry .= 'AND notice_id <= ' . $max_id . ' ';
+ }
+
+ // NOTE: we sort by fave time, not by notice time!
+
+ $qry .= 'ORDER BY modified DESC ';
+
+ if (!is_null($offset)) {
+ $qry .= "LIMIT $limit OFFSET $offset";
+ }
+
+ $fav->query($qry);
+
+ $ids = array();
+
+ while ($fav->fetch()) {
+ $ids[] = $fav->notice_id;
+ }
+
+ $fav->free();
+ unset($fav);
+
+ return $ids;
+ }
+}
+
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Base class for sections showing lists of notices
+ *
+ * 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 Widget
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009,2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+/**
+ * Base class for sections showing lists of notices
+ *
+ * These are the widgets that show interesting data about a person
+ * group, or site.
+ *
+ * @category Widget
+ * @package StatusNet
+ * @author Evan Prodromou <evan@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 PopularNoticeSection extends NoticeSection
+{
+ protected $viewer;
+
+ function __construct($out, $viewer)
+ {
+ parent::__construct($out);
+ $this->viewer = $viewer;
+ }
+
+ function getNotices()
+ {
+ $stream = new PopularNoticeStream($this->viewer);
+ return $stream->getNotices(0, NOTICES_PER_SECTION + 1);
+ }
+
+ function title()
+ {
+ // TRANS: Title for favourited notices section.
+ return _('Popular notices');
+ }
+
+ function divId()
+ {
+ return 'popular_notices';
+ }
+
+ function moreUrl()
+ {
+ if (common_config('singleuser', 'enabled')) {
+ $user = User::singleUser();
+ common_local_url('showfavorites', array('nickname' =>
+ $user->nickname));
+ } else {
+ return common_local_url('favorited');
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Stream of notices sorted by popularity
+ *
+ * PHP version 5
+ *
+ * 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 Popular
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Stream of notices sorted by popularity
+ *
+ * @category Popular
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class PopularNoticeStream extends ScopingNoticeStream
+{
+ function __construct($profile=null)
+ {
+ parent::__construct(new CachingNoticeStream(new RawPopularNoticeStream(),
+ 'popular',
+ false),
+ $profile);
+ }
+}
+
+class RawPopularNoticeStream extends NoticeStream
+{
+ function getNoticeIds($offset, $limit, $since_id, $max_id)
+ {
+ $weightexpr = common_sql_weight('modified', common_config('popular', 'dropoff'));
+ $cutoff = sprintf("modified > '%s'",
+ common_sql_date(time() - common_config('popular', 'cutoff')));
+
+ $fave = new Fave();
+ $fave->selectAdd();
+ $fave->selectAdd('notice_id');
+ $fave->selectAdd("$weightexpr as weight");
+ $fave->whereAdd($cutoff);
+ $fave->orderBy('weight DESC');
+ $fave->groupBy('notice_id');
+
+ if (!is_null($offset)) {
+ $fave->limit($offset, $limit);
+ }
+
+ // FIXME: $since_id, $max_id are ignored
+
+ $ids = array();
+
+ if ($fave->find()) {
+ while ($fave->fetch()) {
+ $ids[] = $fave->notice_id;
+ }
+ }
+
+ return $ids;
+ }
+}
+