]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Favorite functionality put into plugin (not done yet)
authorMikael Nordfeldth <mmn@hethane.se>
Tue, 24 Jun 2014 13:52:54 +0000 (15:52 +0200)
committerMikael Nordfeldth <mmn@hethane.se>
Tue, 24 Jun 2014 13:58:53 +0000 (15:58 +0200)
Now we have to fix any code in the core which directly uses the Fave class
or any other favorite stuff, since it is pluginised and thus might not be
available on some installations.

37 files changed:
actions/apifavoritecreate.php [deleted file]
actions/apifavoritedestroy.php [deleted file]
actions/apistatusesfavs.php [deleted file]
actions/apitimelinefavorites.php [deleted file]
actions/atompubfavoritefeed.php [deleted file]
actions/atompubshowfavorite.php [deleted file]
actions/disfavor.php [deleted file]
actions/favor.php [deleted file]
actions/favorited.php [deleted file]
actions/favoritesrss.php [deleted file]
actions/showfavorites.php [deleted file]
classes/Fave.php [deleted file]
lib/default.php
lib/disfavorform.php [deleted file]
lib/favenoticestream.php [deleted file]
lib/favorform.php [deleted file]
lib/popularnoticesection.php [deleted file]
lib/popularnoticestream.php [deleted file]
lib/router.php
plugins/Favorite/FavoritePlugin.php [new file with mode: 0644]
plugins/Favorite/actions/apifavoritecreate.php [new file with mode: 0644]
plugins/Favorite/actions/apifavoritedestroy.php [new file with mode: 0644]
plugins/Favorite/actions/apistatusesfavs.php [new file with mode: 0644]
plugins/Favorite/actions/apitimelinefavorites.php [new file with mode: 0644]
plugins/Favorite/actions/atompubfavoritefeed.php [new file with mode: 0644]
plugins/Favorite/actions/atompubshowfavorite.php [new file with mode: 0644]
plugins/Favorite/actions/disfavor.php [new file with mode: 0644]
plugins/Favorite/actions/favor.php [new file with mode: 0644]
plugins/Favorite/actions/favorited.php [new file with mode: 0644]
plugins/Favorite/actions/favoritesrss.php [new file with mode: 0644]
plugins/Favorite/actions/showfavorites.php [new file with mode: 0644]
plugins/Favorite/classes/Fave.php [new file with mode: 0644]
plugins/Favorite/forms/disfavor.php [new file with mode: 0644]
plugins/Favorite/forms/favor.php [new file with mode: 0644]
plugins/Favorite/lib/favenoticestream.php [new file with mode: 0644]
plugins/Favorite/lib/popularnoticesection.php [new file with mode: 0644]
plugins/Favorite/lib/popularnoticestream.php [new file with mode: 0644]

