code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * List a user's subscribers
 *
 * 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  Social
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Sarven Capadisli <csarven@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);
}

/**
 * List a user's subscribers
 *
 * @category Social
 * @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 SubscribersAction extends GalleryAction
{
    function title()
    {
        if ($this->page == 1) {
            // TRANS: Header for list of subscribers for a user (first page).
            // TRANS: %s is the user's nickname.
            return sprintf(_('%s subscribers'), $this->target->getNickname());
        } else {
            // TRANS: Header for list of subscribers for a user (not first page).
            // TRANS: %1$s is the user's nickname, $2$d is the page number.
            return sprintf(_('%1$s subscribers, page %2$d'),
                           $this->target->getNickname(),
                           $this->page);
        }
    }

    function showPageNotice()
    {
        if ($this->scoped instanceof Profile && $this->scoped->id === $this->target->id) {
            $this->element('p', null,
                           // TRANS: Page notice for page with an overview of all subscribers
                           // TRANS: of the logged in user's own profile.
                           _('These are the people who listen to '.
                             'your notices.'));
        } else {
            $this->element('p', null,
                           // TRANS: Page notice for page with an overview of all subscribers of a user other
                           // TRANS: than the logged in user. %s is the user nickname.
                           sprintf(_('These are the people who '.
                                     'listen to %s\'s notices.'),
                                   $this->target->getNickname()));
        }
    }

    function showContent()
    {
        parent::showContent();

        $offset = ($this->page-1) * PROFILES_PER_PAGE;
        $limit =  PROFILES_PER_PAGE + 1;

        $cnt = 0;

        if ($this->tag) {
            $subscribers = $this->target->getTaggedSubscribers($this->tag, $offset, $limit);
        } else {
            $subscribers = $this->target->getSubscribers($offset, $limit);
        }

        if ($subscribers) {
            $subscribers_list = new SubscribersList($subscribers, $this->target, $this);
            $cnt = $subscribers_list->show();
            if (0 == $cnt) {
                $this->showEmptyListMessage();
            }
        }

        $this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE,
                          $this->page, 'subscribers',
                          array('nickname' => $this->target->getNickname()));
    }

    function showEmptyListMessage()
    {
        if ($this->scoped instanceof Profile && $this->target->id === $this->scoped->id) {
            // TRANS: Subscriber list text when the logged in user has no subscribers.
            $message = _('You have no subscribers. Try subscribing to people you know and they might return the favor.');
        } elseif ($this->scoped instanceof Profile) {
            // TRANS: Subscriber list text when looking at the subscribers for a of a user other
            // TRANS: than the logged in user that has no subscribers. %s is the user nickname.
            $message = sprintf(_('%s has no subscribers. Want to be the first?'), $this->target->getNickname());
        } else {
            // TRANS: Subscriber list text when looking at the subscribers for a of a user that has none
            // TRANS: as an anonymous user. %s is the user nickname.
            // TRANS: This message contains a Markdown URL. The link description is between
            // TRANS: square brackets, and the link between parentheses. Do not separate "]("
            // TRANS: and do not change the URL part.
            $message = sprintf(_('%s has no subscribers. Why not [register an account](%%%%action.register%%%%) and be the first?'), $this->target->getNickname());
        }

        $this->elementStart('div', 'guide');
        $this->raw(common_markup_to_html($message));
        $this->elementEnd('div');
    }

    function showSections()
    {
        parent::showSections();
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * List of a user's subscriptions
 *
 * 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  Social
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Sarven Capadisli <csarven@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('GNUSOCIAL')) { exit(1); }

/**
 * A list of the user's subscriptions
 *
 * @category Social
 * @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 SubscriptionsAction extends GalleryAction
{
    function title()
    {
        if ($this->page == 1) {
            // TRANS: Header for subscriptions overview for a user (first page).
            // TRANS: %s is a user nickname.
            return sprintf(_('%s subscriptions'), $this->target->getNickname());
        } else {
            // TRANS: Header for subscriptions overview for a user (not first page).
            // TRANS: %1$s is a user nickname, %2$d is the page number.
            return sprintf(_('%1$s subscriptions, page %2$d'),
                           $this->target->getNickname(),
                           $this->page);
        }
    }

    function showPageNotice()
    {
        if ($this->scoped instanceof Profile && $this->scoped->sameAs($this->getTarget())) {
            $this->element('p', null,
                           // TRANS: Page notice for page with an overview of all subscriptions
                           // TRANS: of the logged in user's own profile.
                           _('These are the people whose notices '.
                             'you listen to.'));
        } else {
            $this->element('p', null,
                           // TRANS: Page notice for page with an overview of all subscriptions of a user other
                           // TRANS: than the logged in user. %s is the user nickname.
                           sprintf(_('These are the people whose '.
                                     'notices %s listens to.'),
                                   $this->target->getNickname()));
        }
    }

    function getAllTags()
    {
        return $this->getTags('subscribed', 'subscriber');
    }

    function showContent()
    {
        if (Event::handle('StartShowSubscriptionsContent', array($this))) {
            parent::showContent();

            $offset = ($this->page-1) * PROFILES_PER_PAGE;
            $limit =  PROFILES_PER_PAGE + 1;

            $cnt = 0;

            if ($this->tag) {
                $subscriptions = $this->target->getTaggedSubscriptions($this->tag, $offset, $limit);
            } else {
                $subscriptions = $this->target->getSubscribed($offset, $limit);
            }

            if ($subscriptions) {
                $subscriptions_list = new SubscriptionsList($subscriptions, $this->target, $this);
                $cnt = $subscriptions_list->show();
                if (0 == $cnt) {
                    $this->showEmptyListMessage();
                }
            }

            $this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE,
                              $this->page, 'subscriptions',
                              array('nickname' => $this->target->getNickname()));

            Event::handle('EndShowSubscriptionsContent', array($this));
        }
    }

    function showScripts()
    {
        parent::showScripts();
        $this->autofocus('tag');
    }

    function showEmptyListMessage()
    {
        if ($this->scoped instanceof Profile && $this->target->id === $this->scoped->id) {
                // TRANS: Subscription list text when the logged in user has no subscriptions.
                // TRANS: This message contains Markdown URLs. The link description is between
                // TRANS: square brackets, and the link between parentheses. Do not separate "]("
                // TRANS: and do not change the URL part.
                $message = _('You\'re not listening to anyone\'s notices right now, try subscribing to people you know. '.
                             'Try [people search](%%action.peoplesearch%%), look for members in groups you\'re interested '.
                             'in and in our [featured users](%%action.featured%%).');
        } else {
            // TRANS: Subscription list text when looking at the subscriptions for a of a user that has none
            // TRANS: as an anonymous user. %s is the user nickname.
            $message = sprintf(_('%s is not listening to anyone.'), $this->target->getNickname());
        }

        $this->elementStart('div', 'guide');
        $this->raw(common_markup_to_html($message));
        $this->elementEnd('div');
    }

    /**
     * Link to feeds of subscriptions
     *
     * @return array of Feed objects
     */
    function getFeeds()
    {
        return array(new Feed(Feed::ATOM,
                              common_local_url('AtomPubSubscriptionFeed',
                                               array('subscriber' => $this->target->id)),
                              // TRANS: Atom feed title. %s is a profile nickname.
                              sprintf(_('Subscription feed for %s (Atom)'),
                                      $this->target->getNickname())));
    }
}

repo_name: dansup/gnu

license: mit


code:
<?php
/*
 * 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); }

// @todo FIXME: documentation needed.
class SupAction extends Action
{
    function handle($args)
    {
        parent::handle($args);

        $seconds = $this->trimmed('seconds');

        if (!$seconds) {
            $seconds = 15;
        }

        $updates = $this->getUpdates($seconds);

        header('Content-Type: application/json; charset=utf-8');

        print json_encode(array('updated_time' => date('c'),
                                'since_time' => date('c', time() - $seconds),
                                'available_periods' => $this->availablePeriods(),
                                'period' => $seconds,
                                'updates' => $updates));
    }

    function availablePeriods()
    {
        static $periods = array(86400, 43200, 21600, 7200,
                                3600, 1800, 600, 300, 120,
                                60, 30, 15);
        $available = array();
        foreach ($periods as $period) {
            $available[$period] = common_local_url('sup',
                                                   array('seconds' => $period));
        }

        return $available;
    }

    function getUpdates($seconds)
    {
        $notice = new Notice();

        // XXX: cache this. Depends on how big this protocol becomes;
        // Re-doing this query every 15 seconds isn't the end of the world.

        $divider = common_sql_date(time() - $seconds);

        $notice->query('SELECT profile_id, max(id) AS max_id ' .
                       'FROM ( ' .
                       'SELECT profile_id, id FROM notice ' .
                        ((common_config('db','type') == 'pgsql') ?
                       'WHERE extract(epoch from created) > (extract(epoch from now()) - ' . $seconds . ') ' :
                       'WHERE created > "'.$divider.'" ' ) .
                       ') AS latest ' .
                       'GROUP BY profile_id');

        $updates = array();

        while ($notice->fetch()) {
            $updates[] = array($notice->profile_id, $notice->max_id);
        }

        return $updates;
    }

    function isReadOnly($args)
    {
        return true;
    }
}


code:
<?php
/*
 * 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); }

// @todo FIXME: documentation missing.
class TagAction extends ManagedAction
{
    var $notice;
    var $tag;
    var $page;

    protected function prepare(array $args=array())
    {
        parent::prepare($args);

        $taginput = $this->trimmed('tag');
        $this->tag = common_canonical_tag($taginput);

        if (empty($this->tag)) {
            common_redirect(common_local_url('publictagcloud'), 301);
        }

        // after common_canonical_tag we have a lowercase, no-specials tag string
        if ($this->tag !== $taginput) {
            common_redirect(common_local_url('tag', array('tag' => $this->tag)), 301);
        }

        $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;

        common_set_returnto($this->selfUrl());

        $this->notice = Notice_tag::getStream($this->tag)->getNotices(($this->page-1)*NOTICES_PER_PAGE,
                                                                       NOTICES_PER_PAGE + 1);

        if($this->page > 1 && $this->notice->N == 0){
            // TRANS: Client error when page not found (404).
            $this->clientError(_('No such page.'), 404);
        }

        return true;
    }

    function title()
    {
        if ($this->page == 1) {
            // TRANS: Title for first page of notices with tags.
            // TRANS: %s is the tag.
            return sprintf(_('Notices tagged with %s'), $this->tag);
        } else {
            // TRANS: Title for all but the first page of notices with tags.
            // TRANS: %1$s is the tag, %2$d is the page number.
            return sprintf(_('Notices tagged with %1$s, page %2$d'),
                           $this->tag,
                           $this->page);
        }
    }

    function getFeeds()
    {
        return array(new Feed(Feed::JSON,
                              common_local_url('ApiTimelineTag',
                                               array('format' => 'as',
                                                     'tag' => $this->tag)),
                              // TRANS: Link label for feed on "notices with tag" page.
                              // TRANS: %s is the tag the feed is for.
                              sprintf(_('Notice feed for tag %s (Activity Streams JSON)'),
                                      $this->tag)),
                     new Feed(Feed::RSS1,
                              common_local_url('tagrss',
                                               array('tag' => $this->tag)),
                              // TRANS: Link label for feed on "notices with tag" page.
                              // TRANS: %s is the tag the feed is for.
                              sprintf(_('Notice feed for tag %s (RSS 1.0)'),
                                      $this->tag)),
                     new Feed(Feed::RSS2,
                              common_local_url('ApiTimelineTag',
                                               array('format' => 'rss',
                                                     'tag' => $this->tag)),
                              // TRANS: Link label for feed on "notices with tag" page.
                              // TRANS: %s is the tag the feed is for.
                              sprintf(_('Notice feed for tag %s (RSS 2.0)'),
                                      $this->tag)),
                     new Feed(Feed::ATOM,
                              common_local_url('ApiTimelineTag',
                                               array('format' => 'atom',
                                                     'tag' => $this->tag)),
                              // TRANS: Link label for feed on "notices with tag" page.
                              // TRANS: %s is the tag the feed is for.
                              sprintf(_('Notice feed for tag %s (Atom)'),
                                      $this->tag)));
    }

    protected function showContent()
    {
        if(Event::handle('StartTagShowContent', array($this))) {

            $nl = new PrimaryNoticeList($this->notice, $this, array('show_n'=>NOTICES_PER_PAGE));

            $cnt = $nl->show();

            $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
                              $this->page, 'tag', array('tag' => $this->tag));

            Event::handle('EndTagShowContent', array($this));
        }
    }

    function isReadOnly($args)
    {
        return true;
    }
}


code:
<?php
/*
 * 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); }

class TagprofileAction extends FormAction
{
    var $error = null;

    protected $target = null;
    protected $form = 'TagProfile';

    protected function doPreparation()
    {
        $id = $this->trimmed('id');
        $uri = $this->trimmed('uri');
        if (!empty($id))  {
            $this->target = Profile::getKV('id', $id);

            if (!$this->target instanceof Profile) {
                // TRANS: Client error displayed when referring to non-existing profile ID.
                $this->clientError(_('No profile with that ID.'));
            }
        } elseif (!empty($uri)) {
            $this->target = Profile::fromUri($uri);
        } else {
            // TRANS: Client error displayed when trying to tag a user but no ID or profile is provided.
            $this->clientError(_('No profile identifier provided.'));
        }

        if (!$this->scoped->canTag($this->target)) {
            // TRANS: Client error displayed when trying to tag a user that cannot be tagged.
            $this->clientError(_('You cannot tag this user.'));
        }

        $this->formOpts = $this->target;

        return true;
    }

    function title()
    {
        if (!$this->target instanceof Profile) {
            // TRANS: Title for list form when not on a profile page.
            return _('List a profile');
        }
        // TRANS: Title for list form when on a profile page.
        // TRANS: %s is a profile nickname.
        return sprintf(_m('ADDTOLIST','List %s'), $this->target->getNickname());
    }

    function showPage()
    {
        // Only serve page content if we aren't POSTing via ajax
        // otherwise, we serve XML content from doPost()
        if (!$this->isPost() || !$this->boolean('ajax')) {
            parent::showPage();
        }
    }

    function showContent()
    {
        $this->elementStart('div', 'entity_profile h-card');
        // TRANS: Header in list form.
        $this->element('h2', null, _('User profile'));

        $avatarUrl = $this->target->avatarUrl(AVATAR_PROFILE_SIZE);
        $this->element('img', array('src' => $avatarUrl,
                                    'class' => 'u-photo avatar entity_depiction',
                                    'width' => AVATAR_PROFILE_SIZE,
                                    'height' => AVATAR_PROFILE_SIZE,
                                    'alt' => $this->target->getBestName()));

        $this->element('a', array('href' => $this->target->getUrl(),
                                  'class' => 'entity_nickname p-nickname'),
                       $this->target->getNickname());
        if ($this->target->fullname) {
            $this->element('div', 'p-name entity_fn', $this->target->fullname);
        }

        if ($this->target->location) {
            $this->element('div', 'p-locality label entity_location', $this->target->location);
        }

        if ($this->target->homepage) {
            $this->element('a', array('href' => $this->target->homepage,
                                      'rel' => 'me',
                                      'class' => 'u-url entity_url'),
                           $this->target->homepage);
        }

        if ($this->target->bio) {
            $this->element('div', 'p-note entity_note', $this->target->bio);
        }

        $this->elementEnd('div');

        if (Event::handle('StartShowTagProfileForm', array($this, $this->target))) {
            parent::showContent();
            Event::handle('EndShowTagProfileForm', array($this, $this->target));
        }
    }

    protected function doPost()
    {
        $tagstring = $this->trimmed('tags');
        $token = $this->trimmed('token');

        if (Event::handle('StartSavePeopletags', array($this, $tagstring))) {
            $tags = array();
            $tag_priv = array();

            if (is_string($tagstring) && strlen($tagstring) > 0) {

                $tags = preg_split('/[\s,]+/', $tagstring);

                foreach ($tags as &$tag) {
                    $private = @$tag[0] === '.';

                    $tag = common_canonical_tag($tag);
                    if (!common_valid_profile_tag($tag)) {
                        // TRANS: Form validation error displayed if a given tag is invalid.
                        // TRANS: %s is the invalid tag.
                        throw new ClientException(sprintf(_('Invalid tag: "%s".'), $tag));
                    }

                    $tag_priv[$tag] = $private;
                }
            }

            $result = Profile_tag::setTags($this->scoped->getID(), $this->target->getID(), $tags, $tag_priv);
            if (!$result) {
                throw new ServerException('The tags could not be saved.');
            }

            if ($this->boolean('ajax')) {
                $this->startHTML('text/xml;charset=utf-8');
                $this->elementStart('head');
                $this->element('title', null, _m('TITLE','Tags'));
                $this->elementEnd('head');
                $this->elementStart('body');

                if ($this->scoped->id == $this->target->id) {
                    $widget = new SelftagsWidget($this, $this->scoped, $this->target);
                    $widget->show();
                } else {
                    $widget = new PeopletagsWidget($this, $this->scoped, $this->target);
                    $widget->show();
                }

                $this->elementEnd('body');
                $this->endHTML();
            } else {
                // TRANS: Success message if lists are saved.
                $this->msg = _('Lists saved.');
                $this->showForm();
            }

            Event::handle('EndSavePeopletags', array($this, $tagstring));
        }
    }
}


code:
<?php
/*
 * 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); }

// Formatting of RSS handled by Rss10Action

class TagrssAction extends Rss10Action
{
    protected $tag;

    protected function doStreamPreparation()
    {
        $tag = common_canonical_tag($this->trimmed('tag'));
        $this->tag = Notice_tag::getKV('tag', $tag);
        if (!$this->tag instanceof Notice_tag) {
            // TRANS: Client error when requesting a tag feed for a non-existing tag.
            $this->clientError(_('No such tag.'));
        }
    }

    protected function getNotices()
    {
        $stream = Notice_tag::getStream($this->tag->tag)->getNotices(0, $this->limit);
        return $stream->fetchAll();
    }

    function getChannel()
    {
        $tagname = $this->tag->tag;
        $c = array('url' => common_local_url('tagrss', array('tag' => $tagname)),
               'title' => $tagname,
               'link' => common_local_url('tagrss', array('tag' => $tagname)),
               // TRANS: Tag feed description.
               // TRANS: %1$s is the tag name, %2$s is the StatusNet sitename.
               'description' => sprintf(_('Updates tagged with %1$s on %2$s!'),
                                        $tagname, common_config('site', 'name')));
        return $c;
    }

    function isReadOnly($args)
    {
        return true;
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2011, StatusNet, Inc.
 *
 * Redirect to the appropriate top-of-site
 *
 * 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  Action
 * @package   GNUsocial
 * @author    Evan Prodromou <evan@status.net>
 * @author    Mikael Nordfeldth <mmn@hethane.se>
 * @copyright 2010 StatusNet, Inc.
 * @copyright 2015 Free Software Foundation, Inc.
 * @license   https://www.gnu.org/licenses/agpl-3.0.html AGPL 3.0
 * @link      https://gnu.io/social
 */