diff --git a/actions/apifavoritecreate.php b/actions/apifavoritecreate.php
deleted file mode 100644 (file)
index 607fb76..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-<?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
-        }
-    }
-}
diff --git a/actions/apifavoritedestroy.php b/actions/apifavoritedestroy.php
deleted file mode 100644 (file)
index 02f81cf..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-<?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);
-        }
-    }
-}
diff --git a/actions/apistatusesfavs.php b/actions/apistatusesfavs.php
deleted file mode 100644 (file)
index 01a5d30..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-<?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;
-    }
-}
diff --git a/actions/apitimelinefavorites.php b/actions/apitimelinefavorites.php
deleted file mode 100644 (file)
index 13dc842..0000000
+++ /dev/null
@@ -1,263 +0,0 @@
-<?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;
-    }
-}
diff --git a/actions/atompubfavoritefeed.php b/actions/atompubfavoritefeed.php
deleted file mode 100644 (file)
index 837a9da..0000000
+++ /dev/null
@@ -1,372 +0,0 @@
-<?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
-        }
-    }
-}
diff --git a/actions/atompubshowfavorite.php b/actions/atompubshowfavorite.php
deleted file mode 100644 (file)
index 436e88e..0000000
+++ /dev/null
@@ -1,222 +0,0 @@
-<?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;
-        }
-    }
-}
diff --git a/actions/disfavor.php b/actions/disfavor.php
deleted file mode 100644 (file)
index ef9ee1e..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-<?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;
-        }
-    }
-}
diff --git a/actions/favor.php b/actions/favor.php
deleted file mode 100644 (file)
index 8c19f9d..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-<?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
-        }
-    }
-}
diff --git a/actions/favorited.php b/actions/favorited.php
deleted file mode 100644 (file)
index ff4a99c..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-<?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');
-    }
-}
diff --git a/actions/favoritesrss.php b/actions/favoritesrss.php
deleted file mode 100644 (file)
index de901b0..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-<?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;
-    }
-
-}
diff --git a/actions/showfavorites.php b/actions/showfavorites.php
deleted file mode 100644 (file)
index 0e02841..0000000
+++ /dev/null
@@ -1,261 +0,0 @@
-<?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
-{
-}
diff --git a/classes/Fave.php b/classes/Fave.php
deleted file mode 100644 (file)
index 2076143..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-<?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));
-    }
-}
index f00104936339dc8459673453bb20daf52de2e12a..59f3cd99856f0a884fccb6d25787be43a7e6e4d8 100644 (file)
@@ -294,6 +294,7 @@ $default =
         array('core' => array(
                             'AuthCrypt' => array(),
                             'Cronish' => array(),
+                            'Favorite' => array(),
                             'LRDD' => array(),
                             'StrictTransportSecurity' => array(),
                         ),
diff --git a/lib/disfavorform.php b/lib/disfavorform.php
deleted file mode 100644 (file)
index 51903b6..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-<?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';
-    }
-}
diff --git a/lib/favenoticestream.php b/lib/favenoticestream.php
deleted file mode 100644 (file)
index 6527e54..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-<?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;
-    }
-}
-
diff --git a/lib/favorform.php b/lib/favorform.php
deleted file mode 100644 (file)
index cd956f6..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-<?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';
-    }
-}
diff --git a/lib/popularnoticesection.php b/lib/popularnoticesection.php
deleted file mode 100644 (file)
index 2000d30..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-<?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');
-        }
-    }
-}
diff --git a/lib/popularnoticestream.php b/lib/popularnoticestream.php
deleted file mode 100644 (file)
index eeba541..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-<?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;
-    }
-}
-
index 0a835ce4d8d5f5e317856ab20f175c6253833fc8..54683e986e67977aff5a3e72fed935df4e122571 100644 (file)
@@ -143,7 +143,7 @@ class Router
             $main = array('login', 'logout', 'register', 'subscribe',
                           'unsubscribe', 'cancelsubscription', 'approvesub',
                           'confirmaddress', 'recoverpassword',
-                          'invite', 'favor', 'disfavor', 'sup',
+                          'invite', 'sup',
                           'block', 'unblock', 'subedit',
                           'groupblock', 'groupunblock',
                           'sandbox', 'unsandbox',
@@ -454,11 +454,6 @@ class Router
                               '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',
@@ -595,39 +590,6 @@ class Router
             $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',
@@ -921,16 +883,12 @@ class Router
                                       '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));
@@ -1011,11 +969,8 @@ class Router
                 $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',
@@ -1096,16 +1051,12 @@ class Router
                                 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));
@@ -1155,15 +1106,6 @@ class Router
                         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]+',