if (!defined('GNUSOCIAL')) { exit(1); }

class TopAction extends ManagedAction
{
    public function showPage()
    {
        if (common_config('singleuser', 'enabled')) {
            $user = User::singleUser();
            common_redirect(common_local_url('showstream', array('nickname' => $user->getNickname())), 303);
        } elseif (common_config('public', 'localonly')) {
            common_redirect(common_local_url('public'), 303);
        } else {
            common_redirect(common_local_url('networkpublic'), 303);
        }
    }
}


code:
<?php
/**
 * Unblock a user 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);
}

/**
 * Unblock a user action class.
 *
 * @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/
 */
class UnblockAction extends ProfileFormAction
{
    function prepare($args)
    {
        if (!parent::prepare($args)) {
            return false;
        }

        $cur = common_current_user();

        assert(!empty($cur)); // checked by parent

        if (!$cur->hasBlocked($this->profile)) {
            // TRANS: Client error displayed when trying to unblock a non-blocked user.
            $this->clientError(_("You haven't blocked that user."));
        }

        return true;
    }

    /**
     * Unblock a user.
     *
     * @return void
     */
    function handlePost()
    {
        $cur = common_current_user();

        $result = false;

        if (Event::handle('StartUnblockProfile', array($cur, $this->profile))) {
            $result = $cur->unblock($this->profile);
            if ($result) {
                Event::handle('EndUnblockProfile', array($cur, $this->profile));
            }
        }

        if (!$result) {
            // TRANS: Server error displayed when removing a user block.
            $this->serverError(_('Error removing the block.'));
        }
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Action class to unsandbox a user
 *
 * 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  Action
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @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://status.net/
 */

if (!defined('STATUSNET')) {
    exit(1);
}

/**
 * Unsandbox a user.
 *
 * @category Action
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 * @link     http://status.net/
 */
class UnsandboxAction extends ProfileFormAction
{
    /**
     * Check parameters
     *
     * @param array $args action arguments (URL, GET, POST)
     *
     * @return boolean success flag
     */
    function prepare($args)
    {
        if (!parent::prepare($args)) {
            return false;
        }

        $cur = common_current_user();

        assert(!empty($cur)); // checked by parent

        if (!$cur->hasRight(Right::SANDBOXUSER)) {
            // TRANS: Client error on page to unsandbox a user when the feature is not enabled.
            $this->clientError(_('You cannot sandbox users on this site.'));
        }

        assert(!empty($this->profile)); // checked by parent

        if (!$this->profile->isSandboxed()) {
            // TRANS: Client error on page to unsilence a user when the to be unsandboxed user has not been sandboxed.
            $this->clientError(_('User is not sandboxed.'));
        }

        return true;
    }

    /**
     * Unsandbox a user.
     *
     * @return void
     */
    function handlePost()
    {
        $this->profile->unsandbox();
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Action class to unsilence a user
 *
 * 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  Action
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @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://status.net/
 */

if (!defined('GNUSOCIAL')) { exit(1); }

/**
 * Unsilence a user.
 *
 * @category Action
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 * @link     http://status.net/
 */
class UnsilenceAction extends ProfileFormAction
{
    function handlePost()
    {
        assert($this->scoped instanceof Profile);
        assert($this->profile instanceof Profile);

        $this->profile->unsilenceAs($this->scoped);
    }
}


code:
<?php
/**
 * Unsubscribe handler
 *
 * 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);
}

/**
 * Unsubscribe handler
 *
 * @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/
 */
class UnsubscribeAction extends Action
{
    function handle($args)
    {
        parent::handle($args);
        if (!common_logged_in()) {
            // TRANS: Error message displayed when trying to perform an action that requires a logged in user.
            $this->clientError(_('Not logged in.'));
        }

        if ($_SERVER['REQUEST_METHOD'] != 'POST') {
            common_redirect(common_local_url('subscriptions',
                                             array('nickname' => $this->scoped->nickname)));
        }

        /* Use a session token for CSRF protection. */

        $token = $this->trimmed('token');

        if (!$token || $token != common_session_token()) {
            // TRANS: Client error displayed when the session token does not match or is not given.
            $this->clientError(_('There was a problem with your session token. ' .
                                 'Try again, please.'));
        }

        $other_id = $this->arg('unsubscribeto');

        if (!$other_id) {
            // TRANS: Client error displayed when trying to unsubscribe without providing a profile ID.
            $this->clientError(_('No profile ID in request.'));
        }

        $other = Profile::getKV('id', $other_id);

        if (!($other instanceof Profile)) {
            // TRANS: Client error displayed when trying to unsubscribe while providing a non-existing profile ID.
            $this->clientError(_('No profile with that ID.'));
        }

        try {
            Subscription::cancel($this->scoped, $other);
        } catch (Exception $e) {
            $this->clientError($e->getMessage());
        }

        if ($this->boolean('ajax')) {
            $this->startHTML('text/xml;charset=utf-8');
            $this->elementStart('head');
            // TRANS: Page title for page to unsubscribe.
            $this->element('title', null, _('Unsubscribed'));
            $this->elementEnd('head');
            $this->elementStart('body');
            $subscribe = new SubscribeForm($this, $other);
            $subscribe->show();
            $this->elementEnd('body');
            $this->endHTML();
        } else {
            common_redirect(common_local_url('subscriptions', array('nickname' => $this->scoped->nickname)), 303);
        }
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Unsubscribe to a peopletag
 *
 * 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  Peopletag
 * @package   StatusNet
 * @author    Shashi Gowda <connect2shashi@gmail.com>
 * @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);
}

/**
 * Unsubscribe to a peopletag
 *
 * This is the action for subscribing to a peopletag. It works more or less like the join action
 * for groups.
 *
 * @category Peopletag
 * @package  StatusNet
 * @author   Shashi Gowda <connect2shashi@gmail.com>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class UnsubscribepeopletagAction extends Action
{
    var $peopletag = null;
    var $tagger = null;

    /**
     * Prepare to run
     */

    function prepare($args)
    {
        parent::prepare($args);

        if (!common_logged_in()) {
            // TRANS: Client error displayed when trying to perform an action while not logged in.
            $this->clientError(_('You must be logged in to unsubscribe from a list.'));
        }
        // Only allow POST requests

        if ($_SERVER['REQUEST_METHOD'] != 'POST') {
            // TRANS: Client error displayed when trying to use another method than POST.
            $this->clientError(_('This action only accepts POST requests.'));
        }

        // CSRF protection

        $token = $this->trimmed('token');

        if (!$token || $token != common_session_token()) {
            // TRANS: Client error displayed when the session token does not match or is not given.
            $this->clientError(_('There was a problem with your session token.'.
                                 ' Try again, please.'));
        }

        $tagger_arg = $this->trimmed('tagger');
        $tag_arg = $this->trimmed('tag');

        $id = intval($this->arg('id'));
        if ($id) {
            $this->peopletag = Profile_list::getKV('id', $id);
        } else {
            // TRANS: Client error displayed when trying to perform an action without providing an ID.
            $this->clientError(_('No ID given.'), 404);
        }

        if (!$this->peopletag || $this->peopletag->private) {
            // TRANS: Client error displayed trying to reference a non-existing list.
            $this->clientError(_('No such list.'), 404);
        }

        $this->tagger = Profile::getKV('id', $this->peopletag->tagger);

        return true;
    }

    /**
     * Handle the request
     *
     * On POST, add the current user to the group
     *
     * @param array $args unused
     *
     * @return void
     */
    function handle($args)
    {
        parent::handle($args);

        $cur = common_current_user();

        Profile_tag_subscription::remove($this->peopletag, $cur);

        if ($this->boolean('ajax')) {
            $this->startHTML('text/xml;charset=utf-8');
            $this->elementStart('head');
            // TRANS: Page title for form that allows unsubscribing from a list.
            // TRANS: %1$s is a nickname, %2$s is a list, %3$s is a tagger nickname.
            $this->element('title', null, sprintf(_('%1$s unsubscribed from list %2$s by %3$s'),
                                                  $cur->nickname,
                                                  $this->peopletag->tag,
                                                  $this->tagger->nickname));
            $this->elementEnd('head');
            $this->elementStart('body');
            $lf = new SubscribePeopletagForm($this, $this->peopletag);
            $lf->show();
            $this->elementEnd('body');
            $this->endHTML();
        } else {
            if (common_get_returnto()) {
                common_redirect(common_get_returnto(), 303);
            }
            common_redirect(common_local_url('peopletagsbyuser', array('nickname' => $this->tagger->nickname)), 303);
        }
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Miscellaneous settings
 *
 * 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  Settings
 * @package   StatusNet
 * @author    Robin Millette <millette@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('GNUSOCIAL')) { exit(1); }

/**
 * Miscellaneous settings actions
 *
 * Currently this just manages URL shortening.
 *
 * @category Settings
 * @package  StatusNet
 * @author   Robin Millette <millette@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 UrlsettingsAction extends SettingsAction
{
    /**
     * Title of the page
     *
     * @return string Title of the page
     */
    function title()
    {
        // TRANS: Title of URL settings tab in profile settings.
        return _('URL settings');
    }

    /**
     * Instructions for use
     *
     * @return instructions for use
     */
    function getInstructions()
    {
        // TRANS: Instructions for tab "Other" in user profile settings.
        return _('Manage various other options.');
    }

    function showScripts()
    {
        parent::showScripts();
        $this->autofocus('urlshorteningservice');
    }

    /**
     * Content area of the page
     *
     * Shows a form for uploading an avatar.
     *
     * @return void
     */
    function showContent()
    {
        $user = $this->scoped->getUser();

        $this->elementStart('form', array('method' => 'post',
                                          'id' => 'form_settings_other',
                                          'class' => 'form_settings',
                                          'action' =>
                                          common_local_url('urlsettings')));
        $this->elementStart('fieldset');
        $this->hidden('token', common_session_token());
        $this->elementStart('ul', 'form_data');

        $shorteners = array();

        Event::handle('GetUrlShorteners', array(&$shorteners));

        $services = array();

        foreach ($shorteners as $name => $value)
        {
            $services[$name] = $name;
            if ($value['freeService']) {
                // TRANS: Used as a suffix for free URL shorteners in a dropdown list in the tab "Other" of a
                // TRANS: user's profile settings. This message has one space at the beginning. Use your
                // TRANS: language's word separator here if it has one (most likely a single space).
                $services[$name] .= _(' (free service)');
            }
        }

        // Include default values

        // TRANS: Default value for URL shortening settings.
        $services['none']     = _('[none]');
        // TRANS: Default value for URL shortening settings.
        $services['internal'] = _('[internal]');

        if ($services) {
            asort($services);

            $this->elementStart('li');
            // TRANS: Label for dropdown with URL shortener services.
            $this->dropdown('urlshorteningservice', _('Shorten URLs with'),
                            // TRANS: Tooltip for for dropdown with URL shortener services.
                            $services, _('Automatic shortening service to use.'),
                            false, $user->urlshorteningservice);
            $this->elementEnd('li');
        }
        $this->elementStart('li');
        $this->input('maxurllength',
                     // TRANS: Field label in URL settings in profile.
                     _('URL longer than'),
                     (!is_null($this->arg('maxurllength'))) ?
                     $this->arg('maxurllength') : User_urlshortener_prefs::maxUrlLength($user),
                     // TRANS: Field title in URL settings in profile.
                     _('URLs longer than this will be shortened, -1 means never shorten because a URL is long.'));
        $this->elementEnd('li');
        $this->elementStart('li');
        $this->input('maxnoticelength',
                     // TRANS: Field label in URL settings in profile.
                     _('Text longer than'),
                     (!is_null($this->arg('maxnoticelength'))) ?
                     $this->arg('maxnoticelength') : User_urlshortener_prefs::maxNoticeLength($user),
                     // TRANS: Field title in URL settings in profile.
                     _('URLs in notices longer than this will always be shortened, -1 means only shorten if the full post exceeds maximum length.'));
        $this->elementEnd('li');
        $this->elementEnd('ul');
        // TRANS: Button text for saving "Other settings" in profile.
        $this->submit('save', _m('BUTTON','Save'));
        $this->elementEnd('fieldset');
        $this->elementEnd('form');
    }

    protected function doPost()
    {
        $urlshorteningservice = $this->trimmed('urlshorteningservice');

        if (!is_null($urlshorteningservice) && strlen($urlshorteningservice) > 50) {
            // TRANS: Form validation error for form "Other settings" in user profile.
            throw new ClientException(_('URL shortening service is too long (maximum 50 characters).'));
        }

        $maxurllength = $this->trimmed('maxurllength');

        if (!Validate::number($maxurllength, array('min' => -1))) {
            // TRANS: Client exception thrown when the maximum URL settings value is invalid in profile URL settings.
            throw new ClientException(_('Invalid number for maximum URL length.'));
        }

        $maxnoticelength = $this->trimmed('maxnoticelength');

        if (!Validate::number($maxnoticelength, array('min' => -1))) {
            // TRANS: Client exception thrown when the maximum notice length settings value is invalid in profile URL settings.
            throw new ClientException(_('Invalid number for maximum notice length.'));
        }

        $user = $this->scoped->getUser();

        $user->query('BEGIN');

        $original = clone($user);

        $user->urlshorteningservice = $urlshorteningservice;

        $result = $user->update($original);

        if ($result === false) {
            common_log_db_error($user, 'UPDATE', __FILE__);
            $user->query('ROLLBACK');
            // TRANS: Server error displayed when "Other" settings in user profile could not be updated on the server.
            throw new ServerException(_('Could not update user.'));
        }

        $prefs = User_urlshortener_prefs::getPrefs($user);
        $orig  = null;

        if (!$prefs instanceof User_urlshortener_prefs) {
            $prefs = new User_urlshortener_prefs();

            $prefs->user_id = $user->id;
            $prefs->created = common_sql_now();
        } else {
            $orig = clone($prefs);
        }

        $prefs->urlshorteningservice = $urlshorteningservice;
        $prefs->maxurllength         = $maxurllength;
        $prefs->maxnoticelength      = $maxnoticelength;

        if ($orig instanceof User_urlshortener_prefs) {
            $result = $prefs->update($orig);
        } else {
            $result = $prefs->insert();
        }

        if ($result === null) {
            $user->query('ROLLBACK');
            // TRANS: Server exception thrown in profile URL settings when preferences could not be saved.
            throw new ServerException(_('Error saving user URL shortening preferences.'));
        }

        $user->query('COMMIT');

        // TRANS: Confirmation message after saving preferences.
        return _('Preferences saved.');
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * User administration panel
 *
 * 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  Settings
 * @package   StatusNet
 * @author    Evan Prodromou <evan@status.net>
 * @author    Zach Copley <zach@status.net>
 * @author    Sarven Capadisli <csarven@status.net>
 * @copyright 2008-2010 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')) {
    exit(1);
}

/**
 * Administer user settings
 *
 * @category Admin
 * @package  StatusNet
 * @author   Evan Prodromou <evan@status.net>
 * @author   Zach Copley <zach@status.net>
 * @author   Sarven Capadisli <csarven@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 UseradminpanelAction extends AdminPanelAction
{
    /**
     * Returns the page title
     *
     * @return string page title
     */
    function title()
    {
        // TRANS: User admin panel title.
        return _m('TITLE', 'User');
    }

    /**
     * Instructions for using this form.
     *
     * @return string instructions
     */
    function getInstructions()
    {
        // TRANS: Instruction for user admin panel.
        return _('User settings for this StatusNet site');
    }

    /**
     * Show the site admin panel form
     *
     * @return void
     */
    function showForm()
    {
        $form = new UserAdminPanelForm($this);
        $form->show();
        return;
    }

    /**
     * Save settings from the form
     *
     * @return void
     */
    function saveSettings()
    {
        static $settings = array(
                'profile' => array('biolimit'),
                'newuser' => array('welcome', 'default')
        );

        static $booleans = array(
            'invite' => array('enabled')
        );

        $values = array();

        foreach ($settings as $section => $parts) {
            foreach ($parts as $setting) {
                $values[$section][$setting] = $this->trimmed("$section-$setting");
            }
        }

        foreach ($booleans as $section => $parts) {
            foreach ($parts as $setting) {
                $values[$section][$setting] = ($this->boolean("$section-$setting")) ? 1 : 0;
            }
        }

        // This throws an exception on validation errors

        $this->validate($values);

        // assert(all values are valid);

        $config = new Config();

        $config->query('BEGIN');

        foreach ($settings as $section => $parts) {
            foreach ($parts as $setting) {
                Config::save($section, $setting, $values[$section][$setting]);
            }
        }

        foreach ($booleans as $section => $parts) {
            foreach ($parts as $setting) {
                Config::save($section, $setting, $values[$section][$setting]);
            }
        }

        $config->query('COMMIT');

        return;
    }

    function validate(&$values)
    {
        // Validate biolimit

        if (!Validate::number($values['profile']['biolimit'])) {
            // TRANS: Form validation error in user admin panel when a non-numeric character limit was set.
            $this->clientError(_('Invalid bio limit. Must be numeric.'));
        }

        // Validate welcome text

        if (mb_strlen($values['newuser']['welcome']) > 255) {
            // TRANS: Form validation error in user admin panel when welcome text is too long.
            $this->clientError(_('Invalid welcome text. Maximum length is 255 characters.'));
        }

        // Validate default subscription

        if (!empty($values['newuser']['default'])) {
            $defuser = User::getKV('nickname', trim($values['newuser']['default']));
            if (empty($defuser)) {
                $this->clientError(
                    sprintf(
                        // TRANS: Client error displayed when trying to set a non-existing user as default subscription for new
                        // TRANS: users in user admin panel. %1$s is the invalid nickname.
                        _('Invalid default subscripton: "%1$s" is not a user.'),
                        $values['newuser']['default']
                    )
                );
            }
        }
    }
}

// @todo FIXME: Class documentation missing.
class UserAdminPanelForm extends AdminForm
{
    /**
     * ID of the form
     *
     * @return int ID of the form
     */
    function id()
    {
        return 'useradminpanel';
    }

    /**
     * class of the form
     *
     * @return string class of the form
     */
    function formClass()
    {
        return 'form_settings';
    }

    /**
     * Action of the form
     *
     * @return string URL of the action
     */
    function action()
    {
        return common_local_url('useradminpanel');
    }

    /**
     * Data elements of the form
     *
     * @return void
     */
    function formData()
    {
        $this->out->elementStart('fieldset', array('id' => 'settings_user-profile'));
        // TRANS: Fieldset legend in user administration panel.
        $this->out->element('legend', null, _m('LEGEND','Profile'));
        $this->out->elementStart('ul', 'form_data');

        $this->li();
        // TRANS: Field label in user admin panel for setting the character limit for the bio field.
        $this->input('biolimit', _('Bio Limit'),
                     // TRANS: Tooltip in user admin panel for setting the character limit for the bio field.
                     _('Maximum length of a profile bio in characters.'),
                     'profile');
        $this->unli();

        $this->out->elementEnd('ul');
        $this->out->elementEnd('fieldset');

        $this->out->elementStart('fieldset', array('id' => 'settings_user-newusers'));
        // TRANS: Form legend in user admin panel.
        $this->out->element('legend', null, _('New users'));
        $this->out->elementStart('ul', 'form_data');

        $this->li();
        // TRANS: Field label in user admin panel for setting new user welcome text.
        $this->input('welcome', _('New user welcome'),
                     // TRANS: Tooltip in user admin panel for setting new user welcome text.
                     _('Welcome text for new users (maximum 255 characters).'),
                     'newuser');
        $this->unli();

        $this->li();
        // TRANS: Field label in user admin panel for setting default subscription for new users.
        $this->input('default', _('Default subscription'),
                     // TRANS: Tooltip in user admin panel for setting default subscription for new users.
                     _('Automatically subscribe new users to this user.'),
                     'newuser');
        $this->unli();

        $this->out->elementEnd('ul');

        $this->out->elementEnd('fieldset');

        $this->out->elementStart('fieldset', array('id' => 'settings_user-invitations'));
        // TRANS: Form legend in user admin panel.
        $this->out->element('legend', null, _('Invitations'));
        $this->out->elementStart('ul', 'form_data');

        $this->li();

        // TRANS: Field label for checkbox in user admin panel for allowing users to invite friend using site e-mail.
        $this->out->checkbox('invite-enabled', _('Invitations enabled'),
                              (bool) $this->value('enabled', 'invite'),
                              // TRANS: Tooltip for checkbox in user admin panel for allowing users to invite friend using site e-mail.
                              _('Whether to allow users to invite new users.'));
        $this->unli();

        $this->out->elementEnd('ul');
        $this->out->elementEnd('fieldset');
    }

    /**
     * Utility to simplify some of the duplicated code around
     * params and settings.  Overrided from base class to be
     * more specific about input ids.
     *
     * @param string $setting      Name of the setting
     * @param string $title        Title to use for the input
     * @param string $instructions Instructions for this field
     * @param string $section      config section, default = 'site'
     *
     * @return void
     */
    function input($setting, $title, $instructions, $section='site')
    {
        $this->out->input("$section-$setting", $title, $this->value($setting, $section), $instructions);
    }

    /**
     * Action elements
     *
     * @return void
     */
    function formActions()
    {
        $this->out->submit('submit',
                           // TRANS: Button text to save user settings in user admin panel.
                           _m('BUTTON','Save'),
                           'submit',
                           null,
                           // TRANS: Button title to save user settings in user admin panel.
                           _('Save user settings.'));
    }
}


code:
<?php
/**
 * User by ID 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('GNUSOCIAL')) { exit(1); }

/**
 * User by ID action class.
 *
 * @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/
 */
class UserbyidAction extends ShowstreamAction
{
    protected function doPreparation()
    {
        // accessing by ID just requires an ID, not a nickname
        $this->target = Profile::getByID($this->trimmed('id'));

        // For local users when accessed by id number, redirect with
        // the nickname as argument instead of id.
        if ($this->target->isLocal()) {
            // Support redirecting to FOAF rdf/xml if the agent prefers it...
            // Internet Explorer doesn't specify "text/html" and does list "*/*"
            // at least through version 8. We need to list text/html up front to
            // ensure that only user-agents who specifically ask for RDF get it.
            $page_prefs = 'text/html,application/xhtml+xml,application/rdf+xml,application/xml;q=0.3,text/xml;q=0.2';
            $httpaccept = isset($_SERVER['HTTP_ACCEPT']) ? $_SERVER['HTTP_ACCEPT'] : null;
            $type       = common_negotiate_type(common_accept_to_prefs($httpaccept),
                                                common_accept_to_prefs($page_prefs));
            $page       = $type === 'application/rdf+xml' ? 'foaf' : 'showstream';
            $url        = common_local_url($page, array('nickname' => $this->target->getNickname()));
            common_redirect($url, 303);
        }
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * User groups information
 *
 * 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>
 * @author    Sarven Capadisli <csarven@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/grouplist.php';

/**
 * User groups page
 *
 * Show the groups a user belongs to
 *
 * @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 UsergroupsAction extends GalleryAction
{
    function title()
    {
        if ($this->page == 1) {
            // TRANS: Page title for first page of groups for a user.
            // TRANS: %s is a nickname.
            return sprintf(_('%s groups'), $this->getTarget()->getNickname());
        } else {
            // TRANS: Page title for all but the first page of groups for a user.
            // TRANS: %1$s is a nickname, %2$d is a page number.
            return sprintf(_('%1$s groups, page %2$d'),
                           $this->getTarget()->getNickname(),
                           $this->page);
        }
    }

    function showPageNotice()
    {
        if ($this->scoped instanceof Profile && $this->scoped->sameAs($this->getTarget())) {
            $this->element('p', 'instructions',
                           // TRANS: Page notice for page with an overview of all subscribed groups
                           // TRANS: of the logged in user's own profile.
                           _('These are the groups whose notices '.
                             'you listen to.'));
        } else {
            $this->element('p', 'instructions',
                           // TRANS: Page notice for page with an overview of all groups a user other
                           // TRANS: than the logged in user. %s is the user nickname.
                           sprintf(_('These are the groups whose '.
                                     'notices %s listens to.'),
                                   $this->target->getNickname()));
        }
    }

    function showContent()
    {
        if ($this->scoped instanceof Profile && $this->scoped->sameAs($this->getTarget())) {
	  $notice =
          // TRANS: Page notice of user's groups page.
          // TRANS: %%%%action.groupsearch%%%% and %%%%action.newgroup%%%% are URLs. Do not change them.
          // TRANS: This message contains Markdown links in the form [link text](link).
          sprintf(_('Groups let you find and talk with ' .
		    'people of similar interests. ' .
		    'You can [search for groups](%%%%action.groups%%%%) in your instance or ' .
                    '[create a new group](%%%%action.newgroup%%%%). ' .
		    'You can also follow groups ' .
		    'from other GNU social instances: click on the remote button below ' .
		    'and copy the group\'s link. ' .
		    'You can find a list of GNU social groups [here](http://skilledtests.com/wiki/List_of_federated_GNU_social_groups)' .
		    ''));
	  $this->elementStart('div', 'instructions');
	  $this->raw(common_markup_to_html($notice));
	  $this->elementEnd('div');
	}

        if (Event::handle('StartShowUserGroupsContent', array($this))) {
            $offset = ($this->page-1) * GROUPS_PER_PAGE;
            $limit =  GROUPS_PER_PAGE + 1;

            $groups = $this->getTarget()->getGroups($offset, $limit);

            if ($groups instanceof User_group) {
                $gl = new GroupList($groups, $this->getTarget(), $this);
                $cnt = $gl->show();
		if (0 == $cnt) {
		  $this->showEmptyListMessage();
		} else {
		  $this->pagination($this->page > 1, $cnt > GROUPS_PER_PAGE,
				    $this->page, 'usergroups',
				    array('nickname' => $this->getTarget()->getNickname()));
		}
            }

            Event::handle('EndShowUserGroupsContent', array($this));
        }
    }

    function showEmptyListMessage()
    {
        // TRANS: Text on group page for a user that is not a member of any group.
        // TRANS: %s is a user nickname.
        $message = sprintf(_('%s is not a member of any group.'), $this->getTarget()->getNickname()) . ' ';
        if (common_logged_in()) {
            if ($this->scoped->sameAs($this->getTarget())) {
                // TRANS: Text on group page for a user that is not a member of any group. This message contains
                // TRANS: a Markdown link in the form [link text](link) and a variable that should not be changed.
	        $message = _('You are not member of any group yet. After you join a group ' .
			     'you can send messages to its members using the ' .
			     'syntax "!groupname".');
            }
	}
        $this->elementStart('div', 'guide');
        $this->raw(common_markup_to_html($message));
        $this->elementEnd('div');
    }

    function showProfileBlock()
    {
        $block = new AccountProfileBlock($this, $this->getTarget());
        $block->show();
    }
}


code:
<?php
/*
 * 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); }

// Formatting of RSS handled by Rss10Action

class UserrssAction extends TargetedRss10Action
{
    protected $tag = null;

    protected function doStreamPreparation()
    {
        parent::doStreamPreparation();

        $this->tag  = $this->trimmed('tag');
    }

    protected function getNotices()
    {
        if (!empty($this->tag)) {
            $stream = $this->getTarget()->getTaggedNotices($this->tag, 0, $this->limit);
            return $stream->fetchAll();
        }
        // otherwise we fetch a normal user stream

        $stream = $this->getTarget()->getNotices(0, $this->limit);
        return $stream->fetchAll();
    }

    function getChannel()
    {
        $c = array('url' => common_local_url('userrss',
                                             array('nickname' =>
                                                   $this->target->getNickname())),
                   // TRANS: Message is used as link title. %s is a user nickname.
                   'title' => sprintf(_('%s timeline'), $this->target->getNickname()),
                   'link' => $this->target->getUrl(),
                   // TRANS: Message is used as link description. %1$s is a username, %2$s is a site name.
                   'description' => sprintf(_('Updates from %1$s on %2$s!'),
                                            $this->target->getNickname(), common_config('site', 'name')));
        return $c;
    }

    // override parent to add X-SUP-ID URL

    function initRss()
    {
        $url = common_local_url('sup', null, null, $this->target->getID());
        header('X-SUP-ID: '.$url);
        parent::initRss();
    }

    function isReadOnly($args)
    {
        return true;
    }
}


code:
<?php
/**
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2008-2011, StatusNet, Inc.
 *
 * Show version information for this software and plugins
 *
 * 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 Info
 * @package  GNUsocial
 * @author   Evan Prodromou <evan@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link     http://status.net/
 */

if (!defined('GNUSOCIAL')) { exit(1); }

/**
 * Version info page
 *
 * A page that shows version information for this site. Helpful for
 * debugging, for giving credit to authors, and for linking to more
 * complete documentation for admins.
 *
 * @category Info
 * @package  GNUsocial
 * @author   Evan Prodromou <evan@status.net>
 * @author   Craig Andrews <candrews@integralblue.com>
 * @copyright 2009-2011 Free Software Foundation, Inc http://www.fsf.org
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
 * @link     http://status.net/
 */
class VersionAction extends Action
{
    var $pluginVersions = array();

    /**
     * Return true since we're read-only.
     *
     * @param array $args other arguments
     *
     * @return boolean is read only action?
     */
    function isReadOnly($args)
    {
        return true;
    }

    /**
     * Returns the page title
     *
     * @return string page title
     */
    function title()
    {
        // TRANS: Title for version page. %1$s is the engine name, %2$s is the engine version.
        return sprintf(_('%1$s %2$s'), GNUSOCIAL_ENGINE, GNUSOCIAL_VERSION);
    }

    /**
     * Prepare to run
     *
     * Fire off an event to let plugins report their
     * versions.
     *
     * @param array $args array misc. arguments
     *
     * @return boolean true
     */
    protected function prepare(array $args=array())
    {
        parent::prepare($args);

        Event::handle('PluginVersion', array(&$this->pluginVersions));

        return true;
    }

    /**
     * Execute the action
     *
     * Shows a page with the version information in the
     * content area.
     *
     * @param array $args ignored.
     *
     * @return void
     */
    protected function handle()
    {
        parent::handle();
        $this->showPage();
    }

    /*
    * Override to add h-entry, and content-inner classes
    *
    * @return void
    */
    function showContentBlock()
     {
         $this->elementStart('div', array('id' => 'content', 'class' => 'h-entry'));
         $this->showPageTitle();
         $this->showPageNoticeBlock();
         $this->elementStart('div', array('id' => 'content_inner',
                                          'class' => 'e-content'));
         // show the actual content (forms, lists, whatever)
         $this->showContent();
         $this->elementEnd('div');
         $this->elementEnd('div');
     }

    /*
    * Overrride to add entry-title class
    *
    * @return void
    */
    function showPageTitle() {
        $this->element('h1', array('class' => 'entry-title'), $this->title());
    }

    /**
     * Show version information
     *
     * @return void
     */
    function showContent()
    {
        $this->elementStart('p');

        // TRANS: Content part of engine version page.
        // TRANS: %1$s is the engine name (GNU social) and %2$s is the GNU social version.
        $this->raw(sprintf(_('This site is powered by %1$s version %2$s, '.
                             'Copyright 2008-2013 StatusNet, Inc. '.
                             'and contributors.'),
                           XMLStringer::estring('a', array('href' => GNUSOCIAL_ENGINE_URL),
                                                // TRANS: Engine name.
                                                GNUSOCIAL_ENGINE),
                           GNUSOCIAL_VERSION));
        $this->elementEnd('p');

        // TRANS: Header for engine software contributors section on the version page.
        $this->element('h2', null, _('Contributors'));

        sort($this->contributors);
        $this->element('p', null, implode(', ', $this->contributors));

        // TRANS: Header for engine software license section on the version page.
        $this->element('h2', null, _('License'));

        $this->element('p', null,
                       // TRANS: Content part of engine software version page. %1s is engine name
                       sprintf(_('%1$s 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.'), GNUSOCIAL_ENGINE));

        $this->element('p', null,
                       // TRANS: Content part of engine software version page.
                       _('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.'));

        $this->elementStart('p');
        // TRANS: Content part of engine version page.
        // TRANS: %s is a link to the AGPL license with link description "http://www.gnu.org/licenses/agpl.html".
        $this->raw(sprintf(_('You should have received a copy of the GNU Affero General Public License '.
                             'along with this program.  If not, see %s.'),
                           XMLStringer::estring('a', array('href' => 'http://www.gnu.org/licenses/agpl.html'),
                                                'http://www.gnu.org/licenses/agpl.html')));
        $this->elementEnd('p');

        // XXX: Theme information?

        if (count($this->pluginVersions)) {
            // TRANS: Header for engine plugins section on the version page.
            $this->element('h2', null, _('Plugins'));

            $this->elementStart('table', array('id' => 'plugins_enabled'));

            $this->elementStart('thead');
            $this->elementStart('tr');
            // TRANS: Column header for plugins table on version page.
            $this->element('th', array('id' => 'plugin_name'), _m('HEADER','Name'));
            // TRANS: Column header for plugins table on version page.
            $this->element('th', array('id' => 'plugin_version'), _m('HEADER','Version'));
            // TRANS: Column header for plugins table on version page.
            $this->element('th', array('id' => 'plugin_authors'), _m('HEADER','Author(s)'));
            // TRANS: Column header for plugins table on version page.
            $this->element('th', array('id' => 'plugin_description'), _m('HEADER','Description'));
            $this->elementEnd('tr');
            $this->elementEnd('thead');

            $this->elementStart('tbody');
            foreach ($this->pluginVersions as $plugin) {
                $this->elementStart('tr');
                if (array_key_exists('homepage', $plugin)) {
                    $this->elementStart('th');
                    $this->element('a', array('href' => $plugin['homepage']),
                                   $plugin['name']);
                    $this->elementEnd('th');
                } else {
                    $this->element('th', null, $plugin['name']);
                }

                $this->element('td', null, $plugin['version']);

                if (array_key_exists('author', $plugin)) {
                    $this->element('td', null, $plugin['author']);
                }

                if (array_key_exists('rawdescription', $plugin)) {
                    $this->elementStart('td');
                    $this->raw($plugin['rawdescription']);
                    $this->elementEnd('td');
                } else if (array_key_exists('description', $plugin)) {
                    $this->element('td', null, $plugin['description']);
                }
                $this->elementEnd('tr');
            }
            $this->elementEnd('tbody');
            $this->elementEnd('table');
        }

    }

    var $contributors = array('Evan Prodromou (StatusNet)',
                              'Zach Copley (StatusNet)',
                              'Earle Martin (StatusNet)',
                              'Marie-Claude Doyon (StatusNet)',
                              'Sarven Capadisli (StatusNet)',
                              'Robin Millette (StatusNet)',
                              'Ciaran Gultnieks',
                              'Michael Landers',
                              'Ori Avtalion',
                              'Garret Buell',
                              'Mike Cochrane',
                              'Matthew Gregg',
                              'Florian Biree',
                              'Erik Stambaugh',
                              'drry',
                              'Gina Haeussge',
                              'Tryggvi Björgvinsson',
                              'Adrian Lang',
                              'Meitar Moscovitz',
                              'Sean Murphy',
                              'Leslie Michael Orchard',
                              'Eric Helgeson',
                              'Ken Sedgwick',
                              'Brian Hendrickson',
                              'Tobias Diekershoff',
                              'Dan Moore',
                              'Fil',
                              'Jeff Mitchell',
                              'Brenda Wallace',
                              'Jeffery To',
                              'Federico Marani',
                              'Craig Andrews',
                              'mEDI',
                              'Brett Taylor',
                              'Brigitte Schuster',
                              'Brion Vibber (StatusNet)',
                              'Siebrand Mazeland',
                              'Samantha Doherty (StatusNet)',
                              'Mikael Nordfeldth (FSF)');
}


code:
<?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/>.
 */

class Attention extends Managed_DataObject
{
    public $__table = 'attention';  // table name
    public $notice_id;              // int(4) primary_key not_null
    public $profile_id;             // int(4) primary_key not_null
    public $reason;                 // varchar(191)   not 255 because utf8mb4 takes more space
    public $created;                // datetime()   not_null
    public $modified;               // timestamp   not_null default_CURRENT_TIMESTAMP

    public static function schemaDef()
    {
        return array(
            'description' => 'Notice attentions to profiles (that are not a mention and not result of a subscription)',
            'fields' => array(
                'notice_id' => array('type' => 'int', 'not null' => true, 'description' => 'notice_id to give attention'),
                'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'profile_id for feed receiver'),
                'reason' => array('type' => 'varchar', 'length' => 191, 'description' => 'Optional reason why this was brought to the attention of profile_id'),
                'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
            ),
            'primary key' => array('notice_id', 'profile_id'),
            'foreign keys' => array(
                'attention_notice_id_fkey' => array('notice', array('notice_id' => 'id')),
                'attention_profile_id_fkey' => array('profile', array('profile_id' => 'id')),
            ),
            'indexes' => array(
                'attention_notice_id_idx' => array('notice_id'),
                'attention_profile_id_idx' => array('profile_id'),
            ),
        );
    }

    public static function saveNew(Notice $notice, Profile $target, $reason=null)
    {
        try {
            $att = Attention::getByKeys(['notice_id'=>$notice->getID(), 'profile_id'=>$target->getID()]);
            throw new AlreadyFulfilledException('Attention already exists with reason: '.var_export($att->reason,true));
        } catch (NoResultException $e) {
            $att = new Attention();

            $att->notice_id = $notice->getID();
            $att->profile_id = $target->getID();
            $att->reason = $reason;
            $att->created = common_sql_now();
            $result = $att->insert();

            if ($result === false) {
                throw new Exception('Failed Attention::saveNew for notice id=='.$notice->getID().' target id=='.$target->getID().', reason=="'.$reason.'"');
            }
        }
        return $att;
    }
}


code:
<?php

if (!defined('GNUSOCIAL')) { exit(1); }

/**
 * Table Definition for avatar
 */

class Avatar extends Managed_DataObject
{
    public $__table = 'avatar';                          // table name
    public $profile_id;                      // int(4)  primary_key not_null
    public $original;                        // tinyint(1)
    public $width;                           // int(4)  primary_key not_null
    public $height;                          // int(4)  primary_key not_null
    public $mediatype;                       // varchar(32)   not_null
    public $filename;                        // varchar(191)   not 255 because utf8mb4 takes more space
    public $created;                         // datetime()   not_null
    public $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP

    public static function schemaDef()
    {
        return array(
            'fields' => array(
                'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'foreign key to profile table'),
                'original' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'uploaded by user or generated?'),
                'width' => array('type' => 'int', 'not null' => true, 'description' => 'image width'),
                'height' => array('type' => 'int', 'not null' => true, 'description' => 'image height'),
                'mediatype' => array('type' => 'varchar', 'length' => 32, 'not null' => true, 'description' => 'file type'),
                'filename' => array('type' => 'varchar', 'length' => 191, 'description' => 'local filename, if local'),
                'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
                'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
            ),
            'primary key' => array('profile_id', 'width', 'height'),
            'unique keys' => array(
//                'avatar_filename_key' => array('filename'),
            ),
            'foreign keys' => array(
                'avatar_profile_id_fkey' => array('profile', array('profile_id' => 'id')),
            ),
            'indexes' => array(
                'avatar_profile_id_idx' => array('profile_id'),
            ),
        );
    }

    // We clean up the file, too
    function delete($useWhere=false)
    {
        $filename = $this->filename;
        if (file_exists(Avatar::path($filename))) {
            @unlink(Avatar::path($filename));
        }

        return parent::delete($useWhere);
    }

    /*
     * Deletes all avatars (but may spare the original) from a profile.
     *
     * @param   Profile $target     The profile we're deleting avatars of.
     * @param   boolean $original   Whether original should be removed or not.
     */
    public static function deleteFromProfile(Profile $target, $original=true) {
        try {
            $avatars = self::getProfileAvatars($target);
            foreach ($avatars as $avatar) {
                if ($avatar->original && !$original) {
                    continue;
                }
                $avatar->delete();
            }
        } catch (NoAvatarException $e) {
            // There are no avatars to delete, a sort of success.
        }

        return true;
    }

    static protected $_avatars = array();

    /*
     * Get an avatar by profile. Currently can't call newSize with $height
     */
    public static function byProfile(Profile $target, $width=null, $height=null)
    {
        $width  = intval($width);
        $height = !is_null($height) ? intval($height) : null;
        if (is_null($height)) {
            $height = $width;
        }

        $size = "{$width}x{$height}";
        if (!isset(self::$_avatars[$target->id])) {
            self::$_avatars[$target->id] = array();
        } elseif (isset(self::$_avatars[$target->id][$size])){
            return self::$_avatars[$target->id][$size];
        }

        $avatar = null;
        if (Event::handle('StartProfileGetAvatar', array($target, $width, &$avatar))) {
            $avatar = self::pkeyGet(
                array(
                    'profile_id' => $target->id,
                    'width'      => $width,
                    'height'     => $height,
                )
            );
            Event::handle('EndProfileGetAvatar', array($target, $width, &$avatar));
        }

        if (is_null($avatar)) {
            // Obviously we can't find an avatar, so let's resize the original!
            $avatar = Avatar::newSize($target, $width);
        } elseif (!($avatar instanceof Avatar)) {
            throw new NoAvatarException($target, $avatar);
        }

        self::$_avatars[$target->id]["{$avatar->width}x{$avatar->height}"] = $avatar;
        return $avatar;
    }

    public static function getUploaded(Profile $target)
    {
        $avatar = new Avatar();
        $avatar->profile_id = $target->id;
        $avatar->original = true;
        if (!$avatar->find(true)) {
            throw new NoAvatarException($target, $avatar);
        }
        if (!file_exists(Avatar::path($avatar->filename))) {
            // The delete call may be odd for, say, unmounted filesystems
            // that cause a file to currently not exist, but actually it does...
            $avatar->delete();
            throw new NoAvatarException($target, $avatar);
        }
        return $avatar;
    }

    public static function getProfileAvatars(Profile $target) {
        $avatar = new Avatar();
        $avatar->profile_id = $target->id;
        if (!$avatar->find()) {
            throw new NoAvatarException($target, $avatar);
        }
        return $avatar->fetchAll();
    }

    /**
     * Where should the avatar go for this user?
     */
    static function filename($id, $extension, $size=null, $extra=null)
    {
        if ($size) {
            return $id . '-' . $size . (($extra) ? ('-' . $extra) : '') . $extension;
        } else {
            return $id . '-original' . (($extra) ? ('-' . $extra) : '') . $extension;
        }
    }

    static function path($filename)
    {
        $dir = common_config('avatar', 'dir');

        if ($dir[strlen($dir)-1] != '/') {
            $dir .= '/';
        }

        return $dir . $filename;
    }

    static function url($filename)
    {
        $path = common_config('avatar', 'path');

        if ($path[strlen($path)-1] != '/') {
            $path .= '/';
        }

        if ($path[0] != '/') {
            $path = '/'.$path;
        }

        $server = common_config('avatar', 'server');

        if (empty($server)) {
            $server = common_config('site', 'server');
        }

        $ssl = (common_config('avatar', 'ssl') || GNUsocial::useHTTPS());

        $protocol = ($ssl) ? 'https' : 'http';

        return $protocol.'://'.$server.$path.$filename;
    }

    function displayUrl()
    {
        return Avatar::url($this->filename);
    }

    static function urlByProfile(Profile $target, $width=null, $height=null) {
        try {
            return self::byProfile($target,  $width, $height)->displayUrl();
        } catch (Exception $e) {
            return self::defaultImage($width);
        }
    }

    static function defaultImage($size)
    {
        static $sizenames = array(AVATAR_PROFILE_SIZE => 'profile',
                                  AVATAR_STREAM_SIZE => 'stream',
                                  AVATAR_MINI_SIZE => 'mini');
        return Theme::path('default-avatar-'.$sizenames[$size].'.png');
    }

    static function newSize(Profile $target, $width) {
        $width = intval($width);
        if ($width < 1 || $width > common_config('avatar', 'maxsize')) {
            // TRANS: An error message when avatar size is unreasonable
            throw new Exception(_m('Avatar size too large'));
        }
        // So far we only have square avatars and I don't have time to
        // rewrite support for non-square ones right now ;)
        $height = $width;

        $original = Avatar::getUploaded($target);

        $imagefile = new ImageFile(null, Avatar::path($original->filename));
        $filename = Avatar::filename($target->getID(), image_type_to_extension($imagefile->preferredType()),
                                     $width, common_timestamp());
        $imagefile->resizeTo(Avatar::path($filename), array('width'=>$width, 'height'=>$height));

        $scaled = clone($original);
        $scaled->original = false;
        $scaled->width = $width;
        $scaled->height = $height;
        $scaled->filename = $filename;
        $scaled->created = common_sql_now();

        if (!$scaled->insert()) {
            // TRANS: An error message when unable to insert avatar data into the db
            throw new Exception(_m('Could not insert new avatar data to database'));
        }

        // Return the new avatar object
        return $scaled;
    }
}