diff --git a/plugins/Favorite/FavoritePlugin.php b/plugins/Favorite/FavoritePlugin.php
new file mode 100644 (file)
index 0000000..9fbaf25
--- /dev/null
@@ -0,0 +1,111 @@
+<?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;
+    }
+}
diff --git a/plugins/Favorite/actions/apifavoritecreate.php b/plugins/Favorite/actions/apifavoritecreate.php
new file mode 100644 (file)
index 0000000..607fb76
--- /dev/null
@@ -0,0 +1,173 @@
+<?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
+        }
+    }
+}
diff --git a/plugins/Favorite/actions/apifavoritedestroy.php b/plugins/Favorite/actions/apifavoritedestroy.php
new file mode 100644 (file)
index 0000000..02f81cf
--- /dev/null
@@ -0,0 +1,154 @@
+<?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);
+        }
+    }
+}
diff --git a/plugins/Favorite/actions/apistatusesfavs.php b/plugins/Favorite/actions/apistatusesfavs.php
new file mode 100644 (file)
index 0000000..01a5d30
--- /dev/null
@@ -0,0 +1,136 @@
+<?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;
+    }
+}
diff --git a/plugins/Favorite/actions/apitimelinefavorites.php b/plugins/Favorite/actions/apitimelinefavorites.php
new file mode 100644 (file)
index 0000000..13dc842
--- /dev/null
@@ -0,0 +1,263 @@
+<?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;
+    }
+}
diff --git a/plugins/Favorite/actions/atompubfavoritefeed.php b/plugins/Favorite/actions/atompubfavoritefeed.php
new file mode 100644 (file)
index 0000000..837a9da
--- /dev/null
@@ -0,0 +1,372 @@
+<?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
+        }
+    }
+}
diff --git a/plugins/Favorite/actions/atompubshowfavorite.php b/plugins/Favorite/actions/atompubshowfavorite.php
new file mode 100644 (file)
index 0000000..436e88e
--- /dev/null
@@ -0,0 +1,222 @@
+<?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;
+        }
+    }
+}
diff --git a/plugins/Favorite/actions/disfavor.php b/plugins/Favorite/actions/disfavor.php
new file mode 100644 (file)
index 0000000..ef9ee1e
--- /dev/null
@@ -0,0 +1,91 @@
+<?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;
+        }
+    }
+}
diff --git a/plugins/Favorite/actions/favor.php b/plugins/Favorite/actions/favor.php
new file mode 100644 (file)
index 0000000..8c19f9d
--- /dev/null
@@ -0,0 +1,106 @@
+<?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
+        }
+    }
+}
diff --git a/plugins/Favorite/actions/favorited.php b/plugins/Favorite/actions/favorited.php
new file mode 100644 (file)
index 0000000..ff4a99c
--- /dev/null
@@ -0,0 +1,189 @@
+<?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');
+    }
+}
diff --git a/plugins/Favorite/actions/favoritesrss.php b/plugins/Favorite/actions/favoritesrss.php
new file mode 100644 (file)
index 0000000..de901b0
--- /dev/null
@@ -0,0 +1,131 @@
+<?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;
+    }
+
+}
diff --git a/plugins/Favorite/actions/showfavorites.php b/plugins/Favorite/actions/showfavorites.php
new file mode 100644 (file)
index 0000000..0e02841
--- /dev/null
@@ -0,0 +1,261 @@
+<?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
+{
+}
diff --git a/plugins/Favorite/classes/Fave.php b/plugins/Favorite/classes/Fave.php
new file mode 100644 (file)
index 0000000..2076143
--- /dev/null
@@ -0,0 +1,204 @@
+<?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));
+    }
+}
diff --git a/plugins/Favorite/forms/disfavor.php b/plugins/Favorite/forms/disfavor.php
new file mode 100644 (file)
index 0000000..51903b6
--- /dev/null
@@ -0,0 +1,139 @@
+<?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';
+    }
+}
diff --git a/plugins/Favorite/forms/favor.php b/plugins/Favorite/forms/favor.php
new file mode 100644 (file)
index 0000000..cd956f6
--- /dev/null
@@ -0,0 +1,138 @@
+<?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';
+    }
+}
diff --git a/plugins/Favorite/lib/favenoticestream.php b/plugins/Favorite/lib/favenoticestream.php
new file mode 100644 (file)
index 0000000..6527e54
--- /dev/null
@@ -0,0 +1,144 @@
+<?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;
+    }
+}
+
diff --git a/plugins/Favorite/lib/popularnoticesection.php b/plugins/Favorite/lib/popularnoticesection.php
new file mode 100644 (file)
index 0000000..2000d30
--- /dev/null
@@ -0,0 +1,83 @@
+<?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');
+        }
+    }
+}
diff --git a/plugins/Favorite/lib/popularnoticestream.php b/plugins/Favorite/lib/popularnoticestream.php
new file mode 100644 (file)
index 0000000..eeba541
--- /dev/null
@@ -0,0 +1,92 @@
+<?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;
+    }
+}
+